diff -Naur ext4/namei.c ext4tb/namei.c --- ext4/namei.c 2006-10-28 16:08:13.000000000 -0400 +++ ext4tb/namei.c 2006-10-28 16:08:27.000000000 -0400 @@ -41,6 +41,7 @@ #include "namei.h" #include "xattr.h" #include "acl.h" +#include "tb.h" /* * define how far ahead to read directories while searching them. @@ -2098,15 +2099,27 @@ inode->i_ino, inode->i_nlink); inode->i_nlink = 1; } - retval = ext4_delete_entry(handle, dir, de, bh); - if (retval) - goto end_unlink; +#ifdef CONFIG_EXT4DEV_FS_TRASH_BIN + if (EXT4_I(dentry->d_inode)->i_flags & (EXT4_UNRM_FL | EXT4_SECRM_FL)) { + retval = ext4_trash_entry(dir, dentry); + if (retval) + goto end_unlink; + } +#endif + if (!(EXT4_I(dentry->d_inode)->i_flags & (EXT4_UNRM_FL | + EXT4_SECRM_FL))) { + retval = ext4_delete_entry(handle, dir, de, bh); + if (retval) + goto end_unlink; + } dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; ext4_update_dx_flag(dir); ext4_mark_inode_dirty(handle, dir); +#ifndef CONFIG_EXT4DEV_FS_TRASH_BIN drop_nlink(inode); if (!inode->i_nlink) ext4_orphan_add(handle, inode); +#endif inode->i_ctime = dir->i_ctime; ext4_mark_inode_dirty(handle, inode); retval = 0; diff -Naur ext4/super.c ext4tb/super.c --- ext4/super.c 2006-10-28 16:08:13.000000000 -0400 +++ ext4tb/super.c 2006-10-28 16:08:27.000000000 -0400 @@ -41,6 +41,7 @@ #include "xattr.h" #include "acl.h" #include "namei.h" +#include "tb.h" static int ext4_load_journal(struct super_block *, struct ext4_super_block *, unsigned long journal_devnum); @@ -1837,6 +1838,11 @@ goto failed_mount4; } +#ifdef CONFIG_EXT4DEV_FS_TRASH_BIN + if (ext4_create_tb(sb)) + goto failed_mount3; +#endif + ext4_setup_super (sb, es, sb->s_flags & MS_RDONLY); /* * akpm: core read_super() calls in here with the superblock locked. diff -Naur ext4/tb.c ext4tb/tb.c --- ext4/tb.c 1969-12-31 19:00:00.000000000 -0500 +++ ext4tb/tb.c 2006-10-28 16:52:30.000000000 -0400 @@ -0,0 +1,148 @@ +/* linux/fs/ext4/tb.c + * + * Copyright (C) 2006 Stony Brook University + * Nikolai Joukov, Harry Papaxenopoulos, and Erez Zadok + */ +#include +#include +#include +#include +#include +#include "tb.h" + +int ext4_create_tb(struct super_block *sb) +{ + int err = 0; + struct dentry *dentry, *root_dentry; + struct inode *mnt_inode; + + root_dentry = sb->s_root; + mnt_inode = root_dentry->d_inode; + + dentry = lookup_one_len(TB_NAME, root_dentry, TB_NAME_LEN); + + if (IS_ERR(dentry)){ + err = PTR_ERR(dentry); + goto out; + } + + if (!dentry->d_inode && mnt_inode->i_op && mnt_inode->i_op->mkdir) { + mutex_lock(&mnt_inode->i_mutex); + err = mnt_inode->i_op->mkdir(mnt_inode, dentry, TB_MODE); + mutex_unlock(&mnt_inode->i_mutex); + if (err) + goto release_out; + } + +release_out: + dput(dentry); +out: + return err; +} + +struct dentry *tb_sillyname( struct dentry *tb_dentry, struct dentry *dentry) +{ + unsigned sillycounter = 1; + char random[4]; + char *silly = NULL; + char *tmp = NULL; + struct dentry *sdentry = NULL; + + silly = kmalloc(PATH_MAX, GFP_KERNEL); + if (!silly) + goto out; + + tmp = kmalloc(PATH_MAX, GFP_KERNEL); + if (!tmp) + goto out; + + if (!tb_dentry->d_inode) { + sdentry = ERR_PTR(-EIO); + goto out; + } + + sdentry = lookup_one_len(dentry->d_name.name, tb_dentry, + dentry->d_name.len); + + if (IS_ERR(sdentry)) + goto out; + + while(sdentry->d_inode != NULL) { + if (PATH_MAX - 5 <= dentry->d_name.len) + snprintf(tmp, PATH_MAX - 6, dentry->d_name.name); + else + sprintf(tmp, dentry->d_name.name); + + sprintf(silly, "%s_%u", dentry->d_name.name, sillycounter); + dput(sdentry); + sdentry = lookup_one_len(silly, tb_dentry, strlen(silly)); + if (IS_ERR(sdentry)) + goto out; + sillycounter++; + } +out: + if (silly) + kfree(silly); + if (tmp) + kfree(tmp); + return sdentry; +} + +int ext4_trash_entry(struct inode *old_dir, struct dentry *old_dentry) +{ + int err = 0; + struct ext3_sb_info *ext3_sb; + struct dentry *new_dentry = NULL; + struct dentry *tb_dentry = NULL; + struct dentry *root_dentry = NULL; + struct inode *tb_inode; + + if (old_dir && old_dir->i_sb && old_dir->i_sb->s_root) + root_dentry = old_dir->i_sb->s_root; + else { + err = -EIO; + goto out; + } + + tb_dentry = lookup_one_len(TB_NAME, root_dentry, TB_NAME_LEN); + if (IS_ERR(tb_dentry)) { + err = PTR_ERR(tb_dentry); + goto out; + } + + tb_inode = tb_dentry->d_inode; + if (!tb_inode) { + err = -EIO; + goto release_out; + } + + if (tb_inode->i_ino == old_dir->i_ino) + goto release_out; + + new_dentry = tb_sillyname(tb_dentry, old_dentry); + if (IS_ERR(new_dentry)) { + err = PTR_ERR(new_dentry); + goto release_out2; + } + if (tb_inode->i_op && tb_inode->i_op->rename) { + mutex_lock(&tb_inode->i_mutex); + err = tb_inode->i_op->rename(old_dir, old_dentry, + tb_inode, new_dentry); + mutex_unlock(&tb_inode->i_mutex); + if (!err) + d_move(old_dentry, new_dentry); + } else { + err = -ENOSYS; + goto release_out; + } + //need to manually unhash the old dentry + if (!d_unhashed(old_dentry)) + __d_drop(old_dentry); +release_out: + dput(new_dentry); +release_out2: + dput(tb_dentry); +out: + return err; +} + diff -Naur ext4/tb.h ext4tb/tb.h --- ext4/tb.h 1969-12-31 19:00:00.000000000 -0500 +++ ext4tb/tb.h 2006-10-28 16:52:30.000000000 -0400 @@ -0,0 +1,15 @@ +/* linux/fs/ext4/tb.h + * + * Copyright (C) 2006 Stony Brook University + * Nikolai Joukov, Harry Papaxenopoulos, and Erez Zadok + */ +#ifdef CONFIG_EXT4DEV_FS_TRASH_BIN + +#define TB_NAME ".trash" +#define TB_NAME_LEN 6 +#define TB_MODE 0711 +#define TB_DEBUG 1 + +extern int ext4_create_tb(struct super_block *); +extern int ext4_trash_entry(struct inode *, struct dentry *); +#endif /*CONFIG_EXT4_FS_TRASH_BIN*/