summaryrefslogtreecommitdiffstats
path: root/contrib/syslinux-4.02/core/fs/chdir.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/syslinux-4.02/core/fs/chdir.c')
-rw-r--r--contrib/syslinux-4.02/core/fs/chdir.c103
1 files changed, 103 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/core/fs/chdir.c b/contrib/syslinux-4.02/core/fs/chdir.c
new file mode 100644
index 0000000..9e8dfd2
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/chdir.c
@@ -0,0 +1,103 @@
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include "fs.h"
+#include "cache.h"
+
+/*
+ * Convert a relative pathname to an absolute pathname
+ * In the future this might also resolve symlinks...
+ */
+void pm_realpath(com32sys_t *regs)
+{
+ const char *src = MK_PTR(regs->ds, regs->esi.w[0]);
+ char *dst = MK_PTR(regs->es, regs->edi.w[0]);
+
+ 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 join_paths(dst, bufsize,
+ src[0] == '/' ? "" : this_fs->cwd_name,
+ src);
+ }
+}
+
+int chdir(const char *src)
+{
+ int rv;
+ struct file *file;
+ char cwd_buf[CURRENTDIR_MAX];
+
+ if (this_fs->fs_ops->chdir)
+ return this_fs->fs_ops->chdir(this_fs, src);
+
+ /* Otherwise it is a "conventional filesystem" */
+ rv = searchdir(src);
+ if (rv < 0)
+ return rv;
+
+ file = handle_to_file(rv);
+ if (file->inode->mode != DT_DIR) {
+ _close_file(file);
+ return -1;
+ }
+
+ put_inode(this_fs->cwd);
+ this_fs->cwd = get_inode(file->inode);
+ _close_file(file);
+
+ /* Save the current working directory */
+ realpath(cwd_buf, src, CURRENTDIR_MAX);
+
+ /* 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, "/");
+
+ return 0;
+}