Index: uspace/lib/c/generic/vfs/vfs.c
===================================================================
--- uspace/lib/c/generic/vfs/vfs.c	(revision 438f35572a570ba2376a8677855d0169c26c1508)
+++ uspace/lib/c/generic/vfs/vfs.c	(revision ca7506fe324d2e1cdddab8cb6add035447f95c9b)
@@ -51,4 +51,67 @@
 #include <ipc/loc.h>
 
+/*
+ * This file contains the implementation of the native HelenOS file system API.
+ *
+ * The API supports client-side file system roots, client-side IO cursors and
+ * uses file handles as a primary means to refer to files. In order to call the
+ * API functions, one just includes vfs/vfs.h.
+ *
+ * The API functions come in two main flavors:
+ *
+ * - functions that operate on integer file handles, such as:
+ *   vfs_walk(), vfs_open(), vfs_read(), vfs_link(), ...
+ *  
+ * - functions that operate on paths, such as:
+ *   vfs_lookup(), vfs_link_path(), vfs_unlink_path(), vfs_rename_path(), ...
+ *
+ * There is usually a corresponding path function for each file handle function
+ * that exists mostly as a convenience wrapper, except for cases when only a
+ * path version exists due to file system consistency considerations (see
+ * vfs_rename_path()). Sometimes one of the versions does not make sense, in
+ * which case it is also omitted.
+ *
+ * Besides of that, the API provides some convenience wrappers for frequently
+ * performed pairs of operations, for example there is a combo API for
+ * vfs_lookup() and vfs_open(): vfs_lookup_open().
+ *
+ * Some of the functions here return a file handle that can be passed to other
+ * functions. Note that a file handle does not automatically represent a file
+ * from which one can read or to which one can write. In order to do so, the
+ * file handle must be opened first for reading/writing using vfs_open().
+ *
+ * All file handles, no matter whether opened or not, must be eventually
+ * returned to the system using vfs_put(). Non-returned file handles are in use
+ * and consume system resources.
+ *
+ * Functions that return int return a negative error code on error and do not
+ * set errno. Depending on function, success is signalled by returning either
+ * EOK or a non-negative file handle.
+ *
+ * An example life-cycle of a file handle is as follows:
+ *
+ * 	#include <vfs/vfs.h>
+ *
+ * 	int file = vfs_lookup("/foo/bar/foobar", WALK_REGULAR);
+ * 	if (file < 0)
+ * 		return file;
+ * 	int rc = vfs_open(file, MODE_READ);
+ * 	if (rc != EOK) {
+ * 		(void) vfs_put(file);
+ *		return rc;
+ * 	}
+ * 	aoff64_t pos = 42;
+ * 	char buf[512];
+ * 	ssize_t size = vfs_read(file, &pos, buf, sizeof(buf));
+ * 	if (size < 0) {
+ * 		vfs_put(file);
+ * 		return size;
+ * 	}
+ *
+ *	// buf is now filled with data from file
+ *
+ *	vfs_put(file);
+ */
+
 static FIBRIL_MUTEX_INITIALIZE(vfs_mutex);
 static async_sess_t *vfs_sess = NULL;
@@ -63,4 +126,8 @@
 static int root_fd = -1;
 
+/** Return a new file handle representing the local root
+ *
+ * @return      A clone of the local root file handle or a negative error code
+ */
 int vfs_root(void)
 {
@@ -75,4 +142,13 @@
 }
 
+/** Set a new local root
+ *
+ * Note that it is still possible to have file handles for other roots and pass
+ * them to the API functions. Functions like vfs_root() and vfs_lookup() will
+ * however consider the file set by this function to be the root.
+ *
+ * @param nroot The new local root file handle
+ */
+
 void vfs_root_set(int nroot)
 {
@@ -84,8 +160,7 @@
 }
 
-/** Start an async exchange on the VFS session.
- *
- * @return New exchange.
- *
+/** Start an async exchange on the VFS session
+ *
+ * @return      New exchange
  */
 async_exch_t *vfs_exchange_begin(void)
@@ -103,8 +178,7 @@
 }
 
-/** Finish an async exchange on the VFS session.
- *
- * @param exch Exchange to be finished.
- *
+/** Finish an async exchange on the VFS session
+ *
+ * @param exch  Exchange to be finished
  */
 void vfs_exchange_end(async_exch_t *exch)
@@ -113,4 +187,13 @@
 }
 
