Index: uspace/srv/fs/ext2fs/ext2fs.c
===================================================================
--- uspace/srv/fs/ext2fs/ext2fs.c	(revision 163cf125af37a4e716f76aa7ffd110208a68257b)
+++ uspace/srv/fs/ext2fs/ext2fs.c	(revision 4dc6a3262ca8f458f6b3ea55c0868d93b41ab612)
@@ -74,5 +74,5 @@
  * request has been completed.
  */
-static void ext2_connection(ipc_callid_t iid, ipc_call_t *icall)
+static void ext2fs_connection(ipc_callid_t iid, ipc_call_t *icall)
 {
 	if (iid) {
@@ -152,6 +152,12 @@
 		return -1;
 	}
-	
-	rc = fs_register(vfs_phone, &ext2fs_reg, &ext2fs_vfs_info, ext2_connection);
+
+	rc = ext2fs_global_init();
+	if (rc != EOK) {
+		printf(NAME ": Failed global initialization\n");
+		return 1;
+	}	
+		
+	rc = fs_register(vfs_phone, &ext2fs_reg, &ext2fs_vfs_info, ext2fs_connection);
 	
 	printf(NAME ": Accepting connections\n");
Index: uspace/srv/fs/ext2fs/ext2fs.h
===================================================================
--- uspace/srv/fs/ext2fs/ext2fs.h	(revision 163cf125af37a4e716f76aa7ffd110208a68257b)
+++ uspace/srv/fs/ext2fs/ext2fs.h	(revision 4dc6a3262ca8f458f6b3ea55c0868d93b41ab612)
@@ -51,4 +51,5 @@
 
 extern int ext2fs_global_init(void);
+extern int ext2fs_global_fini(void);
 extern void ext2fs_mounted(ipc_callid_t, ipc_call_t *);
 extern void ext2fs_mount(ipc_callid_t, ipc_call_t *);
Index: uspace/srv/fs/ext2fs/ext2fs_ops.c
===================================================================
--- uspace/srv/fs/ext2fs/ext2fs_ops.c	(revision 163cf125af37a4e716f76aa7ffd110208a68257b)
+++ uspace/srv/fs/ext2fs/ext2fs_ops.c	(revision 4dc6a3262ca8f458f6b3ea55c0868d93b41ab612)
@@ -57,9 +57,19 @@
 #include <adt/hash_table.h>
 
-#define EXT2_NODE(node)	((node) ? (ext2fs_node_t *) (node)->data : NULL)
-#define FS_NODE(node)	((node) ? (node)->bp : NULL)
-
-#define FS_BUCKETS_LOG	12
-#define FS_BUCKETS	(1 << FS_BUCKETS_LOG)
+#define EXT2FS_NODE(node)	((node) ? (ext2fs_node_t *) (node)->data : NULL)
+#define EXT2FS_DBG(format, ...) {if (false) printf("ext2fs: %s: " format "\n", __FUNCTION__, ##__VA_ARGS__);}
+
+typedef struct ext2fs_instance {
+	link_t link;
+	devmap_handle_t devmap_handle;
+	ext2_filesystem_t *filesystem;
+} ext2fs_instance_t;
+
+typedef struct ext2fs_node {
+	ext2fs_instance_t *instance;
+	ext2_inode_ref_t *inode_ref;
+} ext2fs_node_t;
+
+static int ext2fs_instance_get(devmap_handle_t, ext2fs_instance_t **);
 
 /*
@@ -87,16 +97,5 @@
  * Static variables
  */
-
-/**
- * Global hash table holding a mapping from devmap handles to
- * ext2_filesystem_t structures
- */
-//TODO
-//static hash_table_t fs_hash;
-
-/**
- * Mutex protecting fs_hash
- */
-static FIBRIL_MUTEX_INITIALIZE(fs_hash_lock);
+static LIST_INITIALIZE(instance_list);
 
 /**
@@ -105,9 +104,9 @@
 int ext2fs_global_init(void)
 {
-	//TODO
-	//if (!hash_table_create(&fs_hash, FS_BUCKETS, 1, &fs_hash_ops)) {
-	//	return ENOMEM;
-	//}
-	
+	return EOK;
+}
+
+int ext2fs_global_fini(void)
+{
 	return EOK;
 }
@@ -119,15 +118,103 @@
  */
 
+/**
+ * Find an instance of filesystem for the given devmap_handle
+ */
+int ext2fs_instance_get(devmap_handle_t devmap_handle, ext2fs_instance_t **inst)
+{
+	EXT2FS_DBG("(%u, -)", devmap_handle);
+	link_t *link;
+	ext2fs_instance_t *tmp;
+
+	if (list_empty(&instance_list)) {
+		EXT2FS_DBG("list empty");
+		return EINVAL;
+	}
+
+	for (link = instance_list.next; link != &instance_list; link = link->next) {
+		tmp = list_get_instance(link, ext2fs_instance_t, link);
+		
+		if (tmp->devmap_handle == devmap_handle) {
+			*inst = tmp;
+			return EOK;
+		}
+	}
+	
+	EXT2FS_DBG("not found");
+	return EINVAL;
+}
+
+
+
 int ext2fs_root_get(fs_node_t **rfn, devmap_handle_t devmap_handle)
 {
-	// TODO
-	return 0;
-	//return ext2fs_node_get(rfn, devmap_handle, 0);
+	EXT2FS_DBG("(-, %u)", devmap_handle);
+	return ext2fs_node_get(rfn, devmap_handle, EXT2_INODE_ROOT_INDEX);
 }
 
 int ext2fs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
 {
-	// TODO
-	return ENOTSUP;
+	EXT2FS_DBG("(-,-,%s)", component);
+	ext2fs_node_t *eparent = EXT2FS_NODE(pfn);
+	ext2_filesystem_t *fs;
+	ext2_directory_iterator_t it;
+	int rc;
+	size_t name_size;
+	size_t component_size;
+	bool found = false;
+	
+	fs = eparent->instance->filesystem;
+	
+	if (!ext2_inode_is_type(fs->superblock, eparent->inode_ref->inode,
+	    EXT2_INODE_MODE_DIRECTORY)) {
+		return ENOTDIR;
+	}
+	
+	rc = ext2_directory_iterator_init(&it, fs, eparent->inode_ref);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	// Find length of component in bytes
+	// TODO: check for library function call that does this
+	component_size = 0;
+	while (*(component+component_size) != 0) {
+		component_size++;
+	}
+	
+	while (it.current != NULL) {
+		// ignore empty directory entries
+		if (it.current->inode != 0) {
+			name_size = ext2_directory_entry_ll_get_name_length(fs->superblock,
+				it.current);
+
+			if (name_size == component_size && bcmp(component, &it.current->name,
+				    name_size) == 0) {
+				// FIXME: this may be done better (give instance as param)
+				rc = ext2fs_node_get(rfn, eparent->instance->devmap_handle,
+					it.current->inode);
+				if (rc != EOK) {
+					ext2_directory_iterator_fini(&it);
+					return rc;
+				}
+				found = true;
+				break;
+			}
+		}
+		
+		rc = ext2_directory_iterator_next(&it);
+		if (rc != EOK) {
+			ext2_directory_iterator_fini(&it);
+			return rc;
+		}
+	}
+	
+	ext2_directory_iterator_fini(&it);
+	
+	if (!found) {
+		return ENOENT;
+	}
+	
+	return EOK;
 }
 
@@ -135,10 +222,53 @@
 int ext2fs_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle, fs_index_t index)
 {
-	// TODO
-	return ENOTSUP;
+	EXT2FS_DBG("(-,%u,%u)", devmap_handle, index);
+	int rc;
+	fs_node_t *node = NULL;
+	ext2fs_node_t *enode = NULL;
+	ext2fs_instance_t *inst = NULL;
+	ext2_inode_ref_t *inode_ref = NULL;
+
+	enode = malloc(sizeof(ext2fs_node_t));
+	if (enode == NULL) {
+		return ENOMEM;
+	}
+
+	node = malloc(sizeof(fs_node_t));
+	if (node == NULL) {
+		free(enode);
+		return ENOMEM;
+	}
+	
+	fs_node_initialize(node);
+
+	rc = ext2fs_instance_get(devmap_handle, &inst);
+	if (rc != EOK) {
+		free(enode);
+		free(node);
+		return rc;
+	}
+		
+	rc = ext2_filesystem_get_inode_ref(inst->filesystem, index, &inode_ref);
+	if (rc != EOK) {
+		free(enode);
+		free(node);
+		return rc;
+	}
+	
+	enode->inode_ref = inode_ref;
+	enode->instance = inst;
+	node->data = enode;
+	*rfn = node;
+	
+	EXT2FS_DBG("inode: %u", inode_ref->index);
+	
+	EXT2FS_DBG("EOK");
+
+	return EOK;
 }
 
 int ext2fs_node_open(fs_node_t *fn)
 {
+	EXT2FS_DBG("");
 	/*
 	 * Opening a file is stateless, nothing
@@ -150,36 +280,91 @@
 int ext2fs_node_put(fs_node_t *fn)
 {
+	EXT2FS_DBG("");
+	int rc;
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	rc = ext2_filesystem_put_inode_ref(enode->inode_ref);
+	if (rc != EOK) {
+		EXT2FS_DBG("ext2_filesystem_put_inode_ref failed");
+	}
+	return rc;
+}
+
+int ext2fs_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int flags)
+{
+	EXT2FS_DBG("");
 	// TODO
 	return ENOTSUP;
 }
 
-int ext2fs_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int flags)
-{
+int ext2fs_destroy_node(fs_node_t *fn)
+{
+	EXT2FS_DBG("");
 	// TODO
 	return ENOTSUP;
 }
 
-int ext2fs_destroy_node(fs_node_t *fn)
-{
+int ext2fs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
+{
+	EXT2FS_DBG("");
 	// TODO
 	return ENOTSUP;
 }
 
-int ext2fs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
-{
+int ext2fs_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
+{
+	EXT2FS_DBG("");
 	// TODO
 	return ENOTSUP;
 }
 
-int ext2fs_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
-{
-	// TODO
-	return ENOTSUP;
-}
-
 int ext2fs_has_children(bool *has_children, fs_node_t *fn)
 {
-	// TODO
-	return ENOTSUP;
+	EXT2FS_DBG("");
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	ext2_directory_iterator_t it;
+	ext2_filesystem_t *fs;
+	int rc;
+	bool found = false;
+
+	fs = enode->instance->filesystem;
+
+	if (!ext2_inode_is_type(fs->superblock, enode->inode_ref->inode,
+	    EXT2_INODE_MODE_DIRECTORY)) {
+		*has_children = false;
+		EXT2FS_DBG("EOK - false");
+		return EOK;
+	}
+	
+	rc = ext2_directory_iterator_init(&it, fs, enode->inode_ref);
+	if (rc != EOK) {
+		EXT2FS_DBG("error %u", rc);
+		return rc;
+	}
+	
+	// Find a non-empty directory entry
+	while (it.current != NULL) {
+		if (it.current->inode != 0) {
+			found = true;
+			break;
+		}
+		
+		rc = ext2_directory_iterator_next(&it);
+		if (rc != EOK) {
+			ext2_directory_iterator_fini(&it);
+			EXT2FS_DBG("error %u", rc);
+			return rc;
+		}
+	}
+	
+	rc = ext2_directory_iterator_fini(&it);
+	if (rc != EOK) {
+		EXT2FS_DBG("error %u", rc);
+		return rc;
+	}
+
+	*has_children = found;
+	EXT2FS_DBG("EOK");
+	
+	return EOK;
 }
 
@@ -187,18 +372,24 @@
 fs_index_t ext2fs_index_get(fs_node_t *fn)
 {
-	// TODO
-	return 0;
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	EXT2FS_DBG("%u", enode->inode_ref->index);
+	return enode->inode_ref->index;
 }
 
 aoff64_t ext2fs_size_get(fs_node_t *fn)
 {
-	// TODO
-	return 0;
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	aoff64_t size = ext2_inode_get_size(enode->instance->filesystem->superblock,
+	    enode->inode_ref->inode);
+	EXT2FS_DBG("%" PRIu64, size);
+	return size;
 }
 
 unsigned ext2fs_lnkcnt_get(fs_node_t *fn)
 {
-	// TODO
-	return 0;
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	unsigned count = ext2_inode_get_usage_count(enode->inode_ref->inode);
+	EXT2FS_DBG("%u", count);
+	return count;
 }
 
@@ -210,17 +401,26 @@
 bool ext2fs_is_directory(fs_node_t *fn)
 {
-	// TODO
-	return false;
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	bool is_dir = ext2_inode_is_type(enode->instance->filesystem->superblock,
+	    enode->inode_ref->inode, EXT2_INODE_MODE_DIRECTORY);
+	EXT2FS_DBG("%s", is_dir ? "true" : "false");
+	EXT2FS_DBG("%u", enode->inode_ref->index);
+	return is_dir;
 }
 
 bool ext2fs_is_file(fs_node_t *fn)
 {
-	// TODO
-	return false;
-}
-
-devmap_handle_t ext2fs_device_get(fs_node_t *node)
-{
-	return 0;
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	bool is_file = ext2_inode_is_type(enode->instance->filesystem->superblock,
+	    enode->inode_ref->inode, EXT2_INODE_MODE_FILE);
+	EXT2FS_DBG("%s", is_file ? "true" : "false");
+	return is_file;
+}
+
+devmap_handle_t ext2fs_device_get(fs_node_t *fn)
+{
+	EXT2FS_DBG("");
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	return enode->instance->devmap_handle;
 }
 
@@ -252,7 +452,11 @@
 void ext2fs_mounted(ipc_callid_t rid, ipc_call_t *request)
 {
+	EXT2FS_DBG("");
 	int rc;
 	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
 	ext2_filesystem_t *fs;
+	ext2fs_instance_t *inst;
+	
+	
 	
 	/* Accept the mount options */
@@ -274,7 +478,17 @@
 	}
 	
