[syslinux:master] core, chdir: collapse slashes, avoid copy-to-self
syslinux-bot for H. Peter Anvin
hpa at zytor.com
Sun Jun 27 18:54:13 PDT 2010
Commit-ID: 7e63729cfd781f69f7cb47b85cf8b1fee6b3e62a
Gitweb: http://syslinux.zytor.com/commit/7e63729cfd781f69f7cb47b85cf8b1fee6b3e62a
Author: H. Peter Anvin <hpa at zytor.com>
AuthorDate: Sun, 27 Jun 2010 18:46:36 -0700
Committer: H. Peter Anvin <hpa at zytor.com>
CommitDate: Sun, 27 Jun 2010 18:46:36 -0700
core, chdir: collapse slashes, avoid copy-to-self
Collapse multiple slashes into one (this still doesn't resolve . and
.. in the path, since that requires awareness of symlinks.)
This code also avoids a copy-over-self bug by introducing a temporary
buffer.
Reported-by: Gene Cumm <gene.cumm at gmail.com>
Signed-off-by: H. Peter Anvin <hpa at zytor.com>
---
core/fs/chdir.c | 59 ++++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 48 insertions(+), 11 deletions(-)
diff --git a/core/fs/chdir.c b/core/fs/chdir.c
index bfce9bc..9e8dfd2 100644
--- a/core/fs/chdir.c
+++ b/core/fs/chdir.c
@@ -16,15 +16,56 @@ 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)
+{
+ const char *list[2];
+ int i;
+ char c;
+ const char *p;
+ char *q = dst;
+ size_t n = 0;
+ bool 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);
+ slash = true;
+ } else {
+ EMIT(c);
+ slash = false;
+ }
+ }
+ }
+
+ if (bufsize)
+ *q = '\0';
+
+ return n;
+}
+
size_t realpath(char *dst, const char *src, size_t bufsize)
{
if (this_fs->fs_ops->realpath) {
return this_fs->fs_ops->realpath(this_fs, dst, src, bufsize);
} else {
/* Filesystems with "common" pathname resolution */
- return snprintf(dst, bufsize, "%s%s",
- src[0] == '/' ? "" : this_fs->cwd_name,
- src);
+ return join_paths(dst, bufsize,
+ src[0] == '/' ? "" : this_fs->cwd_name,
+ src);
}
}
@@ -32,7 +73,7 @@ int chdir(const char *src)
{
int rv;
struct file *file;
- char *p;
+ char cwd_buf[CURRENTDIR_MAX];
if (this_fs->fs_ops->chdir)
return this_fs->fs_ops->chdir(this_fs, src);
@@ -53,14 +94,10 @@ int chdir(const char *src)
_close_file(file);
/* Save the current working directory */
- realpath(this_fs->cwd_name, src, CURRENTDIR_MAX);
- p = strchr(this_fs->cwd_name, '\0');
+ realpath(cwd_buf, src, CURRENTDIR_MAX);
/* Make sure the cwd_name ends in a slash, it's supposed to be a prefix */
- if (p < this_fs->cwd_name + CURRENTDIR_MAX - 1 &&
- (p == this_fs->cwd_name || p[1] != '/')) {
- p[0] = '/';
- p[1] = '\0';
- }
+ join_paths(this_fs->cwd_name, CURRENTDIR_MAX, cwd_buf, "/");
+
return 0;
}
More information about the Syslinux-commits
mailing list