+/** Walk a path starting in a parent node
+ *
+ * @param parent        File handle of the parent node where the walk starts
+ * @param path          Parent-relative path to be walked
+ * @param flags         Flags influencing the walk
+ *
+ * @retrun              File handle representing the result on success or
+ *                      a negative error code on error
+ */
 int vfs_walk(int parent, const char *path, int flags)
 {
@@ -134,4 +217,12 @@
 }
 
+/** Lookup a path relative to the local root
+ *
+ * @param path  Path to be looked up
+ * @param flags Walk flags
+ *
+ * @return      File handle representing the result on success or a negative
+ *              error code on error
+ */
 int vfs_lookup(const char *path, int flags)
 {
@@ -151,4 +242,11 @@
 }
 
+/** Open a file handle for I/O
+ *
+ * @param file  File handle to enable I/O on
+ * @param mode  Mode in which to open file in
+ *
+ * @return      EOK on success or a negative error code
+ */
 int vfs_open(int file, int mode)
 {
@@ -160,4 +258,14 @@
 }
 
+/** Lookup a path relative to the local root and open the result
+ *
+ * This function is a convenience combo for vfs_lookup() and vfs_open().
+ *
+ * @param path  Path to be looked up
+ * @param flags Walk flags
+ * @param mode  Mode in which to open file in
+ *
+ * @return      EOK on success or a negative error code
+ */
 int vfs_lookup_open(const char *path, int flags, int mode)
 {
@@ -175,4 +283,15 @@
 }
 
+/** Make a potentially relative path absolute
+ *
+ * This function coverts a current-working-directory-relative path into a
+ * well-formed, absolute path. The caller is responsible for deallocating the
+ * returned buffer.
+ *
+ * @param[in] path      Path to be absolutized
+ * @param[out] retlen   Length of the absolutized path
+ *
+ * @return              New buffer holding the absolutized path or NULL
+ */
 char *vfs_absolutize(const char *path, size_t *retlen)
 {
@@ -225,4 +344,16 @@
 }
 
+/** Mount a file system
+ *
+ * @param[in] mp                File handle representing the mount-point
+ * @param[in] fs_name           File system name
+ * @param[in] serv              Service representing the mountee
+ * @param[in] opts              Mount options for the endpoint file system
+ * @param[in] flags             Mount flags
+ * @param[in] instance          Instance number of the file system server
+ * @param[out] mountedfd        File handle of the mounted root if not NULL
+ *
+ * @return                      EOK on success or a negative error code
+ */
 int vfs_mount(int mp, const char *fs_name, service_id_t serv, const char *opts,
     unsigned int flags, unsigned int instance, int *mountedfd)
@@ -258,4 +389,10 @@
 }
 
+/** Unmount a file system
+ *
+ * @param mp    File handle representing the mount-point
+ *
+ * @return      EOK on success or a negative error code
+ */
 int vfs_unmount(int mp)
 {
@@ -266,4 +403,15 @@
 }
 
+/** Mount a file system
+ *
+ * @param[in] mp                Path representing the mount-point
+ * @param[in] fs_name           File system name
+ * @param[in] fqsn              Fully qualified service name of the mountee
+ * @param[in] opts              Mount options for the endpoint file system
+ * @param[in] flags             Mount flags
+ * @param[in] instance          Instance number of the file system server
+ *
+ * @return                      EOK on success or a negative error code
+ */
 int vfs_mount_path(const char *mp, const char *fs_name, const char *fqsn,
     const char *opts, unsigned int flags, unsigned int instance)
@@ -353,4 +501,10 @@
 }
 
+/** Unmount a file system
+ *
+ * @param mpp   Mount-point path
+ *
+ * @return      EOK on success or a negative error code
+ */
 int vfs_unmount_path(const char *mpp)
 {
@@ -364,26 +518,20 @@
 }
 
