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;
105 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)){
140 if(newentry(ch->fs, ch->loc, b, name, &f, 0) <= 0)
143 perm &= ~0777 | d->mode & 0777;
145 perm &= ~0666 | d->mode & 0666;
147 if(newqid(ch->fs, &f.path) < 0)
149 l = getloc(ch->fs, f, ch->loc);
154 if(willmodify(ch->fs, l, ch->flags & CHFNOLOCK) < 0)
156 b = getbuf(ch->fs->d, l->blk, TDENTRY, 0);
160 d = &b->de[l->deind];
161 memset(d, 0, sizeof(*d));
163 strcpy(d->name, name);
166 d->gid = d->uid = d->muid = ch->uid;
167 d->mode = DALLOC | perm & 0777;
168 if((d->type & QTEXCL) != 0){
170 ch->loc->exlock = ch;
171 ch->loc->lwrite = d->atime;
172 qunlock(&ch->loc->ex);
176 switch(mode & OEXEC){
193 putloc(ch->fs, l, 0);
201 chanopen(Chan *ch, int mode)
210 if((ch->flags & CHFRO) != 0 && (mode & (ORCLOSE | OTRUNC | OWRITE | ORDWR)) != 0)
212 if((mode & OTRUNC) != 0)
213 if(willmodify(ch->fs, ch->loc, ch->flags & CHFNOLOCK) < 0)
215 if((mode & ORCLOSE) != 0){
216 if(ch->loc->next == nil)
218 b = getbuf(ch->fs->d, ch->loc->next->blk, TDENTRY, 0);
221 d = getdent(ch->loc->next, b);
224 if((ch->flags & CHFNOPERM) == 0)
225 if(!permcheck(ch->fs, d, ch->uid, OWRITE))
229 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
232 d = getdent(ch->loc, b);
235 if((d->type & QTAPPEND) != 0)
237 if((d->type & QTDIR) != 0 && (mode & (ORCLOSE | OTRUNC | OWRITE | ORDWR)) != 0)
239 if((ch->flags & CHFNOPERM) == 0){
240 if(!permcheck(ch->fs, d, ch->uid, mode & OEXEC))
242 if((mode & OTRUNC) != 0 && !permcheck(ch->fs, d, ch->uid, OWRITE))
245 if((ch->loc->type & QTEXCL) != 0){
247 if(ch->loc->exlock == nil || ch->loc->lwrite < time(0) - EXCLDUR){
248 ch->loc->exlock = ch;
249 ch->loc->lwrite = time(0);
250 qunlock(&ch->loc->ex);
252 qunlock(&ch->loc->ex);
257 switch(mode & OEXEC){
268 if((mode & OTRUNC) != 0){
269 trunc(ch->fs, ch->loc, b, 0);
273 if((mode & ORCLOSE) != 0)
274 ch->open |= CHRCLOSE;
297 if(ch->loc->exlock == ch){
298 if(ch->loc->lwrite < time(0) - EXCLDUR){
299 ch->loc->exlock = nil;
300 werrstr("lock broken");
303 ch->loc->lwrite = time(0);
308 qunlock(&ch->loc->ex);
313 chanwrite(Chan *ch, void *buf, ulong n, uvlong off)
323 if((ch->flags & CHFRO) != 0){
327 if((ch->open & CHWRITE) == 0){
332 if((ch->loc->type & QTEXCL) != 0 && checklock(ch) < 0){
336 if(willmodify(ch->fs, ch->loc, ch->flags & CHFNOLOCK) < 0){
340 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
345 d = getdent(ch->loc, b);
351 if((d->type & QTAPPEND) != 0)
362 rc = getblk(ch->fs, ch->loc, b, bl, &bl, rn == RBLOCK ? GBOVERWR : GBCREATE);
365 c = getbuf(ch->fs->d, bl, TRAW, rc == 0 || rn == RBLOCK);
368 if(rc == 0 && rn != RBLOCK)
369 memset(c->data, 0, sizeof(c->data));
370 memcpy(c->data + r, p, rn);
372 c->op |= i != e ? BWRIM : BDELWRI;
378 e = off + (p - (uchar *) buf);
386 return p - (uchar *) buf;
389 static int chandirread(Chan *, void *, ulong, uvlong);
392 chanread(Chan *ch, void *buf, ulong n, uvlong off)
400 if((ch->open & CHREAD) == 0){
405 if((ch->loc->type & QTEXCL) != 0 && checklock(ch) < 0){
409 if((ch->loc->Qid.type & QTDIR) != 0)
410 return chandirread(ch, buf, n, off);
411 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
416 d = getdent(ch->loc, b);
421 else if(off + n > d->size)
437 rc = getblk(ch->fs, ch->loc, b, bl, &bl, GBREAD);
443 c = getbuf(ch->fs->d, bl, TRAW, 0);
446 memcpy(p, c->data + r, rn);
462 statbuf(Fs *fs, Dentry *d, Dir *di, char *buf)
465 di->mode = (d->mode & 0777) | (d->Qid.type << 24);
466 di->mtime = d->mtime;
467 di->atime = d->atime;
468 di->length = d->size;
472 di->name = estrdup(d->name);
473 di->uid = uid2name(fs, d->uid, nil);
474 di->gid = uid2name(fs, d->gid, nil);
475 di->muid = uid2name(fs, d->muid, nil);
477 memset(buf, 0, NAMELEN + 3 * USERLEN);
478 strncpy(buf, d->name, NAMELEN - 1);
480 di->uid = uid2name(fs, d->uid, buf + NAMELEN);
481 di->gid = uid2name(fs, d->gid, buf + NAMELEN + USERLEN);
482 di->muid = uid2name(fs, d->muid, buf + NAMELEN + 2 * USERLEN);
487 chanstat(Chan *ch, Dir *di)
493 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
498 d = getdent(ch->loc, b);
504 statbuf(ch->fs, d, di, nil);
511 chandirread(Chan *ch, void *buf, ulong n, uvlong off)
520 char cbuf[NAMELEN + 3 * USERLEN];
526 }else if(ch->dwloff != off){
531 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
536 d = getdent(ch->loc, b);
542 if(ch->dwblk >= d->size){
553 rc = getblk(ch->fs, ch->loc, b, i, &blk, GBREAD);
562 c = getbuf(ch->fs->d, blk, TDENTRY, 0);
566 if((c->de[j].mode & DALLOC) == 0)
568 if((ch->flags & CHFDUMP) != 0 && (c->de[j].type & QTTMP) != 0)
570 statbuf(ch->fs, &c->de[j], &di, cbuf);
571 rc = convD2M(&di, (uchar *) buf + wr, n - wr);
609 if(ch->open & CHRCLOSE){
610 if((ch->flags & CHFRO) != 0)
612 if(willmodify(ch->fs, ch->loc, ch->flags & CHFNOLOCK) < 0)
614 if(ch->loc->next == nil)
616 p = getbuf(ch->fs->d, ch->loc->next->blk, TDENTRY, 0);
619 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
622 d = getdent(ch->loc->next, p);
625 if((ch->flags & CHFNOPERM) == 0)
626 if(!permcheck(ch->fs, d, ch->uid, OWRITE)){
630 d = getdent(ch->loc, b);
633 if((d->type & QTDIR) != 0 && findentry(ch->fs, ch->loc, b, nil, nil, ch->flags & CHFDUMP) != 0)
635 if((d->mode & DGONE) != 0)
637 qlock(&ch->fs->loctree);
638 if(ch->loc->ref > 1){
640 d->mode |= DGONE; /* aaaaand it's gone */
641 ch->loc->flags |= LGONE;
642 qunlock(&ch->fs->loctree);
644 ch->loc->flags &= ~LGONE;
645 qunlock(&ch->fs->loctree);
646 rc = delete(ch->fs, ch->loc, b);
655 if((ch->loc->type & QTEXCL) != 0){
657 if(ch->loc->exlock == ch)
658 ch->loc->exlock = nil;
659 qunlock(&ch->loc->ex);
661 putloc(ch->fs, ch->loc, 1);
673 chanwstat(Chan *ch, Dir *di)
677 int isdir, owner, rc;
682 if((ch->flags & CHFRO) != 0)
684 if(willmodify(ch->fs, ch->loc, ch->flags & CHFNOLOCK) < 0)
687 if(!namevalid(di->name) || ch->loc->next == nil)
689 pb = getbuf(ch->fs->d, ch->loc->next->blk, TDENTRY, 0);
692 d = getdent(ch->loc->next, pb);
695 if((ch->flags & CHFNOPERM) == 0)
696 if(!permcheck(ch->fs, d, ch->uid, OWRITE))
698 rc = findentry(ch->fs, ch->loc->next, pb, di->name, nil, ch->flags & CHFDUMP);
704 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
707 d = getdent(ch->loc, b);
710 isdir = (d->type & QTDIR) != 0;
711 owner = ch->uid == d->uid ||
712 ingroup(ch->fs, ch->uid, d->gid, 1) ||
713 (ch->fs->flags & FSNOPERM) != 0 ||
714 (ch->flags & CHFNOPERM) != 0;
715 if((uvlong)~di->length){
716 if(isdir && di->length != 0)
718 if((ch->flags & CHFNOPERM) == 0)
719 if(di->length != d->size && !permcheck(ch->fs, d, ch->uid, OWRITE))
722 if((ulong)~di->atime)
724 if((ulong)~di->mtime && !owner)
726 if((ulong)~di->mode && !owner)
730 if(*di->uid != 0 && name2uid(ch->fs, di->uid, &nuid) < 0)
732 if(*di->gid != 0 && name2uid(ch->fs, di->gid, &ngid) < 0)
734 if(nuid != NOUID && (ch->fs->flags & FSCHOWN) == 0)
736 if((nuid != NOUID || ngid != NOUID) && !owner)
738 if((uvlong)~di->length && !isdir){
739 trunc(ch->fs, ch->loc, b, di->length);
742 if((ulong)~di->mtime)
743 d->mtime = di->mtime;
744 if((ulong)~di->mode){
745 d->mode = d->mode & ~0777 | di->mode & 0777;
746 ch->loc->type = d->type = di->mode >> 24;
749 memset(d->name, 0, NAMELEN);
750 strcpy(d->name, di->name);
779 ch->open |= CHRCLOSE;
780 return chanclunk(ch);