shithub: lwext4

Download patch

ref: c897dc5a646527c2b87e4bc0399db59b46edbb1d
parent: 00affc044c56435a81fe070a53729c0f6fcbdc08
author: gkostka <kostka.grzegorz@gmail.com>
date: Wed Sep 16 19:46:35 EDT 2015

Linux line-endings

--- a/lwext4/CMakeLists.txt
+++ b/lwext4/CMakeLists.txt
@@ -1,8 +1,8 @@
-
-#LIBRARY
-include_directories(.)
-aux_source_directory(. LWEXT4_SRC)
-add_library(lwext4  ${LWEXT4_SRC})
-add_custom_target(lib_size ALL DEPENDS lwext4 COMMAND ${SIZE} liblwext4.a)
-
-
+
+#LIBRARY
+include_directories(.)
+aux_source_directory(. LWEXT4_SRC)
+add_library(lwext4  ${LWEXT4_SRC})
+add_custom_target(lib_size ALL DEPENDS lwext4 COMMAND ${SIZE} liblwext4.a)
+
+
--- a/lwext4/ext4.c
+++ b/lwext4/ext4.c
@@ -1,1927 +1,1927 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file  ext4.h
- * @brief Ext4 high level operations (file, directory, mountpoints...)
- */
-
-#include "ext4_config.h"
-#include "ext4_blockdev.h"
-#include "ext4_types.h"
-#include "ext4_debug.h"
-#include "ext4_errno.h"
-#include "ext4_fs.h"
-#include "ext4_dir.h"
-#include "ext4_inode.h"
-#include "ext4_super.h"
-#include "ext4_dir_idx.h"
-#include "ext4.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-/**@brief   Mount point OS dependent lock*/
-#define EXT4_MP_LOCK(_m)                                                       \
-	do {                                                                   \
-		if ((_m)->os_locks)                                            \
-			(_m)->os_locks->lock();                                \
-	} while (0)
-
-/**@brief   Mount point OS dependent unlock*/
-#define EXT4_MP_UNLOCK(_m)                                                     \
-	do {                                                                   \
-		if ((_m)->os_locks)                                            \
-			(_m)->os_locks->unlock();                              \
-	} while (0)
-
-/**@brief   Mount point descriptor.*/
-struct ext4_mountpoint {
-
-	/**@brief   Mount done flag.*/
-	bool mounted;
-
-	/**@brief   Mount point name (@ref ext4_mount)*/
-	char name[32];
-
-	/**@brief   OS dependent lock/unlock functions.*/
-	const struct ext4_lock *os_locks;
-
-	/**@brief   Ext4 filesystem internals.*/
-	struct ext4_fs fs;
-
-	/**@brief   Dynamic allocation cache flag.*/
-	bool cache_dynamic;
-};
-
-/**@brief   Block devices descriptor.*/
-struct _ext4_devices {
-
-	/**@brief   Block device name (@ref ext4_device_register)*/
-	char name[32];
-
-	/**@brief   Block device handle.*/
-	struct ext4_blockdev *bd;
-
-	/**@brief   Block cache handle.*/
-	struct ext4_bcache *bc;
-};
-
-/**@brief   Block devices.*/
-struct _ext4_devices _bdevices[CONFIG_EXT4_BLOCKDEVS_COUNT];
-
-/**@brief   Mountpoints.*/
-struct ext4_mountpoint _mp[CONFIG_EXT4_MOUNTPOINTS_COUNT];
-
-int ext4_device_register(struct ext4_blockdev *bd, struct ext4_bcache *bc,
-			 const char *dev_name)
-{
-	uint32_t i;
-	ext4_assert(bd && dev_name);
-
-	for (i = 0; i < CONFIG_EXT4_BLOCKDEVS_COUNT; ++i) {
-		if (!_bdevices[i].bd) {
-			strcpy(_bdevices[i].name, dev_name);
-			_bdevices[i].bd = bd;
-			_bdevices[i].bc = bc;
-			return EOK;
-		}
-
-		if (!strcmp(_bdevices[i].name, dev_name))
-			return EOK;
-	}
-	return ENOSPC;
-}
-
-/****************************************************************************/
-
-static bool ext4_is_dots(const uint8_t *name, size_t name_size)
-{
-	if ((name_size == 1) && (name[0] == '.'))
-		return true;
-
-	if ((name_size == 2) && (name[0] == '.') && (name[1] == '.'))
-		return true;
-
-	return false;
-}
-
-static int ext4_has_children(bool *has_children, struct ext4_inode_ref *enode)
-{
-	struct ext4_fs *fs = enode->fs;
-
-	/* Check if node is directory */
-	if (!ext4_inode_is_type(&fs->sb, enode->inode,
-				EXT4_INODE_MODE_DIRECTORY)) {
-		*has_children = false;
-		return EOK;
-	}
-
-	struct ext4_directory_iterator it;
-	int rc = ext4_dir_iterator_init(&it, enode, 0);
-	if (rc != EOK)
-		return rc;
-
-	/* Find a non-empty directory entry */
-	bool found = false;
-	while (it.current != NULL) {
-		if (ext4_dir_entry_ll_get_inode(it.current) != 0) {
-			uint16_t name_size = ext4_dir_entry_ll_get_name_length(
-			    &fs->sb, it.current);
-			if (!ext4_is_dots(it.current->name, name_size)) {
-				found = true;
-				break;
-			}
-		}
-
-		rc = ext4_dir_iterator_next(&it);
-		if (rc != EOK) {
-			ext4_dir_iterator_fini(&it);
-			return rc;
-		}
-	}
-
-	rc = ext4_dir_iterator_fini(&it);
-	if (rc != EOK)
-		return rc;
-
-	*has_children = found;
-
-	return EOK;
-}
-
-static int ext4_link(struct ext4_mountpoint *mp, struct ext4_inode_ref *parent,
-		     struct ext4_inode_ref *child, const char *name,
-		     uint32_t name_len)
-{
-	/* Check maximum name length */
-	if (name_len > EXT4_DIRECTORY_FILENAME_LEN)
-		return EINVAL;
-
-	/* Add entry to parent directory */
-	int rc = ext4_dir_add_entry(parent, name, name_len, child);
-	if (rc != EOK)
-		return rc;
-
-	/* Fill new dir -> add '.' and '..' entries.
-	 * Also newly allocated inode should have 0 link count.
-	 */
-	if (ext4_inode_is_type(&mp->fs.sb, child->inode,
-			       EXT4_INODE_MODE_DIRECTORY) &&
-	    ext4_inode_get_links_count(child->inode) == 0) {
-		rc = ext4_dir_add_entry(child, ".", strlen("."), child);
-		if (rc != EOK) {
-			ext4_dir_remove_entry(parent, name, strlen(name));
-			return rc;
-		}
-
-		rc = ext4_dir_add_entry(child, "..", strlen(".."), parent);
-		if (rc != EOK) {
-			ext4_dir_remove_entry(parent, name, strlen(name));
-			ext4_dir_remove_entry(child, ".", strlen("."));
-			return rc;
-		}
-
-		/*New empty directory. Two links (. and ..) */
-		ext4_inode_set_links_count(child->inode, 2);
-
-#if CONFIG_DIR_INDEX_ENABLE
-		/* Initialize directory index if supported */
-		if (ext4_sb_has_feature_compatible(
-			&mp->fs.sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) {
-			rc = ext4_dir_dx_init(child);
-			if (rc != EOK)
-				return rc;
-
-			ext4_inode_set_flag(child->inode,
-					    EXT4_INODE_FLAG_INDEX);
-			child->dirty = true;
-		}
-#endif
-
-		ext4_fs_inode_links_count_inc(parent);
-		child->dirty = true;
-		parent->dirty = true;
-	} else {
-		if (ext4_inode_is_type(&mp->fs.sb, child->inode,
-				       EXT4_INODE_MODE_DIRECTORY)) {
-			/* FIXME: SO TRICKY. */
-			int has_flag_index = ext4_inode_has_flag(
-			    child->inode, EXT4_INODE_FLAG_INDEX);
-			struct ext4_directory_search_result result;
-			if (has_flag_index)
-				ext4_inode_clear_flag(child->inode,
-						      EXT4_INODE_FLAG_INDEX);
-
-			rc = ext4_dir_find_entry(&result, child, "..",
-						 strlen(".."));
-			if (has_flag_index)
-				ext4_inode_set_flag(child->inode,
-						    EXT4_INODE_FLAG_INDEX);
-
-			if (rc != EOK)
-				return EIO;
-
-			ext4_dir_entry_ll_set_inode(result.dentry,
-						    parent->index);
-			result.block.dirty = true;
-			rc = ext4_dir_destroy_result(child, &result);
-			if (rc != EOK)
-				return rc;
-
-			ext4_fs_inode_links_count_inc(parent);
-			parent->dirty = true;
-		} else {
-			ext4_fs_inode_links_count_inc(child);
-			child->dirty = true;
-		}
-	}
-
-	return rc;
-}
-
-static int ext4_unlink(struct ext4_mountpoint *mp,
-		       struct ext4_inode_ref *parent,
-		       struct ext4_inode_ref *child_inode_ref, const char *name,
-		       uint32_t name_len)
-{
-	bool has_children;
-	int rc = ext4_has_children(&has_children, child_inode_ref);
-	if (rc != EOK)
-		return rc;
-
-	/* Cannot unlink non-empty node */
-	if (has_children)
-		return ENOTSUP;
-
-	/* Remove entry from parent directory */
-	rc = ext4_dir_remove_entry(parent, name, name_len);
-	if (rc != EOK)
-		return rc;
-
-	bool is_dir = ext4_inode_is_type(&mp->fs.sb, child_inode_ref->inode,
-					 EXT4_INODE_MODE_DIRECTORY);
-
-	/* If directory - handle links from parent */
-	if (is_dir) {
-		// ext4_assert(ext4_inode_get_links_count(child_inode_ref->inode)
-		// == 1);
-		ext4_fs_inode_links_count_dec(parent);
-		parent->dirty = true;
-	}
-
-	/*
-	 * TODO: Update timestamps of the parent
-	 * (when we have wall-clock time).
-	 *
-	 * ext4_inode_set_change_inode_time(parent->inode, (uint32_t) now);
-	 * ext4_inode_set_modification_time(parent->inode, (uint32_t) now);
-	 * parent->dirty = true;
-	 */
-
-	/*
-	 * TODO: Update timestamp for inode.
-	 *
-	 * ext4_inode_set_change_inode_time(child_inode_ref->inode,
-	 *     (uint32_t) now);
-	 */
-	if (ext4_inode_get_links_count(child_inode_ref->inode)) {
-		ext4_fs_inode_links_count_dec(child_inode_ref);
-		child_inode_ref->dirty = true;
-	}
-
-	return EOK;
-}
-
-/****************************************************************************/
-
-int ext4_mount(const char *dev_name, const char *mount_point)
-{
-	ext4_assert(mount_point && dev_name);
-	int r;
-	int i;
-
-	uint32_t bsize;
-	struct ext4_blockdev *bd = 0;
-	struct ext4_bcache *bc = 0;
-	struct ext4_mountpoint *mp = 0;
-
-	if (mount_point[strlen(mount_point) - 1] != '/')
-		return ENOTSUP;
-
-	for (i = 0; i < CONFIG_EXT4_BLOCKDEVS_COUNT; ++i) {
-		if (_bdevices[i].name) {
-			if (!strcmp(dev_name, _bdevices[i].name)) {
-				bd = _bdevices[i].bd;
-				bc = _bdevices[i].bc;
-				break;
-			}
-		}
-	}
-
-	if (!bd)
-		return ENODEV;
-
-	for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) {
-		if (!_mp[i].mounted) {
-			strcpy(_mp[i].name, mount_point);
-			_mp[i].mounted = 1;
-			mp = &_mp[i];
-			break;
-		}
-
-		if (!strcmp(_mp[i].name, mount_point))
-			return EOK;
-	}
-
-	if (!mp)
-		return ENOMEM;
-
-	r = ext4_block_init(bd);
-	if (r != EOK)
-		return r;
-
-	r = ext4_fs_init(&mp->fs, bd);
-	if (r != EOK) {
-		ext4_block_fini(bd);
-		return r;
-	}
-
-	bsize = ext4_sb_get_block_size(&mp->fs.sb);
-	ext4_block_set_lb_size(bd, bsize);
-
-	mp->cache_dynamic = 0;
-
-	if (!bc) {
-		/*Automatic block cache alloc.*/
-		mp->cache_dynamic = 1;
-		bc = malloc(sizeof(struct ext4_bcache));
-
-		r = ext4_bcache_init_dynamic(bc, CONFIG_BLOCK_DEV_CACHE_SIZE,
-					     bsize);
-		if (r != EOK) {
-			free(bc);
-			ext4_block_fini(bd);
-			return r;
-		}
-	}
-
-	if (bsize != bc->itemsize)
-		return ENOTSUP;
-
-	/*Bind block cache to block device*/
-	r = ext4_block_bind_bcache(bd, bc);
-	if (r != EOK) {
-		ext4_block_fini(bd);
-		if (mp->cache_dynamic) {
-			ext4_bcache_fini_dynamic(bc);
-			free(bc);
-		}
-		return r;
-	}
-
-	return r;
-}
-
-int ext4_umount(const char *mount_point)
-{
-	int i;
-	int r;
-	struct ext4_mountpoint *mp = 0;
-
-	for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) {
-		if (!strcmp(_mp[i].name, mount_point)) {
-			mp = &_mp[i];
-			break;
-		}
-	}
-
-	if (!mp)
-		return ENODEV;
-
-	r = ext4_fs_fini(&mp->fs);
-	if (r != EOK)
-		return r;
-
-	mp->mounted = 0;
-
-	if (mp->cache_dynamic) {
-		ext4_bcache_fini_dynamic(mp->fs.bdev->bc);
-		free(mp->fs.bdev->bc);
-	}
-
-	return ext4_block_fini(mp->fs.bdev);
-}
-
-int ext4_mount_point_stats(const char *mount_point,
-			   struct ext4_mount_stats *stats)
-{
-	uint32_t i;
-	struct ext4_mountpoint *mp = 0;
-
-	for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) {
-		if (!strcmp(_mp[i].name, mount_point)) {
-			mp = &_mp[i];
-			break;
-		}
-	}
-	if (!mp)
-		return ENOENT;
-
-	EXT4_MP_LOCK(mp);
-	stats->inodes_count = ext4_get32(&mp->fs.sb, inodes_count);
-	stats->free_inodes_count = ext4_get32(&mp->fs.sb, free_inodes_count);
-	stats->blocks_count = ext4_sb_get_blocks_cnt(&mp->fs.sb);
-	stats->free_blocks_count = ext4_sb_get_free_blocks_cnt(&mp->fs.sb);
-	stats->block_size = ext4_sb_get_block_size(&mp->fs.sb);
-
-	stats->block_group_count = ext4_block_group_cnt(&mp->fs.sb);
-	stats->blocks_per_group = ext4_get32(&mp->fs.sb, blocks_per_group);
-	stats->inodes_per_group = ext4_get32(&mp->fs.sb, inodes_per_group);
-
-	memcpy(stats->volume_name, mp->fs.sb.volume_name, 16);
-	EXT4_MP_UNLOCK(mp);
-
-	return EOK;
-}
-
-int ext4_mount_setup_locks(const char *mount_point,
-			   const struct ext4_lock *locks)
-{
-	uint32_t i;
-	struct ext4_mountpoint *mp = 0;
-
-	for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) {
-		if (!strcmp(_mp[i].name, mount_point)) {
-			mp = &_mp[i];
-			break;
-		}
-	}
-	if (!mp)
-		return ENOENT;
-
-	mp->os_locks = locks;
-	return EOK;
-}
-
-/********************************FILE OPERATIONS*****************************/
-
-static struct ext4_mountpoint *ext4_get_mount(const char *path)
-{
-	int i;
-	for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) {
-
-		if (!_mp[i].mounted)
-			continue;
-
-		if (!strncmp(_mp[i].name, path, strlen(_mp[i].name)))
-			return &_mp[i];
-	}
-	return 0;
-}
-
-static int ext4_path_check(const char *path, bool *is_goal)
-{
-	int i;
-
-	for (i = 0; i < EXT4_DIRECTORY_FILENAME_LEN; ++i) {
-
-		if (path[i] == '/') {
-			*is_goal = false;
-			return i;
-		}
-
-		if (path[i] == 0) {
-			*is_goal = true;
-			return i;
-		}
-	}
-
-	return 0;
-}
-
-static bool ext4_parse_flags(const char *flags, uint32_t *file_flags)
-{
-	if (!flags)
-		return false;
-
-	if (!strcmp(flags, "r") || !strcmp(flags, "rb")) {
-		*file_flags = O_RDONLY;
-		return true;
-	}
-
-	if (!strcmp(flags, "w") || !strcmp(flags, "wb")) {
-		*file_flags = O_WRONLY | O_CREAT | O_TRUNC;
-		return true;
-	}
-
-	if (!strcmp(flags, "a") || !strcmp(flags, "ab")) {
-		*file_flags = O_WRONLY | O_CREAT | O_APPEND;
-		return true;
-	}
-
-	if (!strcmp(flags, "r+") || !strcmp(flags, "rb+") ||
-	    !strcmp(flags, "r+b")) {
-		*file_flags = O_RDWR;
-		return true;
-	}
-
-	if (!strcmp(flags, "w+") || !strcmp(flags, "wb+") ||
-	    !strcmp(flags, "w+b")) {
-		*file_flags = O_RDWR | O_CREAT | O_TRUNC;
-		return true;
-	}
-
-	if (!strcmp(flags, "a+") || !strcmp(flags, "ab+") ||
-	    !strcmp(flags, "a+b")) {
-		*file_flags = O_RDWR | O_CREAT | O_APPEND;
-		return true;
-	}
-
-	return false;
-}
-
-/*
- * NOTICE: if filetype is equal to EXT4_DIRECTORY_FILETYPE_UNKNOWN,
- * any filetype of the target dir entry will be accepted.
- */
-static int ext4_generic_open2(ext4_file *f, const char *path, int flags,
-			      int filetype, uint32_t *parent_inode,
-			      uint32_t *name_off)
-{
-	bool is_goal = false;
-	uint8_t inode_type = EXT4_DIRECTORY_FILETYPE_DIR;
-	uint32_t next_inode;
-
-	int r;
-	struct ext4_mountpoint *mp = ext4_get_mount(path);
-	struct ext4_directory_search_result result;
-	struct ext4_inode_ref ref;
-
-	f->mp = 0;
-
-	if (!mp)
-		return ENOENT;
-
-	f->flags = flags;
-
-	/*Skip mount point*/
-	path += strlen(mp->name);
-
-	if (name_off)
-		*name_off = strlen(mp->name);
-
-	/*Load root*/
-	r = ext4_fs_get_inode_ref(&mp->fs, EXT4_INODE_ROOT_INDEX, &ref);
-
-	if (r != EOK)
-		return r;
-
-	if (parent_inode)
-		*parent_inode = ref.index;
-
-	int len = ext4_path_check(path, &is_goal);
-
-	while (1) {
-
-		len = ext4_path_check(path, &is_goal);
-
-		if (!len) {
-			/*If root open was request.*/
-			if (is_goal &&
-			    ((filetype == EXT4_DIRECTORY_FILETYPE_DIR) ||
-			     (filetype == EXT4_DIRECTORY_FILETYPE_UNKNOWN)))
-				break;
-
-			r = ENOENT;
-			break;
-		}
-
-		r = ext4_dir_find_entry(&result, &ref, path, len);
-		if (r != EOK) {
-
-			if (r != ENOENT)
-				break;
-
-			if (!(f->flags & O_CREAT))
-				break;
-
-			/*O_CREAT allows create new entry*/
-			struct ext4_inode_ref child_ref;
-			r = ext4_fs_alloc_inode(
-			    &mp->fs, &child_ref,
-			    is_goal ? (filetype == EXT4_DIRECTORY_FILETYPE_DIR)
-				    : true);
-			if (r != EOK)
-				break;
-
-			/*Destroy last result*/
-			ext4_dir_destroy_result(&ref, &result);
-
-			/*Link with root dir.*/
-			r = ext4_link(mp, &ref, &child_ref, path, len);
-			if (r != EOK) {
-				/*Fail. Free new inode.*/
-				ext4_fs_free_inode(&child_ref);
-				/*We do not want to write new inode.
-				  But block has to be released.*/
-				child_ref.dirty = false;
-				ext4_fs_put_inode_ref(&child_ref);
-				break;
-			}
-
-			ext4_fs_put_inode_ref(&child_ref);
-
-			continue;
-		}
-
-		if (parent_inode)
-			*parent_inode = ref.index;
-
-		next_inode = ext4_dir_entry_ll_get_inode(result.dentry);
-		inode_type =
-		    ext4_dir_entry_ll_get_inode_type(&mp->fs.sb, result.dentry);
-
-		r = ext4_dir_destroy_result(&ref, &result);
-		if (r != EOK)
-			break;
-
-		/*If expected file error*/
-		if (inode_type != EXT4_DIRECTORY_FILETYPE_DIR && !is_goal) {
-			r = ENOENT;
-			break;
-		}
-		if (filetype != EXT4_DIRECTORY_FILETYPE_UNKNOWN) {
-			if ((inode_type != filetype) && is_goal) {
-				r = ENOENT;
-				break;
-			}
-		}
-
-		r = ext4_fs_put_inode_ref(&ref);
-		if (r != EOK)
-			break;
-
-		r = ext4_fs_get_inode_ref(&mp->fs, next_inode, &ref);
-		if (r != EOK)
-			break;
-
-		if (is_goal)
-			break;
-
-		path += len + 1;
-
-		if (name_off)
-			*name_off += len + 1;
-	};
-
-	if (r != EOK) {
-		ext4_fs_put_inode_ref(&ref);
-		return r;
-	}
-
-	if (is_goal) {
-
-		if ((f->flags & O_TRUNC) &&
-		    (inode_type == EXT4_DIRECTORY_FILETYPE_REG_FILE)) {
-
-			r = ext4_fs_truncate_inode(&ref, 0);
-			if (r != EOK) {
-				ext4_fs_put_inode_ref(&ref);
-				return r;
-			}
-		}
-
-		f->mp = mp;
-		f->fsize = ext4_inode_get_size(&f->mp->fs.sb, ref.inode);
-		f->inode = ref.index;
-		f->fpos = 0;
-
-		if (f->flags & O_APPEND)
-			f->fpos = f->fsize;
-	}
-
-	r = ext4_fs_put_inode_ref(&ref);
-	return r;
-}
-
-/****************************************************************************/
-
-static int ext4_generic_open(ext4_file *f, const char *path, const char *flags,
-			     bool file_expect, uint32_t *parent_inode,
-			     uint32_t *name_off)
-{
-	uint32_t iflags;
-	int filetype;
-	if (ext4_parse_flags(flags, &iflags) == false)
-		return EINVAL;
-
-	if (file_expect == true)
-		filetype = EXT4_DIRECTORY_FILETYPE_REG_FILE;
-	else
-		filetype = EXT4_DIRECTORY_FILETYPE_DIR;
-
-	return ext4_generic_open2(f, path, iflags, filetype, parent_inode,
-				  name_off);
-}
-
-static int __ext4_create_hardlink(const char *path,
-				  struct ext4_inode_ref *child_ref)
-{
-	bool is_goal = false;
-	uint8_t inode_type = EXT4_DIRECTORY_FILETYPE_DIR;
-	uint32_t next_inode;
-
-	int r;
-	struct ext4_mountpoint *mp = ext4_get_mount(path);
-	struct ext4_directory_search_result result;
-	struct ext4_inode_ref ref;
-
-	if (!mp)
-		return ENOENT;
-
-	/*Skip mount point*/
-	path += strlen(mp->name);
-
-	/*Load root*/
-	r = ext4_fs_get_inode_ref(&mp->fs, EXT4_INODE_ROOT_INDEX, &ref);
-
-	if (r != EOK)
-		return r;
-
-	int len = ext4_path_check(path, &is_goal);
-
-	while (1) {
-
-		len = ext4_path_check(path, &is_goal);
-
-		if (!len) {
-			/*If root open was request.*/
-			if (is_goal)
-				r = EINVAL;
-			else
-				r = ENOENT;
-			break;
-		}
-
-		r = ext4_dir_find_entry(&result, &ref, path, len);
-		if (r != EOK) {
-
-			if (r != ENOENT || !is_goal)
-				break;
-
-			/*Destroy last result*/
-			ext4_dir_destroy_result(&ref, &result);
-
-			/*Link with root dir.*/
-			r = ext4_link(mp, &ref, child_ref, path, len);
-			break;
-		}
-
-		next_inode = ext4_dir_entry_ll_get_inode(result.dentry);
-		inode_type =
-		    ext4_dir_entry_ll_get_inode_type(&mp->fs.sb, result.dentry);
-
-		r = ext4_dir_destroy_result(&ref, &result);
-		if (r != EOK)
-			break;
-
-		if (inode_type == EXT4_DIRECTORY_FILETYPE_REG_FILE) {
-			if (is_goal)
-				r = EEXIST;
-			else
-				r = ENOENT;
-
-			break;
-		}
-
-		r = ext4_fs_put_inode_ref(&ref);
-		if (r != EOK)
-			break;
-
-		r = ext4_fs_get_inode_ref(&mp->fs, next_inode, &ref);
-		if (r != EOK)
-			break;
-
-		if (is_goal)
-			break;
-
-		path += len + 1;
-	};
-
-	if (r != EOK) {
-		ext4_fs_put_inode_ref(&ref);
-		return r;
-	}
-
-	r = ext4_fs_put_inode_ref(&ref);
-	return r;
-}
-
-static int __ext4_get_inode_ref_remove_hardlink(const char *path,
-						struct ext4_inode_ref *child)
-{
-	ext4_file f;
-	uint32_t parent_inode;
-	uint32_t name_off;
-	bool is_goal;
-	int r;
-	int len;
-	struct ext4_inode_ref parent;
-	struct ext4_mountpoint *mp = ext4_get_mount(path);
-
-	if (!mp)
-		return ENOENT;
-
-	r = ext4_generic_open2(&f, path, O_RDONLY,
-			       EXT4_DIRECTORY_FILETYPE_UNKNOWN, &parent_inode,
-			       &name_off);
-	if (r != EOK)
-		return r;
-
-	/*Load parent*/
-	r = ext4_fs_get_inode_ref(&mp->fs, parent_inode, &parent);
-	if (r != EOK) {
-		return r;
-	}
-
-	/*We have file to unlink. Load it.*/
-	r = ext4_fs_get_inode_ref(&mp->fs, f.inode, child);
-	if (r != EOK) {
-		ext4_fs_put_inode_ref(&parent);
-		return r;
-	}
-
-	if (r != EOK)
-		goto Finish;
-
-	/*Set path*/
-	path += name_off;
-
-	len = ext4_path_check(path, &is_goal);
-
-	/*Unlink from parent*/
-	r = ext4_unlink(mp, &parent, child, path, len);
-	if (r != EOK)
-		goto Finish;
-
-Finish:
-	if (r != EOK)
-		ext4_fs_put_inode_ref(child);
-
-	ext4_fs_put_inode_ref(&parent);
-	return r;
-}
-
-int ext4_frename(const char *path, const char *new_path)
-{
-	int r;
-	struct ext4_mountpoint *mp = ext4_get_mount(path);
-	struct ext4_inode_ref inode_ref;
-
-	if (!mp)
-		return ENOENT;
-
-	EXT4_MP_LOCK(mp);
-
-	r = __ext4_get_inode_ref_remove_hardlink(path, &inode_ref);
-	if (r != EOK)
-		goto Finish;
-
-	r = __ext4_create_hardlink(new_path, &inode_ref);
-	if (r != EOK)
-		r = __ext4_create_hardlink(path, &inode_ref);
-
-	ext4_fs_put_inode_ref(&inode_ref);
-
-Finish:
-	EXT4_MP_UNLOCK(mp);
-	return r;
-}
-
-/****************************************************************************/
-
-int ext4_get_sblock(const char *mount_point, struct ext4_sblock **sb)
-{
-	struct ext4_mountpoint *mp = ext4_get_mount(mount_point);
-
-	if (!mp)
-		return ENOENT;
-
-	*sb = &mp->fs.sb;
-	return EOK;
-}
-
-int ext4_cache_write_back(const char *path, bool on)
-{
-	struct ext4_mountpoint *mp = ext4_get_mount(path);
-
-	if (!mp)
-		return ENOENT;
-
-	EXT4_MP_LOCK(mp);
-	ext4_block_cache_write_back(mp->fs.bdev, on);
-	EXT4_MP_UNLOCK(mp);
-	return EOK;
-}
-
-int ext4_fremove(const char *path)
-{
-	ext4_file f;
-	uint32_t parent_inode;
-	uint32_t name_off;
-	bool is_goal;
-	int r;
-	int len;
-	struct ext4_inode_ref child;
-	struct ext4_inode_ref parent;
-	struct ext4_mountpoint *mp = ext4_get_mount(path);
-
-	if (!mp)
-		return ENOENT;
-
-	EXT4_MP_LOCK(mp);
-	r = ext4_generic_open(&f, path, "r", true, &parent_inode, &name_off);
-	if (r != EOK) {
-		EXT4_MP_UNLOCK(mp);
-		return r;
-	}
-
-	/*Load parent*/
-	r = ext4_fs_get_inode_ref(&mp->fs, parent_inode, &parent);
-	if (r != EOK) {
-		EXT4_MP_UNLOCK(mp);
-		return r;
-	}
-
-	/*We have file to delete. Load it.*/
-	r = ext4_fs_get_inode_ref(&mp->fs, f.inode, &child);
-	if (r != EOK) {
-		ext4_fs_put_inode_ref(&parent);
-		EXT4_MP_UNLOCK(mp);
-		return r;
-	}
-
-	/*Set path*/
-	path += name_off;
-
-	len = ext4_path_check(path, &is_goal);
-
-	/*Unlink from parent*/
-	r = ext4_unlink(mp, &parent, &child, path, len);
-	if (r != EOK)
-		goto Finish;
-
-	/*Link count is zero, the inode should be freed. */
-	if (!ext4_inode_get_links_count(child.inode)) {
-		printf("ttttt\n");
-		ext4_inode_set_deletion_time(child.inode, 0xFFFFFFFF);
-		/*Turncate*/
-		ext4_block_cache_write_back(mp->fs.bdev, 1);
-		/*Truncate may be IO heavy. Do it writeback cache mode.*/
-		r = ext4_fs_truncate_inode(&child, 0);
-		ext4_block_cache_write_back(mp->fs.bdev, 0);
-
-		if (r != EOK)
-			goto Finish;
-
-		r = ext4_fs_free_inode(&child);
-		if (r != EOK)
-			goto Finish;
-	}
-
-Finish:
-	ext4_fs_put_inode_ref(&child);
-	ext4_fs_put_inode_ref(&parent);
-	EXT4_MP_UNLOCK(mp);
-	return r;
-}
-
-int ext4_fill_raw_inode(const char *mount_point, uint32_t ino,
-			struct ext4_inode *inode)
-{
-	int r;
-	struct ext4_inode_ref inode_ref;
-	struct ext4_mountpoint *mp = ext4_get_mount(mount_point);
-
-	if (!mp)
-		return ENOENT;
-
-	EXT4_MP_LOCK(mp);
-
-	/*Load parent*/
-	r = ext4_fs_get_inode_ref(&mp->fs, ino, &inode_ref);
-	if (r != EOK) {
-		EXT4_MP_UNLOCK(mp);
-		return r;
-	}
-
-	memcpy(inode, inode_ref.inode, sizeof(struct ext4_inode));
-
-	ext4_fs_put_inode_ref(&inode_ref);
-	EXT4_MP_UNLOCK(mp);
-	return r;
-}
-
-int ext4_fopen(ext4_file *f, const char *path, const char *flags)
-{
-	struct ext4_mountpoint *mp = ext4_get_mount(path);
-	int r;
-
-	if (!mp)
-		return ENOENT;
-
-	EXT4_MP_LOCK(mp);
-	ext4_block_cache_write_back(mp->fs.bdev, 1);
-	r = ext4_generic_open(f, path, flags, true, 0, 0);
-	ext4_block_cache_write_back(mp->fs.bdev, 0);
-	EXT4_MP_UNLOCK(mp);
-	return r;
-}
-
-int ext4_fopen2(ext4_file *f, const char *path, int flags, bool file_expect)
-{
-	struct ext4_mountpoint *mp = ext4_get_mount(path);
-	int r;
-	int filetype;
-
-	if (!mp)
-		return ENOENT;
-
-	if (file_expect == true)
-		filetype = EXT4_DIRECTORY_FILETYPE_REG_FILE;
-	else
-		filetype = EXT4_DIRECTORY_FILETYPE_DIR;
-
-	EXT4_MP_LOCK(mp);
-	ext4_block_cache_write_back(mp->fs.bdev, 1);
-	r = ext4_generic_open2(f, path, flags, filetype, 0, 0);
-	ext4_block_cache_write_back(mp->fs.bdev, 0);
-	EXT4_MP_UNLOCK(mp);
-	return r;
-}
-
-int ext4_fclose(ext4_file *f)
-{
-	ext4_assert(f && f->mp);
-
-	f->mp = 0;
-	f->flags = 0;
-	f->inode = 0;
-	f->fpos = f->fsize = 0;
-
-	return EOK;
-}
-
-int ext4_ftruncate(ext4_file *f, uint64_t size)
-{
-	struct ext4_inode_ref ref;
-	int r;
-
-	ext4_assert(f && f->mp);
-
-	if (f->flags & O_RDONLY)
-		return EPERM;
-
-	EXT4_MP_LOCK(f->mp);
-
-	r = ext4_fs_get_inode_ref(&f->mp->fs, f->inode, &ref);
-	if (r != EOK) {
-		EXT4_MP_UNLOCK(f->mp);
-		return r;
-	}
-
-	/*Sync file size*/
-	f->fsize = ext4_inode_get_size(&f->mp->fs.sb, ref.inode);
-	if (f->fsize <= size) {
-		r = EOK;
-		goto Finish;
-	}
-
-	/*Start write back cache mode.*/
-	r = ext4_block_cache_write_back(f->mp->fs.bdev, 1);
-	if (r != EOK)
-		goto Finish;
-
-	r = ext4_fs_truncate_inode(&ref, size);
-	if (r != EOK)
-		goto Finish;
-
-	f->fsize = size;
-	if (f->fpos > size)
-		f->fpos = size;
-
-	/*Stop write back cache mode*/
-	ext4_block_cache_write_back(f->mp->fs.bdev, 0);
-
-	if (r != EOK)
-		goto Finish;
-
-Finish:
-	ext4_fs_put_inode_ref(&ref);
-	EXT4_MP_UNLOCK(f->mp);
-	return r;
-}
-
-int ext4_fread(ext4_file *f, void *buf, uint32_t size, uint32_t *rcnt)
-{
-	uint32_t u;
-	uint32_t fblock;
-	uint32_t fblock_start;
-	uint32_t fblock_cnt;
-	uint32_t sblock;
-	uint32_t sblock_end;
-	uint32_t block_size;
-	uint8_t *u8_buf = buf;
-	int r;
-	struct ext4_block b;
-	struct ext4_inode_ref ref;
-
-	ext4_assert(f && f->mp);
-
-	if (f->flags & O_WRONLY)
-		return EPERM;
-
-	if (!size)
-		return EOK;
-
-	EXT4_MP_LOCK(f->mp);
-
-	if (rcnt)
-		*rcnt = 0;
-
-	r = ext4_fs_get_inode_ref(&f->mp->fs, f->inode, &ref);
-	if (r != EOK) {
-		EXT4_MP_UNLOCK(f->mp);
-		return r;
-	}
-
-	/*Sync file size*/
-	f->fsize = ext4_inode_get_size(&f->mp->fs.sb, ref.inode);
-
-	block_size = ext4_sb_get_block_size(&f->mp->fs.sb);
-	size = size > (f->fsize - f->fpos) ? (f->fsize - f->fpos) : size;
-	sblock = (f->fpos) / block_size;
-	sblock_end = (f->fpos + size) / block_size;
-	u = (f->fpos) % block_size;
-
-	if (u) {
-
-		uint32_t ll = size > (block_size - u) ? (block_size - u) : size;
-
-		r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
-		if (r != EOK)
-			goto Finish;
-
-		r = ext4_block_get(f->mp->fs.bdev, &b, fblock);
-		if (r != EOK)
-			goto Finish;
-
-		memcpy(u8_buf, b.data + u, ll);
-
-		r = ext4_block_set(f->mp->fs.bdev, &b);
-		if (r != EOK)
-			goto Finish;
-
-		u8_buf += ll;
-		size -= ll;
-		f->fpos += ll;
-
-		if (rcnt)
-			*rcnt += ll;
-
-		sblock++;
-	}
-
-	fblock_start = 0;
-	fblock_cnt = 0;
-	while (size >= block_size) {
-		while (sblock < sblock_end) {
-			r = ext4_fs_get_inode_data_block_index(&ref, sblock,
-							       &fblock);
-			if (r != EOK)
-				goto Finish;
-
-			sblock++;
-
-			if (!fblock_start) {
-				fblock_start = fblock;
-			}
-
-			if ((fblock_start + fblock_cnt) != fblock)
-				break;
-
-			fblock_cnt++;
-		}
-
-		r = ext4_blocks_get_direct(f->mp->fs.bdev, u8_buf, fblock_start,
-					   fblock_cnt);
-		if (r != EOK)
-			goto Finish;
-
-		size -= block_size * fblock_cnt;
-		u8_buf += block_size * fblock_cnt;
-		f->fpos += block_size * fblock_cnt;
-
-		if (rcnt)
-			*rcnt += block_size * fblock_cnt;
-
-		fblock_start = fblock;
-		fblock_cnt = 1;
-	}
-
-	if (size) {
-		r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
-		if (r != EOK)
-			goto Finish;
-
-		r = ext4_block_get(f->mp->fs.bdev, &b, fblock);
-		if (r != EOK)
-			goto Finish;
-
-		memcpy(u8_buf, b.data, size);
-
-		r = ext4_block_set(f->mp->fs.bdev, &b);
-		if (r != EOK)
-			goto Finish;
-
-		f->fpos += size;
-
-		if (rcnt)
-			*rcnt += size;
-	}
-
-Finish:
-	ext4_fs_put_inode_ref(&ref);
-	EXT4_MP_UNLOCK(f->mp);
-	return r;
-}
-
-int ext4_fwrite(ext4_file *f, const void *buf, uint32_t size, uint32_t *wcnt)
-{
-	uint32_t u;
-	uint32_t fblock;
-
-	uint32_t sblock;
-	uint32_t sblock_end;
-	uint32_t file_blocks;
-	uint32_t block_size;
-	uint32_t fblock_start;
-	uint32_t fblock_cnt;
-
-	struct ext4_block b;
-	struct ext4_inode_ref ref;
-	const uint8_t *u8_buf = buf;
-	int r;
-
-	ext4_assert(f && f->mp);
-
-	if (f->flags & O_RDONLY)
-		return EPERM;
-
-	if (!size)
-		return EOK;
-
-	EXT4_MP_LOCK(f->mp);
-
-	if (wcnt)
-		*wcnt = 0;
-
-	r = ext4_fs_get_inode_ref(&f->mp->fs, f->inode, &ref);
-	if (r != EOK) {
-		EXT4_MP_UNLOCK(f->mp);
-		return r;
-	}
-
-	/*Sync file size*/
-	f->fsize = ext4_inode_get_size(&f->mp->fs.sb, ref.inode);
-
-	block_size = ext4_sb_get_block_size(&f->mp->fs.sb);
-
-	sblock_end = (f->fpos + size) > f->fsize ? (f->fpos + size) : f->fsize;
-	sblock_end /= block_size;
-	file_blocks = (f->fsize / block_size);
-
-	if (f->fsize % block_size)
-		file_blocks++;
-
-	sblock = (f->fpos) / block_size;
-
-	u = (f->fpos) % block_size;
-
-	if (u) {
-		uint32_t ll = size > (block_size - u) ? (block_size - u) : size;
-
-		r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
-		if (r != EOK)
-			goto Finish;
-
-		r = ext4_block_get(f->mp->fs.bdev, &b, fblock);
-		if (r != EOK)
-			goto Finish;
-
-		memcpy(b.data + u, u8_buf, ll);
-		b.dirty = true;
-
-		r = ext4_block_set(f->mp->fs.bdev, &b);
-		if (r != EOK)
-			goto Finish;
-
-		u8_buf += ll;
-		size -= ll;
-		f->fpos += ll;
-
-		if (wcnt)
-			*wcnt += ll;
-
-		sblock++;
-	}
-
-	/*Start write back cache mode.*/
-	r = ext4_block_cache_write_back(f->mp->fs.bdev, 1);
-	if (r != EOK)
-		goto Finish;
-
-	fblock_start = 0;
-	fblock_cnt = 0;
-	while (size >= block_size) {
-
-		while (sblock < sblock_end) {
-			if (sblock < file_blocks) {
-				r = ext4_fs_get_inode_data_block_index(
-				    &ref, sblock, &fblock);
-				if (r != EOK)
-					break;
-			} else {
-				r = ext4_fs_append_inode_block(&ref, &fblock,
-							       &sblock);
-				if (r != EOK)
-					break;
-			}
-
-			sblock++;
-
-			if (!fblock_start) {
-				fblock_start = fblock;
-			}
-
-			if ((fblock_start + fblock_cnt) != fblock)
-				break;
-
-			fblock_cnt++;
-		}
-
-		r = ext4_blocks_set_direct(f->mp->fs.bdev, u8_buf, fblock_start,
-					   fblock_cnt);
-		if (r != EOK)
-			break;
-
-		size -= block_size * fblock_cnt;
-		u8_buf += block_size * fblock_cnt;
-		f->fpos += block_size * fblock_cnt;
-
-		if (wcnt)
-			*wcnt += block_size * fblock_cnt;
-
-		fblock_start = fblock;
-		fblock_cnt = 1;
-	}
-
-	/*Stop write back cache mode*/
-	ext4_block_cache_write_back(f->mp->fs.bdev, 0);
-
-	if (r != EOK)
-		goto Finish;
-
-	if (size) {
-		if (sblock < file_blocks) {
-			r = ext4_fs_get_inode_data_block_index(&ref, sblock,
-							       &fblock);
-			if (r != EOK)
-				goto Finish;
-		} else {
-			r = ext4_fs_append_inode_block(&ref, &fblock, &sblock);
-			if (r != EOK)
-				goto Finish;
-		}
-
-		r = ext4_block_get(f->mp->fs.bdev, &b, fblock);
-		if (r != EOK)
-			goto Finish;
-
-		memcpy(b.data, u8_buf, size);
-		b.dirty = true;
-
-		r = ext4_block_set(f->mp->fs.bdev, &b);
-		if (r != EOK)
-			goto Finish;
-
-		f->fpos += size;
-
-		if (wcnt)
-			*wcnt += size;
-	}
-
-	if (f->fpos > f->fsize) {
-		f->fsize = f->fpos;
-		ext4_inode_set_size(ref.inode, f->fsize);
-		ref.dirty = true;
-	}
-
-Finish:
-	ext4_fs_put_inode_ref(&ref);
-	EXT4_MP_UNLOCK(f->mp);
-	return r;
-}
-
-int ext4_fseek(ext4_file *f, uint64_t offset, uint32_t origin)
-{
-	switch (origin) {
-	case SEEK_SET:
-		if (offset > f->fsize)
-			return EINVAL;
-
-		f->fpos = offset;
-		return EOK;
-	case SEEK_CUR:
-		if ((offset + f->fpos) > f->fsize)
-			return EINVAL;
-
-		f->fpos += offset;
-		return EOK;
-	case SEEK_END:
-		if (offset > f->fsize)
-			return EINVAL;
-
-		f->fpos = f->fsize - offset;
-		return EOK;
-	}
-	return EINVAL;
-}
-
-uint64_t ext4_ftell(ext4_file *f) { return f->fpos; }
-
-uint64_t ext4_fsize(ext4_file *f) { return f->fsize; }
-
-int ext4_fchmod(ext4_file *f, uint32_t mode)
-{
-	int r;
-	uint32_t ino;
-	struct ext4_sblock *sb;
-	struct ext4_inode_ref inode_ref;
-	struct ext4_mountpoint *mp = f->mp;
-
-	if (!mp)
-		return ENOENT;
-
-	EXT4_MP_LOCK(mp);
-
-	ino = f->inode;
-	r = ext4_fs_get_inode_ref(&mp->fs, ino, &inode_ref);
-	if (r != EOK) {
-		EXT4_MP_UNLOCK(mp);
-		return r;
-	}
-
-	sb = &f->mp->fs.sb;
-	ext4_inode_set_mode(sb, inode_ref.inode, mode);
-	inode_ref.dirty = true;
-
-	ext4_fs_put_inode_ref(&inode_ref);
-	EXT4_MP_UNLOCK(mp);
-	return r;
-}
-
-int ext4_fchown(ext4_file *f, uint32_t uid, uint32_t gid)
-{
-	int r;
-	uint32_t ino;
-	struct ext4_inode_ref inode_ref;
-	struct ext4_mountpoint *mp = f->mp;
-
-	if (!mp)
-		return ENOENT;
-
-	EXT4_MP_LOCK(mp);
-
-	ino = f->inode;
-	r = ext4_fs_get_inode_ref(&mp->fs, ino, &inode_ref);
-	if (r != EOK) {
-		EXT4_MP_UNLOCK(mp);
-		return r;
-	}
-
-	ext4_inode_set_uid(inode_ref.inode, uid);
-	ext4_inode_set_gid(inode_ref.inode, gid);
-	inode_ref.dirty = true;
-
-	ext4_fs_put_inode_ref(&inode_ref);
-	EXT4_MP_UNLOCK(mp);
-	return r;
-}
-
-int ext4_file_set_atime(ext4_file *f, uint32_t atime)
-{
-	int r;
-	uint32_t ino;
-	struct ext4_inode_ref inode_ref;
-	struct ext4_mountpoint *mp = f->mp;
-
-	if (!mp)
-		return ENOENT;
-
-	EXT4_MP_LOCK(mp);
-
-	ino = f->inode;
-	r = ext4_fs_get_inode_ref(&mp->fs, ino, &inode_ref);
-	if (r != EOK) {
-		EXT4_MP_UNLOCK(mp);
-		return r;
-	}
-
-	ext4_inode_set_access_time(inode_ref.inode, atime);
-	inode_ref.dirty = true;
-
-	ext4_fs_put_inode_ref(&inode_ref);
-	EXT4_MP_UNLOCK(mp);
-	return r;
-}
-
-int ext4_file_set_mtime(ext4_file *f, uint32_t mtime)
-{
-	int r;
-	uint32_t ino;
-	struct ext4_inode_ref inode_ref;
-	struct ext4_mountpoint *mp = f->mp;
-
-	if (!mp)
-		return ENOENT;
-
-	EXT4_MP_LOCK(mp);
-
-	ino = f->inode;
-	r = ext4_fs_get_inode_ref(&mp->fs, ino, &inode_ref);
-	if (r != EOK) {
-		EXT4_MP_UNLOCK(mp);
-		return r;
-	}
-
-	ext4_inode_set_modification_time(inode_ref.inode, mtime);
-	inode_ref.dirty = true;
-
-	ext4_fs_put_inode_ref(&inode_ref);
-	EXT4_MP_UNLOCK(mp);
-	return r;
-}
-
-int ext4_file_set_ctime(ext4_file *f, uint32_t ctime)
-{
-	int r;
-	uint32_t ino;
-	struct ext4_inode_ref inode_ref;
-	struct ext4_mountpoint *mp = f->mp;
-
-	if (!mp)
-		return ENOENT;
-
-	EXT4_MP_LOCK(mp);
-
-	ino = f->inode;
-	r = ext4_fs_get_inode_ref(&mp->fs, ino, &inode_ref);
-	if (r != EOK) {
-		EXT4_MP_UNLOCK(mp);
-		return r;
-	}
-
-	ext4_inode_set_change_inode_time(inode_ref.inode, ctime);
-	inode_ref.dirty = true;
-
-	ext4_fs_put_inode_ref(&inode_ref);
-	EXT4_MP_UNLOCK(mp);
-	return r;
-}
-
-/*********************************DIRECTORY OPERATION************************/
-
-int ext4_dir_rm(const char *path)
-{
-	int r;
-	int len;
-	ext4_file f;
-
-	struct ext4_mountpoint *mp = ext4_get_mount(path);
-	struct ext4_inode_ref current;
-	struct ext4_inode_ref child;
-	struct ext4_directory_iterator it;
-
-	uint32_t name_off;
-	uint32_t inode_up;
-	uint32_t inode_current;
-	uint32_t depth = 1;
-
-	bool has_children;
-	bool is_goal;
-	bool dir_end;
-
-	if (!mp)
-		return ENOENT;
-
-	EXT4_MP_LOCK(mp);
-
-	/*Check if exist.*/
-	r = ext4_generic_open(&f, path, "r", false, &inode_up, &name_off);
-	if (r != EOK) {
-		EXT4_MP_UNLOCK(mp);
-		return r;
-	}
-
-	path += name_off;
-	len = ext4_path_check(path, &is_goal);
-
-	inode_current = f.inode;
-	dir_end = false;
-
-	ext4_block_cache_write_back(mp->fs.bdev, 1);
-
-	do {
-		/*Load directory node.*/
-		r = ext4_fs_get_inode_ref(&f.mp->fs, inode_current, &current);
-		if (r != EOK) {
-			break;
-		}
-
-		/*Initialize iterator.*/
-		r = ext4_dir_iterator_init(&it, &current, 0);
-		if (r != EOK) {
-			ext4_fs_put_inode_ref(&current);
-			break;
-		}
-
-		while (r == EOK) {
-
-			if (!it.current) {
-				dir_end = true;
-				break;
-			}
-
-			/*Get up directory inode when ".." entry*/
-			if ((it.current->name_length == 2) &&
-			    ext4_is_dots(it.current->name,
-					 it.current->name_length)) {
-				inode_up = ext4_dir_entry_ll_get_inode(it.current);
-			}
-
-			/*If directory or file entry,  but not "." ".." entry*/
-			if (!ext4_is_dots(it.current->name,
-					  it.current->name_length)) {
-
-				/*Get child inode reference do unlink
-				 * directory/file.*/
-				r = ext4_fs_get_inode_ref(&f.mp->fs,
-				        ext4_dir_entry_ll_get_inode(it.current),
-				        &child);
-				if (r != EOK)
-					break;
-
-				/*If directory with no leaf children*/
-				r = ext4_has_children(&has_children, &child);
-				if (r != EOK) {
-					ext4_fs_put_inode_ref(&child);
-					break;
-				}
-
-				if (has_children) {
-					/*Has directory children. Go into this
-					 * directory.*/
-					inode_up = inode_current;
-					inode_current = ext4_dir_entry_ll_get_inode(it.current);
-					depth++;
-					ext4_fs_put_inode_ref(&child);
-					break;
-				}
-
-				/*No children in child directory or file. Just
-				 * unlink.*/
-				r = ext4_unlink(f.mp, &current, &child,
-						(char *)it.current->name,
-						it.current->name_length);
-				if (r != EOK) {
-					ext4_fs_put_inode_ref(&child);
-					break;
-				}
-
-				ext4_inode_set_deletion_time(child.inode,
-							     0xFFFFFFFF);
-				ext4_inode_set_links_count(child.inode, 0);
-				child.dirty = true;
-				/*Turncate*/
-				r = ext4_fs_truncate_inode(&child, 0);
-				if (r != EOK) {
-					ext4_fs_put_inode_ref(&child);
-					break;
-				}
-
-				r = ext4_fs_free_inode(&child);
-				if (r != EOK) {
-					ext4_fs_put_inode_ref(&child);
-					break;
-				}
-
-				r = ext4_fs_put_inode_ref(&child);
-				if (r != EOK)
-					break;
-			}
-
-			r = ext4_dir_iterator_next(&it);
-		}
-
-		if (dir_end) {
-			/*Directory iterator reached last entry*/
-			ext4_has_children(&has_children, &current);
-			if (!has_children) {
-				inode_current = inode_up;
-				if (depth)
-					depth--;
-			}
-			/*Last unlink*/
-			if (!depth) {
-				/*Load parent.*/
-				struct ext4_inode_ref parent;
-				r = ext4_fs_get_inode_ref(&f.mp->fs, inode_up,
-							  &parent);
-				if (r != EOK)
-					goto End;
-
-				/* In this place all directories should be
-				 * unlinked.
-				 * Last unlink from root of current directory*/
-				r = ext4_unlink(f.mp, &parent, &current,
-						(char *)path, len);
-				if (r != EOK) {
-					ext4_fs_put_inode_ref(&parent);
-					goto End;
-				}
-
-				if (ext4_inode_get_links_count(current.inode) ==
-				    2) {
-					ext4_inode_set_deletion_time(
-					    current.inode, 0xFFFFFFFF);
-					ext4_inode_set_links_count(
-					    current.inode, 0);
-					current.dirty = true;
-					/*Turncate*/
-					r = ext4_fs_truncate_inode(&current, 0);
-					if (r != EOK) {
-						ext4_fs_put_inode_ref(&parent);
-						goto End;
-					}
-
-					r = ext4_fs_free_inode(&current);
-					if (r != EOK) {
-						ext4_fs_put_inode_ref(&parent);
-						goto End;
-					}
-				}
-
-				r = ext4_fs_put_inode_ref(&parent);
-				if (r != EOK)
-					goto End;
-			}
-		}
-
-	End:
-		ext4_dir_iterator_fini(&it);
-		ext4_fs_put_inode_ref(&current);
-		dir_end = false;
-
-		/*When something goes wrong. End loop.*/
-		if (r != EOK)
-			break;
-
-	} while (depth);
-
-	ext4_block_cache_write_back(mp->fs.bdev, 0);
-	EXT4_MP_UNLOCK(mp);
-	return r;
-}
-
-int ext4_dir_mk(const char *path)
-{
-	int r;
-	ext4_file f;
-
-	struct ext4_mountpoint *mp = ext4_get_mount(path);
-
-	if (!mp)
-		return ENOENT;
-
-	EXT4_MP_LOCK(mp);
-
-	/*Check if exist.*/
-	r = ext4_generic_open(&f, path, "r", false, 0, 0);
-	if (r == EOK) {
-		/*Directory already created*/
-		EXT4_MP_UNLOCK(mp);
-		return r;
-	}
-
-	/*Create new dir*/
-	r = ext4_generic_open(&f, path, "w", false, 0, 0);
-	if (r != EOK) {
-		EXT4_MP_UNLOCK(mp);
-		return r;
-	}
-
-	EXT4_MP_UNLOCK(mp);
-	return r;
-}
-
-int ext4_dir_open(ext4_dir *d, const char *path)
-{
-	struct ext4_mountpoint *mp = ext4_get_mount(path);
-	int r;
-
-	if (!mp)
-		return ENOENT;
-
-	EXT4_MP_LOCK(mp);
-	r = ext4_generic_open(&d->f, path, "r", false, 0, 0);
-	d->next_off = 0;
-	EXT4_MP_UNLOCK(mp);
-	return r;
-}
-
-int ext4_dir_close(ext4_dir *d) { return ext4_fclose(&d->f); }
-
-const ext4_direntry *ext4_dir_entry_next(ext4_dir *d)
-{
-#define EXT4_DIR_ENTRY_OFFSET_TERM (uint64_t)(-1)
-
-	int r;
-	ext4_direntry *de = 0;
-	struct ext4_inode_ref dir;
-	struct ext4_directory_iterator it;
-
-	EXT4_MP_LOCK(d->f.mp);
-
-	if (d->next_off == EXT4_DIR_ENTRY_OFFSET_TERM)
-		return 0;
-
-	r = ext4_fs_get_inode_ref(&d->f.mp->fs, d->f.inode, &dir);
-	if (r != EOK) {
-		goto Finish;
-	}
-
-	r = ext4_dir_iterator_init(&it, &dir, d->next_off);
-	if (r != EOK) {
-		ext4_fs_put_inode_ref(&dir);
-		goto Finish;
-	}
-
-	memcpy(&d->de, it.current, sizeof(ext4_direntry));
-	de = &d->de;
-
-	ext4_dir_iterator_next(&it);
-
-	d->next_off =
-	    it.current ? it.current_offset : EXT4_DIR_ENTRY_OFFSET_TERM;
-
-	ext4_dir_iterator_fini(&it);
-	ext4_fs_put_inode_ref(&dir);
-
-Finish:
-	EXT4_MP_UNLOCK(d->f.mp);
-	return de;
-}
-
-/**
- * @}
- */
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file  ext4.h
+ * @brief Ext4 high level operations (file, directory, mountpoints...)
+ */
+
+#include "ext4_config.h"
+#include "ext4_blockdev.h"
+#include "ext4_types.h"
+#include "ext4_debug.h"
+#include "ext4_errno.h"
+#include "ext4_fs.h"
+#include "ext4_dir.h"
+#include "ext4_inode.h"
+#include "ext4_super.h"
+#include "ext4_dir_idx.h"
+#include "ext4.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/**@brief   Mount point OS dependent lock*/
+#define EXT4_MP_LOCK(_m)                                                       \
+	do {                                                                   \
+		if ((_m)->os_locks)                                            \
+			(_m)->os_locks->lock();                                \
+	} while (0)
+
+/**@brief   Mount point OS dependent unlock*/
+#define EXT4_MP_UNLOCK(_m)                                                     \
+	do {                                                                   \
+		if ((_m)->os_locks)                                            \
+			(_m)->os_locks->unlock();                              \
+	} while (0)
+
+/**@brief   Mount point descriptor.*/
+struct ext4_mountpoint {
+
+	/**@brief   Mount done flag.*/
+	bool mounted;
+
+	/**@brief   Mount point name (@ref ext4_mount)*/
+	char name[32];
+
+	/**@brief   OS dependent lock/unlock functions.*/
+	const struct ext4_lock *os_locks;
+
+	/**@brief   Ext4 filesystem internals.*/
+	struct ext4_fs fs;
+
+	/**@brief   Dynamic allocation cache flag.*/
+	bool cache_dynamic;
+};
+
+/**@brief   Block devices descriptor.*/
+struct _ext4_devices {
+
+	/**@brief   Block device name (@ref ext4_device_register)*/
+	char name[32];
+
+	/**@brief   Block device handle.*/
+	struct ext4_blockdev *bd;
+
+	/**@brief   Block cache handle.*/
+	struct ext4_bcache *bc;
+};
+
+/**@brief   Block devices.*/
+struct _ext4_devices _bdevices[CONFIG_EXT4_BLOCKDEVS_COUNT];
+
+/**@brief   Mountpoints.*/
+struct ext4_mountpoint _mp[CONFIG_EXT4_MOUNTPOINTS_COUNT];
+
+int ext4_device_register(struct ext4_blockdev *bd, struct ext4_bcache *bc,
+			 const char *dev_name)
+{
+	uint32_t i;
+	ext4_assert(bd && dev_name);
+
+	for (i = 0; i < CONFIG_EXT4_BLOCKDEVS_COUNT; ++i) {
+		if (!_bdevices[i].bd) {
+			strcpy(_bdevices[i].name, dev_name);
+			_bdevices[i].bd = bd;
+			_bdevices[i].bc = bc;
+			return EOK;
+		}
+
+		if (!strcmp(_bdevices[i].name, dev_name))
+			return EOK;
+	}
+	return ENOSPC;
+}
+
+/****************************************************************************/
+
+static bool ext4_is_dots(const uint8_t *name, size_t name_size)
+{
+	if ((name_size == 1) && (name[0] == '.'))
+		return true;
+
+	if ((name_size == 2) && (name[0] == '.') && (name[1] == '.'))
+		return true;
+
+	return false;
+}
+
+static int ext4_has_children(bool *has_children, struct ext4_inode_ref *enode)
+{
+	struct ext4_fs *fs = enode->fs;
+
+	/* Check if node is directory */
+	if (!ext4_inode_is_type(&fs->sb, enode->inode,
+				EXT4_INODE_MODE_DIRECTORY)) {
+		*has_children = false;
+		return EOK;
+	}
+
+	struct ext4_directory_iterator it;
+	int rc = ext4_dir_iterator_init(&it, enode, 0);
+	if (rc != EOK)
+		return rc;
+
+	/* Find a non-empty directory entry */
+	bool found = false;
+	while (it.current != NULL) {
+		if (ext4_dir_entry_ll_get_inode(it.current) != 0) {
+			uint16_t name_size = ext4_dir_entry_ll_get_name_length(
+			    &fs->sb, it.current);
+			if (!ext4_is_dots(it.current->name, name_size)) {
+				found = true;
+				break;
+			}
+		}
+
+		rc = ext4_dir_iterator_next(&it);
+		if (rc != EOK) {
+			ext4_dir_iterator_fini(&it);
+			return rc;
+		}
+	}
+
+	rc = ext4_dir_iterator_fini(&it);
+	if (rc != EOK)
+		return rc;
+
+	*has_children = found;
+
+	return EOK;
+}
+
+static int ext4_link(struct ext4_mountpoint *mp, struct ext4_inode_ref *parent,
+		     struct ext4_inode_ref *child, const char *name,
+		     uint32_t name_len)
+{
+	/* Check maximum name length */
+	if (name_len > EXT4_DIRECTORY_FILENAME_LEN)
+		return EINVAL;
+
+	/* Add entry to parent directory */
+	int rc = ext4_dir_add_entry(parent, name, name_len, child);
+	if (rc != EOK)
+		return rc;
+
+	/* Fill new dir -> add '.' and '..' entries.
+	 * Also newly allocated inode should have 0 link count.
+	 */
+	if (ext4_inode_is_type(&mp->fs.sb, child->inode,
+			       EXT4_INODE_MODE_DIRECTORY) &&
+	    ext4_inode_get_links_count(child->inode) == 0) {
+		rc = ext4_dir_add_entry(child, ".", strlen("."), child);
+		if (rc != EOK) {
+			ext4_dir_remove_entry(parent, name, strlen(name));
+			return rc;
+		}
+
+		rc = ext4_dir_add_entry(child, "..", strlen(".."), parent);
+		if (rc != EOK) {
+			ext4_dir_remove_entry(parent, name, strlen(name));
+			ext4_dir_remove_entry(child, ".", strlen("."));
+			return rc;
+		}
+
+		/*New empty directory. Two links (. and ..) */
+		ext4_inode_set_links_count(child->inode, 2);
+
+#if CONFIG_DIR_INDEX_ENABLE
+		/* Initialize directory index if supported */
+		if (ext4_sb_has_feature_compatible(
+			&mp->fs.sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) {
+			rc = ext4_dir_dx_init(child);
+			if (rc != EOK)
+				return rc;
+
+			ext4_inode_set_flag(child->inode,
+					    EXT4_INODE_FLAG_INDEX);
+			child->dirty = true;
+		}
+#endif
+
+		ext4_fs_inode_links_count_inc(parent);
+		child->dirty = true;
+		parent->dirty = true;
+	} else {
+		if (ext4_inode_is_type(&mp->fs.sb, child->inode,
+				       EXT4_INODE_MODE_DIRECTORY)) {
+			/* FIXME: SO TRICKY. */
+			int has_flag_index = ext4_inode_has_flag(
+			    child->inode, EXT4_INODE_FLAG_INDEX);
+			struct ext4_directory_search_result result;
+			if (has_flag_index)
+				ext4_inode_clear_flag(child->inode,
+						      EXT4_INODE_FLAG_INDEX);
+
+			rc = ext4_dir_find_entry(&result, child, "..",
+						 strlen(".."));
+			if (has_flag_index)
+				ext4_inode_set_flag(child->inode,
+						    EXT4_INODE_FLAG_INDEX);
+
+			if (rc != EOK)
+				return EIO;
+
+			ext4_dir_entry_ll_set_inode(result.dentry,
+						    parent->index);
+			result.block.dirty = true;
+			rc = ext4_dir_destroy_result(child, &result);
+			if (rc != EOK)
+				return rc;
+
+			ext4_fs_inode_links_count_inc(parent);
+			parent->dirty = true;
+		} else {
+			ext4_fs_inode_links_count_inc(child);
+			child->dirty = true;
+		}
+	}
+
+	return rc;
+}
+
+static int ext4_unlink(struct ext4_mountpoint *mp,
+		       struct ext4_inode_ref *parent,
+		       struct ext4_inode_ref *child_inode_ref, const char *name,
+		       uint32_t name_len)
+{
+	bool has_children;
+	int rc = ext4_has_children(&has_children, child_inode_ref);
+	if (rc != EOK)
+		return rc;
+
+	/* Cannot unlink non-empty node */
+	if (has_children)
+		return ENOTSUP;
+
+	/* Remove entry from parent directory */
+	rc = ext4_dir_remove_entry(parent, name, name_len);
+	if (rc != EOK)
+		return rc;
+
+	bool is_dir = ext4_inode_is_type(&mp->fs.sb, child_inode_ref->inode,
+					 EXT4_INODE_MODE_DIRECTORY);
+
+	/* If directory - handle links from parent */
+	if (is_dir) {
+		// ext4_assert(ext4_inode_get_links_count(child_inode_ref->inode)
+		// == 1);
+		ext4_fs_inode_links_count_dec(parent);
+		parent->dirty = true;
+	}
+
+	/*
+	 * TODO: Update timestamps of the parent
+	 * (when we have wall-clock time).
+	 *
+	 * ext4_inode_set_change_inode_time(parent->inode, (uint32_t) now);
+	 * ext4_inode_set_modification_time(parent->inode, (uint32_t) now);
+	 * parent->dirty = true;
+	 */
+
+	/*
+	 * TODO: Update timestamp for inode.
+	 *
+	 * ext4_inode_set_change_inode_time(child_inode_ref->inode,
+	 *     (uint32_t) now);
+	 */
+	if (ext4_inode_get_links_count(child_inode_ref->inode)) {
+		ext4_fs_inode_links_count_dec(child_inode_ref);
+		child_inode_ref->dirty = true;
+	}
+
+	return EOK;
+}
+
+/****************************************************************************/
+
+int ext4_mount(const char *dev_name, const char *mount_point)
+{
+	ext4_assert(mount_point && dev_name);
+	int r;
+	int i;
+
+	uint32_t bsize;
+	struct ext4_blockdev *bd = 0;
+	struct ext4_bcache *bc = 0;
+	struct ext4_mountpoint *mp = 0;
+
+	if (mount_point[strlen(mount_point) - 1] != '/')
+		return ENOTSUP;
+
+	for (i = 0; i < CONFIG_EXT4_BLOCKDEVS_COUNT; ++i) {
+		if (_bdevices[i].name) {
+			if (!strcmp(dev_name, _bdevices[i].name)) {
+				bd = _bdevices[i].bd;
+				bc = _bdevices[i].bc;
+				break;
+			}
+		}
+	}
+
+	if (!bd)
+		return ENODEV;
+
+	for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) {
+		if (!_mp[i].mounted) {
+			strcpy(_mp[i].name, mount_point);
+			_mp[i].mounted = 1;
+			mp = &_mp[i];
+			break;
+		}
+
+		if (!strcmp(_mp[i].name, mount_point))
+			return EOK;
+	}
+
+	if (!mp)
+		return ENOMEM;
+
+	r = ext4_block_init(bd);
+	if (r != EOK)
+		return r;
+
+	r = ext4_fs_init(&mp->fs, bd);
+	if (r != EOK) {
+		ext4_block_fini(bd);
+		return r;
+	}
+
+	bsize = ext4_sb_get_block_size(&mp->fs.sb);
+	ext4_block_set_lb_size(bd, bsize);
+
+	mp->cache_dynamic = 0;
+
+	if (!bc) {
+		/*Automatic block cache alloc.*/
+		mp->cache_dynamic = 1;
+		bc = malloc(sizeof(struct ext4_bcache));
+
+		r = ext4_bcache_init_dynamic(bc, CONFIG_BLOCK_DEV_CACHE_SIZE,
+					     bsize);
+		if (r != EOK) {
+			free(bc);
+			ext4_block_fini(bd);
+			return r;
+		}
+	}
+
+	if (bsize != bc->itemsize)
+		return ENOTSUP;
+
+	/*Bind block cache to block device*/
+	r = ext4_block_bind_bcache(bd, bc);
+	if (r != EOK) {
+		ext4_block_fini(bd);
+		if (mp->cache_dynamic) {
+			ext4_bcache_fini_dynamic(bc);
+			free(bc);
+		}
+		return r;
+	}
+
+	return r;
+}
+
+int ext4_umount(const char *mount_point)
+{
+	int i;
+	int r;
+	struct ext4_mountpoint *mp = 0;
+
+	for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) {
+		if (!strcmp(_mp[i].name, mount_point)) {
+			mp = &_mp[i];
+			break;
+		}
+	}
+
+	if (!mp)
+		return ENODEV;
+
+	r = ext4_fs_fini(&mp->fs);
+	if (r != EOK)
+		return r;
+
+	mp->mounted = 0;
+
+	if (mp->cache_dynamic) {
+		ext4_bcache_fini_dynamic(mp->fs.bdev->bc);
+		free(mp->fs.bdev->bc);
+	}
+
+	return ext4_block_fini(mp->fs.bdev);
+}
+
+int ext4_mount_point_stats(const char *mount_point,
+			   struct ext4_mount_stats *stats)
+{
+	uint32_t i;
+	struct ext4_mountpoint *mp = 0;
+
+	for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) {
+		if (!strcmp(_mp[i].name, mount_point)) {
+			mp = &_mp[i];
+			break;
+		}
+	}
+	if (!mp)
+		return ENOENT;
+
+	EXT4_MP_LOCK(mp);
+	stats->inodes_count = ext4_get32(&mp->fs.sb, inodes_count);
+	stats->free_inodes_count = ext4_get32(&mp->fs.sb, free_inodes_count);
+	stats->blocks_count = ext4_sb_get_blocks_cnt(&mp->fs.sb);
+	stats->free_blocks_count = ext4_sb_get_free_blocks_cnt(&mp->fs.sb);
+	stats->block_size = ext4_sb_get_block_size(&mp->fs.sb);
+
+	stats->block_group_count = ext4_block_group_cnt(&mp->fs.sb);
+	stats->blocks_per_group = ext4_get32(&mp->fs.sb, blocks_per_group);
+	stats->inodes_per_group = ext4_get32(&mp->fs.sb, inodes_per_group);
+
+	memcpy(stats->volume_name, mp->fs.sb.volume_name, 16);
+	EXT4_MP_UNLOCK(mp);
+
+	return EOK;
+}
+
+int ext4_mount_setup_locks(const char *mount_point,
+			   const struct ext4_lock *locks)
+{
+	uint32_t i;
+	struct ext4_mountpoint *mp = 0;
+
+	for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) {
+		if (!strcmp(_mp[i].name, mount_point)) {
+			mp = &_mp[i];
+			break;
+		}
+	}
+	if (!mp)
+		return ENOENT;
+
+	mp->os_locks = locks;
+	return EOK;
+}
+
+/********************************FILE OPERATIONS*****************************/
+
+static struct ext4_mountpoint *ext4_get_mount(const char *path)
+{
+	int i;
+	for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) {
+
+		if (!_mp[i].mounted)
+			continue;
+
+		if (!strncmp(_mp[i].name, path, strlen(_mp[i].name)))
+			return &_mp[i];
+	}
+	return 0;
+}
+
+static int ext4_path_check(const char *path, bool *is_goal)
+{
+	int i;
+
+	for (i = 0; i < EXT4_DIRECTORY_FILENAME_LEN; ++i) {
+
+		if (path[i] == '/') {
+			*is_goal = false;
+			return i;
+		}
+
+		if (path[i] == 0) {
+			*is_goal = true;
+			return i;
+		}
+	}
+
+	return 0;
+}
+
+static bool ext4_parse_flags(const char *flags, uint32_t *file_flags)
+{
+	if (!flags)
+		return false;
+
+	if (!strcmp(flags, "r") || !strcmp(flags, "rb")) {
+		*file_flags = O_RDONLY;
+		return true;
+	}
+
+	if (!strcmp(flags, "w") || !strcmp(flags, "wb")) {
+		*file_flags = O_WRONLY | O_CREAT | O_TRUNC;
+		return true;
+	}
+
+	if (!strcmp(flags, "a") || !strcmp(flags, "ab")) {
+		*file_flags = O_WRONLY | O_CREAT | O_APPEND;
+		return true;
+	}
+
+	if (!strcmp(flags, "r+") || !strcmp(flags, "rb+") ||
+	    !strcmp(flags, "r+b")) {
+		*file_flags = O_RDWR;
+		return true;
+	}
+
+	if (!strcmp(flags, "w+") || !strcmp(flags, "wb+") ||
+	    !strcmp(flags, "w+b")) {
+		*file_flags = O_RDWR | O_CREAT | O_TRUNC;
+		return true;
+	}
+
+	if (!strcmp(flags, "a+") || !strcmp(flags, "ab+") ||
+	    !strcmp(flags, "a+b")) {
+		*file_flags = O_RDWR | O_CREAT | O_APPEND;
+		return true;
+	}
+
+	return false;
+}
+
+/*
+ * NOTICE: if filetype is equal to EXT4_DIRECTORY_FILETYPE_UNKNOWN,
+ * any filetype of the target dir entry will be accepted.
+ */
+static int ext4_generic_open2(ext4_file *f, const char *path, int flags,
+			      int filetype, uint32_t *parent_inode,
+			      uint32_t *name_off)
+{
+	bool is_goal = false;
+	uint8_t inode_type = EXT4_DIRECTORY_FILETYPE_DIR;
+	uint32_t next_inode;
+
+	int r;
+	struct ext4_mountpoint *mp = ext4_get_mount(path);
+	struct ext4_directory_search_result result;
+	struct ext4_inode_ref ref;
+
+	f->mp = 0;
+
+	if (!mp)
+		return ENOENT;
+
+	f->flags = flags;
+
+	/*Skip mount point*/
+	path += strlen(mp->name);
+
+	if (name_off)
+		*name_off = strlen(mp->name);
+
+	/*Load root*/
+	r = ext4_fs_get_inode_ref(&mp->fs, EXT4_INODE_ROOT_INDEX, &ref);
+
+	if (r != EOK)
+		return r;
+
+	if (parent_inode)
+		*parent_inode = ref.index;
+
+	int len = ext4_path_check(path, &is_goal);
+
+	while (1) {
+
+		len = ext4_path_check(path, &is_goal);
+
+		if (!len) {
+			/*If root open was request.*/
+			if (is_goal &&
+			    ((filetype == EXT4_DIRECTORY_FILETYPE_DIR) ||
+			     (filetype == EXT4_DIRECTORY_FILETYPE_UNKNOWN)))
+				break;
+
+			r = ENOENT;
+			break;
+		}
+
+		r = ext4_dir_find_entry(&result, &ref, path, len);
+		if (r != EOK) {
+
+			if (r != ENOENT)
+				break;
+
+			if (!(f->flags & O_CREAT))
+				break;
+
+			/*O_CREAT allows create new entry*/
+			struct ext4_inode_ref child_ref;
+			r = ext4_fs_alloc_inode(
+			    &mp->fs, &child_ref,
+			    is_goal ? (filetype == EXT4_DIRECTORY_FILETYPE_DIR)
+				    : true);
+			if (r != EOK)
+				break;
+
+			/*Destroy last result*/
+			ext4_dir_destroy_result(&ref, &result);
+
+			/*Link with root dir.*/
+			r = ext4_link(mp, &ref, &child_ref, path, len);
+			if (r != EOK) {
+				/*Fail. Free new inode.*/
+				ext4_fs_free_inode(&child_ref);
+				/*We do not want to write new inode.
+				  But block has to be released.*/
+				child_ref.dirty = false;
+				ext4_fs_put_inode_ref(&child_ref);
+				break;
+			}
+
+			ext4_fs_put_inode_ref(&child_ref);
+
+			continue;
+		}
+
+		if (parent_inode)
+			*parent_inode = ref.index;
+
+		next_inode = ext4_dir_entry_ll_get_inode(result.dentry);
+		inode_type =
+		    ext4_dir_entry_ll_get_inode_type(&mp->fs.sb, result.dentry);
+
+		r = ext4_dir_destroy_result(&ref, &result);
+		if (r != EOK)
+			break;
+
+		/*If expected file error*/
+		if (inode_type != EXT4_DIRECTORY_FILETYPE_DIR && !is_goal) {
+			r = ENOENT;
+			break;
+		}
+		if (filetype != EXT4_DIRECTORY_FILETYPE_UNKNOWN) {
+			if ((inode_type != filetype) && is_goal) {
+				r = ENOENT;
+				break;
+			}
+		}
+
+		r = ext4_fs_put_inode_ref(&ref);
+		if (r != EOK)
+			break;
+
+		r = ext4_fs_get_inode_ref(&mp->fs, next_inode, &ref);
+		if (r != EOK)
+			break;
+
+		if (is_goal)
+			break;
+
+		path += len + 1;
+
+		if (name_off)
+			*name_off += len + 1;
+	};
+
+	if (r != EOK) {
+		ext4_fs_put_inode_ref(&ref);
+		return r;
+	}
+
+	if (is_goal) {
+
+		if ((f->flags & O_TRUNC) &&
+		    (inode_type == EXT4_DIRECTORY_FILETYPE_REG_FILE)) {
+
+			r = ext4_fs_truncate_inode(&ref, 0);
+			if (r != EOK) {
+				ext4_fs_put_inode_ref(&ref);
+				return r;
+			}
+		}
+
+		f->mp = mp;
+		f->fsize = ext4_inode_get_size(&f->mp->fs.sb, ref.inode);
+		f->inode = ref.index;
+		f->fpos = 0;
+
+		if (f->flags & O_APPEND)
+			f->fpos = f->fsize;
+	}
+
+	r = ext4_fs_put_inode_ref(&ref);
+	return r;
+}
+
+/****************************************************************************/
+
+static int ext4_generic_open(ext4_file *f, const char *path, const char *flags,
+			     bool file_expect, uint32_t *parent_inode,
+			     uint32_t *name_off)
+{
+	uint32_t iflags;
+	int filetype;
+	if (ext4_parse_flags(flags, &iflags) == false)
+		return EINVAL;
+
+	if (file_expect == true)
+		filetype = EXT4_DIRECTORY_FILETYPE_REG_FILE;
+	else
+		filetype = EXT4_DIRECTORY_FILETYPE_DIR;
+
+	return ext4_generic_open2(f, path, iflags, filetype, parent_inode,
+				  name_off);
+}
+
+static int __ext4_create_hardlink(const char *path,
+				  struct ext4_inode_ref *child_ref)
+{
+	bool is_goal = false;
+	uint8_t inode_type = EXT4_DIRECTORY_FILETYPE_DIR;
+	uint32_t next_inode;
+
+	int r;
+	struct ext4_mountpoint *mp = ext4_get_mount(path);
+	struct ext4_directory_search_result result;
+	struct ext4_inode_ref ref;
+
+	if (!mp)
+		return ENOENT;
+
+	/*Skip mount point*/
+	path += strlen(mp->name);
+
+	/*Load root*/
+	r = ext4_fs_get_inode_ref(&mp->fs, EXT4_INODE_ROOT_INDEX, &ref);
+
+	if (r != EOK)
+		return r;
+
+	int len = ext4_path_check(path, &is_goal);
+
+	while (1) {
+
+		len = ext4_path_check(path, &is_goal);
+
+		if (!len) {
+			/*If root open was request.*/
+			if (is_goal)
+				r = EINVAL;
+			else
+				r = ENOENT;
+			break;
+		}
+
+		r = ext4_dir_find_entry(&result, &ref, path, len);
+		if (r != EOK) {
+
+			if (r != ENOENT || !is_goal)
+				break;
+
+			/*Destroy last result*/
+			ext4_dir_destroy_result(&ref, &result);
+
+			/*Link with root dir.*/
+			r = ext4_link(mp, &ref, child_ref, path, len);
+			break;
+		}
+
+		next_inode = ext4_dir_entry_ll_get_inode(result.dentry);
+		inode_type =
+		    ext4_dir_entry_ll_get_inode_type(&mp->fs.sb, result.dentry);
+
+		r = ext4_dir_destroy_result(&ref, &result);
+		if (r != EOK)
+			break;
+
+		if (inode_type == EXT4_DIRECTORY_FILETYPE_REG_FILE) {
+			if (is_goal)
+				r = EEXIST;
+			else
+				r = ENOENT;
+
+			break;
+		}
+
+		r = ext4_fs_put_inode_ref(&ref);
+		if (r != EOK)
+			break;
+
+		r = ext4_fs_get_inode_ref(&mp->fs, next_inode, &ref);
+		if (r != EOK)
+			break;
+
+		if (is_goal)
+			break;
+
+		path += len + 1;
+	};
+
+	if (r != EOK) {
+		ext4_fs_put_inode_ref(&ref);
+		return r;
+	}
+
+	r = ext4_fs_put_inode_ref(&ref);
+	return r;
+}
+
+static int __ext4_get_inode_ref_remove_hardlink(const char *path,
+						struct ext4_inode_ref *child)
+{
+	ext4_file f;
+	uint32_t parent_inode;
+	uint32_t name_off;
+	bool is_goal;
+	int r;
+	int len;
+	struct ext4_inode_ref parent;
+	struct ext4_mountpoint *mp = ext4_get_mount(path);
+
+	if (!mp)
+		return ENOENT;
+
+	r = ext4_generic_open2(&f, path, O_RDONLY,
+			       EXT4_DIRECTORY_FILETYPE_UNKNOWN, &parent_inode,
+			       &name_off);
+	if (r != EOK)
+		return r;
+
+	/*Load parent*/
+	r = ext4_fs_get_inode_ref(&mp->fs, parent_inode, &parent);
+	if (r != EOK) {
+		return r;
+	}
+
+	/*We have file to unlink. Load it.*/
+	r = ext4_fs_get_inode_ref(&mp->fs, f.inode, child);
+	if (r != EOK) {
+		ext4_fs_put_inode_ref(&parent);
+		return r;
+	}
+
+	if (r != EOK)
+		goto Finish;
+
+	/*Set path*/
+	path += name_off;
+
+	len = ext4_path_check(path, &is_goal);
+
+	/*Unlink from parent*/
+	r = ext4_unlink(mp, &parent, child, path, len);
+	if (r != EOK)
+		goto Finish;
+
+Finish:
+	if (r != EOK)
+		ext4_fs_put_inode_ref(child);
+
+	ext4_fs_put_inode_ref(&parent);
+	return r;
+}
+
+int ext4_frename(const char *path, const char *new_path)
+{
+	int r;
+	struct ext4_mountpoint *mp = ext4_get_mount(path);
+	struct ext4_inode_ref inode_ref;
+
+	if (!mp)
+		return ENOENT;
+
+	EXT4_MP_LOCK(mp);
+
+	r = __ext4_get_inode_ref_remove_hardlink(path, &inode_ref);
+	if (r != EOK)
+		goto Finish;
+
+	r = __ext4_create_hardlink(new_path, &inode_ref);
+	if (r != EOK)
+		r = __ext4_create_hardlink(path, &inode_ref);
+
+	ext4_fs_put_inode_ref(&inode_ref);
+
+Finish:
+	EXT4_MP_UNLOCK(mp);
+	return r;
+}
+
+/****************************************************************************/
+
+int ext4_get_sblock(const char *mount_point, struct ext4_sblock **sb)
+{
+	struct ext4_mountpoint *mp = ext4_get_mount(mount_point);
+
+	if (!mp)
+		return ENOENT;
+
+	*sb = &mp->fs.sb;
+	return EOK;
+}
+
+int ext4_cache_write_back(const char *path, bool on)
+{
+	struct ext4_mountpoint *mp = ext4_get_mount(path);
+
+	if (!mp)
+		return ENOENT;
+
+	EXT4_MP_LOCK(mp);
+	ext4_block_cache_write_back(mp->fs.bdev, on);
+	EXT4_MP_UNLOCK(mp);
+	return EOK;
+}
+
+int ext4_fremove(const char *path)
+{
+	ext4_file f;
+	uint32_t parent_inode;
+	uint32_t name_off;
+	bool is_goal;
+	int r;
+	int len;
+	struct ext4_inode_ref child;
+	struct ext4_inode_ref parent;
+	struct ext4_mountpoint *mp = ext4_get_mount(path);
+
+	if (!mp)
+		return ENOENT;
+
+	EXT4_MP_LOCK(mp);
+	r = ext4_generic_open(&f, path, "r", true, &parent_inode, &name_off);
+	if (r != EOK) {
+		EXT4_MP_UNLOCK(mp);
+		return r;
+	}
+
+	/*Load parent*/
+	r = ext4_fs_get_inode_ref(&mp->fs, parent_inode, &parent);
+	if (r != EOK) {
+		EXT4_MP_UNLOCK(mp);
+		return r;
+	}
+
+	/*We have file to delete. Load it.*/
+	r = ext4_fs_get_inode_ref(&mp->fs, f.inode, &child);
+	if (r != EOK) {
+		ext4_fs_put_inode_ref(&parent);
+		EXT4_MP_UNLOCK(mp);
+		return r;
+	}
+
+	/*Set path*/
+	path += name_off;
+
+	len = ext4_path_check(path, &is_goal);
+
+	/*Unlink from parent*/
+	r = ext4_unlink(mp, &parent, &child, path, len);
+	if (r != EOK)
+		goto Finish;
+
+	/*Link count is zero, the inode should be freed. */
+	if (!ext4_inode_get_links_count(child.inode)) {
+		printf("ttttt\n");
+		ext4_inode_set_deletion_time(child.inode, 0xFFFFFFFF);
+		/*Turncate*/
+		ext4_block_cache_write_back(mp->fs.bdev, 1);
+		/*Truncate may be IO heavy. Do it writeback cache mode.*/
+		r = ext4_fs_truncate_inode(&child, 0);
+		ext4_block_cache_write_back(mp->fs.bdev, 0);
+
+		if (r != EOK)
+			goto Finish;
+
+		r = ext4_fs_free_inode(&child);
+		if (r != EOK)
+			goto Finish;
+	}
+
+Finish:
+	ext4_fs_put_inode_ref(&child);
+	ext4_fs_put_inode_ref(&parent);
+	EXT4_MP_UNLOCK(mp);
+	return r;
+}
+
+int ext4_fill_raw_inode(const char *mount_point, uint32_t ino,
+			struct ext4_inode *inode)
+{
+	int r;
+	struct ext4_inode_ref inode_ref;
+	struct ext4_mountpoint *mp = ext4_get_mount(mount_point);
+
+	if (!mp)
+		return ENOENT;
+
+	EXT4_MP_LOCK(mp);
+
+	/*Load parent*/
+	r = ext4_fs_get_inode_ref(&mp->fs, ino, &inode_ref);
+	if (r != EOK) {
+		EXT4_MP_UNLOCK(mp);
+		return r;
+	}
+
+	memcpy(inode, inode_ref.inode, sizeof(struct ext4_inode));
+
+	ext4_fs_put_inode_ref(&inode_ref);
+	EXT4_MP_UNLOCK(mp);
+	return r;
+}
+
+int ext4_fopen(ext4_file *f, const char *path, const char *flags)
+{
+	struct ext4_mountpoint *mp = ext4_get_mount(path);
+	int r;
+
+	if (!mp)
+		return ENOENT;
+
+	EXT4_MP_LOCK(mp);
+	ext4_block_cache_write_back(mp->fs.bdev, 1);
+	r = ext4_generic_open(f, path, flags, true, 0, 0);
+	ext4_block_cache_write_back(mp->fs.bdev, 0);
+	EXT4_MP_UNLOCK(mp);
+	return r;
+}
+
+int ext4_fopen2(ext4_file *f, const char *path, int flags, bool file_expect)
+{
+	struct ext4_mountpoint *mp = ext4_get_mount(path);
+	int r;
+	int filetype;
+
+	if (!mp)
+		return ENOENT;
+
+	if (file_expect == true)
+		filetype = EXT4_DIRECTORY_FILETYPE_REG_FILE;
+	else
+		filetype = EXT4_DIRECTORY_FILETYPE_DIR;
+
+	EXT4_MP_LOCK(mp);
+	ext4_block_cache_write_back(mp->fs.bdev, 1);
+	r = ext4_generic_open2(f, path, flags, filetype, 0, 0);
+	ext4_block_cache_write_back(mp->fs.bdev, 0);
+	EXT4_MP_UNLOCK(mp);
+	return r;
+}
+
+int ext4_fclose(ext4_file *f)
+{
+	ext4_assert(f && f->mp);
+
+	f->mp = 0;
+	f->flags = 0;
+	f->inode = 0;
+	f->fpos = f->fsize = 0;
+
+	return EOK;
+}
+
+int ext4_ftruncate(ext4_file *f, uint64_t size)
+{
+	struct ext4_inode_ref ref;
+	int r;
+
+	ext4_assert(f && f->mp);
+
+	if (f->flags & O_RDONLY)
+		return EPERM;
+
+	EXT4_MP_LOCK(f->mp);
+
+	r = ext4_fs_get_inode_ref(&f->mp->fs, f->inode, &ref);
+	if (r != EOK) {
+		EXT4_MP_UNLOCK(f->mp);
+		return r;
+	}
+
+	/*Sync file size*/
+	f->fsize = ext4_inode_get_size(&f->mp->fs.sb, ref.inode);
+	if (f->fsize <= size) {
+		r = EOK;
+		goto Finish;
+	}
+
+	/*Start write back cache mode.*/
+	r = ext4_block_cache_write_back(f->mp->fs.bdev, 1);
+	if (r != EOK)
+		goto Finish;
+
+	r = ext4_fs_truncate_inode(&ref, size);
+	if (r != EOK)
+		goto Finish;
+
+	f->fsize = size;
+	if (f->fpos > size)
+		f->fpos = size;
+
+	/*Stop write back cache mode*/
+	ext4_block_cache_write_back(f->mp->fs.bdev, 0);
+
+	if (r != EOK)
+		goto Finish;
+
+Finish:
+	ext4_fs_put_inode_ref(&ref);
+	EXT4_MP_UNLOCK(f->mp);
+	return r;
+}
+
+int ext4_fread(ext4_file *f, void *buf, uint32_t size, uint32_t *rcnt)
+{
+	uint32_t u;
+	uint32_t fblock;
+	uint32_t fblock_start;
+	uint32_t fblock_cnt;
+	uint32_t sblock;
+	uint32_t sblock_end;
+	uint32_t block_size;
+	uint8_t *u8_buf = buf;
+	int r;
+	struct ext4_block b;
+	struct ext4_inode_ref ref;
+
+	ext4_assert(f && f->mp);
+
+	if (f->flags & O_WRONLY)
+		return EPERM;
+
+	if (!size)
+		return EOK;
+
+	EXT4_MP_LOCK(f->mp);
+
+	if (rcnt)
+		*rcnt = 0;
+
+	r = ext4_fs_get_inode_ref(&f->mp->fs, f->inode, &ref);
+	if (r != EOK) {
+		EXT4_MP_UNLOCK(f->mp);
+		return r;
+	}
+
+	/*Sync file size*/
+	f->fsize = ext4_inode_get_size(&f->mp->fs.sb, ref.inode);
+
+	block_size = ext4_sb_get_block_size(&f->mp->fs.sb);
+	size = size > (f->fsize - f->fpos) ? (f->fsize - f->fpos) : size;
+	sblock = (f->fpos) / block_size;
+	sblock_end = (f->fpos + size) / block_size;
+	u = (f->fpos) % block_size;
+
+	if (u) {
+
+		uint32_t ll = size > (block_size - u) ? (block_size - u) : size;
+
+		r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
+		if (r != EOK)
+			goto Finish;
+
+		r = ext4_block_get(f->mp->fs.bdev, &b, fblock);
+		if (r != EOK)
+			goto Finish;
+
+		memcpy(u8_buf, b.data + u, ll);
+
+		r = ext4_block_set(f->mp->fs.bdev, &b);
+		if (r != EOK)
+			goto Finish;
+
+		u8_buf += ll;
+		size -= ll;
+		f->fpos += ll;
+
+		if (rcnt)
+			*rcnt += ll;
+
+		sblock++;
+	}
+
+	fblock_start = 0;
+	fblock_cnt = 0;
+	while (size >= block_size) {
+		while (sblock < sblock_end) {
+			r = ext4_fs_get_inode_data_block_index(&ref, sblock,
+							       &fblock);
+			if (r != EOK)
+				goto Finish;
+
+			sblock++;
+
+			if (!fblock_start) {
+				fblock_start = fblock;
+			}
+
+			if ((fblock_start + fblock_cnt) != fblock)
+				break;
+
+			fblock_cnt++;
+		}
+
+		r = ext4_blocks_get_direct(f->mp->fs.bdev, u8_buf, fblock_start,
+					   fblock_cnt);
+		if (r != EOK)
+			goto Finish;
+
+		size -= block_size * fblock_cnt;
+		u8_buf += block_size * fblock_cnt;
+		f->fpos += block_size * fblock_cnt;
+
+		if (rcnt)
+			*rcnt += block_size * fblock_cnt;
+
+		fblock_start = fblock;
+		fblock_cnt = 1;
+	}
+
+	if (size) {
+		r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
+		if (r != EOK)
+			goto Finish;
+
+		r = ext4_block_get(f->mp->fs.bdev, &b, fblock);
+		if (r != EOK)
+			goto Finish;
+
+		memcpy(u8_buf, b.data, size);
+
+		r = ext4_block_set(f->mp->fs.bdev, &b);
+		if (r != EOK)
+			goto Finish;
+
+		f->fpos += size;
+
+		if (rcnt)
+			*rcnt += size;
+	}
+
+Finish:
+	ext4_fs_put_inode_ref(&ref);
+	EXT4_MP_UNLOCK(f->mp);
+	return r;
+}
+
+int ext4_fwrite(ext4_file *f, const void *buf, uint32_t size, uint32_t *wcnt)
+{
+	uint32_t u;
+	uint32_t fblock;
+
+	uint32_t sblock;
+	uint32_t sblock_end;
+	uint32_t file_blocks;
+	uint32_t block_size;
+	uint32_t fblock_start;
+	uint32_t fblock_cnt;
+
+	struct ext4_block b;
+	struct ext4_inode_ref ref;
+	const uint8_t *u8_buf = buf;
+	int r;
+
+	ext4_assert(f && f->mp);
+
+	if (f->flags & O_RDONLY)
+		return EPERM;
+
+	if (!size)
+		return EOK;
+
+	EXT4_MP_LOCK(f->mp);
+
+	if (wcnt)
+		*wcnt = 0;
+
+	r = ext4_fs_get_inode_ref(&f->mp->fs, f->inode, &ref);
+	if (r != EOK) {
+		EXT4_MP_UNLOCK(f->mp);
+		return r;
+	}
+
+	/*Sync file size*/
+	f->fsize = ext4_inode_get_size(&f->mp->fs.sb, ref.inode);
+
+	block_size = ext4_sb_get_block_size(&f->mp->fs.sb);
+
+	sblock_end = (f->fpos + size) > f->fsize ? (f->fpos + size) : f->fsize;
+	sblock_end /= block_size;
+	file_blocks = (f->fsize / block_size);
+
+	if (f->fsize % block_size)
+		file_blocks++;
+
+	sblock = (f->fpos) / block_size;
+
+	u = (f->fpos) % block_size;
+
+	if (u) {
+		uint32_t ll = size > (block_size - u) ? (block_size - u) : size;
+
+		r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
+		if (r != EOK)
+			goto Finish;
+
+		r = ext4_block_get(f->mp->fs.bdev, &b, fblock);
+		if (r != EOK)
+			goto Finish;
+
+		memcpy(b.data + u, u8_buf, ll);
+		b.dirty = true;
+
+		r = ext4_block_set(f->mp->fs.bdev, &b);
+		if (r != EOK)
+			goto Finish;
+
+		u8_buf += ll;
+		size -= ll;
+		f->fpos += ll;
+
+		if (wcnt)
+			*wcnt += ll;
+
+		sblock++;
+	}
+
+	/*Start write back cache mode.*/
+	r = ext4_block_cache_write_back(f->mp->fs.bdev, 1);
+	if (r != EOK)
+		goto Finish;
+
+	fblock_start = 0;
+	fblock_cnt = 0;
+	while (size >= block_size) {
+
+		while (sblock < sblock_end) {
+			if (sblock < file_blocks) {
+				r = ext4_fs_get_inode_data_block_index(
+				    &ref, sblock, &fblock);
+				if (r != EOK)
+					break;
+			} else {
+				r = ext4_fs_append_inode_block(&ref, &fblock,
+							       &sblock);
+				if (r != EOK)
+					break;
+			}
+
+			sblock++;
+
+			if (!fblock_start) {
+				fblock_start = fblock;
+			}
+
+			if ((fblock_start + fblock_cnt) != fblock)
+				break;
+
+			fblock_cnt++;
+		}
+
+		r = ext4_blocks_set_direct(f->mp->fs.bdev, u8_buf, fblock_start,
+					   fblock_cnt);
+		if (r != EOK)
+			break;
+
+		size -= block_size * fblock_cnt;
+		u8_buf += block_size * fblock_cnt;
+		f->fpos += block_size * fblock_cnt;
+
+		if (wcnt)
+			*wcnt += block_size * fblock_cnt;
+
+		fblock_start = fblock;
+		fblock_cnt = 1;
+	}
+
+	/*Stop write back cache mode*/
+	ext4_block_cache_write_back(f->mp->fs.bdev, 0);
+
+	if (r != EOK)
+		goto Finish;
+
+	if (size) {
+		if (sblock < file_blocks) {
+			r = ext4_fs_get_inode_data_block_index(&ref, sblock,
+							       &fblock);
+			if (r != EOK)
+				goto Finish;
+		} else {
+			r = ext4_fs_append_inode_block(&ref, &fblock, &sblock);
+			if (r != EOK)
+				goto Finish;
+		}
+
+		r = ext4_block_get(f->mp->fs.bdev, &b, fblock);
+		if (r != EOK)
+			goto Finish;
+
+		memcpy(b.data, u8_buf, size);
+		b.dirty = true;
+
+		r = ext4_block_set(f->mp->fs.bdev, &b);
+		if (r != EOK)
+			goto Finish;
+
+		f->fpos += size;
+
+		if (wcnt)
+			*wcnt += size;
+	}
+
+	if (f->fpos > f->fsize) {
+		f->fsize = f->fpos;
+		ext4_inode_set_size(ref.inode, f->fsize);
+		ref.dirty = true;
+	}
+
+Finish:
+	ext4_fs_put_inode_ref(&ref);
+	EXT4_MP_UNLOCK(f->mp);
+	return r;
+}
+
+int ext4_fseek(ext4_file *f, uint64_t offset, uint32_t origin)
+{
+	switch (origin) {
+	case SEEK_SET:
+		if (offset > f->fsize)
+			return EINVAL;
+
+		f->fpos = offset;
+		return EOK;
+	case SEEK_CUR:
+		if ((offset + f->fpos) > f->fsize)
+			return EINVAL;
+
+		f->fpos += offset;
+		return EOK;
+	case SEEK_END:
+		if (offset > f->fsize)
+			return EINVAL;
+
+		f->fpos = f->fsize - offset;
+		return EOK;
+	}
+	return EINVAL;
+}
+
+uint64_t ext4_ftell(ext4_file *f) { return f->fpos; }
+
+uint64_t ext4_fsize(ext4_file *f) { return f->fsize; }
+
+int ext4_fchmod(ext4_file *f, uint32_t mode)
+{
+	int r;
+	uint32_t ino;
+	struct ext4_sblock *sb;
+	struct ext4_inode_ref inode_ref;
+	struct ext4_mountpoint *mp = f->mp;
+
+	if (!mp)
+		return ENOENT;
+
+	EXT4_MP_LOCK(mp);
+
+	ino = f->inode;
+	r = ext4_fs_get_inode_ref(&mp->fs, ino, &inode_ref);
+	if (r != EOK) {
+		EXT4_MP_UNLOCK(mp);
+		return r;
+	}
+
+	sb = &f->mp->fs.sb;
+	ext4_inode_set_mode(sb, inode_ref.inode, mode);
+	inode_ref.dirty = true;
+
+	ext4_fs_put_inode_ref(&inode_ref);
+	EXT4_MP_UNLOCK(mp);
+	return r;
+}
+
+int ext4_fchown(ext4_file *f, uint32_t uid, uint32_t gid)
+{
+	int r;
+	uint32_t ino;
+	struct ext4_inode_ref inode_ref;
+	struct ext4_mountpoint *mp = f->mp;
+
+	if (!mp)
+		return ENOENT;
+
+	EXT4_MP_LOCK(mp);
+
+	ino = f->inode;
+	r = ext4_fs_get_inode_ref(&mp->fs, ino, &inode_ref);
+	if (r != EOK) {
+		EXT4_MP_UNLOCK(mp);
+		return r;
+	}
+
+	ext4_inode_set_uid(inode_ref.inode, uid);
+	ext4_inode_set_gid(inode_ref.inode, gid);
+	inode_ref.dirty = true;
+
+	ext4_fs_put_inode_ref(&inode_ref);
+	EXT4_MP_UNLOCK(mp);
+	return r;
+}
+
+int ext4_file_set_atime(ext4_file *f, uint32_t atime)
+{
+	int r;
+	uint32_t ino;
+	struct ext4_inode_ref inode_ref;
+	struct ext4_mountpoint *mp = f->mp;
+
+	if (!mp)
+		return ENOENT;
+
+	EXT4_MP_LOCK(mp);
+
+	ino = f->inode;
+	r = ext4_fs_get_inode_ref(&mp->fs, ino, &inode_ref);
+	if (r != EOK) {
+		EXT4_MP_UNLOCK(mp);
+		return r;
+	}
+
+	ext4_inode_set_access_time(inode_ref.inode, atime);
+	inode_ref.dirty = true;
+
+	ext4_fs_put_inode_ref(&inode_ref);
+	EXT4_MP_UNLOCK(mp);
+	return r;
+}
+
+int ext4_file_set_mtime(ext4_file *f, uint32_t mtime)
+{
+	int r;
+	uint32_t ino;
+	struct ext4_inode_ref inode_ref;
+	struct ext4_mountpoint *mp = f->mp;
+
+	if (!mp)
+		return ENOENT;
+
+	EXT4_MP_LOCK(mp);
+
+	ino = f->inode;
+	r = ext4_fs_get_inode_ref(&mp->fs, ino, &inode_ref);
+	if (r != EOK) {
+		EXT4_MP_UNLOCK(mp);
+		return r;
+	}
+
+	ext4_inode_set_modification_time(inode_ref.inode, mtime);
+	inode_ref.dirty = true;
+
+	ext4_fs_put_inode_ref(&inode_ref);
+	EXT4_MP_UNLOCK(mp);
+	return r;
+}
+
+int ext4_file_set_ctime(ext4_file *f, uint32_t ctime)
+{
+	int r;
+	uint32_t ino;
+	struct ext4_inode_ref inode_ref;
+	struct ext4_mountpoint *mp = f->mp;
+
+	if (!mp)
+		return ENOENT;
+
+	EXT4_MP_LOCK(mp);
+
+	ino = f->inode;
+	r = ext4_fs_get_inode_ref(&mp->fs, ino, &inode_ref);
+	if (r != EOK) {
+		EXT4_MP_UNLOCK(mp);
+		return r;
+	}
+
+	ext4_inode_set_change_inode_time(inode_ref.inode, ctime);
+	inode_ref.dirty = true;
+
+	ext4_fs_put_inode_ref(&inode_ref);
+	EXT4_MP_UNLOCK(mp);
+	return r;
+}
+
+/*********************************DIRECTORY OPERATION************************/
+
+int ext4_dir_rm(const char *path)
+{
+	int r;
+	int len;
+	ext4_file f;
+
+	struct ext4_mountpoint *mp = ext4_get_mount(path);
+	struct ext4_inode_ref current;
+	struct ext4_inode_ref child;
+	struct ext4_directory_iterator it;
+
+	uint32_t name_off;
+	uint32_t inode_up;
+	uint32_t inode_current;
+	uint32_t depth = 1;
+
+	bool has_children;
+	bool is_goal;
+	bool dir_end;
+
+	if (!mp)
+		return ENOENT;
+
+	EXT4_MP_LOCK(mp);
+
+	/*Check if exist.*/
+	r = ext4_generic_open(&f, path, "r", false, &inode_up, &name_off);
+	if (r != EOK) {
+		EXT4_MP_UNLOCK(mp);
+		return r;
+	}
+
+	path += name_off;
+	len = ext4_path_check(path, &is_goal);
+
+	inode_current = f.inode;
+	dir_end = false;
+
+	ext4_block_cache_write_back(mp->fs.bdev, 1);
+
+	do {
+		/*Load directory node.*/
+		r = ext4_fs_get_inode_ref(&f.mp->fs, inode_current, &current);
+		if (r != EOK) {
+			break;
+		}
+
+		/*Initialize iterator.*/
+		r = ext4_dir_iterator_init(&it, &current, 0);
+		if (r != EOK) {
+			ext4_fs_put_inode_ref(&current);
+			break;
+		}
+
+		while (r == EOK) {
+
+			if (!it.current) {
+				dir_end = true;
+				break;
+			}
+
+			/*Get up directory inode when ".." entry*/
+			if ((it.current->name_length == 2) &&
+			    ext4_is_dots(it.current->name,
+					 it.current->name_length)) {
+				inode_up = ext4_dir_entry_ll_get_inode(it.current);
+			}
+
+			/*If directory or file entry,  but not "." ".." entry*/
+			if (!ext4_is_dots(it.current->name,
+					  it.current->name_length)) {
+
+				/*Get child inode reference do unlink
+				 * directory/file.*/
+				r = ext4_fs_get_inode_ref(&f.mp->fs,
+				        ext4_dir_entry_ll_get_inode(it.current),
+				        &child);
+				if (r != EOK)
+					break;
+
+				/*If directory with no leaf children*/
+				r = ext4_has_children(&has_children, &child);
+				if (r != EOK) {
+					ext4_fs_put_inode_ref(&child);
+					break;
+				}
+
+				if (has_children) {
+					/*Has directory children. Go into this
+					 * directory.*/
+					inode_up = inode_current;
+					inode_current = ext4_dir_entry_ll_get_inode(it.current);
+					depth++;
+					ext4_fs_put_inode_ref(&child);
+					break;
+				}
+
+				/*No children in child directory or file. Just
+				 * unlink.*/
+				r = ext4_unlink(f.mp, &current, &child,
+						(char *)it.current->name,
+						it.current->name_length);
+				if (r != EOK) {
+					ext4_fs_put_inode_ref(&child);
+					break;
+				}
+
+				ext4_inode_set_deletion_time(child.inode,
+							     0xFFFFFFFF);
+				ext4_inode_set_links_count(child.inode, 0);
+				child.dirty = true;
+				/*Turncate*/
+				r = ext4_fs_truncate_inode(&child, 0);
+				if (r != EOK) {
+					ext4_fs_put_inode_ref(&child);
+					break;
+				}
+
+				r = ext4_fs_free_inode(&child);
+				if (r != EOK) {
+					ext4_fs_put_inode_ref(&child);
+					break;
+				}
+
+				r = ext4_fs_put_inode_ref(&child);
+				if (r != EOK)
+					break;
+			}
+
+			r = ext4_dir_iterator_next(&it);
+		}
+
+		if (dir_end) {
+			/*Directory iterator reached last entry*/
+			ext4_has_children(&has_children, &current);
+			if (!has_children) {
+				inode_current = inode_up;
+				if (depth)
+					depth--;
+			}
+			/*Last unlink*/
+			if (!depth) {
+				/*Load parent.*/
+				struct ext4_inode_ref parent;
+				r = ext4_fs_get_inode_ref(&f.mp->fs, inode_up,
+							  &parent);
+				if (r != EOK)
+					goto End;
+
+				/* In this place all directories should be
+				 * unlinked.
+				 * Last unlink from root of current directory*/
+				r = ext4_unlink(f.mp, &parent, &current,
+						(char *)path, len);
+				if (r != EOK) {
+					ext4_fs_put_inode_ref(&parent);
+					goto End;
+				}
+
+				if (ext4_inode_get_links_count(current.inode) ==
+				    2) {
+					ext4_inode_set_deletion_time(
+					    current.inode, 0xFFFFFFFF);
+					ext4_inode_set_links_count(
+					    current.inode, 0);
+					current.dirty = true;
+					/*Turncate*/
+					r = ext4_fs_truncate_inode(&current, 0);
+					if (r != EOK) {
+						ext4_fs_put_inode_ref(&parent);
+						goto End;
+					}
+
+					r = ext4_fs_free_inode(&current);
+					if (r != EOK) {
+						ext4_fs_put_inode_ref(&parent);
+						goto End;
+					}
+				}
+
+				r = ext4_fs_put_inode_ref(&parent);
+				if (r != EOK)
+					goto End;
+			}
+		}
+
+	End:
+		ext4_dir_iterator_fini(&it);
+		ext4_fs_put_inode_ref(&current);
+		dir_end = false;
+
+		/*When something goes wrong. End loop.*/
+		if (r != EOK)
+			break;
+
+	} while (depth);
+
+	ext4_block_cache_write_back(mp->fs.bdev, 0);
+	EXT4_MP_UNLOCK(mp);
+	return r;
+}
+
+int ext4_dir_mk(const char *path)
+{
+	int r;
+	ext4_file f;
+
+	struct ext4_mountpoint *mp = ext4_get_mount(path);
+
+	if (!mp)
+		return ENOENT;
+
+	EXT4_MP_LOCK(mp);
+
+	/*Check if exist.*/
+	r = ext4_generic_open(&f, path, "r", false, 0, 0);
+	if (r == EOK) {
+		/*Directory already created*/
+		EXT4_MP_UNLOCK(mp);
+		return r;
+	}
+
+	/*Create new dir*/
+	r = ext4_generic_open(&f, path, "w", false, 0, 0);
+	if (r != EOK) {
+		EXT4_MP_UNLOCK(mp);
+		return r;
+	}
+
+	EXT4_MP_UNLOCK(mp);
+	return r;
+}
+
+int ext4_dir_open(ext4_dir *d, const char *path)
+{
+	struct ext4_mountpoint *mp = ext4_get_mount(path);
+	int r;
+
+	if (!mp)
+		return ENOENT;
+
+	EXT4_MP_LOCK(mp);
+	r = ext4_generic_open(&d->f, path, "r", false, 0, 0);
+	d->next_off = 0;
+	EXT4_MP_UNLOCK(mp);
+	return r;
+}
+
+int ext4_dir_close(ext4_dir *d) { return ext4_fclose(&d->f); }
+
+const ext4_direntry *ext4_dir_entry_next(ext4_dir *d)
+{
+#define EXT4_DIR_ENTRY_OFFSET_TERM (uint64_t)(-1)
+
+	int r;
+	ext4_direntry *de = 0;
+	struct ext4_inode_ref dir;
+	struct ext4_directory_iterator it;
+
+	EXT4_MP_LOCK(d->f.mp);
+
+	if (d->next_off == EXT4_DIR_ENTRY_OFFSET_TERM)
+		return 0;
+
+	r = ext4_fs_get_inode_ref(&d->f.mp->fs, d->f.inode, &dir);
+	if (r != EOK) {
+		goto Finish;
+	}
+
+	r = ext4_dir_iterator_init(&it, &dir, d->next_off);
+	if (r != EOK) {
+		ext4_fs_put_inode_ref(&dir);
+		goto Finish;
+	}
+
+	memcpy(&d->de, it.current, sizeof(ext4_direntry));
+	de = &d->de;
+
+	ext4_dir_iterator_next(&it);
+
+	d->next_off =
+	    it.current ? it.current_offset : EXT4_DIR_ENTRY_OFFSET_TERM;
+
+	ext4_dir_iterator_fini(&it);
+	ext4_fs_put_inode_ref(&dir);
+
+Finish:
+	EXT4_MP_UNLOCK(d->f.mp);
+	return de;
+}
+
+/**
+ * @}
+ */
--- a/lwext4/ext4.h
+++ b/lwext4/ext4.h
@@ -1,389 +1,389 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file  ext4.h
- * @brief Ext4 high level operations (files, directories, mount points...).
- *        Client has to include only this file.
- */
-
-#ifndef EXT4_H_
-#define EXT4_H_
-
-#include "ext4_config.h"
-#include "ext4_types.h"
-#include "ext4_blockdev.h"
-
-#include <stdint.h>
-
-/********************************FILE OPEN FLAGS*****************************/
-
-#ifndef O_RDONLY
-#define O_RDONLY 00
-#endif
-
-#ifndef O_WRONLY
-#define O_WRONLY 01
-#endif
-
-#ifndef O_RDWR
-#define O_RDWR 02
-#endif
-
-#ifndef O_CREAT
-#define O_CREAT 0100
-#endif
-
-#ifndef O_EXCL
-#define O_EXCL 0200
-#endif
-
-#ifndef O_TRUNC
-#define O_TRUNC 01000
-#endif
-
-#ifndef O_APPEND
-#define O_APPEND 02000
-#endif
-
-/********************************FILE SEEK FLAGS*****************************/
-
-#ifndef SEEK_SET
-#define SEEK_SET 0
-#endif
-
-#ifndef SEEK_CUR
-#define SEEK_CUR 1
-#endif
-
-#ifndef SEEK_END
-#define SEEK_END 2
-#endif
-
-/********************************OS LOCK INFERFACE***************************/
-
-/**@brief   OS dependent lock interface.*/
-struct ext4_lock {
-
-	/**@brief   Lock access to mount point*/
-	void (*lock)(void);
-
-	/**@brief   Unlock access to mount point*/
-	void (*unlock)(void);
-};
-
-/********************************FILE DESCRIPTOR*****************************/
-
-/**@brief   File descriptor*/
-typedef struct ext4_file {
-
-	/**@brief   Mount point handle.*/
-	struct ext4_mountpoint *mp;
-
-	/**@brief   File inode id*/
-	uint32_t inode;
-
-	/**@brief   Open flags.*/
-	uint32_t flags;
-
-	/**@brief   File size.*/
-	uint64_t fsize;
-
-	/**@brief   File position*/
-	uint64_t fpos;
-} ext4_file;
-
-/*****************************DIRECTORY DESCRIPTOR***************************/
-/**@brief   Directory entry types. Copy from ext4_types.h*/
-enum { EXT4_DIRENTRY_UNKNOWN = 0,
-       EXT4_DIRENTRY_REG_FILE,
-       EXT4_DIRENTRY_DIR,
-       EXT4_DIRENTRY_CHRDEV,
-       EXT4_DIRENTRY_BLKDEV,
-       EXT4_DIRENTRY_FIFO,
-       EXT4_DIRENTRY_SOCK,
-       EXT4_DIRENTRY_SYMLINK };
-
-/**@brief   Directory entry descriptor. Copy from ext4_types.h*/
-typedef struct {
-	uint32_t inode;
-	uint16_t entry_length;
-	uint8_t name_length;
-	uint8_t inode_type;
-	uint8_t name[255];
-} ext4_direntry;
-
-typedef struct {
-	/**@brief   File descriptor*/
-	ext4_file f;
-	/**@brief   Current directory entry.*/
-	ext4_direntry de;
-	/**@brief   Next entry offset*/
-	uint64_t next_off;
-} ext4_dir;
-
-/********************************MOUNT OPERATIONS****************************/
-
-/**@brief   Register a block device to a name.
- *          @warning Block device has to be filled by
- *          @ref EXT4_BLOCKDEV_STATIC_INSTANCE. Block cache may be created
- *          @ref EXT4_BCACHE_STATIC_INSTANCE.
- *          Block cache may by created automatically when bc parameter is 0.
- * @param   bd block device
- * @param   bd block device cache (0 = automatic cache mode)
- * @param   dev_name register name
- * @param   standard error code*/
-int ext4_device_register(struct ext4_blockdev *bd, struct ext4_bcache *bc,
-			 const char *dev_name);
-
-/**@brief   Mount a block device with EXT4 partition to the mount point.
- * @param   dev_name block device name (@ref ext4_device_register)
- * @param   mount_point mount point, for example
- *          -   /
- *          -   /my_partition/
- *          -   /my_second_partition/
- *
- * @return standard error code */
-int ext4_mount(const char *dev_name, const char *mount_point);
-
-/**@brief   Umount operation.
- * @param   mount_point mount name
- * @return  standard error code */
-int ext4_umount(const char *mount_point);
-
-/**@brief   Some of the filesystem stats.*/
-struct ext4_mount_stats {
-	uint32_t inodes_count;
-	uint32_t free_inodes_count;
-	uint64_t blocks_count;
-	uint64_t free_blocks_count;
-
-	uint32_t block_size;
-	uint32_t block_group_count;
-	uint32_t blocks_per_group;
-	uint32_t inodes_per_group;
-
-	char volume_name[16];
-};
-
-/**@brief   Get file system params.
- * @param   mount_point mount path
- * @param   stats ext fs stats
- * @return  standard error code */
-int ext4_mount_point_stats(const char *mount_point,
-			   struct ext4_mount_stats *stats);
-
-/**@brief   Setup OS lock routines.
- * @param   mount_point mount path
- * @param   locks - lock and unlock functions
- * @return  standard error code */
-int ext4_mount_setup_locks(const char *mount_point,
-			   const struct ext4_lock *locks);
-
-/**@brief   Acquire the filesystem superblock pointer of a mp.
- * @param   mount_point mount path
- * @param   superblock pointer
- * @return  standard error code */
-int ext4_get_sblock(const char *mount_point, struct ext4_sblock **sb);
-
-/**@brief   Enable/disable write back cache mode.
- * @warning Default model of cache is write trough. It means that when You do:
- *
- *          ext4_fopen(...);
- *          ext4_fwrie(...);
- *                           < --- data is flushed to physical drive
- *
- *          When you do:
- *          ext4_cache_write_back(..., 1);
- *          ext4_fopen(...);
- *          ext4_fwrie(...);
- *                           < --- data is NOT flushed to physical drive
- *          ext4_cache_write_back(..., 0);
- *                           < --- when write back mode is disabled all
- *                                 cache data will be flushed
- * To enable write back mode permanently just call this function
- * once after ext4_mount (and disable before ext4_umount).
- *
- * Some of the function use write back cache mode internally.
- * If you enable write back mode twice you have to disable it twice
- * to flush all data:
- *
- *      ext4_cache_write_back(..., 1);
- *      ext4_cache_write_back(..., 1);
- *
- *      ext4_cache_write_back(..., 0);
- *      ext4_cache_write_back(..., 0);
- *
- * Write back mode is useful when you want to create a lot of empty
- * files/directories.
- *
- * @param   path mount point path
- * @param   on enable/disable
- *
- * @return  standard error code */
-int ext4_cache_write_back(const char *path, bool on);
-
-/********************************FILE OPERATIONS*****************************/
-
-/**@brief   Remove file by path.
- * @param   path path to file
- * @return  standard error code */
-int ext4_fremove(const char *path);
-
-/**@brief Rename file
- * @param path source
- * @param new_path destination
- * @return  standard error code */
-int ext4_frename(const char *path, const char *new_path);
-
-/**@brief   File open function.
- * @param   filename, (has to start from mount point)
- *          /my_partition/my_file
- * @param   flags open file flags
- *  |---------------------------------------------------------------|
- *  |   r or rb                 O_RDONLY                            |
- *  |---------------------------------------------------------------|
- *  |   w or wb                 O_WRONLY|O_CREAT|O_TRUNC            |
- *  |---------------------------------------------------------------|
- *  |   a or ab                 O_WRONLY|O_CREAT|O_APPEND           |
- *  |---------------------------------------------------------------|
- *  |   r+ or rb+ or r+b        O_RDWR                              |
- *  |---------------------------------------------------------------|
- *  |   w+ or wb+ or w+b        O_RDWR|O_CREAT|O_TRUNC              |
- *  |---------------------------------------------------------------|
- *  |   a+ or ab+ or a+b        O_RDWR|O_CREAT|O_APPEND             |
- *  |---------------------------------------------------------------|
- *
- * @return  standard error code*/
-int ext4_fopen(ext4_file *f, const char *path, const char *flags);
-
-/**@brief   Alternate file open function.
- * @param   filename, (has to start from mount point)
- *          /my_partition/my_file
- * @param   flags open file flags
- * @return  standard error code*/
-int ext4_fopen2(ext4_file *f, const char *path, int flags, bool file_expect);
-
-/**@brief   File close function.
- * @param   f file handle
- * @return  standard error code*/
-int ext4_fclose(ext4_file *f);
-
-/**@brief   Fill in the ext4_inode buffer.
- * @param   mount_point
- * @param   inode no.
- * @param   ext4_inode buffer
- * @return  standard error code*/
-int ext4_fill_raw_inode(const char *mount_point, uint32_t ino,
-			struct ext4_inode *inode);
-
-/**@brief   File truncate function.
- * @param   f file handle
- * @param   new file size
- * @return  standard error code*/
-int ext4_ftruncate(ext4_file *f, uint64_t size);
-
-/**@brief   Read data from file.
- * @param   f file handle
- * @param   buf output buffer
- * @param   size bytes to read
- * @param   rcnt bytes read (may be NULL)
- * @return  standard error code*/
-int ext4_fread(ext4_file *f, void *buf, uint32_t size, uint32_t *rcnt);
-
-/**@brief   Write data to file.
- * @param   f file handle
- * @param   buf data to write
- * @param   size write length
- * @param   wcnt bytes written (may be NULL)
- * @return  standard error code*/
-int ext4_fwrite(ext4_file *f, const void *buf, uint32_t size, uint32_t *wcnt);
-
-/**@brief   File seek operation.
- * @param   f file handle
- * @param   offset offset to seek
- * @param   origin seek type:
- *              @ref SEEK_SET
- *              @ref SEEK_CUR
- *              @ref SEEK_END
- * @return  standard error code*/
-int ext4_fseek(ext4_file *f, uint64_t offset, uint32_t origin);
-
-/**@brief   Get file position.
- * @param   f file handle
- * @return  actual file position */
-uint64_t ext4_ftell(ext4_file *f);
-
-/**@brief   Get file size.
- * @param   f file handle
- * @return  file size */
-uint64_t ext4_fsize(ext4_file *f);
-
-int ext4_fchmod(ext4_file *f, uint32_t mode);
-int ext4_fchown(ext4_file *f, uint32_t uid, uint32_t gid);
-int ext4_file_set_atime(ext4_file *f, uint32_t atime);
-int ext4_file_set_mtime(ext4_file *f, uint32_t mtime);
-int ext4_file_set_ctime(ext4_file *f, uint32_t ctime);
-
-/*********************************DIRECTORY OPERATION***********************/
-
-/**@brief   Recursive directory remove.
- * @param   path directory path to remove
- * @return  standard error code*/
-int ext4_dir_rm(const char *path);
-
-/**@brief   Create new directory.
- * @param   name new directory name
- * @return  standard error code*/
-int ext4_dir_mk(const char *path);
-
-/**@brief   Directory open.
- * @param   d directory handle
- * @param   path directory path
- * @return  standard error code*/
-int ext4_dir_open(ext4_dir *d, const char *path);
-
-/**@brief   Directory close.
- * @param   d directory handle
- * @return  standard error code*/
-int ext4_dir_close(ext4_dir *d);
-
-/**@brief   Return next directory entry.
- * @param   d directory handle
- * @param   id entry id
- * @return  directory entry id (NULL if no entry)*/
-const ext4_direntry *ext4_dir_entry_next(ext4_dir *d);
-
-#endif /* EXT4_H_ */
-
-/**
- * @}
- */
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file  ext4.h
+ * @brief Ext4 high level operations (files, directories, mount points...).
+ *        Client has to include only this file.
+ */
+
+#ifndef EXT4_H_
+#define EXT4_H_
+
+#include "ext4_config.h"
+#include "ext4_types.h"
+#include "ext4_blockdev.h"
+
+#include <stdint.h>
+
+/********************************FILE OPEN FLAGS*****************************/
+
+#ifndef O_RDONLY
+#define O_RDONLY 00
+#endif
+
+#ifndef O_WRONLY
+#define O_WRONLY 01
+#endif
+
+#ifndef O_RDWR
+#define O_RDWR 02
+#endif
+
+#ifndef O_CREAT
+#define O_CREAT 0100
+#endif
+
+#ifndef O_EXCL
+#define O_EXCL 0200
+#endif
+
+#ifndef O_TRUNC
+#define O_TRUNC 01000
+#endif
+
+#ifndef O_APPEND
+#define O_APPEND 02000
+#endif
+
+/********************************FILE SEEK FLAGS*****************************/
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+#ifndef SEEK_CUR
+#define SEEK_CUR 1
+#endif
+
+#ifndef SEEK_END
+#define SEEK_END 2
+#endif
+
+/********************************OS LOCK INFERFACE***************************/
+
+/**@brief   OS dependent lock interface.*/
+struct ext4_lock {
+
+	/**@brief   Lock access to mount point*/
+	void (*lock)(void);
+
+	/**@brief   Unlock access to mount point*/
+	void (*unlock)(void);
+};
+
+/********************************FILE DESCRIPTOR*****************************/
+
+/**@brief   File descriptor*/
+typedef struct ext4_file {
+
+	/**@brief   Mount point handle.*/
+	struct ext4_mountpoint *mp;
+
+	/**@brief   File inode id*/
+	uint32_t inode;
+
+	/**@brief   Open flags.*/
+	uint32_t flags;
+
+	/**@brief   File size.*/
+	uint64_t fsize;
+
+	/**@brief   File position*/
+	uint64_t fpos;
+} ext4_file;
+
+/*****************************DIRECTORY DESCRIPTOR***************************/
+/**@brief   Directory entry types. Copy from ext4_types.h*/
+enum { EXT4_DIRENTRY_UNKNOWN = 0,
+       EXT4_DIRENTRY_REG_FILE,
+       EXT4_DIRENTRY_DIR,
+       EXT4_DIRENTRY_CHRDEV,
+       EXT4_DIRENTRY_BLKDEV,
+       EXT4_DIRENTRY_FIFO,
+       EXT4_DIRENTRY_SOCK,
+       EXT4_DIRENTRY_SYMLINK };
+
+/**@brief   Directory entry descriptor. Copy from ext4_types.h*/
+typedef struct {
+	uint32_t inode;
+	uint16_t entry_length;
+	uint8_t name_length;
+	uint8_t inode_type;
+	uint8_t name[255];
+} ext4_direntry;
+
+typedef struct {
+	/**@brief   File descriptor*/
+	ext4_file f;
+	/**@brief   Current directory entry.*/
+	ext4_direntry de;
+	/**@brief   Next entry offset*/
+	uint64_t next_off;
+} ext4_dir;
+
+/********************************MOUNT OPERATIONS****************************/
+
+/**@brief   Register a block device to a name.
+ *          @warning Block device has to be filled by
+ *          @ref EXT4_BLOCKDEV_STATIC_INSTANCE. Block cache may be created
+ *          @ref EXT4_BCACHE_STATIC_INSTANCE.
+ *          Block cache may by created automatically when bc parameter is 0.
+ * @param   bd block device
+ * @param   bd block device cache (0 = automatic cache mode)
+ * @param   dev_name register name
+ * @param   standard error code*/
+int ext4_device_register(struct ext4_blockdev *bd, struct ext4_bcache *bc,
+			 const char *dev_name);
+
+/**@brief   Mount a block device with EXT4 partition to the mount point.
+ * @param   dev_name block device name (@ref ext4_device_register)
+ * @param   mount_point mount point, for example
+ *          -   /
+ *          -   /my_partition/
+ *          -   /my_second_partition/
+ *
+ * @return standard error code */
+int ext4_mount(const char *dev_name, const char *mount_point);
+
+/**@brief   Umount operation.
+ * @param   mount_point mount name
+ * @return  standard error code */
+int ext4_umount(const char *mount_point);
+
+/**@brief   Some of the filesystem stats.*/
+struct ext4_mount_stats {
+	uint32_t inodes_count;
+	uint32_t free_inodes_count;
+	uint64_t blocks_count;
+	uint64_t free_blocks_count;
+
+	uint32_t block_size;
+	uint32_t block_group_count;
+	uint32_t blocks_per_group;
+	uint32_t inodes_per_group;
+
+	char volume_name[16];
+};
+
+/**@brief   Get file system params.
+ * @param   mount_point mount path
+ * @param   stats ext fs stats
+ * @return  standard error code */
+int ext4_mount_point_stats(const char *mount_point,
+			   struct ext4_mount_stats *stats);
+
+/**@brief   Setup OS lock routines.
+ * @param   mount_point mount path
+ * @param   locks - lock and unlock functions
+ * @return  standard error code */
+int ext4_mount_setup_locks(const char *mount_point,
+			   const struct ext4_lock *locks);
+
+/**@brief   Acquire the filesystem superblock pointer of a mp.
+ * @param   mount_point mount path
+ * @param   superblock pointer
+ * @return  standard error code */
+int ext4_get_sblock(const char *mount_point, struct ext4_sblock **sb);
+
+/**@brief   Enable/disable write back cache mode.
+ * @warning Default model of cache is write trough. It means that when You do:
+ *
+ *          ext4_fopen(...);
+ *          ext4_fwrie(...);
+ *                           < --- data is flushed to physical drive
+ *
+ *          When you do:
+ *          ext4_cache_write_back(..., 1);
+ *          ext4_fopen(...);
+ *          ext4_fwrie(...);
+ *                           < --- data is NOT flushed to physical drive
+ *          ext4_cache_write_back(..., 0);
+ *                           < --- when write back mode is disabled all
+ *                                 cache data will be flushed
+ * To enable write back mode permanently just call this function
+ * once after ext4_mount (and disable before ext4_umount).
+ *
+ * Some of the function use write back cache mode internally.
+ * If you enable write back mode twice you have to disable it twice
+ * to flush all data:
+ *
+ *      ext4_cache_write_back(..., 1);
+ *      ext4_cache_write_back(..., 1);
+ *
+ *      ext4_cache_write_back(..., 0);
+ *      ext4_cache_write_back(..., 0);
+ *
+ * Write back mode is useful when you want to create a lot of empty
+ * files/directories.
+ *
+ * @param   path mount point path
+ * @param   on enable/disable
+ *
+ * @return  standard error code */
+int ext4_cache_write_back(const char *path, bool on);
+
+/********************************FILE OPERATIONS*****************************/
+
+/**@brief   Remove file by path.
+ * @param   path path to file
+ * @return  standard error code */
+int ext4_fremove(const char *path);
+
+/**@brief Rename file
+ * @param path source
+ * @param new_path destination
+ * @return  standard error code */
+int ext4_frename(const char *path, const char *new_path);
+
+/**@brief   File open function.
+ * @param   filename, (has to start from mount point)
+ *          /my_partition/my_file
+ * @param   flags open file flags
+ *  |---------------------------------------------------------------|
+ *  |   r or rb                 O_RDONLY                            |
+ *  |---------------------------------------------------------------|
+ *  |   w or wb                 O_WRONLY|O_CREAT|O_TRUNC            |
+ *  |---------------------------------------------------------------|
+ *  |   a or ab                 O_WRONLY|O_CREAT|O_APPEND           |
+ *  |---------------------------------------------------------------|
+ *  |   r+ or rb+ or r+b        O_RDWR                              |
+ *  |---------------------------------------------------------------|
+ *  |   w+ or wb+ or w+b        O_RDWR|O_CREAT|O_TRUNC              |
+ *  |---------------------------------------------------------------|
+ *  |   a+ or ab+ or a+b        O_RDWR|O_CREAT|O_APPEND             |
+ *  |---------------------------------------------------------------|
+ *
+ * @return  standard error code*/
+int ext4_fopen(ext4_file *f, const char *path, const char *flags);
+
+/**@brief   Alternate file open function.
+ * @param   filename, (has to start from mount point)
+ *          /my_partition/my_file
+ * @param   flags open file flags
+ * @return  standard error code*/
+int ext4_fopen2(ext4_file *f, const char *path, int flags, bool file_expect);
+
+/**@brief   File close function.
+ * @param   f file handle
+ * @return  standard error code*/
+int ext4_fclose(ext4_file *f);
+
+/**@brief   Fill in the ext4_inode buffer.
+ * @param   mount_point
+ * @param   inode no.
+ * @param   ext4_inode buffer
+ * @return  standard error code*/
+int ext4_fill_raw_inode(const char *mount_point, uint32_t ino,
+			struct ext4_inode *inode);
+
+/**@brief   File truncate function.
+ * @param   f file handle
+ * @param   new file size
+ * @return  standard error code*/
+int ext4_ftruncate(ext4_file *f, uint64_t size);
+
+/**@brief   Read data from file.
+ * @param   f file handle
+ * @param   buf output buffer
+ * @param   size bytes to read
+ * @param   rcnt bytes read (may be NULL)
+ * @return  standard error code*/
+int ext4_fread(ext4_file *f, void *buf, uint32_t size, uint32_t *rcnt);
+
+/**@brief   Write data to file.
+ * @param   f file handle
+ * @param   buf data to write
+ * @param   size write length
+ * @param   wcnt bytes written (may be NULL)
+ * @return  standard error code*/
+int ext4_fwrite(ext4_file *f, const void *buf, uint32_t size, uint32_t *wcnt);
+
+/**@brief   File seek operation.
+ * @param   f file handle
+ * @param   offset offset to seek
+ * @param   origin seek type:
+ *              @ref SEEK_SET
+ *              @ref SEEK_CUR
+ *              @ref SEEK_END
+ * @return  standard error code*/
+int ext4_fseek(ext4_file *f, uint64_t offset, uint32_t origin);
+
+/**@brief   Get file position.
+ * @param   f file handle
+ * @return  actual file position */
+uint64_t ext4_ftell(ext4_file *f);
+
+/**@brief   Get file size.
+ * @param   f file handle
+ * @return  file size */
+uint64_t ext4_fsize(ext4_file *f);
+
+int ext4_fchmod(ext4_file *f, uint32_t mode);
+int ext4_fchown(ext4_file *f, uint32_t uid, uint32_t gid);
+int ext4_file_set_atime(ext4_file *f, uint32_t atime);
+int ext4_file_set_mtime(ext4_file *f, uint32_t mtime);
+int ext4_file_set_ctime(ext4_file *f, uint32_t ctime);
+
+/*********************************DIRECTORY OPERATION***********************/
+
+/**@brief   Recursive directory remove.
+ * @param   path directory path to remove
+ * @return  standard error code*/
+int ext4_dir_rm(const char *path);
+
+/**@brief   Create new directory.
+ * @param   name new directory name
+ * @return  standard error code*/
+int ext4_dir_mk(const char *path);
+
+/**@brief   Directory open.
+ * @param   d directory handle
+ * @param   path directory path
+ * @return  standard error code*/
+int ext4_dir_open(ext4_dir *d, const char *path);
+
+/**@brief   Directory close.
+ * @param   d directory handle
+ * @return  standard error code*/
+int ext4_dir_close(ext4_dir *d);
+
+/**@brief   Return next directory entry.
+ * @param   d directory handle
+ * @param   id entry id
+ * @return  directory entry id (NULL if no entry)*/
+const ext4_direntry *ext4_dir_entry_next(ext4_dir *d);
+
+#endif /* EXT4_H_ */
+
+/**
+ * @}
+ */
--- a/lwext4/ext4_bcache.c
+++ b/lwext4/ext4_bcache.c
@@ -1,213 +1,213 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file  ext4_bcache.c
- * @brief Block cache allocator.
- */
-
-#include "ext4_config.h"
-#include "ext4_bcache.h"
-#include "ext4_debug.h"
-#include "ext4_errno.h"
-
-#include <string.h>
-#include <stdlib.h>
-
-int ext4_bcache_init_dynamic(struct ext4_bcache *bc, uint32_t cnt,
-			     uint32_t itemsize)
-{
-	ext4_assert(bc && cnt && itemsize);
-
-	memset(bc, 0, sizeof(struct ext4_bcache));
-
-	bc->data = malloc(cnt * itemsize);
-	if (!bc->data)
-		goto error;
-
-	bc->cnt = cnt;
-	bc->itemsize = itemsize;
-	bc->ref_blocks = 0;
-	bc->max_ref_blocks = 0;
-
-	return EOK;
-
-error:
-
-	if (bc->data)
-		free(bc->data);
-
-	memset(bc, 0, sizeof(struct ext4_bcache));
-
-	return ENOMEM;
-}
-
-int ext4_bcache_fini_dynamic(struct ext4_bcache *bc)
-{
-	if (bc->data)
-		free(bc->data);
-
-	memset(bc, 0, sizeof(struct ext4_bcache));
-
-	return EOK;
-}
-
-int ext4_bcache_alloc(struct ext4_bcache *bc, struct ext4_block *b,
-		      bool *is_new)
-{
-	uint32_t i;
-	ext4_assert(bc && b && is_new);
-
-	/*Check if valid.*/
-	ext4_assert(b->lb_id);
-	if (!b->lb_id) {
-		ext4_assert(b->lb_id);
-	}
-
-	uint32_t cache_id = bc->cnt;
-	uint32_t alloc_id = 0;
-
-	*is_new = false;
-
-	/*Find in free blocks (Last Recently Used).*/
-	for (i = 0; i < bc->cnt; ++i) {
-
-		/*Check if block is already in cache*/
-		if (b->lb_id == bc->lba[i]) {
-
-			if (!bc->refctr[i] && !bc->free_delay[i])
-				bc->ref_blocks++;
-
-			/*Update reference counter*/
-			bc->refctr[i]++;
-
-			/*Update usage marker*/
-			bc->lru_id[i] = ++bc->lru_ctr;
-
-			/*Set valid cache data and id*/
-			b->data = bc->data + i * bc->itemsize;
-			b->cache_id = i;
-
-			return EOK;
-		}
-
-		/*Best fit calculations.*/
-		if (bc->refctr[i])
-			continue;
-
-		if (bc->free_delay[i])
-			continue;
-
-		/*Block is unreferenced, but it may exist block with
-		 * lower usage marker*/
-
-		/*First find.*/
-		if (cache_id == bc->cnt) {
-			cache_id = i;
-			alloc_id = bc->lru_id[i];
-			continue;
-		}
-
-		/*Next find*/
-		if (alloc_id <= bc->lru_id[i])
-			continue;
-
-		/*This block has lower alloc id marker*/
-		cache_id = i;
-		alloc_id = bc->lru_id[i];
-	}
-
-	if (cache_id != bc->cnt) {
-		/*There was unreferenced block*/
-		bc->lba[cache_id] = b->lb_id;
-		bc->refctr[cache_id] = 1;
-		bc->lru_id[cache_id] = ++bc->lru_ctr;
-
-		/*Set valid cache data and id*/
-		b->data = bc->data + cache_id * bc->itemsize;
-		b->cache_id = cache_id;
-
-		/*Statistics*/
-		bc->ref_blocks++;
-		if (bc->ref_blocks > bc->max_ref_blocks)
-			bc->max_ref_blocks = bc->ref_blocks;
-
-		/*Block needs to be read.*/
-		*is_new = true;
-
-		return EOK;
-	}
-
-	ext4_dprintf(EXT4_DEBUG_BCACHE,
-		     "ext4_bcache_alloc: FAIL, unable to alloc block cache!\n");
-	return ENOMEM;
-}
-
-int ext4_bcache_free(struct ext4_bcache *bc, struct ext4_block *b,
-		     uint8_t free_delay)
-{
-	ext4_assert(bc && b);
-
-	/*Check if valid.*/
-	ext4_assert(b->lb_id);
-
-	/*Block should be in cache.*/
-	ext4_assert(b->cache_id < bc->cnt);
-
-	/*Check if someone don't try free unreferenced block cache.*/
-	ext4_assert(bc->refctr[b->cache_id]);
-
-	/*Just decrease reference counter*/
-	if (bc->refctr[b->cache_id])
-		bc->refctr[b->cache_id]--;
-
-	if (free_delay)
-		bc->free_delay[b->cache_id] = free_delay;
-
-	/*Update statistics*/
-	if (!bc->refctr[b->cache_id] && !bc->free_delay[b->cache_id])
-		bc->ref_blocks--;
-
-	b->lb_id = 0;
-	b->data = 0;
-	b->cache_id = 0;
-
-	return EOK;
-}
-
-bool ext4_bcache_is_full(struct ext4_bcache *bc)
-{
-	return (bc->cnt == bc->ref_blocks);
-}
-
-/**
- * @}
- */
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file  ext4_bcache.c
+ * @brief Block cache allocator.
+ */
+
+#include "ext4_config.h"
+#include "ext4_bcache.h"
+#include "ext4_debug.h"
+#include "ext4_errno.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+int ext4_bcache_init_dynamic(struct ext4_bcache *bc, uint32_t cnt,
+			     uint32_t itemsize)
+{
+	ext4_assert(bc && cnt && itemsize);
+
+	memset(bc, 0, sizeof(struct ext4_bcache));
+
+	bc->data = malloc(cnt * itemsize);
+	if (!bc->data)
+		goto error;
+
+	bc->cnt = cnt;
+	bc->itemsize = itemsize;
+	bc->ref_blocks = 0;
+	bc->max_ref_blocks = 0;
+
+	return EOK;
+
+error:
+
+	if (bc->data)
+		free(bc->data);
+
+	memset(bc, 0, sizeof(struct ext4_bcache));
+
+	return ENOMEM;
+}
+
+int ext4_bcache_fini_dynamic(struct ext4_bcache *bc)
+{
+	if (bc->data)
+		free(bc->data);
+
+	memset(bc, 0, sizeof(struct ext4_bcache));
+
+	return EOK;
+}
+
+int ext4_bcache_alloc(struct ext4_bcache *bc, struct ext4_block *b,
+		      bool *is_new)
+{
+	uint32_t i;
+	ext4_assert(bc && b && is_new);
+
+	/*Check if valid.*/
+	ext4_assert(b->lb_id);
+	if (!b->lb_id) {
+		ext4_assert(b->lb_id);
+	}
+
+	uint32_t cache_id = bc->cnt;
+	uint32_t alloc_id = 0;
+
+	*is_new = false;
+
+	/*Find in free blocks (Last Recently Used).*/
+	for (i = 0; i < bc->cnt; ++i) {
+
+		/*Check if block is already in cache*/
+		if (b->lb_id == bc->lba[i]) {
+
+			if (!bc->refctr[i] && !bc->free_delay[i])
+				bc->ref_blocks++;
+
+			/*Update reference counter*/
+			bc->refctr[i]++;
+
+			/*Update usage marker*/
+			bc->lru_id[i] = ++bc->lru_ctr;
+
+			/*Set valid cache data and id*/
+			b->data = bc->data + i * bc->itemsize;
+			b->cache_id = i;
+
+			return EOK;
+		}
+
+		/*Best fit calculations.*/
+		if (bc->refctr[i])
+			continue;
+
+		if (bc->free_delay[i])
+			continue;
+
+		/*Block is unreferenced, but it may exist block with
+		 * lower usage marker*/
+
+		/*First find.*/
+		if (cache_id == bc->cnt) {
+			cache_id = i;
+			alloc_id = bc->lru_id[i];
+			continue;
+		}
+
+		/*Next find*/
+		if (alloc_id <= bc->lru_id[i])
+			continue;
+
+		/*This block has lower alloc id marker*/
+		cache_id = i;
+		alloc_id = bc->lru_id[i];
+	}
+
+	if (cache_id != bc->cnt) {
+		/*There was unreferenced block*/
+		bc->lba[cache_id] = b->lb_id;
+		bc->refctr[cache_id] = 1;
+		bc->lru_id[cache_id] = ++bc->lru_ctr;
+
+		/*Set valid cache data and id*/
+		b->data = bc->data + cache_id * bc->itemsize;
+		b->cache_id = cache_id;
+
+		/*Statistics*/
+		bc->ref_blocks++;
+		if (bc->ref_blocks > bc->max_ref_blocks)
+			bc->max_ref_blocks = bc->ref_blocks;
+
+		/*Block needs to be read.*/
+		*is_new = true;
+
+		return EOK;
+	}
+
+	ext4_dprintf(EXT4_DEBUG_BCACHE,
+		     "ext4_bcache_alloc: FAIL, unable to alloc block cache!\n");
+	return ENOMEM;
+}
+
+int ext4_bcache_free(struct ext4_bcache *bc, struct ext4_block *b,
+		     uint8_t free_delay)
+{
+	ext4_assert(bc && b);
+
+	/*Check if valid.*/
+	ext4_assert(b->lb_id);
+
+	/*Block should be in cache.*/
+	ext4_assert(b->cache_id < bc->cnt);
+
+	/*Check if someone don't try free unreferenced block cache.*/
+	ext4_assert(bc->refctr[b->cache_id]);
+
+	/*Just decrease reference counter*/
+	if (bc->refctr[b->cache_id])
+		bc->refctr[b->cache_id]--;
+
+	if (free_delay)
+		bc->free_delay[b->cache_id] = free_delay;
+
+	/*Update statistics*/
+	if (!bc->refctr[b->cache_id] && !bc->free_delay[b->cache_id])
+		bc->ref_blocks--;
+
+	b->lb_id = 0;
+	b->data = 0;
+	b->cache_id = 0;
+
+	return EOK;
+}
+
+bool ext4_bcache_is_full(struct ext4_bcache *bc)
+{
+	return (bc->cnt == bc->ref_blocks);
+}
+
+/**
+ * @}
+ */
--- a/lwext4/ext4_bcache.h
+++ b/lwext4/ext4_bcache.h
@@ -1,147 +1,147 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file  ext4_bcache.h
- * @brief Block cache allocator.
- */
-
-#ifndef EXT4_BCACHE_H_
-#define EXT4_BCACHE_H_
-
-#include "ext4_config.h"
-
-#include <stdint.h>
-#include <stdbool.h>
-
-/**@brief   Single block descriptor*/
-struct ext4_block {
-	/**@brief   Dirty flag*/
-	bool dirty;
-
-	/**@brief   Logical block ID*/
-	uint64_t lb_id;
-
-	/**@brief   Cache id*/
-	uint32_t cache_id;
-
-	/**@brief   Data buffer.*/
-	uint8_t *data;
-};
-
-/**@brief   Block cache descriptor*/
-struct ext4_bcache {
-
-	/**@brief   Item count in block cache*/
-	uint32_t cnt;
-
-	/**@brief   Item size in block cache*/
-	uint32_t itemsize;
-
-	/**@brief   Last recently used counter*/
-	uint32_t lru_ctr;
-
-	/**@brief   Reference count table*/
-	uint32_t refctr[CONFIG_BLOCK_DEV_CACHE_SIZE];
-
-	/**@brief   Last recently used ID table*/
-	uint32_t lru_id[CONFIG_BLOCK_DEV_CACHE_SIZE];
-
-	/**@brief   Writeback free delay mode table*/
-	uint8_t free_delay[CONFIG_BLOCK_DEV_CACHE_SIZE];
-
-	/**@brief   Logical block table*/
-	uint64_t lba[CONFIG_BLOCK_DEV_CACHE_SIZE];
-
-	/**@brief   Dirty mark*/
-	bool dirty[CONFIG_BLOCK_DEV_CACHE_SIZE];
-
-	/**@brief   Cache data buffers*/
-	uint8_t *data;
-
-	/**@brief   Currently referenced datablocks*/
-	uint32_t ref_blocks;
-
-	/**@brief   Maximum referenced datablocks*/
-	uint32_t max_ref_blocks;
-};
-
-/**@brief   Static initializer of block cache structure.*/
-#define EXT4_BCACHE_STATIC_INSTANCE(__name, __cnt, __itemsize)                 \
-	static uint8_t __name##_data[(__cnt) * (__itemsize)];                  \
-	static struct ext4_bcache __name = {                                   \
-	    .cnt = __cnt,                                                      \
-	    .itemsize = __itemsize,                                            \
-	    .lru_ctr = 0,                                                      \
-	    .data = __name##_data,                                             \
-	}
-
-/**@brief   Dynamic initialization of block cache.
- * @param   bc block cache descriptor
- * @param   cnt items count in block cache
- * @param   itemsize single item size (in bytes)
- * @return  standard error code*/
-int ext4_bcache_init_dynamic(struct ext4_bcache *bc, uint32_t cnt,
-			     uint32_t itemsize);
-
-/**@brief   Dynamic de-initialization of block cache.
- * @param   bc block cache descriptor
- * @return  standard error code*/
-int ext4_bcache_fini_dynamic(struct ext4_bcache *bc);
-
-/**@brief   Allocate block from block cache memory.
- *          Unreferenced block allocation is based on LRU
- *          (Last Recently Used) algorithm.
- * @param   bc block cache descriptor
- * @param   b block to alloc
- * @param   is_new block is new (needs to be read)
- * @return  standard error code*/
-int ext4_bcache_alloc(struct ext4_bcache *bc, struct ext4_block *b,
-		      bool *is_new);
-
-/**@brief   Free block from cache memory (decrement reference counter).
- * @param   bc block cache descriptor
- * @param   b block to free
- * @param   cache writeback mode
- * @return  standard error code*/
-int ext4_bcache_free(struct ext4_bcache *bc, struct ext4_block *b,
-		     uint8_t free_delay);
-
-/**@brief   Return a full status of block cache.
- * @param   bc block cache descriptor
- * @return  full status*/
-bool ext4_bcache_is_full(struct ext4_bcache *bc);
-
-#endif /* EXT4_BCACHE_H_ */
-
-/**
- * @}
- */
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file  ext4_bcache.h
+ * @brief Block cache allocator.
+ */
+
+#ifndef EXT4_BCACHE_H_
+#define EXT4_BCACHE_H_
+
+#include "ext4_config.h"
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/**@brief   Single block descriptor*/
+struct ext4_block {
+	/**@brief   Dirty flag*/
+	bool dirty;
+
+	/**@brief   Logical block ID*/
+	uint64_t lb_id;
+
+	/**@brief   Cache id*/
+	uint32_t cache_id;
+
+	/**@brief   Data buffer.*/
+	uint8_t *data;
+};
+
+/**@brief   Block cache descriptor*/
+struct ext4_bcache {
+
+	/**@brief   Item count in block cache*/
+	uint32_t cnt;
+
+	/**@brief   Item size in block cache*/
+	uint32_t itemsize;
+
+	/**@brief   Last recently used counter*/
+	uint32_t lru_ctr;
+
+	/**@brief   Reference count table*/
+	uint32_t refctr[CONFIG_BLOCK_DEV_CACHE_SIZE];
+
+	/**@brief   Last recently used ID table*/
+	uint32_t lru_id[CONFIG_BLOCK_DEV_CACHE_SIZE];
+
+	/**@brief   Writeback free delay mode table*/
+	uint8_t free_delay[CONFIG_BLOCK_DEV_CACHE_SIZE];
+
+	/**@brief   Logical block table*/
+	uint64_t lba[CONFIG_BLOCK_DEV_CACHE_SIZE];
+
+	/**@brief   Dirty mark*/
+	bool dirty[CONFIG_BLOCK_DEV_CACHE_SIZE];
+
+	/**@brief   Cache data buffers*/
+	uint8_t *data;
+
+	/**@brief   Currently referenced datablocks*/
+	uint32_t ref_blocks;
+
+	/**@brief   Maximum referenced datablocks*/
+	uint32_t max_ref_blocks;
+};
+
+/**@brief   Static initializer of block cache structure.*/
+#define EXT4_BCACHE_STATIC_INSTANCE(__name, __cnt, __itemsize)                 \
+	static uint8_t __name##_data[(__cnt) * (__itemsize)];                  \
+	static struct ext4_bcache __name = {                                   \
+	    .cnt = __cnt,                                                      \
+	    .itemsize = __itemsize,                                            \
+	    .lru_ctr = 0,                                                      \
+	    .data = __name##_data,                                             \
+	}
+
+/**@brief   Dynamic initialization of block cache.
+ * @param   bc block cache descriptor
+ * @param   cnt items count in block cache
+ * @param   itemsize single item size (in bytes)
+ * @return  standard error code*/
+int ext4_bcache_init_dynamic(struct ext4_bcache *bc, uint32_t cnt,
+			     uint32_t itemsize);
+
+/**@brief   Dynamic de-initialization of block cache.
+ * @param   bc block cache descriptor
+ * @return  standard error code*/
+int ext4_bcache_fini_dynamic(struct ext4_bcache *bc);
+
+/**@brief   Allocate block from block cache memory.
+ *          Unreferenced block allocation is based on LRU
+ *          (Last Recently Used) algorithm.
+ * @param   bc block cache descriptor
+ * @param   b block to alloc
+ * @param   is_new block is new (needs to be read)
+ * @return  standard error code*/
+int ext4_bcache_alloc(struct ext4_bcache *bc, struct ext4_block *b,
+		      bool *is_new);
+
+/**@brief   Free block from cache memory (decrement reference counter).
+ * @param   bc block cache descriptor
+ * @param   b block to free
+ * @param   cache writeback mode
+ * @return  standard error code*/
+int ext4_bcache_free(struct ext4_bcache *bc, struct ext4_block *b,
+		     uint8_t free_delay);
+
+/**@brief   Return a full status of block cache.
+ * @param   bc block cache descriptor
+ * @return  full status*/
+bool ext4_bcache_is_full(struct ext4_bcache *bc);
+
+#endif /* EXT4_BCACHE_H_ */
+
+/**
+ * @}
+ */
--- a/lwext4/ext4_dir.c
+++ b/lwext4/ext4_dir.c
@@ -1,574 +1,574 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file  ext4_dir.h
- * @brief Directory handle procedures.
- */
-
-#include "ext4_config.h"
-#include "ext4_dir.h"
-#include "ext4_dir_idx.h"
-#include "ext4_inode.h"
-#include "ext4_fs.h"
-
-#include <string.h>
-
-/****************************************************************************/
-
-/**@brief Do some checks before returning iterator.
- * @param it Iterator to be checked
- * @param block_size Size of data block
- * @return Error code
- */
-static int ext4_dir_iterator_set(struct ext4_directory_iterator *it,
-				 uint32_t block_size)
-{
-	it->current = NULL;
-
-	uint32_t offset_in_block = it->current_offset % block_size;
-
-	/* Ensure proper alignment */
-	if ((offset_in_block % 4) != 0)
-		return EIO;
-
-	/* Ensure that the core of the entry does not overflow the block */
-	if (offset_in_block > block_size - 8)
-		return EIO;
-
-	struct ext4_directory_entry_ll *entry =
-	    (void *)(it->current_block.data + offset_in_block);
-
-	/* Ensure that the whole entry does not overflow the block */
-	uint16_t length = ext4_dir_entry_ll_get_entry_length(entry);
-	if (offset_in_block + length > block_size)
-		return EIO;
-
-	/* Ensure the name length is not too large */
-	if (ext4_dir_entry_ll_get_name_length(&it->inode_ref->fs->sb, entry) >
-	    length - 8)
-		return EIO;
-
-	/* Everything OK - "publish" the entry */
-	it->current = entry;
-	return EOK;
-}
-
-/**@brief Seek to next valid directory entry.
- *        Here can be jumped to the next data block.
- * @param it  Initialized iterator
- * @param pos Position of the next entry
- * @return Error code
- */
-static int ext4_dir_iterator_seek(struct ext4_directory_iterator *it,
-				  uint64_t pos)
-{
-	uint64_t size =
-	    ext4_inode_get_size(&it->inode_ref->fs->sb, it->inode_ref->inode);
-
-	/* The iterator is not valid until we seek to the desired position */
-	it->current = NULL;
-
-	/* Are we at the end? */
-	if (pos >= size) {
-		if (it->current_block.lb_id) {
-
-			int rc = ext4_block_set(it->inode_ref->fs->bdev,
-						&it->current_block);
-			it->current_block.lb_id = 0;
-
-			if (rc != EOK)
-				return rc;
-		}
-
-		it->current_offset = pos;
-		return EOK;
-	}
-
-	/* Compute next block address */
-	uint32_t block_size = ext4_sb_get_block_size(&it->inode_ref->fs->sb);
-	uint64_t current_block_idx = it->current_offset / block_size;
-	uint64_t next_block_idx = pos / block_size;
-
-	/*
-	 * If we don't have a block or are moving across block boundary,
-	 * we need to get another block
-	 */
-	if ((it->current_block.lb_id == 0) ||
-	    (current_block_idx != next_block_idx)) {
-		if (it->current_block.lb_id) {
-			int rc = ext4_block_set(it->inode_ref->fs->bdev,
-						&it->current_block);
-			it->current_block.lb_id = 0;
-
-			if (rc != EOK)
-				return rc;
-		}
-
-		uint32_t next_block_phys_idx;
-		int rc = ext4_fs_get_inode_data_block_index(
-		    it->inode_ref, next_block_idx, &next_block_phys_idx);
-		if (rc != EOK)
-			return rc;
-
-		rc = ext4_block_get(it->inode_ref->fs->bdev, &it->current_block,
-				    next_block_phys_idx);
-		if (rc != EOK) {
-			it->current_block.lb_id = 0;
-			return rc;
-		}
-	}
-
-	it->current_offset = pos;
-
-	return ext4_dir_iterator_set(it, block_size);
-}
-
-int ext4_dir_iterator_init(struct ext4_directory_iterator *it,
-			   struct ext4_inode_ref *inode_ref, uint64_t pos)
-{
-	it->inode_ref = inode_ref;
-	it->current = 0;
-	it->current_offset = 0;
-	it->current_block.lb_id = 0;
-
-	return ext4_dir_iterator_seek(it, pos);
-}
-
-int ext4_dir_iterator_next(struct ext4_directory_iterator *it)
-{
-	int r = EOK;
-	uint16_t skip;
-
-	while (r == EOK) {
-		skip = ext4_dir_entry_ll_get_entry_length(it->current);
-		r = ext4_dir_iterator_seek(it, it->current_offset + skip);
-
-		if (!it->current)
-			break;
-		/*Skip NULL referenced entry*/
-		if (ext4_dir_entry_ll_get_inode(it->current) != 0)
-			break;
-	}
-
-	return r;
-}
-
-int ext4_dir_iterator_fini(struct ext4_directory_iterator *it)
-{
-	it->current = 0;
-
-	if (it->current_block.lb_id)
-		return ext4_block_set(it->inode_ref->fs->bdev,
-				      &it->current_block);
-
-	return EOK;
-}
-
-void ext4_dir_write_entry(struct ext4_sblock *sb,
-			  struct ext4_directory_entry_ll *entry,
-			  uint16_t entry_len, struct ext4_inode_ref *child,
-			  const char *name, size_t name_len)
-{
-	/* Check maximum entry length */
-	ext4_assert(entry_len <= ext4_sb_get_block_size(sb));
-
-	/* Set basic attributes */
-	ext4_dir_entry_ll_set_inode(entry, child->index);
-	ext4_dir_entry_ll_set_entry_length(entry, entry_len);
-	ext4_dir_entry_ll_set_name_length(sb, entry, name_len);
-
-	/* Write name */
-	memcpy(entry->name, name, name_len);
-
-	/* Set type of entry */
-	if (ext4_inode_is_type(sb, child->inode, EXT4_INODE_MODE_DIRECTORY))
-		ext4_dir_entry_ll_set_inode_type(sb, entry,
-						 EXT4_DIRECTORY_FILETYPE_DIR);
-	else
-		ext4_dir_entry_ll_set_inode_type(
-		    sb, entry, EXT4_DIRECTORY_FILETYPE_REG_FILE);
-}
-
-int ext4_dir_add_entry(struct ext4_inode_ref *parent, const char *name,
-		       uint32_t name_len, struct ext4_inode_ref *child)
-{
-	struct ext4_fs *fs = parent->fs;
-
-#if CONFIG_DIR_INDEX_ENABLE
-	/* Index adding (if allowed) */
-	if ((ext4_sb_has_feature_compatible(&fs->sb,
-					    EXT4_FEATURE_COMPAT_DIR_INDEX)) &&
-	    (ext4_inode_has_flag(parent->inode, EXT4_INODE_FLAG_INDEX))) {
-		int rc = ext4_dir_dx_add_entry(parent, child, name);
-
-		/* Check if index is not corrupted */
-		if (rc != EXT4_ERR_BAD_DX_DIR) {
-			if (rc != EOK)
-				return rc;
-
-			return EOK;
-		}
-
-		/* Needed to clear dir index flag if corrupted */
-		ext4_inode_clear_flag(parent->inode, EXT4_INODE_FLAG_INDEX);
-		parent->dirty = true;
-	}
-#endif
-
-	/* Linear algorithm */
-	uint32_t iblock = 0;
-	uint32_t fblock = 0;
-	uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
-	uint32_t inode_size = ext4_inode_get_size(&fs->sb, parent->inode);
-	uint32_t total_blocks = inode_size / block_size;
-
-	/* Find block, where is space for new entry and try to add */
-	bool success = false;
-	for (iblock = 0; iblock < total_blocks; ++iblock) {
-		int rc =
-		    ext4_fs_get_inode_data_block_index(parent, iblock, &fblock);
-		if (rc != EOK)
-			return rc;
-
-		struct ext4_block block;
-		rc = ext4_block_get(fs->bdev, &block, fblock);
-		if (rc != EOK)
-			return rc;
-
-		/* If adding is successful, function can finish */
-		rc = ext4_dir_try_insert_entry(&fs->sb, &block, child, name,
-					       name_len);
-		if (rc == EOK)
-			success = true;
-
-		rc = ext4_block_set(fs->bdev, &block);
-		if (rc != EOK)
-			return rc;
-
-		if (success)
-			return EOK;
-	}
-
-	/* No free block found - needed to allocate next data block */
-
-	iblock = 0;
-	fblock = 0;
-	int rc = ext4_fs_append_inode_block(parent, &fblock, &iblock);
-	if (rc != EOK)
-		return rc;
-
-	/* Load new block */
-	struct ext4_block new_block;
-
-	rc = ext4_block_get(fs->bdev, &new_block, fblock);
-	if (rc != EOK)
-		return rc;
-
-	/* Fill block with zeroes */
-	memset(new_block.data, 0, block_size);
-	struct ext4_directory_entry_ll *block_entry = (void *)new_block.data;
-	ext4_dir_write_entry(&fs->sb, block_entry, block_size, child, name,
-			     name_len);
-
-	/* Save new block */
-	new_block.dirty = true;
-	rc = ext4_block_set(fs->bdev, &new_block);
-
-	return rc;
-}
-
-int ext4_dir_find_entry(struct ext4_directory_search_result *result,
-			struct ext4_inode_ref *parent, const char *name,
-			uint32_t name_len)
-{
-	struct ext4_sblock *sb = &parent->fs->sb;
-
-#if CONFIG_DIR_INDEX_ENABLE
-	/* Index search */
-	if ((ext4_sb_has_feature_compatible(sb,
-					    EXT4_FEATURE_COMPAT_DIR_INDEX)) &&
-	    (ext4_inode_has_flag(parent->inode, EXT4_INODE_FLAG_INDEX))) {
-		int rc = ext4_dir_dx_find_entry(result, parent, name_len, name);
-
-		/* Check if index is not corrupted */
-		if (rc != EXT4_ERR_BAD_DX_DIR) {
-			if (rc != EOK)
-				return rc;
-
-			return EOK;
-		}
-
-		/* Needed to clear dir index flag if corrupted */
-		ext4_inode_clear_flag(parent->inode, EXT4_INODE_FLAG_INDEX);
-		parent->dirty = true;
-	}
-#endif
-
-	/* Linear algorithm */
-
-	uint32_t iblock;
-	uint32_t fblock;
-	uint32_t block_size = ext4_sb_get_block_size(sb);
-	uint32_t inode_size = ext4_inode_get_size(sb, parent->inode);
-	uint32_t total_blocks = inode_size / block_size;
-
-	/* Walk through all data blocks */
-	for (iblock = 0; iblock < total_blocks; ++iblock) {
-		/* Load block address */
-		int rc =
-		    ext4_fs_get_inode_data_block_index(parent, iblock, &fblock);
-		if (rc != EOK)
-			return rc;
-
-		/* Load data block */
-		struct ext4_block block;
-		rc = ext4_block_get(parent->fs->bdev, &block, fblock);
-		if (rc != EOK)
-			return rc;
-
-		/* Try to find entry in block */
-		struct ext4_directory_entry_ll *res_entry;
-		rc = ext4_dir_find_in_block(&block, sb, name_len, name,
-					    &res_entry);
-		if (rc == EOK) {
-			result->block = block;
-			result->dentry = res_entry;
-			return EOK;
-		}
-
-		/* Entry not found - put block and continue to the next block */
-
-		rc = ext4_block_set(parent->fs->bdev, &block);
-		if (rc != EOK)
-			return rc;
-	}
-
-	/* Entry was not found */
-
-	result->block.lb_id = 0;
-	result->dentry = NULL;
-
-	return ENOENT;
-}
-
-int ext4_dir_remove_entry(struct ext4_inode_ref *parent, const char *name,
-			  uint32_t name_len)
-{
-	/* Check if removing from directory */
-	if (!ext4_inode_is_type(&parent->fs->sb, parent->inode,
-				EXT4_INODE_MODE_DIRECTORY))
-		return ENOTDIR;
-
-	/* Try to find entry */
-	struct ext4_directory_search_result result;
-	int rc = ext4_dir_find_entry(&result, parent, name, name_len);
-	if (rc != EOK)
-		return rc;
-
-	/* Invalidate entry */
-	ext4_dir_entry_ll_set_inode(result.dentry, 0);
-
-	/* Store entry position in block */
-	uint32_t pos = (uint8_t *)result.dentry - result.block.data;
-
-	/*
-	 * If entry is not the first in block, it must be merged
-	 * with previous entry
-	 */
-	if (pos != 0) {
-		uint32_t offset = 0;
-
-		/* Start from the first entry in block */
-		struct ext4_directory_entry_ll *tmp_dentry =
-		    (void *)result.block.data;
-		uint16_t tmp_dentry_length =
-		    ext4_dir_entry_ll_get_entry_length(tmp_dentry);
-
-		/* Find direct predecessor of removed entry */
-		while ((offset + tmp_dentry_length) < pos) {
-			offset +=
-			    ext4_dir_entry_ll_get_entry_length(tmp_dentry);
-			tmp_dentry = (void *)(result.block.data + offset);
-			tmp_dentry_length =
-			    ext4_dir_entry_ll_get_entry_length(tmp_dentry);
-		}
-
-		ext4_assert(tmp_dentry_length + offset == pos);
-
-		/* Add to removed entry length to predecessor's length */
-		uint16_t del_entry_length =
-		    ext4_dir_entry_ll_get_entry_length(result.dentry);
-		ext4_dir_entry_ll_set_entry_length(
-		    tmp_dentry, tmp_dentry_length + del_entry_length);
-	}
-
-	result.block.dirty = true;
-
-	return ext4_dir_destroy_result(parent, &result);
-}
-
-int ext4_dir_try_insert_entry(struct ext4_sblock *sb,
-			      struct ext4_block *target_block,
-			      struct ext4_inode_ref *child, const char *name,
-			      uint32_t name_len)
-{
-	/* Compute required length entry and align it to 4 bytes */
-	uint32_t block_size = ext4_sb_get_block_size(sb);
-	uint16_t required_len =
-	    sizeof(struct ext4_fake_directory_entry) + name_len;
-
-	if ((required_len % 4) != 0)
-		required_len += 4 - (required_len % 4);
-
-	/* Initialize pointers, stop means to upper bound */
-	struct ext4_directory_entry_ll *dentry = (void *)target_block->data;
-	struct ext4_directory_entry_ll *stop =
-	    (void *)(target_block->data + block_size);
-
-	/*
-	 * Walk through the block and check for invalid entries
-	 * or entries with free space for new entry
-	 */
-	while (dentry < stop) {
-		uint32_t inode = ext4_dir_entry_ll_get_inode(dentry);
-		uint16_t rec_len = ext4_dir_entry_ll_get_entry_length(dentry);
-
-		/* If invalid and large enough entry, use it */
-		if ((inode == 0) && (rec_len >= required_len)) {
-			ext4_dir_write_entry(sb, dentry, rec_len, child, name,
-					     name_len);
-			target_block->dirty = true;
-
-			return EOK;
-		}
-
-		/* Valid entry, try to split it */
-		if (inode != 0) {
-			uint16_t used_name_len =
-			    ext4_dir_entry_ll_get_name_length(sb, dentry);
-
-			uint16_t used_space =
-			    sizeof(struct ext4_fake_directory_entry) +
-			    used_name_len;
-
-			if ((used_name_len % 4) != 0)
-				used_space += 4 - (used_name_len % 4);
-
-			uint16_t free_space = rec_len - used_space;
-
-			/* There is free space for new entry */
-			if (free_space >= required_len) {
-				/* Cut tail of current entry */
-				ext4_dir_entry_ll_set_entry_length(dentry,
-								   used_space);
-				struct ext4_directory_entry_ll *new_entry =
-				    (void *)((uint8_t *)dentry + used_space);
-				ext4_dir_write_entry(sb, new_entry, free_space,
-						     child, name, name_len);
-
-				target_block->dirty = true;
-				return EOK;
-			}
-		}
-
-		/* Jump to the next entry */
-		dentry = (void *)((uint8_t *)dentry + rec_len);
-	}
-
-	/* No free space found for new entry */
-	return ENOSPC;
-}
-
-int ext4_dir_find_in_block(struct ext4_block *block, struct ext4_sblock *sb,
-			   size_t name_len, const char *name,
-			   struct ext4_directory_entry_ll **res_entry)
-{
-	/* Start from the first entry in block */
-	struct ext4_directory_entry_ll *dentry =
-	    (struct ext4_directory_entry_ll *)block->data;
-
-	/* Set upper bound for cycling */
-	uint8_t *addr_limit = block->data + ext4_sb_get_block_size(sb);
-
-	/* Walk through the block and check entries */
-	while ((uint8_t *)dentry < addr_limit) {
-		/* Termination condition */
-		if ((uint8_t *)dentry + name_len > addr_limit)
-			break;
-
-		/* Valid entry - check it */
-		if (ext4_dir_entry_ll_get_inode(dentry) != 0) {
-			/* For more efficient compare only lengths firstly*/
-			if (ext4_dir_entry_ll_get_name_length(sb, dentry) ==
-			    name_len) {
-				/* Compare names */
-				if (memcmp((uint8_t *)name, dentry->name,
-					   name_len) == 0) {
-					*res_entry = dentry;
-					return EOK;
-				}
-			}
-		}
-
-		uint16_t dentry_len =
-		    ext4_dir_entry_ll_get_entry_length(dentry);
-
-		/* Corrupted entry */
-		if (dentry_len == 0)
-			return EINVAL;
-
-		/* Jump to next entry */
-		dentry = (struct ext4_directory_entry_ll *)((uint8_t *)dentry +
-							    dentry_len);
-	}
-
-	/* Entry not found */
-	return ENOENT;
-}
-
-int ext4_dir_destroy_result(struct ext4_inode_ref *parent,
-			    struct ext4_directory_search_result *result)
-{
-	if (result->block.lb_id)
-		return ext4_block_set(parent->fs->bdev, &result->block);
-
-	return EOK;
-}
-
-/**
- * @}
- */
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file  ext4_dir.h
+ * @brief Directory handle procedures.
+ */
+
+#include "ext4_config.h"
+#include "ext4_dir.h"
+#include "ext4_dir_idx.h"
+#include "ext4_inode.h"
+#include "ext4_fs.h"
+
+#include <string.h>
+
+/****************************************************************************/
+
+/**@brief Do some checks before returning iterator.
+ * @param it Iterator to be checked
+ * @param block_size Size of data block
+ * @return Error code
+ */
+static int ext4_dir_iterator_set(struct ext4_directory_iterator *it,
+				 uint32_t block_size)
+{
+	it->current = NULL;
+
+	uint32_t offset_in_block = it->current_offset % block_size;
+
+	/* Ensure proper alignment */
+	if ((offset_in_block % 4) != 0)
+		return EIO;
+
+	/* Ensure that the core of the entry does not overflow the block */
+	if (offset_in_block > block_size - 8)
+		return EIO;
+
+	struct ext4_directory_entry_ll *entry =
+	    (void *)(it->current_block.data + offset_in_block);
+
+	/* Ensure that the whole entry does not overflow the block */
+	uint16_t length = ext4_dir_entry_ll_get_entry_length(entry);
+	if (offset_in_block + length > block_size)
+		return EIO;
+
+	/* Ensure the name length is not too large */
+	if (ext4_dir_entry_ll_get_name_length(&it->inode_ref->fs->sb, entry) >
+	    length - 8)
+		return EIO;
+
+	/* Everything OK - "publish" the entry */
+	it->current = entry;
+	return EOK;
+}
+
+/**@brief Seek to next valid directory entry.
+ *        Here can be jumped to the next data block.
+ * @param it  Initialized iterator
+ * @param pos Position of the next entry
+ * @return Error code
+ */
+static int ext4_dir_iterator_seek(struct ext4_directory_iterator *it,
+				  uint64_t pos)
+{
+	uint64_t size =
+	    ext4_inode_get_size(&it->inode_ref->fs->sb, it->inode_ref->inode);
+
+	/* The iterator is not valid until we seek to the desired position */
+	it->current = NULL;
+
+	/* Are we at the end? */
+	if (pos >= size) {
+		if (it->current_block.lb_id) {
+
+			int rc = ext4_block_set(it->inode_ref->fs->bdev,
+						&it->current_block);
+			it->current_block.lb_id = 0;
+
+			if (rc != EOK)
+				return rc;
+		}
+
+		it->current_offset = pos;
+		return EOK;
+	}
+
+	/* Compute next block address */
+	uint32_t block_size = ext4_sb_get_block_size(&it->inode_ref->fs->sb);
+	uint64_t current_block_idx = it->current_offset / block_size;
+	uint64_t next_block_idx = pos / block_size;
+
+	/*
+	 * If we don't have a block or are moving across block boundary,
+	 * we need to get another block
+	 */
+	if ((it->current_block.lb_id == 0) ||
+	    (current_block_idx != next_block_idx)) {
+		if (it->current_block.lb_id) {
+			int rc = ext4_block_set(it->inode_ref->fs->bdev,
+						&it->current_block);
+			it->current_block.lb_id = 0;
+
+			if (rc != EOK)
+				return rc;
+		}
+
+		uint32_t next_block_phys_idx;
+		int rc = ext4_fs_get_inode_data_block_index(
+		    it->inode_ref, next_block_idx, &next_block_phys_idx);
+		if (rc != EOK)
+			return rc;
+
+		rc = ext4_block_get(it->inode_ref->fs->bdev, &it->current_block,
+				    next_block_phys_idx);
+		if (rc != EOK) {
+			it->current_block.lb_id = 0;
+			return rc;
+		}
+	}
+
+	it->current_offset = pos;
+
+	return ext4_dir_iterator_set(it, block_size);
+}
+
+int ext4_dir_iterator_init(struct ext4_directory_iterator *it,
+			   struct ext4_inode_ref *inode_ref, uint64_t pos)
+{
+	it->inode_ref = inode_ref;
+	it->current = 0;
+	it->current_offset = 0;
+	it->current_block.lb_id = 0;
+
+	return ext4_dir_iterator_seek(it, pos);
+}
+
+int ext4_dir_iterator_next(struct ext4_directory_iterator *it)
+{
+	int r = EOK;
+	uint16_t skip;
+
+	while (r == EOK) {
+		skip = ext4_dir_entry_ll_get_entry_length(it->current);
+		r = ext4_dir_iterator_seek(it, it->current_offset + skip);
+
+		if (!it->current)
+			break;
+		/*Skip NULL referenced entry*/
+		if (ext4_dir_entry_ll_get_inode(it->current) != 0)
+			break;
+	}
+
+	return r;
+}
+
+int ext4_dir_iterator_fini(struct ext4_directory_iterator *it)
+{
+	it->current = 0;
+
+	if (it->current_block.lb_id)
+		return ext4_block_set(it->inode_ref->fs->bdev,
+				      &it->current_block);
+
+	return EOK;
+}
+
+void ext4_dir_write_entry(struct ext4_sblock *sb,
+			  struct ext4_directory_entry_ll *entry,
+			  uint16_t entry_len, struct ext4_inode_ref *child,
+			  const char *name, size_t name_len)
+{
+	/* Check maximum entry length */
+	ext4_assert(entry_len <= ext4_sb_get_block_size(sb));
+
+	/* Set basic attributes */
+	ext4_dir_entry_ll_set_inode(entry, child->index);
+	ext4_dir_entry_ll_set_entry_length(entry, entry_len);
+	ext4_dir_entry_ll_set_name_length(sb, entry, name_len);
+
+	/* Write name */
+	memcpy(entry->name, name, name_len);
+
+	/* Set type of entry */
+	if (ext4_inode_is_type(sb, child->inode, EXT4_INODE_MODE_DIRECTORY))
+		ext4_dir_entry_ll_set_inode_type(sb, entry,
+						 EXT4_DIRECTORY_FILETYPE_DIR);
+	else
+		ext4_dir_entry_ll_set_inode_type(
+		    sb, entry, EXT4_DIRECTORY_FILETYPE_REG_FILE);
+}
+
+int ext4_dir_add_entry(struct ext4_inode_ref *parent, const char *name,
+		       uint32_t name_len, struct ext4_inode_ref *child)
+{
+	struct ext4_fs *fs = parent->fs;
+
+#if CONFIG_DIR_INDEX_ENABLE
+	/* Index adding (if allowed) */
+	if ((ext4_sb_has_feature_compatible(&fs->sb,
+					    EXT4_FEATURE_COMPAT_DIR_INDEX)) &&
+	    (ext4_inode_has_flag(parent->inode, EXT4_INODE_FLAG_INDEX))) {
+		int rc = ext4_dir_dx_add_entry(parent, child, name);
+
+		/* Check if index is not corrupted */
+		if (rc != EXT4_ERR_BAD_DX_DIR) {
+			if (rc != EOK)
+				return rc;
+
+			return EOK;
+		}
+
+		/* Needed to clear dir index flag if corrupted */
+		ext4_inode_clear_flag(parent->inode, EXT4_INODE_FLAG_INDEX);
+		parent->dirty = true;
+	}
+#endif
+
+	/* Linear algorithm */
+	uint32_t iblock = 0;
+	uint32_t fblock = 0;
+	uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
+	uint32_t inode_size = ext4_inode_get_size(&fs->sb, parent->inode);
+	uint32_t total_blocks = inode_size / block_size;
+
+	/* Find block, where is space for new entry and try to add */
+	bool success = false;
+	for (iblock = 0; iblock < total_blocks; ++iblock) {
+		int rc =
+		    ext4_fs_get_inode_data_block_index(parent, iblock, &fblock);
+		if (rc != EOK)
+			return rc;
+
+		struct ext4_block block;
+		rc = ext4_block_get(fs->bdev, &block, fblock);
+		if (rc != EOK)
+			return rc;
+
+		/* If adding is successful, function can finish */
+		rc = ext4_dir_try_insert_entry(&fs->sb, &block, child, name,
+					       name_len);
+		if (rc == EOK)
+			success = true;
+
+		rc = ext4_block_set(fs->bdev, &block);
+		if (rc != EOK)
+			return rc;
+
+		if (success)
+			return EOK;
+	}
+
+	/* No free block found - needed to allocate next data block */
+
+	iblock = 0;
+	fblock = 0;
+	int rc = ext4_fs_append_inode_block(parent, &fblock, &iblock);
+	if (rc != EOK)
+		return rc;
+
+	/* Load new block */
+	struct ext4_block new_block;
+
+	rc = ext4_block_get(fs->bdev, &new_block, fblock);
+	if (rc != EOK)
+		return rc;
+
+	/* Fill block with zeroes */
+	memset(new_block.data, 0, block_size);
+	struct ext4_directory_entry_ll *block_entry = (void *)new_block.data;
+	ext4_dir_write_entry(&fs->sb, block_entry, block_size, child, name,
+			     name_len);
+
+	/* Save new block */
+	new_block.dirty = true;
+	rc = ext4_block_set(fs->bdev, &new_block);
+
+	return rc;
+}
+
+int ext4_dir_find_entry(struct ext4_directory_search_result *result,
+			struct ext4_inode_ref *parent, const char *name,
+			uint32_t name_len)
+{
+	struct ext4_sblock *sb = &parent->fs->sb;
+
+#if CONFIG_DIR_INDEX_ENABLE
+	/* Index search */
+	if ((ext4_sb_has_feature_compatible(sb,
+					    EXT4_FEATURE_COMPAT_DIR_INDEX)) &&
+	    (ext4_inode_has_flag(parent->inode, EXT4_INODE_FLAG_INDEX))) {
+		int rc = ext4_dir_dx_find_entry(result, parent, name_len, name);
+
+		/* Check if index is not corrupted */
+		if (rc != EXT4_ERR_BAD_DX_DIR) {
+			if (rc != EOK)
+				return rc;
+
+			return EOK;
+		}
+
+		/* Needed to clear dir index flag if corrupted */
+		ext4_inode_clear_flag(parent->inode, EXT4_INODE_FLAG_INDEX);
+		parent->dirty = true;
+	}
+#endif
+
+	/* Linear algorithm */
+
+	uint32_t iblock;
+	uint32_t fblock;
+	uint32_t block_size = ext4_sb_get_block_size(sb);
+	uint32_t inode_size = ext4_inode_get_size(sb, parent->inode);
+	uint32_t total_blocks = inode_size / block_size;
+
+	/* Walk through all data blocks */
+	for (iblock = 0; iblock < total_blocks; ++iblock) {
+		/* Load block address */
+		int rc =
+		    ext4_fs_get_inode_data_block_index(parent, iblock, &fblock);
+		if (rc != EOK)
+			return rc;
+
+		/* Load data block */
+		struct ext4_block block;
+		rc = ext4_block_get(parent->fs->bdev, &block, fblock);
+		if (rc != EOK)
+			return rc;
+
+		/* Try to find entry in block */
+		struct ext4_directory_entry_ll *res_entry;
+		rc = ext4_dir_find_in_block(&block, sb, name_len, name,
+					    &res_entry);
+		if (rc == EOK) {
+			result->block = block;
+			result->dentry = res_entry;
+			return EOK;
+		}
+
+		/* Entry not found - put block and continue to the next block */
+
+		rc = ext4_block_set(parent->fs->bdev, &block);
+		if (rc != EOK)
+			return rc;
+	}
+
+	/* Entry was not found */
+
+	result->block.lb_id = 0;
+	result->dentry = NULL;
+
+	return ENOENT;
+}
+
+int ext4_dir_remove_entry(struct ext4_inode_ref *parent, const char *name,
+			  uint32_t name_len)
+{
+	/* Check if removing from directory */
+	if (!ext4_inode_is_type(&parent->fs->sb, parent->inode,
+				EXT4_INODE_MODE_DIRECTORY))
+		return ENOTDIR;
+
+	/* Try to find entry */
+	struct ext4_directory_search_result result;
+	int rc = ext4_dir_find_entry(&result, parent, name, name_len);
+	if (rc != EOK)
+		return rc;
+
+	/* Invalidate entry */
+	ext4_dir_entry_ll_set_inode(result.dentry, 0);
+
+	/* Store entry position in block */
+	uint32_t pos = (uint8_t *)result.dentry - result.block.data;
+
+	/*
+	 * If entry is not the first in block, it must be merged
+	 * with previous entry
+	 */
+	if (pos != 0) {
+		uint32_t offset = 0;
+
+		/* Start from the first entry in block */
+		struct ext4_directory_entry_ll *tmp_dentry =
+		    (void *)result.block.data;
+		uint16_t tmp_dentry_length =
+		    ext4_dir_entry_ll_get_entry_length(tmp_dentry);
+
+		/* Find direct predecessor of removed entry */
+		while ((offset + tmp_dentry_length) < pos) {
+			offset +=
+			    ext4_dir_entry_ll_get_entry_length(tmp_dentry);
+			tmp_dentry = (void *)(result.block.data + offset);
+			tmp_dentry_length =
+			    ext4_dir_entry_ll_get_entry_length(tmp_dentry);
+		}
+
+		ext4_assert(tmp_dentry_length + offset == pos);
+
+		/* Add to removed entry length to predecessor's length */
+		uint16_t del_entry_length =
+		    ext4_dir_entry_ll_get_entry_length(result.dentry);
+		ext4_dir_entry_ll_set_entry_length(
+		    tmp_dentry, tmp_dentry_length + del_entry_length);
+	}
+
+	result.block.dirty = true;
+
+	return ext4_dir_destroy_result(parent, &result);
+}
+
+int ext4_dir_try_insert_entry(struct ext4_sblock *sb,
+			      struct ext4_block *target_block,
+			      struct ext4_inode_ref *child, const char *name,
+			      uint32_t name_len)
+{
+	/* Compute required length entry and align it to 4 bytes */
+	uint32_t block_size = ext4_sb_get_block_size(sb);
+	uint16_t required_len =
+	    sizeof(struct ext4_fake_directory_entry) + name_len;
+
+	if ((required_len % 4) != 0)
+		required_len += 4 - (required_len % 4);
+
+	/* Initialize pointers, stop means to upper bound */
+	struct ext4_directory_entry_ll *dentry = (void *)target_block->data;
+	struct ext4_directory_entry_ll *stop =
+	    (void *)(target_block->data + block_size);
+
+	/*
+	 * Walk through the block and check for invalid entries
+	 * or entries with free space for new entry
+	 */
+	while (dentry < stop) {
+		uint32_t inode = ext4_dir_entry_ll_get_inode(dentry);
+		uint16_t rec_len = ext4_dir_entry_ll_get_entry_length(dentry);
+
+		/* If invalid and large enough entry, use it */
+		if ((inode == 0) && (rec_len >= required_len)) {
+			ext4_dir_write_entry(sb, dentry, rec_len, child, name,
+					     name_len);
+			target_block->dirty = true;
+
+			return EOK;
+		}
+
+		/* Valid entry, try to split it */
+		if (inode != 0) {
+			uint16_t used_name_len =
+			    ext4_dir_entry_ll_get_name_length(sb, dentry);
+
+			uint16_t used_space =
+			    sizeof(struct ext4_fake_directory_entry) +
+			    used_name_len;
+
+			if ((used_name_len % 4) != 0)
+				used_space += 4 - (used_name_len % 4);
+
+			uint16_t free_space = rec_len - used_space;
+
+			/* There is free space for new entry */
+			if (free_space >= required_len) {
+				/* Cut tail of current entry */
+				ext4_dir_entry_ll_set_entry_length(dentry,
+								   used_space);
+				struct ext4_directory_entry_ll *new_entry =
+				    (void *)((uint8_t *)dentry + used_space);
+				ext4_dir_write_entry(sb, new_entry, free_space,
+						     child, name, name_len);
+
+				target_block->dirty = true;
+				return EOK;
+			}
+		}
+
+		/* Jump to the next entry */
+		dentry = (void *)((uint8_t *)dentry + rec_len);
+	}
+
+	/* No free space found for new entry */
+	return ENOSPC;
+}
+
+int ext4_dir_find_in_block(struct ext4_block *block, struct ext4_sblock *sb,
+			   size_t name_len, const char *name,
+			   struct ext4_directory_entry_ll **res_entry)
+{
+	/* Start from the first entry in block */
+	struct ext4_directory_entry_ll *dentry =
+	    (struct ext4_directory_entry_ll *)block->data;
+
+	/* Set upper bound for cycling */
+	uint8_t *addr_limit = block->data + ext4_sb_get_block_size(sb);
+
+	/* Walk through the block and check entries */
+	while ((uint8_t *)dentry < addr_limit) {
+		/* Termination condition */
+		if ((uint8_t *)dentry + name_len > addr_limit)
+			break;
+
+		/* Valid entry - check it */
+		if (ext4_dir_entry_ll_get_inode(dentry) != 0) {
+			/* For more efficient compare only lengths firstly*/
+			if (ext4_dir_entry_ll_get_name_length(sb, dentry) ==
+			    name_len) {
+				/* Compare names */
+				if (memcmp((uint8_t *)name, dentry->name,
+					   name_len) == 0) {
+					*res_entry = dentry;
+					return EOK;
+				}
+			}
+		}
+
+		uint16_t dentry_len =
+		    ext4_dir_entry_ll_get_entry_length(dentry);
+
+		/* Corrupted entry */
+		if (dentry_len == 0)
+			return EINVAL;
+
+		/* Jump to next entry */
+		dentry = (struct ext4_directory_entry_ll *)((uint8_t *)dentry +
+							    dentry_len);
+	}
+
+	/* Entry not found */
+	return ENOENT;
+}
+
+int ext4_dir_destroy_result(struct ext4_inode_ref *parent,
+			    struct ext4_directory_search_result *result)
+{
+	if (result->block.lb_id)
+		return ext4_block_set(parent->fs->bdev, &result->block);
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
--- a/lwext4/ext4_dir.h
+++ b/lwext4/ext4_dir.h
@@ -1,258 +1,258 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file  ext4_dir.h
- * @brief Directory handle procedures.
- */
-
-#ifndef EXT4_DIR_H_
-#define EXT4_DIR_H_
-
-#include "ext4_config.h"
-#include "ext4_types.h"
-#include "ext4_blockdev.h"
-#include "ext4_super.h"
-
-#include <stdint.h>
-
-/**@brief Get i-node number from directory entry.
- * @param de Directory entry
- * @return I-node number
- */
-static inline uint32_t
-ext4_dir_entry_ll_get_inode(struct ext4_directory_entry_ll *de)
-{
-	return to_le32(de->inode);
-}
-
-/**@brief Set i-node number to directory entry.
- * @param de Directory entry
- * @param inode I-node number
- */
-static inline void
-ext4_dir_entry_ll_set_inode(struct ext4_directory_entry_ll *de, uint32_t inode)
-{
-	de->inode = to_le32(inode);
-}
-
-/**@brief Get directory entry length.
- * @param de Directory entry
- * @return Entry length
- */
-static inline uint16_t
-ext4_dir_entry_ll_get_entry_length(struct ext4_directory_entry_ll *de)
-{
-	return to_le16(de->entry_length);
-}
-
-/**@brief Set directory entry length.
- * @param de     Directory entry
- * @param length Entry length
- */
-static inline void
-ext4_dir_entry_ll_set_entry_length(struct ext4_directory_entry_ll *de,
-				   uint16_t len)
-{
-	de->entry_length = to_le16(len);
-}
-
-/**@brief Get directory entry name length.
- * @param sb Superblock
- * @param de Directory entry
- * @return Entry name length
- */
-static inline uint16_t
-ext4_dir_entry_ll_get_name_length(struct ext4_sblock *sb,
-				  struct ext4_directory_entry_ll *de)
-{
-	uint16_t v = de->name_length;
-
-	if ((ext4_get32(sb, rev_level) == 0) &&
-	    (ext4_get32(sb, minor_rev_level) < 5))
-		v |= ((uint16_t)de->in.name_length_high) << 8;
-
-	return v;
-}
-
-/**@brief Set directory entry name length.
- * @param sb     Superblock
- * @param de     Directory entry
- * @param length Entry name length
- */
-static inline void ext4_dir_entry_ll_set_name_length(
-    struct ext4_sblock *sb, struct ext4_directory_entry_ll *de, uint16_t len)
-{
-	de->name_length = (len << 8) >> 8;
-
-	if ((ext4_get32(sb, rev_level) == 0) &&
-	    (ext4_get32(sb, minor_rev_level) < 5))
-		de->in.name_length_high = len >> 8;
-}
-
-/**@brief Get i-node type of directory entry.
- * @param sb Superblock
- * @param de Directory entry
- * @return I-node type (file, dir, etc.)
- */
-static inline uint8_t
-ext4_dir_entry_ll_get_inode_type(struct ext4_sblock *sb,
-				 struct ext4_directory_entry_ll *de)
-{
-	if ((ext4_get32(sb, rev_level) > 0) ||
-	    (ext4_get32(sb, minor_rev_level) >= 5))
-		return de->in.inode_type;
-
-	return EXT4_DIRECTORY_FILETYPE_UNKNOWN;
-}
-/**@brief Set i-node type of directory entry.
- * @param sb   Superblock
- * @param de   Directory entry
- * @param type I-node type (file, dir, etc.)
- */
-
-static inline void ext4_dir_entry_ll_set_inode_type(
-    struct ext4_sblock *sb, struct ext4_directory_entry_ll *de, uint8_t type)
-{
-	if ((ext4_get32(sb, rev_level) > 0) ||
-	    (ext4_get32(sb, minor_rev_level) >= 5))
-		de->in.inode_type = type;
-}
-
-/**@brief Initialize directory iterator.
- * Set position to the first valid entry from the required position.
- * @param it        Pointer to iterator to be initialized
- * @param inode_ref Directory i-node
- * @param pos       Position to start reading entries from
- * @return Error code
- */
-int ext4_dir_iterator_init(struct ext4_directory_iterator *it,
-			   struct ext4_inode_ref *inode_ref, uint64_t pos);
-
-/**@brief Jump to the next valid entry
- * @param it Initialized iterator
- * @return Error code
- */
-int ext4_dir_iterator_next(struct ext4_directory_iterator *it);
-
-/**@brief Uninitialize directory iterator.
- *        Release all allocated structures.
- * @param it Iterator to be finished
- * @return Error code
- */
-int ext4_dir_iterator_fini(struct ext4_directory_iterator *it);
-
-/**@brief Write directory entry to concrete data block.
- * @param sb        Superblock
- * @param entry     Pointer to entry to be written
- * @param entry_len Length of new entry
- * @param child     Child i-node to be written to new entry
- * @param name      Name of the new entry
- * @param name_len  Length of entry name
- */
-void ext4_dir_write_entry(struct ext4_sblock *sb,
-			  struct ext4_directory_entry_ll *entry,
-			  uint16_t entry_len, struct ext4_inode_ref *child,
-			  const char *name, size_t name_len);
-
-/**@brief Add new entry to the directory.
- * @param parent Directory i-node
- * @param name   Name of new entry
- * @param child  I-node to be referenced from new entry
- * @return Error code
- */
-int ext4_dir_add_entry(struct ext4_inode_ref *parent, const char *name,
-		       uint32_t name_len, struct ext4_inode_ref *child);
-
-/**@brief Find directory entry with passed name.
- * @param result Result structure to be returned if entry found
- * @param parent Directory i-node
- * @param name   Name of entry to be found
- * @param name_len  Name length
- * @return Error code
- */
-int ext4_dir_find_entry(struct ext4_directory_search_result *result,
-			struct ext4_inode_ref *parent, const char *name,
-			uint32_t name_len);
-
-/**@brief Remove directory entry.
- * @param parent Directory i-node
- * @param name   Name of the entry to be removed
- * @param name_len  Name length
- * @return Error code
- */
-int ext4_dir_remove_entry(struct ext4_inode_ref *parent, const char *name,
-			  uint32_t name_len);
-
-/**@brief Try to insert entry to concrete data block.
- * @param sb           Superblock
- * @param target_block Block to try to insert entry to
- * @param child        Child i-node to be inserted by new entry
- * @param name         Name of the new entry
- * @param name_len     Length of the new entry name
- * @return Error code
- */
-int ext4_dir_try_insert_entry(struct ext4_sblock *sb,
-			      struct ext4_block *target_block,
-			      struct ext4_inode_ref *child, const char *name,
-			      uint32_t name_len);
-
-/**@brief Try to find entry in block by name.
- * @param block     Block containing entries
- * @param sb        Superblock
- * @param name_len  Length of entry name
- * @param name      Name of entry to be found
- * @param res_entry Output pointer to found entry, NULL if not found
- * @return Error code
- */
-int ext4_dir_find_in_block(struct ext4_block *block, struct ext4_sblock *sb,
-			   size_t name_len, const char *name,
-			   struct ext4_directory_entry_ll **res_entry);
-
-/**@brief Simple function to release allocated data from result.
- * @param parent Parent inode
- * @param result Search result to destroy
- * @return Error code
- *
- */
-int ext4_dir_destroy_result(struct ext4_inode_ref *parent,
-			    struct ext4_directory_search_result *result);
-
-#endif /* EXT4_DIR_H_ */
-
-/**
- * @}
- */
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file  ext4_dir.h
+ * @brief Directory handle procedures.
+ */
+
+#ifndef EXT4_DIR_H_
+#define EXT4_DIR_H_
+
+#include "ext4_config.h"
+#include "ext4_types.h"
+#include "ext4_blockdev.h"
+#include "ext4_super.h"
+
+#include <stdint.h>
+
+/**@brief Get i-node number from directory entry.
+ * @param de Directory entry
+ * @return I-node number
+ */
+static inline uint32_t
+ext4_dir_entry_ll_get_inode(struct ext4_directory_entry_ll *de)
+{
+	return to_le32(de->inode);
+}
+
+/**@brief Set i-node number to directory entry.
+ * @param de Directory entry
+ * @param inode I-node number
+ */
+static inline void
+ext4_dir_entry_ll_set_inode(struct ext4_directory_entry_ll *de, uint32_t inode)
+{
+	de->inode = to_le32(inode);
+}
+
+/**@brief Get directory entry length.
+ * @param de Directory entry
+ * @return Entry length
+ */
+static inline uint16_t
+ext4_dir_entry_ll_get_entry_length(struct ext4_directory_entry_ll *de)
+{
+	return to_le16(de->entry_length);
+}
+
+/**@brief Set directory entry length.
+ * @param de     Directory entry
+ * @param length Entry length
+ */
+static inline void
+ext4_dir_entry_ll_set_entry_length(struct ext4_directory_entry_ll *de,
+				   uint16_t len)
+{
+	de->entry_length = to_le16(len);
+}
+
+/**@brief Get directory entry name length.
+ * @param sb Superblock
+ * @param de Directory entry
+ * @return Entry name length
+ */
+static inline uint16_t
+ext4_dir_entry_ll_get_name_length(struct ext4_sblock *sb,
+				  struct ext4_directory_entry_ll *de)
+{
+	uint16_t v = de->name_length;
+
+	if ((ext4_get32(sb, rev_level) == 0) &&
+	    (ext4_get32(sb, minor_rev_level) < 5))
+		v |= ((uint16_t)de->in.name_length_high) << 8;
+
+	return v;
+}
+
+/**@brief Set directory entry name length.
+ * @param sb     Superblock
+ * @param de     Directory entry
+ * @param length Entry name length
+ */
+static inline void ext4_dir_entry_ll_set_name_length(
+    struct ext4_sblock *sb, struct ext4_directory_entry_ll *de, uint16_t len)
+{
+	de->name_length = (len << 8) >> 8;
+
+	if ((ext4_get32(sb, rev_level) == 0) &&
+	    (ext4_get32(sb, minor_rev_level) < 5))
+		de->in.name_length_high = len >> 8;
+}
+
+/**@brief Get i-node type of directory entry.
+ * @param sb Superblock
+ * @param de Directory entry
+ * @return I-node type (file, dir, etc.)
+ */
+static inline uint8_t
+ext4_dir_entry_ll_get_inode_type(struct ext4_sblock *sb,
+				 struct ext4_directory_entry_ll *de)
+{
+	if ((ext4_get32(sb, rev_level) > 0) ||
+	    (ext4_get32(sb, minor_rev_level) >= 5))
+		return de->in.inode_type;
+
+	return EXT4_DIRECTORY_FILETYPE_UNKNOWN;
+}
+/**@brief Set i-node type of directory entry.
+ * @param sb   Superblock
+ * @param de   Directory entry
+ * @param type I-node type (file, dir, etc.)
+ */
+
+static inline void ext4_dir_entry_ll_set_inode_type(
+    struct ext4_sblock *sb, struct ext4_directory_entry_ll *de, uint8_t type)
+{
+	if ((ext4_get32(sb, rev_level) > 0) ||
+	    (ext4_get32(sb, minor_rev_level) >= 5))
+		de->in.inode_type = type;
+}
+
+/**@brief Initialize directory iterator.
+ * Set position to the first valid entry from the required position.
+ * @param it        Pointer to iterator to be initialized
+ * @param inode_ref Directory i-node
+ * @param pos       Position to start reading entries from
+ * @return Error code
+ */
+int ext4_dir_iterator_init(struct ext4_directory_iterator *it,
+			   struct ext4_inode_ref *inode_ref, uint64_t pos);
+
+/**@brief Jump to the next valid entry
+ * @param it Initialized iterator
+ * @return Error code
+ */
+int ext4_dir_iterator_next(struct ext4_directory_iterator *it);
+
+/**@brief Uninitialize directory iterator.
+ *        Release all allocated structures.
+ * @param it Iterator to be finished
+ * @return Error code
+ */
+int ext4_dir_iterator_fini(struct ext4_directory_iterator *it);
+
+/**@brief Write directory entry to concrete data block.
+ * @param sb        Superblock
+ * @param entry     Pointer to entry to be written
+ * @param entry_len Length of new entry
+ * @param child     Child i-node to be written to new entry
+ * @param name      Name of the new entry
+ * @param name_len  Length of entry name
+ */
+void ext4_dir_write_entry(struct ext4_sblock *sb,
+			  struct ext4_directory_entry_ll *entry,
+			  uint16_t entry_len, struct ext4_inode_ref *child,
+			  const char *name, size_t name_len);
+
+/**@brief Add new entry to the directory.
+ * @param parent Directory i-node
+ * @param name   Name of new entry
+ * @param child  I-node to be referenced from new entry
+ * @return Error code
+ */
+int ext4_dir_add_entry(struct ext4_inode_ref *parent, const char *name,
+		       uint32_t name_len, struct ext4_inode_ref *child);
+
+/**@brief Find directory entry with passed name.
+ * @param result Result structure to be returned if entry found
+ * @param parent Directory i-node
+ * @param name   Name of entry to be found
+ * @param name_len  Name length
+ * @return Error code
+ */
+int ext4_dir_find_entry(struct ext4_directory_search_result *result,
+			struct ext4_inode_ref *parent, const char *name,
+			uint32_t name_len);
+
+/**@brief Remove directory entry.
+ * @param parent Directory i-node
+ * @param name   Name of the entry to be removed
+ * @param name_len  Name length
+ * @return Error code
+ */
+int ext4_dir_remove_entry(struct ext4_inode_ref *parent, const char *name,
+			  uint32_t name_len);
+
+/**@brief Try to insert entry to concrete data block.
+ * @param sb           Superblock
+ * @param target_block Block to try to insert entry to
+ * @param child        Child i-node to be inserted by new entry
+ * @param name         Name of the new entry
+ * @param name_len     Length of the new entry name
+ * @return Error code
+ */
+int ext4_dir_try_insert_entry(struct ext4_sblock *sb,
+			      struct ext4_block *target_block,
+			      struct ext4_inode_ref *child, const char *name,
+			      uint32_t name_len);
+
+/**@brief Try to find entry in block by name.
+ * @param block     Block containing entries
+ * @param sb        Superblock
+ * @param name_len  Length of entry name
+ * @param name      Name of entry to be found
+ * @param res_entry Output pointer to found entry, NULL if not found
+ * @return Error code
+ */
+int ext4_dir_find_in_block(struct ext4_block *block, struct ext4_sblock *sb,
+			   size_t name_len, const char *name,
+			   struct ext4_directory_entry_ll **res_entry);
+
+/**@brief Simple function to release allocated data from result.
+ * @param parent Parent inode
+ * @param result Search result to destroy
+ * @return Error code
+ *
+ */
+int ext4_dir_destroy_result(struct ext4_inode_ref *parent,
+			    struct ext4_directory_search_result *result);
+
+#endif /* EXT4_DIR_H_ */
+
+/**
+ * @}
+ */
--- a/lwext4/ext4_dir_idx.c
+++ b/lwext4/ext4_dir_idx.c
@@ -1,1198 +1,1198 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file  ext4_dir_idx.c
- * @brief Directory indexing procedures.
- */
-
-#include "ext4_config.h"
-#include "ext4_dir_idx.h"
-#include "ext4_dir.h"
-#include "ext4_blockdev.h"
-#include "ext4_fs.h"
-#include "ext4_super.h"
-#include "ext4_hash.h"
-
-#include <string.h>
-#include <stdlib.h>
-
-/**@brief Get hash version used in directory index.
- * @param root_info Pointer to root info structure of index
- * @return Hash algorithm version
- */
-static inline uint8_t ext4_dir_dx_root_info_get_hash_version(
-    struct ext4_directory_dx_root_info *root_info)
-{
-	return root_info->hash_version;
-}
-
-/**@brief Set hash version, that will be used in directory index.
- * @param root_info Pointer to root info structure of index
- * @param v Hash algorithm version
- */
-static inline void ext4_dir_dx_root_info_set_hash_version(
-    struct ext4_directory_dx_root_info *root_info, uint8_t v)
-{
-	root_info->hash_version = v;
-}
-
-/**@brief Get length of root_info structure in bytes.
- * @param root_info Pointer to root info structure of index
- * @return Length of the structure
- */
-static inline uint8_t ext4_dir_dx_root_info_get_info_length(
-    struct ext4_directory_dx_root_info *root_info)
-{
-	return root_info->info_length;
-}
-
-/**@brief Set length of root_info structure in bytes.
- * @param root_info   Pointer to root info structure of index
- * @param info_length Length of the structure
- */
-static inline void ext4_dir_dx_root_info_set_info_length(
-    struct ext4_directory_dx_root_info *root_info, uint8_t len)
-{
-	root_info->info_length = len;
-}
-
-/**@brief Get number of indirect levels of HTree.
- * @param root_info Pointer to root info structure of index
- * @return Height of HTree (actually only 0 or 1)
- */
-static inline uint8_t ext4_dir_dx_root_info_get_indirect_levels(
-    struct ext4_directory_dx_root_info *root_info)
-{
-	return root_info->indirect_levels;
-}
-
-/**@brief Set number of indirect levels of HTree.
- * @param root_info Pointer to root info structure of index
- * @param lvl Height of HTree (actually only 0 or 1)
- */
-static inline void ext4_dir_dx_root_info_set_indirect_levels(
-    struct ext4_directory_dx_root_info *root_info, uint8_t lvl)
-{
-	root_info->indirect_levels = lvl;
-}
-
-/**@brief Get maximum number of index node entries.
- * @param climit Pointer to counlimit structure
- * @return Maximum of entries in node
- */
-static inline uint16_t
-ext4_dir_dx_countlimit_get_limit(struct ext4_directory_dx_countlimit *climit)
-{
-	return to_le16(climit->limit);
-}
-
-/**@brief Set maximum number of index node entries.
- * @param climit Pointer to counlimit structure
- * @param limit Maximum of entries in node
- */
-static inline void
-ext4_dir_dx_countlimit_set_limit(struct ext4_directory_dx_countlimit *climit,
-				 uint16_t limit)
-{
-	climit->limit = to_le16(limit);
-}
-
-/**@brief Get current number of index node entries.
- * @param climit Pointer to counlimit structure
- * @return Number of entries in node
- */
-static inline uint16_t
-ext4_dir_dx_countlimit_get_count(struct ext4_directory_dx_countlimit *climit)
-{
-	return to_le16(climit->count);
-}
-
-/**@brief Set current number of index node entries.
- * @param climit Pointer to counlimit structure
- * @param count Number of entries in node
- */
-static inline void
-ext4_dir_dx_countlimit_set_count(struct ext4_directory_dx_countlimit *climit,
-				 uint16_t count)
-{
-	climit->count = to_le16(count);
-}
-
-/**@brief Get hash value of index entry.
- * @param entry Pointer to index entry
- * @return Hash value
- */
-static inline uint32_t
-ext4_dir_dx_entry_get_hash(struct ext4_directory_dx_entry *entry)
-{
-	return to_le32(entry->hash);
-}
-
-/**@brief Set hash value of index entry.
- * @param entry Pointer to index entry
- * @param hash  Hash value
- */
-static inline void
-ext4_dir_dx_entry_set_hash(struct ext4_directory_dx_entry *entry, uint32_t hash)
-{
-	entry->hash = to_le32(hash);
-}
-
-/**@brief Get block address where child node is located.
- * @param entry Pointer to index entry
- * @return Block address of child node
- */
-static inline uint32_t
-ext4_dir_dx_entry_get_block(struct ext4_directory_dx_entry *entry)
-{
-	return to_le32(entry->block);
-}
-
-/**@brief Set block address where child node is located.
- * @param entry Pointer to index entry
- * @param block Block address of child node
- */
-static inline void
-ext4_dir_dx_entry_set_block(struct ext4_directory_dx_entry *entry,
-			    uint32_t block)
-{
-	entry->block = to_le32(block);
-}
-
-/**@brief Sort entry item.*/
-struct ext4_dx_sort_entry {
-	uint32_t hash;
-	uint32_t rec_len;
-	void *dentry;
-};
-
-static int ext4_dir_dx_hash_string(struct ext4_hash_info *hinfo, int len,
-				   const char *name)
-{
-	return ext2_htree_hash(name, len, hinfo->seed, hinfo->hash_version,
-			       &hinfo->hash, &hinfo->minor_hash);
-}
-
-/****************************************************************************/
-
-int ext4_dir_dx_init(struct ext4_inode_ref *dir)
-{
-	/* Load block 0, where will be index root located */
-	uint32_t fblock;
-	int rc = ext4_fs_get_inode_data_block_index(dir, 0, &fblock);
-	if (rc != EOK)
-		return rc;
-
-	struct ext4_block block;
-	rc = ext4_block_get(dir->fs->bdev, &block, fblock);
-	if (rc != EOK)
-		return rc;
-
-	/* Initialize pointers to data structures */
-	struct ext4_directory_dx_root *root = (void *)block.data;
-	struct ext4_directory_dx_root_info *info = &(root->info);
-
-	/* Initialize root info structure */
-	uint8_t hash_version = ext4_get8(&dir->fs->sb, default_hash_version);
-
-	ext4_dir_dx_root_info_set_hash_version(info, hash_version);
-	ext4_dir_dx_root_info_set_indirect_levels(info, 0);
-	ext4_dir_dx_root_info_set_info_length(info, 8);
-
-	/* Set limit and current number of entries */
-	struct ext4_directory_dx_countlimit *countlimit =
-	    (struct ext4_directory_dx_countlimit *)&root->entries;
-
-	ext4_dir_dx_countlimit_set_count(countlimit, 1);
-
-	uint32_t block_size = ext4_sb_get_block_size(&dir->fs->sb);
-	uint32_t entry_space = block_size -
-			       2 * sizeof(struct ext4_directory_dx_dot_entry) -
-			       sizeof(struct ext4_directory_dx_root_info);
-	uint16_t root_limit =
-	    entry_space / sizeof(struct ext4_directory_dx_entry);
-	ext4_dir_dx_countlimit_set_limit(countlimit, root_limit);
-
-	/* Append new block, where will be new entries inserted in the future */
-	uint32_t iblock;
-	rc = ext4_fs_append_inode_block(dir, &fblock, &iblock);
-	if (rc != EOK) {
-		ext4_block_set(dir->fs->bdev, &block);
-		return rc;
-	}
-
-	struct ext4_block new_block;
-
-	rc = ext4_block_get(dir->fs->bdev, &new_block, fblock);
-	if (rc != EOK) {
-		ext4_block_set(dir->fs->bdev, &block);
-		return rc;
-	}
-
-	/* Fill the whole block with empty entry */
-	struct ext4_directory_entry_ll *block_entry = (void *)new_block.data;
-
-	ext4_dir_entry_ll_set_entry_length(block_entry, block_size);
-	ext4_dir_entry_ll_set_inode(block_entry, 0);
-
-	new_block.dirty = true;
-	rc = ext4_block_set(dir->fs->bdev, &new_block);
-	if (rc != EOK) {
-		ext4_block_set(dir->fs->bdev, &block);
-		return rc;
-	}
-
-	/* Connect new block to the only entry in index */
-	struct ext4_directory_dx_entry *entry = root->entries;
-	ext4_dir_dx_entry_set_block(entry, iblock);
-
-	block.dirty = true;
-
-	return ext4_block_set(dir->fs->bdev, &block);
-}
-
-/**@brief Initialize hash info structure necessary for index operations.
- * @param hinfo      Pointer to hinfo to be initialized
- * @param root_block Root block (number 0) of index
- * @param sb         Pointer to superblock
- * @param name_len   Length of name to be computed hash value from
- * @param name       Name to be computed hash value from
- * @return Standard error code
- */
-static int ext4_dir_hinfo_init(struct ext4_hash_info *hinfo,
-			       struct ext4_block *root_block,
-			       struct ext4_sblock *sb, size_t name_len,
-			       const char *name)
-{
-	struct ext4_directory_dx_root *root =
-	    (struct ext4_directory_dx_root *)root_block->data;
-
-	if ((root->info.hash_version != EXT2_HTREE_LEGACY) &&
-	    (root->info.hash_version != EXT2_HTREE_HALF_MD4) &&
-	    (root->info.hash_version != EXT2_HTREE_TEA))
-		return EXT4_ERR_BAD_DX_DIR;
-
-	/* Check unused flags */
-	if (root->info.unused_flags != 0)
-		return EXT4_ERR_BAD_DX_DIR;
-
-	/* Check indirect levels */
-	if (root->info.indirect_levels > 1)
-		return EXT4_ERR_BAD_DX_DIR;
-
-	/* Check if node limit is correct */
-	uint32_t block_size = ext4_sb_get_block_size(sb);
-	uint32_t entry_space = block_size;
-	entry_space -= 2 * sizeof(struct ext4_directory_dx_dot_entry);
-	entry_space -= sizeof(struct ext4_directory_dx_root_info);
-	entry_space = entry_space / sizeof(struct ext4_directory_dx_entry);
-
-	uint16_t limit = ext4_dir_dx_countlimit_get_limit(
-	    (struct ext4_directory_dx_countlimit *)&root->entries);
-	if (limit != entry_space)
-		return EXT4_ERR_BAD_DX_DIR;
-
-	/* Check hash version and modify if necessary */
-	hinfo->hash_version =
-	    ext4_dir_dx_root_info_get_hash_version(&root->info);
-	if ((hinfo->hash_version <= EXT2_HTREE_TEA) &&
-	    (ext4_sb_check_flag(sb, EXT4_SUPERBLOCK_FLAGS_UNSIGNED_HASH))) {
-		/* Use unsigned hash */
-		hinfo->hash_version += 3;
-	}
-
-	/* Load hash seed from superblock */
-
-	hinfo->seed = ext4_get8(sb, hash_seed);
-
-	/* Compute hash value of name */
-	if (name)
-		return ext4_dir_dx_hash_string(hinfo, name_len, name);
-
-	return EOK;
-}
-
-/**@brief Walk through index tree and load leaf with corresponding hash value.
- * @param hinfo      Initialized hash info structure
- * @param inode_ref  Current i-node
- * @param root_block Root block (iblock 0), where is root node located
- * @param dx_block   Pointer to leaf node in dx_blocks array
- * @param dx_blocks  Array with the whole path from root to leaf
- * @return Standard error code
- */
-static int ext4_dir_dx_get_leaf(struct ext4_hash_info *hinfo,
-				struct ext4_inode_ref *inode_ref,
-				struct ext4_block *root_block,
-				struct ext4_directory_dx_block **dx_block,
-				struct ext4_directory_dx_block *dx_blocks)
-{
-	struct ext4_directory_dx_block *tmp_dx_block = dx_blocks;
-	struct ext4_directory_dx_root *root =
-	    (struct ext4_directory_dx_root *)root_block->data;
-	struct ext4_directory_dx_entry *entries =
-	    (struct ext4_directory_dx_entry *)&root->entries;
-
-	uint16_t limit = ext4_dir_dx_countlimit_get_limit(
-	    (struct ext4_directory_dx_countlimit *)entries);
-	uint8_t indirect_level =
-	    ext4_dir_dx_root_info_get_indirect_levels(&root->info);
-
-	struct ext4_block *tmp_block = root_block;
-	struct ext4_directory_dx_entry *p;
-	struct ext4_directory_dx_entry *q;
-	struct ext4_directory_dx_entry *m;
-	struct ext4_directory_dx_entry *at;
-
-	/* Walk through the index tree */
-	while (true) {
-		uint16_t count = ext4_dir_dx_countlimit_get_count(
-		    (struct ext4_directory_dx_countlimit *)entries);
-		if ((count == 0) || (count > limit))
-			return EXT4_ERR_BAD_DX_DIR;
-
-		/* Do binary search in every node */
-		p = entries + 1;
-		q = entries + count - 1;
-
-		while (p <= q) {
-			m = p + (q - p) / 2;
-			if (ext4_dir_dx_entry_get_hash(m) > hinfo->hash)
-				q = m - 1;
-			else
-				p = m + 1;
-		}
-
-		at = p - 1;
-
-		/* Write results */
-
-		memcpy(&tmp_dx_block->block, tmp_block,
-		       sizeof(struct ext4_block));
-		tmp_dx_block->entries = entries;
-		tmp_dx_block->position = at;
-
-		/* Is algorithm in the leaf? */
-		if (indirect_level == 0) {
-			*dx_block = tmp_dx_block;
-			return EOK;
-		}
-
-		/* Goto child node */
-		uint32_t next_block = ext4_dir_dx_entry_get_block(at);
-
-		indirect_level--;
-
-		uint32_t fblock;
-		int rc = ext4_fs_get_inode_data_block_index(
-		    inode_ref, next_block, &fblock);
-		if (rc != EOK)
-			return rc;
-
-		rc = ext4_block_get(inode_ref->fs->bdev, tmp_block, fblock);
-		if (rc != EOK)
-			return rc;
-
-		entries =
-		    ((struct ext4_directory_dx_node *)tmp_block->data)->entries;
-		limit = ext4_dir_dx_countlimit_get_limit(
-		    (struct ext4_directory_dx_countlimit *)entries);
-
-		uint16_t entry_space =
-		    ext4_sb_get_block_size(&inode_ref->fs->sb) -
-		    sizeof(struct ext4_fake_directory_entry);
-
-		entry_space =
-		    entry_space / sizeof(struct ext4_directory_dx_entry);
-
-		if (limit != entry_space) {
-			ext4_block_set(inode_ref->fs->bdev, tmp_block);
-			return EXT4_ERR_BAD_DX_DIR;
-		}
-
-		++tmp_dx_block;
-	}
-
-	/* Unreachable */
-	return EOK;
-}
-
-/**@brief Check if the the next block would be checked during entry search.
- * @param inode_ref Directory i-node
- * @param hash      Hash value to check
- * @param dx_block  Current block
- * @param dx_blocks Array with path from root to leaf node
- * @return Standard Error code
- */
-static int ext4_dir_dx_next_block(struct ext4_inode_ref *inode_ref,
-				  uint32_t hash,
-				  struct ext4_directory_dx_block *dx_block,
-				  struct ext4_directory_dx_block *dx_blocks)
-{
-	uint32_t num_handles = 0;
-	struct ext4_directory_dx_block *p = dx_block;
-
-	/* Try to find data block with next bunch of entries */
-	while (true) {
-		p->position++;
-		uint16_t count = ext4_dir_dx_countlimit_get_count(
-		    (struct ext4_directory_dx_countlimit *)p->entries);
-
-		if (p->position < p->entries + count)
-			break;
-
-		if (p == dx_blocks)
-			return EOK;
-
-		num_handles++;
-		p--;
-	}
-
-	/* Check hash collision (if not occurred - no next block cannot be
-	 * used)*/
-	uint32_t current_hash = ext4_dir_dx_entry_get_hash(p->position);
-	if ((hash & 1) == 0) {
-		if ((current_hash & ~1) != hash)
-			return 0;
-	}
-
-	/* Fill new path */
-	while (num_handles--) {
-		uint32_t block_idx = ext4_dir_dx_entry_get_block(p->position);
-		uint32_t block_addr;
-
-		int rc = ext4_fs_get_inode_data_block_index(
-		    inode_ref, block_idx, &block_addr);
-		if (rc != EOK)
-			return rc;
-
-		struct ext4_block block;
-		rc = ext4_block_get(inode_ref->fs->bdev, &block, block_addr);
-		if (rc != EOK)
-			return rc;
-
-		p++;
-
-		/* Don't forget to put old block (prevent memory leak) */
-		rc = ext4_block_set(inode_ref->fs->bdev, &p->block);
-		if (rc != EOK)
-			return rc;
-
-		memcpy(&p->block, &p->block, sizeof(block));
-		p->entries =
-		    ((struct ext4_directory_dx_node *)block.data)->entries;
-		p->position = p->entries;
-	}
-
-	return ENOENT;
-}
-
-int ext4_dir_dx_find_entry(struct ext4_directory_search_result *result,
-			   struct ext4_inode_ref *inode_ref, size_t name_len,
-			   const char *name)
-{
-	/* Load direct block 0 (index root) */
-	uint32_t root_block_addr;
-	int rc2;
-	int rc =
-	    ext4_fs_get_inode_data_block_index(inode_ref, 0, &root_block_addr);
-	if (rc != EOK)
-		return rc;
-
-	struct ext4_fs *fs = inode_ref->fs;
-
-	struct ext4_block root_block;
-	rc = ext4_block_get(fs->bdev, &root_block, root_block_addr);
-	if (rc != EOK)
-		return rc;
-
-	/* Initialize hash info (compute hash value) */
-	struct ext4_hash_info hinfo;
-	rc = ext4_dir_hinfo_init(&hinfo, &root_block, &fs->sb, name_len, name);
-	if (rc != EOK) {
-		ext4_block_set(fs->bdev, &root_block);
-		return EXT4_ERR_BAD_DX_DIR;
-	}
-
-	/*
-	 * Hardcoded number 2 means maximum height of index tree,
-	 * specified in the Linux driver.
-	 */
-	struct ext4_directory_dx_block dx_blocks[2];
-	struct ext4_directory_dx_block *dx_block;
-	struct ext4_directory_dx_block *tmp;
-
-	rc = ext4_dir_dx_get_leaf(&hinfo, inode_ref, &root_block, &dx_block,
-				  dx_blocks);
-	if (rc != EOK) {
-		ext4_block_set(fs->bdev, &root_block);
-		return EXT4_ERR_BAD_DX_DIR;
-	}
-
-	do {
-		/* Load leaf block */
-		uint32_t leaf_block_idx =
-		    ext4_dir_dx_entry_get_block(dx_block->position);
-		uint32_t leaf_block_addr;
-
-		rc = ext4_fs_get_inode_data_block_index(
-		    inode_ref, leaf_block_idx, &leaf_block_addr);
-		if (rc != EOK)
-			goto cleanup;
-
-		struct ext4_block leaf_block;
-		rc = ext4_block_get(fs->bdev, &leaf_block, leaf_block_addr);
-		if (rc != EOK)
-			goto cleanup;
-
-		/* Linear search inside block */
-		struct ext4_directory_entry_ll *res_dentry;
-		rc = ext4_dir_find_in_block(&leaf_block, &fs->sb, name_len,
-					    name, &res_dentry);
-
-		/* Found => return it */
-		if (rc == EOK) {
-			result->block = leaf_block;
-			result->dentry = res_dentry;
-			goto cleanup;
-		}
-
-		/* Not found, leave untouched */
-		rc2 = ext4_block_set(fs->bdev, &leaf_block);
-		if (rc2 != EOK)
-			goto cleanup;
-
-		if (rc != ENOENT)
-			goto cleanup;
-
-		/* check if the next block could be checked */
-		rc = ext4_dir_dx_next_block(inode_ref, hinfo.hash, dx_block,
-					    &dx_blocks[0]);
-		if (rc < 0)
-			goto cleanup;
-	} while (rc == ENOENT);
-
-	/* Entry not found */
-	rc = ENOENT;
-
-cleanup:
-	/* The whole path must be released (preventing memory leak) */
-	tmp = dx_blocks;
-
-	while (tmp <= dx_block) {
-		rc2 = ext4_block_set(fs->bdev, &tmp->block);
-		if (rc == EOK && rc2 != EOK)
-			rc = rc2;
-		++tmp;
-	}
-
-	return rc;
-}
-
-#if CONFIG_DIR_INDEX_COMB_SORT
-#define SWAP_ENTRY(se1, se2)                                                   \
-	do {                                                                   \
-		struct ext4_dx_sort_entry tmp = se1;                           \
-		se1 = se2;                                                     \
-		se2 = tmp;                                                     \
-	\
-} while (0)
-
-static void comb_sort(struct ext4_dx_sort_entry *se, uint32_t count)
-{
-	struct ext4_dx_sort_entry *p, *q, *top = se + count - 1;
-	bool more;
-	/* Combsort */
-	while (count > 2) {
-		count = (count * 10) / 13;
-		if (count - 9 < 2)
-			count = 11;
-		for (p = top, q = p - count; q >= se; p--, q--)
-			if (p->hash < q->hash)
-				SWAP_ENTRY(*p, *q);
-	}
-	/* Bubblesort */
-	do {
-		more = 0;
-		q = top;
-		while (q-- > se) {
-			if (q[1].hash >= q[0].hash)
-				continue;
-			SWAP_ENTRY(*(q + 1), *q);
-			more = 1;
-		}
-	} while (more);
-}
-#else
-
-/**@brief  Compare function used to pass in quicksort implementation.
- *         It can compare two entries by hash value.
- * @param arg1  First entry
- * @param arg2  Second entry
- * @param dummy Unused parameter, can be NULL
- *
- * @return Classic compare result
- *         (0: equal, -1: arg1 < arg2, 1: arg1 > arg2)
- */
-static int ext4_dir_dx_entry_comparator(const void *arg1, const void *arg2)
-{
-	struct ext4_dx_sort_entry *entry1 = (void *)arg1;
-	struct ext4_dx_sort_entry *entry2 = (void *)arg2;
-
-	if (entry1->hash == entry2->hash)
-		return 0;
-
-	if (entry1->hash < entry2->hash)
-		return -1;
-	else
-		return 1;
-}
-#endif
-
-/**@brief  Insert new index entry to block.
- *         Note that space for new entry must be checked by caller.
- * @param index_block Block where to insert new entry
- * @param hash        Hash value covered by child node
- * @param iblock      Logical number of child block
- *
- */
-static void
-ext4_dir_dx_insert_entry(struct ext4_directory_dx_block *index_block,
-			 uint32_t hash, uint32_t iblock)
-{
-	struct ext4_directory_dx_entry *old_index_entry = index_block->position;
-	struct ext4_directory_dx_entry *new_index_entry = old_index_entry + 1;
-
-	struct ext4_directory_dx_countlimit *countlimit =
-	    (struct ext4_directory_dx_countlimit *)index_block->entries;
-	uint32_t count = ext4_dir_dx_countlimit_get_count(countlimit);
-
-	struct ext4_directory_dx_entry *start_index = index_block->entries;
-	size_t bytes =
-	    (uint8_t *)(start_index + count) - (uint8_t *)(new_index_entry);
-
-	memmove(new_index_entry + 1, new_index_entry, bytes);
-
-	ext4_dir_dx_entry_set_block(new_index_entry, iblock);
-	ext4_dir_dx_entry_set_hash(new_index_entry, hash);
-
-	ext4_dir_dx_countlimit_set_count(countlimit, count + 1);
-
-	index_block->block.dirty = true;
-}
-
-/**@brief Split directory entries to two parts preventing node overflow.
- * @param inode_ref      Directory i-node
- * @param hinfo          Hash info
- * @param old_data_block Block with data to be split
- * @param index_block    Block where index entries are located
- * @param new_data_block Output value for newly allocated data block
- */
-static int ext4_dir_dx_split_data(struct ext4_inode_ref *inode_ref,
-				  struct ext4_hash_info *hinfo,
-				  struct ext4_block *old_data_block,
-				  struct ext4_directory_dx_block *index_block,
-				  struct ext4_block *new_data_block)
-{
-	int rc = EOK;
-
-	/* Allocate buffer for directory entries */
-	uint32_t block_size = ext4_sb_get_block_size(&inode_ref->fs->sb);
-
-	uint8_t *entry_buffer = malloc(block_size);
-	if (entry_buffer == NULL)
-		return ENOMEM;
-
-	/* dot entry has the smallest size available */
-	uint32_t max_entry_count =
-	    block_size / sizeof(struct ext4_directory_dx_dot_entry);
-
-	/* Allocate sort entry */
-	struct ext4_dx_sort_entry *sort_array =
-	    malloc(max_entry_count * sizeof(struct ext4_dx_sort_entry));
-
-	if (sort_array == NULL) {
-		free(entry_buffer);
-		return ENOMEM;
-	}
-
-	uint32_t idx = 0;
-	uint32_t real_size = 0;
-
-	/* Initialize hinfo */
-	struct ext4_hash_info tmp_hinfo;
-	memcpy(&tmp_hinfo, hinfo, sizeof(struct ext4_hash_info));
-
-	/* Load all valid entries to the buffer */
-	struct ext4_directory_entry_ll *dentry = (void *)old_data_block->data;
-	uint8_t *entry_buffer_ptr = entry_buffer;
-	while ((void *)dentry < (void *)(old_data_block->data + block_size)) {
-		/* Read only valid entries */
-		if (ext4_dir_entry_ll_get_inode(dentry) &&
-		    dentry->name_length) {
-			uint8_t len = ext4_dir_entry_ll_get_name_length(
-			    &inode_ref->fs->sb, dentry);
-
-			rc = ext4_dir_dx_hash_string(&tmp_hinfo, len,
-						     (char *)dentry->name);
-			if (rc != EOK) {
-				free(sort_array);
-				free(entry_buffer);
-				return rc;
-			}
-
-			uint32_t rec_len = 8 + len;
-
-			if ((rec_len % 4) != 0)
-				rec_len += 4 - (rec_len % 4);
-
-			memcpy(entry_buffer_ptr, dentry, rec_len);
-
-			sort_array[idx].dentry = entry_buffer_ptr;
-			sort_array[idx].rec_len = rec_len;
-			sort_array[idx].hash = tmp_hinfo.hash;
-
-			entry_buffer_ptr += rec_len;
-			real_size += rec_len;
-			idx++;
-		}
-
-		dentry = (void *)((uint8_t *)dentry +
-				  ext4_dir_entry_ll_get_entry_length(dentry));
-	}
-
-/* Sort all entries */
-#if CONFIG_DIR_INDEX_COMB_SORT
-	comb_sort(sort_array, idx);
-#else
-	qsort(sort_array, idx, sizeof(struct ext4_dx_sort_entry),
-	      ext4_dir_dx_entry_comparator);
-#endif
-	/* Allocate new block for store the second part of entries */
-	uint32_t new_fblock;
-	uint32_t new_iblock;
-	rc = ext4_fs_append_inode_block(inode_ref, &new_fblock, &new_iblock);
-	if (rc != EOK) {
-		free(sort_array);
-		free(entry_buffer);
-		return rc;
-	}
-
-	/* Load new block */
-	struct ext4_block new_data_block_tmp;
-	rc = ext4_block_get(inode_ref->fs->bdev, &new_data_block_tmp,
-			    new_fblock);
-	if (rc != EOK) {
-		free(sort_array);
-		free(entry_buffer);
-		return rc;
-	}
-
-	/*
-	 * Distribute entries to two blocks (by size)
-	 * - compute the half
-	 */
-	uint32_t new_hash = 0;
-	uint32_t current_size = 0;
-	uint32_t mid = 0;
-	uint32_t i;
-	for (i = 0; i < idx; ++i) {
-		if ((current_size + sort_array[i].rec_len) > (block_size / 2)) {
-			new_hash = sort_array[i].hash;
-			mid = i;
-			break;
-		}
-
-		current_size += sort_array[i].rec_len;
-	}
-
-	/* Check hash collision */
-	uint32_t continued = 0;
-	if (new_hash == sort_array[mid - 1].hash)
-		continued = 1;
-
-	uint32_t offset = 0;
-	void *ptr;
-
-	/* First part - to the old block */
-	for (i = 0; i < mid; ++i) {
-		ptr = old_data_block->data + offset;
-		memcpy(ptr, sort_array[i].dentry, sort_array[i].rec_len);
-
-		struct ext4_directory_entry_ll *tmp = ptr;
-		if (i < (mid - 1))
-			ext4_dir_entry_ll_set_entry_length(
-			    tmp, sort_array[i].rec_len);
-		else
-			ext4_dir_entry_ll_set_entry_length(tmp,
-							   block_size - offset);
-
-		offset += sort_array[i].rec_len;
-	}
-
-	/* Second part - to the new block */
-	offset = 0;
-	for (i = mid; i < idx; ++i) {
-		ptr = new_data_block_tmp.data + offset;
-		memcpy(ptr, sort_array[i].dentry, sort_array[i].rec_len);
-
-		struct ext4_directory_entry_ll *tmp = ptr;
-		if (i < (idx - 1))
-			ext4_dir_entry_ll_set_entry_length(
-			    tmp, sort_array[i].rec_len);
-		else
-			ext4_dir_entry_ll_set_entry_length(tmp,
-							   block_size - offset);
-
-		offset += sort_array[i].rec_len;
-	}
-
-	/* Do some steps to finish operation */
-	old_data_block->dirty = true;
-	new_data_block_tmp.dirty = true;
-
-	free(sort_array);
-	free(entry_buffer);
-
-	ext4_dir_dx_insert_entry(index_block, new_hash + continued, new_iblock);
-
-	*new_data_block = new_data_block_tmp;
-
-	return EOK;
-}
-
-/**@brief  Split index node and maybe some parent nodes in the tree hierarchy.
- * @param inode_ref Directory i-node
- * @param dx_blocks Array with path from root to leaf node
- * @param dx_block  Leaf block to be split if needed
- * @return Error code
- */
-static int
-ext4_dir_dx_split_index(struct ext4_inode_ref *inode_ref,
-			struct ext4_directory_dx_block *dx_blocks,
-			struct ext4_directory_dx_block *dx_block,
-			struct ext4_directory_dx_block **new_dx_block)
-{
-	struct ext4_directory_dx_entry *entries;
-
-	if (dx_block == dx_blocks)
-		entries =
-		    ((struct ext4_directory_dx_root *)dx_block->block.data)
-			->entries;
-	else
-		entries =
-		    ((struct ext4_directory_dx_node *)dx_block->block.data)
-			->entries;
-
-	struct ext4_directory_dx_countlimit *countlimit =
-	    (struct ext4_directory_dx_countlimit *)entries;
-
-	uint16_t leaf_limit = ext4_dir_dx_countlimit_get_limit(countlimit);
-	uint16_t leaf_count = ext4_dir_dx_countlimit_get_count(countlimit);
-
-	/* Check if is necessary to split index block */
-	if (leaf_limit == leaf_count) {
-		size_t levels = dx_block - dx_blocks;
-
-		struct ext4_directory_dx_entry *root_entries =
-		    ((struct ext4_directory_dx_root *)dx_blocks[0].block.data)
-			->entries;
-
-		struct ext4_directory_dx_countlimit *root_countlimit =
-		    (struct ext4_directory_dx_countlimit *)root_entries;
-		uint16_t root_limit =
-		    ext4_dir_dx_countlimit_get_limit(root_countlimit);
-		uint16_t root_count =
-		    ext4_dir_dx_countlimit_get_count(root_countlimit);
-
-		/* Linux limitation */
-		if ((levels > 0) && (root_limit == root_count))
-			return ENOSPC;
-
-		/* Add new block to directory */
-		uint32_t new_fblock;
-		uint32_t new_iblock;
-		int rc = ext4_fs_append_inode_block(inode_ref, &new_fblock,
-						    &new_iblock);
-		if (rc != EOK)
-			return rc;
-
-		/* load new block */
-		struct ext4_block new_block;
-		rc =
-		    ext4_block_get(inode_ref->fs->bdev, &new_block, new_fblock);
-		if (rc != EOK)
-			return rc;
-
-		struct ext4_directory_dx_node *new_node =
-		    (void *)new_block.data;
-		struct ext4_directory_dx_entry *new_entries = new_node->entries;
-
-		memset(&new_node->fake, 0,
-		       sizeof(struct ext4_fake_directory_entry));
-
-		uint32_t block_size =
-		    ext4_sb_get_block_size(&inode_ref->fs->sb);
-
-		new_node->fake.entry_length = block_size;
-
-		/* Split leaf node */
-		if (levels > 0) {
-			uint32_t count_left = leaf_count / 2;
-			uint32_t count_right = leaf_count - count_left;
-			uint32_t hash_right =
-			    ext4_dir_dx_entry_get_hash(entries + count_left);
-
-			/* Copy data to new node */
-			memcpy((void *)new_entries,
-			       (void *)(entries + count_left),
-			       count_right *
-				   sizeof(struct ext4_directory_dx_entry));
-
-			/* Initialize new node */
-			struct ext4_directory_dx_countlimit *left_countlimit =
-			    (struct ext4_directory_dx_countlimit *)entries;
-			struct ext4_directory_dx_countlimit *right_countlimit =
-			    (struct ext4_directory_dx_countlimit *)new_entries;
-
-			ext4_dir_dx_countlimit_set_count(left_countlimit,
-							 count_left);
-			ext4_dir_dx_countlimit_set_count(right_countlimit,
-							 count_right);
-
-			uint32_t entry_space =
-			    block_size -
-			    sizeof(struct ext4_fake_directory_entry);
-			uint32_t node_limit =
-			    entry_space /
-			    sizeof(struct ext4_directory_dx_entry);
-			ext4_dir_dx_countlimit_set_limit(right_countlimit,
-							 node_limit);
-
-			/* Which index block is target for new entry */
-			uint32_t position_index =
-			    (dx_block->position - dx_block->entries);
-			if (position_index >= count_left) {
-				dx_block->block.dirty = true;
-
-				struct ext4_block block_tmp = dx_block->block;
-
-				dx_block->block = new_block;
-
-				dx_block->position =
-				    new_entries + position_index - count_left;
-				dx_block->entries = new_entries;
-
-				new_block = block_tmp;
-			}
-
-			/* Finally insert new entry */
-			ext4_dir_dx_insert_entry(dx_blocks, hash_right,
-						 new_iblock);
-			dx_blocks[0].block.dirty = true;
-			dx_blocks[1].block.dirty = true;
-
-			new_block.dirty = true;
-			return ext4_block_set(inode_ref->fs->bdev, &new_block);
-		} else {
-			/* Create second level index */
-
-			/* Copy data from root to child block */
-			memcpy((void *)new_entries, (void *)entries,
-			       leaf_count *
-				   sizeof(struct ext4_directory_dx_entry));
-
-			struct ext4_directory_dx_countlimit *new_countlimit =
-			    (struct ext4_directory_dx_countlimit *)new_entries;
-
-			uint32_t entry_space =
-			    block_size -
-			    sizeof(struct ext4_fake_directory_entry);
-			uint32_t node_limit =
-			    entry_space /
-			    sizeof(struct ext4_directory_dx_entry);
-			ext4_dir_dx_countlimit_set_limit(new_countlimit,
-							 node_limit);
-
-			/* Set values in root node */
-			struct ext4_directory_dx_countlimit
-			    *new_root_countlimit =
-				(struct ext4_directory_dx_countlimit *)entries;
-
-			ext4_dir_dx_countlimit_set_count(new_root_countlimit,
-							 1);
-			ext4_dir_dx_entry_set_block(entries, new_iblock);
-
-			((struct ext4_directory_dx_root *)dx_blocks[0]
-			     .block.data)
-			    ->info.indirect_levels = 1;
-
-			/* Add new entry to the path */
-			dx_block = dx_blocks + 1;
-			dx_block->position =
-			    dx_blocks->position - entries + new_entries;
-			dx_block->entries = new_entries;
-			dx_block->block = new_block;
-
-			*new_dx_block = dx_block;
-
-			dx_blocks[0].block.dirty = true;
-			dx_blocks[1].block.dirty = true;
-		}
-	}
-
-	return EOK;
-}
-
-int ext4_dir_dx_add_entry(struct ext4_inode_ref *parent,
-			  struct ext4_inode_ref *child, const char *name)
-{
-	int rc2 = EOK;
-
-	/* Get direct block 0 (index root) */
-	uint32_t root_block_addr;
-	int rc =
-	    ext4_fs_get_inode_data_block_index(parent, 0, &root_block_addr);
-	if (rc != EOK)
-		return rc;
-
-	struct ext4_fs *fs = parent->fs;
-	struct ext4_block root_block;
-
-	rc = ext4_block_get(fs->bdev, &root_block, root_block_addr);
-	if (rc != EOK)
-		return rc;
-
-	/* Initialize hinfo structure (mainly compute hash) */
-	uint32_t name_len = strlen(name);
-	struct ext4_hash_info hinfo;
-	rc = ext4_dir_hinfo_init(&hinfo, &root_block, &fs->sb, name_len, name);
-	if (rc != EOK) {
-		ext4_block_set(fs->bdev, &root_block);
-		return EXT4_ERR_BAD_DX_DIR;
-	}
-
-	/*
-	 * Hardcoded number 2 means maximum height of index
-	 * tree defined in Linux.
-	 */
-	struct ext4_directory_dx_block dx_blocks[2];
-	struct ext4_directory_dx_block *dx_block;
-	struct ext4_directory_dx_block *dx_it;
-
-	rc = ext4_dir_dx_get_leaf(&hinfo, parent, &root_block, &dx_block,
-				  dx_blocks);
-	if (rc != EOK) {
-		rc = EXT4_ERR_BAD_DX_DIR;
-		goto release_index;
-	}
-
-	/* Try to insert to existing data block */
-	uint32_t leaf_block_idx =
-	    ext4_dir_dx_entry_get_block(dx_block->position);
-	uint32_t leaf_block_addr;
-	rc = ext4_fs_get_inode_data_block_index(parent, leaf_block_idx,
-						&leaf_block_addr);
-	if (rc != EOK)
-		goto release_index;
-
-	/*
-	 * Check if there is needed to split index node
-	 * (and recursively also parent nodes)
-	 */
-	rc = ext4_dir_dx_split_index(parent, dx_blocks, dx_block, &dx_block);
-	if (rc != EOK)
-		goto release_target_index;
-
-	struct ext4_block target_block;
-	rc = ext4_block_get(fs->bdev, &target_block, leaf_block_addr);
-	if (rc != EOK)
-		goto release_index;
-
-	/* Check if insert operation passed */
-	rc = ext4_dir_try_insert_entry(&fs->sb, &target_block, child, name,
-				       name_len);
-	if (rc == EOK)
-		goto release_target_index;
-
-	/* Split entries to two blocks (includes sorting by hash value) */
-	struct ext4_block new_block;
-	rc = ext4_dir_dx_split_data(parent, &hinfo, &target_block, dx_block,
-				    &new_block);
-	if (rc != EOK) {
-		rc2 = rc;
-		goto release_target_index;
-	}
-
-	/* Where to save new entry */
-	uint32_t new_block_hash =
-	    ext4_dir_dx_entry_get_hash(dx_block->position + 1);
-	if (hinfo.hash >= new_block_hash)
-		rc = ext4_dir_try_insert_entry(&fs->sb, &new_block, child, name,
-					       name_len);
-	else
-		rc = ext4_dir_try_insert_entry(&fs->sb, &target_block, child,
-					       name, name_len);
-
-	/* Cleanup */
-	rc = ext4_block_set(fs->bdev, &new_block);
-	if (rc != EOK)
-		return rc;
-
-/* Cleanup operations */
-
-release_target_index:
-	rc2 = rc;
-
-	rc = ext4_block_set(fs->bdev, &target_block);
-	if (rc != EOK)
-		return rc;
-
-release_index:
-	if (rc != EOK)
-		rc2 = rc;
-
-	dx_it = dx_blocks;
-
-	while (dx_it <= dx_block) {
-		rc = ext4_block_set(fs->bdev, &dx_it->block);
-		if (rc != EOK)
-			return rc;
-
-		dx_it++;
-	}
-
-	return rc2;
-}
-
-/**
- * @}
- */
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file  ext4_dir_idx.c
+ * @brief Directory indexing procedures.
+ */
+
+#include "ext4_config.h"
+#include "ext4_dir_idx.h"
+#include "ext4_dir.h"
+#include "ext4_blockdev.h"
+#include "ext4_fs.h"
+#include "ext4_super.h"
+#include "ext4_hash.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+/**@brief Get hash version used in directory index.
+ * @param root_info Pointer to root info structure of index
+ * @return Hash algorithm version
+ */
+static inline uint8_t ext4_dir_dx_root_info_get_hash_version(
+    struct ext4_directory_dx_root_info *root_info)
+{
+	return root_info->hash_version;
+}
+
+/**@brief Set hash version, that will be used in directory index.
+ * @param root_info Pointer to root info structure of index
+ * @param v Hash algorithm version
+ */
+static inline void ext4_dir_dx_root_info_set_hash_version(
+    struct ext4_directory_dx_root_info *root_info, uint8_t v)
+{
+	root_info->hash_version = v;
+}
+
+/**@brief Get length of root_info structure in bytes.
+ * @param root_info Pointer to root info structure of index
+ * @return Length of the structure
+ */
+static inline uint8_t ext4_dir_dx_root_info_get_info_length(
+    struct ext4_directory_dx_root_info *root_info)
+{
+	return root_info->info_length;
+}
+
+/**@brief Set length of root_info structure in bytes.
+ * @param root_info   Pointer to root info structure of index
+ * @param info_length Length of the structure
+ */
+static inline void ext4_dir_dx_root_info_set_info_length(
+    struct ext4_directory_dx_root_info *root_info, uint8_t len)
+{
+	root_info->info_length = len;
+}
+
+/**@brief Get number of indirect levels of HTree.
+ * @param root_info Pointer to root info structure of index
+ * @return Height of HTree (actually only 0 or 1)
+ */
+static inline uint8_t ext4_dir_dx_root_info_get_indirect_levels(
+    struct ext4_directory_dx_root_info *root_info)
+{
+	return root_info->indirect_levels;
+}
+
+/**@brief Set number of indirect levels of HTree.
+ * @param root_info Pointer to root info structure of index
+ * @param lvl Height of HTree (actually only 0 or 1)
+ */
+static inline void ext4_dir_dx_root_info_set_indirect_levels(
+    struct ext4_directory_dx_root_info *root_info, uint8_t lvl)
+{
+	root_info->indirect_levels = lvl;
+}
+
+/**@brief Get maximum number of index node entries.
+ * @param climit Pointer to counlimit structure
+ * @return Maximum of entries in node
+ */
+static inline uint16_t
+ext4_dir_dx_countlimit_get_limit(struct ext4_directory_dx_countlimit *climit)
+{
+	return to_le16(climit->limit);
+}
+
+/**@brief Set maximum number of index node entries.
+ * @param climit Pointer to counlimit structure
+ * @param limit Maximum of entries in node
+ */
+static inline void
+ext4_dir_dx_countlimit_set_limit(struct ext4_directory_dx_countlimit *climit,
+				 uint16_t limit)
+{
+	climit->limit = to_le16(limit);
+}
+
+/**@brief Get current number of index node entries.
+ * @param climit Pointer to counlimit structure
+ * @return Number of entries in node
+ */
+static inline uint16_t
+ext4_dir_dx_countlimit_get_count(struct ext4_directory_dx_countlimit *climit)
+{
+	return to_le16(climit->count);
+}
+
+/**@brief Set current number of index node entries.
+ * @param climit Pointer to counlimit structure
+ * @param count Number of entries in node
+ */
+static inline void
+ext4_dir_dx_countlimit_set_count(struct ext4_directory_dx_countlimit *climit,
+				 uint16_t count)
+{
+	climit->count = to_le16(count);
+}
+
+/**@brief Get hash value of index entry.
+ * @param entry Pointer to index entry
+ * @return Hash value
+ */
+static inline uint32_t
+ext4_dir_dx_entry_get_hash(struct ext4_directory_dx_entry *entry)
+{
+	return to_le32(entry->hash);
+}
+
+/**@brief Set hash value of index entry.
+ * @param entry Pointer to index entry
+ * @param hash  Hash value
+ */
+static inline void
+ext4_dir_dx_entry_set_hash(struct ext4_directory_dx_entry *entry, uint32_t hash)
+{
+	entry->hash = to_le32(hash);
+}
+
+/**@brief Get block address where child node is located.
+ * @param entry Pointer to index entry
+ * @return Block address of child node
+ */
+static inline uint32_t
+ext4_dir_dx_entry_get_block(struct ext4_directory_dx_entry *entry)
+{
+	return to_le32(entry->block);
+}
+
+/**@brief Set block address where child node is located.
+ * @param entry Pointer to index entry
+ * @param block Block address of child node
+ */
+static inline void
+ext4_dir_dx_entry_set_block(struct ext4_directory_dx_entry *entry,
+			    uint32_t block)
+{
+	entry->block = to_le32(block);
+}
+
+/**@brief Sort entry item.*/
+struct ext4_dx_sort_entry {
+	uint32_t hash;
+	uint32_t rec_len;
+	void *dentry;
+};
+
+static int ext4_dir_dx_hash_string(struct ext4_hash_info *hinfo, int len,
+				   const char *name)
+{
+	return ext2_htree_hash(name, len, hinfo->seed, hinfo->hash_version,
+			       &hinfo->hash, &hinfo->minor_hash);
+}
+
+/****************************************************************************/
+
+int ext4_dir_dx_init(struct ext4_inode_ref *dir)
+{
+	/* Load block 0, where will be index root located */
+	uint32_t fblock;
+	int rc = ext4_fs_get_inode_data_block_index(dir, 0, &fblock);
+	if (rc != EOK)
+		return rc;
+
+	struct ext4_block block;
+	rc = ext4_block_get(dir->fs->bdev, &block, fblock);
+	if (rc != EOK)
+		return rc;
+
+	/* Initialize pointers to data structures */
+	struct ext4_directory_dx_root *root = (void *)block.data;
+	struct ext4_directory_dx_root_info *info = &(root->info);
+
+	/* Initialize root info structure */
+	uint8_t hash_version = ext4_get8(&dir->fs->sb, default_hash_version);
+
+	ext4_dir_dx_root_info_set_hash_version(info, hash_version);
+	ext4_dir_dx_root_info_set_indirect_levels(info, 0);
+	ext4_dir_dx_root_info_set_info_length(info, 8);
+
+	/* Set limit and current number of entries */
+	struct ext4_directory_dx_countlimit *countlimit =
+	    (struct ext4_directory_dx_countlimit *)&root->entries;
+
+	ext4_dir_dx_countlimit_set_count(countlimit, 1);
+
+	uint32_t block_size = ext4_sb_get_block_size(&dir->fs->sb);
+	uint32_t entry_space = block_size -
+			       2 * sizeof(struct ext4_directory_dx_dot_entry) -
+			       sizeof(struct ext4_directory_dx_root_info);
+	uint16_t root_limit =
+	    entry_space / sizeof(struct ext4_directory_dx_entry);
+	ext4_dir_dx_countlimit_set_limit(countlimit, root_limit);
+
+	/* Append new block, where will be new entries inserted in the future */
+	uint32_t iblock;
+	rc = ext4_fs_append_inode_block(dir, &fblock, &iblock);
+	if (rc != EOK) {
+		ext4_block_set(dir->fs->bdev, &block);
+		return rc;
+	}
+
+	struct ext4_block new_block;
+
+	rc = ext4_block_get(dir->fs->bdev, &new_block, fblock);
+	if (rc != EOK) {
+		ext4_block_set(dir->fs->bdev, &block);
+		return rc;
+	}
+
+	/* Fill the whole block with empty entry */
+	struct ext4_directory_entry_ll *block_entry = (void *)new_block.data;
+
+	ext4_dir_entry_ll_set_entry_length(block_entry, block_size);
+	ext4_dir_entry_ll_set_inode(block_entry, 0);
+
+	new_block.dirty = true;
+	rc = ext4_block_set(dir->fs->bdev, &new_block);
+	if (rc != EOK) {
+		ext4_block_set(dir->fs->bdev, &block);
+		return rc;
+	}
+
+	/* Connect new block to the only entry in index */
+	struct ext4_directory_dx_entry *entry = root->entries;
+	ext4_dir_dx_entry_set_block(entry, iblock);
+
+	block.dirty = true;
+
+	return ext4_block_set(dir->fs->bdev, &block);
+}
+
+/**@brief Initialize hash info structure necessary for index operations.
+ * @param hinfo      Pointer to hinfo to be initialized
+ * @param root_block Root block (number 0) of index
+ * @param sb         Pointer to superblock
+ * @param name_len   Length of name to be computed hash value from
+ * @param name       Name to be computed hash value from
+ * @return Standard error code
+ */
+static int ext4_dir_hinfo_init(struct ext4_hash_info *hinfo,
+			       struct ext4_block *root_block,
+			       struct ext4_sblock *sb, size_t name_len,
+			       const char *name)
+{
+	struct ext4_directory_dx_root *root =
+	    (struct ext4_directory_dx_root *)root_block->data;
+
+	if ((root->info.hash_version != EXT2_HTREE_LEGACY) &&
+	    (root->info.hash_version != EXT2_HTREE_HALF_MD4) &&
+	    (root->info.hash_version != EXT2_HTREE_TEA))
+		return EXT4_ERR_BAD_DX_DIR;
+
+	/* Check unused flags */
+	if (root->info.unused_flags != 0)
+		return EXT4_ERR_BAD_DX_DIR;
+
+	/* Check indirect levels */
+	if (root->info.indirect_levels > 1)
+		return EXT4_ERR_BAD_DX_DIR;
+
+	/* Check if node limit is correct */
+	uint32_t block_size = ext4_sb_get_block_size(sb);
+	uint32_t entry_space = block_size;
+	entry_space -= 2 * sizeof(struct ext4_directory_dx_dot_entry);
+	entry_space -= sizeof(struct ext4_directory_dx_root_info);
+	entry_space = entry_space / sizeof(struct ext4_directory_dx_entry);
+
+	uint16_t limit = ext4_dir_dx_countlimit_get_limit(
+	    (struct ext4_directory_dx_countlimit *)&root->entries);
+	if (limit != entry_space)
+		return EXT4_ERR_BAD_DX_DIR;
+
+	/* Check hash version and modify if necessary */
+	hinfo->hash_version =
+	    ext4_dir_dx_root_info_get_hash_version(&root->info);
+	if ((hinfo->hash_version <= EXT2_HTREE_TEA) &&
+	    (ext4_sb_check_flag(sb, EXT4_SUPERBLOCK_FLAGS_UNSIGNED_HASH))) {
+		/* Use unsigned hash */
+		hinfo->hash_version += 3;
+	}
+
+	/* Load hash seed from superblock */
+
+	hinfo->seed = ext4_get8(sb, hash_seed);
+
+	/* Compute hash value of name */
+	if (name)
+		return ext4_dir_dx_hash_string(hinfo, name_len, name);
+
+	return EOK;
+}
+
+/**@brief Walk through index tree and load leaf with corresponding hash value.
+ * @param hinfo      Initialized hash info structure
+ * @param inode_ref  Current i-node
+ * @param root_block Root block (iblock 0), where is root node located
+ * @param dx_block   Pointer to leaf node in dx_blocks array
+ * @param dx_blocks  Array with the whole path from root to leaf
+ * @return Standard error code
+ */
+static int ext4_dir_dx_get_leaf(struct ext4_hash_info *hinfo,
+				struct ext4_inode_ref *inode_ref,
+				struct ext4_block *root_block,
+				struct ext4_directory_dx_block **dx_block,
+				struct ext4_directory_dx_block *dx_blocks)
+{
+	struct ext4_directory_dx_block *tmp_dx_block = dx_blocks;
+	struct ext4_directory_dx_root *root =
+	    (struct ext4_directory_dx_root *)root_block->data;
+	struct ext4_directory_dx_entry *entries =
+	    (struct ext4_directory_dx_entry *)&root->entries;
+
+	uint16_t limit = ext4_dir_dx_countlimit_get_limit(
+	    (struct ext4_directory_dx_countlimit *)entries);
+	uint8_t indirect_level =
+	    ext4_dir_dx_root_info_get_indirect_levels(&root->info);
+
+	struct ext4_block *tmp_block = root_block;
+	struct ext4_directory_dx_entry *p;
+	struct ext4_directory_dx_entry *q;
+	struct ext4_directory_dx_entry *m;
+	struct ext4_directory_dx_entry *at;
+
+	/* Walk through the index tree */
+	while (true) {
+		uint16_t count = ext4_dir_dx_countlimit_get_count(
+		    (struct ext4_directory_dx_countlimit *)entries);
+		if ((count == 0) || (count > limit))
+			return EXT4_ERR_BAD_DX_DIR;
+
+		/* Do binary search in every node */
+		p = entries + 1;
+		q = entries + count - 1;
+
+		while (p <= q) {
+			m = p + (q - p) / 2;
+			if (ext4_dir_dx_entry_get_hash(m) > hinfo->hash)
+				q = m - 1;
+			else
+				p = m + 1;
+		}
+
+		at = p - 1;
+
+		/* Write results */
+
+		memcpy(&tmp_dx_block->block, tmp_block,
+		       sizeof(struct ext4_block));
+		tmp_dx_block->entries = entries;
+		tmp_dx_block->position = at;
+
+		/* Is algorithm in the leaf? */
+		if (indirect_level == 0) {
+			*dx_block = tmp_dx_block;
+			return EOK;
+		}
+
+		/* Goto child node */
+		uint32_t next_block = ext4_dir_dx_entry_get_block(at);
+
+		indirect_level--;
+
+		uint32_t fblock;
+		int rc = ext4_fs_get_inode_data_block_index(
+		    inode_ref, next_block, &fblock);
+		if (rc != EOK)
+			return rc;
+
+		rc = ext4_block_get(inode_ref->fs->bdev, tmp_block, fblock);
+		if (rc != EOK)
+			return rc;
+
+		entries =
+		    ((struct ext4_directory_dx_node *)tmp_block->data)->entries;
+		limit = ext4_dir_dx_countlimit_get_limit(
+		    (struct ext4_directory_dx_countlimit *)entries);
+
+		uint16_t entry_space =
+		    ext4_sb_get_block_size(&inode_ref->fs->sb) -
+		    sizeof(struct ext4_fake_directory_entry);
+
+		entry_space =
+		    entry_space / sizeof(struct ext4_directory_dx_entry);
+
+		if (limit != entry_space) {
+			ext4_block_set(inode_ref->fs->bdev, tmp_block);
+			return EXT4_ERR_BAD_DX_DIR;
+		}
+
+		++tmp_dx_block;
+	}
+
+	/* Unreachable */
+	return EOK;
+}
+
+/**@brief Check if the the next block would be checked during entry search.
+ * @param inode_ref Directory i-node
+ * @param hash      Hash value to check
+ * @param dx_block  Current block
+ * @param dx_blocks Array with path from root to leaf node
+ * @return Standard Error code
+ */
+static int ext4_dir_dx_next_block(struct ext4_inode_ref *inode_ref,
+				  uint32_t hash,
+				  struct ext4_directory_dx_block *dx_block,
+				  struct ext4_directory_dx_block *dx_blocks)
+{
+	uint32_t num_handles = 0;
+	struct ext4_directory_dx_block *p = dx_block;
+
+	/* Try to find data block with next bunch of entries */
+	while (true) {
+		p->position++;
+		uint16_t count = ext4_dir_dx_countlimit_get_count(
+		    (struct ext4_directory_dx_countlimit *)p->entries);
+
+		if (p->position < p->entries + count)
+			break;
+
+		if (p == dx_blocks)
+			return EOK;
+
+		num_handles++;
+		p--;
+	}
+
+	/* Check hash collision (if not occurred - no next block cannot be
+	 * used)*/
+	uint32_t current_hash = ext4_dir_dx_entry_get_hash(p->position);
+	if ((hash & 1) == 0) {
+		if ((current_hash & ~1) != hash)
+			return 0;
+	}
+
+	/* Fill new path */
+	while (num_handles--) {
+		uint32_t block_idx = ext4_dir_dx_entry_get_block(p->position);
+		uint32_t block_addr;
+
+		int rc = ext4_fs_get_inode_data_block_index(
+		    inode_ref, block_idx, &block_addr);
+		if (rc != EOK)
+			return rc;
+
+		struct ext4_block block;
+		rc = ext4_block_get(inode_ref->fs->bdev, &block, block_addr);
+		if (rc != EOK)
+			return rc;
+
+		p++;
+
+		/* Don't forget to put old block (prevent memory leak) */
+		rc = ext4_block_set(inode_ref->fs->bdev, &p->block);
+		if (rc != EOK)
+			return rc;
+
+		memcpy(&p->block, &p->block, sizeof(block));
+		p->entries =
+		    ((struct ext4_directory_dx_node *)block.data)->entries;
+		p->position = p->entries;
+	}
+
+	return ENOENT;
+}
+
+int ext4_dir_dx_find_entry(struct ext4_directory_search_result *result,
+			   struct ext4_inode_ref *inode_ref, size_t name_len,
+			   const char *name)
+{
+	/* Load direct block 0 (index root) */
+	uint32_t root_block_addr;
+	int rc2;
+	int rc =
+	    ext4_fs_get_inode_data_block_index(inode_ref, 0, &root_block_addr);
+	if (rc != EOK)
+		return rc;
+
+	struct ext4_fs *fs = inode_ref->fs;
+
+	struct ext4_block root_block;
+	rc = ext4_block_get(fs->bdev, &root_block, root_block_addr);
+	if (rc != EOK)
+		return rc;
+
+	/* Initialize hash info (compute hash value) */
+	struct ext4_hash_info hinfo;
+	rc = ext4_dir_hinfo_init(&hinfo, &root_block, &fs->sb, name_len, name);
+	if (rc != EOK) {
+		ext4_block_set(fs->bdev, &root_block);
+		return EXT4_ERR_BAD_DX_DIR;
+	}
+
+	/*
+	 * Hardcoded number 2 means maximum height of index tree,
+	 * specified in the Linux driver.
+	 */
+	struct ext4_directory_dx_block dx_blocks[2];
+	struct ext4_directory_dx_block *dx_block;
+	struct ext4_directory_dx_block *tmp;
+
+	rc = ext4_dir_dx_get_leaf(&hinfo, inode_ref, &root_block, &dx_block,
+				  dx_blocks);
+	if (rc != EOK) {
+		ext4_block_set(fs->bdev, &root_block);
+		return EXT4_ERR_BAD_DX_DIR;
+	}
+
+	do {
+		/* Load leaf block */
+		uint32_t leaf_block_idx =
+		    ext4_dir_dx_entry_get_block(dx_block->position);
+		uint32_t leaf_block_addr;
+
+		rc = ext4_fs_get_inode_data_block_index(
+		    inode_ref, leaf_block_idx, &leaf_block_addr);
+		if (rc != EOK)
+			goto cleanup;
+
+		struct ext4_block leaf_block;
+		rc = ext4_block_get(fs->bdev, &leaf_block, leaf_block_addr);
+		if (rc != EOK)
+			goto cleanup;
+
+		/* Linear search inside block */
+		struct ext4_directory_entry_ll *res_dentry;
+		rc = ext4_dir_find_in_block(&leaf_block, &fs->sb, name_len,
+					    name, &res_dentry);
+
+		/* Found => return it */
+		if (rc == EOK) {
+			result->block = leaf_block;
+			result->dentry = res_dentry;
+			goto cleanup;
+		}
+
+		/* Not found, leave untouched */
+		rc2 = ext4_block_set(fs->bdev, &leaf_block);
+		if (rc2 != EOK)
+			goto cleanup;
+
+		if (rc != ENOENT)
+			goto cleanup;
+
+		/* check if the next block could be checked */
+		rc = ext4_dir_dx_next_block(inode_ref, hinfo.hash, dx_block,
+					    &dx_blocks[0]);
+		if (rc < 0)
+			goto cleanup;
+	} while (rc == ENOENT);
+
+	/* Entry not found */
+	rc = ENOENT;
+
+cleanup:
+	/* The whole path must be released (preventing memory leak) */
+	tmp = dx_blocks;
+
+	while (tmp <= dx_block) {
+		rc2 = ext4_block_set(fs->bdev, &tmp->block);
+		if (rc == EOK && rc2 != EOK)
+			rc = rc2;
+		++tmp;
+	}
+
+	return rc;
+}
+
+#if CONFIG_DIR_INDEX_COMB_SORT
+#define SWAP_ENTRY(se1, se2)                                                   \
+	do {                                                                   \
+		struct ext4_dx_sort_entry tmp = se1;                           \
+		se1 = se2;                                                     \
+		se2 = tmp;                                                     \
+	\
+} while (0)
+
+static void comb_sort(struct ext4_dx_sort_entry *se, uint32_t count)
+{
+	struct ext4_dx_sort_entry *p, *q, *top = se + count - 1;
+	bool more;
+	/* Combsort */
+	while (count > 2) {
+		count = (count * 10) / 13;
+		if (count - 9 < 2)
+			count = 11;
+		for (p = top, q = p - count; q >= se; p--, q--)
+			if (p->hash < q->hash)
+				SWAP_ENTRY(*p, *q);
+	}
+	/* Bubblesort */
+	do {
+		more = 0;
+		q = top;
+		while (q-- > se) {
+			if (q[1].hash >= q[0].hash)
+				continue;
+			SWAP_ENTRY(*(q + 1), *q);
+			more = 1;
+		}
+	} while (more);
+}
+#else
+
+/**@brief  Compare function used to pass in quicksort implementation.
+ *         It can compare two entries by hash value.
+ * @param arg1  First entry
+ * @param arg2  Second entry
+ * @param dummy Unused parameter, can be NULL
+ *
+ * @return Classic compare result
+ *         (0: equal, -1: arg1 < arg2, 1: arg1 > arg2)
+ */
+static int ext4_dir_dx_entry_comparator(const void *arg1, const void *arg2)
+{
+	struct ext4_dx_sort_entry *entry1 = (void *)arg1;
+	struct ext4_dx_sort_entry *entry2 = (void *)arg2;
+
+	if (entry1->hash == entry2->hash)
+		return 0;
+
+	if (entry1->hash < entry2->hash)
+		return -1;
+	else
+		return 1;
+}
+#endif
+
+/**@brief  Insert new index entry to block.
+ *         Note that space for new entry must be checked by caller.
+ * @param index_block Block where to insert new entry
+ * @param hash        Hash value covered by child node
+ * @param iblock      Logical number of child block
+ *
+ */
+static void
+ext4_dir_dx_insert_entry(struct ext4_directory_dx_block *index_block,
+			 uint32_t hash, uint32_t iblock)
+{
+	struct ext4_directory_dx_entry *old_index_entry = index_block->position;
+	struct ext4_directory_dx_entry *new_index_entry = old_index_entry + 1;
+
+	struct ext4_directory_dx_countlimit *countlimit =
+	    (struct ext4_directory_dx_countlimit *)index_block->entries;
+	uint32_t count = ext4_dir_dx_countlimit_get_count(countlimit);
+
+	struct ext4_directory_dx_entry *start_index = index_block->entries;
+	size_t bytes =
+	    (uint8_t *)(start_index + count) - (uint8_t *)(new_index_entry);
+
+	memmove(new_index_entry + 1, new_index_entry, bytes);
+
+	ext4_dir_dx_entry_set_block(new_index_entry, iblock);
+	ext4_dir_dx_entry_set_hash(new_index_entry, hash);
+
+	ext4_dir_dx_countlimit_set_count(countlimit, count + 1);
+
+	index_block->block.dirty = true;
+}
+
+/**@brief Split directory entries to two parts preventing node overflow.
+ * @param inode_ref      Directory i-node
+ * @param hinfo          Hash info
+ * @param old_data_block Block with data to be split
+ * @param index_block    Block where index entries are located
+ * @param new_data_block Output value for newly allocated data block
+ */
+static int ext4_dir_dx_split_data(struct ext4_inode_ref *inode_ref,
+				  struct ext4_hash_info *hinfo,
+				  struct ext4_block *old_data_block,
+				  struct ext4_directory_dx_block *index_block,
+				  struct ext4_block *new_data_block)
+{
+	int rc = EOK;
+
+	/* Allocate buffer for directory entries */
+	uint32_t block_size = ext4_sb_get_block_size(&inode_ref->fs->sb);
+
+	uint8_t *entry_buffer = malloc(block_size);
+	if (entry_buffer == NULL)
+		return ENOMEM;
+
+	/* dot entry has the smallest size available */
+	uint32_t max_entry_count =
+	    block_size / sizeof(struct ext4_directory_dx_dot_entry);
+
+	/* Allocate sort entry */
+	struct ext4_dx_sort_entry *sort_array =
+	    malloc(max_entry_count * sizeof(struct ext4_dx_sort_entry));
+
+	if (sort_array == NULL) {
+		free(entry_buffer);
+		return ENOMEM;
+	}
+
+	uint32_t idx = 0;
+	uint32_t real_size = 0;
+
+	/* Initialize hinfo */
+	struct ext4_hash_info tmp_hinfo;
+	memcpy(&tmp_hinfo, hinfo, sizeof(struct ext4_hash_info));
+
+	/* Load all valid entries to the buffer */
+	struct ext4_directory_entry_ll *dentry = (void *)old_data_block->data;
+	uint8_t *entry_buffer_ptr = entry_buffer;
+	while ((void *)dentry < (void *)(old_data_block->data + block_size)) {
+		/* Read only valid entries */
+		if (ext4_dir_entry_ll_get_inode(dentry) &&
+		    dentry->name_length) {
+			uint8_t len = ext4_dir_entry_ll_get_name_length(
+			    &inode_ref->fs->sb, dentry);
+
+			rc = ext4_dir_dx_hash_string(&tmp_hinfo, len,
+						     (char *)dentry->name);
+			if (rc != EOK) {
+				free(sort_array);
+				free(entry_buffer);
+				return rc;
+			}
+
+			uint32_t rec_len = 8 + len;
+
+			if ((rec_len % 4) != 0)
+				rec_len += 4 - (rec_len % 4);
+
+			memcpy(entry_buffer_ptr, dentry, rec_len);
+
+			sort_array[idx].dentry = entry_buffer_ptr;
+			sort_array[idx].rec_len = rec_len;
+			sort_array[idx].hash = tmp_hinfo.hash;
+
+			entry_buffer_ptr += rec_len;
+			real_size += rec_len;
+			idx++;
+		}
+
+		dentry = (void *)((uint8_t *)dentry +
+				  ext4_dir_entry_ll_get_entry_length(dentry));
+	}
+
+/* Sort all entries */
+#if CONFIG_DIR_INDEX_COMB_SORT
+	comb_sort(sort_array, idx);
+#else
+	qsort(sort_array, idx, sizeof(struct ext4_dx_sort_entry),
+	      ext4_dir_dx_entry_comparator);
+#endif
+	/* Allocate new block for store the second part of entries */
+	uint32_t new_fblock;
+	uint32_t new_iblock;
+	rc = ext4_fs_append_inode_block(inode_ref, &new_fblock, &new_iblock);
+	if (rc != EOK) {
+		free(sort_array);
+		free(entry_buffer);
+		return rc;
+	}
+
+	/* Load new block */
+	struct ext4_block new_data_block_tmp;
+	rc = ext4_block_get(inode_ref->fs->bdev, &new_data_block_tmp,
+			    new_fblock);
+	if (rc != EOK) {
+		free(sort_array);
+		free(entry_buffer);
+		return rc;
+	}
+
+	/*
+	 * Distribute entries to two blocks (by size)
+	 * - compute the half
+	 */
+	uint32_t new_hash = 0;
+	uint32_t current_size = 0;
+	uint32_t mid = 0;
+	uint32_t i;
+	for (i = 0; i < idx; ++i) {
+		if ((current_size + sort_array[i].rec_len) > (block_size / 2)) {
+			new_hash = sort_array[i].hash;
+			mid = i;
+			break;
+		}
+
+		current_size += sort_array[i].rec_len;
+	}
+
+	/* Check hash collision */
+	uint32_t continued = 0;
+	if (new_hash == sort_array[mid - 1].hash)
+		continued = 1;
+
+	uint32_t offset = 0;
+	void *ptr;
+
+	/* First part - to the old block */
+	for (i = 0; i < mid; ++i) {
+		ptr = old_data_block->data + offset;
+		memcpy(ptr, sort_array[i].dentry, sort_array[i].rec_len);
+
+		struct ext4_directory_entry_ll *tmp = ptr;
+		if (i < (mid - 1))
+			ext4_dir_entry_ll_set_entry_length(
+			    tmp, sort_array[i].rec_len);
+		else
+			ext4_dir_entry_ll_set_entry_length(tmp,
+							   block_size - offset);
+
+		offset += sort_array[i].rec_len;
+	}
+
+	/* Second part - to the new block */
+	offset = 0;
+	for (i = mid; i < idx; ++i) {
+		ptr = new_data_block_tmp.data + offset;
+		memcpy(ptr, sort_array[i].dentry, sort_array[i].rec_len);
+
+		struct ext4_directory_entry_ll *tmp = ptr;
+		if (i < (idx - 1))
+			ext4_dir_entry_ll_set_entry_length(
+			    tmp, sort_array[i].rec_len);
+		else
+			ext4_dir_entry_ll_set_entry_length(tmp,
+							   block_size - offset);
+
+		offset += sort_array[i].rec_len;
+	}
+
+	/* Do some steps to finish operation */
+	old_data_block->dirty = true;
+	new_data_block_tmp.dirty = true;
+
+	free(sort_array);
+	free(entry_buffer);
+
+	ext4_dir_dx_insert_entry(index_block, new_hash + continued, new_iblock);
+
+	*new_data_block = new_data_block_tmp;
+
+	return EOK;
+}
+
+/**@brief  Split index node and maybe some parent nodes in the tree hierarchy.
+ * @param inode_ref Directory i-node
+ * @param dx_blocks Array with path from root to leaf node
+ * @param dx_block  Leaf block to be split if needed
+ * @return Error code
+ */
+static int
+ext4_dir_dx_split_index(struct ext4_inode_ref *inode_ref,
+			struct ext4_directory_dx_block *dx_blocks,
+			struct ext4_directory_dx_block *dx_block,
+			struct ext4_directory_dx_block **new_dx_block)
+{
+	struct ext4_directory_dx_entry *entries;
+
+	if (dx_block == dx_blocks)
+		entries =
+		    ((struct ext4_directory_dx_root *)dx_block->block.data)
+			->entries;
+	else
+		entries =
+		    ((struct ext4_directory_dx_node *)dx_block->block.data)
+			->entries;
+
+	struct ext4_directory_dx_countlimit *countlimit =
+	    (struct ext4_directory_dx_countlimit *)entries;
+
+	uint16_t leaf_limit = ext4_dir_dx_countlimit_get_limit(countlimit);
+	uint16_t leaf_count = ext4_dir_dx_countlimit_get_count(countlimit);
+
+	/* Check if is necessary to split index block */
+	if (leaf_limit == leaf_count) {
+		size_t levels = dx_block - dx_blocks;
+
+		struct ext4_directory_dx_entry *root_entries =
+		    ((struct ext4_directory_dx_root *)dx_blocks[0].block.data)
+			->entries;
+
+		struct ext4_directory_dx_countlimit *root_countlimit =
+		    (struct ext4_directory_dx_countlimit *)root_entries;
+		uint16_t root_limit =
+		    ext4_dir_dx_countlimit_get_limit(root_countlimit);
+		uint16_t root_count =
+		    ext4_dir_dx_countlimit_get_count(root_countlimit);
+
+		/* Linux limitation */
+		if ((levels > 0) && (root_limit == root_count))
+			return ENOSPC;
+
+		/* Add new block to directory */
+		uint32_t new_fblock;
+		uint32_t new_iblock;
+		int rc = ext4_fs_append_inode_block(inode_ref, &new_fblock,
+						    &new_iblock);
+		if (rc != EOK)
+			return rc;
+
+		/* load new block */
+		struct ext4_block new_block;
+		rc =
+		    ext4_block_get(inode_ref->fs->bdev, &new_block, new_fblock);
+		if (rc != EOK)
+			return rc;
+
+		struct ext4_directory_dx_node *new_node =
+		    (void *)new_block.data;
+		struct ext4_directory_dx_entry *new_entries = new_node->entries;
+
+		memset(&new_node->fake, 0,
+		       sizeof(struct ext4_fake_directory_entry));
+
+		uint32_t block_size =
+		    ext4_sb_get_block_size(&inode_ref->fs->sb);
+
+		new_node->fake.entry_length = block_size;
+
+		/* Split leaf node */
+		if (levels > 0) {
+			uint32_t count_left = leaf_count / 2;
+			uint32_t count_right = leaf_count - count_left;
+			uint32_t hash_right =
+			    ext4_dir_dx_entry_get_hash(entries + count_left);
+
+			/* Copy data to new node */
+			memcpy((void *)new_entries,
+			       (void *)(entries + count_left),
+			       count_right *
+				   sizeof(struct ext4_directory_dx_entry));
+
+			/* Initialize new node */
+			struct ext4_directory_dx_countlimit *left_countlimit =
+			    (struct ext4_directory_dx_countlimit *)entries;
+			struct ext4_directory_dx_countlimit *right_countlimit =
+			    (struct ext4_directory_dx_countlimit *)new_entries;
+
+			ext4_dir_dx_countlimit_set_count(left_countlimit,
+							 count_left);
+			ext4_dir_dx_countlimit_set_count(right_countlimit,
+							 count_right);
+
+			uint32_t entry_space =
+			    block_size -
+			    sizeof(struct ext4_fake_directory_entry);
+			uint32_t node_limit =
+			    entry_space /
+			    sizeof(struct ext4_directory_dx_entry);
+			ext4_dir_dx_countlimit_set_limit(right_countlimit,
+							 node_limit);
+
+			/* Which index block is target for new entry */
+			uint32_t position_index =
+			    (dx_block->position - dx_block->entries);
+			if (position_index >= count_left) {
+				dx_block->block.dirty = true;
+
+				struct ext4_block block_tmp = dx_block->block;
+
+				dx_block->block = new_block;
+
+				dx_block->position =
+				    new_entries + position_index - count_left;
+				dx_block->entries = new_entries;
+
+				new_block = block_tmp;
+			}
+
+			/* Finally insert new entry */
+			ext4_dir_dx_insert_entry(dx_blocks, hash_right,
+						 new_iblock);
+			dx_blocks[0].block.dirty = true;
+			dx_blocks[1].block.dirty = true;
+
+			new_block.dirty = true;
+			return ext4_block_set(inode_ref->fs->bdev, &new_block);
+		} else {
+			/* Create second level index */
+
+			/* Copy data from root to child block */
+			memcpy((void *)new_entries, (void *)entries,
+			       leaf_count *
+				   sizeof(struct ext4_directory_dx_entry));
+
+			struct ext4_directory_dx_countlimit *new_countlimit =
+			    (struct ext4_directory_dx_countlimit *)new_entries;
+
+			uint32_t entry_space =
+			    block_size -
+			    sizeof(struct ext4_fake_directory_entry);
+			uint32_t node_limit =
+			    entry_space /
+			    sizeof(struct ext4_directory_dx_entry);
+			ext4_dir_dx_countlimit_set_limit(new_countlimit,
+							 node_limit);
+
+			/* Set values in root node */
+			struct ext4_directory_dx_countlimit
+			    *new_root_countlimit =
+				(struct ext4_directory_dx_countlimit *)entries;
+
+			ext4_dir_dx_countlimit_set_count(new_root_countlimit,
+							 1);
+			ext4_dir_dx_entry_set_block(entries, new_iblock);
+
+			((struct ext4_directory_dx_root *)dx_blocks[0]
+			     .block.data)
+			    ->info.indirect_levels = 1;
+
+			/* Add new entry to the path */
+			dx_block = dx_blocks + 1;
+			dx_block->position =
+			    dx_blocks->position - entries + new_entries;
+			dx_block->entries = new_entries;
+			dx_block->block = new_block;
+
+			*new_dx_block = dx_block;
+
+			dx_blocks[0].block.dirty = true;
+			dx_blocks[1].block.dirty = true;
+		}
+	}
+
+	return EOK;
+}
+
+int ext4_dir_dx_add_entry(struct ext4_inode_ref *parent,
+			  struct ext4_inode_ref *child, const char *name)
+{
+	int rc2 = EOK;
+
+	/* Get direct block 0 (index root) */
+	uint32_t root_block_addr;
+	int rc =
+	    ext4_fs_get_inode_data_block_index(parent, 0, &root_block_addr);
+	if (rc != EOK)
+		return rc;
+
+	struct ext4_fs *fs = parent->fs;
+	struct ext4_block root_block;
+
+	rc = ext4_block_get(fs->bdev, &root_block, root_block_addr);
+	if (rc != EOK)
+		return rc;
+
+	/* Initialize hinfo structure (mainly compute hash) */
+	uint32_t name_len = strlen(name);
+	struct ext4_hash_info hinfo;
+	rc = ext4_dir_hinfo_init(&hinfo, &root_block, &fs->sb, name_len, name);
+	if (rc != EOK) {
+		ext4_block_set(fs->bdev, &root_block);
+		return EXT4_ERR_BAD_DX_DIR;
+	}
+
+	/*
+	 * Hardcoded number 2 means maximum height of index
+	 * tree defined in Linux.
+	 */
+	struct ext4_directory_dx_block dx_blocks[2];
+	struct ext4_directory_dx_block *dx_block;
+	struct ext4_directory_dx_block *dx_it;
+
+	rc = ext4_dir_dx_get_leaf(&hinfo, parent, &root_block, &dx_block,
+				  dx_blocks);
+	if (rc != EOK) {
+		rc = EXT4_ERR_BAD_DX_DIR;
+		goto release_index;
+	}
+
+	/* Try to insert to existing data block */
+	uint32_t leaf_block_idx =
+	    ext4_dir_dx_entry_get_block(dx_block->position);
+	uint32_t leaf_block_addr;
+	rc = ext4_fs_get_inode_data_block_index(parent, leaf_block_idx,
+						&leaf_block_addr);
+	if (rc != EOK)
+		goto release_index;
+
+	/*
+	 * Check if there is needed to split index node
+	 * (and recursively also parent nodes)
+	 */
+	rc = ext4_dir_dx_split_index(parent, dx_blocks, dx_block, &dx_block);
+	if (rc != EOK)
+		goto release_target_index;
+
+	struct ext4_block target_block;
+	rc = ext4_block_get(fs->bdev, &target_block, leaf_block_addr);
+	if (rc != EOK)
+		goto release_index;
+
+	/* Check if insert operation passed */
+	rc = ext4_dir_try_insert_entry(&fs->sb, &target_block, child, name,
+				       name_len);
+	if (rc == EOK)
+		goto release_target_index;
+
+	/* Split entries to two blocks (includes sorting by hash value) */
+	struct ext4_block new_block;
+	rc = ext4_dir_dx_split_data(parent, &hinfo, &target_block, dx_block,
+				    &new_block);
+	if (rc != EOK) {
+		rc2 = rc;
+		goto release_target_index;
+	}
+
+	/* Where to save new entry */
+	uint32_t new_block_hash =
+	    ext4_dir_dx_entry_get_hash(dx_block->position + 1);
+	if (hinfo.hash >= new_block_hash)
+		rc = ext4_dir_try_insert_entry(&fs->sb, &new_block, child, name,
+					       name_len);
+	else
+		rc = ext4_dir_try_insert_entry(&fs->sb, &target_block, child,
+					       name, name_len);
+
+	/* Cleanup */
+	rc = ext4_block_set(fs->bdev, &new_block);
+	if (rc != EOK)
+		return rc;
+
+/* Cleanup operations */
+
+release_target_index:
+	rc2 = rc;
+
+	rc = ext4_block_set(fs->bdev, &target_block);
+	if (rc != EOK)
+		return rc;
+
+release_index:
+	if (rc != EOK)
+		rc2 = rc;
+
+	dx_it = dx_blocks;
+
+	while (dx_it <= dx_block) {
+		rc = ext4_block_set(fs->bdev, &dx_it->block);
+		if (rc != EOK)
+			return rc;
+
+		dx_it++;
+	}
+
+	return rc2;
+}
+
+/**
+ * @}
+ */
--- a/lwext4/ext4_dir_idx.h
+++ b/lwext4/ext4_dir_idx.h
@@ -1,82 +1,82 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file  ext4_dir_idx.h
- * @brief Directory indexing procedures.
- */
-
-#ifndef EXT4_DIR_IDX_H_
-#define EXT4_DIR_IDX_H_
-
-#include "ext4_config.h"
-#include "ext4_types.h"
-
-#include <stdint.h>
-#include <stdbool.h>
-
-/**@brief Initialize index structure of new directory.
- * @param dir Pointer to directory i-node
- * @return Error code
- */
-int ext4_dir_dx_init(struct ext4_inode_ref *dir);
-
-/**@brief Try to find directory entry using directory index.
- * @param result    Output value - if entry will be found,
- *                  than will be passed through this parameter
- * @param inode_ref Directory i-node
- * @param name_len  Length of name to be found
- * @param name      Name to be found
- * @return Error code
- */
-int ext4_dir_dx_find_entry(struct ext4_directory_search_result *result,
-			   struct ext4_inode_ref *inode_ref, size_t name_len,
-			   const char *name);
-
-/**@brief Add new entry to indexed directory
- * @param parent Directory i-node
- * @param child  I-node to be referenced from directory entry
- * @param name   Name of new directory entry
- * @return Error code
- */
-int ext4_dir_dx_add_entry(struct ext4_inode_ref *parent,
-			  struct ext4_inode_ref *child, const char *name);
-
-#endif /* EXT4_DIR_IDX_H_ */
-
-/**
- * @}
- */
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file  ext4_dir_idx.h
+ * @brief Directory indexing procedures.
+ */
+
+#ifndef EXT4_DIR_IDX_H_
+#define EXT4_DIR_IDX_H_
+
+#include "ext4_config.h"
+#include "ext4_types.h"
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/**@brief Initialize index structure of new directory.
+ * @param dir Pointer to directory i-node
+ * @return Error code
+ */
+int ext4_dir_dx_init(struct ext4_inode_ref *dir);
+
+/**@brief Try to find directory entry using directory index.
+ * @param result    Output value - if entry will be found,
+ *                  than will be passed through this parameter
+ * @param inode_ref Directory i-node
+ * @param name_len  Length of name to be found
+ * @param name      Name to be found
+ * @return Error code
+ */
+int ext4_dir_dx_find_entry(struct ext4_directory_search_result *result,
+			   struct ext4_inode_ref *inode_ref, size_t name_len,
+			   const char *name);
+
+/**@brief Add new entry to indexed directory
+ * @param parent Directory i-node
+ * @param child  I-node to be referenced from directory entry
+ * @param name   Name of new directory entry
+ * @return Error code
+ */
+int ext4_dir_dx_add_entry(struct ext4_inode_ref *parent,
+			  struct ext4_inode_ref *child, const char *name);
+
+#endif /* EXT4_DIR_IDX_H_ */
+
+/**
+ * @}
+ */
--- a/lwext4/ext4_extent.c
+++ b/lwext4/ext4_extent.c
@@ -1,984 +1,984 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file  ext4_extent.c
- * @brief More complex filesystem functions.
- */
-
-#include "ext4_config.h"
-#include "ext4_extent.h"
-#include "ext4_inode.h"
-#include "ext4_super.h"
-#include "ext4_blockdev.h"
-#include "ext4_balloc.h"
-
-#include <string.h>
-#include <stdlib.h>
-
-uint32_t ext4_extent_get_first_block(struct ext4_extent *extent)
-{
-	return to_le32(extent->first_block);
-}
-
-void ext4_extent_set_first_block(struct ext4_extent *extent, uint32_t iblock)
-{
-	extent->first_block = to_le32(iblock);
-}
-
-uint16_t ext4_extent_get_block_count(struct ext4_extent *extent)
-{
-	return to_le16(extent->block_count);
-}
-
-void ext4_extent_set_block_count(struct ext4_extent *extent, uint16_t count)
-{
-	extent->block_count = to_le16(count);
-}
-
-uint64_t ext4_extent_get_start(struct ext4_extent *extent)
-{
-	return ((uint64_t)to_le16(extent->start_hi)) << 32 |
-	       ((uint64_t)to_le32(extent->start_lo));
-}
-
-void ext4_extent_set_start(struct ext4_extent *extent, uint64_t fblock)
-{
-	extent->start_lo = to_le32((fblock << 32) >> 32);
-	extent->start_hi = to_le16((uint16_t)(fblock >> 32));
-}
-
-uint32_t ext4_extent_index_get_first_block(struct ext4_extent_index *index)
-{
-	return to_le32(index->first_block);
-}
-
-void ext4_extent_index_set_first_block(struct ext4_extent_index *index,
-				       uint32_t iblock)
-{
-	index->first_block = to_le32(iblock);
-}
-
-uint64_t ext4_extent_index_get_leaf(struct ext4_extent_index *index)
-{
-	return ((uint64_t)to_le16(index->leaf_hi)) << 32 |
-	       ((uint64_t)to_le32(index->leaf_lo));
-}
-
-void ext4_extent_index_set_leaf(struct ext4_extent_index *index,
-				uint64_t fblock)
-{
-	index->leaf_lo = to_le32((fblock << 32) >> 32);
-	index->leaf_hi = to_le16((uint16_t)(fblock >> 32));
-}
-
-uint16_t ext4_extent_header_get_magic(struct ext4_extent_header *header)
-{
-	return to_le16(header->magic);
-}
-
-void ext4_extent_header_set_magic(struct ext4_extent_header *header,
-				  uint16_t magic)
-{
-	header->magic = to_le16(magic);
-}
-
-uint16_t ext4_extent_header_get_entries_count(struct ext4_extent_header *header)
-{
-	return to_le16(header->entries_count);
-}
-
-void ext4_extent_header_set_entries_count(struct ext4_extent_header *header,
-					  uint16_t count)
-{
-	header->entries_count = to_le16(count);
-}
-
-uint16_t
-ext4_extent_header_get_max_entries_count(struct ext4_extent_header *header)
-{
-	return to_le16(header->max_entries_count);
-}
-
-void ext4_extent_header_set_max_entries_count(struct ext4_extent_header *header,
-					      uint16_t max_count)
-{
-	header->max_entries_count = to_le16(max_count);
-}
-
-uint16_t ext4_extent_header_get_depth(struct ext4_extent_header *header)
-{
-	return to_le16(header->depth);
-}
-
-void ext4_extent_header_set_depth(struct ext4_extent_header *header,
-				  uint16_t depth)
-{
-	header->depth = to_le16(depth);
-}
-
-uint32_t ext4_extent_header_get_generation(struct ext4_extent_header *header)
-{
-	return to_le32(header->generation);
-}
-
-void ext4_extent_header_set_generation(struct ext4_extent_header *header,
-				       uint32_t generation)
-{
-	header->generation = to_le32(generation);
-}
-
-/**@brief Binary search in extent index node.
- * @param header Extent header of index node
- * @param index  Output value - found index will be set here
- * @param iblock Logical block number to find in index node */
-static void ext4_extent_binsearch_idx(struct ext4_extent_header *header,
-				      struct ext4_extent_index **index,
-				      uint32_t iblock)
-{
-	struct ext4_extent_index *r;
-	struct ext4_extent_index *l;
-	struct ext4_extent_index *m;
-
-	uint16_t entries_count = ext4_extent_header_get_entries_count(header);
-
-	/* Initialize bounds */
-	l = EXT4_EXTENT_FIRST_INDEX(header) + 1;
-	r = EXT4_EXTENT_FIRST_INDEX(header) + entries_count - 1;
-
-	/* Do binary search */
-	while (l <= r) {
-		m = l + (r - l) / 2;
-		uint32_t first_block = ext4_extent_index_get_first_block(m);
-
-		if (iblock < first_block)
-			r = m - 1;
-		else
-			l = m + 1;
-	}
-
-	/* Set output value */
-	*index = l - 1;
-}
-
-/**@brief Binary search in extent leaf node.
- * @param header Extent header of leaf node
- * @param extent Output value - found extent will be set here,
- *               or NULL if node is empty
- * @param iblock Logical block number to find in leaf node */
-static void ext4_extent_binsearch(struct ext4_extent_header *header,
-				  struct ext4_extent **extent, uint32_t iblock)
-{
-	struct ext4_extent *r;
-	struct ext4_extent *l;
-	struct ext4_extent *m;
-
-	uint16_t entries_count = ext4_extent_header_get_entries_count(header);
-
-	if (entries_count == 0) {
-		/* this leaf is empty */
-		*extent = NULL;
-		return;
-	}
-
-	/* Initialize bounds */
-	l = EXT4_EXTENT_FIRST(header) + 1;
-	r = EXT4_EXTENT_FIRST(header) + entries_count - 1;
-
-	/* Do binary search */
-	while (l <= r) {
-		m = l + (r - l) / 2;
-		uint32_t first_block = ext4_extent_get_first_block(m);
-
-		if (iblock < first_block)
-			r = m - 1;
-		else
-			l = m + 1;
-	}
-
-	/* Set output value */
-	*extent = l - 1;
-}
-
-int ext4_extent_find_block(struct ext4_inode_ref *inode_ref, uint32_t iblock,
-			   uint32_t *fblock)
-{
-	int rc;
-	/* Compute bound defined by i-node size */
-	uint64_t inode_size =
-	    ext4_inode_get_size(&inode_ref->fs->sb, inode_ref->inode);
-
-	uint32_t block_size = ext4_sb_get_block_size(&inode_ref->fs->sb);
-
-	uint32_t last_idx = (inode_size - 1) / block_size;
-
-	/* Check if requested iblock is not over size of i-node */
-	if (iblock > last_idx) {
-		*fblock = 0;
-		return EOK;
-	}
-
-	struct ext4_block block;
-	block.lb_id = 0;
-
-	/* Walk through extent tree */
-	struct ext4_extent_header *header =
-	    ext4_inode_get_extent_header(inode_ref->inode);
-
-	while (ext4_extent_header_get_depth(header) != 0) {
-		/* Search index in node */
-		struct ext4_extent_index *index;
-		ext4_extent_binsearch_idx(header, &index, iblock);
-
-		/* Load child node and set values for the next iteration */
-		uint64_t child = ext4_extent_index_get_leaf(index);
-
-		if (block.lb_id) {
-			rc = ext4_block_set(inode_ref->fs->bdev, &block);
-			if (rc != EOK)
-				return rc;
-		}
-
-		int rc = ext4_block_get(inode_ref->fs->bdev, &block, child);
-		if (rc != EOK)
-			return rc;
-
-		header = (struct ext4_extent_header *)block.data;
-	}
-
-	/* Search extent in the leaf block */
-	struct ext4_extent *extent = NULL;
-	ext4_extent_binsearch(header, &extent, iblock);
-
-	/* Prevent empty leaf */
-	if (extent == NULL) {
-		*fblock = 0;
-	} else {
-		/* Compute requested physical block address */
-		uint32_t phys_block;
-		uint32_t first = ext4_extent_get_first_block(extent);
-		phys_block = ext4_extent_get_start(extent) + iblock - first;
-
-		*fblock = phys_block;
-	}
-
-	/* Cleanup */
-	if (block.lb_id) {
-		rc = ext4_block_set(inode_ref->fs->bdev, &block);
-		if (rc != EOK)
-			return rc;
-	}
-
-	return EOK;
-}
-
-/**@brief Find extent for specified iblock.
- * This function is used for finding block in the extent tree with
- * saving the path through the tree for possible future modifications.
- * @param inode_ref I-node to read extent tree from
- * @param iblock    Iblock to find extent for
- * @param ret_path  Output value for loaded path from extent tree
- * @return Error code */
-static int ext4_extent_find_extent(struct ext4_inode_ref *inode_ref,
-				   uint32_t iblock,
-				   struct ext4_extent_path **ret_path)
-{
-	struct ext4_extent_header *eh =
-	    ext4_inode_get_extent_header(inode_ref->inode);
-
-	uint16_t depth = ext4_extent_header_get_depth(eh);
-	uint16_t i;
-	struct ext4_extent_path *tmp_path;
-
-	/* Added 2 for possible tree growing */
-	tmp_path = malloc(sizeof(struct ext4_extent_path) * (depth + 2));
-	if (tmp_path == NULL)
-		return ENOMEM;
-
-	/* Initialize structure for algorithm start */
-	tmp_path[0].block = inode_ref->block;
-	tmp_path[0].header = eh;
-
-	/* Walk through the extent tree */
-	uint16_t pos = 0;
-	int rc;
-	while (ext4_extent_header_get_depth(eh) != 0) {
-		/* Search index in index node by iblock */
-		ext4_extent_binsearch_idx(tmp_path[pos].header,
-					  &tmp_path[pos].index, iblock);
-
-		tmp_path[pos].depth = depth;
-		tmp_path[pos].extent = NULL;
-
-		ext4_assert(tmp_path[pos].index != 0);
-
-		/* Load information for the next iteration */
-		uint64_t fblock =
-		    ext4_extent_index_get_leaf(tmp_path[pos].index);
-
-		struct ext4_block block;
-		rc = ext4_block_get(inode_ref->fs->bdev, &block, fblock);
-		if (rc != EOK)
-			goto cleanup;
-
-		pos++;
-
-		eh = (struct ext4_extent_header *)block.data;
-		tmp_path[pos].block = block;
-		tmp_path[pos].header = eh;
-	}
-
-	tmp_path[pos].depth = 0;
-	tmp_path[pos].extent = NULL;
-	tmp_path[pos].index = NULL;
-
-	/* Find extent in the leaf node */
-	ext4_extent_binsearch(tmp_path[pos].header, &tmp_path[pos].extent,
-			      iblock);
-	*ret_path = tmp_path;
-
-	return EOK;
-
-cleanup:
-	/*
-	 * Put loaded blocks
-	 * From 1: 0 is a block with inode data
-	 */
-	for (i = 1; i < tmp_path->depth; ++i) {
-		if (tmp_path[i].block.lb_id) {
-			int r = ext4_block_set(inode_ref->fs->bdev,
-					       &tmp_path[i].block);
-			if (r != EOK)
-				rc = r;
-		}
-	}
-
-	/* Destroy temporary data structure */
-	free(tmp_path);
-
-	return rc;
-}
-
-/**@brief Release extent and all data blocks covered by the extent.
- * @param inode_ref I-node to release extent and block from
- * @param extent    Extent to release
- * @return Error code */
-static int ext4_extent_release(struct ext4_inode_ref *inode_ref,
-			       struct ext4_extent *extent)
-{
-	/* Compute number of the first physical block to release */
-	uint64_t start = ext4_extent_get_start(extent);
-	uint16_t block_count = ext4_extent_get_block_count(extent);
-
-	return ext4_balloc_free_blocks(inode_ref, start, block_count);
-}
-
-/** Recursively release the whole branch of the extent tree.
- * For each entry of the node release the subbranch and finally release
- * the node. In the leaf node all extents will be released.
- * @param inode_ref I-node where the branch is released
- * @param index     Index in the non-leaf node to be released
- *                  with the whole subtree
- * @return Error code */
-static int ext4_extent_release_branch(struct ext4_inode_ref *inode_ref,
-				      struct ext4_extent_index *index)
-{
-	uint32_t fblock = ext4_extent_index_get_leaf(index);
-	uint32_t i;
-	struct ext4_block block;
-	int rc = ext4_block_get(inode_ref->fs->bdev, &block, fblock);
-	if (rc != EOK)
-		return rc;
-
-	struct ext4_extent_header *header = (void *)block.data;
-
-	if (ext4_extent_header_get_depth(header)) {
-		/* The node is non-leaf, do recursion */
-		struct ext4_extent_index *idx = EXT4_EXTENT_FIRST_INDEX(header);
-
-		/* Release all subbranches */
-		for (i = 0; i < ext4_extent_header_get_entries_count(header);
-		     ++i, ++idx) {
-			rc = ext4_extent_release_branch(inode_ref, idx);
-			if (rc != EOK)
-				return rc;
-		}
-	} else {
-		/* Leaf node reached */
-		struct ext4_extent *ext = EXT4_EXTENT_FIRST(header);
-
-		/* Release all extents and stop recursion */
-		for (i = 0; i < ext4_extent_header_get_entries_count(header);
-		     ++i, ++ext) {
-			rc = ext4_extent_release(inode_ref, ext);
-			if (rc != EOK)
-				return rc;
-		}
-	}
-
-	/* Release data block where the node was stored */
-
-	rc = ext4_block_set(inode_ref->fs->bdev, &block);
-	if (rc != EOK)
-		return rc;
-
-	return ext4_balloc_free_block(inode_ref, fblock);
-}
-
-int ext4_extent_release_blocks_from(struct ext4_inode_ref *inode_ref,
-				    uint32_t iblock_from)
-{
-	/* Find the first extent to modify */
-	struct ext4_extent_path *path;
-	uint16_t i;
-	int rc = ext4_extent_find_extent(inode_ref, iblock_from, &path);
-	if (rc != EOK)
-		return rc;
-
-	/* Jump to last item of the path (extent) */
-	struct ext4_extent_path *path_ptr = path;
-	while (path_ptr->depth != 0)
-		path_ptr++;
-
-	ext4_assert(path_ptr->extent != NULL);
-
-	/* First extent maybe released partially */
-	uint32_t first_iblock = ext4_extent_get_first_block(path_ptr->extent);
-	uint32_t first_fblock = ext4_extent_get_start(path_ptr->extent) +
-				iblock_from - first_iblock;
-
-	uint16_t block_count = ext4_extent_get_block_count(path_ptr->extent);
-
-	uint16_t delete_count =
-	    block_count -
-	    (ext4_extent_get_start(path_ptr->extent) - first_fblock);
-
-	/* Release all blocks */
-	rc = ext4_balloc_free_blocks(inode_ref, first_fblock, delete_count);
-	if (rc != EOK)
-		goto cleanup;
-
-	/* Correct counter */
-	block_count -= delete_count;
-	ext4_extent_set_block_count(path_ptr->extent, block_count);
-
-	/* Initialize the following loop */
-	uint16_t entries =
-	    ext4_extent_header_get_entries_count(path_ptr->header);
-	struct ext4_extent *tmp_ext = path_ptr->extent + 1;
-	struct ext4_extent *stop_ext =
-	    EXT4_EXTENT_FIRST(path_ptr->header) + entries;
-
-	/* If first extent empty, release it */
-	if (block_count == 0)
-		entries--;
-
-	/* Release all successors of the first extent in the same node */
-	while (tmp_ext < stop_ext) {
-		first_fblock = ext4_extent_get_start(tmp_ext);
-		delete_count = ext4_extent_get_block_count(tmp_ext);
-
-		rc = ext4_balloc_free_blocks(inode_ref, first_fblock,
-					     delete_count);
-		if (rc != EOK)
-			goto cleanup;
-
-		entries--;
-		tmp_ext++;
-	}
-
-	ext4_extent_header_set_entries_count(path_ptr->header, entries);
-	path_ptr->block.dirty = true;
-
-	/* If leaf node is empty, parent entry must be modified */
-	bool remove_parent_record = false;
-
-	/* Don't release root block (including inode data) !!! */
-	if ((path_ptr != path) && (entries == 0)) {
-		rc = ext4_balloc_free_block(inode_ref, path_ptr->block.lb_id);
-		if (rc != EOK)
-			goto cleanup;
-
-		remove_parent_record = true;
-	}
-
-	/* Jump to the parent */
-	--path_ptr;
-
-	/* Release all successors in all tree levels */
-	while (path_ptr >= path) {
-		entries =
-		    ext4_extent_header_get_entries_count(path_ptr->header);
-		struct ext4_extent_index *index = path_ptr->index + 1;
-		struct ext4_extent_index *stop =
-		    EXT4_EXTENT_FIRST_INDEX(path_ptr->header) + entries;
-
-		/* Correct entries count because of changes in the previous
-		 * iteration */
-		if (remove_parent_record)
-			entries--;
-
-		/* Iterate over all entries and release the whole subtrees */
-		while (index < stop) {
-			rc = ext4_extent_release_branch(inode_ref, index);
-			if (rc != EOK)
-				goto cleanup;
-
-			++index;
-			--entries;
-		}
-
-		ext4_extent_header_set_entries_count(path_ptr->header, entries);
-		path_ptr->block.dirty = true;
-
-		/* Free the node if it is empty */
-		if ((entries == 0) && (path_ptr != path)) {
-			rc = ext4_balloc_free_block(inode_ref,
-						    path_ptr->block.lb_id);
-			if (rc != EOK)
-				goto cleanup;
-
-			/* Mark parent to be checked */
-			remove_parent_record = true;
-		} else
-			remove_parent_record = false;
-
-		--path_ptr;
-	}
-
-	if (!entries)
-		ext4_extent_header_set_depth(path->header, 0);
-
-cleanup:
-	/*
-	 * Put loaded blocks
-	 * starting from 1: 0 is a block with inode data
-	 */
-	for (i = 1; i <= path->depth; ++i) {
-		if (path[i].block.lb_id) {
-			int r =
-			    ext4_block_set(inode_ref->fs->bdev, &path[i].block);
-			if (r != EOK)
-				rc = r;
-		}
-	}
-
-	/* Destroy temporary data structure */
-	free(path);
-
-	return rc;
-}
-
-/**@brief Append new extent to the i-node and do some splitting if necessary.
- * @param inode_ref      I-node to append extent to
- * @param path           Path in the extent tree for possible splitting
- * @param last_path_item Input/output parameter for pointer to the last
- *                       valid item in the extent tree path
- * @param iblock         Logical index of block to append extent for
- * @return Error code */
-static int ext4_extent_append_extent(struct ext4_inode_ref *inode_ref,
-				     struct ext4_extent_path *path,
-				     uint32_t iblock)
-{
-	struct ext4_extent_path *path_ptr = path + path->depth;
-
-	uint32_t block_size = ext4_sb_get_block_size(&inode_ref->fs->sb);
-
-	/* Start splitting */
-	while (path_ptr > path) {
-		uint16_t entries =
-		    ext4_extent_header_get_entries_count(path_ptr->header);
-		uint16_t limit =
-		    ext4_extent_header_get_max_entries_count(path_ptr->header);
-
-		if (entries == limit) {
-			/* Full node - allocate block for new one */
-			uint32_t fblock;
-			int rc = ext4_balloc_alloc_block(inode_ref, &fblock);
-			if (rc != EOK)
-				return rc;
-
-			struct ext4_block block;
-			rc =
-			    ext4_block_get(inode_ref->fs->bdev, &block, fblock);
-			if (rc != EOK) {
-				ext4_balloc_free_block(inode_ref, fblock);
-				return rc;
-			}
-
-			/* Put back not modified old block */
-			rc = ext4_block_set(inode_ref->fs->bdev,
-					    &path_ptr->block);
-			if (rc != EOK) {
-				ext4_balloc_free_block(inode_ref, fblock);
-				return rc;
-			}
-
-			/* Initialize newly allocated block and remember it */
-			memset(block.data, 0, block_size);
-			path_ptr->block = block;
-
-			/* Update pointers in extent path structure */
-			path_ptr->header = (void *)block.data;
-			if (path_ptr->depth) {
-				path_ptr->index =
-				    EXT4_EXTENT_FIRST_INDEX(path_ptr->header);
-				ext4_extent_index_set_first_block(
-				    path_ptr->index, iblock);
-				ext4_extent_index_set_leaf(
-				    path_ptr->index,
-				    (path_ptr + 1)->block.lb_id);
-				limit = (block_size -
-					 sizeof(struct ext4_extent_header)) /
-					sizeof(struct ext4_extent_index);
-			} else {
-				path_ptr->extent =
-				    EXT4_EXTENT_FIRST(path_ptr->header);
-				ext4_extent_set_first_block(path_ptr->extent,
-							    iblock);
-				limit = (block_size -
-					 sizeof(struct ext4_extent_header)) /
-					sizeof(struct ext4_extent);
-			}
-
-			/* Initialize on-disk structure (header) */
-			ext4_extent_header_set_entries_count(path_ptr->header,
-							     1);
-			ext4_extent_header_set_max_entries_count(
-			    path_ptr->header, limit);
-			ext4_extent_header_set_magic(path_ptr->header,
-						     EXT4_EXTENT_MAGIC);
-			ext4_extent_header_set_depth(path_ptr->header,
-						     path_ptr->depth);
-			ext4_extent_header_set_generation(path_ptr->header, 0);
-
-			path_ptr->block.dirty = true;
-
-			/* Jump to the preceding item */
-			path_ptr--;
-		} else {
-			/* Node with free space */
-			if (path_ptr->depth) {
-				path_ptr->index =
-				    EXT4_EXTENT_FIRST_INDEX(path_ptr->header) +
-				    entries;
-				ext4_extent_index_set_first_block(
-				    path_ptr->index, iblock);
-				ext4_extent_index_set_leaf(
-				    path_ptr->index,
-				    (path_ptr + 1)->block.lb_id);
-			} else {
-				path_ptr->extent =
-				    EXT4_EXTENT_FIRST(path_ptr->header) +
-				    entries;
-				ext4_extent_set_first_block(path_ptr->extent,
-							    iblock);
-			}
-
-			ext4_extent_header_set_entries_count(path_ptr->header,
-							     entries + 1);
-			path_ptr->block.dirty = true;
-
-			/* No more splitting needed */
-			return EOK;
-		}
-	}
-
-	ext4_assert(path_ptr == path);
-
-	/* Should be the root split too? */
-
-	uint16_t entries = ext4_extent_header_get_entries_count(path->header);
-	uint16_t limit = ext4_extent_header_get_max_entries_count(path->header);
-
-	if (entries == limit) {
-		uint32_t new_fblock;
-		int rc = ext4_balloc_alloc_block(inode_ref, &new_fblock);
-		if (rc != EOK)
-			return rc;
-
-		struct ext4_block block;
-		rc = ext4_block_get(inode_ref->fs->bdev, &block, new_fblock);
-		if (rc != EOK)
-			return rc;
-
-		/* Initialize newly allocated block */
-		memset(block.data, 0, block_size);
-
-		/* Move data from root to the new block */
-		memcpy(block.data, inode_ref->inode->blocks,
-		       EXT4_INODE_BLOCKS * sizeof(uint32_t));
-
-		/* Data block is initialized */
-
-		struct ext4_block *root_block = &path->block;
-		uint16_t root_depth = path->depth;
-		struct ext4_extent_header *root_header = path->header;
-
-		/* Make space for tree growing */
-		struct ext4_extent_path *new_root = path;
-		struct ext4_extent_path *old_root = path + 1;
-
-		size_t nbytes =
-		    sizeof(struct ext4_extent_path) * (path->depth + 1);
-		memmove(old_root, new_root, nbytes);
-		memset(new_root, 0, sizeof(struct ext4_extent_path));
-
-		/* Update old root structure */
-		old_root->block = block;
-		old_root->header = (struct ext4_extent_header *)block.data;
-
-		/* Add new entry and update limit for entries */
-		if (old_root->depth) {
-			limit =
-			    (block_size - sizeof(struct ext4_extent_header)) /
-			    sizeof(struct ext4_extent_index);
-			old_root->index =
-			    EXT4_EXTENT_FIRST_INDEX(old_root->header) + entries;
-			ext4_extent_index_set_first_block(old_root->index,
-							  iblock);
-			ext4_extent_index_set_leaf(old_root->index,
-						   (old_root + 1)->block.lb_id);
-			old_root->extent = NULL;
-		} else {
-			limit =
-			    (block_size - sizeof(struct ext4_extent_header)) /
-			    sizeof(struct ext4_extent);
-			old_root->extent =
-			    EXT4_EXTENT_FIRST(old_root->header) + entries;
-			ext4_extent_set_first_block(old_root->extent, iblock);
-			old_root->index = NULL;
-		}
-
-		ext4_extent_header_set_entries_count(old_root->header,
-						     entries + 1);
-		ext4_extent_header_set_max_entries_count(old_root->header,
-							 limit);
-
-		old_root->block.dirty = true;
-
-		/* Re-initialize new root metadata */
-		new_root->depth = root_depth + 1;
-		new_root->block = *root_block;
-		new_root->header = root_header;
-		new_root->extent = NULL;
-		new_root->index = EXT4_EXTENT_FIRST_INDEX(new_root->header);
-
-		ext4_extent_header_set_depth(new_root->header, new_root->depth);
-
-		/* Create new entry in root */
-		ext4_extent_header_set_entries_count(new_root->header, 1);
-		ext4_extent_index_set_first_block(new_root->index, 0);
-		ext4_extent_index_set_leaf(new_root->index, new_fblock);
-
-		new_root->block.dirty = true;
-	} else {
-		if (path->depth) {
-			path->index =
-			    EXT4_EXTENT_FIRST_INDEX(path->header) + entries;
-			ext4_extent_index_set_first_block(path->index, iblock);
-			ext4_extent_index_set_leaf(path->index,
-						   (path + 1)->block.lb_id);
-		} else {
-			path->extent =
-			    EXT4_EXTENT_FIRST(path->header) + entries;
-			ext4_extent_set_first_block(path->extent, iblock);
-		}
-
-		ext4_extent_header_set_entries_count(path->header, entries + 1);
-		path->block.dirty = true;
-	}
-
-	return EOK;
-}
-
-int ext4_extent_append_block(struct ext4_inode_ref *inode_ref, uint32_t *iblock,
-			     uint32_t *fblock, bool update_size)
-{
-	uint16_t i;
-	struct ext4_sblock *sb = &inode_ref->fs->sb;
-	uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
-	uint32_t block_size = ext4_sb_get_block_size(sb);
-
-	/* Calculate number of new logical block */
-	uint32_t new_block_idx = 0;
-	if (inode_size > 0) {
-		if ((inode_size % block_size) != 0)
-			inode_size += block_size - (inode_size % block_size);
-
-		new_block_idx = inode_size / block_size;
-	}
-
-	/* Load the nearest leaf (with extent) */
-	struct ext4_extent_path *path;
-	int rc = ext4_extent_find_extent(inode_ref, new_block_idx, &path);
-	if (rc != EOK)
-		return rc;
-
-	/* Jump to last item of the path (extent) */
-	struct ext4_extent_path *path_ptr = path;
-	while (path_ptr->depth != 0)
-		path_ptr++;
-
-	/* Add new extent to the node if not present */
-	if (path_ptr->extent == NULL)
-		goto append_extent;
-
-	uint16_t block_count = ext4_extent_get_block_count(path_ptr->extent);
-	uint16_t block_limit = (1 << 15);
-
-	uint32_t phys_block = 0;
-	if (block_count < block_limit) {
-		/* There is space for new block in the extent */
-		if (block_count == 0) {
-			/* Existing extent is empty */
-			rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
-			if (rc != EOK)
-				goto finish;
-
-			/* Initialize extent */
-			ext4_extent_set_first_block(path_ptr->extent,
-						    new_block_idx);
-			ext4_extent_set_start(path_ptr->extent, phys_block);
-			ext4_extent_set_block_count(path_ptr->extent, 1);
-
-			/* Update i-node */
-			if (update_size) {
-				ext4_inode_set_size(inode_ref->inode,
-						    inode_size + block_size);
-				inode_ref->dirty = true;
-			}
-
-			path_ptr->block.dirty = true;
-
-			goto finish;
-		} else {
-			/* Existing extent contains some blocks */
-			phys_block = ext4_extent_get_start(path_ptr->extent);
-			phys_block +=
-			    ext4_extent_get_block_count(path_ptr->extent);
-
-			/* Check if the following block is free for allocation
-			 */
-			bool free;
-			rc = ext4_balloc_try_alloc_block(inode_ref, phys_block,
-							 &free);
-			if (rc != EOK)
-				goto finish;
-
-			if (!free) {
-				/* Target is not free, new block must be
-				 * appended to new extent
-				 */
-				goto append_extent;
-			}
-
-			/* Update extent */
-			ext4_extent_set_block_count(path_ptr->extent,
-						    block_count + 1);
-
-			/* Update i-node */
-			if (update_size) {
-				ext4_inode_set_size(inode_ref->inode,
-						    inode_size + block_size);
-				inode_ref->dirty = true;
-			}
-
-			path_ptr->block.dirty = true;
-
-			goto finish;
-		}
-	}
-
-append_extent:
-	/* Append new extent to the tree */
-	phys_block = 0;
-
-	/* Allocate new data block */
-	rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
-	if (rc != EOK)
-		goto finish;
-
-	/* Append extent for new block (includes tree splitting if needed) */
-	rc = ext4_extent_append_extent(inode_ref, path, new_block_idx);
-	if (rc != EOK) {
-		ext4_balloc_free_block(inode_ref, phys_block);
-		goto finish;
-	}
-
-	uint32_t tree_depth = ext4_extent_header_get_depth(path->header);
-	path_ptr = path + tree_depth;
-
-	/* Initialize newly created extent */
-	ext4_extent_set_block_count(path_ptr->extent, 1);
-	ext4_extent_set_first_block(path_ptr->extent, new_block_idx);
-	ext4_extent_set_start(path_ptr->extent, phys_block);
-
-	/* Update i-node */
-	if (update_size) {
-		ext4_inode_set_size(inode_ref->inode, inode_size + block_size);
-		inode_ref->dirty = true;
-	}
-
-	path_ptr->block.dirty = true;
-
-finish:
-	/* Set return values */
-	*iblock = new_block_idx;
-	*fblock = phys_block;
-
-	/*
-	 * Put loaded blocks
-	 * starting from 1: 0 is a block with inode data
-	 */
-	for (i = 1; i <= path->depth; ++i) {
-		if (path[i].block.lb_id) {
-			int r =
-			    ext4_block_set(inode_ref->fs->bdev, &path[i].block);
-			if (r != EOK)
-				rc = r;
-		}
-	}
-
-	/* Destroy temporary data structure */
-	free(path);
-
-	return rc;
-}
-
-/**
- * @}
- */
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file  ext4_extent.c
+ * @brief More complex filesystem functions.
+ */
+
+#include "ext4_config.h"
+#include "ext4_extent.h"
+#include "ext4_inode.h"
+#include "ext4_super.h"
+#include "ext4_blockdev.h"
+#include "ext4_balloc.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+uint32_t ext4_extent_get_first_block(struct ext4_extent *extent)
+{
+	return to_le32(extent->first_block);
+}
+
+void ext4_extent_set_first_block(struct ext4_extent *extent, uint32_t iblock)
+{
+	extent->first_block = to_le32(iblock);
+}
+
+uint16_t ext4_extent_get_block_count(struct ext4_extent *extent)
+{
+	return to_le16(extent->block_count);
+}
+
+void ext4_extent_set_block_count(struct ext4_extent *extent, uint16_t count)
+{
+	extent->block_count = to_le16(count);
+}
+
+uint64_t ext4_extent_get_start(struct ext4_extent *extent)
+{
+	return ((uint64_t)to_le16(extent->start_hi)) << 32 |
+	       ((uint64_t)to_le32(extent->start_lo));
+}
+
+void ext4_extent_set_start(struct ext4_extent *extent, uint64_t fblock)
+{
+	extent->start_lo = to_le32((fblock << 32) >> 32);
+	extent->start_hi = to_le16((uint16_t)(fblock >> 32));
+}
+
+uint32_t ext4_extent_index_get_first_block(struct ext4_extent_index *index)
+{
+	return to_le32(index->first_block);
+}
+
+void ext4_extent_index_set_first_block(struct ext4_extent_index *index,
+				       uint32_t iblock)
+{
+	index->first_block = to_le32(iblock);
+}
+
+uint64_t ext4_extent_index_get_leaf(struct ext4_extent_index *index)
+{
+	return ((uint64_t)to_le16(index->leaf_hi)) << 32 |
+	       ((uint64_t)to_le32(index->leaf_lo));
+}
+
+void ext4_extent_index_set_leaf(struct ext4_extent_index *index,
+				uint64_t fblock)
+{
+	index->leaf_lo = to_le32((fblock << 32) >> 32);
+	index->leaf_hi = to_le16((uint16_t)(fblock >> 32));
+}
+
+uint16_t ext4_extent_header_get_magic(struct ext4_extent_header *header)
+{
+	return to_le16(header->magic);
+}
+
+void ext4_extent_header_set_magic(struct ext4_extent_header *header,
+				  uint16_t magic)
+{
+	header->magic = to_le16(magic);
+}
+
+uint16_t ext4_extent_header_get_entries_count(struct ext4_extent_header *header)
+{
+	return to_le16(header->entries_count);
+}
+
+void ext4_extent_header_set_entries_count(struct ext4_extent_header *header,
+					  uint16_t count)
+{
+	header->entries_count = to_le16(count);
+}
+
+uint16_t
+ext4_extent_header_get_max_entries_count(struct ext4_extent_header *header)
+{
+	return to_le16(header->max_entries_count);
+}
+
+void ext4_extent_header_set_max_entries_count(struct ext4_extent_header *header,
+					      uint16_t max_count)
+{
+	header->max_entries_count = to_le16(max_count);
+}
+
+uint16_t ext4_extent_header_get_depth(struct ext4_extent_header *header)
+{
+	return to_le16(header->depth);
+}
+
+void ext4_extent_header_set_depth(struct ext4_extent_header *header,
+				  uint16_t depth)
+{
+	header->depth = to_le16(depth);
+}
+
+uint32_t ext4_extent_header_get_generation(struct ext4_extent_header *header)
+{
+	return to_le32(header->generation);
+}
+
+void ext4_extent_header_set_generation(struct ext4_extent_header *header,
+				       uint32_t generation)
+{
+	header->generation = to_le32(generation);
+}
+
+/**@brief Binary search in extent index node.
+ * @param header Extent header of index node
+ * @param index  Output value - found index will be set here
+ * @param iblock Logical block number to find in index node */
+static void ext4_extent_binsearch_idx(struct ext4_extent_header *header,
+				      struct ext4_extent_index **index,
+				      uint32_t iblock)
+{
+	struct ext4_extent_index *r;
+	struct ext4_extent_index *l;
+	struct ext4_extent_index *m;
+
+	uint16_t entries_count = ext4_extent_header_get_entries_count(header);
+
+	/* Initialize bounds */
+	l = EXT4_EXTENT_FIRST_INDEX(header) + 1;
+	r = EXT4_EXTENT_FIRST_INDEX(header) + entries_count - 1;
+
+	/* Do binary search */
+	while (l <= r) {
+		m = l + (r - l) / 2;
+		uint32_t first_block = ext4_extent_index_get_first_block(m);
+
+		if (iblock < first_block)
+			r = m - 1;
+		else
+			l = m + 1;
+	}
+
+	/* Set output value */
+	*index = l - 1;
+}
+
+/**@brief Binary search in extent leaf node.
+ * @param header Extent header of leaf node
+ * @param extent Output value - found extent will be set here,
+ *               or NULL if node is empty
+ * @param iblock Logical block number to find in leaf node */
+static void ext4_extent_binsearch(struct ext4_extent_header *header,
+				  struct ext4_extent **extent, uint32_t iblock)
+{
+	struct ext4_extent *r;
+	struct ext4_extent *l;
+	struct ext4_extent *m;
+
+	uint16_t entries_count = ext4_extent_header_get_entries_count(header);
+
+	if (entries_count == 0) {
+		/* this leaf is empty */
+		*extent = NULL;
+		return;
+	}
+
+	/* Initialize bounds */
+	l = EXT4_EXTENT_FIRST(header) + 1;
+	r = EXT4_EXTENT_FIRST(header) + entries_count - 1;
+
+	/* Do binary search */
+	while (l <= r) {
+		m = l + (r - l) / 2;
+		uint32_t first_block = ext4_extent_get_first_block(m);
+
+		if (iblock < first_block)
+			r = m - 1;
+		else
+			l = m + 1;
+	}
+
+	/* Set output value */
+	*extent = l - 1;
+}
+
+int ext4_extent_find_block(struct ext4_inode_ref *inode_ref, uint32_t iblock,
+			   uint32_t *fblock)
+{
+	int rc;
+	/* Compute bound defined by i-node size */
+	uint64_t inode_size =
+	    ext4_inode_get_size(&inode_ref->fs->sb, inode_ref->inode);
+
+	uint32_t block_size = ext4_sb_get_block_size(&inode_ref->fs->sb);
+
+	uint32_t last_idx = (inode_size - 1) / block_size;
+
+	/* Check if requested iblock is not over size of i-node */
+	if (iblock > last_idx) {
+		*fblock = 0;
+		return EOK;
+	}
+
+	struct ext4_block block;
+	block.lb_id = 0;
+
+	/* Walk through extent tree */
+	struct ext4_extent_header *header =
+	    ext4_inode_get_extent_header(inode_ref->inode);
+
+	while (ext4_extent_header_get_depth(header) != 0) {
+		/* Search index in node */
+		struct ext4_extent_index *index;
+		ext4_extent_binsearch_idx(header, &index, iblock);
+
+		/* Load child node and set values for the next iteration */
+		uint64_t child = ext4_extent_index_get_leaf(index);
+
+		if (block.lb_id) {
+			rc = ext4_block_set(inode_ref->fs->bdev, &block);
+			if (rc != EOK)
+				return rc;
+		}
+
+		int rc = ext4_block_get(inode_ref->fs->bdev, &block, child);
+		if (rc != EOK)
+			return rc;
+
+		header = (struct ext4_extent_header *)block.data;
+	}
+
+	/* Search extent in the leaf block */
+	struct ext4_extent *extent = NULL;
+	ext4_extent_binsearch(header, &extent, iblock);
+
+	/* Prevent empty leaf */
+	if (extent == NULL) {
+		*fblock = 0;
+	} else {
+		/* Compute requested physical block address */
+		uint32_t phys_block;
+		uint32_t first = ext4_extent_get_first_block(extent);
+		phys_block = ext4_extent_get_start(extent) + iblock - first;
+
+		*fblock = phys_block;
+	}
+
+	/* Cleanup */
+	if (block.lb_id) {
+		rc = ext4_block_set(inode_ref->fs->bdev, &block);
+		if (rc != EOK)
+			return rc;
+	}
+
+	return EOK;
+}
+
+/**@brief Find extent for specified iblock.
+ * This function is used for finding block in the extent tree with
+ * saving the path through the tree for possible future modifications.
+ * @param inode_ref I-node to read extent tree from
+ * @param iblock    Iblock to find extent for
+ * @param ret_path  Output value for loaded path from extent tree
+ * @return Error code */
+static int ext4_extent_find_extent(struct ext4_inode_ref *inode_ref,
+				   uint32_t iblock,
+				   struct ext4_extent_path **ret_path)
+{
+	struct ext4_extent_header *eh =
+	    ext4_inode_get_extent_header(inode_ref->inode);
+
+	uint16_t depth = ext4_extent_header_get_depth(eh);
+	uint16_t i;
+	struct ext4_extent_path *tmp_path;
+
+	/* Added 2 for possible tree growing */
+	tmp_path = malloc(sizeof(struct ext4_extent_path) * (depth + 2));
+	if (tmp_path == NULL)
+		return ENOMEM;
+
+	/* Initialize structure for algorithm start */
+	tmp_path[0].block = inode_ref->block;
+	tmp_path[0].header = eh;
+
+	/* Walk through the extent tree */
+	uint16_t pos = 0;
+	int rc;
+	while (ext4_extent_header_get_depth(eh) != 0) {
+		/* Search index in index node by iblock */
+		ext4_extent_binsearch_idx(tmp_path[pos].header,
+					  &tmp_path[pos].index, iblock);
+
+		tmp_path[pos].depth = depth;
+		tmp_path[pos].extent = NULL;
+
+		ext4_assert(tmp_path[pos].index != 0);
+
+		/* Load information for the next iteration */
+		uint64_t fblock =
+		    ext4_extent_index_get_leaf(tmp_path[pos].index);
+
+		struct ext4_block block;
+		rc = ext4_block_get(inode_ref->fs->bdev, &block, fblock);
+		if (rc != EOK)
+			goto cleanup;
+
+		pos++;
+
+		eh = (struct ext4_extent_header *)block.data;
+		tmp_path[pos].block = block;
+		tmp_path[pos].header = eh;
+	}
+
+	tmp_path[pos].depth = 0;
+	tmp_path[pos].extent = NULL;
+	tmp_path[pos].index = NULL;
+
+	/* Find extent in the leaf node */
+	ext4_extent_binsearch(tmp_path[pos].header, &tmp_path[pos].extent,
+			      iblock);
+	*ret_path = tmp_path;
+
+	return EOK;
+
+cleanup:
+	/*
+	 * Put loaded blocks
+	 * From 1: 0 is a block with inode data
+	 */
+	for (i = 1; i < tmp_path->depth; ++i) {
+		if (tmp_path[i].block.lb_id) {
+			int r = ext4_block_set(inode_ref->fs->bdev,
+					       &tmp_path[i].block);
+			if (r != EOK)
+				rc = r;
+		}
+	}
+
+	/* Destroy temporary data structure */
+	free(tmp_path);
+
+	return rc;
+}
+
+/**@brief Release extent and all data blocks covered by the extent.
+ * @param inode_ref I-node to release extent and block from
+ * @param extent    Extent to release
+ * @return Error code */
+static int ext4_extent_release(struct ext4_inode_ref *inode_ref,
+			       struct ext4_extent *extent)
+{
+	/* Compute number of the first physical block to release */
+	uint64_t start = ext4_extent_get_start(extent);
+	uint16_t block_count = ext4_extent_get_block_count(extent);
+
+	return ext4_balloc_free_blocks(inode_ref, start, block_count);
+}
+
+/** Recursively release the whole branch of the extent tree.
+ * For each entry of the node release the subbranch and finally release
+ * the node. In the leaf node all extents will be released.
+ * @param inode_ref I-node where the branch is released
+ * @param index     Index in the non-leaf node to be released
+ *                  with the whole subtree
+ * @return Error code */
+static int ext4_extent_release_branch(struct ext4_inode_ref *inode_ref,
+				      struct ext4_extent_index *index)
+{
+	uint32_t fblock = ext4_extent_index_get_leaf(index);
+	uint32_t i;
+	struct ext4_block block;
+	int rc = ext4_block_get(inode_ref->fs->bdev, &block, fblock);
+	if (rc != EOK)
+		return rc;
+
+	struct ext4_extent_header *header = (void *)block.data;
+
+	if (ext4_extent_header_get_depth(header)) {
+		/* The node is non-leaf, do recursion */
+		struct ext4_extent_index *idx = EXT4_EXTENT_FIRST_INDEX(header);
+
+		/* Release all subbranches */
+		for (i = 0; i < ext4_extent_header_get_entries_count(header);
+		     ++i, ++idx) {
+			rc = ext4_extent_release_branch(inode_ref, idx);
+			if (rc != EOK)
+				return rc;
+		}
+	} else {
+		/* Leaf node reached */
+		struct ext4_extent *ext = EXT4_EXTENT_FIRST(header);
+
+		/* Release all extents and stop recursion */
+		for (i = 0; i < ext4_extent_header_get_entries_count(header);
+		     ++i, ++ext) {
+			rc = ext4_extent_release(inode_ref, ext);
+			if (rc != EOK)
+				return rc;
+		}
+	}
+
+	/* Release data block where the node was stored */
+
+	rc = ext4_block_set(inode_ref->fs->bdev, &block);
+	if (rc != EOK)
+		return rc;
+
+	return ext4_balloc_free_block(inode_ref, fblock);
+}
+
+int ext4_extent_release_blocks_from(struct ext4_inode_ref *inode_ref,
+				    uint32_t iblock_from)
+{
+	/* Find the first extent to modify */
+	struct ext4_extent_path *path;
+	uint16_t i;
+	int rc = ext4_extent_find_extent(inode_ref, iblock_from, &path);
+	if (rc != EOK)
+		return rc;
+
+	/* Jump to last item of the path (extent) */
+	struct ext4_extent_path *path_ptr = path;
+	while (path_ptr->depth != 0)
+		path_ptr++;
+
+	ext4_assert(path_ptr->extent != NULL);
+
+	/* First extent maybe released partially */
+	uint32_t first_iblock = ext4_extent_get_first_block(path_ptr->extent);
+	uint32_t first_fblock = ext4_extent_get_start(path_ptr->extent) +
+				iblock_from - first_iblock;
+
+	uint16_t block_count = ext4_extent_get_block_count(path_ptr->extent);
+
+	uint16_t delete_count =
+	    block_count -
+	    (ext4_extent_get_start(path_ptr->extent) - first_fblock);
+
+	/* Release all blocks */
+	rc = ext4_balloc_free_blocks(inode_ref, first_fblock, delete_count);
+	if (rc != EOK)
+		goto cleanup;
+
+	/* Correct counter */
+	block_count -= delete_count;
+	ext4_extent_set_block_count(path_ptr->extent, block_count);
+
+	/* Initialize the following loop */
+	uint16_t entries =
+	    ext4_extent_header_get_entries_count(path_ptr->header);
+	struct ext4_extent *tmp_ext = path_ptr->extent + 1;
+	struct ext4_extent *stop_ext =
+	    EXT4_EXTENT_FIRST(path_ptr->header) + entries;
+
+	/* If first extent empty, release it */
+	if (block_count == 0)
+		entries--;
+
+	/* Release all successors of the first extent in the same node */
+	while (tmp_ext < stop_ext) {
+		first_fblock = ext4_extent_get_start(tmp_ext);
+		delete_count = ext4_extent_get_block_count(tmp_ext);
+
+		rc = ext4_balloc_free_blocks(inode_ref, first_fblock,
+					     delete_count);
+		if (rc != EOK)
+			goto cleanup;
+
+		entries--;
+		tmp_ext++;
+	}
+
+	ext4_extent_header_set_entries_count(path_ptr->header, entries);
+	path_ptr->block.dirty = true;
+
+	/* If leaf node is empty, parent entry must be modified */
+	bool remove_parent_record = false;
+
+	/* Don't release root block (including inode data) !!! */
+	if ((path_ptr != path) && (entries == 0)) {
+		rc = ext4_balloc_free_block(inode_ref, path_ptr->block.lb_id);
+		if (rc != EOK)
+			goto cleanup;
+
+		remove_parent_record = true;
+	}
+
+	/* Jump to the parent */
+	--path_ptr;
+
+	/* Release all successors in all tree levels */
+	while (path_ptr >= path) {
+		entries =
+		    ext4_extent_header_get_entries_count(path_ptr->header);
+		struct ext4_extent_index *index = path_ptr->index + 1;
+		struct ext4_extent_index *stop =
+		    EXT4_EXTENT_FIRST_INDEX(path_ptr->header) + entries;
+
+		/* Correct entries count because of changes in the previous
+		 * iteration */
+		if (remove_parent_record)
+			entries--;
+
+		/* Iterate over all entries and release the whole subtrees */
+		while (index < stop) {
+			rc = ext4_extent_release_branch(inode_ref, index);
+			if (rc != EOK)
+				goto cleanup;
+
+			++index;
+			--entries;
+		}
+
+		ext4_extent_header_set_entries_count(path_ptr->header, entries);
+		path_ptr->block.dirty = true;
+
+		/* Free the node if it is empty */
+		if ((entries == 0) && (path_ptr != path)) {
+			rc = ext4_balloc_free_block(inode_ref,
+						    path_ptr->block.lb_id);
+			if (rc != EOK)
+				goto cleanup;
+
+			/* Mark parent to be checked */
+			remove_parent_record = true;
+		} else
+			remove_parent_record = false;
+
+		--path_ptr;
+	}
+
+	if (!entries)
+		ext4_extent_header_set_depth(path->header, 0);
+
+cleanup:
+	/*
+	 * Put loaded blocks
+	 * starting from 1: 0 is a block with inode data
+	 */
+	for (i = 1; i <= path->depth; ++i) {
+		if (path[i].block.lb_id) {
+			int r =
+			    ext4_block_set(inode_ref->fs->bdev, &path[i].block);
+			if (r != EOK)
+				rc = r;
+		}
+	}
+
+	/* Destroy temporary data structure */
+	free(path);
+
+	return rc;
+}
+
+/**@brief Append new extent to the i-node and do some splitting if necessary.
+ * @param inode_ref      I-node to append extent to
+ * @param path           Path in the extent tree for possible splitting
+ * @param last_path_item Input/output parameter for pointer to the last
+ *                       valid item in the extent tree path
+ * @param iblock         Logical index of block to append extent for
+ * @return Error code */
+static int ext4_extent_append_extent(struct ext4_inode_ref *inode_ref,
+				     struct ext4_extent_path *path,
+				     uint32_t iblock)
+{
+	struct ext4_extent_path *path_ptr = path + path->depth;
+
+	uint32_t block_size = ext4_sb_get_block_size(&inode_ref->fs->sb);
+
+	/* Start splitting */
+	while (path_ptr > path) {
+		uint16_t entries =
+		    ext4_extent_header_get_entries_count(path_ptr->header);
+		uint16_t limit =
+		    ext4_extent_header_get_max_entries_count(path_ptr->header);
+
+		if (entries == limit) {
+			/* Full node - allocate block for new one */
+			uint32_t fblock;
+			int rc = ext4_balloc_alloc_block(inode_ref, &fblock);
+			if (rc != EOK)
+				return rc;
+
+			struct ext4_block block;
+			rc =
+			    ext4_block_get(inode_ref->fs->bdev, &block, fblock);
+			if (rc != EOK) {
+				ext4_balloc_free_block(inode_ref, fblock);
+				return rc;
+			}
+
+			/* Put back not modified old block */
+			rc = ext4_block_set(inode_ref->fs->bdev,
+					    &path_ptr->block);
+			if (rc != EOK) {
+				ext4_balloc_free_block(inode_ref, fblock);
+				return rc;
+			}
+
+			/* Initialize newly allocated block and remember it */
+			memset(block.data, 0, block_size);
+			path_ptr->block = block;
+
+			/* Update pointers in extent path structure */
+			path_ptr->header = (void *)block.data;
+			if (path_ptr->depth) {
+				path_ptr->index =
+				    EXT4_EXTENT_FIRST_INDEX(path_ptr->header);
+				ext4_extent_index_set_first_block(
+				    path_ptr->index, iblock);
+				ext4_extent_index_set_leaf(
+				    path_ptr->index,
+				    (path_ptr + 1)->block.lb_id);
+				limit = (block_size -
+					 sizeof(struct ext4_extent_header)) /
+					sizeof(struct ext4_extent_index);
+			} else {
+				path_ptr->extent =
+				    EXT4_EXTENT_FIRST(path_ptr->header);
+				ext4_extent_set_first_block(path_ptr->extent,
+							    iblock);
+				limit = (block_size -
+					 sizeof(struct ext4_extent_header)) /
+					sizeof(struct ext4_extent);
+			}
+
+			/* Initialize on-disk structure (header) */
+			ext4_extent_header_set_entries_count(path_ptr->header,
+							     1);
+			ext4_extent_header_set_max_entries_count(
+			    path_ptr->header, limit);
+			ext4_extent_header_set_magic(path_ptr->header,
+						     EXT4_EXTENT_MAGIC);
+			ext4_extent_header_set_depth(path_ptr->header,
+						     path_ptr->depth);
+			ext4_extent_header_set_generation(path_ptr->header, 0);
+
+			path_ptr->block.dirty = true;
+
+			/* Jump to the preceding item */
+			path_ptr--;
+		} else {
+			/* Node with free space */
+			if (path_ptr->depth) {
+				path_ptr->index =
+				    EXT4_EXTENT_FIRST_INDEX(path_ptr->header) +
+				    entries;
+				ext4_extent_index_set_first_block(
+				    path_ptr->index, iblock);
+				ext4_extent_index_set_leaf(
+				    path_ptr->index,
+				    (path_ptr + 1)->block.lb_id);
+			} else {
+				path_ptr->extent =
+				    EXT4_EXTENT_FIRST(path_ptr->header) +
+				    entries;
+				ext4_extent_set_first_block(path_ptr->extent,
+							    iblock);
+			}
+
+			ext4_extent_header_set_entries_count(path_ptr->header,
+							     entries + 1);
+			path_ptr->block.dirty = true;
+
+			/* No more splitting needed */
+			return EOK;
+		}
+	}
+
+	ext4_assert(path_ptr == path);
+
+	/* Should be the root split too? */
+
+	uint16_t entries = ext4_extent_header_get_entries_count(path->header);
+	uint16_t limit = ext4_extent_header_get_max_entries_count(path->header);
+
+	if (entries == limit) {
+		uint32_t new_fblock;
+		int rc = ext4_balloc_alloc_block(inode_ref, &new_fblock);
+		if (rc != EOK)
+			return rc;
+
+		struct ext4_block block;
+		rc = ext4_block_get(inode_ref->fs->bdev, &block, new_fblock);
+		if (rc != EOK)
+			return rc;
+
+		/* Initialize newly allocated block */
+		memset(block.data, 0, block_size);
+
+		/* Move data from root to the new block */
+		memcpy(block.data, inode_ref->inode->blocks,
+		       EXT4_INODE_BLOCKS * sizeof(uint32_t));
+
+		/* Data block is initialized */
+
+		struct ext4_block *root_block = &path->block;
+		uint16_t root_depth = path->depth;
+		struct ext4_extent_header *root_header = path->header;
+
+		/* Make space for tree growing */
+		struct ext4_extent_path *new_root = path;
+		struct ext4_extent_path *old_root = path + 1;
+
+		size_t nbytes =
+		    sizeof(struct ext4_extent_path) * (path->depth + 1);
+		memmove(old_root, new_root, nbytes);
+		memset(new_root, 0, sizeof(struct ext4_extent_path));
+
+		/* Update old root structure */
+		old_root->block = block;
+		old_root->header = (struct ext4_extent_header *)block.data;
+
+		/* Add new entry and update limit for entries */
+		if (old_root->depth) {
+			limit =
+			    (block_size - sizeof(struct ext4_extent_header)) /
+			    sizeof(struct ext4_extent_index);
+			old_root->index =
+			    EXT4_EXTENT_FIRST_INDEX(old_root->header) + entries;
+			ext4_extent_index_set_first_block(old_root->index,
+							  iblock);
+			ext4_extent_index_set_leaf(old_root->index,
+						   (old_root + 1)->block.lb_id);
+			old_root->extent = NULL;
+		} else {
+			limit =
+			    (block_size - sizeof(struct ext4_extent_header)) /
+			    sizeof(struct ext4_extent);
+			old_root->extent =
+			    EXT4_EXTENT_FIRST(old_root->header) + entries;
+			ext4_extent_set_first_block(old_root->extent, iblock);
+			old_root->index = NULL;
+		}
+
+		ext4_extent_header_set_entries_count(old_root->header,
+						     entries + 1);
+		ext4_extent_header_set_max_entries_count(old_root->header,
+							 limit);
+
+		old_root->block.dirty = true;
+
+		/* Re-initialize new root metadata */
+		new_root->depth = root_depth + 1;
+		new_root->block = *root_block;
+		new_root->header = root_header;
+		new_root->extent = NULL;
+		new_root->index = EXT4_EXTENT_FIRST_INDEX(new_root->header);
+
+		ext4_extent_header_set_depth(new_root->header, new_root->depth);
+
+		/* Create new entry in root */
+		ext4_extent_header_set_entries_count(new_root->header, 1);
+		ext4_extent_index_set_first_block(new_root->index, 0);
+		ext4_extent_index_set_leaf(new_root->index, new_fblock);
+
+		new_root->block.dirty = true;
+	} else {
+		if (path->depth) {
+			path->index =
+			    EXT4_EXTENT_FIRST_INDEX(path->header) + entries;
+			ext4_extent_index_set_first_block(path->index, iblock);
+			ext4_extent_index_set_leaf(path->index,
+						   (path + 1)->block.lb_id);
+		} else {
+			path->extent =
+			    EXT4_EXTENT_FIRST(path->header) + entries;
+			ext4_extent_set_first_block(path->extent, iblock);
+		}
+
+		ext4_extent_header_set_entries_count(path->header, entries + 1);
+		path->block.dirty = true;
+	}
+
+	return EOK;
+}
+
+int ext4_extent_append_block(struct ext4_inode_ref *inode_ref, uint32_t *iblock,
+			     uint32_t *fblock, bool update_size)
+{
+	uint16_t i;
+	struct ext4_sblock *sb = &inode_ref->fs->sb;
+	uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
+	uint32_t block_size = ext4_sb_get_block_size(sb);
+
+	/* Calculate number of new logical block */
+	uint32_t new_block_idx = 0;
+	if (inode_size > 0) {
+		if ((inode_size % block_size) != 0)
+			inode_size += block_size - (inode_size % block_size);
+
+		new_block_idx = inode_size / block_size;
+	}
+
+	/* Load the nearest leaf (with extent) */
+	struct ext4_extent_path *path;
+	int rc = ext4_extent_find_extent(inode_ref, new_block_idx, &path);
+	if (rc != EOK)
+		return rc;
+
+	/* Jump to last item of the path (extent) */
+	struct ext4_extent_path *path_ptr = path;
+	while (path_ptr->depth != 0)
+		path_ptr++;
+
+	/* Add new extent to the node if not present */
+	if (path_ptr->extent == NULL)
+		goto append_extent;
+
+	uint16_t block_count = ext4_extent_get_block_count(path_ptr->extent);
+	uint16_t block_limit = (1 << 15);
+
+	uint32_t phys_block = 0;
+	if (block_count < block_limit) {
+		/* There is space for new block in the extent */
+		if (block_count == 0) {
+			/* Existing extent is empty */
+			rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
+			if (rc != EOK)
+				goto finish;
+
+			/* Initialize extent */
+			ext4_extent_set_first_block(path_ptr->extent,
+						    new_block_idx);
+			ext4_extent_set_start(path_ptr->extent, phys_block);
+			ext4_extent_set_block_count(path_ptr->extent, 1);
+
+			/* Update i-node */
+			if (update_size) {
+				ext4_inode_set_size(inode_ref->inode,
+						    inode_size + block_size);
+				inode_ref->dirty = true;
+			}
+
+			path_ptr->block.dirty = true;
+
+			goto finish;
+		} else {
+			/* Existing extent contains some blocks */
+			phys_block = ext4_extent_get_start(path_ptr->extent);
+			phys_block +=
+			    ext4_extent_get_block_count(path_ptr->extent);
+
+			/* Check if the following block is free for allocation
+			 */
+			bool free;
+			rc = ext4_balloc_try_alloc_block(inode_ref, phys_block,
+							 &free);
+			if (rc != EOK)
+				goto finish;
+
+			if (!free) {
+				/* Target is not free, new block must be
+				 * appended to new extent
+				 */
+				goto append_extent;
+			}
+
+			/* Update extent */
+			ext4_extent_set_block_count(path_ptr->extent,
+						    block_count + 1);
+
+			/* Update i-node */
+			if (update_size) {
+				ext4_inode_set_size(inode_ref->inode,
+						    inode_size + block_size);
+				inode_ref->dirty = true;
+			}
+
+			path_ptr->block.dirty = true;
+
+			goto finish;
+		}
+	}
+
+append_extent:
+	/* Append new extent to the tree */
+	phys_block = 0;
+
+	/* Allocate new data block */
+	rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
+	if (rc != EOK)
+		goto finish;
+
+	/* Append extent for new block (includes tree splitting if needed) */
+	rc = ext4_extent_append_extent(inode_ref, path, new_block_idx);
+	if (rc != EOK) {
+		ext4_balloc_free_block(inode_ref, phys_block);
+		goto finish;
+	}
+
+	uint32_t tree_depth = ext4_extent_header_get_depth(path->header);
+	path_ptr = path + tree_depth;
+
+	/* Initialize newly created extent */
+	ext4_extent_set_block_count(path_ptr->extent, 1);
+	ext4_extent_set_first_block(path_ptr->extent, new_block_idx);
+	ext4_extent_set_start(path_ptr->extent, phys_block);
+
+	/* Update i-node */
+	if (update_size) {
+		ext4_inode_set_size(inode_ref->inode, inode_size + block_size);
+		inode_ref->dirty = true;
+	}
+
+	path_ptr->block.dirty = true;
+
+finish:
+	/* Set return values */
+	*iblock = new_block_idx;
+	*fblock = phys_block;
+
+	/*
+	 * Put loaded blocks
+	 * starting from 1: 0 is a block with inode data
+	 */
+	for (i = 1; i <= path->depth; ++i) {
+		if (path[i].block.lb_id) {
+			int r =
+			    ext4_block_set(inode_ref->fs->bdev, &path[i].block);
+			if (r != EOK)
+				rc = r;
+		}
+	}
+
+	/* Destroy temporary data structure */
+	free(path);
+
+	return rc;
+}
+
+/**
+ * @}
+ */
--- a/lwext4/ext4_extent.h
+++ b/lwext4/ext4_extent.h
@@ -1,187 +1,187 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file  ext4_extent.h
- * @brief More complex filesystem functions.
- */
-#ifndef EXT4_EXTENT_H_
-#define EXT4_EXTENT_H_
-
-#include "ext4_config.h"
-#include "ext4_types.h"
-
-/**@brief Get logical number of the block covered by extent.
- * @param extent Extent to load number from
- * @return Logical number of the first block covered by extent */
-uint32_t ext4_extent_get_first_block(struct ext4_extent *extent);
-
-/**@brief Set logical number of the first block covered by extent.
- * @param extent Extent to set number to
- * @param iblock Logical number of the first block covered by extent */
-void ext4_extent_set_first_block(struct ext4_extent *extent, uint32_t iblock);
-
-/**@brief Get number of blocks covered by extent.
- * @param extent Extent to load count from
- * @return Number of blocks covered by extent */
-uint16_t ext4_extent_get_block_count(struct ext4_extent *extent);
-
-/**@brief Set number of blocks covered by extent.
- * @param extent Extent to load count from
- * @param count  Number of blocks covered by extent */
-void ext4_extent_set_block_count(struct ext4_extent *extent, uint16_t count);
-
-/**@brief Get physical number of the first block covered by extent.
- * @param extent Extent to load number
- * @return Physical number of the first block covered by extent */
-uint64_t ext4_extent_get_start(struct ext4_extent *extent);
-
-/**@brief Set physical number of the first block covered by extent.
- * @param extent Extent to load number
- * @param fblock Physical number of the first block covered by extent */
-void ext4_extent_set_start(struct ext4_extent *extent, uint64_t fblock);
-
-/**@brief Get logical number of the block covered by extent index.
- * @param index Extent index to load number from
- * @return Logical number of the first block covered by extent index */
-uint32_t ext4_extent_index_get_first_block(struct ext4_extent_index *index);
-
-/**@brief Set logical number of the block covered by extent index.
- * @param index  Extent index to set number to
- * @param iblock Logical number of the first block covered by extent index */
-void ext4_extent_index_set_first_block(struct ext4_extent_index *index,
-				       uint32_t iblock);
-
-/**@brief Get physical number of block where the child node is located.
- * @param index Extent index to load number from
- * @return Physical number of the block with child node */
-uint64_t ext4_extent_index_get_leaf(struct ext4_extent_index *index);
-
-/**@brief Set physical number of block where the child node is located.
- * @param index  Extent index to set number to
- * @param fblock Ohysical number of the block with child node */
-void ext4_extent_index_set_leaf(struct ext4_extent_index *index,
-				uint64_t fblock);
-
-/**@brief Get magic value from extent header.
- * @param header Extent header to load value from
- * @return Magic value of extent header */
-uint16_t ext4_extent_header_get_magic(struct ext4_extent_header *header);
-
-/**@brief Set magic value to extent header.
- * @param header Extent header to set value to
- * @param magic  Magic value of extent header */
-void ext4_extent_header_set_magic(struct ext4_extent_header *header,
-				  uint16_t magic);
-
-/**@brief Get number of entries from extent header
- * @param header Extent header to get value from
- * @return Number of entries covered by extent header */
-uint16_t
-ext4_extent_header_get_entries_count(struct ext4_extent_header *header);
-
-/**@brief Set number of entries to extent header
- * @param header Extent header to set value to
- * @param count  Number of entries covered by extent header */
-void ext4_extent_header_set_entries_count(struct ext4_extent_header *header,
-					  uint16_t count);
-
-/**@brief Get maximum number of entries from extent header
- * @param header Extent header to get value from
- * @return Maximum number of entries covered by extent header */
-uint16_t
-ext4_extent_header_get_max_entries_count(struct ext4_extent_header *header);
-
-/**@brief Set maximum number of entries to extent header
- * @param header    Extent header to set value to
- * @param max_count Maximum number of entries covered by extent header */
-void ext4_extent_header_set_max_entries_count(struct ext4_extent_header *header,
-					      uint16_t max_count);
-
-/**@brief Get depth of extent subtree.
- * @param header Extent header to get value from
- * @return Depth of extent subtree */
-uint16_t ext4_extent_header_get_depth(struct ext4_extent_header *header);
-
-/**@brief Set depth of extent subtree.
- * @param header Extent header to set value to
- * @param depth  Depth of extent subtree */
-void ext4_extent_header_set_depth(struct ext4_extent_header *header,
-				  uint16_t depth);
-
-/**@brief Get generation from extent header
- * @param header Extent header to get value from
- * @return Generation */
-uint32_t ext4_extent_header_get_generation(struct ext4_extent_header *header);
-
-/**@brief Set generation to extent header
- * @param header     Extent header to set value to
- * @param generation Generation */
-void ext4_extent_header_set_generation(struct ext4_extent_header *header,
-				       uint32_t generation);
-
-/**@brief Find physical block in the extent tree by logical block number.
- * There is no need to save path in the tree during this algorithm.
- * @param inode_ref I-node to load block from
- * @param iblock    Logical block number to find
- * @param fblock    Output value for physical block number
- * @return Error code*/
-int ext4_extent_find_block(struct ext4_inode_ref *inode_ref, uint32_t iblock,
-			   uint32_t *fblock);
-
-/**@brief Release all data blocks starting from specified logical block.
- * @param inode_ref   I-node to release blocks from
- * @param iblock_from First logical block to release
- * @return Error code */
-int ext4_extent_release_blocks_from(struct ext4_inode_ref *inode_ref,
-				    uint32_t iblock_from);
-
-/**@brief Append data block to the i-node.
- * This function allocates data block, tries to append it
- * to some existing extent or creates new extents.
- * It includes possible extent tree modifications (splitting).
- * @param inode_ref I-node to append block to
- * @param iblock    Output logical number of newly allocated block
- * @param fblock    Output physical block address of newly allocated block
- *
- * @return Error code*/
-int ext4_extent_append_block(struct ext4_inode_ref *inode_ref, uint32_t *iblock,
-			     uint32_t *fblock, bool update_size);
-
-#endif /* EXT4_EXTENT_H_ */
-       /**
-	* @}
-	*/
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file  ext4_extent.h
+ * @brief More complex filesystem functions.
+ */
+#ifndef EXT4_EXTENT_H_
+#define EXT4_EXTENT_H_
+
+#include "ext4_config.h"
+#include "ext4_types.h"
+
+/**@brief Get logical number of the block covered by extent.
+ * @param extent Extent to load number from
+ * @return Logical number of the first block covered by extent */
+uint32_t ext4_extent_get_first_block(struct ext4_extent *extent);
+
+/**@brief Set logical number of the first block covered by extent.
+ * @param extent Extent to set number to
+ * @param iblock Logical number of the first block covered by extent */
+void ext4_extent_set_first_block(struct ext4_extent *extent, uint32_t iblock);
+
+/**@brief Get number of blocks covered by extent.
+ * @param extent Extent to load count from
+ * @return Number of blocks covered by extent */
+uint16_t ext4_extent_get_block_count(struct ext4_extent *extent);
+
+/**@brief Set number of blocks covered by extent.
+ * @param extent Extent to load count from
+ * @param count  Number of blocks covered by extent */
+void ext4_extent_set_block_count(struct ext4_extent *extent, uint16_t count);
+
+/**@brief Get physical number of the first block covered by extent.
+ * @param extent Extent to load number
+ * @return Physical number of the first block covered by extent */
+uint64_t ext4_extent_get_start(struct ext4_extent *extent);
+
+/**@brief Set physical number of the first block covered by extent.
+ * @param extent Extent to load number
+ * @param fblock Physical number of the first block covered by extent */
+void ext4_extent_set_start(struct ext4_extent *extent, uint64_t fblock);
+
+/**@brief Get logical number of the block covered by extent index.
+ * @param index Extent index to load number from
+ * @return Logical number of the first block covered by extent index */
+uint32_t ext4_extent_index_get_first_block(struct ext4_extent_index *index);
+
+/**@brief Set logical number of the block covered by extent index.
+ * @param index  Extent index to set number to
+ * @param iblock Logical number of the first block covered by extent index */
+void ext4_extent_index_set_first_block(struct ext4_extent_index *index,
+				       uint32_t iblock);
+
+/**@brief Get physical number of block where the child node is located.
+ * @param index Extent index to load number from
+ * @return Physical number of the block with child node */
+uint64_t ext4_extent_index_get_leaf(struct ext4_extent_index *index);
+
+/**@brief Set physical number of block where the child node is located.
+ * @param index  Extent index to set number to
+ * @param fblock Ohysical number of the block with child node */
+void ext4_extent_index_set_leaf(struct ext4_extent_index *index,
+				uint64_t fblock);
+
+/**@brief Get magic value from extent header.
+ * @param header Extent header to load value from
+ * @return Magic value of extent header */
+uint16_t ext4_extent_header_get_magic(struct ext4_extent_header *header);
+
+/**@brief Set magic value to extent header.
+ * @param header Extent header to set value to
+ * @param magic  Magic value of extent header */
+void ext4_extent_header_set_magic(struct ext4_extent_header *header,
+				  uint16_t magic);
+
+/**@brief Get number of entries from extent header
+ * @param header Extent header to get value from
+ * @return Number of entries covered by extent header */
+uint16_t
+ext4_extent_header_get_entries_count(struct ext4_extent_header *header);
+
+/**@brief Set number of entries to extent header
+ * @param header Extent header to set value to
+ * @param count  Number of entries covered by extent header */
+void ext4_extent_header_set_entries_count(struct ext4_extent_header *header,
+					  uint16_t count);
+
+/**@brief Get maximum number of entries from extent header
+ * @param header Extent header to get value from
+ * @return Maximum number of entries covered by extent header */
+uint16_t
+ext4_extent_header_get_max_entries_count(struct ext4_extent_header *header);
+
+/**@brief Set maximum number of entries to extent header
+ * @param header    Extent header to set value to
+ * @param max_count Maximum number of entries covered by extent header */
+void ext4_extent_header_set_max_entries_count(struct ext4_extent_header *header,
+					      uint16_t max_count);
+
+/**@brief Get depth of extent subtree.
+ * @param header Extent header to get value from
+ * @return Depth of extent subtree */
+uint16_t ext4_extent_header_get_depth(struct ext4_extent_header *header);
+
+/**@brief Set depth of extent subtree.
+ * @param header Extent header to set value to
+ * @param depth  Depth of extent subtree */
+void ext4_extent_header_set_depth(struct ext4_extent_header *header,
+				  uint16_t depth);
+
+/**@brief Get generation from extent header
+ * @param header Extent header to get value from
+ * @return Generation */
+uint32_t ext4_extent_header_get_generation(struct ext4_extent_header *header);
+
+/**@brief Set generation to extent header
+ * @param header     Extent header to set value to
+ * @param generation Generation */
+void ext4_extent_header_set_generation(struct ext4_extent_header *header,
+				       uint32_t generation);
+
+/**@brief Find physical block in the extent tree by logical block number.
+ * There is no need to save path in the tree during this algorithm.
+ * @param inode_ref I-node to load block from
+ * @param iblock    Logical block number to find
+ * @param fblock    Output value for physical block number
+ * @return Error code*/
+int ext4_extent_find_block(struct ext4_inode_ref *inode_ref, uint32_t iblock,
+			   uint32_t *fblock);
+
+/**@brief Release all data blocks starting from specified logical block.
+ * @param inode_ref   I-node to release blocks from
+ * @param iblock_from First logical block to release
+ * @return Error code */
+int ext4_extent_release_blocks_from(struct ext4_inode_ref *inode_ref,
+				    uint32_t iblock_from);
+
+/**@brief Append data block to the i-node.
+ * This function allocates data block, tries to append it
+ * to some existing extent or creates new extents.
+ * It includes possible extent tree modifications (splitting).
+ * @param inode_ref I-node to append block to
+ * @param iblock    Output logical number of newly allocated block
+ * @param fblock    Output physical block address of newly allocated block
+ *
+ * @return Error code*/
+int ext4_extent_append_block(struct ext4_inode_ref *inode_ref, uint32_t *iblock,
+			     uint32_t *fblock, bool update_size);
+
+#endif /* EXT4_EXTENT_H_ */
+       /**
+	* @}
+	*/
--- a/lwext4/ext4_hash.c
+++ b/lwext4/ext4_hash.c
@@ -1,322 +1,322 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- * FreeBSD:
- * Copyright (c) 2010, 2013 Zheng Liu <lz@freebsd.org>
- * Copyright (c) 2012, Vyacheslav Matyushin
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
-/*
- * The following notice applies to the code in ext2_half_md4():
- *
- * Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
- *
- * License to copy and use this software is granted provided that it
- * is identified as the "RSA Data Security, Inc. MD4 Message-Digest
- * Algorithm" in all material mentioning or referencing this software
- * or this function.
- *
- * License is also granted to make and use derivative works provided
- * that such works are identified as "derived from the RSA Data
- * Security, Inc. MD4 Message-Digest Algorithm" in all material
- * mentioning or referencing the derived work.
- *
- * RSA Data Security, Inc. makes no representations concerning either
- * the merchantability of this software or the suitability of this
- * software for any particular purpose. It is provided "as is"
- * without express or implied warranty of any kind.
- *
- * These notices must be retained in any copies of any part of this
- * documentation and/or software.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file  ext4_hash.c
- * @brief Directory indexing hash functions.
- */
-
-#include "ext4_config.h"
-#include "ext4_types.h"
-#include "ext4_errno.h"
-
-#include <string.h>
-
-/* F, G, and H are MD4 functions */
-#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
-#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-
-/* ROTATE_LEFT rotates x left n bits */
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
-
-/*
- * FF, GG, and HH are transformations for rounds 1, 2, and 3.
- * Rotation is separated from addition to prevent recomputation.
- */
-#define FF(a, b, c, d, x, s)                                                   \
-	{                                                                      \
-		(a) += F((b), (c), (d)) + (x);                                 \
-		(a) = ROTATE_LEFT((a), (s));                                   \
-	\
-}
-
-#define GG(a, b, c, d, x, s)                                                   \
-	{                                                                      \
-		(a) += G((b), (c), (d)) + (x) + (uint32_t)0x5A827999;          \
-		(a) = ROTATE_LEFT((a), (s));                                   \
-	\
-}
-
-#define HH(a, b, c, d, x, s)                                                   \
-	{                                                                      \
-		(a) += H((b), (c), (d)) + (x) + (uint32_t)0x6ED9EBA1;          \
-		(a) = ROTATE_LEFT((a), (s));                                   \
-	\
-}
-
-/*
- * MD4 basic transformation.  It transforms state based on block.
- *
- * This is a half md4 algorithm since Linux uses this algorithm for dir
- * index.  This function is derived from the RSA Data Security, Inc. MD4
- * Message-Digest Algorithm and was modified as necessary.
- *
- * The return value of this function is uint32_t in Linux, but actually we don't
- * need to check this value, so in our version this function doesn't return any
- * value.
- */
-static void ext2_half_md4(uint32_t hash[4], uint32_t data[8])
-{
-	uint32_t a = hash[0], b = hash[1], c = hash[2], d = hash[3];
-
-	/* Round 1 */
-	FF(a, b, c, d, data[0], 3);
-	FF(d, a, b, c, data[1], 7);
-	FF(c, d, a, b, data[2], 11);
-	FF(b, c, d, a, data[3], 19);
-	FF(a, b, c, d, data[4], 3);
-	FF(d, a, b, c, data[5], 7);
-	FF(c, d, a, b, data[6], 11);
-	FF(b, c, d, a, data[7], 19);
-
-	/* Round 2 */
-	GG(a, b, c, d, data[1], 3);
-	GG(d, a, b, c, data[3], 5);
-	GG(c, d, a, b, data[5], 9);
-	GG(b, c, d, a, data[7], 13);
-	GG(a, b, c, d, data[0], 3);
-	GG(d, a, b, c, data[2], 5);
-	GG(c, d, a, b, data[4], 9);
-	GG(b, c, d, a, data[6], 13);
-
-	/* Round 3 */
-	HH(a, b, c, d, data[3], 3);
-	HH(d, a, b, c, data[7], 9);
-	HH(c, d, a, b, data[2], 11);
-	HH(b, c, d, a, data[6], 15);
-	HH(a, b, c, d, data[1], 3);
-	HH(d, a, b, c, data[5], 9);
-	HH(c, d, a, b, data[0], 11);
-	HH(b, c, d, a, data[4], 15);
-
-	hash[0] += a;
-	hash[1] += b;
-	hash[2] += c;
-	hash[3] += d;
-}
-
-/*
- * Tiny Encryption Algorithm.
- */
-static void ext2_tea(uint32_t hash[4], uint32_t data[8])
-{
-	uint32_t tea_delta = 0x9E3779B9;
-	uint32_t sum;
-	uint32_t x = hash[0], y = hash[1];
-	int n = 16;
-	int i = 1;
-
-	while (n-- > 0) {
-		sum = i * tea_delta;
-		x += ((y << 4) + data[0]) ^ (y + sum) ^ ((y >> 5) + data[1]);
-		y += ((x << 4) + data[2]) ^ (x + sum) ^ ((x >> 5) + data[3]);
-		i++;
-	}
-
-	hash[0] += x;
-	hash[1] += y;
-}
-
-static uint32_t ext2_legacy_hash(const char *name, int len, int unsigned_char)
-{
-	uint32_t h0, h1 = 0x12A3FE2D, h2 = 0x37ABE8F9;
-	uint32_t multi = 0x6D22F5;
-	const unsigned char *uname = (const unsigned char *)name;
-	const signed char *sname = (const signed char *)name;
-	int val, i;
-
-	for (i = 0; i < len; i++) {
-		if (unsigned_char)
-			val = (unsigned int)*uname++;
-		else
-			val = (int)*sname++;
-
-		h0 = h2 + (h1 ^ (val * multi));
-		if (h0 & 0x80000000)
-			h0 -= 0x7FFFFFFF;
-		h2 = h1;
-		h1 = h0;
-	}
-
-	return (h1 << 1);
-}
-
-static void ext2_prep_hashbuf(const char *src, uint32_t slen, uint32_t *dst,
-			      int dlen, int unsigned_char)
-{
-	uint32_t padding = slen | (slen << 8) | (slen << 16) | (slen << 24);
-	uint32_t buf_val;
-	int len, i;
-	int buf_byte;
-	const unsigned char *ubuf = (const unsigned char *)src;
-	const signed char *sbuf = (const signed char *)src;
-
-	if (slen > (uint32_t)dlen)
-		len = dlen;
-	else
-		len = slen;
-
-	buf_val = padding;
-
-	for (i = 0; i < len; i++) {
-		if (unsigned_char)
-			buf_byte = (unsigned int)ubuf[i];
-		else
-			buf_byte = (int)sbuf[i];
-
-		if ((i % 4) == 0)
-			buf_val = padding;
-
-		buf_val <<= 8;
-		buf_val += buf_byte;
-
-		if ((i % 4) == 3) {
-			*dst++ = buf_val;
-			dlen -= sizeof(uint32_t);
-			buf_val = padding;
-		}
-	}
-
-	dlen -= sizeof(uint32_t);
-	if (dlen >= 0)
-		*dst++ = buf_val;
-
-	dlen -= sizeof(uint32_t);
-	while (dlen >= 0) {
-		*dst++ = padding;
-		dlen -= sizeof(uint32_t);
-	}
-}
-
-int ext2_htree_hash(const char *name, int len, const uint32_t *hash_seed,
-		    int hash_version, uint32_t *hash_major,
-		    uint32_t *hash_minor)
-{
-	uint32_t hash[4];
-	uint32_t data[8];
-	uint32_t major = 0, minor = 0;
-	int unsigned_char = 0;
-
-	if (!name || !hash_major)
-		return (-1);
-
-	if (len < 1 || len > 255)
-		goto error;
-
-	hash[0] = 0x67452301;
-	hash[1] = 0xEFCDAB89;
-	hash[2] = 0x98BADCFE;
-	hash[3] = 0x10325476;
-
-	if (hash_seed)
-		memcpy(hash, hash_seed, sizeof(hash));
-
-	switch (hash_version) {
-	case EXT2_HTREE_TEA_UNSIGNED:
-		unsigned_char = 1;
-	case EXT2_HTREE_TEA:
-		while (len > 0) {
-			ext2_prep_hashbuf(name, len, data, 16, unsigned_char);
-			ext2_tea(hash, data);
-			len -= 16;
-			name += 16;
-		}
-		major = hash[0];
-		minor = hash[1];
-		break;
-	case EXT2_HTREE_LEGACY_UNSIGNED:
-		unsigned_char = 1;
-	case EXT2_HTREE_LEGACY:
-		major = ext2_legacy_hash(name, len, unsigned_char);
-		break;
-	case EXT2_HTREE_HALF_MD4_UNSIGNED:
-		unsigned_char = 1;
-	case EXT2_HTREE_HALF_MD4:
-		while (len > 0) {
-			ext2_prep_hashbuf(name, len, data, 32, unsigned_char);
-			ext2_half_md4(hash, data);
-			len -= 32;
-			name += 32;
-		}
-		major = hash[1];
-		minor = hash[2];
-		break;
-	default:
-		goto error;
-	}
-
-	major &= ~1;
-	if (major == (EXT2_HTREE_EOF << 1))
-		major = (EXT2_HTREE_EOF - 1) << 1;
-	*hash_major = major;
-	if (hash_minor)
-		*hash_minor = minor;
-
-	return EOK;
-
-error:
-	*hash_major = 0;
-	if (hash_minor)
-		*hash_minor = 0;
-	return ENOTSUP;
-}
-
-/**
- * @}
- */
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ * FreeBSD:
+ * Copyright (c) 2010, 2013 Zheng Liu <lz@freebsd.org>
+ * Copyright (c) 2012, Vyacheslav Matyushin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ * The following notice applies to the code in ext2_half_md4():
+ *
+ * Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD4 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD4 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file  ext4_hash.c
+ * @brief Directory indexing hash functions.
+ */
+
+#include "ext4_config.h"
+#include "ext4_types.h"
+#include "ext4_errno.h"
+
+#include <string.h>
+
+/* F, G, and H are MD4 functions */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/* ROTATE_LEFT rotates x left n bits */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+/*
+ * FF, GG, and HH are transformations for rounds 1, 2, and 3.
+ * Rotation is separated from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s)                                                   \
+	{                                                                      \
+		(a) += F((b), (c), (d)) + (x);                                 \
+		(a) = ROTATE_LEFT((a), (s));                                   \
+	\
+}
+
+#define GG(a, b, c, d, x, s)                                                   \
+	{                                                                      \
+		(a) += G((b), (c), (d)) + (x) + (uint32_t)0x5A827999;          \
+		(a) = ROTATE_LEFT((a), (s));                                   \
+	\
+}
+
+#define HH(a, b, c, d, x, s)                                                   \
+	{                                                                      \
+		(a) += H((b), (c), (d)) + (x) + (uint32_t)0x6ED9EBA1;          \
+		(a) = ROTATE_LEFT((a), (s));                                   \
+	\
+}
+
+/*
+ * MD4 basic transformation.  It transforms state based on block.
+ *
+ * This is a half md4 algorithm since Linux uses this algorithm for dir
+ * index.  This function is derived from the RSA Data Security, Inc. MD4
+ * Message-Digest Algorithm and was modified as necessary.
+ *
+ * The return value of this function is uint32_t in Linux, but actually we don't
+ * need to check this value, so in our version this function doesn't return any
+ * value.
+ */
+static void ext2_half_md4(uint32_t hash[4], uint32_t data[8])
+{
+	uint32_t a = hash[0], b = hash[1], c = hash[2], d = hash[3];
+
+	/* Round 1 */
+	FF(a, b, c, d, data[0], 3);
+	FF(d, a, b, c, data[1], 7);
+	FF(c, d, a, b, data[2], 11);
+	FF(b, c, d, a, data[3], 19);
+	FF(a, b, c, d, data[4], 3);
+	FF(d, a, b, c, data[5], 7);
+	FF(c, d, a, b, data[6], 11);
+	FF(b, c, d, a, data[7], 19);
+
+	/* Round 2 */
+	GG(a, b, c, d, data[1], 3);
+	GG(d, a, b, c, data[3], 5);
+	GG(c, d, a, b, data[5], 9);
+	GG(b, c, d, a, data[7], 13);
+	GG(a, b, c, d, data[0], 3);
+	GG(d, a, b, c, data[2], 5);
+	GG(c, d, a, b, data[4], 9);
+	GG(b, c, d, a, data[6], 13);
+
+	/* Round 3 */
+	HH(a, b, c, d, data[3], 3);
+	HH(d, a, b, c, data[7], 9);
+	HH(c, d, a, b, data[2], 11);
+	HH(b, c, d, a, data[6], 15);
+	HH(a, b, c, d, data[1], 3);
+	HH(d, a, b, c, data[5], 9);
+	HH(c, d, a, b, data[0], 11);
+	HH(b, c, d, a, data[4], 15);
+
+	hash[0] += a;
+	hash[1] += b;
+	hash[2] += c;
+	hash[3] += d;
+}
+
+/*
+ * Tiny Encryption Algorithm.
+ */
+static void ext2_tea(uint32_t hash[4], uint32_t data[8])
+{
+	uint32_t tea_delta = 0x9E3779B9;
+	uint32_t sum;
+	uint32_t x = hash[0], y = hash[1];
+	int n = 16;
+	int i = 1;
+
+	while (n-- > 0) {
+		sum = i * tea_delta;
+		x += ((y << 4) + data[0]) ^ (y + sum) ^ ((y >> 5) + data[1]);
+		y += ((x << 4) + data[2]) ^ (x + sum) ^ ((x >> 5) + data[3]);
+		i++;
+	}
+
+	hash[0] += x;
+	hash[1] += y;
+}
+
+static uint32_t ext2_legacy_hash(const char *name, int len, int unsigned_char)
+{
+	uint32_t h0, h1 = 0x12A3FE2D, h2 = 0x37ABE8F9;
+	uint32_t multi = 0x6D22F5;
+	const unsigned char *uname = (const unsigned char *)name;
+	const signed char *sname = (const signed char *)name;
+	int val, i;
+
+	for (i = 0; i < len; i++) {
+		if (unsigned_char)
+			val = (unsigned int)*uname++;
+		else
+			val = (int)*sname++;
+
+		h0 = h2 + (h1 ^ (val * multi));
+		if (h0 & 0x80000000)
+			h0 -= 0x7FFFFFFF;
+		h2 = h1;
+		h1 = h0;
+	}
+
+	return (h1 << 1);
+}
+
+static void ext2_prep_hashbuf(const char *src, uint32_t slen, uint32_t *dst,
+			      int dlen, int unsigned_char)
+{
+	uint32_t padding = slen | (slen << 8) | (slen << 16) | (slen << 24);
+	uint32_t buf_val;
+	int len, i;
+	int buf_byte;
+	const unsigned char *ubuf = (const unsigned char *)src;
+	const signed char *sbuf = (const signed char *)src;
+
+	if (slen > (uint32_t)dlen)
+		len = dlen;
+	else
+		len = slen;
+
+	buf_val = padding;
+
+	for (i = 0; i < len; i++) {
+		if (unsigned_char)
+			buf_byte = (unsigned int)ubuf[i];
+		else
+			buf_byte = (int)sbuf[i];
+
+		if ((i % 4) == 0)
+			buf_val = padding;
+
+		buf_val <<= 8;
+		buf_val += buf_byte;
+
+		if ((i % 4) == 3) {
+			*dst++ = buf_val;
+			dlen -= sizeof(uint32_t);
+			buf_val = padding;
+		}
+	}
+
+	dlen -= sizeof(uint32_t);
+	if (dlen >= 0)
+		*dst++ = buf_val;
+
+	dlen -= sizeof(uint32_t);
+	while (dlen >= 0) {
+		*dst++ = padding;
+		dlen -= sizeof(uint32_t);
+	}
+}
+
+int ext2_htree_hash(const char *name, int len, const uint32_t *hash_seed,
+		    int hash_version, uint32_t *hash_major,
+		    uint32_t *hash_minor)
+{
+	uint32_t hash[4];
+	uint32_t data[8];
+	uint32_t major = 0, minor = 0;
+	int unsigned_char = 0;
+
+	if (!name || !hash_major)
+		return (-1);
+
+	if (len < 1 || len > 255)
+		goto error;
+
+	hash[0] = 0x67452301;
+	hash[1] = 0xEFCDAB89;
+	hash[2] = 0x98BADCFE;
+	hash[3] = 0x10325476;
+
+	if (hash_seed)
+		memcpy(hash, hash_seed, sizeof(hash));
+
+	switch (hash_version) {
+	case EXT2_HTREE_TEA_UNSIGNED:
+		unsigned_char = 1;
+	case EXT2_HTREE_TEA:
+		while (len > 0) {
+			ext2_prep_hashbuf(name, len, data, 16, unsigned_char);
+			ext2_tea(hash, data);
+			len -= 16;
+			name += 16;
+		}
+		major = hash[0];
+		minor = hash[1];
+		break;
+	case EXT2_HTREE_LEGACY_UNSIGNED:
+		unsigned_char = 1;
+	case EXT2_HTREE_LEGACY:
+		major = ext2_legacy_hash(name, len, unsigned_char);
+		break;
+	case EXT2_HTREE_HALF_MD4_UNSIGNED:
+		unsigned_char = 1;
+	case EXT2_HTREE_HALF_MD4:
+		while (len > 0) {
+			ext2_prep_hashbuf(name, len, data, 32, unsigned_char);
+			ext2_half_md4(hash, data);
+			len -= 32;
+			name += 32;
+		}
+		major = hash[1];
+		minor = hash[2];
+		break;
+	default:
+		goto error;
+	}
+
+	major &= ~1;
+	if (major == (EXT2_HTREE_EOF << 1))
+		major = (EXT2_HTREE_EOF - 1) << 1;
+	*hash_major = major;
+	if (hash_minor)
+		*hash_minor = minor;
+
+	return EOK;
+
+error:
+	*hash_major = 0;
+	if (hash_minor)
+		*hash_minor = 0;
+	return ENOTSUP;
+}
+
+/**
+ * @}
+ */
--- a/lwext4/ext4_hash.h
+++ b/lwext4/ext4_hash.h
@@ -1,60 +1,60 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file  ext4_hash.h
- * @brief Directory indexing hash functions.
- */
-
-#ifndef EXT4_HASH_H_
-#define EXT4_HASH_H_
-
-#include "ext4_config.h"
-
-#include <stdint.h>
-
-/**@brief   Directory entry name hash function.
- * @param   name entry name
- * @param   len entry name length
- * @param   hash_seed (from superblock)
- * @param   hash version (from superblock)
- * @param   hash_minor output value
- * @param   hash_major output value
- * @return  standard error code*/
-int ext2_htree_hash(const char *name, int len, const uint32_t *hash_seed,
-		    int hash_version, uint32_t *hash_major,
-		    uint32_t *hash_minor);
-
-#endif /* EXT4_HASH_H_ */
-
-/**
- * @}
- */
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file  ext4_hash.h
+ * @brief Directory indexing hash functions.
+ */
+
+#ifndef EXT4_HASH_H_
+#define EXT4_HASH_H_
+
+#include "ext4_config.h"
+
+#include <stdint.h>
+
+/**@brief   Directory entry name hash function.
+ * @param   name entry name
+ * @param   len entry name length
+ * @param   hash_seed (from superblock)
+ * @param   hash version (from superblock)
+ * @param   hash_minor output value
+ * @param   hash_major output value
+ * @return  standard error code*/
+int ext2_htree_hash(const char *name, int len, const uint32_t *hash_seed,
+		    int hash_version, uint32_t *hash_major,
+		    uint32_t *hash_minor);
+
+#endif /* EXT4_HASH_H_ */
+
+/**
+ * @}
+ */
--- a/lwext4/ext4_ialloc.c
+++ b/lwext4/ext4_ialloc.c
@@ -1,296 +1,296 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file  ext4_ialloc.c
- * @brief Inode allocation procedures.
- */
-
-#include "ext4_config.h"
-#include "ext4_types.h"
-#include "ext4_ialloc.h"
-#include "ext4_super.h"
-#include "ext4_fs.h"
-#include "ext4_blockdev.h"
-#include "ext4_block_group.h"
-#include "ext4_bitmap.h"
-
-/**@brief  Convert i-node number to relative index in block group.
- * @param sb    Superblock
- * @param inode I-node number to be converted
- * @return Index of the i-node in the block group
- */
-static uint32_t ext4_ialloc_inode2index_in_group(struct ext4_sblock *sb,
-						 uint32_t inode)
-{
-	uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group);
-	return (inode - 1) % inodes_per_group;
-}
-
-/**@brief Convert relative index of i-node to absolute i-node number.
- * @param sb    Superblock
- * @param index Index to be converted
- * @return Absolute number of the i-node
- *
- */
-static uint32_t ext4_ialloc_index_in_group2inode(struct ext4_sblock *sb,
-						 uint32_t index, uint32_t bgid)
-{
-	uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group);
-	return bgid * inodes_per_group + (index + 1);
-}
-
-/**@brief Compute block group number from the i-node number.
- * @param sb    Superblock
- * @param inode I-node number to be found the block group for
- * @return Block group number computed from i-node number
- */
-static uint32_t ext4_ialloc_get_bgid_of_inode(struct ext4_sblock *sb,
-					      uint32_t inode)
-{
-	uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group);
-	return (inode - 1) / inodes_per_group;
-}
-
-int ext4_ialloc_free_inode(struct ext4_fs *fs, uint32_t index, bool is_dir)
-{
-	struct ext4_sblock *sb = &fs->sb;
-
-	/* Compute index of block group and load it */
-	uint32_t block_group = ext4_ialloc_get_bgid_of_inode(sb, index);
-
-	struct ext4_block_group_ref bg_ref;
-	int rc = ext4_fs_get_block_group_ref(fs, block_group, &bg_ref);
-	if (rc != EOK)
-		return rc;
-
-	/* Load i-node bitmap */
-	uint32_t bitmap_block_addr =
-	    ext4_bg_get_inode_bitmap(bg_ref.block_group, sb);
-
-	struct ext4_block bitmap_block;
-	rc = ext4_block_get(fs->bdev, &bitmap_block, bitmap_block_addr);
-	if (rc != EOK)
-		return rc;
-
-	/* Free i-node in the bitmap */
-	uint32_t index_in_group = ext4_ialloc_inode2index_in_group(sb, index);
-	ext4_bmap_bit_clr(bitmap_block.data, index_in_group);
-	bitmap_block.dirty = true;
-
-	/* Put back the block with bitmap */
-	rc = ext4_block_set(fs->bdev, &bitmap_block);
-	if (rc != EOK) {
-		/* Error in saving bitmap */
-		ext4_fs_put_block_group_ref(&bg_ref);
-		return rc;
-	}
-
-	/* If released i-node is a directory, decrement used directories count
-	 */
-	if (is_dir) {
-		uint32_t bg_used_dirs =
-		    ext4_bg_get_used_dirs_count(bg_ref.block_group, sb);
-		bg_used_dirs--;
-		ext4_bg_set_used_dirs_count(bg_ref.block_group, sb,
-					    bg_used_dirs);
-	}
-
-	/* Update block group free inodes count */
-	uint32_t free_inodes =
-	    ext4_bg_get_free_inodes_count(bg_ref.block_group, sb);
-	free_inodes++;
-	ext4_bg_set_free_inodes_count(bg_ref.block_group, sb, free_inodes);
-
-	bg_ref.dirty = true;
-
-	/* Put back the modified block group */
-	rc = ext4_fs_put_block_group_ref(&bg_ref);
-	if (rc != EOK)
-		return rc;
-
-	/* Update superblock free inodes count */
-	ext4_set32(sb, free_inodes_count,
-		   ext4_get32(sb, free_inodes_count) + 1);
-
-	return EOK;
-}
-
-int ext4_ialloc_alloc_inode(struct ext4_fs *fs, uint32_t *index, bool is_dir)
-{
-	struct ext4_sblock *sb = &fs->sb;
-
-	uint32_t bgid = fs->last_inode_bg_id;
-	uint32_t bg_count = ext4_block_group_cnt(sb);
-	uint32_t sb_free_inodes = ext4_get32(sb, free_inodes_count);
-	bool rewind = false;
-
-	/* Try to find free i-node in all block groups */
-	while (bgid <= bg_count) {
-
-		if (bgid == bg_count) {
-			if (rewind)
-				break;
-			bg_count = fs->last_inode_bg_id;
-			bgid = 0;
-			rewind = true;
-			continue;
-		}
-
-		/* Load block group to check */
-		struct ext4_block_group_ref bg_ref;
-		int rc = ext4_fs_get_block_group_ref(fs, bgid, &bg_ref);
-		if (rc != EOK)
-			return rc;
-
-		struct ext4_bgroup *bg = bg_ref.block_group;
-
-		/* Read necessary values for algorithm */
-		uint32_t free_inodes = ext4_bg_get_free_inodes_count(bg, sb);
-		uint32_t used_dirs = ext4_bg_get_used_dirs_count(bg, sb);
-
-		/* Check if this block group is good candidate for allocation */
-		if (free_inodes > 0) {
-			/* Load block with bitmap */
-			uint32_t bitmap_block_addr =
-			    ext4_bg_get_inode_bitmap(bg_ref.block_group, sb);
-
-			struct ext4_block bitmap_block;
-			rc = ext4_block_get(fs->bdev, &bitmap_block,
-					    bitmap_block_addr);
-			if (rc != EOK) {
-				ext4_fs_put_block_group_ref(&bg_ref);
-				return rc;
-			}
-
-			/* Try to allocate i-node in the bitmap */
-			uint32_t inodes_in_group =
-			    ext4_inodes_in_group_cnt(sb, bgid);
-			uint32_t index_in_group;
-
-			rc = ext4_bmap_bit_find_clr(bitmap_block.data, 0,
-						    inodes_in_group,
-						    &index_in_group);
-			/* Block group has not any free i-node */
-			if (rc == ENOSPC) {
-				rc = ext4_block_set(fs->bdev, &bitmap_block);
-				if (rc != EOK) {
-					ext4_fs_put_block_group_ref(&bg_ref);
-					return rc;
-				}
-
-				rc = ext4_fs_put_block_group_ref(&bg_ref);
-				if (rc != EOK)
-					return rc;
-
-				continue;
-			}
-
-			ext4_bmap_bit_set(bitmap_block.data, index_in_group);
-
-			/* Free i-node found, save the bitmap */
-			bitmap_block.dirty = true;
-
-			ext4_block_set(fs->bdev, &bitmap_block);
-			if (rc != EOK) {
-				ext4_fs_put_block_group_ref(&bg_ref);
-				return rc;
-			}
-
-			/* Modify filesystem counters */
-			free_inodes--;
-			ext4_bg_set_free_inodes_count(bg, sb, free_inodes);
-
-			/* Increment used directories counter */
-			if (is_dir) {
-				used_dirs++;
-				ext4_bg_set_used_dirs_count(bg, sb, used_dirs);
-			}
-
-			/* Decrease unused inodes count */
-			if (ext4_bg_has_flag(bg,
-					     EXT4_BLOCK_GROUP_ITABLE_ZEROED)) {
-				uint32_t unused =
-				    ext4_bg_get_itable_unused(bg, sb);
-
-				uint32_t inodes_in_group =
-				    ext4_inodes_in_group_cnt(sb, bgid);
-
-				uint32_t free = inodes_in_group - unused;
-
-				if (index_in_group >= free) {
-					unused = inodes_in_group -
-						 (index_in_group + 1);
-					ext4_bg_set_itable_unused(bg, sb,
-								  unused);
-				}
-			}
-
-			/* Save modified block group */
-			bg_ref.dirty = true;
-
-			rc = ext4_fs_put_block_group_ref(&bg_ref);
-			if (rc != EOK)
-				return rc;
-
-			/* Update superblock */
-			sb_free_inodes--;
-			ext4_set32(sb, free_inodes_count, sb_free_inodes);
-
-			/* Compute the absolute i-nodex number */
-			*index = ext4_ialloc_index_in_group2inode(
-			    sb, index_in_group, bgid);
-
-			fs->last_inode_bg_id = bgid;
-
-			return EOK;
-		}
-
-		/* Block group not modified, put it and jump to the next block
-		 * group */
-		ext4_fs_put_block_group_ref(&bg_ref);
-		if (rc != EOK)
-			return rc;
-
-		++bgid;
-	}
-
-	return ENOSPC;
-}
-
-/**
- * @}
- */
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file  ext4_ialloc.c
+ * @brief Inode allocation procedures.
+ */
+
+#include "ext4_config.h"
+#include "ext4_types.h"
+#include "ext4_ialloc.h"
+#include "ext4_super.h"
+#include "ext4_fs.h"
+#include "ext4_blockdev.h"
+#include "ext4_block_group.h"
+#include "ext4_bitmap.h"
+
+/**@brief  Convert i-node number to relative index in block group.
+ * @param sb    Superblock
+ * @param inode I-node number to be converted
+ * @return Index of the i-node in the block group
+ */
+static uint32_t ext4_ialloc_inode2index_in_group(struct ext4_sblock *sb,
+						 uint32_t inode)
+{
+	uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group);
+	return (inode - 1) % inodes_per_group;
+}
+
+/**@brief Convert relative index of i-node to absolute i-node number.
+ * @param sb    Superblock
+ * @param index Index to be converted
+ * @return Absolute number of the i-node
+ *
+ */
+static uint32_t ext4_ialloc_index_in_group2inode(struct ext4_sblock *sb,
+						 uint32_t index, uint32_t bgid)
+{
+	uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group);
+	return bgid * inodes_per_group + (index + 1);
+}
+
+/**@brief Compute block group number from the i-node number.
+ * @param sb    Superblock
+ * @param inode I-node number to be found the block group for
+ * @return Block group number computed from i-node number
+ */
+static uint32_t ext4_ialloc_get_bgid_of_inode(struct ext4_sblock *sb,
+					      uint32_t inode)
+{
+	uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group);
+	return (inode - 1) / inodes_per_group;
+}
+
+int ext4_ialloc_free_inode(struct ext4_fs *fs, uint32_t index, bool is_dir)
+{
+	struct ext4_sblock *sb = &fs->sb;
+
+	/* Compute index of block group and load it */
+	uint32_t block_group = ext4_ialloc_get_bgid_of_inode(sb, index);
+
+	struct ext4_block_group_ref bg_ref;
+	int rc = ext4_fs_get_block_group_ref(fs, block_group, &bg_ref);
+	if (rc != EOK)
+		return rc;
+
+	/* Load i-node bitmap */
+	uint32_t bitmap_block_addr =
+	    ext4_bg_get_inode_bitmap(bg_ref.block_group, sb);
+
+	struct ext4_block bitmap_block;
+	rc = ext4_block_get(fs->bdev, &bitmap_block, bitmap_block_addr);
+	if (rc != EOK)
+		return rc;
+
+	/* Free i-node in the bitmap */
+	uint32_t index_in_group = ext4_ialloc_inode2index_in_group(sb, index);
+	ext4_bmap_bit_clr(bitmap_block.data, index_in_group);
+	bitmap_block.dirty = true;
+
+	/* Put back the block with bitmap */
+	rc = ext4_block_set(fs->bdev, &bitmap_block);
+	if (rc != EOK) {
+		/* Error in saving bitmap */
+		ext4_fs_put_block_group_ref(&bg_ref);
+		return rc;
+	}
+
+	/* If released i-node is a directory, decrement used directories count
+	 */
+	if (is_dir) {
+		uint32_t bg_used_dirs =
+		    ext4_bg_get_used_dirs_count(bg_ref.block_group, sb);
+		bg_used_dirs--;
+		ext4_bg_set_used_dirs_count(bg_ref.block_group, sb,
+					    bg_used_dirs);
+	}
+
+	/* Update block group free inodes count */
+	uint32_t free_inodes =
+	    ext4_bg_get_free_inodes_count(bg_ref.block_group, sb);
+	free_inodes++;
+	ext4_bg_set_free_inodes_count(bg_ref.block_group, sb, free_inodes);
+
+	bg_ref.dirty = true;
+
+	/* Put back the modified block group */
+	rc = ext4_fs_put_block_group_ref(&bg_ref);
+	if (rc != EOK)
+		return rc;
+
+	/* Update superblock free inodes count */
+	ext4_set32(sb, free_inodes_count,
+		   ext4_get32(sb, free_inodes_count) + 1);
+
+	return EOK;
+}
+
+int ext4_ialloc_alloc_inode(struct ext4_fs *fs, uint32_t *index, bool is_dir)
+{
+	struct ext4_sblock *sb = &fs->sb;
+
+	uint32_t bgid = fs->last_inode_bg_id;
+	uint32_t bg_count = ext4_block_group_cnt(sb);
+	uint32_t sb_free_inodes = ext4_get32(sb, free_inodes_count);
+	bool rewind = false;
+
+	/* Try to find free i-node in all block groups */
+	while (bgid <= bg_count) {
+
+		if (bgid == bg_count) {
+			if (rewind)
+				break;
+			bg_count = fs->last_inode_bg_id;
+			bgid = 0;
+			rewind = true;
+			continue;
+		}
+
+		/* Load block group to check */
+		struct ext4_block_group_ref bg_ref;
+		int rc = ext4_fs_get_block_group_ref(fs, bgid, &bg_ref);
+		if (rc != EOK)
+			return rc;
+
+		struct ext4_bgroup *bg = bg_ref.block_group;
+
+		/* Read necessary values for algorithm */
+		uint32_t free_inodes = ext4_bg_get_free_inodes_count(bg, sb);
+		uint32_t used_dirs = ext4_bg_get_used_dirs_count(bg, sb);
+
+		/* Check if this block group is good candidate for allocation */
+		if (free_inodes > 0) {
+			/* Load block with bitmap */
+			uint32_t bitmap_block_addr =
+			    ext4_bg_get_inode_bitmap(bg_ref.block_group, sb);
+
+			struct ext4_block bitmap_block;
+			rc = ext4_block_get(fs->bdev, &bitmap_block,
+					    bitmap_block_addr);
+			if (rc != EOK) {
+				ext4_fs_put_block_group_ref(&bg_ref);
+				return rc;
+			}
+
+			/* Try to allocate i-node in the bitmap */
+			uint32_t inodes_in_group =
+			    ext4_inodes_in_group_cnt(sb, bgid);
+			uint32_t index_in_group;
+
+			rc = ext4_bmap_bit_find_clr(bitmap_block.data, 0,
+						    inodes_in_group,
+						    &index_in_group);
+			/* Block group has not any free i-node */
+			if (rc == ENOSPC) {
+				rc = ext4_block_set(fs->bdev, &bitmap_block);
+				if (rc != EOK) {
+					ext4_fs_put_block_group_ref(&bg_ref);
+					return rc;
+				}
+
+				rc = ext4_fs_put_block_group_ref(&bg_ref);
+				if (rc != EOK)
+					return rc;
+
+				continue;
+			}
+
+			ext4_bmap_bit_set(bitmap_block.data, index_in_group);
+
+			/* Free i-node found, save the bitmap */
+			bitmap_block.dirty = true;
+
+			ext4_block_set(fs->bdev, &bitmap_block);
+			if (rc != EOK) {
+				ext4_fs_put_block_group_ref(&bg_ref);
+				return rc;
+			}
+
+			/* Modify filesystem counters */
+			free_inodes--;
+			ext4_bg_set_free_inodes_count(bg, sb, free_inodes);
+
+			/* Increment used directories counter */
+			if (is_dir) {
+				used_dirs++;
+				ext4_bg_set_used_dirs_count(bg, sb, used_dirs);
+			}
+
+			/* Decrease unused inodes count */
+			if (ext4_bg_has_flag(bg,
+					     EXT4_BLOCK_GROUP_ITABLE_ZEROED)) {
+				uint32_t unused =
+				    ext4_bg_get_itable_unused(bg, sb);
+
+				uint32_t inodes_in_group =
+				    ext4_inodes_in_group_cnt(sb, bgid);
+
+				uint32_t free = inodes_in_group - unused;
+
+				if (index_in_group >= free) {
+					unused = inodes_in_group -
+						 (index_in_group + 1);
+					ext4_bg_set_itable_unused(bg, sb,
+								  unused);
+				}
+			}
+
+			/* Save modified block group */
+			bg_ref.dirty = true;
+
+			rc = ext4_fs_put_block_group_ref(&bg_ref);
+			if (rc != EOK)
+				return rc;
+
+			/* Update superblock */
+			sb_free_inodes--;
+			ext4_set32(sb, free_inodes_count, sb_free_inodes);
+
+			/* Compute the absolute i-nodex number */
+			*index = ext4_ialloc_index_in_group2inode(
+			    sb, index_in_group, bgid);
+
+			fs->last_inode_bg_id = bgid;
+
+			return EOK;
+		}
+
+		/* Block group not modified, put it and jump to the next block
+		 * group */
+		ext4_fs_put_block_group_ref(&bg_ref);
+		if (rc != EOK)
+			return rc;
+
+		++bgid;
+	}
+
+	return ENOSPC;
+}
+
+/**
+ * @}
+ */
--- a/lwext4/ext4_ialloc.h
+++ b/lwext4/ext4_ialloc.h
@@ -1,76 +1,76 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file  ext4_ialloc.c
- * @brief Inode allocation procedures.
- */
-
-#ifndef EXT4_IALLOC_H_
-#define EXT4_IALLOC_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "ext4_config.h"
-#include "ext4_types.h"
-
-/**@brief Free i-node number and modify filesystem data structers.
- * @param fs     Filesystem, where the i-node is located
- * @param index  Index of i-node to be release
- * @param is_dir Flag us for information whether i-node is directory or not
- */
-int ext4_ialloc_free_inode(struct ext4_fs *fs, uint32_t index, bool is_dir);
-
-/**@brief I-node allocation algorithm.
- * This is more simple algorithm, than Orlov allocator used
- * in the Linux kernel.
- * @param fs     Filesystem to allocate i-node on
- * @param index  Output value - allocated i-node number
- * @param is_dir Flag if allocated i-node will be file or directory
- * @return Error code
- */
-int ext4_ialloc_alloc_inode(struct ext4_fs *fs, uint32_t *index, bool is_dir);
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* EXT4_IALLOC_H_ */
-
-/**
- * @}
- */
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file  ext4_ialloc.c
+ * @brief Inode allocation procedures.
+ */
+
+#ifndef EXT4_IALLOC_H_
+#define EXT4_IALLOC_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ext4_config.h"
+#include "ext4_types.h"
+
+/**@brief Free i-node number and modify filesystem data structers.
+ * @param fs     Filesystem, where the i-node is located
+ * @param index  Index of i-node to be release
+ * @param is_dir Flag us for information whether i-node is directory or not
+ */
+int ext4_ialloc_free_inode(struct ext4_fs *fs, uint32_t index, bool is_dir);
+
+/**@brief I-node allocation algorithm.
+ * This is more simple algorithm, than Orlov allocator used
+ * in the Linux kernel.
+ * @param fs     Filesystem to allocate i-node on
+ * @param index  Output value - allocated i-node number
+ * @param is_dir Flag if allocated i-node will be file or directory
+ * @return Error code
+ */
+int ext4_ialloc_alloc_inode(struct ext4_fs *fs, uint32_t *index, bool is_dir);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* EXT4_IALLOC_H_ */
+
+/**
+ * @}
+ */
--- a/lwext4/ext4_inode.c
+++ b/lwext4/ext4_inode.c
@@ -1,340 +1,340 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file  ext4_inode.c
- * @brief Inode handle functions
- */
-
-#include "ext4_config.h"
-#include "ext4_types.h"
-#include "ext4_inode.h"
-#include "ext4_super.h"
-
-/**@brief  Compute number of bits for block count.
- * @param block_size Filesystem block_size
- * @return Number of bits
- */
-static uint32_t ext4_inode_block_bits_count(uint32_t block_size)
-{
-	uint32_t bits = 8;
-	uint32_t size = block_size;
-
-	do {
-		bits++;
-		size = size >> 1;
-	} while (size > 256);
-
-	return bits;
-}
-
-uint32_t ext4_inode_get_mode(struct ext4_sblock *sb, struct ext4_inode *inode)
-{
-	uint32_t v = to_le16(inode->mode);
-
-	if (ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_HURD) {
-		v |= ((uint32_t)to_le16(inode->osd2.hurd2.mode_high)) << 16;
-	}
-
-	return v;
-}
-
-void ext4_inode_set_mode(struct ext4_sblock *sb, struct ext4_inode *inode,
-			 uint32_t mode)
-{
-	inode->mode = to_le16((mode << 16) >> 16);
-
-	if (ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_HURD)
-		inode->osd2.hurd2.mode_high = to_le16(mode >> 16);
-}
-
-uint32_t ext4_inode_get_uid(struct ext4_inode *inode)
-{
-	return to_le32(inode->uid);
-}
-
-void ext4_inode_set_uid(struct ext4_inode *inode, uint32_t uid)
-{
-	inode->uid = to_le32(uid);
-}
-
-uint64_t ext4_inode_get_size(struct ext4_sblock *sb, struct ext4_inode *inode)
-{
-	uint64_t v = to_le32(inode->size_lo);
-
-	if ((ext4_get32(sb, rev_level) > 0) &&
-	    (ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_FILE)))
-		v |= ((uint64_t)to_le32(inode->size_hi)) << 32;
-
-	return v;
-}
-
-void ext4_inode_set_size(struct ext4_inode *inode, uint64_t size)
-{
-	inode->size_lo = to_le32((size << 32) >> 32);
-	inode->size_hi = to_le32(size >> 32);
-}
-
-uint32_t ext4_inode_get_access_time(struct ext4_inode *inode)
-{
-	return to_le32(inode->access_time);
-}
-void ext4_inode_set_access_time(struct ext4_inode *inode, uint32_t time)
-{
-	inode->access_time = to_le32(time);
-}
-
-uint32_t ext4_inode_get_change_inode_time(struct ext4_inode *inode)
-{
-	return to_le32(inode->change_inode_time);
-}
-void ext4_inode_set_change_inode_time(struct ext4_inode *inode, uint32_t time)
-{
-	inode->change_inode_time = to_le32(time);
-}
-
-uint32_t ext4_inode_get_modification_time(struct ext4_inode *inode)
-{
-	return to_le32(inode->modification_time);
-}
-
-void ext4_inode_set_modification_time(struct ext4_inode *inode, uint32_t time)
-{
-	inode->modification_time = to_le32(time);
-}
-
-uint32_t ext4_inode_get_deletion_time(struct ext4_inode *inode)
-{
-	return to_le32(inode->deletion_time);
-}
-
-void ext4_inode_set_deletion_time(struct ext4_inode *inode, uint32_t time)
-{
-	inode->deletion_time = to_le32(time);
-}
-
-uint32_t ext4_inode_get_gid(struct ext4_inode *inode)
-{
-	return to_le32(inode->gid);
-}
-void ext4_inode_set_gid(struct ext4_inode *inode, uint32_t gid)
-{
-	inode->gid = to_le32(gid);
-}
-
-uint16_t ext4_inode_get_links_count(struct ext4_inode *inode)
-{
-	return to_le16(inode->links_count);
-}
-void ext4_inode_set_links_count(struct ext4_inode *inode, uint16_t cnt)
-{
-	inode->links_count = to_le16(cnt);
-}
-
-uint64_t ext4_inode_get_blocks_count(struct ext4_sblock *sb,
-				     struct ext4_inode *inode)
-{
-	uint64_t count = to_le32(inode->blocks_count_lo);
-
-	if (ext4_sb_has_feature_read_only(sb,
-					  EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
-
-		/* 48-bit field */
-		count |= ((uint64_t)to_le16(inode->osd2.linux2.blocks_high))
-			 << 32;
-
-		if (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_HUGE_FILE)) {
-
-			uint32_t block_bits = ext4_inode_block_bits_count(
-			    ext4_sb_get_block_size(sb));
-			return count << (block_bits - 9);
-		}
-	}
-
-	return count;
-}
-
-int ext4_inode_set_blocks_count(struct ext4_sblock *sb,
-				struct ext4_inode *inode, uint64_t count)
-{
-	/* 32-bit maximum */
-	uint64_t max = 0;
-	max = ~max >> 32;
-
-	if (count <= max) {
-		inode->blocks_count_lo = to_le32(count);
-		inode->osd2.linux2.blocks_high = 0;
-		ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
-
-		return EOK;
-	}
-
-	/* Check if there can be used huge files (many blocks) */
-	if (!ext4_sb_has_feature_read_only(sb,
-					   EXT4_FEATURE_RO_COMPAT_HUGE_FILE))
-		return EINVAL;
-
-	/* 48-bit maximum */
-	max = 0;
-	max = ~max >> 16;
-
-	if (count <= max) {
-		inode->blocks_count_lo = to_le32(count);
-		inode->osd2.linux2.blocks_high = to_le16(count >> 32);
-		ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
-	} else {
-		uint32_t block_bits =
-		    ext4_inode_block_bits_count(ext4_sb_get_block_size(sb));
-
-		ext4_inode_set_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
-		count = count >> (block_bits - 9);
-		inode->blocks_count_lo = to_le32(count);
-		inode->osd2.linux2.blocks_high = to_le16(count >> 32);
-	}
-
-	return EOK;
-}
-
-uint32_t ext4_inode_get_flags(struct ext4_inode *inode)
-{
-	return to_le32(inode->flags);
-}
-void ext4_inode_set_flags(struct ext4_inode *inode, uint32_t flags)
-{
-	inode->flags = to_le32(flags);
-}
-
-uint32_t ext4_inode_get_generation(struct ext4_inode *inode)
-{
-	return to_le32(inode->generation);
-}
-void ext4_inode_set_generation(struct ext4_inode *inode, uint32_t gen)
-{
-	inode->generation = to_le32(gen);
-}
-
-uint64_t ext4_inode_get_file_acl(struct ext4_inode *inode,
-				 struct ext4_sblock *sb)
-{
-	/*TODO: Verify it*/
-	uint64_t v = to_le32(inode->file_acl_lo);
-
-	if (ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_LINUX)
-		v |= ((uint32_t)to_le16(inode->osd2.linux2.file_acl_high))
-		     << 16;
-
-	return v;
-}
-
-void ext4_inode_set_file_acl(struct ext4_inode *inode, struct ext4_sblock *sb,
-			     uint64_t acl)
-{
-	/*TODO: Verify it*/
-	inode->file_acl_lo = to_le32((acl << 32) >> 32);
-
-	if (ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_LINUX)
-		inode->osd2.linux2.file_acl_high = to_le16(acl >> 32);
-}
-
-uint32_t ext4_inode_get_direct_block(struct ext4_inode *inode, uint32_t idx)
-{
-	return to_le32(inode->blocks[idx]);
-}
-void ext4_inode_set_direct_block(struct ext4_inode *inode, uint32_t idx,
-				 uint32_t block)
-{
-	inode->blocks[idx] = to_le32(block);
-}
-
-uint32_t ext4_inode_get_indirect_block(struct ext4_inode *inode, uint32_t idx)
-{
-	return to_le32(inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK]);
-}
-
-void ext4_inode_set_indirect_block(struct ext4_inode *inode, uint32_t idx,
-				   uint32_t block)
-{
-	inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK] = to_le32(block);
-}
-
-bool ext4_inode_is_type(struct ext4_sblock *sb, struct ext4_inode *inode,
-			uint32_t type)
-{
-	return (ext4_inode_get_mode(sb, inode) & EXT4_INODE_MODE_TYPE_MASK) ==
-	       type;
-}
-
-bool ext4_inode_has_flag(struct ext4_inode *inode, uint32_t f)
-{
-	return ext4_inode_get_flags(inode) & f;
-}
-
-void ext4_inode_clear_flag(struct ext4_inode *inode, uint32_t f)
-{
-	uint32_t flags = ext4_inode_get_flags(inode);
-	flags = flags & (~f);
-	ext4_inode_set_flags(inode, flags);
-}
-
-void ext4_inode_set_flag(struct ext4_inode *inode, uint32_t f)
-{
-	uint32_t flags = ext4_inode_get_flags(inode);
-	flags = flags | f;
-	ext4_inode_set_flags(inode, flags);
-}
-
-bool ext4_inode_can_truncate(struct ext4_sblock *sb, struct ext4_inode *inode)
-{
-	if ((ext4_inode_has_flag(inode, EXT4_INODE_FLAG_APPEND)) ||
-	    (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_IMMUTABLE)))
-		return false;
-
-	if ((ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_FILE)) ||
-	    (ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_DIRECTORY)))
-		return true;
-
-	return false;
-}
-
-struct ext4_extent_header *
-ext4_inode_get_extent_header(struct ext4_inode *inode)
-{
-	return (struct ext4_extent_header *)inode->blocks;
-}
-
-/**
- * @}
- */
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file  ext4_inode.c
+ * @brief Inode handle functions
+ */
+
+#include "ext4_config.h"
+#include "ext4_types.h"
+#include "ext4_inode.h"
+#include "ext4_super.h"
+
+/**@brief  Compute number of bits for block count.
+ * @param block_size Filesystem block_size
+ * @return Number of bits
+ */
+static uint32_t ext4_inode_block_bits_count(uint32_t block_size)
+{
+	uint32_t bits = 8;
+	uint32_t size = block_size;
+
+	do {
+		bits++;
+		size = size >> 1;
+	} while (size > 256);
+
+	return bits;
+}
+
+uint32_t ext4_inode_get_mode(struct ext4_sblock *sb, struct ext4_inode *inode)
+{
+	uint32_t v = to_le16(inode->mode);
+
+	if (ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_HURD) {
+		v |= ((uint32_t)to_le16(inode->osd2.hurd2.mode_high)) << 16;
+	}
+
+	return v;
+}
+
+void ext4_inode_set_mode(struct ext4_sblock *sb, struct ext4_inode *inode,
+			 uint32_t mode)
+{
+	inode->mode = to_le16((mode << 16) >> 16);
+
+	if (ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_HURD)
+		inode->osd2.hurd2.mode_high = to_le16(mode >> 16);
+}
+
+uint32_t ext4_inode_get_uid(struct ext4_inode *inode)
+{
+	return to_le32(inode->uid);
+}
+
+void ext4_inode_set_uid(struct ext4_inode *inode, uint32_t uid)
+{
+	inode->uid = to_le32(uid);
+}
+
+uint64_t ext4_inode_get_size(struct ext4_sblock *sb, struct ext4_inode *inode)
+{
+	uint64_t v = to_le32(inode->size_lo);
+
+	if ((ext4_get32(sb, rev_level) > 0) &&
+	    (ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_FILE)))
+		v |= ((uint64_t)to_le32(inode->size_hi)) << 32;
+
+	return v;
+}
+
+void ext4_inode_set_size(struct ext4_inode *inode, uint64_t size)
+{
+	inode->size_lo = to_le32((size << 32) >> 32);
+	inode->size_hi = to_le32(size >> 32);
+}
+
+uint32_t ext4_inode_get_access_time(struct ext4_inode *inode)
+{
+	return to_le32(inode->access_time);
+}
+void ext4_inode_set_access_time(struct ext4_inode *inode, uint32_t time)
+{
+	inode->access_time = to_le32(time);
+}
+
+uint32_t ext4_inode_get_change_inode_time(struct ext4_inode *inode)
+{
+	return to_le32(inode->change_inode_time);
+}
+void ext4_inode_set_change_inode_time(struct ext4_inode *inode, uint32_t time)
+{
+	inode->change_inode_time = to_le32(time);
+}
+
+uint32_t ext4_inode_get_modification_time(struct ext4_inode *inode)
+{
+	return to_le32(inode->modification_time);
+}
+
+void ext4_inode_set_modification_time(struct ext4_inode *inode, uint32_t time)
+{
+	inode->modification_time = to_le32(time);
+}
+
+uint32_t ext4_inode_get_deletion_time(struct ext4_inode *inode)
+{
+	return to_le32(inode->deletion_time);
+}
+
+void ext4_inode_set_deletion_time(struct ext4_inode *inode, uint32_t time)
+{
+	inode->deletion_time = to_le32(time);
+}
+
+uint32_t ext4_inode_get_gid(struct ext4_inode *inode)
+{
+	return to_le32(inode->gid);
+}
+void ext4_inode_set_gid(struct ext4_inode *inode, uint32_t gid)
+{
+	inode->gid = to_le32(gid);
+}
+
+uint16_t ext4_inode_get_links_count(struct ext4_inode *inode)
+{
+	return to_le16(inode->links_count);
+}
+void ext4_inode_set_links_count(struct ext4_inode *inode, uint16_t cnt)
+{
+	inode->links_count = to_le16(cnt);
+}
+
+uint64_t ext4_inode_get_blocks_count(struct ext4_sblock *sb,
+				     struct ext4_inode *inode)
+{
+	uint64_t count = to_le32(inode->blocks_count_lo);
+
+	if (ext4_sb_has_feature_read_only(sb,
+					  EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
+
+		/* 48-bit field */
+		count |= ((uint64_t)to_le16(inode->osd2.linux2.blocks_high))
+			 << 32;
+
+		if (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_HUGE_FILE)) {
+
+			uint32_t block_bits = ext4_inode_block_bits_count(
+			    ext4_sb_get_block_size(sb));
+			return count << (block_bits - 9);
+		}
+	}
+
+	return count;
+}
+
+int ext4_inode_set_blocks_count(struct ext4_sblock *sb,
+				struct ext4_inode *inode, uint64_t count)
+{
+	/* 32-bit maximum */
+	uint64_t max = 0;
+	max = ~max >> 32;
+
+	if (count <= max) {
+		inode->blocks_count_lo = to_le32(count);
+		inode->osd2.linux2.blocks_high = 0;
+		ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
+
+		return EOK;
+	}
+
+	/* Check if there can be used huge files (many blocks) */
+	if (!ext4_sb_has_feature_read_only(sb,
+					   EXT4_FEATURE_RO_COMPAT_HUGE_FILE))
+		return EINVAL;
+
+	/* 48-bit maximum */
+	max = 0;
+	max = ~max >> 16;
+
+	if (count <= max) {
+		inode->blocks_count_lo = to_le32(count);
+		inode->osd2.linux2.blocks_high = to_le16(count >> 32);
+		ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
+	} else {
+		uint32_t block_bits =
+		    ext4_inode_block_bits_count(ext4_sb_get_block_size(sb));
+
+		ext4_inode_set_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
+		count = count >> (block_bits - 9);
+		inode->blocks_count_lo = to_le32(count);
+		inode->osd2.linux2.blocks_high = to_le16(count >> 32);
+	}
+
+	return EOK;
+}
+
+uint32_t ext4_inode_get_flags(struct ext4_inode *inode)
+{
+	return to_le32(inode->flags);
+}
+void ext4_inode_set_flags(struct ext4_inode *inode, uint32_t flags)
+{
+	inode->flags = to_le32(flags);
+}
+
+uint32_t ext4_inode_get_generation(struct ext4_inode *inode)
+{
+	return to_le32(inode->generation);
+}
+void ext4_inode_set_generation(struct ext4_inode *inode, uint32_t gen)
+{
+	inode->generation = to_le32(gen);
+}
+
+uint64_t ext4_inode_get_file_acl(struct ext4_inode *inode,
+				 struct ext4_sblock *sb)
+{
+	/*TODO: Verify it*/
+	uint64_t v = to_le32(inode->file_acl_lo);
+
+	if (ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_LINUX)
+		v |= ((uint32_t)to_le16(inode->osd2.linux2.file_acl_high))
+		     << 16;
+
+	return v;
+}
+
+void ext4_inode_set_file_acl(struct ext4_inode *inode, struct ext4_sblock *sb,
+			     uint64_t acl)
+{
+	/*TODO: Verify it*/
+	inode->file_acl_lo = to_le32((acl << 32) >> 32);
+
+	if (ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_LINUX)
+		inode->osd2.linux2.file_acl_high = to_le16(acl >> 32);
+}
+
+uint32_t ext4_inode_get_direct_block(struct ext4_inode *inode, uint32_t idx)
+{
+	return to_le32(inode->blocks[idx]);
+}
+void ext4_inode_set_direct_block(struct ext4_inode *inode, uint32_t idx,
+				 uint32_t block)
+{
+	inode->blocks[idx] = to_le32(block);
+}
+
+uint32_t ext4_inode_get_indirect_block(struct ext4_inode *inode, uint32_t idx)
+{
+	return to_le32(inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK]);
+}
+
+void ext4_inode_set_indirect_block(struct ext4_inode *inode, uint32_t idx,
+				   uint32_t block)
+{
+	inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK] = to_le32(block);
+}
+
+bool ext4_inode_is_type(struct ext4_sblock *sb, struct ext4_inode *inode,
+			uint32_t type)
+{
+	return (ext4_inode_get_mode(sb, inode) & EXT4_INODE_MODE_TYPE_MASK) ==
+	       type;
+}
+
+bool ext4_inode_has_flag(struct ext4_inode *inode, uint32_t f)
+{
+	return ext4_inode_get_flags(inode) & f;
+}
+
+void ext4_inode_clear_flag(struct ext4_inode *inode, uint32_t f)
+{
+	uint32_t flags = ext4_inode_get_flags(inode);
+	flags = flags & (~f);
+	ext4_inode_set_flags(inode, flags);
+}
+
+void ext4_inode_set_flag(struct ext4_inode *inode, uint32_t f)
+{
+	uint32_t flags = ext4_inode_get_flags(inode);
+	flags = flags | f;
+	ext4_inode_set_flags(inode, flags);
+}
+
+bool ext4_inode_can_truncate(struct ext4_sblock *sb, struct ext4_inode *inode)
+{
+	if ((ext4_inode_has_flag(inode, EXT4_INODE_FLAG_APPEND)) ||
+	    (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_IMMUTABLE)))
+		return false;
+
+	if ((ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_FILE)) ||
+	    (ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_DIRECTORY)))
+		return true;
+
+	return false;
+}
+
+struct ext4_extent_header *
+ext4_inode_get_extent_header(struct ext4_inode *inode)
+{
+	return (struct ext4_extent_header *)inode->blocks;
+}
+
+/**
+ * @}
+ */
--- a/lwext4/ext4_inode.h
+++ b/lwext4/ext4_inode.h
@@ -1,294 +1,294 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file  ext4_inode.h
- * @brief Inode handle functions
- */
-
-#ifndef EXT4_INODE_H_
-#define EXT4_INODE_H_
-
-#include "ext4_config.h"
-
-#include <stdint.h>
-
-/**@brief Get mode of the i-node.
- * @param sb    Superblock
- * @param inode I-node to load mode from
- * @return Mode of the i-node
- */
-uint32_t ext4_inode_get_mode(struct ext4_sblock *sb, struct ext4_inode *inode);
-
-/**@brief Set mode of the i-node.
- * @param sb    Superblock
- * @param inode I-node to set mode to
- * @param mode  Mode to set to i-node
- */
-void ext4_inode_set_mode(struct ext4_sblock *sb, struct ext4_inode *inode,
-			 uint32_t mode);
-
-/**@brief Get ID of the i-node owner (user id).
- * @param inode I-node to load uid from
- * @return User ID of the i-node owner
- */
-uint32_t ext4_inode_get_uid(struct ext4_inode *inode);
-
-/**@brief Set ID of the i-node owner.
- * @param inode I-node to set uid to
- * @param uid   ID of the i-node owner
- */
-void ext4_inode_set_uid(struct ext4_inode *inode, uint32_t uid);
-
-/**@brief Get real i-node size.
- * @param sb    Superblock
- * @param inode I-node to load size from
- * @return Real size of i-node
- */
-uint64_t ext4_inode_get_size(struct ext4_sblock *sb, struct ext4_inode *inode);
-
-/**@brief Set real i-node size.
- * @param inode I-node to set size to
- * @param size  Size of the i-node
- */
-void ext4_inode_set_size(struct ext4_inode *inode, uint64_t size);
-
-/**@brief Get time, when i-node was last accessed.
- * @param inode I-node
- * @return Time of the last access (POSIX)
- */
-uint32_t ext4_inode_get_access_time(struct ext4_inode *inode);
-
-/**@brief Set time, when i-node was last accessed.
- * @param inode I-node
- * @param time  Time of the last access (POSIX)
- */
-void ext4_inode_set_access_time(struct ext4_inode *inode, uint32_t time);
-
-/**@brief Get time, when i-node was last changed.
- * @param inode I-node
- * @return Time of the last change (POSIX)
- */
-uint32_t ext4_inode_get_change_inode_time(struct ext4_inode *inode);
-
-/**@brief Set time, when i-node was last changed.
- * @param inode I-node
- * @param time  Time of the last change (POSIX)
- */
-void ext4_inode_set_change_inode_time(struct ext4_inode *inode, uint32_t time);
-
-/**@brief Get time, when i-node content was last modified.
- * @param inode I-node
- * @return Time of the last content modification (POSIX)
- */
-uint32_t ext4_inode_get_modification_time(struct ext4_inode *inode);
-
-/**@brief Set time, when i-node content was last modified.
- * @param inode I-node
- * @param time  Time of the last content modification (POSIX)
- */
-void ext4_inode_set_modification_time(struct ext4_inode *inode, uint32_t time);
-
-/**@brief Get time, when i-node was deleted.
- * @param inode I-node
- * @return Time of the delete action (POSIX)
- */
-uint32_t ext4_inode_get_deletion_time(struct ext4_inode *inode);
-
-/**@brief Set time, when i-node was deleted.
- * @param inode I-node
- * @param time  Time of the delete action (POSIX)
- */
-void ext4_inode_set_deletion_time(struct ext4_inode *inode, uint32_t time);
-
-/**@brief Get ID of the i-node owner's group.
- * @param inode I-node to load gid from
- * @return Group ID of the i-node owner
- */
-uint32_t ext4_inode_get_gid(struct ext4_inode *inode);
-
-/**@brief Set ID to the i-node owner's group.
- * @param inode I-node to set gid to
- * @param gid   Group ID of the i-node owner
- */
-void ext4_inode_set_gid(struct ext4_inode *inode, uint32_t gid);
-
-/**@brief Get number of links to i-node.
- * @param inode I-node to load number of links from
- * @return Number of links to i-node
- */
-uint16_t ext4_inode_get_links_count(struct ext4_inode *inode);
-
-/**@brief Set number of links to i-node.
- * @param inode I-node to set number of links to
- * @param count Number of links to i-node
- */
-void ext4_inode_set_links_count(struct ext4_inode *inode, uint16_t cnt);
-
-/**@brief Get number of 512-bytes blocks used for i-node.
- * @param sb    Superblock
- * @param inode I-node
- * @return Number of 512-bytes blocks
- */
-uint64_t ext4_inode_get_blocks_count(struct ext4_sblock *sb,
-				     struct ext4_inode *inode);
-
-/**@brief Set number of 512-bytes blocks used for i-node.
- * @param sb    Superblock
- * @param inode I-node
- * @param count Number of 512-bytes blocks
- * @return Error code
- */
-int ext4_inode_set_blocks_count(struct ext4_sblock *sb,
-				struct ext4_inode *inode, uint64_t cnt);
-
-/**@brief Get flags (features) of i-node.
- * @param inode I-node to get flags from
- * @return Flags (bitmap)
- */
-uint32_t ext4_inode_get_flags(struct ext4_inode *inode);
-
-/**@brief Set flags (features) of i-node.
- * @param inode I-node to set flags to
- * @param flags Flags to set to i-node
- */
-void ext4_inode_set_flags(struct ext4_inode *inode, uint32_t flags);
-
-/**@brief Get file generation (used by NFS).
- * @param inode I-node
- * @return File generation
- */
-uint32_t ext4_inode_get_generation(struct ext4_inode *inode);
-
-/**@brief Set file generation (used by NFS).
- * @param inode      I-node
- * @param generation File generation
- */
-void ext4_inode_set_generation(struct ext4_inode *inode, uint32_t gen);
-
-/**@brief Get address of block, where are extended attributes located.
- * @param inode I-node
- * @param sb    Superblock
- * @return Block address
- */
-uint64_t ext4_inode_get_file_acl(struct ext4_inode *inode,
-				 struct ext4_sblock *sb);
-
-/**@brief Set address of block, where are extended attributes located.
- * @param inode    I-node
- * @param sb       Superblock
- * @param file_acl Block address
- */
-void ext4_inode_set_file_acl(struct ext4_inode *inode, struct ext4_sblock *sb,
-			     uint64_t acl);
-
-/**@brief Get block address of specified direct block.
- * @param inode I-node to load block from
- * @param idx   Index of logical block
- * @return Physical block address
- */
-uint32_t ext4_inode_get_direct_block(struct ext4_inode *inode, uint32_t idx);
-
-/**@brief Set block address of specified direct block.
- * @param inode  I-node to set block address to
- * @param idx    Index of logical block
- * @param fblock Physical block address
- */
-void ext4_inode_set_direct_block(struct ext4_inode *inode, uint32_t idx,
-				 uint32_t block);
-
-/**@brief Get block address of specified indirect block.
- * @param inode I-node to get block address from
- * @param idx   Index of indirect block
- * @return Physical block address
- */
-uint32_t ext4_inode_get_indirect_block(struct ext4_inode *inode, uint32_t idx);
-
-/**@brief Set block address of specified indirect block.
- * @param inode  I-node to set block address to
- * @param idx    Index of indirect block
- * @param fblock Physical block address
- */
-void ext4_inode_set_indirect_block(struct ext4_inode *inode, uint32_t idx,
-				   uint32_t block);
-
-/**@brief Check if i-node has specified type.
- * @param sb    Superblock
- * @param inode I-node to check type of
- * @param type  Type to check
- * @return Result of check operation
- */
-bool ext4_inode_is_type(struct ext4_sblock *sb, struct ext4_inode *inode,
-			uint32_t type);
-
-/**@brief Check if i-node has specified flag.
- * @param inode I-node to check flags of
- * @param flag  Flag to check
- * @return Result of check operation
- */
-bool ext4_inode_has_flag(struct ext4_inode *inode, uint32_t f);
-
-/**@brief Remove specified flag from i-node.
- * @param inode      I-node to clear flag on
- * @param clear_flag Flag to be cleared
- */
-void ext4_inode_clear_flag(struct ext4_inode *inode, uint32_t f);
-
-/**@brief Set specified flag to i-node.
- * @param inode    I-node to set flag on
- * @param set_flag Flag to be set
- */
-void ext4_inode_set_flag(struct ext4_inode *inode, uint32_t f);
-
-/**@brief Check if i-node can be truncated.
- * @param sb    Superblock
- * @param inode I-node to check
- * @return Result of the check operation
- */
-bool ext4_inode_can_truncate(struct ext4_sblock *sb, struct ext4_inode *inode);
-
-/**@brief Get extent header from the root of the extent tree.
- * @param inode I-node to get extent header from
- * @return Pointer to extent header of the root node
- */
-struct ext4_extent_header *
-ext4_inode_get_extent_header(struct ext4_inode *inode);
-
-#endif /* EXT4_INODE_H_ */
-
-/**
- * @}
- */
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file  ext4_inode.h
+ * @brief Inode handle functions
+ */
+
+#ifndef EXT4_INODE_H_
+#define EXT4_INODE_H_
+
+#include "ext4_config.h"
+
+#include <stdint.h>
+
+/**@brief Get mode of the i-node.
+ * @param sb    Superblock
+ * @param inode I-node to load mode from
+ * @return Mode of the i-node
+ */
+uint32_t ext4_inode_get_mode(struct ext4_sblock *sb, struct ext4_inode *inode);
+
+/**@brief Set mode of the i-node.
+ * @param sb    Superblock
+ * @param inode I-node to set mode to
+ * @param mode  Mode to set to i-node
+ */
+void ext4_inode_set_mode(struct ext4_sblock *sb, struct ext4_inode *inode,
+			 uint32_t mode);
+
+/**@brief Get ID of the i-node owner (user id).
+ * @param inode I-node to load uid from
+ * @return User ID of the i-node owner
+ */
+uint32_t ext4_inode_get_uid(struct ext4_inode *inode);
+
+/**@brief Set ID of the i-node owner.
+ * @param inode I-node to set uid to
+ * @param uid   ID of the i-node owner
+ */
+void ext4_inode_set_uid(struct ext4_inode *inode, uint32_t uid);
+
+/**@brief Get real i-node size.
+ * @param sb    Superblock
+ * @param inode I-node to load size from
+ * @return Real size of i-node
+ */
+uint64_t ext4_inode_get_size(struct ext4_sblock *sb, struct ext4_inode *inode);
+
+/**@brief Set real i-node size.
+ * @param inode I-node to set size to
+ * @param size  Size of the i-node
+ */
+void ext4_inode_set_size(struct ext4_inode *inode, uint64_t size);
+
+/**@brief Get time, when i-node was last accessed.
+ * @param inode I-node
+ * @return Time of the last access (POSIX)
+ */
+uint32_t ext4_inode_get_access_time(struct ext4_inode *inode);
+
+/**@brief Set time, when i-node was last accessed.
+ * @param inode I-node
+ * @param time  Time of the last access (POSIX)
+ */
+void ext4_inode_set_access_time(struct ext4_inode *inode, uint32_t time);
+
+/**@brief Get time, when i-node was last changed.
+ * @param inode I-node
+ * @return Time of the last change (POSIX)
+ */
+uint32_t ext4_inode_get_change_inode_time(struct ext4_inode *inode);
+
+/**@brief Set time, when i-node was last changed.
+ * @param inode I-node
+ * @param time  Time of the last change (POSIX)
+ */
+void ext4_inode_set_change_inode_time(struct ext4_inode *inode, uint32_t time);
+
+/**@brief Get time, when i-node content was last modified.
+ * @param inode I-node
+ * @return Time of the last content modification (POSIX)
+ */
+uint32_t ext4_inode_get_modification_time(struct ext4_inode *inode);
+
+/**@brief Set time, when i-node content was last modified.
+ * @param inode I-node
+ * @param time  Time of the last content modification (POSIX)
+ */
+void ext4_inode_set_modification_time(struct ext4_inode *inode, uint32_t time);
+
+/**@brief Get time, when i-node was deleted.
+ * @param inode I-node
+ * @return Time of the delete action (POSIX)
+ */
+uint32_t ext4_inode_get_deletion_time(struct ext4_inode *inode);
+
+/**@brief Set time, when i-node was deleted.
+ * @param inode I-node
+ * @param time  Time of the delete action (POSIX)
+ */
+void ext4_inode_set_deletion_time(struct ext4_inode *inode, uint32_t time);
+
+/**@brief Get ID of the i-node owner's group.
+ * @param inode I-node to load gid from
+ * @return Group ID of the i-node owner
+ */
+uint32_t ext4_inode_get_gid(struct ext4_inode *inode);
+
+/**@brief Set ID to the i-node owner's group.
+ * @param inode I-node to set gid to
+ * @param gid   Group ID of the i-node owner
+ */
+void ext4_inode_set_gid(struct ext4_inode *inode, uint32_t gid);
+
+/**@brief Get number of links to i-node.
+ * @param inode I-node to load number of links from
+ * @return Number of links to i-node
+ */
+uint16_t ext4_inode_get_links_count(struct ext4_inode *inode);
+
+/**@brief Set number of links to i-node.
+ * @param inode I-node to set number of links to
+ * @param count Number of links to i-node
+ */
+void ext4_inode_set_links_count(struct ext4_inode *inode, uint16_t cnt);
+
+/**@brief Get number of 512-bytes blocks used for i-node.
+ * @param sb    Superblock
+ * @param inode I-node
+ * @return Number of 512-bytes blocks
+ */
+uint64_t ext4_inode_get_blocks_count(struct ext4_sblock *sb,
+				     struct ext4_inode *inode);
+
+/**@brief Set number of 512-bytes blocks used for i-node.
+ * @param sb    Superblock
+ * @param inode I-node
+ * @param count Number of 512-bytes blocks
+ * @return Error code
+ */
+int ext4_inode_set_blocks_count(struct ext4_sblock *sb,
+				struct ext4_inode *inode, uint64_t cnt);
+
+/**@brief Get flags (features) of i-node.
+ * @param inode I-node to get flags from
+ * @return Flags (bitmap)
+ */
+uint32_t ext4_inode_get_flags(struct ext4_inode *inode);
+
+/**@brief Set flags (features) of i-node.
+ * @param inode I-node to set flags to
+ * @param flags Flags to set to i-node
+ */
+void ext4_inode_set_flags(struct ext4_inode *inode, uint32_t flags);
+
+/**@brief Get file generation (used by NFS).
+ * @param inode I-node
+ * @return File generation
+ */
+uint32_t ext4_inode_get_generation(struct ext4_inode *inode);
+
+/**@brief Set file generation (used by NFS).
+ * @param inode      I-node
+ * @param generation File generation
+ */
+void ext4_inode_set_generation(struct ext4_inode *inode, uint32_t gen);
+
+/**@brief Get address of block, where are extended attributes located.
+ * @param inode I-node
+ * @param sb    Superblock
+ * @return Block address
+ */
+uint64_t ext4_inode_get_file_acl(struct ext4_inode *inode,
+				 struct ext4_sblock *sb);
+
+/**@brief Set address of block, where are extended attributes located.
+ * @param inode    I-node
+ * @param sb       Superblock
+ * @param file_acl Block address
+ */
+void ext4_inode_set_file_acl(struct ext4_inode *inode, struct ext4_sblock *sb,
+			     uint64_t acl);
+
+/**@brief Get block address of specified direct block.
+ * @param inode I-node to load block from
+ * @param idx   Index of logical block
+ * @return Physical block address
+ */
+uint32_t ext4_inode_get_direct_block(struct ext4_inode *inode, uint32_t idx);
+
+/**@brief Set block address of specified direct block.
+ * @param inode  I-node to set block address to
+ * @param idx    Index of logical block
+ * @param fblock Physical block address
+ */
+void ext4_inode_set_direct_block(struct ext4_inode *inode, uint32_t idx,
+				 uint32_t block);
+
+/**@brief Get block address of specified indirect block.
+ * @param inode I-node to get block address from
+ * @param idx   Index of indirect block
+ * @return Physical block address
+ */
+uint32_t ext4_inode_get_indirect_block(struct ext4_inode *inode, uint32_t idx);
+
+/**@brief Set block address of specified indirect block.
+ * @param inode  I-node to set block address to
+ * @param idx    Index of indirect block
+ * @param fblock Physical block address
+ */
+void ext4_inode_set_indirect_block(struct ext4_inode *inode, uint32_t idx,
+				   uint32_t block);
+
+/**@brief Check if i-node has specified type.
+ * @param sb    Superblock
+ * @param inode I-node to check type of
+ * @param type  Type to check
+ * @return Result of check operation
+ */
+bool ext4_inode_is_type(struct ext4_sblock *sb, struct ext4_inode *inode,
+			uint32_t type);
+
+/**@brief Check if i-node has specified flag.
+ * @param inode I-node to check flags of
+ * @param flag  Flag to check
+ * @return Result of check operation
+ */
+bool ext4_inode_has_flag(struct ext4_inode *inode, uint32_t f);
+
+/**@brief Remove specified flag from i-node.
+ * @param inode      I-node to clear flag on
+ * @param clear_flag Flag to be cleared
+ */
+void ext4_inode_clear_flag(struct ext4_inode *inode, uint32_t f);
+
+/**@brief Set specified flag to i-node.
+ * @param inode    I-node to set flag on
+ * @param set_flag Flag to be set
+ */
+void ext4_inode_set_flag(struct ext4_inode *inode, uint32_t f);
+
+/**@brief Check if i-node can be truncated.
+ * @param sb    Superblock
+ * @param inode I-node to check
+ * @return Result of the check operation
+ */
+bool ext4_inode_can_truncate(struct ext4_sblock *sb, struct ext4_inode *inode);
+
+/**@brief Get extent header from the root of the extent tree.
+ * @param inode I-node to get extent header from
+ * @return Pointer to extent header of the root node
+ */
+struct ext4_extent_header *
+ext4_inode_get_extent_header(struct ext4_inode *inode);
+
+#endif /* EXT4_INODE_H_ */
+
+/**
+ * @}
+ */