4 * Open Hack'Ware BIOS file systems management
6 * Copyright (c) 2004-2005 Jocelyn Mayer
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
27 #define FS_DPRINTF(fmt, args...) do { } while (0)
29 static int special_file_get_type (const unsigned char *name
)
33 if (strcmp(name
, "root") == 0)
35 else if (strcmp(name
, "boot") == 0)
37 else if (strcmp(name
, "bootdir") == 0)
45 void fs_cache_add_inode (inode_t
*parent
, inode_t
*inode
)
49 if (parent
== NULL
|| inode
== NULL
)
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) {
60 static inode_t
*fs_cache_get_inode (inode_t
*parent
,
61 const unsigned char *name
)
66 FS_DPRINTF("Look for '%s' into '%s' cache\n", name
, parent
->name
);
67 if (name
== NULL
|| parent
== 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;
75 for (cur
= parent
->child
; cur
!= NULL
; cur
= cur
->next
) {
76 if (strcmp(cur
->name
+ dec
, name
+ dec
) == 0) {
78 for (rec
= parent
; rec
!= NULL
; rec
= rec
->parent
)
88 static void fs_cache_put_inode (inode_t
*inode
)
90 void (*put_inode
)(inode_t
*inode
);
93 if (inode
!= NULL
&& --inode
->refcount
== 0) {
94 if (inode
->parent
== NULL
)
96 fs_cache_put_inode(inode
->parent
);
97 upd
= &inode
->parent
->child
;
98 for (cur
= *upd
; cur
!= NULL
; cur
= cur
->next
) {
101 put_inode
= inode
->fs
->fs_ops
->put_inode
;
103 FS_DPRINTF("Free inode '%s' from '%s' cache\n",
104 inode
->name
, inode
->parent
->name
);
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
);
119 if (parent
== NULL
) {
120 FS_ERROR("Invalide inode '%s' (NULL)\n", name
);
123 if (fs_inode_get_type(parent
) != INODE_TYPE_DIR
) {
124 FS_ERROR("Try to recurse in a non-directory inode (%d)\n",
129 if (is_special_file(name
)) {
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);
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
);
148 parent
->fs
->root
= cur
;
150 cur
->fs
= parent
->fs
;
151 cur
->name
= strdup("");
154 parent
->fs
->bootfile
= cur
;
157 parent
->fs
->bootdir
= cur
;
161 parent
= cur
->parent
;
163 cur
->fs
= parent
->fs
;
167 FS_DPRINTF("look for file '%s' in %p '%s'\n", name
, parent
,
169 DPRINTF("look for file '%s' in %p '%s'\n", name
, parent
,
171 cur
= fs_cache_get_inode(parent
, name
);
173 FS_DPRINTF("found inode '%s' %p in cache\n", name
, cur
);
174 DPRINTF("found inode '%s' %p in cache\n", name
, cur
);
177 get_inode
= parent
->fs
->fs_ops
->get_inode
;
178 cur
= (*get_inode
)(parent
, name
);
179 cur
->name
= strdup(name
);
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
,
188 DPRINTF("Inode '%s' in '%s': %d blocs size %d %d\n",
189 name
, parent
->name
, cur
->nb_blocs
, cur
->size
.bloc
,
192 FS_ERROR("Inode '%s' not found in '%s'\n", name
, parent
->name
);
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
++)
212 DPRINTF("'%s' %p\n", name
, parent
);
213 strcpy(tmpname
, name
);
214 sl
= strchr(tmpname
, '/');
217 subdir
= fs_get_inode(parent
, tmpname
);
220 new = _fs_walk(subdir
, sl
+ 1);
222 new = fs_get_inode(parent
, tmpname
);
228 static inode_t
*fs_walk (inode_t
*parent
, const unsigned char *name
)
230 unsigned char tmpname
[MAXNAME_LEN
];
233 FS_DPRINTF("'%s' %p\n", name
, parent
);
234 DPRINTF("'%s' %p %p\n", name
, parent
, parent
->fs
->root
);
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
;
251 parent
= inode
->parent
;
252 if (parent
== NULL
|| (inode
->name
[0] == '/' && inode
->name
[1] == '\0')) {
253 FS_DPRINTF("Reached root node '/'\n");
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
);
260 memcpy(tmpname
, pname
, len
);
261 if (tmpname
[len
- 1] != '/')
262 tmpname
[len
++] = '/';
263 strcpy(tmpname
+ len
, inode
->name
);
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
)
281 fs_ops_t
*fs_ops
= NULL
;
282 unsigned char *name
= NULL
;
283 void *private = NULL
;
285 int type
= FS_TYPE_UNKNOWN
;
289 DPRINTF("Check raw only\n");
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);
301 DPRINTF("Probe raw\n");
303 type
= fs_raw_probe(part
, &size
, &fs_ops
, &name
, &private);
305 if (type
== FS_TYPE_UNKNOWN
) {
306 FS_ERROR("FS not identified\n");
311 if (fs_ops
== NULL
|| size
== 0) {
312 FS_ERROR("Missing param: %p %d\n", fs_ops
, size
);
315 new = malloc(sizeof(fs_t
));
321 new->fs_ops
= fs_ops
;
323 new->private = private;
325 memset(&fake_inode
, 0, sizeof(inode_t
));
326 fake_inode
.name
= "fake_root";
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");
335 FS_DPRINTF("fs: %p root: %p root fs: %p\n", new, new->root
, new->root
->fs
);
341 dir_t
*fs_opendir (fs_t
*fs
, const unsigned char *name
)
346 FS_DPRINTF("'%s'\n", name
);
347 inode
= fs_walk(fs
->root
, name
);
350 new = malloc(sizeof(dir_t
));
356 dirent_t
*fs_readdir (dir_t
*dir
)
358 void (*put_inode
)(inode_t
*inode
);
361 inode
= fs_get_inode(dir
->inode
, NULL
);
364 if (dir
->cur
== NULL
) {
365 dir
->cur
= malloc(sizeof(dirent_t
));
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
;
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
);
394 inode_t
*fs_open (fs_t
*fs
, const unsigned char *name
)
398 FS_DPRINTF("'%s'\n", name
);
399 inode
= fs_walk(fs
->root
, name
);
401 fs_seek(inode
, 0, 0);
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
);
413 FS_DPRINTF("%08x %08x\n", bloc
, pos
);
414 if (part_seek(inode
->fs
->part
, fs_map_bloc(inode
, bloc
), pos
) == -1)
422 int fs_read (inode_t
*inode
, void *buffer
, int len
)
424 uint32_t bsize
, total
;
427 bsize
= part_blocsize(inode
->fs
->part
);
429 if (fs_seek(inode
, inode
->vbloc
, inode
->vpos
) < 0)
431 for (; len
!= 0; len
-= done
) {
432 tmp
= bsize
- inode
->vpos
;
435 done
= part_read(inode
->fs
->part
, buffer
, tmp
);
439 if (inode
->vpos
>= bsize
) {
441 inode
->vpos
-= bsize
;
450 int fs_write (inode_t
*inode
, const void *buffer
, unused
int len
)
452 uint32_t bsize
, total
;
455 bsize
= part_blocsize(inode
->fs
->part
);
457 for (; len
!= 0; len
-= done
) {
458 tmp
= bsize
- inode
->vpos
;
461 done
= part_write(inode
->fs
->part
, buffer
, tmp
);
465 if (inode
->vpos
>= bsize
) {
467 inode
->vpos
-= bsize
;
468 if (fs_seek(inode
, inode
->vbloc
, inode
->vpos
) < 0)
478 void fs_close (inode_t
*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
)) +
501 part_t
*fs_part (fs_t
*fs
)
506 uint32_t fs_get_type (fs_t
*fs
)
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
);
529 unsigned char *fs_get_boot_dirname (fs_t
*fs
)
531 if (fs
->bootdir
== NULL
) {
533 if (fs
->bootdir
== 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
)
552 if (fs
->bootdir
== 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
);