1 /* 2 * bzip2-based file system. 3 * the file system itself is just a bzipped2 xzipped mkfs archive 4 * prefixed with "bzfilesystem\n" and suffixed with 5 * a kilobyte of zeros. 6 * 7 * changes to the file system are only kept in 8 * memory, not written back to the disk. 9 * 10 * this is intended for use on a floppy boot disk. 11 * we assume the file is in the dos file system and 12 * contiguous on the disk: finding it amounts to 13 * looking at the beginning of each sector for 14 * "bzfilesystem\n". then we pipe it through 15 * bunzip2 and store the files in a file tree in memory. 16 * things are slightly complicated by the fact that 17 * devfloppy requires reads to be on a 512-byte 18 * boundary and be a multiple of 512 bytes; we 19 * fork a process to relieve bunzip2 of this restriction. 20 */ 21 22 #include <u.h> 23 #include <libc.h> 24 #include <bio.h> 25 #include <auth.h> 26 #include <fcall.h> 27 #include "bzfs.h" 28 29 enum{ 30 LEN = 8*1024, 31 NFLDS = 6, /* filename, modes, uid, gid, mtime, bytes */ 32 }; 33 34 void mkdirs(char*, char*); 35 void mkdir(char*, ulong, ulong, char*, char*); 36 void extract(char*, ulong, ulong, char*, char*, ulong); 37 void seekpast(ulong); 38 void error(char*, ...); 39 void warn(char*, ...); 40 void usage(void); 41 char *mtpt; 42 Biobufhdr bin; 43 uchar binbuf[2*LEN]; 44 45 void 46 usage(void) 47 { 48 fprint(2, "usage: bzfs [-m mtpt] [-s] [-f file] [-h]\n"); 49 exits("usage"); 50 } 51 52 /* 53 * floppy disks can only be read on 512-byte 54 * boundaries and in 512 byte multiples. 55 * feed one over a pipe to allow arbitrary reading. 56 */ 57 char zero[512]; 58 int 59 blockread(int in, char *first, int nfirst) 60 { 61 int p[2], out, n, rv; 62 char blk[512]; 63 64 if(pipe(p) < 0) 65 sysfatal("pipe: %r"); 66 rv = p[0]; 67 out = p[1]; 68 switch(rfork(RFPROC|RFNOTEG|RFFDG)){ 69 case -1: 70 sysfatal("fork: %r"); 71 case 0: 72 close(rv); 73 break; 74 default: 75 close(in); 76 close(out); 77 return rv; 78 } 79 80 write(out, first, nfirst); 81 82 while((n=read(in, blk, sizeof blk)) > 0){ 83 if(write(out, blk, n) != n) 84 break; 85 if(n == sizeof(blk) && memcmp(zero, blk, n) == n) 86 break; 87 } 88 _exits(0); 89 return -1; 90 } 91 92 enum { NAMELEN = 28 }; 93 94 void 95 main(int argc, char **argv) 96 { 97 char *rargv[10]; 98 int rargc; 99 char *fields[NFLDS], name[2*LEN], *p, *namep; 100 char uid[NAMELEN], gid[NAMELEN]; 101 ulong mode, bytes, mtime; 102 char *file; 103 int i, n, stdin, fd, chatty; 104 char blk[512]; 105 106 if(argc>1 && strcmp(argv[1], "RAMFS") == 0){ 107 argv[1] = argv[0]; 108 ramfsmain(argc-1, argv+1); 109 exits(nil); 110 } 111 if(argc>1 && strcmp(argv[1], "BUNZIP") == 0){ 112 _unbzip(0, 1); 113 exits(nil); 114 } 115 116 rfork(RFNOTEG); 117 stdin = 0; 118 file = nil; 119 namep = name; 120 mtpt = "/root"; 121 chatty = 0; 122 ARGBEGIN{ 123 case 'd': 124 chatty = !chatty; 125 break; 126 case 'f': 127 file = ARGF(); 128 break; 129 case 's': 130 stdin++; 131 break; 132 case 'm': 133 mtpt = ARGF(); 134 break; 135 default: 136 usage(); 137 }ARGEND 138 139 if(argc != 0) 140 usage(); 141 142 if(file == nil) { 143 fprint(2, "must specify -f file\n"); 144 usage(); 145 } 146 147 if((fd = open(file, OREAD)) < 0) { 148 fprint(2, "cannot open \"%s\": %r\n", file); 149 exits("open"); 150 } 151 152 rargv[0] = "ramfs"; 153 rargc = 1; 154 if(stdin) 155 rargv[rargc++] = "-i"; 156 rargv[rargc++] = "-m"; 157 rargv[rargc++] = mtpt; 158 rargv[rargc] = nil; 159 ramfsmain(rargc, rargv); 160 161 if(1 || strstr(file, "disk")) { /* search for archive on block boundary */ 162 if(chatty) fprint(2, "searching for bz\n"); 163 for(i=0;; i++){ 164 if((n = readn(fd, blk, sizeof blk)) != sizeof blk) 165 sysfatal("read %d gets %d: %r\n", i, n); 166 if(strncmp(blk, "bzfilesystem\n", 13) == 0) 167 break; 168 } 169 if(chatty) fprint(2, "found at %d\n", i); 170 } 171 172 if(chdir(mtpt) < 0) 173 error("chdir %s: %r", mtpt); 174 175 fd = unbflz(unbzip(blockread(fd, blk+13, sizeof(blk)-13))); 176 177 Binits(&bin, fd, OREAD, binbuf, sizeof binbuf); 178 while(p = Brdline(&bin, '\n')){ 179 p[Blinelen(&bin)-1] = '\0'; 180 if(chatty) fprint(2, "%s\n", p); 181 if(strcmp(p, "end of archive") == 0){ 182 _exits(0); 183 } 184 if(getfields(p, fields, NFLDS, 0, " \t") != NFLDS){ 185 warn("too few fields in file header"); 186 continue; 187 } 188 strcpy(namep, fields[0]); 189 mode = strtoul(fields[1], 0, 8); 190 mtime = strtoul(fields[4], 0, 10); 191 bytes = strtoul(fields[5], 0, 10); 192 strncpy(uid, fields[2], NAMELEN); 193 strncpy(gid, fields[3], NAMELEN); 194 if(mode & DMDIR) 195 mkdir(name, mode, mtime, uid, gid); 196 else 197 extract(name, mode, mtime, uid, gid, bytes); 198 } 199 fprint(2, "premature end of archive\n"); 200 exits("premature end of archive"); 201 } 202 203 char buf[8192]; 204 205 int 206 ffcreate(char *name, ulong mode, char *uid, char *gid, ulong mtime, int length) 207 { 208 int fd, om; 209 Dir nd; 210 211 sprint(buf, "%s/%s", mtpt, name); 212 om = ORDWR; 213 if(mode&DMDIR) 214 om = OREAD; 215 if((fd = create(buf, om, (mode&DMDIR)|0666)) < 0) 216 error("create %s: %r", buf); 217 218 nulldir(&nd); 219 nd.mode = mode; 220 nd.uid = uid; 221 nd.gid = gid; 222 nd.mtime = mtime; 223 if(length) 224 nd.length = length; 225 if(dirfwstat(fd, &nd) < 0) 226 error("fwstat %s: %r", buf); 227 228 return fd; 229 } 230 231 void 232 mkdir(char *name, ulong mode, ulong mtime, char *uid, char *gid) 233 { 234 close(ffcreate(name, mode, uid, gid, mtime, 0)); 235 } 236 237 void 238 extract(char *name, ulong mode, ulong mtime, char *uid, char *gid, ulong bytes) 239 { 240 int fd, tot, n; 241 242 fd = ffcreate(name, mode, uid, gid, mtime, bytes); 243 244 for(tot = 0; tot < bytes; tot += n){ 245 n = sizeof buf; 246 if(tot + n > bytes) 247 n = bytes - tot; 248 n = Bread(&bin, buf, n); 249 if(n <= 0) 250 error("premature eof reading %s", name); 251 if(write(fd, buf, n) != n) 252 error("short write writing %s", name); 253 } 254 close(fd); 255 } 256 257 void 258 error(char *fmt, ...) 259 { 260 char buf[1024]; 261 va_list arg; 262 263 sprint(buf, "%s: ", argv0); 264 va_start(arg, fmt); 265 vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg); 266 va_end(arg); 267 fprint(2, "%s\n", buf); 268 exits(0); 269 } 270 271 void 272 warn(char *fmt, ...) 273 { 274 char buf[1024]; 275 va_list arg; 276 277 sprint(buf, "%s: ", argv0); 278 va_start(arg, fmt); 279 vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg); 280 va_end(arg); 281 fprint(2, "%s\n", buf); 282 } 283 284 int 285 _efgfmt(Fmt*) 286 { 287 return -1; 288 } 289