shithub: lwext4

Download patch

ref: ffb796f2aa4c7933dbce539865d90e7db00fabf4
parent: b0ccb70ff6260f332a18372f85bf65bc370f82c9
author: gkostka <kostka.grzegorz@gmail.com>
date: Sun Oct 20 13:55:17 EDT 2013

1. Directory opreations:
 - ext4_dir_rm - delete dir recursive
 - ext4_dir_mk - make dir

2. Bugfix in ext4_dir (bad iterator behaviour).
3. Comments inr ext4.h.
4. Demo app has directory operations test.
5. Better ext4_femove implementation.
6. Most file functions base on ext4_open_generic.
7. Extent feature preprocessor switches.

--- a/demos/generic/main.c
+++ b/demos/generic/main.c
@@ -46,6 +46,9 @@
 /**@brief	Read-write size*/
 static int rw_count = 1024;
 
+/**@brief   Directory test count*/
+static int dir_cnt  = 10;
+
 static bool cache_mode = false;
 
 
@@ -65,10 +68,11 @@
 Welcome in ext4 generic demo.									\n\
 Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)	\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\
+	-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\
+    -dirs  - directory test count (default = 0)                 \n\
 \n";
 
 static char* entry_to_str(uint8_t type)
@@ -106,7 +110,7 @@
 	printf("**********************************************\n");
 
 	ext4_dir_open(&d, path);
-	de = ext4_entry_get(&d, j++);
+	de = ext4_dir_entry_get(&d, j++);
 	printf("ls %s\n", path);
 
 	while(de){
@@ -115,7 +119,7 @@
 		printf(entry_to_str(de->inode_type));
 		printf(sss);
 		printf("\n");
-		de = ext4_entry_get(&d, j++);
+		de = ext4_dir_entry_get(&d, j++);
 	}
 	printf("**********************************************\n");
 	ext4_dir_close(&d);
@@ -128,14 +132,14 @@
 
     printf("**********************************************\n");
     printf("ext4_mount_point_stats\n");
-    printf("inodes_count        = %d\n", stats.inodes_count);
-    printf("free_inodes_count   = %d\n", stats.free_inodes_count);
-    printf("blocks_count        = %d\n", stats.blocks_count);
-    printf("free_blocks_count   = %d\n", stats.free_blocks_count);
-    printf("block_size          = %d\n", stats.block_size);
-    printf("block_group_count   = %d\n", stats.block_group_count);
-    printf("blocks_per_group    = %d\n", stats.blocks_per_group);
-    printf("inodes_per_group    = %d\n", stats.inodes_per_group);
+    printf("inodes_count        = %u\n", stats.inodes_count);
+    printf("free_inodes_count   = %u\n", stats.free_inodes_count);
+    printf("blocks_count        = %u\n", (uint32_t)stats.blocks_count);
+    printf("free_blocks_count   = %u\n", (uint32_t)stats.free_blocks_count);
+    printf("block_size          = %u\n", stats.block_size);
+    printf("block_group_count   = %u\n", stats.block_group_count);
+    printf("blocks_per_group    = %u\n", stats.blocks_per_group);
+    printf("inodes_per_group    = %u\n", stats.inodes_per_group);
     printf("volume_name         = %s\n", stats.volume_name);
 
     printf("**********************************************\n");
@@ -148,22 +152,22 @@
 
     printf("**********************************************\n");
     printf("ext4 blockdev stats\n");
-    printf("bdev->bread_ctr          = %d\n", bd->bread_ctr);
-    printf("bdev->bwrite_ctr         = %d\n", bd->bwrite_ctr);
+    printf("bdev->bread_ctr          = %u\n", bd->bread_ctr);
+    printf("bdev->bwrite_ctr         = %u\n", bd->bwrite_ctr);
 
 
-    printf("bcache->ref_blocks       = %d\n", bc->ref_blocks);
-    printf("bcache->max_ref_blocks   = %d\n", bc->max_ref_blocks);
-    printf("bcache->lru_ctr          = %d\n", bc->lru_ctr);
+    printf("bcache->ref_blocks       = %u\n", bc->ref_blocks);
+    printf("bcache->max_ref_blocks   = %u\n", bc->max_ref_blocks);
+    printf("bcache->lru_ctr          = %u\n", bc->lru_ctr);
 
     printf("\n");
     for (i = 0; i < bc->cnt; ++i) {
-        printf("bcache->refctr[%d]     = %d\n", i, bc->refctr[i]);
+        printf("bcache->refctr[%d]     = %u\n", i, bc->refctr[i]);
     }
 
     printf("\n");
     for (i = 0; i < bc->cnt; ++i) {
-        printf("bcache->lru_id[%d]     = %d\n", i, bc->lru_id[i]);
+        printf("bcache->lru_id[%d]     = %u\n", i, bc->lru_id[i]);
     }
 
     printf("\n");