-/** Close file.
- *
- * @param fildes File descriptor
- * @return EOK on success or a negative error code otherwise.
- */
-int vfs_put(int fildes)
-{
-	sysarg_t rc;
-	
-	async_exch_t *exch = vfs_exchange_begin();
-	rc = async_req_1_0(exch, VFS_IN_PUT, fildes);
-	vfs_exchange_end(exch);
-	
-	if (rc != EOK) {
-		errno = rc;
-		return -1;
-	}
-	
-	return 0;
-}
-
-/** Read bytes from file.
+/** Stop working with a file handle
+ *
+ * @param file  File handle to put
+ *
+ * @return      EOK on success or a negative error code
+ */
+int vfs_put(int file)
+{
+	async_exch_t *exch = vfs_exchange_begin();
+	int rc = async_req_1_0(exch, VFS_IN_PUT, file);
+	vfs_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Read bytes from a file
  *
  * Read up to @a nbyte bytes from file. The actual number of bytes read
@@ -392,11 +540,11 @@
  * return success with zero bytes read.
  *
- * @param file File descriptor
- * @param pos Position to read from
- * @param buf Buffer
- * @param nbyte Maximum number of bytes to read
- * @param nread Place to store actual number of bytes read (0 or more)
- *
- * @return EOK on success, non-zero error code on error.
+ * @param file          File handle to read from
+ * @param[in] pos       Position to read from
+ * @param buf           Buffer to read from
+ * @param nbyte         Maximum number of bytes to read
+ * @param[out] nread	Actual number of bytes read (0 or more)
+ *
+ * @return              EOK on success or a negative error code
  */
 int vfs_read_short(int file, aoff64_t pos, void *buf, size_t nbyte,
@@ -430,16 +578,16 @@
 }
 
-/** Write bytes to file.
+/** Write bytes to a file
  *
  * Write up to @a nbyte bytes from file. The actual number of bytes written
  * may be lower, but greater than zero.
  *
- * @param file File descriptor
- * @param pos Position to write to
- * @param buf Buffer
- * @param nbyte Maximum number of bytes to write
- * @param nread Place to store actual number of bytes written (0 or more)
- *
- * @return EOK on success, non-zero error code on error.
+ * @param file          File handle to write to
+ * @param[in] pos       Position to write to
+ * @param buf           Buffer to write to
+ * @param nbyte         Maximum number of bytes to write
+ * @param[out] nread    Actual number of bytes written (0 or more)
+ *
+ * @return              EOK on success or a negative error code
  */
 int vfs_write_short(int file, aoff64_t pos, const void *buf, size_t nbyte,
@@ -473,16 +621,16 @@
 }
 
-/** Read data.
+/** Read data
  *
  * Read up to @a nbytes bytes from file if available. This function always reads
  * all the available bytes up to @a nbytes.
  *
- * @param fildes	File descriptor
- * @param pos		Pointer to position to read from 
+ * @param file          File handle to read from
+ * @param[inout] pos    Position to read from, updated by the actual bytes read
  * @param buf		Buffer, @a nbytes bytes long
  * @param nbytes	Number of bytes to read
  *
- * @return		On success, non-negative number of bytes red.
- *			On failure, a negative error code.
+ * @return              On success, non-negative number of bytes read
+ * @return              On failure, a negative error code
  */
 ssize_t vfs_read(int file, aoff64_t *pos, void *buf, size_t nbyte)
@@ -507,15 +655,16 @@
 }
 
-/** Write data.
+/** Write data
  *
  * This function fails if it cannot write exactly @a len bytes to the file.
  *
- * @param file		File descriptor
- * @param pos		Pointer to position to write to
- * @param buf		Data, @a nbytes bytes long
- * @param nbytes	Number of bytes to write
- *
- * @return		On success, non-negative number of bytes written.
- *			On failure, a negative error code.
+ * @param file          File handle to write to
+ * @param[inout] pos    Position to write to, updated by the actual bytes
+ *                      written
+ * @param buf           Data, @a nbytes bytes long
+ * @param nbytes        Number of bytes to write
+ *
+ * @return		On success, non-negative number of bytes written
+ * @return              On failure, a negative error code
  */
 ssize_t vfs_write(int file, aoff64_t *pos, const void *buf, size_t nbyte)
@@ -540,33 +689,32 @@
 }
 
-/** Synchronize file.
- *
- * @param fildes File descriptor
- * @return EOK on success or a negative error code otherwise.
+/** Synchronize file
+ *
+ * @param file  File handle to synchronize
+ *
+ * @return      EOK on success or a negative error code
  */
 int vfs_sync(int file)
 {
 	async_exch_t *exch = vfs_exchange_begin();
-	sysarg_t rc = async_req_1_0(exch, VFS_IN_SYNC, file);
-	vfs_exchange_end(exch);
-	
-	return rc;
-}
-
-/** Truncate file to a specified length.
- *
- * Truncate file so that its size is exactly @a length
- *
- * @param fildes File descriptor
- * @param length Length
- *
- * @return EOK on success or a negative erroc code otherwise.
+	int rc = async_req_1_0(exch, VFS_IN_SYNC, file);
+	vfs_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Resize file to a specified length
+ *
+ * Resize file so that its size is exactly @a length.
+ *
+ * @param file          File handle to resize
+ * @param length        New length
+ *
+ * @return              EOK on success or a negative error code
  */
 int vfs_resize(int file, aoff64_t length)
 {
-	sysarg_t rc;
-	
-	async_exch_t *exch = vfs_exchange_begin();
-	rc = async_req_3_0(exch, VFS_IN_RESIZE, file, LOWER32(length),
+	async_exch_t *exch = vfs_exchange_begin();
+	int rc = async_req_3_0(exch, VFS_IN_RESIZE, file, LOWER32(length),
 	    UPPER32(length));
 	vfs_exchange_end(exch);
@@ -575,10 +723,10 @@
 }
 
-/** Get file status.
- *
- * @param file File descriptor
- * @param stat Place to store file information
- *
- * @return EOK on success or a negative error code otherwise.
+/** Get file information
+ *
+ * @param file          File handle to get information about
+ * @param[out] stat     Place to store file information
+ *
+ * @return              EOK on success or a negative error code
  */
 int vfs_stat(int file, struct stat *stat)
@@ -609,10 +757,10 @@
 }
 
