FuseRename.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /** @file
  2. FUSE_RENAME2 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. Rename a regular file or a directory, by sending the FUSE_RENAME2 request to
  10. the Virtio Filesystem device. If the new filename exists, the request will
  11. fail.
  12. The function may only be called after VirtioFsFuseInitSession() returns
  13. successfully and before VirtioFsUninit() is called.
  14. @param[in,out] VirtioFs The Virtio Filesystem device to send the
  15. FUSE_RENAME2 request to. On output, the FUSE
  16. request counter "VirtioFs->RequestId" will have
  17. been incremented.
  18. @param[in] OldParentNodeId The inode number of the directory in which
  19. OldName should be removed.
  20. @param[in] OldName The single-component filename to remove in the
  21. directory identified by OldParentNodeId.
  22. @param[in] NewParentNodeId The inode number of the directory in which
  23. NewName should be created, such that on
  24. successful return, (NewParentNodeId, NewName)
  25. refer to the same inode as (OldParentNodeId,
  26. OldName) did on entry.
  27. @param[in] NewName The single-component filename to create in the
  28. directory identified by NewParentNodeId.
  29. @retval EFI_SUCCESS The file or directory has been renamed.
  30. @return The "errno" value mapped to an EFI_STATUS code, if the
  31. Virtio Filesystem device explicitly reported an error.
  32. @return Error codes propagated from VirtioFsSgListsValidate(),
  33. VirtioFsFuseNewRequest(), VirtioFsSgListsSubmit(),
  34. VirtioFsFuseCheckResponse().
  35. **/
  36. EFI_STATUS
  37. VirtioFsFuseRename (
  38. IN OUT VIRTIO_FS *VirtioFs,
  39. IN UINT64 OldParentNodeId,
  40. IN CHAR8 *OldName,
  41. IN UINT64 NewParentNodeId,
  42. IN CHAR8 *NewName
  43. )
  44. {
  45. VIRTIO_FS_FUSE_REQUEST CommonReq;
  46. VIRTIO_FS_FUSE_RENAME2_REQUEST Rename2Req;
  47. VIRTIO_FS_IO_VECTOR ReqIoVec[4];
  48. VIRTIO_FS_SCATTER_GATHER_LIST ReqSgList;
  49. VIRTIO_FS_FUSE_RESPONSE CommonResp;
  50. VIRTIO_FS_IO_VECTOR RespIoVec[1];
  51. VIRTIO_FS_SCATTER_GATHER_LIST RespSgList;
  52. EFI_STATUS Status;
  53. //
  54. // Set up the scatter-gather lists.
  55. //
  56. ReqIoVec[0].Buffer = &CommonReq;
  57. ReqIoVec[0].Size = sizeof CommonReq;
  58. ReqIoVec[1].Buffer = &Rename2Req;
  59. ReqIoVec[1].Size = sizeof Rename2Req;
  60. ReqIoVec[2].Buffer = OldName;
  61. ReqIoVec[2].Size = AsciiStrSize (OldName);
  62. ReqIoVec[3].Buffer = NewName;
  63. ReqIoVec[3].Size = AsciiStrSize (NewName);
  64. ReqSgList.IoVec = ReqIoVec;
  65. ReqSgList.NumVec = ARRAY_SIZE (ReqIoVec);
  66. RespIoVec[0].Buffer = &CommonResp;
  67. RespIoVec[0].Size = sizeof CommonResp;
  68. RespSgList.IoVec = RespIoVec;
  69. RespSgList.NumVec = ARRAY_SIZE (RespIoVec);
  70. //
  71. // Validate the scatter-gather lists; calculate the total transfer sizes.
  72. //
  73. Status = VirtioFsSgListsValidate (VirtioFs, &ReqSgList, &RespSgList);
  74. if (EFI_ERROR (Status)) {
  75. return Status;
  76. }
  77. //
  78. // Populate the common request header.
  79. //
  80. Status = VirtioFsFuseNewRequest (
  81. VirtioFs,
  82. &CommonReq,
  83. ReqSgList.TotalSize,
  84. VirtioFsFuseOpRename2,
  85. OldParentNodeId
  86. );
  87. if (EFI_ERROR (Status)) {
  88. return Status;
  89. }
  90. //
  91. // Populate the FUSE_RENAME2-specific fields.
  92. //
  93. Rename2Req.NewDir = NewParentNodeId;
  94. Rename2Req.Flags = VIRTIO_FS_FUSE_RENAME2_REQ_F_NOREPLACE;
  95. Rename2Req.Padding = 0;
  96. //
  97. // Submit the request.
  98. //
  99. Status = VirtioFsSgListsSubmit (VirtioFs, &ReqSgList, &RespSgList);
  100. if (EFI_ERROR (Status)) {
  101. return Status;
  102. }
  103. //
  104. // Verify the response (all response buffers are fixed size).
  105. //
  106. Status = VirtioFsFuseCheckResponse (&RespSgList, CommonReq.Unique, NULL);
  107. if (Status == EFI_DEVICE_ERROR) {
  108. DEBUG ((
  109. DEBUG_ERROR,
  110. "%a: Label=\"%s\" OldParentNodeId=%Lu OldName=\"%a\" "
  111. "NewParentNodeId=%Lu NewName=\"%a\" Errno=%d\n",
  112. __FUNCTION__,
  113. VirtioFs->Label,
  114. OldParentNodeId,
  115. OldName,
  116. NewParentNodeId,
  117. NewName,
  118. CommonResp.Error
  119. ));
  120. Status = VirtioFsErrnoToEfiStatus (CommonResp.Error);
  121. }
  122. return Status;
  123. }