@@ -173,7 +177,7 @@
 
     printf("\n");
     for (i = 0; i < bc->cnt; ++i) {
-        printf("bcache->lba[%d]        = %d\n", i, bc->lba[i]);
+        printf("bcache->lba[%d]        = %u\n", i, (uint32_t)bc->lba[i]);
     }
 
 
@@ -181,7 +185,60 @@
     printf("**********************************************\n");
 }
 
+static bool dir_test(int len)
+{
+    ext4_file f;
+    int       r;
+    int       i;
+    char path[64];
 
+    printf("Remove directory /mp/dir1\n");
+    ext4_dir_rm("/mp/dir1");
+
+
+    printf("Directory create: /mp/dir1\n");
+    r = ext4_dir_mk("/mp/dir1");
+    if(r != EOK){
+        printf("Unable to create directory: /mp/dir1\n");
+        return false;
+    }
+
+
+    printf("Add files to: /mp/dir1\n");
+    for (i = 0; i < len; ++i) {
+        sprintf(path, "/mp/dir1/f%d", i);
+        r = ext4_fopen(&f, path, "wb");
+        if(r != EOK){
+            printf("Unable to create file in directory: /mp/dir1\n");
+            return false;
+        }
+    }
+
+    printf("Add directories to: /mp/dir1\n");
+    for (i = 0; i < len; ++i) {
+        sprintf(path, "/mp/dir1/d%d", i);
+        r = ext4_dir_mk(path);
+        if(r != EOK){
+            printf("Unable to create directory in directory: /mp/dir1\n");
+            return false;
+        }
+    }
+
+    printf("Add file directories in: /mp/dir1\n");
+
+    for (i = 0; i < len; ++i) {
+        sprintf(path, "/mp/dir1/d%d/ff", i);
+        r = ext4_fopen(&f, path, "wb");
+        if(r != EOK){
+            printf("Unable to create file in directory: /mp/dir1\n");
+            return false;
+        }
+    }
+
+    dir_ls("/mp/dir1");
+    return true;
+}
+
 int main(int argc, char **argv)
 {
 	int option_index = 0;
@@ -197,10 +254,11 @@
         {"rws",     required_argument, 0, 'b'},
         {"rwc",		required_argument, 0, 'c'},
         {"cache",   required_argument, 0, 'd'},
+        {"dirs",   required_argument,  0, 'e'},
         {0, 0, 0, 0}
       };
 
