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)
115 if(!namevalid(name) || ch->open != 0)
117 if((ch->flags & CHFRO) != 0)
119 if(willmodify(ch->fs, ch->loc, ch->flags & CHFNOLOCK) < 0)
121 if(isdir = ((perm & DMDIR) != 0))
122 if((mode & (OWRITE | OEXEC | ORCLOSE | OTRUNC)) != 0)
124 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
127 d = getdent(ch->loc, b);
130 if((d->type & QTDIR) == 0){
134 if((ch->flags & CHFNOPERM) == 0){
135 if(!permcheck(ch->fs, d, ch->uid, OWRITE)){
140 perm &= ~0777 | d->mode & 0777;
142 perm &= ~0666 | d->mode & 0666;
144 if(newentry(ch->fs, ch->loc, b, name, &f, 0) <= 0)
148 if(newqid(ch->fs, &f.path) < 0)
150 l = getloc(ch->fs, f, ch->loc);
155 if(willmodify(ch->fs, l, ch->flags & CHFNOLOCK) < 0)
157 b = getbuf(ch->fs->d, l->blk, TDENTRY, 0);
161 d = &b->de[l->deind];
162 memset(d, 0, sizeof(*d));
164 strcpy(d->name, name);
167 d->gid = d->uid = d->muid = ch->uid;
168 d->mode = DALLOC | perm & 0777;
169 if((d->type & QTEXCL) != 0){
171 ch->loc->exlock = ch;
172 ch->loc->lwrite = d->atime;
173 qunlock(&ch->loc->ex);
177 switch(mode & OEXEC){
188 if((mode & ORCLOSE) != 0)
189 ch->open |= CHRCLOSE;
196 putloc(ch->fs, l, 0);
204 chanopen(Chan *ch, int mode)
213 if((ch->flags & CHFRO) != 0 && (mode & (ORCLOSE | OTRUNC | OWRITE | ORDWR)) != 0)
215 if((mode & OTRUNC) != 0)
216 if(willmodify(ch->fs, ch->loc, ch->flags & CHFNOLOCK) < 0)
218 if((mode & ORCLOSE) != 0){
219 if(ch->loc->next == nil)
221 b = getbuf(ch->fs->d, ch->loc->next->blk, TDENTRY, 0);
224 d = getdent(ch->loc->next, b);
227 if((ch->flags & CHFNOPERM) == 0)
228 if(!permcheck(ch->fs, d, ch->uid, OWRITE))
232 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
235 d = getdent(ch->loc, b);
238 if((d->type & QTAPPEND) != 0)
240 if((d->type & QTDIR) != 0 && (mode & (ORCLOSE | OTRUNC | OWRITE | ORDWR)) != 0)
242 if((ch->flags & CHFNOPERM) == 0){
243 if(!permcheck(ch->fs, d, ch->uid, mode & OEXEC))
245 if((mode & OTRUNC) != 0 && !permcheck(ch->fs, d, ch->uid, OWRITE))
248 if((ch->loc->type & QTEXCL) != 0){
250 if(ch->loc->exlock == nil || ch->loc->lwrite < time(0) - EXCLDUR){
251 ch->loc->exlock = ch;
252 ch->loc->lwrite = time(0);
253 qunlock(&ch->loc->ex);
255 qunlock(&ch->loc->ex);
260 switch(mode & OEXEC){
271 if((mode & OTRUNC) != 0){
272 trunc(ch->fs, ch->loc, b, 0);
276 if((mode & ORCLOSE) != 0)
277 ch->open |= CHRCLOSE;
300 if(ch->loc->exlock == ch){
301 if(ch->loc->lwrite < time(0) - EXCLDUR){
302 ch->loc->exlock = nil;
303 werrstr("lock broken");
306 ch->loc->lwrite = time(0);
311 qunlock(&ch->loc->ex);
316 chanwrite(Chan *ch, void *buf, ulong n, uvlong off)
326 if((ch->flags & CHFRO) != 0){
330 if((ch->open & CHWRITE) == 0){
335 if((ch->loc->type & QTEXCL) != 0 && checklock(ch) < 0){
339 if(willmodify(ch->fs, ch->loc, ch->flags & CHFNOLOCK) < 0){
343 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
348 d = getdent(ch->loc, b);
354 if((d->type & QTAPPEND) != 0)
365 rc = getblk(ch->fs, ch->loc, b, bl, &bl, rn == RBLOCK ? GBOVERWR : GBCREATE);
368 c = getbuf(ch->fs->d, bl, TRAW, rc == 0 || rn == RBLOCK);
371 if(rc == 0 && rn != RBLOCK)
372 memset(c->data, 0, sizeof(c->data));
373 memcpy(c->data + r, p, rn);
375 c->op |= i != e ? BWRIM : BDELWRI;
381 e = off + (p - (uchar *) buf);
389 return p - (uchar *) buf;
392 static int chandirread(Chan *, void *, ulong, uvlong);
395 chanread(Chan *ch, void *buf, ulong n, uvlong off)
403 if((ch->open & CHREAD) == 0){
408 if((ch->loc->type & QTEXCL) != 0 && checklock(ch) < 0){
412 if((ch->loc->Qid.type & QTDIR) != 0)
413 return chandirread(ch, buf, n, off);
414 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
419 d = getdent(ch->loc, b);
424 else if(off + n > d->size)
440 rc = getblk(ch->fs, ch->loc, b, bl, &bl, GBREAD);
446 c = getbuf(ch->fs->d, bl, TRAW, 0);
449 memcpy(p, c->data + r, rn);
465 statbuf(Fs *fs, Dentry *d, Dir *di, char *buf)
468 di->mode = (d->mode & 0777) | (d->Qid.type << 24);
469 di->mtime = d->mtime;
470 di->atime = d->atime;
471 di->length = d->size;
475 di->name = estrdup(d->name);
476 di->uid = uid2name(fs, d->uid, nil);
477 di->gid = uid2name(fs, d->gid, nil);
478 di->muid = uid2name(fs, d->muid, nil);
480 memset(buf, 0, NAMELEN + 3 * USERLEN);
481 strncpy(buf, d->name, NAMELEN - 1);
483 di->uid = uid2name(fs, d->uid, buf + NAMELEN);
484 di->gid = uid2name(fs, d->gid, buf + NAMELEN + USERLEN);
485 di->muid = uid2name(fs, d->muid, buf + NAMELEN + 2 * USERLEN);
490 chanstat(Chan *ch, Dir *di)
496 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
501 d = getdent(ch->loc, b);
507 statbuf(ch->fs, d, di, nil);
514 chandirread(Chan *ch, void *buf, ulong n, uvlong off)
523 char cbuf[NAMELEN + 3 * USERLEN];
529 }else if(ch->dwloff != off){
534 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
539 d = getdent(ch->loc, b);
545 if(ch->dwblk >= d->size){
556 rc = getblk(ch->fs, ch->loc, b, i, &blk, GBREAD);
565 c = getbuf(ch->fs->d, blk, TDENTRY, 0);
569 if((c->de[j].mode & DALLOC) == 0)
571 if((ch->flags & CHFDUMP) != 0 && (c->de[j].type & QTTMP) != 0)
573 statbuf(ch->fs, &c->de[j], &di, cbuf);
574 rc = convD2M(&di, (uchar *) buf + wr, n - wr);
612 if(ch->open & CHRCLOSE){
613 if((ch->flags & CHFRO) != 0)
615 if(willmodify(ch->fs, ch->loc, ch->flags & CHFNOLOCK) < 0)
617 if(ch->loc->next == nil)
619 p = getbuf(ch->fs->d, ch->loc->next->blk, TDENTRY, 0);
622 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
625 d = getdent(ch->loc->next, p);
628 if((ch->flags & CHFNOPERM) == 0)
629 if(!permcheck(ch->fs, d, ch->uid, OWRITE)){
633 d = getdent(ch->loc, b);
636 if((d->type & QTDIR) != 0 && findentry(ch->fs, ch->loc, b, nil, nil, ch->flags & CHFDUMP) != 0)
638 if((d->mode & DGONE) != 0)
640 qlock(&ch->fs->loctree);
641 if(ch->loc->ref > 1){
643 d->mode |= DGONE; /* aaaaand it's gone */
644 ch->loc->flags |= LGONE;
645 qunlock(&ch->fs->loctree);
647 ch->loc->flags &= ~LGONE;
648 qunlock(&ch->fs->loctree);
649 rc = delete(ch->fs, ch->loc, b);
658 if((ch->loc->type & QTEXCL) != 0){
660 if(ch->loc->exlock == ch)
661 ch->loc->exlock = nil;
662 qunlock(&ch->loc->ex);
664 putloc(ch->fs, ch->loc, 1);
676 chanwstat(Chan *ch, Dir *di)
680 int isdir, owner, rc;
685 if((ch->flags & CHFRO) != 0)
687 if(willmodify(ch->fs, ch->loc, ch->flags & CHFNOLOCK) < 0)
692 if(!namevalid(di->name) || ch->loc->next == nil)
694 pb = getbuf(ch->fs->d, ch->loc->next->blk, TDENTRY, 0);
697 d = getdent(ch->loc->next, pb);
700 rc = findentry(ch->fs, ch->loc->next, pb, di->name, &f, ch->flags & CHFDUMP);
704 if((ch->flags & CHFNOPERM) == 0)
705 if(!permcheck(ch->fs, d, ch->uid, OWRITE))
707 } else if(f.blk != ch->loc->blk || f.deind != ch->loc->deind){
712 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
715 d = getdent(ch->loc, b);
718 isdir = (d->type & QTDIR) != 0;
719 owner = ch->uid == d->uid ||
720 ingroup(ch->fs, ch->uid, d->gid, 1) ||
721 (ch->fs->flags & FSNOPERM) != 0 ||
722 (ch->flags & CHFNOPERM) != 0;
723 if(di->length != ~0){
724 if(isdir && di->length != 0)
726 if((ch->flags & CHFNOPERM) == 0)
727 if(di->length != d->size && !permcheck(ch->fs, d, ch->uid, OWRITE))
730 if(di->mtime != ~0 && !owner)
732 if(di->mode != ~0 && !owner)
736 if(*di->uid != 0 && name2uid(ch->fs, di->uid, &nuid) < 0)
738 if(*di->gid != 0 && name2uid(ch->fs, di->gid, &ngid) < 0)
740 if(nuid != d->uid && (ch->fs->flags & FSCHOWN) == 0)
742 if((nuid != d->uid || ngid != d->gid) && !owner)
746 if(di->length != ~0 && di->length != d->size && !isdir){
747 trunc(ch->fs, ch->loc, b, di->length);
751 d->mtime = di->mtime;
753 d->mode = d->mode & ~0777 | di->mode & 0777;
754 ch->loc->type = d->type = di->mode >> 24;
757 memset(d->name, 0, NAMELEN);
758 strcpy(d->name, di->name);
783 ch->open |= CHRCLOSE;
784 return chanclunk(ch);