/* Copyright (C) 2005 David Decotigny Copyright (C) 2000-2005 The KOS Team (Thomas Petazzoni, David Decotigny, Julien Munier) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _SOS_FS_NSCACHE_H_ #define _SOS_FS_NSCACHE_H_ /** * @file fs_nscache.h * * FS Namespace cache (aka file hierarchy) management. Internal API * reserved to fs.c and to the FS managers ! See fs.c for details and * role of this subsystem in the whole VFS. * * We keep the usual filesystem semantics of a "file hierarchy": * * parent0 * / \ * child1 child2 * / \ \ * child1a child1b child2a * * The system allows that different children actually reference the * same "on-disk" node (sos_fs_node). For example: child1a and child2a * might reference the same sos_fs_node: this represents a so-called * "hard link". * * The functions of this module are in charge of updating the nscache * nodes and their reference count. They don't influence the other * subsystems (apart from the sos_fs_nscache_unref_node() function * which can unreference the underlying sos_fs_node). * * Note: only the nscache nodes that are actually used or those that * are their parents (ie in the path from these nodes to the global * root) will remain in memory. The others will be destroyed as soon * as they are not needed anymore. For example, il I do a * stat("/mnt/toto/titi.txt", & st), all the nscache nodes from "/" to * "titi.txt" will be allocated, the stat performed, and all of them * will be destroyed. We could imagine a real "cache" here to avoid * these bursts of allocations/deallocations, by keeping the last * accessed nodes aside when they are not referenced anymore (in a * hash table for example, the key being {parent nscache node address, * child name}). * * Note about mountpoints: When a FS is mounted in, say "/mnt", the * nscache node of the new FS is registered neither as its child nor * as its parent, but as a kind of "brother" of /mnt. As seen from the * global root ("/"), "mnt" in a direct child and the mounted root is * its brother. But, once mounted, as seen from a child node * "/mnt/toto", the mounted root is seen as the direct parent of * /mnt/toto and "mnt" is seen as its brother. That is, each time we * try to resolve (lookup) the children on a mountpoint, we must * "follow" the mountchain. In the previous example, multiple * successive FS could be mounted on the same "/mnt". */ #include #include /** * Opaque structure defined in fs_nscache.c * * Essentially contains: * - a name (allocated in-place) * - a reference to the associated FS node (struct sos_fs_node) * - a reference to the parent nscache node (if any) * - a list of pointers to the children nscache nodes (for directories) */ struct sos_fs_nscache_node; #include "fs.h" /** * Support for non-0 terminated strings (Pascal-style). Useful to * prevent from altering the contents of the string in order to split * pathnames into components (@see sos_fs_pathname_split_path) */ struct sos_fs_pathname { const char * contents; sos_size_t length; }; sos_ret_t sos_fs_nscache_subsystem_setup(void); /** * Lookup the given entry in the given nsnode. The lookup is limited * to the children entries that are already in memory. When this * lookup fails, this simply means that the entry is not already in * memory, and has to be resolved using disk accesses (@see * fs_lookup_node in fs.c) * * @param cur_nsnode The node in which we are looking for the entry * @param root_node The base node beyond which lookup must not go (to * support chroot): a kind of "barrier" * * @param result_nsnode The nsnode for the given entry (set only when * the return value is SOS_OK) * * @return error if the entry could not be found in the nsnode * directory. OK otherwise, and *result_nsnode is set. * * @note The symlinks are NOT expanded. The mountpoints ARE followed. * @note result_nsnode is a NEW reference to the node. It should be * unreferenced when unused */ sos_ret_t sos_fs_nscache_lookup(struct sos_fs_nscache_node * cur_nsnode, const struct sos_fs_pathname * node_name, const struct sos_fs_nscache_node * root_nsnode, struct sos_fs_nscache_node ** result_nsnode); /** * Add a new child node for the given parent, for the given fs_node * * @param parent might be NULL, meaning that the node is the root of a * mounted filesystem * * @note The new node has the value 0 for the opened_file and * mount_chain counters * @note result_nsnode is a NEW reference to the node. It should be * unreferenced when unused */ sos_ret_t sos_fs_nscache_add_new_child_node(struct sos_fs_nscache_node * parent, const struct sos_fs_pathname * node_name, struct sos_fs_node * fsnode, struct sos_fs_nscache_node ** result_nsnode); /** * Add a new child node for the given parent, for the given already * existing nsnode (with no parent !) * * @param parent can not be NULL * * @note nsnode should NOT have any parent */ sos_ret_t sos_fs_nscache_add_existing_child_node(struct sos_fs_nscache_node * parent, const struct sos_fs_pathname * node_name, struct sos_fs_nscache_node * nsnode); /** * Disconnect the given node from its parent, if any * @note reference count of nsnode is NOT modified */ sos_ret_t sos_fs_nscache_disconnect_node(struct sos_fs_nscache_node * nsnode); /** * Register the given root of a new file system (mounted_root) in the * mountpoint chain located at mountpoint, ie build the mountchain. */ sos_ret_t sos_fs_nscache_mount(struct sos_fs_nscache_node * mountpoint, struct sos_fs_nscache_node * mounted_root); /** * Break the mountchain at the given mounted root, making sure that * this nscache node is not reference by any opened file or child node * anymore. */ sos_ret_t sos_fs_nscache_umount(struct sos_fs_nscache_node * mounted_root); /** Return true if the node is involved in any mountchain */ sos_bool_t sos_fs_nscache_is_mountnode(const struct sos_fs_nscache_node * nsnode); /* * Accessor functions */ /** * Return the FS node of the given nscache node. * * @note The FS node returned is NOT newly referenced */ struct sos_fs_node * sos_fs_nscache_get_fs_node(const struct sos_fs_nscache_node * nsnode); /** * Return the parent nscache node of the given nscache node. * * @note The nscache node returned is NOT newly referenced */ sos_ret_t sos_fs_nscache_get_parent(const struct sos_fs_nscache_node * nsnode, struct sos_fs_nscache_node ** result_parent); sos_ret_t sos_fs_nscache_get_name(const struct sos_fs_nscache_node * nsnode, struct sos_fs_pathname * result_pathname); /** * Return the value of the reference count for the given nscache node */ sos_ret_t sos_fs_nscache_get_ref_cnt(const struct sos_fs_nscache_node * nsnode); sos_ret_t sos_fs_nscache_register_opened_file(struct sos_fs_nscache_node * nsnode, struct sos_fs_opened_file * of); sos_ret_t sos_fs_nscache_ref_node(struct sos_fs_nscache_node * nsnode); sos_ret_t _sos_fs_nscache_unref_node(struct sos_fs_nscache_node ** nsnode); #define sos_fs_nscache_unref_node(n) _sos_fs_nscache_unref_node(& (n)) /* * Functions reserved to sos_fs_manager_type::mount() and * sos_fs_manager_type::umount() */ #define sos_fs_nscache_create_mounted_root(fsnode,result_nsnode) \ sos_fs_nscache_add_new_child_node(NULL, NULL, (fsnode), (result_nsnode)) /* * Pathname manipulation functions */ sos_bool_t fs_pathname_iseq(const struct sos_fs_pathname * p1, const struct sos_fs_pathname * p2); /** * Remove any leading slash from the path * * @Return TRUE when slashes were found at the begining */ sos_bool_t sos_fs_pathname_eat_slashes(const struct sos_fs_pathname * path, struct sos_fs_pathname * result); /** * Transform "a/b/c" into { first_component="a" remaining_path="/b/c" } * Transform "/a/b/c" into { first_component="a" remaining_path="/b/c" } * Transform "////a////b/c" into { first_component="a" remaining_path="////b/c" } * Transform "a" into { first_component="a" remaining_path="" } * Transform "/a" into { first_component="a" remaining_path="" } * Transform "a/" into { first_component="a" remaining_path="" } * Transform "/a/" into { first_component="a" remaining_path="" } * * @Return TRUE when slashes after first component were found. In the * previous example: true everywhere except for the path "a" and "/a" */ sos_bool_t sos_fs_pathname_split_path(const struct sos_fs_pathname * path, struct sos_fs_pathname * result_first_component, struct sos_fs_pathname * result_remaining_path); #endif /* _SOS_FS_NSCACHE_H_ */