#include #include #include enum{ LEN = 8*1024, NFLDS = 5, /* filename, modes, uid, gid, bytes */ }; int selected(char*, int, char*[]); void mkdirs(char*, char*); void mkdir(char*, ulong, char*, char*); void extract(char*, ulong, char*, char*, ulong); void seekpast(ulong); void error(char*, ...); void warn(char*, ...); void usage(void); Biobufhdr bin; uchar binbuf[2*LEN]; int uflag; int hflag; void main(int argc, char **argv) { Biobuf bout; char *fields[NFLDS], name[2*LEN], *p, *namep; char uid[NAMELEN], gid[NAMELEN]; ulong mode, bytes; namep = name; ARGBEGIN{ case 'd': p = ARGF(); if(strlen(p) >= LEN) error("destination fs name too long\n"); strcpy(name, p); namep = name + strlen(name); break; case 'h': hflag = 1; Binit(&bout, 1, OWRITE); break; case 'u': uflag = 1; break; default: usage(); }ARGEND Binits(&bin, 0, OREAD, binbuf, sizeof binbuf); while(p = Brdline(&bin, '\n')){ p[Blinelen(&bin)-1] = '\0'; if(strcmp(p, "end of archive") == 0){ fprint(2, "done\n"); exits(0); } if(getfields(p, fields, NFLDS) != NFLDS){ warn("too few fields in file header"); continue; } strcpy(namep, fields[0]); mode = strtoul(fields[1], 0, 8); bytes = strtoul(fields[4], 0, 10); strncpy(uid, fields[2], NAMELEN); strncpy(gid, fields[3], NAMELEN); if(strcmp(uid, "ucds")==0) strcpy(uid, "cda"); if(strcmp(gid, "ucds")==0) strcpy(gid, "cda"); if(argc){ if(!selected(namep, argc, argv)){ if(bytes) seekpast(bytes); continue; } mkdirs(name, namep); } if(hflag){ Bprint(&bout, "%s %luo %s %s %d\n", name, mode, uid, gid, bytes); if(bytes) seekpast(bytes); continue; } if(mode & CHDIR) mkdir(name, mode, uid, gid); else extract(name, mode, uid, gid, bytes); } fprint(2, "premature end of archive\n"); exits("premature end of archive"); } int fileprefix(char *prefix, char *s) { while(*prefix) if(*prefix++ != *s++) return 0; if(*s && *s != '/') return 0; return 1; } int selected(char *s, int argc, char *argv[]) { int i; for(i=0; i bytes) n = bytes - tot; n = Bread(&bin, buf, n); if(n < 0) error("premature eof reading %s", name); if(Bwrite(b, buf, n) != n) warn("error writing %s: %r", name); } if(dirfstat(Bfildes(b), &d) < 0) warn("can' stat %s: %r", name); p = utfrrune(name, '/'); if(p) p++; else p = name; strncpy(d.name, p, NAMELEN); if(uflag){ strncpy(d.uid, uid, NAMELEN); strncpy(d.gid, gid, NAMELEN); } d.mode = mode; if(dirfwstat(Bfildes(b), &d) < 0) warn("can't set modes for %s: %r", name); if(uflag){ if(dirfstat(Bfildes(b), &d) < 0) warn("can't reread modes for %s: %r", name); if(strcmp(uid, d.uid)) warn("%s: uid mismatch %s %s", name, uid, d.uid); if(strcmp(gid, d.gid)) warn("%s: gid mismatch %s %s", name, gid, d.gid); } Bclose(b); } void seekpast(ulong bytes) { char buf[LEN]; ulong tot, n; for(tot = 0; tot < bytes; tot += n){ n = sizeof buf; if(tot + n > bytes) n = bytes - tot; n = Bread(&bin, buf, n); if(n < 0) error("premature eof"); } } void error(char *fmt, ...) { char buf[1024]; sprint(buf, "%s: ", argv0); doprint(buf+strlen(buf), buf+sizeof(buf), fmt, (&fmt+1)); fprint(2, "%s\n", buf); exits(0); } void warn(char *fmt, ...) { char buf[1024]; sprint(buf, "%s: ", argv0); doprint(buf+strlen(buf), buf+sizeof(buf), fmt, (&fmt+1)); fprint(2, "%s\n", buf); } void usage(void) { fprint(2, "usage: mkext [-h] [-u] [-d dest-fs] [file ...]\n"); }