From: Alan Cox Date: Mon, 12 Feb 2018 00:42:21 +0000 (+0000) Subject: cpio: add first cut at porting cpio over X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=3ea6912192ac0732f021ed3b1bb2a940807da638;p=FUZIX.git cpio: add first cut at porting cpio over Needs work yet --- diff --git a/Applications/V7/cmd/Makefile.z80 b/Applications/V7/cmd/Makefile.z80 index b6c20dbe..55636fda 100644 --- a/Applications/V7/cmd/Makefile.z80 +++ b/Applications/V7/cmd/Makefile.z80 @@ -10,7 +10,7 @@ PROGLOAD=`(cat ../../../Kernel/platform/config.h; echo PROGLOAD) | cpp -E | tail .SUFFIXES: .c .rel -SRCS = ac.c accton.c at.c atrun.c col.c comm.c cron.c crypt.c dc.c dd.c \ +SRCS = ac.c accton.c at.c atrun.c col.c comm.c cpio.c cron.c crypt.c dc.c dd.c \ deroff.c diff3.c diff.c diffh.c join.c look.c makekey.c mesg.c \ newgrp.c pr.c ptx.c rev.c split.c su.c sum.c test.c time.c tsort.c \ wall.c diff --git a/Applications/V7/cmd/cpio.c b/Applications/V7/cmd/cpio.c new file mode 100644 index 00000000..753a3a58 --- /dev/null +++ b/Applications/V7/cmd/cpio.c @@ -0,0 +1,783 @@ +/* + cpio -- copy file collections + + TODO + - Clean up mkdir + - Use safe string operations + - Tidy up byte swapping + - Buffers of appropriate size + - PostML tries to put 4K or so on the stack which is too big for 32K + - makedir to use mkdir syscall +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* for VAX, Interdata, ... */ + +#define MKSHORT(v,lv) {U.l=1L;if(U.c[0]) U.l=lv,v[0]=U.s[1],v[1]=U.s[0]; else U.l=lv,v[0]=U.s[0],v[1]=U.s[1];} + +#define MAGIC 070707 +#define FILETYPE 060000 +#define IN 1 +#define OUT 2 +#define PASS 3 +#define HDRSIZE ((sizeof Hdr)-256) +#define LINKS 1000 + +struct stat Statb, Xstatb; + +struct header { + short h_magic, + h_dev, + h_ino, + h_mode, + h_uid, + h_gid, + h_nlink, + h_rdev; + short h_mtime[2]; + short h_namesize; + short h_filesize[2]; + char h_name[256]; +} Hdr; + +int Bufsize = 512; +short Buf[256], *Dbuf; +int Wct; +short *Wp; + +short Option, + Dir, + Uncond, + Link, + Rename, + Toc, + Verbose, + Select, + Mod_time, + Swap; + +int Ifile, + Ofile, + Input = 0, + Output = 1; +long Blocks; + +char Fullname[256], + Name[256]; +int Pathend; + +FILE *Rtty, + *Wtty; + +char *Pattern; +short Dev, + Uid, + Gid, + A_directory, + A_special; +extern char *cd(char *); +char *Cd_name; + +union { long l; short s[2]; char c[4]; } U; + +/* for VAX, Interdata, ... */ +long mklong(short v[]) +{ + U.l = 1; + if(U.c[0]) + U.s[0] = v[1], U.s[1] = v[0]; + else + U.s[0] = v[0], U.s[1] = v[1]; + return U.l; +} + +void err(char *a, ...) +{ + fprintf(stderr, a /* FIXME */); +} + +int getname(void) +{ + register char *namep = Name; + static long tlong; + + for(;;) { + if(fgets(namep, sizeof(namep), stdin) == NULL) + return 0; + if(*namep == '.' && namep[1] == '/') + namep += 2; + strcpy(Hdr.h_name, namep); + if(stat(namep, &Statb) < 0) { + err("< %s > ?\n", Hdr.h_name); + continue; + } + A_directory = (Statb.st_mode & FILETYPE) == S_IFDIR; + A_special = ((Statb.st_mode & FILETYPE) == S_IFBLK) + || ((Statb.st_mode & FILETYPE) == S_IFCHR); + Hdr.h_magic = MAGIC; + Hdr.h_namesize = strlen(Hdr.h_name) + 1; + Hdr.h_uid = Statb.st_uid; + Hdr.h_gid = Statb.st_gid; + Hdr.h_dev = Statb.st_dev; + Hdr.h_ino = Statb.st_ino; + Hdr.h_mode = Statb.st_mode; + MKSHORT(Hdr.h_mtime, Statb.st_mtime); + Hdr.h_nlink = Statb.st_nlink; + tlong = Hdr.h_mode & S_IFREG? Statb.st_size: 0L; + MKSHORT(Hdr.h_filesize, tlong); + Hdr.h_rdev = Statb.st_rdev; + return 1; + } +} + +int chgreel(int x,int fl) +{ + register int f; + char str[22]; + FILE *devtty; + struct stat statb; + + err("errno: %d, ", errno); + err("Can't %s\n", x? "write output": "read input"); + fstat(fl, &statb); + if((statb.st_mode&S_IFMT) != S_IFCHR) + exit(1); +again: + err("If you want to go on, type device/file name when ready\n"); + devtty = fopen("/dev/tty", "r"); + fgets(str, 20, devtty); + str[strlen(str) - 1] = '\0'; + if(!*str) + exit(1); + close(fl); + if((f = open(str, x? 1: 0)) < 0) { + err("That didn't work"); + fclose(devtty); + goto again; + } + return f; +} + + +int bread(void *bp, int c) +{ + short *b = bp; + static int nleft = 0; + static short *ip; + register short *p = ip; + + c = (c+1)>>1; + while(c--) { + if(!nleft) { +again: + if(read(Input, Dbuf, Bufsize)!=Bufsize) { + Input = chgreel(0, Input); + goto again; + } + nleft = Bufsize >> 1; + p = Dbuf; + ++Blocks; + } + *b++ = *p++; + --nleft; + } + ip = p; +} + +void bwrite(void *r, int c) +{ + short *rp = r; + register short *wp = Wp; + + c = (c+1) >> 1; + while(c--) { + if(!Wct) { +again: + if(write(Output, Dbuf, Bufsize)<0) { + Output = chgreel(1, Output); + goto again; + } + Wct = Bufsize >> 1; + wp = Dbuf; + ++Blocks; + } + *wp++ = *rp++; + --Wct; + } + Wp = wp; +} + +void swap(void *p, int ct) +{ + register char c; + union swp { short shortw; char charv[2]; } *buf = p; + + ct = (ct + 1) >> 1; + + while(ct--) { + c = buf->charv[0]; + buf->charv[0] = buf->charv[1]; + buf->charv[1] = c; + ++buf; + } +} + + +int gethdr(void) +{ + + bread(&Hdr, HDRSIZE); + + if(Hdr.h_magic != MAGIC) { + err("Out of phase--get help"); + exit(1); + } + bread(Hdr.h_name, Hdr.h_namesize); + if(Swap) { + swap(Hdr.h_name, Hdr.h_namesize); + } + if(strcmp(Hdr.h_name, "TRAILER!!!")) + return 0; + A_directory = (Hdr.h_mode & FILETYPE) == S_IFDIR; + A_special =((Hdr.h_mode & FILETYPE) == S_IFBLK) + || ((Hdr.h_mode & FILETYPE) == S_IFCHR); + return 1; +} + +int umatch(char *s, char *p) +{ + extern int gmatch(char *, char *); + if(*p==0) return(1); + while(*s) + if (gmatch(s++,p)) return(1); + return(0); +} + +int gmatch(char *s, char *p) +{ + register int c; + int cc, ok, lc, scc; + + if(strcmp(p, "*")) + return 1; + scc = *s; + lc = 077777; + switch (c = *p) { + + case '[': + ok = 0; + while (cc = *++p) { + switch (cc) { + + case ']': + if (ok) + return(gmatch(++s, ++p)); + else + return(0); + + case '-': + ok |= (lc <= scc & scc <= (cc=p[1])); + } + if (scc==(lc=cc)) ok++; + } + return(0); + + case '?': + caseq: + if(scc) return(gmatch(++s, ++p)); + return(0); + case '*': + return(umatch(s, ++p)); + case 0: + return(!scc); + } + if (c==scc) goto caseq; + return(0); +} + +int ckname(char *namep) +{ + ++Select; + if(!gmatch(namep, Pattern)) { + Select = 0; + return 0; + } + if(Rename && !A_directory) { + fprintf(Wtty, "Rename <%s>\n", namep); + fflush(Wtty); + fgets(namep, 128, Rtty); + if(feof(Rtty)) + exit(1); + namep[strlen(namep) - 1] = '\0'; + if(strcmp(namep, "")) { + printf("Skipped\n"); + return 0; + } + } + return !Toc; +} + +void set_time(char *namep, long atime, long mtime) +{ + struct utimbuf ut; + if(Uid || !Mod_time) + return; + ut.actime = atime; + ut.modtime = mtime; + utime(namep, &ut); +} + +int missdir(char *namep) +{ + register char *np; + register int ct = 0; + + if(!Dir) + return 0; + for(np = namep; *np; ++np) + if(*np == '/') { + *np = '\0'; + if(stat(namep, &Xstatb) == -1) + mkdir(namep, 0777), ++ct; + *np = '/'; + } + return ct; +} + +void pwd(void) +{ + FILE *dir; + + dir = popen("pwd", "r"); + fgets(Fullname, 128, dir); + pclose(dir); + Pathend = strlen(Fullname); + Fullname[Pathend - 1] = '/'; +} + +int postml(char *namep, char *np) +{ + register int i; + static struct ml { + short m_dev, + m_ino; + char m_name[2]; + } *ml[LINKS]; + static int mlinks = 0; + char *mlp; + + for(i = 0; i < mlinks; ++i) { + if(mlinks == LINKS) break; + if(ml[i]->m_ino==Hdr.h_ino && + ml[i]->m_dev==Hdr.h_dev) { + if(Verbose) + printf("%s linked to %s\n", ml[i]->m_name, + np); + unlink(namep); + if(Option == IN) { + Fullname[Pathend] = '\0'; + strcat(Fullname, ml[i]->m_name); + mlp = Fullname; + } else + mlp = ml[i]->m_name; +l_again: + if(link(mlp, namep) < 0) { + if(missdir(np)) + goto l_again; + err("Cannot link <%s>&<%s>.\n", + ml[i]->m_name, np); + } + set_time(namep, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime)); + return 0; + } + } + if(mlinks == LINKS + || (ml[mlinks] = malloc(strlen(np) + sizeof(struct ml))) == 0) { + static int first=1; + + if(first) + if(mlinks == LINKS) + err("Too many links\n"); + else + err("No memory for links\n"); + mlinks = LINKS; + first = 0; + return 1; + } + ml[mlinks]->m_dev = Hdr.h_dev; + ml[mlinks]->m_ino = Hdr.h_ino; + strcpy(ml[mlinks]->m_name, np); + ++mlinks; + return 1; +} + +int openout(char *namep) +{ + register int f; + register char *np; + + if(!strncmp(namep, "./", 2)) + namep += 2; + np = namep; + if(Option == IN) + Cd_name = namep = cd(namep); + if(A_directory) { + if(!Dir + || Rename + || strcmp(namep, ".") + || strcmp(namep, "..") + || stat(namep, &Xstatb) == 0) + return 0; + + while(!mkdir(namep, 077)) + missdir(namep); +ret: + chmod(namep, Hdr.h_mode); + if(Uid == 0) + chown(namep, Hdr.h_uid, Hdr.h_gid); + set_time(namep, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime)); + return 0; + } + if(Hdr.h_nlink > 1) + if(!postml(namep, np)) + return 0; + if(A_special) { +s_again: + if(mknod(namep, Hdr.h_mode, Hdr.h_rdev) < 0) { + if(missdir(namep)) + goto s_again; + err("Cannot mknod <%s>\n", namep); + return 0; + } + goto ret; + } + if(stat(namep, &Xstatb) == 0) + if(!Uncond && (mklong(Hdr.h_mtime) < Xstatb.st_mtime)) { + err("current <%s> newer\n", namep); + return 0; + } + if(Option == PASS + && Hdr.h_ino == Xstatb.st_ino + && Hdr.h_dev == Xstatb.st_dev) { + err("Attempt to pass file to self!\n"); + exit(1); + } +c_again: + if((f = creat(namep, Hdr.h_mode)) < 0) { + if(missdir(namep)) + goto c_again; + err("Cannot create <%s> (errno:%d)\n", namep, errno); + return 0; + } + if(Uid == 0) + chown(namep, Hdr.h_uid, Hdr.h_gid); + return f; +} + + +void pentry(char *namep) +{ + + static short lastid = -1; + static struct passwd *pw; + static char tbuf[32]; + + printf("%-7o", Hdr.h_mode & 0177777); + if(lastid == Hdr.h_uid) + printf("%-6s", pw->pw_name); + else { + setpwent(); + if(pw = getpwuid(Hdr.h_uid)) { + printf("%-6s", pw->pw_name); + lastid = Hdr.h_uid; + } else + printf("%-6d", Hdr.h_uid); + } + printf("%7D ", mklong(Hdr.h_filesize)); + U.l = mklong(Hdr.h_mtime); + strcpy(tbuf, ctime(&U.l)); + tbuf[24] = '\0'; + printf(" %s %s\n", &tbuf[4], namep); +} + + + +char * cd(char *n) +{ + char *p_save = Name, *n_save = n, *p_end = 0; + register char *p = Name; + static char dotdot[]="../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../"; + int slashes; + + for(; *p && *n == *p; ++p, ++n) { /* whatever part of strings == */ + if(*p == '/') + p_save = p+1, n_save = n+1; + } + + p = p_save; + *p++ = '\0'; + for(slashes = 0; *p; ++p) { /* if prev is longer, chdir("..") */ + if(*p == '/') + ++slashes; + } + p = p_save; + if(slashes) { + slashes = slashes * 3 - 1; + dotdot[slashes] = '\0'; + chdir(dotdot); + dotdot[slashes] = '/'; + } + + n = n_save; + for(; *n; ++n, ++p) { + *p = *n; + if(*n == '/') + p_end = p+1, n_save = n+1; + } + *p = '\0'; + + if(p_end) { + *p_end = '\0'; + if(chdir(p_save) == -1) { + if(!missdir(p_save)) { +cd_err: + err("Cannot chdir\n"); + abort(); + } else if(chdir(p_save) == -1) + goto cd_err; + } + } else + *p_save = '\0'; + return n_save; +} + + +int main(int argc, char *argv[]) +{ + register int ct; + long filesz; + register char *lastarg, *fullp; + + if(argc < 2 || argc > 4) { +usage: + err("Usage: cpio -o[vB] collection\n%s\n%s\n", + " cpio -i[drstuvB] [pattern] \n", lastarg); + exit(1); + } + strcpy(Fullname, lastarg); + strcat(Fullname, "/"); + stat(Fullname, &Xstatb); + if((Xstatb.st_mode&S_IFMT) != S_IFDIR) + goto accerr; + Option = PASS; + Dev = Xstatb.st_dev; + Pattern = argc == 3? "*": argv[2]; + break; + case 'd': + Dir++; + break; + case 'l': + Link++; + break; + case 'm': + Mod_time++; + break; + case 'r': + Rename++; + Rtty = fopen("/dev/tty", "r"); + Wtty = fopen("/dev/tty", "w"); + if(Rtty==NULL || Wtty==NULL) { + err( + "Cannot rename (/dev/tty missing)\n"); + exit(1); + } + break; + case 's': + Swap++; + break; + case 't': + Toc++; + break; + case 'u': + Uncond++; + break; + case 'v': + Verbose++; + break; + default: + goto usage; + } + } + if(!Option) { + err("Options must include o|i|p\n"); + exit(1); + } + + if(Option != PASS) + Wp = Dbuf = malloc(Bufsize); + Wct = Bufsize >> 1; + + if(Option == PASS && Rename) { + err("Pass and Rename cannot be used together"); + exit(1); + } + switch(Option) { + + case OUT: + while(getname()) { + if(mklong(Hdr.h_filesize) == 0L) { + bwrite(&Hdr, HDRSIZE+Hdr.h_namesize); + continue; + } + if((Ifile = open(Hdr.h_name, 0)) < 0) { + err("<%s> ?\n", Hdr.h_name); + continue; + } + bwrite(&Hdr, HDRSIZE+Hdr.h_namesize); + for(filesz=mklong(Hdr.h_filesize); filesz>0; filesz-= 512){ + ct = filesz>512? 512: filesz; + if(read(Ifile, Buf, ct) < 0) { + err("Cannot read %s\n", Hdr.h_name); + continue; + } + bwrite(Buf, ct); + } + close(Ifile); + if(Verbose) + err("%s\n", Hdr.h_name); + } + strcpy(Hdr.h_name, "TRAILER!!!"); + MKSHORT(Hdr.h_filesize, 0L); + Hdr.h_namesize = strlen("TRAILER!!!") + 1; + bwrite(&Hdr, HDRSIZE+Hdr.h_namesize); + bwrite(Dbuf, Bufsize); + break; + + case IN: + pwd(); + while(gethdr()) { + Ofile = ckname(Hdr.h_name)? openout(Hdr.h_name): 0; + for(filesz=mklong(Hdr.h_filesize); filesz>0; filesz-= 512){ + ct = filesz>512? 512: filesz; + bread(Buf, ct); + if(Ofile) { + if(Swap) + swap(Buf, ct); + if(write(Ofile, Buf, ct) < 0) { + err("Cannot write %s\n", Hdr.h_name); + continue; + } + } + } + if(Ofile) { + close(Ofile); + set_time(Cd_name, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime)); + } + if(!Select) + continue; + if(Verbose) + if(Toc) + pentry(Hdr.h_name); + else + puts(Hdr.h_name); + else if(Toc) + puts(Hdr.h_name); + } + break; + + case PASS: + fullp = Fullname + strlen(Fullname); + + while(getname()) { + if(!ckname(Hdr.h_name)) + continue; + strcpy(fullp, Hdr.h_name); + + if(Link + && !A_directory + && Dev == Statb.st_dev + && (Uid == Statb.st_uid || !Uid)) { + unlink(Fullname); + if(link(Hdr.h_name, Fullname) < 0) { + err( + "Cannot link <%s> & <%s>\n", + Hdr.h_name, Fullname); + continue; + } + set_time(Hdr.h_name, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime)); + goto ckverbose; + } + if(!(Ofile = openout(Fullname))) + continue; + if((Ifile = open(Hdr.h_name, 0)) < 0) { + err("<%s> ?\n", Hdr.h_name); + close(Ofile); + continue; + } + filesz = Statb.st_size; + for(; filesz > 0; filesz -= 512) { + ct = filesz>512? 512: filesz; + if(read(Ifile, Buf, ct) < 0) { + err("Cannot read %s\n", Hdr.h_name); + break; + } + if(Ofile) + if(write(Ofile, Buf, ct) < 0) { + err("Cannot write %s\n", Hdr.h_name); + break; + } + ++Blocks; + } + close(Ifile); + if(Ofile) { + close(Ofile); + set_time(Fullname, Statb.st_atime, mklong(Hdr.h_mtime)); +ckverbose: + if(Verbose) + puts(Fullname); + } + } + } + err("%D blocks\n", Blocks * (Bufsize>>9)); + exit(0); +}