1 | /** @file
|
---|
2 | EFI_FILE_PROTOCOL.Open() member function for the Virtio Filesystem driver.
|
---|
3 |
|
---|
4 | Copyright (C) 2020, Red Hat, Inc.
|
---|
5 |
|
---|
6 | SPDX-License-Identifier: BSD-2-Clause-Patent
|
---|
7 | **/
|
---|
8 |
|
---|
9 | #include <Library/BaseLib.h> // AsciiStrCmp()
|
---|
10 | #include <Library/MemoryAllocationLib.h> // AllocatePool()
|
---|
11 |
|
---|
12 | #include "VirtioFsDxe.h"
|
---|
13 |
|
---|
14 | /**
|
---|
15 | Open the root directory, possibly for writing.
|
---|
16 |
|
---|
17 | @param[in,out] VirtioFs The Virtio Filesystem device whose root directory
|
---|
18 | should be opened.
|
---|
19 |
|
---|
20 | @param[out] NewHandle The new EFI_FILE_PROTOCOL instance through which
|
---|
21 | the root directory can be accessed.
|
---|
22 |
|
---|
23 | @param[in] OpenForWriting TRUE if the root directory should be opened for
|
---|
24 | read-write access. FALSE if the root directory
|
---|
25 | should be opened for read-only access. Opening the
|
---|
26 | root directory for read-write access is useful for
|
---|
27 | calling EFI_FILE_PROTOCOL.Flush() or
|
---|
28 | EFI_FILE_PROTOCOL.SetInfo() later, for syncing or
|
---|
29 | touching the root directory, respectively.
|
---|
30 |
|
---|
31 | @retval EFI_SUCCESS The root directory has been opened successfully.
|
---|
32 |
|
---|
33 | @retval EFI_ACCESS_DENIED OpenForWriting is TRUE, but the root directory is
|
---|
34 | marked as read-only.
|
---|
35 |
|
---|
36 | @return Error codes propagated from underlying functions.
|
---|
37 | **/
|
---|
38 | STATIC
|
---|
39 | EFI_STATUS
|
---|
40 | OpenRootDirectory (
|
---|
41 | IN OUT VIRTIO_FS *VirtioFs,
|
---|
42 | OUT EFI_FILE_PROTOCOL **NewHandle,
|
---|
43 | IN BOOLEAN OpenForWriting
|
---|
44 | )
|
---|
45 | {
|
---|
46 | EFI_STATUS Status;
|
---|
47 | VIRTIO_FS_FILE *NewVirtioFsFile;
|
---|
48 |
|
---|
49 | //
|
---|
50 | // VirtioFsOpenVolume() opens the root directory for read-only access. If the
|
---|
51 | // current request is to open the root directory for read-write access, so
|
---|
52 | // that EFI_FILE_PROTOCOL.Flush() or EFI_FILE_PROTOCOL.SetInfo()+timestamps
|
---|
53 | // can be used on the root directory later, then we have to check for write
|
---|
54 | // permission first.
|
---|
55 | //
|
---|
56 | if (OpenForWriting) {
|
---|
57 | VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE FuseAttr;
|
---|
58 | EFI_FILE_INFO FileInfo;
|
---|
59 |
|
---|
60 | Status = VirtioFsFuseGetAttr (
|
---|
61 | VirtioFs,
|
---|
62 | VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID,
|
---|
63 | &FuseAttr
|
---|
64 | );
|
---|
65 | if (EFI_ERROR (Status)) {
|
---|
66 | return Status;
|
---|
67 | }
|
---|
68 |
|
---|
69 | Status = VirtioFsFuseAttrToEfiFileInfo (&FuseAttr, &FileInfo);
|
---|
70 | if (EFI_ERROR (Status)) {
|
---|
71 | return Status;
|
---|
72 | }
|
---|
73 |
|
---|
74 | if ((FileInfo.Attribute & EFI_FILE_READ_ONLY) != 0) {
|
---|
75 | return EFI_ACCESS_DENIED;
|
---|
76 | }
|
---|
77 | }
|
---|
78 |
|
---|
79 | Status = VirtioFsOpenVolume (&VirtioFs->SimpleFs, NewHandle);
|
---|
80 | if (EFI_ERROR (Status)) {
|
---|
81 | return Status;
|
---|
82 | }
|
---|
83 |
|
---|
84 | NewVirtioFsFile = VIRTIO_FS_FILE_FROM_SIMPLE_FILE (*NewHandle);
|
---|
85 | NewVirtioFsFile->IsOpenForWriting = OpenForWriting;
|
---|
86 | return EFI_SUCCESS;
|
---|
87 | }
|
---|
88 |
|
---|
89 | /**
|
---|
90 | Open an existent regular file or non-root directory.
|
---|
91 |
|
---|
92 | @param[in,out] VirtioFs The Virtio Filesystem device on which the
|
---|
93 | regular file or directory should be opened.
|
---|
94 |
|
---|
95 | @param[in] DirNodeId The inode number of the immediate parent
|
---|
96 | directory of the regular file or directory to
|
---|
97 | open.
|
---|
98 |
|
---|
99 | @param[in] Name The single-component filename of the regular
|
---|
100 | file or directory to open, under the immediate
|
---|
101 | parent directory identified by DirNodeId.
|
---|
102 |
|
---|
103 | @param[in] OpenForWriting TRUE if the regular file or directory should be
|
---|
104 | opened for read-write access. FALSE if the
|
---|
105 | regular file or directory should be opened for
|
---|
106 | read-only access. Opening a directory for
|
---|
107 | read-write access is useful for deleting,
|
---|
108 | renaming, syncing or touching the directory
|
---|
109 | later.
|
---|
110 |
|
---|
111 | @param[out] NodeId The inode number of the regular file or
|
---|
112 | directory, returned by the Virtio Filesystem
|
---|
113 | device.
|
---|
114 |
|
---|
115 | @param[out] FuseHandle The open handle to the regular file or
|
---|
116 | directory, returned by the Virtio Filesystem
|
---|
117 | device.
|
---|
118 |
|
---|
119 | @param[out] NodeIsDirectory Set to TRUE on output if Name was found to refer
|
---|
120 | to a directory. Set to FALSE if Name was found
|
---|
121 | to refer to a regular file.
|
---|
122 |
|
---|
123 | @retval EFI_SUCCESS The regular file or directory has been looked up
|
---|
124 | and opened successfully.
|
---|
125 |
|
---|
126 | @retval EFI_ACCESS_DENIED OpenForWriting is TRUE, but the regular file or
|
---|
127 | directory is marked read-only.
|
---|
128 |
|
---|
129 | @retval EFI_NOT_FOUND A directory entry called Name was not found in the
|
---|
130 | directory identified by DirNodeId. (EFI_NOT_FOUND
|
---|
131 | is not returned for any other condition.)
|
---|
132 |
|
---|
133 | @return Errors propagated from underlying functions. If
|
---|
134 | the error code to propagate were EFI_NOT_FOUND, it
|
---|
135 | is remapped to EFI_DEVICE_ERROR.
|
---|
136 | **/
|
---|
137 | STATIC
|
---|
138 | EFI_STATUS
|
---|
139 | OpenExistentFileOrDirectory (
|
---|
140 | IN OUT VIRTIO_FS *VirtioFs,
|
---|
141 | IN UINT64 DirNodeId,
|
---|
142 | IN CHAR8 *Name,
|
---|
143 | IN BOOLEAN OpenForWriting,
|
---|
144 | OUT UINT64 *NodeId,
|
---|
145 | OUT UINT64 *FuseHandle,
|
---|
146 | OUT BOOLEAN *NodeIsDirectory
|
---|
147 | )
|
---|
148 | {
|
---|
149 | EFI_STATUS Status;
|
---|
150 | UINT64 ResolvedNodeId;
|
---|
151 | VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE FuseAttr;
|
---|
152 | EFI_FILE_INFO FileInfo;
|
---|
153 | BOOLEAN IsDirectory;
|
---|
154 | UINT64 NewFuseHandle;
|
---|
155 |
|
---|
156 | Status = VirtioFsFuseLookup (
|
---|
157 | VirtioFs,
|
---|
158 | DirNodeId,
|
---|
159 | Name,
|
---|
160 | &ResolvedNodeId,
|
---|
161 | &FuseAttr
|
---|
162 | );
|
---|
163 | if (EFI_ERROR (Status)) {
|
---|
164 | return Status;
|
---|
165 | }
|
---|
166 |
|
---|
167 | Status = VirtioFsFuseAttrToEfiFileInfo (&FuseAttr, &FileInfo);
|
---|
168 | if (EFI_ERROR (Status)) {
|
---|
169 | goto ForgetResolvedNodeId;
|
---|
170 | }
|
---|
171 |
|
---|
172 | if (OpenForWriting && ((FileInfo.Attribute & EFI_FILE_READ_ONLY) != 0)) {
|
---|
173 | Status = EFI_ACCESS_DENIED;
|
---|
174 | goto ForgetResolvedNodeId;
|
---|
175 | }
|
---|
176 |
|
---|
177 | IsDirectory = (BOOLEAN)((FileInfo.Attribute & EFI_FILE_DIRECTORY) != 0);
|
---|
178 | if (IsDirectory) {
|
---|
179 | //
|
---|
180 | // If OpenForWriting is TRUE here, that's not passed to
|
---|
181 | // VirtioFsFuseOpenDir(); it does not affect the FUSE_OPENDIR request we
|
---|
182 | // send. OpenForWriting=TRUE will only permit attempts to delete, rename,
|
---|
183 | // flush (sync), and touch the directory.
|
---|
184 | //
|
---|
185 | Status = VirtioFsFuseOpenDir (VirtioFs, ResolvedNodeId, &NewFuseHandle);
|
---|
186 | } else {
|
---|
187 | Status = VirtioFsFuseOpen (
|
---|
188 | VirtioFs,
|
---|
189 | ResolvedNodeId,
|
---|
190 | OpenForWriting,
|
---|
191 | &NewFuseHandle
|
---|
192 | );
|
---|
193 | }
|
---|
194 |
|
---|
195 | if (EFI_ERROR (Status)) {
|
---|
196 | goto ForgetResolvedNodeId;
|
---|
197 | }
|
---|
198 |
|
---|
199 | *NodeId = ResolvedNodeId;
|
---|
200 | *FuseHandle = NewFuseHandle;
|
---|
201 | *NodeIsDirectory = IsDirectory;
|
---|
202 | return EFI_SUCCESS;
|
---|
203 |
|
---|
204 | ForgetResolvedNodeId:
|
---|
205 | VirtioFsFuseForget (VirtioFs, ResolvedNodeId);
|
---|
206 | return (Status == EFI_NOT_FOUND) ? EFI_DEVICE_ERROR : Status;
|
---|
207 | }
|
---|
208 |
|
---|
209 | /**
|
---|
210 | Create a directory.
|
---|
211 |
|
---|
212 | @param[in,out] VirtioFs The Virtio Filesystem device on which the directory
|
---|
213 | should be created.
|
---|
214 |
|
---|
215 | @param[in] DirNodeId The inode number of the immediate parent directory
|
---|
216 | of the directory to create.
|
---|
217 |
|
---|
218 | @param[in] Name The single-component filename of the directory to
|
---|
219 | create, under the immediate parent directory
|
---|
220 | identified by DirNodeId.
|
---|
221 |
|
---|
222 | @param[out] NodeId The inode number of the directory created, returned
|
---|
223 | by the Virtio Filesystem device.
|
---|
224 |
|
---|
225 | @param[out] FuseHandle The open handle to the directory created, returned
|
---|
226 | by the Virtio Filesystem device.
|
---|
227 |
|
---|
228 | @retval EFI_SUCCESS The directory has been created successfully.
|
---|
229 |
|
---|
230 | @return Errors propagated from underlying functions.
|
---|
231 | **/
|
---|
232 | STATIC
|
---|
233 | EFI_STATUS
|
---|
234 | CreateDirectory (
|
---|
235 | IN OUT VIRTIO_FS *VirtioFs,
|
---|
236 | IN UINT64 DirNodeId,
|
---|
237 | IN CHAR8 *Name,
|
---|
238 | OUT UINT64 *NodeId,
|
---|
239 | OUT UINT64 *FuseHandle
|
---|
240 | )
|
---|
241 | {
|
---|
242 | EFI_STATUS Status;
|
---|
243 | UINT64 NewChildDirNodeId;
|
---|
244 | UINT64 NewFuseHandle;
|
---|
245 |
|
---|
246 | Status = VirtioFsFuseMkDir (VirtioFs, DirNodeId, Name, &NewChildDirNodeId);
|
---|
247 | if (EFI_ERROR (Status)) {
|
---|
248 | return Status;
|
---|
249 | }
|
---|
250 |
|
---|
251 | Status = VirtioFsFuseOpenDir (VirtioFs, NewChildDirNodeId, &NewFuseHandle);
|
---|
252 | if (EFI_ERROR (Status)) {
|
---|
253 | goto RemoveNewChildDir;
|
---|
254 | }
|
---|
255 |
|
---|
256 | *NodeId = NewChildDirNodeId;
|
---|
257 | *FuseHandle = NewFuseHandle;
|
---|
258 | return EFI_SUCCESS;
|
---|
259 |
|
---|
260 | RemoveNewChildDir:
|
---|
261 | VirtioFsFuseRemoveFileOrDir (VirtioFs, DirNodeId, Name, TRUE /* IsDir */);
|
---|
262 | VirtioFsFuseForget (VirtioFs, NewChildDirNodeId);
|
---|
263 | return Status;
|
---|
264 | }
|
---|
265 |
|
---|
266 | /**
|
---|
267 | Create a regular file.
|
---|
268 |
|
---|
269 | @param[in,out] VirtioFs The Virtio Filesystem device on which the regular
|
---|
270 | file should be created.
|
---|
271 |
|
---|
272 | @param[in] DirNodeId The inode number of the immediate parent directory
|
---|
273 | of the regular file to create.
|
---|
274 |
|
---|
275 | @param[in] Name The single-component filename of the regular file to
|
---|
276 | create, under the immediate parent directory
|
---|
277 | identified by DirNodeId.
|
---|
278 |
|
---|
279 | @param[out] NodeId The inode number of the regular file created,
|
---|
280 | returned by the Virtio Filesystem device.
|
---|
281 |
|
---|
282 | @param[out] FuseHandle The open handle to the regular file created,
|
---|
283 | returned by the Virtio Filesystem device.
|
---|
284 |
|
---|
285 | @retval EFI_SUCCESS The regular file has been created successfully.
|
---|
286 |
|
---|
287 | @return Errors propagated from underlying functions.
|
---|
288 | **/
|
---|
289 | STATIC
|
---|
290 | EFI_STATUS
|
---|
291 | CreateRegularFile (
|
---|
292 | IN OUT VIRTIO_FS *VirtioFs,
|
---|
293 | IN UINT64 DirNodeId,
|
---|
294 | IN CHAR8 *Name,
|
---|
295 | OUT UINT64 *NodeId,
|
---|
296 | OUT UINT64 *FuseHandle
|
---|
297 | )
|
---|
298 | {
|
---|
299 | return VirtioFsFuseOpenOrCreate (
|
---|
300 | VirtioFs,
|
---|
301 | DirNodeId,
|
---|
302 | Name,
|
---|
303 | NodeId,
|
---|
304 | FuseHandle
|
---|
305 | );
|
---|
306 | }
|
---|
307 |
|
---|
308 | EFI_STATUS
|
---|
309 | EFIAPI
|
---|
310 | VirtioFsSimpleFileOpen (
|
---|
311 | IN EFI_FILE_PROTOCOL *This,
|
---|
312 | OUT EFI_FILE_PROTOCOL **NewHandle,
|
---|
313 | IN CHAR16 *FileName,
|
---|
314 | IN UINT64 OpenMode,
|
---|
315 | IN UINT64 Attributes
|
---|
316 | )
|
---|
317 | {
|
---|
318 | VIRTIO_FS_FILE *VirtioFsFile;
|
---|
319 | VIRTIO_FS *VirtioFs;
|
---|
320 | BOOLEAN OpenForWriting;
|
---|
321 | BOOLEAN PermitCreation;
|
---|
322 | BOOLEAN CreateDirectoryIfCreating;
|
---|
323 | VIRTIO_FS_FILE *NewVirtioFsFile;
|
---|
324 | EFI_STATUS Status;
|
---|
325 | CHAR8 *NewCanonicalPath;
|
---|
326 | BOOLEAN RootEscape;
|
---|
327 | UINT64 DirNodeId;
|
---|
328 | CHAR8 *LastComponent;
|
---|
329 | UINT64 NewNodeId;
|
---|
330 | UINT64 NewFuseHandle;
|
---|
331 | BOOLEAN NewNodeIsDirectory;
|
---|
332 |
|
---|
333 | VirtioFsFile = VIRTIO_FS_FILE_FROM_SIMPLE_FILE (This);
|
---|
334 | VirtioFs = VirtioFsFile->OwnerFs;
|
---|
335 |
|
---|
336 | //
|
---|
337 | // Validate OpenMode.
|
---|
338 | //
|
---|
339 | switch (OpenMode) {
|
---|
340 | case EFI_FILE_MODE_READ:
|
---|
341 | OpenForWriting = FALSE;
|
---|
342 | PermitCreation = FALSE;
|
---|
343 | break;
|
---|
344 | case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE:
|
---|
345 | OpenForWriting = TRUE;
|
---|
346 | PermitCreation = FALSE;
|
---|
347 | break;
|
---|
348 | case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE:
|
---|
349 | OpenForWriting = TRUE;
|
---|
350 | PermitCreation = TRUE;
|
---|
351 | break;
|
---|
352 | default:
|
---|
353 | return EFI_INVALID_PARAMETER;
|
---|
354 | }
|
---|
355 |
|
---|
356 | //
|
---|
357 | // Set CreateDirectoryIfCreating to suppress incorrect compiler/analyzer
|
---|
358 | // warnings.
|
---|
359 | //
|
---|
360 | CreateDirectoryIfCreating = FALSE;
|
---|
361 |
|
---|
362 | //
|
---|
363 | // Validate the Attributes requested for the case when the file ends up being
|
---|
364 | // created, provided creation is permitted.
|
---|
365 | //
|
---|
366 | if (PermitCreation) {
|
---|
367 | if ((Attributes & ~EFI_FILE_VALID_ATTR) != 0) {
|
---|
368 | //
|
---|
369 | // Unknown attribute requested.
|
---|
370 | //
|
---|
371 | return EFI_INVALID_PARAMETER;
|
---|
372 | }
|
---|
373 |
|
---|
374 | ASSERT (OpenForWriting);
|
---|
375 | if ((Attributes & EFI_FILE_READ_ONLY) != 0) {
|
---|
376 | DEBUG ((
|
---|
377 | DEBUG_ERROR,
|
---|
378 | ("%a: Label=\"%s\" CanonicalPathname=\"%a\" FileName=\"%s\" "
|
---|
379 | "OpenMode=0x%Lx Attributes=0x%Lx: nonsensical request to possibly "
|
---|
380 | "create a file marked read-only, for read-write access\n"),
|
---|
381 | __func__,
|
---|
382 | VirtioFs->Label,
|
---|
383 | VirtioFsFile->CanonicalPathname,
|
---|
384 | FileName,
|
---|
385 | OpenMode,
|
---|
386 | Attributes
|
---|
387 | ));
|
---|
388 | return EFI_INVALID_PARAMETER;
|
---|
389 | }
|
---|
390 |
|
---|
391 | CreateDirectoryIfCreating = (BOOLEAN)((Attributes &
|
---|
392 | EFI_FILE_DIRECTORY) != 0);
|
---|
393 | }
|
---|
394 |
|
---|
395 | //
|
---|
396 | // Referring to a file relative to a regular file makes no sense (or at least
|
---|
397 | // it cannot be implemented consistently with how a file is referred to
|
---|
398 | // relative to a directory). See USWG Mantis ticket #2367.
|
---|
399 | //
|
---|
400 | if (!VirtioFsFile->IsDirectory) {
|
---|
401 | BOOLEAN BugCompat;
|
---|
402 |
|
---|
403 | //
|
---|
404 | // Tolerate this bug in the caller if FileName is absolute. If FileName is
|
---|
405 | // absolute, then VirtioFsAppendPath() below will disregard
|
---|
406 | // VirtioFsFile->CanonicalPathname.
|
---|
407 | //
|
---|
408 | BugCompat = (FileName[0] == L'\\');
|
---|
409 |
|
---|
410 | DEBUG ((
|
---|
411 | BugCompat ? DEBUG_WARN : DEBUG_ERROR,
|
---|
412 | ("%a: Label=\"%s\" CanonicalPathname=\"%a\" FileName=\"%s\": "
|
---|
413 | "nonsensical request to open a file or directory relative to a regular "
|
---|
414 | "file\n"),
|
---|
415 | __func__,
|
---|
416 | VirtioFs->Label,
|
---|
417 | VirtioFsFile->CanonicalPathname,
|
---|
418 | FileName
|
---|
419 | ));
|
---|
420 | if (!BugCompat) {
|
---|
421 | return EFI_INVALID_PARAMETER;
|
---|
422 | }
|
---|
423 | }
|
---|
424 |
|
---|
425 | //
|
---|
426 | // Allocate the new VIRTIO_FS_FILE object.
|
---|
427 | //
|
---|
428 | NewVirtioFsFile = AllocatePool (sizeof *NewVirtioFsFile);
|
---|
429 | if (NewVirtioFsFile == NULL) {
|
---|
430 | return EFI_OUT_OF_RESOURCES;
|
---|
431 | }
|
---|
432 |
|
---|
433 | //
|
---|
434 | // Create the canonical pathname at which the desired file is expected to
|
---|
435 | // exist.
|
---|
436 | //
|
---|
437 | Status = VirtioFsAppendPath (
|
---|
438 | VirtioFsFile->CanonicalPathname,
|
---|
439 | FileName,
|
---|
440 | &NewCanonicalPath,
|
---|
441 | &RootEscape
|
---|
442 | );
|
---|
443 | if (EFI_ERROR (Status)) {
|
---|
444 | goto FreeNewVirtioFsFile;
|
---|
445 | }
|
---|
446 |
|
---|
447 | if (RootEscape) {
|
---|
448 | Status = EFI_ACCESS_DENIED;
|
---|
449 | goto FreeNewCanonicalPath;
|
---|
450 | }
|
---|
451 |
|
---|
452 | //
|
---|
453 | // If the desired file is the root directory, just open the volume one more
|
---|
454 | // time, without looking up anything.
|
---|
455 | //
|
---|
456 | if (AsciiStrCmp (NewCanonicalPath, "/") == 0) {
|
---|
457 | FreePool (NewCanonicalPath);
|
---|
458 | FreePool (NewVirtioFsFile);
|
---|
459 | return OpenRootDirectory (VirtioFs, NewHandle, OpenForWriting);
|
---|
460 | }
|
---|
461 |
|
---|
462 | //
|
---|
463 | // Split the new canonical pathname into most specific parent directory
|
---|
464 | // (given by DirNodeId) and last pathname component (i.e., immediate child
|
---|
465 | // within that parent directory).
|
---|
466 | //
|
---|
467 | Status = VirtioFsLookupMostSpecificParentDir (
|
---|
468 | VirtioFs,
|
---|
469 | NewCanonicalPath,
|
---|
470 | &DirNodeId,
|
---|
471 | &LastComponent
|
---|
472 | );
|
---|
473 | if (EFI_ERROR (Status)) {
|
---|
474 | goto FreeNewCanonicalPath;
|
---|
475 | }
|
---|
476 |
|
---|
477 | //
|
---|
478 | // Set NewNodeIsDirectory to suppress incorrect compiler/analyzer warnings.
|
---|
479 | //
|
---|
480 | NewNodeIsDirectory = FALSE;
|
---|
481 |
|
---|
482 | //
|
---|
483 | // Try to open LastComponent directly under DirNodeId, as an existent regular
|
---|
484 | // file or directory.
|
---|
485 | //
|
---|
486 | Status = OpenExistentFileOrDirectory (
|
---|
487 | VirtioFs,
|
---|
488 | DirNodeId,
|
---|
489 | LastComponent,
|
---|
490 | OpenForWriting,
|
---|
491 | &NewNodeId,
|
---|
492 | &NewFuseHandle,
|
---|
493 | &NewNodeIsDirectory
|
---|
494 | );
|
---|
495 | //
|
---|
496 | // If LastComponent could not be found under DirNodeId, but the request
|
---|
497 | // allows us to create a new entry, attempt creating the requested regular
|
---|
498 | // file or directory.
|
---|
499 | //
|
---|
500 | if ((Status == EFI_NOT_FOUND) && PermitCreation) {
|
---|
501 | ASSERT (OpenForWriting);
|
---|
502 | if (CreateDirectoryIfCreating) {
|
---|
503 | Status = CreateDirectory (
|
---|
504 | VirtioFs,
|
---|
505 | DirNodeId,
|
---|
506 | LastComponent,
|
---|
507 | &NewNodeId,
|
---|
508 | &NewFuseHandle
|
---|
509 | );
|
---|
510 | } else {
|
---|
511 | Status = CreateRegularFile (
|
---|
512 | VirtioFs,
|
---|
513 | DirNodeId,
|
---|
514 | LastComponent,
|
---|
515 | &NewNodeId,
|
---|
516 | &NewFuseHandle
|
---|
517 | );
|
---|
518 | }
|
---|
519 |
|
---|
520 | NewNodeIsDirectory = CreateDirectoryIfCreating;
|
---|
521 | }
|
---|
522 |
|
---|
523 | //
|
---|
524 | // Regardless of the branch taken, we're done with DirNodeId.
|
---|
525 | //
|
---|
526 | if (DirNodeId != VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID) {
|
---|
527 | VirtioFsFuseForget (VirtioFs, DirNodeId);
|
---|
528 | }
|
---|
529 |
|
---|
530 | if (EFI_ERROR (Status)) {
|
---|
531 | goto FreeNewCanonicalPath;
|
---|
532 | }
|
---|
533 |
|
---|
534 | //
|
---|
535 | // Populate the new VIRTIO_FS_FILE object.
|
---|
536 | //
|
---|
537 | NewVirtioFsFile->Signature = VIRTIO_FS_FILE_SIG;
|
---|
538 | NewVirtioFsFile->SimpleFile.Revision = EFI_FILE_PROTOCOL_REVISION;
|
---|
539 | NewVirtioFsFile->SimpleFile.Open = VirtioFsSimpleFileOpen;
|
---|
540 | NewVirtioFsFile->SimpleFile.Close = VirtioFsSimpleFileClose;
|
---|
541 | NewVirtioFsFile->SimpleFile.Delete = VirtioFsSimpleFileDelete;
|
---|
542 | NewVirtioFsFile->SimpleFile.Read = VirtioFsSimpleFileRead;
|
---|
543 | NewVirtioFsFile->SimpleFile.Write = VirtioFsSimpleFileWrite;
|
---|
544 | NewVirtioFsFile->SimpleFile.GetPosition = VirtioFsSimpleFileGetPosition;
|
---|
545 | NewVirtioFsFile->SimpleFile.SetPosition = VirtioFsSimpleFileSetPosition;
|
---|
546 | NewVirtioFsFile->SimpleFile.GetInfo = VirtioFsSimpleFileGetInfo;
|
---|
547 | NewVirtioFsFile->SimpleFile.SetInfo = VirtioFsSimpleFileSetInfo;
|
---|
548 | NewVirtioFsFile->SimpleFile.Flush = VirtioFsSimpleFileFlush;
|
---|
549 | NewVirtioFsFile->IsDirectory = NewNodeIsDirectory;
|
---|
550 | NewVirtioFsFile->IsOpenForWriting = OpenForWriting;
|
---|
551 | NewVirtioFsFile->OwnerFs = VirtioFs;
|
---|
552 | NewVirtioFsFile->CanonicalPathname = NewCanonicalPath;
|
---|
553 | NewVirtioFsFile->FilePosition = 0;
|
---|
554 | NewVirtioFsFile->NodeId = NewNodeId;
|
---|
555 | NewVirtioFsFile->FuseHandle = NewFuseHandle;
|
---|
556 | NewVirtioFsFile->FileInfoArray = NULL;
|
---|
557 | NewVirtioFsFile->SingleFileInfoSize = 0;
|
---|
558 | NewVirtioFsFile->NumFileInfo = 0;
|
---|
559 | NewVirtioFsFile->NextFileInfo = 0;
|
---|
560 |
|
---|
561 | //
|
---|
562 | // One more file is now open for the filesystem.
|
---|
563 | //
|
---|
564 | InsertTailList (&VirtioFs->OpenFiles, &NewVirtioFsFile->OpenFilesEntry);
|
---|
565 |
|
---|
566 | *NewHandle = &NewVirtioFsFile->SimpleFile;
|
---|
567 | return EFI_SUCCESS;
|
---|
568 |
|
---|
569 | FreeNewCanonicalPath:
|
---|
570 | FreePool (NewCanonicalPath);
|
---|
571 |
|
---|
572 | FreeNewVirtioFsFile:
|
---|
573 | FreePool (NewVirtioFsFile);
|
---|
574 |
|
---|
575 | return Status;
|
---|
576 | }
|
---|