Index: uspace/lib/libfs/libfs.c
===================================================================
--- uspace/lib/libfs/libfs.c	(revision 6c441cf8f35799043d891a3a77032e1b0e49112b)
+++ uspace/lib/libfs/libfs.c	(revision 7fe1f75f70531c93a931eb2ac453b58c55151e62)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2007 Jakub Jermar 
+ * Copyright (c) 2008 Jakub Jermar 
  * All rights reserved.
  *
@@ -41,4 +41,6 @@
 #include <ipc/ipc.h>
 #include <as.h>
+#include <assert.h>
+#include <dirent.h>
 
 /** Register file system server.
@@ -121,4 +123,152 @@
 }
 
+void libfs_lookup(libfs_ops_t *ops, int fs_handle, ipc_callid_t rid,
+    ipc_call_t *request)
+{
+	unsigned next = IPC_GET_ARG1(*request);
+	unsigned last = IPC_GET_ARG2(*request);
+	int dev_handle = IPC_GET_ARG3(*request);
+	int lflag = IPC_GET_ARG4(*request);
+
+	if (last < next)
+		last += PLB_SIZE;
+
+	void *cur = ops->root_get();
+	void *tmp = ops->child_get(cur);
+
+	if (ops->plb_get_char(next) == '/')
+		next++;		/* eat slash */
+	
+	char component[NAME_MAX + 1];
+	int len = 0;
+	while (tmp && next <= last) {
+
+		/* collect the component */
+		if (ops->plb_get_char(next) != '/') {
+			if (len + 1 == NAME_MAX) {
+				/* comopnent length overflow */
+				ipc_answer_0(rid, ENAMETOOLONG);
+				return;
+			}
+			component[len++] = ops->plb_get_char(next);
+			next++;	/* process next character */
+			if (next <= last) 
+				continue;
+		}
+
+		assert(len);
+		component[len] = '\0';
+		next++;		/* eat slash */
+		len = 0;
+
+		/* match the component */
+		while (tmp && !ops->match(tmp, component))
+			tmp = ops->sibling_get(tmp);
+
+		/* handle miss: match amongst siblings */
+		if (!tmp) {
+			if ((next > last) && (lflag & L_CREATE)) {
+				/* no components left and L_CREATE specified */
+				if (!ops->is_directory(cur)) {
+					ipc_answer_0(rid, ENOTDIR);
+					return;
+				} 
+				void *nodep = ops->create(lflag);
+				if (nodep) {
+					if (!ops->link(cur, nodep, component)) {
+						ops->destroy(nodep);
+						ipc_answer_0(rid, ENOSPC);
+					} else {
+						ipc_answer_5(rid, EOK,
+						    fs_handle, dev_handle,
+						    ops->index_get(nodep), 0,
+						    ops->lnkcnt_get(nodep));
+					}
+				} else {
+					ipc_answer_0(rid, ENOSPC);
+				}
+				return;
+			}
+			ipc_answer_0(rid, ENOENT);
+			return;
+		}
+
+		/* descend one level */
+		cur = tmp;
+		tmp = ops->child_get(tmp);
+	}
+
+	/* handle miss: excessive components */
+	if (!tmp && next <= last) {
+		if (lflag & L_CREATE) {
+			if (!ops->is_directory(cur)) {
+				ipc_answer_0(rid, ENOTDIR);
+				return;
+			}
+
+			/* collect next component */
+			while (next <= last) {
+				if (ops->plb_get_char(next) == '/') {
+					/* more than one component */
+					ipc_answer_0(rid, ENOENT);
+					return;
+				}
+				if (len + 1 == NAME_MAX) {
+					/* component length overflow */
+					ipc_answer_0(rid, ENAMETOOLONG);
+					return;
+				}
+				component[len++] = ops->plb_get_char(next);
+				next++;	/* process next character */
+			}
+			assert(len);
+			component[len] = '\0';
+			len = 0;
+				
+			void *nodep = ops->create(lflag);
+			if (nodep) {
+				if (!ops->link(cur, nodep, component)) {
+					ops->destroy(nodep);
+					ipc_answer_0(rid, ENOSPC);
+				} else {
+					ipc_answer_5(rid, EOK,
+					    fs_handle, dev_handle,
+					    ops->index_get(nodep), 0,
+					    ops->lnkcnt_get(nodep));
+				}
+			} else {
+				ipc_answer_0(rid, ENOSPC);
+			}
+			return;
+		}
+		ipc_answer_0(rid, ENOENT);
+		return;
+	}
+
+	/* handle hit */
+	if (lflag & L_DESTROY) {
+		unsigned old_lnkcnt = ops->lnkcnt_get(cur);
+		int res = ops->unlink(cur);
+		ipc_answer_5(rid, (ipcarg_t)res, fs_handle, dev_handle,
+		    ops->index_get(cur), ops->size_get(cur), old_lnkcnt);
+		return;
+	}
+	if ((lflag & (L_CREATE | L_EXCLUSIVE)) == (L_CREATE | L_EXCLUSIVE)) {
+		ipc_answer_0(rid, EEXIST);
+		return;
+	}
+	if ((lflag & L_FILE) && (ops->is_directory(cur))) {
+		ipc_answer_0(rid, EISDIR);
+		return;
+	}
+	if ((lflag & L_DIRECTORY) && (ops->is_file(cur))) {
+		ipc_answer_0(rid, ENOTDIR);
+		return;
+	}
+
+	ipc_answer_5(rid, EOK, fs_handle, dev_handle, ops->index_get(cur),
+	    ops->size_get(cur), ops->lnkcnt_get(cur));
+}
+
 /** @}
  */
Index: uspace/lib/libfs/libfs.h
===================================================================
--- uspace/lib/libfs/libfs.h	(revision 6c441cf8f35799043d891a3a77032e1b0e49112b)
+++ uspace/lib/libfs/libfs.h	(revision 7fe1f75f70531c93a931eb2ac453b58c55151e62)
@@ -43,4 +43,21 @@
 
 typedef struct {
+	bool (* match)(void *, const char *);
+	void * (* create)(int);
+	void (* destroy)(void *);
+	bool (* link)(void *, void *, const char *);
+	int (* unlink)(void *);
+	unsigned long (* index_get)(void *);
+	unsigned long (* size_get)(void *);
+	unsigned (* lnkcnt_get)(void *);
+	void *(* child_get)(void *);
+	void *(* sibling_get)(void *);
+	void *(* root_get)(void);
+	char (* plb_get_char)(unsigned pos);	
+	bool (* is_directory)(void *);
+	bool (* is_file)(void *);
+} libfs_ops_t;
+
+typedef struct {
 	int fs_handle;		/**< File system handle. */
 	ipcarg_t vfs_phonehash;	/**< Initial VFS phonehash. */
@@ -56,4 +73,7 @@
 extern void node_del_mp(int, unsigned long);
 extern bool node_is_mp(int, unsigned long);
+
+extern void libfs_lookup(libfs_ops_t *, int, ipc_callid_t, ipc_call_t *);
+
 #endif
 
