shithub: lwext4

Download patch

ref: 4f7ba4713a87e5af892b108f47949d114e0c38ec
parent: 7e4cd24af9c6201a5f11ba5b42b2f1961d1f8524
author: gkostka <[email protected]>
date: Mon Oct 7 16:03:18 EDT 2013

.

--- /dev/null
+++ b/src/CMakeLists.txt
@@ -1,0 +1,34 @@
+project(lwext4 C)
+cmake_minimum_required(VERSION 2.8)
+
+
+#LIBRARY
+include_directories(. lwext4)
+aux_source_directory(lwext4 LWEXT4_SRC)
+add_library(lwext4  ${LWEXT4_SRC})
+
+
+#EXECUTABLE
+
+if(CMAKE_SYSTEM_PROCESSOR STREQUAL  cortex-m3)
+#Library size print
+add_custom_target(size ALL DEPENDS lwext4 COMMAND ${SIZE} -B liblwext4.a)
+
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL  cortex-m4)
+#Library size print
+add_custom_target(size ALL DEPENDS lwext4 COMMAND ${SIZE} -B liblwext4.a)
+
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL  bf518)
+#Library size print
+add_custom_target(size ALL DEPENDS lwext4 COMMAND ${SIZE} -B liblwext4.a)
+
+else()
+#Generic example target
+include_directories(blockdev/filedev)
+aux_source_directory(blockdev/filedev FILEDEV_SRC)
+aux_source_directory(demos/generic GENERIC_SRC)
+add_executable(fileimage_demo ${GENERIC_SRC} ${FILEDEV_SRC})
+target_link_libraries(fileimage_demo lwext4)
+add_custom_target(size ALL DEPENDS lwext4 COMMAND size -B liblwext4.a)
+endif()
+ 
--- /dev/null
+++ b/src/blockdev/filedev/ext4_filedev.c
@@ -1,0 +1,135 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ * 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.
+ */
+#include <ext4_config.h>
+#include <ext4_blockdev.h>
+#include <ext4_errno.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+
+/**@brief	Default filename.*/
+const char *fname = "ext2";
+
+/**@brief	Image block size.*/
+#define EXT4_FILEDEV_BSIZE		512
+
+/**@brief	Image file descriptor.*/
+static FILE	*dev_file;
+
+
+/**********************BLOCKDEV INTERFACE**************************************/
+static int filedev_open(struct ext4_blockdev *bdev);
+static int filedev_bread(struct ext4_blockdev *bdev, void *buf, uint64_t blk_id,
+		uint32_t blk_cnt);
+static int filedev_bwrite(struct ext4_blockdev *bdev, const void *buf,
+		uint64_t blk_id, uint32_t blk_cnt);
+static int filedev_close(struct  ext4_blockdev *bdev);
+
+
+/******************************************************************************/
+EXT4_BLOCKDEV_STATIC_INSTANCE(
+		_filedev,
+		EXT4_FILEDEV_BSIZE,
+		0,
+		filedev_open,
+		filedev_bread,
+		filedev_bwrite,
+		filedev_close
+);
+
+/******************************************************************************/
+EXT4_BCACHE_STATIC_INSTANCE(__cache, 8, 1024);
+
+/******************************************************************************/
+static int filedev_open(struct ext4_blockdev *bdev)
+{
+	dev_file = fopen(fname, "r+b");
+
+	if(!dev_file)
+		return ENOENT;
+
+	if(fseek(dev_file, 0, SEEK_END))
+		return EFAULT;
+
+	_filedev.ph_bcnt = ftell(dev_file) / _filedev.ph_bsize;
+
+	return EOK;
+}
+
+/******************************************************************************/
+
+static int filedev_bread(struct  ext4_blockdev *bdev, void *buf, uint64_t blk_id,
+		uint32_t blk_cnt)
+{
+	if(fseek(dev_file, blk_id * bdev->ph_bsize, SEEK_SET))
+		return EIO;
+
+	if(!fread(buf, bdev->ph_bsize * blk_cnt, 1, dev_file))
+		return EIO;
+
+	return EOK;
+}
+
+/******************************************************************************/
+static int filedev_bwrite(struct ext4_blockdev *bdev, const void *buf,
+		uint64_t blk_id, uint32_t blk_cnt)
+{
+	if(fseek(dev_file, blk_id * bdev->ph_bsize, SEEK_SET))
+		return EIO;
+
+	if(!fwrite(buf, bdev->ph_bsize * blk_cnt, 1, dev_file))
+		return EIO;
+	return EOK;
+}
+
+/******************************************************************************/
+static int filedev_close(struct  ext4_blockdev *bdev)
+{
+	fclose(dev_file);
+	return EOK;
+}
+
+
+/******************************************************************************/
+
+struct	ext4_bcache* ext4_filecache_get(void)
+{
+	return &__cache;
+}
+/******************************************************************************/
+struct	ext4_blockdev* ext4_filedev_get(void)
+{
+	return &_filedev;
+}
+/******************************************************************************/
+void ext4_filedev_filename(const char *n)
+{
+	fname = n;
+}
+
+/******************************************************************************/
--- /dev/null
+++ b/src/blockdev/filedev/ext4_filedev.h
@@ -1,0 +1,45 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ * 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.
+ */
+#ifndef EXT4_FILEDEV_H_
+#define EXT4_FILEDEV_H_
+
+#include <ext4_config.h>
+#include <ext4_blockdev.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/**@brief	Filecache get.*/
+struct	ext4_bcache*   ext4_filecache_get(void);
+
+/**@brief	File blockdev get.*/
+struct	ext4_blockdev* ext4_filedev_get(void);
+
+void 	ext4_filedev_filename(const char *n);
+
+#endif /* EXT4_FILEDEV_H_ */
--- /dev/null
+++ b/src/demos/generic/main.c
@@ -1,0 +1,274 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <stdbool.h>
+
+#include <ext4_filedev.h>
+#include <ext4.h>
+
+
+
+char input_name[128] = "ext2";
+
+/**@brief	Read-write size*/
+static int rw_szie  = 1024;
+
+/**@brief	Read-write size*/
+static int rw_count = 1024;
+
+static bool cache_mode = false;
+
+
+/**@brief	File write buffer*/
+static uint8_t	*wr_buff;
+
+/**@brief	File read buffer.*/
+static uint8_t	*rd_buff;
+
+/**@brief	Block device handle.*/
+static struct ext4_blockdev *bd;
+
+/**@brief	Block cache handle.*/
+static struct ext4_bcache   *bc;
+
+static const char *usage = "									\n\
+Welcome in ext4 generic demo.									\n\
+Copyright (c) 2013 Grzegorz Kostka ([email protected])	\n\
+Usage:															\n\
+	-i   - input file            (default = ext2)				\n\
+	-rws - single R/W size       (default = 1024)				\n\
+	-rwc - R/W count             (default = 1024)				\n\
+	-cache - 0 static, 1 dynamic (default = 0)					\n\
+\n";
+
+static char* entry_to_str(uint8_t type)
+{
+	switch(type){
+	case EXT4_DIRENTRY_UNKNOWN:
+		return "[UNK] ";
+	case EXT4_DIRENTRY_REG_FILE:
+		return "[FIL] ";
+	case EXT4_DIRENTRY_DIR:
+		return "[DIR] ";
+	case EXT4_DIRENTRY_CHRDEV:
+		return "[CHA] ";
+	case EXT4_DIRENTRY_BLKDEV:
+		return "[BLK] ";
+	case EXT4_DIRENTRY_FIFO:
+		return "[FIF] ";
+	case EXT4_DIRENTRY_SOCK:
+		return "[SOC] ";
+	case EXT4_DIRENTRY_SYMLINK:
+		return "[SYM] ";
+	default:
+		break;
+	}
+	return "[???]";
+}
+
+static void dir_ls(const char *path)
+{
+	int j = 0;
+	char sss[255];
+	ext4_dir d;
+	ext4_direntry *de;
+
+	printf("**********************************************\n");
+
+	ext4_dir_open(&d, path);
+	de = ext4_entry_get(&d, j++);
+	printf("ls %s\n", path);
+
+	while(de){
+		memcpy(sss, de->name, de->name_length);
+		sss[de->name_length] = 0;
+		printf(entry_to_str(de->inode_type));
+		printf(sss);
+		printf("\n");
+		de = ext4_entry_get(&d, j++);
+	}
+	printf("**********************************************\n");
+	ext4_dir_close(&d);
+}
+
+
+int main(int argc, char **argv)
+{
+	int option_index = 0;
+	int	c;
+	int	r;
+	int	i;
+	uint32_t  size;
+	ext4_file f;
+
+    static struct option long_options[] =
+      {
+        {"in",     	required_argument, 0, 'a'},
+        {"rws",     required_argument, 0, 'b'},
+        {"rwc",		required_argument, 0, 'c'},
+        {"cache",   required_argument, 0, 'd'},
+        {0, 0, 0, 0}
+      };
+
+    while(-1 != (c = getopt_long (argc, argv, "a:b:c:d:", long_options, &option_index))) {
+
+    	switch(c){
+    		case 'a':
+    			strcpy(input_name, optarg);
+    			break;
+    		case 'b':
+    			rw_szie = atoi(optarg);
+    			break;
+    		case 'c':
+    			rw_count = atoi(optarg);
+    			break;
+    		case 'd':
+    			cache_mode = atoi(optarg);
+    			break;
+    		default:
+    			printf(usage);
+    			return EXIT_FAILURE;
+
+    	}
+    }
+
+    printf("Test conditions:\n");
+    printf("Imput name: %s\n", input_name);
+    printf("RW size: %d\n",  rw_szie);
+    printf("RW count: %d\n", rw_count);
+    printf("Cache mode: %s\n", cache_mode ? "dynamic" : "static");
+
+
+
+    ext4_filedev_filename(input_name);
+
+    wr_buff = malloc(rw_szie);
+    rd_buff = malloc(rw_szie);
+
+    if(!wr_buff || !rd_buff){
+    	printf("Read-Write allocation ERROR\n");
+    	return EXIT_FAILURE;
+    }
+
+	bd = ext4_filedev_get();
+	bc = ext4_filecache_get();
+
+    if(!bd || !bc){
+    	printf("Block device ERROR\n");
+    	return EXIT_FAILURE;
+    }
+
+	ext4_dmask_set(EXT4_DEBUG_ALL);
+
+	r = ext4_device_register(bd, cache_mode ? 0 : bc, "ext4_filesim");
+	if(r != EOK){
+		printf("ext4_device_register ERROR = %d\n", r);
+		return EXIT_FAILURE;
+	}
+
+	r = ext4_mount("ext4_filesim", "/mp");
+	if(r != EOK){
+		printf("ext4_mount ERROR = %d\n", r);
+		return EXIT_FAILURE;
+	}
+
+
+	ext4_fremove("/mp/test1");
+	dir_ls("/mp/");
+
+	printf("ext4_fopen: test1\n");
+
+	r = ext4_fopen(&f, "/mp/test1", "wb");
+	if(r != EOK){
+		printf("ext4_fopen ERROR = %d\n", r);
+		return EXIT_FAILURE;
+	}
+
+	printf("ext4_write: %d * %d ..." , rw_count, rw_szie);
+
+	for (i = 0; i < rw_count; ++i) {
+
+		memset(wr_buff, i & 0xFF, rw_szie);
+
+		r = ext4_fwrite(&f, wr_buff, rw_szie, &size);
+
+		if((r != EOK) || (size != rw_szie))
+			break;
+	}
+
+	if(i != rw_count){
+		printf("ERROR: rw_count = %d\n", i);
+		return EXIT_FAILURE;
+	}
+
+	printf("OK\n");
+	r = ext4_fclose(&f);
+	printf("ext4_fopen: test1\n");
+
+	r = ext4_fopen(&f, "/mp/test1", "r+");
+	if(r != EOK){
+		printf("ext4_fopen ERROR = %d\n", r);
+		return EXIT_FAILURE;
+	}
+
+	printf("ext4_read: %d * %d ..." , rw_count, rw_szie);
+
+	for (i = 0; i < rw_count; ++i) {
+		memset(wr_buff, i & 0xFF, rw_szie);
+		r = ext4_fread(&f, rd_buff, rw_szie, &size);
+
+		if((r != EOK) || (size != rw_szie))
+			break;
+
+		if(memcmp(rd_buff, wr_buff, rw_szie)){
+			break;
+		}
+	}
+	if(i != rw_count){
+		printf("ERROR: rw_count = %d\n", i);
+		return EXIT_FAILURE;
+	}
+
+	printf("OK\n");
+
+	r = ext4_fclose(&f);
+
+
+	dir_ls("/mp/");
+
+	r = ext4_umount("/mp");
+
+	printf("Test finish: OK\n");
+    return EXIT_SUCCESS;
+
+}
--- /dev/null
+++ b/src/ext4.h
@@ -1,0 +1,246 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ * 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, mountpoints...).
+ * 		  Client has to include only this file.
+ */
+
+#ifndef EXT4_H_
+#define EXT4_H_
+
+#include <ext4_config.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 mountpoint*/
+	void (*lock)(void);
+
+	/**@brief	Unlock access to mountpoint*/
+	void (*unlock)(void);
+};
+
+
+/********************************FILE DESCRIPTOR********************************/
+
+/**@brief	File descriptor*/
+typedef struct	ext4_file {
+
+	/**@brief	Pountpoint 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;
+	union {
+		uint8_t name_length_high;
+		uint8_t inode_type;
+	};
+	uint8_t name[255];
+}ext4_direntry;
+
+typedef struct  {
+	/**@brief 	File descriptor*/
+	ext4_file		f;
+	/**@brief	Current direntry.*/
+	ext4_direntry	de;
+}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. But block cache may by created automaticly 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 mountpoint.
+ * @param	dev_name block device name (@ref ext4_device_register)
+ * @param	mount_point pount point, for example
+ * 			-	/my_partition
+ * 			-	/my_second_partition
+ *
+ * @return standard error code */
+int			ext4_mount(const char * dev_name,  char *mount_point);
+
+/**@brief	Umount operation.
+ * @param	mount_point mount name
+ * @return  standard error code */
+int			ext4_umount(char *mount_point);
+
+/********************************FILE OPERATIONS********************************/
+
+/**@brief	*/
+int			ext4_fremove(const char *path);
+
+/**@brief	File open function.
+ * @param	filename, (has to start from mountpoint)
+ * 			/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	*/
+int			ext4_fclose(ext4_file *f);
+
+/**@brief	*/
+int			ext4_fread (ext4_file *f, void *buf, uint32_t size, uint32_t *rcnt);
+
+/**@brief	*/
+int			ext4_fwrite(ext4_file *f, void *buf, uint32_t size, uint32_t *wcnt);
+
+/**@brief	*/
+int 		ext4_fseek (ext4_file *f, uint64_t offset, uint32_t origin);
+
+/**@brief	*/
+uint64_t	ext4_ftell (ext4_file *f);
+
+/**@brief	*/
+uint64_t	ext4_fsize (ext4_file *f);
+
+/*********************************DIRECTORY OPERATION***************************/
+/**@brief	*/
+int			ext4_mkdir(const char *path);
+
+/**@brief	*/
+int			ext4_rmdir(const char *path);
+
+/**@brief	*/
+int			ext4_dir_open (ext4_dir *d, const char *path);
+
+/**@brief	*/
+int			ext4_dir_close(ext4_dir *d);
+
+/**@brief	*/
+ext4_direntry*	ext4_entry_get(ext4_dir *d, uint32_t id);
+
+#endif /* EXT4_H_ */
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/src/lwext4/ext4.c
@@ -1,0 +1,1175 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include "ext4.h"
+
+/**@brief	Mount point OS dependent lock*/
+#define EXT4_MP_LOCK(_m)	do { (_m)->os_locks ? (_m)->os_locks->lock()   : 0; }while(0)
+
+/**@brief	Mount point OS dependent unlock*/
+#define EXT4_MP_UNLOCK(_m)	do { (_m)->os_locks ? (_m)->os_locks->unlock() : 0;	}while(0)
+
+/**@brief	Mount point descrpitor.*/
+struct ext4_mountpoint {
+
+	/**@brief	Mount point name (@ref ext4_mount)*/
+	const char 		 *name;
+
+	/**@brief	Os dependent lock/unlock functions.*/
+	struct ext4_lock *os_locks;
+
+	/**@brief	Ext4 filesystem internals.*/
+	struct ext4_fs	 fs;
+
+	/**@brief	Dynamic alocation cache flag.*/
+	bool			cache_dynamic;
+};
+
+/**@brief	Block devices descriptor.*/
+struct	_ext4_devices {
+
+	/**@brief	Block device name (@ref ext4_device_register)*/
+	const char				*name;
+
+	/**@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].name){
+			_bdevices[i].name   = dev_name;
+			_bdevices[i].bd 	= bd;
+			_bdevices[i].bc 	= bc;
+			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 (it.current->inode != 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)
+{
+	/* Check maximum name length */
+	if (strlen(name) > EXT4_DIRECTORY_FILENAME_LEN)
+		return EINVAL;
+
+	/* Add entry to parent directory */
+	int rc = ext4_dir_add_entry(parent, name,
+	    child);
+	if (rc != EOK)
+		return rc;
+
+	/* Fill new dir -> add '.' and '..' entries */
+	if (ext4_inode_is_type(&mp->fs.sb, child->inode,
+	    EXT4_INODE_MODE_DIRECTORY)) {
+		rc = ext4_dir_add_entry(child, ".",
+		    child);
+		if (rc != EOK) {
+			ext4_dir_remove_entry(parent, name);
+			return rc;
+		}
+
+		rc = ext4_dir_add_entry(child, "..",
+		    parent);
+		if (rc != EOK) {
+			ext4_dir_remove_entry(parent, name);
+			ext4_dir_remove_entry(child, ".");
+			return rc;
+		}
+
+#if CONFIG_DIR_INDEX_ENABLE
+		/* Initialize directory index if supported */
+		if (ext4_sb_check_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
+
+		uint16_t parent_links =
+		    ext4_inode_get_links_count(parent->inode);
+		parent_links++;
+		ext4_inode_set_links_count(parent->inode, parent_links);
+
+		parent->dirty = true;
+	}
+
+	uint16_t child_links =
+	    ext4_inode_get_links_count(child->inode);
+	child_links++;
+	ext4_inode_set_links_count(child->inode, child_links);
+
+	child->dirty = true;
+
+	return EOK;
+}
+
+static int ext4_unlink(struct ext4_mountpoint *mp, struct ext4_inode_ref *parent, struct ext4_inode_ref *child_inode_ref, const char *name)
+{
+	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);
+	if (rc != EOK)
+		return rc;
+
+
+	uint32_t lnk_count =
+	    ext4_inode_get_links_count(child_inode_ref->inode);
+	lnk_count--;
+
+	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 ((lnk_count <= 1) && (is_dir)) {
+		ext4_assert(lnk_count == 1);
+
+		lnk_count--;
+
+		uint32_t parent_lnk_count = ext4_inode_get_links_count(
+				parent->inode);
+
+		parent_lnk_count--;
+		ext4_inode_set_links_count(parent->inode, parent_lnk_count);
+
+		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);
+	 */
+
+	ext4_inode_set_deletion_time(child_inode_ref->inode, 1);
+	ext4_inode_set_links_count(child_inode_ref->inode, lnk_count);
+	child_inode_ref->dirty = true;
+
+	return EOK;
+}
+
+/*****************************************************************************/
+
+int			ext4_mount(const char * dev_name,  char *mount_point)
+{
+	ext4_assert(mount_point && dev_name);
+	int r = EOK;
+	int i;
+
+	uint32_t bsize;
+	struct ext4_blockdev	*bd = 0;
+	struct ext4_bcache		*bc = 0;
+	struct ext4_mountpoint	*mp = 0;
+
+	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].name){
+			_mp[i].name = mount_point;
+			mp = &_mp[i];
+			break;
+		}
+	}
+
+	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, 8, 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(char *mount_point)
+{
+	int 	i;
+	int 	r = EOK;
+	struct ext4_mountpoint	*mp = 0;
+
+	for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) {
+		if(_mp[i].name){
+			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->name = 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);
+}
+
+
+/********************************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].name){
+			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;
+}
+
+/*****************************************************************************/
+
+static	int ext4_generic_open (ext4_file *f, const char *path, const char *flags, bool file_expect)
+{
+	struct ext4_mountpoint *mp = ext4_get_mount(path);
+	struct ext4_directory_search_result result;
+	struct ext4_inode_ref	ref;
+	char	entry_name[255];
+	bool	is_goal = false;
+	uint8_t	inode_type;
+	int		r = ENOENT;
+	uint32_t next_inode;
+
+	f->mp = 0;
+
+	if(!mp)
+		return ENOENT;
+
+	if(ext4_parse_flags(flags, &f->flags) == false)
+		return EINVAL;
+
+	/*Skip mount point*/
+	path += strlen(mp->name);
+
+	/*Skip first /*/
+	if(*path != '/')
+		return ENOENT;
+
+	path++;
+
+	EXT4_MP_LOCK(mp);
+
+	/*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);
+
+	/*If root open was request.*/
+	if(!len && is_goal)
+		goto IsGoal;
+
+	while(1){
+
+		len = ext4_path_check(path, &is_goal);
+
+		if(!len){
+			r = ENOENT;
+			break;
+		}
+
+		memcpy(entry_name, path, len);
+		entry_name[len] = 0;
+
+		r = ext4_dir_find_entry(&result, &ref, entry_name);
+		if(r != EOK){
+
+			if(r != ENOENT)
+				break;
+
+			if(!(f->flags & O_CREAT))
+				break;
+
+			/*O_CREAT allows to create new entry*/
+			struct ext4_inode_ref	child_ref;
+			r = ext4_fs_alloc_inode(&mp->fs, &child_ref, !is_goal);
+			if(r != EOK)
+				break;
+
+			/*Destroy last result*/
+			ext4_dir_destroy_result(&ref, &result);
+
+			/*Link with root dir.*/
+			r = ext4_link(mp, &ref, &child_ref, entry_name);
+			if(r != EOK){
+				/*Fali. 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;
+		}
+
+		next_inode = result.dentry->inode;
+		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_REG_FILE) && !file_expect && is_goal){
+			r = ENOENT;
+			break;
+		}
+
+		/*If expected directory error*/
+		if((inode_type == EXT4_DIRECTORY_FILETYPE_DIR) && file_expect && 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(r != EOK){
+		ext4_fs_put_inode_ref(&ref);
+		EXT4_MP_UNLOCK(mp);
+		return r;
+	}
+
+	IsGoal:
+	if(is_goal){
+
+		if(f->flags & O_TRUNC){
+			/*Turncate.*/
+			ext4_block_delay_cache_flush(mp->fs.bdev, 1);
+			/*Truncate may be IO heavy. Do it with delayed cache flush mode.*/
+			r = ext4_fs_truncate_inode(&ref, 0);
+			ext4_block_delay_cache_flush(mp->fs.bdev, 0);
+
+			if(r != EOK){
+				ext4_fs_put_inode_ref(&ref);
+				EXT4_MP_UNLOCK(mp);
+				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);
+	EXT4_MP_UNLOCK(mp);
+	return r;
+}
+
+/*****************************************************************************/
+
+int			ext4_fremove(const char *path)
+{
+	struct ext4_mountpoint *mp = ext4_get_mount(path);
+	struct ext4_directory_search_result result;
+	char	entry_name[255];
+	bool	is_goal = false;
+	uint8_t	inode_type;
+	int		r = ENOENT;
+	uint32_t next_inode;
+
+	struct ext4_inode_ref	parent;
+	struct ext4_inode_ref	child;
+
+	if(!mp)
+		return ENOENT;
+
+
+	/*Skip mount point*/
+	path += strlen(mp->name);
+
+	/*Skip first /*/
+	if(*path != '/')
+		return ENOENT;
+
+	path++;
+
+	/*Lock mountpoint*/
+	EXT4_MP_LOCK(mp);
+
+	/*Load root*/
+	r = ext4_fs_get_inode_ref(&mp->fs, EXT4_INODE_ROOT_INDEX, &parent);
+
+	if(r != EOK){
+		EXT4_MP_UNLOCK(mp);
+		return r;
+	}
+
+	while(1){
+
+		int len = ext4_path_check(path, &is_goal);
+
+		if(!len){
+			r = ENOENT;
+			break;
+		}
+
+		memcpy(entry_name, path, len);
+		entry_name[len] = 0;
+
+		r = ext4_dir_find_entry(&result, &parent, entry_name);
+		if(r != EOK){
+			ext4_dir_destroy_result(&parent, &result);
+			break;
+		}
+
+		next_inode = result.dentry->inode;
+		inode_type = ext4_dir_entry_ll_get_inode_type(&mp->fs.sb, result.dentry);
+
+		r = ext4_dir_destroy_result(&parent, &result);
+		if(r != EOK)
+			break;
+
+		/*If expected file error*/
+		if((inode_type == EXT4_DIRECTORY_FILETYPE_REG_FILE) && !is_goal){
+			r = ENOENT;
+			break;
+		}
+
+		/*If expected directory error*/
+		if((inode_type == EXT4_DIRECTORY_FILETYPE_DIR) && is_goal){
+			r = ENOENT;
+			break;
+		}
+
+		if(is_goal)
+			break;
+
+		r = ext4_fs_put_inode_ref(&parent);
+		if(r != EOK)
+			break;
+
+
+		r = ext4_fs_get_inode_ref(&mp->fs, next_inode, &parent);
+		if(r != EOK)
+			break;
+
+		path += len + 1;
+	};
+
+	if(r != EOK){
+		/*No entry or other error.*/
+		ext4_fs_put_inode_ref(&parent);
+		EXT4_MP_UNLOCK(mp);
+		return r;
+	}
+
+
+	/*We have file to delete. Load it.*/
+	r = ext4_fs_get_inode_ref(&mp->fs, next_inode, &child);
+	if(r != EOK){
+		/*Parent free*/
+		ext4_fs_put_inode_ref(&parent);
+		EXT4_MP_UNLOCK(mp);
+		return r;
+	}
+
+	/*Turncate.*/
+	ext4_block_delay_cache_flush(mp->fs.bdev, 1);
+
+	/*Truncate may be IO heavy. Do it with delayed cache flush mode.*/
+	r = ext4_fs_truncate_inode(&child, 0);
+
+	ext4_block_delay_cache_flush(mp->fs.bdev, 0);
+	if(r != EOK)
+		goto Finish;
+
+	/*Unlink from parent.*/
+	r = ext4_unlink(mp, &parent, &child, entry_name);
+	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_fopen (ext4_file *f, const char *path, const char *flags)
+{
+	return ext4_generic_open(f, path, flags, true);
+}
+
+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_fread (ext4_file *f, void *buf, uint32_t size, uint32_t *rcnt)
+{
+	int		 r = EOK;
+	uint32_t u;
+	uint32_t fblock;
+	struct ext4_block b;
+	uint8_t	*u8_buf = buf;
+	struct ext4_inode_ref ref;
+	uint32_t sblock;
+	uint32_t block_size;
+
+	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;
+
+	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++;
+	}
+
+	while(size >= block_size){
+
+		r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
+		if(r != EOK)
+			goto Finish;
+
+		r = ext4_block_get_direct(f->mp->fs.bdev, u8_buf, fblock);
+		if(r != EOK)
+			goto Finish;
+
+
+		u8_buf  += block_size;
+		size    -= block_size;
+		f->fpos += block_size;
+
+		if(rcnt)
+			*rcnt += block_size;
+
+		sblock++;
+	}
+
+	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, void *buf, uint32_t size, uint32_t *wcnt)
+{
+	int		 r = EOK;
+	uint32_t u;
+	uint32_t fblock;
+	struct ext4_block b;
+	uint8_t	*u8_buf = buf;
+	struct ext4_inode_ref ref;
+	uint32_t sblock;
+	uint32_t file_blocks;
+	uint32_t block_size;
+
+	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);
+
+	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 delay cache flush mode.*/
+	r = ext4_block_delay_cache_flush(f->mp->fs.bdev, 1);
+	if(r != EOK)
+		goto Finish;
+
+	while(size >= block_size){
+
+		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;
+		}
+
+		r = ext4_block_set_direct(f->mp->fs.bdev, u8_buf, fblock);
+		if(r != EOK)
+			break;
+
+		u8_buf  += block_size;
+		size    -= block_size;
+		f->fpos += block_size;
+
+		if(wcnt)
+			*wcnt += block_size;
+
+		sblock++;
+	}
+
+	/*Stop delay cache flush mode*/
+	ext4_block_delay_cache_flush(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;
+}
+
+/*********************************DIRECTORY OPERATION***************************/
+
+int			ext4_dir_open (ext4_dir *d, const char *path)
+{
+	return ext4_generic_open(&d->f, path, "r", false);
+}
+
+int			ext4_dir_close(ext4_dir *d)
+{
+	return ext4_fclose(&d->f);
+}
+
+ext4_direntry*	ext4_entry_get(ext4_dir *d, uint32_t id)
+{
+	int 	 r;
+	uint32_t i;
+	ext4_direntry *de = 0;
+	struct ext4_inode_ref dir;
+	struct ext4_directory_iterator it;
+
+	EXT4_MP_LOCK(d->f.mp);
+
+	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, 0);
+	if(r != EOK){
+		ext4_fs_put_inode_ref(&dir);
+		goto Finish;
+	}
+
+	i = 0;
+	while(r == EOK){
+
+		if(!it.current)
+			break;
+
+		if(i == id){
+			memcpy(&d->de, it.current, sizeof(ext4_direntry));
+			de = &d->de;
+			break;
+		}
+
+
+		i++;
+		r = ext4_dir_iterator_next(&it);
+	}
+
+	ext4_dir_iterator_fini(&it);
+	ext4_fs_put_inode_ref(&dir);
+
+	Finish:
+	EXT4_MP_UNLOCK(d->f.mp);
+	return de;
+}
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/src/lwext4/ext4_balloc.c
@@ -1,0 +1,601 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ *
+ *
+ * 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_balloc.c
+ * @brief Physical block allocator.
+ */
+
+#include <ext4_config.h>
+#include <ext4_balloc.h>
+#include <ext4_super.h>
+#include <ext4_block_group.h>
+#include <ext4_fs.h>
+#include <ext4_bitmap.h>
+#include <ext4_inode.h>
+
+
+
+static uint32_t ext4_balloc_get_bgid_of_block(struct ext4_sblock *s, uint32_t baddr)
+{
+	if(ext4_get32(s, first_data_block))
+		baddr--;
+
+	return baddr / ext4_get32(s, blocks_per_group);
+}
+
+
+uint32_t ext4_balloc_get_first_data_block_in_group(struct ext4_sblock *s, struct ext4_block_group_ref * bg_ref)
+{
+	uint32_t block_group_count 		 = ext4_block_group_cnt(s);
+	uint32_t inode_table_first_block = ext4_bg_get_inode_table_first_block(bg_ref->block_group, s);
+	uint32_t block_size 			 = ext4_sb_get_block_size(s);
+
+	uint16_t inode_size 	  = ext4_get16(s, inode_size);
+	uint32_t inodes_per_group = ext4_get32(s, inodes_per_group);
+
+	uint32_t inode_table_bytes;
+
+
+	if (bg_ref->index < block_group_count - 1) {
+		inode_table_bytes = inodes_per_group * inode_size;
+	} else {
+		/* Last block group could be smaller */
+		uint32_t inodes_count_total =	ext4_get32(s, inodes_count);
+		inode_table_bytes =
+				(inodes_count_total - ((block_group_count - 1) * inodes_per_group)) *
+				inode_size;
+	}
+
+	uint32_t inode_table_blocks = inode_table_bytes / block_size;
+
+	if (inode_table_bytes % block_size)
+		inode_table_blocks++;
+
+	return inode_table_first_block + inode_table_blocks;
+}
+
+int 	ext4_balloc_free_block(struct ext4_inode_ref *inode_ref, uint32_t baddr)
+{
+	struct ext4_fs 	     *fs   = inode_ref->fs;
+	struct ext4_sblock   *sb   = &fs->sb;
+
+
+	uint32_t block_group    = ext4_balloc_get_bgid_of_block(sb, baddr);
+	uint32_t index_in_group	= ext4_fs_baddr2_index_in_group(sb, baddr);
+
+	/* Load block group reference */
+	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 block with bitmap */
+	uint32_t bitmap_block_addr =
+	    ext4_bg_get_block_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;
+
+	/* Modify bitmap */
+	ext4_bmap_bit_clr(bitmap_block.data, index_in_group);
+	bitmap_block.dirty = true;
+
+	/* Release 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;
+	}
+
+	uint32_t block_size = ext4_sb_get_block_size(sb);
+
+	/* Update superblock free blocks count */
+	uint64_t sb_free_blocks =
+			ext4_sb_get_free_blocks_cnt(sb);
+	sb_free_blocks++;
+	ext4_sb_set_free_blocks_cnt(sb, sb_free_blocks);
+
+	/* Update inode blocks count */
+	uint64_t ino_blocks =
+	    ext4_inode_get_blocks_count(sb, inode_ref->inode);
+	ino_blocks -= block_size / EXT4_INODE_BLOCK_SIZE;
+	ext4_inode_set_blocks_count(sb, inode_ref->inode, ino_blocks);
+	inode_ref->dirty = true;
+
+	/* Update block group free blocks count */
+	uint32_t free_blocks =
+	    ext4_bg_get_free_blocks_count(bg_ref.block_group, sb);
+	free_blocks++;
+	ext4_bg_set_free_blocks_count(bg_ref.block_group,
+	    sb, free_blocks);
+
+	bg_ref.dirty = true;
+
+	/* Release block group reference */
+	rc = ext4_fs_put_block_group_ref(&bg_ref);
+	if (rc != EOK)
+		return rc;
+
+	return EOK;
+}
+
+int 	ext4_balloc_free_blocks(struct ext4_inode_ref *inode_ref, uint32_t first, uint32_t count)
+{
+	struct ext4_fs *fs = inode_ref->fs;
+	struct ext4_sblock *sb = &fs->sb;
+
+	/* Compute indexes */
+	uint32_t block_group_first =
+	    ext4_balloc_get_bgid_of_block(sb, first);
+	uint32_t block_group_last =
+	    ext4_balloc_get_bgid_of_block(sb, first + count - 1);
+
+	ext4_assert(block_group_first == block_group_last);
+
+	/* Load block group reference */
+	struct ext4_block_group_ref bg_ref;
+	int rc = ext4_fs_get_block_group_ref(fs, block_group_first, &bg_ref);
+	if (rc != EOK)
+		return rc;
+
+	uint32_t index_in_group_first =
+	    ext4_fs_baddr2_index_in_group(sb, first);
+
+	/* Load block with bitmap */
+	uint32_t bitmap_block_addr =
+	    ext4_bg_get_block_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;
+
+	/* Modify bitmap */
+	ext4_bmap_bits_free(bitmap_block.data, index_in_group_first, count);
+	bitmap_block.dirty = true;
+
+	/* Release block with bitmap */
+	rc = ext4_block_set(fs->bdev, &bitmap_block);
+	if (rc != EOK) {
+		ext4_fs_put_block_group_ref(&bg_ref);
+		return rc;
+	}
+
+	uint32_t block_size = ext4_sb_get_block_size(sb);
+
+	/* Update superblock free blocks count */
+	uint64_t sb_free_blocks =
+			ext4_sb_get_free_blocks_cnt(sb);
+	sb_free_blocks += count;
+	ext4_sb_set_free_blocks_cnt(sb, sb_free_blocks);
+
+	/* Update inode blocks count */
+	uint64_t ino_blocks =
+	    ext4_inode_get_blocks_count(sb, inode_ref->inode);
+	ino_blocks -= count * (block_size / EXT4_INODE_BLOCK_SIZE);
+	ext4_inode_set_blocks_count(sb, inode_ref->inode, ino_blocks);
+	inode_ref->dirty = true;
+
+	/* Update block group free blocks count */
+	uint32_t free_blocks =
+	    ext4_bg_get_free_blocks_count(bg_ref.block_group, sb);
+	free_blocks += count;
+	ext4_bg_set_free_blocks_count(bg_ref.block_group,
+	    sb, free_blocks);
+	bg_ref.dirty = true;
+
+	/* Release block group reference */
+	rc = ext4_fs_put_block_group_ref(&bg_ref);
+	if (rc != EOK)
+		return rc;
+
+	return EOK;
+}
+
+static uint32_t ext4_balloc_find_goal(struct ext4_inode_ref *inode_ref)
+{
+	uint32_t goal = 0;
+
+	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);
+	uint32_t inode_block_count = inode_size / block_size;
+
+	if (inode_size % block_size != 0)
+		inode_block_count++;
+
+	/* If inode has some blocks, get last block address + 1 */
+	if (inode_block_count > 0) {
+		int rc = ext4_fs_get_inode_data_block_index(inode_ref,
+		    inode_block_count - 1, &goal);
+		if (rc != EOK)
+			return 0;
+
+		if (goal != 0) {
+			goal++;
+			return goal;
+		}
+
+		/* If goal == 0, sparse file -> continue */
+	}
+
+	/* Identify block group of inode */
+
+	uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group);
+	uint32_t block_group = (inode_ref->index - 1) / inodes_per_group;
+	block_size = ext4_sb_get_block_size(sb);
+
+	/* Load block group reference */
+	struct ext4_block_group_ref bg_ref;
+	int rc = ext4_fs_get_block_group_ref(inode_ref->fs,
+	    block_group, &bg_ref);
+	if (rc != EOK)
+		return 0;
+
+	/* Compute indexes */
+	uint32_t block_group_count = ext4_block_group_cnt(sb);
+	uint32_t inode_table_first_block =
+	    ext4_bg_get_inode_table_first_block(bg_ref.block_group, sb);
+	uint16_t inode_table_item_size = ext4_get16(sb, inode_size);
+	uint32_t inode_table_bytes;
+
+	/* Check for last block group */
+	if (block_group < block_group_count - 1) {
+		inode_table_bytes = inodes_per_group * inode_table_item_size;
+	} else {
+		/* Last block group could be smaller */
+		uint32_t inodes_count_total = ext4_get32(sb, inodes_count);
+
+		inode_table_bytes =
+		    (inodes_count_total - ((block_group_count - 1) * inodes_per_group)) *
+		    inode_table_item_size;
+	}
+
+	uint32_t inode_table_blocks = inode_table_bytes / block_size;
+
+	if (inode_table_bytes % block_size)
+		inode_table_blocks++;
+
+	goal = inode_table_first_block + inode_table_blocks;
+
+	ext4_fs_put_block_group_ref(&bg_ref);
+
+	return goal;
+}
+
+
+int 	ext4_balloc_alloc_block(struct ext4_inode_ref *inode_ref, uint32_t *fblock)
+{
+	uint32_t allocated_block = 0;
+	uint32_t bitmap_block_addr;
+	uint32_t rel_block_idx = 0;
+
+	struct	ext4_block bitmap_block;
+
+	/* Find GOAL */
+	uint32_t goal = ext4_balloc_find_goal(inode_ref);
+	if (goal == 0) {
+		/* no goal found => partition is full */
+		return ENOSPC;
+	}
+
+	struct ext4_sblock *sb = &inode_ref->fs->sb;
+
+	/* Load block group number for goal and relative index */
+	uint32_t block_group = ext4_balloc_get_bgid_of_block(sb, goal);
+	uint32_t index_in_group =
+	    ext4_fs_baddr2_index_in_group(sb, goal);
+
+	/* Load block group reference */
+	struct ext4_block_group_ref bg_ref;
+	int rc = ext4_fs_get_block_group_ref(inode_ref->fs,
+	    block_group, &bg_ref);
+	if (rc != EOK)
+		return rc;
+
+	/* Compute indexes */
+	uint32_t first_in_group =
+	    ext4_balloc_get_first_data_block_in_group(sb, &bg_ref);
+
+	uint32_t first_in_group_index =
+	    ext4_fs_baddr2_index_in_group(sb, first_in_group);
+
+	if (index_in_group < first_in_group_index)
+		index_in_group = first_in_group_index;
+
+	/* Load block with bitmap */
+	bitmap_block_addr =
+	    ext4_bg_get_block_bitmap(bg_ref.block_group, sb);
+
+	rc = ext4_block_get(inode_ref->fs->bdev, &bitmap_block, bitmap_block_addr);
+	if (rc != EOK) {
+		ext4_fs_put_block_group_ref(&bg_ref);
+		return rc;
+	}
+
+	/* Check if goal is free */
+	if (ext4_bmap_is_bit_clr(bitmap_block.data, index_in_group)) {
+		ext4_bmap_bit_set(bitmap_block.data, index_in_group);
+		bitmap_block.dirty = true;
+		rc = ext4_block_set(inode_ref->fs->bdev, &bitmap_block);
+		if (rc != EOK) {
+			ext4_fs_put_block_group_ref(&bg_ref);
+			return rc;
+		}
+
+		allocated_block =
+		    ext4_fs_index_in_group2_baddr(sb, index_in_group,
+		    block_group);
+
+		goto success;
+	}
+
+	uint32_t blocks_in_group =
+			ext4_blocks_in_group_cnt(sb, block_group);
+
+	uint32_t end_idx = (index_in_group + 63) & ~63;
+	if (end_idx > blocks_in_group)
+		end_idx = blocks_in_group;
+
+	/* Try to find free block near to goal */
+	uint32_t tmp_idx;
+	for (tmp_idx = index_in_group + 1; tmp_idx < end_idx;
+	    ++tmp_idx) {
+		if (ext4_bmap_is_bit_clr(bitmap_block.data, tmp_idx)) {
+			ext4_bmap_bit_set(bitmap_block.data, tmp_idx);
+
+			bitmap_block.dirty = true;
+			rc = ext4_block_set(inode_ref->fs->bdev, &bitmap_block);
+			if (rc != EOK)
+				return rc;
+
+			allocated_block =
+			    ext4_fs_index_in_group2_baddr(sb, tmp_idx,
+			    block_group);
+
+			goto success;
+		}
+	}
+
+
+
+	/* Find free bit in bitmap */
+	rc = ext4_bmap_bit_find_clr(bitmap_block.data,
+	    index_in_group, blocks_in_group, &rel_block_idx);
+	if (rc == EOK) {
+		ext4_bmap_bit_set(bitmap_block.data, rel_block_idx);
+		bitmap_block.dirty = true;
+		rc = ext4_block_set(inode_ref->fs->bdev, &bitmap_block);
+		if (rc != EOK)
+			return rc;
+
+		allocated_block =
+		    ext4_fs_index_in_group2_baddr(sb, rel_block_idx,
+		    block_group);
+
+		goto success;
+	}
+
+	/* No free block found yet */
+	ext4_block_set(inode_ref->fs->bdev, &bitmap_block);
+	ext4_fs_put_block_group_ref(&bg_ref);
+
+	/* Try other block groups */
+	uint32_t block_group_count = ext4_block_group_cnt(sb);
+
+	uint32_t bgid = (block_group + 1) % block_group_count;
+	uint32_t count = block_group_count;
+
+	while (count > 0) {
+		rc = ext4_fs_get_block_group_ref(inode_ref->fs, bgid,
+		    &bg_ref);
+		if (rc != EOK)
+			return rc;
+
+		/* Load block with bitmap */
+		bitmap_block_addr =
+		    ext4_bg_get_block_bitmap(bg_ref.block_group, sb);
+
+		rc = ext4_block_get(inode_ref->fs->bdev, &bitmap_block, bitmap_block_addr);
+
+		if (rc != EOK) {
+			ext4_fs_put_block_group_ref(&bg_ref);
+			return rc;
+		}
+
+		/* Compute indexes */
+		first_in_group =
+		    ext4_balloc_get_first_data_block_in_group(sb, &bg_ref);
+		index_in_group =
+		    ext4_fs_baddr2_index_in_group(sb, first_in_group);
+		blocks_in_group = ext4_blocks_in_group_cnt(sb, bgid);
+
+		first_in_group_index =
+		    ext4_fs_baddr2_index_in_group(sb, first_in_group);
+
+		if (index_in_group < first_in_group_index)
+			index_in_group = first_in_group_index;
+
+
+		rc = ext4_bmap_bit_find_clr(bitmap_block.data,
+		    index_in_group, blocks_in_group, &rel_block_idx);
+
+		if (rc == EOK) {
+
+			ext4_bmap_bit_set(bitmap_block.data, rel_block_idx);
+
+			bitmap_block.dirty = true;
+			rc = ext4_block_set(inode_ref->fs->bdev, &bitmap_block);
+			if (rc != EOK)
+				return rc;
+
+			allocated_block =
+			    ext4_fs_index_in_group2_baddr(sb, rel_block_idx,
+			    bgid);
+
+			goto success;
+		}
+
+		ext4_block_set(inode_ref->fs->bdev, &bitmap_block);
+		ext4_fs_put_block_group_ref(&bg_ref);
+
+		/* Goto next group */
+		bgid = (bgid + 1) % block_group_count;
+		count--;
+	}
+
+	return ENOSPC;
+
+success:
+	/* Empty command - because of syntax */
+	;
+
+	uint32_t block_size = ext4_sb_get_block_size(sb);
+
+	/* Update superblock free blocks count */
+	uint64_t sb_free_blocks = ext4_sb_get_free_blocks_cnt(sb);
+	sb_free_blocks--;
+	ext4_sb_set_free_blocks_cnt(sb, sb_free_blocks);
+
+	/* Update inode blocks (different block size!) count */
+	uint64_t ino_blocks =
+	    ext4_inode_get_blocks_count(sb, inode_ref->inode);
+	ino_blocks += block_size / EXT4_INODE_BLOCK_SIZE;
+	ext4_inode_set_blocks_count(sb, inode_ref->inode, ino_blocks);
+	inode_ref->dirty = true;
+
+	/* Update block group free blocks count */
+	uint32_t bg_free_blocks =
+	    ext4_bg_get_free_blocks_count(bg_ref.block_group, sb);
+	bg_free_blocks--;
+	ext4_bg_set_free_blocks_count(bg_ref.block_group, sb,
+	    bg_free_blocks);
+
+	bg_ref.dirty = true;
+
+	ext4_fs_put_block_group_ref(&bg_ref);
+
+	*fblock = allocated_block;
+	return EOK;
+}
+
+int 	ext4_balloc_try_alloc_block(struct ext4_inode_ref *inode_ref, uint32_t baddr, bool *free)
+{
+	int rc = EOK;
+
+	struct ext4_fs *fs = inode_ref->fs;
+	struct ext4_sblock *sb = &fs->sb;
+
+	/* Compute indexes */
+	uint32_t block_group = ext4_balloc_get_bgid_of_block(sb, baddr);
+	uint32_t index_in_group =
+	    ext4_fs_baddr2_index_in_group(sb, baddr);
+
+	/* Load block group reference */
+	struct ext4_block_group_ref bg_ref;
+	rc = ext4_fs_get_block_group_ref(fs, block_group, &bg_ref);
+	if (rc != EOK)
+		return rc;
+
+	/* Load block with bitmap */
+	uint32_t bitmap_block_addr =
+	    ext4_bg_get_block_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;
+
+	/* Check if block is free */
+	*free = ext4_bmap_is_bit_clr(bitmap_block.data, index_in_group);
+
+	/* Allocate block if possible */
+	if (*free) {
+		ext4_bmap_bit_set(bitmap_block.data, index_in_group);
+		bitmap_block.dirty = true;
+	}
+
+	/* Release 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 block is not free, return */
+	if (!(*free))
+		goto terminate;
+
+	uint32_t block_size = ext4_sb_get_block_size(sb);
+
+	/* Update superblock free blocks count */
+	uint64_t sb_free_blocks = ext4_sb_get_free_blocks_cnt(sb);
+	sb_free_blocks--;
+	ext4_sb_set_free_blocks_cnt(sb, sb_free_blocks);
+
+	/* Update inode blocks count */
+	uint64_t ino_blocks =
+	    ext4_inode_get_blocks_count(sb, inode_ref->inode);
+	ino_blocks += block_size / EXT4_INODE_BLOCK_SIZE;
+	ext4_inode_set_blocks_count(sb, inode_ref->inode, ino_blocks);
+	inode_ref->dirty = true;
+
+	/* Update block group free blocks count */
+	uint32_t free_blocks =
+	    ext4_bg_get_free_blocks_count(bg_ref.block_group, sb);
+	free_blocks--;
+	ext4_bg_set_free_blocks_count(bg_ref.block_group,
+	    sb, free_blocks);
+
+	bg_ref.dirty = true;
+
+terminate:
+	return ext4_fs_put_block_group_ref(&bg_ref);
+}
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/src/lwext4/ext4_balloc.h
@@ -1,0 +1,88 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ *
+ *
+ * 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_balloc.h
+ * @brief Physical block allocator.
+ */
+
+#ifndef EXT4_BALLOC_H_
+#define EXT4_BALLOC_H_
+
+#include <ext4_config.h>
+#include <ext4_types.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+
+
+/**@brief	Get first datablock in block group
+ * @param	s superblock descriptor
+ * @param	bg_ref block group reference
+ * @return	block id of the first datablock in block group*/
+uint32_t ext4_balloc_get_first_data_block_in_group(struct ext4_sblock *s, struct ext4_block_group_ref * bg_ref);
+
+/**@brief	Free block from inode.
+ * @param	inode_ref inode reference
+ * @param	baddr block address
+ * @return 	standard error code*/
+int 	ext4_balloc_free_block(struct ext4_inode_ref *inode_ref, uint32_t baddr);
+
+/**@brief	Free blocks from inode.
+ * @param	inode_ref inode reference
+ * @param	baddr block address
+ * @return 	standard error code*/
+int 	ext4_balloc_free_blocks(struct ext4_inode_ref *inode_ref, uint32_t first, uint32_t count);
+
+/**@brief	Allocate block procedure.
+ * @param	inode_ref inode reference
+ * @param	baddr allocated block address
+ * @return 	standard error code*/
+int 	ext4_balloc_alloc_block(struct ext4_inode_ref *inode_ref, uint32_t *baddr);
+
+/**@brief	Try allocate selected block.
+ * @param	inode_ref inode reference
+ * @param	baddr block address to allocate
+ * @param	free if baddr is not allocated
+ * @return 	standard error code*/
+int 	ext4_balloc_try_alloc_block(struct ext4_inode_ref *inode_ref, uint32_t baddr, bool *free);
+
+#endif /* EXT4_BALLOC_H_ */
+
+/**
+ * @}
+ */
+
--- /dev/null
+++ b/src/lwext4/ext4_bcache.c
@@ -1,0 +1,277 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ * 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);
+
+	bc->lru_ctr= 0;
+
+	bc->refctr	 	= 0;
+	bc->lru_id 		= 0;
+	bc->free_delay  = 0;
+	bc->lba	  	 	= 0;
+	bc->data	 	= 0;
+
+	bc->refctr   = malloc(cnt * sizeof(uint32_t));
+	if(!bc->refctr)
+		goto error;
+
+	bc->lru_id = malloc(cnt * sizeof(uint32_t));
+	if(!bc->lru_id)
+		goto error;
+
+	bc->free_delay = malloc(cnt * sizeof(uint8_t));
+	if(!bc->free_delay)
+		goto error;
+
+	bc->lba 	 = malloc(cnt * sizeof(uint64_t));
+	if(!bc->lba)
+		goto error;
+
+	bc->data	 = malloc(cnt * itemsize);
+	if(!bc->data)
+		goto error;
+
+	memset(bc->refctr, 0, cnt * sizeof(uint32_t));
+	memset(bc->lru_id, 0, cnt * sizeof(uint32_t));
+	memset(bc->free_delay, 0, cnt * sizeof(uint8_t));
+	memset(bc->lba, 0, cnt * sizeof(uint64_t));
+
+	bc->cnt      = cnt;
+	bc->itemsize = itemsize;
+	bc->ref_blocks = 0;
+	bc->max_ref_blocks = 0;
+
+	return EOK;
+
+	error:
+
+	if(bc->refctr)
+		free(bc->refctr);
+
+	if(bc->lru_id)
+		free(bc->lru_id);
+
+	if(bc->free_delay)
+		free(bc->free_delay);
+
+	if(bc->lba)
+		free(bc->lba);
+
+	if(bc->data)
+		free(bc->data);
+
+	return ENOMEM;
+}
+
+int ext4_bcache_fini_dynamic(struct	ext4_bcache *bc)
+{
+	if(bc->refctr)
+		free(bc->refctr);
+
+	if(bc->lru_id)
+		free(bc->lru_id);
+
+	if(bc->free_delay)
+		free(bc->free_delay);
+
+	if(bc->lba)
+		free(bc->lba);
+
+	if(bc->data)
+		free(bc->data);
+
+	bc->lru_ctr= 0;
+
+	bc->refctr	 	= 0;
+	bc->lru_id 		= 0;
+	bc->free_delay  = 0;
+	bc->lba	  	 	= 0;
+	bc->data	 	= 0;
+
+	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;
+
+	*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*/
+			b->data = bc->data + i * bc->itemsize;
+
+			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*/
+		b->data = bc->data + cache_id * bc->itemsize;
+
+		/*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)
+{
+	uint32_t i;
+
+	ext4_assert(bc && b);
+
+	/*Check if valid.*/
+	ext4_assert(b->lb_id);
+
+	/*Block should be in cache.*/
+	for (i = 0; i < bc->cnt; ++i) {
+
+		if(bc->lba[i] != b->lb_id)
+			continue;
+
+		/*Check if someone don't try free unreferenced block cache.*/
+		ext4_assert(bc->refctr[i]);
+
+		/*Just decrease reference counter*/
+		if(bc->refctr[i])
+			bc->refctr[i]--;
+
+
+		if(free_delay)
+			bc->free_delay[i] = free_delay;
+
+		/*Update statistics*/
+		if(!bc->refctr[i] && !bc->free_delay[i])
+			bc->ref_blocks--;
+
+		b->lb_id = 0;
+		b->data  = 0;
+
+		return EOK;
+	}
+
+	ext4_dprintf(EXT4_DEBUG_BCACHE, "ext4_bcache_free: FAIL, block should be in cache memory !\n");
+	return EFAULT;
+}
+
+bool ext4_bcache_is_full(struct ext4_bcache *bc)
+{
+	return (bc->cnt == bc->ref_blocks);
+}
+
+/**
+ * @}
+ */
+
+
--- /dev/null
+++ b/src/lwext4/ext4_bcache.h
@@ -1,0 +1,148 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ * 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	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 (cnt).*/
+	uint32_t	*refctr;
+
+	/**@brief	Last recently used ID table (cnt)*/
+	uint32_t 	*lru_id;
+
+	/**@brief	Free delay mode table (cnt)*/
+	uint8_t 	*free_delay;
+
+	/**@brief	Logical block table (cnt).*/
+	uint64_t	*lba;
+
+	/**@brief	Cache data buffers (cnt * itemsize)*/
+	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 uint32_t	__name##_refctr[(__cnt)];					\
+	static uint32_t	__name##_lru_id[(__cnt)];					\
+	static uint8_t		__name##_free_delay[(__cnt)];			\
+	static uint64_t	__name##_lba[(__cnt)];						\
+	static uint8_t 	__name##_data[(__cnt) * (__itemsize)];		\
+	static struct ext4_bcache	__name = {						\
+		.cnt 	   = __cnt,										\
+		.itemsize  = __itemsize,								\
+		.lru_ctr   = 0,											\
+		.refctr	   = __name##_refctr,							\
+		.lru_id    = __name##_lru_id,							\
+		.lba	   = __name##_lba,								\
+		.free_delay= __name##_free_delay,						\
+		.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
+ * @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_ */
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/src/lwext4/ext4_bitmap.c
@@ -1,0 +1,172 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ * 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_bitmap.c
+ * @brief Block/inode bitmap allocator.
+ */
+
+#include <ext4_config.h>
+#include <ext4_bitmap.h>
+
+#include <ext4_errno.h>
+
+
+void	ext4_bmap_bits_free(uint8_t *bmap, uint32_t sbit, uint32_t bcnt)
+{
+	uint32_t i;
+
+	i = sbit;
+
+	while(i & 7){
+
+		if(!bcnt)
+			return;
+
+		ext4_bmap_bit_clr(bmap, i);
+
+		bcnt--;
+		i++;
+	}
+
+	sbit  = i;
+	bmap += (sbit >> 3);
+
+
+
+	while(bcnt >= 32){
+		*(uint32_t *)bmap = 0;
+
+		bmap += 4;
+		bcnt -= 32;
+		sbit += 32;
+	}
+
+	while(bcnt >= 16){
+		*(uint16_t *)bmap = 0;
+
+		bmap += 2;
+		bcnt -= 16;
+		sbit += 16;
+	}
+
+	while(bcnt >= 8){
+		*bmap = 0;
+
+		bmap += 1;
+		bcnt -= 8;
+		sbit += 8;
+	}
+
+	for (i = 0; i < bcnt; ++i) {
+		ext4_bmap_bit_clr(bmap, i);
+	}
+}
+
+
+
+int 	ext4_bmap_bit_find_clr(uint8_t *bmap, uint32_t sbit, uint32_t ebit, uint32_t *bit_id)
+{
+	uint32_t i;
+	uint32_t bcnt = ebit - sbit;
+
+	i = sbit;
+
+	while(i & 7){
+
+		if(!bcnt)
+			return ENOSPC;
+
+		if(ext4_bmap_is_bit_clr(bmap, i)){
+			*bit_id = sbit;
+			return EOK;
+		}
+
+		i++;
+		bcnt--;
+	}
+
+	sbit  = i;
+	bmap += (sbit >> 3);
+
+
+	while(bcnt >= 32){
+		if(*(uint32_t *)bmap != 0xFFFFFFFF)
+			goto finish_it;
+
+
+		bmap += 4;
+		bcnt -= 32;
+		sbit += 32;
+	}
+
+	while(bcnt >= 16){
+		if(*(uint16_t *)bmap != 0xFFFF)
+			goto finish_it;
+
+
+		bmap += 2;
+		bcnt -= 16;
+		sbit += 16;
+	}
+
+	finish_it:
+	while(bcnt >= 8){
+		if(*bmap != 0xFF){
+			for (i = 0; i < 8; ++i) {
+				if(ext4_bmap_is_bit_clr(bmap, i)){
+					*bit_id = sbit + i;
+					return EOK;
+				}
+			}
+		}
+
+		bmap += 1;
+		bcnt -= 8;
+		sbit += 8;
+	}
+
+	for (i = 0; i < bcnt; ++i) {
+		if(ext4_bmap_is_bit_clr(bmap, i)){
+			*bit_id = sbit + i;
+			return EOK;
+		}
+	}
+
+
+	return ENOSPC;
+}
+
+/**
+ * @}
+ */
+
+
--- /dev/null
+++ b/src/lwext4/ext4_bitmap.h
@@ -1,0 +1,97 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ * 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_bitmap.h
+ * @brief Block/inode bitmap allocator.
+ */
+
+
+#ifndef EXT4_BITMAP_H_
+#define EXT4_BITMAP_H_
+
+#include <ext4_config.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+/**@brief	Set bitmap bit.
+ * @param	bmap bitmap
+ * @param	bit	 bit to set*/
+static inline void	ext4_bmap_bit_set(uint8_t *bmap, uint32_t bit)
+{
+	*(bmap + (bit >> 3)) |= (1 << (bit & 7));
+}
+
+/**@brief	Clear bitmap bit.
+ * @param	bmap bitmap buffer
+ * @param	bit	 bit to clear*/
+static inline void	ext4_bmap_bit_clr(uint8_t *bmap, uint32_t bit)
+{
+	*(bmap + (bit >> 3)) &= ~(1 << (bit & 7));
+}
+
+
+/**@brief	Check if the bitmap bit is set.
+ * @param	bmap bitmap buffer
+ * @param	bit	 bit to check*/
+static inline bool	 ext4_bmap_is_bit_set(uint8_t *bmap, uint32_t bit)
+{
+	return (*(bmap + (bit >> 3)) & (1 << (bit & 7)));
+}
+
+/**@brief	Check if the bitmap bit is clear.
+ * @param	bmap bitmap buffer
+ * @param	bit	 bit to check*/
+static inline bool	 ext4_bmap_is_bit_clr(uint8_t *bmap, uint32_t bit)
+{
+	return !ext4_bmap_is_bit_set(bmap, bit);
+}
+
+/**@brief	Free range of bits in bitmap.
+ * @param	bmap bitmap buffer
+ * @param	sbit start bit
+ * @param	bcnt bit count*/
+void	ext4_bmap_bits_free(uint8_t *bmap, uint32_t sbit, uint32_t bcnt);
+
+/**@brief	Find first clear bit in bitmap.
+ * @param	sbit start bit of search
+ * @param	ebit end bit of search
+ * @param	bit_id output parameter (first free bit)
+ * @return	standard error code*/
+int 	ext4_bmap_bit_find_clr(uint8_t *bmap, uint32_t sbit, uint32_t ebit, uint32_t *bit_id);
+
+
+#endif /* EXT4_BITMAP_H_ */
+
+/**
+ * @}
+ */
+
--- /dev/null
+++ b/src/lwext4/ext4_block_group.c
@@ -1,0 +1,55 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ *
+ *
+ * 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_block_group.c
+ * @brief Block group function set.
+ */
+
+#include <ext4_config.h>
+#include <ext4_block_group.h>
+
+
+
+uint16_t ext4_bg_crc16(uint16_t crc, const uint8_t *buffer, size_t len)
+{
+	// TODO
+	return 0;
+}
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/src/lwext4/ext4_block_group.h
@@ -1,0 +1,187 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ *
+ *
+ * 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_block_group.h
+ * @brief Block group function set.
+ */
+
+#ifndef EXT4_BLOCK_GROUP_H_
+#define EXT4_BLOCK_GROUP_H_
+
+
+#include <ext4_config.h>
+#include <ext4_types.h>
+#include <ext4_super.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+
+static inline uint64_t ext4_bg_get_block_bitmap(struct ext4_bgroup *bg, struct ext4_sblock *s)
+{
+	uint64_t v = to_le32(bg->block_bitmap_lo);
+
+	if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+		v |= (uint64_t) to_le32(bg->block_bitmap_hi) << 32;
+
+	return v;
+}
+
+static inline uint64_t ext4_bg_get_inode_bitmap(struct ext4_bgroup *bg, struct ext4_sblock *s)
+{
+
+	uint64_t v = to_le32(bg->inode_bitmap_lo);
+
+	if (ext4_sb_get_desc_size(s)> EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+		v |= (uint64_t) to_le32(bg->inode_bitmap_hi) << 32;
+
+	return v;
+}
+
+static inline uint64_t ext4_bg_get_inode_table_first_block(struct ext4_bgroup *bg, struct ext4_sblock *s)
+{
+	uint64_t v = to_le32(bg->inode_table_first_block_lo);
+
+	if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+		v |= (uint64_t) to_le32(bg->inode_table_first_block_hi) << 32;
+
+	return v;
+}
+
+static inline uint32_t ext4_bg_get_free_blocks_count(struct ext4_bgroup *bg, struct ext4_sblock *s)
+{
+	uint32_t v = to_le16(bg->free_blocks_count_lo);
+
+	if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+		v |= (uint32_t) to_le16(bg->free_blocks_count_hi) << 16;
+
+	return v;
+}
+
+static inline void 	 ext4_bg_set_free_blocks_count(struct ext4_bgroup *bg, struct ext4_sblock *s, uint32_t cnt)
+{
+	bg->free_blocks_count_lo = to_le16((cnt << 16) >> 16);
+	if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+		bg->free_blocks_count_hi = to_le16(cnt >> 16);
+}
+
+static inline uint32_t ext4_bg_get_free_inodes_count(struct ext4_bgroup *bg, struct ext4_sblock *s)
+{
+	uint32_t v = to_le16(bg->free_inodes_count_lo);
+
+	if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+		v |= (uint32_t) to_le16(bg->free_inodes_count_hi) << 16;
+
+	return v;
+}
+
+static inline void 	 ext4_bg_set_free_inodes_count(struct ext4_bgroup *bg, struct ext4_sblock *s, uint32_t cnt)
+{
+	bg->free_inodes_count_lo = to_le16((cnt << 16) >> 16);
+	if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+		bg->free_inodes_count_hi = to_le16(cnt >> 16);
+}
+
+
+static inline uint32_t ext4_bg_get_used_dirs_count(struct ext4_bgroup *bg, struct ext4_sblock *s)
+{
+	uint32_t v = to_le16(bg->used_dirs_count_lo);
+
+	if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+		v |= (uint32_t) to_le16(bg->used_dirs_count_hi) << 16;
+
+	return v;
+}
+
+static inline void 	 ext4_bg_set_used_dirs_count(struct ext4_bgroup *bg, struct ext4_sblock *s, uint32_t cnt)
+{
+	bg->used_dirs_count_lo = to_le16((cnt << 16) >> 16);
+	if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+		bg->used_dirs_count_hi = to_le16(cnt >> 16);
+}
+
+
+static inline uint32_t ext4_bg_get_itable_unused(struct ext4_bgroup *bg, struct ext4_sblock *s)
+{
+
+	uint32_t v = to_le16(bg->itable_unused_lo);
+
+	if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+		v |= (uint32_t) to_le16(bg->itable_unused_hi) << 16;
+
+	return v;
+}
+
+static inline void 	 ext4_bg_set_itable_unused(struct ext4_bgroup *bg, struct ext4_sblock *s, uint32_t cnt)
+{
+	bg->itable_unused_lo = to_le16((cnt << 16) >> 16);
+	if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+		bg->itable_unused_hi = to_le16(cnt >> 16);
+}
+
+
+static inline void 	 ext4_bg_set_checksum(struct ext4_bgroup *bg, uint16_t crc)
+{
+	bg->checksum = to_le16(crc);
+}
+
+static inline bool 	 ext4_bg_has_flag(struct ext4_bgroup *bg, uint32_t f)
+{
+	return to_le16(bg->flags) & f;
+}
+
+static inline void 	 ext4_bg_set_flag(struct ext4_bgroup *bg, uint32_t f)
+{
+	uint16_t flags = to_le16(bg->flags);
+	flags |= f;
+	bg->flags = to_le16(flags);
+}
+
+static inline void 	 ext4_bg_clear_flag(struct ext4_bgroup *bg, uint32_t f)
+{
+	uint16_t flags = to_le16(bg->flags);
+	flags &= ~f;
+	bg->flags = to_le16(flags);
+}
+
+
+uint16_t ext4_bg_crc16(uint16_t crc, const uint8_t *buffer, size_t len);
+
+#endif /* EXT4_BLOCK_GROUP_H_ */
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/src/lwext4/ext4_blockdev.c
@@ -1,0 +1,439 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ * 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_blockdev.c
+ * @brief Block device module.
+ */
+
+#include <ext4_config.h>
+#include <ext4_blockdev.h>
+#include <ext4_errno.h>
+#include <ext4_debug.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+
+
+int	ext4_block_init(struct	ext4_blockdev *bdev)
+{
+	int rc;
+	ext4_assert(bdev);
+
+	ext4_assert(bdev->open && bdev->close && bdev->bread  && bdev->bwrite);
+
+	/*Low level block init*/
+	rc = bdev->open(bdev);
+	if(EOK != rc)
+		return rc;
+
+	bdev->flags |= EXT4_BDEV_INITIALIZED;
+
+	return	EOK;
+}
+
+int ext4_block_bind_bcache(struct ext4_blockdev *bdev, struct ext4_bcache *bc)
+{
+	ext4_assert(bdev && bc);
+	bdev->bc = bc;
+	return EOK;
+}
+
+void ext4_block_set_lb_size(struct	ext4_blockdev *bdev, uint64_t	lb_bsize)
+{
+	/*Logical block size has to be multiply of physical */
+	ext4_assert(!(lb_bsize % bdev->ph_bsize));
+
+	bdev->lg_bsize = lb_bsize;
+	bdev->lg_bcnt = (bdev->ph_bcnt * bdev->ph_bsize) / lb_bsize;
+
+}
+
+int ext4_block_fini(struct	ext4_blockdev *bdev)
+{
+	ext4_assert(bdev);
+
+	bdev->flags &= ~(EXT4_BDEV_INITIALIZED);
+
+	/*Low level block fini*/
+	return bdev->close(bdev);
+}
+
+
+int ext4_block_get(struct	ext4_blockdev *bdev, struct	ext4_block *b, uint64_t lba)
+{
+	uint64_t pba;
+	uint32_t pb_cnt;
+	bool	 is_new;
+	int 	 r;
+	ext4_assert(bdev && b);
+
+	if(!(bdev->flags & EXT4_BDEV_INITIALIZED))
+		return EIO;
+
+	if(!(lba < bdev->lg_bcnt))
+		return ERANGE;
+
+	b->dirty = 0;
+	b->lb_id = lba;
+
+	r = ext4_bcache_alloc(bdev->bc, b, &is_new);
+	if(r != EOK)
+		return r;
+
+
+	if(!is_new){
+		/*Block is in cache. Read from physical device is not required*/
+		return EOK;
+	}
+
+	if(!b->data)
+		return ENOMEM;
+
+	pba 	= (lba * bdev->lg_bsize) / bdev->ph_bsize;
+	pb_cnt  =  bdev->lg_bsize / bdev->ph_bsize;
+
+
+	r = bdev->bread(bdev, b->data, pba, pb_cnt);
+
+	if(r != EOK){
+		ext4_bcache_free(bdev->bc, b, 0);
+		b->lb_id = 0;
+		return r;
+	}
+
+	bdev->bread_ctr++;
+
+	return EOK;
+}
+
+int ext4_block_set(struct	ext4_blockdev *bdev, struct	ext4_block *b)
+{
+	uint64_t pba;
+	uint32_t pb_cnt;
+	uint32_t i;
+	int r;
+
+	ext4_assert(bdev && b);
+
+	if(!(bdev->flags & EXT4_BDEV_INITIALIZED))
+		return EIO;
+
+	/*Doesn,t need to write.*/
+	if(b->dirty == false){
+		ext4_bcache_free(bdev->bc, b, 0);
+		return EOK;
+	}
+
+	b->dirty = false;
+
+
+	/*Free cache delay mode*/
+	if(bdev->cache_flush_delay){
+
+		/*Free cahe block and mark as free delayed*/
+		ext4_bcache_free(bdev->bc, b, bdev->cache_flush_delay);
+
+		/*If cache is full we have to flush it anyway :(*/
+		if(ext4_bcache_is_full(bdev->bc)){
+			for (i = 0; i < bdev->bc->cnt; ++i) {
+				/*Check if buffer free was delayed.*/
+				if(!bdev->bc->free_delay[i])
+					continue;
+
+				/*Check reference counter.*/
+				if(bdev->bc->refctr[i])
+					continue;
+
+				/*Buffer free was delayed and have no reference. Flush it.*/
+				r = ext4_block_set_direct(bdev, bdev->bc->data + bdev->bc->itemsize * i, bdev->bc->lba[i]);
+				if(r != EOK)
+					return r;
+
+				/*No delayed anymore*/
+				bdev->bc->free_delay[i] = 0;
+
+				/*Reduce refered block count*/
+				bdev->bc->ref_blocks--;
+			}
+		}
+
+		return EOK;
+	}
+
+	pba 	= (b->lb_id * bdev->lg_bsize) / bdev->ph_bsize;
+	pb_cnt  =  bdev->lg_bsize / bdev->ph_bsize;
+
+
+	r = bdev->bwrite(bdev, b->data, pba, pb_cnt);
+
+	if(r != EOK){
+		b->dirty = false;
+		ext4_bcache_free(bdev->bc, b, 0);
+		return r;
+	}
+
+	bdev->bwrite_ctr++;
+	b->dirty = false;
+	ext4_bcache_free(bdev->bc, b, 0);
+	return EOK;
+}
+
+int ext4_block_get_direct(struct	ext4_blockdev *bdev, void *buf, uint64_t lba)
+{
+	uint64_t pba;
+	uint32_t pb_cnt;
+
+	ext4_assert(bdev && buf);
+
+	pba 	= (lba * bdev->lg_bsize) / bdev->ph_bsize;
+	pb_cnt  =  bdev->lg_bsize / bdev->ph_bsize;
+
+	bdev->bread_ctr++;
+
+	return bdev->bread(bdev, buf, pba, pb_cnt);
+}
+
+
+
+int ext4_block_set_direct(struct	ext4_blockdev *bdev, const void *buf, uint64_t lba)
+{
+	uint64_t pba;
+	uint32_t pb_cnt;
+
+	ext4_assert(bdev && buf);
+
+	pba 	= (lba * bdev->lg_bsize) / bdev->ph_bsize;
+	pb_cnt  =  bdev->lg_bsize / bdev->ph_bsize;
+
+	bdev->bwrite_ctr++;
+
+	return bdev->bwrite(bdev, buf, pba, pb_cnt);
+}
+
+
+int	ext4_block_writebytes(struct	ext4_blockdev *bdev, uint64_t off, const void *buf, uint32_t len)
+{
+	uint64_t block_idx;
+	uint64_t block_end;
+
+	uint32_t blen;
+
+	uint32_t unalg;
+	int		 r = EOK;
+
+	const uint8_t	*p = (void *)buf;
+
+	ext4_assert(bdev && buf);
+
+	if(!(bdev->flags & EXT4_BDEV_INITIALIZED))
+		return EIO;
+
+
+	block_idx =  off / bdev->ph_bsize;
+	block_end   =  block_idx + len / bdev->ph_bsize;
+
+	if(!(block_end < bdev->ph_bcnt))
+		return EINVAL;				/*Ups. Out of range operation*/
+
+
+	/*OK lets deal with the first possible unaligned block*/
+	unalg = (off & (bdev->ph_bsize - 1));
+	if(unalg){
+
+		uint32_t wlen = (bdev->ph_bsize - unalg) > len ? len : (bdev->ph_bsize - unalg);
+
+		r = bdev->bread(bdev, bdev->ph_bbuf, block_idx, 1);
+
+		if(r != EOK)
+			return r;
+
+		memcpy(bdev->ph_bbuf + unalg, p, wlen);
+
+		r = bdev->bwrite(bdev, bdev->ph_bbuf, block_idx, 1);
+
+		if(r != EOK)
+			return r;
+
+		p   += wlen;
+		len -= wlen;
+		block_idx++;
+	}
+
+
+	/*Aligned data*/
+	blen = len / bdev->ph_bsize;
+
+	r = bdev->bwrite(bdev, p, block_idx, blen);
+
+	if(r != EOK)
+		return r;
+
+	p 	+= bdev->ph_bsize * blen;
+	len -= bdev->ph_bsize * blen;
+
+	block_idx += blen;
+
+
+	/*Rest of the data*/
+	if(len){
+
+		r = bdev->bread(bdev, bdev->ph_bbuf, block_idx, 1);
+
+		if(r != EOK)
+			return r;
+
+		memcpy(bdev->ph_bbuf, p, len);
+
+		r = bdev->bwrite(bdev, bdev->ph_bbuf, block_idx, 1);
+
+		if(r != EOK)
+			return r;
+	}
+
+	return r;
+}
+
+
+
+
+int ext4_block_readbytes(struct	ext4_blockdev *bdev, uint64_t off, void *buf, uint32_t len)
+{
+
+	uint64_t block_idx;
+	uint64_t block_end;
+	uint32_t blen;
+
+	uint32_t unalg;
+	int		 r = EOK;
+
+	uint8_t	*p = (void *)buf;
+
+	ext4_assert(bdev && buf);
+
+	if(!(bdev->flags & EXT4_BDEV_INITIALIZED))
+		return EIO;
+
+
+	block_idx =  off / bdev->ph_bsize;
+	block_end   =  block_idx + len / bdev->ph_bsize;
+
+	if(!(block_end < bdev->ph_bcnt))
+		return EINVAL;				/*Ups. Out of range operation*/
+
+
+	/*OK lets deal with the first possible unaligned block*/
+	unalg = (off & (bdev->ph_bsize - 1));
+	if(unalg){
+
+		uint32_t rlen = (bdev->ph_bsize - unalg) > len ? len : (bdev->ph_bsize - unalg);
+
+		r = bdev->bread(bdev, bdev->ph_bbuf, block_idx, 1);
+
+		if(r != EOK)
+			return r;
+
+		memcpy(p, bdev->ph_bbuf + unalg, rlen);
+
+		p   += rlen;
+		len -= rlen;
+		block_idx++;
+	}
+
+
+	/*Aligned data*/
+	blen = len / bdev->ph_bsize;
+
+	r = bdev->bread(bdev, p, block_idx, blen);
+
+	if(r != EOK)
+		return r;
+
+	p 	+= bdev->ph_bsize * blen;
+	len -= bdev->ph_bsize * blen;
+
+	block_idx += blen;
+
+
+	/*Rest of the data*/
+	if(len){
+
+		r = bdev->bread(bdev, bdev->ph_bbuf, block_idx, 1);
+
+		if(r != EOK)
+			return r;
+
+		memcpy(p, bdev->ph_bbuf, len);
+
+	}
+
+	return r;
+}
+
+int 	ext4_block_delay_cache_flush(struct	ext4_blockdev *bdev, uint8_t on_off)
+{
+	int r;
+	uint32_t i;
+	bdev->cache_flush_delay = on_off;
+
+	/*Flush all delayed cache blocks*/
+	if(!on_off){
+		for (i = 0; i < bdev->bc->cnt; ++i) {
+
+			/*Check if buffer free was delayed.*/
+			if(!bdev->bc->free_delay[i])
+				continue;
+
+			/*Check reference counter.*/
+			if(bdev->bc->refctr[i])
+				continue;
+
+			/*Buffer free was delayed and have no reference. Flush it.*/
+			r = ext4_block_set_direct(bdev, bdev->bc->data + bdev->bc->itemsize * i, bdev->bc->lba[i]);
+			if(r != EOK)
+				return r;
+
+			/*No delayed anymore*/
+			bdev->bc->free_delay[i] = 0;
+
+			/*Reduce refered block count*/
+			bdev->bc->ref_blocks--;
+		}
+	}
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
+
--- /dev/null
+++ b/src/lwext4/ext4_blockdev.h
@@ -1,0 +1,201 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ * 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.
+ */
+#ifndef EXT4_BLOCKDEV_H_
+#define EXT4_BLOCKDEV_H_
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file  ext4_blockdev.h
+ * @brief Block device module.
+ */
+
+#include <ext4_config.h>
+#include <ext4_bcache.h>
+#include <ext4_debug.h>
+
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/**@brief	Initialization status flag*/
+#define EXT4_BDEV_INITIALIZED			(1 << 0)
+
+
+/**@brief	Definiton of the simple block device.*/
+struct	ext4_blockdev  {
+
+	/**@brief	Open device function
+	 * @param	bdev block device.*/
+	int			(*open)(struct	ext4_blockdev *bdev);
+
+	/**@brief	Block read function.
+	 * @param	bdev block device
+	 * @param	buf	output buffer
+	 * @param	blk_id	block id
+	 * @param	blk_cnt block count*/
+	int			(*bread)(struct	ext4_blockdev *bdev, void 	*buf, uint64_t blk_id, uint32_t blk_cnt);
+
+	/**@brief	Block write function.
+	 * @param	buf input buffer
+	 * @param	blk_id block id
+	 * @param	blk_cnt block count*/
+	int			(*bwrite)(struct	ext4_blockdev *bdev, const void *buf, uint64_t blk_id, uint32_t blk_cnt);
+
+	/**@brief	Close device function.
+	 * @param	bdev block device.*/
+	int			(*close)(struct	ext4_blockdev *bdev);
+
+	/**@brief	Block size (bytes): physical*/
+	uint32_t	ph_bsize;
+
+	/**@brief	Block count: physical.*/
+	uint64_t	ph_bcnt;
+
+	/**@brief	Block size buffer: physical.*/
+	uint8_t		*ph_bbuf;
+
+	/**@brief	Block size (bytes) logical*/
+	uint32_t	lg_bsize;
+
+	/**@brief	Block count: phisical.*/
+	uint64_t	lg_bcnt;
+
+	/**@brief	Flags of te block device.*/
+	uint8_t		flags;
+
+	/**@brief	Block cache.*/
+	struct	ext4_bcache *bc;
+
+	uint8_t		cache_flush_delay;
+
+	uint32_t	bread_ctr;
+	uint32_t	bwrite_ctr;
+};
+
+
+/**@brief	Static initialization fo the block device.*/
+#define EXT4_BLOCKDEV_STATIC_INSTANCE(__name, __bsize, __bcnt, __open, __bread, __bwrite, __close)	\
+	static uint8_t	__name##_ph_bbuf[(__bsize)];													\
+	static struct	ext4_blockdev __name = {														\
+		.open   = __open,																			\
+		.bread  = __bread,																			\
+		.bwrite = __bwrite,																			\
+		.close  = __close,																			\
+		.ph_bsize  = __bsize,																		\
+		.ph_bcnt   = __bcnt,																		\
+		.ph_bbuf   = __name##_ph_bbuf,																\
+}
+
+/**@brief	Block device initialization.
+ * @param	bdev block device descriptor
+ * @param	bg_bsize logical block size
+ * @param	bdev block device descriptor
+ * @return 	standard error code*/
+int	ext4_block_init(struct	ext4_blockdev *bdev);
+
+
+/**@brief	Binds a bcache to block device.
+ * @param	bdev block device descriptor
+ * @param	bc block cache descriptor
+ * @return 	standard error code*/
+int ext4_block_bind_bcache(struct ext4_blockdev *bdev, struct ext4_bcache *bc);
+
+/**@brief	Close block device
+ * @param	bdev block device descriptor
+ * @return 	standard error code*/
+int ext4_block_fini(struct	ext4_blockdev *bdev);
+
+
+/**@brief	Set logical block size in block device.
+ * @param	bdev block device descriptor
+ * @param	lb_size ligical block size (in bytes)
+ * @return 	standard error code*/
+void ext4_block_set_lb_size(struct	ext4_blockdev *bdev, uint64_t	lb_bsize);
+
+/**@brief	Block get function (through cache).
+ * @param	bdev block device descriptor
+ * @param	b block descriptor
+ * @param	lba logical block address
+ * @return 	standard error code*/
+int ext4_block_get(struct	ext4_blockdev *bdev, struct	ext4_block *b, uint64_t lba);
+
+/**@brief	Block set procedure (through cache).
+ * @param	bdev block device descriptor
+ * @param	b block descriptor
+ * @return 	standard error code*/
+int ext4_block_set(struct	ext4_blockdev *bdev, struct	ext4_block *b);
+
+
+/**@brief	Block read procedure (without cache)
+ * @param	bdev block device descriptor
+ * @param	buf output buffer
+ * @param	lba logical block adderss
+ * @return 	standard error code*/
+int ext4_block_get_direct(struct	ext4_blockdev *bdev, void *buf, uint64_t lba);
+
+
+/**@brief	Block write procedure (without cache)
+ * @param	bdev block device descriptor
+ * @param	buf output buffer
+ * @param	lba logical block address
+ * @return 	standard error code*/
+int ext4_block_set_direct(struct	ext4_blockdev *bdev, const void *buf, uint64_t lba);
+
+/**@brief	Write to block device (by direct adress).
+ * @param	bdev block device descriptor
+ * @param	off byte offset in block device
+ * @param	buf input buffer
+ * @param	len length of the write nuffer
+ * @return 	EOK when sucess*/
+int	ext4_block_writebytes(struct	ext4_blockdev *bdev, uint64_t off, const void *buf, uint32_t len);
+
+
+
+/**@brief	Read freom block device (by direct adress).
+ * @param	bdev block device descriptor
+ * @param	off byte offset in block device
+ * @param	buf input buffer
+ * @param	len length of the write nuffer
+ * @return 	EOK when sucess*/
+int ext4_block_readbytes(struct	ext4_blockdev *bdev, uint64_t off, void *buf, uint32_t len);
+
+/**@brief	Enable/disable delayed cache flush mode.
+ * @param	bdev block device descriptor
+ * @param	on_off
+ * 				!0 	- ENABLE
+ * 				 0	- DISABLE (all delayed cache buffers will be flushed)
+ * @return	standard error code*/
+int ext4_block_delay_cache_flush(struct	ext4_blockdev *bdev, uint8_t on_off);
+
+#endif /* EXT4_BLOCKDEV_H_ */
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/src/lwext4/ext4_config.h
@@ -1,0 +1,99 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ * 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_config.h
+ * @brief Configuration file.
+ */
+
+#ifndef EXT4_CONFIG_H_
+#define EXT4_CONFIG_H_
+
+#ifdef CONFIG_HAVE_OWN_CFG
+#include <config.h>
+#endif
+
+
+/**@brief	Enable directory indexing feature (EXT3 feature)*/
+#ifndef CONFIG_DIR_INDEX_ENABLE
+#define CONFIG_DIR_INDEX_ENABLE				0
+#endif
+
+/**@brief	Enable extents feature (EXT4 feature)*/
+#ifndef CONFIG_EXTENT_ENABLE
+#define CONFIG_EXTENT_ENABLE				0
+#endif
+
+
+
+/**@brief	Include error codes from ext4_errno or sandard library.*/
+#ifndef CONFIG_HAVE_OWN_ERRNO
+#define CONFIG_HAVE_OWN_ERRNO				1
+#endif
+
+
+/**@brief	Debug printf enable (stdout)*/
+#ifndef CONFIG_DEBUG_PRINTF
+#define CONFIG_DEBUG_PRINTF					1
+#endif
+
+/**@brief	Assert printf enable (stdout)*/
+#ifndef CONFIG_DEBUG_ASSERT
+#define CONFIG_DEBUG_ASSERT					1
+#endif
+
+/**@brief	Statistics of block device*/
+#ifndef CONFIG_BLOCK_DEV_ENABLE_STATS
+#define CONFIG_BLOCK_DEV_ENABLE_STATS		1
+#endif
+
+/**@brief	Cache size of block device.*/
+#ifndef CONFIG_BLOCK_DEV_CACHE_SIZE
+#define CONFIG_BLOCK_DEV_CACHE_SIZE			8
+#endif
+
+
+/**@brief	Ilosc urzadzen blokowych.*/
+#ifndef CONFIG_EXT4_BLOCKDEVS_COUNT
+#define CONFIG_EXT4_BLOCKDEVS_COUNT			2
+#endif
+
+/**@brief	Ilosc punktow montowania systemu plikow*/
+#ifndef CONFIG_EXT4_MOUNTPOINTS_COUNT
+#define CONFIG_EXT4_MOUNTPOINTS_COUNT		2
+#endif
+
+
+#endif /* EXT4_CONFIG_H_ */
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/src/lwext4/ext4_debug.c
@@ -1,0 +1,58 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ * 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_debug.c
+ * @brief Debug printf and assert macros.
+ */
+
+#include <ext4_config.h>
+#include <ext4_debug.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+
+static uint32_t		__dbg_mask__;
+
+
+void	ext4_dmask_set(uint32_t m)
+{
+	__dbg_mask__ = m;
+}
+
+uint32_t ext4_dmask_get(void)
+{
+	return __dbg_mask__;
+}
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/src/lwext4/ext4_debug.h
@@ -1,0 +1,116 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ * 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_debug.c
+ * @brief Debug printf and assert macros.
+ */
+
+#ifndef EXT4_DEBUG_H_
+#define EXT4_DEBUG_H_
+
+#include <ext4_config.h>
+#include <ext4_errno.h>
+#include <stdint.h>
+#include <stdio.h>
+
+/**@brief	Debug mask: ext4_blockdev.c*/
+#define EXT4_DEBUG_BLOCKDEV			(1 << 0)
+
+/**@brief	Debug mask: ext4_fs.c*/
+#define EXT4_DEBUG_FS				(1 << 1)
+
+/**@brief	Debug mask: ext4_balloc.c*/
+#define EXT4_DEBUG_BALLOC			(1 << 2)
+
+/**@brief	Debug mask: ext4_bitmap.c*/
+#define EXT4_DEBUG_BITMAP			(1 << 3)
+
+/**@brief	Debug mask: ext4_dir_idx.c*/
+#define EXT4_DEBUG_DIR_IDX			(1 << 4)
+
+/**@brief	Debug mask: ext4_dir.c*/
+#define EXT4_DEBUG_DIR				(1 << 5)
+
+/**@brief	Debug mask: ext4_ialloc.c*/
+#define EXT4_DEBUG_IALLOC			(1 << 6)
+
+/**@brief	Debug mask: ext4_inode.c*/
+#define EXT4_DEBUG_INODE			(1 << 7)
+
+/**@brief	Debug mask: ext4_super.c*/
+#define EXT4_DEBUG_SUPER			(1 << 8)
+
+/**@brief	Debug mask: ext4_bcache.c*/
+#define EXT4_DEBUG_BCACHE			(1 << 9)
+
+
+/**@brief	All debug printf enabled.*/
+#define EXT4_DEBUG_ALL				(0xFFFFFFFF)
+
+/**@brief	Global mask debug settings.
+ * @brief	m new debug mask.*/
+void	 ext4_dmask_set(uint32_t m);
+
+/**@brief	Global debug mask get.
+ * @return	debug mask*/
+uint32_t ext4_dmask_get(void);
+
+
+#if CONFIG_DEBUG_PRINTF
+/**@brief	Debug printf.*/
+#define 	ext4_dprintf(m, ...)	do {					\
+	(m & ext4_dmask_get()) ? printf(__VA_ARGS__) : (void)0;	\
+	fflush(stdout);											\
+}while(0)
+#else
+#define 	ext4_dprintf(m, ...)
+#endif
+
+
+
+#if CONFIG_DEBUG_ASSERT
+#define 	ext4_assert(_v)	do {						\
+	if(!(_v)){											\
+		printf("Assertion failed:\nModule: %s\nFunc: %s\nLine: %d\n", __FILE__, __FUNCTION__, __LINE__);	\
+		fflush(stdout);																					\
+	}																								\
+}while(0)
+#else
+#define 	ext4_assert(_v)
+#endif
+
+
+#endif /* EXT4_DEBUG_H_ */
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/src/lwext4/ext4_dir.c
@@ -1,0 +1,611 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ *
+ *
+ * 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>
+
+uint32_t ext4_dir_entry_ll_get_inode(struct ext4_directory_entry_ll *de)
+{
+	return to_le32(de->inode);
+}
+
+void 	 ext4_dir_entry_ll_set_inode(struct ext4_directory_entry_ll *de,
+		uint32_t inode)
+{
+	de->inode = to_le32(inode);
+}
+
+
+uint16_t ext4_dir_entry_ll_get_entry_length(struct ext4_directory_entry_ll *de)
+{
+	return to_le16(de->entry_length);
+}
+
+void 	 ext4_dir_entry_ll_set_entry_length(struct ext4_directory_entry_ll *de,
+		uint16_t len)
+{
+	de->entry_length = to_le16(len);
+}
+
+
+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->name_length_high) << 8;
+
+	return v;
+}
+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->name_length_high = len >> 8;
+}
+
+
+
+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->inode_type;
+
+	return EXT4_DIRECTORY_FILETYPE_UNKNOWN;
+}
+
+
+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->inode_type = type;
+}
+
+/*****************************************************************************/
+
+
+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;
+}
+
+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 accross 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)
+{
+	uint16_t skip = ext4_dir_entry_ll_get_entry_length(it->current);
+
+	return ext4_dir_iterator_seek(it, it->current_offset + skip);
+}
+
+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 */
+	uint32_t block_size = ext4_sb_get_block_size(sb);
+	ext4_assert(entry_len <= block_size);
+
+	/* 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,
+		struct ext4_inode_ref *child)
+{
+	struct ext4_fs *fs = parent->fs;
+
+#if CONFIG_DIR_INDEX_ENABLE
+	/* Index adding (if allowed) */
+	if ((ext4_sb_check_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;
+
+	uint32_t name_len = strlen(name);
+
+	/* 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 = strlen(name);
+
+	struct ext4_sblock *sb = &parent->fs->sb;
+
+
+#if CONFIG_DIR_INDEX_ENABLE
+	/* Index search */
+	if ((ext4_sb_check_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)
+{
+	/* 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);
+	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 *) 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 *) 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 (dentry->inode != 0) {
+			/* For more effectivity compare firstly only lengths */
+			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;
+}
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/src/lwext4/ext4_dir.h
@@ -1,0 +1,109 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ *
+ *
+ * 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>
+
+uint32_t ext4_dir_entry_ll_get_inode(struct ext4_directory_entry_ll *de);
+
+void 	 ext4_dir_entry_ll_set_inode(struct ext4_directory_entry_ll *de,
+		uint32_t inode);
+
+
+uint16_t ext4_dir_entry_ll_get_entry_length(struct ext4_directory_entry_ll *de);
+void 	 ext4_dir_entry_ll_set_entry_length(struct ext4_directory_entry_ll *de,
+		uint16_t len);
+
+
+uint16_t ext4_dir_entry_ll_get_name_length(struct ext4_sblock *sb,
+		struct ext4_directory_entry_ll *de);
+void 	ext4_dir_entry_ll_set_name_length(struct ext4_sblock *sb,
+		struct ext4_directory_entry_ll *de, uint16_t len);
+
+
+
+uint8_t ext4_dir_entry_ll_get_inode_type(struct ext4_sblock *sb,
+		struct ext4_directory_entry_ll *de);
+void 	ext4_dir_entry_ll_set_inode_type(struct ext4_sblock *sb,
+		struct ext4_directory_entry_ll *de, uint8_t type);
+
+
+int ext4_dir_iterator_init(struct ext4_directory_iterator *it,
+    struct ext4_inode_ref *inode_ref, uint64_t pos);
+
+int ext4_dir_iterator_next(struct ext4_directory_iterator *it);
+int ext4_dir_iterator_fini(struct ext4_directory_iterator *it);
+
+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);
+
+int  ext4_dir_add_entry(struct ext4_inode_ref *parent, const char *name,
+		struct ext4_inode_ref *child);
+
+int ext4_dir_find_entry(struct ext4_directory_search_result *result,
+    struct ext4_inode_ref *parent, const char *name);
+
+int ext4_dir_remove_entry(struct ext4_inode_ref *parent, const char *name);
+
+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);
+
+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);
+
+int ext4_dir_destroy_result(struct ext4_inode_ref *parent, struct ext4_directory_search_result *result);
+
+
+#endif /* EXT4_DIR_H_ */
+
+/**
+ * @}
+ */
+
+
--- /dev/null
+++ b/src/lwext4/ext4_dir_idx.c
@@ -1,0 +1,1010 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ * 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>
+
+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);
+}
+
+
+uint8_t ext4_dir_dx_root_info_get_hash_version(
+		struct ext4_directory_dx_root_info *root_info)
+{
+	return root_info->hash_version;
+}
+
+
+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;
+}
+
+uint8_t ext4_dir_dx_root_info_get_info_length(
+		struct ext4_directory_dx_root_info *root_info)
+{
+	return root_info->info_length;
+}
+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;
+}
+
+uint8_t ext4_dir_dx_root_info_get_indirect_levels(
+		struct ext4_directory_dx_root_info *root_info)
+{
+	return root_info->indirect_levels;
+}
+
+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;
+}
+
+
+
+uint16_t ext4_dir_dx_countlimit_get_limit(
+		struct ext4_directory_dx_countlimit *climit)
+{
+	return to_le16(climit->limit);
+}
+void 	ext4_dir_dx_countlimit_set_limit(
+		struct ext4_directory_dx_countlimit *climit, uint16_t limit)
+{
+	climit->limit = to_le16(limit);
+}
+
+uint16_t ext4_dir_dx_countlimit_get_count(
+		struct ext4_directory_dx_countlimit *climit)
+{
+	return to_le16(climit->count);
+}
+
+void 	ext4_dir_dx_countlimit_set_count(
+		struct ext4_directory_dx_countlimit *climit, uint16_t count)
+{
+	climit->count = to_le16(count);
+}
+
+
+uint32_t ext4_dir_dx_entry_get_hash(
+		struct ext4_directory_dx_entry *entry)
+{
+	return to_le32(entry->hash);
+}
+void ext4_dir_dx_entry_set_hash(
+		struct ext4_directory_dx_entry *entry, uint32_t hash)
+{
+	entry->hash = to_le32(hash);
+}
+
+uint32_t ext4_dir_dx_entry_get_block(
+		struct ext4_directory_dx_entry *entry)
+{
+	return to_le32(entry->block);
+}
+void 	ext4_dir_dx_entry_set_block(
+		struct ext4_directory_dx_entry *entry, uint32_t block)
+{
+	entry->block = to_le32(block);
+}
+/*****************************************************************************/
+
+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);
+}
+
+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;
+}
+
+
+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_directory_dx_dot_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;
+}
+
+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 occured - 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) */
+		ext4_block_set(inode_ref->fs->bdev, &p->block);
+
+
+
+		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 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 */
+		ext4_block_set(fs->bdev, &leaf_block);
+
+		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) {
+		ext4_block_set(fs->bdev, &tmp->block);
+		++tmp;
+	}
+
+	return rc;
+}
+
+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;
+}
+
+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 = (void *) (start_index + count) - (void *) (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;
+}
+
+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);
+
+	void *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;
+	void *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) != 0) {
+			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 *) dentry +
+				ext4_dir_entry_ll_get_entry_length(dentry);
+	}
+
+	/* Sort all entries */
+	qsort(sort_array, idx, sizeof(struct ext4_dx_sort_entry),
+			ext4_dir_dx_entry_comparator);
+
+	/* 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) > (real_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;
+}
+
+/** 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_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;
+
+		uint32_t block_size =
+				ext4_sb_get_block_size(&inode_ref->fs->sb);
+
+		/* 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);
+
+			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_block->position - entries + new_entries;
+			dx_block->entries = new_entries;
+			dx_block->block = new_block;
+		}
+	}
+
+	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;
+
+	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;
+
+	/*
+	 * 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);
+	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;
+}
+
+/**
+ * @}
+ */
+
--- /dev/null
+++ b/src/lwext4/ext4_dir_idx.h
@@ -1,0 +1,103 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ *
+ *
+ * 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>
+
+uint8_t ext4_dir_dx_root_info_get_hash_version(
+		struct ext4_directory_dx_root_info *root_info);
+void 	ext4_dir_dx_root_info_set_hash_version(
+		struct ext4_directory_dx_root_info  *root_info, uint8_t v);
+
+uint8_t ext4_dir_dx_root_info_get_info_length(
+		struct ext4_directory_dx_root_info *root_info);
+void 	ext4_dir_dx_root_info_set_info_length(
+		struct ext4_directory_dx_root_info  *root_info, uint8_t len);
+
+uint8_t ext4_dir_dx_root_info_get_indirect_levels(
+		struct ext4_directory_dx_root_info *root_info);
+void 	ext4_dir_dx_root_info_set_indirect_levels(
+		struct ext4_directory_dx_root_info *root_info, uint8_t lvl);
+
+
+
+uint16_t ext4_dir_dx_countlimit_get_limit(
+		struct ext4_directory_dx_countlimit *climit);
+void 	ext4_dir_dx_countlimit_set_limit(
+		struct ext4_directory_dx_countlimit *climit, uint16_t limit);
+
+uint16_t ext4_dir_dx_countlimit_get_count(
+		struct ext4_directory_dx_countlimit *climit);
+void 	ext4_dir_dx_countlimit_set_count(
+		struct ext4_directory_dx_countlimit *climit, uint16_t count);
+
+
+uint32_t ext4_dir_dx_entry_get_hash(
+		struct ext4_directory_dx_entry *entry);
+void ext4_dir_dx_entry_set_hash(
+		struct ext4_directory_dx_entry *entry, uint32_t hash);
+
+uint32_t ext4_dir_dx_entry_get_block(
+		struct ext4_directory_dx_entry *entry);
+void 	ext4_dir_dx_entry_set_block(
+		struct ext4_directory_dx_entry *entry, uint32_t block);
+
+
+int 	ext4_dir_dx_init(struct ext4_inode_ref *dir);
+
+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);
+
+int 	ext4_dir_dx_add_entry(struct ext4_inode_ref *parent,
+		struct ext4_inode_ref *child, const char *name);
+
+#endif /* EXT4_DIR_IDX_H_ */
+
+/**
+ * @}
+ */
+
--- /dev/null
+++ b/src/lwext4/ext4_errno.h
@@ -1,0 +1,92 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ * 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_errno.h
+ * @brief Error codes.
+ */
+#ifndef EXT4_ERRNO_H_
+#define EXT4_ERRNO_H_
+
+#include <ext4_config.h>
+
+#ifndef CONFIG_HAVE_OWN_ERRNO
+#include <errno.h>
+#else
+#define	EPERM		 1	/* Operation not permitted */
+#define	ENOENT		 2	/* No such file or directory */
+#define	ESRCH		 3	/* No such process */
+#define	EINTR		 4	/* Interrupted system call */
+#define	EIO			 5	/* I/O error */
+#define	ENXIO		 6	/* No such device or address */
+#define	E2BIG		 7	/* Argument list too long */
+#define	ENOEXEC		 8	/* Exec format error */
+#define	EBADF		 9	/* Bad file number */
+#define	ECHILD		10	/* No child processes */
+#define	EAGAIN		11	/* Try again */
+#define	ENOMEM		12	/* Out of memory */
+#define	EACCES		13	/* Permission denied */
+#define	EFAULT		14	/* Bad address */
+#define	ENOTBLK		15	/* Block device required */
+#define	EBUSY		16	/* Device or resource busy */
+#define	EEXIST		17	/* File exists */
+#define	EXDEV		18	/* Cross-device link */
+#define	ENODEV		19	/* No such device */
+#define	ENOTDIR		20	/* Not a directory */
+#define	EISDIR		21	/* Is a directory */
+#define	EINVAL		22	/* Invalid argument */
+#define	ENFILE		23	/* File table overflow */
+#define	EMFILE		24	/* Too many open files */
+#define	ENOTTY		25	/* Not a typewriter */
+#define	ETXTBSY		26	/* Text file busy */
+#define	EFBIG		27	/* File too large */
+#define	ENOSPC		28	/* No space left on device */
+#define	ESPIPE		29	/* Illegal seek */
+#define	EROFS		30	/* Read-only file system */
+#define	EMLINK		31	/* Too many links */
+#define	EPIPE		32	/* Broken pipe */
+#define	EDOM		33	/* Math argument out of domain of func */
+#define	ERANGE		34	/* Math result not representable */
+
+#define	ENOTSUP		95
+#endif
+
+/**@brief	OK return value*/
+#ifndef EOK
+#define EOK			0
+#endif
+
+#endif /* EXT4_ERRNO_H_ */
+
+/**
+ * @}
+ */
+
--- /dev/null
+++ b/src/lwext4/ext4_fs.c
@@ -1,0 +1,1177 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ *
+ *
+ * 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_fs.c
+ * @brief More complex filesystem functions.
+ */
+
+#include <ext4_config.h>
+#include <ext4_types.h>
+#include <ext4_fs.h>
+#include <ext4_errno.h>
+#include <ext4_blockdev.h>
+#include <ext4_super.h>
+#include <ext4_debug.h>
+#include <ext4_block_group.h>
+#include <ext4_balloc.h>
+#include <ext4_bitmap.h>
+#include <ext4_inode.h>
+#include <ext4_ialloc.h>
+#include <string.h>
+
+int ext4_fs_init(struct ext4_fs *fs, struct ext4_blockdev *bdev)
+{
+	int r, i;
+	uint16_t tmp;
+	uint32_t bsize;
+	bool read_only = false;
+
+	ext4_assert(fs && bdev);
+
+	fs->bdev = bdev;
+
+	r = ext4_sb_read(fs->bdev, &fs->sb);
+	if(r != EOK)
+		return r;
+
+	if(!ext4_sb_check(&fs->sb))
+		return ENOTSUP;
+
+	bsize = ext4_sb_get_block_size(&fs->sb);
+	if (bsize > EXT4_MAX_BLOCK_SIZE)
+		return ENXIO;
+
+	r = ext4_fs_check_features(fs, &read_only);
+	if(r != EOK)
+		return r;
+
+	if(read_only)
+		return ENOTSUP;
+
+	/* Compute limits for indirect block levels */
+	uint32_t blocks_id = bsize / sizeof(uint32_t);
+
+	fs->inode_block_limits[0] = EXT4_INODE_DIRECT_BLOCK_COUNT;
+	fs->inode_blocks_per_level[0] = 1;
+
+	for (i = 1; i < 4; i++) {
+		fs->inode_blocks_per_level[i] = fs->inode_blocks_per_level[i - 1] *
+				blocks_id;
+		fs->inode_block_limits[i] = fs->inode_block_limits[i - 1] +
+		    fs->inode_blocks_per_level[i];
+	}
+
+	/*Validate FS*/
+	tmp = ext4_get16(&fs->sb, state);
+	if (tmp & EXT4_SUPERBLOCK_STATE_ERROR_FS) {
+		ext4_dprintf(EXT4_DEBUG_FS, "Filesystem was not cleanly unmounted before \n");
+	}
+
+	/* Mark system as mounted */
+	ext4_set16(&fs->sb, state, EXT4_SUPERBLOCK_STATE_ERROR_FS);
+	r = ext4_sb_write(fs->bdev, &fs->sb);
+	if (r != EOK)
+		return r;
+
+
+	/*Update mount count*/
+	ext4_set16(&fs->sb, mount_count, ext4_get16(&fs->sb, mount_count) + 1);
+
+	return r;
+}
+
+
+int ext4_fs_fini(struct ext4_fs *fs)
+{
+	ext4_assert(fs);
+
+	/*Set superblock state*/
+	ext4_set16(&fs->sb, state, EXT4_SUPERBLOCK_STATE_VALID_FS);
+
+	return ext4_sb_write(fs->bdev, &fs->sb);
+}
+
+int ext4_fs_check_features(struct ext4_fs *fs, bool *read_only)
+{
+	ext4_assert(fs && read_only);
+
+	if(ext4_get32(&fs->sb, rev_level) == 0){
+		*read_only = false;
+		return EOK;
+	}
+
+	/*Check features_incompatible*/
+	if ((ext4_get32(&fs->sb, features_incompatible) & (~EXT4_FEATURE_INCOMPAT_SUPP)) )
+		return ENOTSUP;
+
+
+	/*Check features_read_only*/
+	if ((ext4_get32(&fs->sb, features_read_only) & (~EXT4_FEATURE_RO_COMPAT_SUPP))){
+		*read_only = true;
+		return EOK;
+	}
+
+	*read_only = false;
+
+	return EOK;
+}
+
+uint32_t ext4_fs_baddr2_index_in_group(struct ext4_sblock *s, uint32_t baddr)
+{
+	ext4_assert(baddr);
+	if(ext4_get32(s, first_data_block))
+		baddr--;
+
+	return  baddr % ext4_get32(s, blocks_per_group);
+}
+
+
+
+uint32_t ext4_fs_index_in_group2_baddr(struct ext4_sblock *s, uint32_t index, uint32_t bgid)
+{
+	if(ext4_get32(s, first_data_block))
+		index++;
+
+	return ext4_get32(s, blocks_per_group) * bgid + index;
+}
+
+
+
+
+static int ext4_fs_init_block_bitmap(struct ext4_block_group_ref *bg_ref)
+{
+	uint32_t i;
+	uint32_t bitmap_block_addr = ext4_bg_get_block_bitmap(
+	    bg_ref->block_group, &bg_ref->fs->sb);
+
+	struct ext4_block block_bitmap;
+	int rc = ext4_block_get(bg_ref->fs->bdev, &block_bitmap, bitmap_block_addr);
+	if (rc != EOK)
+		return rc;
+
+
+	memset(block_bitmap.data, 0, ext4_sb_get_block_size(&bg_ref->fs->sb));
+
+	/* Determine first block and first data block in group */
+	uint32_t first_idx = 0;
+
+	uint32_t first_data = ext4_balloc_get_first_data_block_in_group(
+	    &bg_ref->fs->sb, bg_ref);
+	uint32_t first_data_idx = ext4_fs_baddr2_index_in_group(
+	    &bg_ref->fs->sb, first_data);
+
+	/* Set bits from to first block to first data block - 1 to one (allocated) */
+	/*TODO: Optimize it*/
+	for (i = first_idx; i < first_data_idx; ++i)
+		ext4_bmap_bit_set(block_bitmap.data, i);
+
+
+	block_bitmap.dirty = true;
+
+	/* Save bitmap */
+	return ext4_block_set(bg_ref->fs->bdev, &block_bitmap);
+}
+
+static int ext4_fs_init_inode_bitmap(struct ext4_block_group_ref *bg_ref)
+{
+	/* Load bitmap */
+	uint32_t bitmap_block_addr = ext4_bg_get_inode_bitmap(
+	    bg_ref->block_group, &bg_ref->fs->sb);
+
+	struct ext4_block block_bitmap;
+	int rc = ext4_block_get(bg_ref->fs->bdev, &block_bitmap, bitmap_block_addr);
+	if (rc != EOK)
+		return rc;
+
+	/* Initialize all bitmap bits to zero */
+	uint32_t block_size = ext4_sb_get_block_size(&bg_ref->fs->sb);
+	uint32_t inodes_per_group = ext4_get32(&bg_ref->fs->sb, inodes_per_group);
+
+	memset(block_bitmap.data, 0, (inodes_per_group + 7) / 8);
+
+	uint32_t start_bit = inodes_per_group;
+	uint32_t end_bit = block_size * 8;
+
+	uint32_t i;
+	for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++)
+		ext4_bmap_bit_set(block_bitmap.data, i);
+
+	if (i < end_bit)
+		memset(block_bitmap.data + (i >> 3), 0xff, (end_bit - i) >> 3);
+
+	block_bitmap.dirty = true;
+
+	/* Save bitmap */
+	return ext4_block_set(bg_ref->fs->bdev, &block_bitmap);
+}
+
+static int ext4_fs_init_inode_table(struct ext4_block_group_ref *bg_ref)
+{
+	struct ext4_sblock *sb = &bg_ref->fs->sb;
+
+	uint32_t inode_size 	  = ext4_get32(sb, inode_size);
+	uint32_t block_size 	  = ext4_sb_get_block_size(sb);
+	uint32_t inodes_per_block = block_size / inode_size;
+	uint32_t inodes_in_group  = ext4_inodes_in_group_cnt(sb, bg_ref->index);
+	uint32_t table_blocks = inodes_in_group / inodes_per_block;
+	uint32_t fblock;
+
+	if (inodes_in_group % inodes_per_block)
+		table_blocks++;
+
+	/* Compute initialization bounds */
+	uint32_t first_block = ext4_bg_get_inode_table_first_block(
+	    bg_ref->block_group, sb);
+
+	uint32_t last_block = first_block + table_blocks - 1;
+
+	/* Initialization of all itable blocks */
+	for (fblock = first_block; fblock <= last_block; ++fblock) {
+
+		struct ext4_block block;
+		int rc = ext4_block_get(bg_ref->fs->bdev, &block, fblock);
+		if (rc != EOK)
+			return rc;
+
+		memset(block.data, 0, block_size);
+		block.dirty = true;
+
+		ext4_block_set(bg_ref->fs->bdev, &block);
+		if (rc != EOK)
+			return rc;
+	}
+
+	return EOK;
+}
+
+
+int ext4_fs_get_block_group_ref(struct ext4_fs *fs, uint32_t bgid, struct ext4_block_group_ref *ref)
+{
+	/* Compute number of descriptors, that fits in one data block */
+	uint32_t dsc_per_block = ext4_sb_get_block_size(&fs->sb) /
+			ext4_sb_get_desc_size(&fs->sb);
+
+	/* Block group descriptor table starts at the next block after superblock */
+	uint64_t block_id = ext4_get32(&fs->sb, first_data_block) + 1;
+
+	/* Find the block containing the descriptor we are looking for */
+	block_id += bgid / dsc_per_block;
+	uint32_t offset = (bgid % dsc_per_block) *
+			ext4_sb_get_desc_size(&fs->sb);
+
+
+	int rc = ext4_block_get(fs->bdev, &ref->block, block_id);
+	if (rc != EOK)
+		return rc;
+
+	ref->block_group = (void *)(ref->block.data + offset);
+	ref->fs = fs;
+	ref->index = bgid;
+	ref->dirty = false;
+
+	if (ext4_bg_has_flag(ref->block_group,
+	    EXT4_BLOCK_GROUP_BLOCK_UNINIT)) {
+		rc = ext4_fs_init_block_bitmap(ref);
+		if (rc != EOK) {
+			ext4_block_set(fs->bdev, &ref->block);
+			return rc;
+		}
+		ext4_bg_clear_flag(ref->block_group,
+		    EXT4_BLOCK_GROUP_BLOCK_UNINIT);
+
+		ref->dirty = true;
+	}
+
+	if (ext4_bg_has_flag(ref->block_group,
+	    EXT4_BLOCK_GROUP_INODE_UNINIT)) {
+		rc = ext4_fs_init_inode_bitmap(ref);
+		if (rc != EOK) {
+			ext4_block_set(ref->fs->bdev, &ref->block);
+			return rc;
+		}
+
+		ext4_bg_clear_flag(ref->block_group,
+		    EXT4_BLOCK_GROUP_INODE_UNINIT);
+
+		if (!ext4_bg_has_flag(ref->block_group,
+		    EXT4_BLOCK_GROUP_ITABLE_ZEROED)) {
+			rc = ext4_fs_init_inode_table(ref);
+			if (rc != EOK){
+				ext4_block_set(fs->bdev, &ref->block);
+				return rc;
+			}
+
+			ext4_bg_set_flag(ref->block_group,
+			    EXT4_BLOCK_GROUP_ITABLE_ZEROED);
+		}
+
+		ref->dirty = true;
+	}
+
+	return EOK;
+}
+
+static uint16_t ext4_fs_bg_checksum(struct ext4_sblock *sb, uint32_t bgid, struct ext4_bgroup *bg)
+{
+	/* If checksum not supported, 0 will be returned */
+	uint16_t crc = 0;
+
+	/* Compute the checksum only if the filesystem supports it */
+	if (ext4_sb_check_read_only(sb,
+	    EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+		void *base = bg;
+		void *checksum = &bg->checksum;
+
+		uint32_t offset = (uint32_t) (checksum - base);
+
+		/* Convert block group index to little endian */
+		uint32_t le_group = to_le32(bgid);
+
+		/* Initialization */
+		crc = ext4_bg_crc16(~0, sb->uuid, sizeof(sb->uuid));
+
+		/* Include index of block group */
+		crc = ext4_bg_crc16(crc, (uint8_t *) &le_group, sizeof(le_group));
+
+		/* Compute crc from the first part (stop before checksum field) */
+		crc = ext4_bg_crc16(crc, (uint8_t *) bg, offset);
+
+		/* Skip checksum */
+		offset += sizeof(bg->checksum);
+
+		/* Checksum of the rest of block group descriptor */
+		if ((ext4_sb_check_feature_incompatible(sb,
+		    EXT4_FEATURE_INCOMPAT_64BIT)) &&
+		    (offset < ext4_sb_get_desc_size(sb)))
+
+			crc = ext4_bg_crc16(crc, ((uint8_t *) bg) + offset,
+					ext4_sb_get_desc_size(sb) - offset);
+	}
+	return crc;
+}
+
+int ext4_fs_put_block_group_ref(struct ext4_block_group_ref *ref)
+{
+	/* Check if reference modified */
+	if (ref->dirty) {
+		/* Compute new checksum of block group */
+		uint16_t checksum =
+		    ext4_fs_bg_checksum(&ref->fs->sb, ref->index,
+		    ref->block_group);
+
+		ref->block_group->checksum = to_le16(checksum);
+
+		/* Mark block dirty for writing changes to physical device */
+		ref->block.dirty = true;
+	}
+
+	/* Put back block, that contains block group descriptor */
+	return ext4_block_set(ref->fs->bdev, &ref->block);
+}
+
+int ext4_fs_get_inode_ref(struct ext4_fs *fs, uint32_t index,  struct ext4_inode_ref *ref)
+{
+	/* Compute number of i-nodes, that fits in one data block */
+	uint32_t inodes_per_group = ext4_get32(&fs->sb, inodes_per_group);
+
+	/*
+	 * Inode numbers are 1-based, but it is simpler to work with 0-based
+	 * when computing indices
+	 */
+	index -= 1;
+	uint32_t block_group = index / inodes_per_group;
+	uint32_t offset_in_group = index % inodes_per_group;
+
+	/* Load block group, where i-node is located */
+	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 block address, where i-node table is located */
+	uint32_t inode_table_start =
+	    ext4_bg_get_inode_table_first_block(bg_ref.block_group,
+	    &fs->sb);
+
+	/* Put back block group reference (not needed more) */
+	rc = ext4_fs_put_block_group_ref(&bg_ref);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Compute position of i-node in the block group */
+	uint16_t inode_size = ext4_get16(&fs->sb, inode_size);
+	uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
+	uint32_t byte_offset_in_group = offset_in_group * inode_size;
+
+	/* Compute block address */
+	uint64_t block_id = inode_table_start + (byte_offset_in_group / block_size);
+
+
+	rc = ext4_block_get(fs->bdev, &ref->block, block_id);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Compute position of i-node in the data block */
+	uint32_t offset_in_block = byte_offset_in_group % block_size;
+	ref->inode = (struct ext4_inode *)(ref->block.data + offset_in_block);
+
+	/* We need to store the original value of index in the reference */
+	ref->index = index + 1;
+	ref->fs = fs;
+	ref->dirty = false;
+
+	return EOK;
+}
+
+int ext4_fs_put_inode_ref(struct ext4_inode_ref *ref)
+{
+	/* Check if reference modified */
+	if (ref->dirty) {
+		/* Mark block dirty for writing changes to physical device */
+		ref->block.dirty = true;
+	}
+
+	/* Put back block, that contains i-node */
+	return  ext4_block_set(ref->fs->bdev, &ref->block);
+}
+
+int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref, bool is_directory)
+{
+	/* Check if newly allocated i-node will be a directory */
+	uint32_t i;
+	bool is_dir;
+
+	is_dir = is_directory;
+
+	/* Allocate inode by allocation algorithm */
+	uint32_t index;
+	int rc = ext4_ialloc_alloc_inode(fs, &index, is_dir);
+	if (rc != EOK)
+		return rc;
+
+	/* Load i-node from on-disk i-node table */
+	rc = ext4_fs_get_inode_ref(fs, index, inode_ref);
+	if (rc != EOK) {
+		ext4_ialloc_free_inode(fs, index, is_dir);
+		return rc;
+	}
+
+	/* Initialize i-node */
+	struct ext4_inode *inode = inode_ref->inode;
+
+	uint16_t mode;
+	if (is_dir) {
+		/*
+		 * Default directory permissions to be compatible with other systems
+		 * 0777 (octal) == rwxrwxrwx
+		 */
+
+		mode = 0777;
+		mode |= EXT4_INODE_MODE_DIRECTORY;
+		ext4_inode_set_mode(&fs->sb, inode, mode);
+		ext4_inode_set_links_count(inode, 1);  /* '.' entry */
+
+	} else {
+		/*
+		 * Default file permissions to be compatible with other systems
+		 * 0666 (octal) == rw-rw-rw-
+		 */
+
+		mode = 0666;
+		mode |= EXT4_INODE_MODE_FILE;
+		ext4_inode_set_mode(&fs->sb, inode, mode);
+		ext4_inode_set_links_count(inode, 0);
+	}
+
+	ext4_inode_set_uid(inode, 0);
+	ext4_inode_set_gid(inode, 0);
+	ext4_inode_set_size(inode, 0);
+	ext4_inode_set_access_time(inode, 		0);
+	ext4_inode_set_change_inode_time(inode, 0);
+	ext4_inode_set_modification_time(inode, 0);
+	ext4_inode_set_deletion_time(inode, 	0);
+	ext4_inode_set_blocks_count(&fs->sb, inode, 0);
+	ext4_inode_set_flags(inode, 0);
+	ext4_inode_set_generation(inode, 0);
+
+	/* Reset blocks array */
+	for (i = 0; i < EXT4_INODE_BLOCKS; i++)
+		inode->blocks[i] = 0;
+
+#if 0
+	/* Initialize extents if needed */
+	if (ext4_sb_check_feature_incompatible(
+	    &fs->sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
+		ext4_inode_set_flag(inode, EXT4_INODE_FLAG_EXTENTS);
+
+
+		/* Initialize extent root header */
+		ext4_extent_header_t *header = ext4_inode_get_extent_header(inode);
+		ext4_extent_header_set_depth(header, 0);
+		ext4_extent_header_set_entries_count(header, 0);
+		ext4_extent_header_set_generation(header, 0);
+		ext4_extent_header_set_magic(header, EXT4_EXTENT_MAGIC);
+
+		uint16_t max_entries = (EXT4_INODE_BLOCKS * sizeof(uint32_t) -
+		    sizeof(ext4_extent_header_t)) / sizeof(ext4_extent_t);
+
+		ext4_extent_header_set_max_entries_count(header, max_entries);
+	}
+#endif
+
+	inode_ref->dirty = true;
+
+	return EOK;
+}
+
+int ext4_fs_free_inode(struct ext4_inode_ref *inode_ref)
+{
+	struct ext4_fs *fs = inode_ref->fs;
+	uint32_t offset;
+	uint32_t suboffset;
+	/* For extents must be data block destroyed by other way */
+	if ((ext4_sb_check_feature_incompatible(&fs->sb,
+	    EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
+	    (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
+		/* Data structures are released during truncate operation... */
+		goto finish;
+	}
+
+	/* Release all indirect (no data) blocks */
+
+	/* 1) Single indirect */
+	uint32_t fblock = ext4_inode_get_indirect_block(inode_ref->inode, 0);
+	if (fblock != 0) {
+		int rc = ext4_balloc_free_block(inode_ref, fblock);
+		if (rc != EOK)
+			return rc;
+
+		ext4_inode_set_indirect_block(inode_ref->inode, 0, 0);
+	}
+
+	uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
+	uint32_t count = block_size / sizeof(uint32_t);
+
+	struct	ext4_block  block;
+
+	/* 2) Double indirect */
+	fblock = ext4_inode_get_indirect_block(inode_ref->inode, 1);
+	if (fblock != 0) {
+		int rc = ext4_block_get(fs->bdev, &block, fblock);
+		if (rc != EOK)
+			return rc;
+
+		uint32_t ind_block;
+		for (offset = 0; offset < count; ++offset) {
+			ind_block = to_le32(((uint32_t *) block.data)[offset]);
+
+			if (ind_block != 0) {
+				rc = ext4_balloc_free_block(inode_ref, ind_block);
+				if (rc != EOK) {
+					ext4_block_set(fs->bdev, &block);
+					return rc;
+				}
+			}
+		}
+
+		ext4_block_set(fs->bdev, &block);
+		rc = ext4_balloc_free_block(inode_ref, fblock);
+		if (rc != EOK)
+			return rc;
+
+		ext4_inode_set_indirect_block(inode_ref->inode, 1, 0);
+	}
+
+	/* 3) Tripple indirect */
+	struct	ext4_block  subblock;
+	fblock = ext4_inode_get_indirect_block(inode_ref->inode, 2);
+	if (fblock != 0) {
+		int rc = ext4_block_get(fs->bdev, &block, fblock);
+		if (rc != EOK)
+			return rc;
+
+		uint32_t ind_block;
+		for ( offset = 0; offset < count; ++offset) {
+			ind_block = to_le32(((uint32_t *) block.data)[offset]);
+
+			if (ind_block != 0) {
+				rc = ext4_block_get(fs->bdev, &subblock, ind_block);
+				if (rc != EOK) {
+					ext4_block_set(fs->bdev, &block);
+					return rc;
+				}
+
+				uint32_t ind_subblock;
+				for (suboffset = 0; suboffset < count;
+				    ++suboffset) {
+					ind_subblock = to_le32(((uint32_t *)
+					    subblock.data)[suboffset]);
+
+					if (ind_subblock != 0) {
+						rc = ext4_balloc_free_block(inode_ref, ind_subblock);
+						if (rc != EOK) {
+							ext4_block_set(fs->bdev, &subblock);
+							ext4_block_set(fs->bdev, &block);
+							return rc;
+						}
+					}
+				}
+
+				ext4_block_set(fs->bdev, &subblock);
+
+
+				rc = ext4_balloc_free_block(inode_ref, ind_block);
+				if (rc != EOK) {
+					ext4_block_set(fs->bdev, &block);
+					return rc;
+				}
+			}
+		}
+
+		ext4_block_set(fs->bdev, &block);
+		rc = ext4_balloc_free_block(inode_ref, fblock);
+		if (rc != EOK)
+			return rc;
+
+		ext4_inode_set_indirect_block(inode_ref->inode, 2, 0);
+	}
+
+finish:
+	/* Mark inode dirty for writing to the physical device */
+	inode_ref->dirty = true;
+
+	/* Free block with extended attributes if present */
+	uint32_t xattr_block = ext4_inode_get_file_acl(
+	    inode_ref->inode, &fs->sb);
+	if (xattr_block) {
+		int rc = ext4_balloc_free_block(inode_ref, xattr_block);
+		if (rc != EOK)
+			return rc;
+
+		ext4_inode_set_file_acl(inode_ref->inode, &fs->sb, 0);
+	}
+
+	/* Free inode by allocator */
+	int rc;
+	if (ext4_inode_is_type(&fs->sb, inode_ref->inode,
+	    EXT4_INODE_MODE_DIRECTORY))
+		rc = ext4_ialloc_free_inode(fs, inode_ref->index, true);
+	else
+		rc = ext4_ialloc_free_inode(fs, inode_ref->index, false);
+
+	return rc;
+}
+
+int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref,
+    uint64_t new_size)
+{
+	struct ext4_sblock *sb = &inode_ref->fs->sb;
+	uint32_t i;
+
+	/* Check flags, if i-node can be truncated */
+	if (!ext4_inode_can_truncate(sb, inode_ref->inode))
+		return EINVAL;
+
+	/* If sizes are equal, nothing has to be done. */
+	uint64_t old_size = ext4_inode_get_size(sb, inode_ref->inode);
+	if (old_size == new_size)
+		return EOK;
+
+	/* It's not suppported to make the larger file by truncate operation */
+	if (old_size < new_size)
+		return EINVAL;
+
+	/* Compute how many blocks will be released */
+	uint64_t size_diff = old_size - new_size;
+	uint32_t block_size  = ext4_sb_get_block_size(sb);
+	uint32_t diff_blocks_count = size_diff / block_size;
+	if (size_diff % block_size != 0)
+		diff_blocks_count++;
+
+	uint32_t old_blocks_count = old_size / block_size;
+	if (old_size % block_size != 0)
+		old_blocks_count++;
+
+	if ((ext4_sb_check_feature_incompatible(sb,
+	    EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
+	    (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
+#if 0
+		/* Extents require special operation */
+		int rc = ext4_extent_release_blocks_from(inode_ref,
+		    old_blocks_count - diff_blocks_count);
+		if (rc != EOK)
+			return rc;
+#endif
+	} else {
+		/* Release data blocks from the end of file */
+
+		/* Starting from 1 because of logical blocks are numbered from 0 */
+		for (i = 1; i <= diff_blocks_count; ++i) {
+			int rc = ext4_fs_release_inode_block(inode_ref,
+			    old_blocks_count - i);
+			if (rc != EOK)
+				return rc;
+		}
+	}
+
+	/* Update i-node */
+	ext4_inode_set_size(inode_ref->inode, new_size);
+	inode_ref->dirty = true;
+
+	return EOK;
+}
+
+int ext4_fs_get_inode_data_block_index(struct ext4_inode_ref *inode_ref,
+    uint64_t iblock, uint32_t *fblock)
+{
+	struct ext4_fs *fs = inode_ref->fs;
+
+	/* For empty file is situation simple */
+	if (ext4_inode_get_size(&fs->sb, inode_ref->inode) == 0) {
+		*fblock = 0;
+		return EOK;
+	}
+
+	uint32_t current_block;
+
+	/* Handle i-node using extents */
+	if ((ext4_sb_check_feature_incompatible(&fs->sb,
+	    EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
+	    (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
+
+#if 0
+		int rc = ext4_extent_find_block(inode_ref, iblock, &current_block);
+		if (rc != EOK)
+			return rc;
+
+		*fblock = current_block;
+		return EOK;
+#endif
+	}
+
+	struct ext4_inode *inode = inode_ref->inode;
+
+	/* Direct block are read directly from array in i-node structure */
+	if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
+		current_block = ext4_inode_get_direct_block(inode, (uint32_t) iblock);
+		*fblock = current_block;
+		return EOK;
+	}
+
+	/* Determine indirection level of the target block */
+	unsigned int level = 0;
+	unsigned int i;
+	for (i = 1; i < 4; i++) {
+		if (iblock < fs->inode_block_limits[i]) {
+			level = i;
+			break;
+		}
+	}
+
+	if (level == 0)
+		return EIO;
+
+	/* Compute offsets for the topmost level */
+	uint64_t block_offset_in_level =
+	    iblock - fs->inode_block_limits[level - 1];
+	current_block = ext4_inode_get_indirect_block(inode, level - 1);
+	uint32_t offset_in_block =
+	    block_offset_in_level / fs->inode_blocks_per_level[level - 1];
+
+	/* Sparse file */
+	if (current_block == 0) {
+		*fblock = 0;
+		return EOK;
+	}
+
+	struct	ext4_block block;
+
+	/*
+	 * Navigate through other levels, until we find the block number
+	 * or find null reference meaning we are dealing with sparse file
+	 */
+	while (level > 0) {
+		/* Load indirect block */
+		int rc = ext4_block_get(fs->bdev, &block, current_block);
+		if (rc != EOK)
+			return rc;
+
+		/* Read block address from indirect block */
+		current_block =
+		    to_le32(((uint32_t *) block.data)[offset_in_block]);
+
+		/* Put back indirect block untouched */
+		rc = ext4_block_set(fs->bdev, &block);
+		if (rc != EOK)
+			return rc;
+
+		/* Check for sparse file */
+		if (current_block == 0) {
+			*fblock = 0;
+			return EOK;
+		}
+
+		/* Jump to the next level */
+		level--;
+
+		/* Termination condition - we have address of data block loaded */
+		if (level == 0)
+			break;
+
+		/* Visit the next level */
+		block_offset_in_level %= fs->inode_blocks_per_level[level];
+		offset_in_block =
+		    block_offset_in_level / fs->inode_blocks_per_level[level - 1];
+	}
+
+	*fblock = current_block;
+
+	return EOK;
+}
+
+int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref,
+    uint64_t iblock, uint32_t fblock)
+{
+	struct ext4_fs *fs = inode_ref->fs;
+
+	/* Handle inode using extents */
+	if ((ext4_sb_check_feature_incompatible(&fs->sb,
+	    EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
+	    (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
+		/* Not reachable */
+		return ENOTSUP;
+	}
+
+	/* Handle simple case when we are dealing with direct reference */
+	if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
+		ext4_inode_set_direct_block(inode_ref->inode, (uint32_t) iblock, fblock);
+		inode_ref->dirty = true;
+
+		return EOK;
+	}
+
+	/* Determine the indirection level needed to get the desired block */
+	unsigned int level = 0;
+	unsigned int i;
+	for (i = 1; i < 4; i++) {
+		if (iblock < fs->inode_block_limits[i]) {
+			level = i;
+			break;
+		}
+	}
+
+	if (level == 0)
+		return EIO;
+
+	uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
+
+	/* Compute offsets for the topmost level */
+	uint64_t block_offset_in_level =
+	    iblock - fs->inode_block_limits[level - 1];
+	uint32_t current_block =
+	    ext4_inode_get_indirect_block(inode_ref->inode, level - 1);
+	uint32_t offset_in_block =
+	    block_offset_in_level / fs->inode_blocks_per_level[level - 1];
+
+	uint32_t new_block_addr;
+
+	struct	ext4_block block;
+	struct	ext4_block new_block;
+
+	/* Is needed to allocate indirect block on the i-node level */
+	if (current_block == 0) {
+		/* Allocate new indirect block */
+		int rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr);
+		if (rc != EOK)
+			return rc;
+
+		/* Update i-node */
+		ext4_inode_set_indirect_block(inode_ref->inode, level - 1,
+		    new_block_addr);
+		inode_ref->dirty = true;
+
+		/* Load newly allocated block */
+		rc = ext4_block_get(fs->bdev, &new_block, new_block_addr);
+		if (rc != EOK) {
+			ext4_balloc_free_block(inode_ref, new_block_addr);
+			return rc;
+		}
+
+		/* Initialize new block */
+		memset(new_block.data, 0, block_size);
+		new_block.dirty = true;
+
+		/* Put back the allocated block */
+		rc = ext4_block_set(fs->bdev, &new_block);
+		if (rc != EOK)
+			return rc;
+
+		current_block = new_block_addr;
+	}
+
+	/*
+	 * Navigate through other levels, until we find the block number
+	 * or find null reference meaning we are dealing with sparse file
+	 */
+	while (level > 0) {
+		int rc = ext4_block_get(fs->bdev, &block, current_block);
+		if (rc != EOK)
+			return rc;
+
+		current_block =
+		    to_le32(((uint32_t *) block.data)[offset_in_block]);
+
+		if ((level > 1) && (current_block == 0)) {
+			/* Allocate new block */
+			rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr);
+			if (rc != EOK) {
+				ext4_block_set(fs->bdev, &block);
+				return rc;
+			}
+
+			/* Load newly allocated block */
+			rc = ext4_block_get(fs->bdev, &new_block, new_block_addr);
+
+			if (rc != EOK) {
+				ext4_block_set(fs->bdev, &block);
+				return rc;
+			}
+
+			/* Initialize allocated block */
+			memset(new_block.data, 0, block_size);
+			new_block.dirty = true;
+
+			rc = ext4_block_set(fs->bdev, &new_block);
+			if (rc != EOK) {
+				ext4_block_set(fs->bdev, &block);
+				return rc;
+			}
+
+			/* Write block address to the parent */
+			((uint32_t *) block.data)[offset_in_block] =
+			    to_le32(new_block_addr);
+			block.dirty = true;
+			current_block = new_block_addr;
+		}
+
+		/* Will be finished, write the fblock address */
+		if (level == 1) {
+			((uint32_t *) block.data)[offset_in_block] =
+					to_le32(fblock);
+			block.dirty = true;
+		}
+
+		rc = ext4_block_set(fs->bdev, &block);
+		if (rc != EOK)
+			return rc;
+
+		level--;
+
+		/*
+		 * If we are on the last level, break here as
+		 * there is no next level to visit
+		 */
+		if (level == 0)
+			break;
+
+		/* Visit the next level */
+		block_offset_in_level %= fs->inode_blocks_per_level[level];
+		offset_in_block =
+		    block_offset_in_level / fs->inode_blocks_per_level[level - 1];
+	}
+
+	return EOK;
+}
+
+int ext4_fs_release_inode_block(struct ext4_inode_ref *inode_ref,
+    uint32_t iblock)
+{
+	uint32_t fblock;
+
+	struct ext4_fs *fs = inode_ref->fs;
+
+	/* Extents are handled otherwise = there is not support in this function */
+	ext4_assert(!(ext4_sb_check_feature_incompatible(&fs->sb,
+	    EXT4_FEATURE_INCOMPAT_EXTENTS) &&
+	    (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))));
+
+	struct ext4_inode *inode = inode_ref->inode;
+
+	/* Handle simple case when we are dealing with direct reference */
+	if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
+		fblock = ext4_inode_get_direct_block(inode, iblock);
+
+		/* Sparse file */
+		if (fblock == 0)
+			return EOK;
+
+		ext4_inode_set_direct_block(inode, iblock, 0);
+		return ext4_balloc_free_block(inode_ref, fblock);
+	}
+
+	/* Determine the indirection level needed to get the desired block */
+	unsigned int level = 0;
+	unsigned int i;
+	for (i = 1; i < 4; i++) {
+		if (iblock < fs->inode_block_limits[i]) {
+			level = i;
+			break;
+		}
+	}
+
+	if (level == 0)
+		return EIO;
+
+	/* Compute offsets for the topmost level */
+	uint64_t block_offset_in_level =
+	    iblock - fs->inode_block_limits[level - 1];
+	uint32_t current_block =
+	    ext4_inode_get_indirect_block(inode, level - 1);
+	uint32_t offset_in_block =
+	    block_offset_in_level / fs->inode_blocks_per_level[level - 1];
+
+	/*
+	 * Navigate through other levels, until we find the block number
+	 * or find null reference meaning we are dealing with sparse file
+	 */
+	struct	ext4_block block;
+
+	while (level > 0) {
+
+		/* Sparse check */
+		if (current_block == 0)
+			return EOK;
+
+		int rc = ext4_block_get(fs->bdev, &block, current_block);
+		if (rc != EOK)
+			return rc;
+
+		current_block =
+		    to_le32(((uint32_t *) block.data)[offset_in_block]);
+
+		/* Set zero if physical data block address found */
+		if (level == 1) {
+			((uint32_t *) block.data)[offset_in_block] =
+					to_le32(0);
+			block.dirty = true;
+		}
+
+		rc = ext4_block_set(fs->bdev, &block);
+		if (rc != EOK)
+			return rc;
+
+		level--;
+
+		/*
+		 * If we are on the last level, break here as
+		 * there is no next level to visit
+		 */
+		if (level == 0)
+			break;
+
+		/* Visit the next level */
+		block_offset_in_level %= fs->inode_blocks_per_level[level];
+		offset_in_block =
+		    block_offset_in_level / fs->inode_blocks_per_level[level - 1];
+	}
+
+	fblock = current_block;
+	if (fblock == 0)
+		return EOK;
+
+	/* Physical block is not referenced, it can be released */
+	return ext4_balloc_free_block(inode_ref, fblock);
+}
+
+
+int ext4_fs_append_inode_block(struct ext4_inode_ref *inode_ref,
+    uint32_t *fblock, uint32_t *iblock)
+{
+	/* Handle extents separately */
+	if ((ext4_sb_check_feature_incompatible(&inode_ref->fs->sb,
+	    EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
+	    (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))){
+
+#if 0
+		return ext4_extent_append_block(inode_ref, iblock, fblock, true);
+#endif
+	}
+
+	struct ext4_sblock *sb = &inode_ref->fs->sb;
+
+	/* Compute next block index and allocate data block */
+	uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
+	uint32_t block_size = ext4_sb_get_block_size(sb);
+
+	/* Align size i-node size */
+	if ((inode_size % block_size) != 0)
+		inode_size += block_size - (inode_size % block_size);
+
+	/* Logical blocks are numbered from 0 */
+	uint32_t new_block_idx = inode_size / block_size;
+
+	/* Allocate new physical block */
+	uint32_t phys_block;
+	int rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
+	if (rc != EOK)
+		return rc;
+
+	/* Add physical block address to the i-node */
+	rc = ext4_fs_set_inode_data_block_index(inode_ref,
+	    new_block_idx, phys_block);
+	if (rc != EOK) {
+		ext4_balloc_free_block(inode_ref, phys_block);
+		return rc;
+	}
+
+	/* Update i-node */
+	ext4_inode_set_size(inode_ref->inode, inode_size + block_size);
+	inode_ref->dirty = true;
+
+	*fblock = phys_block;
+	*iblock = new_block_idx;
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
+
--- /dev/null
+++ b/src/lwext4/ext4_fs.h
@@ -1,0 +1,91 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ *
+ *
+ * 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_fs.c
+ * @brief More complex filesystem functions.
+ */
+
+#ifndef EXT4_FS_H_
+#define EXT4_FS_H_
+
+#include <ext4_config.h>
+#include <ext4_types.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+
+int ext4_fs_init(struct ext4_fs *fs, struct ext4_blockdev *bdev);
+int ext4_fs_fini(struct ext4_fs *fs);
+
+int ext4_fs_check_features(struct ext4_fs *fs, bool *read_only);
+
+
+uint32_t ext4_fs_baddr2_index_in_group(struct ext4_sblock *s, uint32_t baddr);
+uint32_t ext4_fs_index_in_group2_baddr(struct ext4_sblock *s, uint32_t index, uint32_t bgid);
+
+
+int ext4_fs_get_block_group_ref(struct ext4_fs *fs, uint32_t bgid, struct ext4_block_group_ref *ref);
+int ext4_fs_put_block_group_ref(struct ext4_block_group_ref *ref);
+
+
+int ext4_fs_get_inode_ref(struct ext4_fs *fs, uint32_t index,  struct ext4_inode_ref *ref);
+int ext4_fs_put_inode_ref(struct ext4_inode_ref *ref);
+
+
+int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref, bool is_directory);
+int ext4_fs_free_inode(struct ext4_inode_ref *inode_ref);
+
+int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref,
+    uint64_t new_size);
+
+int ext4_fs_get_inode_data_block_index(struct ext4_inode_ref *inode_ref,
+    uint64_t iblock, uint32_t *fblock);
+
+int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref,
+    uint64_t iblock, uint32_t fblock);
+
+int ext4_fs_release_inode_block(struct ext4_inode_ref *inode_ref,
+    uint32_t iblock);
+
+int ext4_fs_append_inode_block(struct ext4_inode_ref *inode_ref,
+    uint32_t *fblock, uint32_t *iblock);
+
+#endif /* EXT4_FS_H_ */
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/src/lwext4/ext4_hash.c
@@ -1,0 +1,320 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ *
+ * FreeBSD:
+ * Copyright (c) 2010, 2013 Zheng Liu <[email protected]>
+ * 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 <string.h>
+#include <ext4_errno.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, int 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 > 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[0];
+		minor = hash[1];
+		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;
+}
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/src/lwext4/ext4_hash.h
@@ -1,0 +1,61 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ * 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_ */
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/src/lwext4/ext4_ialloc.c
@@ -1,0 +1,247 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ *
+ *
+ * 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>
+
+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;
+}
+
+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);
+}
+
+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 = 0;
+	uint32_t bg_count = ext4_block_group_cnt(sb);
+	uint32_t sb_free_inodes = ext4_get32(sb, free_inodes_count);
+	uint32_t avg_free_inodes = sb_free_inodes / bg_count;
+
+	/* Try to find free i-node in all block groups */
+	while (bgid < bg_count) {
+		/* 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_blocks = ext4_bg_get_free_blocks_count(bg, sb);
+		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 >= avg_free_inodes) && (free_blocks > 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)
+				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) {
+				ext4_block_set(fs->bdev, &bitmap_block);
+				ext4_fs_put_block_group_ref(&bg_ref);
+				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)
+				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);
+
+			return EOK;
+		}
+
+		/* Block group not modified, put it and jump to the next block group */
+		ext4_fs_put_block_group_ref(&bg_ref);
+		++bgid;
+	}
+
+	return ENOSPC;
+}
+
+/**
+ * @}
+ */
+
--- /dev/null
+++ b/src/lwext4/ext4_ialloc.h
@@ -1,0 +1,63 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ *
+ *
+ * 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>
+
+
+int ext4_ialloc_free_inode(struct ext4_fs *fs, uint32_t index, bool is_dir);
+int ext4_ialloc_alloc_inode(struct ext4_fs *fs, uint32_t *index, bool is_dir);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* EXT4_IALLOC_H_ */
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/src/lwext4/ext4_inode.c
@@ -1,0 +1,338 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ *
+ *
+ * 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>
+
+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_check_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);
+		} else
+			return count;
+	}
+
+	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_check_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;
+}
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/src/lwext4/ext4_inode.h
@@ -1,0 +1,120 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ *
+ *
+ * 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>
+
+uint32_t ext4_inode_get_mode(struct ext4_sblock *sb, struct ext4_inode *inode);
+void 	 ext4_inode_set_mode(struct ext4_sblock *sb, struct ext4_inode *inode, uint32_t mode);
+
+
+uint32_t ext4_inode_get_uid(struct ext4_inode *inode);
+void 	 ext4_inode_set_uid(struct ext4_inode *inode, uint32_t uid);
+
+
+uint64_t ext4_inode_get_size(struct ext4_sblock *sb, struct ext4_inode *inode);
+void 	 ext4_inode_set_size(struct ext4_inode *inode, uint64_t size);
+
+
+uint32_t ext4_inode_get_access_time(struct ext4_inode *inode);
+void 	 ext4_inode_set_access_time(struct ext4_inode *inode, uint32_t time);
+
+
+uint32_t ext4_inode_get_change_inode_time(struct ext4_inode *inode);
+void 	 ext4_inode_set_change_inode_time(struct ext4_inode *inode, uint32_t time);
+
+
+uint32_t ext4_inode_get_modification_time(struct ext4_inode *inode);
+void 	 ext4_inode_set_modification_time(struct ext4_inode *inode, uint32_t time);
+
+
+uint32_t ext4_inode_get_deletion_time(struct ext4_inode *inode);
+void 	 ext4_inode_set_deletion_time(struct ext4_inode *inode, uint32_t time);
+
+uint32_t ext4_inode_get_gid(struct ext4_inode *inode);
+void 	 ext4_inode_set_gid(struct ext4_inode *inode, uint32_t gid);
+
+uint16_t ext4_inode_get_links_count(struct ext4_inode *inode);
+void 	 ext4_inode_set_links_count(struct ext4_inode *inode, uint16_t cnt);
+
+
+uint64_t ext4_inode_get_blocks_count(struct ext4_sblock *sb,  struct ext4_inode *inode);
+int 	 ext4_inode_set_blocks_count(struct ext4_sblock *sb,  struct ext4_inode *inode, uint64_t cnt);
+
+
+uint32_t ext4_inode_get_flags(struct ext4_inode *inode);
+void 	 ext4_inode_set_flags(struct ext4_inode *inode, uint32_t flags);
+
+uint32_t ext4_inode_get_generation(struct ext4_inode *inode);
+void 	 ext4_inode_set_generation(struct ext4_inode *inode, uint32_t gen);
+
+uint64_t ext4_inode_get_file_acl(struct ext4_inode *inode, struct ext4_sblock *sb);
+void 	 ext4_inode_set_file_acl(struct ext4_inode *inode, struct ext4_sblock *sb, uint64_t acl);
+
+
+uint32_t ext4_inode_get_direct_block(struct ext4_inode *inode, uint32_t idx);
+void 	 ext4_inode_set_direct_block(struct ext4_inode *inode, uint32_t idx, uint32_t block);
+
+
+uint32_t ext4_inode_get_indirect_block(struct ext4_inode *inode, uint32_t idx);
+void	 ext4_inode_set_indirect_block(struct ext4_inode *inode, uint32_t idx, uint32_t block);
+
+bool 	 ext4_inode_is_type(struct ext4_sblock *sb, struct ext4_inode *inode, uint32_t type);
+
+
+bool 	 ext4_inode_has_flag(struct ext4_inode *inode, uint32_t f);
+void 	 ext4_inode_clear_flag(struct ext4_inode *inode, uint32_t f);
+void 	 ext4_inode_set_flag(struct ext4_inode *inode, uint32_t f);
+
+bool 	 ext4_inode_can_truncate(struct ext4_sblock *sb, struct ext4_inode *inode);
+
+
+struct ext4_extent_header * ext4_inode_get_extent_header(struct ext4_inode *inode);
+
+#endif /* EXT4_INODE_H_ */
+
+/**
+ * @}
+ */
+
--- /dev/null
+++ b/src/lwext4/ext4_super.c
@@ -1,0 +1,133 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ *
+ *
+ * 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_super.h
+ * @brief Superblock operations.
+ */
+
+#include <ext4_config.h>
+#include <ext4_super.h>
+
+
+uint32_t ext4_block_group_cnt(struct ext4_sblock *s)
+{
+	uint64_t blocks_count = ext4_sb_get_blocks_cnt(s);
+	uint32_t blocks_per_group = ext4_get32(s, blocks_per_group);
+
+	uint32_t block_groups_count = blocks_count / blocks_per_group;
+
+	if (blocks_count % blocks_per_group)
+		block_groups_count++;
+
+	return block_groups_count;
+}
+
+uint32_t ext4_blocks_in_group_cnt(struct ext4_sblock *s, uint32_t bgid)
+{
+	uint32_t block_group_count = ext4_block_group_cnt(s);
+	uint32_t blocks_per_group  = ext4_get32(s, blocks_per_group);
+	uint64_t total_blocks 	   = ext4_sb_get_blocks_cnt(s);
+
+	if (bgid < block_group_count - 1)
+		return blocks_per_group;
+
+
+	return (total_blocks - ((block_group_count - 1) * blocks_per_group));
+}
+
+uint32_t ext4_inodes_in_group_cnt(struct ext4_sblock *s, uint32_t bgid)
+{
+	uint32_t block_group_count = ext4_block_group_cnt(s);
+	uint32_t inodes_per_group  = ext4_get32(s, inodes_per_group);
+	uint32_t total_inodes =		 ext4_get32(s, inodes_count);
+
+
+	if (bgid < block_group_count - 1)
+		return inodes_per_group;
+
+	return (total_inodes - ((block_group_count - 1) * inodes_per_group));
+}
+
+int	ext4_sb_write(struct ext4_blockdev *bdev, struct ext4_sblock *s)
+{
+	return ext4_block_writebytes(bdev, EXT4_SUPERBLOCK_OFFSET,
+								 s, EXT4_SUPERBLOCK_SIZE);
+}
+
+int	ext4_sb_read(struct ext4_blockdev *bdev, struct ext4_sblock *s)
+{
+	return ext4_block_readbytes(bdev, EXT4_SUPERBLOCK_OFFSET,
+								s, EXT4_SUPERBLOCK_SIZE);
+}
+
+bool ext4_sb_check(struct ext4_sblock *s)
+{
+	if (ext4_get16(s, magic) != EXT4_SUPERBLOCK_MAGIC)
+		return false;
+
+	if (ext4_get32(s, inodes_count) == 0)
+		return false;
+
+	if (ext4_sb_get_blocks_cnt(s) == 0)
+		return false;
+
+	if (ext4_get32(s, blocks_per_group) == 0)
+		return false;
+
+	if (ext4_get32(s, inodes_per_group) == 0)
+		return false;
+
+	if (ext4_get16(s, inode_size) < 128)
+		return false;
+
+	if (ext4_get32(s, first_inode) < 11)
+		return false;
+
+	if (ext4_sb_get_desc_size(s) <
+	    EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+		return false;
+
+	if (ext4_sb_get_desc_size(s)  >
+	    EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE)
+		return false;
+
+	return true;
+}
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/src/lwext4/ext4_super.h
@@ -1,0 +1,180 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ *
+ *
+ * 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_super.c
+ * @brief Superblock operations.
+ */
+
+#ifndef EXT4_SUPER_H_
+#define EXT4_SUPER_H_
+
+
+#include <ext4_config.h>
+#include <ext4_types.h>
+
+
+/****************************Unstandard access to superblock*****************/
+
+/**@brief	Blocks count get stored in superblock.
+ * @param	s superblock descriptor
+ * @return	count of blocks*/
+static inline uint64_t 	ext4_sb_get_blocks_cnt(struct ext4_sblock *s)
+{
+	return ((uint64_t) to_le32(s->blocks_count_hi) << 32) | to_le32(s->blocks_count_lo);
+}
+
+/**@brief	Free blocks count get stored in superblock.
+ * @param	s superblock descriptor
+ * @return	free blocks*/
+static inline uint64_t 	ext4_sb_get_free_blocks_cnt(struct ext4_sblock *s)
+{
+	return ((uint64_t) to_le32(s->free_blocks_count_hi) << 32) | to_le32(s->free_blocks_count_lo);
+}
+
+/**@brief	Free blocks count set.
+ * @param	s superblock descriptor
+ * @param	cnt new value of free blocks*/
+static inline void 	ext4_sb_set_free_blocks_cnt(struct ext4_sblock *s, uint64_t cnt)
+{
+	s->free_blocks_count_lo = to_le32((cnt << 32) >> 32);
+	s->free_blocks_count_hi = to_le32(cnt >> 32);
+}
+
+/**@brief	Block size get from superblock.
+ * @param	s superblock descriptor
+ * @return	block size in bytes*/
+static inline uint32_t 	ext4_sb_get_block_size(struct ext4_sblock *s)
+{
+	return 1024 << to_le32(s->log_block_size);
+}
+
+/**@brief	Block group descriptor size.
+ * @param	s superblock descriptor
+ * @return	block group descriptor size in bytes*/
+static inline uint16_t ext4_sb_get_desc_size(struct ext4_sblock *s)
+{
+	uint16_t size = to_le16(s->desc_size);
+
+	return size < EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE ?
+			EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE : size;
+}
+
+/*************************Flags and features**********************************/
+
+/**@brief	Support check of flag.
+ * @param	s superblock descriptor
+ * @param	v flag to check
+ * @return	true if flag is supported*/
+static inline bool ext4_sb_check_flag(struct ext4_sblock *s, uint32_t v)
+{
+	return to_le32(s->flags) & v;
+}
+
+/**@brief	Support check of feature compatible.
+ * @param	s superblock descriptor
+ * @param	v feature to check
+ * @return	true if feature is supported*/
+static inline bool ext4_sb_check_feature_compatible(struct ext4_sblock *s, uint32_t v)
+{
+	return to_le32(s->features_compatible) & v;
+}
+
+
+/**@brief	Support check of feature incompatible.
+ * @param	s superblock descriptor
+ * @param	v feature to check
+ * @return	true if feature is supported*/
+static inline bool ext4_sb_check_feature_incompatible(struct ext4_sblock *s, uint32_t v)
+{
+	return to_le32(s->features_incompatible) & v;
+}
+
+
+/**@brief	Support check of read only flag.
+ * @param	s superblock descriptor
+ * @param	v flag to check
+ * @return	true if flag is supported*/
+static inline bool ext4_sb_check_read_only(struct ext4_sblock *s, uint32_t v)
+{
+	return to_le32(s->features_read_only) & v;
+}
+
+/**************************More complex functions*****************************/
+
+/**@brief	Returns a block group count.
+ * @param	s superblock descriptor
+ * @return	count of block groups*/
+uint32_t ext4_block_group_cnt(struct ext4_sblock *s);
+
+/**@brief	Returns block count in block group (last block group may have less blocks)
+ * @param	s superblock descriptor
+ * @param	bgid block group id
+ * @return	blocks count*/
+uint32_t ext4_blocks_in_group_cnt(struct ext4_sblock *s, uint32_t bgid);
+
+/**@brief	Returns inodes count in block group (last block group may have less inodes)
+ * @param	s superblock descriptor
+ * @param	bgid block group id
+ * @return	inodes count*/
+uint32_t ext4_inodes_in_group_cnt(struct ext4_sblock *s, uint32_t bgid);
+
+/***************************Read/write/check superblock***********************/
+
+/**@brief	Superblock write.
+ * @param	bdev block device descriptor.
+ * @param	s superblock descruptor
+ * @return 	Standard error code */
+int	ext4_sb_write(struct ext4_blockdev *bdev, struct ext4_sblock *s);
+
+/**@brief	Superblock read.
+ * @param	bdev block device descriptor.
+ * @param	s superblock descruptor
+ * @return 	Standard error code */
+int	ext4_sb_read(struct ext4_blockdev *bdev, struct ext4_sblock *s);
+
+/**@brief	Superblock simple validation.
+ * @param	s superblock dsecriptor
+ * @return	true if OK*/
+bool ext4_sb_check(struct ext4_sblock *s);
+
+
+#endif /* EXT4_SUPER_H_ */
+
+/**
+ * @}
+ */
+
--- /dev/null
+++ b/src/lwext4/ext4_types.h
@@ -1,0 +1,613 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka ([email protected])
+ *
+ *
+ * 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_types.h
+ * @brief Ext4 data structure definitions.
+ */
+
+#ifndef EXT4_TYPES_H_
+#define EXT4_TYPES_H_
+
+#include <ext4_config.h>
+#include <ext4_blockdev.h>
+
+#include <stdint.h>
+
+
+/*
+ * Structure of the super block
+ */
+struct ext4_sblock {
+	uint32_t inodes_count;              /* I-nodes count */
+	uint32_t blocks_count_lo;           /* Blocks count */
+	uint32_t reserved_blocks_count_lo;  /* Reserved blocks count */
+	uint32_t free_blocks_count_lo;      /* Free blocks count */
+	uint32_t free_inodes_count;         /* Free inodes count */
+	uint32_t first_data_block;          /* First Data Block */
+	uint32_t log_block_size;            /* Block size */
+	uint32_t log_frag_size;             /* Obsoleted fragment size */
+	uint32_t blocks_per_group;          /* Number of blocks per group */
+	uint32_t frags_per_group;           /* Obsoleted fragments per group */
+	uint32_t inodes_per_group;          /* Number of inodes per group */
+	uint32_t mount_time;                /* Mount time */
+	uint32_t write_time;                /* Write time */
+	uint16_t mount_count;               /* Mount count */
+	uint16_t max_mount_count;           /* Maximal mount count */
+	uint16_t magic;                     /* Magic signature */
+	uint16_t state;                     /* File system state */
+	uint16_t errors;                    /* Behaviour when detecting errors */
+	uint16_t minor_rev_level;           /* Minor revision level */
+	uint32_t last_check_time;           /* Time of last check */
+	uint32_t check_interval;            /* Maximum time between checks */
+	uint32_t creator_os;                /* Creator OS */
+	uint32_t rev_level;                 /* Revision level */
+	uint16_t def_resuid;                /* Default uid for reserved blocks */
+	uint16_t def_resgid;                /* Default gid for reserved blocks */
+
+	/* Fields for EXT4_DYNAMIC_REV superblocks only. */
+	uint32_t first_inode;             /* First non-reserved inode */
+	uint16_t inode_size;              /* Size of inode structure */
+	uint16_t block_group_index;       /* Block group index of this superblock */
+	uint32_t features_compatible;     /* Compatible feature set */
+	uint32_t features_incompatible;   /* Incompatible feature set */
+	uint32_t features_read_only;      /* Readonly-compatible feature set */
+	uint8_t uuid[16];                 /* 128-bit uuid for volume */
+	char volume_name[16];             /* Volume name */
+	char last_mounted[64];            /* Directory where last mounted */
+	uint32_t algorithm_usage_bitmap;  /* For compression */
+
+	/*
+	 * Performance hints. Directory preallocation should only
+	 * happen if the EXT4_FEATURE_COMPAT_DIR_PREALLOC flag is on.
+	 */
+	uint8_t s_prealloc_blocks;       /* Number of blocks to try to preallocate */
+	uint8_t s_prealloc_dir_blocks;   /* Number to preallocate for dirs */
+	uint16_t s_reserved_gdt_blocks;  /* Per group desc for online growth */
+
+	/*
+	 * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set.
+	 */
+	uint8_t journal_uuid[16];       /* UUID of journal superblock */
+	uint32_t journal_inode_number;  /* Inode number of journal file */
+	uint32_t journal_dev;           /* Device number of journal file */
+	uint32_t last_orphan;           /* Head of list of inodes to delete */
+	uint32_t hash_seed[4];          /* HTREE hash seed */
+	uint8_t default_hash_version;   /* Default hash version to use */
+	uint8_t journal_backup_type;
+	uint16_t desc_size;             /* Size of group descriptor */
+	uint32_t default_mount_opts;    /* Default mount options */
+	uint32_t first_meta_bg;         /* First metablock block group */
+	uint32_t mkfs_time;             /* When the filesystem was created */
+	uint32_t journal_blocks[17];    /* Backup of the journal inode */
+
+	/* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */
+	uint32_t blocks_count_hi;           /* Blocks count */
+	uint32_t reserved_blocks_count_hi;  /* Reserved blocks count */
+	uint32_t free_blocks_count_hi;      /* Free blocks count */
+	uint16_t min_extra_isize;           /* All inodes have at least # bytes */
+	uint16_t want_extra_isize;          /* New inodes should reserve # bytes */
+	uint32_t flags;                     /* Miscellaneous flags */
+	uint16_t raid_stride;               /* RAID stride */
+	uint16_t mmp_interval;              /* # seconds to wait in MMP checking */
+	uint64_t mmp_block;                 /* Block for multi-mount protection */
+	uint32_t raid_stripe_width;         /* Blocks on all data disks (N * stride) */
+	uint8_t log_groups_per_flex;        /* FLEX_BG group size */
+	uint8_t reserved_char_pad;
+	uint16_t reserved_pad;
+	uint64_t kbytes_written;            /* Number of lifetime kilobytes written */
+	uint32_t snapshot_inum;             /* I-node number of active snapshot */
+	uint32_t snapshot_id;               /* Sequential ID of active snapshot */
+	uint64_t snapshot_r_blocks_count;   /* Reserved blocks for active snapshot's future use */
+	uint32_t snapshot_list;             /* I-node number of the head of the on-disk snapshot list */
+	uint32_t error_count;               /* Number of file system errors */
+	uint32_t first_error_time;          /* First time an error happened */
+	uint32_t first_error_ino;           /* I-node involved in first error */
+	uint64_t first_error_block;         /* Block involved of first error */
+	uint8_t first_error_func[32];       /* Function where the error happened */
+	uint32_t first_error_line;          /* Line number where error happened */
+	uint32_t last_error_time;           /* Most recent time of an error */
+	uint32_t last_error_ino;            /* I-node involved in last error */
+	uint32_t last_error_line;           /* Line number where error happened */
+	uint64_t last_error_block;          /* Block involved of last error */
+	uint8_t last_error_func[32];        /* Function where the error happened */
+	uint8_t mount_opts[64];
+	uint32_t padding[112];              /* Padding to the end of the block */
+} __attribute__((packed));
+
+
+#define EXT4_SUPERBLOCK_MAGIC   0xEF53
+#define EXT4_SUPERBLOCK_SIZE    1024
+#define EXT4_SUPERBLOCK_OFFSET  1024
+
+#define EXT4_SUPERBLOCK_OS_LINUX  0
+#define EXT4_SUPERBLOCK_OS_HURD   1
+
+/*
+ * Misc. filesystem flags
+ */
+#define EXT4_SUPERBLOCK_FLAGS_SIGNED_HASH    0x0001  /* Signed dirhash in use */
+#define EXT4_SUPERBLOCK_FLAGS_UNSIGNED_HASH  0x0002  /* Unsigned dirhash in use */
+#define EXT4_SUPERBLOCK_FLAGS_TEST_FILESYS   0x0004  /* to test development code */
+
+/*
+ * Filesystem states
+ */
+#define EXT4_SUPERBLOCK_STATE_VALID_FS   0x0001  /* Unmounted cleanly */
+#define EXT4_SUPERBLOCK_STATE_ERROR_FS   0x0002  /* Errors detected */
+#define EXT4_SUPERBLOCK_STATE_ORPHAN_FS  0x0004  /* Orphans being recovered */
+
+/*
+ * Behaviour when errors detected
+ */
+#define EXT4_SUPERBLOCK_ERRORS_CONTINUE  1  /* Continue execution */
+#define EXT4_SUPERBLOCK_ERRORS_RO        2  /* Remount fs read-only */
+#define EXT4_SUPERBLOCK_ERRORS_PANIC     3  /* Panic */
+#define EXT4_SUPERBLOCK_ERRORS_DEFAULT   EXT4_ERRORS_CONTINUE
+
+/*
+ * Compatible features
+ */
+#define EXT4_FEATURE_COMPAT_DIR_PREALLOC   0x0001
+#define EXT4_FEATURE_COMPAT_IMAGIC_INODES  0x0002
+#define EXT4_FEATURE_COMPAT_HAS_JOURNAL    0x0004
+#define EXT4_FEATURE_COMPAT_EXT_ATTR       0x0008
+#define EXT4_FEATURE_COMPAT_RESIZE_INODE   0x0010
+#define EXT4_FEATURE_COMPAT_DIR_INDEX      0x0020
+
+/*
+ * Read-only compatible features
+ */
+#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER  0x0001
+#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE    0x0002
+#define EXT4_FEATURE_RO_COMPAT_BTREE_DIR     0x0004
+#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE     0x0008
+#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM      0x0010
+#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK     0x0020
+#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE   0x0040
+
+/*
+ * Incompatible features
+ */
+#define EXT4_FEATURE_INCOMPAT_COMPRESSION  0x0001
+#define EXT4_FEATURE_INCOMPAT_FILETYPE     0x0002
+#define EXT4_FEATURE_INCOMPAT_RECOVER      0x0004  /* Needs recovery */
+#define EXT4_FEATURE_INCOMPAT_JOURNAL_DEV  0x0008  /* Journal device */
+#define EXT4_FEATURE_INCOMPAT_META_BG      0x0010
+#define EXT4_FEATURE_INCOMPAT_EXTENTS      0x0040  /* extents support */
+#define EXT4_FEATURE_INCOMPAT_64BIT        0x0080
+#define EXT4_FEATURE_INCOMPAT_MMP          0x0100
+#define EXT4_FEATURE_INCOMPAT_FLEX_BG      0x0200
+#define EXT4_FEATURE_INCOMPAT_EA_INODE     0x0400  /* EA in inode */
+#define EXT4_FEATURE_INCOMPAT_DIRDATA      0x1000  /* data in dirent */
+
+#define EXT4_FEATURE_COMPAT_SUPP  (EXT4_FEATURE_COMPAT_DIR_INDEX)
+
+#define EXT4_FEATURE_INCOMPAT_SUPP \
+	(EXT4_FEATURE_INCOMPAT_FILETYPE | \
+	EXT4_FEATURE_INCOMPAT_EXTENTS | \
+	EXT4_FEATURE_INCOMPAT_64BIT)
+
+#define EXT4_FEATURE_RO_COMPAT_SUPP \
+	(EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER | \
+	EXT4_FEATURE_RO_COMPAT_DIR_NLINK | \
+	EXT4_FEATURE_RO_COMPAT_HUGE_FILE | \
+	EXT4_FEATURE_RO_COMPAT_LARGE_FILE | \
+	EXT4_FEATURE_RO_COMPAT_GDT_CSUM | \
+	EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)
+
+struct ext4_fs {
+	struct ext4_blockdev	*bdev;
+	struct ext4_sblock  	sb;
+
+	uint64_t inode_block_limits[4];
+	uint64_t inode_blocks_per_level[4];
+};
+
+
+#define EXT4_BLOCK_GROUP_INODE_UNINIT   0x0001  /* Inode table/bitmap not in use */
+#define EXT4_BLOCK_GROUP_BLOCK_UNINIT   0x0002  /* Block bitmap not in use */
+#define EXT4_BLOCK_GROUP_ITABLE_ZEROED  0x0004  /* On-disk itable initialized to zero */
+
+/*
+ * Structure of a blocks group descriptor
+ */
+struct ext4_bgroup {
+	uint32_t block_bitmap_lo;             /* Blocks bitmap block */
+	uint32_t inode_bitmap_lo;             /* Inodes bitmap block */
+	uint32_t inode_table_first_block_lo;  /* Inodes table block */
+	uint16_t free_blocks_count_lo;        /* Free blocks count */
+	uint16_t free_inodes_count_lo;        /* Free inodes count */
+	uint16_t used_dirs_count_lo;          /* Directories count */
+	uint16_t flags;                       /* EXT4_BG_flags (INODE_UNINIT, etc) */
+	uint32_t reserved[2];                 /* Likely block/inode bitmap checksum */
+	uint16_t itable_unused_lo;            /* Unused inodes count */
+	uint16_t checksum;                    /* crc16(sb_uuid+group+desc) */
+
+	uint32_t block_bitmap_hi;             /* Blocks bitmap block MSB */
+	uint32_t inode_bitmap_hi;             /* I-nodes bitmap block MSB */
+	uint32_t inode_table_first_block_hi;  /* I-nodes table block MSB */
+	uint16_t free_blocks_count_hi;        /* Free blocks count MSB */
+	uint16_t free_inodes_count_hi;        /* Free i-nodes count MSB */
+	uint16_t used_dirs_count_hi;          /* Directories count MSB */
+	uint16_t itable_unused_hi;            /* Unused inodes count MSB */
+	uint32_t reserved2[3];                /* Padding */
+} ;
+
+struct ext4_block_group_ref {
+	struct ext4_block 	block;
+	struct ext4_bgroup 	*block_group;
+	struct ext4_fs  	*fs;
+	uint32_t 			index;
+	bool 				dirty;
+};
+
+#define EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE  32
+#define EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE  64
+
+#define EXT4_MIN_BLOCK_SIZE   1024   /* 1 KiB */
+#define EXT4_MAX_BLOCK_SIZE   65536  /* 64 KiB */
+#define EXT4_REV0_INODE_SIZE  128
+
+#define EXT4_INODE_BLOCK_SIZE  512
+
+#define EXT4_INODE_DIRECT_BLOCK_COUNT      12
+#define EXT4_INODE_INDIRECT_BLOCK          EXT4_INODE_DIRECT_BLOCK_COUNT
+#define EXT4_INODE_DOUBLE_INDIRECT_BLOCK   (EXT4_INODE_INDIRECT_BLOCK + 1)
+#define EXT4_INODE_TRIPPLE_INDIRECT_BLOCK  (EXT4_INODE_DOUBLE_INDIRECT_BLOCK + 1)
+#define EXT4_INODE_BLOCKS                  (EXT4_INODE_TRIPPLE_INDIRECT_BLOCK + 1)
+#define EXT4_INODE_INDIRECT_BLOCK_COUNT    (EXT4_INODE_BLOCKS - EXT4_INODE_DIRECT_BLOCK_COUNT)
+
+/*
+ * Structure of an inode on the disk
+ */
+struct ext4_inode {
+	uint16_t mode;                       /* File mode */
+	uint16_t uid;                        /* Low 16 bits of owner uid */
+	uint32_t size_lo;                    /* Size in bytes */
+	uint32_t access_time;                /* Access time */
+	uint32_t change_inode_time;          /* I-node change time */
+	uint32_t modification_time;          /* Modification time */
+	uint32_t deletion_time;              /* Deletion time */
+	uint16_t gid;                        /* Low 16 bits of group id */
+	uint16_t links_count;                /* Links count */
+	uint32_t blocks_count_lo;            /* Blocks count */
+	uint32_t flags;                      /* File flags */
+	uint32_t unused_osd1;                /* OS dependent - not used in HelenOS */
+	uint32_t blocks[EXT4_INODE_BLOCKS];  /* Pointers to blocks */
+	uint32_t generation;                 /* File version (for NFS) */
+	uint32_t file_acl_lo;                /* File ACL */
+	uint32_t size_hi;
+	uint32_t obso_faddr;                 /* Obsoleted fragment address */
+
+	union {
+		struct {
+			uint16_t blocks_high;
+			uint16_t file_acl_high;
+			uint16_t uid_high;
+			uint16_t gid_high;
+			uint32_t reserved2;
+		} linux2;
+		struct {
+			uint16_t reserved1;
+			uint16_t mode_high;
+			uint16_t uid_high;
+			uint16_t gid_high;
+			uint32_t author;
+		} hurd2;
+	} __attribute__ ((packed)) osd2;
+
+	uint16_t extra_isize;
+	uint16_t pad1;
+	uint32_t ctime_extra;   /* Extra change time (nsec << 2 | epoch) */
+	uint32_t mtime_extra;   /* Extra Modification time (nsec << 2 | epoch) */
+	uint32_t atime_extra;   /* Extra Access time (nsec << 2 | epoch) */
+	uint32_t crtime;        /* File creation time */
+	uint32_t crtime_extra;  /* Extra file creation time (nsec << 2 | epoch) */
+	uint32_t version_hi;    /* High 32 bits for 64-bit version */
+} __attribute__ ((packed)) ;
+
+#define EXT4_INODE_MODE_FIFO       0x1000
+#define EXT4_INODE_MODE_CHARDEV    0x2000
+#define EXT4_INODE_MODE_DIRECTORY  0x4000
+#define EXT4_INODE_MODE_BLOCKDEV   0x6000
+#define EXT4_INODE_MODE_FILE       0x8000
+#define EXT4_INODE_MODE_SOFTLINK   0xA000
+#define EXT4_INODE_MODE_SOCKET     0xC000
+#define EXT4_INODE_MODE_TYPE_MASK  0xF000
+
+/*
+ * Inode flags
+ */
+#define EXT4_INODE_FLAG_SECRM      0x00000001  /* Secure deletion */
+#define EXT4_INODE_FLAG_UNRM       0x00000002  /* Undelete */
+#define EXT4_INODE_FLAG_COMPR      0x00000004  /* Compress file */
+#define EXT4_INODE_FLAG_SYNC       0x00000008  /* Synchronous updates */
+#define EXT4_INODE_FLAG_IMMUTABLE  0x00000010  /* Immutable file */
+#define EXT4_INODE_FLAG_APPEND     0x00000020  /* writes to file may only append */
+#define EXT4_INODE_FLAG_NODUMP     0x00000040  /* do not dump file */
+#define EXT4_INODE_FLAG_NOATIME    0x00000080  /* do not update atime */
+
+/* Compression flags */
+#define EXT4_INODE_FLAG_DIRTY     0x00000100
+#define EXT4_INODE_FLAG_COMPRBLK  0x00000200  /* One or more compressed clusters */
+#define EXT4_INODE_FLAG_NOCOMPR   0x00000400  /* Don't compress */
+#define EXT4_INODE_FLAG_ECOMPR    0x00000800  /* Compression error */
+
+#define EXT4_INODE_FLAG_INDEX         0x00001000  /* hash-indexed directory */
+#define EXT4_INODE_FLAG_IMAGIC        0x00002000  /* AFS directory */
+#define EXT4_INODE_FLAG_JOURNAL_DATA  0x00004000  /* File data should be journaled */
+#define EXT4_INODE_FLAG_NOTAIL        0x00008000  /* File tail should not be merged */
+#define EXT4_INODE_FLAG_DIRSYNC       0x00010000  /* Dirsync behaviour (directories only) */
+#define EXT4_INODE_FLAG_TOPDIR        0x00020000  /* Top of directory hierarchies */
+#define EXT4_INODE_FLAG_HUGE_FILE     0x00040000  /* Set to each huge file */
+#define EXT4_INODE_FLAG_EXTENTS       0x00080000  /* Inode uses extents */
+#define EXT4_INODE_FLAG_EA_INODE      0x00200000  /* Inode used for large EA */
+#define EXT4_INODE_FLAG_EOFBLOCKS     0x00400000  /* Blocks allocated beyond EOF */
+#define EXT4_INODE_FLAG_RESERVED      0x80000000  /* reserved for ext4 lib */
+
+#define EXT4_INODE_ROOT_INDEX  2
+
+struct ext4_inode_ref {
+	struct ext4_block 		 block;
+	struct ext4_inode 		*inode;
+	struct ext4_fs  *fs;
+	uint32_t index;
+	bool dirty;
+} ;
+
+
+#define EXT4_DIRECTORY_FILENAME_LEN  255
+
+#define EXT4_DIRECTORY_FILETYPE_UNKNOWN   0
+#define EXT4_DIRECTORY_FILETYPE_REG_FILE  1
+#define EXT4_DIRECTORY_FILETYPE_DIR       2
+#define EXT4_DIRECTORY_FILETYPE_CHRDEV    3
+#define EXT4_DIRECTORY_FILETYPE_BLKDEV    4
+#define EXT4_DIRECTORY_FILETYPE_FIFO      5
+#define EXT4_DIRECTORY_FILETYPE_SOCK      6
+#define EXT4_DIRECTORY_FILETYPE_SYMLINK   7
+
+/**
+ * Linked list directory entry structure
+ */
+struct ext4_directory_entry_ll {
+	uint32_t inode;         /* I-node for the entry */
+	uint16_t entry_length;  /* Distance to the next directory entry */
+	uint8_t name_length;    /* Lower 8 bits of name length */
+
+	union {
+		uint8_t name_length_high;  /* Higher 8 bits of name length */
+		uint8_t inode_type;        /* Type of referenced inode (in rev >= 0.5) */
+	} __attribute__ ((packed));
+
+	uint8_t name[EXT4_DIRECTORY_FILENAME_LEN];  /* Entry name */
+} __attribute__((packed)) ;
+
+struct ext4_directory_iterator {
+	struct ext4_inode_ref 			*inode_ref;
+	struct ext4_block 	   			current_block;
+	uint64_t 						current_offset;
+	struct ext4_directory_entry_ll  *current;
+};
+
+struct ext4_directory_search_result {
+	struct	ext4_block 		 		block;
+	struct  ext4_directory_entry_ll *dentry;
+};
+
+/* Structures for indexed directory */
+
+struct ext4_directory_dx_countlimit {
+	uint16_t limit;
+	uint16_t count;
+} ;
+
+struct ext4_directory_dx_dot_entry {
+	uint32_t inode;
+	uint16_t entry_length;
+	uint8_t name_length;
+	uint8_t inode_type;
+	uint8_t name[4];
+} ;
+
+struct ext4_directory_dx_root_info {
+	uint32_t reserved_zero;
+	uint8_t hash_version;
+	uint8_t info_length;
+	uint8_t indirect_levels;
+	uint8_t unused_flags;
+} ;
+
+struct ext4_directory_dx_entry {
+	uint32_t hash;
+	uint32_t block;
+} ;
+
+struct ext4_directory_dx_root {
+	struct ext4_directory_dx_dot_entry dots[2];
+	struct ext4_directory_dx_root_info info;
+	struct ext4_directory_dx_entry entries[0];
+};
+
+struct ext4_fake_directory_entry {
+	uint32_t inode;
+	uint16_t entry_length;
+	uint8_t name_length;
+	uint8_t inode_type;
+};
+
+struct ext4_directory_dx_node {
+	struct ext4_fake_directory_entry fake;
+	struct ext4_directory_dx_entry entries[0];
+};
+
+struct ext4_directory_dx_block {
+	struct ext4_block 		 	    block;
+	struct ext4_directory_dx_entry *entries;
+	struct ext4_directory_dx_entry *position;
+} ;
+
+#define EXT4_ERR_BAD_DX_DIR       (-75000)
+
+
+/*
+ * This is the extent on-disk structure.
+ * It's used at the bottom of the tree.
+ */
+struct ext4_extent {
+	uint32_t first_block;  /* First logical block extent covers */
+	uint16_t block_count;  /* Number of blocks covered by extent */
+	uint16_t start_hi;     /* High 16 bits of physical block */
+	uint32_t start_lo;     /* Low 32 bits of physical block */
+} ;
+
+/*
+ * This is index on-disk structure.
+ * It's used at all the levels except the bottom.
+ */
+struct ext4_extent_index {
+	uint32_t first_block;  /* Index covers logical blocks from 'block' */
+
+	/**
+	 * Pointer to the physical block of the next
+	 * level. leaf or next index could be there
+	 * high 16 bits of physical block
+	 */
+	uint32_t leaf_lo;
+	uint16_t leaf_hi;
+	uint16_t padding;
+} ;
+
+/*
+ * Each block (leaves and indexes), even inode-stored has header.
+ */
+struct ext4_extent_header {
+	uint16_t magic;
+	uint16_t entries_count;      /* Number of valid entries */
+	uint16_t max_entries_count;  /* Capacity of store in entries */
+	uint16_t depth;              /* Has tree real underlying blocks? */
+	uint32_t generation;         /* generation of the tree */
+} ;
+
+struct ext4_extent_path {
+	struct	ext4_block 		 	block;
+	uint16_t 					depth;
+	struct ext4_extent_header *header;
+	struct ext4_extent_index  *index;
+	struct ext4_extent 		  *extent;
+} ;
+
+#define EXT4_EXTENT_MAGIC  0xF30A
+
+#define	EXT4_EXTENT_FIRST(header) \
+	((struct ext4_extent *) (((void *) (header)) + sizeof(struct ext4_extent_header)))
+
+#define	EXT4_EXTENT_FIRST_INDEX(header) \
+	((struct ext4_extent_index *) (((void *) (header)) + sizeof(struct ext4_extent_header)))
+
+
+/* EXT3 HTree directory indexing */
+#define EXT2_HTREE_LEGACY					0
+#define EXT2_HTREE_HALF_MD4					1
+#define EXT2_HTREE_TEA						2
+#define EXT2_HTREE_LEGACY_UNSIGNED			3
+#define EXT2_HTREE_HALF_MD4_UNSIGNED		4
+#define EXT2_HTREE_TEA_UNSIGNED				5
+
+#define EXT2_HTREE_EOF 						0x7FFFFFFF
+
+
+struct ext4_hash_info {
+	uint32_t hash;
+	uint32_t minor_hash;
+	uint32_t hash_version;
+	const uint32_t *seed;
+};
+
+/*****************************************************************************/
+
+
+#ifdef CONFIG_BIG_ENDIAN
+static inline uint64_t to_le64(uint64_t n)
+{
+	return  ((n & 0xff) << 56) |
+			((n & 0xff00) << 40) |
+			((n & 0xff0000) << 24) |
+			((n & 0xff000000LL) << 8) |
+			((n & 0xff00000000LL) >> 8) |
+			((n & 0xff0000000000LL) >> 24) |
+			((n & 0xff000000000000LL) >> 40) |
+			((n & 0xff00000000000000LL) >> 56);
+}
+
+static inline uint32_t to_le32(uint32_t n)
+{
+	return 	((n & 0xff) << 24) |
+	    	((n & 0xff00) << 8) |
+	    	((n & 0xff0000) >> 8) |
+	    	((n & 0xff000000) >> 24);
+}
+
+static inline uint16_t to_le16(uint16_t n)
+{
+	return 	((n & 0xff) << 8) |
+			((n & 0xff00) >> 8);
+}
+
+
+#else
+#define to_le64(_n)	_n
+#define to_le32(_n)	_n
+#define to_le16(_n)	_n
+#endif
+
+/****************************Access macros to ext4 structures*****************/
+
+#define ext4_get32(s, f)		to_le32((s)->f)
+#define ext4_get16(s, f)		to_le16((s)->f)
+#define ext4_get8(s, f)			(s)->f
+
+
+#define ext4_set32(s, f, v)		do { (s)->f = to_le32(v); }while(0)
+#define ext4_set16(s, f, v)		do { (s)->f = to_le16(v); }while(0)
+#define ext4_set8 (s, f, v)		do { (s)->f = (v); 		  }while(0)
+
+#endif /* EXT4_TYPES_H_ */
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/src/toolchain/bf518.cmake
@@ -1,0 +1,22 @@
+# Name of the target
+SET(CMAKE_SYSTEM_NAME Generic)
+set(CMAKE_SYSTEM_PROCESSOR bf518)
+
+# Toolchain settings
+set(CMAKE_C_COMPILER 	bfin-elf-gcc)
+set(CMAKE_CXX_COMPILER	bfin-elf-g++)
+set(AS                  bfin-elf--gcc)
+set(AR			        bfin-elf-ar)
+set(OBJCOPY 		    bfin-elf-objcopy)
+set(OBJDUMP 		    bfin-elf-objdump)
+set(SIZE                bfin-elf-size)
+
+set(CMAKE_C_FLAGS   "-mcpu=bf518 -Wall -std=gnu99 -fdata-sections -ffunction-sections" CACHE INTERNAL "c compiler flags")
+set(CMAKE_CXX_FLAGS "-mcpu=bf518 -fno-builtin -Wall -fdata-sections -ffunction-sections" CACHE INTERNAL "cxx compiler flags")
+set(CMAKE_ASM_FLAGS "-mcpu=bf518 -x assembler-with-cpp" CACHE INTERNAL "asm compiler flags")
+set(CMAKE_EXE_LINKER_FLAGS "-nostartfiles -Wl,--gc-sections -mcpu=bf592" CACHE INTERNAL "exe link flags")
+					
+							
+		
+		
+		
\ No newline at end of file
--- /dev/null
+++ b/src/toolchain/cortex-m3.cmake
@@ -1,0 +1,18 @@
+# Name of the target
+SET(CMAKE_SYSTEM_NAME Generic)
+set(CMAKE_SYSTEM_PROCESSOR cortex-m3)
+
+# Toolchain settings
+set(CMAKE_C_COMPILER 	arm-none-eabi-gcc)
+set(CMAKE_CXX_COMPILER 	arm-none-eabi-g++)
+set(AS 	                arm-none-eabi-as)
+set(AR         			arm-none-eabi-ar)
+set(OBJCOPY 	    	arm-none-eabi-objcopy)
+set(OBJDUMP     		arm-none-eabi-objdump)
+set(SIZE                arm-none-eabi-size)
+
+set(CMAKE_C_FLAGS   "-mthumb -mcpu=cortex-m3 -fno-builtin -Wall -std=gnu99 -fdata-sections -ffunction-sections" CACHE INTERNAL "c compiler flags")
+set(CMAKE_CXX_FLAGS "-mthumb -mcpu=cortex-m3 -fno-builtin -Wall -fdata-sections -ffunction-sections" CACHE INTERNAL "cxx compiler flags")
+set(CMAKE_ASM_FLAGS "-mthumb -mcpu=cortex-m3" CACHE INTERNAL "asm compiler flags")
+set(CMAKE_EXE_LINKER_FLAGS "-nostartfiles -Wl,--gc-sections -mthumb -mcpu=cortex-m3" CACHE INTERNAL "exe link flags")
+
--- /dev/null
+++ b/src/toolchain/cortex-m4.cmake
@@ -1,0 +1,18 @@
+# Name of the target
+SET(CMAKE_SYSTEM_NAME Generic)
+set(CMAKE_SYSTEM_PROCESSOR cortex-m4)
+
+# Toolchain settings
+set(CMAKE_C_COMPILER 	arm-none-eabi-gcc)
+set(CMAKE_CXX_COMPILER 	arm-none-eabi-g++)
+set(AS 	                arm-none-eabi-as)
+set(AR         			arm-none-eabi-ar)
+set(OBJCOPY 	    	arm-none-eabi-objcopy)
+set(OBJDUMP     		arm-none-eabi-objdump)
+set(SIZE                arm-none-eabi-size)
+
+set(CMAKE_C_FLAGS   "-mthumb -mcpu=cortex-m4 -fno-builtin -Wall -std=gnu99 -fdata-sections -ffunction-sections" CACHE INTERNAL "c compiler flags")
+set(CMAKE_CXX_FLAGS "-mthumb -mcpu=cortex-m4 -fno-builtin -Wall -fdata-sections -ffunction-sections" CACHE INTERNAL "cxx compiler flags")
+set(CMAKE_ASM_FLAGS "-mthumb -mcpu=cortex-m4" CACHE INTERNAL "asm compiler flags")
+set(CMAKE_EXE_LINKER_FLAGS "-nostartfiles -Wl,--gc-sections -mthumb -mcpu=cortex-m4" CACHE INTERNAL "exe link flags")
+