diff -ruN linux-2.4.26.trustee/Documentation/Configure.help linux-2.4.26/Documentation/Configure.help
--- linux-2.4.26.trustee/Documentation/Configure.help 2004-04-15 13:52:41.000000000 +0200
+++ linux-2.4.26/Documentation/Configure.help 2004-04-15 14:07:46.000000000 +0200
@@ -13749,6 +13749,22 @@
need this functionality say Y here. Note that you will need latest
quota utilities for new quota format with this kernel.
+VFS /deleted support
+CONFIG_DELETED
+ Move deleted files to /deleted directory on each mounted filesystem
+ instead of unlinking. Deleted files are grouped by N hours to separate
+ directories.
+
+ If you want use this feature for getting ability to undelete files
+ you need answer Y here and create directory 'deleted' accessible only
+ for user 'root' on root directory of every mounted filesystem which you
+ want to have undelete ability.
+
+ You also need user space utility for undeleting files and user space
+ daemon which periodically checks free space on mounted filesystems and
+ if needed remove older files from 'deleted' directory. Those utilities
+ can be found at .
+
Memory Technology Device (MTD) support
CONFIG_MTD
Memory Technology Devices are flash, RAM and similar chips, often
diff -ruN linux-2.4.26.trustee/fs/Config.in linux-2.4.26/fs/Config.in
--- linux-2.4.26.trustee/fs/Config.in 2004-04-15 13:52:40.000000000 +0200
+++ linux-2.4.26/fs/Config.in 2004-04-15 14:07:46.000000000 +0200
@@ -7,6 +7,13 @@
bool 'Quota support' CONFIG_QUOTA
dep_tristate ' VFS v0 quota format support' CONFIG_QFMT_V2 $CONFIG_QUOTA
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool 'VFS /deleted support' CONFIG_DELETED
+ if [ "$CONFIG_DELETED" = "y" ] ; then
+ int 'Gruping deleted files by N hours' CONFIG_DELETED_HOURS 1
+ fi
+fi
+
tristate 'Kernel automounter support' CONFIG_AUTOFS_FS
tristate 'Kernel automounter version 4 support (also supports v3)' CONFIG_AUTOFS4_FS
bool ' Linux trustees (ACL) support ' CONFIG_TRUSTEES
diff -ruN linux-2.4.26.trustee/fs/Makefile linux-2.4.26/fs/Makefile
--- linux-2.4.26.trustee/fs/Makefile 2004-04-15 13:59:00.000000000 +0200
+++ linux-2.4.26/fs/Makefile 2004-04-15 14:07:46.000000000 +0200
@@ -14,6 +14,7 @@
super.o block_dev.o char_dev.o stat.o exec.o pipe.o namei.o \
fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \
dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \
+ evocate_mnt.o deleted.o \
filesystems.o namespace.o seq_file.o xattr.o quota.o
obj-$(CONFIG_QUOTA) += dquot.o quota_v1.o
diff -ruN linux-2.4.26.trustee/fs/deleted.c linux-2.4.26/fs/deleted.c
--- linux-2.4.26.trustee/fs/deleted.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.26/fs/deleted.c 2004-04-15 14:07:46.000000000 +0200
@@ -0,0 +1,320 @@
+
+#define DELETED_DIR "deleted"
+// #define CONFIG_DELETED_HOURS 1
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static DECLARE_MUTEX(deleted_mutex);
+
+struct vfsmount * vfs_evocate_mnt(struct dentry *dentry);
+
+static int is_offspring( struct dentry * dir, struct dentry * offspring )
+{
+ /* FIXME: do locking */
+ /* maybe add some depth limitation eg. /deleted/xxx/yyy */
+ while( offspring->d_parent!=NULL && offspring->d_parent!=offspring )
+ {
+ if( offspring->d_parent==dir )
+ return(1);
+ offspring=offspring->d_parent;
+ }
+ return(0);
+}
+
+struct proc_priv {
+ uid_t fsuid;
+ gid_t fsgid;
+ kernel_cap_t cap_effective;
+};
+
+static void save_proc_priv( struct proc_priv *p )
+{
+ p->fsuid=current->fsuid;
+ p->fsgid=current->fsgid;
+ cap_t(p->cap_effective) = cap_t(current->cap_effective);
+}
+
+static void restore_proc_priv( struct proc_priv *p )
+{
+ current->fsuid=p->fsuid;
+ current->fsgid=p->fsgid;
+ cap_t(current->cap_effective) = cap_t(p->cap_effective);
+}
+
+static void set_proc_priv( void )
+{
+ current->fsuid=0;
+ current->fsgid=0;
+ cap_t(current->cap_effective) = to_cap_t(CAP_FS_MASK);
+}
+
+static int write_to_file( struct file *file, char *buf, int len )
+{ int r;
+ mm_segment_t fs;
+
+ if( buf==NULL )
+ return(0);
+ if( locks_verify_area(FLOCK_VERIFY_WRITE,file->f_dentry->d_inode,file,file->f_pos,len)!=0 )
+ return(-1);
+ fs = get_fs(); set_fs(KERNEL_DS);
+ r=file->f_op->write(file,buf,len,&file->f_pos);
+ set_fs(fs);
+ if( r>0 )
+ dnotify_parent(file->f_dentry, DN_MODIFY);
+ return(r);
+}
+
+static int write_path_to_file( struct file *file, struct dentry *dentry, struct vfsmount *mnt )
+{ char *fn;
+ char *page = (char *) __get_free_page(GFP_USER);
+ struct dentry *root;
+
+ if( page!=NULL )
+ {
+ root = dget(dentry->d_sb->s_root);
+ spin_lock(&dcache_lock);
+ fn=__d_path(dentry,mnt,root,mnt,page,PAGE_SIZE);
+ spin_unlock(&dcache_lock);
+ if( fn!=NULL )
+ write_to_file(file,fn,strlen(fn));
+ dput(root);
+ free_page((unsigned long) page);
+ return(0);
+ }
+ return(0);
+}
+
+int deleted_move( struct inode *dir, struct dentry * dentry )
+{
+ struct dentry *deldir;
+ struct proc_priv proc_priv;
+ struct timeval now;
+ int num;
+ char buf[64];
+ struct dentry *d,*f;
+ struct iattr newattrs;
+ struct file *file;
+ struct vfsmount *mnt;
+ unsigned long ino;
+ int ret = -1;
+
+ /* We move only a valid dentry */
+
+ if( !dentry->d_inode )
+ return(ret);
+
+
+ /* Save current process privileges and set root privileges */
+
+ save_proc_priv(&proc_priv);
+ set_proc_priv();
+
+
+ /* search for /deleted directory */
+
+ deldir=lookup_one_len(DELETED_DIR,dentry->d_sb->s_root,strlen(DELETED_DIR));
+ if( IS_ERR(deldir) )
+ {
+ printk("deleted_move: Error 1 (%d) [patent inode %ld]\n",(int)(deldir),dentry->d_sb->s_root->d_inode->i_ino);
+ goto Out0;
+ }
+ if( !deldir->d_inode )
+ {
+ /* /deleted does not exist */
+ goto Out;
+ }
+ if( !S_ISDIR(deldir->d_inode->i_mode) )
+ {
+ /* /deleted is not a directory! */
+/* printk("deleted_move: /deleted is not a directory!\n"); */
+ goto Out;
+ }
+ if( is_offspring(deldir,dentry) )
+ {
+ /* Deleting inside /deleted */
+ /* printk("deleted_move: Deleting inside /deleted\n"); */
+ goto Out;
+ }
+
+
+ /* search for /deleted/