Index: uspace/lib/c/generic/vfs/vfs.c
===================================================================
--- uspace/lib/c/generic/vfs/vfs.c	(revision cb65bbe6ec28f0093b952e0a2de1517506c6379d)
+++ uspace/lib/c/generic/vfs/vfs.c	(revision 0b18364c6fa42d415600ee3c44b15f8f5ad21769)
@@ -90,4 +90,43 @@
 {
 	async_exchange_end(exch);
+}
+
+int _vfs_walk(int parent, const char *path, int flags)
+{
+	async_exch_t *exch = vfs_exchange_begin();
+	
+	// TODO: assume this is done at a higher level.
+	char *precanon = str_dup(path);
+	size_t canon_size;
+	char *canon = canonify(precanon, &canon_size);
+	
+	ipc_call_t answer;
+	aid_t req = async_send_2(exch, VFS_IN_WALK, parent, flags, &answer);
+	sysarg_t rc = async_data_write_start(exch, canon, canon_size);
+	
+	free(precanon);
+	vfs_exchange_end(exch);
+		
+	sysarg_t rc_orig;
+	async_wait_for(req, &rc_orig);
+
+	if (rc_orig != EOK) {
+		return (int) rc_orig;
+	}
+		
+	if (rc != EOK) {
+		return (int) rc;
+	}
+	
+	return (int) IPC_GET_ARG1(answer);
+}
+
+int _vfs_open(int fildes, int mode)
+{
+	async_exch_t *exch = vfs_exchange_begin();
+	sysarg_t rc = async_req_2_0(exch, VFS_IN_OPEN2, fildes, mode);
+	vfs_exchange_end(exch);
+	
+	return (int) rc;
 }
 
Index: uspace/lib/c/include/ipc/vfs.h
===================================================================
--- uspace/lib/c/include/ipc/vfs.h	(revision cb65bbe6ec28f0093b952e0a2de1517506c6379d)
+++ uspace/lib/c/include/ipc/vfs.h	(revision 0b18364c6fa42d415600ee3c44b15f8f5ad21769)
@@ -181,5 +181,11 @@
 	//WALK_PARTIAL = (1 << 0),
 	
-	WALK_ALL_FLAGS = 0,
+	WALK_MAY_CREATE = (1 << 1),
+	WALK_MUST_CREATE = (1 << 2),
+	
+	WALK_REGULAR = (1 << 3),
+	WALK_DIRECTORY = (1 << 4),
+	
+	WALK_ALL_FLAGS = WALK_MAY_CREATE | WALK_MUST_CREATE | WALK_REGULAR | WALK_DIRECTORY,
 };
 
Index: uspace/lib/c/include/vfs/vfs.h
===================================================================
--- uspace/lib/c/include/vfs/vfs.h	(revision cb65bbe6ec28f0093b952e0a2de1517506c6379d)
+++ uspace/lib/c/include/vfs/vfs.h	(revision 0b18364c6fa42d415600ee3c44b15f8f5ad21769)
@@ -62,4 +62,7 @@
 extern void vfs_exchange_end(async_exch_t *);
 
+extern int _vfs_walk(int parent, const char *path, int flags);
+extern int _vfs_open(int file, int mode);
+
 #endif
 
Index: uspace/srv/vfs/vfs_ops.c
===================================================================
--- uspace/srv/vfs/vfs_ops.c	(revision cb65bbe6ec28f0093b952e0a2de1517506c6379d)
+++ uspace/srv/vfs/vfs_ops.c	(revision 0b18364c6fa42d415600ee3c44b15f8f5ad21769)
@@ -568,4 +568,41 @@
 }
 
+static inline bool walk_flags_valid(int flags)
+{
+	if ((flags&~WALK_ALL_FLAGS) != 0) {
+		return false;
+	}
+	if ((flags&WALK_MAY_CREATE) && (flags&WALK_MUST_CREATE)) {
+		return false;
+	}
+	if ((flags&WALK_REGULAR) && (flags&WALK_DIRECTORY)) {
+		return false;
+	}
+	if ((flags&WALK_MAY_CREATE) || (flags&WALK_MUST_CREATE)) {
+		if (!(flags&WALK_DIRECTORY) && !(flags&WALK_REGULAR)) {
+			return false;
+		}
+	}
+	return true;
+}
+
+static inline int walk_lookup_flags(int flags)
+{
+	int lflags = 0;
+	if (flags&WALK_MAY_CREATE || flags&WALK_MUST_CREATE) {
+		lflags |= L_CREATE;
+	}
+	if (flags&WALK_MUST_CREATE) {
+		lflags |= L_EXCLUSIVE;
+	}
+	if (flags&WALK_REGULAR) {
+		lflags |= L_FILE;
+	}
+	if (flags&WALK_DIRECTORY) {
+		lflags |= L_DIRECTORY;
+	}
+	return lflags;
+}
+
 void vfs_walk(ipc_callid_t rid, ipc_call_t *request)
 {
@@ -577,6 +614,5 @@
 	int flags = IPC_GET_ARG2(*request);
 	
-	if ((flags&~WALK_ALL_FLAGS) != 0) {
-		/* Invalid flags. */
+	if (!walk_flags_valid(flags)) {
 		async_answer_0(rid, EINVAL);
 		return;
@@ -603,5 +639,5 @@
 	
 	vfs_lookup_res_t lr;
-	rc = vfs_lookup_internal(path, 0, &lr, parent_node);
+	rc = vfs_lookup_internal(path, walk_lookup_flags(flags), &lr, parent_node);
 	free(path);
 
