[syslinux:master] chdir: collapse /./ and /../ in path for conventional filesystems

syslinux-bot for H. Peter Anvin hpa at zytor.com
Thu Jun 28 17:27:06 PDT 2012


Commit-ID:  255fd8e592d2fb014e4a13a98655aed0bf9d6121
Gitweb:     http://www.syslinux.org/commit/255fd8e592d2fb014e4a13a98655aed0bf9d6121
Author:     H. Peter Anvin <hpa at zytor.com>
AuthorDate: Thu, 28 Jun 2012 17:26:19 -0700
Committer:  H. Peter Anvin <hpa at zytor.com>
CommitDate: Thu, 28 Jun 2012 17:26:49 -0700

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 <hpa at zytor.com>

---
 core/fs/chdir.c |   56 +++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files 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 <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;
 }


More information about the Syslinux-commits mailing list