aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2012-06-28 17:26:19 -0700
committerH. Peter Anvin <hpa@zytor.com>2012-06-28 17:26:49 -0700
commit255fd8e592d2fb014e4a13a98655aed0bf9d6121 (patch)
treefe50e90ccbff46a2a03ef28dac03e2059dd667b3
parent2a2fd4f65be041d467532c0f19325978dbda7a5b (diff)
downloadsyslinux-255fd8e592d2fb014e4a13a98655aed0bf9d6121.tar.gz
syslinux-255fd8e592d2fb014e4a13a98655aed0bf9d6121.tar.xz
syslinux-255fd8e592d2fb014e4a13a98655aed0bf9d6121.zip
chdir: collapse /./ and /../ in path for conventional filesystemssyslinux-4.06-pre8
For conventional filesystems (i.e. not PXE), collapse /./ and /../ in the path when doing chdir. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--core/fs/chdir.c56
1 files changed, 50 insertions, 6 deletions
diff --git a/core/fs/chdir.c b/core/fs/chdir.c
index 9e8dfd2e..c40e91bf 100644
--- a/core/fs/chdir.c
+++ b/core/fs/chdir.c
@@ -1,6 +1,7 @@
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
+#include <dprintf.h>
#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;
}