/*===========================================================================* * do_rename * *===========================================================================*/ int do_rename() { /* Perform the rename(name1, name2) system call. */ int r = 0, r1; size_t len; struct vnode *old_dirp, *new_dirp, *vp; char old_name[PATH_MAX+1]; /* See if 'name1' (existing file) exists. Get dir and file inodes. */ if (fetch_name(user_fullpath, PATH_MAX, m_in.name1) < 0) return(err_code); if ((old_dirp = last_dir()) == NIL_VNODE) return(err_code); /* If the sticky bit is set, only the owner of the file or a privileged user is allowed to rename */ if((old_dirp->v_mode & S_ISVTX) == S_ISVTX) { /* Look up inode of file to unlink to retrieve owner */ vp = advance(old_dirp, PATH_RET_SYMLINK); if (vp != NIL_VNODE) { if(vp->v_uid != fp->fp_effuid && fp->fp_effuid != SU_UID) r = -EPERM; put_vnode(vp); } else r = err_code; if (r != 0) { put_vnode(old_dirp); return(r); } } /* Save the last component of the old name */ if(strlen(user_fullpath) >= sizeof(old_name)) { put_vnode(old_dirp); return(-ENAMETOOLONG); } strcpy(old_name, user_fullpath); /* See if 'name2' (new name) exists. Get dir inode */ if (fetch_name(user_fullpath, PATH_MAX, m_in.name2) < 0) r = err_code; else if ((new_dirp = last_dir()) == NIL_VNODE) r = err_code; if (r != 0) { put_vnode(old_dirp); return r; } /* Both parent directories must be on the same device. */ if(old_dirp->v_fs_e != new_dirp->v_fs_e) r = -EXDEV; /* Parent dirs must be writable, searchable and on a writable device */ if ((r1 = forbidden(old_dirp, W_BIT|X_BIT)) != 0 || (r1 = forbidden(new_dirp, W_BIT|X_BIT)) != 0) r = r1; if(r == 0) r = req_rename(old_dirp->v_fs_e, old_dirp->v_inode_nr, old_name, new_dirp->v_inode_nr, user_fullpath); put_vnode(old_dirp); put_vnode(new_dirp); return(r); }
/*===========================================================================* * do_rename * *===========================================================================*/ PUBLIC int do_rename() { /* Perform the rename(name1, name2) system call. */ int r; int old_dir_inode; int old_fs_e; int new_dir_inode; int new_fs_e; size_t len; struct vnode *vp_od, *vp_nd; char old_name[PATH_MAX+1]; /* See if 'name1' (existing file) exists. Get dir and file inodes. */ if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); /* Request lookup */ if ((r = lookup_lastdir(0 /*!use_realuid*/, &vp_od)) != OK) return r; r= forbidden(vp_od, W_BIT|X_BIT, 0 /*!use_realuid*/); if (r != OK) { put_vnode(vp_od); return r; } /* Remeber FS endpoint */ old_fs_e = vp_od->v_fs_e; /* Save the last component of the old name */ len= strlen(user_fullpath); if (len >= sizeof(old_name)) { put_vnode(vp_od); return ENAMETOOLONG; } memcpy(old_name, user_fullpath, len+1); /* See if 'name2' (new name) exists. Get dir inode */ if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) { put_vnode(vp_od); return err_code; } /* Request lookup */ r = lookup_lastdir(0 /*!use_realuid*/, &vp_nd); if (r != OK) { put_vnode(vp_od); return r; } r= forbidden(vp_nd, W_BIT|X_BIT, 0 /*!use_realuid*/); if (r != OK) { put_vnode(vp_od); put_vnode(vp_nd); return r; } /* Remeber FS endpoint */ new_fs_e = vp_nd->v_fs_e; /* Both parent directories must be on the same device. */ if (old_fs_e != new_fs_e) { put_vnode(vp_od); put_vnode(vp_nd); return EXDEV; } /* Issue request */ r= req_rename(old_fs_e, vp_od->v_inode_nr, old_name, vp_nd->v_inode_nr, user_fullpath); put_vnode(vp_od); put_vnode(vp_nd); return r; }