+2002-01-03 Theodore Tso <tytso@valinux.com>
+
+ * 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.
+
2001-12-24 Theodore Tso <tytso@valinux.com>
* ismounted.c (is_swap_device): New function used by
OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \
ext2_err.o \
alloc.o \
+ alloc_stats.o \
alloc_tables.o \
badblocks.o \
bb_inode.o \
SRCS= ext2_err.c \
$(srcdir)/alloc.c \
+ $(srcdir)/alloc_stats.c \
$(srcdir)/alloc_tables.c \
$(srcdir)/badblocks.c \
$(srcdir)/bb_compat.c \
{
errcode_t retval;
blk_t block;
- int group;
char *buf = 0;
if (!block_buf) {
if (retval)
goto fail;
- fs->super->s_free_blocks_count--;
- group = ext2fs_group_of_blk(fs, block);
- fs->group_desc[group].bg_free_blocks_count--;
- ext2fs_mark_block_bitmap(fs->block_map, block);
- ext2fs_mark_super_dirty(fs);
- ext2fs_mark_bb_dirty(fs);
+ ext2fs_block_alloc_stats(fs, block, +1);
*ret = block;
return 0;
--- /dev/null
+/*
+ * alloc_stats.c --- Update allocation statistics for ext2fs
+ *
+ * Copyright (C) 2001 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ *
+ */
+
+#include <stdio.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+void ext2fs_inode_alloc_stats(ext2_filsys fs, ext2_ino_t ino, int inuse)
+{
+ int group = ext2fs_group_of_ino(fs, ino);
+
+ if (inuse > 0)
+ ext2fs_mark_inode_bitmap(fs->inode_map, ino);
+ else
+ ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
+ fs->group_desc[group].bg_free_inodes_count -= inuse;
+ fs->super->s_free_inodes_count -= inuse;
+ ext2fs_mark_super_dirty(fs);
+ ext2fs_mark_ib_dirty(fs);
+}
+
+void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse)
+{
+ int group = ext2fs_group_of_blk(fs, blk);
+
+ if (inuse > 0)
+ ext2fs_mark_block_bitmap(fs->block_map, blk);
+ else
+ ext2fs_unmark_block_bitmap(fs->block_map, blk);
+ fs->group_desc[group].bg_free_blocks_count -= inuse;
+ fs->super->s_free_blocks_count -= inuse;
+ ext2fs_mark_super_dirty(fs);
+ ext2fs_mark_bb_dirty(fs);
+}
errcode_t retval;
struct set_badblock_record rec;
struct ext2_inode inode;
- blk_t blk;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
* block inode (!).
*/
if (bb_list) {
- retval = ext2fs_badblocks_list_iterate_begin(bb_list,
- &rec.bb_iter);
- if (retval)
- goto cleanup;
- while (ext2fs_badblocks_list_iterate(rec.bb_iter, &blk)) {
- ext2fs_mark_block_bitmap(fs->block_map, blk);
- }
- ext2fs_badblocks_list_iterate_end(rec.bb_iter);
- ext2fs_mark_bb_dirty(fs);
-
retval = ext2fs_badblocks_list_iterate_begin(bb_list,
&rec.bb_iter);
if (retval)
struct set_badblock_record *rec = (struct set_badblock_record *)
priv_data;
errcode_t retval;
- int group;
unsigned long old_size;
if (!*block_nr)
/*
* Mark the block as unused, and update accounting information
*/
- ext2fs_unmark_block_bitmap(fs->block_map, *block_nr);
- ext2fs_mark_bb_dirty(fs);
- group = ext2fs_group_of_blk(fs, *block_nr);
- fs->group_desc[group].bg_free_blocks_count++;
- fs->super->s_free_blocks_count++;
- ext2fs_mark_super_dirty(fs);
+ ext2fs_block_alloc_stats(fs, *block_nr, -1);
*block_nr = 0;
return BLOCK_CHANGED;
priv_data;
errcode_t retval;
blk_t blk;
- int group;
if (blockcnt >= 0) {
/*
rec->err = retval;
return BLOCK_ABORT;
}
- ext2fs_mark_block_bitmap(fs->block_map, blk);
- ext2fs_mark_bb_dirty(fs);
}
/*
* Update block counts
*/
- group = ext2fs_group_of_blk(fs, blk);
- fs->group_desc[group].bg_free_blocks_count--;
- fs->super->s_free_blocks_count--;
- ext2fs_mark_super_dirty(fs);
+ ext2fs_block_alloc_stats(fs, blk, +1);
*block_nr = blk;
return BLOCK_CHANGED;
if (retval)
return retval;
}
- ctx.func = 0;
- ctx.func2 = func;
+ ctx.func = func;
ctx.priv_data = priv_data;
ctx.errcode = 0;
#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;
return retval;
}
ctx.func = func;
- ctx.func2 = 0;
ctx.priv_data = priv_data;
ctx.errcode = 0;
retval = ext2fs_block_iterate2(fs, dir, 0, 0,
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()
{
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)
!(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++;
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;
}
static blk_t last_blk = 0;
char *block;
errcode_t retval;
- int group;
if (*blocknr) {
last_blk = *blocknr;
}
ext2fs_free_mem((void **) &block);
*blocknr = new_blk;
- ext2fs_mark_block_bitmap(fs->block_map, new_blk);
- ext2fs_mark_bb_dirty(fs);
- group = ext2fs_group_of_blk(fs, new_blk);
- fs->group_desc[group].bg_free_blocks_count--;
- fs->super->s_free_blocks_count--;
- ext2fs_mark_super_dirty(fs);
+ ext2fs_block_alloc_stats(fs, new_blk, +1);
es->newblocks++;
if (es->done)
*/
#define DIRENT_FLAG_INCLUDE_EMPTY 1
-
+#define DIRENT_FLAG_INCLUDE_REMOVED 2
#define DIRENT_DOT_FILE 1
#define DIRENT_DOT_DOT_FILE 2
#define DIRENT_OTHER_FILE 3
+#define DIRENT_DELETED_FILE 4
/*
* Inode scan definitions
extern errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal,
char *block_buf, blk_t *ret);
+/* alloc_stats.c */
+void ext2fs_inode_alloc_stats(ext2_filsys fs, ext2_ino_t ino, int inuse);
+void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse);
+
/* alloc_tables.c */
extern errcode_t ext2fs_allocate_tables(ext2_filsys fs);
extern errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group,
char *buf,
void *priv_data),
void *priv_data);
+extern 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);
/* dupfs.c */
extern errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest);
ext2_ino_t dir;
int flags;
char *buf;
- int (*func)(struct ext2_dir_entry *dirent,
+ int (*func)(ext2_ino_t dir,
+ int entry,
+ struct ext2_dir_entry *dirent,
int offset,
int blocksize,
char *buf,
void *priv_data);
- int (*func2)(ext2_ino_t dir,
- int entry,
- struct ext2_dir_entry *dirent,
- int offset,
- int blocksize,
- char *buf,
- void *priv_data);
void *priv_data;
errcode_t errcode;
};
ext2_ino_t scratch_ino;
blk_t blk;
char *block = 0;
- int group;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
/*
* Update accounting....
*/
- ext2fs_mark_block_bitmap(fs->block_map, blk);
- ext2fs_mark_bb_dirty(fs);
- ext2fs_mark_inode_bitmap(fs->inode_map, ino);
- ext2fs_mark_ib_dirty(fs);
-
- group = ext2fs_group_of_blk(fs, blk);
- fs->group_desc[group].bg_free_blocks_count--;
- group = ext2fs_group_of_ino(fs, ino);
- fs->group_desc[group].bg_free_inodes_count--;
- fs->group_desc[group].bg_used_dirs_count++;
- fs->super->s_free_blocks_count--;
- fs->super->s_free_inodes_count--;
- ext2fs_mark_super_dirty(fs);
-
+ ext2fs_block_alloc_stats(fs, blk, +1);
+ ext2fs_inode_alloc_stats(fs, ino, +1);
+
cleanup:
if (block)
ext2fs_free_mem((void **) &block);
blk_t new_blk;
static blk_t last_blk = 0;
errcode_t retval;
- int group;
if (*blocknr) {
last_blk = *blocknr;
}
*blocknr = new_blk;
last_blk = new_blk;
- ext2fs_mark_block_bitmap(fs->block_map, new_blk);
- ext2fs_mark_bb_dirty(fs);
- group = ext2fs_group_of_blk(fs, new_blk);
- fs->group_desc[group].bg_free_blocks_count--;
- fs->super->s_free_blocks_count--;
- ext2fs_mark_super_dirty(fs);
+ ext2fs_block_alloc_stats(fs, new_blk, +1);
if (es->num_blocks == 0)
return (BLOCK_CHANGED | BLOCK_ABORT);