Index: uspace/lib/libfs/libfs.c
===================================================================
--- uspace/lib/libfs/libfs.c	(revision d27ed127903ea6d811485f75c5dc394ec19f814e)
+++ uspace/lib/libfs/libfs.c	(revision 2e3730821d5835626bc82dc1e3f9652b540ed7f6)
@@ -46,4 +46,19 @@
 #include <sys/stat.h>
 
+#define on_error(rc, action) \
+	do { \
+		if ((rc) != EOK) \
+			action; \
+	} while (0)
+
+#define combine_rc(rc1, rc2) \
+	((rc1) == EOK ? (rc2) : (rc1))
+
+#define answer_and_return(rid, rc) \
+	do { \
+		ipc_answer_0((rid), (rc)); \
+		return; \
+	} while (0)
+
 /** Register file system server.
  *
@@ -162,9 +177,10 @@
 	}
 
-	fs_node_t *fn = ops->node_get(mp_dev_handle, mp_fs_index);
-	if (!fn) {
+	fs_node_t *fn;
+	res = ops->node_get(&fn, mp_dev_handle, mp_fs_index);
+	if (res != EOK || !fn) {
 		ipc_hangup(mountee_phone);
-		ipc_answer_0(callid, ENOENT);
-		ipc_answer_0(rid, ENOENT);
+		ipc_answer_0(callid, combine_rc(res, ENOENT));
+		ipc_answer_0(rid, combine_rc(res, ENOENT));
 		return;
 	}
@@ -172,5 +188,5 @@
 	if (fn->mp_data.mp_active) {
 		ipc_hangup(mountee_phone);
-		ops->node_put(fn);
+		(void) ops->node_put(fn);
 		ipc_answer_0(callid, EBUSY);
 		ipc_answer_0(rid, EBUSY);
@@ -179,7 +195,7 @@
 
 	rc = async_req_0_0(mountee_phone, IPC_M_CONNECT_ME);
-	if (rc != 0) {
+	if (rc != EOK) {
 		ipc_hangup(mountee_phone);
-		ops->node_put(fn);
+		(void) ops->node_put(fn);
 		ipc_answer_0(callid, rc);
 		ipc_answer_0(rid, rc);
@@ -230,4 +246,5 @@
 	char component[NAME_MAX + 1];
 	int len;
+	int rc;
 
 	if (last < next)
@@ -235,6 +252,9 @@
 
 	fs_node_t *par = NULL;
-	fs_node_t *cur = ops->root_get(dev_handle);
+	fs_node_t *cur = NULL;
 	fs_node_t *tmp = NULL;
+
+	rc = ops->root_get(&cur, dev_handle);
+	on_error(rc, goto out_with_answer);
 
 	if (cur->mp_data.mp_active) {
@@ -242,5 +262,5 @@
 		    next, last, cur->mp_data.dev_handle, lflag, index,
 		    IPC_FF_ROUTE_FROM_ME);
-		ops->node_put(cur);
+		(void) ops->node_put(cur);
 		return;
 	}
@@ -249,5 +269,12 @@
 		next++;		/* eat slash */
 	
