BOOL file_list_rename(u16 *p_old, u16 *p_new) { u16 *p_old_temp = p_old; u16 *p_new_temp = p_new; CHECK_FAIL_RET_FALSE(p_old_temp != NULL); CHECK_FAIL_RET_FALSE(p_new_temp != NULL); #ifndef WIN32 if (p_old_temp[1] == 0x3A && (p_old_temp[2] == 0x5C || p_old_temp[2] == 0x2F))//:\ or :/ { p_old_temp += 3; } if (p_new_temp[1] == 0x3A && (p_new_temp[2] == 0x5C || p_new_temp[2] == 0x2F))//:\ or :/ { p_new_temp += 3; } #endif if(vfs_rename(p_old_temp, p_new_temp) == ERR_FAILURE) { return FALSE; } return TRUE; }
/* utility to rename a file */ int lustre_rename(struct dentry *dir, struct vfsmount *mnt, char *oldname, char *newname) { struct dentry *dchild_old, *dchild_new; int err = 0; ENTRY; ASSERT_KERNEL_CTXT("kernel doing rename outside kernel context\n"); CDEBUG(D_INODE, "renaming file %.*s to %.*s\n", (int)strlen(oldname), oldname, (int)strlen(newname), newname); dchild_old = ll_lookup_one_len(oldname, dir, strlen(oldname)); if (IS_ERR(dchild_old)) RETURN(PTR_ERR(dchild_old)); if (!dchild_old->d_inode) GOTO(put_old, err = -ENOENT); dchild_new = ll_lookup_one_len(newname, dir, strlen(newname)); if (IS_ERR(dchild_new)) GOTO(put_old, err = PTR_ERR(dchild_new)); err = vfs_rename(dir->d_inode, dchild_old, dir->d_inode, dchild_new); dput(dchild_new); put_old: dput(dchild_old); RETURN(err); }
static int ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { int rc; struct dentry *lower_old_dentry; struct dentry *lower_new_dentry; struct dentry *lower_old_dir_dentry; struct dentry *lower_new_dir_dentry; lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry); lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry); dget(lower_old_dentry); dget(lower_new_dentry); lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry); if (rc) goto out_lock; fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode, NULL); if (new_dir != old_dir) fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode, NULL); out_lock: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_new_dentry->d_parent); dput(lower_old_dentry->d_parent); dput(lower_new_dentry); dput(lower_old_dentry); return rc; }
static int file_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { int err=0; err = vfs_rename(old_dir, old_dentry, new_dir, new_dentry, NULL, 0); return err; }
/* * The locking rules in wrapfs_rename are complex. We could use a simpler * superblock-level name-space lock for renames and copy-ups. */ static int wrapfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { int err = 0; struct dentry *lower_old_dentry = NULL; struct dentry *lower_new_dentry = NULL; struct dentry *lower_old_dir_dentry = NULL; struct dentry *lower_new_dir_dentry = NULL; struct dentry *trap = NULL; struct path lower_old_path, lower_new_path; wrapfs_get_lower_path(old_dentry, &lower_old_path); wrapfs_get_lower_path(new_dentry, &lower_new_path); lower_old_dentry = lower_old_path.dentry; lower_new_dentry = lower_new_path.dentry; lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); /* source should not be ancestor of target */ if (trap == lower_old_dentry) { err = -EINVAL; goto out; } /* target should not be ancestor of source */ if (trap == lower_new_dentry) { err = -ENOTEMPTY; goto out; } err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry, NULL, 0); if (err) goto out; fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); fsstack_copy_inode_size(new_dir, lower_new_dir_dentry->d_inode); if (new_dir != old_dir) { fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode); fsstack_copy_inode_size(old_dir, lower_old_dir_dentry->d_inode); } out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_old_dir_dentry); dput(lower_new_dir_dentry); wrapfs_put_lower_path(old_dentry, &lower_old_path); wrapfs_put_lower_path(new_dentry, &lower_new_path); #ifdef NEKTECH_LOGGER /*NEKTECH LOGGING*/ nektech_logger (new_dir, new_dentry, NEKTECH_RENAME); #endif /*NEKTECH LOGGING*/ return err; }
static int ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { int rc; struct dentry *lower_old_dentry; struct dentry *lower_new_dentry; struct dentry *lower_old_dir_dentry; struct dentry *lower_new_dir_dentry; struct dentry *trap = NULL; struct inode *target_inode; #ifdef CONFIG_SDP if(IS_CHAMBER_DENTRY(old_dentry)) { printk("You're renaming chamber directory. I/O error\n"); return -EIO; } #endif lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry); lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry); dget(lower_old_dentry); dget(lower_new_dentry); lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); target_inode = new_dentry->d_inode; trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); /* source should not be ancestor of target */ if (trap == lower_old_dentry) { rc = -EINVAL; goto out_lock; } /* target should not be ancestor of source */ if (trap == lower_new_dentry) { rc = -ENOTEMPTY; goto out_lock; } rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry); if (rc) goto out_lock; if (target_inode) fsstack_copy_attr_all(target_inode, ecryptfs_inode_to_lower(target_inode)); fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); if (new_dir != old_dir) fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode); out_lock: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_new_dir_dentry); dput(lower_old_dir_dentry); dput(lower_new_dentry); dput(lower_old_dentry); return rc; }
static int ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, unsigned int flags) { int rc; struct dentry *lower_old_dentry; struct dentry *lower_new_dentry; struct dentry *lower_old_dir_dentry; struct dentry *lower_new_dir_dentry; struct dentry *trap = NULL; struct inode *target_inode; if (flags) return -EINVAL; lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry); lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry); dget(lower_old_dentry); dget(lower_new_dentry); lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); target_inode = d_inode(new_dentry); trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); /* source should not be ancestor of target */ if (trap == lower_old_dentry) { rc = -EINVAL; goto out_lock; } /* target should not be ancestor of source */ if (trap == lower_new_dentry) { rc = -ENOTEMPTY; goto out_lock; } rc = vfs_rename(d_inode(lower_old_dir_dentry), lower_old_dentry, d_inode(lower_new_dir_dentry), lower_new_dentry, NULL, 0); if (rc) goto out_lock; if (target_inode) fsstack_copy_attr_all(target_inode, ecryptfs_inode_to_lower(target_inode)); fsstack_copy_attr_all(new_dir, d_inode(lower_new_dir_dentry)); if (new_dir != old_dir) fsstack_copy_attr_all(old_dir, d_inode(lower_old_dir_dentry)); out_lock: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_new_dir_dentry); dput(lower_old_dir_dentry); dput(lower_new_dentry); dput(lower_old_dentry); return rc; }
/* * The locking rules in diaryfs_rename are complex. We could use a simpler * superblock level namespace lock for renames and copy-ups */ static int diaryfs_rename(struct inode * old_dir, struct dentry * old_dentry, struct inode * new_dir, struct dentry * new_dentry) { int err = 0; struct dentry * lower_old_dentry = NULL; struct dentry * lower_new_dentry = NULL; struct dentry * lower_old_dir_dentry = NULL; struct dentry * lower_new_dir_dentry = NULL; struct dentry * trap = NULL; struct path lower_old_path, lower_new_path; diaryfs_get_lower_path(old_dentry, &lower_old_path); diaryfs_get_lower_path(new_dentry, &lower_new_path); lower_old_dentry = lower_old_path.dentry; lower_new_dentry = lower_new_path.dentry; lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); /* source should not be ancestor of the target */ if (trap == lower_old_dentry) { err = -EINVAL; goto out; } /* target should not be ancestor of source */ if (trap == lower_new_dentry) { err = -EINVAL; goto out; } err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry, NULL, 0); if (err) goto out; fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); fsstack_copy_inode_size(new_dir, lower_new_dir_dentry->d_inode); if (new_dir != old_dir) { fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode); fsstack_copy_inode_size(old_dir, lower_old_dir_dentry->d_inode); } out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_old_dir_dentry); dput(lower_new_dir_dentry); diaryfs_put_lower_path(old_dentry, &lower_old_path); diaryfs_put_lower_path(new_dentry, &lower_new_path); return err; }
/* sysfile_rename - rename file */ int sysfile_rename(const char *__path1, const char *__path2) { int ret; char *old_path, *new_path; if ((ret = copy_path(&old_path, __path1)) != 0) { return ret; } if ((ret = copy_path(&new_path, __path2)) != 0) { kfree(old_path); return ret; } ret = vfs_rename(old_path, new_path); kfree(old_path), kfree(new_path); return ret; }
static int rename_temp_file(struct file *fp_old, struct file *fp_new) { int rc; struct inode *pi_old = fp_old->f_path.dentry->d_parent->d_inode; struct inode *pi_new = fp_new->f_path.dentry->d_parent->d_inode; struct dentry *d_old = fp_old->f_path.dentry; struct dentry *d_new = fp_new->f_path.dentry; struct dentry *pd_old = NULL; struct dentry *pd_new = NULL; struct dentry *trap = NULL; dget(d_old); dget(d_new); pd_old=dget_parent(d_old); pd_new=dget_parent(d_new); trap = lock_rename(pd_old,pd_new); if(trap == d_old){ rc = -EINVAL; goto out; } if(trap == d_new){ rc = -ENOTEMPTY; goto out; } rc = vfs_rename(pi_old,d_old,pi_new,d_new,NULL,0); if(rc){ printk("Error in vfs_rename() \n"); rc= -ECANCELED; goto out; } out: unlock_rename(pd_old,pd_new); dput(pd_new); dput(pd_old); dput(d_new); dput(d_old); return rc; }
int do_rename (struct inode *olddir, const char *oname, int olen, struct inode *newdir, const char *nname, int nlen, int must_be_dir) { #if POST_20_KERNEL_F struct dentry *old_dent; struct dentry *new_dent; #endif int ret; #if POST_20_KERNEL_F ret = ovlfs_inode_get_child_dentry(olddir, oname, olen, &old_dent, OVLFS_DENT_GET_POSITIVE); if ( ret == 0 ) { /* Get a dentry for the target; note that this may */ /* be a positive or negative dentry. */ ret = ovlfs_inode_get_child_dentry(newdir, nname, nlen, &new_dent, OVLFS_DENT_GET_ANY); if ( ret != 0 ) dput(old_dent); } if ( ret == 0 ) { ret = vfs_rename(olddir, old_dent, newdir, new_dent); dput(old_dent); dput(new_dent); } #else DOWN(&(newdir->i_sem)); IMARK(olddir); IMARK(newdir); ret = o_olddir->i_op->rename(o_olddir, oname, olen, o_newdir, nname, nlen, must_be_dir); UP(&(newdir->i_sem)); #endif return ret; }
static int ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { int rc; struct dentry *lower_old_dentry; struct dentry *lower_new_dentry; struct dentry *lower_old_dir_dentry; struct dentry *lower_new_dir_dentry; struct dentry *trap = NULL; if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode)) dentry_unhash(new_dentry); lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry); lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry); dget(lower_old_dentry); dget(lower_new_dentry); lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); /* source should not be ancestor of target */ if (trap == lower_old_dentry) { rc = -EINVAL; goto out_lock; } /* target should not be ancestor of source */ if (trap == lower_new_dentry) { rc = -ENOTEMPTY; goto out_lock; } rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry); if (rc) goto out_lock; fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); if (new_dir != old_dir) fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode); out_lock: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_new_dir_dentry); dput(lower_old_dir_dentry); dput(lower_new_dentry); dput(lower_old_dentry); return rc; }
static int _mv_handler(int argc, char **argv) { if (argc < 3) { _vfs_usage(argv); return 1; } char *src_name = argv[1]; char *dest_name = argv[2]; printf("%s: move src: %s dest: %s\n", argv[0], src_name, dest_name); int res = vfs_rename(src_name, dest_name); if (res < 0) { char errbuf[16]; _errno_string(res, (char *)errbuf, sizeof(errbuf)); printf("mv ERR: %s\n", errbuf); return 2; } return 0; }
static int cmd_vfs_mv(struct vmm_chardev *cdev, const char *old_path, const char *new_path) { int rc; struct stat st; rc = vfs_stat(old_path, &st); if (rc) { vmm_cprintf(cdev, "Path %s does not exist.\n", old_path); return rc; } rc = vfs_rename(old_path, new_path); if (rc) { vmm_cprintf(cdev, "Failed to rename.\n"); return rc; } return VMM_OK; }
static void cmd_rnto(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { if (fsm->state != FTPD_RNFR) { send_msg(pcb, fsm, msg503); return; } fsm->state = FTPD_IDLE; if (arg == NULL) { send_msg(pcb, fsm, msg501); return; } if (*arg == '\0') { send_msg(pcb, fsm, msg501); return; } if (vfs_rename(fsm->vfs, fsm->renamefrom, arg)) { send_msg(pcb, fsm, msg450); } else { send_msg(pcb, fsm, msg250); } }
int do_vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, struct inode *dir, struct dentry *dentry) { int err; LKTRTrace("i%lu, %.*s, i%lu, %.*s\n", src_dir->i_ino, AuDLNPair(src_dentry), dir->i_ino, AuDLNPair(dentry)); IMustLock(dir); IMustLock(src_dir); AuDebugOn(src_dir != dir && !vfsub_is_rename_mutex_locked(dir->i_sb)); lockdep_off(); err = vfs_rename(src_dir, src_dentry, dir, dentry); lockdep_on(); if (!err) { /* dir inode is locked */ au_update_fuse_h_inode(NULL, dentry->d_parent); /*ignore*/ au_update_fuse_h_inode(NULL, src_dentry->d_parent); /*ignore*/ au_update_fuse_h_inode(NULL, src_dentry); /*ignore*/ } return err; }
static int do_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, int bindex, struct dentry **wh_old) { int err = 0; struct dentry *hidden_old_dentry; struct dentry *hidden_new_dentry; struct dentry *hidden_old_dir_dentry; struct dentry *hidden_new_dir_dentry; struct dentry *hidden_wh_dentry; struct dentry *hidden_wh_dir_dentry; char *wh_name = NULL; hidden_new_dentry = unionfs_lower_dentry_idx(new_dentry, bindex); hidden_old_dentry = unionfs_lower_dentry_idx(old_dentry, bindex); if (!hidden_new_dentry) { hidden_new_dentry = create_parents(new_dentry->d_parent->d_inode, new_dentry, bindex); if (IS_ERR(hidden_new_dentry)) { printk(KERN_DEBUG "error creating directory tree for" " rename, bindex = %d, err = %ld\n", bindex, PTR_ERR(hidden_new_dentry)); err = PTR_ERR(hidden_new_dentry); goto out; } } wh_name = alloc_whname(new_dentry->d_name.name, new_dentry->d_name.len); if (IS_ERR(wh_name)) { err = PTR_ERR(wh_name); goto out; } hidden_wh_dentry = lookup_one_len(wh_name, hidden_new_dentry->d_parent, new_dentry->d_name.len + UNIONFS_WHLEN); if (IS_ERR(hidden_wh_dentry)) { err = PTR_ERR(hidden_wh_dentry); goto out; } if (hidden_wh_dentry->d_inode) { /* get rid of the whiteout that is existing */ if (hidden_new_dentry->d_inode) { printk(KERN_WARNING "Both a whiteout and a dentry" " exist when doing a rename!\n"); err = -EIO; dput(hidden_wh_dentry); goto out; } hidden_wh_dir_dentry = lock_parent(hidden_wh_dentry); if (!(err = is_robranch_super(old_dentry->d_sb, bindex))) err = vfs_unlink(hidden_wh_dir_dentry->d_inode, hidden_wh_dentry); dput(hidden_wh_dentry); unlock_dir(hidden_wh_dir_dentry); if (err) goto out; } else dput(hidden_wh_dentry); dget(hidden_old_dentry); hidden_old_dir_dentry = dget_parent(hidden_old_dentry); hidden_new_dir_dentry = dget_parent(hidden_new_dentry); lock_rename(hidden_old_dir_dentry, hidden_new_dir_dentry); err = is_robranch_super(old_dentry->d_sb, bindex); if (err) goto out_unlock; /* ready to whiteout for old_dentry. caller will create the actual * whiteout, and must dput(*wh_old) */ if (wh_old) { char *whname; whname = alloc_whname(old_dentry->d_name.name, old_dentry->d_name.len); err = PTR_ERR(whname); if (IS_ERR(whname)) goto out_unlock; *wh_old = lookup_one_len(whname, hidden_old_dir_dentry, old_dentry->d_name.len + UNIONFS_WHLEN); kfree(whname); err = PTR_ERR(*wh_old); if (IS_ERR(*wh_old)) { *wh_old = NULL; goto out_unlock; } } err = vfs_rename(hidden_old_dir_dentry->d_inode, hidden_old_dentry, hidden_new_dir_dentry->d_inode, hidden_new_dentry); out_unlock: unlock_rename(hidden_old_dir_dentry, hidden_new_dir_dentry); dput(hidden_old_dir_dentry); dput(hidden_new_dir_dentry); dput(hidden_old_dentry); out: if (!err) { /* Fixup the newdentry. */ if (bindex < dbstart(new_dentry)) set_dbstart(new_dentry, bindex); else if (bindex > dbend(new_dentry)) set_dbend(new_dentry, bindex); } kfree(wh_name); return err; }
/* * The locking rules in wrapfs_rename are complex. We could use a simpler * superblock-level name-space lock for renames and copy-ups. */ static int wrapfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { int err = 0; struct dentry *lower_old_dentry = NULL; struct dentry *lower_new_dentry = NULL; struct dentry *lower_old_dir_dentry = NULL; struct dentry *lower_new_dir_dentry = NULL; struct dentry *trap = NULL; struct path lower_old_path, lower_new_path; wrapfs_get_lower_path(old_dentry, &lower_old_path); wrapfs_get_lower_path(new_dentry, &lower_new_path); lower_old_dentry = lower_old_path.dentry; lower_new_dentry = lower_new_path.dentry; lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); /* source should not be ancestor of target */ if (trap == lower_old_dentry) { err = -EINVAL; goto out; } /* target should not be ancestor of source */ if (trap == lower_new_dentry) { err = -ENOTEMPTY; goto out; } err = mnt_want_write(lower_old_path.mnt); if (err) goto out; err = mnt_want_write(lower_new_path.mnt); if (err) goto out_drop_old_write; err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry); if (err) goto out_err; fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); fsstack_copy_inode_size(new_dir, lower_new_dir_dentry->d_inode); if (new_dir != old_dir) { fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode); fsstack_copy_inode_size(old_dir, lower_old_dir_dentry->d_inode); } out_err: mnt_drop_write(lower_new_path.mnt); out_drop_old_write: mnt_drop_write(lower_old_path.mnt); out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_old_dir_dentry); dput(lower_new_dir_dentry); wrapfs_put_lower_path(old_dentry, &lower_old_path); wrapfs_put_lower_path(new_dentry, &lower_new_path); return err; }
static void vfs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) { bool cont = true; /* * The connection was opened via the IPC_CONNECT_ME_TO call. * This call needs to be answered. */ async_answer_0(iid, EOK); while (cont) { ipc_call_t call; ipc_callid_t callid = async_get_call(&call); if (!IPC_GET_IMETHOD(call)) break; switch (IPC_GET_IMETHOD(call)) { case VFS_IN_REGISTER: vfs_register(callid, &call); cont = false; break; case VFS_IN_MOUNT: vfs_mount(callid, &call); break; case VFS_IN_UNMOUNT: vfs_unmount(callid, &call); break; case VFS_IN_OPEN: vfs_open(callid, &call); break; case VFS_IN_CLOSE: vfs_close(callid, &call); break; case VFS_IN_READ: vfs_read(callid, &call); break; case VFS_IN_WRITE: vfs_write(callid, &call); break; case VFS_IN_SEEK: vfs_seek(callid, &call); break; case VFS_IN_TRUNCATE: vfs_truncate(callid, &call); break; case VFS_IN_FSTAT: vfs_fstat(callid, &call); break; case VFS_IN_STAT: vfs_stat(callid, &call); break; case VFS_IN_MKDIR: vfs_mkdir(callid, &call); break; case VFS_IN_UNLINK: vfs_unlink(callid, &call); break; case VFS_IN_RENAME: vfs_rename(callid, &call); break; case VFS_IN_SYNC: vfs_sync(callid, &call); break; case VFS_IN_DUP: vfs_dup(callid, &call); break; case VFS_IN_WAIT_HANDLE: vfs_wait_handle(callid, &call); break; case VFS_IN_MTAB_GET: vfs_get_mtab(callid, &call); break; default: async_answer_0(callid, ENOTSUP); break; } } /* * Open files for this client will be cleaned up when its last * connection fibril terminates. */ }
int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, struct inode *dir, struct path *path) { int err; struct path tmp = { .mnt = path->mnt }; struct dentry *d; IMustLock(dir); IMustLock(src_dir); d = path->dentry; path->dentry = d->d_parent; tmp.dentry = src_dentry->d_parent; err = security_path_rename(&tmp, src_dentry, path, d); path->dentry = d; if (unlikely(err)) goto out; lockdep_off(); err = vfs_rename(src_dir, src_dentry, dir, path->dentry); lockdep_on(); if (!err) { int did; tmp.dentry = d->d_parent; vfsub_update_h_iattr(&tmp, &did); if (did) { tmp.dentry = src_dentry; vfsub_update_h_iattr(&tmp, /*did*/NULL); tmp.dentry = src_dentry->d_parent; vfsub_update_h_iattr(&tmp, /*did*/NULL); } /*ignore*/ } out: return err; } int vfsub_mkdir(struct inode *dir, struct path *path, int mode) { int err; struct dentry *d; IMustLock(dir); d = path->dentry; path->dentry = d->d_parent; err = security_path_mkdir(path, d, mode); path->dentry = d; if (unlikely(err)) goto out; err = vfs_mkdir(dir, path->dentry, mode); if (!err) { struct path tmp = *path; int did; vfsub_update_h_iattr(&tmp, &did); if (did) { tmp.dentry = path->dentry->d_parent; vfsub_update_h_iattr(&tmp, /*did*/NULL); } /*ignore*/ } out: return err; }
/* * The locking rules in amfs_rename are complex. We could use a simpler * superblock-level name-space lock for renames and copy-ups. */ static int amfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { int err = 0; struct dentry *lower_old_dentry = NULL; struct dentry *lower_new_dentry = NULL; struct dentry *lower_old_dir_dentry = NULL; struct dentry *lower_new_dir_dentry = NULL; struct dentry *trap = NULL; struct path lower_old_path, lower_new_path; /*******Variable which will help in checking XATTR***************/ char *value = NULL; if (old_dentry->d_inode->i_ino == AMFS_SB(old_dentry->d_sb)->inode_no) { err = -EPERM; goto exitcode; } value = kzalloc(5, __GFP_WAIT); if (value == NULL) { err = -ENOMEM; goto exitcode; } if (amfs_getxattr(old_dentry, AMFS_XATTR_NAME, value, 5) > 0) { if (!strncmp(value, AMFS_BADFILE, 3)) { err = -EPERM; goto freevalue; } } else if (amfs_getxattr(old_dentry, AMFS_XATTR_NAME, value, 5) != -ENODATA) { err = amfs_getxattr(old_dentry, AMFS_XATTR_NAME, value, 5); goto freevalue; } /****************************************************************/ amfs_get_lower_path(old_dentry, &lower_old_path); amfs_get_lower_path(new_dentry, &lower_new_path); lower_old_dentry = lower_old_path.dentry; lower_new_dentry = lower_new_path.dentry; lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); /* source should not be ancestor of target */ if (trap == lower_old_dentry) { err = -EINVAL; goto out; } /* target should not be ancestor of source */ if (trap == lower_new_dentry) { err = -ENOTEMPTY; goto out; } err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry, NULL, 0); if (err) goto out; fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); fsstack_copy_inode_size(new_dir, lower_new_dir_dentry->d_inode); if (new_dir != old_dir) { fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode); fsstack_copy_inode_size(old_dir, lower_old_dir_dentry->d_inode); } out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_old_dir_dentry); dput(lower_new_dir_dentry); amfs_put_lower_path(old_dentry, &lower_old_path); amfs_put_lower_path(new_dentry, &lower_new_path); freevalue: kfree(value); exitcode: return err; }
/* * The locking rules in sdcardfs_rename are complex. We could use a simpler * superblock-level name-space lock for renames and copy-ups. */ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { int err = 0; struct dentry *lower_old_dentry = NULL; struct dentry *lower_new_dentry = NULL; struct dentry *lower_old_dir_dentry = NULL; struct dentry *lower_new_dir_dentry = NULL; struct dentry *trap = NULL; struct dentry *new_parent = NULL; struct path lower_old_path, lower_new_path; struct sdcardfs_sb_info *sbi = SDCARDFS_SB(old_dentry->d_sb); const struct cred *saved_cred = NULL; int has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); if(!check_caller_access_to_name(old_dir, old_dentry->d_name.name, sbi->options.derive, 1, has_rw) || !check_caller_access_to_name(new_dir, new_dentry->d_name.name, sbi->options.derive, 1, has_rw)) { err = -EACCES; goto out_eacces; } /* save current_cred and override it */ OVERRIDE_CRED(SDCARDFS_SB(old_dir->i_sb), saved_cred); sdcardfs_get_real_lower(old_dentry, &lower_old_path); sdcardfs_get_lower_path(new_dentry, &lower_new_path); lower_old_dentry = lower_old_path.dentry; lower_new_dentry = lower_new_path.dentry; lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); /* source should not be ancestor of target */ if (trap == lower_old_dentry) { err = -EINVAL; goto out; } /* target should not be ancestor of source */ if (trap == lower_new_dentry) { err = -ENOTEMPTY; goto out; } err = mnt_want_write(lower_old_path.mnt); if (err) goto out; err = mnt_want_write(lower_new_path.mnt); if (err) goto out_drop_old_write; err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry); if (err) goto out_err; /* Copy attrs from lower dir, but i_uid/i_gid */ fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); fsstack_copy_inode_size(new_dir, lower_new_dir_dentry->d_inode); fix_derived_permission(new_dir); if (new_dir != old_dir) { fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode); fsstack_copy_inode_size(old_dir, lower_old_dir_dentry->d_inode); fix_derived_permission(old_dir); /* update the derived permission of the old_dentry * with its new parent */ new_parent = dget_parent(new_dentry); if(new_parent) { if(old_dentry->d_inode) { get_derived_permission(new_parent, old_dentry); fix_derived_permission(old_dentry->d_inode); } dput(new_parent); } } out_err: mnt_drop_write(lower_new_path.mnt); out_drop_old_write: mnt_drop_write(lower_old_path.mnt); out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_old_dir_dentry); dput(lower_new_dir_dentry); sdcardfs_put_real_lower(old_dentry, &lower_old_path); sdcardfs_put_lower_path(new_dentry, &lower_new_path); REVERT_CRED(saved_cred); out_eacces: return err; }
/* * The locking rules in u2fs_rename are complex. We could use a simpler * superblock-level name-space lock for renames and copy-ups. */ static int u2fs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { int err = 0; struct dentry *lower_old_dentry = NULL; struct dentry *lower_new_dentry = NULL; struct dentry *lower_old_dir_dentry = NULL; struct dentry *lower_new_dir_dentry = NULL; struct dentry *trap = NULL; struct dentry *ret = NULL; struct path lower_old_path, lower_new_path; /* creating parent directories if destination is read-only */ if((U2FS_D(old_dentry)->lower_path[LEFT].dentry) == NULL && (U2FS_D(old_dentry)->lower_path[LEFT].mnt) == NULL){ err = create_whiteout(old_dentry); if(err){ err = -EIO; goto out_copyup; } err = copyup_dentry(old_dir, old_dentry, old_dentry->d_name.name, old_dentry->d_name.len, NULL, i_size_read(old_dentry->d_inode)); if(err) goto out_copyup; } if((U2FS_D(new_dentry)->lower_path[LEFT].dentry) == NULL && (U2FS_D(new_dentry)->lower_path[LEFT].mnt) == NULL){ ret = create_parents(new_dir, new_dentry, new_dentry->d_name.name); if (!ret || IS_ERR(ret)) { err = PTR_ERR(ret); if (!IS_COPYUP_ERR(err)) printk(KERN_ERR "u2fs: create_parents for " "u2fs_rename failed" "err=%d\n", err); goto out_copyup; } u2fs_postcopyup_setmnt(new_dentry); u2fs_put_reset_lower_path(new_dentry, RIGHT); if(err) goto out_copyup; } u2fs_get_lower_path(old_dentry, &lower_old_path, LEFT); u2fs_get_lower_path(new_dentry, &lower_new_path, LEFT); lower_old_dentry = lower_old_path.dentry; lower_new_dentry = lower_new_path.dentry; lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); /* source should not be ancestor of target */ if (trap == lower_old_dentry) { err = -EINVAL; goto out; } /* target should not be ancestor of source */ if (trap == lower_new_dentry) { err = -ENOTEMPTY; goto out; } err = mnt_want_write(lower_old_path.mnt); if (err) goto out; err = mnt_want_write(lower_new_path.mnt); if (err) goto out_drop_old_write; err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry); if (err) goto out_err; fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); fsstack_copy_inode_size(new_dir, lower_new_dir_dentry->d_inode); if (new_dir != old_dir) { fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode); fsstack_copy_inode_size(old_dir, lower_old_dir_dentry->d_inode); } out_err: mnt_drop_write(lower_new_path.mnt); out_drop_old_write: mnt_drop_write(lower_old_path.mnt); out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_old_dir_dentry); dput(lower_new_dir_dentry); u2fs_put_lower_path(old_dentry, &lower_old_path); u2fs_put_lower_path(new_dentry, &lower_new_path); out_copyup: return err; }
/* * Rename a file * N.B. After this call _both_ ffhp and tfhp need an fh_put */ int nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, struct svc_fh *tfhp, char *tname, int tlen) { struct dentry *fdentry, *tdentry, *odentry, *ndentry; struct inode *fdir, *tdir; int err; err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_REMOVE); if (err) goto out; err = fh_verify(rqstp, tfhp, S_IFDIR, MAY_CREATE); if (err) goto out; fdentry = ffhp->fh_dentry; fdir = fdentry->d_inode; tdentry = tfhp->fh_dentry; tdir = tdentry->d_inode; /* N.B. We shouldn't need this ... dentry layer handles it */ err = nfserr_perm; if (!flen || (fname[0] == '.' && (flen == 1 || (flen == 2 && fname[1] == '.'))) || !tlen || (tname[0] == '.' && (tlen == 1 || (tlen == 2 && tname[1] == '.')))) goto out; odentry = lookup_dentry(fname, dget(fdentry), 0); err = PTR_ERR(odentry); if (IS_ERR(odentry)) goto out_nfserr; err = -ENOENT; if (!odentry->d_inode) goto out_dput_old; ndentry = lookup_dentry(tname, dget(tdentry), 0); err = PTR_ERR(ndentry); if (IS_ERR(ndentry)) goto out_dput_old; /* * Lock the parent directories. */ nfsd_double_down(&tdir->i_sem, &fdir->i_sem); err = -ENOENT; /* GAM3 check for parent changes after locking. */ if (check_parent(fdir, odentry) && check_parent(tdir, ndentry)) { err = vfs_rename(fdir, odentry, tdir, ndentry); if (!err && EX_ISSYNC(tfhp->fh_export)) { write_inode_now(fdir); write_inode_now(tdir); } } else dprintk("nfsd: Caught race in nfsd_rename"); DQUOT_DROP(fdir); DQUOT_DROP(tdir); nfsd_double_up(&tdir->i_sem, &fdir->i_sem); dput(ndentry); out_dput_old: dput(odentry); if (err) goto out_nfserr; out: return err; out_nfserr: err = nfserrno(-err); goto out; }
/* * The locking rules in sdcardfs_rename are complex. We could use a simpler * superblock-level name-space lock for renames and copy-ups. */ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { int err = 0; struct dentry *lower_old_dentry = NULL; struct dentry *lower_new_dentry = NULL; struct dentry *lower_old_dir_dentry = NULL; struct dentry *lower_new_dir_dentry = NULL; struct dentry *trap = NULL; struct dentry *new_parent = NULL; struct path lower_old_path, lower_new_path; const struct cred *saved_cred = NULL; if(!check_caller_access_to_name(old_dir, old_dentry->d_name.name) || !check_caller_access_to_name(new_dir, new_dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " new_dentry: %s, task:%s\n", __func__, new_dentry->d_name.name, current->comm); err = -EACCES; goto out_eacces; } /* save current_cred and override it */ OVERRIDE_CRED(SDCARDFS_SB(old_dir->i_sb), saved_cred); sdcardfs_get_real_lower(old_dentry, &lower_old_path); sdcardfs_get_lower_path(new_dentry, &lower_new_path); lower_old_dentry = lower_old_path.dentry; lower_new_dentry = lower_new_path.dentry; lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); /* source should not be ancestor of target */ if (trap == lower_old_dentry) { err = -EINVAL; goto out; } /* target should not be ancestor of source */ if (trap == lower_new_dentry) { err = -ENOTEMPTY; goto out; } err = mnt_want_write(lower_old_path.mnt); if (err) goto out; err = mnt_want_write(lower_new_path.mnt); if (err) goto out_drop_old_write; err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry); if (err) goto out_err; /* Copy attrs from lower dir, but i_uid/i_gid */ sdcardfs_copy_inode_attr(new_dir, lower_new_dir_dentry->d_inode); fsstack_copy_inode_size(new_dir, lower_new_dir_dentry->d_inode); fix_derived_permission(new_dir); if (new_dir != old_dir) { sdcardfs_copy_inode_attr(old_dir, lower_old_dir_dentry->d_inode); fsstack_copy_inode_size(old_dir, lower_old_dir_dentry->d_inode); fix_derived_permission(old_dir); /* update the derived permission of the old_dentry * with its new parent */ new_parent = dget_parent(new_dentry); if(new_parent) { if(old_dentry->d_inode) { get_derived_permission(new_parent, old_dentry); fix_derived_permission(old_dentry->d_inode); } dput(new_parent); } } out_err: mnt_drop_write(lower_new_path.mnt); out_drop_old_write: mnt_drop_write(lower_old_path.mnt); out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_old_dir_dentry); dput(lower_new_dir_dentry); sdcardfs_put_real_lower(old_dentry, &lower_old_path); sdcardfs_put_lower_path(new_dentry, &lower_new_path); REVERT_CRED(saved_cred); out_eacces: return err; }
static int unionfs_unlink_whiteout(struct inode *dir, struct dentry *dentry) { int err = 0; struct dentry *hidden_old_dentry; struct dentry *hidden_wh_dentry = NULL; struct dentry *hidden_old_dir_dentry, *hidden_new_dir_dentry; char *name = NULL; struct iattr newattrs; print_entry_location(); fist_print_dentry("IN unionfs_unlink_whiteout: ", dentry); /* create whiteout, get the leftmost underlying dentry and rename it */ hidden_old_dentry = dtohd(dentry); /* lookup .wh.foo first, MUST NOT EXIST */ name = KMALLOC(dentry->d_name.len + sizeof(".wh."), GFP_UNIONFS); if (!name) { err = -ENOMEM; goto out; } strcpy(name, ".wh."); strncat(name, dentry->d_name.name, dentry->d_name.len); name[4 + dentry->d_name.len] = '\0'; hidden_wh_dentry = LOOKUP_ONE_LEN(name, hidden_old_dentry->d_parent, dentry->d_name.len + 4); if (IS_ERR(hidden_wh_dentry)) { err = PTR_ERR(hidden_wh_dentry); goto out; } ASSERT(hidden_wh_dentry->d_inode == NULL); DGET(hidden_old_dentry); hidden_old_dir_dentry = GET_PARENT(hidden_old_dentry); hidden_new_dir_dentry = GET_PARENT(hidden_wh_dentry); double_lock(hidden_old_dir_dentry, hidden_new_dir_dentry); if (!(err = is_robranch(dentry))) { if (S_ISREG(hidden_old_dentry->d_inode->i_mode)) { err = vfs_rename(hidden_old_dir_dentry->d_inode, hidden_old_dentry, hidden_new_dir_dentry->d_inode, hidden_wh_dentry); } else { err = vfs_unlink(hidden_old_dir_dentry->d_inode, hidden_old_dentry); if (!err) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) err = vfs_create(hidden_new_dir_dentry->d_inode, hidden_wh_dentry, 0666, NULL); #else err = vfs_create(hidden_new_dir_dentry->d_inode, hidden_wh_dentry, 0666); #endif } } double_unlock(hidden_old_dir_dentry, hidden_new_dir_dentry); DPUT(hidden_old_dentry); DPUT(hidden_wh_dentry); if (!err) { hidden_wh_dentry = LOOKUP_ONE_LEN(name, hidden_old_dentry->d_parent, dentry->d_name.len + 4); if (IS_ERR(hidden_wh_dentry)) { err = PTR_ERR(hidden_wh_dentry); goto out; } PASSERT(hidden_wh_dentry->d_inode); down(&hidden_wh_dentry->d_inode->i_sem); newattrs.ia_valid = ATTR_CTIME; if (hidden_wh_dentry->d_inode->i_size != 0) { newattrs.ia_valid |= ATTR_SIZE; newattrs.ia_size = 0; } /* We discard this error, because the entry is whited out * even if we fail here. */ notify_change(hidden_wh_dentry, &newattrs); up(&hidden_wh_dentry->d_inode->i_sem); DPUT(hidden_wh_dentry); } if (err) { if (dbstart(dentry) == 0) goto out; /* exit if the error returned was NOT -EROFS */ if (!IS_COPYUP_ERR(err)) goto out; err = create_whiteout(dentry, dbstart(dentry) - 1); } else { fist_copy_attr_all(dir, hidden_new_dir_dentry->d_inode); } out: KFREE(name); print_exit_status(err); return err; }
SYSCALL_HANDLER3(sys_rename, const char *oldpath, const char *newpath, int *ret) { *ret = vfs_rename(oldpath, newpath); }
/* * The locking rules in esdfs_rename are complex. We could use a simpler * superblock-level name-space lock for renames and copy-ups. */ static int esdfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { int err = 0; struct dentry *lower_old_dentry = NULL; struct dentry *lower_new_dentry = NULL; struct dentry *lower_old_dir_dentry = NULL; struct dentry *lower_new_dir_dentry = NULL; struct dentry *trap = NULL; struct path lower_old_path, lower_new_path; int mask; const struct cred *creds = esdfs_override_creds(ESDFS_SB(old_dir->i_sb), &mask); if (!creds) return -ENOMEM; /* Never rename to or from a pseudo hard link target. */ if (ESDFS_DENTRY_HAS_STUB(old_dentry)) esdfs_get_lower_stub_path(old_dentry, &lower_old_path); else esdfs_get_lower_path(old_dentry, &lower_old_path); if (ESDFS_DENTRY_HAS_STUB(new_dentry)) esdfs_get_lower_stub_path(new_dentry, &lower_new_path); else esdfs_get_lower_path(new_dentry, &lower_new_path); lower_old_dentry = lower_old_path.dentry; lower_new_dentry = lower_new_path.dentry; esdfs_get_lower_parent(old_dentry, lower_old_dentry, &lower_old_dir_dentry); esdfs_get_lower_parent(new_dentry, lower_new_dentry, &lower_new_dir_dentry); trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); /* source should not be ancestor of target */ if (trap == lower_old_dentry) { err = -EINVAL; goto out; } /* target should not be ancestor of source */ if (trap == lower_new_dentry) { err = -ENOTEMPTY; goto out; } err = mnt_want_write(lower_old_path.mnt); if (err) goto out; err = mnt_want_write(lower_new_path.mnt); if (err) goto out_drop_old_write; err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry); if (err) goto out_err; esdfs_copy_attr(new_dir, lower_new_dir_dentry->d_inode); fsstack_copy_inode_size(new_dir, lower_new_dir_dentry->d_inode); if (new_dir != old_dir) { esdfs_copy_attr(old_dir, lower_old_dir_dentry->d_inode); fsstack_copy_inode_size(old_dir, lower_old_dir_dentry->d_inode); } /* Drop any old links */ if (ESDFS_DENTRY_HAS_STUB(old_dentry)) d_drop(old_dentry); if (ESDFS_DENTRY_HAS_STUB(new_dentry)) d_drop(new_dentry); out_err: mnt_drop_write(lower_new_path.mnt); out_drop_old_write: mnt_drop_write(lower_old_path.mnt); out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); esdfs_put_lower_parent(old_dentry, &lower_old_dir_dentry); esdfs_put_lower_parent(new_dentry, &lower_new_dir_dentry); esdfs_put_lower_path(old_dentry, &lower_old_path); esdfs_put_lower_path(new_dentry, &lower_new_path); esdfs_revert_creds(creds, &mask); return err; }
/* * The locking rules in sdcardfs_rename are complex. We could use a simpler * superblock-level name-space lock for renames and copy-ups. */ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { int err = 0; struct dentry *lower_old_dentry = NULL; struct dentry *lower_new_dentry = NULL; struct dentry *lower_old_dir_dentry = NULL; struct dentry *lower_new_dir_dentry = NULL; struct dentry *trap = NULL; struct path lower_old_path, lower_new_path; OVERRIDE_CRED(SDCARDFS_SB(old_dir->i_sb)); sdcardfs_get_lower_path(old_dentry, &lower_old_path); sdcardfs_get_lower_path(new_dentry, &lower_new_path); lower_old_dentry = lower_old_path.dentry; lower_new_dentry = lower_new_path.dentry; lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); /* source should not be ancestor of target */ if (trap == lower_old_dentry) { err = -EINVAL; goto out; } /* target should not be ancestor of source */ if (trap == lower_new_dentry) { err = -ENOTEMPTY; goto out; } err = mnt_want_write(lower_old_path.mnt); if (err) goto out; err = mnt_want_write(lower_new_path.mnt); if (err) goto out_drop_old_write; err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry); if (err) goto out_err; /* Copy attrs from lower dir, but i_uid/i_gid */ fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); fsstack_copy_inode_size(new_dir, lower_new_dir_dentry->d_inode); fix_fat_permission(new_dir); if (new_dir != old_dir) { fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode); fsstack_copy_inode_size(old_dir, lower_old_dir_dentry->d_inode); fix_fat_permission(old_dir); } out_err: mnt_drop_write(lower_new_path.mnt); out_drop_old_write: mnt_drop_write(lower_old_path.mnt); out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_old_dir_dentry); dput(lower_new_dir_dentry); sdcardfs_put_lower_path(old_dentry, &lower_old_path); sdcardfs_put_lower_path(new_dentry, &lower_new_path); REVERT_CRED(); return err; }
static int do_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, int bindex, struct dentry **wh_old) { int err = 0; struct dentry *hidden_old_dentry; struct dentry *hidden_new_dentry; struct dentry *hidden_old_dir_dentry; struct dentry *hidden_new_dir_dentry; struct dentry *hidden_wh_dentry; struct dentry *hidden_wh_dir_dentry; char *wh_name = NULL; print_entry(" bindex=%d", bindex); fist_print_dentry("IN: do_rename, old_dentry", old_dentry); fist_print_dentry("IN: do_rename, new_dentry", new_dentry); fist_dprint(7, "do_rename for bindex = %d\n", bindex); hidden_new_dentry = dtohd_index(new_dentry, bindex); hidden_old_dentry = dtohd_index(old_dentry, bindex); if (!hidden_new_dentry) { hidden_new_dentry = create_parents(new_dentry->d_parent->d_inode, new_dentry, bindex); if (IS_ERR(hidden_new_dentry)) { fist_dprint(7, "error creating directory tree for rename, bindex = %d\n", bindex); err = PTR_ERR(hidden_new_dentry); goto out; } } wh_name = alloc_whname(new_dentry->d_name.name, new_dentry->d_name.len); if (IS_ERR(wh_name)) { err = PTR_ERR(wh_name); goto out; } hidden_wh_dentry = LOOKUP_ONE_LEN(wh_name, hidden_new_dentry->d_parent, new_dentry->d_name.len + WHLEN); if (IS_ERR(hidden_wh_dentry)) { err = PTR_ERR(hidden_wh_dentry); goto out; } if (hidden_wh_dentry->d_inode) { /* get rid of the whiteout that is existing */ if (hidden_new_dentry->d_inode) { printk(KERN_WARNING "Both a whiteout and a dentry exist when doing a rename!\n"); err = -EIO; DPUT(hidden_wh_dentry); goto out; } hidden_wh_dir_dentry = lock_parent(hidden_wh_dentry); if (!(err = is_robranch_super(old_dentry->d_sb, bindex))) { err = vfs_unlink(hidden_wh_dir_dentry->d_inode, hidden_wh_dentry); } DPUT(hidden_wh_dentry); unlock_dir(hidden_wh_dir_dentry); if (err) goto out; } else DPUT(hidden_wh_dentry); DGET(hidden_old_dentry); hidden_old_dir_dentry = GET_PARENT(hidden_old_dentry); hidden_new_dir_dentry = GET_PARENT(hidden_new_dentry); lock_rename(hidden_old_dir_dentry, hidden_new_dir_dentry); err = is_robranch_super(old_dentry->d_sb, bindex); if (err) goto out_unlock; /* ready to whiteout for old_dentry. caller will create the actual whiteout, and must dput(*wh_old) */ if (wh_old) { char *whname; whname = alloc_whname(old_dentry->d_name.name, old_dentry->d_name.len); err = PTR_ERR(whname); if (IS_ERR(whname)) goto out_unlock; *wh_old = LOOKUP_ONE_LEN(whname, hidden_old_dir_dentry, old_dentry->d_name.len + WHLEN); KFREE(whname); err = PTR_ERR(*wh_old); if (IS_ERR(*wh_old)) { *wh_old = NULL; goto out_unlock; } } fist_print_dentry("NEWBEF", new_dentry); fist_print_dentry("OLDBEF", old_dentry); err = vfs_rename(hidden_old_dir_dentry->d_inode, hidden_old_dentry, hidden_new_dir_dentry->d_inode, hidden_new_dentry); fist_print_dentry("NEWAFT", new_dentry); fist_print_dentry("OLDAFT", old_dentry); out_unlock: unlock_rename(hidden_old_dir_dentry, hidden_new_dir_dentry); DPUT(hidden_old_dir_dentry); DPUT(hidden_new_dir_dentry); DPUT(hidden_old_dentry); out: if (!err) { /* Fixup the newdentry. */ if (bindex < dbstart(new_dentry)) set_dbstart(new_dentry, bindex); else if (bindex > dbend(new_dentry)) set_dbend(new_dentry, bindex); } KFREE(wh_name); fist_print_dentry("OUT: do_rename, old_dentry", old_dentry); fist_print_dentry("OUT: do_rename, new_dentry", new_dentry); print_exit_status(err); return err; }