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