aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/9660/direc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/9660/direc.c')
-rw-r--r--src/cmd/9660/direc.c222
1 files changed, 222 insertions, 0 deletions
diff --git a/src/cmd/9660/direc.c b/src/cmd/9660/direc.c
new file mode 100644
index 00000000..8185f680
--- /dev/null
+++ b/src/cmd/9660/direc.c
@@ -0,0 +1,222 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <libsec.h>
+
+#include "iso9660.h"
+
+void
+mkdirec(Direc *direc, XDir *d)
+{
+ memset(direc, 0, sizeof(Direc));
+ direc->name = atom(d->name);
+ direc->uid = atom(d->uid);
+ direc->gid = atom(d->gid);
+ direc->uidno = d->uidno;
+ direc->gidno = d->gidno;
+ direc->mode = d->mode;
+ direc->length = d->length;
+ direc->mtime = d->mtime;
+ direc->atime = d->atime;
+ direc->ctime = d->ctime;
+ direc->symlink = d->symlink;
+}
+
+static int
+strecmp(char *a, char *ea, char *b)
+{
+ int r;
+
+ if((r = strncmp(a, b, ea-a)) != 0)
+ return r;
+
+ if(b[ea-a] == '\0')
+ return 0;
+ return 1;
+}
+
+/*
+ * Binary search a list of directories for the
+ * entry with name name.
+ * If no entry is found, return a pointer to
+ * where a new such entry would go.
+ */
+static Direc*
+dbsearch(char *name, int nname, Direc *d, int n)
+{
+ int i;
+
+ while(n > 0) {
+ i = strecmp(name, name+nname, d[n/2].name);
+ if(i < 0)
+ n = n/2;
+ else if(i > 0) {
+ d += n/2+1;
+ n -= (n/2+1);
+ } else
+ return &d[n/2];
+ }
+ return d;
+}
+
+/*
+ * Walk to name, starting at d.
+ */
+Direc*
+walkdirec(Direc *d, char *name)
+{
+ char *p, *nextp, *slashp;
+ Direc *nd;
+
+ for(p=name; p && *p; p=nextp) {
+ if((slashp = strchr(p, '/')) != nil)
+ nextp = slashp+1;
+ else
+ nextp = slashp = p+strlen(p);
+
+ nd = dbsearch(p, slashp-p, d->child, d->nchild);
+ if(nd >= d->child+d->nchild || strecmp(p, slashp, nd->name) != 0)
+ return nil;
+ d = nd;
+ }
+ return d;
+}
+
+/*
+ * Add the file ``name'' with attributes d to the
+ * directory ``root''. Name may contain multiple
+ * elements; all but the last must exist already.
+ *
+ * The child lists are kept sorted by utfname.
+ */
+Direc*
+adddirec(Direc *root, char *name, XDir *d)
+{
+ char *p;
+ Direc *nd;
+ int off;
+
+ if(name[0] == '/')
+ name++;
+ if((p = strrchr(name, '/')) != nil) {
+ *p = '\0';
+ root = walkdirec(root, name);
+ if(root == nil) {
+ sysfatal("error in proto file: no entry for /%s but /%s/%s\n", name, name, p+1);
+ return nil;
+ }
+ *p = '/';
+ p++;
+ } else
+ p = name;
+
+ nd = dbsearch(p, strlen(p), root->child, root->nchild);
+ off = nd - root->child;
+ if(off < root->nchild && strcmp(nd->name, p) == 0) {
+ if ((d->mode & DMDIR) == 0)
+ fprint(2, "warning: proto lists %s twice\n", name);
+ return nil;
+ }
+
+ if(root->nchild%Ndirblock == 0) {
+ root->child = erealloc(root->child, (root->nchild+Ndirblock)*sizeof(Direc));
+ nd = root->child + off;
+ }
+
+ memmove(nd+1, nd, (root->nchild - off)*sizeof(Direc));
+ mkdirec(nd, d);
+ nd->name = atom(p);
+ root->nchild++;
+ return nd;
+}
+
+/*
+ * Copy the tree src into dst.
+ */
+void
+copydirec(Direc *dst, Direc *src)
+{
+ int i, n;
+
+ *dst = *src;
+
+ if((src->mode & DMDIR) == 0)
+ return;
+
+ n = (src->nchild + Ndirblock - 1);
+ n -= n%Ndirblock;
+ dst->child = emalloc(n*sizeof(Direc));
+
+ n = dst->nchild;
+ for(i=0; i<n; i++)
+ copydirec(&dst->child[i], &src->child[i]);
+}
+
+/*
+ * Turn the Dbadname flag on for any entries
+ * that have non-conforming names.
+ */
+static void
+_checknames(Direc *d, int (*isbadname)(char*), int isroot)
+{
+ int i;
+
+ if(!isroot && isbadname(d->name))
+ d->flags |= Dbadname;
+
+ if(strcmp(d->name, "_conform.map") == 0)
+ d->flags |= Dbadname;
+
+ for(i=0; i<d->nchild; i++)
+ _checknames(&d->child[i], isbadname, 0);
+}
+
+void
+checknames(Direc *d, int (*isbadname)(char*))
+{
+ _checknames(d, isbadname, 1);
+}
+
+/*
+ * Set the names to conform to 8.3
+ * by changing them to numbers.
+ * Plan 9 gets the right names from its
+ * own directory entry.
+ *
+ * We used to write a _conform.map file to translate
+ * names. Joliet should take care of most of the
+ * interoperability with other systems now.
+ */
+void
+convertnames(Direc *d, char* (*cvt)(char*, char*))
+{
+ int i;
+ char new[1024];
+
+ if(d->flags & Dbadname)
+ cvt(new, conform(d->name, d->mode & DMDIR));
+ else
+ cvt(new, d->name);
+ d->confname = atom(new);
+
+ for(i=0; i<d->nchild; i++)
+ convertnames(&d->child[i], cvt);
+}
+
+/*
+ * Sort a directory with a given comparison function.
+ * After this is called on a tree, adddirec should not be,
+ * since the entries may no longer be sorted as adddirec expects.
+ */
+void
+dsort(Direc *d, int (*cmp)(const void*, const void*))
+{
+ int i, n;
+
+ n = d->nchild;
+ qsort(d->child, n, sizeof(d[0]), cmp);
+
+ for(i=0; i<n; i++)
+ dsort(&d->child[i], cmp);
+}
+