/** * Rename a regular file / directory. * * @param old_parent inode of the old parent directory * @param old_dentry old directory cache entry * @param new_parent inode of the new parent directory * @param new_dentry new directory cache entry * @returns 0 on success, Linux error code otherwise */ static int sf_rename(struct inode *old_parent, struct dentry *old_dentry, struct inode *new_parent, struct dentry *new_dentry) { int err = 0, rc = VINF_SUCCESS; struct sf_glob_info *sf_g = GET_GLOB_INFO(old_parent->i_sb); TRACE(); if (sf_g != GET_GLOB_INFO(new_parent->i_sb)) { LogFunc(("rename with different roots\n")); err = -EINVAL; } else { struct sf_inode_info *sf_old_i = GET_INODE_INFO(old_parent); struct sf_inode_info *sf_new_i = GET_INODE_INFO(new_parent); /* As we save the relative path inside the inode structure, we need to change this if the rename is successful. */ struct sf_inode_info *sf_file_i = GET_INODE_INFO(old_dentry->d_inode); SHFLSTRING *old_path; SHFLSTRING *new_path; BUG_ON(!sf_old_i); BUG_ON(!sf_new_i); BUG_ON(!sf_file_i); old_path = sf_file_i->path; err = sf_path_from_dentry(__func__, sf_g, sf_new_i, new_dentry, &new_path); if (err) LogFunc(("failed to create new path\n")); else { int fDir = ((old_dentry->d_inode->i_mode & S_IFDIR) != 0); rc = vboxCallRename(&client_handle, &sf_g->map, old_path, new_path, fDir ? 0 : SHFL_RENAME_FILE | SHFL_RENAME_REPLACE_IF_EXISTS); if (RT_SUCCESS(rc)) { kfree(old_path); sf_new_i->force_restat = 1; sf_old_i->force_restat = 1; /* XXX: needed? */ /* Set the new relative path in the inode. */ sf_file_i->path = new_path; } else { LogFunc(("vboxCallRename failed rc=%Rrc\n", rc)); err = -RTErrConvertToErrno(rc); kfree(new_path); } } } return err; }
NTSTATUS vbsfRename(IN PRX_CONTEXT RxContext, IN FILE_INFORMATION_CLASS FileInformationClass, IN PVOID pBuffer, IN ULONG BufferLength) { NTSTATUS Status = STATUS_SUCCESS; RxCaptureFcb; RxCaptureFobx; PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension = VBoxMRxGetDeviceExtension(RxContext); PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot); PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx); PMRX_SRV_OPEN pSrvOpen = capFobx->pSrvOpen; PFILE_RENAME_INFORMATION RenameInformation = (PFILE_RENAME_INFORMATION)RxContext->Info.Buffer; PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME(pSrvOpen, capFcb); int vboxRC; PSHFLSTRING SrcPath = 0, DestPath = 0; ULONG ParsedPathSize, flags; Assert(FileInformationClass == FileRenameInformation); Log(("VBOXSF: vbsfRename: FileName = %.*ls\n", RenameInformation->FileNameLength / sizeof(WCHAR), &RenameInformation->FileName[0])); /* Must close the file before renaming it! */ if (pVBoxFobx->hFile != SHFL_HANDLE_NIL) { vbsfCloseFileHandle(pDeviceExtension, pNetRootExtension, pVBoxFobx); } /* Mark it as renamed, so we do nothing during close */ SetFlag(pSrvOpen->Flags, SRVOPEN_FLAG_FILE_RENAMED); /* Calculate length required for destination path. */ ParsedPathSize = sizeof(*DestPath) + (RenameInformation->FileNameLength + sizeof(WCHAR)); Log(("VBOXSF: vbsfRename: ParsedPathSize = %d\n", ParsedPathSize)); DestPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize); if (NULL == DestPath) { return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(DestPath, ParsedPathSize); ShflStringInitBuffer(DestPath, ParsedPathSize - sizeof(SHFLSTRING)); Log(("VBOXSF: vbsfRename: Setting up destination path\n")); DestPath->u16Size = (USHORT)(RenameInformation->FileNameLength + sizeof(WCHAR)); DestPath->u16Length = DestPath->u16Size - sizeof(WCHAR); /* without terminating null */ RtlCopyMemory(DestPath->String.ucs2, RenameInformation->FileName, DestPath->u16Length); Log(("VBOXSF: vbsfRename: Destination path = %.*ls\n", DestPath->u16Length / sizeof(WCHAR), &DestPath->String.ucs2[0])); /* Calculate length required for source path */ ParsedPathSize = sizeof(*DestPath) + (RemainingName->Length + sizeof(WCHAR)); Log(("VBOXSF: vbsfRename: ParsedPathSize = %d\n", ParsedPathSize)); SrcPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize); if (NULL == SrcPath) { vbsfFreeNonPagedMem(DestPath); return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(SrcPath, ParsedPathSize); ShflStringInitBuffer(SrcPath, ParsedPathSize - sizeof(SHFLSTRING)); Log(("VBOXSF: vbsfRename: Setting up source path\n")); SrcPath->u16Size = RemainingName->Length + sizeof(WCHAR); SrcPath->u16Length = SrcPath->u16Size - sizeof(WCHAR); /* without terminating null */ RtlCopyMemory(SrcPath->String.ucs2, RemainingName->Buffer, SrcPath->u16Length); Log(("VBOXSF: vbsfRename: Source path = %.*ls\n", SrcPath->u16Length / sizeof(WCHAR), &SrcPath->String.ucs2[0])); /* Call host. */ flags = pVBoxFobx->FileStandardInfo.Directory? SHFL_RENAME_DIR : SHFL_RENAME_FILE; if (RenameInformation->ReplaceIfExists) { flags |= SHFL_RENAME_REPLACE_IF_EXISTS; } Log(("VBOXSF: vbsfRename: Calling vboxCallRename\n")); vboxRC = vboxCallRename(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, SrcPath, DestPath, flags); vbsfFreeNonPagedMem(SrcPath); vbsfFreeNonPagedMem(DestPath); Status = VBoxErrorToNTStatus(vboxRC); if (vboxRC != VINF_SUCCESS) { Log(("VBOXSF: vbsfRename: vboxCallRename failed with %Rrc\n", vboxRC)); } Log(("VBOXSF: vbsfRename: Returned 0x%08X\n", Status)); return Status; }