14 typedef struct File File;
24 typedef void Mkfserr(char*, void*);
25 typedef void Mkfsenum(char*, char*, Dir*, void*);
27 typedef struct Name Name;
33 typedef struct Opt Opt;
44 typedef struct Mkaux Mkaux;
63 static void domkfs(Mkaux *mkaux, File *me, int level);
65 static int copyfile(Mkaux*, File*, Dir*, int);
66 static void freefile(File*);
67 static File* getfile(Mkaux*, File*);
68 static char* getmode(Mkaux*, char*, ulong*);
69 static char* getname(Mkaux*, char*, char**);
70 static char* getpath(Mkaux*, char*);
71 static int mkfile(Mkaux*, File*);
72 static char* mkpath(Mkaux*, char*, char*);
73 static void mktree(Mkaux*, File*, int);
74 static void setname(Mkaux*, Name*, File*);
75 static void skipdir(Mkaux*);
76 static void warn(Mkaux*, char *, ...);
77 static void popopt(Mkaux *mkaux);
80 //mprint(char *new, char *old, Dir *d, void*)
82 // print("%s %s %D\n", new, old, d);
86 rdproto(char *proto, char *root, Mkfsenum *mkenum, Mkfserr *mkerr, void *a)
93 memset(&mx, 0, sizeof mx);
105 if((m->b = Bopen(proto, OREAD)) == nil) {
106 werrstr("open '%s': %r", proto);
110 memset(&file, 0, sizeof file);
115 if(setjmp(m->jmp) == 0)
116 domkfs(m, &file, -1);
127 emalloc(Mkaux *mkaux, ulong n)
133 longjmp(mkaux->jmp, 1); /* memory leak */
139 estrdup(Mkaux *mkaux, char *s)
143 longjmp(mkaux->jmp, 1); /* memory leak */
148 domkfs(Mkaux *mkaux, File *me, int level)
153 child = getfile(mkaux, me);
156 if((child->elem[0] == '+' || child->elem[0] == '*') && child->elem[1] == '\0'){
157 rec = child->elem[0] == '+';
159 child->new = estrdup(mkaux, me->new);
160 setname(mkaux, &mkaux->oldfile, child);
161 mktree(mkaux, child, rec);
163 child = getfile(mkaux, me);
165 while(child && mkaux->indent > level){
166 if(mkfile(mkaux, child))
167 domkfs(mkaux, child, mkaux->indent);
169 child = getfile(mkaux, me);
173 Bseek(mkaux->b, -Blinelen(mkaux->b), 1);
179 mktree(Mkaux *mkaux, File *me, int rec)
185 fd = open(mkaux->oldfile.s, OREAD);
187 warn(mkaux, "can't open %s: %r", mkaux->oldfile.s);
191 while((n = dirread(fd, &d)) > 0){
192 for(i = 0; i < n; i++){
193 if(mkaux->opt && mkaux->opt->skip){
196 memset(m, 0, sizeof(m));
197 if(regexec(mkaux->opt->skip, d[i].name, m, nelem(m)))
200 child.new = mkpath(mkaux, me->new, d[i].name);
202 child.old = mkpath(mkaux, me->old, d[i].name);
203 child.elem = d[i].name;
204 setname(mkaux, &mkaux->oldfile, &child);
205 if((!(d[i].mode&DMDIR) || rec) && copyfile(mkaux, &child, &d[i], 1) && rec)
206 mktree(mkaux, &child, rec);
217 mkfile(Mkaux *mkaux, File *f)
221 if((d = dirstat(mkaux->oldfile.s)) == nil){
222 warn(mkaux, "can't stat file %s: %r", mkaux->oldfile.s);
226 return copyfile(mkaux, f, d, 0);
234 setname(Mkaux *mkaux, Name *name, File *f)
242 /* if old is not a absolute path, dont append root to it */
251 ss = (*s1 && *s2 && *s2 != '/' && s1[l-1] != '/') ? "/" : "";
255 if(name->n < l+SLOP/2) {
257 name->s = emalloc(mkaux, l+SLOP);
260 snprint(name->s, name->n, "%s%s%s", s1, ss, s2);
265 copyfile(Mkaux *mkaux, File *f, Dir *d, int permonly)
272 setname(mkaux, &mkaux->fullname, f);
275 * Extra stat here is inefficient but accounts for binds.
277 if((nd = dirstat(mkaux->fullname.s)) != nil)
282 if(strcmp(f->uid, "-") != 0)
286 if(strcmp(f->gid, "-") != 0)
292 d->mode = (d->mode & ~0666) | (f->mode & 0666);
293 else if((d->mode&DMDIR) != (f->mode&DMDIR))
294 warn(mkaux, "inconsistent mode for %s", f->new);
297 } else if(o && o->mask)
298 d->mode = (d->mode & ~o->mask) | (o->mode & o->mask);
300 if(p = strrchr(f->new, '/'))
304 mkaux->mkenum(f->new, mkaux->fullname.s, d, mkaux->a);
307 return (xmode&DMDIR) != 0;
311 mkpath(Mkaux *mkaux, char *prefix, char *elem)
316 n = strlen(prefix) + strlen(elem) + 2;
317 p = emalloc(mkaux, n);
325 parsemode(char *spec, long *pmask, long *pmode)
334 mask = DMAPPEND | DMEXCL | DMTMP;
336 if(*s >= '0' && *s <= '7'){
338 mode = strtoul(s, 0, 8);
343 for(; *s && op == 0; s++){
397 if(op == '+' || op == '-')
405 *pmode = (*pmode & ~mask) | (mode & mask);
411 setopt(Mkaux *mkaux, char *key, char *val)
416 if(o == nil || mkaux->indent > o->level){
417 o = emalloc(mkaux, sizeof(*o));
419 longjmp(mkaux->jmp, 1);
423 o->uid = estrdup(mkaux, o->uid);
425 o->gid = estrdup(mkaux, o->gid);
427 memset(o, 0, sizeof(*o));
428 o->level = mkaux->indent;
429 o->prev = mkaux->opt;
431 } else if(mkaux->indent < o->level)
433 if(strcmp(key, "skip") == 0){
434 o->skip = regcomp(val);
435 } else if(strcmp(key, "uid") == 0){
437 o->uid = *val ? estrdup(mkaux, val) : nil;
438 } else if(strcmp(key, "gid") == 0){
440 o->gid = *val ? estrdup(mkaux, val) : nil;
441 } else if(strcmp(key, "mode") == 0){
442 if(!parsemode(val, &o->mask, &o->mode))
443 warn(mkaux, "bad mode specification %s", val);
445 warn(mkaux, "bad option %s=%s", key, val);
454 while(o = mkaux->opt){
455 if(o->level <= mkaux->indent)
457 mkaux->opt = o->prev;
475 * skip all files in the proto that
476 * could be in the current dir
479 skipdir(Mkaux *mkaux)
484 if(mkaux->indent < 0)
486 level = mkaux->indent;
489 p = Brdline(mkaux->b, '\n');
495 while((c = *p++) != '\n')
502 if(mkaux->indent <= level){
504 Bseek(mkaux->b, -Blinelen(mkaux->b), 1);
512 getfile(Mkaux *mkaux, File *old)
519 if(mkaux->indent < 0)
523 p = Brdline(mkaux->b, '\n');
529 while((c = *p++) != '\n')
536 if(c == '\n' || c == '#')
540 *strchr(p, '\n') = 0;
541 if(s = strchr(p, '=')){
547 f = emalloc(mkaux, sizeof *f);
548 p = getname(mkaux, p, &elem);
552 f->new = mkpath(mkaux, old->new, elem);
554 f->elem = utfrrune(f->new, L'/') + 1;
555 p = getmode(mkaux, p, &f->mode);
556 p = getname(mkaux, p, &f->uid); /* LEAK */
562 p = getname(mkaux, p, &f->gid); /* LEAK */
568 f->old = getpath(mkaux, p);
569 if(f->old && strcmp(f->old, "-") == 0){
573 setname(mkaux, &mkaux->oldfile, f);
579 getpath(Mkaux *mkaux, char *p)
584 while((c = *p) == ' ' || c == '\t')
587 while((c = *q) != '\n' && c != ' ' && c != '\t')
592 new = emalloc(mkaux, n + 1);
599 getname(Mkaux *mkaux, char *p, char **buf)
604 while((c = *p) == ' ' || c == '\t')
608 while((c = *p) != '\n' && c != ' ' && c != '\t')
611 *buf = malloc(p+2-start); /* +2: need at least 2 bytes; might strcpy "-" into buf */
614 memmove(*buf, start, p-start);
616 (*buf)[p-start] = '\0';
621 warn(mkaux, "can't read environment variable %s", *buf+1);
633 getmode(Mkaux *mkaux, char *p, ulong *xmode)
639 p = getname(mkaux, p, &buf);
644 if(!*s || strcmp(s, "-") == 0)
659 if(s[0] < '0' || s[0] > '7'
660 || s[1] < '0' || s[1] > '7'
661 || s[2] < '0' || s[2] > '7'
663 warn(mkaux, "bad mode specification %s", buf);
667 *xmode = m | strtoul(s, 0, 8);
673 warn(Mkaux *mkaux, char *fmt, ...)
679 vseprint(buf, buf+sizeof(buf), fmt, va);
683 mkaux->warn(buf, mkaux->a);
685 fprint(2, "warning: %s\n", buf);