aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/tapefs/tarfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/tapefs/tarfs.c')
-rw-r--r--src/cmd/tapefs/tarfs.c144
1 files changed, 144 insertions, 0 deletions
diff --git a/src/cmd/tapefs/tarfs.c b/src/cmd/tapefs/tarfs.c
new file mode 100644
index 00000000..5bbd8b9c
--- /dev/null
+++ b/src/cmd/tapefs/tarfs.c
@@ -0,0 +1,144 @@
+#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 = g8byte(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);
+}