From 4e60fb609b330fb488f2fcbfe9e330b1441201c0 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Fri, 7 Jan 2005 22:09:49 -0500 Subject: [PATCH] Ex2fs_unlink() will return an error if both the name and inode number are unspecified, to avoid doing something surprising (such as unconditionally deleting the first directory entry). Directory entries are now deleted by coalescing them with the previous directory entry if possible, to avoid directory fragmentation. This is not an issue with the e2fsprogs suite, but may be a problem for some of the users of libext2fs, such as e2tools. --- lib/ext2fs/ChangeLog | 9 +++++++++ lib/ext2fs/unlink.c | 37 ++++++++++++++++++++++++++++--------- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/lib/ext2fs/ChangeLog b/lib/ext2fs/ChangeLog index 7b5e802..260cd2f 100644 --- a/lib/ext2fs/ChangeLog +++ b/lib/ext2fs/ChangeLog @@ -1,3 +1,12 @@ +2005-01-07 Theodore Ts'o + + * unlink.c (ext2fs_unlink): If both the name and the inode number + are unspecified, then return an error, so that we don't do + something surprising such as unconditionally deleting the + first directory entry. + (unlink_proc): Delete directory entries by coalescing it + with the previous entry, to avoid directory fragmentation. + 2005-01-06 Theodore Ts'o * version.c (ext2fs_parse_version_string): Change parsing diff --git a/lib/ext2fs/unlink.c b/lib/ext2fs/unlink.c index 5612b3d..e7b2182 100644 --- a/lib/ext2fs/unlink.c +++ b/lib/ext2fs/unlink.c @@ -23,6 +23,7 @@ struct link_struct { int namelen; ext2_ino_t inode; int flags; + struct ext2_dir_entry *prev; int done; }; @@ -36,16 +37,29 @@ static int unlink_proc(struct ext2_dir_entry *dirent, void *priv_data) { struct link_struct *ls = (struct link_struct *) priv_data; + struct ext2_dir_entry *prev; - if (ls->name && ((dirent->name_len & 0xFF) != ls->namelen)) - return 0; - if (ls->name && strncmp(ls->name, dirent->name, - dirent->name_len & 0xFF)) - return 0; - if (ls->inode && (dirent->inode != ls->inode)) - return 0; + prev = ls->prev; + ls->prev = dirent; - dirent->inode = 0; + if (ls->name) { + if ((dirent->name_len & 0xFF) != ls->namelen) + return 0; + if (strncmp(ls->name, dirent->name, dirent->name_len & 0xFF)) + return 0; + } + if (ls->inode) { + if (dirent->inode != ls->inode) + return 0; + } else { + if (!dirent->inode) + return 0; + } + + if (prev) + prev->rec_len += dirent->rec_len; + else + dirent->inode = 0; ls->done++; return DIRENT_ABORT|DIRENT_CHANGED; } @@ -62,6 +76,9 @@ errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir, EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + if (!name && !ino) + return EXT2_ET_INVALID_ARGUMENT; + if (!(fs->flags & EXT2_FLAG_RW)) return EXT2_ET_RO_FILSYS; @@ -70,8 +87,10 @@ errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir, ls.inode = ino; ls.flags = 0; ls.done = 0; + ls.prev = 0; - retval = ext2fs_dir_iterate(fs, dir, 0, 0, unlink_proc, &ls); + retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY, + 0, unlink_proc, &ls); if (retval) return retval; -- 1.8.3.1