-/** Get file status.
- *
- * @param path Path to file
- * @param stat Place to store file information
- *
- * @return EOK on success or a negative error code otherwise.
+/** Get file information 
+ *
+ * @param path          File path to get information about
+ * @param[out] stat     Place to store file information
+ *
+ * @return              EOK on success or a negative error code
  */
 int vfs_stat_path(const char *path, struct stat *stat)
@@ -660,4 +808,17 @@
 }
 
+/** Link a file or directory
+ *
+ * Create a new name and an empty file or an empty directory in a parent
+ * directory. If child with the same name already exists, the function returns
+ * a failure, the existing file remains untouched and no file system object
+ * is created.
+ *
+ * @param parent        File handle of the parent directory node
+ * @param child         New name to be linked
+ * @param kind          Kind of the object to be created: KIND_FILE or
+ *                      KIND_DIRECTORY
+ * @return              EOK on success or a negative error code
+ */
 int vfs_link(int parent, const char *child, vfs_file_kind_t kind)
 {
@@ -673,9 +834,15 @@
 }
 
-/** Link a file or directory.
- *
- * @param path Path
- * @param kind Kind of the file to be created.
- * @return EOK on success or a negative error code otherwise
+/** Link a file or directory
+ *
+ * Create a new name and an empty file or an empty directory at given path.
+ * If a link with the same name already exists, the function returns
+ * a failure, the existing file remains untouched and no file system object
+ * is created.
+ *
+ * @param path          New path to be linked
+ * @param kind          Kind of the object to be created: KIND_FILE or
+ *                      KIND_DIRECTORY
+ * @return              EOK on success or a negative error code
  */
 int vfs_link_path(const char *path, vfs_file_kind_t kind)
@@ -693,4 +860,17 @@
 }	
 
+/** Unlink a file or directory
+ *
+ * Unlink a name from a parent directory. The caller can supply the file handle
+ * of the unlinked child in order to detect a possible race with vfs_link() and
+ * avoid unlinking a wrong file. If the last link for a file or directory is
+ * removed, the FS implementation will deallocate its resources.
+ *
+ * @param parent        File handle of the parent directory node
+ * @param child         Old name to be unlinked
+ * @param expect        File handle of the unlinked child
+ *
+ * @return              EOK on success or a negative error code
+ */
 int vfs_unlink(int parent, const char *child, int expect)
 {
@@ -713,8 +893,12 @@
 }
 
-/** Unlink a file or directory.
- *
- * @param path Path
- * @return EOK on success or a negative error code otherwise
+/** Unlink a file or directory
+ *
+ * Unlink a path. If the last link for a file or directory is removed, the FS
+ * implementation will deallocate its resources.
+ *
+ * @param path          Old path to be unlinked
+ *
+ * @return              EOK on success or a negative error code
  */
 int vfs_unlink_path(const char *path)
@@ -739,10 +923,15 @@
 }
 
-/** Rename directory entry.
- *
- * @param old Old name
- * @param new New name
- *
- * @return EOK on success or a negative error code otherwise.
+/** Rename a file or directory
+ *
+ * There is no file-handle-based variant to disallow attempts to introduce loops
+ * and breakage in the directory tree when relinking eg. a node under its own
+ * descendant.  The path-based variant is not susceptible because the VFS can
+ * prevent this lexically by comparing the paths.
+ *
+ * @param old   Old path
+ * @param new   New path
+ *
+ * @return      EOK on success or a negative error code
  */
 int vfs_rename_path(const char *old, const char *new)
@@ -804,8 +993,9 @@
 }
 