-	while (next <= last && ops->has_children(cur)) {
+	while (next <= last) {
+		bool has_children;
+
+		rc = ops->has_children(&has_children, cur);
+		on_error(rc, goto out_with_answer);
+		if (!has_children)
+			break;
+
 		/* collect the component */
 		len = 0;
@@ -267,5 +294,7 @@
 
 		/* match the component */
-		tmp = ops->match(cur, component);
+		rc = ops->match(&tmp, cur, component);
+		on_error(rc, goto out_with_answer);
+
 		if (tmp && tmp->mp_data.mp_active) {
 			if (next > last)
@@ -277,8 +306,8 @@
 			    VFS_OUT_LOOKUP, next, last, tmp->mp_data.dev_handle,
 			    lflag, index, IPC_FF_ROUTE_FROM_ME);
-			ops->node_put(cur);
-			ops->node_put(tmp);
+			(void) ops->node_put(cur);
+			(void) ops->node_put(tmp);
 			if (par)
-				ops->node_put(par);
+				(void) ops->node_put(par);
 			return;
 		}
@@ -300,16 +329,15 @@
 				fs_node_t *fn;
 				if (lflag & L_CREATE)
-					fn = ops->create(dev_handle, lflag);
+					rc = ops->create(&fn, dev_handle,
+					    lflag);
 				else
-					fn = ops->node_get(dev_handle,
+					rc = ops->node_get(&fn, dev_handle,
 					    index);
+				on_error(rc, goto out_with_answer);
 				if (fn) {
-					int rc;
-
 					rc = ops->link(cur, fn, component);
 					if (rc != EOK) {
-						if (lflag & L_CREATE) {
-							(void)ops->destroy(fn);
-						}
+						if (lflag & L_CREATE)
+							(void) ops->destroy(fn);
 						ipc_answer_0(rid, rc);
 					} else {
@@ -319,5 +347,5 @@
 						    ops->size_get(fn),
 						    ops->lnkcnt_get(fn));
-						ops->node_put(fn);
+						(void) ops->node_put(fn);
 					}
 				} else {
@@ -330,6 +358,8 @@
 		}
 
-		if (par)
-			ops->node_put(par);
+		if (par) {
+			rc = ops->node_put(par);
+			on_error(rc, goto out_with_answer);
+		}
 
 		/* descend one level */
@@ -340,5 +370,12 @@
 
 	/* handle miss: excessive components */
-	if (next <= last && !ops->has_children(cur)) {
+	if (next <= last) {
+		bool has_children;
+
+		rc = ops->has_children(&has_children, cur);
+		on_error(rc, goto out_with_answer);
+		if (has_children)
+			goto skip_miss;
+
 		if (lflag & (L_CREATE | L_LINK)) {
 			if (!ops->is_directory(cur)) {
@@ -368,14 +405,13 @@
 			fs_node_t *fn;
 			if (lflag & L_CREATE)
-				fn = ops->create(dev_handle, lflag);
+				rc = ops->create(&fn, dev_handle, lflag);
 			else
-				fn = ops->node_get(dev_handle, index);
+				rc = ops->node_get(&fn, dev_handle, index);
+			on_error(rc, goto out_with_answer);
 			if (fn) {
-				int rc;
-
 				rc = ops->link(cur, fn, component);
 				if (rc != EOK) {
 					if (lflag & L_CREATE)
-						(void)ops->destroy(fn);
+						(void) ops->destroy(fn);
 					ipc_answer_0(rid, rc);
 				} else {
@@ -385,5 +421,5 @@
 					    ops->size_get(fn),
 					    ops->lnkcnt_get(fn));
-					ops->node_put(fn);
+					(void) ops->node_put(fn);
 				}
 			} else {
@@ -395,10 +431,11 @@
 		goto out;
 	}
+skip_miss:
 
 	/* handle hit */
 	if (lflag & L_UNLINK) {
 		unsigned old_lnkcnt = ops->lnkcnt_get(cur);
-		int res = ops->unlink(par, cur, component);
-		ipc_answer_5(rid, (ipcarg_t)res, fs_handle, dev_handle,
+		rc = ops->unlink(par, cur, component);
+		ipc_answer_5(rid, (ipcarg_t)rc, fs_handle, dev_handle,
 		    ops->index_get(cur), ops->size_get(cur), old_lnkcnt);
 		goto out;
@@ -418,14 +455,20 @@
 	}
 
-	ipc_answer_5(rid, EOK, fs_handle, dev_handle, ops->index_get(cur),
-	    ops->size_get(cur), ops->lnkcnt_get(cur));
+out_with_answer:
+	if (rc == EOK) {
+		ipc_answer_5(rid, EOK, fs_handle, dev_handle,
+		    ops->index_get(cur), ops->size_get(cur),
+		    ops->lnkcnt_get(cur));
+	} else {
+		ipc_answer_0(rid, rc);
+	}
 
 out:
 	if (par)
-		ops->node_put(par);
+		(void) ops->node_put(par);
 	if (cur)
-		ops->node_put(cur);
+		(void) ops->node_put(cur);
 	if (tmp)
-		ops->node_put(tmp);
+		(void) ops->node_put(tmp);
 }
 
@@ -435,5 +478,9 @@
 	dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
 	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
-	fs_node_t *fn = ops->node_get(dev_handle, index);
+	fs_node_t *fn;
+	int rc;
+
+	rc = ops->node_get(&fn, dev_handle, index);
+	on_error(rc, answer_and_return(rid, rc));
 
 	ipc_callid_t callid;
@@ -473,16 +520,19 @@
 	dev_handle_t dev_handle = IPC_GET_ARG1(*request);
 	fs_index_t index = IPC_GET_ARG2(*request);
-	
-	fs_node_t *node = ops->node_get(dev_handle, index);
-	
-	if (node == NULL) {
+	fs_node_t *fn;
+	int rc;
+	
+	rc = ops->node_get(&fn, dev_handle, index);
+	on_error(rc, answer_and_return(rid, rc));
+	
+	if (fn == NULL) {
 		ipc_answer_0(rid, ENOENT);
 		return;
 	}
 	
-	ipc_answer_5(rid, EOK, fs_handle, dev_handle, index,
-	    ops->size_get(node), ops->lnkcnt_get(node));
-	
-	ops->node_put(node);
+	ipc_answer_5(rid, EOK, fs_handle, dev_handle, index, ops->size_get(fn),
+	    ops->lnkcnt_get(fn));
+	
+	(void) ops->node_put(fn);
 }
 
Index: uspace/lib/libfs/libfs.h
===================================================================
--- uspace/lib/libfs/libfs.h	(revision d27ed127903ea6d811485f75c5dc394ec19f814e)
+++ uspace/lib/libfs/libfs.h	(revision 2e3730821d5835626bc82dc1e3f9652b540ed7f6)
@@ -56,16 +56,25 @@
 
 typedef struct {
-	fs_node_t * (* match)(fs_node_t *, const char *);
-	fs_node_t * (* node_get)(dev_handle_t, fs_index_t);
-	void (* node_put)(fs_node_t *);
-	fs_node_t * (* create)(dev_handle_t, int);
+	/*
+	 * The first set of methods are functions that return an integer error
+	 * code. If some additional return value is to be returned, the first
+	 * argument holds the output argument.
+	 */
+	int (* root_get)(fs_node_t **, dev_handle_t);
+	int (* match)(fs_node_t **, fs_node_t *, const char *);
+	int (* node_get)(fs_node_t **, dev_handle_t, fs_index_t);
+	int (* node_put)(fs_node_t *);
+	int (* create)(fs_node_t **, dev_handle_t, int);
 	int (* destroy)(fs_node_t *);
 	int (* link)(fs_node_t *, fs_node_t *, const char *);
 	int (* unlink)(fs_node_t *, fs_node_t *, const char *);
+	int (* has_children)(bool *, fs_node_t *);
+	/*
+	 * The second set of methods are usually mere getters that do not return
+	 * an integer error code.
+	 */
 	fs_index_t (* index_get)(fs_node_t *);
 	size_t (* size_get)(fs_node_t *);
 	unsigned (* lnkcnt_get)(fs_node_t *);
-	bool (* has_children)(fs_node_t *);
-	fs_node_t *(* root_get)(dev_handle_t);
 	char (* plb_get_char)(unsigned pos);
 	bool (* is_directory)(fs_node_t *);
Index: uspace/srv/fs/fat/fat_ops.c
===================================================================
--- uspace/srv/fs/fat/fat_ops.c	(revision d27ed127903ea6d811485f75c5dc394ec19f814e)
+++ uspace/srv/fs/fat/fat_ops.c	(revision 2e3730821d5835626bc82dc1e3f9652b540ed7f6)
@@ -250,16 +250,16 @@
  * Forward declarations of FAT libfs operations.
  */
-static fs_node_t *fat_node_get(dev_handle_t, fs_index_t);
-static void fat_node_put(fs_node_t *);
-static fs_node_t *fat_create_node(dev_handle_t, int);
+static int fat_root_get(fs_node_t **, dev_handle_t);
+static int fat_match(fs_node_t **, fs_node_t *, const char *);
+static int fat_node_get(fs_node_t **, dev_handle_t, fs_index_t);
+static int fat_node_put(fs_node_t *);
+static int fat_create_node(fs_node_t **, dev_handle_t, int);
 static int fat_destroy_node(fs_node_t *);
 static int fat_link(fs_node_t *, fs_node_t *, const char *);
 static int fat_unlink(fs_node_t *, fs_node_t *, const char *);
-static fs_node_t *fat_match(fs_node_t *, const char *);
+static int fat_has_children(bool *, fs_node_t *);
 static fs_index_t fat_index_get(fs_node_t *);
 static size_t fat_size_get(fs_node_t *);
 static unsigned fat_lnkcnt_get(fs_node_t *);
-static bool fat_has_children(fs_node_t *);
-static fs_node_t *fat_root_get(dev_handle_t);
 static char fat_plb_get_char(unsigned);
 static bool fat_is_directory(fs_node_t *);
@@ -270,372 +270,10 @@
  */
 
-/** Instantiate a FAT in-core node. */
-fs_node_t *fat_node_get(dev_handle_t dev_handle, fs_index_t index)
-{
-	fat_node_t *nodep;
-	fat_idx_t *idxp;
-
-	idxp = fat_idx_get_by_index(dev_handle, index);
-	if (!idxp)
-		return NULL;
-	/* idxp->lock held */
-	nodep = fat_node_get_core(idxp);
-	fibril_mutex_unlock(&idxp->lock);
-	return FS_NODE(nodep);
-}
-
-void fat_node_put(fs_node_t *fn)
-{
-	fat_node_t *nodep = FAT_NODE(fn);
-	bool destroy = false;
-
-	fibril_mutex_lock(&nodep->lock);
-	if (!--nodep->refcnt) {
-		if (nodep->idx) {
-			fibril_mutex_lock(&ffn_mutex);
-			list_append(&nodep->ffn_link, &ffn_head);
-			fibril_mutex_unlock(&ffn_mutex);
-		} else {
-			/*
-			 * The node does not have any index structure associated
-			 * with itself. This can only mean that we are releasing
-			 * the node after a failed attempt to allocate the index
-			 * structure for it.
-			 */
-			destroy = true;
-		}
-	}
-	fibril_mutex_unlock(&nodep->lock);
-	if (destroy) {
-		free(nodep->bp);
-		free(nodep);
-	}
-}
-
-fs_node_t *fat_create_node(dev_handle_t dev_handle, int flags)
-{
-	fat_idx_t *idxp;
-	fat_node_t *nodep;
-	fat_bs_t *bs;
-	fat_cluster_t mcl, lcl;
-	uint16_t bps;
-	int rc;
-
-	bs = block_bb_get(dev_handle);
-	bps = uint16_t_le2host(bs->bps);
-	if (flags & L_DIRECTORY) {
-		/* allocate a cluster */
-		rc = fat_alloc_clusters(bs, dev_handle, 1, &mcl, &lcl);
-		if (rc != EOK) 
-			return NULL;
-	}
-
-	nodep = fat_node_get_new();
-	if (!nodep) {
-		(void) fat_free_clusters(bs, dev_handle, mcl);
-		return NULL;
-	}
-	idxp = fat_idx_get_new(dev_handle);
-	if (!idxp) {
-		(void) fat_free_clusters(bs, dev_handle, mcl);	
-		fat_node_put(FS_NODE(nodep));
-		return NULL;
-	}
-	/* idxp->lock held */
-	if (flags & L_DIRECTORY) {
-		/* Populate the new cluster with unused dentries. */
-		rc = fat_zero_cluster(bs, dev_handle, mcl);
-		assert(rc == EOK);
-		nodep->type = FAT_DIRECTORY;
-		nodep->firstc = mcl;
-		nodep->size = bps * bs->spc;
-	} else {
-		nodep->type = FAT_FILE;
-		nodep->firstc = FAT_CLST_RES0;
-		nodep->size = 0;
-	}
-	nodep->lnkcnt = 0;	/* not linked anywhere */
-	nodep->refcnt = 1;
-	nodep->dirty = true;
-
-	nodep->idx = idxp;
-	idxp->nodep = nodep;
-
-	fibril_mutex_unlock(&idxp->lock);
-	return FS_NODE(nodep);
-}
-
-int fat_destroy_node(fs_node_t *fn)
-{
-	fat_node_t *nodep = FAT_NODE(fn);
-	fat_bs_t *bs;
-	int rc = EOK;
-
-	/*
-	 * The node is not reachable from the file system. This means that the
-	 * link count should be zero and that the index structure cannot be
-	 * found in the position hash. Obviously, we don't need to lock the node
-	 * nor its index structure.
-	 */
-	assert(nodep->lnkcnt == 0);
-
-	/*
-	 * The node may not have any children.
-	 */
-	assert(fat_has_children(fn) == false);
-
-	bs = block_bb_get(nodep->idx->dev_handle);
-	if (nodep->firstc != FAT_CLST_RES0) {
-		assert(nodep->size);
-		/* Free all clusters allocated to the node. */
-		rc = fat_free_clusters(bs, nodep->idx->dev_handle,
-		    nodep->firstc);
-	}
-
-	fat_idx_destroy(nodep->idx);
-	free(nodep->bp);
-	free(nodep);
-	return rc;
-}
-
-int fat_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
-{
-	fat_node_t *parentp = FAT_NODE(pfn);
-	fat_node_t *childp = FAT_NODE(cfn);
-	fat_dentry_t *d;
-	fat_bs_t *bs;
-	block_t *b;
-	unsigned i, j;
-	uint16_t bps;
-	unsigned dps;
-	unsigned blocks;
-	fat_cluster_t mcl, lcl;
-	int rc;
-
-	fibril_mutex_lock(&childp->lock);
-	if (childp->lnkcnt == 1) {
-		/*
-		 * On FAT, we don't support multiple hard links.
-		 */
-		fibril_mutex_unlock(&childp->lock);
-		return EMLINK;
-	}
-	assert(childp->lnkcnt == 0);
-	fibril_mutex_unlock(&childp->lock);
-
-	if (!fat_dentry_name_verify(name)) {
-		/*
-		 * Attempt to create unsupported name.
-		 */
-		return ENOTSUP;
-	}
-
-	/*
-	 * Get us an unused parent node's dentry or grow the parent and allocate
-	 * a new one.
-	 */
-	
-	fibril_mutex_lock(&parentp->idx->lock);
-	bs = block_bb_get(parentp->idx->dev_handle);
-	bps = uint16_t_le2host(bs->bps);
-	dps = bps / sizeof(fat_dentry_t);
-
-	blocks = parentp->size / bps;
-
-	for (i = 0; i < blocks; i++) {
-		rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
-		if (rc != EOK) {
-			fibril_mutex_unlock(&parentp->idx->lock);
-			return rc;
-		}
-		for (j = 0; j < dps; j++) {
-			d = ((fat_dentry_t *)b->data) + j;
-			switch (fat_classify_dentry(d)) {
-			case FAT_DENTRY_SKIP:
-			case FAT_DENTRY_VALID:
-				/* skipping used and meta entries */
-				continue;
-			case FAT_DENTRY_FREE:
-			case FAT_DENTRY_LAST:
-				/* found an empty slot */
-				goto hit;
-			}
-		}
-		rc = block_put(b);
-		if (rc != EOK) {
-			fibril_mutex_unlock(&parentp->idx->lock);
-			return rc;
-		}
-	}
-	j = 0;
-	
-	/*
-	 * We need to grow the parent in order to create a new unused dentry.
-	 */
-	if (parentp->firstc == FAT_CLST_ROOT) {
-		/* Can't grow the root directory. */
-		fibril_mutex_unlock(&parentp->idx->lock);
-		return ENOSPC;
-	}
-	rc = fat_alloc_clusters(bs, parentp->idx->dev_handle, 1, &mcl, &lcl);
-	if (rc != EOK) {
-		fibril_mutex_unlock(&parentp->idx->lock);
-		return rc;
-	}
-	rc = fat_zero_cluster(bs, parentp->idx->dev_handle, mcl);
-	if (rc != EOK) {
-		fibril_mutex_unlock(&parentp->idx->lock);
-		return rc;
-	}
-	rc = fat_append_clusters(bs, parentp, mcl);
-	if (rc != EOK) {
-		fibril_mutex_unlock(&parentp->idx->lock);
-		return rc;
-	}
-	parentp->size += bps * bs->spc;
-	parentp->dirty = true;		/* need to sync node */
-	rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
-	if (rc != EOK) {
-		fibril_mutex_unlock(&parentp->idx->lock);
-		return rc;
-	}
-	d = (fat_dentry_t *)b->data;
-
-hit:
-	/*
-	 * At this point we only establish the link between the parent and the
-	 * child.  The dentry, except of the name and the extension, will remain
-	 * uninitialized until the corresponding node is synced. Thus the valid
-	 * dentry data is kept in the child node structure.
-	 */
-	memset(d, 0, sizeof(fat_dentry_t));
-	fat_dentry_name_set(d, name);
-	b->dirty = true;		/* need to sync block */
-	rc = block_put(b);
-	fibril_mutex_unlock(&parentp->idx->lock);
-	if (rc != EOK) 
-		return rc;
-
-	fibril_mutex_lock(&childp->idx->lock);
-	
-	/*
-	 * If possible, create the Sub-directory Identifier Entry and the
-	 * Sub-directory Parent Pointer Entry (i.e. "." and ".."). These entries
-	 * are not mandatory according to Standard ECMA-107 and HelenOS VFS does
-	 * not use them anyway, so this is rather a sign of our good will.
-	 */
-	rc = fat_block_get(&b, bs, childp, 0, BLOCK_FLAGS_NONE);
-	if (rc != EOK) {
-		/*
-		 * Rather than returning an error, simply skip the creation of
-		 * these two entries.
-		 */
-		goto skip_dots;
-	}
-	d = (fat_dentry_t *)b->data;
-	if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
-	    str_cmp(d->name, FAT_NAME_DOT) == 0) {
-	   	memset(d, 0, sizeof(fat_dentry_t));
-	   	str_cpy(d->name, 8, FAT_NAME_DOT);
-		str_cpy(d->ext, 3, FAT_EXT_PAD);
-		d->attr = FAT_ATTR_SUBDIR;
-		d->firstc = host2uint16_t_le(childp->firstc);
-		/* TODO: initialize also the date/time members. */
-	}
-	d++;
-	if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
-	    str_cmp(d->name, FAT_NAME_DOT_DOT) == 0) {
-		memset(d, 0, sizeof(fat_dentry_t));
-		str_cpy(d->name, 8, FAT_NAME_DOT_DOT);
-		str_cpy(d->ext, 3, FAT_EXT_PAD);
-		d->attr = FAT_ATTR_SUBDIR;
-		d->firstc = (parentp->firstc == FAT_CLST_ROOT) ?
-		    host2uint16_t_le(FAT_CLST_RES0) :
-		    host2uint16_t_le(parentp->firstc);
-		/* TODO: initialize also the date/time members. */
-	}
-	b->dirty = true;		/* need to sync block */
-	/*
-	 * Ignore the return value as we would have fallen through on error
-	 * anyway.
-	 */
-	(void) block_put(b);
-skip_dots:
-
-	childp->idx->pfc = parentp->firstc;
-	childp->idx->pdi = i * dps + j;
-	fibril_mutex_unlock(&childp->idx->lock);
-
-	fibril_mutex_lock(&childp->lock);
-	childp->lnkcnt = 1;
-	childp->dirty = true;		/* need to sync node */
-	fibril_mutex_unlock(&childp->lock);
-
-	/*
-	 * Hash in the index structure into the position hash.
-	 */
-	fat_idx_hashin(childp->idx);
-
-	return EOK;
-}
-
-int fat_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
-{
-	fat_node_t *parentp = FAT_NODE(pfn);
-	fat_node_t *childp = FAT_NODE(cfn);
-	fat_bs_t *bs;
-	fat_dentry_t *d;
-	uint16_t bps;
-	block_t *b;
-	int rc;
-
-	if (!parentp)
-		return EBUSY;
-	
-	if (fat_has_children(cfn))
-		return ENOTEMPTY;
-
-	fibril_mutex_lock(&parentp->lock);
-	fibril_mutex_lock(&childp->lock);
-	assert(childp->lnkcnt == 1);
-	fibril_mutex_lock(&childp->idx->lock);
-	bs = block_bb_get(childp->idx->dev_handle);
-	bps = uint16_t_le2host(bs->bps);
-
-	rc = _fat_block_get(&b, bs, childp->idx->dev_handle, childp->idx->pfc,
-	    (childp->idx->pdi * sizeof(fat_dentry_t)) / bps,
-	    BLOCK_FLAGS_NONE);
-	if (rc != EOK) 
-		goto error;
-	d = (fat_dentry_t *)b->data +
-	    (childp->idx->pdi % (bps / sizeof(fat_dentry_t)));
-	/* mark the dentry as not-currently-used */
-	d->name[0] = FAT_DENTRY_ERASED;
-	b->dirty = true;		/* need to sync block */
-	rc = block_put(b);
-	if (rc != EOK)
-		goto error;
-
-	/* remove the index structure from the position hash */
-	fat_idx_hashout(childp->idx);
-	/* clear position information */
-	childp->idx->pfc = FAT_CLST_RES0;
-	childp->idx->pdi = 0;
-	fibril_mutex_unlock(&childp->idx->lock);
-	childp->lnkcnt = 0;
-	childp->dirty = true;
-	fibril_mutex_unlock(&childp->lock);
-	fibril_mutex_unlock(&parentp->lock);
-
-	return EOK;
-
-error:
-	fibril_mutex_unlock(&parentp->idx->lock);
-	fibril_mutex_unlock(&childp->lock);
-	fibril_mutex_unlock(&childp->idx->lock);
-	return rc;
-}
-
-fs_node_t *fat_match(fs_node_t *pfn, const char *component)
+int fat_root_get(fs_node_t **rfn, dev_handle_t dev_handle)
+{
+	return fat_node_get(rfn, dev_handle, 0);
+}
+
+int fat_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
 {
 	fat_bs_t *bs;
@@ -657,5 +295,8 @@
 	for (i = 0; i < blocks; i++) {
 		rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
-		assert(rc == EOK);
+		if (rc != EOK) {
+			fibril_mutex_unlock(&parentp->idx->lock);
+			return rc;
+		}
 		for (j = 0; j < dps; j++) { 
 			d = ((fat_dentry_t *)b->data) + j;
@@ -666,7 +307,9 @@
 			case FAT_DENTRY_LAST:
 				rc = block_put(b);
-				assert(rc == EOK);
+				/* expect EOK as b was not dirty */
+				assert(rc == EOK);	
 				fibril_mutex_unlock(&parentp->idx->lock);
-				return NULL;
+				*rfn = NULL;
+				return EOK;
 			default:
 			case FAT_DENTRY_VALID:
@@ -693,38 +336,412 @@
 					 */
 					rc = block_put(b);
-					assert(rc == EOK);
-					return NULL;
+					/* expect EOK as b was not dirty */
+					assert(rc == EOK);	
+					return ENOMEM;
 				}
 				nodep = fat_node_get_core(idx);
 				fibril_mutex_unlock(&idx->lock);
 				rc = block_put(b);
+				/* expect EOK as b was not dirty */
 				assert(rc == EOK);
-				return FS_NODE(nodep);
+				*rfn = FS_NODE(nodep);
+				return EOK;
 			}
 		}
 		rc = block_put(b);
-		assert(rc == EOK);
+		assert(rc == EOK);	/* expect EOK as b was not dirty */
 	}
 
 	fibril_mutex_unlock(&parentp->idx->lock);
-	return NULL;
-}
-
-fs_index_t fat_index_get(fs_node_t *fn)
-{
-	return FAT_NODE(fn)->idx->index;
-}
-
-size_t fat_size_get(fs_node_t *fn)
-{
-	return FAT_NODE(fn)->size;
-}
-
-unsigned fat_lnkcnt_get(fs_node_t *fn)
-{
-	return FAT_NODE(fn)->lnkcnt;
-}
-
-bool fat_has_children(fs_node_t *fn)
+	*rfn = NULL;
+	return EOK;
+}
+
+/** Instantiate a FAT in-core node. */
+int fat_node_get(fs_node_t **rfn, dev_handle_t dev_handle, fs_index_t index)
+{
+	fat_node_t *nodep;
+	fat_idx_t *idxp;
+
+	idxp = fat_idx_get_by_index(dev_handle, index);
+	if (!idxp) {
+		*rfn = NULL;
+		return EOK;
+	}
+	/* idxp->lock held */
+	nodep = fat_node_get_core(idxp);
+	fibril_mutex_unlock(&idxp->lock);
+	*rfn = FS_NODE(nodep);
+	return EOK;
+}
+
+int fat_node_put(fs_node_t *fn)
+{
+	fat_node_t *nodep = FAT_NODE(fn);
+	bool destroy = false;
+
+	fibril_mutex_lock(&nodep->lock);
+	if (!--nodep->refcnt) {
+		if (nodep->idx) {
+			fibril_mutex_lock(&ffn_mutex);
+			list_append(&nodep->ffn_link, &ffn_head);
+			fibril_mutex_unlock(&ffn_mutex);
+		} else {
+			/*
+			 * The node does not have any index structure associated
+			 * with itself. This can only mean that we are releasing
+			 * the node after a failed attempt to allocate the index
+			 * structure for it.
+			 */
+			destroy = true;
+		}
+	}
+	fibril_mutex_unlock(&nodep->lock);
+	if (destroy) {
+		free(nodep->bp);
+		free(nodep);
+	}
+	return EOK;
+}
+
+int fat_create_node(fs_node_t **rfn, dev_handle_t dev_handle, int flags)
+{
+	fat_idx_t *idxp;
+	fat_node_t *nodep;
+	fat_bs_t *bs;
+	fat_cluster_t mcl, lcl;
+	uint16_t bps;
+	int rc;
+
+	bs = block_bb_get(dev_handle);
+	bps = uint16_t_le2host(bs->bps);
+	if (flags & L_DIRECTORY) {
+		/* allocate a cluster */
+		rc = fat_alloc_clusters(bs, dev_handle, 1, &mcl, &lcl);
+		if (rc != EOK)
+			return rc;
+		/* populate the new cluster with unused dentries */
+		rc = fat_zero_cluster(bs, dev_handle, mcl);
+		if (rc != EOK) {
+			(void) fat_free_clusters(bs, dev_handle, mcl);
+			return rc;
+		}
+	}
+
+	nodep = fat_node_get_new();
+	if (!nodep) {
+		(void) fat_free_clusters(bs, dev_handle, mcl);
+		return ENOMEM;	/* FIXME: determine the true error code */
+	}
+	idxp = fat_idx_get_new(dev_handle);
+	if (!idxp) {
+		(void) fat_free_clusters(bs, dev_handle, mcl);	
+		(void) fat_node_put(FS_NODE(nodep));
+		return ENOMEM;	/* FIXME: determine the true error code */
+	}
+	/* idxp->lock held */
+	if (flags & L_DIRECTORY) {
+		nodep->type = FAT_DIRECTORY;
+		nodep->firstc = mcl;
+		nodep->size = bps * bs->spc;
+	} else {
+		nodep->type = FAT_FILE;
+		nodep->firstc = FAT_CLST_RES0;
+		nodep->size = 0;
+	}
+	nodep->lnkcnt = 0;	/* not linked anywhere */
+	nodep->refcnt = 1;
+	nodep->dirty = true;
+
+	nodep->idx = idxp;
+	idxp->nodep = nodep;
+
+	fibril_mutex_unlock(&idxp->lock);
+	*rfn = FS_NODE(nodep);
+	return EOK;
+}
+
+int fat_destroy_node(fs_node_t *fn)
+{
+	fat_node_t *nodep = FAT_NODE(fn);
+	fat_bs_t *bs;
+	bool has_children;
+	int rc;
+
+	/*
+	 * The node is not reachable from the file system. This means that the
+	 * link count should be zero and that the index structure cannot be
+	 * found in the position hash. Obviously, we don't need to lock the node
+	 * nor its index structure.
+	 */
+	assert(nodep->lnkcnt == 0);
+
+	/*
+	 * The node may not have any children.
+	 */
+	rc = fat_has_children(&has_children, fn);
+	if (rc != EOK)
+		return rc;
+	assert(!has_children);
+
+	bs = block_bb_get(nodep->idx->dev_handle);
+	if (nodep->firstc != FAT_CLST_RES0) {
+		assert(nodep->size);
+		/* Free all clusters allocated to the node. */
+		rc = fat_free_clusters(bs, nodep->idx->dev_handle,
+		    nodep->firstc);
+	}
+
+	fat_idx_destroy(nodep->idx);
+	free(nodep->bp);
+	free(nodep);
+	return rc;
+}
+
+int fat_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
+{
+	fat_node_t *parentp = FAT_NODE(pfn);
+	fat_node_t *childp = FAT_NODE(cfn);
+	fat_dentry_t *d;
+	fat_bs_t *bs;
+	block_t *b;
+	unsigned i, j;
+	uint16_t bps;
+	unsigned dps;
+	unsigned blocks;
+	fat_cluster_t mcl, lcl;
+	int rc;
+
+	fibril_mutex_lock(&childp->lock);
+	if (childp->lnkcnt == 1) {
+		/*
+		 * On FAT, we don't support multiple hard links.
+		 */
+		fibril_mutex_unlock(&childp->lock);
+		return EMLINK;
+	}
+	assert(childp->lnkcnt == 0);
+	fibril_mutex_unlock(&childp->lock);
+
+	if (!fat_dentry_name_verify(name)) {
+		/*
+		 * Attempt to create unsupported name.
+		 */
+		return ENOTSUP;
+	}
+
+	/*
+	 * Get us an unused parent node's dentry or grow the parent and allocate
+	 * a new one.
+	 */
+	
+	fibril_mutex_lock(&parentp->idx->lock);
+	bs = block_bb_get(parentp->idx->dev_handle);
+	bps = uint16_t_le2host(bs->bps);
+	dps = bps / sizeof(fat_dentry_t);
+
+	blocks = parentp->size / bps;
+
+	for (i = 0; i < blocks; i++) {
+		rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
+		if (rc != EOK) {
+			fibril_mutex_unlock(&parentp->idx->lock);
+			return rc;
+		}
+		for (j = 0; j < dps; j++) {
+			d = ((fat_dentry_t *)b->data) + j;
+			switch (fat_classify_dentry(d)) {
+			case FAT_DENTRY_SKIP:
+			case FAT_DENTRY_VALID:
+				/* skipping used and meta entries */
+				continue;
+			case FAT_DENTRY_FREE:
+			case FAT_DENTRY_LAST:
+				/* found an empty slot */
+				goto hit;
+			}
+		}
+		rc = block_put(b);
+		if (rc != EOK) {
+			fibril_mutex_unlock(&parentp->idx->lock);
+			return rc;
+		}
+	}
+	j = 0;
+	
+	/*
+	 * We need to grow the parent in order to create a new unused dentry.
+	 */
+	if (parentp->firstc == FAT_CLST_ROOT) {
+		/* Can't grow the root directory. */
+		fibril_mutex_unlock(&parentp->idx->lock);
+		return ENOSPC;
+	}
+	rc = fat_alloc_clusters(bs, parentp->idx->dev_handle, 1, &mcl, &lcl);
+	if (rc != EOK) {
+		fibril_mutex_unlock(&parentp->idx->lock);
+		return rc;
+	}
+	rc = fat_zero_cluster(bs, parentp->idx->dev_handle, mcl);
+	if (rc != EOK) {
+		(void) fat_free_clusters(bs, parentp->idx->dev_handle, mcl);
+		fibril_mutex_unlock(&parentp->idx->lock);
+		return rc;
+	}
+	rc = fat_append_clusters(bs, parentp, mcl);
+	if (rc != EOK) {
+		(void) fat_free_clusters(bs, parentp->idx->dev_handle, mcl);
+		fibril_mutex_unlock(&parentp->idx->lock);
+		return rc;
+	}
+	parentp->size += bps * bs->spc;
+	parentp->dirty = true;		/* need to sync node */
+	rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
+	if (rc != EOK) {
+		fibril_mutex_unlock(&parentp->idx->lock);
+		return rc;
+	}
+	d = (fat_dentry_t *)b->data;
+
+hit:
+	/*
+	 * At this point we only establish the link between the parent and the
+	 * child.  The dentry, except of the name and the extension, will remain
+	 * uninitialized until the corresponding node is synced. Thus the valid
+	 * dentry data is kept in the child node structure.
+	 */
+	memset(d, 0, sizeof(fat_dentry_t));
+	fat_dentry_name_set(d, name);
+	b->dirty = true;		/* need to sync block */
+	rc = block_put(b);
+	fibril_mutex_unlock(&parentp->idx->lock);
+	if (rc != EOK) 
+		return rc;
+
+	fibril_mutex_lock(&childp->idx->lock);
+	
+	/*
+	 * If possible, create the Sub-directory Identifier Entry and the
+	 * Sub-directory Parent Pointer Entry (i.e. "." and ".."). These entries
+	 * are not mandatory according to Standard ECMA-107 and HelenOS VFS does
+	 * not use them anyway, so this is rather a sign of our good will.
+	 */
+	rc = fat_block_get(&b, bs, childp, 0, BLOCK_FLAGS_NONE);
+	if (rc != EOK) {
+		/*
+		 * Rather than returning an error, simply skip the creation of
+		 * these two entries.
+		 */
+		goto skip_dots;
+	}
+	d = (fat_dentry_t *)b->data;
+	if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
+	    str_cmp(d->name, FAT_NAME_DOT) == 0) {
+	   	memset(d, 0, sizeof(fat_dentry_t));
+	   	str_cpy(d->name, 8, FAT_NAME_DOT);
+		str_cpy(d->ext, 3, FAT_EXT_PAD);
+		d->attr = FAT_ATTR_SUBDIR;
+		d->firstc = host2uint16_t_le(childp->firstc);
+		/* TODO: initialize also the date/time members. */
+	}
+	d++;
+	if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
+	    str_cmp(d->name, FAT_NAME_DOT_DOT) == 0) {
+		memset(d, 0, sizeof(fat_dentry_t));
+		str_cpy(d->name, 8, FAT_NAME_DOT_DOT);
+		str_cpy(d->ext, 3, FAT_EXT_PAD);
+		d->attr = FAT_ATTR_SUBDIR;
+		d->firstc = (parentp->firstc == FAT_CLST_ROOT) ?
+		    host2uint16_t_le(FAT_CLST_RES0) :
+		    host2uint16_t_le(parentp->firstc);
+		/* TODO: initialize also the date/time members. */
+	}
+	b->dirty = true;		/* need to sync block */
+	/*
+	 * Ignore the return value as we would have fallen through on error
+	 * anyway.
+	 */
+	(void) block_put(b);
+skip_dots:
+
+	childp->idx->pfc = parentp->firstc;
+	childp->idx->pdi = i * dps + j;
+	fibril_mutex_unlock(&childp->idx->lock);
+
+	fibril_mutex_lock(&childp->lock);
+	childp->lnkcnt = 1;
+	childp->dirty = true;		/* need to sync node */
+	fibril_mutex_unlock(&childp->lock);
+
+	/*
+	 * Hash in the index structure into the position hash.
+	 */
+	fat_idx_hashin(childp->idx);
+
+	return EOK;
+}
+
+int fat_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
+{
+	fat_node_t *parentp = FAT_NODE(pfn);
+	fat_node_t *childp = FAT_NODE(cfn);
+	fat_bs_t *bs;
+	fat_dentry_t *d;
+	uint16_t bps;
+	block_t *b;
+	bool has_children;
+	int rc;
+
+	if (!parentp)
+		return EBUSY;
+	
+	rc = fat_has_children(&has_children, cfn);
+	if (rc != EOK)
+		return rc;
+	if (has_children)
+		return ENOTEMPTY;
+
+	fibril_mutex_lock(&parentp->lock);
+	fibril_mutex_lock(&childp->lock);
+	assert(childp->lnkcnt == 1);
+	fibril_mutex_lock(&childp->idx->lock);
+	bs = block_bb_get(childp->idx->dev_handle);
+	bps = uint16_t_le2host(bs->bps);
+
+	rc = _fat_block_get(&b, bs, childp->idx->dev_handle, childp->idx->pfc,
+	    (childp->idx->pdi * sizeof(fat_dentry_t)) / bps,
+	    BLOCK_FLAGS_NONE);
+	if (rc != EOK) 
+		goto error;
+	d = (fat_dentry_t *)b->data +
+	    (childp->idx->pdi % (bps / sizeof(fat_dentry_t)));
+	/* mark the dentry as not-currently-used */
+	d->name[0] = FAT_DENTRY_ERASED;
+	b->dirty = true;		/* need to sync block */
+	rc = block_put(b);
+	if (rc != EOK)
+		goto error;
+
+	/* remove the index structure from the position hash */
+	fat_idx_hashout(childp->idx);
+	/* clear position information */
+	childp->idx->pfc = FAT_CLST_RES0;
+	childp->idx->pdi = 0;
+	fibril_mutex_unlock(&childp->idx->lock);
+	childp->lnkcnt = 0;
+	childp->dirty = true;
+	fibril_mutex_unlock(&childp->lock);
+	fibril_mutex_unlock(&parentp->lock);
+
+	return EOK;
+
+error:
+	fibril_mutex_unlock(&parentp->idx->lock);
+	fibril_mutex_unlock(&childp->lock);
+	fibril_mutex_unlock(&childp->idx->lock);
+	return rc;
+}
+
+int fat_has_children(bool *has_children, fs_node_t *fn)
 {
 	fat_bs_t *bs;
@@ -737,6 +754,8 @@
 	int rc;
 
-	if (nodep->type != FAT_DIRECTORY)
-		return false;
+	if (nodep->type != FAT_DIRECTORY) {
+		*has_children = false;
+		return EOK;
+	}
 	
 	fibril_mutex_lock(&nodep->idx->lock);
@@ -751,5 +770,8 @@
 	
 		rc = fat_block_get(&b, bs, nodep, i, BLOCK_FLAGS_NONE);
-		assert(rc == EOK);
+		if (rc != EOK) {
+			fibril_mutex_unlock(&nodep->idx->lock);
+			return rc;
+		}
 		for (j = 0; j < dps; j++) {
 			d = ((fat_dentry_t *)b->data) + j;
@@ -760,30 +782,42 @@
 			case FAT_DENTRY_LAST:
 				rc = block_put(b);
+				/* expect EOK as b was not dirty */
 				assert(rc == EOK);
 				fibril_mutex_unlock(&nodep->idx->lock);
-				return false;
+				*has_children = false;
+				return EOK;
 			default:
 			case FAT_DENTRY_VALID:
 				rc = block_put(b);
+				/* expect EOK as b was not dirty */
 				assert(rc == EOK);
 				fibril_mutex_unlock(&nodep->idx->lock);
-				return true;
+				*has_children = true;
+				return EOK;
 			}
-			rc = block_put(b);
-			assert(rc == EOK);
-			fibril_mutex_unlock(&nodep->idx->lock);
-			return true;
 		}
 		rc = block_put(b);
