Add support for named roots so that we can understand MS-Windows paths
authorJ. Ali Harlow <ali@juiblex.co.uk>
Wed, 22 Apr 2009 14:09:17 +0000 (15:09 +0100)
committerJ. Ali Harlow <ali@juiblex.co.uk>
Wed, 22 Apr 2009 14:09:17 +0000 (15:09 +0100)
such as c:/windows. Without this, the user always has to ensure they
are on the correct drive before running razor.

librazor/importer.c
librazor/merger.c
librazor/razor.c
librazor/razor.h
librazor/rpm.c
librazor/util.c
src/main.c
test/Makefile.am
test/named-root.sh [new file with mode: 0755]

index a942cf4..2b1a0e1 100644 (file)
@@ -367,48 +367,56 @@ build_file_tree(struct razor_importer *importer)
        int count, i, length;
        struct import_entry *filenames;
        char *f, *end;
-       uint32_t name, *r;
-       char dirname[256];
-       struct import_directory *d, root;
+       uint32_t name, *r, s;
+       char rootname[256], dirname[256];
+       struct import_directory *d, *last_root;
+       struct array roots;
        struct razor_entry *e;
 
        count = importer->files.size / sizeof (struct import_entry);
-       razor_qsort_with_data(importer->files.data,
+       filenames = importer->files.data;
+       razor_qsort_with_data(filenames,
                              count,
                              sizeof (struct import_entry),
                              compare_filenames,
                              NULL);
 
-       root.name = hashtable_tokenize(&importer->file_table, "");
-       array_init(&root.files);
-       array_init(&root.packages);
-       root.last = NULL;
+       array_init(&roots);
+       last_root = NULL;
 
-       filenames = importer->files.data;
        for (i = 0; i < count; i++) {
                f = filenames[i].name;
-               if (*f != '/')
-                       continue;
-               f++;
-
-               d = &root;
+               d = NULL;
                while (*f) {
                        end = strchr(f, '/');
                        if (end == NULL)
                                end = f + strlen(f);
                        length = end - f;
                        memcpy(dirname, f, length);
-                       dirname[length] ='\0';
+                       dirname[length] = '\0';
                        name = hashtable_tokenize(&importer->file_table,
                                                  dirname);
-                       if (d->last == NULL || d->last->name != name) {
-                               d->last = array_add(&d->files, sizeof *d);
-                               d->last->name = name;
-                               d->last->last = NULL;
-                               array_init(&d->last->files);
-                               array_init(&d->last->packages);
+                       if (!d) {
+                               if (!last_root || last_root->name != name) {
+                                       d = array_add(&roots, sizeof *d);
+                                       d->name = name;
+                                       d->last = NULL;
+                                       array_init(&d->files);
+                                       array_init(&d->packages);
+                                       last_root = d;
+                               }
+                               d = last_root;
+                       } else {
+                               if (!d->last || d->last->name != name) {
+                                       d->last = array_add(&d->files,
+                                                           sizeof *d);
+                                       d->last->name = name;
+                                       d->last->last = NULL;
+                                       array_init(&d->last->files);
+                                       array_init(&d->last->packages);
+                               }
+                               d = d->last;
                        }
-                       d = d->last;
                        f = end + 1;
                        if (*end == '\0')
                                break;
@@ -419,16 +427,33 @@ build_file_tree(struct razor_importer *importer)
                free(filenames[i].name);
        }
 
-       count_entries(&root);
-       e = importer->set->files.data;
-       e->name = root.name;
-       e->flags = RAZOR_ENTRY_LAST;
-       e->start = importer->files.size ? 1 : 0;
-       list_set_empty(&e->packages);
+       count = roots.size / sizeof (struct import_directory);
+       d = roots.data;
+       s = count;
+       for (i = 0; i < count; i++) {
+               count_entries(d);
+               if (i)
+                       e = array_add(&importer->set->files, sizeof *e);
+               else
+                       e = importer->set->files.data;
+               e->name = d->name;
+               e->flags = 0;
+               e->start = d->count > 0 ? s : 0;
+               s += d->count;
+               list_set_empty(&e->packages);
+               d++;
+       }
+       if (count)
+               e->flags |= RAZOR_ENTRY_LAST;
 
-       serialize_files(importer->set, &root, &importer->set->files);
+       d = roots.data;
+       for (i = 0; i < count; i++) {
+               serialize_files(importer->set, d, &importer->set->files);
+               d++;
+       }
 
        array_release(&importer->files);
+       array_release(&roots);
 }
 
 static void
index c954d8f..44b6ce0 100644 (file)
@@ -231,16 +231,15 @@ fix_file_map(uint32_t *map,
        uint32_t e;
        int found_file = 0;
 
-       e = top->start;
+       e = top - files;
        do {
-               if (files[e].start)
-                       fix_file_map(map, files, &files[e]);
+               if (files[e].start &&
+                   fix_file_map(map, files, &files[files[e].start]))
+                       map[e] = 1;
                if (map[e])
                        found_file = 1;
        } while (!(files[e++].flags & RAZOR_ENTRY_LAST));
 
-       if (found_file)
-               map[top - files] = 1;
        return found_file;
 }
 
@@ -271,9 +270,9 @@ merge_one_directory(struct razor_merger *merger, struct merge_directory *md)
        array_init(&merge_stack);
 
        start = merger->set->files.size / sizeof (struct razor_entry);
-       last = 0;
-       e1 = md->dir1 ? root1 + md->dir1 : NULL;
-       e2 = md->dir2 ? root2 + md->dir2 : NULL;
+       last = 0xFFFFFFFF;
+       e1 = md->dir1 != 0xFFFFFFFF ? root1 + md->dir1 : NULL;
+       e2 = md->dir2 != 0xFFFFFFFF ? root2 + md->dir2 : NULL;
        while (e1 || e2) {
                if (!e2 && !map1[e1 - root1]) {
                        if ((e1++)->flags & RAZOR_ENTRY_LAST)
@@ -311,7 +310,7 @@ merge_one_directory(struct razor_merger *merger, struct merge_directory *md)
                                        child_md = array_add(&merge_stack, sizeof (struct merge_directory));
                                        child_md->merged = last;
                                        child_md->dir1 = e1->start;
-                                       child_md->dir2 = 0;
+                                       child_md->dir2 = 0xFFFFFFFF;
                                }
                        }
                        if ((e1++)->flags & RAZOR_ENTRY_LAST)
@@ -323,7 +322,7 @@ merge_one_directory(struct razor_merger *merger, struct merge_directory *md)
                                if (e2->start) {
                                        child_md = array_add(&merge_stack, sizeof (struct merge_directory));
                                        child_md->merged = last;
-                                       child_md->dir1 = 0;
+                                       child_md->dir1 = 0xFFFFFFFF;
                                        child_md->dir2 = e2->start;
                                }
                        }
@@ -335,8 +334,8 @@ merge_one_directory(struct razor_merger *merger, struct merge_directory *md)
                        if (e1->start || e2->start) {
                                child_md = array_add(&merge_stack, sizeof (struct merge_directory));
                                child_md->merged = last;
-                               child_md->dir1 = e1->start;
-                               child_md->dir2 = e2->start;
+                               child_md->dir1 = e1->start ? e1->start : 0xFFFFFFFF;
+                               child_md->dir2 = e2->start ? e2->start : 0xFFFFFFFF;
                        }
                        if ((e1++)->flags & RAZOR_ENTRY_LAST)
                                e1 = NULL;
@@ -346,11 +345,10 @@ merge_one_directory(struct razor_merger *merger, struct merge_directory *md)
        }
 
        mroot = (struct razor_entry *)merger->set->files.data;
