]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/hjfs/fs2.c
fix ref822 again: remove uniqarray(), fix case with many entries in 'n'.
[plan9front.git] / sys / src / cmd / hjfs / fs2.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <fcall.h>
5 #include "dat.h"
6 #include "fns.h"
7
8 Chan *
9 chanattach(Fs *fs, int flags)
10 {       
11         Chan *ch;
12
13         ch = emalloc(sizeof(*ch));
14         ch->fs = fs;
15         ch->flags = flags;
16         ch->loc = cloneloc(fs, (flags & CHFDUMP) != 0 ? fs->dumprootloc : fs->rootloc);
17         return ch;
18 }
19
20 Chan *
21 chanclone(Chan *ch)
22 {
23         Chan *d;
24
25         chbegin(ch);
26         d = emalloc(sizeof(*d));
27         d->fs = ch->fs;
28         d->flags = ch->flags;
29         d->uid = ch->uid;
30         d->loc = cloneloc(ch->fs, ch->loc);
31         chend(ch);
32         return d;
33 }
34
35 int
36 chanwalk(Chan *ch, char *name)
37 {
38         Buf *b;
39         Dentry *d;
40         Loc *l;
41         FLoc f;
42         
43         if(name == nil || name[0] == 0 || name[0] == '.' && name[1] == 0)
44                 return 1;
45         chbegin(ch);
46         if(ch->open != 0){
47                 werrstr(Einval);
48                 chend(ch);
49                 return -1;
50         }
51         b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
52         if(b == nil){
53                 chend(ch);
54                 return -1;
55         }
56         d = getdent(ch->loc, b);
57         if(d == nil)
58                 goto error;
59         if((d->type & QTDIR) == 0){
60                 werrstr(Enotadir);
61                 goto error;
62         }
63         if(!permcheck(ch->fs, d, ch->uid, OEXEC)){
64                 werrstr(Eperm);
65                 goto error;
66         }
67         if(strcmp(name, "..") == 0){
68                 l = ch->loc->next;
69                 if(l == nil)
70                         goto done;
71                 putloc(ch->fs, ch->loc, 0);
72                 ch->loc = l;
73                 goto done;
74         }
75         if(findentry(ch->fs, ch->loc, b, name, &f, ch->flags & CHFDUMP) <= 0)
76                 goto error;
77         ch->loc = getloc(ch->fs, f, ch->loc);
78 done:
79         putbuf(b);
80         chend(ch);
81         return 1;
82 error:
83         putbuf(b);
84         chend(ch);
85         return -1;
86 }
87
88 int
89 namevalid(char *name)
90 {
91         char *p;
92         
93         if(name == nil || name[0] == 0)
94                 return 0;
95         if(name[0] == '.' && (name[1] == 0 || name[1] == '.' && name[2] == 0))
96                 return 0;
97         for(p = name; *p; p++)
98                 if((uchar) *p < ' ' || *p == '/')
99                         return 0;
100         return p - name < NAMELEN;
101 }
102
103 int
104 chancreat(Chan *ch, char *name, int perm, int mode)
105 {
106         Buf *b;
107         Dentry *d;
108         int isdir;
109         Loc *l;
110         FLoc f;
111         short pgid;
112
113         b = nil;
114         l = nil;
115         chbegin(ch);
116         if(!namevalid(name) || ch->open != 0)
117                 goto inval;
118         if((ch->flags & CHFRO) != 0)
119                 goto inval;
120         if(willmodify(ch->fs, ch->loc, ch->flags & CHFNOLOCK) < 0)
121                 goto error;
122         if(isdir = ((perm & DMDIR) != 0))
123                 if((mode & (OWRITE | OEXEC | ORCLOSE | OTRUNC)) != 0)
124                         goto inval;
125         b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
126         if(b == nil)
127                 goto error;
128         d = getdent(ch->loc, b);
129         if(d == nil)
130                 goto error;
131         if((d->type & QTDIR) == 0){
132                 werrstr(Enotadir);
133                 goto error;
134         }
135         if((ch->flags & CHFNOPERM) == 0){
136                 if(!permcheck(ch->fs, d, ch->uid, OWRITE)){
137                         werrstr(Eperm);
138                         goto error;
139                 }
140                 if(isdir)
141                         perm &= ~0777 | d->mode & 0777;
142                 else
143                         perm &= ~0666 | d->mode & 0666;
144         }
145         if(newentry(ch->fs, ch->loc, b, name, &f, 0) <= 0)
146                 goto error;
147
148         f.type = perm >> 24;
149         if(newqid(ch->fs, &f.path) < 0)
150                 goto error;
151         l = getloc(ch->fs, f, ch->loc);
152         modified(ch, d);
153         b->op |= BDELWRI;
154         pgid = d->gid;
155         putbuf(b);
156         b = nil;
157         if(willmodify(ch->fs, l, ch->flags & CHFNOLOCK) < 0)
158                 goto error;
159         b = getbuf(ch->fs->d, l->blk, TDENTRY, 0);
160         if(b == nil)
161                 goto error;
162         ch->loc = l;
163         d = &b->de[l->deind];
164         memset(d, 0, sizeof(*d));
165         d->Qid = l->Qid;
166         strcpy(d->name, name);
167         d->mtime = time(0);
168         d->atime = d->mtime;
169         d->gid = pgid;
170         d->uid = d->muid = ch->uid;
171         d->mode = DALLOC | perm & 0777;
172         if((d->type & QTEXCL) != 0){
173                 qlock(&ch->loc->ex);
174                 ch->loc->exlock = ch;
175                 ch->loc->lwrite = d->atime;
176                 qunlock(&ch->loc->ex);
177         }
178         b->op |= BDELWRI;
179         putbuf(b);
180         switch(mode & OEXEC){
181         case ORDWR:
182                 ch->open |= CHREAD;
183         case OWRITE:
184                 ch->open |= CHWRITE;
185                 break;
186         case OEXEC:
187         case OREAD:
188                 ch->open |= CHREAD;
189                 break;
190         }
191         if((mode & ORCLOSE) != 0)
192                 ch->open |= CHRCLOSE;
193         chend(ch);
194         return 1;
195 inval:
196         werrstr(Einval);
197 error:
198         if(l != nil)
199                 putloc(ch->fs, l, 0);
200         if(b != nil)
201                 putbuf(b);
202         chend(ch);
203         return -1;
204 }
205
206 int
207 chanopen(Chan *ch, int mode)
208 {
209         Buf *b;
210         Dentry *d;
211
212         b = nil;
213         chbegin(ch);
214         if(ch->open != 0)
215                 goto inval;
216         if((ch->flags & CHFRO) != 0 && (mode & (ORCLOSE | OTRUNC | OWRITE | ORDWR)) != 0)
217                 goto inval;
218         if((mode & OTRUNC) != 0)
219                 if(willmodify(ch->fs, ch->loc, ch->flags & CHFNOLOCK) < 0)
220                         goto error;
221         if((mode & ORCLOSE) != 0){
222                 if(ch->loc->next == nil)
223                         goto inval;
224                 b = getbuf(ch->fs->d, ch->loc->next->blk, TDENTRY, 0);
225                 if(b == nil)
226                         goto error;
227                 d = getdent(ch->loc->next, b);
228                 if(d == nil)
229                         goto error;
230                 if((ch->flags & CHFNOPERM) == 0)
231                         if(!permcheck(ch->fs, d, ch->uid, OWRITE))
232                                 goto perm;
233                 putbuf(b);
234         }
235         b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
236         if(b == nil)
237                 goto error;
238         d = getdent(ch->loc, b);
239         if(d == nil)
240                 goto error;
241         if((d->type & QTAPPEND) != 0)
242                 mode &= ~OTRUNC;
243         if((d->type & QTDIR) != 0 && (mode & (ORCLOSE | OTRUNC | OWRITE | ORDWR)) != 0)
244                 goto inval;
245         if((ch->flags & CHFNOPERM) == 0){
246                 if(!permcheck(ch->fs, d, ch->uid, mode & OEXEC))
247                         goto perm;
248                 if((mode & OTRUNC) != 0 && !permcheck(ch->fs, d, ch->uid, OWRITE))
249                         goto perm;
250         }
251         if((ch->loc->type & QTEXCL) != 0){
252                 qlock(&ch->loc->ex);
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);
257                 }else{
258                         qunlock(&ch->loc->ex);
259                         werrstr(Elocked);
260                         goto error;
261                 }
262         }
263         switch(mode & OEXEC){
264         case ORDWR:
265                 ch->open |= CHREAD;
266         case OWRITE:
267                 ch->open |= CHWRITE;
268                 break;
269         case OEXEC:
270         case OREAD:
271                 ch->open |= CHREAD;
272                 break;
273         }
274         if((mode & OTRUNC) != 0){
275                 trunc(ch->fs, ch->loc, b, 0);
276                 modified(ch, d);
277                 b->op |= BDELWRI;
278         }
279         if((mode & ORCLOSE) != 0)
280                 ch->open |= CHRCLOSE;
281         putbuf(b);
282         chend(ch);
283         return 1;
284 inval:
285         werrstr(Einval);
286         goto error;
287 perm:
288         werrstr(Eperm);
289 error:
290         if(b != nil)
291                 putbuf(b);
292         chend(ch);
293         return -1;
294 }
295
296 static int
297 checklock(Chan *ch)
298 {
299         int rc;
300
301         qlock(&ch->loc->ex);
302         rc = 1;
303         if(ch->loc->exlock == ch){
304                 if(ch->loc->lwrite < time(0) - EXCLDUR){
305                         ch->loc->exlock = nil;
306                         werrstr("lock broken");
307                         rc = -1;
308                 }else
309                         ch->loc->lwrite = time(0);
310         }else{
311                 werrstr(Elocked);
312                 rc = -1;
313         }
314         qunlock(&ch->loc->ex);
315         return rc;
316 }
317
318 int
319 chanwrite(Chan *ch, void *buf, ulong n, uvlong off)
320 {
321         uvlong i, e, bl;
322         int r, rn, rc;
323         Buf *b, *c;
324         Dentry *d;
325         uchar *p;
326
327         if(n == 0)
328                 return 0;
329         if((ch->flags & CHFRO) != 0){
330                 werrstr(Einval);
331                 return -1;
332         }
333         if((ch->open & CHWRITE) == 0){
334                 werrstr(Einval);
335                 return -1;
336         }
337         chbegin(ch);
338         if((ch->loc->type & QTEXCL) != 0 && checklock(ch) < 0){
339                 chend(ch);
340                 return -1;
341         }
342         if(willmodify(ch->fs, ch->loc, ch->flags & CHFNOLOCK) < 0){
343                 chend(ch);
344                 return -1;
345         }
346         b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
347         if(b == nil){
348                 chend(ch);
349                 return -1;
350         }
351         d = getdent(ch->loc, b);
352         if(d == nil){
353                 putbuf(b);
354                 chend(ch);
355                 return -1;
356         }
357         if((d->type & QTAPPEND) != 0)
358                 off = d->size;
359         e = off + n;
360         i = off;
361         p = buf;
362         while(i < e){
363                 bl = i / RBLOCK;
364                 r = i % RBLOCK;
365                 rn = RBLOCK - r;
366                 if(i + rn > e)
367                         rn = e - i;
368                 rc = getblk(ch->fs, ch->loc, b, bl, &bl, rn == RBLOCK ? GBOVERWR : GBCREATE);
369                 if(rc < 0)
370                         goto done;
371                 c = getbuf(ch->fs->d, bl, TRAW, rc == 0 || rn == RBLOCK);
372                 if(c == nil)
373                         goto done;
374                 if(rc == 0 && rn != RBLOCK)
375                         memset(c->data, 0, sizeof(c->data));
376                 memcpy(c->data + r, p, rn);
377                 i += rn;
378                 c->op |= i != e ? BWRIM : BDELWRI;
379                 putbuf(c);
380                 p += rn;
381         }
382 done:
383         modified(ch, d);
384         e = off + (p - (uchar *) buf);
385         if(e > d->size)
386                 d->size = e;
387         b->op |= BDELWRI;
388         putbuf(b);
389         chend(ch);
390         if(p == buf)
391                 return -1;
392         return p - (uchar *) buf;
393 }
394
395 static int chandirread(Chan *, void *, ulong, uvlong);
396
397 int
398 chanread(Chan *ch, void *buf, ulong n, uvlong off)
399 {
400         uvlong i, e, bl;
401         int r, rn, rc;
402         uchar *p;
403         Buf *b, *c;
404         Dentry *d;
405
406         if((ch->open & CHREAD) == 0){
407                 werrstr(Einval);
408                 return -1;
409         }
410         chbegin(ch);
411         if((ch->loc->type & QTEXCL) != 0 && checklock(ch) < 0){
412                 chend(ch);
413                 return -1;
414         }
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);
418         if(b == nil){
419                 chend(ch);
420                 return -1;
421         }
422         d = getdent(ch->loc, b);
423         if(d == nil)
424                 goto error;
425         if(off >= d->size)
426                 n = 0;
427         else if(off + n > d->size)
428                 n = d->size - off;
429         if(n == 0){
430                 putbuf(b);
431                 chend(ch);
432                 return 0;
433         }
434         e = off + n;
435         i = off;
436         p = buf;
437         while(i < e){
438                 bl = i / RBLOCK;
439                 r = i % RBLOCK;
440                 rn = RBLOCK - r;
441                 if(i + rn > e)
442                         rn = e - i;
443                 rc = getblk(ch->fs, ch->loc, b, bl, &bl, GBREAD);
444                 if(rc < 0)
445                         goto error;
446                 if(rc == 0)
447                         memset(p, 0, rn);
448                 else{
449                         c = getbuf(ch->fs->d, bl, TRAW, 0);
450                         if(c == nil)
451                                 goto error;
452                         memcpy(p, c->data + r, rn);
453                         putbuf(c);
454                 }
455                 i += rn;
456                 p += rn;
457         }
458         putbuf(b);
459         chend(ch);
460         return n;
461 error:
462         putbuf(b);
463         chend(ch);
464         return -1;
465 }
466
467 static void
468 statbuf(Fs *fs, Dentry *d, Dir *di, char *buf)
469 {
470         di->qid = d->Qid;
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;
475         if(d->type & QTDIR)
476                 di->length = 0;
477         if(buf == nil){
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);
482         }else{
483                 memset(buf, 0, NAMELEN + 3 * USERLEN);
484                 strncpy(buf, d->name, NAMELEN - 1);
485                 di->name = buf;
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);
489         }
490 }
491
492 int
493 chanstat(Chan *ch, Dir *di)
494 {
495         Buf *b;
496         Dentry *d;
497         
498         chbegin(ch);
499         b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
500         if(b == nil){
501                 chend(ch);
502                 return -1;
503         }
504         d = getdent(ch->loc, b);
505         if(d == nil){
506                 putbuf(b);
507                 chend(ch);
508                 return -1;
509         }
510         statbuf(ch->fs, d, di, nil);
511         putbuf(b);
512         chend(ch);
513         return 0;
514 }
515
516 static int
517 chandirread(Chan *ch, void *buf, ulong n, uvlong off)
518 {
519         Buf *b, *c;
520         Dentry *d;
521         uvlong i, blk;
522         int j;
523         int rc;
524         ulong wr;
525         Dir di;
526         char cbuf[NAMELEN + 3 * USERLEN];
527
528         if(off == 0){
529                 ch->dwloff = 0;
530                 ch->dwblk = 0;
531                 ch->dwind = 0;
532         }else if(ch->dwloff != off){
533                 werrstr(Einval);
534                 chend(ch);
535                 return -1;
536         }
537         b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
538         if(b == nil){
539                 chend(ch);
540                 return -1;
541         }
542         d = getdent(ch->loc, b);
543         if(d == nil){
544                 putbuf(b);
545                 chend(ch);
546                 return -1;
547         }
548         if(ch->dwblk >= d->size){
549                 putbuf(b);
550                 chend(ch);
551                 return 0;
552         }
553         c = nil;
554         wr = 0;
555         i = ch->dwblk;
556         j = ch->dwind;
557         for(;;){
558                 if(c == nil){
559                         rc = getblk(ch->fs, ch->loc, b, i, &blk, GBREAD);
560                         if(rc < 0)
561                                 goto error;
562                         if(rc == 0){
563                                 j = 0;
564                                 if(++i >= d->size)
565                                         break;
566                                 continue;
567                         }
568                         c = getbuf(ch->fs->d, blk, TDENTRY, 0);
569                         if(c == nil)
570                                 goto error;
571                 }
572                 if((c->de[j].mode & DALLOC) == 0)
573                         goto next;
574                 if((ch->flags & CHFDUMP) != 0 && (c->de[j].type & QTTMP) != 0)
575                         goto next;
576                 statbuf(ch->fs, &c->de[j], &di, cbuf);
577                 rc = convD2M(&di, (uchar *) buf + wr, n - wr);
578                 if(rc <= BIT16SZ)
579                         break;
580                 wr += rc;
581         next:
582                 if(++j >= DEPERBLK){
583                         j = 0;
584                         if(c != nil)
585                                 putbuf(c);
586                         c = nil;
587                         if(++i >= d->size)
588                                 break;
589                 }
590         }
591         ch->dwblk = i;
592         ch->dwind = j;
593         ch->dwloff += wr;
594         if(c != nil)
595                 putbuf(c);
596         putbuf(b);
597         chend(ch);
598         return wr;
599 error:
600         putbuf(b);
601         chend(ch);
602         return -1;
603 }
604
605 int
606 chanclunk(Chan *ch)
607 {
608         Buf *b, *p;
609         int rc;
610         Dentry *d;
611
612         rc = 1;
613         b = p = nil;
614         chbegin(ch);
615         if(ch->open & CHRCLOSE){
616                 if((ch->flags & CHFRO) != 0)
617                         goto inval;
618                 if(willmodify(ch->fs, ch->loc, ch->flags & CHFNOLOCK) < 0)
619                         goto error;
620                 if(ch->loc->next == nil)
621                         goto inval;
622                 p = getbuf(ch->fs->d, ch->loc->next->blk, TDENTRY, 0);
623                 if(p == nil)
624                         goto error;
625                 b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
626                 if(b == nil)
627                         goto error;
628                 d = getdent(ch->loc->next, p);
629                 if(d == nil)
630                         goto error;
631                 if((ch->flags & CHFNOPERM) == 0)
632                         if(!permcheck(ch->fs, d, ch->uid, OWRITE)){
633                                 werrstr(Eperm);
634                                 goto error;
635                         }
636                 d = getdent(ch->loc, b);
637                 if(d == nil)
638                         goto error;
639                 if((d->type & QTDIR) != 0 && findentry(ch->fs, ch->loc, b, nil, nil, ch->flags & CHFDUMP) != 0)
640                         goto inval;
641                 if((d->mode & DGONE) != 0)
642                         goto done;
643                 qlock(&ch->fs->loctree);
644                 if(ch->loc->ref > 1){
645                         d->mode &= ~DALLOC;
646                         d->mode |= DGONE; /* aaaaand it's gone */
647                         ch->loc->flags |= LGONE;
648                         qunlock(&ch->fs->loctree);
649                 }else{
650                         ch->loc->flags &= ~LGONE;
651                         qunlock(&ch->fs->loctree);
652                         rc = delete(ch->fs, ch->loc, b);
653                 }
654                 b->op |= BDELWRI;
655         }
656 done:
657         if(b != nil)
658                 putbuf(b);
659         if(p != nil)
660                 putbuf(p);
661         if((ch->loc->type & QTEXCL) != 0){
662                 qlock(&ch->loc->ex);
663                 if(ch->loc->exlock == ch)
664                         ch->loc->exlock = nil;
665                 qunlock(&ch->loc->ex);
666         }
667         putloc(ch->fs, ch->loc, 1);
668         chend(ch);
669         free(ch);
670         return rc;
671 inval:
672         werrstr(Einval);
673 error:
674         rc = -1;
675         goto done;
676 }
677
678 int
679 chanwstat(Chan *ch, Dir *di)
680 {
681         Buf *b, *pb;
682         Dentry *d;
683         int isdir, owner, rc;
684         short nuid, ngid;
685
686         b = pb = nil;
687         chbegin(ch);
688         if((ch->flags & CHFRO) != 0)
689                 goto inval;
690         if(willmodify(ch->fs, ch->loc, ch->flags & CHFNOLOCK) < 0)
691                 goto error;
692         if(*di->name){
693                 FLoc f;
694
695                 if(!namevalid(di->name) || ch->loc->next == nil)
696                         goto inval;
697                 pb = getbuf(ch->fs->d, ch->loc->next->blk, TDENTRY, 0);
698                 if(pb == nil)
699                         goto error;
700                 d = getdent(ch->loc->next, pb);
701                 if(d == nil)
702                         goto error;
703                 rc = findentry(ch->fs, ch->loc->next, pb, di->name, &f, ch->flags & CHFDUMP);
704                 if(rc < 0)
705                         goto error;
706                 else if(rc == 0){
707                         if((ch->flags & CHFNOPERM) == 0)
708                                 if(!permcheck(ch->fs, d, ch->uid, OWRITE))
709                                         goto perm;
710                 } else if(f.blk != ch->loc->blk || f.deind != ch->loc->deind){
711                         werrstr(Eexists);
712                         goto error;
713                 }
714         }
715         b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0);
716         if(b == nil)
717                 goto error;
718         d = getdent(ch->loc, b);
719         if(d == nil)
720                 goto error;
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)
728                         goto inval;
729                 if((ch->flags & CHFNOPERM) == 0)
730                         if(di->length != d->size && !permcheck(ch->fs, d, ch->uid, OWRITE))
731                                 goto perm;
732         }
733         if(di->mtime != ~0 && !owner)
734                 goto perm;
735         if(di->mode != ~0 && !owner)
736                 goto perm;
737         nuid = d->uid;
738         ngid = d->gid;
739         if(*di->uid != 0 && name2uid(ch->fs, di->uid, &nuid) < 0)
740                 goto inval;
741         if(*di->gid != 0 && name2uid(ch->fs, di->gid, &ngid) < 0)
742                 goto inval;
743         if(nuid != d->uid && (ch->fs->flags & FSCHOWN) == 0)
744                 goto perm;
745         if((nuid != d->uid || ngid != d->gid) && !owner)
746                 goto perm;
747         d->uid = nuid;
748         d->gid = ngid;
749         if(di->length != ~0 && di->length != d->size && !isdir){
750                 trunc(ch->fs, ch->loc, b, di->length);
751                 modified(ch, d);
752         }
753         if(di->mtime != ~0)
754                 d->mtime = di->mtime;
755         if(di->mode != ~0){
756                 d->mode = d->mode & ~0777 | di->mode & 0777;
757                 ch->loc->type = d->type = di->mode >> 24;
758         }
759         if(*di->name){
760                 memset(d->name, 0, NAMELEN);
761                 strcpy(d->name, di->name);
762         }
763         b->op |= BDELWRI;
764         if(pb != nil)
765                 putbuf(pb);
766         putbuf(b);
767         chend(ch);
768         return 1;
769 inval:
770         werrstr(Einval);
771         goto error;
772 perm:
773         werrstr(Eperm);
774 error:
775         if(pb != nil)
776                 putbuf(pb);
777         if(b != nil)
778                 putbuf(b);
779         chend(ch);
780         return -1;
781 }
782
783 int
784 chanremove(Chan *ch)
785 {
786         ch->open |= CHRCLOSE;
787         return chanclunk(ch);
788 }