/**@brief Read-write size*/\r
static int rw_count = 1024;\r
\r
+/**@brief Directory test count*/\r
+static int dir_cnt = 10;\r
+\r
static bool cache_mode = false;\r
\r
\r
Welcome in ext4 generic demo. \n\\r
Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com) \n\\r
Usage: \n\\r
- -i - input file (default = ext2) \n\\r
- -rws - single R/W size (default = 1024) \n\\r
- -rwc - R/W count (default = 1024) \n\\r
- -cache - 0 static, 1 dynamic (default = 0) \n\\r
+ -i - input file (default = ext2) \n\\r
+ -rws - single R/W size (default = 1024) \n\\r
+ -rwc - R/W count (default = 1024) \n\\r
+ -cache - 0 static, 1 dynamic (default = 0) \n\\r
+ -dirs - directory test count (default = 0) \n\\r
\n";\r
\r
static char* entry_to_str(uint8_t type)\r
printf("**********************************************\n");\r
\r
ext4_dir_open(&d, path);\r
- de = ext4_entry_get(&d, j++);\r
+ de = ext4_dir_entry_get(&d, j++);\r
printf("ls %s\n", path);\r
\r
while(de){\r
printf(entry_to_str(de->inode_type));\r
printf(sss);\r
printf("\n");\r
- de = ext4_entry_get(&d, j++);\r
+ de = ext4_dir_entry_get(&d, j++);\r
}\r
printf("**********************************************\n");\r
ext4_dir_close(&d);\r
\r
printf("**********************************************\n");\r
printf("ext4_mount_point_stats\n");\r
- printf("inodes_count = %d\n", stats.inodes_count);\r
- printf("free_inodes_count = %d\n", stats.free_inodes_count);\r
- printf("blocks_count = %d\n", stats.blocks_count);\r
- printf("free_blocks_count = %d\n", stats.free_blocks_count);\r
- printf("block_size = %d\n", stats.block_size);\r
- printf("block_group_count = %d\n", stats.block_group_count);\r
- printf("blocks_per_group = %d\n", stats.blocks_per_group);\r
- printf("inodes_per_group = %d\n", stats.inodes_per_group);\r
+ printf("inodes_count = %u\n", stats.inodes_count);\r
+ printf("free_inodes_count = %u\n", stats.free_inodes_count);\r
+ printf("blocks_count = %u\n", (uint32_t)stats.blocks_count);\r
+ printf("free_blocks_count = %u\n", (uint32_t)stats.free_blocks_count);\r
+ printf("block_size = %u\n", stats.block_size);\r
+ printf("block_group_count = %u\n", stats.block_group_count);\r
+ printf("blocks_per_group = %u\n", stats.blocks_per_group);\r
+ printf("inodes_per_group = %u\n", stats.inodes_per_group);\r
printf("volume_name = %s\n", stats.volume_name);\r
\r
printf("**********************************************\n");\r
\r
printf("**********************************************\n");\r
printf("ext4 blockdev stats\n");\r
- printf("bdev->bread_ctr = %d\n", bd->bread_ctr);\r
- printf("bdev->bwrite_ctr = %d\n", bd->bwrite_ctr);\r
+ printf("bdev->bread_ctr = %u\n", bd->bread_ctr);\r
+ printf("bdev->bwrite_ctr = %u\n", bd->bwrite_ctr);\r
\r
\r
- printf("bcache->ref_blocks = %d\n", bc->ref_blocks);\r
- printf("bcache->max_ref_blocks = %d\n", bc->max_ref_blocks);\r
- printf("bcache->lru_ctr = %d\n", bc->lru_ctr);\r
+ printf("bcache->ref_blocks = %u\n", bc->ref_blocks);\r
+ printf("bcache->max_ref_blocks = %u\n", bc->max_ref_blocks);\r
+ printf("bcache->lru_ctr = %u\n", bc->lru_ctr);\r
\r
printf("\n");\r
for (i = 0; i < bc->cnt; ++i) {\r
- printf("bcache->refctr[%d] = %d\n", i, bc->refctr[i]);\r
+ printf("bcache->refctr[%d] = %u\n", i, bc->refctr[i]);\r
}\r
\r
printf("\n");\r
for (i = 0; i < bc->cnt; ++i) {\r
- printf("bcache->lru_id[%d] = %d\n", i, bc->lru_id[i]);\r
+ printf("bcache->lru_id[%d] = %u\n", i, bc->lru_id[i]);\r
}\r
\r
printf("\n");\r
\r
printf("\n");\r
for (i = 0; i < bc->cnt; ++i) {\r
- printf("bcache->lba[%d] = %d\n", i, bc->lba[i]);\r
+ printf("bcache->lba[%d] = %u\n", i, (uint32_t)bc->lba[i]);\r
}\r
\r
\r
printf("**********************************************\n");\r
}\r
\r
+static bool dir_test(int len)\r
+{\r
+ ext4_file f;\r
+ int r;\r
+ int i;\r
+ char path[64];\r
+\r
+ printf("Remove directory /mp/dir1\n");\r
+ ext4_dir_rm("/mp/dir1");\r
+\r
+\r
+ printf("Directory create: /mp/dir1\n");\r
+ r = ext4_dir_mk("/mp/dir1");\r
+ if(r != EOK){\r
+ printf("Unable to create directory: /mp/dir1\n");\r
+ return false;\r
+ }\r
+\r
+\r
+ printf("Add files to: /mp/dir1\n");\r
+ for (i = 0; i < len; ++i) {\r
+ sprintf(path, "/mp/dir1/f%d", i);\r
+ r = ext4_fopen(&f, path, "wb");\r
+ if(r != EOK){\r
+ printf("Unable to create file in directory: /mp/dir1\n");\r
+ return false;\r
+ }\r
+ }\r
+\r
+ printf("Add directories to: /mp/dir1\n");\r
+ for (i = 0; i < len; ++i) {\r
+ sprintf(path, "/mp/dir1/d%d", i);\r
+ r = ext4_dir_mk(path);\r
+ if(r != EOK){\r
+ printf("Unable to create directory in directory: /mp/dir1\n");\r
+ return false;\r
+ }\r
+ }\r
+\r
+ printf("Add file directories in: /mp/dir1\n");\r
+\r
+ for (i = 0; i < len; ++i) {\r
+ sprintf(path, "/mp/dir1/d%d/ff", i);\r
+ r = ext4_fopen(&f, path, "wb");\r
+ if(r != EOK){\r
+ printf("Unable to create file in directory: /mp/dir1\n");\r
+ return false;\r
+ }\r
+ }\r
+\r
+ dir_ls("/mp/dir1");\r
+ return true;\r
+}\r
\r
int main(int argc, char **argv)\r
{\r
{"rws", required_argument, 0, 'b'},\r
{"rwc", required_argument, 0, 'c'},\r
{"cache", required_argument, 0, 'd'},\r
+ {"dirs", required_argument, 0, 'e'},\r
{0, 0, 0, 0}\r
};\r
\r
- while(-1 != (c = getopt_long (argc, argv, "a:b:c:d:", long_options, &option_index))) {\r
+ while(-1 != (c = getopt_long (argc, argv, "a:b:c:d:e:", long_options, &option_index))) {\r
\r
switch(c){\r
case 'a':\r
case 'd':\r
cache_mode = atoi(optarg);\r
break;\r
+ case 'e':\r
+ dir_cnt = atoi(optarg);\r
+ break;\r
default:\r
printf(usage);\r
return EXIT_FAILURE;\r
return EXIT_FAILURE;\r
}\r
\r
+ dir_test(dir_cnt);\r
\r
ext4_fremove("/mp/hello.txt");\r
ext4_fremove("/mp/test1");\r
#include <ext4_blockdev.h>\r
#include <stdint.h>\r
\r
-/********************************FILE OPEN FLAGS********************************/\r
+/********************************FILE OPEN FLAGS*****************************/\r
\r
#ifndef O_RDONLY\r
-#define O_RDONLY 00\r
+#define O_RDONLY 00\r
#endif\r
\r
#ifndef O_WRONLY\r
-#define O_WRONLY 01\r
+#define O_WRONLY 01\r
#endif\r
\r
#ifndef O_RDWR\r
-#define O_RDWR 02\r
+#define O_RDWR 02\r
#endif\r
\r
#ifndef O_CREAT\r
-#define O_CREAT 0100\r
+#define O_CREAT 0100\r
#endif\r
\r
#ifndef O_EXCL\r
-#define O_EXCL 0200\r
+#define O_EXCL 0200\r
#endif\r
\r
#ifndef O_TRUNC\r
-#define O_TRUNC 01000\r
+#define O_TRUNC 01000\r
#endif\r
\r
#ifndef O_APPEND\r
-#define O_APPEND 02000\r
+#define O_APPEND 02000\r
#endif\r
\r
/********************************FILE SEEK FLAGS*****************************/\r
EXT4_DIRENTRY_SYMLINK\r
};\r
\r
-/**@brief Directory entry descriptor. Copy from ext4_types.h*/\r
+/**@brief Directory entry descriptor. Copy from ext4_types.h*/\r
typedef struct {\r
uint32_t inode;\r
uint16_t entry_length;\r
int ext4_umount(char *mount_point);\r
\r
\r
-/**@brief Some of the filesystem params.*/\r
+/**@brief Some of the filesystem stats.*/\r
struct ext4_mount_stats {\r
uint32_t inodes_count;\r
uint32_t free_inodes_count;\r
char volume_name[16];\r
};\r
\r
+/**@brief Get file system params.\r
+ * @param mount_point mount path\r
+ * @param stats ext fs stats\r
+ * @return standard error code */\r
int ext4_mount_point_stats(const char *mount_point,\r
struct ext4_mount_stats *stats);\r
\r
/********************************FILE OPERATIONS*****************************/\r
\r
-/**@brief */\r
+/**@brief Remove file by path.\r
+ * @param path path to file\r
+ * @return standard error code */\r
int ext4_fremove(const char *path);\r
\r
/**@brief File open function.\r
* @return standard error code*/\r
int ext4_fopen (ext4_file *f, const char *path, const char *flags);\r
\r
-/**@brief */\r
+/**@brief File close function.\r
+ * @param f file handle\r
+ * @return standard error code*/\r
int ext4_fclose(ext4_file *f);\r
\r
-/**@brief */\r
+/**@brief Read data from file.\r
+ * @param f file handle\r
+ * @param buf output buffer\r
+ * @param size bytes to read\r
+ * @param rcnt readed bytes (may be NULL)\r
+ * @return standard error code*/\r
int ext4_fread (ext4_file *f, void *buf, uint32_t size, uint32_t *rcnt);\r
\r
-/**@brief */\r
+/**@brief Write data to file.\r
+ * @param f file handle\r
+ * @param buf data to write\r
+ * @param size write length\r
+ * @param wcnt bytes written (may be NULL)\r
+ * @return standard error code*/\r
int ext4_fwrite(ext4_file *f, void *buf, uint32_t size, uint32_t *wcnt);\r
\r
-/**@brief */\r
+/**@brief File seek operation.\r
+ * @param f file handle\r
+ * @param offset offset to seek\r
+ * @param origin seek type:\r
+ * @ref SEEK_SET\r
+ * @ref SEEK_CUR\r
+ * @ref SEEK_END\r
+ * @return standard error code*/\r
int ext4_fseek (ext4_file *f, uint64_t offset, uint32_t origin);\r
\r
-/**@brief */\r
+/**@brief Get file position.\r
+ * @param f file handle\r
+ * @return actual file position */\r
uint64_t ext4_ftell (ext4_file *f);\r
\r
-/**@brief */\r
+/**@brief Get file size.\r
+ * @param f file handle\r
+ * @return file size */\r
uint64_t ext4_fsize (ext4_file *f);\r
\r
/*********************************DIRECTORY OPERATION***********************/\r
-/**@brief */\r
-int ext4_mkdir(const char *path);\r
\r
-/**@brief */\r
-int ext4_rmdir(const char *path);\r
+/**@brief Recursive directory remove.\r
+ * @param path directory path to remove\r
+ * @return standard error code*/\r
+int ext4_dir_rm(const char *path);\r
\r
-/**@brief */\r
+/**@brief Create new directory.\r
+ * @param name new directory name\r
+ * @return standard error code*/\r
+int ext4_dir_mk(const char *path);\r
+\r
+/**@brief Directory open.\r
+ * @param d directory handle\r
+ * @param path directory path\r
+ * @return standard error code*/\r
int ext4_dir_open (ext4_dir *d, const char *path);\r
\r
-/**@brief */\r
+/**@brief Directory close.\r
+ * @param d directory handle\r
+ * @return standard error code*/\r
int ext4_dir_close(ext4_dir *d);\r
\r
-/**@brief */\r
-ext4_direntry* ext4_entry_get(ext4_dir *d, uint32_t id);\r
+\r
+/**@brief Return directory entry by id.\r
+ * @param d directory handle\r
+ * @param id entry id\r
+ * @return directory entry id (NULL id no entry)*/\r
+ext4_direntry* ext4_dir_entry_get(ext4_dir *d, uint32_t id);\r
\r
#endif /* EXT4_H_ */\r
\r
\r
/**@brief Mount point OS dependent lock*/\r
#define EXT4_MP_LOCK(_m) \\r
- do { (_m)->os_locks ? (_m)->os_locks->lock() : 0; }while(0)\r
+ do { (_m)->os_locks ? (_m)->os_locks->lock() : 0; }while(0)\r
\r
/**@brief Mount point OS dependent unlock*/\r
#define EXT4_MP_UNLOCK(_m) \\r
- do { (_m)->os_locks ? (_m)->os_locks->unlock() : 0; }while(0)\r
+ do { (_m)->os_locks ? (_m)->os_locks->unlock() : 0; }while(0)\r
\r
/**@brief Mount point descrpitor.*/\r
struct ext4_mountpoint {\r
return 0;\r
}\r
\r
-\r
static bool ext4_parse_flags(const char *flags, uint32_t *file_flags)\r
{\r
if(!flags)\r
/****************************************************************************/\r
\r
static int ext4_generic_open (ext4_file *f, const char *path,\r
- const char *flags, bool file_expect)\r
+ const char *flags, bool file_expect, uint32_t *parent_inode, uint32_t *name_off)\r
{\r
struct ext4_mountpoint *mp = ext4_get_mount(path);\r
struct ext4_directory_search_result result;\r
/*Skip mount point*/\r
path += strlen(mp->name);\r
\r
- EXT4_MP_LOCK(mp);\r
+ if(name_off)\r
+ *name_off = strlen(mp->name);\r
\r
/*Load root*/\r
r = ext4_fs_get_inode_ref(&mp->fs, EXT4_INODE_ROOT_INDEX, &ref);\r
if(r != EOK)\r
return r;\r
\r
- int len = ext4_path_check(path, &is_goal);\r
+ if(parent_inode)\r
+ *parent_inode = ref.index;\r
\r
- /*If root open was request.*/\r
- if(!len && is_goal)\r
- goto IsGoal;\r
+ int len = ext4_path_check(path, &is_goal);\r
\r
while(1){\r
\r
len = ext4_path_check(path, &is_goal);\r
\r
if(!len){\r
+ /*If root open was request.*/\r
+ if(is_goal && !file_expect)\r
+ break;\r
+\r
r = ENOENT;\r
break;\r
}\r
if(!(f->flags & O_CREAT))\r
break;\r
\r
- /*O_CREAT allows to create new entry*/\r
+ /*O_CREAT allows create new entry*/\r
struct ext4_inode_ref child_ref;\r
- r = ext4_fs_alloc_inode(&mp->fs, &child_ref, !is_goal);\r
+ r = ext4_fs_alloc_inode(&mp->fs, &child_ref, is_goal ? !file_expect : true);\r
if(r != EOK)\r
break;\r
\r
continue;\r
}\r
\r
+ if(parent_inode)\r
+ *parent_inode = ref.index;\r
+\r
next_inode = result.dentry->inode;\r
inode_type = ext4_dir_entry_ll_get_inode_type(&mp->fs.sb, result.dentry);\r
\r
break;\r
\r
path += len + 1;\r
+\r
+ if(name_off)\r
+ *name_off += len + 1;\r
};\r
\r
if(r != EOK){\r
ext4_fs_put_inode_ref(&ref);\r
- EXT4_MP_UNLOCK(mp);\r
return r;\r
}\r
\r
- IsGoal:\r
if(is_goal){\r
\r
- if(f->flags & O_TRUNC){\r
+ if((f->flags & O_TRUNC) &&\r
+ (inode_type == EXT4_DIRECTORY_FILETYPE_REG_FILE)){\r
/*Turncate.*/\r
ext4_block_delay_cache_flush(mp->fs.bdev, 1);\r
/*Truncate may be IO heavy.\r
\r
if(r != EOK){\r
ext4_fs_put_inode_ref(&ref);\r
- EXT4_MP_UNLOCK(mp);\r
return r;\r
}\r
}\r
}\r
\r
r = ext4_fs_put_inode_ref(&ref);\r
- EXT4_MP_UNLOCK(mp);\r
return r;\r
}\r
\r
\r
int ext4_fremove(const char *path)\r
{\r
+ ext4_file f;\r
+ uint32_t parent_inode;\r
+ uint32_t name_off;\r
+ int r;\r
+ int len;\r
+ bool is_goal;\r
struct ext4_mountpoint *mp = ext4_get_mount(path);\r
- struct ext4_directory_search_result result;\r
- bool is_goal = false;\r
- uint8_t inode_type;\r
- int r = ENOENT;\r
- uint32_t next_inode;\r
\r
- struct ext4_inode_ref parent;\r
- struct ext4_inode_ref child;\r
- int len = 0;\r
+ struct ext4_inode_ref child;\r
+ struct ext4_inode_ref parent;\r
\r
if(!mp)\r
return ENOENT;\r
\r
-\r
- /*Skip mount point*/\r
- path += strlen(mp->name);\r
-\r
- /*Lock mountpoint*/\r
EXT4_MP_LOCK(mp);\r
-\r
- /*Load root*/\r
- r = ext4_fs_get_inode_ref(&mp->fs, EXT4_INODE_ROOT_INDEX, &parent);\r
-\r
+ r = ext4_generic_open(&f, path, "r", true, &parent_inode, &name_off);\r
if(r != EOK){\r
EXT4_MP_UNLOCK(mp);\r
return r;\r
}\r
\r
- while(1){\r
-\r
- len = ext4_path_check(path, &is_goal);\r
-\r
- if(!len){\r
- r = ENOENT;\r
- break;\r
- }\r
-\r
- r = ext4_dir_find_entry(&result, &parent, path, len);\r
- if(r != EOK){\r
- ext4_dir_destroy_result(&parent, &result);\r
- break;\r
- }\r
-\r
- next_inode = result.dentry->inode;\r
- inode_type = ext4_dir_entry_ll_get_inode_type(&mp->fs.sb,\r
- result.dentry);\r
-\r
- r = ext4_dir_destroy_result(&parent, &result);\r
- if(r != EOK)\r
- break;\r
-\r
- /*If expected file error*/\r
- if((inode_type == EXT4_DIRECTORY_FILETYPE_REG_FILE) && !is_goal){\r
- r = ENOENT;\r
- break;\r
- }\r
-\r
- /*If expected directory error*/\r
- if((inode_type == EXT4_DIRECTORY_FILETYPE_DIR) && is_goal){\r
- r = ENOENT;\r
- break;\r
- }\r
-\r
- if(is_goal)\r
- break;\r
-\r
- r = ext4_fs_put_inode_ref(&parent);\r
- if(r != EOK)\r
- break;\r
-\r
-\r
- r = ext4_fs_get_inode_ref(&mp->fs, next_inode, &parent);\r
- if(r != EOK)\r
- break;\r
-\r
- path += len + 1;\r
- };\r
-\r
+ /*Load parent*/\r
+ r = ext4_fs_get_inode_ref(&mp->fs, parent_inode, &parent);\r
if(r != EOK){\r
- /*No entry or other error.*/\r
- ext4_fs_put_inode_ref(&parent);\r
EXT4_MP_UNLOCK(mp);\r
return r;\r
}\r
\r
-\r
/*We have file to delete. Load it.*/\r
- r = ext4_fs_get_inode_ref(&mp->fs, next_inode, &child);\r
+ r = ext4_fs_get_inode_ref(&mp->fs, f.inode, &child);\r
if(r != EOK){\r
- /*Parent free*/\r
ext4_fs_put_inode_ref(&parent);\r
EXT4_MP_UNLOCK(mp);\r
return r;\r
\r
/*Turncate.*/\r
ext4_block_delay_cache_flush(mp->fs.bdev, 1);\r
-\r
/*Truncate may be IO heavy. Do it with delayed cache flush mode.*/\r
r = ext4_fs_truncate_inode(&child, 0);\r
-\r
ext4_block_delay_cache_flush(mp->fs.bdev, 0);\r
+\r
if(r != EOK)\r
goto Finish;\r
\r
+ /*Set path*/\r
+ path += name_off;\r
+\r
+ len = ext4_path_check(path, &is_goal);\r
+\r
/*Unlink from parent.*/\r
r = ext4_unlink(mp, &parent, &child, path, len);\r
if(r != EOK)\r
if(r != EOK)\r
goto Finish;\r
\r
-\r
Finish:\r
ext4_fs_put_inode_ref(&child);\r
ext4_fs_put_inode_ref(&parent);\r
\r
int ext4_fopen (ext4_file *f, const char *path, const char *flags)\r
{\r
- return ext4_generic_open(f, path, flags, true);\r
+ struct ext4_mountpoint *mp = ext4_get_mount(path);\r
+ int r;\r
+\r
+ if(!mp)\r
+ return ENOENT;\r
+\r
+ EXT4_MP_LOCK(mp);\r
+ r = ext4_generic_open(f, path, flags, true, 0, 0);\r
+ EXT4_MP_UNLOCK(mp);\r
+ return r;\r
}\r
\r
int ext4_fclose(ext4_file *f)\r
\r
/*********************************DIRECTORY OPERATION************************/\r
\r
+int ext4_dir_rm(const char *path)\r
+{\r
+ int r;\r
+ int len;\r
+ ext4_file f;\r
+ struct ext4_mountpoint *mp = ext4_get_mount(path);\r
+ struct ext4_inode_ref current;\r
+ struct ext4_inode_ref child;\r
+\r
+ struct ext4_directory_iterator it;\r
+ uint32_t name_off;\r
+ uint32_t inode_up;\r
+ uint32_t inode_current;\r
+ uint32_t depth = 1;\r
+ bool has_children;\r
+ bool is_goal;\r
+ bool dir_end;\r
+\r
+ if(!mp)\r
+ return ENOENT;\r
+\r
+ EXT4_MP_LOCK(mp);\r
+\r
+ /*Check if exist.*/\r
+ r = ext4_generic_open(&f, path, "r", false, &inode_up, &name_off);\r
+ if(r != EOK){\r
+ EXT4_MP_UNLOCK(mp);\r
+ return r;\r
+ }\r
+\r
+ path += name_off;\r
+ len = ext4_path_check(path, &is_goal);\r
+\r
+ inode_current = f.inode;\r
+ dir_end = false;\r
+ do {\r
+ /*Load directory node.*/\r
+ r = ext4_fs_get_inode_ref(&f.mp->fs, inode_current, ¤t);\r
+ if(r != EOK){\r
+ break;\r
+ }\r
+\r
+ /*Initialize iterator.*/\r
+ r = ext4_dir_iterator_init(&it, ¤t, 0);\r
+ if(r != EOK){\r
+ ext4_fs_put_inode_ref(¤t);\r
+ break;\r
+ }\r
+\r
+ while(r == EOK){\r
+\r
+ if(!it.current){\r
+ dir_end = true;\r
+ break;\r
+ }\r
+\r
+ /*Get up directory inode when ".." entry*/\r
+ if((it.current->name_length == 2) &&\r
+ ext4_is_dots(it.current->name, it.current->name_length)){\r
+ inode_up = it.current->inode;\r
+ }\r
+\r
+ /*If directory or file entry, but not "." ".." entry*/\r
+ if(!ext4_is_dots(it.current->name, it.current->name_length)){\r
+\r
+ /*Get child inode reference do unlink directory/file.*/\r
+ r = ext4_fs_get_inode_ref(&f.mp->fs, it.current->inode, &child);\r
+ if(r != EOK)\r
+ break;\r
+\r
+ /*If directory with no leaf children*/\r
+ r = ext4_has_children(&has_children, &child);\r
+ if(r != EOK){\r
+ ext4_fs_put_inode_ref(&child);\r
+ break;\r
+ }\r
+\r
+ if(has_children){\r
+ /*Has directory children. Go into this tirectory.*/\r
+ inode_up = inode_current;\r
+ inode_current = it.current->inode;\r
+ depth++;\r
+ ext4_fs_put_inode_ref(&child);\r
+ break;\r
+ }\r
+\r
+ /*Directory is empty. Truncate it.*/\r
+ r = ext4_fs_truncate_inode(&child, 0);\r
+ if(r != EOK){\r
+ ext4_fs_put_inode_ref(&child);\r
+ break;\r
+ }\r
+\r
+ /*No children in child directory or file. Just unlink.*/\r
+ r = ext4_unlink(f.mp, ¤t, &child,\r
+ (char *)it.current->name, it.current->name_length);\r
+ if(r != EOK){\r
+ ext4_fs_put_inode_ref(&child);\r
+ break;\r
+ }\r
+\r
+ r = ext4_fs_free_inode(&child);\r
+ if(r != EOK){\r
+ ext4_fs_put_inode_ref(&child);\r
+ break;\r
+ }\r
+\r
+ r = ext4_fs_put_inode_ref(&child);\r
+ if(r != EOK)\r
+ break;\r
+ }\r
+\r
+ r = ext4_dir_iterator_next(&it);\r
+ }\r
+\r
+ if(dir_end){\r
+ /*Directory iterator reached last entry*/\r
+ ext4_has_children(&has_children, ¤t);\r
+ if(!has_children){\r
+ inode_current = inode_up;\r
+ if(depth)\r
+ depth--;\r
+ }\r
+ /*Last unlink*/\r
+ if(!depth){\r
+ /*Load parent.*/\r
+ struct ext4_inode_ref parent;\r
+ r = ext4_fs_get_inode_ref(&f.mp->fs, inode_up, &parent);\r
+ if(r != EOK)\r
+ goto End;\r
+\r
+ r = ext4_fs_truncate_inode(¤t, 0);\r
+ if(r != EOK){\r
+ ext4_fs_put_inode_ref(&parent);\r
+ goto End;\r
+ }\r
+\r
+ /* In this place all directories should be unlinked.\r
+ * Last unlink from root of current directory*/\r
+ r = ext4_unlink(f.mp, &parent, ¤t, (char *)path, len);\r
+ if(r != EOK){\r
+ ext4_fs_put_inode_ref(&parent);\r
+ goto End;\r
+ }\r
+\r
+ r = ext4_fs_free_inode(¤t);\r
+ if(r != EOK){\r
+ ext4_fs_put_inode_ref(&parent);\r
+ goto End;\r
+ }\r
+\r
+ r = ext4_fs_put_inode_ref(&parent);\r
+ if(r != EOK)\r
+ goto End;\r
+ }\r
+ }\r
+\r
+ End:\r
+ ext4_dir_iterator_fini(&it);\r
+ ext4_fs_put_inode_ref(¤t);\r
+ dir_end = false;\r
+\r
+ /*When something goes wrong. End loop.*/\r
+ if(r != EOK)\r
+ break;\r
+\r
+ }while(depth);\r
+\r
+\r
+ EXT4_MP_UNLOCK(mp);\r
+ return r;\r
+}\r
+\r
+int ext4_dir_mk(const char *path)\r
+{\r
+ int r;\r
+ ext4_file f;\r
+\r
+ struct ext4_mountpoint *mp = ext4_get_mount(path);\r
+\r
+ if(!mp)\r
+ return ENOENT;\r
+\r
+ EXT4_MP_LOCK(mp);\r
+\r
+ /*Check if exist.*/\r
+ r = ext4_generic_open(&f, path, "r", false, 0, 0);\r
+ if(r == EOK){\r
+ /*Directory already created*/\r
+ EXT4_MP_UNLOCK(mp);\r
+ return r;\r
+ }\r
+\r
+ /*Create new dir*/\r
+ r = ext4_generic_open(&f, path, "w", false, 0, 0);\r
+ if(r != EOK){\r
+ EXT4_MP_UNLOCK(mp);\r
+ return r;\r
+ }\r
+\r
+ EXT4_MP_UNLOCK(mp);\r
+ return r;\r
+}\r
+\r
int ext4_dir_open (ext4_dir *d, const char *path)\r
{\r
- return ext4_generic_open(&d->f, path, "r", false);\r
+ struct ext4_mountpoint *mp = ext4_get_mount(path);\r
+ int r;\r
+\r
+ if(!mp)\r
+ return ENOENT;\r
+\r
+ EXT4_MP_LOCK(mp);\r
+ r = ext4_generic_open(&d->f, path, "r", false, 0, 0);\r
+ EXT4_MP_UNLOCK(mp);\r
+ return r;\r
}\r
\r
int ext4_dir_close(ext4_dir *d)\r
return ext4_fclose(&d->f);\r
}\r
\r
-ext4_direntry* ext4_entry_get(ext4_dir *d, uint32_t id)\r
+ext4_direntry* ext4_dir_entry_get(ext4_dir *d, uint32_t id)\r
{\r
int r;\r
uint32_t i;\r
break;\r
}\r
\r
-\r
i++;\r
r = ext4_dir_iterator_next(&it);\r
}\r
\r
int ext4_dir_iterator_next(struct ext4_directory_iterator *it)\r
{\r
- uint16_t skip = ext4_dir_entry_ll_get_entry_length(it->current);\r
+ int r = EOK;\r
+ uint16_t skip;\r
\r
- return ext4_dir_iterator_seek(it, it->current_offset + skip);\r
+ while(r == EOK){\r
+ skip = ext4_dir_entry_ll_get_entry_length(it->current);\r
+ r = ext4_dir_iterator_seek(it, it->current_offset + skip);\r
+\r
+ if(!it->current)\r
+ break;\r
+ /*Skip NULL referenced entry*/\r
+ if(it->current->inode != 0)\r
+ break;\r
+ }\r
+\r
+ return r;\r
}\r
\r
int ext4_dir_iterator_fini(struct ext4_directory_iterator *it)\r
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)) {
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)) &&
/* Data structures are released during truncate operation... */
goto finish;
}
-
+#endif
/* Release all indirect (no data) blocks */
/* 1) Single indirect */
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 */
}
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, ¤t_block);
if (rc != EOK)
return rc;
*fblock = current_block;
return EOK;
-#endif
}
+#endif
struct ext4_inode *inode = inode_ref->inode;
{
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)) &&
/* Not reachable */
return ENOTSUP;
}
+#endif
/* Handle simple case when we are dealing with direct reference */
if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
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 */