Adding upstream version 4.01+dfsg.
[syslinux-debian/hramrach.git] / core / fs / fs.c
blob48856c9ed66c13efe2312fc83fe2e8b4c6dc129c
1 #include <stdio.h>
2 #include <stdbool.h>
3 #include <string.h>
4 #include <dprintf.h>
5 #include "fs.h"
6 #include "cache.h"
8 /* The currently mounted filesystem */
9 struct fs_info *this_fs = NULL; /* Root filesystem */
11 /* Actual file structures (we don't have malloc yet...) */
12 struct file files[MAX_OPEN];
14 /* Symlink hard limits */
15 #define MAX_SYMLINK_CNT 20
16 #define MAX_SYMLINK_BUF 4096
19 * Get a new inode structure
21 struct inode *alloc_inode(struct fs_info *fs, uint32_t ino, size_t data)
23 struct inode *inode = zalloc(sizeof(struct inode) + data);
24 if (inode) {
25 inode->fs = fs;
26 inode->ino = ino;
27 inode->refcnt = 1;
29 return inode;
33 * Free a refcounted inode
35 void put_inode(struct inode *inode)
37 while (inode && --inode->refcnt == 0) {
38 struct inode *dead = inode;
39 inode = inode->parent;
40 free(dead);
45 * Get an empty file structure
47 static struct file *alloc_file(void)
49 int i;
50 struct file *file = files;
52 for (i = 0; i < MAX_OPEN; i++) {
53 if (!file->fs)
54 return file;
55 file++;
58 return NULL;
62 * Close and free a file structure
64 static inline void free_file(struct file *file)
66 memset(file, 0, sizeof *file);
69 void _close_file(struct file *file)
71 if (file->fs)
72 file->fs->fs_ops->close_file(file);
73 free_file(file);
77 * Convert between a 16-bit file handle and a file structure
80 void load_config(void)
82 int err;
84 err = this_fs->fs_ops->load_config();
86 if (err)
87 printf("ERROR: No configuration file found\n");
90 void pm_mangle_name(com32sys_t *regs)
92 const char *src = MK_PTR(regs->ds, regs->esi.w[0]);
93 char *dst = MK_PTR(regs->es, regs->edi.w[0]);
95 mangle_name(dst, src);
98 void mangle_name(char *dst, const char *src)
100 this_fs->fs_ops->mangle_name(dst, src);
103 void getfssec(com32sys_t *regs)
105 int sectors;
106 bool have_more;
107 uint32_t bytes_read;
108 char *buf;
109 struct file *file;
110 uint16_t handle;
112 sectors = regs->ecx.w[0];
114 handle = regs->esi.w[0];
115 file = handle_to_file(handle);
117 buf = MK_PTR(regs->es, regs->ebx.w[0]);
118 bytes_read = file->fs->fs_ops->getfssec(file, buf, sectors, &have_more);
121 * If we reach EOF, the filesystem driver will have already closed
122 * the underlying file... this really should be cleaner.
124 if (!have_more) {
125 _close_file(file);
126 regs->esi.w[0] = 0;
129 regs->ecx.l = bytes_read;
132 void getfsbytes(com32sys_t *regs)
134 int sectors;
135 bool have_more;
136 uint32_t bytes_read;
137 char *buf;
138 struct file *file;
139 uint16_t handle;
141 handle = regs->esi.w[0];
142 file = handle_to_file(handle);
144 sectors = regs->ecx.w[0] >> SECTOR_SHIFT(file->fs);
146 buf = MK_PTR(regs->es, regs->ebx.w[0]);
147 bytes_read = file->fs->fs_ops->getfssec(file, buf, sectors, &have_more);
150 * If we reach EOF, the filesystem driver will have already closed
151 * the underlying file... this really should be cleaner.
153 if (!have_more) {
154 _close_file(file);
155 regs->esi.w[0] = 0;
158 regs->ecx.l = bytes_read;
161 size_t pmapi_read_file(uint16_t *handle, void *buf, size_t sectors)
163 bool have_more;
164 size_t bytes_read;
165 struct file *file;
167 file = handle_to_file(*handle);
168 bytes_read = file->fs->fs_ops->getfssec(file, buf, sectors, &have_more);
171 * If we reach EOF, the filesystem driver will have already closed
172 * the underlying file... this really should be cleaner.
174 if (!have_more) {
175 _close_file(file);
176 *handle = 0;
179 return bytes_read;
182 void pm_searchdir(com32sys_t *regs)
184 char *name = MK_PTR(regs->ds, regs->edi.w[0]);
185 int rv;
187 rv = searchdir(name);
188 if (rv < 0) {
189 regs->esi.w[0] = 0;
190 regs->eax.l = 0;
191 regs->eflags.l |= EFLAGS_ZF;
192 } else {
193 regs->esi.w[0] = rv;
194 regs->eax.l = handle_to_file(rv)->inode->size;
195 regs->eflags.l &= ~EFLAGS_ZF;
199 int searchdir(const char *name)
201 struct inode *inode = NULL;
202 struct inode *parent = NULL;
203 struct file *file;
204 char *pathbuf = NULL;
205 char *part, *p, echar;
206 int symlink_count = MAX_SYMLINK_CNT;
208 if (!(file = alloc_file()))
209 goto err_no_close;
210 file->fs = this_fs;
212 /* if we have ->searchdir method, call it */
213 if (file->fs->fs_ops->searchdir) {
214 file->fs->fs_ops->searchdir(name, file);
216 if (file->inode)
217 return file_to_handle(file);
218 else
219 goto err;
222 /* else, try the generic-path-lookup method */
224 parent = get_inode(this_fs->cwd);
225 p = pathbuf = strdup(name);
226 if (!pathbuf)
227 goto err;
229 do {
230 got_link:
231 if (*p == '/') {
232 put_inode(parent);
233 parent = get_inode(this_fs->root);
236 do {
237 inode = get_inode(parent);
239 while (*p == '/')
240 p++;
242 if (!*p)
243 break;
245 part = p;
246 while ((echar = *p) && echar != '/')
247 p++;
248 *p++ = '\0';
250 if (part[0] == '.' && part[1] == '.' && part[2] == '\0') {
251 if (inode->parent) {
252 put_inode(parent);
253 parent = get_inode(inode->parent);
254 put_inode(inode);
255 inode = NULL;
256 if (!echar) {
257 /* Terminal double dots */
258 inode = parent;
259 parent = inode->parent ?
260 get_inode(inode->parent) : NULL;
263 } else if (part[0] != '.' || part[1] != '\0') {
264 inode = this_fs->fs_ops->iget(part, parent);
265 if (!inode)
266 goto err;
267 if (inode->mode == DT_LNK) {
268 char *linkbuf, *q;
269 int name_len = echar ? strlen(p) : 0;
270 int total_len = inode->size + name_len + 2;
271 int link_len;
273 if (!this_fs->fs_ops->readlink ||
274 --symlink_count == 0 || /* limit check */
275 total_len > MAX_SYMLINK_BUF)
276 goto err;
278 linkbuf = malloc(total_len);
279 if (!linkbuf)
280 goto err;
282 link_len = this_fs->fs_ops->readlink(inode, linkbuf);
283 if (link_len <= 0) {
284 free(linkbuf);
285 goto err;
288 q = linkbuf + link_len;
290 if (echar) {
291 if (link_len > 0 && q[-1] != '/')
292 *q++ = '/';
294 memcpy(q, p, name_len+1);
295 } else {
296 *q = '\0';
299 free(pathbuf);
300 p = pathbuf = linkbuf;
301 put_inode(inode);
302 inode = NULL;
303 goto got_link;
306 inode->parent = parent;
307 parent = NULL;
309 if (!echar)
310 break;
312 if (inode->mode != DT_DIR)
313 goto err;
315 parent = inode;
316 inode = NULL;
318 } while (echar);
319 } while (0);
321 free(pathbuf);
322 pathbuf = NULL;
323 put_inode(parent);
324 parent = NULL;
326 if (!inode)
327 goto err;
329 file->inode = inode;
330 file->offset = 0;
332 return file_to_handle(file);
334 err:
335 put_inode(inode);
336 put_inode(parent);
337 if (pathbuf)
338 free(pathbuf);
339 _close_file(file);
340 err_no_close:
341 return -1;
344 int open_file(const char *name, struct com32_filedata *filedata)
346 int rv;
347 struct file *file;
348 char mangled_name[FILENAME_MAX];
350 mangle_name(mangled_name, name);
351 rv = searchdir(mangled_name);
353 if (rv < 0)
354 return rv;
356 file = handle_to_file(rv);
358 if (file->inode->mode != DT_REG) {
359 _close_file(file);
360 return -1;
363 filedata->size = file->inode->size;
364 filedata->blocklg2 = SECTOR_SHIFT(file->fs);
365 filedata->handle = rv;
367 return rv;
370 void pm_open_file(com32sys_t *regs)
372 int rv;
373 struct file *file;
374 const char *name = MK_PTR(regs->es, regs->esi.w[0]);
375 char mangled_name[FILENAME_MAX];
377 mangle_name(mangled_name, name);
378 rv = searchdir(mangled_name);
379 if (rv < 0) {
380 regs->eflags.l |= EFLAGS_CF;
381 } else {
382 file = handle_to_file(rv);
383 regs->eflags.l &= ~EFLAGS_CF;
384 regs->eax.l = file->inode->size;
385 regs->ecx.w[0] = SECTOR_SIZE(file->fs);
386 regs->esi.w[0] = rv;
390 void close_file(uint16_t handle)
392 struct file *file;
394 if (handle) {
395 file = handle_to_file(handle);
396 _close_file(file);
400 void pm_close_file(com32sys_t *regs)
402 close_file(regs->esi.w[0]);
406 * it will do:
407 * initialize the memory management function;
408 * set up the vfs fs structure;
409 * initialize the device structure;
410 * invoke the fs-specific init function;
411 * initialize the cache if we need one;
412 * finally, get the current inode for relative path looking.
414 __bss16 uint16_t SectorSize, SectorShift;
416 void fs_init(com32sys_t *regs)
418 static struct fs_info fs; /* The actual filesystem buffer */
419 uint8_t disk_devno = regs->edx.b[0];
420 uint8_t disk_cdrom = regs->edx.b[1];
421 sector_t disk_offset = regs->ecx.l | ((sector_t)regs->ebx.l << 32);
422 uint16_t disk_heads = regs->esi.w[0];
423 uint16_t disk_sectors = regs->edi.w[0];
424 uint32_t maxtransfer = regs->ebp.l;
425 int blk_shift = -1;
426 struct device *dev = NULL;
427 /* ops is a ptr list for several fs_ops */
428 const struct fs_ops **ops = (const struct fs_ops **)regs->eax.l;
430 /* Initialize malloc() */
431 mem_init();
433 /* Default name for the root directory */
434 fs.cwd_name[0] = '/';
436 while ((blk_shift < 0) && *ops) {
437 /* set up the fs stucture */
438 fs.fs_ops = *ops;
441 * This boldly assumes that we don't mix FS_NODEV filesystems
442 * with FS_DEV filesystems...
444 if (fs.fs_ops->fs_flags & FS_NODEV) {
445 fs.fs_dev = NULL;
446 } else {
447 if (!dev)
448 dev = device_init(disk_devno, disk_cdrom, disk_offset,
449 disk_heads, disk_sectors, maxtransfer);
450 fs.fs_dev = dev;
452 /* invoke the fs-specific init code */
453 blk_shift = fs.fs_ops->fs_init(&fs);
454 ops++;
456 if (blk_shift < 0) {
457 printf("No valid file system found!\n");
458 while (1)
461 this_fs = &fs;
463 /* initialize the cache */
464 if (fs.fs_dev && fs.fs_dev->cache_data)
465 cache_init(fs.fs_dev, blk_shift);
467 /* start out in the root directory */
468 if (fs.fs_ops->iget_root) {
469 fs.root = fs.fs_ops->iget_root(&fs);
470 fs.cwd = get_inode(fs.root);
473 SectorShift = fs.sector_shift;
474 SectorSize = fs.sector_size;