# HG changeset patch # User Pascal Bellard # Date 1359909336 -3600 # Node ID c47262ac1b57a8c93267fd69b9772e8521fe067e # Parent 108b6ea76839078f918c24a604c6ba377be74779 syslinux: add 5.0 searchdir resource leak fix diff -r 108b6ea76839 -r c47262ac1b57 syslinux/receipt --- a/syslinux/receipt Fri Feb 01 17:38:08 2013 -0200 +++ b/syslinux/receipt Sun Feb 03 17:35:36 2013 +0100 @@ -16,8 +16,9 @@ compile_rules() { cd $src - #patch -p 0 < $stuff/extra/iso9660.u + patch -p 0 < $stuff/extra/iso9660.u patch -p 0 < $stuff/extra/readconfig.u + patch -p 0 < $stuff/extra/fs.u cp -a $stuff/iso2exe . make -C iso2exe cp $stuff/tools/isohybrid.sh . diff -r 108b6ea76839 -r c47262ac1b57 syslinux/stuff/extra/fs.u --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/syslinux/stuff/extra/fs.u Sun Feb 03 17:35:36 2013 +0100 @@ -0,0 +1,347 @@ +--- core/fs/fs.c ++++ core/fs/fs.c +@@ -1,10 +1,16 @@ ++#include + #include + #include + #include ++#include + #include ++#include "core.h" ++#include "dev.h" + #include "fs.h" + #include "cache.h" + ++char *PATH; ++ + /* The currently mounted filesystem */ + struct fs_info *this_fs = NULL; /* Root filesystem */ + +@@ -76,19 +82,30 @@ + } + + /* +- * Convert between a 16-bit file handle and a file structure ++ * Find and open the configuration file + */ +- +-void pm_load_config(com32sys_t *regs) ++int open_config(void) + { +- int err; ++ int fd, handle; ++ struct file_info *fp; + +- err = this_fs->fs_ops->load_config(); ++ fd = opendev(&__file_dev, NULL, O_RDONLY); ++ if (fd < 0) ++ return -1; + +- if (err) +- printf("ERROR: No configuration file found\n"); ++ fp = &__file_info[fd]; + +- set_flags(regs, err ? EFLAGS_ZF : 0); ++ handle = this_fs->fs_ops->open_config(&fp->i.fd); ++ if (handle < 0) { ++ close(fd); ++ errno = ENOENT; ++ return -1; ++ } ++ ++ fp->i.offset = 0; ++ fp->i.nbytes = 0; ++ ++ return fd; + } + + void pm_mangle_name(com32sys_t *regs) +@@ -202,11 +219,10 @@ + + int searchdir(const char *name) + { +- struct inode *inode = NULL; +- struct inode *parent = NULL; ++ static char root_name[] = "/"; + struct file *file; +- char *pathbuf = NULL; +- char *part, *p, echar; ++ char *path, *inode_name, *next_inode_name; ++ struct inode *tmp, *inode = NULL; + int symlink_count = MAX_SYMLINK_CNT; + + dprintf("searchdir: %s root: %p cwd: %p\n", +@@ -228,113 +244,165 @@ + + /* else, try the generic-path-lookup method */ + +- parent = get_inode(this_fs->cwd); +- p = pathbuf = strdup(name); +- if (!pathbuf) +- goto err; ++ /* Copy the path */ ++ path = strdup(name); ++ if (!path) { ++ dprintf("searchdir: Couldn't copy path\n"); ++ goto err_path; ++ } + +- do { +- got_link: +- if (*p == '/') { +- put_inode(parent); +- parent = get_inode(this_fs->root); ++ /* Work with the current directory, by default */ ++ inode = get_inode(this_fs->cwd); ++ if (!inode) { ++ dprintf("searchdir: Couldn't use current directory\n"); ++ goto err_curdir; ++ } ++ ++ for (inode_name = path; inode_name; inode_name = next_inode_name) { ++ /* Root directory? */ ++ if (inode_name[0] == '/') { ++ next_inode_name = inode_name + 1; ++ inode_name = root_name; ++ } else { ++ /* Find the next inode name */ ++ next_inode_name = strchr(inode_name + 1, '/'); ++ if (next_inode_name) { ++ /* Terminate the current inode name and point to next */ ++ *next_inode_name++ = '\0'; ++ } + } ++ if (next_inode_name) { ++ /* Advance beyond redundant slashes */ ++ while (*next_inode_name == '/') ++ next_inode_name++; + +- do { +- inode = get_inode(parent); ++ /* Check if we're at the end */ ++ if (*next_inode_name == '\0') ++ next_inode_name = NULL; ++ } ++ dprintf("searchdir: inode_name: %s\n", inode_name); ++ if (next_inode_name) ++ dprintf("searchdir: Remaining: %s\n", next_inode_name); + +- while (*p == '/') +- p++; ++ /* Root directory? */ ++ if (inode_name[0] == '/') { ++ /* Release any chain that's already been established */ ++ put_inode(inode); ++ inode = get_inode(this_fs->root); ++ continue; ++ } + +- if (!*p) +- break; ++ /* Current directory? */ ++ if (!strncmp(inode_name, ".", sizeof ".")) ++ continue; + +- part = p; +- while ((echar = *p) && echar != '/') +- p++; +- *p++ = '\0'; ++ /* Parent directory? */ ++ if (!strncmp(inode_name, "..", sizeof "..")) { ++ /* If there is no parent, just ignore it */ ++ if (!inode->parent) ++ continue; + +- if (part[0] == '.' && part[1] == '.' && part[2] == '\0') { +- if (inode->parent) { +- put_inode(parent); +- parent = get_inode(inode->parent); +- put_inode(inode); +- inode = NULL; +- if (!echar) { +- /* Terminal double dots */ +- inode = parent; +- parent = inode->parent ? +- get_inode(inode->parent) : NULL; +- } +- } +- } else if (part[0] != '.' || part[1] != '\0') { +- inode = this_fs->fs_ops->iget(part, parent); +- if (!inode) +- goto err; +- if (inode->mode == DT_LNK) { +- char *linkbuf, *q; +- int name_len = echar ? strlen(p) : 0; +- int total_len = inode->size + name_len + 2; +- int link_len; ++ /* Add a reference to the parent so we can release the child */ ++ tmp = get_inode(inode->parent); + +- if (!this_fs->fs_ops->readlink || +- --symlink_count == 0 || /* limit check */ +- total_len > MAX_SYMLINK_BUF) +- goto err; ++ /* Releasing the child will drop the parent back down to 1 */ ++ put_inode(inode); + +- linkbuf = malloc(total_len); +- if (!linkbuf) +- goto err; ++ inode = tmp; ++ continue; ++ } + +- link_len = this_fs->fs_ops->readlink(inode, linkbuf); +- if (link_len <= 0) { +- free(linkbuf); +- goto err; +- } ++ /* Anything else */ ++ tmp = inode; ++ inode = this_fs->fs_ops->iget(inode_name, inode); ++ if (!inode) { ++ /* Failure. Release the chain */ ++ put_inode(tmp); ++ break; ++ } + +- q = linkbuf + link_len; ++ /* Sanity-check */ ++ if (inode->parent && inode->parent != tmp) { ++ dprintf("searchdir: iget returned a different parent\n"); ++ put_inode(inode); ++ inode = NULL; ++ put_inode(tmp); ++ break; ++ } ++ inode->parent = tmp; ++ inode->name = strdup(inode_name); ++ dprintf("searchdir: path component: %s\n", inode->name); + +- if (echar) { +- if (link_len > 0 && q[-1] != '/') +- *q++ = '/'; ++ /* Symlink handling */ ++ if (inode->mode == DT_LNK) { ++ char *new_path; ++ int new_len, copied; + +- memcpy(q, p, name_len+1); +- } else { +- *q = '\0'; +- } ++ /* target path + NUL */ ++ new_len = inode->size + 1; + +- free(pathbuf); +- p = pathbuf = linkbuf; +- put_inode(inode); +- inode = NULL; +- goto got_link; +- } ++ if (next_inode_name) { ++ /* target path + slash + remaining + NUL */ ++ new_len += strlen(next_inode_name) + 1; ++ } + +- inode->name = strdup(part); +- dprintf("path component: %s\n", inode->name); ++ if (!this_fs->fs_ops->readlink || ++ /* limit checks */ ++ --symlink_count == 0 || ++ new_len > MAX_SYMLINK_BUF) ++ goto err_new_len; + +- inode->parent = parent; +- parent = NULL; ++ new_path = malloc(new_len); ++ if (!new_path) ++ goto err_new_path; + +- if (!echar) +- break; ++ copied = this_fs->fs_ops->readlink(inode, new_path); ++ if (copied <= 0) ++ goto err_copied; ++ new_path[copied] = '\0'; ++ dprintf("searchdir: Symlink: %s\n", new_path); + +- if (inode->mode != DT_DIR) +- goto err; +- +- parent = inode; +- inode = NULL; ++ if (next_inode_name) { ++ new_path[copied] = '/'; ++ strcpy(new_path + copied + 1, next_inode_name); ++ dprintf("searchdir: New path: %s\n", new_path); + } +- } while (echar); +- } while (0); + +- free(pathbuf); +- pathbuf = NULL; +- put_inode(parent); +- parent = NULL; ++ free(path); ++ path = next_inode_name = new_path; + +- if (!inode) ++ /* Add a reference to the parent so we can release the child */ ++ tmp = get_inode(inode->parent); ++ ++ /* Releasing the child will drop the parent back down to 1 */ ++ put_inode(inode); ++ ++ inode = tmp; ++ continue; ++err_copied: ++ free(new_path); ++err_new_path: ++err_new_len: ++ put_inode(inode); ++ inode = NULL; ++ break; ++ } ++ ++ /* If there's more to process, this should be a directory */ ++ if (next_inode_name && inode->mode != DT_DIR) { ++ dprintf("searchdir: Expected a directory\n"); ++ put_inode(inode); ++ inode = NULL; ++ break; ++ } ++ } ++err_curdir: ++ free(path); ++err_path: ++ if (!inode) { ++ dprintf("searchdir: Not found\n"); + goto err; ++ } + + file->inode = inode; + file->offset = 0; +@@ -342,10 +410,6 @@ + return file_to_handle(file); + + err: +- put_inode(inode); +- put_inode(parent); +- if (pathbuf) +- free(pathbuf); + _close_file(file); + err_no_close: + return -1; +@@ -483,6 +547,11 @@ + 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); ++ } ++ ++ if (fs.fs_ops->chdir_start) { ++ if (fs.fs_ops->chdir_start() < 0) ++ printf("Failed to chdir to start directory\n"); + } + + SectorShift = fs.sector_shift;