123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- enum{
- LEN = 8*1024,
- NFLDS = 6, /* filename, modes, uid, gid, mtime, bytes */
- };
- int selected(char*, int, char*[]);
- void mkdirs(char*, char*);
- void mkdir(char*, uint32_t, uint32_t, char*, char*);
- void extract(char*, uint32_t, uint32_t, char*, char*,
- uint64_t);
- void seekpast(uint64_t);
- void error(char*, ...);
- void warn(char*, ...);
- void usage(void);
- //#pragma varargck argpos warn 1
- //#pragma varargck argpos error 1
- Biobufhdr bin;
- unsigned char binbuf[2*LEN];
- char linebuf[LEN];
- int uflag;
- int hflag;
- int vflag;
- int Tflag;
- void
- main(int argc, char **argv)
- {
- Biobuf bout;
- char *fields[NFLDS], name[2*LEN], *p, *namep;
- char *uid, *gid;
- uint32_t mode, mtime;
- uint64_t bytes;
- quotefmtinstall();
- namep = name;
- ARGBEGIN{
- case 'd':
- p = ARGF();
- if(strlen(p) >= LEN)
- error("destination fs name too long\n");
- strcpy(name, p);
- namep = name + strlen(name);
- break;
- case 'h':
- hflag = 1;
- Binit(&bout, 1, OWRITE);
- break;
- case 'u':
- uflag = 1;
- Tflag = 1;
- break;
- case 'T':
- Tflag = 1;
- break;
- case 'v':
- vflag = 1;
- break;
- default:
- usage();
- }ARGEND
- Binits(&bin, 0, OREAD, binbuf, sizeof binbuf);
- while((p = Brdline(&bin, '\n')) != nil){
- p[Blinelen(&bin)-1] = '\0';
- strcpy(linebuf, p);
- p = linebuf;
- if(strcmp(p, "end of archive") == 0){
- Bterm(&bout);
- fprint(2, "done\n");
- exits(0);
- }
- if (gettokens(p, fields, NFLDS, " \t") != NFLDS){
- warn("too few fields in file header");
- continue;
- }
- p = unquotestrdup(fields[0]);
- strcpy(namep, p);
- free(p);
- mode = strtoul(fields[1], 0, 8);
- uid = fields[2];
- gid = fields[3];
- mtime = strtoul(fields[4], 0, 10);
- bytes = strtoull(fields[5], 0, 10);
- if(argc){
- if(!selected(namep, argc, argv)){
- if(bytes)
- seekpast(bytes);
- continue;
- }
- mkdirs(name, namep);
- }
- if(hflag){
- Bprint(&bout, "%q %lo %q %q %lu %llu\n",
- name, mode, uid, gid, mtime, bytes);
- if(bytes)
- seekpast(bytes);
- continue;
- }
- if(mode & DMDIR)
- mkdir(name, mode, mtime, uid, gid);
- else
- extract(name, mode, mtime, uid, gid, bytes);
- }
- fprint(2, "premature end of archive\n");
- exits("premature end of archive");
- }
- int
- fileprefix(char *prefix, char *s)
- {
- while(*prefix)
- if(*prefix++ != *s++)
- return 0;
- if(*s && *s != '/')
- return 0;
- return 1;
- }
- int
- selected(char *s, int argc, char *argv[])
- {
- int i;
- for(i=0; i<argc; i++)
- if(fileprefix(argv[i], s))
- return 1;
- return 0;
- }
- void
- mkdirs(char *name, char *namep)
- {
- char buf[2*LEN], *p;
- int fd;
- strcpy(buf, name);
- for(p = &buf[namep - name]; (p = utfrune(p, '/')) != nil; p++){
- if(p[1] == '\0')
- return;
- *p = 0;
- fd = create(buf, OREAD, 0775|DMDIR);
- close(fd);
- *p = '/';
- }
- }
- void
- mkdir(char *name, uint32_t mode, uint32_t mtime, char *uid,
- char *gid)
- {
- Dir *d, xd;
- int fd;
- char *p;
- char olderr[256];
- fd = create(name, OREAD, mode);
- if(fd < 0){
- rerrstr(olderr, sizeof(olderr));
- if((d = dirstat(name)) == nil || !(d->mode & DMDIR)){
- free(d);
- warn("can't make directory %q, mode %lo: %s", name, mode, olderr);
- return;
- }
- free(d);
- }
- close(fd);
- d = &xd;
- nulldir(d);
- p = utfrrune(name, L'/');
- if(p)
- p++;
- else
- p = name;
- d->name = p;
- if(uflag){
- d->uid = uid;
- d->gid = gid;
- }
- if(Tflag)
- d->mtime = mtime;
- d->mode = mode;
- if(dirwstat(name, d) < 0)
- warn("can't set modes for %q: %r", name);
- if(uflag||Tflag){
- if((d = dirstat(name)) == nil){
- warn("can't reread modes for %q: %r", name);
- return;
- }
- if(Tflag && d->mtime != mtime)
- warn("%q: time mismatch %lu %lu\n", name, mtime, d->mtime);
- if(uflag && strcmp(uid, d->uid))
- warn("%q: uid mismatch %q %q", name, uid, d->uid);
- if(uflag && strcmp(gid, d->gid))
- warn("%q: gid mismatch %q %q", name, gid, d->gid);
- }
- }
- void
- extract(char *name, uint32_t mode, uint32_t mtime, char *uid,
- char *gid,
- uint64_t bytes)
- {
- Dir d, *nd;
- Biobuf *b;
- char buf[LEN];
- char *p;
- uint32_t n;
- uint64_t tot;
- if(vflag)
- print("x %q %llu bytes\n", name, bytes);
- b = Bopen(name, OWRITE);
- if(!b){
- warn("can't make file %q: %r", name);
- seekpast(bytes);
- return;
- }
- for(tot = 0; tot < bytes; tot += n){
- n = sizeof buf;
- if(tot + n > bytes)
- n = bytes - tot;
- n = Bread(&bin, buf, n);
- if(n <= 0)
- error("premature eof reading %q", name);
- if(Bwrite(b, buf, n) != n)
- warn("error writing %q: %r", name);
- }
- nulldir(&d);
- p = utfrrune(name, '/');
- if(p)
- p++;
- else
- p = name;
- d.name = p;
- if(uflag){
- d.uid = uid;
- d.gid = gid;
- }
- if(Tflag)
- d.mtime = mtime;
- d.mode = mode;
- Bflush(b);
- if(dirfwstat(Bfildes(b), &d) < 0)
- warn("can't set modes for %q: %r", name);
- if(uflag||Tflag){
- if((nd = dirfstat(Bfildes(b))) == nil)
- warn("can't reread modes for %q: %r", name);
- else{
- if(Tflag && nd->mtime != mtime)
- warn("%q: time mismatch %lu %lu\n",
- name, mtime, nd->mtime);
- if(uflag && strcmp(uid, nd->uid))
- warn("%q: uid mismatch %q %q",
- name, uid, nd->uid);
- if(uflag && strcmp(gid, nd->gid))
- warn("%q: gid mismatch %q %q",
- name, gid, nd->gid);
- free(nd);
- }
- }
- Bterm(b);
- }
- void
- seekpast(uint64_t bytes)
- {
- char buf[LEN];
- int32_t n;
- uint64_t tot;
- for(tot = 0; tot < bytes; tot += n){
- n = sizeof buf;
- if(tot + n > bytes)
- n = bytes - tot;
- n = Bread(&bin, buf, n);
- if(n < 0)
- error("premature eof");
- }
- }
- void
- error(char *fmt, ...)
- {
- char buf[1024];
- va_list arg;
- sprint(buf, "%q: ", argv0);
- va_start(arg, fmt);
- vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
- va_end(arg);
- fprint(2, "%s\n", buf);
- exits(0);
- }
- void
- warn(char *fmt, ...)
- {
- char buf[1024];
- va_list arg;
- sprint(buf, "%q: ", argv0);
- va_start(arg, fmt);
- vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
- va_end(arg);
- fprint(2, "%s\n", buf);
- }
- void
- usage(void)
- {
- fprint(2, "usage: mkext [-h] [-u] [-v] [-d dest-fs] [file ...]\n");
- exits("usage");
- }
|