-    while(-1 != (c = getopt_long (argc, argv, "a:b:c:d:", long_options, &option_index))) {
+    while(-1 != (c = getopt_long (argc, argv, "a:b:c:d:e:", long_options, &option_index))) {
 
     	switch(c){
     		case 'a':
@@ -215,6 +273,9 @@
     		case 'd':
     			cache_mode = atoi(optarg);
     			break;
+            case 'e':
+                dir_cnt = atoi(optarg);
+                break;
     		default:
     			printf(usage);
     			return EXIT_FAILURE;
@@ -262,6 +323,7 @@
 		return EXIT_FAILURE;
 	}
 
+	dir_test(dir_cnt);
 
 	ext4_fremove("/mp/hello.txt");
 	ext4_fremove("/mp/test1");
--- a/ext4.h
+++ b/ext4.h
@@ -42,34 +42,34 @@
 #include <ext4_blockdev.h>
 #include <stdint.h>
 
-/********************************FILE OPEN FLAGS********************************/
+/********************************FILE OPEN FLAGS*****************************/
 
 #ifndef O_RDONLY
-#define O_RDONLY	00
+#define O_RDONLY    00
 #endif
 
 #ifndef O_WRONLY
-#define O_WRONLY	01
+#define O_WRONLY    01
 #endif
 
 #ifndef O_RDWR
-#define O_RDWR		02
+#define O_RDWR      02
 #endif
 
 #ifndef O_CREAT
-#define O_CREAT	    0100
+#define O_CREAT     0100
 #endif
 
 #ifndef O_EXCL
-#define O_EXCL		0200
+#define O_EXCL      0200
 #endif
 
 #ifndef O_TRUNC
-#define O_TRUNC		01000
+#define O_TRUNC     01000
 #endif
 
 #ifndef O_APPEND
-#define O_APPEND	02000
+#define O_APPEND    02000
 #endif
 
 /********************************FILE SEEK FLAGS*****************************/
@@ -133,7 +133,7 @@
     EXT4_DIRENTRY_SYMLINK
 };
 
-/**@brief	Directory entry descriptor. Copy from ext4_types.h*/
+/**@brief   Directory entry descriptor. Copy from ext4_types.h*/
 typedef struct {
     uint32_t inode;
     uint16_t entry_length;
@@ -182,7 +182,7 @@
 int	ext4_umount(char *mount_point);
 
 
-/**@brief   Some of the filesystem params.*/
+/**@brief   Some of the filesystem stats.*/
 struct ext4_mount_stats {
     uint32_t inodes_count;
     uint32_t free_inodes_count;
@@ -197,12 +197,18 @@
     char volume_name[16];
 };
 
+/**@brief   Get file system params.
+ * @param   mount_point mount path
+ * @param   stats ext fs stats
+ * @return  standard error code */
 int ext4_mount_point_stats(const char *mount_point,
     struct ext4_mount_stats *stats);
 
 /********************************FILE OPERATIONS*****************************/
 
-/**@brief	*/
+/**@brief	Remove file by path.
+ * @param   path path to file
+ * @return  standard error code */
 int ext4_fremove(const char *path);
 
 /**@brief	File open function.
@@ -226,39 +232,76 @@
  * @return	standard error code*/
 int ext4_fopen (ext4_file *f, const char *path, const char *flags);
 
-/**@brief	*/
+/**@brief	File close function.
+ * @param   f file handle
+ * @return  standard error code*/
 int ext4_fclose(ext4_file *f);
 
-/**@brief	*/
+/**@brief   Read data from file.
+ * @param   f file handle
+ * @param   buf output buffer
+ * @param   size bytes to read
+ * @param   rcnt readed bytes (may be NULL)
+ * @return  standard error code*/
 int ext4_fread (ext4_file *f, void *buf, uint32_t size, uint32_t *rcnt);
 
-/**@brief	*/
+/**@brief	Write data to file.
+ * @param   f file handle
+ * @param   buf data to write
+ * @param   size write length
+ * @param   wcnt bytes written (may be NULL)
+ * @return  standard error code*/
 int ext4_fwrite(ext4_file *f, void *buf, uint32_t size, uint32_t *wcnt);
 
-/**@brief	*/
+/**@brief	File seek operation.
+ * @param   f file handle
+ * @param   offset offset to seek
+ * @param   origin seek type:
+ *              @ref SEEK_SET
+ *              @ref SEEK_CUR
+ *              @ref SEEK_END
+ * @return  standard error code*/
 int ext4_fseek (ext4_file *f, uint64_t offset, uint32_t origin);
 
-/**@brief	*/
+/**@brief	Get file position.
+ * @param   f file handle
+ * @return  actual file position */
 uint64_t ext4_ftell (ext4_file *f);
 
-/**@brief	*/
+/**@brief	Get file size.
+ * @param   f file handle
+ * @return  file size */
 uint64_t ext4_fsize (ext4_file *f);
 
 /*********************************DIRECTORY OPERATION***********************/
-/**@brief	*/
-int ext4_mkdir(const char *path);
 
-/**@brief	*/
-int ext4_rmdir(const char *path);
+/**@brief	Recursive directory remove.
+ * @param   path directory path to remove
+ * @return  standard error code*/
+int ext4_dir_rm(const char *path);
 
-/**@brief	*/
+/**@brief   Create new directory.
+ * @param   name new directory name
+ * @return  standard error code*/
+int ext4_dir_mk(const char *path);
+
+/**@brief	Directory open.
+ * @param   d directory handle
+ * @param   path directory path
+ * @return  standard error code*/
 int ext4_dir_open (ext4_dir *d, const char *path);
 
-/**@brief	*/
+/**@brief	Directory close.
+ * @param   d directory handle
+ * @return  standard error code*/
 int ext4_dir_close(ext4_dir *d);
 
-/**@brief	*/
-ext4_direntry* ext4_entry_get(ext4_dir *d, uint32_t id);
+
+/**@brief	Return directory entry by id.
+ * @param   d directory handle
+ * @param   id entry id
+ * @return  directory entry id (NULL id no entry)*/
+ext4_direntry* ext4_dir_entry_get(ext4_dir *d, uint32_t id);
 
 #endif /* EXT4_H_ */
 
--- a/lwext4/ext4.c
+++ b/lwext4/ext4.c
@@ -52,11 +52,11 @@
 
 /**@brief	Mount point OS dependent lock*/
 #define EXT4_MP_LOCK(_m)    \
-        do { (_m)->os_locks ? (_m)->os_locks->lock()   : 0; }while(0)
+        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)
+        do { (_m)->os_locks ? (_m)->os_locks->unlock() : 0; }while(0)
 
 /**@brief	Mount point descrpitor.*/
 struct ext4_mountpoint {
@@ -491,7 +491,6 @@
     return 0;
 }
 
-
 static bool ext4_parse_flags(const char *flags, uint32_t *file_flags)
 {
     if(!flags)
@@ -533,7 +532,7 @@
 /****************************************************************************/
 
 static int ext4_generic_open (ext4_file *f, const char *path,
-        const char *flags, bool file_expect)
+        const char *flags, bool file_expect, uint32_t *parent_inode, uint32_t *name_off)
 {
     struct ext4_mountpoint *mp = ext4_get_mount(path);
     struct ext4_directory_search_result result;
@@ -554,7 +553,8 @@
     /*Skip mount point*/
     path += strlen(mp->name);
 
-    EXT4_MP_LOCK(mp);
+    if(name_off)
+        *name_off = strlen(mp->name);
 
     /*Load root*/
     r = ext4_fs_get_inode_ref(&mp->fs, EXT4_INODE_ROOT_INDEX, &ref);
@@ -562,17 +562,20 @@
     if(r != EOK)
         return r;
 
+    if(parent_inode)
+        *parent_inode = ref.index;
+
     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){
+            /*If root open was request.*/
+            if(is_goal && !file_expect)
+                break;
+
             r = ENOENT;
             break;
         }
@@ -586,9 +589,9 @@
             if(!(f->flags & O_CREAT))
                 break;
 
-            /*O_CREAT allows to create new entry*/
+            /*O_CREAT allows create new entry*/
             struct ext4_inode_ref	child_ref;
-            r = ext4_fs_alloc_inode(&mp->fs, &child_ref, !is_goal);
+            r = ext4_fs_alloc_inode(&mp->fs, &child_ref, is_goal ? !file_expect : true);
             if(r != EOK)
                 break;
 
@@ -612,6 +615,9 @@
             continue;
         }
 
