13e12c5d1SDavid du Colombier #include <u.h> 23e12c5d1SDavid du Colombier #include <libc.h> 33e12c5d1SDavid du Colombier #include <bio.h> 43e12c5d1SDavid du Colombier 53e12c5d1SDavid du Colombier enum{ 63e12c5d1SDavid du Colombier LEN = 8*1024, 7*219b2ee8SDavid du Colombier NFLDS = 6, /* filename, modes, uid, gid, mtime, bytes */ 83e12c5d1SDavid du Colombier }; 93e12c5d1SDavid du Colombier 103e12c5d1SDavid du Colombier int selected(char*, int, char*[]); 113e12c5d1SDavid du Colombier void mkdirs(char*, char*); 12*219b2ee8SDavid du Colombier void mkdir(char*, ulong, ulong, char*, char*); 13*219b2ee8SDavid du Colombier void extract(char*, ulong, ulong, char*, char*, ulong); 143e12c5d1SDavid du Colombier void seekpast(ulong); 153e12c5d1SDavid du Colombier void error(char*, ...); 163e12c5d1SDavid du Colombier void warn(char*, ...); 173e12c5d1SDavid du Colombier void usage(void); 183e12c5d1SDavid du Colombier 193e12c5d1SDavid du Colombier Biobufhdr bin; 203e12c5d1SDavid du Colombier uchar binbuf[2*LEN]; 213e12c5d1SDavid du Colombier int uflag; 223e12c5d1SDavid du Colombier int hflag; 23*219b2ee8SDavid du Colombier int vflag; 243e12c5d1SDavid du Colombier 253e12c5d1SDavid du Colombier void 263e12c5d1SDavid du Colombier main(int argc, char **argv) 273e12c5d1SDavid du Colombier { 283e12c5d1SDavid du Colombier Biobuf bout; 293e12c5d1SDavid du Colombier char *fields[NFLDS], name[2*LEN], *p, *namep; 303e12c5d1SDavid du Colombier char uid[NAMELEN], gid[NAMELEN]; 31*219b2ee8SDavid du Colombier ulong mode, bytes, mtime; 323e12c5d1SDavid du Colombier 333e12c5d1SDavid du Colombier namep = name; 343e12c5d1SDavid du Colombier ARGBEGIN{ 353e12c5d1SDavid du Colombier case 'd': 363e12c5d1SDavid du Colombier p = ARGF(); 373e12c5d1SDavid du Colombier if(strlen(p) >= LEN) 383e12c5d1SDavid du Colombier error("destination fs name too long\n"); 393e12c5d1SDavid du Colombier strcpy(name, p); 403e12c5d1SDavid du Colombier namep = name + strlen(name); 413e12c5d1SDavid du Colombier break; 423e12c5d1SDavid du Colombier case 'h': 433e12c5d1SDavid du Colombier hflag = 1; 443e12c5d1SDavid du Colombier Binit(&bout, 1, OWRITE); 453e12c5d1SDavid du Colombier break; 463e12c5d1SDavid du Colombier case 'u': 473e12c5d1SDavid du Colombier uflag = 1; 483e12c5d1SDavid du Colombier break; 49*219b2ee8SDavid du Colombier case 'v': 50*219b2ee8SDavid du Colombier vflag = 1; 51*219b2ee8SDavid du Colombier break; 523e12c5d1SDavid du Colombier default: 533e12c5d1SDavid du Colombier usage(); 543e12c5d1SDavid du Colombier }ARGEND 553e12c5d1SDavid du Colombier 563e12c5d1SDavid du Colombier Binits(&bin, 0, OREAD, binbuf, sizeof binbuf); 573e12c5d1SDavid du Colombier while(p = Brdline(&bin, '\n')){ 583e12c5d1SDavid du Colombier p[Blinelen(&bin)-1] = '\0'; 593e12c5d1SDavid du Colombier if(strcmp(p, "end of archive") == 0){ 603e12c5d1SDavid du Colombier fprint(2, "done\n"); 613e12c5d1SDavid du Colombier exits(0); 623e12c5d1SDavid du Colombier } 633e12c5d1SDavid du Colombier if(getfields(p, fields, NFLDS) != NFLDS){ 643e12c5d1SDavid du Colombier warn("too few fields in file header"); 653e12c5d1SDavid du Colombier continue; 663e12c5d1SDavid du Colombier } 673e12c5d1SDavid du Colombier strcpy(namep, fields[0]); 683e12c5d1SDavid du Colombier mode = strtoul(fields[1], 0, 8); 69*219b2ee8SDavid du Colombier mtime = strtoul(fields[4], 0, 10); 70*219b2ee8SDavid du Colombier bytes = strtoul(fields[5], 0, 10); 713e12c5d1SDavid du Colombier strncpy(uid, fields[2], NAMELEN); 723e12c5d1SDavid du Colombier strncpy(gid, fields[3], NAMELEN); 733e12c5d1SDavid du Colombier if(argc){ 743e12c5d1SDavid du Colombier if(!selected(namep, argc, argv)){ 753e12c5d1SDavid du Colombier if(bytes) 763e12c5d1SDavid du Colombier seekpast(bytes); 773e12c5d1SDavid du Colombier continue; 783e12c5d1SDavid du Colombier } 793e12c5d1SDavid du Colombier mkdirs(name, namep); 803e12c5d1SDavid du Colombier } 813e12c5d1SDavid du Colombier if(hflag){ 82*219b2ee8SDavid du Colombier Bprint(&bout, "%s %luo %s %s %lud %d\n", 83*219b2ee8SDavid du Colombier name, mode, uid, gid, mtime, bytes); 843e12c5d1SDavid du Colombier if(bytes) 853e12c5d1SDavid du Colombier seekpast(bytes); 863e12c5d1SDavid du Colombier continue; 873e12c5d1SDavid du Colombier } 883e12c5d1SDavid du Colombier if(mode & CHDIR) 89*219b2ee8SDavid du Colombier mkdir(name, mode, mtime, uid, gid); 903e12c5d1SDavid du Colombier else 91*219b2ee8SDavid du Colombier extract(name, mode, mtime, uid, gid, bytes); 923e12c5d1SDavid du Colombier } 933e12c5d1SDavid du Colombier fprint(2, "premature end of archive\n"); 943e12c5d1SDavid du Colombier exits("premature end of archive"); 953e12c5d1SDavid du Colombier } 963e12c5d1SDavid du Colombier 973e12c5d1SDavid du Colombier int 983e12c5d1SDavid du Colombier fileprefix(char *prefix, char *s) 993e12c5d1SDavid du Colombier { 1003e12c5d1SDavid du Colombier while(*prefix) 1013e12c5d1SDavid du Colombier if(*prefix++ != *s++) 1023e12c5d1SDavid du Colombier return 0; 1033e12c5d1SDavid du Colombier if(*s && *s != '/') 1043e12c5d1SDavid du Colombier return 0; 1053e12c5d1SDavid du Colombier return 1; 1063e12c5d1SDavid du Colombier } 1073e12c5d1SDavid du Colombier 1083e12c5d1SDavid du Colombier int 1093e12c5d1SDavid du Colombier selected(char *s, int argc, char *argv[]) 1103e12c5d1SDavid du Colombier { 1113e12c5d1SDavid du Colombier int i; 1123e12c5d1SDavid du Colombier 1133e12c5d1SDavid du Colombier for(i=0; i<argc; i++) 1143e12c5d1SDavid du Colombier if(fileprefix(argv[i], s)) 1153e12c5d1SDavid du Colombier return 1; 1163e12c5d1SDavid du Colombier return 0; 1173e12c5d1SDavid du Colombier } 1183e12c5d1SDavid du Colombier 1193e12c5d1SDavid du Colombier void 1203e12c5d1SDavid du Colombier mkdirs(char *name, char *namep) 1213e12c5d1SDavid du Colombier { 1223e12c5d1SDavid du Colombier char buf[2*LEN], *p; 1233e12c5d1SDavid du Colombier int fd; 1243e12c5d1SDavid du Colombier 1253e12c5d1SDavid du Colombier strcpy(buf, name); 1263e12c5d1SDavid du Colombier for(p = &buf[namep - name]; p = utfrune(p, '/'); p++){ 1273e12c5d1SDavid du Colombier if(p[1] == '\0') 1283e12c5d1SDavid du Colombier return; 1293e12c5d1SDavid du Colombier *p = 0; 1303e12c5d1SDavid du Colombier fd = create(buf, OREAD, 0775|CHDIR); 1313e12c5d1SDavid du Colombier close(fd); 1323e12c5d1SDavid du Colombier *p = '/'; 1333e12c5d1SDavid du Colombier } 1343e12c5d1SDavid du Colombier } 1353e12c5d1SDavid du Colombier 1363e12c5d1SDavid du Colombier void 137*219b2ee8SDavid du Colombier mkdir(char *name, ulong mode, ulong mtime, char *uid, char *gid) 1383e12c5d1SDavid du Colombier { 1393e12c5d1SDavid du Colombier Dir d; 1403e12c5d1SDavid du Colombier int fd; 1413e12c5d1SDavid du Colombier char *p; 1423e12c5d1SDavid du Colombier 1433e12c5d1SDavid du Colombier fd = create(name, OREAD, mode); 1443e12c5d1SDavid du Colombier if(fd < 0){ 1453e12c5d1SDavid du Colombier if(dirstat(name, &d) < 0 || !(d.mode & CHDIR)){ 1463e12c5d1SDavid du Colombier warn("can't make directory %s: %r", name); 1473e12c5d1SDavid du Colombier return; 1483e12c5d1SDavid du Colombier } 1493e12c5d1SDavid du Colombier }else if(dirfstat(fd, &d) < 0) 150*219b2ee8SDavid du Colombier warn("can't stat %s: %r", name); 1513e12c5d1SDavid du Colombier close(fd); 1523e12c5d1SDavid du Colombier 1533e12c5d1SDavid du Colombier p = utfrrune(name, L'/'); 1543e12c5d1SDavid du Colombier if(p) 1553e12c5d1SDavid du Colombier p++; 1563e12c5d1SDavid du Colombier else 1573e12c5d1SDavid du Colombier p = name; 1583e12c5d1SDavid du Colombier strncpy(d.name, p, NAMELEN); 1593e12c5d1SDavid du Colombier if(uflag){ 1603e12c5d1SDavid du Colombier strncpy(d.uid, uid, NAMELEN); 1613e12c5d1SDavid du Colombier strncpy(d.gid, gid, NAMELEN); 162*219b2ee8SDavid du Colombier d.mtime = mtime; 1633e12c5d1SDavid du Colombier } 1643e12c5d1SDavid du Colombier d.mode = mode; 1653e12c5d1SDavid du Colombier if(dirwstat(name, &d) < 0) 1663e12c5d1SDavid du Colombier warn("can't set modes for %s: %r", name); 1673e12c5d1SDavid du Colombier if(uflag){ 1683e12c5d1SDavid du Colombier if(dirstat(name, &d) < 0) 1693e12c5d1SDavid du Colombier warn("can't reread modes for %s: %r", name); 170*219b2ee8SDavid du Colombier if(d.mtime != mtime) 171*219b2ee8SDavid du Colombier warn("%s: time mismatch %lud %lud\n", name, mtime, d.mtime); 1723e12c5d1SDavid du Colombier if(strcmp(uid, d.uid)) 1733e12c5d1SDavid du Colombier warn("%s: uid mismatch %s %s", name, uid, d.uid); 1743e12c5d1SDavid du Colombier if(strcmp(gid, d.gid)) 1753e12c5d1SDavid du Colombier warn("%s: gid mismatch %s %s", name, gid, d.gid); 1763e12c5d1SDavid du Colombier } 1773e12c5d1SDavid du Colombier close(fd); 1783e12c5d1SDavid du Colombier } 1793e12c5d1SDavid du Colombier 1803e12c5d1SDavid du Colombier void 181*219b2ee8SDavid du Colombier extract(char *name, ulong mode, ulong mtime, char *uid, char *gid, ulong bytes) 1823e12c5d1SDavid du Colombier { 1833e12c5d1SDavid du Colombier Dir d; 1843e12c5d1SDavid du Colombier Biobuf *b; 1853e12c5d1SDavid du Colombier char buf[LEN]; 1863e12c5d1SDavid du Colombier char *p; 1873e12c5d1SDavid du Colombier ulong n, tot; 1883e12c5d1SDavid du Colombier 189*219b2ee8SDavid du Colombier if(vflag) 190*219b2ee8SDavid du Colombier print("x %s %d bytes\n", name, bytes); 191*219b2ee8SDavid du Colombier 1923e12c5d1SDavid du Colombier b = Bopen(name, OWRITE); 1933e12c5d1SDavid du Colombier if(!b){ 1943e12c5d1SDavid du Colombier warn("can't make file %s: %r", name); 1953e12c5d1SDavid du Colombier seekpast(bytes); 1963e12c5d1SDavid du Colombier return; 1973e12c5d1SDavid du Colombier } 1983e12c5d1SDavid du Colombier for(tot = 0; tot < bytes; tot += n){ 1993e12c5d1SDavid du Colombier n = sizeof buf; 2003e12c5d1SDavid du Colombier if(tot + n > bytes) 2013e12c5d1SDavid du Colombier n = bytes - tot; 2023e12c5d1SDavid du Colombier n = Bread(&bin, buf, n); 203*219b2ee8SDavid du Colombier if(n <= 0) 2043e12c5d1SDavid du Colombier error("premature eof reading %s", name); 2053e12c5d1SDavid du Colombier if(Bwrite(b, buf, n) != n) 2063e12c5d1SDavid du Colombier warn("error writing %s: %r", name); 2073e12c5d1SDavid du Colombier } 2083e12c5d1SDavid du Colombier 2093e12c5d1SDavid du Colombier if(dirfstat(Bfildes(b), &d) < 0) 210*219b2ee8SDavid du Colombier warn("can't stat %s: %r", name); 2113e12c5d1SDavid du Colombier p = utfrrune(name, '/'); 2123e12c5d1SDavid du Colombier if(p) 2133e12c5d1SDavid du Colombier p++; 2143e12c5d1SDavid du Colombier else 2153e12c5d1SDavid du Colombier p = name; 2163e12c5d1SDavid du Colombier strncpy(d.name, p, NAMELEN); 2173e12c5d1SDavid du Colombier if(uflag){ 2183e12c5d1SDavid du Colombier strncpy(d.uid, uid, NAMELEN); 2193e12c5d1SDavid du Colombier strncpy(d.gid, gid, NAMELEN); 220*219b2ee8SDavid du Colombier d.mtime = mtime; 2213e12c5d1SDavid du Colombier } 2223e12c5d1SDavid du Colombier d.mode = mode; 223*219b2ee8SDavid du Colombier Bflush(b); 2243e12c5d1SDavid du Colombier if(dirfwstat(Bfildes(b), &d) < 0) 2253e12c5d1SDavid du Colombier warn("can't set modes for %s: %r", name); 2263e12c5d1SDavid du Colombier if(uflag){ 2273e12c5d1SDavid du Colombier if(dirfstat(Bfildes(b), &d) < 0) 2283e12c5d1SDavid du Colombier warn("can't reread modes for %s: %r", name); 229*219b2ee8SDavid du Colombier if(d.mtime != mtime) 230*219b2ee8SDavid du Colombier warn("%s: time mismatch %lud %lud\n", name, mtime, d.mtime); 2313e12c5d1SDavid du Colombier if(strcmp(uid, d.uid)) 2323e12c5d1SDavid du Colombier warn("%s: uid mismatch %s %s", name, uid, d.uid); 2333e12c5d1SDavid du Colombier if(strcmp(gid, d.gid)) 2343e12c5d1SDavid du Colombier warn("%s: gid mismatch %s %s", name, gid, d.gid); 2353e12c5d1SDavid du Colombier } 236*219b2ee8SDavid du Colombier Bterm(b); 2373e12c5d1SDavid du Colombier } 2383e12c5d1SDavid du Colombier 2393e12c5d1SDavid du Colombier void 2403e12c5d1SDavid du Colombier seekpast(ulong bytes) 2413e12c5d1SDavid du Colombier { 2423e12c5d1SDavid du Colombier char buf[LEN]; 2433e12c5d1SDavid du Colombier ulong tot, n; 2443e12c5d1SDavid du Colombier 2453e12c5d1SDavid du Colombier for(tot = 0; tot < bytes; tot += n){ 2463e12c5d1SDavid du Colombier n = sizeof buf; 2473e12c5d1SDavid du Colombier if(tot + n > bytes) 2483e12c5d1SDavid du Colombier n = bytes - tot; 2493e12c5d1SDavid du Colombier n = Bread(&bin, buf, n); 2503e12c5d1SDavid du Colombier if(n < 0) 2513e12c5d1SDavid du Colombier error("premature eof"); 2523e12c5d1SDavid du Colombier } 2533e12c5d1SDavid du Colombier } 2543e12c5d1SDavid du Colombier 2553e12c5d1SDavid du Colombier void 2563e12c5d1SDavid du Colombier error(char *fmt, ...) 2573e12c5d1SDavid du Colombier { 2583e12c5d1SDavid du Colombier char buf[1024]; 2593e12c5d1SDavid du Colombier 2603e12c5d1SDavid du Colombier sprint(buf, "%s: ", argv0); 2613e12c5d1SDavid du Colombier doprint(buf+strlen(buf), buf+sizeof(buf), fmt, (&fmt+1)); 2623e12c5d1SDavid du Colombier fprint(2, "%s\n", buf); 2633e12c5d1SDavid du Colombier exits(0); 2643e12c5d1SDavid du Colombier } 2653e12c5d1SDavid du Colombier 2663e12c5d1SDavid du Colombier void 2673e12c5d1SDavid du Colombier warn(char *fmt, ...) 2683e12c5d1SDavid du Colombier { 2693e12c5d1SDavid du Colombier char buf[1024]; 2703e12c5d1SDavid du Colombier 2713e12c5d1SDavid du Colombier sprint(buf, "%s: ", argv0); 2723e12c5d1SDavid du Colombier doprint(buf+strlen(buf), buf+sizeof(buf), fmt, (&fmt+1)); 2733e12c5d1SDavid du Colombier fprint(2, "%s\n", buf); 2743e12c5d1SDavid du Colombier } 2753e12c5d1SDavid du Colombier 2763e12c5d1SDavid du Colombier void 2773e12c5d1SDavid du Colombier usage(void) 2783e12c5d1SDavid du Colombier { 279*219b2ee8SDavid du Colombier fprint(2, "usage: mkext [-h] [-u] [-v] [-d dest-fs] [file ...]\n"); 2803e12c5d1SDavid du Colombier } 281