AUSAM/source/S/cpio.c
#include <stdio.h>
#include <stat.h>
#define EQ(x,y) (strcmp(x,y)==0)
#define MAGIC 070707
#define IN 1
#define OUT 2
#define PASS 3
#define HDRSIZE ((sizeof Hdr)-256)
#define INPUT 0
#define OUTPUT 1
struct statb Statb, Xstatb;
struct header {
int h_magic,
h_dev,
h_ino,
h_mode,
h_uid,
h_gid,
h_nlink,
h_majmin;
long h_mtime;
int h_namesize;
long h_filesize;
char h_name[256];
} Hdr;
int Buf[256], Wbuf[256];
int *Wp Wbuf,
Wct 256;
union { int integ; };
struct { char lobyte,hibyte; };
int Option,
Mod_time,
Dir,
Uncond,
Link,
Rename,
Toc,
Verbose,
Select;
int Ifile,
Ofile;
unsigned Blocks;
char Fullname[256],
Name[128];
FILE *Rtty,
*Wtty;
char *Pattern;
int Dev;
int Uid;
int A_directory,
A_special;
main(argc, argv)
char **argv;
{
register ct;
long filesz;
register char *fullp, *lastarg;
long itol();
if(argc < 2 || argc > 4) {
usage:
fprintf(stderr,
"Usage: cpio -o[v] <name-list >archive\n%s\n%s\n",
" cpio -i[dmrtuv] [pattern] <archive",
" cpio -p[dlmruv] [pattern] directory <name-list");
exit(1);
}
lastarg = argv[argc-1];
if(*argv[1] != '-')
goto usage;
Uid = getuid();
while(*++argv[1]) {
switch(*argv[1]) {
case 'i':
Option = IN;
Pattern = argc == 2? "*": argv[2];
break;
case 'o':
Option = OUT;
break;
case 'p':
if(access(lastarg, 2) == -1) {
accerr:
fprintf(stderr, "cannot write in <%s>\n",
lastarg);
exit(1);
}
strcpy(Fullname, lastarg);
strcat(Fullname, "/");
stat(Fullname, &Xstatb);
if((Xstatb.i_mode&IFMT) != IFDIR)
goto accerr;
Option = PASS;
Dev = Xstatb.i_dev;
Pattern = argc == 3? "*": argv[2];
break;
case 'm':
++Mod_time;
break;
case 'd':
Dir++;
break;
case 'r':
Rename++;
Rtty = fopen("/dev/tty", "r");
Wtty = fopen("/dev/tty", "w");
break;
case 't':
Toc++;
break;
case 'u':
Uncond++;
break;
case 'l':
Link++;
break;
case 'v':
Verbose++;
break;
default:
goto usage;
}
}
if(!Option) {
fprintf(stderr, "Options must include o|i|p\n");
exit(1);
}
switch(Option) {
case OUT:
while(getname()) {
if(Hdr.h_filesize == 0L) {
bwrite(OUTPUT, &Hdr, HDRSIZE+Hdr.h_namesize);
continue;
}
if((Ifile = open(Hdr.h_name, 0)) < 0) {
fprintf(stderr, "<%s> ?\n", Hdr.h_name);
continue;
}
bwrite(OUTPUT, &Hdr, HDRSIZE+Hdr.h_namesize);
for(filesz=Hdr.h_filesize; filesz>0; filesz=- 512){
ct = filesz>512? 512: filesz;
read(Ifile, Buf, ct);
bwrite(OUTPUT, Buf, ct);
}
close(Ifile);
if(Verbose)
fprintf(stderr, "%s\n", Hdr.h_name);
}
strcpy(Hdr.h_name, "TRAILER!!!");
Hdr.h_filesize = 0L;
Hdr.h_namesize = strlen("TRAILER!!!") + 1;
bwrite(OUTPUT, &Hdr, 600);
break;
case IN:
while(gethdr()) {
Ofile = ckname(Hdr.h_name)? openout(Hdr.h_name): 0;
for(filesz=Hdr.h_filesize; filesz>0; filesz=- 512){
ct = filesz>512? 512: filesz;
bread(ct, Wbuf);
if(Ofile)
write(Ofile, &Wbuf, ct);
}
if(Ofile) {
close(Ofile);
set_time(Hdr.h_name, Hdr.h_mtime, 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.i_dev
&& ((Uid.lobyte == Statb.i_uidl
&& Uid.hibyte == Statb.i_uidh) || !Uid)) {
unlink(Fullname);
if(link(Hdr.h_name, Fullname) < 0) {
fprintf(stderr,
"Cannot link <%s> & <%s>\n",
Hdr.h_name, Fullname);
continue;
}
set_time(Fullname, Hdr.h_mtime, Hdr.h_mtime);
goto ckverbose;
}
if(!(Ofile = openout(Fullname)))
continue;
if((Ifile = open(Hdr.h_name, 0)) < 0) {
fprintf(stderr, "<%s> ?\n", Hdr.h_name);
close(Ofile);
continue;
}
filesz = itol(Statb.i_size0 & 0377, Statb.i_size1);
for(; filesz > 0; filesz =- 512) {
ct = filesz>512? 512: filesz;
read(Ifile, Buf, ct);
if(Ofile)
write(Ofile, Buf, ct);
++Blocks;
}
close(Ifile);
if(Ofile) {
close(Ofile);
set_time(Fullname, Statb.i_atime,
Statb.i_mtime);
ckverbose:
if(Verbose)
puts(Fullname);
}
}
}
fprintf(stderr, "%l blocks\n", Blocks);
exit(0);
}
getname()
{
register char *namep Name;
for(;;) {
if(gets(namep) == NULL)
return 0;
if(*namep == '.' && namep[1] == '/')
strcpy(Hdr.h_name, namep+2);
else
strcpy(Hdr.h_name, namep);
if(stat(Hdr.h_name, &Statb) < 0) {
fprintf(stderr, "<%s> ?\n", Hdr.h_name);
continue;
}
A_directory = (Statb.i_mode & IFMT) == IFDIR;
A_special = Statb.i_mode & IFMT;
Hdr.h_magic = MAGIC;
Hdr.h_namesize = strlen(Hdr.h_name) + 1;
Hdr.h_uid.lobyte = Statb.i_uidl;
Hdr.h_uid.hibyte = Statb.i_uidh;
Hdr.h_gid = 0;
Hdr.h_dev = Statb.i_dev;
Hdr.h_ino = Statb.i_ino;
Hdr.h_mode = Statb.i_mode;
Hdr.h_mtime = Statb.i_mtime;
Hdr.h_nlink = Statb.i_nlink;
Hdr.h_filesize = Hdr.h_mode&IFMT? 0L:
itol(Statb.i_size0 & 0377, Statb.i_size1);
Hdr.h_majmin = Statb.i_addr[0];
return 1;
}
}
gethdr()
{
bread(HDRSIZE, &Hdr);
if(Hdr.h_magic != MAGIC) {
fprintf(stderr,
"Out of phase--get help (or try `_cpio' for old format)\n");
exit(1);
}
bread(Hdr.h_namesize, &Hdr.h_name);
if(EQ(Hdr.h_name, "TRAILER!!!"))
return 0;
A_directory = (Hdr.h_mode & IFMT) == IFDIR;
A_special = Hdr.h_mode & IFMT;
return 1;
}
ckname(namep)
register char *namep;
{
++Select;
if(!gmatch(namep, Pattern)) {
Select = 0;
return 0;
}
if(Rename) {
fprintf(Wtty, "Rename <%s>\n", namep);
fflush(Wtty);
fgets(namep, 128, Rtty);
if(feof(Rtty))
exit(1);
namep[strlen(namep) - 1] = '\0';
if(EQ(namep, "")) {
printf("Skipped\n");
return 0;
}
}
return !Toc;
}
openout(namep)
register char *namep;
{
register f;
if(A_directory) {
if(!Dir
|| Rename
|| EQ(namep, ".")
|| EQ(namep, "..")
|| stat(namep, &Xstatb) == 0)
return 0;
makdir(namep);
ret:
chmod(namep, Hdr.h_mode);
if(Uid == 0)
chown(namep, Hdr.h_uid.integ);
return 0;
}
if(Hdr.h_nlink > 1)
if(!postml(namep))
return 0;
if(A_special) {
unlink(namep);
if(mknod(namep, Hdr.h_mode, Hdr.h_majmin) < 0) {
fprintf(stderr, "Cannot mknod <%s>\n", namep);
return 0;
}
goto ret;
}
if(stat(namep, &Xstatb) == 0)
if(!Uncond && (Hdr.h_mtime < Xstatb.i_mtime)) {
fprintf(stderr, "current <%s> newer\n",
namep);
return 0;
}
if(Option == PASS
&& Hdr.h_ino == Xstatb.i_ino
&& Hdr.h_dev == Xstatb.i_dev) {
fprintf(stderr, "Attempt to pass file to self!\n");
exit(1);
}
if((f = creat(namep, 0600)) < 0) {
if(Dir) {
register char *np;
register v;
for(np = namep; *np; ++np) {
if(*np == '/') {
*np = '\0';
if((v=stat(namep, &Xstatb))== -1) {
makdir(namep);
*np = '/';
} else if((Xstatb.i_mode&IFMT)
!= IFDIR) {
*np = '/';
break;
}
*np = '/';
}
}
}
if((f = creat(namep, 0600)) < 0) {
fprintf(stderr, "Cannot create <%s>\n", namep);
return 0;
}
}
if(Uid == 0)
chown(namep, Hdr.h_uid.integ);
chmod(namep, Hdr.h_mode); /* move til after copy */
return f;
}
bread(fct, b)
register fct, *b;
{
static nleft;
static *ip;
fct = (fct+1)>>1;
while(fct--) {
if(!nleft) {
if(read(INPUT, Buf, 512)!=512) {
fprintf(stderr, "Read error\n");
exit(1);
}
nleft = 256;
ip = Buf;
++Blocks;
}
*b++ = *ip++;
--nleft;
}
}
bwrite(f, rp, c)
register *rp;
register c;
{
c = (c+1) >> 1;
while(c--) {
if(!Wct) {
if(write(f, Wbuf, 512)<0) {
fprintf(stderr, "Cannot write.\n");
exit(1);
}
Wct = 256;
Wp = Wbuf;
++Blocks;
}
*Wp++ = *rp++;
--Wct;
}
}
postml(namep)
register char *namep;
{
register i;
static struct ml {
int m_dev,
m_ino;
char m_name[2];
} *ml[250];
static mlinks 0;
for(i = 0; i < mlinks; ++i) {
if(mlinks == 250) 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,
Hdr.h_name);
unlink(namep);
if(link(ml[i]->m_name, namep) < 0) {
fprintf(stderr, "Cannot link <%s>&<%s>.\n",
ml[i]->m_name, namep);
}
set_time(namep, Hdr.h_mtime, Hdr.h_mtime);
return 0;
}
}
if(mlinks == 250
|| (ml[mlinks] = alloc(strlen(namep) + sizeof *ml[0])) < 0) {
fprintf(stderr, "Out of core for links\n");
mlinks = 250;
return 1;
}
ml[mlinks]->m_dev = Hdr.h_dev;
ml[mlinks]->m_ino = Hdr.h_ino;
strcpy(ml[mlinks]->m_name, namep);
++mlinks;
return 1;
}
pentry(namep)
register char *namep;
{
register i;
static lastid -1;
#include <local-system>
#include <passwd.h>
static struct pwent pe;
static char nbuf[100], tbuf[32];
printf("%-7o", Hdr.h_mode);
if(lastid == Hdr.h_uid)
printf("%-6s", pe.pw_strings[LNAME]);
else {
pe.pw_uid = Hdr.h_uid;
if(getpwlog(&pe, nbuf, sizeof nbuf) >= 0) {
printf("%-6s", pe.pw_strings[LNAME]);
lastid = Hdr.h_uid;
} else
printf("%-6d", Hdr.h_uid);
}
printf("%7D ", Hdr.h_filesize);
strcpy(tbuf, ctime(&Hdr.h_mtime));
tbuf[24] = '\0';
printf(" %s %s\n", &tbuf[4], namep);
}
gmatch(s, p)
register char *s, *p;
{
register int c;
int cc, ok, lc, scc;
if(EQ(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);
}
umatch(s, p)
register char *s, *p;
{
if(*p==0) return(1);
while(*s)
if (gmatch(s++,p)) return(1);
return(0);
}
makdir(namep)
register char *namep;
{
if(fork())
wait(0);
else {
execl("/bin/mkdir", "mkdir", namep, 0);
fprintf(stderr, "mkdir <%s> failed\n", namep);
exit(1);
}
}
set_time(namep, atime, mtime)
register *namep;
long atime, mtime;
{
if(!Mod_time)
return;
smdate(namep, mtime);
}