lkml.org 
[lkml]   [1997]   [Jul]   [28]   [last100]   RSS Feed
Views: [more markup]  [less markup]  [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
DateMon, 28 Jul 1997 13:50:04 +0200 (CEST)
FromKurt Huwig <>
SubjectPATCH: ext2-undelete!
On Sun, 27 Jul 1997, Kurt Huwig wrote:
> On Sun, 27 Jul 1997, Rogier Wolff wrote:
> > Kurt Huwig wrote:
> > > 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:
> > 
> > Kurt, there should be a followup that had a slightly different patch.
> > There is an attribute bit that says "this file needs safe delete",
> > which is currently unused. I didn't know that, so I wrote it without
> > using that bit. Someon else volunteerd "but there is a bit, for which
> > you just made the implementation". 
> 
> After some time, I found the patch.

Darren made some mistakes in his patch:

- he made the name of the directory adjustable via define, but overlooked
  that you need the length of it in 'ext2_lookup'. So it would only work
  if you use a name with 12 letters. I don't want to use 'strlen' here.
- he did not move the 'ext2_unlink' code after 'do_ext2_rename', so it
  won't compile at all. A
- he changed some of the 'printk' into 'ext2_debug' but still every move
  is reported via one printk...annoying
- you/he said 'moveing' instead of 'moving'...ok my English is worse ;-)

I included the reference to 'chattr' and 'lsattr' in the config help. I
think this will prevent any FAQs about how to set the 'u'-bit... ;-)

Kurt

-------------------------------------------------------------
Impossible doesn't exist!             Unmöglich gibt's nicht!
Difficult exists.                           Schwierig gibt's.
--- linux/Documentation/Configure.help.orig	Sun Jul 27 14:27:45 1997
+++ linux/Documentation/Configure.help	Mon Jul 28 13:34:17 1997
@@ -2987,6 +2987,29 @@
   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. Files marked
+  with the ext2 attribute 'u' for 'undo remove' will be moved to a
+  .wastebasket directory at the top of the fs, similar to lost+found
+  and the bit will be cleared. If no .wastebasket directory exists
+  then undeletion is not active on that partition. All files created
+  in a directory with the 'u'-bit set will have it set, too.
+  You can use 'chattr' and 'lsattr' to change and view this attribute.
+  They are in the package 'e2fsprogs' available at
+    ftp://sunsite.unc.edu/pub/Linux/system/filesystems/ext2/
+  At present if a file in the .wastebasket directory already exists
+  then _0 is appened to the next file of that name and so on.
+  CAVEATS:
+    - 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!
+    - Remember to set the 'u' bit on undeleted files if you want them
+      to be undelete-able again.
+
 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	Mon Jul 28 13:42:52 1997
@@ -11,6 +11,9 @@
 tristate 'Second extended fs support' CONFIG_EXT2_FS
 if [ "$CONFIG_EXT2_FS" = "y" ]; then
 	bool '	NO_ATIME support for ext2 filesystems' CONFIG_EXT2_NOATIME
+	if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+		bool '  Undelete support for ext2 filesystems (EXPERIMENTAL)' CONFIG_EXT2_UNDELETE
+	fi
 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	Mon Jul 28 00:58:24 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,120 @@
 	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
+	/* Only move if 'UNDO REMOVE' bit set */
+	if (inode->u.ext2_i.i_flags & EXT2_UNRM_FL) {
+		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) {
+				ext2_debug ("inode_c=%d, dir_c=%d,wb_c=%d\n",inode->i_count,dir->i_count,wb->i_count); 
+				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++;
+				}
+				ext2_debug ("moving %s to wastebasket as %s.\n",name,new_name);
+				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);
+				ext2_debug ("inode_c=%d, dir_c=%d,wb_c=%d\n",inode->i_count,dir->i_count,wb->i_count); 
+				brelse (bh);
+				inode->u.ext2_i.i_flags &= ~EXT2_UNRM_FL;
+				iput (inode);
+				return retval;
+			} else {
+				ext2_debug ("No wastebasket. Old unlink for %s....\n",name);
+			}
+		} 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	Mon Jul 28 13:42:32 1997
@@ -0,0 +1 @@
+ext2 undelete support (Rogier Wolff <R.E.Wolff@BitWizard.nl>/Darren J Moffat <darren@xarius.demon.co.uk>/Kurt Huwig <kurt@huwig.de>)
\
 
 \ /
  Last update: 2005-03-22 12:40    [from the cache]
©2003-2008