lkml.org 
[lkml]   [1997]   [Jul]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: 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>)
\
 
 \ /
  Last update: 2005-03-22 13:40    [W:0.140 / U:0.276 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site