aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ext2fs/dir_iterate.c
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2002-01-03 03:29:19 -0500
committerTheodore Ts'o <tytso@mit.edu>2002-01-03 03:29:19 -0500
commit8bd0c95908baa3af706b9e731daff9472bec74c9 (patch)
treea98b28dc42ee8981ea33b057d63c277b96babe84 /lib/ext2fs/dir_iterate.c
parent5493a27dc1138d2e30193b80217a0127d247af1e (diff)
downloadandroid_external_e2fsprogs-8bd0c95908baa3af706b9e731daff9472bec74c9.tar.gz
android_external_e2fsprogs-8bd0c95908baa3af706b9e731daff9472bec74c9.tar.bz2
android_external_e2fsprogs-8bd0c95908baa3af706b9e731daff9472bec74c9.zip
dir_iterate.c (ext2fs_dir_iterate2, ext2fs_process_dir_block):
Add support for a new flag, DIRENT_FLAG_INCLUDE_REMOVED, which will return deleted directory entries. ext2fs_dir_iterate2 takes a new callback function which is identical with the one used by ext2fs_dblist_dir_iterate(). If the directory entry is deleted, the callback function will be called with the entry paraemter set to DIRENT_DELETED_FILE. Makefile.in, alloc_stats.c (ext2fs_inode_alloc_stats, ext2fs_block_alloc_stats): New functions which update block/inode allocation statistics in the bitmaps, block group descriptors, and superblock. mkjournal.c (mkjournal_proc), mkdir.c (ext2fs_mkdir), expanddir.c (expand_dir_proc), bb_inode.c (clear_bad_block_proc, set_bad_block_proc, ext2fs_update_bb_inode), alloc.c (ext2fs_alloc_block): Update to use new block/inode allocation statistics.
Diffstat (limited to 'lib/ext2fs/dir_iterate.c')
-rw-r--r--lib/ext2fs/dir_iterate.c124
1 files changed, 102 insertions, 22 deletions
diff --git a/lib/ext2fs/dir_iterate.c b/lib/ext2fs/dir_iterate.c
index ae97d820..35fae073 100644
--- a/lib/ext2fs/dir_iterate.c
+++ b/lib/ext2fs/dir_iterate.c
@@ -21,16 +21,41 @@
#include "ext2_fs.h"
#include "ext2fsP.h"
-errcode_t ext2fs_dir_iterate(ext2_filsys fs,
- ext2_ino_t dir,
- int flags,
- char *block_buf,
- int (*func)(struct ext2_dir_entry *dirent,
- int offset,
- int blocksize,
- char *buf,
- void *priv_data),
- void *priv_data)
+/*
+ * This function checks to see whether or not a potential deleted
+ * directory entry looks valid. What we do is check the deleted entry
+ * and each successive entry to make sure that they all look valid and
+ * that the last deleted entry ends at the beginning of the next
+ * undeleted entry. Returns 1 if the deleted entry looks valid, zero
+ * if not valid.
+ */
+static int ext2fs_validate_entry(char *buf, int offset, int final_offset)
+{
+ struct ext2_dir_entry *dirent;
+
+ while (offset < final_offset) {
+ dirent = (struct ext2_dir_entry *)(buf + offset);
+ offset += dirent->rec_len;
+ if ((dirent->rec_len < 8) ||
+ ((dirent->rec_len % 4) != 0) ||
+ (((dirent->name_len & 0xFF)+8) > dirent->rec_len))
+ return 0;
+ }
+ return (offset == final_offset);
+}
+
+errcode_t ext2fs_dir_iterate2(ext2_filsys fs,
+ ext2_ino_t dir,
+ int flags,
+ char *block_buf,
+ int (*func)(ext2_ino_t dir,
+ int entry,
+ struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data),
+ void *priv_data)
{
struct dir_context ctx;
errcode_t retval;
@@ -51,7 +76,6 @@ errcode_t ext2fs_dir_iterate(ext2_filsys fs,
return retval;
}
ctx.func = func;
- ctx.func2 = 0;
ctx.priv_data = priv_data;
ctx.errcode = 0;
retval = ext2fs_block_iterate2(fs, dir, 0, 0,
@@ -63,6 +87,45 @@ errcode_t ext2fs_dir_iterate(ext2_filsys fs,
return ctx.errcode;
}
+struct xlate {
+ int (*func)(struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data);
+ void *real_private;
+};
+
+static int xlate_func(ext2_ino_t dir, int entry,
+ struct ext2_dir_entry *dirent, int offset,
+ int blocksize, char *buf, void *priv_data)
+{
+ struct xlate *xl = (struct xlate *) priv_data;
+
+ return (*xl->func)(dirent, offset, blocksize, buf, xl->real_private);
+}
+
+extern errcode_t ext2fs_dir_iterate(ext2_filsys fs,
+ ext2_ino_t dir,
+ int flags,
+ char *block_buf,
+ int (*func)(struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data),
+ void *priv_data)
+{
+ struct xlate xl;
+
+ xl.real_private = priv_data;
+ xl.func = func;
+
+ return ext2fs_dir_iterate2(fs, dir, flags, block_buf,
+ xlate_func, &xl);
+}
+
+
/*
* Helper function which is private to this module. Used by
* ext2fs_dir_iterate() and ext2fs_dblist_dir_iterate()
@@ -76,10 +139,11 @@ int ext2fs_process_dir_block(ext2_filsys fs,
{
struct dir_context *ctx = (struct dir_context *) priv_data;
int offset = 0;
+ int next_real_entry = 0;
int ret = 0;
int changed = 0;
int do_abort = 0;
- int entry;
+ int entry, size;
struct ext2_dir_entry *dirent;
if (blockcnt < 0)
@@ -104,16 +168,14 @@ int ext2fs_process_dir_block(ext2_filsys fs,
!(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY))
goto next;
- if (ctx->func)
- ret = (ctx->func)(dirent, offset, fs->blocksize,
- ctx->buf, ctx->priv_data);
- else if (ctx->func2) {
- ret = (ctx->func2)(ctx->dir, entry, dirent, offset,
- fs->blocksize, ctx->buf,
- ctx->priv_data);
- if (entry < DIRENT_OTHER_FILE)
- entry++;
- }
+ ret = (ctx->func)(ctx->dir,
+ (next_real_entry > offset) ?
+ DIRENT_DELETED_FILE : entry,
+ dirent, offset,
+ fs->blocksize, ctx->buf,
+ ctx->priv_data);
+ if (entry < DIRENT_OTHER_FILE)
+ entry++;
if (ret & DIRENT_CHANGED)
changed++;
@@ -122,6 +184,24 @@ int ext2fs_process_dir_block(ext2_filsys fs,
break;
}
next:
+ if (next_real_entry == offset)
+ next_real_entry += dirent->rec_len;
+
+ if (ctx->flags & DIRENT_FLAG_INCLUDE_REMOVED) {
+ size = ((dirent->name_len & 0xFF) + 11) & ~3;
+
+ if (dirent->rec_len != size) {
+ int final_offset = offset + dirent->rec_len;
+
+ offset += size;
+ while (offset < final_offset &&
+ !ext2fs_validate_entry(ctx->buf,
+ offset,
+ final_offset))
+ offset += 4;
+ continue;
+ }
+ }
offset += dirent->rec_len;
}