ref: eec357955403829d0751bf82a4407061a3c52bec
parent: dba02ea68719d50d0fd45d4edf2eac5f81c83fd6
author: ngkaho1234 <ngkaho1234@gmail.com>
date: Fri Jan 15 18:41:29 EST 2016
ext4: bring the support of recursive removal of directory back.
--- a/lwext4/ext4.c
+++ b/lwext4/ext4.c
@@ -2498,13 +2498,18 @@
ext4_file f;
struct ext4_mountpoint *mp = ext4_get_mount(path);
- struct ext4_inode_ref act, parent;
+ struct ext4_inode_ref act;
+ struct ext4_inode_ref child;
+ struct ext4_dir_iter it;
uint32_t name_off;
- uint32_t inode_up, inode_current;
+ uint32_t inode_up;
+ uint32_t inode_current;
+ uint32_t depth = 1;
- bool has_children = false;
+ bool has_children;
bool is_goal;
+ bool dir_end;
if (!mp)
return ENOENT;
@@ -2511,6 +2516,8 @@
EXT4_MP_LOCK(mp);
+ struct ext4_fs *const fs = &mp->fs;
+
/*Check if exist.*/
r = ext4_generic_open(&f, path, "r", false, &inode_up, &name_off);
if (r != EOK) {
@@ -2526,74 +2533,188 @@
ext4_block_cache_write_back(mp->fs.bdev, 1);
- /*Load parent.*/
- r = ext4_fs_get_inode_ref(&f.mp->fs, inode_up,
- &parent);
- if (r != EOK)
- goto Finish;
- r = ext4_fs_get_inode_ref(&f.mp->fs, inode_current,
- &act);
- if (r != EOK) {
- ext4_fs_put_inode_ref(&parent);
- goto Finish;
- }
- r = ext4_has_children(&has_children, &act);
- if (r != EOK) {
- ext4_fs_put_inode_ref(&parent);
- ext4_fs_put_inode_ref(&act);
- goto Finish;
- }
- if (has_children) {
- r = ENOTEMPTY;
- ext4_fs_put_inode_ref(&parent);
- ext4_fs_put_inode_ref(&act);
- goto Finish;
- }
+ do {
- ext4_trans_start(mp);
+ uint64_t act_curr_pos = 0;
+ has_children = false;
+ dir_end = false;
- if (ext4_inode_get_links_cnt(act.inode) == 2) {
- /*Truncate*/
- r = ext4_fs_truncate_inode(&act, 0);
+ while (r == EOK && !has_children && !dir_end) {
+
+ /*Load directory node.*/
+ r = ext4_fs_get_inode_ref(fs, inode_current, &act);
+ if (r != EOK) {
+ break;
+ }
+
+ /*Initialize iterator.*/
+ r = ext4_dir_iterator_init(&it, &act, act_curr_pos);
+ if (r != EOK) {
+ ext4_fs_put_inode_ref(&act);
+ break;
+ }
+
+ if (!it.curr) {
+ dir_end = true;
+ goto End;
+ }
+
+ ext4_trans_start(mp);
+
+ /*Get up directory inode when ".." entry*/
+ if ((it.curr->name_len == 2) &&
+ ext4_is_dots(it.curr->name, it.curr->name_len)) {
+ inode_up = ext4_dir_en_get_inode(it.curr);
+ }
+
+ /*If directory or file entry, but not "." ".." entry*/
+ if (!ext4_is_dots(it.curr->name, it.curr->name_len)) {
+
+ /*Get child inode reference do unlink
+ * directory/file.*/
+ uint32_t cinode;
+ cinode = ext4_dir_en_get_inode(it.curr);
+ r = ext4_fs_get_inode_ref(fs, cinode, &child);
+ if (r != EOK)
+ goto End;
+
+ /*If directory with no leaf children*/
+ r = ext4_has_children(&has_children, &child);
+ if (r != EOK) {
+ ext4_fs_put_inode_ref(&child);
+ goto End;
+ }
+
+ if (has_children) {
+ /*Has directory children. Go into this
+ * directory.*/
+ inode_up = inode_current;
+ inode_current = cinode;
+ depth++;
+ ext4_fs_put_inode_ref(&child);
+ goto End;
+ }
+
+ /* Truncate */
+ r = ext4_fs_truncate_inode(&child, 0);
+ if (r != EOK) {
+ ext4_fs_put_inode_ref(&child);
+ goto End;
+ }
+
+ /*No children in child directory or file. Just
+ * unlink.*/
+ r = ext4_unlink(f.mp, &act, &child,
+ (char *)it.curr->name,
+ it.curr->name_len);
+ if (r != EOK) {
+ ext4_fs_put_inode_ref(&child);
+ goto End;
+ }
+
+ ext4_inode_set_del_time(child.inode, -1L);
+ ext4_inode_set_links_cnt(child.inode, 0);
+ child.dirty = true;
+
+ r = ext4_fs_free_inode(&child);
+ if (r != EOK) {
+ ext4_fs_put_inode_ref(&child);
+ goto End;
+ }
+
+ r = ext4_fs_put_inode_ref(&child);
+ if (r != EOK)
+ goto End;
+
+ }
+
+ r = ext4_dir_iterator_next(&it);
+ if (r != EOK)
+ goto End;
+
+ act_curr_pos = it.curr_off;
+End:
+ ext4_dir_iterator_fini(&it);
+ if (r == EOK)
+ r = ext4_fs_put_inode_ref(&act);
+ else
+ ext4_fs_put_inode_ref(&act);
+
+ if (r != EOK)
+ ext4_trans_abort(mp);
+ else
+ ext4_trans_stop(mp);
+ }
+
+ if (dir_end) {
+ /*Directory iterator reached last entry*/
+ depth--;
+ if (depth)
+ inode_current = inode_up;
+
+ }
+
+ } while (depth);
+
+ /*Last unlink*/
+ if (r == EOK && !depth) {
+ /*Load parent.*/
+ struct ext4_inode_ref parent;
+ r = ext4_fs_get_inode_ref(&f.mp->fs, inode_up,
+ &parent);
+ if (r != EOK)
+ goto Finish;
+ r = ext4_fs_get_inode_ref(&f.mp->fs, inode_current,
+ &act);
if (r != EOK) {
- ext4_fs_put_inode_ref(&parent);
ext4_fs_put_inode_ref(&act);
goto Finish;
}
- }
- /* Unlink from root of current directory*/
- r = ext4_unlink(f.mp, &parent, &act,
- (char *)path, len);
- if (r != EOK) {
- ext4_fs_put_inode_ref(&parent);
- ext4_fs_put_inode_ref(&act);
- goto Finish;
- }
+ ext4_trans_start(mp);
- if (ext4_inode_get_links_cnt(act.inode) == 2) {
- ext4_inode_set_del_time(act.inode, -1L);
- ext4_inode_set_links_cnt(act.inode, 0);
- act.dirty = true;
-
- r = ext4_fs_free_inode(&act);
+ /* In this place all directories should be
+ * unlinked.
+ * Last unlink from root of current directory*/
+ r = ext4_unlink(f.mp, &parent, &act,
+ (char *)path, len);
if (r != EOK) {
ext4_fs_put_inode_ref(&parent);
ext4_fs_put_inode_ref(&act);
goto Finish;
}
- }
- r = ext4_fs_put_inode_ref(&parent);
- if (r != EOK)
- goto Finish;
+ if (ext4_inode_get_links_cnt(act.inode) == 2) {
+ ext4_inode_set_del_time(act.inode, -1L);
+ ext4_inode_set_links_cnt(act.inode, 0);
+ act.dirty = true;
+ /*Turncate*/
+ r = ext4_fs_truncate_inode(&act, 0);
+ if (r != EOK) {
+ ext4_fs_put_inode_ref(&parent);
+ ext4_fs_put_inode_ref(&act);
+ goto Finish;
+ }
- r = ext4_fs_put_inode_ref(&act);
-Finish:
- if (r != EOK)
- ext4_trans_abort(mp);
- else
- ext4_trans_stop(mp);
+ r = ext4_fs_free_inode(&act);
+ if (r != EOK) {
+ ext4_fs_put_inode_ref(&parent);
+ ext4_fs_put_inode_ref(&act);
+ goto Finish;
+ }
+ }
+
+ r = ext4_fs_put_inode_ref(&parent);
+ if (r != EOK)
+ goto Finish;
+
+ r = ext4_fs_put_inode_ref(&act);
+ Finish:
+ if (r != EOK)
+ ext4_trans_abort(mp);
+ else
+ ext4_trans_stop(mp);
+ }
ext4_block_cache_write_back(mp->fs.bdev, 0);
EXT4_MP_UNLOCK(mp);