]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/VirtioFsDxe/Helpers.c
OvmfPkg/VirtioFsDxe: split canon. path into last parent + last component
[mirror_edk2.git] / OvmfPkg / VirtioFsDxe / Helpers.c
index e9582e46bd3faf25a44874818698f66dc3ad9112..0e4390b005996f85783052b8a4465fa05c5f1e0f 100644 (file)
@@ -1591,6 +1591,137 @@ FreeRhsPath8:
   return Status;\r
 }\r
 \r
+/**\r
+  For a given canonical pathname (as defined at VirtioFsAppendPath()), look up\r
+  the NodeId of the most specific parent directory, plus output a pointer to\r
+  the last pathname component (which is therefore a direct child of said parent\r
+  directory).\r
+\r
+  The function may only be called after VirtioFsFuseInitSession() returns\r
+  successfully and before VirtioFsUninit() is called.\r
+\r
+  @param[in,out] VirtioFs    The Virtio Filesystem device to send FUSE_LOOKUP\r
+                             and FUSE_FORGET requests to. On output, the FUSE\r
+                             request counter "VirtioFs->RequestId" will have\r
+                             been incremented several times.\r
+\r
+  @param[in,out] Path        The canonical pathname (as defined in the\r
+                             description of VirtioFsAppendPath()) to split.\r
+                             Path is modified in-place temporarily; however, on\r
+                             return (successful or otherwise), Path reassumes\r
+                             its original contents.\r
+\r
+  @param[out] DirNodeId      The NodeId of the most specific parent directory\r
+                             identified by Path. The caller is responsible for\r
+                             sending a FUSE_FORGET request to the Virtio\r
+                             Filesystem device for DirNodeId -- unless\r
+                             DirNodeId equals VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID\r
+                             --, when DirNodeId's use ends.\r
+\r
+  @param[out] LastComponent  A pointer into Path, pointing at the start of the\r
+                             last pathname component.\r
+\r
+  @retval EFI_SUCCESS            Splitting successful.\r
+\r
+  @retval EFI_INVALID_PARAMETER  Path is "/".\r
+\r
+  @retval EFI_ACCESS_DENIED      One of the components on Path before the last\r
+                                 is not a directory.\r
+\r
+  @return                        Error codes propagated from\r
+                                 VirtioFsFuseLookup() and\r
+                                 VirtioFsFuseAttrToEfiFileInfo().\r
+**/\r
+EFI_STATUS\r
+VirtioFsLookupMostSpecificParentDir (\r
+  IN OUT VIRTIO_FS *VirtioFs,\r
+  IN OUT CHAR8     *Path,\r
+     OUT UINT64    *DirNodeId,\r
+     OUT CHAR8     **LastComponent\r
+  )\r
+{\r
+  UINT64     ParentDirNodeId;\r
+  CHAR8      *Slash;\r
+  EFI_STATUS Status;\r
+  UINT64     NextDirNodeId;\r
+\r
+  if (AsciiStrCmp (Path, "/") == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ParentDirNodeId = VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID;\r
+  Slash           = Path;\r
+  for (;;) {\r
+    CHAR8                              *NextSlash;\r
+    VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE FuseAttr;\r
+    EFI_FILE_INFO                      FileInfo;\r
+\r
+    //\r
+    // Find the slash (if any) that terminates the next pathname component.\r
+    //\r
+    NextSlash = AsciiStrStr (Slash + 1, "/");\r
+    if (NextSlash == NULL) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Temporarily replace the found slash character with a NUL in-place, for\r
+    // easy construction of the single-component filename that we need to look\r
+    // up.\r
+    //\r
+    *NextSlash = '\0';\r
+    Status = VirtioFsFuseLookup (VirtioFs, ParentDirNodeId, Slash + 1,\r
+               &NextDirNodeId, &FuseAttr);\r
+    *NextSlash = '/';\r
+\r
+    //\r
+    // We're done with the directory inode that was the basis for the lookup.\r
+    //\r
+    if (ParentDirNodeId != VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID) {\r
+      VirtioFsFuseForget (VirtioFs, ParentDirNodeId);\r
+    }\r
+\r
+    //\r
+    // If we couldn't look up the next *non-final* pathname component, bail.\r
+    //\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Lookup successful; now check if the next (non-final) component is a\r
+    // directory. If not, bail.\r
+    //\r
+    Status = VirtioFsFuseAttrToEfiFileInfo (&FuseAttr, &FileInfo);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ForgetNextDirNodeId;\r
+    }\r
+    if ((FileInfo.Attribute & EFI_FILE_DIRECTORY) == 0) {\r
+      Status = EFI_ACCESS_DENIED;\r
+      goto ForgetNextDirNodeId;\r
+    }\r
+\r
+    //\r
+    // Advance.\r
+    //\r
+    ParentDirNodeId = NextDirNodeId;\r
+    Slash           = NextSlash;\r
+  }\r
+\r
+  //\r
+  // ParentDirNodeId corresponds to the last containing directory. The\r
+  // remaining single-component filename represents a direct child under that\r
+  // directory. Said filename starts at (Slash + 1).\r
+  //\r
+  *DirNodeId     = ParentDirNodeId;\r
+  *LastComponent = Slash + 1;\r
+  return EFI_SUCCESS;\r
+\r
+ForgetNextDirNodeId:\r
+  VirtioFsFuseForget (VirtioFs, NextDirNodeId);\r
+  return Status;\r
+}\r
+\r
 /**\r
   Convert select fields of a VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE object to\r
   corresponding fields in EFI_FILE_INFO.\r