Actually keep track of the pathnames for all elements syslinux-4.06-pre9
authorH. Peter Anvin <hpa@zytor.com>
Fri, 29 Jun 2012 02:33:16 +0000 (19:33 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Fri, 29 Jun 2012 02:33:16 +0000 (19:33 -0700)
Actually keep track of the pathnames for all elements for on-disk
filesystems.  This makes sure we can always reconstruct the correct
path.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
core/fs/chdir.c
core/fs/fs.c
core/fs/lib/searchconfig.c
core/include/fs.h

index c40e91b..903cabc 100644 (file)
@@ -17,96 +17,70 @@ void pm_realpath(com32sys_t *regs)
     realpath(dst, src, FILENAME_MAX);
 }
 
-#define EMIT(x)                                \
-do {                                   \
-    if (++n < bufsize)                 \
-       *q++ = (x);                     \
-} while (0)
-
-
-static size_t join_paths(char *dst, size_t bufsize,
-                        const char *s1, const char *s2)
+static size_t copy_string(char *buf, size_t ix, size_t bufsize, const char *src)
 {
-    const char *list[2];
-    int i;
     char c;
-    const char *p;
-    char *q  = dst;
-    size_t n = 0;
-    bool slash;
-    struct bufstat {
-       struct bufstat *prev;
-       size_t n;
-       char *q;
-    };
-    struct bufstat *stk = NULL;
-    struct bufstat *bp;
-    
-    slash = false;
-
-    list[0] = s1;
-    list[1] = s2;
-
-    for (i = 0; i < 2; i++) {
-       p = list[i];
-
-       while ((c = *p++)) {
-           if (c == '/') {
-               if (!slash) {
-                   EMIT(c);
-                   bp = malloc(sizeof *bp);
-                   bp->n = n;
-                   bp->q = q;
-                   bp->prev = stk;
-                   stk = bp;
-               }
-               slash = true;
-           } else if (c == '.' && slash) {
-               if (!*p || *p == '/') {
-                   continue;   /* Single dot */
-               }
-               if (*p == '.' && (!p[1] || p[1] == '/')) {
-                   /* Double dot; unwind one level */
-                   p++;
-                   if (stk) {
-                       bp = stk;
-                       stk = stk->prev;
-                       free(bp);
-                   }
-                   if (stk) {
-                       n = stk->n;
-                       q = stk->q;
-                   }
-                   continue;
-               }
-           } else {
-               EMIT(c);
-               slash = false;
-           }
-       }
+
+    while ((c = *src++)) {
+       if (ix+1 < bufsize)
+           buf[ix] = c;
+       ix++;
     }
 
-    if (bufsize)
-       *q = '\0';
+    if (ix < bufsize)
+       buf[ix] = '\0';
+
+    return ix;
+}
+
+static size_t generic_inode_to_path(struct inode *inode, char *dst, size_t bufsize)
+{
+    size_t s = 0;
+
+    dprintf("inode %p name %s\n", inode, inode->name);
+
+    if (inode->parent) {
+       if (!inode->name)       /* Only the root should have no name */
+           return -1;
+
+       s = generic_inode_to_path(inode->parent, dst, bufsize);
+       if (s == (size_t)-1)
+           return s;           /* Error! */
 
-    while ((bp = stk)) {
-       stk = stk->prev;
-       free(bp);
+       s = copy_string(dst, s, bufsize, "/");
+       s = copy_string(dst, s, bufsize, inode->name);
     }
 
-    return n;
+    return s;
 }
 
 size_t realpath(char *dst, const char *src, size_t bufsize)
 {
+    int rv;
+    struct file *file;
+    size_t s;
+
+    dprintf("realpath: input: %s\n", src);
+
     if (this_fs->fs_ops->realpath) {
-       return this_fs->fs_ops->realpath(this_fs, dst, src, bufsize);
+       s = this_fs->fs_ops->realpath(this_fs, dst, src, bufsize);
     } else {
-       /* Filesystems with "common" pathname resolution */
-       return join_paths(dst, bufsize, 
-                         src[0] == '/' ? "" : this_fs->cwd_name,
-                         src);
+       rv = searchdir(src);
+       if (rv < 0) {
+           dprintf("realpath: searchpath failure\n");
+           return -1;
+       }
+
+       file = handle_to_file(rv);
+       s = generic_inode_to_path(file->inode, dst, bufsize);
+       if (s == 0)
+           s = copy_string(dst, 0, bufsize, "/");
+
+       _close_file(file);
     }
+
+    dprintf("realpath: output: %s\n", dst);
+    return s;
 }
 
 int chdir(const char *src)
@@ -114,8 +88,10 @@ int chdir(const char *src)
     int rv;
     struct file *file;
     char cwd_buf[CURRENTDIR_MAX];
+    size_t s;
 
-    dprintf("chdir: from %s add %s\n", this_fs->cwd_name, src);
+    dprintf("chdir: from %s (inode %p) add %s\n",
+           this_fs->cwd_name, this_fs->cwd, src);
 
     if (this_fs->fs_ops->chdir)
        return this_fs->fs_ops->chdir(this_fs, src);
@@ -136,12 +112,20 @@ int chdir(const char *src)
     _close_file(file);
 
     /* Save the current working directory */
-    realpath(cwd_buf, src, CURRENTDIR_MAX);
+    s = generic_inode_to_path(this_fs->cwd, cwd_buf, CURRENTDIR_MAX-1);
 
     /* Make sure the cwd_name ends in a slash, it's supposed to be a prefix */
-    join_paths(this_fs->cwd_name, CURRENTDIR_MAX, cwd_buf, "/");
+    if (s < 1 || cwd_buf[s-1] != '/')
+       cwd_buf[s++] = '/';
+
+    if (s >= CURRENTDIR_MAX)
+       s = CURRENTDIR_MAX - 1;
+
+    cwd_buf[s++] = '\0';
+    memcpy(this_fs->cwd_name, cwd_buf, s);
 
-    dprintf("chdir: final: %s\n", this_fs->cwd_name);
+    dprintf("chdir: final %s (inode %p)\n",
+           this_fs->cwd_name, this_fs->cwd);
 
     return 0;
 }
index ad2fb37..21f5dba 100644 (file)
@@ -37,6 +37,8 @@ void put_inode(struct inode *inode)
     while (inode && --inode->refcnt == 0) {
        struct inode *dead = inode;
        inode = inode->parent;
+       if (dead->name)
+           free((char *)dead->name);
        free(dead);
     }
 }
