summaryrefslogtreecommitdiff
path: root/utils/mkext
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
commit74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch)
treec6e220ba61db3a6ea4052e6841296d829654e664 /utils/mkext
parent46439007cf417cbd9ac8049bb4122c890097a0fa (diff)
20060303
Diffstat (limited to 'utils/mkext')
-rw-r--r--utils/mkext/mkext.c313
-rw-r--r--utils/mkext/mkfile13
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