OvmfPkg/VirtioFsDxe: implement EFI_FILE_PROTOCOL.Open()
Using the functions introduced previously, we can now implement VirtioFsSimpleFileOpen(). This lets the "MKDIR" command to work in the UEFI shell, for example. 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-27-lersek@redhat.com> Acked-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
This commit is contained in:
		
				
					committed by
					
						
						mergify[bot]
					
				
			
			
				
	
			
			
			
						parent
						
							e3bc957706
						
					
				
				
					commit
					de0e11902b
				
			@@ -6,8 +6,284 @@
 | 
			
		||||
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
			
		||||
**/
 | 
			
		||||
 | 
			
		||||
#include <Library/BaseLib.h>             // AsciiStrCmp()
 | 
			
		||||
#include <Library/MemoryAllocationLib.h> // AllocatePool()
 | 
			
		||||
 | 
			
		||||
#include "VirtioFsDxe.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  Open the root directory, possibly for writing.
 | 
			
		||||
 | 
			
		||||
  @param[in,out] VirtioFs    The Virtio Filesystem device whose root directory
 | 
			
		||||
                             should be opened.
 | 
			
		||||
 | 
			
		||||
  @param[out] NewHandle      The new EFI_FILE_PROTOCOL instance through which
 | 
			
		||||
                             the root directory can be accessed.
 | 
			
		||||
 | 
			
		||||
  @param[in] OpenForWriting  TRUE if the root directory should be opened for
 | 
			
		||||
                             read-write access. FALSE if the root directory
 | 
			
		||||
                             should be opened for read-only access. Opening the
 | 
			
		||||
                             root directory for read-write access is useful for
 | 
			
		||||
                             calling EFI_FILE_PROTOCOL.Flush() or
 | 
			
		||||
                             EFI_FILE_PROTOCOL.SetInfo() later, for syncing or
 | 
			
		||||
                             touching the root directory, respectively.
 | 
			
		||||
 | 
			
		||||
  @retval EFI_SUCCESS        The root directory has been opened successfully.
 | 
			
		||||
 | 
			
		||||
  @retval EFI_ACCESS_DENIED  OpenForWriting is TRUE, but the root directory is
 | 
			
		||||
                             marked as read-only.
 | 
			
		||||
 | 
			
		||||
  @return                    Error codes propagated from underlying functions.
 | 
			
		||||
**/
 | 
			
		||||
