diff options
author | Laszlo Ersek <lersek@redhat.com> | 2020-12-16 22:11:00 +0100 |
---|---|---|
committer | mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> | 2020-12-21 17:16:23 +0000 |
commit | ca61b84586d59bdda1837ba00eb6e24fa900dc56 (patch) | |
tree | 9fc5aa4fc6db41064f448b59b5ac59f2f9feb759 /OvmfPkg/VirtioFsDxe | |
parent | b6ce961a42f08be13f7fc7a561be530ad58434e5 (diff) | |
download | edk2-ca61b84586d59bdda1837ba00eb6e24fa900dc56.zip edk2-ca61b84586d59bdda1837ba00eb6e24fa900dc56.tar.gz edk2-ca61b84586d59bdda1837ba00eb6e24fa900dc56.tar.bz2 |
OvmfPkg/VirtioFsDxe: split canon. path into last parent + last component
Given a canonical pathname (as defined by VirtioFsAppendPath()), different
from "/", introduce a helper function for:
- looking up the NodeId of the most specific parent directory, and
- exposing the last component stand-alone (which is therefore a direct
child of said parent directory).
This splitting operation will be necessary in multiple subsequent patches.
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-24-lersek@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
Diffstat (limited to 'OvmfPkg/VirtioFsDxe')
-rw-r--r-- | OvmfPkg/VirtioFsDxe/Helpers.c | 131 | ||||
-rw-r--r-- | OvmfPkg/VirtioFsDxe/VirtioFsDxe.h | 8 |
2 files changed, 139 insertions, 0 deletions
diff --git a/OvmfPkg/VirtioFsDxe/Helpers.c b/OvmfPkg/VirtioFsDxe/Helpers.c index e9582e4..0e4390b 100644 --- a/OvmfPkg/VirtioFsDxe/Helpers.c +++ b/OvmfPkg/VirtioFsDxe/Helpers.c @@ -1592,6 +1592,137 @@ FreeRhsPath8: }
/**
+ For a given canonical pathname (as defined at VirtioFsAppendPath()), look up
+ the NodeId of the most specific parent directory, plus output a pointer to
+ the last pathname component (which is therefore a direct child of said parent
+ directory).
+
+ 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 FUSE_LOOKUP
+ and FUSE_FORGET requests to. On output, the FUSE
+ request counter "VirtioFs->RequestId" will have
+ been incremented several times.
+
+ @param[in,out] Path The canonical pathname (as defined in the
+ description of VirtioFsAppendPath()) to split.
+ Path is modified in-place temporarily; however, on
+ return (successful or otherwise), Path reassumes
+ its original contents.
+
+ @param[out] DirNodeId The NodeId of the most specific parent directory
+ identified by Path. The caller is responsible for
+ sending a FUSE_FORGET request to the Virtio
+ Filesystem device for DirNodeId -- unless
+ DirNodeId equals VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID
+ --, when DirNodeId's use ends.
+
+ @param[out] LastComponent A pointer into Path, pointing at the start of the
+ last pathname component.
+
+ @retval EFI_SUCCESS Splitting successful.
+
+ @retval EFI_INVALID_PARAMETER Path is "/".
+
+ @retval EFI_ACCESS_DENIED One of the components on Path before the last
+ is not a directory.
+
+ @return Error codes propagated from
+ VirtioFsFuseLookup() and
+ VirtioFsFuseAttrToEfiFileInfo().
+**/
+EFI_STATUS
+VirtioFsLookupMostSpecificParentDir (
+ IN OUT VIRTIO_FS *VirtioFs,
+ IN OUT CHAR8 *Path,
+ OUT UINT64 *DirNodeId,
+ OUT CHAR8 **LastComponent
+ )
+{
+ UINT64 ParentDirNodeId;
+ CHAR8 *Slash;
+ EFI_STATUS Status;
+ UINT64 NextDirNodeId;
+
+ if (AsciiStrCmp (Path, "/") == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ParentDirNodeId = VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID;
+ Slash = Path;
+ for (;;) {
+ CHAR8 *NextSlash;
+ VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE FuseAttr;
+ EFI_FILE_INFO FileInfo;
+
+ //
+ // Find the slash (if any) that terminates the next pathname component.
+ //
+ NextSlash = AsciiStrStr (Slash + 1, "/");
+ if (NextSlash == NULL) {
+ break;
+ }
+
+ //
+ // Temporarily replace the found slash character with a NUL in-place, for
+ // easy construction of the single-component filename that we need to look
+ // up.
+ //
+ *NextSlash = '\0';
+ Status = VirtioFsFuseLookup (VirtioFs, ParentDirNodeId, Slash + 1,
+ &NextDirNodeId, &FuseAttr);
+ *NextSlash = '/';
+
+ //
+ // We're done with the directory inode that was the basis for the lookup.
+ //
+ if (ParentDirNodeId != VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID) {
+ VirtioFsFuseForget (VirtioFs, ParentDirNodeId);
+ }
+
+ //
+ // If we couldn't look up the next *non-final* pathname component, bail.
+ //
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Lookup successful; now check if the next (non-final) component is a
+ // directory. If not, bail.
+ //
+ Status = VirtioFsFuseAttrToEfiFileInfo (&FuseAttr, &FileInfo);
+ if (EFI_ERROR (Status)) {
+ goto ForgetNextDirNodeId;
+ }
+ if ((FileInfo.Attribute & EFI_FILE_DIRECTORY) == 0) {
+ Status = EFI_ACCESS_DENIED;
+ goto ForgetNextDirNodeId;
+ }
+
+ //
+ // Advance.
+ //
+ ParentDirNodeId = NextDirNodeId;
+ Slash = NextSlash;
+ }
+
+ //
+ // ParentDirNodeId corresponds to the last containing directory. The
+ // remaining single-component filename represents a direct child under that
+ // directory. Said filename starts at (Slash + 1).
+ //
+ *DirNodeId = ParentDirNodeId;
+ *LastComponent = Slash + 1;
+ return EFI_SUCCESS;
+
+ForgetNextDirNodeId:
+ VirtioFsFuseForget (VirtioFs, NextDirNodeId);
+ return Status;
+}
+
+/**
Convert select fields of a VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE object to
corresponding fields in EFI_FILE_INFO.
diff --git a/OvmfPkg/VirtioFsDxe/VirtioFsDxe.h b/OvmfPkg/VirtioFsDxe/VirtioFsDxe.h index b2e4adc..6ae5c36 100644 --- a/OvmfPkg/VirtioFsDxe/VirtioFsDxe.h +++ b/OvmfPkg/VirtioFsDxe/VirtioFsDxe.h @@ -227,6 +227,14 @@ VirtioFsAppendPath ( );
EFI_STATUS
+VirtioFsLookupMostSpecificParentDir (
+ IN OUT VIRTIO_FS *VirtioFs,
+ IN OUT CHAR8 *Path,
+ OUT UINT64 *DirNodeId,
+ OUT CHAR8 **LastComponent
+ );
+
+EFI_STATUS
VirtioFsFuseAttrToEfiFileInfo (
IN VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE *FuseAttr,
OUT EFI_FILE_INFO *FileInfo
|