OvmfPkg/VirtioFsDxe: implement the wrapper function for FUSE_RENAME2

Add the VirtioFsFuseRename() function, for sending the FUSE_RENAME2
command to the Virtio Filesystem device.

Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3097
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Message-Id: <20201216211125.19496-42-lersek@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
This commit is contained in:
Laszlo Ersek 2020-12-16 22:11:18 +01:00 committed by mergify[bot]
parent c9f473df33
commit bea1f51d6e
4 changed files with 156 additions and 0 deletions

View File

@ -141,6 +141,11 @@ typedef struct {
) \ ) \
) )
//
// Flags for VirtioFsFuseOpRename2.
//
#define VIRTIO_FS_FUSE_RENAME2_REQ_F_NOREPLACE BIT0
// //
// FUSE operation codes. // FUSE operation codes.
// //
@ -164,6 +169,7 @@ typedef enum {
VirtioFsFuseOpFsyncDir = 30, VirtioFsFuseOpFsyncDir = 30,
VirtioFsFuseOpCreate = 35, VirtioFsFuseOpCreate = 35,
VirtioFsFuseOpReadDirPlus = 44, VirtioFsFuseOpReadDirPlus = 44,
VirtioFsFuseOpRename2 = 45,
} VIRTIO_FS_FUSE_OPCODE; } VIRTIO_FS_FUSE_OPCODE;
#pragma pack (1) #pragma pack (1)
@ -398,6 +404,15 @@ typedef struct {
UINT32 Namelen; UINT32 Namelen;
UINT32 Type; UINT32 Type;
} VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE; } VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE;
//
// Header for VirtioFsFuseOpRename2.
//
typedef struct {
UINT64 NewDir;
UINT32 Flags;
UINT32 Padding;
} VIRTIO_FS_FUSE_RENAME2_REQUEST;
#pragma pack () #pragma pack ()
#endif // VIRTIO_FS_H_ #endif // VIRTIO_FS_H_

View File

@ -0,0 +1,131 @@
/** @file
FUSE_RENAME2 wrapper for the Virtio Filesystem device.
Copyright (C) 2020, Red Hat, Inc.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Library/BaseLib.h> // AsciiStrSize()
#include "VirtioFsDxe.h"
/**
Rename a regular file or a directory, by sending the FUSE_RENAME2 request to
the Virtio Filesystem device. If the new filename exists, the request will
fail.
The function may only be called after VirtioFsFuseInitSession() returns
successfully and before VirtioFsUninit() is called.
@param[in,out] VirtioFs The Virtio Filesystem device to send the
FUSE_RENAME2 request to. On output, the FUSE
request counter "VirtioFs->RequestId" will have
been incremented.
@param[in] OldParentNodeId The inode number of the directory in which
OldName should be removed.
@param[in] OldName The single-component filename to remove in the
directory identified by OldParentNodeId.
@param[in] NewParentNodeId The inode number of the directory in which
NewName should be created, such that on
successful return, (NewParentNodeId, NewName)
refer to the same inode as (OldParentNodeId,
OldName) did on entry.
@param[in] NewName The single-component filename to create in the
directory identified by NewParentNodeId.
@retval EFI_SUCCESS The file or directory has been renamed.
@return The "errno" value mapped to an EFI_STATUS code, if the
Virtio Filesystem device explicitly reported an error.
@return Error codes propagated from VirtioFsSgListsValidate(),
VirtioFsFuseNewRequest(), VirtioFsSgListsSubmit(),
VirtioFsFuseCheckResponse().
**/
EFI_STATUS
VirtioFsFuseRename (
IN OUT VIRTIO_FS *VirtioFs,
IN UINT64 OldParentNodeId,
IN CHAR8 *OldName,
IN UINT64 NewParentNodeId,
IN CHAR8 *NewName
)
{
VIRTIO_FS_FUSE_REQUEST CommonReq;
VIRTIO_FS_FUSE_RENAME2_REQUEST Rename2Req;
VIRTIO_FS_IO_VECTOR ReqIoVec[4];
VIRTIO_FS_SCATTER_GATHER_LIST ReqSgList;
VIRTIO_FS_FUSE_RESPONSE CommonResp;
VIRTIO_FS_IO_VECTOR RespIoVec[1];
VIRTIO_FS_SCATTER_GATHER_LIST RespSgList;
EFI_STATUS Status;
//
// Set up the scatter-gather lists.
//
ReqIoVec[0].Buffer = &CommonReq;
ReqIoVec[0].Size = sizeof CommonReq;
ReqIoVec[1].Buffer = &Rename2Req;
ReqIoVec[1].Size = sizeof Rename2Req;
ReqIoVec[2].Buffer = OldName;
ReqIoVec[2].Size = AsciiStrSize (OldName);
ReqIoVec[3].Buffer = NewName;
ReqIoVec[3].Size = AsciiStrSize (NewName);
ReqSgList.IoVec = ReqIoVec;
ReqSgList.NumVec = ARRAY_SIZE (ReqIoVec);
RespIoVec[0].Buffer = &CommonResp;
RespIoVec[0].Size = sizeof CommonResp;
RespSgList.IoVec = RespIoVec;
RespSgList.NumVec = ARRAY_SIZE (RespIoVec);
//
// Validate the scatter-gather lists; calculate the total transfer sizes.
//
Status = VirtioFsSgListsValidate (VirtioFs, &ReqSgList, &RespSgList);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Populate the common request header.
//
Status = VirtioFsFuseNewRequest (VirtioFs, &CommonReq, ReqSgList.TotalSize,
VirtioFsFuseOpRename2, OldParentNodeId);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Populate the FUSE_RENAME2-specific fields.
//
Rename2Req.NewDir = NewParentNodeId;
Rename2Req.Flags = VIRTIO_FS_FUSE_RENAME2_REQ_F_NOREPLACE;
Rename2Req.Padding = 0;
//
// Submit the request.
//
Status = VirtioFsSgListsSubmit (VirtioFs, &ReqSgList, &RespSgList);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Verify the response (all response buffers are fixed size).
//
Status = VirtioFsFuseCheckResponse (&RespSgList, CommonReq.Unique, NULL);
if (Status == EFI_DEVICE_ERROR) {
DEBUG ((DEBUG_ERROR, "%a: Label=\"%s\" OldParentNodeId=%Lu OldName=\"%a\" "
"NewParentNodeId=%Lu NewName=\"%a\" Errno=%d\n", __FUNCTION__,
VirtioFs->Label, OldParentNodeId, OldName, NewParentNodeId, NewName,
CommonResp.Error));
Status = VirtioFsErrnoToEfiStatus (CommonResp.Error);
}
return Status;
}

View File

@ -396,6 +396,15 @@ VirtioFsFuseOpenOrCreate (
OUT UINT64 *FuseHandle OUT UINT64 *FuseHandle
); );
EFI_STATUS
VirtioFsFuseRename (
IN OUT VIRTIO_FS *VirtioFs,
IN UINT64 OldParentNodeId,
IN CHAR8 *OldName,
IN UINT64 NewParentNodeId,
IN CHAR8 *NewName
);
// //
// EFI_SIMPLE_FILE_SYSTEM_PROTOCOL member functions for the Virtio Filesystem // EFI_SIMPLE_FILE_SYSTEM_PROTOCOL member functions for the Virtio Filesystem
// driver. // driver.

View File

@ -95,6 +95,7 @@
FuseOpenOrCreate.c FuseOpenOrCreate.c
FuseRead.c FuseRead.c
FuseRelease.c FuseRelease.c
FuseRename.c
FuseStatFs.c FuseStatFs.c
FuseUnlink.c FuseUnlink.c
FuseWrite.c FuseWrite.c