-/** Change working directory.
- *
- * @param path Path
- * @return EOK on success or a negative error code otherwise.
+/** Change working directory
+ *
+ * @param path  Path of the new working directory
+ *
+ * @return      EOK on success or a negative error code
  */
 int vfs_cwd_set(const char *path)
@@ -838,9 +1028,10 @@
 }
 
-/** Get current working directory path.
- *
- * @param buf Buffer
- * @param size Size of @a buf
- * @return EOK on success and a non-negative error code otherwise.
+/** Get current working directory path
+ *
+ * @param[out] buf      Buffer
+ * @param size          Size of @a buf
+ *
+ * @return              EOK on success or a non-negative error code
  */
 int vfs_cwd_get(char *buf, size_t size)
@@ -859,12 +1050,14 @@
 }
 
-/** Open session to service represented by a special file.
- *
- * Given that the file referred to by @a fildes represents a service,
+/** Open session to service represented by a special file
+ *
+ * Given that the file referred to by @a file represents a service,
  * open a session to that service.
  *
- * @param fildes File descriptor
+ * @param file  File handle representing a service
  * @param iface Interface to connect to (XXX Should be automatic)
- * @return On success returns session pointer. On error returns @c NULL.
+ *
+ * @return      Session pointer on success.
+ * @return      @c NULL or error.
  */
 async_sess_t *vfs_fd_session(int file, iface_t iface)
@@ -881,9 +1074,10 @@
 }
 
-/** Get filesystem statistics.
- *
- * @param file File located on the queried file system
- * @param st Buffer for storing information
- * @return EOK on success or a negative error code otherwise.
+/** Get filesystem statistics
+ *
+ * @param file          File located on the queried file system
+ * @param[out] st       Buffer for storing information
+ *
+ * @return              EOK on success or a negative error code
  */
 int vfs_statfs(int file, struct statfs *st)
@@ -904,9 +1098,11 @@
 	return rc;
 }
-/** Get filesystem statistics.
- *
- * @param path Mount point path
- * @param st Buffer for storing information
- * @return EOK on success or a negative error code otherwise.
+
+/** Get filesystem statistics
+ *
+ * @param file          Path pointing to the queried file system
+ * @param[out] st       Buffer for storing information
+ *
+ * @return              EOK on success or a negative error code
  */
 int vfs_statfs_path(const char *path, struct statfs *st)
@@ -923,4 +1119,12 @@
 }
 
+/** Pass a file handle to another VFS client
+ *
+ * @param vfs_exch      Donor's VFS exchange
+ * @param file          Donor's file handle to pass
+ * @param exch          Exchange to the acceptor
+ *
+ * @return              EOK on success or a negative error code
+ */
 int vfs_pass_handle(async_exch_t *vfs_exch, int file, async_exch_t *exch)
 {
@@ -929,5 +1133,12 @@
 }
 
-int vfs_receive_handle(bool high_descriptor)
+/** Receive a file handle from another VFS client
+ *
+ * @param high   If true, the received file handle will be allocated from high
+ *               indices
+ *
+ * @return       EOK on success or a negative error code
+ */
+int vfs_receive_handle(bool high)
 {
 	ipc_callid_t callid;
@@ -942,6 +1153,5 @@
 
 	sysarg_t ret;
-	sysarg_t rc = async_req_1_1(vfs_exch, VFS_IN_WAIT_HANDLE,
-	    high_descriptor, &ret);
+	sysarg_t rc = async_req_1_1(vfs_exch, VFS_IN_WAIT_HANDLE, high, &ret);
 
 	async_exchange_end(vfs_exch);
@@ -952,9 +1162,22 @@
 }
 
-int vfs_clone(int file_from, int file_to, bool high_descriptor)
+/** Clone a file handle
+ *
+ * The caller can choose whether to clone an existing file handle into another
+ * already existing file handle (in which case it is first closed) or to a new
+ * file handle allocated either from low or high indices.
+ *
+ * @param file_from     Source file handle
+ * @param file_to       Destination file handle or -1
+ * @param high          If file_to is -1, high controls whether the new file
+ *                      handle will be allocated from high indices
+ *
+ * @return              New file handle on success or a negative error code
+ */
+int vfs_clone(int file_from, int file_to, bool high)
 {
 	async_exch_t *vfs_exch = vfs_exchange_begin();
 	int rc = async_req_3_0(vfs_exch, VFS_IN_CLONE, (sysarg_t) file_from,
-	    (sysarg_t) file_to, (sysarg_t) high_descriptor);
+	    (sysarg_t) file_to, (sysarg_t) high);
 	vfs_exchange_end(vfs_exch);
 	return rc;
