diff options
Diffstat (limited to 'utils/mkext')
| -rw-r--r-- | utils/mkext/mkext.c | 313 | ||||
| -rw-r--r-- | utils/mkext/mkfile | 13 |
2 files changed, 326 insertions, 0 deletions
diff --git a/utils/mkext/mkext.c b/utils/mkext/mkext.c new file mode 100644 index 00000000..3361a23b --- /dev/null +++ b/utils/mkext/mkext.c @@ -0,0 +1,313 @@ +#include <lib9.h> +#include <bio.h> + +#define dirfwstat(b,d) 0 /* lib9 doesn't implement it */ +#define mkdir extmkdir + +enum{ + LEN = 8*1024, + NFLDS = 6, /* filename, modes, uid, gid, mtime, bytes */ +}; + +int selected(char*, int, char*[]); +void mkdirs(char*, char*); +void mkdir(char*, ulong, ulong, char*, char*); +void extract(char*, ulong, ulong, char*, char*, ulong); +void seekpast(ulong); +void error(char*, ...); +void warn(char*, ...); +void usage(void); +#pragma varargck argpos warn 1 +#pragma varargck argpos error 1 + +Biobuf bin; +uchar 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; + ulong mode, bytes, mtime; + + setbinmode(); + 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')){ + 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(getfields(p, fields, NFLDS, 0, " \t") != NFLDS){ + warn("too few fields in file header"); + continue; + } + strcpy(namep, fields[0]); + mode = strtoul(fields[1], 0, 8); + uid = fields[2]; + gid = fields[3]; + mtime = strtoul(fields[4], 0, 10); + bytes = strtoul(fields[5], 0, 10); + if(argc){ + if(!selected(namep, argc, argv)){ + if(bytes) + seekpast(bytes); + continue; + } + mkdirs(name, namep); + } + if(hflag){ + Bprint(&bout, "%q %luo %q %q %lud %lud\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, '/'); p++){ + if(p[1] == '\0') + return; + *p = 0; + fd = create(buf, OREAD, 0775|DMDIR); + close(fd); + *p = '/'; + } +} + +void +mkdir(char *name, ulong mode, ulong 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 %luo: %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 %lud %lud\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, ulong mode, ulong mtime, char *uid, char *gid, ulong bytes) +{ + Dir d, *nd; + Biobuf *b; + char buf[LEN]; + char *p; + ulong n, tot; + + if(vflag) + print("x %q %lud 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 %lud %lud\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(ulong bytes) +{ + char buf[LEN]; + ulong tot, n; + + 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"); +} diff --git a/utils/mkext/mkfile b/utils/mkext/mkfile new file mode 100644 index 00000000..a8b4caad --- /dev/null +++ b/utils/mkext/mkfile @@ -0,0 +1,13 @@ +<../../mkconfig + +TARG=mkext + +OFILES= mkext.$O\ + +HFILES= + +LIBS=bio 9 + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE |
