From 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a Mon Sep 17 00:00:00 2001 From: "Charles.Forsyth" Date: Fri, 22 Dec 2006 21:39:35 +0000 Subject: 20060303 --- utils/mkext/mkext.c | 313 ++++++++++++++++++++++++++++++++++++++++++++++++++++ utils/mkext/mkfile | 13 +++ 2 files changed, 326 insertions(+) create mode 100644 utils/mkext/mkext.c create mode 100644 utils/mkext/mkfile (limited to 'utils/mkext') 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 +#include + +#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; imode & 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 -- cgit v1.2.3