Releasing debian version 4.04+dfsg-9.
[syslinux-debian/hramrach.git] / core / fs / fs.c
blobad2fb37052ea5fe928d48df66c0525a7c11070f5
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 pm_load_config(com32sys_t *regs)
82 int err;
84 err = this_fs->fs_ops->load_config();
86 if (err)
87 printf("ERROR: No configuration file found\n");
89 set_flags(regs, err ? EFLAGS_ZF : 0);
92 void pm_mangle_name(com32sys_t *regs)
94 const char *src = MK_PTR(regs->ds, regs->esi.w[0]);
95 char *dst = MK_PTR(regs->es, regs->edi.w[0]);
97 mangle_name(dst, src);
100 void mangle_name(char *dst, const char *src)
102 this_fs->fs_ops->mangle_name(dst, src);
105 void getfssec(com32sys_t *regs)
107 int sectors;
108 bool have_more;
109 uint32_t bytes_read;
110 char *buf;
111 struct file *file;
112 uint16_t handle;
114 sectors = regs->ecx.w[0];
116 handle = regs->esi.w[0];
117 file = handle_to_file(handle);
119 buf = MK_PTR(regs->es, regs->ebx.w[0]);
120 bytes_read = file->fs->fs_ops->getfssec(file, buf, sectors, &have_more);
123 * If we reach EOF, the filesystem driver will have already closed
124 * the underlying file... this really should be cleaner.
126 if (!have_more) {
127 _close_file(file);
128 regs->esi.w[0] = 0;
131 regs->ecx.l = bytes_read;
134 void getfsbytes(com32sys_t *regs)
136 int sectors;
137 bool have_more;
138 uint32_t bytes_read;
139 char *buf;
140 struct file *file;
141 uint16_t handle;
143 handle = regs->esi.w[0];
144 file = handle_to_file(handle);
146 sectors = regs->ecx.w[0] >> SECTOR_SHIFT(file->fs);
148 buf = MK_PTR(regs->es, regs->ebx.w[0]);
149 bytes_read = file->fs->fs_ops->getfssec(file, buf, sectors, &have_more);
152 * If we reach EOF, the filesystem driver will have already closed
153 * the underlying file... this really should be cleaner.
155 if (!have_more) {
156 _close_file(file);
157 regs->esi.w[0] = 0;
160 regs->ecx.l = bytes_read;
163 size_t pmapi_read_file(uint16_t *handle, void *buf, size_t sectors)
165 bool have_more;
166 size_t bytes_read;
167 struct file *file;
169 file = handle_to_file(*handle);
170 bytes_read = file->fs->fs_ops->getfssec(file, buf, sectors, &have_more);
173 * If we reach EOF, the filesystem driver will have already closed
174 * the underlying file... this really should be cleaner.
176 if (!have_more) {
177 _close_file(file);
178 *handle = 0;
181 return bytes_read;
184 void pm_searchdir(com32sys_t *regs)
186 char *name = MK_PTR(regs->ds, regs->edi.w[0]);
187 int rv;
189 rv = searchdir(name);
190 if (rv < 0) {
191 regs->esi.w[0] = 0;
192 regs->eax.l = 0;
193 regs->eflags.l |= EFLAGS_ZF;
194 } else {
195 regs->esi.w[0] = rv;
196 regs->eax.l = handle_to_file(rv)->inode->size;
197 regs->eflags.l &= ~EFLAGS_ZF;
201 int searchdir(const char *name)
203 struct inode *inode = NULL;
204 struct inode *parent = NULL;
205 struct file *file;
206 char *pathbuf = NULL;
207 char *part, *p, echar;
208 int symlink_count = MAX_SYMLINK_CNT;
210 if (!(file = alloc_file()))
211 goto err_no_close;
212 file->fs = this_fs;
214 /* if we have ->searchdir method, call it */
215 if (file->fs->fs_ops->searchdir) {
216 file->fs->fs_ops->searchdir(name, file);
218 if (file->inode)
219 return file_to_handle(file);
220 else
221 goto err;
224 /* else, try the generic-path-lookup method */
226 parent = get_inode(this_fs->cwd);
227 p = pathbuf = strdup(name);
228 if (!pathbuf)
229 goto err;
231 do {
232 got_link:
233 if (*p == '/') {
234 put_inode(parent);
235 parent = get_inode(this_fs->root);
238 do {
239 inode = get_inode(parent);
241 while (*p == '/')
242 p++;
244 if (!*p)
245 break;
247 part = p;
248 while ((echar = *p) && echar != '/')
249 p++;
250 *p++ = '\0';
252 if (part[0] == '.' && part[1] == '.' && part[2] == '\0') {
253 if (inode->parent) {
254 put_inode(parent);
255 parent = get_inode(inode->parent);
256 put_inode(inode);
257 inode = NULL;
258 if (!echar) {
259 /* Terminal double dots */
260 inode = parent;
261 parent = inode->parent ?
262 get_inode(inode->parent) : NULL;
265 } else if (part[0] != '.' || part[1] != '\0') {
266 inode = this_fs->fs_ops->iget(part, parent);
267 if (!inode)
268 goto err;
269 if (inode->mode == DT_LNK) {
270 char *linkbuf, *q;
271 int name_len = echar ? strlen(p) : 0;
272 int total_len = inode->size + name_len + 2;
273 int link_len;
275 if (!this_fs->fs_ops->readlink ||
276 --symlink_count == 0 || /* limit check */
277 total_len > MAX_SYMLINK_BUF)
278 goto err;
280 linkbuf = malloc(total_len);
281 if (!linkbuf)
282 goto err;
284 link_len = this_fs->fs_ops->readlink(inode, linkbuf);
285 if (link_len <= 0) {
286 free(linkbuf);
287 goto err;
290 q = linkbuf + link_len;
292 if (echar) {
293 if (link_len > 0 && q[-1] != '/')
294 *q++ = '/';
296 memcpy(q, p, name_len+1);
297 } else {
298 *q = '\0';
301 free(pathbuf);
302 p = pathbuf = linkbuf;
303 put_inode(inode);
304 inode = NULL;
305 goto got_link;
308 inode->parent = parent;
309 parent = NULL;
311 if (!echar)
312 break;
314 if (inode->mode != DT_DIR)
315 goto err;
317 parent = inode;
318 inode = NULL;
320 } while (echar);
321 } while (0);
323 free(pathbuf);
324 pathbuf = NULL;
325 put_inode(parent);
326 parent = NULL;
328 if (!inode)
329 goto err;
331 file->inode = inode;
332 file->offset = 0;
334 return file_to_handle(file);
336 err:
337 put_inode(inode);
338 put_inode(parent);
339 if (pathbuf)
340 free(pathbuf);
341 _close_file(file);
342 err_no_close:
343 return -1;
346 int open_file(const char *name, struct com32_filedata *filedata)
348 int rv;
349 struct file *file;
350 char mangled_name[FILENAME_MAX];
352 mangle_name(mangled_name, name);
353 rv = searchdir(mangled_name);
355 if (rv < 0)
356 return rv;
358 file = handle_to_file(rv);
360 if (file->inode->mode != DT_REG) {
361 _close_file(file);
362 return -1;
365 filedata->size = file->inode->size;
366 filedata->blocklg2 = SECTOR_SHIFT(file->fs);
367 filedata->handle = rv;
369 return rv;
372 void pm_open_file(com32sys_t *regs)
374 int rv;
375 struct file *file;
376 const char *name = MK_PTR(regs->es, regs->esi.w[0]);
377 char mangled_name[FILENAME_MAX];
379 mangle_name(mangled_name, name);
380 rv = searchdir(mangled_name);
381 if (rv < 0) {
382 regs->eflags.l |= EFLAGS_CF;
383 } else {
384 file = handle_to_file(rv);
385 regs->eflags.l &= ~EFLAGS_CF;
386 regs->eax.l = file->inode->size;
387 regs->ecx.w[0] = SECTOR_SIZE(file->fs);
388 regs->esi.w[0] = rv;
392 void close_file(uint16_t handle)
394 struct file *file;
396 if (handle) {
397 file = handle_to_file(handle);
398 _close_file(file);
402 void pm_close_file(com32sys_t *regs)
404 close_file(regs->esi.w[0]);
408 * it will do:
409 * initialize the memory management function;
410 * set up the vfs fs structure;
411 * initialize the device structure;
412 * invoke the fs-specific init function;
413 * initialize the cache if we need one;
414 * finally, get the current inode for relative path looking.
416 __bss16 uint16_t SectorSize, SectorShift;
418 void fs_init(com32sys_t *regs)
420 static struct fs_info fs; /* The actual filesystem buffer */
421 uint8_t disk_devno = regs->edx.b[0];
422 uint8_t disk_cdrom = regs->edx.b[1];
423 sector_t disk_offset = regs->ecx.l | ((sector_t)regs->ebx.l << 32);
424 uint16_t disk_heads = regs->esi.w[0];
425 uint16_t disk_sectors = regs->edi.w[0];
426 uint32_t maxtransfer = regs->ebp.l;
427 int blk_shift = -1;
428 struct device *dev = NULL;
429 /* ops is a ptr list for several fs_ops */
430 const struct fs_ops **ops = (const struct fs_ops **)regs->eax.l;
432 /* Initialize malloc() */
433 mem_init();
435 /* Default name for the root directory */
436 fs.cwd_name[0] = '/';
438 while ((blk_shift < 0) && *ops) {
439 /* set up the fs stucture */
440 fs.fs_ops = *ops;
443 * This boldly assumes that we don't mix FS_NODEV filesystems
444 * with FS_DEV filesystems...
446 if (fs.fs_ops->fs_flags & FS_NODEV) {
447 fs.fs_dev = NULL;
448 } else {
449 if (!dev)
450 dev = device_init(disk_devno, disk_cdrom, disk_offset,
451 disk_heads, disk_sectors, maxtransfer);
452 fs.fs_dev = dev;
454 /* invoke the fs-specific init code */
455 blk_shift = fs.fs_ops->fs_init(&fs);
456 ops++;
458 if (blk_shift < 0) {
459 printf("No valid file system found!\n");
460 while (1)
463 this_fs = &fs;
465 /* initialize the cache */
466 if (fs.fs_dev && fs.fs_dev->cache_data)
467 cache_init(fs.fs_dev, blk_shift);
469 /* start out in the root directory */
470 if (fs.fs_ops->iget_root) {
471 fs.root = fs.fs_ops->iget_root(&fs);
472 fs.cwd = get_inode(fs.root);
475 SectorShift = fs.sector_shift;
476 SectorSize = fs.sector_size;