Helpers.c 86 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525
  1. /** @file
  2. Initialization and helper routines 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> // StrLen()
  7. #include <Library/BaseMemoryLib.h> // CopyMem()
  8. #include <Library/MemoryAllocationLib.h> // AllocatePool()
  9. #include <Library/TimeBaseLib.h> // EpochToEfiTime()
  10. #include <Library/VirtioLib.h> // Virtio10WriteFeatures()
  11. #include "VirtioFsDxe.h"
  12. /**
  13. Read the Virtio Filesystem device configuration structure in full.
  14. @param[in] Virtio The Virtio protocol underlying the VIRTIO_FS object.
  15. @param[out] Config The fully populated VIRTIO_FS_CONFIG structure.
  16. @retval EFI_SUCCESS Config has been filled in.
  17. @return Error codes propagated from Virtio->ReadDevice(). The
  18. contents of Config are indeterminate.
  19. **/
  20. STATIC
  21. EFI_STATUS
  22. VirtioFsReadConfig (
  23. IN VIRTIO_DEVICE_PROTOCOL *Virtio,
  24. OUT VIRTIO_FS_CONFIG *Config
  25. )
  26. {
  27. UINTN Idx;
  28. EFI_STATUS Status;
  29. for (Idx = 0; Idx < VIRTIO_FS_TAG_BYTES; Idx++) {
  30. Status = Virtio->ReadDevice (
  31. Virtio, // This
  32. OFFSET_OF (VIRTIO_FS_CONFIG, Tag[Idx]), // FieldOffset
  33. sizeof Config->Tag[Idx], // FieldSize
  34. sizeof Config->Tag[Idx], // BufferSize
  35. &Config->Tag[Idx] // Buffer
  36. );
  37. if (EFI_ERROR (Status)) {
  38. return Status;
  39. }
  40. }
  41. Status = Virtio->ReadDevice (
  42. Virtio, // This
  43. OFFSET_OF (VIRTIO_FS_CONFIG, NumReqQueues), // FieldOffset
  44. sizeof Config->NumReqQueues, // FieldSize
  45. sizeof Config->NumReqQueues, // BufferSize
  46. &Config->NumReqQueues // Buffer
  47. );
  48. return Status;
  49. }
  50. /**
  51. Configure the Virtio Filesystem device underlying VirtioFs.
  52. @param[in,out] VirtioFs The VIRTIO_FS object for which Virtio communication
  53. should be set up. On input, the caller is
  54. responsible for VirtioFs->Virtio having been
  55. initialized. On output, synchronous Virtio
  56. Filesystem commands (primitives) may be submitted to
  57. the device.
  58. @retval EFI_SUCCESS Virtio machinery has been set up.
  59. @retval EFI_UNSUPPORTED The host-side configuration of the Virtio Filesystem
  60. is not supported by this driver.
  61. @return Error codes from underlying functions.
  62. **/
  63. EFI_STATUS
  64. VirtioFsInit (
  65. IN OUT VIRTIO_FS *VirtioFs
  66. )
  67. {
  68. UINT8 NextDevStat;
  69. EFI_STATUS Status;
  70. UINT64 Features;
  71. VIRTIO_FS_CONFIG Config;
  72. UINTN Idx;
  73. UINT64 RingBaseShift;
  74. //
  75. // Execute virtio-v1.1-cs01-87fa6b5d8155, 3.1.1 Driver Requirements: Device
  76. // Initialization.
  77. //
  78. // 1. Reset the device.
  79. //
  80. NextDevStat = 0;
  81. Status = VirtioFs->Virtio->SetDeviceStatus (VirtioFs->Virtio, NextDevStat);
  82. if (EFI_ERROR (Status)) {
  83. goto Failed;
  84. }
  85. //
  86. // 2. Set the ACKNOWLEDGE status bit [...]
  87. //
  88. NextDevStat |= VSTAT_ACK;
  89. Status = VirtioFs->Virtio->SetDeviceStatus (VirtioFs->Virtio, NextDevStat);
  90. if (EFI_ERROR (Status)) {
  91. goto Failed;
  92. }
  93. //
  94. // 3. Set the DRIVER status bit [...]
  95. //
  96. NextDevStat |= VSTAT_DRIVER;
  97. Status = VirtioFs->Virtio->SetDeviceStatus (VirtioFs->Virtio, NextDevStat);
  98. if (EFI_ERROR (Status)) {
  99. goto Failed;
  100. }
  101. //
  102. // 4. Read device feature bits...
  103. //
  104. Status = VirtioFs->Virtio->GetDeviceFeatures (VirtioFs->Virtio, &Features);
  105. if (EFI_ERROR (Status)) {
  106. goto Failed;
  107. }
  108. if ((Features & VIRTIO_F_VERSION_1) == 0) {
  109. Status = EFI_UNSUPPORTED;
  110. goto Failed;
  111. }
  112. //
  113. // No device-specific feature bits have been defined in file "virtio-fs.tex"
  114. // of the virtio spec at <https://github.com/oasis-tcs/virtio-spec.git>, as
  115. // of commit 87fa6b5d8155.
  116. //
  117. Features &= VIRTIO_F_VERSION_1 | VIRTIO_F_IOMMU_PLATFORM;
  118. //
  119. // ... and write the subset of feature bits understood by the [...] driver to
  120. // the device. [...]
  121. // 5. Set the FEATURES_OK status bit.
  122. // 6. Re-read device status to ensure the FEATURES_OK bit is still set [...]
  123. //
  124. Status = Virtio10WriteFeatures (VirtioFs->Virtio, Features, &NextDevStat);
  125. if (EFI_ERROR (Status)) {
  126. goto Failed;
  127. }
  128. //
  129. // 7. Perform device-specific setup, including discovery of virtqueues for
  130. // the device, [...] reading [...] the device's virtio configuration space
  131. //
  132. Status = VirtioFsReadConfig (VirtioFs->Virtio, &Config);
  133. if (EFI_ERROR (Status)) {
  134. goto Failed;
  135. }
  136. //
  137. // 7.a. Convert the filesystem label from UTF-8 to UCS-2. Only labels with
  138. // printable ASCII code points (U+0020 through U+007E) are supported.
  139. // NUL-terminate at either the terminator we find, or right after the
  140. // original label.
  141. //
  142. for (Idx = 0; Idx < VIRTIO_FS_TAG_BYTES && Config.Tag[Idx] != '\0'; Idx++) {
  143. if ((Config.Tag[Idx] < 0x20) || (Config.Tag[Idx] > 0x7E)) {
  144. Status = EFI_UNSUPPORTED;
  145. goto Failed;
  146. }
  147. VirtioFs->Label[Idx] = Config.Tag[Idx];
  148. }
  149. VirtioFs->Label[Idx] = L'\0';
  150. //
  151. // 7.b. We need one queue for sending normal priority requests.
  152. //
  153. if (Config.NumReqQueues < 1) {
  154. Status = EFI_UNSUPPORTED;
  155. goto Failed;
  156. }
  157. //
  158. // 7.c. Fetch and remember the number of descriptors we can place on the
  159. // queue at once. We'll need two descriptors per request, as a minimum --
  160. // request header, response header.
  161. //
  162. Status = VirtioFs->Virtio->SetQueueSel (
  163. VirtioFs->Virtio,
  164. VIRTIO_FS_REQUEST_QUEUE
  165. );
  166. if (EFI_ERROR (Status)) {
  167. goto Failed;
  168. }
  169. Status = VirtioFs->Virtio->GetQueueNumMax (
  170. VirtioFs->Virtio,
  171. &VirtioFs->QueueSize
  172. );
  173. if (EFI_ERROR (Status)) {
  174. goto Failed;
  175. }
  176. if (VirtioFs->QueueSize < 2) {
  177. Status = EFI_UNSUPPORTED;
  178. goto Failed;
  179. }
  180. //
  181. // 7.d. [...] population of virtqueues [...]
  182. //
  183. Status = VirtioRingInit (
  184. VirtioFs->Virtio,
  185. VirtioFs->QueueSize,
  186. &VirtioFs->Ring
  187. );
  188. if (EFI_ERROR (Status)) {
  189. goto Failed;
  190. }
  191. Status = VirtioRingMap (
  192. VirtioFs->Virtio,
  193. &VirtioFs->Ring,
  194. &RingBaseShift,
  195. &VirtioFs->RingMap
  196. );
  197. if (EFI_ERROR (Status)) {
  198. goto ReleaseQueue;
  199. }
  200. Status = VirtioFs->Virtio->SetQueueAddress (
  201. VirtioFs->Virtio,
  202. &VirtioFs->Ring,
  203. RingBaseShift
  204. );
  205. if (EFI_ERROR (Status)) {
  206. goto UnmapQueue;
  207. }
  208. //
  209. // 8. Set the DRIVER_OK status bit.
  210. //
  211. NextDevStat |= VSTAT_DRIVER_OK;
  212. Status = VirtioFs->Virtio->SetDeviceStatus (VirtioFs->Virtio, NextDevStat);
  213. if (EFI_ERROR (Status)) {
  214. goto UnmapQueue;
  215. }
  216. return EFI_SUCCESS;
  217. UnmapQueue:
  218. VirtioFs->Virtio->UnmapSharedBuffer (VirtioFs->Virtio, VirtioFs->RingMap);
  219. ReleaseQueue:
  220. VirtioRingUninit (VirtioFs->Virtio, &VirtioFs->Ring);
  221. Failed:
  222. //
  223. // If any of these steps go irrecoverably wrong, the driver SHOULD set the
  224. // FAILED status bit to indicate that it has given up on the device (it can
  225. // reset the device later to restart if desired). [...]
  226. //
  227. // Virtio access failure here should not mask the original error.
  228. //
  229. NextDevStat |= VSTAT_FAILED;
  230. VirtioFs->Virtio->SetDeviceStatus (VirtioFs->Virtio, NextDevStat);
  231. return Status;
  232. }
  233. /**
  234. De-configure the Virtio Filesystem device underlying VirtioFs.
  235. @param[in] VirtioFs The VIRTIO_FS object for which Virtio communication
  236. should be torn down. On input, the caller is responsible
  237. for having called VirtioFsInit(). On output, Virtio
  238. Filesystem commands (primitives) must no longer be
  239. submitted to the device.
  240. **/
  241. VOID
  242. VirtioFsUninit (
  243. IN OUT VIRTIO_FS *VirtioFs
  244. )
  245. {
  246. //
  247. // Resetting the Virtio device makes it release its resources and forget its
  248. // configuration.
  249. //
  250. VirtioFs->Virtio->SetDeviceStatus (VirtioFs->Virtio, 0);
  251. VirtioFs->Virtio->UnmapSharedBuffer (VirtioFs->Virtio, VirtioFs->RingMap);
  252. VirtioRingUninit (VirtioFs->Virtio, &VirtioFs->Ring);
  253. }
  254. /**
  255. ExitBootServices event notification function for a Virtio Filesystem object.
  256. This function resets the VIRTIO_FS.Virtio device, causing it to release all
  257. references to guest-side resources. The function may only be called after
  258. VirtioFsInit() returns successfully and before VirtioFsUninit() is called.
  259. @param[in] ExitBootEvent The VIRTIO_FS.ExitBoot event that has been
  260. signaled.
  261. @param[in] VirtioFsAsVoid Pointer to the VIRTIO_FS object, passed in as
  262. (VOID*).
  263. **/
  264. VOID
  265. EFIAPI
  266. VirtioFsExitBoot (
  267. IN EFI_EVENT ExitBootEvent,
  268. IN VOID *VirtioFsAsVoid
  269. )
  270. {
  271. VIRTIO_FS *VirtioFs;
  272. VirtioFs = VirtioFsAsVoid;
  273. DEBUG ((
  274. DEBUG_VERBOSE,
  275. "%a: VirtioFs=0x%p Label=\"%s\"\n",
  276. __FUNCTION__,
  277. VirtioFsAsVoid,
  278. VirtioFs->Label
  279. ));
  280. VirtioFs->Virtio->SetDeviceStatus (VirtioFs->Virtio, 0);
  281. }
  282. /**
  283. Validate two VIRTIO_FS_SCATTER_GATHER_LIST objects -- list of request
  284. buffers, list of response buffers -- together.
  285. On input, the caller is required to populate the following fields:
  286. - VIRTIO_FS_IO_VECTOR.Buffer,
  287. - VIRTIO_FS_IO_VECTOR.Size,
  288. - VIRTIO_FS_SCATTER_GATHER_LIST.IoVec,
  289. - VIRTIO_FS_SCATTER_GATHER_LIST.NumVec.
  290. On output (on successful return), the following fields will be
  291. zero-initialized:
  292. - VIRTIO_FS_IO_VECTOR.Mapped,
  293. - VIRTIO_FS_IO_VECTOR.MappedAddress,
  294. - VIRTIO_FS_IO_VECTOR.Mapping,
  295. - VIRTIO_FS_IO_VECTOR.Transferred.
  296. On output (on successful return), the following fields will be calculated:
  297. - VIRTIO_FS_SCATTER_GATHER_LIST.TotalSize.
  298. The function may only be called after VirtioFsInit() returns successfully and
  299. before VirtioFsUninit() is called.
  300. @param[in] VirtioFs The Virtio Filesystem device that the
  301. request-response exchange, expressed via
  302. RequestSgList and ResponseSgList, will be
  303. submitted to.
  304. @param[in,out] RequestSgList The scatter-gather list that describes the
  305. request part of the exchange -- the buffers
  306. that should be sent to the Virtio Filesystem
  307. device in the virtio transfer.
  308. @param[in,out] ResponseSgList The scatter-gather list that describes the
  309. response part of the exchange -- the buffers
  310. that the Virtio Filesystem device should
  311. populate in the virtio transfer. May be NULL
  312. if the exchange with the Virtio Filesystem
  313. device consists of a request only, with the
  314. response part omitted altogether.
  315. @retval EFI_SUCCESS RequestSgList and ResponseSgList have been
  316. validated, output fields have been set.
  317. @retval EFI_INVALID_PARAMETER RequestSgList is NULL.
  318. @retval EFI_INVALID_PARAMETER On input, a
  319. VIRTIO_FS_SCATTER_GATHER_LIST.IoVec field is
  320. NULL, or a
  321. VIRTIO_FS_SCATTER_GATHER_LIST.NumVec field is
  322. zero.
  323. @retval EFI_INVALID_PARAMETER On input, a VIRTIO_FS_IO_VECTOR.Buffer field
  324. is NULL, or a VIRTIO_FS_IO_VECTOR.Size field
  325. is zero.
  326. @retval EFI_UNSUPPORTED (RequestSgList->NumVec +
  327. ResponseSgList->NumVec) exceeds
  328. VirtioFs->QueueSize, meaning that the total
  329. list of buffers cannot be placed on the virtio
  330. queue in a single descriptor chain (with one
  331. descriptor per buffer).
  332. @retval EFI_UNSUPPORTED One of the
  333. VIRTIO_FS_SCATTER_GATHER_LIST.TotalSize fields
  334. would exceed MAX_UINT32.
  335. **/
  336. EFI_STATUS
  337. VirtioFsSgListsValidate (
  338. IN VIRTIO_FS *VirtioFs,
  339. IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *RequestSgList,
  340. IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *ResponseSgList OPTIONAL
  341. )
  342. {
  343. VIRTIO_FS_SCATTER_GATHER_LIST *SgListParam[2];
  344. UINT16 DescriptorsNeeded;
  345. UINTN ListId;
  346. if (RequestSgList == NULL) {
  347. return EFI_INVALID_PARAMETER;
  348. }
  349. SgListParam[0] = RequestSgList;
  350. SgListParam[1] = ResponseSgList;
  351. DescriptorsNeeded = 0;
  352. for (ListId = 0; ListId < ARRAY_SIZE (SgListParam); ListId++) {
  353. VIRTIO_FS_SCATTER_GATHER_LIST *SgList;
  354. UINT32 SgListTotalSize;
  355. UINTN IoVecIdx;
  356. SgList = SgListParam[ListId];
  357. if (SgList == NULL) {
  358. continue;
  359. }
  360. //
  361. // Sanity-check SgList -- it must provide at least one IO Vector.
  362. //
  363. if ((SgList->IoVec == NULL) || (SgList->NumVec == 0)) {
  364. return EFI_INVALID_PARAMETER;
  365. }
  366. //
  367. // Make sure that, for each IO Vector in this SgList, a virtio descriptor
  368. // can be added to the virtio queue, after the other descriptors added
  369. // previously.
  370. //
  371. if ((SgList->NumVec > (UINTN)(MAX_UINT16 - DescriptorsNeeded)) ||
  372. (DescriptorsNeeded + SgList->NumVec > VirtioFs->QueueSize))
  373. {
  374. return EFI_UNSUPPORTED;
  375. }
  376. DescriptorsNeeded += (UINT16)SgList->NumVec;
  377. SgListTotalSize = 0;
  378. for (IoVecIdx = 0; IoVecIdx < SgList->NumVec; IoVecIdx++) {
  379. VIRTIO_FS_IO_VECTOR *IoVec;
  380. IoVec = &SgList->IoVec[IoVecIdx];
  381. //
  382. // Sanity-check this IoVec -- it must describe a non-empty buffer.
  383. //
  384. if ((IoVec->Buffer == NULL) || (IoVec->Size == 0)) {
  385. return EFI_INVALID_PARAMETER;
  386. }
  387. //
  388. // Make sure the cumulative size of all IO Vectors in this SgList remains
  389. // expressible as a UINT32.
  390. //
  391. if (IoVec->Size > MAX_UINT32 - SgListTotalSize) {
  392. return EFI_UNSUPPORTED;
  393. }
  394. SgListTotalSize += (UINT32)IoVec->Size;
  395. //
  396. // Initialize those fields in this IO Vector that will be updated in
  397. // relation to mapping / transfer.
  398. //
  399. IoVec->Mapped = FALSE;
  400. IoVec->MappedAddress = 0;
  401. IoVec->Mapping = NULL;
  402. IoVec->Transferred = 0;
  403. }
  404. //
  405. // Store the cumulative size of all IO Vectors that we have calculated in
  406. // this SgList.
  407. //
  408. SgList->TotalSize = SgListTotalSize;
  409. }
  410. return EFI_SUCCESS;
  411. }
  412. /**
  413. Submit a validated pair of (request buffer list, response buffer list) to the
  414. Virtio Filesystem device.
  415. On input, the pair of VIRTIO_FS_SCATTER_GATHER_LIST objects must have been
  416. validated together, using the VirtioFsSgListsValidate() function.
  417. On output (on successful return), the following fields will be re-initialized
  418. to zero (after temporarily setting them to different values):
  419. - VIRTIO_FS_IO_VECTOR.Mapped,
  420. - VIRTIO_FS_IO_VECTOR.MappedAddress,
  421. - VIRTIO_FS_IO_VECTOR.Mapping.
  422. On output (on successful return), the following fields will be calculated:
  423. - VIRTIO_FS_IO_VECTOR.Transferred.
  424. The function may only be called after VirtioFsInit() returns successfully and
  425. before VirtioFsUninit() is called.
  426. @param[in,out] VirtioFs The Virtio Filesystem device that the
  427. request-response exchange, expressed via
  428. RequestSgList and ResponseSgList, should now
  429. be submitted to.
  430. @param[in,out] RequestSgList The scatter-gather list that describes the
  431. request part of the exchange -- the buffers
  432. that should be sent to the Virtio Filesystem
  433. device in the virtio transfer.
  434. @param[in,out] ResponseSgList The scatter-gather list that describes the
  435. response part of the exchange -- the buffers
  436. that the Virtio Filesystem device should
  437. populate in the virtio transfer. May be NULL
  438. if and only if NULL was passed to
  439. VirtioFsSgListsValidate() as ResponseSgList.
  440. @retval EFI_SUCCESS Transfer complete. The caller should investigate
  441. the VIRTIO_FS_IO_VECTOR.Transferred fields in
  442. ResponseSgList, to ensure coverage of the relevant
  443. response buffers. Subsequently, the caller should
  444. investigate the contents of those buffers.
  445. @retval EFI_DEVICE_ERROR The Virtio Filesystem device reported populating
  446. more response bytes than ResponseSgList->TotalSize.
  447. @return Error codes propagated from
  448. VirtioMapAllBytesInSharedBuffer(), VirtioFlush(),
  449. or VirtioFs->Virtio->UnmapSharedBuffer().
  450. **/
  451. EFI_STATUS
  452. VirtioFsSgListsSubmit (
  453. IN OUT VIRTIO_FS *VirtioFs,
  454. IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *RequestSgList,
  455. IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *ResponseSgList OPTIONAL
  456. )
  457. {
  458. VIRTIO_FS_SCATTER_GATHER_LIST *SgListParam[2];
  459. VIRTIO_MAP_OPERATION SgListVirtioMapOp[ARRAY_SIZE (SgListParam)];
  460. UINT16 SgListDescriptorFlag[ARRAY_SIZE (SgListParam)];
  461. UINTN ListId;
  462. VIRTIO_FS_SCATTER_GATHER_LIST *SgList;
  463. UINTN IoVecIdx;
  464. VIRTIO_FS_IO_VECTOR *IoVec;
  465. EFI_STATUS Status;
  466. DESC_INDICES Indices;
  467. UINT32 TotalBytesWrittenByDevice;
  468. UINT32 BytesPermittedForWrite;
  469. SgListParam[0] = RequestSgList;
  470. SgListVirtioMapOp[0] = VirtioOperationBusMasterRead;
  471. SgListDescriptorFlag[0] = 0;
  472. SgListParam[1] = ResponseSgList;
  473. SgListVirtioMapOp[1] = VirtioOperationBusMasterWrite;
  474. SgListDescriptorFlag[1] = VRING_DESC_F_WRITE;
  475. //
  476. // Map all IO Vectors.
  477. //
  478. for (ListId = 0; ListId < ARRAY_SIZE (SgListParam); ListId++) {
  479. SgList = SgListParam[ListId];
  480. if (SgList == NULL) {
  481. continue;
  482. }
  483. for (IoVecIdx = 0; IoVecIdx < SgList->NumVec; IoVecIdx++) {
  484. IoVec = &SgList->IoVec[IoVecIdx];
  485. //
  486. // Map this IO Vector.
  487. //
  488. Status = VirtioMapAllBytesInSharedBuffer (
  489. VirtioFs->Virtio,
  490. SgListVirtioMapOp[ListId],
  491. IoVec->Buffer,
  492. IoVec->Size,
  493. &IoVec->MappedAddress,
  494. &IoVec->Mapping
  495. );
  496. if (EFI_ERROR (Status)) {
  497. goto Unmap;
  498. }
  499. IoVec->Mapped = TRUE;
  500. }
  501. }
  502. //
  503. // Compose the descriptor chain.
  504. //
  505. VirtioPrepare (&VirtioFs->Ring, &Indices);
  506. for (ListId = 0; ListId < ARRAY_SIZE (SgListParam); ListId++) {
  507. SgList = SgListParam[ListId];
  508. if (SgList == NULL) {
  509. continue;
  510. }
  511. for (IoVecIdx = 0; IoVecIdx < SgList->NumVec; IoVecIdx++) {
  512. UINT16 NextFlag;
  513. IoVec = &SgList->IoVec[IoVecIdx];
  514. //
  515. // Set VRING_DESC_F_NEXT on all except the very last descriptor.
  516. //
  517. NextFlag = VRING_DESC_F_NEXT;
  518. if ((ListId == ARRAY_SIZE (SgListParam) - 1) &&
  519. (IoVecIdx == SgList->NumVec - 1))
  520. {
  521. NextFlag = 0;
  522. }
  523. VirtioAppendDesc (
  524. &VirtioFs->Ring,
  525. IoVec->MappedAddress,
  526. (UINT32)IoVec->Size,
  527. SgListDescriptorFlag[ListId] | NextFlag,
  528. &Indices
  529. );
  530. }
  531. }
  532. //
  533. // Submit the descriptor chain.
  534. //
  535. Status = VirtioFlush (
  536. VirtioFs->Virtio,
  537. VIRTIO_FS_REQUEST_QUEUE,
  538. &VirtioFs->Ring,
  539. &Indices,
  540. &TotalBytesWrittenByDevice
  541. );
  542. if (EFI_ERROR (Status)) {
  543. goto Unmap;
  544. }
  545. //
  546. // Sanity-check: the Virtio Filesystem device should not have written more
  547. // bytes than what we offered buffers for.
  548. //
  549. if (ResponseSgList == NULL) {
  550. BytesPermittedForWrite = 0;
  551. } else {
  552. BytesPermittedForWrite = ResponseSgList->TotalSize;
  553. }
  554. if (TotalBytesWrittenByDevice > BytesPermittedForWrite) {
  555. Status = EFI_DEVICE_ERROR;
  556. goto Unmap;
  557. }
  558. //
  559. // Update the transfer sizes in the IO Vectors.
  560. //
  561. for (ListId = 0; ListId < ARRAY_SIZE (SgListParam); ListId++) {
  562. SgList = SgListParam[ListId];
  563. if (SgList == NULL) {
  564. continue;
  565. }
  566. for (IoVecIdx = 0; IoVecIdx < SgList->NumVec; IoVecIdx++) {
  567. IoVec = &SgList->IoVec[IoVecIdx];
  568. if (SgListVirtioMapOp[ListId] == VirtioOperationBusMasterRead) {
  569. //
  570. // We report that the Virtio Filesystem device has read all buffers in
  571. // the request.
  572. //
  573. IoVec->Transferred = IoVec->Size;
  574. } else {
  575. //
  576. // Regarding the response, calculate how much of the current IO Vector
  577. // has been populated by the Virtio Filesystem device. In
  578. // "TotalBytesWrittenByDevice", VirtioFlush() reported the total count
  579. // across all device-writeable descriptors, in the order they were
  580. // chained on the ring.
  581. //
  582. IoVec->Transferred = MIN (
  583. (UINTN)TotalBytesWrittenByDevice,
  584. IoVec->Size
  585. );
  586. TotalBytesWrittenByDevice -= (UINT32)IoVec->Transferred;
  587. }
  588. }
  589. }
  590. //
  591. // By now, "TotalBytesWrittenByDevice" has been exhausted.
  592. //
  593. ASSERT (TotalBytesWrittenByDevice == 0);
  594. //
  595. // We've succeeded; fall through.
  596. //
  597. Unmap:
  598. //
  599. // Unmap all mapped IO Vectors on both the success and the error paths. The
  600. // unmapping occurs in reverse order of mapping, in an attempt to avoid
  601. // memory fragmentation.
  602. //
  603. ListId = ARRAY_SIZE (SgListParam);
  604. while (ListId > 0) {
  605. --ListId;
  606. SgList = SgListParam[ListId];
  607. if (SgList == NULL) {
  608. continue;
  609. }
  610. IoVecIdx = SgList->NumVec;
  611. while (IoVecIdx > 0) {
  612. EFI_STATUS UnmapStatus;
  613. --IoVecIdx;
  614. IoVec = &SgList->IoVec[IoVecIdx];
  615. //
  616. // Unmap this IO Vector, if it has been mapped.
  617. //
  618. if (!IoVec->Mapped) {
  619. continue;
  620. }
  621. UnmapStatus = VirtioFs->Virtio->UnmapSharedBuffer (
  622. VirtioFs->Virtio,
  623. IoVec->Mapping
  624. );
  625. //
  626. // Re-set the following fields to the values they initially got from
  627. // VirtioFsSgListsValidate() -- the above unmapping attempt is considered
  628. // final, even if it fails.
  629. //
  630. IoVec->Mapped = FALSE;
  631. IoVec->MappedAddress = 0;
  632. IoVec->Mapping = NULL;
  633. //
  634. // If we are on the success path, but the unmapping failed, we need to
  635. // transparently flip to the failure path -- the caller must learn they
  636. // should not consult the response buffers.
  637. //
  638. // The branch below can be taken at most once.
  639. //
  640. if (!EFI_ERROR (Status) && EFI_ERROR (UnmapStatus)) {
  641. Status = UnmapStatus;
  642. }
  643. }
  644. }
  645. return Status;
  646. }
  647. /**
  648. Set up the fields of a new VIRTIO_FS_FUSE_REQUEST object.
  649. The function may only be called after VirtioFsInit() returns successfully and
  650. before VirtioFsUninit() is called.
  651. @param[in,out] VirtioFs The Virtio Filesystem device that the request is
  652. being prepared for. The "VirtioFs->RequestId" field
  653. will be copied into "Request->Unique". On output (on
  654. successful return), "VirtioFs->RequestId" will be
  655. incremented.
  656. @param[out] Request The VIRTIO_FS_FUSE_REQUEST object whose fields are to
  657. be set.
  658. @param[in] RequestSize The total size of the request, including
  659. sizeof(VIRTIO_FS_FUSE_REQUEST).
  660. @param[in] Opcode The VIRTIO_FS_FUSE_OPCODE that identifies the command
  661. to send.
  662. @param[in] NodeId The inode number of the file that the request refers
  663. to. When Opcode is VirtioFsFuseOpInit, NodeId is
  664. ignored by the Virtio Filesystem device.
  665. @retval EFI_INVALID_PARAMETER RequestSize is smaller than
  666. sizeof(VIRTIO_FS_FUSE_REQUEST).
  667. @retval EFI_OUT_OF_RESOURCES "VirtioFs->RequestId" is MAX_UINT64, and can
  668. be incremented no more.
  669. @retval EFI_SUCCESS Request has been populated,
  670. "VirtioFs->RequestId" has been incremented.
  671. **/
  672. EFI_STATUS
  673. VirtioFsFuseNewRequest (
  674. IN OUT VIRTIO_FS *VirtioFs,
  675. OUT VIRTIO_FS_FUSE_REQUEST *Request,
  676. IN UINT32 RequestSize,
  677. IN VIRTIO_FS_FUSE_OPCODE Opcode,
  678. IN UINT64 NodeId
  679. )
  680. {
  681. if (RequestSize < sizeof *Request) {
  682. return EFI_INVALID_PARAMETER;
  683. }
  684. if (VirtioFs->RequestId == MAX_UINT64) {
  685. return EFI_OUT_OF_RESOURCES;
  686. }
  687. Request->Len = RequestSize;
  688. Request->Opcode = Opcode;
  689. Request->Unique = VirtioFs->RequestId++;
  690. Request->NodeId = NodeId;
  691. Request->Uid = 0;
  692. Request->Gid = 0;
  693. Request->Pid = 1;
  694. Request->Padding = 0;
  695. return EFI_SUCCESS;
  696. }
  697. /**
  698. Check the common FUSE response format.
  699. The first buffer in the response scatter-gather list is assumed a
  700. VIRTIO_FS_FUSE_RESPONSE structure. Subsequent response buffers, if any, up to
  701. and excluding the last one, are assumed fixed size. The last response buffer
  702. may or may not be fixed size, as specified by the caller.
  703. This function may only be called after VirtioFsSgListsSubmit() returns
  704. successfully.
  705. @param[in] ResponseSgList The scatter-gather list that describes the
  706. response part of the exchange -- the buffers that
  707. the Virtio Filesystem device filled in during the
  708. virtio transfer.
  709. @param[in] RequestId The request identifier to which the response is
  710. expected to belong.
  711. @param[out] TailBufferFill If NULL, then the last buffer in ResponseSgList
  712. is considered fixed size. Otherwise, the last
  713. buffer is considered variable size, and on
  714. successful return, TailBufferFill reports the
  715. number of bytes in the last buffer.
  716. @retval EFI_INVALID_PARAMETER TailBufferFill is not NULL (i.e., the last
  717. buffer is considered variable size), and
  718. ResponseSgList->NumVec is 1.
  719. @retval EFI_INVALID_PARAMETER The allocated size of the first buffer does
  720. not match sizeof(VIRTIO_FS_FUSE_RESPONSE).
  721. @retval EFI_PROTOCOL_ERROR The VIRTIO_FS_FUSE_RESPONSE structure in the
  722. first buffer has not been fully populated.
  723. @retval EFI_PROTOCOL_ERROR "VIRTIO_FS_FUSE_RESPONSE.Len" in the first
  724. buffer does not equal the sum of the
  725. individual buffer sizes (as populated).
  726. @retval EFI_PROTOCOL_ERROR "VIRTIO_FS_FUSE_RESPONSE.Unique" in the first
  727. buffer does not equal RequestId.
  728. @retval EFI_PROTOCOL_ERROR "VIRTIO_FS_FUSE_RESPONSE.Error" in the first
  729. buffer is zero, but a subsequent fixed size
  730. buffer has not been fully populated.
  731. @retval EFI_DEVICE_ERROR "VIRTIO_FS_FUSE_RESPONSE.Error" in the first
  732. buffer is nonzero. The caller may investigate
  733. "VIRTIO_FS_FUSE_RESPONSE.Error". Note that the
  734. completeness of the subsequent fixed size
  735. buffers is not verified in this case.
  736. @retval EFI_SUCCESS Verification successful.
  737. **/
  738. EFI_STATUS
  739. VirtioFsFuseCheckResponse (
  740. IN VIRTIO_FS_SCATTER_GATHER_LIST *ResponseSgList,
  741. IN UINT64 RequestId,
  742. OUT UINTN *TailBufferFill
  743. )
  744. {
  745. UINTN NumFixedSizeVec;
  746. VIRTIO_FS_FUSE_RESPONSE *CommonResp;
  747. UINT32 TotalTransferred;
  748. UINTN Idx;
  749. //
  750. // Ensured by VirtioFsSgListsValidate().
  751. //
  752. ASSERT (ResponseSgList->NumVec > 0);
  753. if (TailBufferFill == NULL) {
  754. //
  755. // All buffers are considered fixed size.
  756. //
  757. NumFixedSizeVec = ResponseSgList->NumVec;
  758. } else {
  759. //
  760. // If the last buffer is variable size, then we need that buffer to be
  761. // different from the first buffer, which is considered a
  762. // VIRTIO_FS_FUSE_RESPONSE (fixed size) structure.
  763. //
  764. if (ResponseSgList->NumVec == 1) {
  765. return EFI_INVALID_PARAMETER;
  766. }
  767. NumFixedSizeVec = ResponseSgList->NumVec - 1;
  768. }
  769. //
  770. // The first buffer is supposed to carry a (fully populated)
  771. // VIRTIO_FS_FUSE_RESPONSE structure.
  772. //
  773. if (ResponseSgList->IoVec[0].Size != sizeof *CommonResp) {
  774. return EFI_INVALID_PARAMETER;
  775. }
  776. if (ResponseSgList->IoVec[0].Transferred != ResponseSgList->IoVec[0].Size) {
  777. return EFI_PROTOCOL_ERROR;
  778. }
  779. //
  780. // FUSE must report the same number of bytes, written by the Virtio
  781. // Filesystem device, as the virtio transport does.
  782. //
  783. CommonResp = ResponseSgList->IoVec[0].Buffer;
  784. TotalTransferred = 0;
  785. for (Idx = 0; Idx < ResponseSgList->NumVec; Idx++) {
  786. //
  787. // Integer overflow and truncation are not possible, based on
  788. // VirtioFsSgListsValidate() and VirtioFsSgListsSubmit().
  789. //
  790. TotalTransferred += (UINT32)ResponseSgList->IoVec[Idx].Transferred;
  791. }
  792. if (CommonResp->Len != TotalTransferred) {
  793. return EFI_PROTOCOL_ERROR;
  794. }
  795. //
  796. // Enforce that FUSE match our request ID in the response.
  797. //
  798. if (CommonResp->Unique != RequestId) {
  799. return EFI_PROTOCOL_ERROR;
  800. }
  801. //
  802. // If there is an explicit error report, skip checking the transfer
  803. // counts for the rest of the fixed size buffers.
  804. //
  805. if (CommonResp->Error != 0) {
  806. return EFI_DEVICE_ERROR;
  807. }
  808. //
  809. // There was no error reported, so we require that the Virtio Filesystem
  810. // device populate all fixed size buffers. We checked this for the very first
  811. // buffer above; let's check the rest (if any).
  812. //
  813. ASSERT (NumFixedSizeVec >= 1);
  814. for (Idx = 1; Idx < NumFixedSizeVec; Idx++) {
  815. if (ResponseSgList->IoVec[Idx].Transferred !=
  816. ResponseSgList->IoVec[Idx].Size)
  817. {
  818. return EFI_PROTOCOL_ERROR;
  819. }
  820. }
  821. //
  822. // If the last buffer is considered variable size, report its filled size.
  823. //
  824. if (TailBufferFill != NULL) {
  825. *TailBufferFill = ResponseSgList->IoVec[NumFixedSizeVec].Transferred;
  826. }
  827. return EFI_SUCCESS;
  828. }
  829. /**
  830. An ad-hoc function for mapping FUSE (well, Linux) "errno" values to
  831. EFI_STATUS.
  832. @param[in] Errno The "VIRTIO_FS_FUSE_RESPONSE.Error" value, returned by the
  833. Virtio Filesystem device. The value is expected to be
  834. negative.
  835. @return An EFI_STATUS error code that's deemed a passable
  836. mapping for the Errno value.
  837. @retval EFI_DEVICE_ERROR Fallback EFI_STATUS code for unrecognized Errno
  838. values.
  839. **/
  840. EFI_STATUS
  841. VirtioFsErrnoToEfiStatus (
  842. IN INT32 Errno
  843. )
  844. {
  845. switch (Errno) {
  846. case -1:// EPERM Operation not permitted
  847. return EFI_SECURITY_VIOLATION;
  848. case -2: // ENOENT No such file or directory
  849. case -3: // ESRCH No such process
  850. case -6: // ENXIO No such device or address
  851. case -10: // ECHILD No child processes
  852. case -19: // ENODEV No such device
  853. case -49: // EUNATCH Protocol driver not attached
  854. case -65: // ENOPKG Package not installed
  855. case -79: // ELIBACC Can not access a needed shared library
  856. case -126: // ENOKEY Required key not available
  857. return EFI_NOT_FOUND;
  858. case -4: // EINTR Interrupted system call
  859. case -11: // EAGAIN, EWOULDBLOCK Resource temporarily unavailable
  860. case -16: // EBUSY Device or resource busy
  861. case -26: // ETXTBSY Text file busy
  862. case -35: // EDEADLK, EDEADLOCK Resource deadlock avoided
  863. case -39: // ENOTEMPTY Directory not empty
  864. case -42: // ENOMSG No message of desired type
  865. case -61: // ENODATA No data available
  866. case -85: // ERESTART Interrupted system call should be restarted
  867. return EFI_NOT_READY;
  868. case -5: // EIO Input/output error
  869. case -45: // EL2NSYNC Level 2 not synchronized
  870. case -46: // EL3HLT Level 3 halted
  871. case -47: // EL3RST Level 3 reset
  872. case -51: // EL2HLT Level 2 halted
  873. case -121: // EREMOTEIO Remote I/O error
  874. case -133: // EHWPOISON Memory page has hardware error
  875. return EFI_DEVICE_ERROR;
  876. case -7: // E2BIG Argument list too long
  877. case -36: // ENAMETOOLONG File name too long
  878. case -90: // EMSGSIZE Message too long
  879. return EFI_BAD_BUFFER_SIZE;
  880. case -8: // ENOEXEC Exec format error
  881. case -15: // ENOTBLK Block device required
  882. case -18: // EXDEV Invalid cross-device link
  883. case -20: // ENOTDIR Not a directory
  884. case -21: // EISDIR Is a directory
  885. case -25: // ENOTTY Inappropriate ioctl for device
  886. case -27: // EFBIG File too large
  887. case -29: // ESPIPE Illegal seek
  888. case -38: // ENOSYS Function not implemented
  889. case -59: // EBFONT Bad font file format
  890. case -60: // ENOSTR Device not a stream
  891. case -83: // ELIBEXEC Cannot exec a shared library directly
  892. case -88: // ENOTSOCK Socket operation on non-socket
  893. case -91: // EPROTOTYPE Protocol wrong type for socket
  894. case -92: // ENOPROTOOPT Protocol not available
  895. case -93: // EPROTONOSUPPORT Protocol not supported
  896. case -94: // ESOCKTNOSUPPORT Socket type not supported
  897. case -95: // ENOTSUP, EOPNOTSUPP Operation not supported
  898. case -96: // EPFNOSUPPORT Protocol family not supported
  899. case -97: // EAFNOSUPPORT Address family not supported by protocol
  900. case -99: // EADDRNOTAVAIL Cannot assign requested address
  901. case -118: // ENOTNAM Not a XENIX named type file
  902. case -120: // EISNAM Is a named type file
  903. case -124: // EMEDIUMTYPE Wrong medium type
  904. return EFI_UNSUPPORTED;
  905. case -9: // EBADF Bad file descriptor
  906. case -14: // EFAULT Bad address
  907. case -44: // ECHRNG Channel number out of range
  908. case -48: // ELNRNG Link number out of range
  909. case -53: // EBADR Invalid request descriptor
  910. case -56: // EBADRQC Invalid request code
  911. case -57: // EBADSLT Invalid slot
  912. case -76: // ENOTUNIQ Name not unique on network
  913. case -84: // EILSEQ Invalid or incomplete multibyte or wide character
  914. return EFI_NO_MAPPING;
  915. case -12: // ENOMEM Cannot allocate memory
  916. case -23: // ENFILE Too many open files in system
  917. case -24: // EMFILE Too many open files
  918. case -31: // EMLINK Too many links
  919. case -37: // ENOLCK No locks available
  920. case -40: // ELOOP Too many levels of symbolic links
  921. case -50: // ENOCSI No CSI structure available
  922. case -55: // ENOANO No anode
  923. case -63: // ENOSR Out of streams resources
  924. case -82: // ELIBMAX Attempting to link in too many shared libraries
  925. case -87: // EUSERS Too many users
  926. case -105: // ENOBUFS No buffer space available
  927. case -109: // ETOOMANYREFS Too many references: cannot splice
  928. case -119: // ENAVAIL No XENIX semaphores available
  929. case -122: // EDQUOT Disk quota exceeded
  930. return EFI_OUT_OF_RESOURCES;
  931. case -13:// EACCES Permission denied
  932. return EFI_ACCESS_DENIED;
  933. case -17: // EEXIST File exists
  934. case -98: // EADDRINUSE Address already in use
  935. case -106: // EISCONN Transport endpoint is already connected
  936. case -114: // EALREADY Operation already in progress
  937. case -115: // EINPROGRESS Operation now in progress
  938. return EFI_ALREADY_STARTED;
  939. case -22: // EINVAL Invalid argument
  940. case -33: // EDOM Numerical argument out of domain
  941. return EFI_INVALID_PARAMETER;
  942. case -28: // ENOSPC No space left on device
  943. case -54: // EXFULL Exchange full
  944. return EFI_VOLUME_FULL;
  945. case -30:// EROFS Read-only file system
  946. return EFI_WRITE_PROTECTED;
  947. case -32: // EPIPE Broken pipe
  948. case -43: // EIDRM Identifier removed
  949. case -67: // ENOLINK Link has been severed
  950. case -68: // EADV Advertise error
  951. case -69: // ESRMNT Srmount error
  952. case -70: // ECOMM Communication error on send
  953. case -73: // EDOTDOT RFS specific error
  954. case -78: // EREMCHG Remote address changed
  955. case -86: // ESTRPIPE Streams pipe error
  956. case -102: // ENETRESET Network dropped connection on reset
  957. case -103: // ECONNABORTED Software caused connection abort
  958. case -104: // ECONNRESET Connection reset by peer
  959. case -116: // ESTALE Stale file handle
  960. case -125: // ECANCELED Operation canceled
  961. case -128: // EKEYREVOKED Key has been revoked
  962. case -129: // EKEYREJECTED Key was rejected by service
  963. case -130: // EOWNERDEAD Owner died
  964. case -131: // ENOTRECOVERABLE State not recoverable
  965. return EFI_ABORTED;
  966. case -34: // ERANGE Numerical result out of range
  967. case -75: // EOVERFLOW Value too large for defined data type
  968. return EFI_BUFFER_TOO_SMALL;
  969. case -52: // EBADE Invalid exchange
  970. case -108: // ESHUTDOWN Cannot send after transport endpoint shutdown
  971. case -111: // ECONNREFUSED Connection refused
  972. return EFI_END_OF_FILE;
  973. case -62: // ETIME Timer expired
  974. case -110: // ETIMEDOUT Connection timed out
  975. case -127: // EKEYEXPIRED Key has expired
  976. return EFI_TIMEOUT;
  977. case -64: // ENONET Machine is not on the network
  978. case -66: // EREMOTE Object is remote
  979. case -72: // EMULTIHOP Multihop attempted
  980. case -100: // ENETDOWN Network is down
  981. case -101: // ENETUNREACH Network is unreachable
  982. case -112: // EHOSTDOWN Host is down
  983. case -113: // EHOSTUNREACH No route to host
  984. case -123: // ENOMEDIUM No medium found
  985. case -132: // ERFKILL Operation not possible due to RF-kill
  986. return EFI_NO_MEDIA;
  987. case -71:// EPROTO Protocol error
  988. return EFI_PROTOCOL_ERROR;
  989. case -74: // EBADMSG Bad message
  990. case -77: // EBADFD File descriptor in bad state
  991. case -80: // ELIBBAD Accessing a corrupted shared library
  992. case -81: // ELIBSCN .lib section in a.out corrupted
  993. case -117: // EUCLEAN Structure needs cleaning
  994. return EFI_VOLUME_CORRUPTED;
  995. case -89: // EDESTADDRREQ Destination address required
  996. case -107: // ENOTCONN Transport endpoint is not connected
  997. return EFI_NOT_STARTED;
  998. default:
  999. break;
  1000. }
  1001. return EFI_DEVICE_ERROR;
  1002. }
  1003. //
  1004. // Parser states for canonicalizing a POSIX pathname.
  1005. //
  1006. typedef enum {
  1007. ParserInit, // just starting
  1008. ParserEnd, // finished
  1009. ParserSlash, // slash(es) seen
  1010. ParserDot, // one dot seen since last slash
  1011. ParserDotDot, // two dots seen since last slash
  1012. ParserNormal, // a different sequence seen
  1013. } PARSER_STATE;
  1014. /**
  1015. Strip the trailing slash from the parser's output buffer, unless the trailing
  1016. slash stands for the root directory.
  1017. @param[in] Buffer The parser's output buffer. Only used for
  1018. sanity-checking.
  1019. @param[in,out] Position On entry, points at the next character to produce
  1020. (i.e., right past the end of the output written by
  1021. the parser thus far). The last character in the
  1022. parser's output buffer is a slash. On return, the
  1023. slash is stripped, by decrementing Position by one.
  1024. If this action would remove the slash character
  1025. standing for the root directory, then the function
  1026. has no effect.
  1027. **/
  1028. STATIC
  1029. VOID
  1030. ParserStripSlash (
  1031. IN CHAR8 *Buffer,
  1032. IN OUT UINTN *Position
  1033. )
  1034. {
  1035. ASSERT (*Position >= 1);
  1036. ASSERT (Buffer[*Position - 1] == '/');
  1037. if (*Position == 1) {
  1038. return;
  1039. }
  1040. (*Position)--;
  1041. }
  1042. /**
  1043. Produce one character in the parser's output buffer.
  1044. @param[out] Buffer The parser's output buffer. On return, Char8 will
  1045. have been written.
  1046. @param[in,out] Position On entry, points at the next character to produce
  1047. (i.e., right past the end of the output written by
  1048. the parser thus far). On return, Position is
  1049. incremented by one.
  1050. @param[in] Size Total allocated size of the parser's output buffer.
  1051. Used for sanity-checking.
  1052. @param[in] Char8 The character to place in the output buffer.
  1053. **/
  1054. STATIC
  1055. VOID
  1056. ParserCopy (
  1057. OUT CHAR8 *Buffer,
  1058. IN OUT UINTN *Position,
  1059. IN UINTN Size,
  1060. IN CHAR8 Char8
  1061. )
  1062. {
  1063. ASSERT (*Position < Size);
  1064. Buffer[(*Position)++] = Char8;
  1065. }
  1066. /**
  1067. Rewind the last single-dot in the parser's output buffer.
  1068. @param[in] Buffer The parser's output buffer. Only used for
  1069. sanity-checking.
  1070. @param[in,out] Position On entry, points at the next character to produce
  1071. (i.e., right past the end of the output written by
  1072. the parser thus far); the parser's output buffer
  1073. ends with the characters ('/', '.'). On return, the
  1074. dot is rewound by decrementing Position by one; a
  1075. slash character will reside at the new end of the
  1076. parser's output buffer.
  1077. **/
  1078. STATIC
  1079. VOID
  1080. ParserRewindDot (
  1081. IN CHAR8 *Buffer,
  1082. IN OUT UINTN *Position
  1083. )
  1084. {
  1085. ASSERT (*Position >= 2);
  1086. ASSERT (Buffer[*Position - 1] == '.');
  1087. ASSERT (Buffer[*Position - 2] == '/');
  1088. (*Position)--;
  1089. }
  1090. /**
  1091. Rewind the last dot-dot in the parser's output buffer.
  1092. @param[in] Buffer The parser's output buffer. Only used for
  1093. sanity-checking.
  1094. @param[in,out] Position On entry, points at the next character to produce
  1095. (i.e., right past the end of the output written by
  1096. the parser thus far); the parser's output buffer
  1097. ends with the characters ('/', '.', '.'). On return,
  1098. the ('.', '.') pair is rewound unconditionally, by
  1099. decrementing Position by two; a slash character
  1100. resides at the new end of the parser's output
  1101. buffer.
  1102. If this slash character stands for the root
  1103. directory, then RootEscape is set to TRUE.
  1104. Otherwise (i.e., if this slash character is not the
  1105. one standing for the root directory), then the slash
  1106. character, and the pathname component preceding it,
  1107. are removed by decrementing Position further. In
  1108. this case, the slash character preceding the removed
  1109. pathname component will reside at the new end of the
  1110. parser's output buffer.
  1111. @param[out] RootEscape Set to TRUE on output if the dot-dot component tries
  1112. to escape the root directory, as described above.
  1113. Otherwise, RootEscape is not modified.
  1114. **/
  1115. STATIC
  1116. VOID
  1117. ParserRewindDotDot (
  1118. IN CHAR8 *Buffer,
  1119. IN OUT UINTN *Position,
  1120. OUT BOOLEAN *RootEscape
  1121. )
  1122. {
  1123. ASSERT (*Position >= 3);
  1124. ASSERT (Buffer[*Position - 1] == '.');
  1125. ASSERT (Buffer[*Position - 2] == '.');
  1126. ASSERT (Buffer[*Position - 3] == '/');
  1127. (*Position) -= 2;
  1128. if (*Position == 1) {
  1129. //
  1130. // Root directory slash reached; don't try to climb higher.
  1131. //
  1132. *RootEscape = TRUE;
  1133. return;
  1134. }
  1135. //
  1136. // Skip slash.
  1137. //
  1138. (*Position)--;
  1139. //
  1140. // Scan until next slash to the left.
  1141. //
  1142. do {
  1143. ASSERT (*Position > 0);
  1144. (*Position)--;
  1145. } while (Buffer[*Position] != '/');
  1146. (*Position)++;
  1147. }
  1148. /**
  1149. Append the UEFI-style RhsPath16 to the POSIX-style, canonical format
  1150. LhsPath8. Output the POSIX-style, canonical format result in ResultPath, as a
  1151. dynamically allocated string.
  1152. Canonicalization (aka sanitization) establishes the following properties:
  1153. - ResultPath is absolute (starts with "/"),
  1154. - dot (.) and dot-dot (..) components are resolved/eliminated in ResultPath,
  1155. with the usual semantics,
  1156. - ResultPath uses forward slashes,
  1157. - sequences of slashes are squashed in ResultPath,
  1158. - the printable ASCII character set covers ResultPath,
  1159. - CHAR8 encoding is used in ResultPath,
  1160. - no trailing slash present in ResultPath except for the standalone root
  1161. directory,
  1162. - the length of ResultPath is at most VIRTIO_FS_MAX_PATHNAME_LENGTH.
  1163. Any dot-dot in RhsPath16 that would remove the root directory is dropped, and
  1164. reported through RootEscape, without failing the function call.
  1165. @param[in] LhsPath8 Identifies the base directory. The caller is
  1166. responsible for ensuring that LhsPath8 conform to
  1167. the above canonical pathname format on entry.
  1168. @param[in] RhsPath16 Identifies the desired file with a UEFI-style CHAR16
  1169. pathname. If RhsPath16 starts with a backslash, then
  1170. RhsPath16 is considered absolute, and LhsPath8 is
  1171. ignored; RhsPath16 is sanitized in isolation, for
  1172. producing ResultPath8. Otherwise (i.e., if RhsPath16
  1173. is relative), RhsPath16 is transliterated to CHAR8,
  1174. and naively appended to LhsPath8. The resultant
  1175. fused pathname is then sanitized, to produce
  1176. ResultPath8.
  1177. @param[out] ResultPath8 The POSIX-style, canonical format pathname that
  1178. leads to the file desired by the caller. After use,
  1179. the caller is responsible for freeing ResultPath8.
  1180. @param[out] RootEscape Set to TRUE if at least one dot-dot component in
  1181. RhsPath16 attempted to escape the root directory;
  1182. set to FALSE otherwise.
  1183. @retval EFI_SUCCESS ResultPath8 has been produced. RootEscape has
  1184. been output.
  1185. @retval EFI_INVALID_PARAMETER RhsPath16 is zero-length.
  1186. @retval EFI_INVALID_PARAMETER RhsPath16 failed the
  1187. VIRTIO_FS_MAX_PATHNAME_LENGTH check.
  1188. @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
  1189. @retval EFI_OUT_OF_RESOURCES ResultPath8 would have failed the
  1190. VIRTIO_FS_MAX_PATHNAME_LENGTH check.
  1191. @retval EFI_UNSUPPORTED RhsPath16 contains a character that either
  1192. falls outside of the printable ASCII set, or
  1193. is a forward slash.
  1194. **/
  1195. EFI_STATUS
  1196. VirtioFsAppendPath (
  1197. IN CHAR8 *LhsPath8,
  1198. IN CHAR16 *RhsPath16,
  1199. OUT CHAR8 **ResultPath8,
  1200. OUT BOOLEAN *RootEscape
  1201. )
  1202. {
  1203. UINTN RhsLen;
  1204. CHAR8 *RhsPath8;
  1205. UINTN Idx;
  1206. EFI_STATUS Status;
  1207. UINTN SizeToSanitize;
  1208. CHAR8 *BufferToSanitize;
  1209. CHAR8 *SanitizedBuffer;
  1210. PARSER_STATE State;
  1211. UINTN SanitizedPosition;
  1212. //
  1213. // Appending an empty pathname is not allowed.
  1214. //
  1215. RhsLen = StrLen (RhsPath16);
  1216. if (RhsLen == 0) {
  1217. return EFI_INVALID_PARAMETER;
  1218. }
  1219. //
  1220. // Enforce length restriction on RhsPath16.
  1221. //
  1222. if (RhsLen > VIRTIO_FS_MAX_PATHNAME_LENGTH) {
  1223. return EFI_INVALID_PARAMETER;
  1224. }
  1225. //
  1226. // Transliterate RhsPath16 to RhsPath8 by:
  1227. // - rejecting RhsPath16 if a character outside of printable ASCII is seen,
  1228. // - rejecting RhsPath16 if a forward slash is seen,
  1229. // - replacing backslashes with forward slashes,
  1230. // - casting the characters from CHAR16 to CHAR8.
  1231. //
  1232. RhsPath8 = AllocatePool (RhsLen + 1);
  1233. if (RhsPath8 == NULL) {
  1234. return EFI_OUT_OF_RESOURCES;
  1235. }
  1236. for (Idx = 0; RhsPath16[Idx] != L'\0'; Idx++) {
  1237. if ((RhsPath16[Idx] < 0x20) || (RhsPath16[Idx] > 0x7E) ||
  1238. (RhsPath16[Idx] == L'/'))
  1239. {
  1240. Status = EFI_UNSUPPORTED;
  1241. goto FreeRhsPath8;
  1242. }
  1243. RhsPath8[Idx] = (CHAR8)((RhsPath16[Idx] == L'\\') ? L'/' : RhsPath16[Idx]);
  1244. }
  1245. RhsPath8[Idx++] = '\0';
  1246. //
  1247. // Now prepare the input for the canonicalization (squashing of sequences of
  1248. // forward slashes, and eliminating . (dot) and .. (dot-dot) pathname
  1249. // components).
  1250. //
  1251. // The sanitized path can never be longer than the naive concatenation of the
  1252. // left hand side and right hand side paths, so we'll use the catenated size
  1253. // for allocating the sanitized output too.
  1254. //
  1255. if (RhsPath8[0] == '/') {
  1256. //
  1257. // If the right hand side path is absolute, then it is not appended to the
  1258. // left hand side path -- it *replaces* the left hand side path.
  1259. //
  1260. SizeToSanitize = RhsLen + 1;
  1261. BufferToSanitize = RhsPath8;
  1262. } else {
  1263. //
  1264. // If the right hand side path is relative, then it is appended (naively)
  1265. // to the left hand side.
  1266. //
  1267. UINTN LhsLen;
  1268. LhsLen = AsciiStrLen (LhsPath8);
  1269. SizeToSanitize = LhsLen + 1 + RhsLen + 1;
  1270. BufferToSanitize = AllocatePool (SizeToSanitize);
  1271. if (BufferToSanitize == NULL) {
  1272. Status = EFI_OUT_OF_RESOURCES;
  1273. goto FreeRhsPath8;
  1274. }
  1275. CopyMem (BufferToSanitize, LhsPath8, LhsLen);
  1276. BufferToSanitize[LhsLen] = '/';
  1277. CopyMem (BufferToSanitize + LhsLen + 1, RhsPath8, RhsLen + 1);
  1278. }
  1279. //
  1280. // Allocate the output buffer.
  1281. //
  1282. SanitizedBuffer = AllocatePool (SizeToSanitize);
  1283. if (SanitizedBuffer == NULL) {
  1284. Status = EFI_OUT_OF_RESOURCES;
  1285. goto FreeBufferToSanitize;
  1286. }
  1287. //
  1288. // State machine for parsing the input and producing the canonical output
  1289. // follows.
  1290. //
  1291. *RootEscape = FALSE;
  1292. Idx = 0;
  1293. State = ParserInit;
  1294. SanitizedPosition = 0;
  1295. do {
  1296. CHAR8 Chr8;
  1297. ASSERT (Idx < SizeToSanitize);
  1298. Chr8 = BufferToSanitize[Idx++];
  1299. switch (State) {
  1300. case ParserInit: // just starting
  1301. ASSERT (Chr8 == '/');
  1302. ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
  1303. State = ParserSlash;
  1304. break;
  1305. case ParserSlash: // slash(es) seen
  1306. switch (Chr8) {
  1307. case '\0':
  1308. ParserStripSlash (SanitizedBuffer, &SanitizedPosition);
  1309. ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
  1310. State = ParserEnd;
  1311. break;
  1312. case '/':
  1313. //
  1314. // skip & stay in same state
  1315. //
  1316. break;
  1317. case '.':
  1318. ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
  1319. State = ParserDot;
  1320. break;
  1321. default:
  1322. ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
  1323. State = ParserNormal;
  1324. break;
  1325. }
  1326. break;
  1327. case ParserDot: // one dot seen since last slash
  1328. switch (Chr8) {
  1329. case '\0':
  1330. ParserRewindDot (SanitizedBuffer, &SanitizedPosition);
  1331. ParserStripSlash (SanitizedBuffer, &SanitizedPosition);
  1332. ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
  1333. State = ParserEnd;
  1334. break;
  1335. case '/':
  1336. ParserRewindDot (SanitizedBuffer, &SanitizedPosition);
  1337. State = ParserSlash;
  1338. break;
  1339. case '.':
  1340. ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
  1341. State = ParserDotDot;
  1342. break;
  1343. default:
  1344. ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
  1345. State = ParserNormal;
  1346. break;
  1347. }
  1348. break;
  1349. case ParserDotDot: // two dots seen since last slash
  1350. switch (Chr8) {
  1351. case '\0':
  1352. ParserRewindDotDot (SanitizedBuffer, &SanitizedPosition, RootEscape);
  1353. ParserStripSlash (SanitizedBuffer, &SanitizedPosition);
  1354. ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
  1355. State = ParserEnd;
  1356. break;
  1357. case '/':
  1358. ParserRewindDotDot (SanitizedBuffer, &SanitizedPosition, RootEscape);
  1359. State = ParserSlash;
  1360. break;
  1361. case '.':
  1362. //
  1363. // fall through
  1364. //
  1365. default:
  1366. ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
  1367. State = ParserNormal;
  1368. break;
  1369. }
  1370. break;
  1371. case ParserNormal: // a different sequence seen
  1372. switch (Chr8) {
  1373. case '\0':
  1374. ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
  1375. State = ParserEnd;
  1376. break;
  1377. case '/':
  1378. ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
  1379. State = ParserSlash;
  1380. break;
  1381. case '.':
  1382. //
  1383. // fall through
  1384. //
  1385. default:
  1386. //
  1387. // copy and stay in same state
  1388. //
  1389. ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
  1390. break;
  1391. }
  1392. break;
  1393. default:
  1394. ASSERT (FALSE);
  1395. break;
  1396. }
  1397. } while (State != ParserEnd);
  1398. //
  1399. // Ensure length invariant on ResultPath8.
  1400. //
  1401. ASSERT (SanitizedPosition >= 2);
  1402. if (SanitizedPosition - 1 > VIRTIO_FS_MAX_PATHNAME_LENGTH) {
  1403. Status = EFI_OUT_OF_RESOURCES;
  1404. goto FreeSanitizedBuffer;
  1405. }
  1406. *ResultPath8 = SanitizedBuffer;
  1407. SanitizedBuffer = NULL;
  1408. Status = EFI_SUCCESS;
  1409. //
  1410. // Fall through.
  1411. //
  1412. FreeSanitizedBuffer:
  1413. if (SanitizedBuffer != NULL) {
  1414. FreePool (SanitizedBuffer);
  1415. }
  1416. FreeBufferToSanitize:
  1417. if (RhsPath8[0] != '/') {
  1418. FreePool (BufferToSanitize);
  1419. }
  1420. FreeRhsPath8:
  1421. FreePool (RhsPath8);
  1422. return Status;
  1423. }
  1424. /**
  1425. For a given canonical pathname (as defined at VirtioFsAppendPath()), look up
  1426. the NodeId of the most specific parent directory, plus output a pointer to
  1427. the last pathname component (which is therefore a direct child of said parent
  1428. directory).
  1429. The function may only be called after VirtioFsFuseInitSession() returns
  1430. successfully and before VirtioFsUninit() is called.
  1431. @param[in,out] VirtioFs The Virtio Filesystem device to send FUSE_LOOKUP
  1432. and FUSE_FORGET requests to. On output, the FUSE
  1433. request counter "VirtioFs->RequestId" will have
  1434. been incremented several times.
  1435. @param[in,out] Path The canonical pathname (as defined in the
  1436. description of VirtioFsAppendPath()) to split.
  1437. Path is modified in-place temporarily; however, on
  1438. return (successful or otherwise), Path reassumes
  1439. its original contents.
  1440. @param[out] DirNodeId The NodeId of the most specific parent directory
  1441. identified by Path. The caller is responsible for
  1442. sending a FUSE_FORGET request to the Virtio
  1443. Filesystem device for DirNodeId -- unless
  1444. DirNodeId equals VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID
  1445. --, when DirNodeId's use ends.
  1446. @param[out] LastComponent A pointer into Path, pointing at the start of the
  1447. last pathname component.
  1448. @retval EFI_SUCCESS Splitting successful.
  1449. @retval EFI_INVALID_PARAMETER Path is "/".
  1450. @retval EFI_ACCESS_DENIED One of the components on Path before the last
  1451. is not a directory.
  1452. @return Error codes propagated from
  1453. VirtioFsFuseLookup() and
  1454. VirtioFsFuseAttrToEfiFileInfo().
  1455. **/
  1456. EFI_STATUS
  1457. VirtioFsLookupMostSpecificParentDir (
  1458. IN OUT VIRTIO_FS *VirtioFs,
  1459. IN OUT CHAR8 *Path,
  1460. OUT UINT64 *DirNodeId,
  1461. OUT CHAR8 **LastComponent
  1462. )
  1463. {
  1464. UINT64 ParentDirNodeId;
  1465. CHAR8 *Slash;
  1466. EFI_STATUS Status;
  1467. UINT64 NextDirNodeId;
  1468. if (AsciiStrCmp (Path, "/") == 0) {
  1469. return EFI_INVALID_PARAMETER;
  1470. }
  1471. ParentDirNodeId = VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID;
  1472. Slash = Path;
  1473. for ( ; ;) {
  1474. CHAR8 *NextSlash;
  1475. VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE FuseAttr;
  1476. EFI_FILE_INFO FileInfo;
  1477. //
  1478. // Find the slash (if any) that terminates the next pathname component.
  1479. //
  1480. NextSlash = AsciiStrStr (Slash + 1, "/");
  1481. if (NextSlash == NULL) {
  1482. break;
  1483. }
  1484. //
  1485. // Temporarily replace the found slash character with a NUL in-place, for
  1486. // easy construction of the single-component filename that we need to look
  1487. // up.
  1488. //
  1489. *NextSlash = '\0';
  1490. Status = VirtioFsFuseLookup (
  1491. VirtioFs,
  1492. ParentDirNodeId,
  1493. Slash + 1,
  1494. &NextDirNodeId,
  1495. &FuseAttr
  1496. );
  1497. *NextSlash = '/';
  1498. //
  1499. // We're done with the directory inode that was the basis for the lookup.
  1500. //
  1501. if (ParentDirNodeId != VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID) {
  1502. VirtioFsFuseForget (VirtioFs, ParentDirNodeId);
  1503. }
  1504. //
  1505. // If we couldn't look up the next *non-final* pathname component, bail.
  1506. //
  1507. if (EFI_ERROR (Status)) {
  1508. return Status;
  1509. }
  1510. //
  1511. // Lookup successful; now check if the next (non-final) component is a
  1512. // directory. If not, bail.
  1513. //
  1514. Status = VirtioFsFuseAttrToEfiFileInfo (&FuseAttr, &FileInfo);
  1515. if (EFI_ERROR (Status)) {
  1516. goto ForgetNextDirNodeId;
  1517. }
  1518. if ((FileInfo.Attribute & EFI_FILE_DIRECTORY) == 0) {
  1519. Status = EFI_ACCESS_DENIED;
  1520. goto ForgetNextDirNodeId;
  1521. }
  1522. //
  1523. // Advance.
  1524. //
  1525. ParentDirNodeId = NextDirNodeId;
  1526. Slash = NextSlash;
  1527. }
  1528. //
  1529. // ParentDirNodeId corresponds to the last containing directory. The
  1530. // remaining single-component filename represents a direct child under that
  1531. // directory. Said filename starts at (Slash + 1).
  1532. //
  1533. *DirNodeId = ParentDirNodeId;
  1534. *LastComponent = Slash + 1;
  1535. return EFI_SUCCESS;
  1536. ForgetNextDirNodeId:
  1537. VirtioFsFuseForget (VirtioFs, NextDirNodeId);
  1538. return Status;
  1539. }
  1540. /**
  1541. Format the last component of a canonical pathname into a caller-provided
  1542. CHAR16 array.
  1543. @param[in] Path The canonical pathname (as defined in the
  1544. description of VirtioFsAppendPath()) to format
  1545. the last component of.
  1546. @param[out] Basename If BasenameSize is zero on input, Basename may
  1547. be NULL. Otherwise, Basename is allocated by the
  1548. caller. On successful return, Basename contains
  1549. the last component of Path, formatted as a
  1550. NUL-terminated CHAR16 string. When Path is "/"
  1551. on input, Basename is L"" on output.
  1552. @param[in,out] BasenameSize On input, the number of bytes the caller
  1553. provides in Basename. On output, regardless of
  1554. return value, the number of bytes required for
  1555. formatting Basename, including the terminating
  1556. L'\0'.
  1557. @retval EFI_SUCCESS Basename has been filled in.
  1558. @retval EFI_BUFFER_TOO_SMALL BasenameSize was too small on input; Basename
  1559. has not been modified.
  1560. **/
  1561. EFI_STATUS
  1562. VirtioFsGetBasename (
  1563. IN CHAR8 *Path,
  1564. OUT CHAR16 *Basename OPTIONAL,
  1565. IN OUT UINTN *BasenameSize
  1566. )
  1567. {
  1568. UINTN AllocSize;
  1569. UINTN LastComponent;
  1570. UINTN Idx;
  1571. UINTN PathSize;
  1572. AllocSize = *BasenameSize;
  1573. LastComponent = MAX_UINTN;
  1574. for (Idx = 0; Path[Idx] != '\0'; Idx++) {
  1575. if (Path[Idx] == '/') {
  1576. LastComponent = Idx;
  1577. }
  1578. }
  1579. PathSize = Idx + 1;
  1580. ASSERT (LastComponent < MAX_UINTN);
  1581. LastComponent++;
  1582. *BasenameSize = (PathSize - LastComponent) * sizeof Basename[0];
  1583. if (*BasenameSize > AllocSize) {
  1584. return EFI_BUFFER_TOO_SMALL;
  1585. }
  1586. for (Idx = LastComponent; Idx < PathSize; Idx++) {
  1587. Basename[Idx - LastComponent] = Path[Idx];
  1588. }
  1589. return EFI_SUCCESS;
  1590. }
  1591. /**
  1592. Format the destination of a rename/move operation as a dynamically allocated
  1593. canonical pathname.
  1594. Any dot-dot in RhsPath16 that would remove the root directory is dropped, and
  1595. reported through RootEscape, without failing the function call.
  1596. @param[in] LhsPath8 The source pathname operand of the rename/move
  1597. operation, expressed as a canonical pathname (as
  1598. defined in the description of VirtioFsAppendPath()).
  1599. The root directory "/" cannot be renamed/moved, and
  1600. will be rejected.
  1601. @param[in] RhsPath16 The destination pathname operand expressed as a
  1602. UEFI-style CHAR16 pathname.
  1603. If RhsPath16 starts with a backslash, then RhsPath16
  1604. is considered absolute. Otherwise, RhsPath16 is
  1605. interpreted relative to the most specific parent
  1606. directory found in LhsPath8.
  1607. Independently, if RhsPath16 ends with a backslash
  1608. (i.e., RhsPath16 is given in the "move into
  1609. directory" convenience form), then RhsPath16 is
  1610. interpreted with the basename of LhsPath8 appended.
  1611. Otherwise, the last pathname component of RhsPath16
  1612. is taken as the last pathname component of the
  1613. rename/move destination.
  1614. An empty RhsPath16 is rejected.
  1615. @param[out] ResultPath8 The POSIX-style, canonical format pathname that
  1616. leads to the renamed/moved file. After use, the
  1617. caller is responsible for freeing ResultPath8.
  1618. @param[out] RootEscape Set to TRUE if at least one dot-dot component in
  1619. RhsPath16 attempted to escape the root directory;
  1620. set to FALSE otherwise.
  1621. @retval EFI_SUCCESS ResultPath8 has been produced. RootEscape has
  1622. been output.
  1623. @retval EFI_INVALID_PARAMETER LhsPath8 is "/".
  1624. @retval EFI_INVALID_PARAMETER RhsPath16 is zero-length.
  1625. @retval EFI_INVALID_PARAMETER RhsPath16 failed the
  1626. VIRTIO_FS_MAX_PATHNAME_LENGTH check.
  1627. @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
  1628. @retval EFI_OUT_OF_RESOURCES ResultPath8 would have failed the
  1629. VIRTIO_FS_MAX_PATHNAME_LENGTH check.
  1630. @retval EFI_UNSUPPORTED RhsPath16 contains a character that either
  1631. falls outside of the printable ASCII set, or
  1632. is a forward slash.
  1633. **/
  1634. EFI_STATUS
  1635. VirtioFsComposeRenameDestination (
  1636. IN CHAR8 *LhsPath8,
  1637. IN CHAR16 *RhsPath16,
  1638. OUT CHAR8 **ResultPath8,
  1639. OUT BOOLEAN *RootEscape
  1640. )
  1641. {
  1642. //
  1643. // Lengths are expressed as numbers of characters (CHAR8 or CHAR16),
  1644. // excluding terminating NULs. Sizes are expressed as byte counts, including
  1645. // the bytes taken up by terminating NULs.
  1646. //
  1647. UINTN RhsLen;
  1648. UINTN LhsBasename16Size;
  1649. EFI_STATUS Status;
  1650. UINTN LhsBasenameLen;
  1651. UINTN DestSuffix16Size;
  1652. CHAR16 *DestSuffix16;
  1653. CHAR8 *DestPrefix8;
  1654. //
  1655. // An empty destination operand for the rename/move operation is not allowed.
  1656. //
  1657. RhsLen = StrLen (RhsPath16);
  1658. if (RhsLen == 0) {
  1659. return EFI_INVALID_PARAMETER;
  1660. }
  1661. //
  1662. // Enforce length restriction on RhsPath16.
  1663. //
  1664. if (RhsLen > VIRTIO_FS_MAX_PATHNAME_LENGTH) {
  1665. return EFI_INVALID_PARAMETER;
  1666. }
  1667. //
  1668. // Determine the length of the basename of LhsPath8.
  1669. //
  1670. LhsBasename16Size = 0;
  1671. Status = VirtioFsGetBasename (LhsPath8, NULL, &LhsBasename16Size);
  1672. ASSERT (Status == EFI_BUFFER_TOO_SMALL);
  1673. ASSERT (LhsBasename16Size >= sizeof (CHAR16));
  1674. ASSERT (LhsBasename16Size % sizeof (CHAR16) == 0);
  1675. LhsBasenameLen = LhsBasename16Size / sizeof (CHAR16) - 1;
  1676. if (LhsBasenameLen == 0) {
  1677. //
  1678. // The root directory cannot be renamed/moved.
  1679. //
  1680. return EFI_INVALID_PARAMETER;
  1681. }
  1682. //
  1683. // Resolve the "move into directory" convenience form in RhsPath16.
  1684. //
  1685. if (RhsPath16[RhsLen - 1] == L'\\') {
  1686. //
  1687. // Append the basename of LhsPath8 as a CHAR16 string to RhsPath16.
  1688. //
  1689. DestSuffix16Size = RhsLen * sizeof (CHAR16) + LhsBasename16Size;
  1690. DestSuffix16 = AllocatePool (DestSuffix16Size);
  1691. if (DestSuffix16 == NULL) {
  1692. return EFI_OUT_OF_RESOURCES;
  1693. }
  1694. CopyMem (DestSuffix16, RhsPath16, RhsLen * sizeof (CHAR16));
  1695. Status = VirtioFsGetBasename (
  1696. LhsPath8,
  1697. DestSuffix16 + RhsLen,
  1698. &LhsBasename16Size
  1699. );
  1700. ASSERT_EFI_ERROR (Status);
  1701. } else {
  1702. //
  1703. // Just create a copy of RhsPath16.
  1704. //
  1705. DestSuffix16Size = (RhsLen + 1) * sizeof (CHAR16);
  1706. DestSuffix16 = AllocateCopyPool (DestSuffix16Size, RhsPath16);
  1707. if (DestSuffix16 == NULL) {
  1708. return EFI_OUT_OF_RESOURCES;
  1709. }
  1710. }
  1711. //
  1712. // If the destination operand is absolute, it will be interpreted relative to
  1713. // the root directory.
  1714. //
  1715. // Otherwise (i.e., if the destination operand is relative), then create the
  1716. // canonical pathname that the destination operand is interpreted relatively
  1717. // to; that is, the canonical pathname of the most specific parent directory
  1718. // found in LhsPath8.
  1719. //
  1720. if (DestSuffix16[0] == L'\\') {
  1721. DestPrefix8 = AllocateCopyPool (sizeof "/", "/");
  1722. if (DestPrefix8 == NULL) {
  1723. Status = EFI_OUT_OF_RESOURCES;
  1724. goto FreeDestSuffix16;
  1725. }
  1726. } else {
  1727. UINTN LhsLen;
  1728. UINTN DestPrefixLen;
  1729. //
  1730. // Strip the basename of LhsPath8.
  1731. //
  1732. LhsLen = AsciiStrLen (LhsPath8);
  1733. ASSERT (LhsBasenameLen < LhsLen);
  1734. DestPrefixLen = LhsLen - LhsBasenameLen;
  1735. ASSERT (LhsPath8[DestPrefixLen - 1] == '/');
  1736. //
  1737. // If we're not at the root directory, strip the slash too.
  1738. //
  1739. if (DestPrefixLen > 1) {
  1740. DestPrefixLen--;
  1741. }
  1742. DestPrefix8 = AllocatePool (DestPrefixLen + 1);
  1743. if (DestPrefix8 == NULL) {
  1744. Status = EFI_OUT_OF_RESOURCES;
  1745. goto FreeDestSuffix16;
  1746. }
  1747. CopyMem (DestPrefix8, LhsPath8, DestPrefixLen);
  1748. DestPrefix8[DestPrefixLen] = '\0';
  1749. }
  1750. //
  1751. // Now combine DestPrefix8 and DestSuffix16 into the final canonical
  1752. // pathname.
  1753. //
  1754. Status = VirtioFsAppendPath (
  1755. DestPrefix8,
  1756. DestSuffix16,
  1757. ResultPath8,
  1758. RootEscape
  1759. );
  1760. FreePool (DestPrefix8);
  1761. //
  1762. // Fall through.
  1763. //
  1764. FreeDestSuffix16:
  1765. FreePool (DestSuffix16);
  1766. return Status;
  1767. }
  1768. /**
  1769. Convert select fields of a VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE object to
  1770. corresponding fields in EFI_FILE_INFO.
  1771. @param[in] FuseAttr The VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE object to
  1772. convert the relevant fields from.
  1773. @param[out] FileInfo The EFI_FILE_INFO structure to modify. Importantly, the
  1774. FileInfo->Size and FileInfo->FileName fields are not
  1775. overwritten.
  1776. @retval EFI_SUCCESS Conversion successful.
  1777. @retval EFI_UNSUPPORTED The allocated size of the file is inexpressible in
  1778. EFI_FILE_INFO.
  1779. @retval EFI_UNSUPPORTED One of the file access times is inexpressible in
  1780. EFI_FILE_INFO.
  1781. @retval EFI_UNSUPPORTED The file type is inexpressible in EFI_FILE_INFO.
  1782. @retval EFI_UNSUPPORTED The file is a regular file that has multiple names
  1783. on the host side (i.e., its hard link count is
  1784. greater than one).
  1785. **/
  1786. EFI_STATUS
  1787. VirtioFsFuseAttrToEfiFileInfo (
  1788. IN VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE *FuseAttr,
  1789. OUT EFI_FILE_INFO *FileInfo
  1790. )
  1791. {
  1792. UINT64 EpochTime[3];
  1793. EFI_TIME *ConvertedTime[ARRAY_SIZE (EpochTime)];
  1794. UINTN Idx;
  1795. FileInfo->FileSize = FuseAttr->Size;
  1796. //
  1797. // The unit for FuseAttr->Blocks is 512B.
  1798. //
  1799. if (FuseAttr->Blocks >= BIT55) {
  1800. return EFI_UNSUPPORTED;
  1801. }
  1802. FileInfo->PhysicalSize = LShiftU64 (FuseAttr->Blocks, 9);
  1803. //
  1804. // Convert the timestamps. File creation time is not tracked by the Virtio
  1805. // Filesystem device, so set FileInfo->CreateTime from FuseAttr->Mtime as
  1806. // well.
  1807. //
  1808. EpochTime[0] = FuseAttr->Mtime;
  1809. EpochTime[1] = FuseAttr->Atime;
  1810. EpochTime[2] = FuseAttr->Mtime;
  1811. ConvertedTime[0] = &FileInfo->CreateTime;
  1812. ConvertedTime[1] = &FileInfo->LastAccessTime;
  1813. ConvertedTime[2] = &FileInfo->ModificationTime;
  1814. for (Idx = 0; Idx < ARRAY_SIZE (EpochTime); Idx++) {
  1815. //
  1816. // EpochToEfiTime() takes a UINTN for seconds.
  1817. //
  1818. if (EpochTime[Idx] > MAX_UINTN) {
  1819. return EFI_UNSUPPORTED;
  1820. }
  1821. //
  1822. // Set the following fields in the converted time: Year, Month, Day, Hour,
  1823. // Minute, Second, Nanosecond.
  1824. //
  1825. EpochToEfiTime ((UINTN)EpochTime[Idx], ConvertedTime[Idx]);
  1826. //
  1827. // The times are all expressed in UTC. Consequently, they are not affected
  1828. // by daylight saving.
  1829. //
  1830. ConvertedTime[Idx]->TimeZone = 0;
  1831. ConvertedTime[Idx]->Daylight = 0;
  1832. //
  1833. // Clear the padding fields.
  1834. //
  1835. ConvertedTime[Idx]->Pad1 = 0;
  1836. ConvertedTime[Idx]->Pad2 = 0;
  1837. }
  1838. //
  1839. // Set the attributes.
  1840. //
  1841. switch (FuseAttr->Mode & VIRTIO_FS_FUSE_MODE_TYPE_MASK) {
  1842. case VIRTIO_FS_FUSE_MODE_TYPE_DIR:
  1843. FileInfo->Attribute = EFI_FILE_DIRECTORY;
  1844. break;
  1845. case VIRTIO_FS_FUSE_MODE_TYPE_REG:
  1846. FileInfo->Attribute = 0;
  1847. break;
  1848. default:
  1849. //
  1850. // Other file types are not supported.
  1851. //
  1852. return EFI_UNSUPPORTED;
  1853. }
  1854. //
  1855. // Report the regular file or directory as read-only if all classes lack
  1856. // write permission.
  1857. //
  1858. if ((FuseAttr->Mode & (VIRTIO_FS_FUSE_MODE_PERM_WUSR |
  1859. VIRTIO_FS_FUSE_MODE_PERM_WGRP |
  1860. VIRTIO_FS_FUSE_MODE_PERM_WOTH)) == 0)
  1861. {
  1862. FileInfo->Attribute |= EFI_FILE_READ_ONLY;
  1863. }
  1864. //
  1865. // A hard link count greater than 1 is not supported for regular files.
  1866. //
  1867. if (((FileInfo->Attribute & EFI_FILE_DIRECTORY) == 0) && (FuseAttr->Nlink > 1)) {
  1868. return EFI_UNSUPPORTED;
  1869. }
  1870. return EFI_SUCCESS;
  1871. }
  1872. /**
  1873. Convert a VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE filename to an EFI_FILE_INFO
  1874. filename.
  1875. @param[in] FuseDirent The VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE object to
  1876. convert the filename byte array from. The caller is
  1877. responsible for ensuring that FuseDirent->Namelen
  1878. describe valid storage.
  1879. @param[in,out] FileInfo The EFI_FILE_INFO structure to modify. On input, the
  1880. caller is responsible for setting FileInfo->Size
  1881. according to the allocated size. On successful
  1882. return, FileInfo->Size is reduced to reflect the
  1883. filename converted into FileInfo->FileName.
  1884. FileInfo->FileName is set from the filename byte
  1885. array that directly follows the FuseDirent header
  1886. object. Fields other than FileInfo->Size and
  1887. FileInfo->FileName are not modified.
  1888. @retval EFI_SUCCESS Conversion successful.
  1889. @retval EFI_INVALID_PARAMETER VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE_SIZE()
  1890. returns zero for FuseDirent->Namelen.
  1891. @retval EFI_BUFFER_TOO_SMALL On input, FileInfo->Size does not provide
  1892. enough room for converting the filename byte
  1893. array from FuseDirent.
  1894. @retval EFI_UNSUPPORTED The FuseDirent filename byte array contains a
  1895. byte that falls outside of the printable ASCII
  1896. range, or is a forward slash or a backslash.
  1897. **/
  1898. EFI_STATUS
  1899. VirtioFsFuseDirentPlusToEfiFileInfo (
  1900. IN VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE *FuseDirent,
  1901. IN OUT EFI_FILE_INFO *FileInfo
  1902. )
  1903. {
  1904. UINTN DirentSize;
  1905. UINTN FileInfoSize;
  1906. UINT8 *DirentName;
  1907. UINT32 Idx;
  1908. DirentSize = VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE_SIZE (FuseDirent->Namelen);
  1909. if (DirentSize == 0) {
  1910. return EFI_INVALID_PARAMETER;
  1911. }
  1912. //
  1913. // We're now safe from overflow in the calculation below.
  1914. //
  1915. FileInfoSize = (OFFSET_OF (EFI_FILE_INFO, FileName) +
  1916. ((UINTN)FuseDirent->Namelen + 1) * sizeof (CHAR16));
  1917. if (FileInfoSize > FileInfo->Size) {
  1918. return EFI_BUFFER_TOO_SMALL;
  1919. }
  1920. //
  1921. // Convert the name.
  1922. //
  1923. DirentName = (UINT8 *)(FuseDirent + 1);
  1924. for (Idx = 0; Idx < FuseDirent->Namelen; Idx++) {
  1925. UINT8 NameByte;
  1926. NameByte = DirentName[Idx];
  1927. if ((NameByte < 0x20) || (NameByte > 0x7E) ||
  1928. (NameByte == '/') || (NameByte == '\\'))
  1929. {
  1930. return EFI_UNSUPPORTED;
  1931. }
  1932. FileInfo->FileName[Idx] = (CHAR16)NameByte;
  1933. }
  1934. FileInfo->FileName[Idx++] = L'\0';
  1935. //
  1936. // Set the (possibly reduced) size.
  1937. //
  1938. FileInfo->Size = FileInfoSize;
  1939. return EFI_SUCCESS;
  1940. }
  1941. /**
  1942. Given an EFI_FILE_INFO object received in an EFI_FILE_PROTOCOL.SetInfo()
  1943. call, determine whether updating the size of the file is necessary, relative
  1944. to an EFI_FILE_INFO object describing the current state of the file.
  1945. @param[in] Info The EFI_FILE_INFO describing the current state of the
  1946. file. The caller is responsible for populating Info on
  1947. input with VirtioFsFuseAttrToEfiFileInfo(), from the
  1948. current FUSE attributes of the file. The Info->Size and
  1949. Info->FileName members are ignored.
  1950. @param[in] NewInfo The EFI_FILE_INFO object received in the
  1951. EFI_FILE_PROTOCOL.SetInfo() call.
  1952. @param[out] Update Set to TRUE on output if the file size needs to be
  1953. updated. Set to FALSE otherwise.
  1954. @param[out] Size If Update is set to TRUE, then Size provides the new file
  1955. size to set. Otherwise, Size is not written to.
  1956. **/
  1957. VOID
  1958. VirtioFsGetFuseSizeUpdate (
  1959. IN EFI_FILE_INFO *Info,
  1960. IN EFI_FILE_INFO *NewInfo,
  1961. OUT BOOLEAN *Update,
  1962. OUT UINT64 *Size
  1963. )
  1964. {
  1965. BOOLEAN IsDirectory;
  1966. IsDirectory = (BOOLEAN)((Info->Attribute & EFI_FILE_DIRECTORY) != 0);
  1967. if (IsDirectory || (Info->FileSize == NewInfo->FileSize)) {
  1968. *Update = FALSE;
  1969. return;
  1970. }
  1971. *Update = TRUE;
  1972. *Size = NewInfo->FileSize;
  1973. }
  1974. /**
  1975. Given an EFI_FILE_INFO object received in an EFI_FILE_PROTOCOL.SetInfo()
  1976. call, determine whether updating the last access time and/or the last
  1977. modification time of the file is necessary, relative to an EFI_FILE_INFO
  1978. object describing the current state of the file.
  1979. @param[in] Info The EFI_FILE_INFO describing the current state of
  1980. the file. The caller is responsible for populating
  1981. Info on input with VirtioFsFuseAttrToEfiFileInfo(),
  1982. from the current FUSE attributes of the file. The
  1983. Info->Size and Info->FileName members are ignored.
  1984. @param[in] NewInfo The EFI_FILE_INFO object received in the
  1985. EFI_FILE_PROTOCOL.SetInfo() call.
  1986. @param[out] UpdateAtime Set to TRUE on output if the last access time needs
  1987. to be updated. Set to FALSE otherwise.
  1988. @param[out] UpdateMtime Set to TRUE on output if the last modification time
  1989. needs to be updated. Set to FALSE otherwise.
  1990. @param[out] Atime If UpdateAtime is set to TRUE, then Atime provides
  1991. the last access timestamp to set (as seconds since
  1992. the Epoch). Otherwise, Atime is not written to.
  1993. @param[out] Mtime If UpdateMtime is set to TRUE, then Mtime provides
  1994. the last modification timestamp to set (as seconds
  1995. since the Epoch). Otherwise, Mtime is not written
  1996. to.
  1997. @retval EFI_SUCCESS Output parameters have been set successfully.
  1998. @retval EFI_INVALID_PARAMETER At least one of the CreateTime, LastAccessTime
  1999. and ModificationTime fields in NewInfo
  2000. represents an actual update relative to the
  2001. current state of the file (expressed in Info),
  2002. but does not satisfy the UEFI spec
  2003. requirements on EFI_TIME.
  2004. @retval EFI_ACCESS_DENIED NewInfo requests changing both CreateTime and
  2005. ModificationTime, but to values that differ
  2006. from each other. The Virtio Filesystem device
  2007. does not support this.
  2008. **/
  2009. EFI_STATUS
  2010. VirtioFsGetFuseTimeUpdates (
  2011. IN EFI_FILE_INFO *Info,
  2012. IN EFI_FILE_INFO *NewInfo,
  2013. OUT BOOLEAN *UpdateAtime,
  2014. OUT BOOLEAN *UpdateMtime,
  2015. OUT UINT64 *Atime,
  2016. OUT UINT64 *Mtime
  2017. )
  2018. {
  2019. EFI_TIME *Time[3];
  2020. EFI_TIME *NewTime[ARRAY_SIZE (Time)];
  2021. UINTN Idx;
  2022. STATIC CONST EFI_TIME ZeroTime = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  2023. BOOLEAN Change[ARRAY_SIZE (Time)];
  2024. UINT64 Seconds[ARRAY_SIZE (Time)];
  2025. Time[0] = &Info->CreateTime;
  2026. Time[1] = &Info->LastAccessTime;
  2027. Time[2] = &Info->ModificationTime;
  2028. NewTime[0] = &NewInfo->CreateTime;
  2029. NewTime[1] = &NewInfo->LastAccessTime;
  2030. NewTime[2] = &NewInfo->ModificationTime;
  2031. //
  2032. // Determine which timestamps differ from the current state. (A zero time
  2033. // means "don't update", per UEFI spec.) For each timestamp that's being
  2034. // changed, calculate the seconds since the Epoch.
  2035. //
  2036. for (Idx = 0; Idx < ARRAY_SIZE (Time); Idx++) {
  2037. if ((CompareMem (NewTime[Idx], &ZeroTime, sizeof (EFI_TIME)) == 0) ||
  2038. (CompareMem (NewTime[Idx], Time[Idx], sizeof (EFI_TIME)) == 0))
  2039. {
  2040. Change[Idx] = FALSE;
  2041. } else {
  2042. if (!IsTimeValid (NewTime[Idx])) {
  2043. return EFI_INVALID_PARAMETER;
  2044. }
  2045. Change[Idx] = TRUE;
  2046. Seconds[Idx] = EfiTimeToEpoch (NewTime[Idx]);
  2047. }
  2048. }
  2049. //
  2050. // If a change is requested for exactly one of CreateTime and
  2051. // ModificationTime, we'll change the last modification time. If changes are
  2052. // requested for both, and to the same timestamp, we'll similarly update the
  2053. // last modification time. If changes are requested for both, but to
  2054. // different timestamps, we reject the request.
  2055. //
  2056. if (Change[0] && Change[2] && (Seconds[0] != Seconds[2])) {
  2057. return EFI_ACCESS_DENIED;
  2058. }
  2059. *UpdateAtime = FALSE;
  2060. *UpdateMtime = FALSE;
  2061. if (Change[0]) {
  2062. *UpdateMtime = TRUE;
  2063. *Mtime = Seconds[0];
  2064. }
  2065. if (Change[1]) {
  2066. *UpdateAtime = TRUE;
  2067. *Atime = Seconds[1];
  2068. }
  2069. if (Change[2]) {
  2070. *UpdateMtime = TRUE;
  2071. *Mtime = Seconds[2];
  2072. }
  2073. return EFI_SUCCESS;
  2074. }
  2075. /**
  2076. Given an EFI_FILE_INFO object received in an EFI_FILE_PROTOCOL.SetInfo()
  2077. call, determine whether updating the file mode bits of the file is necessary,
  2078. relative to an EFI_FILE_INFO object describing the current state of the file.
  2079. @param[in] Info The EFI_FILE_INFO describing the current state of the
  2080. file. The caller is responsible for populating Info on
  2081. input with VirtioFsFuseAttrToEfiFileInfo(), from the
  2082. current FUSE attributes of the file. The Info->Size and
  2083. Info->FileName members are ignored.
  2084. @param[in] NewInfo The EFI_FILE_INFO object received in the
  2085. EFI_FILE_PROTOCOL.SetInfo() call.
  2086. @param[out] Update Set to TRUE on output if the file mode bits need to be
  2087. updated. Set to FALSE otherwise.
  2088. @param[out] Mode If Update is set to TRUE, then Mode provides the file
  2089. mode bits to set. Otherwise, Mode is not written to.
  2090. @retval EFI_SUCCESS Output parameters have been set successfully.
  2091. @retval EFI_ACCESS_DENIED NewInfo requests toggling an unknown bit in the
  2092. Attribute bitmask.
  2093. @retval EFI_ACCESS_DENIED NewInfo requests toggling EFI_FILE_DIRECTORY in
  2094. the Attribute bitmask.
  2095. **/
  2096. EFI_STATUS
  2097. VirtioFsGetFuseModeUpdate (
  2098. IN EFI_FILE_INFO *Info,
  2099. IN EFI_FILE_INFO *NewInfo,
  2100. OUT BOOLEAN *Update,
  2101. OUT UINT32 *Mode
  2102. )
  2103. {
  2104. UINT64 Toggle;
  2105. BOOLEAN IsDirectory;
  2106. BOOLEAN IsWriteable;
  2107. BOOLEAN WillBeWriteable;
  2108. Toggle = Info->Attribute ^ NewInfo->Attribute;
  2109. if ((Toggle & ~EFI_FILE_VALID_ATTR) != 0) {
  2110. //
  2111. // Unknown attribute requested.
  2112. //
  2113. return EFI_ACCESS_DENIED;
  2114. }
  2115. if ((Toggle & EFI_FILE_DIRECTORY) != 0) {
  2116. //
  2117. // EFI_FILE_DIRECTORY cannot be toggled.
  2118. //
  2119. return EFI_ACCESS_DENIED;
  2120. }
  2121. IsDirectory = (BOOLEAN)((Info->Attribute & EFI_FILE_DIRECTORY) != 0);
  2122. IsWriteable = (BOOLEAN)((Info->Attribute & EFI_FILE_READ_ONLY) == 0);
  2123. WillBeWriteable = (BOOLEAN)((NewInfo->Attribute & EFI_FILE_READ_ONLY) == 0);
  2124. if (IsWriteable == WillBeWriteable) {
  2125. *Update = FALSE;
  2126. return EFI_SUCCESS;
  2127. }
  2128. if (IsDirectory) {
  2129. if (WillBeWriteable) {
  2130. *Mode = (VIRTIO_FS_FUSE_MODE_PERM_RWXU |
  2131. VIRTIO_FS_FUSE_MODE_PERM_RWXG |
  2132. VIRTIO_FS_FUSE_MODE_PERM_RWXO);
  2133. } else {
  2134. *Mode = (VIRTIO_FS_FUSE_MODE_PERM_RUSR |
  2135. VIRTIO_FS_FUSE_MODE_PERM_XUSR |
  2136. VIRTIO_FS_FUSE_MODE_PERM_RGRP |
  2137. VIRTIO_FS_FUSE_MODE_PERM_XGRP |
  2138. VIRTIO_FS_FUSE_MODE_PERM_ROTH |
  2139. VIRTIO_FS_FUSE_MODE_PERM_XOTH);
  2140. }
  2141. } else {
  2142. if (WillBeWriteable) {
  2143. *Mode = (VIRTIO_FS_FUSE_MODE_PERM_RUSR |
  2144. VIRTIO_FS_FUSE_MODE_PERM_WUSR |
  2145. VIRTIO_FS_FUSE_MODE_PERM_RGRP |
  2146. VIRTIO_FS_FUSE_MODE_PERM_WGRP |
  2147. VIRTIO_FS_FUSE_MODE_PERM_ROTH |
  2148. VIRTIO_FS_FUSE_MODE_PERM_WOTH);
  2149. } else {
  2150. *Mode = (VIRTIO_FS_FUSE_MODE_PERM_RUSR |
  2151. VIRTIO_FS_FUSE_MODE_PERM_RGRP |
  2152. VIRTIO_FS_FUSE_MODE_PERM_ROTH);
  2153. }
  2154. }
  2155. *Update = TRUE;
  2156. return EFI_SUCCESS;
  2157. }