FuseLookup.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /** @file
  2. FUSE_LOOKUP wrapper for the Virtio Filesystem device.
  3. Copyright (C) 2020, Red Hat, Inc.
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <Library/BaseLib.h> // AsciiStrSize()
  7. #include "VirtioFsDxe.h"
  8. /**
  9. Send a FUSE_LOOKUP request to the Virtio Filesystem device, for resolving a
  10. filename to an inode.
  11. The function returns EFI_NOT_FOUND exclusively if the Virtio Filesystem
  12. device explicitly responds with ENOENT -- "No such file or directory".
  13. The function may only be called after VirtioFsFuseInitSession() returns
  14. successfully and before VirtioFsUninit() is called.
  15. @param[in,out] VirtioFs The Virtio Filesystem device to send the FUSE_LOOKUP
  16. request to. On output, the FUSE request counter
  17. "VirtioFs->RequestId" will have been incremented.
  18. @param[in] DirNodeId The inode number of the directory in which Name
  19. should be resolved to an inode.
  20. @param[in] Name The single-component filename to resolve in the
  21. directory identified by DirNodeId.
  22. @param[out] NodeId The inode number which Name has been resolved to.
  23. @param[out] FuseAttr The VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE object
  24. describing the properties of the resolved inode.
  25. @retval EFI_SUCCESS Filename to inode resolution successful.
  26. @retval EFI_NOT_FOUND The Virtio Filesystem device explicitly reported
  27. ENOENT -- "No such file or directory".
  28. @return The "errno" value mapped to an EFI_STATUS code, if the
  29. Virtio Filesystem device explicitly reported an error
  30. different from ENOENT. If said mapping resulted in
  31. EFI_NOT_FOUND, it is remapped to EFI_DEVICE_ERROR.
  32. @return Error codes propagated from VirtioFsSgListsValidate(),
  33. VirtioFsFuseNewRequest(), VirtioFsSgListsSubmit(),
  34. VirtioFsFuseCheckResponse(). EFI_NOT_FOUND is remapped
  35. to EFI_DEVICE_ERROR.
  36. **/
  37. EFI_STATUS
  38. VirtioFsFuseLookup (
  39. IN OUT VIRTIO_FS *VirtioFs,
  40. IN UINT64 DirNodeId,
  41. IN CHAR8 *Name,
  42. OUT UINT64 *NodeId,
  43. OUT VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE *FuseAttr
  44. )
  45. {
  46. VIRTIO_FS_FUSE_REQUEST CommonReq;
  47. VIRTIO_FS_IO_VECTOR ReqIoVec[2];
  48. VIRTIO_FS_SCATTER_GATHER_LIST ReqSgList;
  49. VIRTIO_FS_FUSE_RESPONSE CommonResp;
  50. VIRTIO_FS_FUSE_NODE_RESPONSE NodeResp;
  51. VIRTIO_FS_IO_VECTOR RespIoVec[3];
  52. VIRTIO_FS_SCATTER_GATHER_LIST RespSgList;
  53. EFI_STATUS Status;
  54. //
  55. // Set up the scatter-gather lists.
  56. //
  57. ReqIoVec[0].Buffer = &CommonReq;
  58. ReqIoVec[0].Size = sizeof CommonReq;
  59. ReqIoVec[1].Buffer = Name;
  60. ReqIoVec[1].Size = AsciiStrSize (Name);
  61. ReqSgList.IoVec = ReqIoVec;
  62. ReqSgList.NumVec = ARRAY_SIZE (ReqIoVec);
  63. RespIoVec[0].Buffer = &CommonResp;
  64. RespIoVec[0].Size = sizeof CommonResp;
  65. RespIoVec[1].Buffer = &NodeResp;
  66. RespIoVec[1].Size = sizeof NodeResp;
  67. RespIoVec[2].Buffer = FuseAttr;
  68. RespIoVec[2].Size = sizeof *FuseAttr;
  69. RespSgList.IoVec = RespIoVec;
  70. RespSgList.NumVec = ARRAY_SIZE (RespIoVec);
  71. //
  72. // Validate the scatter-gather lists; calculate the total transfer sizes.
  73. //
  74. Status = VirtioFsSgListsValidate (VirtioFs, &ReqSgList, &RespSgList);
  75. if (EFI_ERROR (Status)) {
  76. goto Fail;
  77. }
  78. //
  79. // Populate the common request header.
  80. //
  81. Status = VirtioFsFuseNewRequest (
  82. VirtioFs,
  83. &CommonReq,
  84. ReqSgList.TotalSize,
  85. VirtioFsFuseOpLookup,
  86. DirNodeId
  87. );
  88. if (EFI_ERROR (Status)) {
  89. goto Fail;
  90. }
  91. //
  92. // Submit the request.
  93. //
  94. Status = VirtioFsSgListsSubmit (VirtioFs, &ReqSgList, &RespSgList);
  95. if (EFI_ERROR (Status)) {
  96. goto Fail;
  97. }
  98. //
  99. // Verify the response (all response buffers are fixed size).
  100. //
  101. Status = VirtioFsFuseCheckResponse (&RespSgList, CommonReq.Unique, NULL);
  102. if (EFI_ERROR (Status)) {
  103. if (Status == EFI_DEVICE_ERROR) {
  104. DEBUG ((
  105. ((CommonResp.Error == VIRTIO_FS_FUSE_ERRNO_ENOENT) ?
  106. DEBUG_VERBOSE :
  107. DEBUG_ERROR),
  108. "%a: Label=\"%s\" DirNodeId=%Lu Name=\"%a\" Errno=%d\n",
  109. __FUNCTION__,
  110. VirtioFs->Label,
  111. DirNodeId,
  112. Name,
  113. CommonResp.Error
  114. ));
  115. if (CommonResp.Error == VIRTIO_FS_FUSE_ERRNO_ENOENT) {
  116. return EFI_NOT_FOUND;
  117. }
  118. Status = VirtioFsErrnoToEfiStatus (CommonResp.Error);
  119. }
  120. goto Fail;
  121. }
  122. //
  123. // Output the NodeId to which Name has been resolved to.
  124. //
  125. *NodeId = NodeResp.NodeId;
  126. return EFI_SUCCESS;
  127. Fail:
  128. return (Status == EFI_NOT_FOUND) ? EFI_DEVICE_ERROR : Status;
  129. }