rev |
line source |
pascal@13969
|
1 --- core/fs/fs.c
|
pascal@13969
|
2 +++ core/fs/fs.c
|
pascal@13969
|
3 @@ -1,10 +1,16 @@
|
pascal@13969
|
4 +#include <sys/file.h>
|
pascal@13969
|
5 #include <stdio.h>
|
pascal@13969
|
6 #include <stdbool.h>
|
pascal@13969
|
7 #include <string.h>
|
pascal@13969
|
8 +#include <unistd.h>
|
pascal@13969
|
9 #include <dprintf.h>
|
pascal@13969
|
10 +#include "core.h"
|
pascal@13969
|
11 +#include "dev.h"
|
pascal@13969
|
12 #include "fs.h"
|
pascal@13969
|
13 #include "cache.h"
|
pascal@13969
|
14
|
pascal@13969
|
15 +char *PATH;
|
pascal@13969
|
16 +
|
pascal@13969
|
17 /* The currently mounted filesystem */
|
pascal@13969
|
18 struct fs_info *this_fs = NULL; /* Root filesystem */
|
pascal@13969
|
19
|
pascal@13969
|
20 @@ -76,19 +82,30 @@
|
pascal@13969
|
21 }
|
pascal@13969
|
22
|
pascal@13969
|
23 /*
|
pascal@13969
|
24 - * Convert between a 16-bit file handle and a file structure
|
pascal@13969
|
25 + * Find and open the configuration file
|
pascal@13969
|
26 */
|
pascal@13969
|
27 -
|
pascal@13969
|
28 -void pm_load_config(com32sys_t *regs)
|
pascal@13969
|
29 +int open_config(void)
|
pascal@13969
|
30 {
|
pascal@13969
|
31 - int err;
|
pascal@13969
|
32 + int fd, handle;
|
pascal@13969
|
33 + struct file_info *fp;
|
pascal@13969
|
34
|
pascal@13969
|
35 - err = this_fs->fs_ops->load_config();
|
pascal@13969
|
36 + fd = opendev(&__file_dev, NULL, O_RDONLY);
|
pascal@13969
|
37 + if (fd < 0)
|
pascal@13969
|
38 + return -1;
|
pascal@13969
|
39
|
pascal@13969
|
40 - if (err)
|
pascal@13969
|
41 - printf("ERROR: No configuration file found\n");
|
pascal@13969
|
42 + fp = &__file_info[fd];
|
pascal@13969
|
43
|
pascal@13969
|
44 - set_flags(regs, err ? EFLAGS_ZF : 0);
|
pascal@13969
|
45 + handle = this_fs->fs_ops->open_config(&fp->i.fd);
|
pascal@13969
|
46 + if (handle < 0) {
|
pascal@13969
|
47 + close(fd);
|
pascal@13969
|
48 + errno = ENOENT;
|
pascal@13969
|
49 + return -1;
|
pascal@13969
|
50 + }
|
pascal@13969
|
51 +
|
pascal@13969
|
52 + fp->i.offset = 0;
|
pascal@13969
|
53 + fp->i.nbytes = 0;
|
pascal@13969
|
54 +
|
pascal@13969
|
55 + return fd;
|
pascal@13969
|
56 }
|
pascal@13969
|
57
|
pascal@13969
|
58 void pm_mangle_name(com32sys_t *regs)
|
pascal@13969
|
59 @@ -202,11 +219,10 @@
|
pascal@13969
|
60
|
pascal@13969
|
61 int searchdir(const char *name)
|
pascal@13969
|
62 {
|
pascal@13969
|
63 - struct inode *inode = NULL;
|
pascal@13969
|
64 - struct inode *parent = NULL;
|
pascal@13969
|
65 + static char root_name[] = "/";
|
pascal@13969
|
66 struct file *file;
|
pascal@13969
|
67 - char *pathbuf = NULL;
|
pascal@13969
|
68 - char *part, *p, echar;
|
pascal@13969
|
69 + char *path, *inode_name, *next_inode_name;
|
pascal@13969
|
70 + struct inode *tmp, *inode = NULL;
|
pascal@13969
|
71 int symlink_count = MAX_SYMLINK_CNT;
|
pascal@13969
|
72
|
pascal@13969
|
73 dprintf("searchdir: %s root: %p cwd: %p\n",
|
pascal@13969
|
74 @@ -228,113 +244,165 @@
|
pascal@13969
|
75
|
pascal@13969
|
76 /* else, try the generic-path-lookup method */
|
pascal@13969
|
77
|
pascal@13969
|
78 - parent = get_inode(this_fs->cwd);
|
pascal@13969
|
79 - p = pathbuf = strdup(name);
|
pascal@13969
|
80 - if (!pathbuf)
|
pascal@13969
|
81 - goto err;
|
pascal@13969
|
82 + /* Copy the path */
|
pascal@13969
|
83 + path = strdup(name);
|
pascal@13969
|
84 + if (!path) {
|
pascal@13969
|
85 + dprintf("searchdir: Couldn't copy path\n");
|
pascal@13969
|
86 + goto err_path;
|
pascal@13969
|
87 + }
|
pascal@13969
|
88
|
pascal@13969
|
89 - do {
|
pascal@13969
|
90 - got_link:
|
pascal@13969
|
91 - if (*p == '/') {
|
pascal@13969
|
92 - put_inode(parent);
|
pascal@13969
|
93 - parent = get_inode(this_fs->root);
|
pascal@13969
|
94 + /* Work with the current directory, by default */
|
pascal@13969
|
95 + inode = get_inode(this_fs->cwd);
|
pascal@13969
|
96 + if (!inode) {
|
pascal@13969
|
97 + dprintf("searchdir: Couldn't use current directory\n");
|
pascal@13969
|
98 + goto err_curdir;
|
pascal@13969
|
99 + }
|
pascal@13969
|
100 +
|
pascal@13969
|
101 + for (inode_name = path; inode_name; inode_name = next_inode_name) {
|
pascal@13969
|
102 + /* Root directory? */
|
pascal@13969
|
103 + if (inode_name[0] == '/') {
|
pascal@13969
|
104 + next_inode_name = inode_name + 1;
|
pascal@13969
|
105 + inode_name = root_name;
|
pascal@13969
|
106 + } else {
|
pascal@13969
|
107 + /* Find the next inode name */
|
pascal@13969
|
108 + next_inode_name = strchr(inode_name + 1, '/');
|
pascal@13969
|
109 + if (next_inode_name) {
|
pascal@13969
|
110 + /* Terminate the current inode name and point to next */
|
pascal@13969
|
111 + *next_inode_name++ = '\0';
|
pascal@13969
|
112 + }
|
pascal@13969
|
113 }
|
pascal@13969
|
114 + if (next_inode_name) {
|
pascal@13969
|
115 + /* Advance beyond redundant slashes */
|
pascal@13969
|
116 + while (*next_inode_name == '/')
|
pascal@13969
|
117 + next_inode_name++;
|
pascal@13969
|
118
|
pascal@13969
|
119 - do {
|
pascal@13969
|
120 - inode = get_inode(parent);
|
pascal@13969
|
121 + /* Check if we're at the end */
|
pascal@13969
|
122 + if (*next_inode_name == '\0')
|
pascal@13969
|
123 + next_inode_name = NULL;
|
pascal@13969
|
124 + }
|
pascal@13969
|
125 + dprintf("searchdir: inode_name: %s\n", inode_name);
|
pascal@13969
|
126 + if (next_inode_name)
|
pascal@13969
|
127 + dprintf("searchdir: Remaining: %s\n", next_inode_name);
|
pascal@13969
|
128
|
pascal@13969
|
129 - while (*p == '/')
|
pascal@13969
|
130 - p++;
|
pascal@13969
|
131 + /* Root directory? */
|
pascal@13969
|
132 + if (inode_name[0] == '/') {
|
pascal@13969
|
133 + /* Release any chain that's already been established */
|
pascal@13969
|
134 + put_inode(inode);
|
pascal@13969
|
135 + inode = get_inode(this_fs->root);
|
pascal@13969
|
136 + continue;
|
pascal@13969
|
137 + }
|
pascal@13969
|
138
|
pascal@13969
|
139 - if (!*p)
|
pascal@13969
|
140 - break;
|
pascal@13969
|
141 + /* Current directory? */
|
pascal@13969
|
142 + if (!strncmp(inode_name, ".", sizeof "."))
|
pascal@13969
|
143 + continue;
|
pascal@13969
|
144
|
pascal@13969
|
145 - part = p;
|
pascal@13969
|
146 - while ((echar = *p) && echar != '/')
|
pascal@13969
|
147 - p++;
|
pascal@13969
|
148 - *p++ = '\0';
|
pascal@13969
|
149 + /* Parent directory? */
|
pascal@13969
|
150 + if (!strncmp(inode_name, "..", sizeof "..")) {
|
pascal@13969
|
151 + /* If there is no parent, just ignore it */
|
pascal@13969
|
152 + if (!inode->parent)
|
pascal@13969
|
153 + continue;
|
pascal@13969
|
154
|
pascal@13969
|
155 - if (part[0] == '.' && part[1] == '.' && part[2] == '\0') {
|
pascal@13969
|
156 - if (inode->parent) {
|
pascal@13969
|
157 - put_inode(parent);
|
pascal@13969
|
158 - parent = get_inode(inode->parent);
|
pascal@13969
|
159 - put_inode(inode);
|
pascal@13969
|
160 - inode = NULL;
|
pascal@13969
|
161 - if (!echar) {
|
pascal@13969
|
162 - /* Terminal double dots */
|
pascal@13969
|
163 - inode = parent;
|
pascal@13969
|
164 - parent = inode->parent ?
|
pascal@13969
|
165 - get_inode(inode->parent) : NULL;
|
pascal@13969
|
166 - }
|
pascal@13969
|
167 - }
|
pascal@13969
|
168 - } else if (part[0] != '.' || part[1] != '\0') {
|
pascal@13969
|
169 - inode = this_fs->fs_ops->iget(part, parent);
|
pascal@13969
|
170 - if (!inode)
|
pascal@13969
|
171 - goto err;
|
pascal@13969
|
172 - if (inode->mode == DT_LNK) {
|
pascal@13969
|
173 - char *linkbuf, *q;
|
pascal@13969
|
174 - int name_len = echar ? strlen(p) : 0;
|
pascal@13969
|
175 - int total_len = inode->size + name_len + 2;
|
pascal@13969
|
176 - int link_len;
|
pascal@13969
|
177 + /* Add a reference to the parent so we can release the child */
|
pascal@13969
|
178 + tmp = get_inode(inode->parent);
|
pascal@13969
|
179
|
pascal@13969
|
180 - if (!this_fs->fs_ops->readlink ||
|
pascal@13969
|
181 - --symlink_count == 0 || /* limit check */
|
pascal@13969
|
182 - total_len > MAX_SYMLINK_BUF)
|
pascal@13969
|
183 - goto err;
|
pascal@13969
|
184 + /* Releasing the child will drop the parent back down to 1 */
|
pascal@13969
|
185 + put_inode(inode);
|
pascal@13969
|
186
|
pascal@13969
|
187 - linkbuf = malloc(total_len);
|
pascal@13969
|
188 - if (!linkbuf)
|
pascal@13969
|
189 - goto err;
|
pascal@13969
|
190 + inode = tmp;
|
pascal@13969
|
191 + continue;
|
pascal@13969
|
192 + }
|
pascal@13969
|
193
|
pascal@13969
|
194 - link_len = this_fs->fs_ops->readlink(inode, linkbuf);
|
pascal@13969
|
195 - if (link_len <= 0) {
|
pascal@13969
|
196 - free(linkbuf);
|
pascal@13969
|
197 - goto err;
|
pascal@13969
|
198 - }
|
pascal@13969
|
199 + /* Anything else */
|
pascal@13969
|
200 + tmp = inode;
|
pascal@13969
|
201 + inode = this_fs->fs_ops->iget(inode_name, inode);
|
pascal@13969
|
202 + if (!inode) {
|
pascal@13969
|
203 + /* Failure. Release the chain */
|
pascal@13969
|
204 + put_inode(tmp);
|
pascal@13969
|
205 + break;
|
pascal@13969
|
206 + }
|
pascal@13969
|
207
|
pascal@13969
|
208 - q = linkbuf + link_len;
|
pascal@13969
|
209 + /* Sanity-check */
|
pascal@13969
|
210 + if (inode->parent && inode->parent != tmp) {
|
pascal@13969
|
211 + dprintf("searchdir: iget returned a different parent\n");
|
pascal@13969
|
212 + put_inode(inode);
|
pascal@13969
|
213 + inode = NULL;
|
pascal@13969
|
214 + put_inode(tmp);
|
pascal@13969
|
215 + break;
|
pascal@13969
|
216 + }
|
pascal@13969
|
217 + inode->parent = tmp;
|
pascal@13969
|
218 + inode->name = strdup(inode_name);
|
pascal@13969
|
219 + dprintf("searchdir: path component: %s\n", inode->name);
|
pascal@13969
|
220
|
pascal@13969
|
221 - if (echar) {
|
pascal@13969
|
222 - if (link_len > 0 && q[-1] != '/')
|
pascal@13969
|
223 - *q++ = '/';
|
pascal@13969
|
224 + /* Symlink handling */
|
pascal@13969
|
225 + if (inode->mode == DT_LNK) {
|
pascal@13969
|
226 + char *new_path;
|
pascal@13969
|
227 + int new_len, copied;
|
pascal@13969
|
228
|
pascal@13969
|
229 - memcpy(q, p, name_len+1);
|
pascal@13969
|
230 - } else {
|
pascal@13969
|
231 - *q = '\0';
|
pascal@13969
|
232 - }
|
pascal@13969
|
233 + /* target path + NUL */
|
pascal@13969
|
234 + new_len = inode->size + 1;
|
pascal@13969
|
235
|
pascal@13969
|
236 - free(pathbuf);
|
pascal@13969
|
237 - p = pathbuf = linkbuf;
|
pascal@13969
|
238 - put_inode(inode);
|
pascal@13969
|
239 - inode = NULL;
|
pascal@13969
|
240 - goto got_link;
|
pascal@13969
|
241 - }
|
pascal@13969
|
242 + if (next_inode_name) {
|
pascal@13969
|
243 + /* target path + slash + remaining + NUL */
|
pascal@13969
|
244 + new_len += strlen(next_inode_name) + 1;
|
pascal@13969
|
245 + }
|
pascal@13969
|
246
|
pascal@13969
|
247 - inode->name = strdup(part);
|
pascal@13969
|
248 - dprintf("path component: %s\n", inode->name);
|
pascal@13969
|
249 + if (!this_fs->fs_ops->readlink ||
|
pascal@13969
|
250 + /* limit checks */
|
pascal@13969
|
251 + --symlink_count == 0 ||
|
pascal@13969
|
252 + new_len > MAX_SYMLINK_BUF)
|
pascal@13969
|
253 + goto err_new_len;
|
pascal@13969
|
254
|
pascal@13969
|
255 - inode->parent = parent;
|
pascal@13969
|
256 - parent = NULL;
|
pascal@13969
|
257 + new_path = malloc(new_len);
|
pascal@13969
|
258 + if (!new_path)
|
pascal@13969
|
259 + goto err_new_path;
|
pascal@13969
|
260
|
pascal@13969
|
261 - if (!echar)
|
pascal@13969
|
262 - break;
|
pascal@13969
|
263 + copied = this_fs->fs_ops->readlink(inode, new_path);
|
pascal@13969
|
264 + if (copied <= 0)
|
pascal@13969
|
265 + goto err_copied;
|
pascal@13969
|
266 + new_path[copied] = '\0';
|
pascal@13969
|
267 + dprintf("searchdir: Symlink: %s\n", new_path);
|
pascal@13969
|
268
|
pascal@13969
|
269 - if (inode->mode != DT_DIR)
|
pascal@13969
|
270 - goto err;
|
pascal@13969
|
271 -
|
pascal@13969
|
272 - parent = inode;
|
pascal@13969
|
273 - inode = NULL;
|
pascal@13969
|
274 + if (next_inode_name) {
|
pascal@13969
|
275 + new_path[copied] = '/';
|
pascal@13969
|
276 + strcpy(new_path + copied + 1, next_inode_name);
|
pascal@13969
|
277 + dprintf("searchdir: New path: %s\n", new_path);
|
pascal@13969
|
278 }
|
pascal@13969
|
279 - } while (echar);
|
pascal@13969
|
280 - } while (0);
|
pascal@13969
|
281
|
pascal@13969
|
282 - free(pathbuf);
|
pascal@13969
|
283 - pathbuf = NULL;
|
pascal@13969
|
284 - put_inode(parent);
|
pascal@13969
|
285 - parent = NULL;
|
pascal@13969
|
286 + free(path);
|
pascal@13969
|
287 + path = next_inode_name = new_path;
|
pascal@13969
|
288
|
pascal@13969
|
289 - if (!inode)
|
pascal@13969
|
290 + /* Add a reference to the parent so we can release the child */
|
pascal@13969
|
291 + tmp = get_inode(inode->parent);
|
pascal@13969
|
292 +
|
pascal@13969
|
293 + /* Releasing the child will drop the parent back down to 1 */
|
pascal@13969
|
294 + put_inode(inode);
|
pascal@13969
|
295 +
|
pascal@13969
|
296 + inode = tmp;
|
pascal@13969
|
297 + continue;
|
pascal@13969
|
298 +err_copied:
|
pascal@13969
|
299 + free(new_path);
|
pascal@13969
|
300 +err_new_path:
|
pascal@13969
|
301 +err_new_len:
|
pascal@13969
|
302 + put_inode(inode);
|
pascal@13969
|
303 + inode = NULL;
|
pascal@13969
|
304 + break;
|
pascal@13969
|
305 + }
|
pascal@13969
|
306 +
|
pascal@13969
|
307 + /* If there's more to process, this should be a directory */
|
pascal@13969
|
308 + if (next_inode_name && inode->mode != DT_DIR) {
|
pascal@13969
|
309 + dprintf("searchdir: Expected a directory\n");
|
pascal@13969
|
310 + put_inode(inode);
|
pascal@13969
|
311 + inode = NULL;
|
pascal@13969
|
312 + break;
|
pascal@13969
|
313 + }
|
pascal@13969
|
314 + }
|
pascal@13969
|
315 +err_curdir:
|
pascal@13969
|
316 + free(path);
|
pascal@13969
|
317 +err_path:
|
pascal@13969
|
318 + if (!inode) {
|
pascal@13969
|
319 + dprintf("searchdir: Not found\n");
|
pascal@13969
|
320 goto err;
|
pascal@13969
|
321 + }
|
pascal@13969
|
322
|
pascal@13969
|
323 file->inode = inode;
|
pascal@13969
|
324 file->offset = 0;
|
pascal@13969
|
325 @@ -342,10 +410,6 @@
|
pascal@13969
|
326 return file_to_handle(file);
|
pascal@13969
|
327
|
pascal@13969
|
328 err:
|
pascal@13969
|
329 - put_inode(inode);
|
pascal@13969
|
330 - put_inode(parent);
|
pascal@13969
|
331 - if (pathbuf)
|
pascal@13969
|
332 - free(pathbuf);
|
pascal@13969
|
333 _close_file(file);
|
pascal@13969
|
334 err_no_close:
|
pascal@13969
|
335 return -1;
|
pascal@13969
|
336 @@ -483,6 +547,11 @@
|
pascal@13969
|
337 fs.root = fs.fs_ops->iget_root(&fs);
|
pascal@13969
|
338 fs.cwd = get_inode(fs.root);
|
pascal@13969
|
339 dprintf("init: root inode %p, cwd inode %p\n", fs.root, fs.cwd);
|
pascal@13969
|
340 + }
|
pascal@13969
|
341 +
|
pascal@13969
|
342 + if (fs.fs_ops->chdir_start) {
|
pascal@13969
|
343 + if (fs.fs_ops->chdir_start() < 0)
|
pascal@13969
|
344 + printf("Failed to chdir to start directory\n");
|
pascal@13969
|
345 }
|
pascal@13969
|
346
|
pascal@13969
|
347 SectorShift = fs.sector_shift;
|