blob: e5da154ea785f90b7e2d597630d294217edba5c4 [file] [log] [blame]
#include <u.h>
#include <libc.h>
#include <auth.h>
#include <fcall.h>
#include "tapefs.h"
/*
* File system for tar tapes (read-only)
*/
#define TBLOCK 512
#define NBLOCK 40 /* maximum blocksize */
#define DBLOCK 20 /* default blocksize */
#define TNAMSIZ 100
union hblock {
char dummy[TBLOCK];
char tbuf[Maxbuf];
struct header {
char name[TNAMSIZ];
char mode[8];
char uid[8];
char gid[8];
char size[12];
char mtime[12];
char chksum[8];
char linkflag;
char linkname[TNAMSIZ];
} dbuf;
} dblock;
int tapefile;
int checksum(void);
void
populate(char *name)
{
long blkno, isabs, chksum, linkflg;
Fileinf f;
tapefile = open(name, OREAD);
if (tapefile<0)
error("Can't open argument file");
replete = 1;
for (blkno = 0;;) {
seek(tapefile, TBLOCK*blkno, 0);
if (read(tapefile, dblock.dummy, sizeof(dblock.dummy))<sizeof(dblock.dummy))
break;
if (dblock.dbuf.name[0]=='\0')
break;
f.addr = blkno+1;
f.mode = strtoul(dblock.dbuf.mode, 0, 8);
f.uid = strtoul(dblock.dbuf.uid, 0, 8);
f.gid = strtoul(dblock.dbuf.gid, 0, 8);
if((uchar)dblock.dbuf.size[0] == 0x80)
f.size = b8byte(dblock.dbuf.size+3);
else
f.size = strtoull(dblock.dbuf.size, 0, 8);
f.mdate = strtoul(dblock.dbuf.mtime, 0, 8);
chksum = strtoul(dblock.dbuf.chksum, 0, 8);
/* the mode test is ugly but sometimes necessary */
if (dblock.dbuf.linkflag == '5'
|| (f.mode&0170000) == 040000
|| strrchr(dblock.dbuf.name, '\0')[-1] == '/'){
f.mode |= DMDIR;
f.size = 0;
}
f.mode &= DMDIR|0777;
linkflg = dblock.dbuf.linkflag=='s' || dblock.dbuf.linkflag=='1';
isabs = dblock.dbuf.name[0]=='/';
if (chksum != checksum()){
fprint(1, "bad checksum on %.28s\n", dblock.dbuf.name);
exits("checksum");
}
if (linkflg) {
/*fprint(2, "link %s->%s skipped\n", dblock.dbuf.name,
dblock.dbuf.linkname);*/
f.size = 0;
blkno += 1;
continue;
}
f.name = dblock.dbuf.name+isabs;
if (f.name[0]=='\0')
fprint(1, "null name skipped\n");
else
poppath(f, 1);
blkno += 1 + (f.size+TBLOCK-1)/TBLOCK;
}
}
void
dotrunc(Ram *r)
{
USED(r);
}
void
docreate(Ram *r)
{
USED(r);
}
char *
doread(Ram *r, vlong off, long cnt)
{
seek(tapefile, TBLOCK*r->addr+off, 0);
if (cnt>sizeof(dblock.tbuf))
error("read too big");
read(tapefile, dblock.tbuf, cnt);
return dblock.tbuf;
}
void
popdir(Ram *r)
{
USED(r);
}
void
dowrite(Ram *r, char *buf, long off, long cnt)
{
USED(r); USED(buf); USED(off); USED(cnt);
}
int
dopermw(Ram *r)
{
USED(r);
return 0;
}
int
checksum()
{
int i;
char *cp;
for (cp = dblock.dbuf.chksum; cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++)
*cp = ' ';
i = 0;
for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
i += *cp&0xff;
return(i);
}