@@ -207,6 +209,9 @@ int searchdir(const char *name)
     char *part, *p, echar;
     int symlink_count = MAX_SYMLINK_CNT;
 
+    dprintf("searchdir: %s  root: %p  cwd: %p\n",
+           name, this_fs->root, this_fs->cwd);
+
     if (!(file = alloc_file()))
        goto err_no_close;
     file->fs = this_fs;
@@ -305,6 +310,9 @@ int searchdir(const char *name)
                    goto got_link;
                }
 
+               inode->name = strdup(part);
+               dprintf("path component: %s\n", inode->name);
+
                inode->parent = parent;
                parent = NULL;
 
@@ -349,6 +357,8 @@ int open_file(const char *name, struct com32_filedata *filedata)
     struct file *file;
     char mangled_name[FILENAME_MAX];
 
+    dprintf("open_file %s\n", name);
+
     mangle_name(mangled_name, name);
     rv = searchdir(mangled_name);
 
@@ -376,6 +386,8 @@ void pm_open_file(com32sys_t *regs)
     const char *name = MK_PTR(regs->es, regs->esi.w[0]);
     char mangled_name[FILENAME_MAX];
 
+    dprintf("pm_open_file %s\n", name);
+
     mangle_name(mangled_name, name);
     rv = searchdir(mangled_name);
     if (rv < 0) {
@@ -470,6 +482,7 @@ void fs_init(com32sys_t *regs)
     if (fs.fs_ops->iget_root) {
        fs.root = fs.fs_ops->iget_root(&fs);
        fs.cwd = get_inode(fs.root);
+       dprintf("init: root inode %p, cwd inode %p\n", fs.root, fs.cwd);
     }
 
     SectorShift = fs.sector_shift;
index 24bfde3..f18836a 100644 (file)
@@ -25,7 +25,8 @@ int search_config(const char *search_directories[], const char *filenames[])
                     "%s%s%s",
                     sd, (*sd && sd[strlen(sd)-1] == '/') ? "" : "/",
                     sf);
-           realpath(ConfigName, confignamebuf, FILENAME_MAX);
+           if (realpath(ConfigName, confignamebuf, FILENAME_MAX) == (size_t)-1)
+               continue;
            regs.edi.w[0] = OFFS_WRT(ConfigName, 0);
            dprintf("Config search: %s\n", ConfigName);
            call16(core_open, &regs, &regs);
index ecd148d..e1f5733 100644 (file)
@@ -95,6 +95,7 @@ struct extent {
 struct inode {
     struct fs_info *fs;         /* The filesystem this inode is associated with */
     struct inode *parent;      /* Parent directory, if any */
+    const char *name;          /* Name, valid for generic path search only */
     int                 refcnt;
     int          mode;   /* FILE , DIR or SYMLINK */
     uint32_t     size;