STATIC
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
OpenRootDirectory (
 | 
			
		||||
  IN OUT VIRTIO_FS         *VirtioFs,
 | 
			
		||||
     OUT EFI_FILE_PROTOCOL **NewHandle,
 | 
			
		||||
  IN     BOOLEAN           OpenForWriting
 | 
			
		||||
  )
 | 
			
		||||
{
 | 
			
		||||
  EFI_STATUS     Status;
 | 
			
		||||
  VIRTIO_FS_FILE *NewVirtioFsFile;
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // VirtioFsOpenVolume() opens the root directory for read-only access. If the
 | 
			
		||||
  // current request is to open the root directory for read-write access, so
 | 
			
		||||
  // that EFI_FILE_PROTOCOL.Flush() or EFI_FILE_PROTOCOL.SetInfo()+timestamps
 | 
			
		||||
  // can be used on the root directory later, then we have to check for write
 | 
			
		||||
  // permission first.
 | 
			
		||||
  //
 | 
			
		||||
  if (OpenForWriting) {
 | 
			
		||||
    VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE FuseAttr;
 | 
			
		||||
    EFI_FILE_INFO                      FileInfo;
 | 
			
		||||
 | 
			
		||||
    Status = VirtioFsFuseGetAttr (VirtioFs, VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID,
 | 
			
		||||
               &FuseAttr);
 | 
			
		||||
    if (EFI_ERROR (Status)) {
 | 
			
		||||
      return Status;
 | 
			
		||||
    }
 | 
			
		||||
    Status = VirtioFsFuseAttrToEfiFileInfo (&FuseAttr, &FileInfo);
 | 
			
		||||
    if (EFI_ERROR (Status)) {
 | 
			
		||||
      return Status;
 | 
			
		||||
    }
 | 
			
		||||
    if ((FileInfo.Attribute & EFI_FILE_READ_ONLY) != 0) {
 | 
			
		||||
      return EFI_ACCESS_DENIED;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Status = VirtioFsOpenVolume (&VirtioFs->SimpleFs, NewHandle);
 | 
			
		||||
  if (EFI_ERROR (Status)) {
 | 
			
		||||
    return Status;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  NewVirtioFsFile = VIRTIO_FS_FILE_FROM_SIMPLE_FILE (*NewHandle);
 | 
			
		||||
  NewVirtioFsFile->IsOpenForWriting = OpenForWriting;
 | 
			
		||||
  return EFI_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  Open an existent regular file or non-root directory.
 | 
			
		||||
 | 
			
		||||
  @param[in,out] VirtioFs      The Virtio Filesystem device on which the
 | 
			
		||||
                               regular file or directory should be opened.
 | 
			
		||||
 | 
			
		||||
  @param[in] DirNodeId         The inode number of the immediate parent
 | 
			
		||||
                               directory of the regular file or directory to
 | 
			
		||||
                               open.
 | 
			
		||||
 | 
			
		||||
  @param[in] Name              The single-component filename of the regular
 | 
			
		||||
                               file or directory to open, under the immediate
 | 
			
		||||
                               parent directory identified by DirNodeId.
 | 
			
		||||
 | 
			
		||||
  @param[in] OpenForWriting    TRUE if the regular file or directory should be
 | 
			
		||||
                               opened for read-write access. FALSE if the
 | 
			
		||||
                               regular file or directory should be opened for
 | 
			
		||||
                               read-only access. Opening a directory for
 | 
			
		||||
                               read-write access is useful for deleting,
 | 
			
		||||
                               renaming, syncing or touching the directory
 | 
			
		||||
                               later.
 | 
			
		||||
 | 
			
		||||
  @param[out] NodeId           The inode number of the regular file or
 | 
			
		||||
                               directory, returned by the Virtio Filesystem
 | 
			
		||||
                               device.
 | 
			
		||||
 | 
			
		||||
  @param[out] FuseHandle       The open handle to the regular file or
 | 
			
		||||
                               directory, returned by the Virtio Filesystem
 | 
			
		||||
                               device.
 | 
			
		||||
 | 
			
		||||
  @param[out] NodeIsDirectory  Set to TRUE on output if Name was found to refer
 | 
			
		||||
                               to a directory. Set to FALSE if Name was found
 | 
			
		||||
                               to refer to a regular file.
 | 
			
		||||
 | 
			
		||||
  @retval EFI_SUCCESS        The regular file or directory has been looked up
 | 
			
		||||
                             and opened successfully.
 | 
			
		||||
 | 
			
		||||
  @retval EFI_ACCESS_DENIED  OpenForWriting is TRUE, but the regular file or
 | 
			
		||||
                             directory is marked read-only.
 | 
			
		||||
 | 
			
		||||
  @retval EFI_NOT_FOUND      A directory entry called Name was not found in the
 | 
			
		||||
                             directory identified by DirNodeId. (EFI_NOT_FOUND
 | 
			
		||||
                             is not returned for any other condition.)
 | 
			
		||||
 | 
			
		||||
  @return                    Errors propagated from underlying functions. If
 | 
			
		||||
                             the error code to propagate were EFI_NOT_FOUND, it
 | 
			
		||||
                             is remapped to EFI_DEVICE_ERROR.
 | 
			
		||||
**/
 | 
			
		||||
STATIC
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
OpenExistentFileOrDirectory (
 | 
			
		||||
  IN OUT VIRTIO_FS *VirtioFs,
 | 
			
		||||
  IN     UINT64    DirNodeId,
 | 
			
		||||
  IN     CHAR8     *Name,
 | 
			
		||||
  IN     BOOLEAN   OpenForWriting,
 | 
			
		||||
     OUT UINT64    *NodeId,
 | 
			
		||||
     OUT UINT64    *FuseHandle,
 | 
			
		||||
     OUT BOOLEAN   *NodeIsDirectory
 | 
			
		||||
  )
 | 
			
		||||
{
 | 
			
		||||
  EFI_STATUS                         Status;
 | 
			
		||||
  UINT64                             ResolvedNodeId;
 | 
			
		||||
  VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE FuseAttr;
 | 
			
		||||
  EFI_FILE_INFO                      FileInfo;
 | 
			
		||||
  BOOLEAN                            IsDirectory;
 | 
			
		||||
  UINT64                             NewFuseHandle;
 | 
			
		||||
 | 
			
		||||
  Status = VirtioFsFuseLookup (VirtioFs, DirNodeId, Name, &ResolvedNodeId,
 | 
			
		||||
             &FuseAttr);
 | 
			
		||||
  if (EFI_ERROR (Status)) {
 | 
			
		||||
    return Status;
 | 
			
		||||
  }
 | 
			
		||||
  Status = VirtioFsFuseAttrToEfiFileInfo (&FuseAttr, &FileInfo);
 | 
			
		||||
  if (EFI_ERROR (Status)) {
 | 
			
		||||
    goto ForgetResolvedNodeId;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (OpenForWriting && (FileInfo.Attribute & EFI_FILE_READ_ONLY) != 0) {
 | 
			
		||||
    Status = EFI_ACCESS_DENIED;
 | 
			
		||||
    goto ForgetResolvedNodeId;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  IsDirectory = (BOOLEAN)((FileInfo.Attribute & EFI_FILE_DIRECTORY) != 0);
 | 
			
		||||
  if (IsDirectory) {
 | 
			
		||||
    //
 | 
			
		||||
    // If OpenForWriting is TRUE here, that's not passed to
 | 
			
		||||
    // VirtioFsFuseOpenDir(); it does not affect the FUSE_OPENDIR request we
 | 
			
		||||
    // send. OpenForWriting=TRUE will only permit attempts to delete, rename,
 | 
			
		||||
    // flush (sync), and touch the directory.
 | 
			
		||||
    //
 | 
			
		||||
    Status = VirtioFsFuseOpenDir (VirtioFs, ResolvedNodeId, &NewFuseHandle);
 | 
			
		||||
  } else {
 | 
			
		||||
    Status = VirtioFsFuseOpen (VirtioFs, ResolvedNodeId, OpenForWriting,
 | 
			
		||||
               &NewFuseHandle);
 | 
			
		||||
  }
 | 
			
		||||
  if (EFI_ERROR (Status)) {
 | 
			
		||||
    goto ForgetResolvedNodeId;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  *NodeId          = ResolvedNodeId;
 | 
			
		||||
  *FuseHandle      = NewFuseHandle;
 | 
			
		||||
  *NodeIsDirectory = IsDirectory;
 | 
			
		||||
  return EFI_SUCCESS;
 | 
			
		||||
 | 
			
		||||
ForgetResolvedNodeId:
 | 
			
		||||
  VirtioFsFuseForget (VirtioFs, ResolvedNodeId);
 | 
			
		||||
  return (Status == EFI_NOT_FOUND) ? EFI_DEVICE_ERROR : Status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  Create a directory.
 | 
			
		||||
 | 
			
		||||
  @param[in,out] VirtioFs  The Virtio Filesystem device on which the directory
 | 
			
		||||
                           should be created.
 | 
			
		||||
 | 
			
		||||
  @param[in] DirNodeId     The inode number of the immediate parent directory
 | 
			
		||||
                           of the directory to create.
 | 
			
		||||
 | 
			
		||||
  @param[in] Name          The single-component filename of the directory to
 | 
			
		||||
                           create, under the immediate parent directory
 | 
			
		||||
                           identified by DirNodeId.
 | 
			
		||||
 | 
			
		||||
  @param[out] NodeId       The inode number of the directory created, returned
 | 
			
		||||
                           by the Virtio Filesystem device.
 | 
			
		||||
 | 
			
		||||
  @param[out] FuseHandle   The open handle to the directory created, returned
 | 
			
		||||
                           by the Virtio Filesystem device.
 | 
			
		||||
 | 
			
		||||
  @retval EFI_SUCCESS  The directory has been created successfully.
 | 
			
		||||
 | 
			
		||||
  @return              Errors propagated from underlying functions.
 | 
			
		||||
**/
 | 
			
		||||
STATIC
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
CreateDirectory (
 | 
			
		||||
  IN OUT VIRTIO_FS *VirtioFs,
 | 
			
		||||
  IN     UINT64    DirNodeId,
 | 
			
		||||
  IN     CHAR8     *Name,
 | 
			
		||||
     OUT UINT64    *NodeId,
 | 
			
		||||
     OUT UINT64    *FuseHandle
 | 
			
		||||
  )
 | 
			
		||||
{
 | 
			
		||||
  EFI_STATUS Status;
 | 
			
		||||
  UINT64     NewChildDirNodeId;
 | 
			
		||||
  UINT64     NewFuseHandle;
 | 
			
		||||
 | 
			
		||||
  Status = VirtioFsFuseMkDir (VirtioFs, DirNodeId, Name, &NewChildDirNodeId);
 | 
			
		||||
  if (EFI_ERROR (Status)) {
 | 
			
		||||
    return Status;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Status = VirtioFsFuseOpenDir (VirtioFs, NewChildDirNodeId, &NewFuseHandle);
 | 
			
		||||
  if (EFI_ERROR (Status)) {
 | 
			
		||||
    goto RemoveNewChildDir;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  *NodeId     = NewChildDirNodeId;
 | 
			
		||||
  *FuseHandle = NewFuseHandle;
 | 
			
		||||
  return EFI_SUCCESS;
 | 
			
		||||
 | 
			
		||||
RemoveNewChildDir:
 | 
			
		||||
  VirtioFsFuseRemoveFileOrDir (VirtioFs, DirNodeId, Name, TRUE /* IsDir */);
 | 
			
		||||
  VirtioFsFuseForget (VirtioFs, NewChildDirNodeId);
 | 
			
		||||
  return Status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  Create a regular file.
 | 
			
		||||
 | 
			
		||||
  @param[in,out] VirtioFs  The Virtio Filesystem device on which the regular
 | 
			
		||||
                           file should be created.
 | 
			
		||||
 | 
			
		||||
  @param[in] DirNodeId     The inode number of the immediate parent directory
 | 
			
		||||
                           of the regular file to create.
 | 
			
		||||
 | 
			
		||||
  @param[in] Name          The single-component filename of the regular file to
 | 
			
		||||
                           create, under the immediate parent directory
 | 
			
		||||
                           identified by DirNodeId.
 | 
			
		||||
 | 
			
		||||
  @param[out] NodeId       The inode number of the regular file created,
 | 
			
		||||
                           returned by the Virtio Filesystem device.
 | 
			
		||||
 | 
			
		||||
  @param[out] FuseHandle   The open handle to the regular file created,
 | 
			
		||||
                           returned by the Virtio Filesystem device.
 | 
			
		||||
 | 
			
		||||
  @retval EFI_SUCCESS  The regular file has been created successfully.
 | 
			
		||||
 | 
			
		||||
  @return              Errors propagated from underlying functions.
 | 
			
		||||
**/
 | 
			
		||||
STATIC
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
CreateRegularFile (
 | 
			
		||||
  IN OUT VIRTIO_FS *VirtioFs,
 | 
			
		||||
  IN     UINT64    DirNodeId,
 | 
			
		||||
  IN     CHAR8     *Name,
 | 
			
		||||
     OUT UINT64    *NodeId,
 | 
			
		||||
     OUT UINT64    *FuseHandle
 | 
			
		||||
  )
 | 
			
		||||
{
 | 
			
		||||
  return VirtioFsFuseOpenOrCreate (VirtioFs, DirNodeId, Name, NodeId,
 | 
			
		||||
           FuseHandle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
EFI_STATUS
 | 
			
		||||
EFIAPI
 | 
			
		||||
VirtioFsSimpleFileOpen (
 | 
			
		||||
@@ -18,5 +294,207 @@ VirtioFsSimpleFileOpen (
 | 
			
		||||
  IN     UINT64            Attributes
 | 
			
		||||
  )
 | 
			
		||||
{
 | 
			
		||||
  return EFI_NO_MEDIA;
 | 
			
		||||
  VIRTIO_FS_FILE *VirtioFsFile;
 | 
			
		||||
  VIRTIO_FS      *VirtioFs;
 | 
			
		||||
  BOOLEAN        OpenForWriting;
 | 
			
		||||
  BOOLEAN        PermitCreation;
 | 
			
		||||
  BOOLEAN        CreateDirectoryIfCreating;
 | 
			
		||||
  VIRTIO_FS_FILE *NewVirtioFsFile;
 | 
			
		||||
  EFI_STATUS     Status;
 | 
			
		||||
  CHAR8          *NewCanonicalPath;
 | 
			
		||||
  BOOLEAN        RootEscape;
 | 
			
		||||
  UINT64         DirNodeId;
 | 
			
		||||
  CHAR8          *LastComponent;
 | 
			
		||||
  UINT64         NewNodeId;
 | 
			
		||||
  UINT64         NewFuseHandle;
 | 
			
		||||
  BOOLEAN        NewNodeIsDirectory;
 | 
			
		||||
 | 
			
		||||
  VirtioFsFile = VIRTIO_FS_FILE_FROM_SIMPLE_FILE (This);
 | 
			
		||||
  VirtioFs     = VirtioFsFile->OwnerFs;
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // Validate OpenMode.
 | 
			
		||||
  //
 | 
			
		||||
  switch (OpenMode) {
 | 
			
		||||
  case EFI_FILE_MODE_READ:
 | 
			
		||||
    OpenForWriting = FALSE;
 | 
			
		||||
    PermitCreation = FALSE;
 | 
			
		||||
    break;
 | 
			
		||||
  case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE:
 | 
			
		||||
    OpenForWriting = TRUE;
 | 
			
		||||
    PermitCreation = FALSE;
 | 
			
		||||
    break;
 | 
			
		||||
  case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE:
 | 
			
		||||
    OpenForWriting = TRUE;
 | 
			
		||||
    PermitCreation = TRUE;
 | 
			
		||||
    break;
 | 
			
		||||
  default:
 | 
			
		||||
    return EFI_INVALID_PARAMETER;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // Validate the Attributes requested for the case when the file ends up being
 | 
			
		||||
  // created, provided creation is permitted.
 | 
			
		||||
  //
 | 
			
		||||
  if (PermitCreation) {
 | 
			
		||||
    if ((Attributes & ~EFI_FILE_VALID_ATTR) != 0) {
 | 
			
		||||
      //
 | 
			
		||||
      // Unknown attribute requested.
 | 
			
		||||
      //
 | 
			
		||||
      return EFI_INVALID_PARAMETER;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ASSERT (OpenForWriting);
 | 
			
		||||
    if ((Attributes & EFI_FILE_READ_ONLY) != 0) {
 | 
			
		||||
      DEBUG ((
 | 
			
		||||
        DEBUG_ERROR,
 | 
			
		||||
        ("%a: Label=\"%s\" CanonicalPathname=\"%a\" FileName=\"%s\" "
 | 
			
		||||
         "OpenMode=0x%Lx Attributes=0x%Lx: nonsensical request to possibly "
 | 
			
		||||
         "create a file marked read-only, for read-write access\n"),
 | 
			
		||||
        __FUNCTION__,
 | 
			
		||||
        VirtioFs->Label,
 | 
			
		||||
        VirtioFsFile->CanonicalPathname,
 | 
			
		||||
        FileName,
 | 
			
		||||
        OpenMode,
 | 
			
		||||
        Attributes
 | 
			
		||||
        ));
 | 
			
		||||
      return EFI_INVALID_PARAMETER;
 | 
			
		||||
    }
 | 
			
		||||
    CreateDirectoryIfCreating = (BOOLEAN)((Attributes &
 | 
			
		||||
                                           EFI_FILE_DIRECTORY) != 0);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // Referring to a file relative to a regular file makes no sense (or at least
 | 
			
		||||
  // it cannot be implemented consistently with how a file is referred to
 | 
			
		||||
  // relative to a directory).
 | 
			
		||||
  //
 | 
			
		||||
  if (!VirtioFsFile->IsDirectory) {
 | 
			
		||||
    DEBUG ((
 | 
			
		||||
      DEBUG_ERROR,
 | 
			
		||||
      ("%a: Label=\"%s\" CanonicalPathname=\"%a\" FileName=\"%s\": "
 | 
			
		||||
       "nonsensical request to open a file or directory relative to a regular "
 | 
			
		||||
       "file\n"),
 | 
			
		||||
      __FUNCTION__,
 | 
			
		||||
      VirtioFs->Label,
 | 
			
		||||
      VirtioFsFile->CanonicalPathname,
 | 
			
		||||
      FileName
 | 
			
		||||
      ));
 | 
			
		||||
    return EFI_INVALID_PARAMETER;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // Allocate the new VIRTIO_FS_FILE object.
 | 
			
		||||
  //
 | 
			
		||||
  NewVirtioFsFile = AllocatePool (sizeof *NewVirtioFsFile);
 | 
			
		||||
  if (NewVirtioFsFile == NULL) {
 | 
			
		||||
    return EFI_OUT_OF_RESOURCES;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // Create the canonical pathname at which the desired file is expected to
 | 
			
		||||
  // exist.
 | 
			
		||||
  //
 | 
			
		||||
  Status = VirtioFsAppendPath (VirtioFsFile->CanonicalPathname, FileName,
 | 
			
		||||
             &NewCanonicalPath, &RootEscape);
 | 
			
		||||
  if (EFI_ERROR (Status)) {
 | 
			
		||||
    goto FreeNewVirtioFsFile;
 | 
			
		||||
  }
 | 
			
		||||
  if (RootEscape) {
 | 
			
		||||
    Status = EFI_ACCESS_DENIED;
 | 
			
		||||
    goto FreeNewCanonicalPath;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // If the desired file is the root directory, just open the volume one more
 | 
			
		||||
  // time, without looking up anything.
 | 
			
		||||
  //
 | 
			
		||||
  if (AsciiStrCmp (NewCanonicalPath, "/") == 0) {
 | 
			
		||||
    FreePool (NewCanonicalPath);
 | 
			
		||||
    FreePool (NewVirtioFsFile);
 | 
			
		||||
    return OpenRootDirectory (VirtioFs, NewHandle, OpenForWriting);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // Split the new canonical pathname into most specific parent directory
 | 
			
		||||
  // (given by DirNodeId) and last pathname component (i.e., immediate child
 | 
			
		||||
  // within that parent directory).
 | 
			
		||||
  //
 | 
			
		||||
  Status = VirtioFsLookupMostSpecificParentDir (VirtioFs, NewCanonicalPath,
 | 
			
		||||
             &DirNodeId, &LastComponent);
 | 
			
		||||
  if (EFI_ERROR (Status)) {
 | 
			
		||||
    goto FreeNewCanonicalPath;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // Try to open LastComponent directly under DirNodeId, as an existent regular
 | 
			
		||||
  // file or directory.
 | 
			
		||||
  //
 | 
			
		||||
  Status = OpenExistentFileOrDirectory (VirtioFs, DirNodeId, LastComponent,
 | 
			
		||||
             OpenForWriting, &NewNodeId, &NewFuseHandle, &NewNodeIsDirectory);
 | 
			
		||||
  //
 | 
			
		||||
  // If LastComponent could not be found under DirNodeId, but the request
 | 
			
		||||
  // allows us to create a new entry, attempt creating the requested regular
 | 
			
		||||
  // file or directory.
 | 
			
		||||
  //
 | 
			
		||||
  if (Status == EFI_NOT_FOUND && PermitCreation) {
 | 
			
		||||
    ASSERT (OpenForWriting);
 | 
			
		||||
    if (CreateDirectoryIfCreating) {
 | 
			
		||||
      Status = CreateDirectory (VirtioFs, DirNodeId, LastComponent, &NewNodeId,
 | 
			
		||||
                 &NewFuseHandle);
 | 
			
		||||
    } else {
 | 
			
		||||
      Status = CreateRegularFile (VirtioFs, DirNodeId, LastComponent,
 | 
			
		||||
                 &NewNodeId, &NewFuseHandle);
 | 
			
		||||
    }
 | 
			
		||||
    NewNodeIsDirectory = CreateDirectoryIfCreating;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // Regardless of the branch taken, we're done with DirNodeId.
 | 
			
		||||
  //
 | 
			
		||||
  if (DirNodeId != VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID) {
 | 
			
		||||
    VirtioFsFuseForget (VirtioFs, DirNodeId);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (EFI_ERROR (Status)) {
 | 
			
		||||
    goto FreeNewCanonicalPath;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // Populate the new VIRTIO_FS_FILE object.
 | 
			
		||||
  //
 | 
			
		||||
  NewVirtioFsFile->Signature              = VIRTIO_FS_FILE_SIG;
 | 
			
		||||
  NewVirtioFsFile->SimpleFile.Revision    = EFI_FILE_PROTOCOL_REVISION;
 | 
			
		||||
  NewVirtioFsFile->SimpleFile.Open        = VirtioFsSimpleFileOpen;
 | 
			
		||||
  NewVirtioFsFile->SimpleFile.Close       = VirtioFsSimpleFileClose;
 | 
			
		||||
  NewVirtioFsFile->SimpleFile.Delete      = VirtioFsSimpleFileDelete;
 | 
			
		||||
  NewVirtioFsFile->SimpleFile.Read        = VirtioFsSimpleFileRead;
 | 
			
		||||
  NewVirtioFsFile->SimpleFile.Write       = VirtioFsSimpleFileWrite;
 | 
			
		||||
  NewVirtioFsFile->SimpleFile.GetPosition = VirtioFsSimpleFileGetPosition;
 | 
			
		||||
  NewVirtioFsFile->SimpleFile.SetPosition = VirtioFsSimpleFileSetPosition;
 | 
			
		||||
  NewVirtioFsFile->SimpleFile.GetInfo     = VirtioFsSimpleFileGetInfo;
 | 
			
		||||
  NewVirtioFsFile->SimpleFile.SetInfo     = VirtioFsSimpleFileSetInfo;
 | 
			
		||||
  NewVirtioFsFile->SimpleFile.Flush       = VirtioFsSimpleFileFlush;
 | 
			
		||||
  NewVirtioFsFile->IsDirectory            = NewNodeIsDirectory;
 | 
			
		||||
  NewVirtioFsFile->IsOpenForWriting       = OpenForWriting;
 | 
			
		||||
  NewVirtioFsFile->OwnerFs                = VirtioFs;
 | 
			
		||||
  NewVirtioFsFile->CanonicalPathname      = NewCanonicalPath;
 | 
			
		||||
  NewVirtioFsFile->NodeId                 = NewNodeId;
 | 
			
		||||
  NewVirtioFsFile->FuseHandle             = NewFuseHandle;
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // One more file is now open for the filesystem.
 | 
			
		||||
  //
 | 
			
		||||
  InsertTailList (&VirtioFs->OpenFiles, &NewVirtioFsFile->OpenFilesEntry);
 | 
			
		||||
 | 
			
		||||
  *NewHandle = &NewVirtioFsFile->SimpleFile;
 | 
			
		||||
  return EFI_SUCCESS;
 | 
			
		||||
 | 
			
		||||
FreeNewCanonicalPath:
 | 
			
		||||
  FreePool (NewCanonicalPath);
 | 
			
		||||
 | 
			
		||||
FreeNewVirtioFsFile:
 | 
			
		||||
  FreePool (NewVirtioFsFile);
 | 
			
		||||
 | 
			
		||||
  return Status;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user