shithub: riscv

Download patch

ref: c492a8009ab42d9409d32785c48c1d3c1b8bf076
parent: 543ccb37f47db89be6b6fe0e651f095897bbee08
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Mon Aug 28 15:40:53 EDT 2017

devsegment: handle ORCLOSE on segment directory correctly, fix wrong qid, missing COPEN flag for segmentcreate()

--- a/sys/src/9/port/devsegment.c
+++ b/sys/src/9/port/devsegment.c
@@ -177,8 +177,9 @@
 	Globalseg *g;
 
 	switch(TYPE(c)){
-	case Qtopdir:
 	case Qsegdir:
+		omode &= ~ORCLOSE;
+	case Qtopdir:
 		if(omode != 0)
 			error(Eisdir);
 		break;
@@ -199,20 +200,43 @@
 		panic("segmentopen");
 	}
 	c->mode = openmode(omode);
-	c->offset = 0;
 	c->flag |= COPEN;
+	c->offset = 0;
+
 	return c;
 }
 
 static void
+segmentremove(Chan *c)
+{
+	Globalseg *g;
+	int x;
+
+	if(TYPE(c) != Qsegdir)
+		error(Eperm);
+	lock(&globalseglock);
+	x = SEG(c);
+	g = globalseg[x];
+	globalseg[x] = nil;
+	unlock(&globalseglock);
+	if(g != nil)
+		putgseg(g);
+}
+
+static void
 segmentclose(Chan *c)
 {
-	switch(TYPE(c)){
-	case Qctl:
-	case Qdata:
-		if(c->flag & COPEN){
+	if(c->flag & COPEN){
+		switch(TYPE(c)){
+		case Qsegdir:
+			if(c->flag & CRCLOSE)
+				segmentremove(c);
+			break;
+		case Qctl:
+		case Qdata:
 			putgseg(c->aux);
 			c->aux = nil;
+			break;
 		}
 	}
 }
@@ -235,35 +259,39 @@
 	if((perm & DMDIR) == 0)
 		error(Ebadarg);
 
+	g = smalloc(sizeof(Globalseg));
+	g->ref = 1;
+	g->perm = 0660;
+	kstrdup(&g->name, name);
+	kstrdup(&g->uid, up->user);
+
+	lock(&globalseglock);
 	if(waserror()){
 		unlock(&globalseglock);
+		putgseg(g);
 		nexterror();
 	}
-	lock(&globalseglock);
 	xfree = -1;
 	for(x = 0; x < nelem(globalseg); x++){
-		g = globalseg[x];
-		if(g == nil){
+		if(globalseg[x] == nil){
 			if(xfree < 0)
 				xfree = x;
-		} else if(strcmp(g->name, name) == 0)
+		} else if(strcmp(globalseg[x]->name, name) == 0)
 			error(Eexist);
 	}
 	if(xfree < 0)
 		error("too many global segments");
-	g = smalloc(sizeof(Globalseg));
-	g->ref = 1;
-	kstrdup(&g->name, name);
-	kstrdup(&g->uid, up->user);
-	g->perm = 0660; 
 	globalseg[xfree] = g;
 	unlock(&globalseglock);
 	poperror();
 
-	c->qid.path = PATH(x, Qsegdir);
+	c->qid.path = PATH(xfree, Qsegdir);
 	c->qid.type = QTDIR;
 	c->qid.vers = 0;
 	c->mode = openmode(omode);
+	c->flag |= COPEN;
+	c->offset = 0;
+
 	return c;
 }
 
@@ -371,10 +399,8 @@
 	if(c->qid.type == QTDIR)
 		error(Eperm);
 
-	d = nil;
 	g = getgseg(c);
 	if(waserror()){
-		free(d);
 		putgseg(g);
 		nexterror();
 	}
@@ -381,6 +407,10 @@
 	if(strcmp(g->uid, up->user) && !iseve())
 		error(Eperm);
 	d = smalloc(sizeof(Dir)+n);
+	if(waserror()){
+		free(d);
+		nexterror();
+	}
 	n = convM2D(dp, n, &d[0], (char*)&d[1]);
 	if(n == 0)
 		error(Eshortstat);
@@ -389,6 +419,7 @@
 	if(d->mode != ~0UL)
 		g->perm = d->mode&0777;
 	free(d);
+	poperror();
 	putgseg(g);
 	poperror();
 
@@ -395,23 +426,6 @@
 	return n;
 }
 
-static void
-segmentremove(Chan *c)
-{
-	Globalseg *g;
-	int x;
-
-	if(TYPE(c) != Qsegdir)
-		error(Eperm);
-	lock(&globalseglock);
-	x = SEG(c);
-	g = globalseg[x];
-	globalseg[x] = nil;
-	unlock(&globalseglock);
-	if(g != nil)
-		putgseg(g);
-}
-
 /*
  *  called by segattach()
  */
@@ -422,11 +436,11 @@
 	Globalseg *g;
 	Segment *s;
 
+	lock(&globalseglock);
 	if(waserror()){
 		unlock(&globalseglock);
 		nexterror();
 	}
-	lock(&globalseglock);
 	for(x = 0; x < nelem(globalseg); x++){
 		g = globalseg[x];
 		if(g != nil && strcmp(g->name, name) == 0)