-       if (last) {
+       if (last != 0xFFFFFFFF) {
                mroot[last].flags = RAZOR_ENTRY_LAST;
                mroot[md->merged].start = start;
-       } else
-               mroot[md->merged].start = 0;
+       }
 
        end_md = merge_stack.data + merge_stack.size;
        for (child_md = merge_stack.data; child_md < end_md; child_md++)
@@ -374,17 +372,23 @@ merge_files(struct razor_merger *merger)
                root = (struct razor_entry *) merger->source1.set->files.data;
                if (root->start)
                        fix_file_map(map1, root, root);
-               md.dir1 = root->start;
-       } else
                md.dir1 = 0;
+       } else {
+               md.dir1 = 0xFFFFFFFF;
+       }
 
        if (merger->source2.set->files.size) {
                root = (struct razor_entry *) merger->source2.set->files.data;
                if (root->start)
                        fix_file_map(map2, root, root);
-               md.dir2 = root->start;
-       } else
                md.dir2 = 0;
+       } else {
+               md.dir2 = 0xFFFFFFFF;
+       }
+
+       /* Remove the unnamed root which razor_set_create() added */
+       array_release(&merger->set->files);
+       array_init(&merger->set->files);
 
        merge_one_directory(merger, &md);
 }
index e83d128..5bcb60a 100644 (file)
@@ -504,7 +504,7 @@ RAZOR_EXPORT struct razor_entry *
 razor_set_find_entry(struct razor_set *set,
                     struct razor_entry *dir, const char *pattern)
 {
-       struct razor_entry *e;
+       struct razor_entry *e, *subdir;
        const char *n, *pool = set->file_string_pool.data;
        int len;
 
@@ -512,15 +512,18 @@ razor_set_find_entry(struct razor_set *set,
        assert (dir != NULL);
        assert (pattern != NULL);
 
-       e = (struct razor_entry *) set->files.data + dir->start;
+       e = dir;
        do {
                n = pool + e->name;
-               if (strcmp(pattern + 1, n) == 0)
+               if (strcmp(pattern, n) == 0)
                        return e;
                len = strlen(n);
-               if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 &&
-                   pattern[len + 1] == '/') {
-                       return razor_set_find_entry(set, e, pattern + len + 1);
+               if (e->start != 0 && strncmp(pattern, n, len) == 0 &&
+                   pattern[len] == '/') {
+                       subdir = (struct razor_entry *) set->files.data +
+                                e->start;
+                       return razor_set_find_entry(set, subdir,
+                                                   pattern + len + 1);
                }
        } while (!((e++)->flags & RAZOR_ENTRY_LAST));
 
@@ -531,10 +534,10 @@ static void
 list_dir(struct razor_set *set, struct razor_entry *dir,
         char *prefix, const char *pattern)
 {
-       struct razor_entry *e;
+       struct razor_entry *e, *subdir;
        const char *n, *pool = set->file_string_pool.data;
 
-       e = (struct razor_entry *) set->files.data + dir->start;
+       e = dir;
        do {
                n = pool + e->name;
                if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
@@ -544,7 +547,9 @@ list_dir(struct razor_set *set, struct razor_entry *dir,
                        char *sub = prefix + strlen (prefix);
                        *sub = '/';
                        strcpy (sub + 1, n);
-                       list_dir(set, e, prefix, pattern);
+                       subdir = (struct razor_entry *) set->files.data +
+                                e->start;
+                       list_dir(set, subdir, prefix, pattern);
                        *sub = '\0';
                }
        } while (!((e++)->flags & RAZOR_ENTRY_LAST));
@@ -553,20 +558,28 @@ list_dir(struct razor_set *set, struct razor_entry *dir,
 RAZOR_EXPORT void
 razor_set_list_files(struct razor_set *set, const char *pattern)
 {
-       struct razor_entry *e;
+       struct razor_entry *root, *e;
        char buffer[512], *p, *base;
 
        assert (set != NULL);
 
-       if (pattern == NULL || !strcmp (pattern, "/")) {
-               buffer[0] = '\0';
-               list_dir(set, set->files.data, buffer, NULL);
+       root = (struct razor_entry *) set->files.data;
+
+       if (pattern == NULL) {
+               p = set->file_string_pool.data;
+               e = root;
+               do {
+                       if (e->start) {
+                               strcpy(buffer, p + e->name);
+                               list_dir(set, root + e->start, buffer, NULL);
+                       }
+               } while (!((e++)->flags & RAZOR_ENTRY_LAST));
                return;
        }
 
        strcpy(buffer, pattern);
-       e = razor_set_find_entry(set, set->files.data, buffer);
-       if (e && e->start > 0) {
+       e = razor_set_find_entry(set, root, buffer);
+       if (e && e->start) {
                base = NULL;
        } else {
                p = strrchr(buffer, '/');
@@ -577,9 +590,9 @@ razor_set_list_files(struct razor_set *set, const char *pattern)
                        base = NULL;
                }
        }
-       e = razor_set_find_entry(set, set->files.data, buffer);
-       if (e && e->start != 0)
-               list_dir(set, e, buffer, base);
+       e = razor_set_find_entry(set, root, buffer);
+       if (e && e->start)
+               list_dir(set, root + e->start, buffer, base);
 }
 
 RAZOR_EXPORT void
index a9816a8..e7a0d25 100644 (file)
@@ -378,5 +378,7 @@ void razor_build_evr(char *evr_buf, int size, const char *epoch,
                     const char *version, const char *release);
 int razor_versioncmp(const char *s1, const char *s2);
 
+void razor_disable_root_name_checks(int disable);
+
 
 #endif /* _RAZOR_H_ */
index 51acc52..f2fa569 100644 (file)
@@ -380,8 +380,6 @@ razor_relocations_apply(struct razor_relocations *rr, const char *path)
 
 RAZOR_EXPORT void razor_relocations_destroy(struct razor_relocations *rr)
 {
-       printf("razor_relocations_destroy(rr=%p): path=%p, rel=%p\n",
-         rr,rr->path,rr->relocations);
        free(rr->path);
        free(rr->relocations);
        free(rr);
index e2652a7..5d1bc53 100644 (file)
 #include <errno.h>
 #include <unistd.h>
 #include <fcntl.h>
+#ifdef MSWIN_API
+#include <direct.h>
+#endif
 #if HAVE_SYS_MMAN_H
 #include <sys/mman.h>
 #endif
 
+#include "razor.h"
 #include "razor-internal.h"
 
 #ifndef O_BINARY
 #define O_BINARY       0
 #endif
 
+#define RAZOR_ASCII_ISALPHA(c) \
+                       ((c) >= 'A' && (c) <= 'Z' || (c) >= 'a' && (c) <= 'z')
+
 /* Required by gnulib on non-libc platforms */
 char *program_name = "librazor";
 
+static int allow_all_root_names = 0;
+
+/*
+ * Primarily intended for testing named roots under UNIX platforms.
+ */
+RAZOR_EXPORT void razor_disable_root_name_checks(int disable)
+{
+       allow_all_root_names = disable;
+}
+
+static int razor_valid_root_name(const char *name)
+{
+       if (allow_all_root_names)
+               return !strchr(name,'/');
+
+#ifdef MSWIN_API
+       return RAZOR_ASCII_ISALPHA(name[0]) && name[1] == ':' &&
+              name[2] == '\0';
+#else
+       return name[0] == '\0';
+#endif
+}
+
 int
 razor_create_dir(const char *root, const char *path)
 {
@@ -51,8 +81,9 @@ razor_create_dir(const char *root, const char *path)
        struct stat buf;
 
        /* Create all sub-directories in dir. We know root exists and
-        * is a dir, root does not end in a '/', and path has a
-        * leading '/'. */
+        * is a dir, root does not end in a '/', and path either has a
+        * leading '/' or (on MS-Windows only) root is the empty string
+        * and path starts with drive (eg., "c:/windows"). */
 
        strcpy(buffer, root);
        p = buffer + strlen(buffer);
@@ -66,6 +97,9 @@ razor_create_dir(const char *root, const char *path)
                p += next - slash;
                *p = '\0';
 
+               if (razor_valid_root_name(buffer))
+                       continue;
+
                if (stat(buffer, &buf) == 0) {
                        if (!S_ISDIR(buf.st_mode)) {
                                fprintf(stderr,
index e677c06..c9fb686 100644 (file)
@@ -1165,6 +1165,9 @@ main(int argc, const char *argv[])
        if (yum_url == NULL)
                yum_url = YUM_URL;
 
+       if (getenv("RAZOR_NO_ROOT_NAME_CHECKS"))
+               razor_disable_root_name_checks(1);
+
        if (argc < 2)
                return usage();
 
index 2963ff5..29e6b70 100644 (file)
@@ -1,6 +1,6 @@
 ## Process this file with automake to produce Makefile.in
 
-check_SCRIPTS = relocate
+check_SCRIPTS = relocate named-root
 if HAVE_LUA
   check_SCRIPTS += lua
 endif
@@ -8,6 +8,9 @@ endif
 relocate:      relocate.sh primary.xml.gz
        cp $(srcdir)/relocate.sh relocate
 
+named-root:    named-root.sh primary.xml.gz
+       cp $(srcdir)/named-root.sh named-root
+
 lua:   lua.sh primary.xml.gz
        cp $(srcdir)/lua.sh lua
 
@@ -32,6 +35,7 @@ EXTRA_DIST =                  \
        zsh.spec                \
        filesystem.spec         \
        lua.sh                  \
+       named-root.sh           \
        relocate.sh
 
 clean-local :
diff --git a/test/named-root.sh b/test/named-root.sh
new file mode 100755 (executable)
index 0000000..f85f42f
--- /dev/null
@@ -0,0 +1,53 @@
+#!/bin/sh
+check_file()
+{
+    ../src/razor list-files | grep -x "$1" > /dev/null
+    if [ $? -ne 0 ]; then
+       echo $1: Not in database >&2
+       ../src/razor list-files >&2
+       exit 1
+    fi
+    ../src/razor list-files c: | grep -x "$1" > /dev/null
+    if [ $? -ne 0 ]; then
+       echo $1: Not seen by named root list >&2
+       ../src/razor list-files c: >&2
+       exit 1
+    fi
+    ../src/razor list-files "$1" | grep -x "$1" > /dev/null
+    if [ $? -ne 0 ]; then
+       echo $1: Not seen by patterned list >&2
+       ../src/razor list-files "$1" >&2
+       exit 1
+    fi
+    pkgs=`../src/razor list-file-packages "$1"`
+    if [ -z "$pkgs" ]; then
+       echo $1: Not owned by any package >&2
+       ../src/razor list-file-packages "$1"
+       exit 1
+    fi
+    for nevra in "$pkgs"; do
+       name=`echo $nevra | sed 's/\-.*$//'`
+       ../src/razor list-package-files "$name" | grep -x "$1" > /dev/null
+       if [ $? -ne 0 ]; then
+           echo $1: Not in database for package $name >&2
+           ../src/razor list-package-files "$name"
+           exit 1
+       fi
+    done
+    if [ ! -e "$RAZOR_ROOT$1" ]; then 
+       echo $1: Not in filesystem >&2
+       exit 1
+    fi
+}
+tmpdir=`mktemp -dt` || exit 1
+export RAZOR_ROOT="$tmpdir/x-"
+mkdir -p "$tmpdir/x-/var/lib" "$tmpdir/x-c:"
+export RAZOR_NO_ROOT_NAME_CHECKS=1
+../src/razor init || exit 1
+export YUM_URL="file://localhost/`pwd`"
+../src/razor import-yum || exit 1
+../src/razor install --relocate /usr=c:/test zap || exit 1
+../src/razor install --relocate /usr=c:/test zip || exit 1
+check_file c:/test/bin/zap
+check_file c:/test/bin/zip
+rm -rf "$tmpdir"