/* * Rewrite the results of a directory read to reflect current * name space bindings and mounts. Specifically, replace * directory entries for bind and mount points with the results * of statting what is mounted there. Except leave the old names. */ static int32_t mountfix(Chan *c, uint8_t *op, int32_t n, int32_t maxn) { Proc *up = externup(); char *name; int nbuf; Chan *nc; Mhead *mh; Mount *mount; usize dirlen, nname, r, rest; int32_t l; uint8_t *buf, *e, *p; Dir d; p = op; buf = nil; nbuf = 0; for(e=&p[n]; p+BIT16SZ<e; p+=dirlen){ dirlen = dirfixed(p, e, &d); if(dirlen == 0) break; nc = nil; mh = nil; if(findmount(&nc, &mh, d.type, d.dev, d.qid)){ /* * If it's a union directory and the original is * in the union, don't rewrite anything. */ for(mount=mh->mount; mount; mount=mount->next) if(eqchanddq(mount->to, d.type, d.dev, d.qid, 1)) goto Norewrite; name = dirname(p, &nname); /* * Do the stat but fix the name. If it fails, * leave old entry. * BUG: If it fails because there isn't room for * the entry, what can we do? Nothing, really. * Might as well skip it. */ if(buf == nil){ buf = smalloc(4096); nbuf = 4096; } if(waserror()) goto Norewrite; l = nc->dev->stat(nc, buf, nbuf); r = dirsetname(name, nname, buf, l, nbuf); if(r == BIT16SZ) error("dirsetname"); poperror(); /* * Shift data in buffer to accomodate new entry, * possibly overflowing into rock. */ rest = e - (p+dirlen); if(r > dirlen){ while(p+r+rest > op+maxn){ mountrock(c, p, &e); if(e == p){ dirlen = 0; goto Norewrite; } rest = e - (p+dirlen); } } if(r != dirlen){ memmove(p+r, p+dirlen, rest); dirlen = r; e = p+dirlen+rest; } /* * Rewrite directory entry. */ memmove(p, buf, r); Norewrite: cclose(nc); putmhead(mh); } } if(buf) free(buf); if(p != e) error("oops in mountfix"); return e-op; }
/* * Rewrite the results of a directory read to reflect current * name space bindings and mounts. Specifically, replace * directory entries for bind and mount points with the results * of statting what is mounted there. Except leave the old names. */ static long mountfix(Chan *c, uchar *op, long n, long maxn) { char *name; int nbuf, nname; Chan *nc; Mhead *mh; Mount *m; uchar *p; int dirlen, rest; long l; uchar *buf, *e; Dir d; p = op; buf = nil; nbuf = 0; for(e=&p[n]; p+BIT16SZ<e; p+=dirlen){ dirlen = dirfixed(p, e, &d); if(dirlen < 0) break; nc = nil; mh = nil; if(findmount(&nc, &mh, d.type, d.dev, d.qid)){ /* * If it's a union directory and the original is * in the union, don't rewrite anything. */ for(m=mh->mount; m; m=m->next) if(eqchantdqid(m->to, d.type, d.dev, d.qid, 1)) goto Norewrite; name = dirname(p, &nname); /* * Do the stat but fix the name. If it fails, leave old entry. * BUG: If it fails because there isn't room for the entry, * what can we do? Nothing, really. Might as well skip it. */ if(buf == nil){ buf = smalloc(4096); nbuf = 4096; } if(waserror()) goto Norewrite; l = devtab[nc->type]->stat(nc, buf, nbuf); l = dirsetname(name, nname, buf, l, nbuf); if(l == BIT16SZ) error("dirsetname"); poperror(); /* * Shift data in buffer to accomodate new entry, * possibly overflowing into rock. */ rest = e - (p+dirlen); if(l > dirlen){ while(p+l+rest > op+maxn){ mountrock(c, p, &e); if(e == p){ dirlen = 0; goto Norewrite; } rest = e - (p+dirlen); } } if(l != dirlen){ memmove(p+l, p+dirlen, rest); dirlen = l; e = p+dirlen+rest; } /* * Rewrite directory entry. */ memmove(p, buf, l); Norewrite: cclose(nc); putmhead(mh); } } if(buf) free(buf); if(p != e) error("oops in rockfix"); return e-op; }