]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/bzfs/mkext.c
merge
[plan9front.git] / sys / src / cmd / bzfs / mkext.c
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 }