mkext.c (5827B)
1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 5 #define mkdir plan9mkdir 6 7 enum{ 8 LEN = 8*1024, 9 NFLDS = 6, /* filename, modes, uid, gid, mtime, bytes */ 10 }; 11 12 int selected(char*, int, char*[]); 13 void mkdirs(char*, char*); 14 void mkdir(char*, ulong, ulong, char*, char*); 15 void extract(char*, ulong, ulong, char*, char*, uvlong); 16 void seekpast(uvlong); 17 void error(char*, ...); 18 void warn(char*, ...); 19 void usage(void); 20 #pragma varargck argpos warn 1 21 #pragma varargck argpos error 1 22 23 Biobuf bin; 24 uchar binbuf[2*LEN]; 25 char linebuf[LEN]; 26 int uflag; 27 int hflag; 28 int vflag; 29 int Tflag; 30 31 void 32 main(int argc, char **argv) 33 { 34 Biobuf bout; 35 char *fields[NFLDS], name[2*LEN], *p, *namep; 36 char *uid, *gid; 37 ulong mode, mtime; 38 uvlong bytes; 39 40 quotefmtinstall(); 41 namep = name; 42 ARGBEGIN{ 43 case 'd': 44 p = ARGF(); 45 if(strlen(p) >= LEN) 46 error("destination fs name too long\n"); 47 strcpy(name, p); 48 namep = name + strlen(name); 49 break; 50 case 'h': 51 hflag = 1; 52 Binit(&bout, 1, OWRITE); 53 break; 54 case 'u': 55 uflag = 1; 56 Tflag = 1; 57 break; 58 case 'T': 59 Tflag = 1; 60 break; 61 case 'v': 62 vflag = 1; 63 break; 64 default: 65 usage(); 66 }ARGEND 67 68 Binits(&bin, 0, OREAD, binbuf, sizeof binbuf); 69 while(p = Brdline(&bin, '\n')){ 70 p[Blinelen(&bin)-1] = '\0'; 71 strcpy(linebuf, p); 72 p = linebuf; 73 if(strcmp(p, "end of archive") == 0){ 74 Bterm(&bout); 75 fprint(2, "done\n"); 76 exits(0); 77 } 78 if (gettokens(p, fields, NFLDS, " \t") != NFLDS){ 79 warn("too few fields in file header"); 80 continue; 81 } 82 p = unquotestrdup(fields[0]); 83 strcpy(namep, p); 84 free(p); 85 mode = strtoul(fields[1], 0, 8); 86 uid = fields[2]; 87 gid = fields[3]; 88 mtime = strtoul(fields[4], 0, 10); 89 bytes = strtoull(fields[5], 0, 10); 90 if(argc){ 91 if(!selected(namep, argc, argv)){ 92 if(bytes) 93 seekpast(bytes); 94 continue; 95 } 96 mkdirs(name, namep); 97 } 98 if(hflag){ 99 Bprint(&bout, "%q %luo %q %q %lud %llud\n", 100 name, mode, uid, gid, mtime, bytes); 101 if(bytes) 102 seekpast(bytes); 103 continue; 104 } 105 if(mode & DMDIR) 106 mkdir(name, mode, mtime, uid, gid); 107 else 108 extract(name, mode, mtime, uid, gid, bytes); 109 } 110 fprint(2, "premature end of archive\n"); 111 exits("premature end of archive"); 112 } 113 114 int 115 fileprefix(char *prefix, char *s) 116 { 117 while(*prefix) 118 if(*prefix++ != *s++) 119 return 0; 120 if(*s && *s != '/') 121 return 0; 122 return 1; 123 } 124 125 int 126 selected(char *s, int argc, char *argv[]) 127 { 128 int i; 129 130 for(i=0; i<argc; i++) 131 if(fileprefix(argv[i], s)) 132 return 1; 133 return 0; 134 } 135 136 void 137 mkdirs(char *name, char *namep) 138 { 139 char buf[2*LEN], *p; 140 int fd; 141 142 strcpy(buf, name); 143 for(p = &buf[namep - name]; p = utfrune(p, '/'); p++){ 144 if(p[1] == '\0') 145 return; 146 *p = 0; 147 fd = create(buf, OREAD, 0775|DMDIR); 148 close(fd); 149 *p = '/'; 150 } 151 } 152 153 void 154 mkdir(char *name, ulong mode, ulong mtime, char *uid, char *gid) 155 { 156 Dir *d, xd; 157 int fd; 158 char *p; 159 char olderr[256]; 160 161 fd = create(name, OREAD, mode); 162 if(fd < 0){ 163 rerrstr(olderr, sizeof(olderr)); 164 if((d = dirstat(name)) == nil || !(d->mode & DMDIR)){ 165 free(d); 166 warn("can't make directory %q, mode %luo: %s", name, mode, olderr); 167 return; 168 } 169 free(d); 170 } 171 close(fd); 172 173 d = &xd; 174 nulldir(d); 175 p = utfrrune(name, L'/'); 176 if(p) 177 p++; 178 else 179 p = name; 180 d->name = p; 181 if(uflag){ 182 d->uid = uid; 183 d->gid = gid; 184 } 185 if(Tflag) 186 d->mtime = mtime; 187 d->mode = mode; 188 if(dirwstat(name, d) < 0) 189 warn("can't set modes for %q: %r", name); 190 191 if(uflag||Tflag){ 192 if((d = dirstat(name)) == nil){ 193 warn("can't reread modes for %q: %r", name); 194 return; 195 } 196 if(Tflag && d->mtime != mtime) 197 warn("%q: time mismatch %lud %lud\n", name, mtime, d->mtime); 198 if(uflag && strcmp(uid, d->uid)) 199 warn("%q: uid mismatch %q %q", name, uid, d->uid); 200 if(uflag && strcmp(gid, d->gid)) 201 warn("%q: gid mismatch %q %q", name, gid, d->gid); 202 } 203 } 204 205 void 206 extract(char *name, ulong mode, ulong mtime, char *uid, char *gid, uvlong bytes) 207 { 208 Dir d, *nd; 209 Biobuf *b; 210 char buf[LEN]; 211 char *p; 212 ulong n; 213 uvlong tot; 214 215 if(vflag) 216 print("x %q %llud bytes\n", name, bytes); 217 218 b = Bopen(name, OWRITE); 219 if(!b){ 220 warn("can't make file %q: %r", name); 221 seekpast(bytes); 222 return; 223 } 224 for(tot = 0; tot < bytes; tot += n){ 225 n = sizeof buf; 226 if(tot + n > bytes) 227 n = bytes - tot; 228 n = Bread(&bin, buf, n); 229 if(n <= 0) 230 error("premature eof reading %q", name); 231 if(Bwrite(b, buf, n) != n) 232 warn("error writing %q: %r", name); 233 } 234 235 nulldir(&d); 236 p = utfrrune(name, '/'); 237 if(p) 238 p++; 239 else 240 p = name; 241 d.name = p; 242 if(uflag){ 243 d.uid = uid; 244 d.gid = gid; 245 } 246 if(Tflag) 247 d.mtime = mtime; 248 d.mode = mode; 249 Bflush(b); 250 if(dirfwstat(Bfildes(b), &d) < 0) 251 warn("can't set modes for %q: %r", name); 252 if(uflag||Tflag){ 253 if((nd = dirfstat(Bfildes(b))) == nil) 254 warn("can't reread modes for %q: %r", name); 255 else{ 256 if(Tflag && nd->mtime != mtime) 257 warn("%q: time mismatch %lud %lud\n", 258 name, mtime, nd->mtime); 259 if(uflag && strcmp(uid, nd->uid)) 260 warn("%q: uid mismatch %q %q", 261 name, uid, nd->uid); 262 if(uflag && strcmp(gid, nd->gid)) 263 warn("%q: gid mismatch %q %q", 264 name, gid, nd->gid); 265 free(nd); 266 } 267 } 268 Bterm(b); 269 } 270 271 void 272 seekpast(uvlong bytes) 273 { 274 char buf[LEN]; 275 long n; 276 uvlong tot; 277 278 for(tot = 0; tot < bytes; tot += n){ 279 n = sizeof buf; 280 if(tot + n > bytes) 281 n = bytes - tot; 282 n = Bread(&bin, buf, n); 283 if(n < 0) 284 error("premature eof"); 285 } 286 } 287 288 void 289 error(char *fmt, ...) 290 { 291 char buf[1024]; 292 va_list arg; 293 294 sprint(buf, "%q: ", argv0); 295 va_start(arg, fmt); 296 vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg); 297 va_end(arg); 298 fprint(2, "%s\n", buf); 299 exits(0); 300 } 301 302 void 303 warn(char *fmt, ...) 304 { 305 char buf[1024]; 306 va_list arg; 307 308 sprint(buf, "%q: ", argv0); 309 va_start(arg, fmt); 310 vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg); 311 va_end(arg); 312 fprint(2, "%s\n", buf); 313 } 314 315 void 316 usage(void) 317 { 318 fprint(2, "usage: mkext [-h] [-u] [-v] [-d dest-fs] [file ...]\n"); 319 exits("usage"); 320 }