core, pxe: Don't push on one stack and pop from the other in pxenv
[syslinux.git] / core / fs / chdir.c
blob276ea11ce751ff739becea16566a926df77c99e4
1 #include <stdio.h>
2 #include <stdbool.h>
3 #include <string.h>
4 #include <dprintf.h>
5 #include <fcntl.h>
6 #include "fs.h"
7 #include "cache.h"
9 /*
10 * Convert a relative pathname to an absolute pathname
11 * In the future this might also resolve symlinks...
13 void pm_realpath(com32sys_t *regs)
15 const char *src = MK_PTR(regs->ds, regs->esi.w[0]);
16 char *dst = MK_PTR(regs->es, regs->edi.w[0]);
18 realpath(dst, src, FILENAME_MAX);
21 static size_t copy_string(char *buf, size_t ix, size_t bufsize, const char *src)
23 char c;
25 while ((c = *src++)) {
26 if (ix+1 < bufsize)
27 buf[ix] = c;
28 ix++;
31 if (ix < bufsize)
32 buf[ix] = '\0';
34 return ix;
37 static size_t generic_inode_to_path(struct inode *inode, char *dst, size_t bufsize)
39 size_t s = 0;
41 dprintf("inode %p name %s\n", inode, inode->name);
43 if (inode->parent) {
44 if (!inode->name) /* Only the root should have no name */
45 return -1;
47 s = generic_inode_to_path(inode->parent, dst, bufsize);
48 if (s == (size_t)-1)
49 return s; /* Error! */
51 s = copy_string(dst, s, bufsize, "/");
52 s = copy_string(dst, s, bufsize, inode->name);
55 return s;
58 __export size_t realpath(char *dst, const char *src, size_t bufsize)
60 int rv;
61 struct file *file;
62 size_t s;
64 dprintf("realpath: input: %s\n", src);
66 if (this_fs->fs_ops->realpath) {
67 s = this_fs->fs_ops->realpath(this_fs, dst, src, bufsize);
68 } else {
69 rv = searchdir(src, O_RDONLY);
70 if (rv < 0) {
71 dprintf("realpath: searchpath failure\n");
72 return -1;
75 file = handle_to_file(rv);
76 s = generic_inode_to_path(file->inode, dst, bufsize);
77 if (s == 0)
78 s = copy_string(dst, 0, bufsize, "/");
80 _close_file(file);
83 dprintf("realpath: output: %s\n", dst);
84 return s;
87 __export int chdir(const char *src)
89 int rv;
90 struct file *file;
91 char cwd_buf[CURRENTDIR_MAX];
92 size_t s;
94 dprintf("chdir: from %s (inode %p) add %s\n",
95 this_fs->cwd_name, this_fs->cwd, src);
97 if (this_fs->fs_ops->chdir)
98 return this_fs->fs_ops->chdir(this_fs, src);
100 /* Otherwise it is a "conventional filesystem" */
101 rv = searchdir(src, O_RDONLY|O_DIRECTORY);
102 if (rv < 0)
103 return rv;
105 file = handle_to_file(rv);
106 if (file->inode->mode != DT_DIR) {
107 _close_file(file);
108 return -1;
111 put_inode(this_fs->cwd);
112 this_fs->cwd = get_inode(file->inode);
113 _close_file(file);
115 /* Save the current working directory */
116 s = generic_inode_to_path(this_fs->cwd, cwd_buf, CURRENTDIR_MAX-1);
118 /* Make sure the cwd_name ends in a slash, it's supposed to be a prefix */
119 if (s < 1 || cwd_buf[s-1] != '/')
120 cwd_buf[s++] = '/';
122 if (s >= CURRENTDIR_MAX)
123 s = CURRENTDIR_MAX - 1;
125 cwd_buf[s++] = '\0';
126 memcpy(this_fs->cwd_name, cwd_buf, s);
128 dprintf("chdir: final %s (inode %p)\n",
129 this_fs->cwd_name, this_fs->cwd);
131 return 0;