ref: d3512f60df5d7a2ea5c4cad3cdef797f1f95a182
dir: /sys/src/cmd/ip/cifsd/dir.c/
#include <u.h> #include <libc.h> #include "dat.h" #include "fns.h" static char* append(char **p, char *s) { int n; char *o; if(s == nil) return nil; n = strlen(s)+1; memmove(o = *p, s, n); *p += n; return o; } static Dir* xdirdup(Dir *d, int n) { char *p; Dir *o; int i; p = nil; for(i=0; i<n; i++){ p += strlen(d[i].name)+1; if(d[i].uid) p += strlen(d[i].uid)+1; if(d[i].gid) p += strlen(d[i].gid)+1; if(d[i].muid) p += strlen(d[i].muid)+1; } o = malloc(n*sizeof(*d) + (uintptr)p); memmove(o, d, n*sizeof(*d)); p = (char*)&o[n]; for(i=0; i<n; i++){ o[i].name = append(&p, d[i].name); o[i].uid = append(&p, d[i].uid); o[i].gid = append(&p, d[i].gid); o[i].muid = append(&p, d[i].muid); } return o; } static int xdirread0(char **path, int (*namecmp)(char *, char *), Dir **d); int xdirread(char **path, int (*namecmp)(char *, char *), Dir **d) { Dir *t; int n; if((n = xdirread0(path, namecmp, &t)) > 0) *d = xdirdup(t, n); else *d = nil; return n; } static Dir* xdirstat0(char **path, int (*namecmp)(char *, char *), char *err) { char *base, *name; Dir *d, *t; int n, i; if(d = dirstat(*path)){ if(d->name[0] == 0) d->name = "/"; return d; } if(!splitpath(*path, &base, &name)) return nil; if((n = xdirread0(&base, namecmp, &t)) < 0) goto out; for(i=0; i<n; i++){ if(namecmp(t[i].name, name)) continue; free(*path); *path = conspath(base, t[i].name); d = xdirdup(&t[i], 1); goto out; } werrstr("%s", err); out: free(base); free(name); return d; } Dir* xdirstat(char **path, int (*namecmp)(char *, char *)) { return xdirstat0(path, namecmp, "name not found"); } typedef struct XDir XDir; struct XDir { Qid qid; char *path; int ndir; Dir *dir; XDir *next; }; static void freexdir(XDir *x) { free(x->path); free(x->dir); free(x); } static int qidcmp(Qid *q1, Qid *q2) { return (q1->type != q2->type) || (q1->path != q2->path) || (q1->vers != q2->vers); } static XDir *xdirlist; static int xdircount; static int xdirread0(char **path, int (*namecmp)(char *, char *), Dir **d) { XDir *x, *p; int fd, n; Dir *t; t = nil; for(p = nil, x = xdirlist; x; p=x, x=x->next){ if(namecmp(x->path, *path)) continue; if(x == xdirlist) xdirlist = x->next; else p->next = x->next; while(t = dirstat(x->path)){ if(qidcmp(&t->qid, &x->qid)) break; free(t); x->next = xdirlist; xdirlist = x; if(strcmp(x->path, *path)){ free(*path); *path = strdup(x->path); } if(d) *d = x->dir; return x->ndir; } xdircount--; freexdir(x); break; } if((fd = open(*path, OREAD)) < 0){ free(t); if(t = xdirstat0(path, namecmp, "directory entry not found")) fd = open(*path, OREAD); } else if(t == nil) t = dirfstat(fd); n = -1; if(fd < 0 || t == nil) goto out; if((t->qid.type & QTDIR) == 0){ werrstr("not a directory"); goto out; } if((n = dirreadall(fd, d)) < 0) goto out; if(xdircount >= 8){ xdircount--; for(p = xdirlist, x = xdirlist->next; x->next; p = x, x = x->next) ; p->next = nil; freexdir(x); } x = mallocz(sizeof(*x), 1); x->qid = t->qid; x->path = strdup(*path); x->ndir = n; x->dir = *d; x->next = xdirlist; xdirlist = x; xdircount++; out: if(fd >= 0) close(fd); free(t); return n; } void xdirflush(char *path, int (*namecmp)(char *, char *)) { XDir **pp, **xx, *x; char *d, *s; int n; n = strlen(path); if(s = strrchr(path, '/')) n = s - path; d = smprint("%.*s", utfnlen(path, n), path); s = malloc(++n); for(pp = &xdirlist; x = *pp; pp = xx){ xx = &x->next; snprint(s, n, "%s", x->path); if(namecmp(d, s) == 0){ *pp = *xx; xx = pp; xdircount--; freexdir(x); } } free(s); free(d); }