285 lines
9.2 KiB
C
285 lines
9.2 KiB
C
/* 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 <sos/types.h>
|
|
#include <sos/errno.h>
|
|
|
|
/**
|
|
* 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_ */
|