-		assert(rc == EOK);
+		assert(rc == EOK);	/* expect EOK as b was not dirty */
 	}
 
 	fibril_mutex_unlock(&nodep->idx->lock);
-	return false;
-}
-
-fs_node_t *fat_root_get(dev_handle_t dev_handle)
-{
-	return fat_node_get(dev_handle, 0);
+	*has_children = false;
+	return EOK;
+}
+
+
+fs_index_t fat_index_get(fs_node_t *fn)
+{
+	return FAT_NODE(fn)->idx->index;
+}
+
+size_t fat_size_get(fs_node_t *fn)
+{
+	return FAT_NODE(fn)->size;
+}
+
+unsigned fat_lnkcnt_get(fs_node_t *fn)
+{
+	return FAT_NODE(fn)->lnkcnt;
 }
 
@@ -805,4 +839,5 @@
 /** libfs operations */
 libfs_ops_t fat_libfs_ops = {
+	.root_get = fat_root_get,
 	.match = fat_match,
 	.node_get = fat_node_get,
@@ -812,9 +847,8 @@
 	.link = fat_link,
 	.unlink = fat_unlink,
+	.has_children = fat_has_children,
 	.index_get = fat_index_get,
 	.size_get = fat_size_get,
 	.lnkcnt_get = fat_lnkcnt_get,
-	.has_children = fat_has_children,
-	.root_get = fat_root_get,
 	.plb_get_char =	fat_plb_get_char,
 	.is_directory = fat_is_directory,
@@ -967,5 +1001,5 @@
 	fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
 	off_t pos = (off_t)IPC_GET_ARG3(*request);
-	fs_node_t *fn = fat_node_get(dev_handle, index);
+	fs_node_t *fn;
 	fat_node_t *nodep;
 	fat_bs_t *bs;
@@ -975,4 +1009,9 @@
 	int rc;
 
+	rc = fat_node_get(&fn, dev_handle, index);
+	if (rc != EOK) {
+		ipc_answer_0(rid, rc);
+		return;
+	}
 	if (!fn) {
 		ipc_answer_0(rid, ENOENT);
@@ -1052,5 +1091,5 @@
 				case FAT_DENTRY_VALID:
 					fat_dentry_name_get(d, name);
-					rc == block_put(b);
+					rc = block_put(b);
 					assert(rc == EOK);
 					goto hit;
@@ -1080,5 +1119,5 @@
 	fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
 	off_t pos = (off_t)IPC_GET_ARG3(*request);
-	fs_node_t *fn = fat_node_get(dev_handle, index);
+	fs_node_t *fn;
 	fat_node_t *nodep;
 	fat_bs_t *bs;
@@ -1092,4 +1131,9 @@
 	int rc;
 	
+	rc = fat_node_get(&fn, dev_handle, index);
+	if (rc != EOK) {
+		ipc_answer_0(rid, rc);
+		return;
+	}
 	if (!fn) {
 		ipc_answer_0(rid, ENOENT);
@@ -1196,5 +1240,5 @@
 	fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
 	size_t size = (off_t)IPC_GET_ARG3(*request);
-	fs_node_t *fn = fat_node_get(dev_handle, index);
+	fs_node_t *fn;
 	fat_node_t *nodep;
 	fat_bs_t *bs;
@@ -1204,4 +1248,9 @@
 	int rc;
 
+	rc = fat_node_get(&fn, dev_handle, index);
+	if (rc != EOK) {
+		ipc_answer_0(rid, rc);
+		return;
+	}
 	if (!fn) {
 		ipc_answer_0(rid, ENOENT);
@@ -1267,7 +1316,12 @@
 	dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
 	fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
+	fs_node_t *fn;
 	int rc;
 
-	fs_node_t *fn = fat_node_get(dev_handle, index);
+	rc = fat_node_get(&fn, dev_handle, index);
+	if (rc != EOK) {
+		ipc_answer_0(rid, rc);
+		return;
+	}
 	if (!fn) {
 		ipc_answer_0(rid, ENOENT);
Index: uspace/srv/fs/tmpfs/tmpfs_dump.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs_dump.c	(revision d27ed127903ea6d811485f75c5dc394ec19f814e)
+++ uspace/srv/fs/tmpfs/tmpfs_dump.c	(revision 2e3730821d5835626bc82dc1e3f9652b540ed7f6)
@@ -82,6 +82,6 @@
 				return false;
 			
-			fn = ops->create(dev, L_FILE);
-			if (fn == NULL) {
+			rc = ops->create(&fn, dev, L_FILE);
+			if (rc != EOK || fn == NULL) {
 				free(fname);
 				return false;
@@ -90,5 +90,5 @@
 			if (block_seqread(dev, bufpos, buflen, pos, fname,
 			    entry.len) != EOK) {
-				ops->destroy(fn);
+				(void) ops->destroy(fn);
 				free(fname);
 				return false;
@@ -98,5 +98,5 @@
 			rc = ops->link(pfn, fn, fname);
 			if (rc != EOK) {
-				ops->destroy(fn);
+				(void) ops->destroy(fn);
 				free(fname);
 				return false;
@@ -126,6 +126,6 @@
 				return false;
 			
-			fn = ops->create(dev, L_DIRECTORY);
-			if (fn == NULL) {
+			rc = ops->create(&fn, dev, L_DIRECTORY);
+			if (rc != EOK || fn == NULL) {
 				free(fname);
 				return false;
@@ -134,5 +134,5 @@
 			if (block_seqread(dev, bufpos, buflen, pos, fname,
 			    entry.len) != EOK) {
-				ops->destroy(fn);
+				(void) ops->destroy(fn);
 				free(fname);
 				return false;
@@ -142,5 +142,5 @@
 			rc = ops->link(pfn, fn, fname);
 			if (rc != EOK) {
-				ops->destroy(fn);
+				(void) ops->destroy(fn);
 				free(fname);
 				return false;
@@ -164,4 +164,5 @@
 {
 	libfs_ops_t *ops = &tmpfs_libfs_ops;
+	fs_node_t *fn;
 	int rc;
 
@@ -182,6 +183,9 @@
 		goto error;
 	
-	if (!tmpfs_restore_recursion(dev, &bufpos, &buflen, &pos,
-	    ops->root_get(dev)))
+	rc = ops->root_get(&fn, dev);
+	if (rc != EOK)
+		goto error;
+
+	if (!tmpfs_restore_recursion(dev, &bufpos, &buflen, &pos, fn))
 		goto error;
 		
Index: uspace/srv/fs/tmpfs/tmpfs_ops.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision d27ed127903ea6d811485f75c5dc394ec19f814e)
+++ uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision 2e3730821d5835626bc82dc1e3f9652b540ed7f6)
@@ -67,13 +67,24 @@
 
 /* Forward declarations of static functions. */
-static fs_node_t *tmpfs_match(fs_node_t *, const char *);
-static fs_node_t *tmpfs_node_get(dev_handle_t, fs_index_t);
-static void tmpfs_node_put(fs_node_t *);
-static fs_node_t *tmpfs_create_node(dev_handle_t, int);
+static int tmpfs_match(fs_node_t **, fs_node_t *, const char *);
+static int tmpfs_node_get(fs_node_t **, dev_handle_t, fs_index_t);
+static int tmpfs_node_put(fs_node_t *);
+static int tmpfs_create_node(fs_node_t **, dev_handle_t, int);
+static int tmpfs_destroy_node(fs_node_t *);
 static int tmpfs_link_node(fs_node_t *, fs_node_t *, const char *);
 static int tmpfs_unlink_node(fs_node_t *, fs_node_t *, const char *);
-static int tmpfs_destroy_node(fs_node_t *);
 
 /* Implementation of helper functions. */
+static int tmpfs_root_get(fs_node_t **rfn, dev_handle_t dev_handle)
+{
+	return tmpfs_node_get(rfn, dev_handle, TMPFS_SOME_ROOT); 
+}
+
+static int tmpfs_has_children(bool *has_children, fs_node_t *fn)
+{
+	*has_children = !list_empty(&TMPFS_NODE(fn)->cs_head);
+	return EOK;
+}
+
 static fs_index_t tmpfs_index_get(fs_node_t *fn)
 {
@@ -89,14 +100,4 @@
 {
 	return TMPFS_NODE(fn)->lnkcnt;
-}
-
-static bool tmpfs_has_children(fs_node_t *fn)
-{
-	return !list_empty(&TMPFS_NODE(fn)->cs_head);
-}
-
-static fs_node_t *tmpfs_root_get(dev_handle_t dev_handle)
-{
-	return tmpfs_node_get(dev_handle, TMPFS_SOME_ROOT); 
 }
 
@@ -118,4 +119,5 @@
 /** libfs operations */
 libfs_ops_t tmpfs_libfs_ops = {
+	.root_get = tmpfs_root_get,
 	.match = tmpfs_match,
 	.node_get = tmpfs_node_get,
@@ -125,9 +127,8 @@
 	.link = tmpfs_link_node,
 	.unlink = tmpfs_unlink_node,
+	.has_children = tmpfs_has_children,
 	.index_get = tmpfs_index_get,
 	.size_get = tmpfs_size_get,
 	.lnkcnt_get = tmpfs_lnkcnt_get,
-	.has_children = tmpfs_has_children,
-	.root_get = tmpfs_root_get,
 	.plb_get_char = tmpfs_plb_get_char,
 	.is_directory = tmpfs_is_directory,
@@ -197,7 +198,8 @@
 {
 	fs_node_t *rfn;
+	int rc;
 	
-	rfn = tmpfs_create_node(dev_handle, L_DIRECTORY);
-	if (!rfn) 
+	rc = tmpfs_create_node(&rfn, dev_handle, L_DIRECTORY);
+	if (rc != EOK || !rfn)
 		return false;
 	TMPFS_NODE(rfn)->lnkcnt = 0;	/* FS root is not linked */
@@ -205,5 +207,5 @@
 }
 
-fs_node_t *tmpfs_match(fs_node_t *pfn, const char *component)
+int tmpfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
 {
 	tmpfs_node_t *parentp = TMPFS_NODE(pfn);
@@ -212,14 +214,17 @@
 	for (lnk = parentp->cs_head.next; lnk != &parentp->cs_head;
 	    lnk = lnk->next) {
-		tmpfs_dentry_t *dentryp = list_get_instance(lnk, tmpfs_dentry_t,
-		    link);
-		if (!str_cmp(dentryp->name, component))
-			return FS_NODE(dentryp->node);
-	}
-
-	return NULL;
-}
-
-fs_node_t *tmpfs_node_get(dev_handle_t dev_handle, fs_index_t index)
+		tmpfs_dentry_t *dentryp;
+		dentryp = list_get_instance(lnk, tmpfs_dentry_t, link);
+		if (!str_cmp(dentryp->name, component)) {
+			*rfn = FS_NODE(dentryp->node);
+			return EOK;
+		}
+	}
+
+	*rfn = NULL;
+	return EOK;
+}
+
+int tmpfs_node_get(fs_node_t **rfn, dev_handle_t dev_handle, fs_index_t index)
 {
 	unsigned long key[] = {
@@ -228,30 +233,42 @@
 	};
 	link_t *lnk = hash_table_find(&nodes, key);
-	if (!lnk)
-		return NULL;
-	return FS_NODE(hash_table_get_instance(lnk, tmpfs_node_t, nh_link));
-}
-
-void tmpfs_node_put(fs_node_t *fn)
+	if (lnk) {
+		tmpfs_node_t *nodep;
+		nodep = hash_table_get_instance(lnk, tmpfs_node_t, nh_link);
+		*rfn = FS_NODE(nodep);
+	} else {
+		*rfn = NULL;
+	}
+	return EOK;	
+}
+
+int tmpfs_node_put(fs_node_t *fn)
 {
 	/* nothing to do */
-}
-
-fs_node_t *tmpfs_create_node(dev_handle_t dev_handle, int lflag)
-{
+	return EOK;
+}
+
+int tmpfs_create_node(fs_node_t **rfn, dev_handle_t dev_handle, int lflag)
+{
+	fs_node_t *rootfn;
+	int rc;
+
 	assert((lflag & L_FILE) ^ (lflag & L_DIRECTORY));
 
 	tmpfs_node_t *nodep = malloc(sizeof(tmpfs_node_t));
 	if (!nodep)
-		return NULL;
+		return ENOMEM;
 	tmpfs_node_initialize(nodep);
 	nodep->bp = malloc(sizeof(fs_node_t));
 	if (!nodep->bp) {
 		free(nodep);
-		return NULL;
+		return ENOMEM;
 	}
 	fs_node_initialize(nodep->bp);
 	nodep->bp->data = nodep;	/* link the FS and TMPFS nodes */
-	if (!tmpfs_root_get(dev_handle))
+
+	rc = tmpfs_root_get(&rootfn, dev_handle);
+	assert(rc == EOK);
+	if (!rootfn)
 		nodep->index = TMPFS_SOME_ROOT;
 	else
@@ -269,5 +286,26 @@
 	};
 	hash_table_insert(&nodes, key, &nodep->nh_link);
-	return FS_NODE(nodep);
+	*rfn = FS_NODE(nodep);
+	return EOK;
+}
+
+int tmpfs_destroy_node(fs_node_t *fn)
+{
+	tmpfs_node_t *nodep = TMPFS_NODE(fn);
+	
+	assert(!nodep->lnkcnt);
+	assert(list_empty(&nodep->cs_head));
+
+	unsigned long key[] = {
+		[NODES_KEY_INDEX] = nodep->index,
+		[NODES_KEY_DEV] = nodep->dev_handle
+	};
+	hash_table_remove(&nodes, key, 2);
+
+	if (nodep->type == TMPFS_FILE)
+		free(nodep->data);
+	free(nodep->bp);
+	free(nodep);
+	return EOK;
 }
 
@@ -343,27 +381,8 @@
 }
 
-int tmpfs_destroy_node(fs_node_t *fn)
-{
-	tmpfs_node_t *nodep = TMPFS_NODE(fn);
-	
-	assert(!nodep->lnkcnt);
-	assert(list_empty(&nodep->cs_head));
-
-	unsigned long key[] = {
-		[NODES_KEY_INDEX] = nodep->index,
-		[NODES_KEY_DEV] = nodep->dev_handle
-	};
-	hash_table_remove(&nodes, key, 2);
-
-	if (nodep->type == TMPFS_FILE)
-		free(nodep->data);
-	free(nodep->bp);
-	free(nodep);
-	return EOK;
-}
-
 void tmpfs_mounted(ipc_callid_t rid, ipc_call_t *request)
 {
 	dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
+	int rc;
 
 	/* accept the mount options */
@@ -395,5 +414,8 @@
 	}
 
-	tmpfs_node_t *rootp = TMPFS_NODE(tmpfs_root_get(dev_handle));
+	fs_node_t *rootfn;
+	rc = tmpfs_root_get(&rootfn, dev_handle);
+	assert(rc == EOK);
+	tmpfs_node_t *rootp = TMPFS_NODE(rootfn);
 	if (str_cmp(opts, "restore") == 0) {
 		if (tmpfs_restore(dev_handle))