+        if(parent_inode)
+            *parent_inode = ref.index;
+
         next_inode = result.dentry->inode;
         inode_type = ext4_dir_entry_ll_get_inode_type(&mp->fs.sb, result.dentry);
 
@@ -645,18 +651,20 @@
             break;
 
         path += len + 1;
+
+        if(name_off)
+            *name_off += 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){
+        if((f->flags & O_TRUNC) &&
+                (inode_type == EXT4_DIRECTORY_FILETYPE_REG_FILE)){
             /*Turncate.*/
             ext4_block_delay_cache_flush(mp->fs.bdev, 1);
             /*Truncate may be IO heavy.
@@ -666,7 +674,6 @@
 
             if(r != EOK){
                 ext4_fs_put_inode_ref(&ref);
-                EXT4_MP_UNLOCK(mp);
                 return r;
             }
         }
@@ -682,7 +689,6 @@
     }
 
     r = ext4_fs_put_inode_ref(&ref);
-    EXT4_MP_UNLOCK(mp);
     return r;
 }
 
@@ -690,97 +696,37 @@
 
 int ext4_fremove(const char *path)
 {
+    ext4_file   f;
+    uint32_t    parent_inode;
+    uint32_t    name_off;
+    int     r;
+    int     len;
+    bool    is_goal;
     struct ext4_mountpoint *mp = ext4_get_mount(path);
-    struct ext4_directory_search_result result;
-    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;
-    int len = 0;
+    struct ext4_inode_ref child;
+    struct ext4_inode_ref parent;
 
     if(!mp)
         return ENOENT;
 
-
-    /*Skip mount point*/
-    path += strlen(mp->name);
-
-    /*Lock mountpoint*/
     EXT4_MP_LOCK(mp);
-
-    /*Load root*/
-    r = ext4_fs_get_inode_ref(&mp->fs, EXT4_INODE_ROOT_INDEX, &parent);
-
+    r = ext4_generic_open(&f, path, "r", true, &parent_inode, &name_off);
     if(r != EOK){
         EXT4_MP_UNLOCK(mp);
         return r;
     }
 
-    while(1){
-
-        len = ext4_path_check(path, &is_goal);
-
-        if(!len){
-            r = ENOENT;
-            break;
-        }
-
-        r = ext4_dir_find_entry(&result, &parent, path, len);
-        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;
-    };
-
+    /*Load parent*/
+    r = ext4_fs_get_inode_ref(&mp->fs, parent_inode, &parent);
     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);
+    r = ext4_fs_get_inode_ref(&mp->fs, f.inode, &child);
     if(r != EOK){
-        /*Parent free*/
         ext4_fs_put_inode_ref(&parent);
         EXT4_MP_UNLOCK(mp);
         return r;
@@ -788,14 +734,18 @@
 
     /*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;
 
+    /*Set path*/
+    path += name_off;
+
+    len = ext4_path_check(path, &is_goal);
+
     /*Unlink from parent.*/
     r = ext4_unlink(mp, &parent, &child, path, len);
     if(r != EOK)
@@ -805,7 +755,6 @@
     if(r != EOK)
         goto Finish;
 
-
     Finish:
     ext4_fs_put_inode_ref(&child);
     ext4_fs_put_inode_ref(&parent);
@@ -816,7 +765,16 @@
 
 int	ext4_fopen (ext4_file *f, const char *path, const char *flags)
 {
-    return ext4_generic_open(f, path, flags, true);
+    struct ext4_mountpoint *mp = ext4_get_mount(path);
+    int r;
+
+    if(!mp)
+        return ENOENT;
+
+    EXT4_MP_LOCK(mp);
+    r = ext4_generic_open(f, path, flags, true, 0, 0);
+    EXT4_MP_UNLOCK(mp);
+    return r;
 }
 
 int	ext4_fclose(ext4_file *f)
@@ -1144,9 +1102,222 @@
 
 /*********************************DIRECTORY OPERATION************************/
 
+int ext4_dir_rm(const char *path)
+{
+    int         r;
+    int         len;
+    ext4_file   f;
+    struct ext4_mountpoint *mp = ext4_get_mount(path);
+    struct ext4_inode_ref   current;
+    struct ext4_inode_ref   child;
+
+    struct ext4_directory_iterator it;
+    uint32_t name_off;
+    uint32_t inode_up;
+    uint32_t inode_current;
+    uint32_t depth = 1;
+    bool     has_children;
+    bool     is_goal;
+    bool     dir_end;
+
+    if(!mp)
+        return ENOENT;
+
+    EXT4_MP_LOCK(mp);
+
+    /*Check if exist.*/
+    r = ext4_generic_open(&f, path, "r", false, &inode_up, &name_off);
+    if(r != EOK){
+        EXT4_MP_UNLOCK(mp);
+        return r;
+    }
+
+    path += name_off;
+    len = ext4_path_check(path, &is_goal);
+
+    inode_current = f.inode;
+    dir_end = false;
+    do {
+        /*Load directory node.*/
+        r = ext4_fs_get_inode_ref(&f.mp->fs, inode_current, &current);
+        if(r != EOK){
+            break;
+        }
+
+        /*Initialize iterator.*/
+        r = ext4_dir_iterator_init(&it, &current, 0);
+        if(r != EOK){
+            ext4_fs_put_inode_ref(&current);
+            break;
+        }
+
+        while(r == EOK){
+
+            if(!it.current){
+                dir_end = true;
+                break;
+            }
+
+            /*Get up directory inode when ".." entry*/
+            if((it.current->name_length == 2) &&
+                    ext4_is_dots(it.current->name, it.current->name_length)){
+                inode_up = it.current->inode;
+            }
+
+            /*If directory or file entry,  but not "." ".." entry*/
+            if(!ext4_is_dots(it.current->name, it.current->name_length)){
+
+                /*Get child inode reference do unlink directory/file.*/
+                r = ext4_fs_get_inode_ref(&f.mp->fs, it.current->inode, &child);
+                if(r != EOK)
+                    break;
+
+                /*If directory with no leaf children*/
+                r = ext4_has_children(&has_children, &child);
+                if(r != EOK){
+                    ext4_fs_put_inode_ref(&child);
+                    break;
+                }
+
+                if(has_children){
+                    /*Has directory children. Go into this tirectory.*/
+                    inode_up = inode_current;
+                    inode_current = it.current->inode;
+                    depth++;
+                    ext4_fs_put_inode_ref(&child);
+                    break;
+                }
+
+                /*Directory is empty. Truncate it.*/
+                r = ext4_fs_truncate_inode(&child, 0);
+                if(r != EOK){
+                    ext4_fs_put_inode_ref(&child);
+                    break;
+                }
+
+                /*No children in child directory or file. Just unlink.*/
+                r = ext4_unlink(f.mp, &current, &child,
+                        (char *)it.current->name, it.current->name_length);
+                if(r != EOK){
+                    ext4_fs_put_inode_ref(&child);
+                    break;
+                }
+
+                r = ext4_fs_free_inode(&child);
+                if(r != EOK){
+                    ext4_fs_put_inode_ref(&child);
+                    break;
+                }
+
+                r = ext4_fs_put_inode_ref(&child);
+                if(r != EOK)
+                    break;
+            }
+
+            r = ext4_dir_iterator_next(&it);
+        }
+
+        if(dir_end){
+            /*Directory iterator reached last entry*/
+            ext4_has_children(&has_children, &current);
+            if(!has_children){
+                inode_current = inode_up;
+                if(depth)
+                    depth--;
+            }
+            /*Last unlink*/
+            if(!depth){
+                /*Load parent.*/
+                struct ext4_inode_ref parent;
+                r = ext4_fs_get_inode_ref(&f.mp->fs, inode_up, &parent);
+                if(r != EOK)
+                    goto End;
+
+                r = ext4_fs_truncate_inode(&current, 0);
+                if(r != EOK){
+                    ext4_fs_put_inode_ref(&parent);
+                    goto End;
+                }
+
+                /* In this place all directories should be unlinked.
+                 * Last unlink from root of current directory*/
+                r = ext4_unlink(f.mp, &parent, &current, (char *)path, len);
+                if(r != EOK){
+                    ext4_fs_put_inode_ref(&parent);
+                    goto End;
+                }
+
+                r = ext4_fs_free_inode(&current);
+                if(r != EOK){
+                    ext4_fs_put_inode_ref(&parent);
+                    goto End;
+                }
+
+                r = ext4_fs_put_inode_ref(&parent);
+                if(r != EOK)
+                    goto End;
+            }
+        }
+
+        End:
+        ext4_dir_iterator_fini(&it);
+        ext4_fs_put_inode_ref(&current);
+        dir_end = false;
+
+        /*When something goes wrong. End loop.*/
+        if(r != EOK)
+            break;
+
+    }while(depth);
+
+
+    EXT4_MP_UNLOCK(mp);
+    return r;
+}
+
+int ext4_dir_mk(const char *path)
+{
+    int r;
+    ext4_file   f;
+
+    struct ext4_mountpoint *mp = ext4_get_mount(path);
+
+    if(!mp)
+        return ENOENT;
+
+    EXT4_MP_LOCK(mp);
+
+    /*Check if exist.*/
+    r = ext4_generic_open(&f, path, "r", false, 0, 0);
+    if(r == EOK){
+        /*Directory already created*/
+        EXT4_MP_UNLOCK(mp);
+        return r;
+    }
+
+    /*Create new dir*/
+    r = ext4_generic_open(&f, path, "w", false, 0, 0);
+    if(r != EOK){
+        EXT4_MP_UNLOCK(mp);
+        return r;
+    }
+
+    EXT4_MP_UNLOCK(mp);
+    return r;
+}
+
 int	ext4_dir_open (ext4_dir *d, const char *path)
 {
-    return ext4_generic_open(&d->f, path, "r", false);
+    struct ext4_mountpoint *mp = ext4_get_mount(path);
+    int r;
+
+    if(!mp)
+        return ENOENT;
+
+    EXT4_MP_LOCK(mp);
+    r = ext4_generic_open(&d->f, path, "r", false, 0, 0);
+    EXT4_MP_UNLOCK(mp);
+    return r;
 }
 
 int	ext4_dir_close(ext4_dir *d)
@@ -1154,7 +1325,7 @@
     return ext4_fclose(&d->f);
 }
 
-ext4_direntry*	ext4_entry_get(ext4_dir *d, uint32_t id)
+ext4_direntry*	ext4_dir_entry_get(ext4_dir *d, uint32_t id)
 {
     int 	 r;
     uint32_t i;
@@ -1186,7 +1357,6 @@
             de = &d->de;
             break;
         }
-
 
         i++;
         r = ext4_dir_iterator_next(&it);
--- a/lwext4/ext4_dir.c
+++ b/lwext4/ext4_dir.c
@@ -228,9 +228,21 @@
 
 int ext4_dir_iterator_next(struct ext4_directory_iterator *it)
 {
-    uint16_t skip = ext4_dir_entry_ll_get_entry_length(it->current);
+    int r = EOK;
+    uint16_t skip;
 
-    return ext4_dir_iterator_seek(it, it->current_offset + skip);
+    while(r == EOK){
+        skip = ext4_dir_entry_ll_get_entry_length(it->current);
+        r = ext4_dir_iterator_seek(it, it->current_offset + skip);
+
+        if(!it->current)
+            break;
+		/*Skip NULL referenced entry*/
+        if(it->current->inode != 0)
+            break;
+    }
+
+    return r;
 }
 
 int ext4_dir_iterator_fini(struct ext4_directory_iterator *it)
--- a/lwext4/ext4_fs.c
+++ b/lwext4/ext4_fs.c
@@ -546,7 +546,7 @@
     for (i = 0; i < EXT4_INODE_BLOCKS; i++)
         inode->blocks[i] = 0;
 
-#if 0
+#if CONFIG_EXTENT_ENABLE
     /* Initialize extents if needed */
     if (ext4_sb_check_feature_incompatible(
             &fs->sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
@@ -577,6 +577,7 @@
     struct ext4_fs *fs = inode_ref->fs;
     uint32_t offset;
     uint32_t suboffset;
+#if CONFIG_EXTENT_ENABLE
     /* For extents must be data block destroyed by other way */
     if ((ext4_sb_check_feature_incompatible(&fs->sb,
             EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
@@ -584,7 +585,7 @@
         /* Data structures are released during truncate operation... */
         goto finish;
     }
-
+#endif
     /* Release all indirect (no data) blocks */
 
     /* 1) Single indirect */
@@ -739,18 +740,20 @@
     uint32_t old_blocks_count = old_size / block_size;
     if (old_size % block_size != 0)
         old_blocks_count++;
-
+#if CONFIG_EXTENT_ENABLE
     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;
+
+    } else
 #endif
-    } else {
+    {
         /* Release data blocks from the end of file */
 
         /* Starting from 1 because of logical blocks are numbered from 0 */
@@ -781,13 +784,13 @@
     }
 
     uint32_t current_block;
-
+#if CONFIG_EXTENT_ENABLE
     /* 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;
@@ -794,8 +797,8 @@
 
         *fblock = current_block;
         return EOK;
-#endif
     }
+#endif
 
     struct ext4_inode *inode = inode_ref->inode;
 
@@ -882,6 +885,7 @@
 {
     struct ext4_fs *fs = inode_ref->fs;
 
+#if CONFIG_EXTENT_ENABLE
     /* Handle inode using extents */
     if ((ext4_sb_check_feature_incompatible(&fs->sb,
             EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
@@ -889,6 +893,7 @@
         /* Not reachable */
         return ENOTSUP;
     }
+#endif
 
     /* Handle simple case when we are dealing with direct reference */
     if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
@@ -1136,16 +1141,14 @@
 int ext4_fs_append_inode_block(struct ext4_inode_ref *inode_ref,
     uint32_t *fblock, uint32_t *iblock)
 {
+#if CONFIG_EXTENT_ENABLE
     /* 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
     }
-
+#endif
     struct ext4_sblock *sb = &inode_ref->fs->sb;
 
     /* Compute next block index and allocate data block */