root%bostonu.csnet@csnet-relay.arpa (BostonU SysMgr) (03/23/85)
People asked me to post my short program for reading cpio tapes so here it is. Ok, with comments and the util routines it's a little longer than 100 lines but not much (<200 lines). As I said, it's a hack to read a cpio tape but all the hard work is done. cpi.c -- cc cpi.c -o cpi -Barry Shein, Boston University --------------------cut here-------------------- #include <stdio.h> #include <sys/types.h> #include <sys/file.h> /* * cpi.c - read a cpio tape * usage: cpi prefix * will read in and create all files (and dirs) that * match the prefix, for example 'cpi src/cmd' will * read in src/cmd/foo.c src/cmd/thing/goo.c etc. * TODO- * cmd line: add tape drive, blksize,word/byte swap * maybe more sophisticated selection of files * doesn't check for TRAILER record at end of tape, * just gives an error message and gives up * * Look, this was a hack to get cpio.c off of a SYSV tape. * It could use some cosmetics but all the hard work is done. * although at some point in its history it ran on a 3B5 it's * been changed and has at least one 4.2bsd/VAX dependancy (mkdir()). * * (C) Barry Shein, Boston University * You have the right to distribute this to whomever you * like as long as you don't remove my name so I can become * famous for adding yet another unsupportable hack to the UNIX * environment. If you give this away, give it with source, please. */ FILE *fcreat() ; struct cpio { short h_magic, h_dev; ushort h_ino, h_mode, h_uid, h_gid; ushort h_nlink, h_rdev, h_mtime[2], h_namesize, h_filesize[2] ; } ; #define BSIZE 5120 /* oughta be settable from cmd line */ char fbuf[BSIZE], *fbufp ; int fbufk = 0 ; #define MAXNAME 256 /* actually a cpio limit */ #define DEFTAPE "/dev/rmt0" /* oughta be settable from cmd line */ main(argc,argv) int argc ; char **argv ; { struct cpio cpio ; char namebuf[MAXNAME] ; char buf[BSIZE] ; register short *sip ; int fd ; int siz ; int i,j ; int *ip ; int fsize ; char *prfx ; int prfxl ; FILE *fp ; if(argc != 2) exit(printf("usage: %s prefix\n",*argv)) ; if((fd = open(DEFTAPE,0)) < 0) exit(perror(DEFTAPE)) ; prfx = argv[1] ; prfxl = strlen(prfx) ; siz = sizeof(cpio) ; again: cread(fd,&cpio,siz) ; #ifdef notdef /* 3B5 needed byte swapping */ swabw(&cpio,siz/2) ; printf("MAGIC: %07o\tUID: %6d\n",cpio.h_magic, cpio.h_uid) ; #endif /* rebuild the long, if you re-declare as long alignment gets ya */ fsize = (cpio.h_filesize[0] << 16) | cpio.h_filesize[1] ; #ifdef notdef printf("NSIZE: %8d\tFSIZE: %8d\n",cpio.h_namesize,fsize) ; #endif /* this is also what you will hear on end-of-tape */ if((cpio.h_namesize < 0) || (cpio.h_namesize > MAXNAME)) { printf("ridiculous name, giving up\n") ; printf("(fbufk = %d)\n",fbufk) ; exit(1) ; } /* NOTE: rounded up to even, will be padded on tape */ i = (cpio.h_namesize & 01) ? cpio.h_namesize + 1 : cpio.h_namesize ; cread(fd,namebuf,i) ; /* printf("NAME: %s\n",namebuf) ;*/ j = fsize ; if((j > 0) && (strncmp(namebuf,prfx,prfxl) == 0)) { if((fp = fcreat(namebuf)) == NULL) perror(namebuf) ; else printf("%s\n",namebuf) ; /* always 'verbose' */ } else fp = NULL ; while(j > 0) { /* read in BSIZE pieces */ if((i = cread(fd,buf,(j >= BSIZE) ? BSIZE : j)) <= 0) { printf("Error reading tape? (%s)\n",namebuf) ; exit(1) ; } j -= i ; /* see, I already had fcreat() from another thing I wrote */ /* really shoulda made it not stdio but who cares */ if(fp != NULL) write(fileno(fp),buf,i) ; } if(fp != NULL) fclose(fp) ; if(fsize & 1) cread(fd,buf,1) ; /* get pad byte */ goto again ; } /* buffered read */ cread(fd,bp,n) int fd ; register char *bp ; register int n ; { int nb = 0 ; while(n--) { if(fbufk <= 0) if((fbufk = read(fd,fbufp = fbuf,BSIZE)) <= 0) return(nb) ; *bp++ = *fbufp++ ; --fbufk ; nb++ ; } return(nb) ; } wswab(i) int i ; { return(((i & 0xff00) >> 8) | ((i & 0xff) << 8)) ; } swabw(sip,l) register short int *sip ; register int l ; { while(l--) *sip++ = wswab(*sip) ; } /* * bit of craziness to create output file. Will * attempt to create all intervening path names. * you're gonna need a mkdir() routine. */ FILE * fcreat(path) char *path ; { char buf[BUFSIZ] ; register char *bp ; strcpy(buf,path) ; bp = &buf[strlen(buf) - 1] ; while((*bp != '/') && (bp >= &buf[0])) bp-- ; if(*bp != '/') return(NULL) ; *bp = '\0' ; if(access(buf,F_OK) < 0) { char c ; for(bp = buf ;; bp++) { if((c = *bp) && (*bp != '/')) continue ; *bp = '\0' ; if(access(buf,F_OK) < 0) if(mkdir(buf,0777) < 0) return(NULL) ; if(c == '\0') break ; *bp = '/' ; } } return(fopen(path,"w")) ; }