14 #define warn protowarn
17 #define getmode protogetmode
19 typedef struct File File;
29 typedef void Mkfserr(char*, void*);
30 typedef void Mkfsenum(char*, char*, Dir*, void*);
32 typedef struct Name Name;
38 typedef struct Mkaux Mkaux;
55 static void domkfs(Mkaux *mkaux, File *me, int level);
57 static int copyfile(Mkaux*, File*, Dir*, int);
58 static void freefile(File*);
59 static File* getfile(Mkaux*, File*);
60 static char* getmode(Mkaux*, char*, ulong*);
61 static char* getname(Mkaux*, char*, char**);
62 static char* getpath(Mkaux*, char*);
63 static int mkfile(Mkaux*, File*);
64 static char* mkpath(Mkaux*, char*, char*);
65 static void mktree(Mkaux*, File*, int);
66 static void setnames(Mkaux*, File*);
67 static void skipdir(Mkaux*);
68 static void warn(Mkaux*, char *, ...);
71 /*mprint(char *new, char *old, Dir *d, void*) */
73 /* print("%s %s %D\n", new, old, d); */
77 rdproto(char *proto, char *root, Mkfsenum *mkenum, Mkfserr *mkerr, void *a)
84 memset(&mx, 0, sizeof mx);
95 if((m->b = Bopen(proto, OREAD)) == nil) {
96 werrstr("open '%s': %r", proto);
100 memset(&file, 0, sizeof file);
105 if(setjmp(m->jmp) == 0)
106 domkfs(m, &file, -1);
115 emalloc(Mkaux *mkaux, ulong n)
121 longjmp(mkaux->jmp, 1); /* memory leak */
127 estrdup(Mkaux *mkaux, char *s)
131 longjmp(mkaux->jmp, 1); /* memory leak */
136 domkfs(Mkaux *mkaux, File *me, int level)
141 child = getfile(mkaux, me);
144 if((child->elem[0] == '+' || child->elem[0] == '*') && child->elem[1] == '\0'){
145 rec = child->elem[0] == '+';
147 child->new = estrdup(mkaux, me->new);
148 setnames(mkaux, child);
149 mktree(mkaux, child, rec);
151 child = getfile(mkaux, me);
153 while(child && mkaux->indent > level){
154 if(mkfile(mkaux, child))
155 domkfs(mkaux, child, mkaux->indent);
157 child = getfile(mkaux, me);
161 Bseek(mkaux->b, -Blinelen(mkaux->b), 1);
167 mktree(Mkaux *mkaux, File *me, int rec)
173 fd = open(mkaux->oldfile.s, OREAD);
175 warn(mkaux, "can't open %s: %r", mkaux->oldfile.s);
180 while((n = dirread(fd, &d)) > 0){
181 for(i = 0; i < n; i++){
182 child.new = mkpath(mkaux, me->new, d[i].name);
184 child.old = mkpath(mkaux, me->old, d[i].name);
185 child.elem = d[i].name;
186 setnames(mkaux, &child);
187 if((!(d[i].mode&DMDIR) || rec) && copyfile(mkaux, &child, &d[i], 1) && rec)
188 mktree(mkaux, &child, rec);
198 mkfile(Mkaux *mkaux, File *f)
202 if((d = dirstat(mkaux->oldfile.s)) == nil){
203 warn(mkaux, "can't stat file %s: %r", mkaux->oldfile.s);
207 return copyfile(mkaux, f, d, 0);
215 setname(Mkaux *mkaux, Name *name, char *s1, char *s2)
219 l = strlen(s1)+strlen(s2)+1;
220 if(name->n < l+SLOP/2) {
222 name->s = emalloc(mkaux, l+SLOP);
225 snprint(name->s, name->n, "%s%s%s", s1, s1[0]==0 || s1[strlen(s1)-1]!='/' ? "/" : "", s2);
229 copyfile(Mkaux *mkaux, File *f, Dir *d, int permonly)
235 setname(mkaux, &mkaux->fullname, mkaux->root, f->old ? f->old : f->new);
237 * Extra stat here is inefficient but accounts for binds.
239 if((nd = dirstat(mkaux->fullname.s)) != nil)
246 xmode = (d->mode >> 6) & 7;
247 d->mode |= xmode | (xmode << 3);
249 if(strcmp(f->uid, "-") != 0)
251 if(strcmp(f->gid, "-") != 0)
255 d->mode = (d->mode & ~0666) | (f->mode & 0666);
256 else if((d->mode&DMDIR) != (f->mode&DMDIR))
257 warn(mkaux, "inconsistent mode for %s", f->new);
262 if(p = strrchr(f->new, '/'))
267 mkaux->mkenum(f->new, mkaux->fullname.s, d, mkaux->a);
270 return (xmode&DMDIR) != 0;
274 mkpath(Mkaux *mkaux, char *prefix, char *elem)
279 n = strlen(prefix) + strlen(elem) + 2;
280 p = emalloc(mkaux, n);
288 setnames(Mkaux *mkaux, File *f)
293 setname(mkaux, &mkaux->oldfile, f->old, "");
295 setname(mkaux, &mkaux->oldfile, mkaux->root, f->old);
297 setname(mkaux, &mkaux->oldfile, mkaux->root, f->new);
311 * skip all files in the proto that
312 * could be in the current dir
315 skipdir(Mkaux *mkaux)
320 if(mkaux->indent < 0)
322 level = mkaux->indent;
325 p = Brdline(mkaux->b, '\n');
331 while((c = *p++) != '\n')
338 if(mkaux->indent <= level){
339 Bseek(mkaux->b, -Blinelen(mkaux->b), 1);
347 getfile(Mkaux *mkaux, File *old)
354 if(mkaux->indent < 0)
358 p = Brdline(mkaux->b, '\n');
364 while((c = *p++) != '\n')
371 if(c == '\n' || c == '#')
374 f = emalloc(mkaux, sizeof *f);
375 p = getname(mkaux, p, &elem);
379 f->new = mkpath(mkaux, old->new, elem);
381 f->elem = utfrrune(f->new, '/') + 1;
382 p = getmode(mkaux, p, &f->mode);
383 p = getname(mkaux, p, &f->uid); /* LEAK */
389 p = getname(mkaux, p, &f->gid); /* LEAK */
395 f->old = getpath(mkaux, p);
396 if(f->old && strcmp(f->old, "-") == 0){
406 getpath(Mkaux *mkaux, char *p)
411 while((c = *p) == ' ' || c == '\t')
414 while((c = *q) != '\n' && c != ' ' && c != '\t')
419 new = emalloc(mkaux, n + 1);
426 getname(Mkaux *mkaux, char *p, char **buf)
431 while((c = *p) == ' ' || c == '\t')
435 while((c = *p) != '\n' && c != ' ' && c != '\t')
438 *buf = malloc(p+2-start); /* +2: need at least 2 bytes; might strcpy "-" into buf */
441 memmove(*buf, start, p-start);
443 (*buf)[p-start] = '\0';
448 warn(mkaux, "can't read environment variable %s", *buf+1);
460 getmode(Mkaux *mkaux, char *p, ulong *xmode)
466 p = getname(mkaux, p, &buf);
471 if(!*s || strcmp(s, "-") == 0)
486 if(s[0] < '0' || s[0] > '7'
487 || s[1] < '0' || s[1] > '7'
488 || s[2] < '0' || s[2] > '7'
490 warn(mkaux, "bad mode specification %s", buf);
494 *xmode = m | strtoul(s, 0, 8);
500 warn(Mkaux *mkaux, char *fmt, ...)
506 vseprint(buf, buf+sizeof(buf), fmt, va);
510 mkaux->warn(buf, mkaux->a);
512 fprint(2, "warning: %s\n", buf);