+	/* Allocate instance structure */
+	inst = (ext2fs_instance_t *) malloc(sizeof(ext2fs_instance_t));
+	if (inst == NULL) {
+		free(fs);
+		async_answer_0(rid, ENOMEM);
+		return;
+	}
+	
 	/* Initialize the filesystem  */
 	rc = ext2_filesystem_init(fs, devmap_handle);
 	if (rc != EOK) {
+		free(fs);
+		free(inst);
 		async_answer_0(rid, rc);
 		return;
@@ -285,38 +499,166 @@
 	if (rc != EOK) {
 		ext2_filesystem_fini(fs);
+		free(fs);
+		free(inst);
 		async_answer_0(rid, rc);
 		return;
 	}
 	
-	
-	
-	// TODO
+	/* Initialize instance and add to the list */
+	link_initialize(&inst->link);
+	inst->devmap_handle = devmap_handle;
+	inst->filesystem = fs;
+	list_append(&inst->link, &instance_list);
+	
+	async_answer_0(rid, EOK);
+}
+
+void ext2fs_mount(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	libfs_mount(&ext2fs_libfs_ops, ext2fs_reg.fs_handle, rid, request);
+}
+
+void ext2fs_unmounted(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	ext2fs_instance_t *inst;
+	int rc;
+	
+	rc = ext2fs_instance_get(devmap_handle, &inst);
+	
+	if (rc != EOK) {
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	// TODO: check if the fs is busy
+	
+	// Remove the instance from list
+	list_remove(&inst->link);
+	ext2_filesystem_fini(inst->filesystem);
+	
+	async_answer_0(rid, EOK);
+}
+
+void ext2fs_unmount(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	libfs_unmount(&ext2fs_libfs_ops, rid, request);
+}
+
+void ext2fs_lookup(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	libfs_lookup(&ext2fs_libfs_ops, ext2fs_reg.fs_handle, rid, request);
+}
+
+void ext2fs_read(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+	aoff64_t pos =
+	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
+	
+	ext2fs_instance_t *inst;
+	ext2_inode_ref_t *inode_ref;
+	int rc;
+	ext2_directory_iterator_t it;
+	aoff64_t cur;
+	uint8_t *buf;
+	size_t name_size;
+
+	/*
+	 * Receive the read request.
+	 */
+	ipc_callid_t callid;
+	size_t size;
+	if (!async_data_read_receive(&callid, &size)) {
+		async_answer_0(callid, EINVAL);
+		async_answer_0(rid, EINVAL);
+		return;
+	}
+	
+	rc = ext2fs_instance_get(devmap_handle, &inst);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	rc = ext2_filesystem_get_inode_ref(inst->filesystem, index, &inode_ref);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	if (ext2_inode_is_type(inst->filesystem->superblock, inode_ref->inode,
+		    EXT2_INODE_MODE_FILE)) {
+		async_answer_0(callid, ENOTSUP);
+		async_answer_0(rid, ENOTSUP);
+	}
+	else if (ext2_inode_is_type(inst->filesystem->superblock, inode_ref->inode,
+		    EXT2_INODE_MODE_DIRECTORY)) {
+		rc = ext2_directory_iterator_init(&it, inst->filesystem, inode_ref);
+		if (rc != EOK) {
+			async_answer_0(callid, rc);
+			async_answer_0(rid, rc);
+			return;
+		}
+		
+		cur = 0;
+		while (it.current != NULL) {
+			if (it.current->inode != 0) {
+				if (cur == pos) {
+					// This is the dir entry we want to read
+					name_size = ext2_directory_entry_ll_get_name_length(
+					    inst->filesystem->superblock, it.current);
+					// The on-disk entry does not contain \0 at the end
+					// end of entry name, so we copy it to new buffer
+					// and the \0 at the end
+					buf = malloc(name_size+1);
+					if (buf == NULL) {
+						ext2_directory_iterator_fini(&it);
+						async_answer_0(callid, ENOMEM);
+						async_answer_0(rid, ENOMEM);
+						return;
+					}
+					memcpy(buf, &it.current->name, name_size);
+					*(buf+name_size) = 0;
+					(void) async_data_read_finalize(callid, buf, name_size+1);
+					break;
+				}
+				cur++;
+			}
+			
+			rc = ext2_directory_iterator_next(&it);
+			if (rc != EOK) {
+				ext2_directory_iterator_fini(&it);
+				async_answer_0(callid, rc);
+				async_answer_0(rid, rc);
+				return;
+			}
+		}
+		
+		rc = ext2_directory_iterator_fini(&it);
+		if (rc != EOK) {
+			async_answer_0(rid, ENOMEM);
+			return;
+		}
+		
+		async_answer_1(rid, EOK, 1);		
+	}
+	
+	// Other inode types not supported
+	async_answer_0(callid, ENOTSUP);
 	async_answer_0(rid, ENOTSUP);
 }
 
-void ext2fs_mount(ipc_callid_t rid, ipc_call_t *request)
-{
-	libfs_mount(&ext2fs_libfs_ops, ext2fs_reg.fs_handle, rid, request);
-}
-
-void ext2fs_unmounted(ipc_callid_t rid, ipc_call_t *request)
-{
-//	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
-	// TODO
-	async_answer_0(rid, ENOTSUP);
-}
-
-void ext2fs_unmount(ipc_callid_t rid, ipc_call_t *request)
-{
-	libfs_unmount(&ext2fs_libfs_ops, rid, request);
-}
-
-void ext2fs_lookup(ipc_callid_t rid, ipc_call_t *request)
-{
-	libfs_lookup(&ext2fs_libfs_ops, ext2fs_reg.fs_handle, rid, request);
-}
-
-void ext2fs_read(ipc_callid_t rid, ipc_call_t *request)
-{
+void ext2fs_write(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
 //	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
 //	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
@@ -328,17 +670,7 @@
 }
 
-void ext2fs_write(ipc_callid_t rid, ipc_call_t *request)
-{
-//	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
-//	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
-//	aoff64_t pos =
-//	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
-	
-	// TODO
-	async_answer_0(rid, ENOTSUP);
-}
-
 void ext2fs_truncate(ipc_callid_t rid, ipc_call_t *request)
 {
+	EXT2FS_DBG("");
 //	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
 //	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
@@ -352,4 +684,5 @@
 void ext2fs_close(ipc_callid_t rid, ipc_call_t *request)
 {
+	EXT2FS_DBG("");
 	async_answer_0(rid, EOK);
 }
@@ -357,4 +690,5 @@
 void ext2fs_destroy(ipc_callid_t rid, ipc_call_t *request)
 {
+	EXT2FS_DBG("");
 //	devmap_handle_t devmap_handle = (devmap_handle_t)IPC_GET_ARG1(*request);
 //	fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
@@ -366,4 +700,5 @@
 void ext2fs_open_node(ipc_callid_t rid, ipc_call_t *request)
 {
+	EXT2FS_DBG("");
 	libfs_open_node(&ext2fs_libfs_ops, ext2fs_reg.fs_handle, rid, request);
 }
@@ -371,4 +706,5 @@
 void ext2fs_stat(ipc_callid_t rid, ipc_call_t *request)
 {
+	EXT2FS_DBG("");
 	libfs_stat(&ext2fs_libfs_ops, ext2fs_reg.fs_handle, rid, request);
 }
@@ -376,4 +712,5 @@
 void ext2fs_sync(ipc_callid_t rid, ipc_call_t *request)
 {
+	EXT2FS_DBG("");
 //	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
 //	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
