9 chanattach(Fs *fs, int flags)
13 ch = emalloc(sizeof(*ch));
16 ch->loc = cloneloc(fs, (flags & CHFDUMP) != 0 ? fs->dumprootloc : fs->rootloc);
26 d = emalloc(sizeof(*d));
30 d->loc = cloneloc(ch->fs, ch->loc);
36 chanwalk(Chan *ch, char *name)
43 if(name == nil || name[0] == 0 || name[0] == '.' && name[1] == 0)
51 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
56 d = getdent(ch->loc, b);
59 if((d->type & QTDIR) == 0){
63 if(!permcheck(ch->fs, d, ch->uid, OEXEC)){
67 if(strcmp(name, "..") == 0){
71 putloc(ch->fs, ch->loc, 0);
75 if(findentry(ch->fs, ch->loc, b, name, &f, ch->flags & CHFDUMP) <= 0)
77 ch->loc = getloc(ch->fs, f, ch->loc);
93 if(name == nil || name[0] == 0)
95 if(name[0] == '.' && (name[1] == 0 || name[1] == '.' && name[2] == 0))
97 for(p = name; *p; p++)
98 if((uchar) *p < ' ' || *p == '/')
100 return p - name < NAMELEN;
104 chancreat(Chan *ch, char *name, int perm, int mode)
116 if(!namevalid(name) || ch->open != 0)
118 if((ch->flags & CHFRO) != 0)
120 if(willmodify(ch->fs, ch->loc, ch->flags & CHFNOLOCK) < 0)
122 if(isdir = ((perm & DMDIR) != 0))
123 if((mode & (OWRITE | OEXEC | ORCLOSE | OTRUNC)) != 0)
125 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
128 d = getdent(ch->loc, b);
131 if((d->type & QTDIR) == 0){
135 if((ch->flags & CHFNOPERM) == 0){
136 if(!permcheck(ch->fs, d, ch->uid, OWRITE)){
141 perm &= ~0777 | d->mode & 0777;
143 perm &= ~0666 | d->mode & 0666;
145 if(newentry(ch->fs, ch->loc, b, name, &f, 0) <= 0)
149 if(newqid(ch->fs, &f.path) < 0)
151 l = getloc(ch->fs, f, ch->loc);
157 if(willmodify(ch->fs, l, ch->flags & CHFNOLOCK) < 0)
159 b = getbuf(ch->fs->d, l->blk, TDENTRY, 0);
163 d = &b->de[l->deind];
164 memset(d, 0, sizeof(*d));
166 strcpy(d->name, name);
170 d->uid = d->muid = ch->uid;
171 d->mode = DALLOC | perm & 0777;
172 if((d->type & QTEXCL) != 0){
174 ch->loc->exlock = ch;
175 ch->loc->lwrite = d->atime;
176 qunlock(&ch->loc->ex);
180 switch(mode & OEXEC){
191 if((mode & ORCLOSE) != 0)
192 ch->open |= CHRCLOSE;
199 putloc(ch->fs, l, 0);
207 chanopen(Chan *ch, int mode)
216 if((ch->flags & CHFRO) != 0 && (mode & (ORCLOSE | OTRUNC | OWRITE | ORDWR)) != 0)
218 if((mode & OTRUNC) != 0)
219 if(willmodify(ch->fs, ch->loc, ch->flags & CHFNOLOCK) < 0)
221 if((mode & ORCLOSE) != 0){
222 if(ch->loc->next == nil)
224 b = getbuf(ch->fs->d, ch->loc->next->blk, TDENTRY, 0);
227 d = getdent(ch->loc->next, b);
230 if((ch->flags & CHFNOPERM) == 0)
231 if(!permcheck(ch->fs, d, ch->uid, OWRITE))
235 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
238 d = getdent(ch->loc, b);
241 if((d->type & QTAPPEND) != 0)
243 if((d->type & QTDIR) != 0 && (mode & (ORCLOSE | OTRUNC | OWRITE | ORDWR)) != 0)
245 if((ch->flags & CHFNOPERM) == 0){
246 if(!permcheck(ch->fs, d, ch->uid, mode & OEXEC))
248 if((mode & OTRUNC) != 0 && !permcheck(ch->fs, d, ch->uid, OWRITE))
251 if((ch->loc->type & QTEXCL) != 0){
253 if(ch->loc->exlock == nil || ch->loc->lwrite < time(0) - EXCLDUR){
254 ch->loc->exlock = ch;
255 ch->loc->lwrite = time(0);
256 qunlock(&ch->loc->ex);
258 qunlock(&ch->loc->ex);
263 switch(mode & OEXEC){
274 if((mode & OTRUNC) != 0){
275 trunc(ch->fs, ch->loc, b, 0);
279 if((mode & ORCLOSE) != 0)
280 ch->open |= CHRCLOSE;
303 if(ch->loc->exlock == ch){
304 if(ch->loc->lwrite < time(0) - EXCLDUR){
305 ch->loc->exlock = nil;
306 werrstr("lock broken");
309 ch->loc->lwrite = time(0);
314 qunlock(&ch->loc->ex);
319 chanwrite(Chan *ch, void *buf, ulong n, uvlong off)
329 if((ch->flags & CHFRO) != 0){
333 if((ch->open & CHWRITE) == 0){
338 if((ch->loc->type & QTEXCL) != 0 && checklock(ch) < 0){
342 if(willmodify(ch->fs, ch->loc, ch->flags & CHFNOLOCK) < 0){
346 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
351 d = getdent(ch->loc, b);
357 if((d->type & QTAPPEND) != 0)
368 rc = getblk(ch->fs, ch->loc, b, bl, &bl, rn == RBLOCK ? GBOVERWR : GBCREATE);
371 c = getbuf(ch->fs->d, bl, TRAW, rc == 0 || rn == RBLOCK);
374 if(rc == 0 && rn != RBLOCK)
375 memset(c->data, 0, sizeof(c->data));
376 memcpy(c->data + r, p, rn);
378 c->op |= i != e ? BWRIM : BDELWRI;
384 e = off + (p - (uchar *) buf);
392 return p - (uchar *) buf;
395 static int chandirread(Chan *, void *, ulong, uvlong);
398 chanread(Chan *ch, void *buf, ulong n, uvlong off)
406 if((ch->open & CHREAD) == 0){
411 if((ch->loc->type & QTEXCL) != 0 && checklock(ch) < 0){
415 if((ch->loc->Qid.type & QTDIR) != 0)
416 return chandirread(ch, buf, n, off);
417 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
422 d = getdent(ch->loc, b);
427 else if(off + n > d->size)
443 rc = getblk(ch->fs, ch->loc, b, bl, &bl, GBREAD);
449 c = getbuf(ch->fs->d, bl, TRAW, 0);
452 memcpy(p, c->data + r, rn);
468 statbuf(Fs *fs, Dentry *d, Dir *di, char *buf)
471 di->mode = (d->mode & 0777) | (d->Qid.type << 24);
472 di->mtime = d->mtime;
473 di->atime = d->atime;
474 di->length = d->size;
478 di->name = estrdup(d->name);
479 di->uid = uid2name(fs, d->uid, nil);
480 di->gid = uid2name(fs, d->gid, nil);
481 di->muid = uid2name(fs, d->muid, nil);
483 memset(buf, 0, NAMELEN + 3 * USERLEN);
484 strncpy(buf, d->name, NAMELEN - 1);
486 di->uid = uid2name(fs, d->uid, buf + NAMELEN);
487 di->gid = uid2name(fs, d->gid, buf + NAMELEN + USERLEN);
488 di->muid = uid2name(fs, d->muid, buf + NAMELEN + 2 * USERLEN);
493 chanstat(Chan *ch, Dir *di)
499 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
504 d = getdent(ch->loc, b);
510 statbuf(ch->fs, d, di, nil);
517 chandirread(Chan *ch, void *buf, ulong n, uvlong off)
526 char cbuf[NAMELEN + 3 * USERLEN];
532 }else if(ch->dwloff != off){
537 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
542 d = getdent(ch->loc, b);
548 if(ch->dwblk >= d->size){
559 rc = getblk(ch->fs, ch->loc, b, i, &blk, GBREAD);
568 c = getbuf(ch->fs->d, blk, TDENTRY, 0);
572 if((c->de[j].mode & DALLOC) == 0)
574 if((ch->flags & CHFDUMP) != 0 && (c->de[j].type & QTTMP) != 0)
576 statbuf(ch->fs, &c->de[j], &di, cbuf);
577 rc = convD2M(&di, (uchar *) buf + wr, n - wr);
615 if(ch->open & CHRCLOSE){
616 if((ch->flags & CHFRO) != 0)
618 if(willmodify(ch->fs, ch->loc, ch->flags & CHFNOLOCK) < 0)
620 if(ch->loc->next == nil)
622 p = getbuf(ch->fs->d, ch->loc->next->blk, TDENTRY, 0);
625 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
628 d = getdent(ch->loc->next, p);
631 if((ch->flags & CHFNOPERM) == 0)
632 if(!permcheck(ch->fs, d, ch->uid, OWRITE)){
636 d = getdent(ch->loc, b);
639 if((d->type & QTDIR) != 0 && findentry(ch->fs, ch->loc, b, nil, nil, ch->flags & CHFDUMP) != 0)
641 if((d->mode & DGONE) != 0)
643 qlock(&ch->fs->loctree);
644 if(ch->loc->ref > 1){
646 d->mode |= DGONE; /* aaaaand it's gone */
647 ch->loc->flags |= LGONE;
648 qunlock(&ch->fs->loctree);
650 ch->loc->flags &= ~LGONE;
651 qunlock(&ch->fs->loctree);
652 rc = delete(ch->fs, ch->loc, b);
661 if((ch->loc->type & QTEXCL) != 0){
663 if(ch->loc->exlock == ch)
664 ch->loc->exlock = nil;
665 qunlock(&ch->loc->ex);
667 putloc(ch->fs, ch->loc, 1);
679 chanwstat(Chan *ch, Dir *di)
683 int isdir, owner, rc;
688 if((ch->flags & CHFRO) != 0)
690 if(willmodify(ch->fs, ch->loc, ch->flags & CHFNOLOCK) < 0)
695 if(!namevalid(di->name) || ch->loc->next == nil)
697 pb = getbuf(ch->fs->d, ch->loc->next->blk, TDENTRY, 0);
700 d = getdent(ch->loc->next, pb);
703 rc = findentry(ch->fs, ch->loc->next, pb, di->name, &f, ch->flags & CHFDUMP);
707 if((ch->flags & CHFNOPERM) == 0)
708 if(!permcheck(ch->fs, d, ch->uid, OWRITE))
710 } else if(f.blk != ch->loc->blk || f.deind != ch->loc->deind){
715 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
718 d = getdent(ch->loc, b);
721 isdir = (d->type & QTDIR) != 0;
722 owner = ch->uid == d->uid ||
723 ingroup(ch->fs, ch->uid, d->gid, 1) ||
724 (ch->fs->flags & FSNOPERM) != 0 ||
725 (ch->flags & CHFNOPERM) != 0;
726 if(di->length != ~0){
727 if(isdir && di->length != 0)
729 if((ch->flags & CHFNOPERM) == 0)
730 if(di->length != d->size && !permcheck(ch->fs, d, ch->uid, OWRITE))
733 if(di->mtime != ~0 && !owner)
735 if(di->mode != ~0 && !owner)
739 if(*di->uid != 0 && name2uid(ch->fs, di->uid, &nuid) < 0)
741 if(*di->gid != 0 && name2uid(ch->fs, di->gid, &ngid) < 0)
743 if(nuid != d->uid && (ch->fs->flags & FSCHOWN) == 0)
745 if((nuid != d->uid || ngid != d->gid) && !owner)
749 if(di->length != ~0 && di->length != d->size && !isdir){
750 trunc(ch->fs, ch->loc, b, di->length);
754 d->mtime = di->mtime;
756 d->mode = d->mode & ~0777 | di->mode & 0777;
757 ch->loc->type = d->type = di->mode >> 24;
760 memset(d->name, 0, NAMELEN);
761 strcpy(d->name, di->name);
786 ch->open |= CHRCLOSE;
787 return chanclunk(ch);