--- linux-2.6.2/include/linux/ext2_fs.h 2004-02-04 03:43:12.000000000 +0000 +++ linux-2.6.2/include/linux/ext2_fs.h-secrm 2004-02-05 22:08:59.000000000 +0000 @@ -310,6 +310,7 @@ #define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */ #define EXT2_MOUNT_NOBH 0x0100 /* No buffer_heads */ #define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */ +#define EXT2_MOUNT_SECRM 0x0400 /* Securely delete files */ #define EXT2_MOUNT_XATTR_USER 0x4000 /* Extended user attributes */ #define EXT2_MOUNT_POSIX_ACL 0x8000 /* POSIX Access Control Lists */ --- linux-2.6.2/fs/ext2/balloc.c 2004-02-04 03:43:42.000000000 +0000 +++ linux-2.6.2/fs/ext2-secrm/balloc.c 2004-02-05 21:02:10.000000000 +0000 @@ -173,6 +173,21 @@ } } +static inline void delete_block(struct super_block *sb, unsigned long block) +{ + struct buffer_head * bh; + + bh = sb_getblk(sb, block); + + memset(bh->b_data, 0, bh->b_size); + + mark_buffer_dirty(bh); + wait_on_buffer(bh); /* XXX is this necessary? */ + brelse(bh); + + return; +} + /* Free given blocks, update quota and i_blocks field */ void ext2_free_blocks (struct inode * inode, unsigned long block, unsigned long count) @@ -240,8 +255,11 @@ ext2_error (sb, "ext2_free_blocks", "bit already cleared for block %lu", block + i); - else + else { + if (is_secure_delete(inode)) + delete_block(inode->i_sb, block + i); group_freed++; + } } mark_buffer_dirty(bitmap_bh); --- linux-2.6.2/fs/ext2/dir.c 2004-02-04 03:43:56.000000000 +0000 +++ linux-2.6.2/fs/ext2-secrm/dir.c 2004-02-05 22:01:00.000000000 +0000 @@ -530,6 +530,7 @@ { struct address_space *mapping = page->mapping; struct inode *inode = mapping->host; + struct inode *dino; char *kaddr = page_address(page); unsigned from = ((char*)dir - kaddr) & ~(ext2_chunk_size(inode)-1); unsigned to = ((char*)dir - kaddr) + le16_to_cpu(dir->rec_len); @@ -555,9 +556,24 @@ BUG(); if (pde) pde->rec_len = cpu_to_le16(to-from); - dir->inode = 0; + + dino = iget(inode->i_sb, dir->inode); + if (!dino || (!is_secure_delete(dino) && !is_secure_delete(inode))) { + dir->inode = 0; + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + } else { + unsigned short rec_len = dir->rec_len; + + memset(dir, 0, dir->rec_len); + dir->rec_len = rec_len; + } + + if (dino) + iput(dino); + err = ext2_commit_chunk(page, from, to); - inode->i_ctime = inode->i_mtime = CURRENT_TIME; + + /* XXX should this be in the if (!is_secure_delete()) above? */ EXT2_I(inode)->i_flags &= ~EXT2_BTREE_FL; mark_inode_dirty(inode); out: --- linux-2.6.2/fs/ext2/ext2.h 2004-02-05 20:46:40.000000000 +0000 +++ linux-2.6.2/fs/ext2-secrm/ext2.h 2004-02-05 20:45:25.000000000 +0000 @@ -79,6 +79,16 @@ return container_of(inode, struct ext2_inode_info, vfs_inode); } +static inline int is_secure_delete(struct inode *inode) +{ + /* expanded for readibility */ + if (EXT2_I(inode)->i_flags & EXT2_SECRM_FL) + return 1; + if (test_opt(inode->i_sb, SECRM)) + return 1; + return 0; +} + /* balloc.c */ extern int ext2_bg_has_super(struct super_block *sb, int group); extern unsigned long ext2_bg_num_gdb(struct super_block *sb, int group); --- linux-2.6.2/fs/ext2/inode.c 2004-02-04 03:43:09.000000000 +0000 +++ linux-2.6.2/fs/ext2-secrm/inode.c 2004-02-05 22:18:56.000000000 +0000 @@ -64,6 +64,36 @@ ext2_discard_prealloc(inode); } +static inline void delete_inode(struct inode *inode) +{ + if (!is_secure_delete(inode)) + EXT2_I(inode)->i_dtime = get_seconds(); + else { + inode->i_mode = 0; + inode->i_uid = 0; + inode->i_gid = 0; + inode->i_nlink = 0; + inode->i_atime.tv_sec = 0; + inode->i_atime.tv_nsec = 0; + inode->i_ctime.tv_sec = 0; + inode->i_ctime.tv_nsec = 0; + inode->i_mtime.tv_sec = 0; + inode->i_mtime.tv_nsec = 0; + EXT2_I(inode)->i_dtime = 0; + EXT2_I(inode)->i_faddr = 0; + EXT2_I(inode)->i_frag_no = 0; + EXT2_I(inode)->i_frag_size = 0; + EXT2_I(inode)->i_file_acl = 0; + inode->i_generation = 0; + } +} + +static inline void delete_blocks(struct inode *inode) +{ + inode->i_blocks = 0; + memset(EXT2_I(inode)->i_data, 0, sizeof(EXT2_I(inode)->i_data)); +} + /* * Called at the last iput() if i_nlink is zero. */ @@ -71,13 +101,21 @@ { if (is_bad_inode(inode)) goto no_delete; - EXT2_I(inode)->i_dtime = get_seconds(); + delete_inode(inode); mark_inode_dirty(inode); ext2_update_inode(inode, inode_needs_sync(inode)); inode->i_size = 0; if (inode->i_blocks) ext2_truncate (inode); + + if (is_secure_delete(inode)) { + EXT2_I(inode)->i_flags = 0; + + delete_blocks(inode); + mark_inode_dirty(inode); + ext2_update_inode(inode, inode_needs_sync(inode)); + } ext2_free_inode (inode); return; --- linux-2.6.2/fs/ext2/super.c 2004-02-04 03:44:04.000000000 +0000 +++ linux-2.6.2/fs/ext2-secrm/super.c 2004-02-05 22:04:17.000000000 +0000 @@ -270,7 +270,7 @@ Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid, Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro, Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh, - Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, + Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_secrm, Opt_ignore, Opt_err, }; @@ -299,6 +299,7 @@ {Opt_nouser_xattr, "nouser_xattr"}, {Opt_acl, "acl"}, {Opt_noacl, "noacl"}, + {Opt_secrm, "secrm"}, {Opt_ignore, "grpquota"}, {Opt_ignore, "noquota"}, {Opt_ignore, "quota"}, @@ -410,6 +411,9 @@ printk("EXT2 (no)acl options not supported\n"); break; #endif + case Opt_secrm: + set_opt(sbi->s_mount_opt, SECRM); + break; case Opt_ignore: break; default: