cpio: add first cut at porting cpio over
authorAlan Cox <alan@linux.intel.com>
Mon, 12 Feb 2018 00:42:21 +0000 (00:42 +0000)
committerAlan Cox <alan@linux.intel.com>
Mon, 12 Feb 2018 00:42:21 +0000 (00:42 +0000)
Needs work yet

Applications/V7/cmd/Makefile.z80
Applications/V7/cmd/cpio.c [new file with mode: 0644]

index b6c20db..55636fd 100644 (file)
@@ -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 (file)
index 0000000..753a3a5
--- /dev/null
@@ -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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <pwd.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <utime.h>
+
+/* 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] <name-list >collection\n%s\n%s\n",
+               "       cpio -i[drstuvB] [pattern] <collection",
+               "       cpio -p[dlruv] [pattern] directory <name-list");
+               exit(1);
+       }
+       signal(SIGSYS, SIG_IGN);
+       lastarg = argv[argc-1];
+       if(*argv[1] != '-')
+               goto usage;
+       Uid = getuid();
+       umask(0);
+       Gid = getgid();
+
+       while(*++argv[1]) {
+               switch(*argv[1]) {
+               case 'B':
+                       Bufsize = 5120;
+                       break;
+               case 'i':
+                       Option = IN;
+                       Pattern = argc == 2? "*": argv[2];
+                       break;
+               case 'o':
+                       Option = OUT;
+                       break;
+               case 'p':
+                       if(access(lastarg, 2) == -1) {
+accerr:
+                               err("cannot write in <%s>\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);
+}