]> code.delx.au - refind/blob - filesystems/fsw_core.c
Fixed uninitialized-pointer bug that manifested as a crash with
[refind] / filesystems / fsw_core.c
1 /* $Id: fsw_core.c 29125 2010-05-06 09:43:05Z vboxsync $ */
2 /** @file
3 * fsw_core.c - Core file system wrapper abstraction layer code.
4 */
5
6 /*-
7 * This code is based on:
8 *
9 * Copyright (c) 2006 Christoph Pfisterer
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are
13 * met:
14 *
15 * * Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 *
18 * * Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the
21 * distribution.
22 *
23 * * Neither the name of Christoph Pfisterer nor the names of the
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 #include "fsw_core.h"
41
42
43 // functions
44
45 static void fsw_blockcache_free(struct fsw_volume *vol);
46
47 #define MAX_CACHE_LEVEL (5)
48
49
50 /**
51 * Mount a volume with a given file system driver. This function is called by the
52 * host driver to make a volume accessible. The file system driver to use is specified
53 * by a pointer to its dispatch table. The file system driver will look at the
54 * data on the volume to determine if it can read the format. If the volume is found
55 * unsuitable, FSW_UNSUPPORTED is returned.
56 *
57 * If this function returns FSW_SUCCESS, *vol_out points at a valid volume data
58 * structure. The caller must release it later by calling fsw_unmount.
59 *
60 * If this function returns an error status, the caller only needs to clean up its
61 * own buffers that may have been allocated through the read_block interface.
62 */
63
64 fsw_status_t fsw_mount(void *host_data,
65 struct fsw_host_table *host_table,
66 struct fsw_fstype_table *fstype_table,
67 struct fsw_volume **vol_out)
68 {
69 fsw_status_t status;
70 struct fsw_volume *vol;
71
72 // allocate memory for the structure
73 status = fsw_alloc_zero(fstype_table->volume_struct_size, (void **)&vol);
74 if (status)
75 return status;
76
77 // initialize fields
78 vol->phys_blocksize = 512;
79 vol->log_blocksize = 512;
80 vol->label.type = FSW_STRING_TYPE_EMPTY;
81 vol->host_data = host_data;
82 vol->host_table = host_table;
83 vol->fstype_table = fstype_table;
84 vol->host_string_type = host_table->native_string_type;
85
86 // let the fs driver mount the file system
87 status = vol->fstype_table->volume_mount(vol);
88 if (status)
89 goto errorexit;
90
91 // TODO: anything else?
92
93 *vol_out = vol;
94 return FSW_SUCCESS;
95
96 errorexit:
97 fsw_unmount(vol);
98 return status;
99 }
100
101 /**
102 * Unmount a volume by releasing all memory associated with it. This function is
103 * called by the host driver when a volume is no longer needed. It is also called
104 * by the core after a failed mount to clean up any allocated memory.
105 *
106 * Note that all dnodes must have been released before calling this function.
107 */
108
109 void fsw_unmount(struct fsw_volume *vol)
110 {
111 if (vol->root)
112 fsw_dnode_release(vol->root);
113 // TODO: check that no other dnodes are still around
114
115 vol->fstype_table->volume_free(vol);
116
117 fsw_blockcache_free(vol);
118 fsw_strfree(&vol->label);
119 fsw_free(vol);
120 }
121
122 /**
123 * Get in-depth information on the volume. This function can be called by the host
124 * driver to get additional information on the volume.
125 */
126
127 fsw_status_t fsw_volume_stat(struct fsw_volume *vol, struct fsw_volume_stat *sb)
128 {
129 return vol->fstype_table->volume_stat(vol, sb);
130 }
131
132 /**
133 * Set the physical and logical block sizes of the volume. This functions is called by
134 * the file system driver to announce the block sizes it wants to use for accessing
135 * the disk (physical) and for addressing file contents (logical).
136 * Usually both sizes will be the same but there may be file systems that need to access
137 * metadata at a smaller block size than the allocation unit for files.
138 *
139 * Calling this function causes the block cache to be dropped. All pointers returned
140 * from fsw_block_get become invalid. This function should only be called while
141 * mounting the file system, not as a part of file access operations.
142 *
143 * Both sizes are measured in bytes, must be powers of 2, and must not be smaller
144 * than 512 bytes. The logical block size cannot be smaller than the physical block size.
145 */
146
147 void fsw_set_blocksize(struct fsw_volume *vol, fsw_u32 phys_blocksize, fsw_u32 log_blocksize)
148 {
149 // TODO: Check the sizes. Both must be powers of 2. log_blocksize must not be smaller than
150 // phys_blocksize.
151
152 // drop core block cache if present
153 fsw_blockcache_free(vol);
154
155 // signal host driver to drop caches etc.
156 vol->host_table->change_blocksize(vol,
157 vol->phys_blocksize, vol->log_blocksize,
158 phys_blocksize, log_blocksize);
159
160 vol->phys_blocksize = phys_blocksize;
161 vol->log_blocksize = log_blocksize;
162 }
163
164 /**
165 * Get a block of data from the disk. This function is called by the file system driver
166 * or by core functions. It calls through to the host driver's device access routine.
167 * Given a physical block number, it reads the block into memory (or fetches it from the
168 * block cache) and returns the address of the memory buffer. The caller should provide
169 * an indication of how important the block is in the cache_level parameter. Blocks with
170 * a low level are purged first. Some suggestions for cache levels:
171 *
172 * - 0: File data
173 * - 1: Directory data, symlink data
174 * - 2: File system metadata
175 * - 3..5: File system metadata with a high rate of access
176 *
177 * If this function returns successfully, the returned data pointer is valid until the
178 * caller calls fsw_block_release.
179 */
180
181 fsw_status_t fsw_block_get(struct VOLSTRUCTNAME *vol, fsw_u64 phys_bno, fsw_u32 cache_level, void **buffer_out)
182 {
183 fsw_status_t status;
184 fsw_u32 i, discard_level, new_bcache_size;
185 struct fsw_blockcache *new_bcache;
186
187 // TODO: allow the host driver to do its own caching; just call through if
188 // the appropriate function pointers are set
189
190 if (cache_level > MAX_CACHE_LEVEL)
191 cache_level = MAX_CACHE_LEVEL;
192
193 if (vol->bcache_size > 0 && vol->bcache == NULL) {
194 /* driver set the initial cache size */
195 status = fsw_alloc(vol->bcache_size * sizeof(struct fsw_blockcache), &vol->bcache);
196 if(status)
197 return status;
198 for (i = 0; i < vol->bcache_size; i++) {
199 vol->bcache[i].refcount = 0;
200 vol->bcache[i].cache_level = 0;
201 vol->bcache[i].phys_bno = (fsw_u64)FSW_INVALID_BNO;
202 vol->bcache[i].data = NULL;
203 }
204 i = 0;
205 goto miss;
206 }
207
208 // check block cache
209 for (i = 0; i < vol->bcache_size; i++) {
210 if (vol->bcache[i].phys_bno == phys_bno) {
211 // cache hit!
212 if (vol->bcache[i].cache_level < cache_level)
213 vol->bcache[i].cache_level = cache_level; // promote the entry
214 vol->bcache[i].refcount++;
215 *buffer_out = vol->bcache[i].data;
216 return FSW_SUCCESS;
217 }
218 }
219
220 // find a free entry in the cache table
221 for (i = 0; i < vol->bcache_size; i++) {
222 if (vol->bcache[i].phys_bno == (fsw_u64)FSW_INVALID_BNO)
223 break;
224 }
225 if (i >= vol->bcache_size) {
226 for (discard_level = 0; discard_level <= MAX_CACHE_LEVEL; discard_level++) {
227 for (i = 0; i < vol->bcache_size; i++) {
228 if (vol->bcache[i].refcount == 0 && vol->bcache[i].cache_level <= discard_level)
229 break;
230 }
231 if (i < vol->bcache_size)
232 break;
233 }
234 }
235 if (i >= vol->bcache_size) {
236 // enlarge / create the cache
237 if (vol->bcache_size < 16)
238 new_bcache_size = 16;
239 else
240 new_bcache_size = vol->bcache_size << 1;
241 status = fsw_alloc(new_bcache_size * sizeof(struct fsw_blockcache), &new_bcache);
242 if (status)
243 return status;
244 if (vol->bcache_size > 0)
245 fsw_memcpy(new_bcache, vol->bcache, vol->bcache_size * sizeof(struct fsw_blockcache));
246 for (i = vol->bcache_size; i < new_bcache_size; i++) {
247 new_bcache[i].refcount = 0;
248 new_bcache[i].cache_level = 0;
249 new_bcache[i].phys_bno = (fsw_u64)FSW_INVALID_BNO;
250 new_bcache[i].data = NULL;
251 }
252 i = vol->bcache_size;
253
254 // switch caches
255 if (vol->bcache != NULL)
256 fsw_free(vol->bcache);
257 vol->bcache = new_bcache;
258 vol->bcache_size = new_bcache_size;
259 }
260 vol->bcache[i].phys_bno = (fsw_u64)FSW_INVALID_BNO;
261 miss:
262
263 // read the data
264 if (vol->bcache[i].data == NULL) {
265 status = fsw_alloc(vol->phys_blocksize, &vol->bcache[i].data);
266 if (status)
267 return status;
268 }
269 status = vol->host_table->read_block(vol, phys_bno, vol->bcache[i].data);
270 if (status)
271 return status;
272
273 vol->bcache[i].phys_bno = phys_bno;
274 vol->bcache[i].cache_level = cache_level;
275 vol->bcache[i].refcount = 1;
276 *buffer_out = vol->bcache[i].data;
277 return FSW_SUCCESS;
278 }
279
280 /**
281 * Releases a disk block. This function must be called to release disk blocks returned
282 * from fsw_block_get.
283 */
284
285 void fsw_block_release(struct VOLSTRUCTNAME *vol, fsw_u64 phys_bno, void *buffer)
286 {
287 fsw_u32 i;
288
289 // TODO: allow the host driver to do its own caching; just call through if
290 // the appropriate function pointers are set
291
292 // update block cache
293 for (i = 0; i < vol->bcache_size; i++) {
294 if (vol->bcache[i].phys_bno == phys_bno && vol->bcache[i].refcount > 0)
295 vol->bcache[i].refcount--;
296 }
297 }
298
299 /**
300 * Release the block cache. Called internally when changing block sizes and when
301 * unmounting the volume. It frees all data occupied by the generic block cache.
302 */
303
304 static void fsw_blockcache_free(struct fsw_volume *vol)
305 {
306 fsw_u32 i;
307
308 for (i = 0; i < vol->bcache_size; i++) {
309 if (vol->bcache[i].data != NULL)
310 fsw_free(vol->bcache[i].data);
311 }
312 if (vol->bcache != NULL) {
313 fsw_free(vol->bcache);
314 vol->bcache = NULL;
315 }
316 vol->bcache_size = 0;
317 }
318
319 /**
320 * Add a new dnode to the list of known dnodes. This internal function is used when a
321 * dnode is created to add it to the dnode list that is used to search for existing
322 * dnodes by id.
323 */
324
325 static void fsw_dnode_register(struct fsw_volume *vol, struct fsw_dnode *dno)
326 {
327 dno->next = vol->dnode_head;
328 if (vol->dnode_head != NULL)
329 vol->dnode_head->prev = dno;
330 dno->prev = NULL;
331 vol->dnode_head = dno;
332 }
333
334 /**
335 * Create a dnode representing the root directory. This function is called by the file system
336 * driver while mounting the file system. The root directory is special because it has no parent
337 * dnode, its name is defined to be empty, and its type is also fixed. Otherwise, this functions
338 * behaves in the same way as fsw_dnode_create.
339 */
340
341 fsw_status_t fsw_dnode_create_root_with_tree(struct fsw_volume *vol, fsw_u64 tree_id, fsw_u64 dnode_id, struct fsw_dnode **dno_out)
342 {
343 fsw_status_t status;
344 struct fsw_dnode *dno;
345
346 // allocate memory for the structure
347 status = fsw_alloc_zero(vol->fstype_table->dnode_struct_size, (void **)&dno);
348 if (status)
349 return status;
350
351 // fill the structure
352 dno->vol = vol;
353 dno->parent = NULL;
354 dno->tree_id = tree_id;
355 dno->dnode_id = dnode_id;
356 dno->type = FSW_DNODE_TYPE_DIR;
357 dno->refcount = 1;
358 dno->name.type = FSW_STRING_TYPE_EMPTY;
359 // TODO: instead, call a function to create an empty string in the native string type
360
361 fsw_dnode_register(vol, dno);
362
363 *dno_out = dno;
364 return FSW_SUCCESS;
365 }
366
367 fsw_status_t fsw_dnode_create_root(struct fsw_volume *vol, fsw_u64 dnode_id, struct fsw_dnode **dno_out)
368 {
369 return fsw_dnode_create_root_with_tree( vol, 0, dnode_id, dno_out);
370 }
371 /**
372 * Create a new dnode representing a file system object. This function is called by
373 * the file system driver in response to directory lookup or read requests. Note that
374 * if there already is a dnode with the given dnode_id on record, then no new object
375 * is created. Instead, the existing dnode is returned and its reference count
376 * increased. All other parameters are ignored in this case.
377 *
378 * The type passed into this function may be FSW_DNODE_TYPE_UNKNOWN. It is sufficient
379 * to fill the type field during the dnode_fill call.
380 *
381 * The name parameter must describe a string with the object's name. A copy will be
382 * stored in the dnode structure for future reference. The name will not be used to
383 * shortcut directory lookups, but may be used to reconstruct paths.
384 *
385 * If the function returns successfully, *dno_out contains a pointer to the dnode
386 * that must be released by the caller with fsw_dnode_release.
387 */
388
389 fsw_status_t fsw_dnode_create_with_tree(struct fsw_dnode *parent_dno, fsw_u64 tree_id, fsw_u64 dnode_id, int type,
390 struct fsw_string *name, struct fsw_dnode **dno_out)
391 {
392 fsw_status_t status;
393 struct fsw_volume *vol = parent_dno->vol;
394 struct fsw_dnode *dno;
395
396 // check if we already have a dnode with the same id
397 for (dno = vol->dnode_head; dno; dno = dno->next) {
398 if (dno->dnode_id == dnode_id && dno->tree_id == tree_id) {
399 fsw_dnode_retain(dno);
400 *dno_out = dno;
401 return FSW_SUCCESS;
402 }
403 }
404
405 // allocate memory for the structure
406 status = fsw_alloc_zero(vol->fstype_table->dnode_struct_size, (void **)&dno);
407 if (status)
408 return status;
409
410 // fill the structure
411 dno->vol = vol;
412 dno->parent = parent_dno;
413 fsw_dnode_retain(dno->parent);
414 dno->tree_id = tree_id;
415 dno->dnode_id = dnode_id;
416 dno->type = type;
417 dno->refcount = 1;
418 status = fsw_strdup_coerce(&dno->name, vol->host_table->native_string_type, name);
419 if (status) {
420 fsw_free(dno);
421 return status;
422 }
423
424 fsw_dnode_register(vol, dno);
425
426 *dno_out = dno;
427 return FSW_SUCCESS;
428 }
429
430 fsw_status_t fsw_dnode_create(struct fsw_dnode *parent_dno, fsw_u64 dnode_id, int type,
431 struct fsw_string *name, struct fsw_dnode **dno_out)
432 {
433 return fsw_dnode_create_with_tree(parent_dno, 0, dnode_id, type, name, dno_out);
434 }
435
436 /**
437 * Increases the reference count of a dnode. This must be balanced with
438 * fsw_dnode_release calls. Note that some dnode functions return a retained
439 * dnode pointer to their caller.
440 */
441
442 void fsw_dnode_retain(struct fsw_dnode *dno)
443 {
444 dno->refcount++;
445 }
446
447 /**
448 * Release a dnode pointer, deallocating it if this was the last reference.
449 * This function decrements the reference counter of the dnode. If the counter
450 * reaches zero, the dnode is freed. Since the parent dnode is released
451 * during that process, this function may cause it to be freed, too.
452 */
453
454 void fsw_dnode_release(struct fsw_dnode *dno)
455 {
456 struct fsw_volume *vol = dno->vol;
457 struct fsw_dnode *parent_dno;
458
459 dno->refcount--;
460
461 if (dno->refcount == 0) {
462 parent_dno = dno->parent;
463
464 // de-register from volume's list
465 if (dno->next)
466 dno->next->prev = dno->prev;
467 if (dno->prev)
468 dno->prev->next = dno->next;
469 if (vol->dnode_head == dno)
470 vol->dnode_head = dno->next;
471
472 // run fstype-specific cleanup
473 vol->fstype_table->dnode_free(vol, dno);
474
475 fsw_strfree(&dno->name);
476 fsw_free(dno);
477
478 // release our pointer to the parent, possibly deallocating it, too
479 if (parent_dno)
480 fsw_dnode_release(parent_dno);
481 }
482 }
483
484 /**
485 * Get full information about a dnode from disk. This function is called by the host
486 * driver as well as by the core functions. Some file systems defer reading full
487 * information on a dnode until it is actually needed (i.e. separation between
488 * directory and inode information). This function makes sure that all information
489 * is available in the dnode structure. The following fields may not have a correct
490 * value until fsw_dnode_fill has been called:
491 *
492 * type, size
493 */
494
495 fsw_status_t fsw_dnode_fill(struct fsw_dnode *dno)
496 {
497 // TODO: check a flag right here, call fstype's dnode_fill only once per dnode
498
499 return dno->vol->fstype_table->dnode_fill(dno->vol, dno);
500 }
501
502 /**
503 * Get extended information about a dnode. This function can be called by the host
504 * driver to get a full compliment of information about a dnode in addition to the
505 * fields of the fsw_dnode structure itself.
506 *
507 * Some data requires host-specific conversion to be useful (i.e. timestamps) and
508 * will be passed to callback functions instead of being written into the structure.
509 * These callbacks must be filled in by the caller.
510 */
511
512 fsw_status_t fsw_dnode_stat(struct fsw_dnode *dno, struct fsw_dnode_stat *sb)
513 {
514 fsw_status_t status;
515
516 status = fsw_dnode_fill(dno);
517 if (status)
518 return status;
519
520 sb->used_bytes = 0;
521 status = dno->vol->fstype_table->dnode_stat(dno->vol, dno, sb);
522 if (!status && !sb->used_bytes)
523 sb->used_bytes = FSW_U64_DIV(dno->size + dno->vol->log_blocksize - 1, dno->vol->log_blocksize);
524 return status;
525 }
526
527 /**
528 * Lookup a directory entry by name. This function is called by the host driver.
529 * Given a directory dnode and a file name, it looks up the named entry in the
530 * directory.
531 *
532 * If the dnode is not a directory, the call will fail. The caller is responsible for
533 * resolving symbolic links before calling this function.
534 *
535 * If the function returns FSW_SUCCESS, *child_dno_out points to the requested directory
536 * entry. The caller must call fsw_dnode_release on it.
537 */
538
539 fsw_status_t fsw_dnode_lookup(struct fsw_dnode *dno,
540 struct fsw_string *lookup_name, struct fsw_dnode **child_dno_out)
541 {
542 fsw_status_t status;
543
544 status = fsw_dnode_fill(dno);
545 if (status)
546 return status;
547 if (dno->type != FSW_DNODE_TYPE_DIR)
548 return FSW_UNSUPPORTED;
549
550 return dno->vol->fstype_table->dir_lookup(dno->vol, dno, lookup_name, child_dno_out);
551 }
552
553 /**
554 * Find a file system object by path. This function is called by the host driver.
555 * Given a directory dnode and a relative or absolute path, it walks the directory
556 * tree until it finds the target dnode. If an intermediate node turns out to be
557 * a symlink, it is resolved automatically. If the target node is a symlink, it
558 * is not resolved.
559 *
560 * If the function returns FSW_SUCCESS, *child_dno_out points to the requested directory
561 * entry. The caller must call fsw_dnode_release on it.
562 */
563
564 fsw_status_t fsw_dnode_lookup_path(struct fsw_dnode *dno,
565 struct fsw_string *lookup_path, char separator,
566 struct fsw_dnode **child_dno_out)
567 {
568 fsw_status_t status;
569 struct fsw_volume *vol = dno->vol;
570 struct fsw_dnode *child_dno = NULL;
571 struct fsw_string lookup_name;
572 struct fsw_string remaining_path;
573 int root_if_empty;
574
575 remaining_path = *lookup_path;
576 fsw_dnode_retain(dno);
577
578 // loop over the path
579 for (root_if_empty = 1; fsw_strlen(&remaining_path) > 0; root_if_empty = 0) {
580 // parse next path component
581 fsw_strsplit(&lookup_name, &remaining_path, separator);
582
583 FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: split into %d '%s' and %d '%s'\n"),
584 lookup_name.len, lookup_name.data,
585 remaining_path.len, remaining_path.data));
586
587 if (fsw_strlen(&lookup_name) == 0) { // empty path component
588 if (root_if_empty)
589 child_dno = vol->root;
590 else
591 child_dno = dno;
592 fsw_dnode_retain(child_dno);
593
594 } else {
595 // do an actual directory lookup
596
597 // ensure we have full information
598 status = fsw_dnode_fill(dno);
599 if (status)
600 goto errorexit;
601
602 // resolve symlink if necessary
603 if (dno->type == FSW_DNODE_TYPE_SYMLINK) {
604 status = fsw_dnode_resolve(dno, &child_dno);
605 if (status)
606 goto errorexit;
607
608 // symlink target becomes the new dno
609 fsw_dnode_release(dno);
610 dno = child_dno; // is already retained
611 child_dno = NULL;
612
613 // ensure we have full information
614 status = fsw_dnode_fill(dno);
615 if (status)
616 goto errorexit;
617 }
618
619 // make sure we operate on a directory
620 if (dno->type != FSW_DNODE_TYPE_DIR) {
621 return FSW_UNSUPPORTED;
622 goto errorexit;
623 }
624
625 // check special paths
626 if (fsw_streq_cstr(&lookup_name, ".")) { // self directory
627 child_dno = dno;
628 fsw_dnode_retain(child_dno);
629
630 } else if (fsw_streq_cstr(&lookup_name, "..")) { // parent directory
631 if (dno->parent == NULL) {
632 // We cannot go up from the root directory. Caution: Certain apps like the EFI shell
633 // rely on this behaviour!
634 status = FSW_NOT_FOUND;
635 goto errorexit;
636 }
637 child_dno = dno->parent;
638 fsw_dnode_retain(child_dno);
639
640 } else {
641 // do an actual lookup
642 status = vol->fstype_table->dir_lookup(vol, dno, &lookup_name, &child_dno);
643 if (status)
644 goto errorexit;
645 }
646 }
647
648 // child_dno becomes the new dno
649 fsw_dnode_release(dno);
650 dno = child_dno; // is already retained
651 child_dno = NULL;
652
653 FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: now at inode %d\n"), dno->dnode_id));
654 }
655
656 *child_dno_out = dno;
657 return FSW_SUCCESS;
658
659 errorexit:
660 FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: leaving with error %d\n"), status));
661 fsw_dnode_release(dno);
662 if (child_dno != NULL)
663 fsw_dnode_release(child_dno);
664 return status;
665 }
666
667 /**
668 * Get the next directory item in sequential order. This function is called by the
669 * host driver to read the complete contents of a directory in sequential (file system
670 * defined) order. Calling this function returns the next entry. Iteration state is
671 * kept by a shandle on the directory's dnode. The caller must set up the shandle
672 * when starting the iteration.
673 *
674 * When the end of the directory is reached, this function returns FSW_NOT_FOUND.
675 * If the function returns FSW_SUCCESS, *child_dno_out points to the next directory
676 * entry. The caller must call fsw_dnode_release on it.
677 */
678
679 fsw_status_t fsw_dnode_dir_read(struct fsw_shandle *shand, struct fsw_dnode **child_dno_out)
680 {
681 fsw_status_t status;
682 struct fsw_dnode *dno = shand->dnode;
683 fsw_u64 saved_pos;
684
685 if (dno->type != FSW_DNODE_TYPE_DIR)
686 return FSW_UNSUPPORTED;
687
688 saved_pos = shand->pos;
689 status = dno->vol->fstype_table->dir_read(dno->vol, dno, shand, child_dno_out);
690 if (status)
691 shand->pos = saved_pos;
692 return status;
693 }
694
695 /**
696 * Read the target path of a symbolic link. This function is called by the host driver
697 * to read the "content" of a symbolic link, that is the relative or absolute path
698 * it points to.
699 *
700 * If the function returns FSW_SUCCESS, the string handle provided by the caller is
701 * filled with a string in the host's preferred encoding. The caller is responsible
702 * for calling fsw_strfree on the string.
703 */
704
705 fsw_status_t fsw_dnode_readlink(struct fsw_dnode *dno, struct fsw_string *target_name)
706 {
707 fsw_status_t status;
708
709 status = fsw_dnode_fill(dno);
710 if (status)
711 return status;
712 if (dno->type != FSW_DNODE_TYPE_SYMLINK)
713 return FSW_UNSUPPORTED;
714
715 return dno->vol->fstype_table->readlink(dno->vol, dno, target_name);
716 }
717
718 /**
719 * Read the target path of a symbolic link by accessing file data. This function can
720 * be called by the file system driver if the file system stores the target path
721 * as normal file data. This function will open an shandle, read the whole content
722 * of the file into a buffer, and build a string from that. Currently the encoding
723 * for the string is fixed as FSW_STRING_TYPE_ISO88591.
724 *
725 * If the function returns FSW_SUCCESS, the string handle provided by the caller is
726 * filled with a string in the host's preferred encoding. The caller is responsible
727 * for calling fsw_strfree on the string.
728 */
729
730 fsw_status_t fsw_dnode_readlink_data(struct fsw_dnode *dno, struct fsw_string *link_target)
731 {
732 fsw_status_t status;
733 struct fsw_shandle shand;
734 fsw_u32 buffer_size;
735 char buffer[FSW_PATH_MAX];
736
737 struct fsw_string s;
738
739 if (dno->size > FSW_PATH_MAX)
740 return FSW_VOLUME_CORRUPTED;
741
742 s.type = FSW_STRING_TYPE_ISO88591;
743 s.size = s.len = (int)dno->size;
744 s.data = buffer;
745
746 // open shandle and read the data
747 status = fsw_shandle_open(dno, &shand);
748 if (status)
749 return status;
750 buffer_size = (fsw_u32)s.size;
751 status = fsw_shandle_read(&shand, &buffer_size, buffer);
752 fsw_shandle_close(&shand);
753 if (status)
754 return status;
755 if ((int)buffer_size < s.size)
756 return FSW_VOLUME_CORRUPTED;
757
758 status = fsw_strdup_coerce(link_target, dno->vol->host_string_type, &s);
759 return status;
760 }
761
762 /**
763 * Resolve a symbolic link. This function can be called by the host driver to make
764 * sure the a dnode is fully resolved instead of pointing at a symlink. If the dnode
765 * passed in is not a symlink, it is returned unmodified.
766 *
767 * Note that absolute paths will be resolved relative to the root directory of the
768 * volume. If the host is an operating system with its own VFS layer, it should
769 * resolve symlinks on its own.
770 *
771 * If the function returns FSW_SUCCESS, *target_dno_out points at a dnode that is
772 * not a symlink. The caller is responsible for calling fsw_dnode_release on it.
773 */
774
775 fsw_status_t fsw_dnode_resolve(struct fsw_dnode *dno, struct fsw_dnode **target_dno_out)
776 {
777 fsw_status_t status;
778 struct fsw_string target_name;
779 struct fsw_dnode *target_dno;
780 /* Linux kernel max link count is 40 */
781 int link_count = 40;
782
783 fsw_dnode_retain(dno);
784
785 while (--link_count > 0) {
786 // get full information
787 status = fsw_dnode_fill(dno);
788 if (status)
789 goto errorexit;
790 if (dno->type != FSW_DNODE_TYPE_SYMLINK) {
791 // found a non-symlink target, return it
792 *target_dno_out = dno;
793 return FSW_SUCCESS;
794 }
795 if (dno->parent == NULL) { // safety measure, cannot happen in theory
796 status = FSW_NOT_FOUND;
797 goto errorexit;
798 }
799
800 // read the link's target
801 status = fsw_dnode_readlink(dno, &target_name);
802 if (status)
803 goto errorexit;
804
805 // resolve it
806 status = fsw_dnode_lookup_path(dno->parent, &target_name, '/', &target_dno);
807 fsw_strfree(&target_name);
808 if (status)
809 goto errorexit;
810
811 // target_dno becomes the new dno
812 fsw_dnode_release(dno);
813 dno = target_dno; // is already retained
814 }
815 if(link_count == 0)
816 status = FSW_NOT_FOUND;
817
818 errorexit:
819 fsw_dnode_release(dno);
820 return status;
821 }
822
823 /**
824 * Set up a shandle (storage handle) to access a file's data. This function is called
825 * by the host driver and by the core when they need to access a file's data. It is also
826 * used in accessing the raw data of directories and symlinks if the file system uses
827 * the same mechanisms for storing the data of those items.
828 *
829 * The storage for the fsw_shandle structure is provided by the caller. The dnode and pos
830 * fields may be accessed, pos may also be written to to set the file pointer. The file's
831 * data size is available as shand->dnode->size.
832 *
833 * If this function returns FSW_SUCCESS, the caller must call fsw_shandle_close to release
834 * the dnode reference held by the shandle.
835 */
836
837 fsw_status_t fsw_shandle_open(struct fsw_dnode *dno, struct fsw_shandle *shand)
838 {
839 fsw_status_t status;
840 struct fsw_volume *vol = dno->vol;
841
842 // read full dnode information into memory
843 status = vol->fstype_table->dnode_fill(vol, dno);
844 if (status)
845 return status;
846
847 // setup shandle
848 fsw_dnode_retain(dno);
849
850 shand->dnode = dno;
851 shand->pos = 0;
852 shand->extent.type = FSW_EXTENT_TYPE_INVALID;
853
854 return FSW_SUCCESS;
855 }
856
857 /**
858 * Close a shandle after accessing the dnode's data. This function is called by the host
859 * driver or core functions when they are finished with accessing a file's data. It
860 * releases the dnode reference and frees any buffers associated with the shandle itself.
861 * The dnode is only released if this was the last reference using it.
862 */
863
864 void fsw_shandle_close(struct fsw_shandle *shand)
865 {
866 if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER)
867 fsw_free(shand->extent.buffer);
868 fsw_dnode_release(shand->dnode);
869 }
870
871 /**
872 * Read data from a shandle (storage handle for a dnode). This function is called by the
873 * host driver or internally when data is read from a file. TODO: more
874 */
875
876 fsw_status_t fsw_shandle_read(struct fsw_shandle *shand, fsw_u32 *buffer_size_inout, void *buffer_in)
877 {
878 fsw_status_t status;
879 struct fsw_dnode *dno = shand->dnode;
880 struct fsw_volume *vol = dno->vol;
881 fsw_u8 *buffer, *block_buffer;
882 fsw_u64 buflen, copylen, pos;
883 fsw_u64 log_bno, pos_in_extent, phys_bno, pos_in_physblock;
884 fsw_u32 cache_level;
885
886 if (shand->pos >= dno->size) { // already at EOF
887 *buffer_size_inout = 0;
888 return FSW_SUCCESS;
889 }
890
891 // initialize vars
892 buffer = buffer_in;
893 buflen = *buffer_size_inout;
894 pos = (fsw_u32)shand->pos;
895 cache_level = (dno->type != FSW_DNODE_TYPE_FILE) ? 1 : 0;
896 // restrict read to file size
897 if (buflen > dno->size - pos)
898 buflen = (fsw_u32)(dno->size - pos);
899
900 while (buflen > 0) {
901 // get extent for the current logical block
902 log_bno = FSW_U64_DIV(pos, vol->log_blocksize);
903 if (shand->extent.type == FSW_EXTENT_TYPE_INVALID ||
904 log_bno < shand->extent.log_start ||
905 log_bno >= shand->extent.log_start + shand->extent.log_count) {
906
907 if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER)
908 fsw_free(shand->extent.buffer);
909
910 // ask the file system for the proper extent
911 shand->extent.log_start = log_bno;
912 status = vol->fstype_table->get_extent(vol, dno, &shand->extent);
913 if (status) {
914 shand->extent.type = FSW_EXTENT_TYPE_INVALID;
915 return status;
916 }
917 }
918
919 pos_in_extent = pos - shand->extent.log_start * vol->log_blocksize;
920
921 // dispatch by extent type
922 if (shand->extent.type == FSW_EXTENT_TYPE_PHYSBLOCK) {
923 // convert to physical block number and offset
924 phys_bno = shand->extent.phys_start + FSW_U64_DIV(pos_in_extent, vol->phys_blocksize);
925 pos_in_physblock = pos_in_extent & (vol->phys_blocksize - 1);
926 copylen = vol->phys_blocksize - pos_in_physblock;
927 if (copylen > buflen)
928 copylen = buflen;
929
930 // get one physical block
931 status = fsw_block_get(vol, phys_bno, cache_level, (void **)&block_buffer);
932 if (status)
933 return status;
934
935 // copy data from it
936 fsw_memcpy(buffer, block_buffer + pos_in_physblock, copylen);
937 fsw_block_release(vol, phys_bno, block_buffer);
938
939 } else if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER) {
940 copylen = shand->extent.log_count * vol->log_blocksize - pos_in_extent;
941 if (copylen > buflen)
942 copylen = buflen;
943 fsw_memcpy(buffer, (fsw_u8 *)shand->extent.buffer + pos_in_extent, copylen);
944
945 } else { // _SPARSE or _INVALID
946 copylen = shand->extent.log_count * vol->log_blocksize - pos_in_extent;
947 if (copylen > buflen)
948 copylen = buflen;
949 fsw_memzero(buffer, copylen);
950
951 }
952
953 buffer += copylen;
954 buflen -= copylen;
955 pos += copylen;
956 }
957
958 *buffer_size_inout = (fsw_u32)(pos - shand->pos);
959 shand->pos = pos;
960
961 return FSW_SUCCESS;
962 }
963
964 // EOF