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