Import of openhackware-0.4.1
[openhackware.git] / src / libfs / core.c
blob9743a64a2ac862f699a2db4de50d152e5bc31acd
1 /*
2 * <fs.c>
4 * Open Hack'Ware BIOS file systems management
5 *
6 * Copyright (c) 2004-2005 Jocelyn Mayer
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License V2
10 * as published by the Free Software Foundation
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include "bios.h"
25 #include "libfs.h"
26 #undef FS_DPRINTF
27 #define FS_DPRINTF(fmt, args...) do { } while (0)
29 static int special_file_get_type (const unsigned char *name)
31 int ret;
33 if (strcmp(name, "root") == 0)
34 ret = FILE_ROOT;
35 else if (strcmp(name, "boot") == 0)
36 ret = FILE_BOOT;
37 else if (strcmp(name, "bootdir") == 0)
38 ret = FILE_BOOTDIR;
39 else
40 ret = FILE_UNKNOWN;
42 return ret;
45 void fs_cache_add_inode (inode_t *parent, inode_t *inode)
47 inode_t **cur;
49 if (parent == NULL || inode == NULL)
50 return;
51 FS_DPRINTF("Add inode '%s' to '%s' cache\n", inode->name, parent->name);
52 for (cur = &parent->child; *cur != NULL; cur = &((*cur)->next)) {
53 if (strcmp((*cur)->name, inode->name) == 0) {
54 return;
57 *cur = inode;
60 static inode_t *fs_cache_get_inode (inode_t *parent,
61 const unsigned char *name)
63 inode_t *cur, *rec;
64 int dec;
66 FS_DPRINTF("Look for '%s' into '%s' cache\n", name, parent->name);
67 if (name == NULL || parent == NULL)
68 return NULL;
69 if (name[0] == '/' && name[1] == '\0')
70 return parent->fs->root;
71 if (is_special_file(name))
72 dec = strlen(FS_SPECIAL) + 2;
73 else
74 dec = 0;
75 for (cur = parent->child; cur != NULL; cur = cur->next) {
76 if (strcmp(cur->name + dec, name + dec) == 0) {
77 cur->refcount++;
78 for (rec = parent; rec != NULL; rec = rec->parent)
79 rec->refcount++;
80 break;
83 cur = NULL;
85 return cur;
88 static void fs_cache_put_inode (inode_t *inode)
90 void (*put_inode)(inode_t *inode);
91 inode_t *cur, **upd;
93 if (inode != NULL && --inode->refcount == 0) {
94 if (inode->parent == NULL)
95 return;
96 fs_cache_put_inode(inode->parent);
97 upd = &inode->parent->child;
98 for (cur = *upd; cur != NULL; cur = cur->next) {
99 if (cur == inode) {
100 (*upd) = cur->next;
101 put_inode = inode->fs->fs_ops->put_inode;
102 (*put_inode)(cur);
103 FS_DPRINTF("Free inode '%s' from '%s' cache\n",
104 inode->name, inode->parent->name);
105 free(cur);
106 return;
108 upd = &cur;
110 FS_ERROR("didn't find inode in list !\n");
114 static inode_t *fs_get_inode (inode_t *parent, const unsigned char *name)
116 inode_t *(*get_inode)(inode_t *parent, const unsigned char *name);
117 inode_t *cur;
119 if (parent == NULL) {
120 FS_ERROR("Invalide inode '%s' (NULL)\n", name);
121 return NULL;
122 } else {
123 if (fs_inode_get_type(parent) != INODE_TYPE_DIR) {
124 FS_ERROR("Try to recurse in a non-directory inode (%d)\n",
125 parent->flags);
126 return NULL;
129 if (is_special_file(name)) {
130 int type;
131 /* Special files */
132 FS_DPRINTF("look for special file '%s'\n",
133 name + strlen(FS_SPECIAL) + 2);
134 type = special_file_get_type(name + strlen(FS_SPECIAL) + 2);
135 if (type == FILE_UNKNOWN) {
136 FS_ERROR("Unknown special file '%s'\n",
137 name + strlen(FS_SPECIAL) + 2);
138 return NULL;
140 cur = (*parent->fs->fs_ops->get_special_inode)(parent->fs, type);
141 FS_DPRINTF("boot file: %p '%s' %p boot dir: %p '%s' %p\n",
142 parent->fs->bootfile, parent->fs->bootfile->name,
143 &parent->fs->bootfile,
144 parent->fs->bootdir, parent->fs->bootdir->name,
145 &parent->fs->bootdir);
146 switch (type) {
147 case FILE_ROOT:
148 parent->fs->root = cur;
149 cur->parent = NULL;
150 cur->fs = parent->fs;
151 cur->name = strdup("");
152 return cur;
153 case FILE_BOOT:
154 parent->fs->bootfile = cur;
155 break;
156 case FILE_BOOTDIR:
157 parent->fs->bootdir = cur;
158 break;
160 #if 0
161 parent = cur->parent;
162 #else
163 cur->fs = parent->fs;
164 return cur;
165 #endif
166 } else {
167 FS_DPRINTF("look for file '%s' in %p '%s'\n", name, parent,
168 parent->name);
169 DPRINTF("look for file '%s' in %p '%s'\n", name, parent,
170 parent->name);
171 cur = fs_cache_get_inode(parent, name);
172 if (cur != NULL) {
173 FS_DPRINTF("found inode '%s' %p in cache\n", name, cur);
174 DPRINTF("found inode '%s' %p in cache\n", name, cur);
175 return cur;
177 get_inode = parent->fs->fs_ops->get_inode;
178 cur = (*get_inode)(parent, name);
179 cur->name = strdup(name);
181 if (cur != NULL) {
182 cur->parent = parent;
183 cur->fs = parent->fs;
184 fs_cache_add_inode(parent, cur);
185 FS_DPRINTF("Inode '%s' in '%s': %d blocs size %d %d\n",
186 name, parent->name, cur->nb_blocs, cur->size.bloc,
187 cur->size.offset);
188 DPRINTF("Inode '%s' in '%s': %d blocs size %d %d\n",
189 name, parent->name, cur->nb_blocs, cur->size.bloc,
190 cur->size.offset);
191 } else {
192 FS_ERROR("Inode '%s' not found in '%s'\n", name, parent->name);
195 return cur;
198 static inline void fs_put_inode (inode_t *inode)
200 fs_cache_put_inode(inode);
203 static inode_t *_fs_walk (inode_t *parent, const unsigned char *name)
205 unsigned char tmpname[MAXNAME_LEN], *sl;
206 inode_t *new, *subdir;
208 FS_DPRINTF("'%s' %p\n", name, parent);
209 DPRINTF("'%s' %p\n", name, parent);
210 for (; *name == '/'; name++)
211 continue;
212 DPRINTF("'%s' %p\n", name, parent);
213 strcpy(tmpname, name);
214 sl = strchr(tmpname, '/');
215 if (sl != NULL) {
216 *sl = '\0';
217 subdir = fs_get_inode(parent, tmpname);
218 if (subdir == NULL)
219 return NULL;
220 new = _fs_walk(subdir, sl + 1);
221 } else {
222 new = fs_get_inode(parent, tmpname);
225 return new;
228 static inode_t *fs_walk (inode_t *parent, const unsigned char *name)
230 unsigned char tmpname[MAXNAME_LEN];
231 int len;
233 FS_DPRINTF("'%s' %p\n", name, parent);
234 DPRINTF("'%s' %p %p\n", name, parent, parent->fs->root);
235 len = strlen(name);
236 memcpy(tmpname, name, len + 1);
237 if (tmpname[len - 1] == '/')
238 tmpname[--len] = '\0';
239 if (parent == parent->fs->root && tmpname[0] == '\0')
240 return parent->fs->root;
242 return _fs_walk(parent, tmpname);
245 static unsigned char *fs_inode_get_path (inode_t *inode)
247 unsigned char tmpname[MAXNAME_LEN], *pname;
248 int len;
249 inode_t *parent;
251 parent = inode->parent;
252 if (parent == NULL || (inode->name[0] == '/' && inode->name[1] == '\0')) {
253 FS_DPRINTF("Reached root node '/'\n");
254 return strdup("/");
256 FS_DPRINTF("Recurse to root '%s'...\n", inode->name);
257 pname = fs_inode_get_path(parent);
258 FS_DPRINTF("'%s' '%s'\n", pname, inode->name);
259 len = strlen(pname);
260 memcpy(tmpname, pname, len);
261 if (tmpname[len - 1] != '/')
262 tmpname[len++] = '/';
263 strcpy(tmpname + len, inode->name);
264 free(pname);
265 FS_DPRINTF(" => '%s'\n", tmpname);
267 return strdup(tmpname);
270 static inline uint32_t fs_map_bloc (inode_t *inode, uint32_t bloc)
272 FS_DPRINTF("%s: inode %p bloc %d %p %p %p\n", __func__, inode, bloc,
273 inode->fs, inode->fs->fs_ops, inode->fs->fs_ops->map_bloc);
274 return (*inode->fs->fs_ops->map_bloc)(inode, bloc);
277 fs_t *fs_probe (part_t *part, int set_raw)
279 fs_t *new;
280 inode_t fake_inode;
281 fs_ops_t *fs_ops = NULL;
282 unsigned char *name = NULL;
283 void *private = NULL;
284 uint32_t size = 0;
285 int type = FS_TYPE_UNKNOWN;
287 FS_DPRINTF("\n");
288 if (set_raw == 2) {
289 DPRINTF("Check raw only\n");
290 goto raw_only;
292 DPRINTF("Probe ext2\n");
293 type = fs_ext2_probe(part, &size, &fs_ops, &name, &private);
294 if (type == FS_TYPE_UNKNOWN) {
295 DPRINTF("Probe isofs\n");
296 type = fs_isofs_probe(part, &size, &fs_ops, &name, &private);
297 if (type == FS_TYPE_UNKNOWN) {
298 DPRINTF("Probe HFS\n");
299 type = fs_hfs_probe(part, &size, &fs_ops, &name, &private);
300 if (set_raw) {
301 DPRINTF("Probe raw\n");
302 raw_only:
303 type = fs_raw_probe(part, &size, &fs_ops, &name, &private);
305 if (type == FS_TYPE_UNKNOWN) {
306 FS_ERROR("FS not identified\n");
307 return NULL;
311 if (fs_ops == NULL || size == 0) {
312 FS_ERROR("Missing param: %p %d\n", fs_ops, size);
313 return NULL;
315 new = malloc(sizeof(fs_t));
316 if (new == NULL)
317 return NULL;
318 new->type = type;
319 new->part = part;
320 new->size = size;
321 new->fs_ops = fs_ops;
322 new->name = name;
323 new->private = private;
324 /* Get root inode */
325 memset(&fake_inode, 0, sizeof(inode_t));
326 fake_inode.name = "fake_root";
327 fake_inode.fs = new;
328 fake_inode.refcount = 1;
329 fs_get_inode(&fake_inode, "\0" FS_SPECIAL "\0root");
330 if (new->root == NULL) {
331 FS_ERROR("Didn't find root inode\n");
332 free(new);
333 return NULL;
335 FS_DPRINTF("fs: %p root: %p root fs: %p\n", new, new->root, new->root->fs);
336 FS_DPRINTF("OK\n");
338 return new;
341 dir_t *fs_opendir (fs_t *fs, const unsigned char *name)
343 inode_t *inode;
344 dir_t *new;
346 FS_DPRINTF("'%s'\n", name);
347 inode = fs_walk(fs->root, name);
348 if (inode == NULL)
349 return NULL;
350 new = malloc(sizeof(dir_t));
351 new->inode = inode;
353 return new;
356 dirent_t *fs_readdir (dir_t *dir)
358 void (*put_inode)(inode_t *inode);
359 inode_t *inode;
361 inode = fs_get_inode(dir->inode, NULL);
362 if (inode == NULL)
363 return NULL;
364 if (dir->cur == NULL) {
365 dir->cur = malloc(sizeof(dirent_t));
366 dir->cur->dir = dir;
367 } else {
368 put_inode = dir->inode->fs->fs_ops->put_inode;
369 (*put_inode)(dir->cur->inode);
371 dir->cur->inode = inode;
372 dir->cur->dname = inode->name;
374 return dir->cur;
377 unsigned char *fs_get_path (dirent_t *dirent)
379 return fs_inode_get_path(dirent->inode);
382 void fs_closedir (dir_t *dir)
384 void (*put_inode)(inode_t *inode);
386 if (dir->cur != NULL) {
387 put_inode = dir->inode->fs->fs_ops->put_inode;
388 (*put_inode)(dir->cur->inode);
389 free(dir->cur);
391 free(dir);
394 inode_t *fs_open (fs_t *fs, const unsigned char *name)
396 inode_t *inode;
398 FS_DPRINTF("'%s'\n", name);
399 inode = fs_walk(fs->root, name);
400 if (inode != NULL)
401 fs_seek(inode, 0, 0);
403 return inode;
406 int fs_seek (inode_t *inode, uint32_t bloc, uint32_t pos)
408 if (inode == NULL || inode->fs == NULL) {
409 ERROR("%s: no inode / fs ! %p %p\n", __func__, inode,
410 inode == NULL ? NULL : inode->fs);
411 return -1;
413 FS_DPRINTF("%08x %08x\n", bloc, pos);
414 if (part_seek(inode->fs->part, fs_map_bloc(inode, bloc), pos) == -1)
415 return -1;
416 inode->vbloc = bloc;
417 inode->vpos = pos;
419 return 0;
422 int fs_read (inode_t *inode, void *buffer, int len)
424 uint32_t bsize, total;
425 int done, tmp;
427 bsize = part_blocsize(inode->fs->part);
428 total = 0;
429 if (fs_seek(inode, inode->vbloc, inode->vpos) < 0)
430 return -1;
431 for (; len != 0; len -= done) {
432 tmp = bsize - inode->vpos;
433 if (len < tmp)
434 tmp = len;
435 done = part_read(inode->fs->part, buffer, tmp);
436 if (done < 0)
437 return -1;
438 inode->vpos += done;
439 if (inode->vpos >= bsize) {
440 inode->vbloc++;
441 inode->vpos -= bsize;
443 buffer += done;
444 total += done;
447 return total;
450 int fs_write (inode_t *inode, const void *buffer, unused int len)
452 uint32_t bsize, total;
453 int done, tmp;
455 bsize = part_blocsize(inode->fs->part);
456 total = 0;
457 for (; len != 0; len -= done) {
458 tmp = bsize - inode->vpos;
459 if (len < tmp)
460 tmp = len;
461 done = part_write(inode->fs->part, buffer, tmp);
462 if (done < 0)
463 return -1;
464 inode->vpos += done;
465 if (inode->vpos >= bsize) {
466 inode->vbloc++;
467 inode->vpos -= bsize;
468 if (fs_seek(inode, inode->vbloc, inode->vpos) < 0)
469 return -1;
471 buffer += done;
472 total += done;
475 return total;
478 void fs_close (inode_t *inode)
480 fs_put_inode(inode);
483 uint32_t fs_inode_get_type (inode_t *inode)
485 return inode->flags & INODE_TYPE_MASK;
488 uint32_t fs_inode_get_flags (inode_t *inode)
490 return inode->flags & INODE_FLAG_MASK;
493 uint32_t fs_inode_get_size (inode_t *inode)
495 DPRINTF("%s: (%d * %d) + %d\n", __func__, inode->size.bloc,
496 part_blocsize(inode->fs->part), inode->size.offset);
497 return (inode->size.bloc * part_blocsize(inode->fs->part)) +
498 inode->size.offset;
501 part_t *fs_part (fs_t *fs)
503 return fs->part;
506 uint32_t fs_get_type (fs_t *fs)
508 return fs->type;
511 part_t *fs_inode_get_part (inode_t *inode)
513 return inode->fs->part;
516 inode_t *fs_get_bootdir (fs_t *fs)
518 FS_DPRINTF("fs: %p root: %p root fs: %p\n", fs, fs->root, fs->root->fs);
519 if (fs->bootdir == NULL) {
520 fs->bootdir = fs_get_inode(fs->root, "\0" FS_SPECIAL "\0bootdir");
522 FS_DPRINTF("fs: %p root: %p root fs: %p\n", fs, fs->root, fs->root->fs);
523 FS_DPRINTF("boot file: %p '%s' %p boot dir: %p '%s' %p\n",
524 fs->bootfile, fs->bootfile->name, &fs->bootfile,
525 fs->bootdir, fs->bootdir->name, &fs->bootdir);
527 return fs->bootdir;
529 unsigned char *fs_get_boot_dirname (fs_t *fs)
531 if (fs->bootdir == NULL) {
532 fs_get_bootdir(fs);
533 if (fs->bootdir == NULL)
534 return NULL;
536 FS_DPRINTF("boot file: %p '%s' boot dir: %p '%s'\n",
537 fs->bootfile, fs->bootfile->name,
538 fs->bootdir, fs->bootdir->name);
540 return fs_inode_get_path(fs->bootdir);
543 inode_t *fs_get_bootfile (fs_t *fs)
545 FS_DPRINTF("fs: %p root: %p root fs: %p\n", fs, fs->root, fs->root->fs);
546 FS_DPRINTF("boot file: %p '%s' %p boot dir: %p '%s' %p\n",
547 fs->bootfile, fs->bootfile->name, &fs->bootfile,
548 fs->bootdir, fs->bootdir->name, &fs->bootdir);
549 if (fs->bootfile == NULL) {
550 if (fs->bootdir == NULL)
551 fs_get_bootdir(fs);
552 if (fs->bootdir == NULL)
553 return NULL;
554 fs->bootfile = fs_get_inode(fs->bootdir, "\0" FS_SPECIAL "\0boot");
556 FS_DPRINTF("fs: %p root: %p root fs: %p\n", fs, fs->root, fs->root->fs);
557 FS_DPRINTF("boot file: %p '%s' %p boot dir: %p '%s' %p\n",
558 fs->bootfile, fs->bootfile->name, &fs->bootfile,
559 fs->bootdir, fs->bootdir->name, &fs->bootdir);
561 return fs->bootfile;