1 /* $Id: fsw_core.c 29125 2010-05-06 09:43:05Z vboxsync $ */
3 * fsw_core.c - Core file system wrapper abstraction layer code.
7 * This code is based on:
9 * Copyright (c) 2006 Christoph Pfisterer
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are
15 * * Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
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
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.
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.
45 static void fsw_blockcache_free(struct fsw_volume
*vol
);
47 #define MAX_CACHE_LEVEL (5)
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.
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.
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.
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
)
70 struct fsw_volume
*vol
;
72 // allocate memory for the structure
73 status
= fsw_alloc_zero(fstype_table
->volume_struct_size
, (void **)&vol
);
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
;
86 // let the fs driver mount the file system
87 status
= vol
->fstype_table
->volume_mount(vol
);
91 // TODO: anything else?
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.
106 * Note that all dnodes must have been released before calling this function.
109 void fsw_unmount(struct fsw_volume
*vol
)
112 fsw_dnode_release(vol
->root
);
113 // TODO: check that no other dnodes are still around
115 vol
->fstype_table
->volume_free(vol
);
117 fsw_blockcache_free(vol
);
118 fsw_strfree(&vol
->label
);
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.
127 fsw_status_t
fsw_volume_stat(struct fsw_volume
*vol
, struct fsw_volume_stat
*sb
)
129 return vol
->fstype_table
->volume_stat(vol
, sb
);
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.
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.
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.
147 void fsw_set_blocksize(struct fsw_volume
*vol
, fsw_u32 phys_blocksize
, fsw_u32 log_blocksize
)
149 // TODO: Check the sizes. Both must be powers of 2. log_blocksize must not be smaller than
152 // drop core block cache if present
153 fsw_blockcache_free(vol
);
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
);
160 vol
->phys_blocksize
= phys_blocksize
;
161 vol
->log_blocksize
= log_blocksize
;
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:
173 * - 1: Directory data, symlink data
174 * - 2: File system metadata
175 * - 3..5: File system metadata with a high rate of access
177 * If this function returns successfully, the returned data pointer is valid until the
178 * caller calls fsw_block_release.
181 fsw_status_t
fsw_block_get(struct VOLSTRUCTNAME
*vol
, fsw_u64 phys_bno
, fsw_u32 cache_level
, void **buffer_out
)
184 fsw_u32 i
, discard_level
, new_bcache_size
;
185 struct fsw_blockcache
*new_bcache
;
187 // TODO: allow the host driver to do its own caching; just call through if
188 // the appropriate function pointers are set
190 if (cache_level
> MAX_CACHE_LEVEL
)
191 cache_level
= MAX_CACHE_LEVEL
;
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
);
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
;
209 for (i
= 0; i
< vol
->bcache_size
; i
++) {
210 if (vol
->bcache
[i
].phys_bno
== phys_bno
) {
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
;
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
)
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
)
231 if (i
< vol
->bcache_size
)
235 if (i
>= vol
->bcache_size
) {
236 // enlarge / create the cache
237 if (vol
->bcache_size
< 16)
238 new_bcache_size
= 16;
240 new_bcache_size
= vol
->bcache_size
<< 1;
241 status
= fsw_alloc(new_bcache_size
* sizeof(struct fsw_blockcache
), &new_bcache
);
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
;
252 i
= vol
->bcache_size
;
255 if (vol
->bcache
!= NULL
)
256 fsw_free(vol
->bcache
);
257 vol
->bcache
= new_bcache
;
258 vol
->bcache_size
= new_bcache_size
;
260 vol
->bcache
[i
].phys_bno
= (fsw_u64
)FSW_INVALID_BNO
;
264 if (vol
->bcache
[i
].data
== NULL
) {
265 status
= fsw_alloc(vol
->phys_blocksize
, &vol
->bcache
[i
].data
);
269 status
= vol
->host_table
->read_block(vol
, phys_bno
, vol
->bcache
[i
].data
);
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
;
281 * Releases a disk block. This function must be called to release disk blocks returned
282 * from fsw_block_get.
285 void fsw_block_release(struct VOLSTRUCTNAME
*vol
, fsw_u64 phys_bno
, void *buffer
)
289 // TODO: allow the host driver to do its own caching; just call through if
290 // the appropriate function pointers are set
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
--;
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.
304 static void fsw_blockcache_free(struct fsw_volume
*vol
)
308 for (i
= 0; i
< vol
->bcache_size
; i
++) {
309 if (vol
->bcache
[i
].data
!= NULL
)
310 fsw_free(vol
->bcache
[i
].data
);
312 if (vol
->bcache
!= NULL
) {
313 fsw_free(vol
->bcache
);
316 vol
->bcache_size
= 0;
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
325 static void fsw_dnode_register(struct fsw_volume
*vol
, struct fsw_dnode
*dno
)
327 dno
->next
= vol
->dnode_head
;
328 if (vol
->dnode_head
!= NULL
)
329 vol
->dnode_head
->prev
= dno
;
331 vol
->dnode_head
= dno
;
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.
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
)
344 struct fsw_dnode
*dno
;
346 // allocate memory for the structure
347 status
= fsw_alloc_zero(vol
->fstype_table
->dnode_struct_size
, (void **)&dno
);
351 // fill the structure
354 dno
->tree_id
= tree_id
;
355 dno
->dnode_id
= dnode_id
;
356 dno
->type
= FSW_DNODE_TYPE_DIR
;
358 dno
->name
.type
= FSW_STRING_TYPE_EMPTY
;
359 // TODO: instead, call a function to create an empty string in the native string type
361 fsw_dnode_register(vol
, dno
);
367 fsw_status_t
fsw_dnode_create_root(struct fsw_volume
*vol
, fsw_u64 dnode_id
, struct fsw_dnode
**dno_out
)
369 return fsw_dnode_create_root_with_tree( vol
, 0, dnode_id
, dno_out
);
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.
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.
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.
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.
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
)
393 struct fsw_volume
*vol
= parent_dno
->vol
;
394 struct fsw_dnode
*dno
;
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
);
405 // allocate memory for the structure
406 status
= fsw_alloc_zero(vol
->fstype_table
->dnode_struct_size
, (void **)&dno
);
410 // fill the structure
412 dno
->parent
= parent_dno
;
413 fsw_dnode_retain(dno
->parent
);
414 dno
->tree_id
= tree_id
;
415 dno
->dnode_id
= dnode_id
;
418 status
= fsw_strdup_coerce(&dno
->name
, vol
->host_table
->native_string_type
, name
);
424 fsw_dnode_register(vol
, dno
);
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
)
433 return fsw_dnode_create_with_tree(parent_dno
, 0, dnode_id
, type
, name
, dno_out
);
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.
442 void fsw_dnode_retain(struct fsw_dnode
*dno
)
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.
454 void fsw_dnode_release(struct fsw_dnode
*dno
)
456 struct fsw_volume
*vol
= dno
->vol
;
457 struct fsw_dnode
*parent_dno
;
461 if (dno
->refcount
== 0) {
462 parent_dno
= dno
->parent
;
464 // de-register from volume's list
466 dno
->next
->prev
= dno
->prev
;
468 dno
->prev
->next
= dno
->next
;
469 if (vol
->dnode_head
== dno
)
470 vol
->dnode_head
= dno
->next
;
472 // run fstype-specific cleanup
473 vol
->fstype_table
->dnode_free(vol
, dno
);
475 fsw_strfree(&dno
->name
);
478 // release our pointer to the parent, possibly deallocating it, too
480 fsw_dnode_release(parent_dno
);
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:
495 fsw_status_t
fsw_dnode_fill(struct fsw_dnode
*dno
)
497 // TODO: check a flag right here, call fstype's dnode_fill only once per dnode
499 return dno
->vol
->fstype_table
->dnode_fill(dno
->vol
, dno
);
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.
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.
512 fsw_status_t
fsw_dnode_stat(struct fsw_dnode
*dno
, struct fsw_dnode_stat
*sb
)
516 status
= fsw_dnode_fill(dno
);
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
);
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
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.
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.
539 fsw_status_t
fsw_dnode_lookup(struct fsw_dnode
*dno
,
540 struct fsw_string
*lookup_name
, struct fsw_dnode
**child_dno_out
)
544 status
= fsw_dnode_fill(dno
);
547 if (dno
->type
!= FSW_DNODE_TYPE_DIR
)
548 return FSW_UNSUPPORTED
;
550 return dno
->vol
->fstype_table
->dir_lookup(dno
->vol
, dno
, lookup_name
, child_dno_out
);
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
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.
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
)
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
;
575 remaining_path
= *lookup_path
;
576 fsw_dnode_retain(dno
);
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
);
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
));
587 if (fsw_strlen(&lookup_name
) == 0) { // empty path component
589 child_dno
= vol
->root
;
592 fsw_dnode_retain(child_dno
);
595 // do an actual directory lookup
597 // ensure we have full information
598 status
= fsw_dnode_fill(dno
);
602 // resolve symlink if necessary
603 if (dno
->type
== FSW_DNODE_TYPE_SYMLINK
) {
604 status
= fsw_dnode_resolve(dno
, &child_dno
);
608 // symlink target becomes the new dno
609 fsw_dnode_release(dno
);
610 dno
= child_dno
; // is already retained
613 // ensure we have full information
614 status
= fsw_dnode_fill(dno
);
619 // make sure we operate on a directory
620 if (dno
->type
!= FSW_DNODE_TYPE_DIR
) {
621 return FSW_UNSUPPORTED
;
625 // check special paths
626 if (fsw_streq_cstr(&lookup_name
, ".")) { // self directory
628 fsw_dnode_retain(child_dno
);
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
;
637 child_dno
= dno
->parent
;
638 fsw_dnode_retain(child_dno
);
641 // do an actual lookup
642 status
= vol
->fstype_table
->dir_lookup(vol
, dno
, &lookup_name
, &child_dno
);
648 // child_dno becomes the new dno
649 fsw_dnode_release(dno
);
650 dno
= child_dno
; // is already retained
653 FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: now at inode %d\n"), dno
->dnode_id
));
656 *child_dno_out
= dno
;
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
);
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.
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.
679 fsw_status_t
fsw_dnode_dir_read(struct fsw_shandle
*shand
, struct fsw_dnode
**child_dno_out
)
682 struct fsw_dnode
*dno
= shand
->dnode
;
685 if (dno
->type
!= FSW_DNODE_TYPE_DIR
)
686 return FSW_UNSUPPORTED
;
688 saved_pos
= shand
->pos
;
689 status
= dno
->vol
->fstype_table
->dir_read(dno
->vol
, dno
, shand
, child_dno_out
);
691 shand
->pos
= saved_pos
;
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
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.
705 fsw_status_t
fsw_dnode_readlink(struct fsw_dnode
*dno
, struct fsw_string
*target_name
)
709 status
= fsw_dnode_fill(dno
);
712 if (dno
->type
!= FSW_DNODE_TYPE_SYMLINK
)
713 return FSW_UNSUPPORTED
;
715 return dno
->vol
->fstype_table
->readlink(dno
->vol
, dno
, target_name
);
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.
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.
730 fsw_status_t
fsw_dnode_readlink_data(struct fsw_dnode
*dno
, struct fsw_string
*link_target
)
733 struct fsw_shandle shand
;
735 char buffer
[FSW_PATH_MAX
];
739 if (dno
->size
> FSW_PATH_MAX
)
740 return FSW_VOLUME_CORRUPTED
;
742 s
.type
= FSW_STRING_TYPE_ISO88591
;
743 s
.size
= s
.len
= (int)dno
->size
;
746 // open shandle and read the data
747 status
= fsw_shandle_open(dno
, &shand
);
750 buffer_size
= (fsw_u32
)s
.size
;
751 status
= fsw_shandle_read(&shand
, &buffer_size
, buffer
);
752 fsw_shandle_close(&shand
);
755 if ((int)buffer_size
< s
.size
)
756 return FSW_VOLUME_CORRUPTED
;
758 status
= fsw_strdup_coerce(link_target
, dno
->vol
->host_string_type
, &s
);
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.
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.
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.
775 fsw_status_t
fsw_dnode_resolve(struct fsw_dnode
*dno
, struct fsw_dnode
**target_dno_out
)
778 struct fsw_string target_name
;
779 struct fsw_dnode
*target_dno
;
780 /* Linux kernel max link count is 40 */
783 fsw_dnode_retain(dno
);
785 while (--link_count
> 0) {
786 // get full information
787 status
= fsw_dnode_fill(dno
);
790 if (dno
->type
!= FSW_DNODE_TYPE_SYMLINK
) {
791 // found a non-symlink target, return it
792 *target_dno_out
= dno
;
795 if (dno
->parent
== NULL
) { // safety measure, cannot happen in theory
796 status
= FSW_NOT_FOUND
;
800 // read the link's target
801 status
= fsw_dnode_readlink(dno
, &target_name
);
806 status
= fsw_dnode_lookup_path(dno
->parent
, &target_name
, '/', &target_dno
);
807 fsw_strfree(&target_name
);
811 // target_dno becomes the new dno
812 fsw_dnode_release(dno
);
813 dno
= target_dno
; // is already retained
816 status
= FSW_NOT_FOUND
;
819 fsw_dnode_release(dno
);
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.
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.
833 * If this function returns FSW_SUCCESS, the caller must call fsw_shandle_close to release
834 * the dnode reference held by the shandle.
837 fsw_status_t
fsw_shandle_open(struct fsw_dnode
*dno
, struct fsw_shandle
*shand
)
840 struct fsw_volume
*vol
= dno
->vol
;
842 // read full dnode information into memory
843 status
= vol
->fstype_table
->dnode_fill(vol
, dno
);
848 fsw_dnode_retain(dno
);
852 shand
->extent
.type
= FSW_EXTENT_TYPE_INVALID
;
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.
864 void fsw_shandle_close(struct fsw_shandle
*shand
)
866 if (shand
->extent
.type
== FSW_EXTENT_TYPE_BUFFER
)
867 fsw_free(shand
->extent
.buffer
);
868 fsw_dnode_release(shand
->dnode
);
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
876 fsw_status_t
fsw_shandle_read(struct fsw_shandle
*shand
, fsw_u32
*buffer_size_inout
, void *buffer_in
)
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
;
886 if (shand
->pos
>= dno
->size
) { // already at EOF
887 *buffer_size_inout
= 0;
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
);
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
) {
907 if (shand
->extent
.type
== FSW_EXTENT_TYPE_BUFFER
)
908 fsw_free(shand
->extent
.buffer
);
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
);
914 shand
->extent
.type
= FSW_EXTENT_TYPE_INVALID
;
919 pos_in_extent
= pos
- shand
->extent
.log_start
* vol
->log_blocksize
;
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
)
930 // get one physical block
931 status
= fsw_block_get(vol
, phys_bno
, cache_level
, (void **)&block_buffer
);
936 fsw_memcpy(buffer
, block_buffer
+ pos_in_physblock
, copylen
);
937 fsw_block_release(vol
, phys_bno
, block_buffer
);
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
)
943 fsw_memcpy(buffer
, (fsw_u8
*)shand
->extent
.buffer
+ pos_in_extent
, copylen
);
945 } else { // _SPARSE or _INVALID
946 copylen
= shand
->extent
.log_count
* vol
->log_blocksize
- pos_in_extent
;
947 if (copylen
> buflen
)
949 fsw_memzero(buffer
, copylen
);
958 *buffer_size_inout
= (fsw_u32
)(pos
- shand
->pos
);