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/