Messages in this thread Patch in this message | | | Date | Sun, 27 Jul 1997 15:42:25 +0200 (CEST) | From | Kurt Huwig <> | Subject | Re: undelete? |
| |
On Sun, 27 Jul 1997, Rogier Wolff wrote: > Kurt Huwig wrote: > > On Sat, 26 Jul 1997, Rogier Wolff wrote: > > > About a year ago, I implemented the "undelete feature" as a move to > > > /.deleted. Unlink xyz calls get changed into a mv xyz /.deleted . > > > The rest is user-space. For example: reclaiming the disk space can > > > be done by a deamon that watches the .deleted directory. Any fancy > > > algorithms you want can be implemented there. > > > > > > Implementing it myself did shut up the thread back then, but doesn't > > > prevent the thread to reappear month after month later....
I looked through dejanews and found Rogier's patch. It did not patch in directly, because the sources have changed a little bit, so I did it by hand, together with minor changes:
- replaced spaces by tabs - put all 'printk' in '#ifdef' (I don't want my messages to fill up with every deleted file - updated the call to 'do_ext2_rename' to have the new additional parameter - made it a part of the configure-script
The patch is quite long, because 'ext2_unlink' had to move below 'do_ext2_rename'. The actual patch is very short - it is between '#ifdef CONFIG_EXT2_UNDELETE' and the corresponding '#endif'.
The patch is against 2.0.30, because I'm not on the bleeding edge. Some additions I might think about is to include the directory of the original file in the deleted one, because this way you can find these files easier.
Now, figure out how to clean up the directory regulary. I don't know how to get the time when the file was moved into the directory and I don't want the time to be modified. A quick'n'dirty solution would be to make subdirs 0, 1, 2, 3,... Now delete the directory with the highest number and rename the others. Then create a new directory called '0' and move all the files of '.wastebasket' into it. Then sleep for some time. Everything certainly in userspace.
Maybe I'm blind for something, so please comment on this idea.
Kurt
---------------------------------------------------------------- Let me make myself perfectly clear: Step 1: Find plan! Step 2: Save world! Let's get crackin'... Step 3: Get outta my house! --- linux/Documentation/Configure.help.orig Sun Jul 27 14:27:45 1997 +++ linux/Documentation/Configure.help Sun Jul 27 14:25:26 1997 @@ -2987,6 +2987,23 @@ sunsite.unc.edu:/pub/Linux/docs/faqs. This option will enlarge your kernel by about 41 kB. Default is Y. +undelete support for ext2 filesystems +CONFIG_EXT2_UNDELETE + This enables an undelete feature for ext2-partitions. Every call to + 'unlink' is translated into a move into the directory '.wastebasket' + in the root of the partition (where 'lost+found' is located). + CAVEATS: + - Only works if a directory '.wastebasket' is in the root of the + partition. This can be used to disable this feature for certain + partitions. + - Only 'root' can now delete files. + - If a user has the right to delete a file, it will be moved + to the wastebasket regardless of the permissions of the + wastebasket. If you don't want security holes to others, you + should make the wastebasket mode 700. + - You have to make sure that the directory is emptied or your + harddisk will be full very soon! + xiafs filesystem support CONFIG_XIA_FS This is an old filesystem (= method to organize files on a harddisk --- linux/fs/Config.in.orig Thu Jul 17 01:02:37 1997 +++ linux/fs/Config.in Sun Jul 27 14:15:51 1997 @@ -11,6 +11,7 @@ tristate 'Second extended fs support' CONFIG_EXT2_FS if [ "$CONFIG_EXT2_FS" = "y" ]; then bool ' NO_ATIME support for ext2 filesystems' CONFIG_EXT2_NOATIME + bool ' undelete support for ext2 filesystems' CONFIG_EXT2_UNDELETE fi tristate 'xiafs filesystem support' CONFIG_XIA_FS --- linux/fs/ext2/namei.c.orig Sat Nov 30 11:21:20 1996 +++ linux/fs/ext2/namei.c Sun Jul 27 15:07:34 1997 @@ -695,73 +695,6 @@ return retval; } -int ext2_unlink (struct inode * dir, const char * name, int len) -{ - int retval; - struct inode * inode; - struct buffer_head * bh; - struct ext2_dir_entry * de; - -repeat: - if (!dir) - return -ENOENT; - retval = -ENOENT; - inode = NULL; - if (len > EXT2_NAME_LEN) { - iput (dir); - return -ENAMETOOLONG; - } - bh = ext2_find_entry (dir, name, len, &de); - if (!bh) - goto end_unlink; - if (!(inode = iget (dir->i_sb, de->inode))) - goto end_unlink; - if (inode->i_sb->dq_op) - inode->i_sb->dq_op->initialize (inode, -1); - retval = -EPERM; - if (S_ISDIR(inode->i_mode)) - goto end_unlink; - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) - goto end_unlink; - if (de->inode != inode->i_ino) { - iput(inode); - brelse(bh); - current->counter = 0; - schedule(); - goto repeat; - } - if ((dir->i_mode & S_ISVTX) && !fsuser() && - current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid) - goto end_unlink; - if (!inode->i_nlink) { - ext2_warning (inode->i_sb, "ext2_unlink", - "Deleting nonexistent file (%lu), %d", - inode->i_ino, inode->i_nlink); - inode->i_nlink = 1; - } - retval = ext2_delete_entry (de, bh); - if (retval) - goto end_unlink; - dir->i_version = ++event; - mark_buffer_dirty(bh, 1); - if (IS_SYNC(dir)) { - ll_rw_block (WRITE, 1, &bh); - wait_on_buffer (bh); - } - dir->i_ctime = dir->i_mtime = CURRENT_TIME; - dir->i_dirt = 1; - inode->i_nlink--; - inode->i_dirt = 1; - inode->i_ctime = dir->i_ctime; - retval = 0; -end_unlink: - brelse (bh); - iput (inode); - iput (dir); - return retval; -} - int ext2_symlink (struct inode * dir, const char * name, int len, const char * symname) { @@ -1101,6 +1034,126 @@ iput (new_inode); iput (old_dir); iput (new_dir); + return retval; +} + +int ext2_unlink (struct inode * dir, const char * name, int len) +{ + int retval; + struct inode * inode; + struct buffer_head * bh; + struct ext2_dir_entry * de; + +repeat: + if (!dir) + return -ENOENT; + retval = -ENOENT; + inode = NULL; + if (len > EXT2_NAME_LEN) { + iput (dir); + return -ENAMETOOLONG; + } + bh = ext2_find_entry (dir, name, len, &de); + if (!bh) + goto end_unlink; + if (!(inode = iget (dir->i_sb, de->inode))) + goto end_unlink; + if (inode->i_sb->dq_op) + inode->i_sb->dq_op->initialize (inode, -1); + retval = -EPERM; + if (S_ISDIR(inode->i_mode)) + goto end_unlink; + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + goto end_unlink; + if (de->inode != inode->i_ino) { + iput(inode); + brelse(bh); + current->counter = 0; + schedule(); + goto repeat; + } + if ((dir->i_mode & S_ISVTX) && !fsuser() && + current->fsuid != inode->i_uid && + current->fsuid != dir->i_uid) + goto end_unlink; + if (!inode->i_nlink) { + ext2_warning (inode->i_sb, "ext2_unlink", + "Deleting nonexistent file (%lu), %d", + inode->i_ino, inode->i_nlink); + inode->i_nlink = 1; + } +#ifdef CONFIG_EXT2_UNDELETE + if (!fsuser ()) { /* 'root' uses the old unlink */ + if (inode->i_sb) { + struct inode *wb,*tmp; + const char *new_name; + char buf[EXT2_NAME_LEN]; + int new_len; + int version; + + inode->i_sb->s_mounted->i_count++; + if (ext2_lookup (inode->i_sb->s_mounted,".wastebasket",12,&wb) == 0) { +#ifdef DEBUG_UNDELETE + printk ("inode_c=%d, dir_c=%d,wb_c=%d\n",inode->i_count,dir->i_count,wb->i_count); +#endif + new_name=name; + new_len = len; + version = 0; + wb->i_count++; + while (ext2_lookup (wb,new_name,new_len,&tmp) == 0) { + iput (tmp); + sprintf (buf,"%s_%d",name,version++); + new_name = buf; + new_len = strlen (buf); + wb->i_count++; + } +#ifdef DEBUG_UNDELETE + printk ("moveing %s to wastebasket as %s.\n",name,new_name); +#endif + while (dir->i_sb->u.ext2_sb.s_rename_lock) + sleep_on (&dir->i_sb->u.ext2_sb.s_rename_wait); + dir->i_sb->u.ext2_sb.s_rename_lock = 1; + + retval = do_ext2_rename (dir, name, len, wb, new_name, new_len, 0); + + dir->i_sb->u.ext2_sb.s_rename_lock = 0; + wake_up (&dir->i_sb->u.ext2_sb.s_rename_wait); +#ifdef DEBUG_UNDELETE + printk ("inode_c=%d, dir_c=%d,wb_c=%d\n",inode->i_count,dir->i_count,wb->i_count); +#endif + brelse (bh); + iput (inode); + return retval; +#ifdef DEBUG_UNDELETE + } else { + printk ("No wastebasket. Old unlink for %s....\n",name); +#endif + } + } else { + printk ("Warning: Undelete can't find a superblock for inode %ld\n" + "Deleting file normally.\n",inode->i_ino); + } + } +#endif + retval = ext2_delete_entry (de, bh); + if (retval) + goto end_unlink; + dir->i_version = ++event; + mark_buffer_dirty(bh, 1); + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_dirt = 1; + inode->i_nlink--; + inode->i_dirt = 1; + inode->i_ctime = dir->i_ctime; + retval = 0; +end_unlink: + brelse (bh); + iput (inode); + iput (dir); return retval; } --- /dev/null Sun Jun 29 17:10:20 1997 +++ linux/init/patches/ext2-undelete-2.0.30 Sun Jul 27 14:30:23 1997 @@ -0,0 +1 @@ +ext2 undelete support (Rogier Wolff <R.E.Wolff@BitWizard.nl>) | |