aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/9660/path.c
diff options
context:
space:
mode:
authorwkj <devnull@localhost>2004-06-17 01:47:21 +0000
committerwkj <devnull@localhost>2004-06-17 01:47:21 +0000
commit7285a491c1ce1e630a0751b1011fd33e6b17234b (patch)
treeb2b2e24e333fa4660325a35f6c0f1d333e50e797 /src/cmd/9660/path.c
parente1dddc053287874e82e2b67f95ccee7d7bc63e22 (diff)
downloadplan9port-7285a491c1ce1e630a0751b1011fd33e6b17234b.tar.gz
plan9port-7285a491c1ce1e630a0751b1011fd33e6b17234b.tar.bz2
plan9port-7285a491c1ce1e630a0751b1011fd33e6b17234b.zip
Dump9660 (and mk9660). Until we either do something
intelligent with symlinks or put in a switch for things like dump9660, this is of rather limited utility under Unix.
Diffstat (limited to 'src/cmd/9660/path.c')
-rw-r--r--src/cmd/9660/path.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/src/cmd/9660/path.c b/src/cmd/9660/path.c
new file mode 100644
index 00000000..f2757dba
--- /dev/null
+++ b/src/cmd/9660/path.c
@@ -0,0 +1,155 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <libsec.h>
+
+#include "iso9660.h"
+
+/*
+ * Add the requisite path tables to the CD image.
+ * They get put on the end once everything else is done.
+ * We use the path table itself as a queue in the breadth-first
+ * traversal of the tree.
+ *
+ * The only problem with this is that the path table does not
+ * store the lengths of the directories. So we keep an explicit
+ * map in an array in memory.
+ */
+
+enum {
+ Big,
+ Little
+};
+
+static void
+Crdpath(Cdimg *cd, Cpath *p)
+{
+ p->namelen = Cgetc(cd);
+ if(p->namelen == 0) {
+ Crseek(cd, (Croffset(cd)+Blocksize-1)/Blocksize * Blocksize);
+ p->namelen = Cgetc(cd);
+ assert(p->namelen != 0);
+ }
+
+ p->xlen = Cgetc(cd);
+ assert(p->xlen == 0); /* sanity, might not be true if we start using the extended fields */
+
+ Cread(cd, p->dloc, 4);
+ Cread(cd, p->parent, 2);
+ p->name[0] = '\0';
+ Crseek(cd, Croffset(cd)+p->namelen+p->xlen+(p->namelen&1)); /* skip name, ext data */
+}
+
+static void
+writepath(Cdimg *cd, Cdir *c, int parent, int size)
+{
+/*
+ DO NOT UNCOMMENT THIS CODE.
+ This commented-out code is here only so that no one comes
+ along and adds it later.
+
+ The ISO 9660 spec is silent about whether path table entries
+ need to be padded so that they never cross block boundaries.
+ It would be reasonable to assume that they are like every other
+ data structure in the bloody spec; this code pads them out.
+
+ Empirically, though, they're NOT padded. Windows NT and
+ derivatives are the only known current operating systems
+ that actually read these things.
+
+ int l;
+
+ l = 1+1+4+2+c->namelen;
+ if(Cwoffset(cd)/Blocksize != (Cwoffset(cd)+l)/Blocksize)
+ Cpadblock(cd);
+*/
+ Cputc(cd, c->namelen);
+ Cputc(cd, 0);
+ Cwrite(cd, c->dloc + (size==Little ? 0 : 4), 4);
+ (size==Little ? Cputnl : Cputnm)(cd, parent, 2);
+ Cwrite(cd, c->name, c->namelen);
+ if(c->namelen & 1)
+ Cputc(cd, 0);
+}
+
+static ulong*
+addlength(ulong *a, ulong x, int n)
+{
+ if(n%128==0)
+ a = erealloc(a, (n+128)*sizeof a[0]);
+ a[n] = x;
+ return a;
+}
+
+static ulong
+writepathtable(Cdimg *cd, ulong vdblock, int size)
+{
+ int rp, wp;
+ uchar buf[Blocksize];
+ ulong bk, end, i, *len, n, rdoff, start;
+ Cdir *c;
+ Cpath p;
+
+ Creadblock(cd, buf, vdblock, Blocksize);
+ c = (Cdir*)(buf+offsetof(Cvoldesc, rootdir[0]));
+
+ rp = 0;
+ wp = 0;
+ len = nil;
+ start = cd->nextblock*Blocksize;
+ Cwseek(cd, start);
+ Crseek(cd, start);
+ writepath(cd, c, 1, size);
+ len = addlength(len, little(c->dlen, 4), wp);
+ wp++;
+
+ while(rp < wp) {
+ Crdpath(cd, &p);
+ n = (len[rp]+Blocksize-1)/Blocksize;
+ rp++;
+ bk = (size==Big ? big : little)(p.dloc, 4);
+ rdoff = Croffset(cd);
+ for(i=0; i<n; i++) {
+ Creadblock(cd, buf, bk+i, Blocksize);
+ c = (Cdir*)buf;
+ if(i != 0 && c->namelen == 1 && c->name[0] == '\0') /* hit another directory; stop */
+ break;
+ while(c->len && c->namelen && (uchar*)c+c->len < buf+Blocksize) {
+ if((c->flags & 0x02) && (c->namelen > 1 || c->name[0] > '\001')) { /* directory */
+ writepath(cd, c, rp, size);
+ len = addlength(len, little(c->dlen, 4), wp);
+ wp++;
+ }
+ c = (Cdir*)((uchar*)c+c->len);
+ }
+ }
+ Crseek(cd, rdoff);
+ }
+ end = Cwoffset(cd);
+ Cpadblock(cd);
+ return end-start;
+}
+
+
+static void
+writepathtablepair(Cdimg *cd, ulong vdblock)
+{
+ ulong bloc, lloc, sz, sz2;
+
+ lloc = cd->nextblock;
+ sz = writepathtable(cd, vdblock, Little);
+ bloc = cd->nextblock;
+ sz2 = writepathtable(cd, vdblock, Big);
+ assert(sz == sz2);
+ setpathtable(cd, vdblock, sz, lloc, bloc);
+}
+
+void
+writepathtables(Cdimg *cd)
+{
+ cd->pathblock = cd->nextblock;
+
+ writepathtablepair(cd, cd->iso9660pvd);
+ if(cd->flags & CDjoliet)
+ writepathtablepair(cd, cd->jolietsvd);
+}