summaryrefslogtreecommitdiff
path: root/sys/src/9/port/devsegment.c
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2017-08-28 19:40:53 +0200
committercinap_lenrek <cinap_lenrek@felloff.net>2017-08-28 19:40:53 +0200
commitc492a8009ab42d9409d32785c48c1d3c1b8bf076 (patch)
tree07872cfdcedf9d755e232c619427ee1969f1a4bc /sys/src/9/port/devsegment.c
parent543ccb37f47db89be6b6fe0e651f095897bbee08 (diff)
devsegment: handle ORCLOSE on segment directory correctly, fix wrong qid, missing COPEN flag for segmentcreate()
Diffstat (limited to 'sys/src/9/port/devsegment.c')
-rw-r--r--sys/src/9/port/devsegment.c86
1 files changed, 50 insertions, 36 deletions
diff --git a/sys/src/9/port/devsegment.c b/sys/src/9/port/devsegment.c
index baa39846e..7cd80fc2e 100644
--- a/sys/src/9/port/devsegment.c
+++ b/sys/src/9/port/devsegment.c
@@ -177,8 +177,9 @@ segmentopen(Chan *c, int omode)
Globalseg *g;
switch(TYPE(c)){
- case Qtopdir:
case Qsegdir:
+ omode &= ~ORCLOSE;
+ case Qtopdir:
if(omode != 0)
error(Eisdir);
break;
@@ -199,20 +200,43 @@ segmentopen(Chan *c, int omode)
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 @@ segmentcreate(Chan *c, char *name, int omode, ulong perm)
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,16 +399,18 @@ segmentwstat(Chan *c, uchar *dp, int n)
if(c->qid.type == QTDIR)
error(Eperm);
- d = nil;
g = getgseg(c);
if(waserror()){
- free(d);
putgseg(g);
nexterror();
}
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,29 +419,13 @@ segmentwstat(Chan *c, uchar *dp, int n)
if(d->mode != ~0UL)
g->perm = d->mode&0777;
free(d);
+ poperror();
putgseg(g);
poperror();
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 @@ globalsegattach(char *name)
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)