diff -ruN linux-2.6.20.2.orig/fs/dare.c linux-2.6.20.2/fs/dare.c --- linux-2.6.20.2.orig/fs/dare.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.20.2/fs/dare.c 2007-03-12 12:55:54.000000000 +0100 @@ -0,0 +1,381 @@ +/* + * linux/fs/dare.c + * + * Copyright (C) 2004-2006 by Marek Zelem + */ + +#define DELETED_DIR "deleted" +// #define CONFIG_DARE_HOURS 1 + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// #include +#include + +char * d_path_relative(struct dentry *dentry, struct vfsmount *vfsmnt, + char *buf, int buflen); + +static DECLARE_MUTEX(deleted_mutex); + +struct vfsmount *find_inode_mnt(struct inode *inode); + +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 ) +{ + mm_segment_t old_fs; + int result; + loff_t pos; + + if( buf==NULL ) + return(0); + old_fs = get_fs(); + set_fs(get_ds()); + /* The cast to a user pointer is valid due to the set_fs() */ + pos=file->f_pos; + result = vfs_write(file,buf,len,&pos); + file->f_pos=pos; + set_fs(old_fs); + return(result); +} + +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); + + if( page!=NULL ) + { + fn=d_path_relative(dentry,mnt,page,PAGE_SIZE); + if( fn!=NULL ) + write_to_file(file,fn,strlen(fn)); + free_page((unsigned long) page); + return(0); + } + return(0); +} + +/* + * dare_move( struct inode *dir, struct dentry * dentry ) + * Must be called with mutex_lock(&dir->i_mutex); + */ +int dare_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 = -ENOENT; + + /* We move only a valid dentry */ + + if( !dentry->d_inode ) + return(ret); + + +// printk("ZZZ: start\n"); + /* 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("dare_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("dare_move: /deleted is not a directory!\n"); */ + goto Out; + } + if( deldir==dentry || is_offspring(deldir,dentry) ) + { + /* Deleting inside /deleted */ + /* printk("dare_move: Deleting inside /deleted\n"); */ + goto Out; + } + +// printk("ZZZ: 1\n"); + + /* search for /deleted/