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" |
---|
8 | |
---|
9 | /* |
---|
10 | * Convert a relative pathname to an absolute pathname |
---|
11 | * In the future this might also resolve symlinks... |
---|
12 | */ |
---|
13 | void pm_realpath(com32sys_t *regs) |
---|
14 | { |
---|
15 | const char *src = MK_PTR(regs->ds, regs->esi.w[0]); |
---|
16 | char *dst = MK_PTR(regs->es, regs->edi.w[0]); |
---|
17 | |
---|
18 | realpath(dst, src, FILENAME_MAX); |
---|
19 | } |
---|
20 | |
---|
21 | static size_t copy_string(char *buf, size_t ix, size_t bufsize, const char *src) |
---|
22 | { |
---|
23 | char c; |
---|
24 | |
---|
25 | while ((c = *src++)) { |
---|
26 | if (ix+1 < bufsize) |
---|
27 | buf[ix] = c; |
---|
28 | ix++; |
---|
29 | } |
---|
30 | |
---|
31 | if (ix < bufsize) |
---|
32 | buf[ix] = '\0'; |
---|
33 | |
---|
34 | return ix; |
---|
35 | } |
---|
36 | |
---|
37 | static size_t generic_inode_to_path(struct inode *inode, char *dst, size_t bufsize) |
---|
38 | { |
---|
39 | size_t s = 0; |
---|
40 | |
---|
41 | dprintf("inode %p name %s\n", inode, inode->name); |
---|
42 | |
---|
43 | if (inode->parent) { |
---|
44 | if (!inode->name) /* Only the root should have no name */ |
---|
45 | return -1; |
---|
46 | |
---|
47 | s = generic_inode_to_path(inode->parent, dst, bufsize); |
---|
48 | if (s == (size_t)-1) |
---|
49 | return s; /* Error! */ |
---|
50 | |
---|
51 | s = copy_string(dst, s, bufsize, "/"); |
---|
52 | s = copy_string(dst, s, bufsize, inode->name); |
---|
53 | } |
---|
54 | |
---|
55 | return s; |
---|
56 | } |
---|
57 | |
---|
58 | __export size_t realpath(char *dst, const char *src, size_t bufsize) |
---|
59 | { |
---|
60 | int rv; |
---|
61 | struct file *file; |
---|
62 | size_t s; |
---|
63 | |
---|
64 | dprintf("realpath: input: %s\n", src); |
---|
65 | |
---|
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; |
---|
73 | } |
---|
74 | |
---|
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, "/"); |
---|
79 | |
---|
80 | _close_file(file); |
---|
81 | } |
---|
82 | |
---|
83 | dprintf("realpath: output: %s\n", dst); |
---|
84 | return s; |
---|
85 | } |
---|
86 | |
---|
87 | __export int chdir(const char *src) |
---|
88 | { |
---|
89 | int rv; |
---|
90 | struct file *file; |
---|
91 | char cwd_buf[CURRENTDIR_MAX]; |
---|
92 | size_t s; |
---|
93 | |
---|
94 | dprintf("chdir: from %s (inode %p) add %s\n", |
---|
95 | this_fs->cwd_name, this_fs->cwd, src); |
---|
96 | |
---|
97 | if (this_fs->fs_ops->chdir) |
---|
98 | return this_fs->fs_ops->chdir(this_fs, src); |
---|
99 | |
---|
100 | /* Otherwise it is a "conventional filesystem" */ |
---|
101 | rv = searchdir(src, O_RDONLY|O_DIRECTORY); |
---|
102 | if (rv < 0) |
---|
103 | return rv; |
---|
104 | |
---|
105 | file = handle_to_file(rv); |
---|
106 | if (file->inode->mode != DT_DIR) { |
---|
107 | _close_file(file); |
---|
108 | return -1; |
---|
109 | } |
---|
110 | |
---|
111 | put_inode(this_fs->cwd); |
---|
112 | this_fs->cwd = get_inode(file->inode); |
---|
113 | _close_file(file); |
---|
114 | |
---|
115 | /* Save the current working directory */ |
---|
116 | s = generic_inode_to_path(this_fs->cwd, cwd_buf, CURRENTDIR_MAX-1); |
---|
117 | |
---|
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++] = '/'; |
---|
121 | |
---|
122 | if (s >= CURRENTDIR_MAX) |
---|
123 | s = CURRENTDIR_MAX - 1; |
---|
124 | |
---|
125 | cwd_buf[s++] = '\0'; |
---|
126 | memcpy(this_fs->cwd_name, cwd_buf, s); |
---|
127 | |
---|
128 | dprintf("chdir: final %s (inode %p)\n", |
---|
129 | this_fs->cwd_name, this_fs->cwd); |
---|
130 | |
---|
131 | return 0; |
---|
132 | } |
---|