/* * 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 <auth.h>#include <bio.h> enum{ LEN = 8*1024, HUNKS = 128, /* * types of destination file sytems */ Kfs = 0, Fs, Archive,}; typedef struct File File; struct File{ char *new; char *elem; char *old; char *uid; char *gid; ulong mode;}; void arch(Dir*);void copy(Dir*);int copyfile(File*, Dir*, int);void* emalloc(ulong);void error(char *, ...);void freefile(File*);File* getfile(File*);char* getmode(char*, ulong*);char* getname(char*, char**);char* getpath(char*);void kfscmd(char *);void mkdir(Dir*);int mkfile(File*);void mkfs(File*, int);char* mkpath(char*, char*);void mktree(File*, int);void mountkfs(char*);void printfile(File*);void setnames(File*);void setusers(void);void skipdir(void);char* strdup(char*);int uptodate(Dir*, char*);void usage(void);void warn(char *, ...); Biobuf *b;Biobufhdr bout; /* stdout when writing archive */uchar boutbuf[2*LEN];char newfile[LEN];char oldfile[LEN];char *proto;char *cputype;char *users;char *oldroot;char *newroot;char *prog = "mkfs";int lineno;char *buf;char *zbuf;int buflen = 1024-8;int indent;int verb;int modes;int ream;int debug;int xflag;int sfd;int fskind; /* Kfs, Fs, Archive */int setuid; /* on Fs: set uid and gid? */char *user; voidmain(int argc, char **argv){ File file; char *name; int i, errs; quotefmtinstall(); user = getuser(); name = ""; memset(&file, 0, sizeof file); file.new = ""; file.old = 0; oldroot = ""; newroot = "/n/kfs"; users = 0; fskind = Kfs; ARGBEGIN{ case 'a': if(fskind != Kfs) { fprint(2, "cannot use -a with -d\n"); usage(); } fskind = Archive; newroot = ""; Binits(&bout, 1, OWRITE, boutbuf, sizeof boutbuf); break; case 'd': if(fskind != Kfs) { fprint(2, "cannot use -d with -a\n"); usage(); } fskind = Fs; newroot = ARGF(); break; case 'D': debug = 1; break; case 'n': name = EARGF(usage()); break; case 'p': modes = 1; break; case 'r': ream = 1; break; case 's': oldroot = ARGF(); break; case 'u': users = ARGF(); break; case 'U': setuid = 1; break; case 'v': verb = 1; break; case 'x': xflag = 1; break; case 'z': buflen = atoi(ARGF())-8; break; default: usage(); }ARGEND if(!argc) usage(); buf = emalloc(buflen); zbuf = emalloc(buflen); memset(zbuf, 0, buflen); mountkfs(name); kfscmd("allow"); proto = "users"; setusers(); cputype = getenv("cputype"); if(cputype == 0) cputype = "68020"; errs = 0; for(i = 0; i < argc; i++){ proto = argv[i]; fprint(2, "processing %q\n", proto); b = Bopen(proto, OREAD); if(!b){ fprint(2, "%q: can't open %q: skipping\n", prog, proto); errs++; continue; } lineno = 0; indent = 0; mkfs(&file, -1); Bterm(b); } fprint(2, "file system made\n"); kfscmd("disallow"); kfscmd("sync"); if(errs) exits("skipped protos"); if(fskind == Archive){ Bprint(&bout, "end of archive\n"); Bterm(&bout); } exits(0);} voidmkfs(File *me, int level){ File *child; int rec; child = getfile(me); if(!child) return; if((child->elem[0] == '+' || child->elem[0] == '*') && child->elem[1] == '\0'){ rec = child->elem[0] == '+'; free(child->new); child->new = strdup(me->new); setnames(child); mktree(child, rec); freefile(child); child = getfile(me); } while(child && indent > level){ if(mkfile(child)) mkfs(child, indent); freefile(child); child = getfile(me); } if(child){ freefile(child); Bseek(b, -Blinelen(b), 1); lineno--; }} voidmktree(File *me, int rec){ File child; Dir *d; int i, n, fd; fd = open(oldfile, OREAD); if(fd < 0){ warn("can't open %q: %r", oldfile); return; } child = *me; while((n = dirread(fd, &d)) > 0){ for(i = 0; i < n; i++){ child.new = mkpath(me->new, d[i].name); if(me->old) child.old = mkpath(me->old, d[i].name); child.elem = d[i].name; setnames(&child); if(copyfile(&child, &d[i], 1) && rec) mktree(&child, rec); free(child.new); if(child.old) free(child.old); } } close(fd);} intmkfile(File *f){ Dir *dir; if((dir = dirstat(oldfile)) == nil){ warn("can't stat file %q: %r", oldfile); skipdir(); return 0; } return copyfile(f, dir, 0);} intcopyfile(File *f, Dir *d, int permonly){ ulong mode; Dir nd; if(xflag){ Bprint(&bout, "%q\t%ld\t%lld\n", f->new, d->mtime, d->length); return (d->mode & DMDIR) != 0; } if(verb && (fskind == Archive || ream)) fprint(2, "%q\n", f->new); d->name = f->elem; if(d->type != 'M'){ d->uid = "sys"; d->gid = "sys"; mode = (d->mode >> 6) & 7; d->mode |= mode | (mode << 3); } if(strcmp(f->uid, "-") != 0) d->uid = f->uid; if(strcmp(f->gid, "-") != 0) d->gid = f->gid; if(fskind == Fs && !setuid){ d->uid = ""; d->gid = ""; } if(f->mode != ~0){ if(permonly) d->mode = (d->mode & ~0666) | (f->mode & 0666); else if((d->mode&DMDIR) != (f->mode&DMDIR)) warn("inconsistent mode for %q", f->new); else d->mode = f->mode; } if(!uptodate(d, newfile)){ if(verb && (fskind != Archive && ream == 0)) fprint(2, "%q\n", f->new); if(d->mode & DMDIR) mkdir(d); else copy(d); }else if(modes){ nulldir(&nd); nd.mode = d->mode; nd.gid = d->gid; nd.mtime = d->mtime; if(verb && (fskind != Archive && ream == 0)) fprint(2, "%q\n", f->new); if(dirwstat(newfile, &nd) < 0) warn("can't set modes for %q: %r", f->new); nulldir(&nd); nd.uid = d->uid; dirwstat(newfile, &nd); } return (d->mode & DMDIR) != 0;} /* * check if file to is up to date with * respect to the file represented by df */intuptodate(Dir *df, char *to){ int ret; Dir *dt; if(fskind == Archive || ream || (dt = dirstat(to)) == nil) return 0; ret = dt->mtime >= df->mtime; free(dt); return ret;} voidcopy(Dir *d){ char cptmp[LEN], *p; int f, t, n, needwrite, nowarnyet = 1; vlong tot, len; Dir nd; f = open(oldfile, OREAD); if(f < 0){ warn("can't open %q: %r", oldfile); return; } t = -1; if(fskind == Archive) arch(d); else{ strcpy(cptmp, newfile); p = utfrrune(cptmp, L'/'); if(!p) error("internal temporary file error"); strcpy(p+1, "__mkfstmp"); t = create(cptmp, OWRITE, 0666); if(t < 0){ warn("can't create %q: %r", newfile); close(f); return; } } needwrite = 0; for(tot = 0; tot < d->length; tot += n){ len = d->length - tot; /* don't read beyond d->length */ if (len > buflen) len = buflen; n = read(f, buf, len); if(n <= 0) { if(n < 0 && nowarnyet) { warn("can't read %q: %r", oldfile); nowarnyet = 0; } /* * don't quit: pad to d->length (in pieces) to agree * with the length in the header, already emitted. */ memset(buf, 0, len); n = len; } if(fskind == Archive){ if(Bwrite(&bout, buf, n) != n) error("write error: %r"); }else if(memcmp(buf, zbuf, n) == 0){ if(seek(t, n, 1) < 0) error("can't write zeros to %q: %r", newfile); needwrite = 1; }else{ if(write(t, buf, n) < n) error("can't write %q: %r", newfile); needwrite = 0; } } close(f); if(needwrite){ if(seek(t, -1, 1) < 0 || write(t, zbuf, 1) != 1) error("can't write zero at end of %q: %r", newfile); } if(tot != d->length){ /* this should no longer happen */ warn("wrong number of bytes written to %q (was %lld should be %lld)\n", newfile, tot, d->length); if(fskind == Archive){ warn("seeking to proper position\n"); /* does no good if stdout is a pipe */ Bseek(&bout, d->length - tot, 1); } } if(fskind == Archive) return; remove(newfile); nulldir(&nd); nd.mode = d->mode; nd.gid = d->gid; nd.mtime = d->mtime; nd.name = d->name; if(dirfwstat(t, &nd) < 0) error("can't move tmp file to %q: %r", newfile); nulldir(&nd); nd.uid = d->uid; dirfwstat(t, &nd); close(t);} voidmkdir(Dir *d){ Dir *d1; Dir nd; int fd; if(fskind == Archive){ arch(d); return; } fd = create(newfile, OREAD, d->mode); nulldir(&nd); nd.mode = d->mode; nd.gid = d->gid; nd.mtime = d->mtime; if(fd < 0){ if((d1 = dirstat(newfile)) == nil || !(d1->mode & DMDIR)){ free(d1); error("can't create %q", newfile); } free(d1); if(dirwstat(newfile, &nd) < 0) warn("can't set modes for %q: %r", newfile); nulldir(&nd); nd.uid = d->uid; dirwstat(newfile, &nd); return; } if(dirfwstat(fd, &nd) < 0) warn("can't set modes for %q: %r", newfile); nulldir(&nd); nd.uid = d->uid; dirfwstat(fd, &nd); close(fd);} voidarch(Dir *d){ Bprint(&bout, "%q %luo %q %q %lud %lld\n", newfile, d->mode, d->uid, d->gid, d->mtime, d->length);} char *mkpath(char *prefix, char *elem){ char *p; int n; n = strlen(prefix) + strlen(elem) + 2; p = emalloc(n); sprint(p, "%s/%s", prefix, elem); return p;}Lines 1–500 of 867. Load more
/* * 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 <auth.h> #include <bio.h> enum{ LEN = 8*1024, HUNKS = 128, /* * types of destination file sytems */ Kfs = 0, Fs, Archive, }; typedef struct File File; struct File{ char *new; char *elem; char *old; char *uid; char *gid; ulong mode; }; void arch(Dir*); void copy(Dir*); int copyfile(File*, Dir*, int); void* emalloc(ulong); void error(char *, ...); void freefile(File*); File* getfile(File*); char* getmode(char*, ulong*); char* getname(char*, char**); char* getpath(char*); void kfscmd(char *); void mkdir(Dir*); int mkfile(File*); void mkfs(File*, int); char* mkpath(char*, char*); void mktree(File*, int); void mountkfs(char*); void printfile(File*); void setnames(File*); void setusers(void); void skipdir(void); char* strdup(char*); int uptodate(Dir*, char*); void usage(void); void warn(char *, ...); Biobuf *b; Biobufhdr bout; /* stdout when writing archive */ uchar boutbuf[2*LEN]; char newfile[LEN]; char oldfile[LEN]; char *proto; char *cputype; char *users; char *oldroot; char *newroot; char *prog = "mkfs"; int lineno; char *buf; char *zbuf; int buflen = 1024-8; int indent; int verb; int modes; int ream; int debug; int xflag; int sfd; int fskind; /* Kfs, Fs, Archive */ int setuid; /* on Fs: set uid and gid? */ char *user; void main(int argc, char **argv) { File file; char *name; int i, errs; quotefmtinstall(); user = getuser(); name = ""; memset(&file, 0, sizeof file); file.new = ""; file.old = 0; oldroot = ""; newroot = "/n/kfs"; users = 0; fskind = Kfs; ARGBEGIN{ case 'a': if(fskind != Kfs) { fprint(2, "cannot use -a with -d\n"); usage(); } fskind = Archive; newroot = ""; Binits(&bout, 1, OWRITE, boutbuf, sizeof boutbuf); break; case 'd': if(fskind != Kfs) { fprint(2, "cannot use -d with -a\n"); usage(); } fskind = Fs; newroot = ARGF(); break; case 'D': debug = 1; break; case 'n': name = EARGF(usage()); break; case 'p': modes = 1; break; case 'r': ream = 1; break; case 's': oldroot = ARGF(); break; case 'u': users = ARGF(); break; case 'U': setuid = 1; break; case 'v': verb = 1; break; case 'x': xflag = 1; break; case 'z': buflen = atoi(ARGF())-8; break; default: usage(); }ARGEND if(!argc) usage(); buf = emalloc(buflen); zbuf = emalloc(buflen); memset(zbuf, 0, buflen); mountkfs(name); kfscmd("allow"); proto = "users"; setusers(); cputype = getenv("cputype"); if(cputype == 0) cputype = "68020"; errs = 0; for(i = 0; i < argc; i++){ proto = argv[i]; fprint(2, "processing %q\n", proto); b = Bopen(proto, OREAD); if(!b){ fprint(2, "%q: can't open %q: skipping\n", prog, proto); errs++; continue; } lineno = 0; indent = 0; mkfs(&file, -1); Bterm(b); } fprint(2, "file system made\n"); kfscmd("disallow"); kfscmd("sync"); if(errs) exits("skipped protos"); if(fskind == Archive){ Bprint(&bout, "end of archive\n"); Bterm(&bout); } exits(0); } void mkfs(File *me, int level) { File *child; int rec; child = getfile(me); if(!child) return; if((child->elem[0] == '+' || child->elem[0] == '*') && child->elem[1] == '\0'){ rec = child->elem[0] == '+'; free(child->new); child->new = strdup(me->new); setnames(child); mktree(child, rec); freefile(child); child = getfile(me); } while(child && indent > level){ if(mkfile(child)) mkfs(child, indent); freefile(child); child = getfile(me); } if(child){ freefile(child); Bseek(b, -Blinelen(b), 1); lineno--; } } void mktree(File *me, int rec) { File child; Dir *d; int i, n, fd; fd = open(oldfile, OREAD); if(fd < 0){ warn("can't open %q: %r", oldfile); return; } child = *me; while((n = dirread(fd, &d)) > 0){ for(i = 0; i < n; i++){ child.new = mkpath(me->new, d[i].name); if(me->old) child.old = mkpath(me->old, d[i].name); child.elem = d[i].name; setnames(&child); if(copyfile(&child, &d[i], 1) && rec) mktree(&child, rec); free(child.new); if(child.old) free(child.old); } } close(fd); } int mkfile(File *f) { Dir *dir; if((dir = dirstat(oldfile)) == nil){ warn("can't stat file %q: %r", oldfile); skipdir(); return 0; } return copyfile(f, dir, 0); } int copyfile(File *f, Dir *d, int permonly) { ulong mode; Dir nd; if(xflag){ Bprint(&bout, "%q\t%ld\t%lld\n", f->new, d->mtime, d->length); return (d->mode & DMDIR) != 0; } if(verb && (fskind == Archive || ream)) fprint(2, "%q\n", f->new); d->name = f->elem; if(d->type != 'M'){ d->uid = "sys"; d->gid = "sys"; mode = (d->mode >> 6) & 7; d->mode |= mode | (mode << 3); } if(strcmp(f->uid, "-") != 0) d->uid = f->uid; if(strcmp(f->gid, "-") != 0) d->gid = f->gid; if(fskind == Fs && !setuid){ d->uid = ""; d->gid = ""; } if(f->mode != ~0){ if(permonly) d->mode = (d->mode & ~0666) | (f->mode & 0666); else if((d->mode&DMDIR) != (f->mode&DMDIR)) warn("inconsistent mode for %q", f->new); else d->mode = f->mode; } if(!uptodate(d, newfile)){ if(verb && (fskind != Archive && ream == 0)) fprint(2, "%q\n", f->new); if(d->mode & DMDIR) mkdir(d); else copy(d); }else if(modes){ nulldir(&nd); nd.mode = d->mode; nd.gid = d->gid; nd.mtime = d->mtime; if(verb && (fskind != Archive && ream == 0)) fprint(2, "%q\n", f->new); if(dirwstat(newfile, &nd) < 0) warn("can't set modes for %q: %r", f->new); nulldir(&nd); nd.uid = d->uid; dirwstat(newfile, &nd); } return (d->mode & DMDIR) != 0; } /* * check if file to is up to date with * respect to the file represented by df */ int uptodate(Dir *df, char *to) { int ret; Dir *dt; if(fskind == Archive || ream || (dt = dirstat(to)) == nil) return 0; ret = dt->mtime >= df->mtime; free(dt); return ret; } void copy(Dir *d) { char cptmp[LEN], *p; int f, t, n, needwrite, nowarnyet = 1; vlong tot, len; Dir nd; f = open(oldfile, OREAD); if(f < 0){ warn("can't open %q: %r", oldfile); return; } t = -1; if(fskind == Archive) arch(d); else{ strcpy(cptmp, newfile); p = utfrrune(cptmp, L'/'); if(!p) error("internal temporary file error"); strcpy(p+1, "__mkfstmp"); t = create(cptmp, OWRITE, 0666); if(t < 0){ warn("can't create %q: %r", newfile); close(f); return; } } needwrite = 0; for(tot = 0; tot < d->length; tot += n){ len = d->length - tot; /* don't read beyond d->length */ if (len > buflen) len = buflen; n = read(f, buf, len); if(n <= 0) { if(n < 0 && nowarnyet) { warn("can't read %q: %r", oldfile); nowarnyet = 0; } /* * don't quit: pad to d->length (in pieces) to agree * with the length in the header, already emitted. */ memset(buf, 0, len); n = len; } if(fskind == Archive){ if(Bwrite(&bout, buf, n) != n) error("write error: %r"); }else if(memcmp(buf, zbuf, n) == 0){ if(seek(t, n, 1) < 0) error("can't write zeros to %q: %r", newfile); needwrite = 1; }else{ if(write(t, buf, n) < n) error("can't write %q: %r", newfile); needwrite = 0; } } close(f); if(needwrite){ if(seek(t, -1, 1) < 0 || write(t, zbuf, 1) != 1) error("can't write zero at end of %q: %r", newfile); } if(tot != d->length){ /* this should no longer happen */ warn("wrong number of bytes written to %q (was %lld should be %lld)\n", newfile, tot, d->length); if(fskind == Archive){ warn("seeking to proper position\n"); /* does no good if stdout is a pipe */ Bseek(&bout, d->length - tot, 1); } } if(fskind == Archive) return; remove(newfile); nulldir(&nd); nd.mode = d->mode; nd.gid = d->gid; nd.mtime = d->mtime; nd.name = d->name; if(dirfwstat(t, &nd) < 0) error("can't move tmp file to %q: %r", newfile); nulldir(&nd); nd.uid = d->uid; dirfwstat(t, &nd); close(t); } void mkdir(Dir *d) { Dir *d1; Dir nd; int fd; if(fskind == Archive){ arch(d); return; } fd = create(newfile, OREAD, d->mode); nulldir(&nd); nd.mode = d->mode; nd.gid = d->gid; nd.mtime = d->mtime; if(fd < 0){ if((d1 = dirstat(newfile)) == nil || !(d1->mode & DMDIR)){ free(d1); error("can't create %q", newfile); } free(d1); if(dirwstat(newfile, &nd) < 0) warn("can't set modes for %q: %r", newfile); nulldir(&nd); nd.uid = d->uid; dirwstat(newfile, &nd); return; } if(dirfwstat(fd, &nd) < 0) warn("can't set modes for %q: %r", newfile); nulldir(&nd); nd.uid = d->uid; dirfwstat(fd, &nd); close(fd); } void arch(Dir *d) { Bprint(&bout, "%q %luo %q %q %lud %lld\n", newfile, d->mode, d->uid, d->gid, d->mtime, d->length); } char * mkpath(char *prefix, char *elem) { char *p; int n; n = strlen(prefix) + strlen(elem) + 2; p = emalloc(n); sprint(p, "%s/%s", prefix, elem); return p; }