From 255fd8e592d2fb014e4a13a98655aed0bf9d6121 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Thu, 28 Jun 2012 17:26:19 -0700 Subject: [PATCH] chdir: collapse /./ and /../ in path for conventional filesystems For conventional filesystems (i.e. not PXE), collapse /./ and /../ in the path when doing chdir. Signed-off-by: H. Peter Anvin --- core/fs/chdir.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/core/fs/chdir.c b/core/fs/chdir.c index 9e8dfd2..c40e91b 100644 --- a/core/fs/chdir.c +++ b/core/fs/chdir.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "fs.h" #include "cache.h" @@ -16,12 +17,13 @@ void pm_realpath(com32sys_t *regs) realpath(dst, src, FILENAME_MAX); } -#define EMIT(x) \ -do { \ - if (++n < bufsize) \ - *q++ = (x); \ +#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) { @@ -31,8 +33,17 @@ static size_t join_paths(char *dst, size_t bufsize, const char *p; char *q = dst; size_t n = 0; - bool slash = false; + 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; @@ -41,9 +52,33 @@ static size_t join_paths(char *dst, size_t bufsize, while ((c = *p++)) { if (c == '/') { - if (!slash) + 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; @@ -54,6 +89,11 @@ static size_t join_paths(char *dst, size_t bufsize, if (bufsize) *q = '\0'; + while ((bp = stk)) { + stk = stk->prev; + free(bp); + } + return n; } @@ -75,6 +115,8 @@ int chdir(const char *src) struct file *file; char cwd_buf[CURRENTDIR_MAX]; + dprintf("chdir: from %s add %s\n", this_fs->cwd_name, src); + if (this_fs->fs_ops->chdir) return this_fs->fs_ops->chdir(this_fs, src); @@ -99,5 +141,7 @@ int chdir(const char *src) /* 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, "/"); + dprintf("chdir: final: %s\n", this_fs->cwd_name); + return 0; } -- 2.7.4