1 /* file.c - SimpleFileIo Interface */
3 * Copyright © 2014-2017 Pete Batard <pete@akeo.ie>
4 * Based on iPXE's efi_driver.c and efi_file.c:
5 * Copyright © 2011,2013 Michael Brown <mbrown@fensystems.co.uk>.
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * Get EFI file name (for debugging)
30 FileName(EFI_GRUB_FILE
*File
)
33 static CHAR16 Path
[MAX_PATH
];
35 Status
= Utf8ToUtf16NoAlloc(File
->path
, Path
, sizeof(Path
));
36 if (EFI_ERROR(Status
)) {
37 PrintStatusError(Status
, L
"Could not convert filename to UTF16");
44 /* Simple hook to populate the timestamp and directory flag when opening a file */
46 InfoHook(const CHAR8
*name
, const GRUB_DIRHOOK_INFO
*Info
, VOID
*Data
)
48 EFI_GRUB_FILE
*File
= (EFI_GRUB_FILE
*) Data
;
50 /* Look for a specific file */
51 if (strcmpa(name
, File
->basename
) != 0)
54 File
->IsDir
= (BOOLEAN
) (Info
->Dir
);
56 File
->Mtime
= Info
->Mtime
;
65 * @ret new New file handle
68 * @v Attributes File attributes (for newly-created files)
69 * @ret Status EFI status code
71 static EFI_STATUS EFIAPI
72 FileOpen(EFI_FILE_HANDLE This
, EFI_FILE_HANDLE
*New
,
73 CHAR16
*Name
, UINT64 Mode
, UINT64 Attributes
)
76 EFI_GRUB_FILE
*File
= _CR(This
, EFI_GRUB_FILE
, EfiFile
);
77 EFI_GRUB_FILE
*NewFile
;
79 // TODO: Use dynamic buffers?
80 char path
[MAX_PATH
], clean_path
[MAX_PATH
], *dirname
;
82 BOOLEAN AbsolutePath
= (*Name
== L
'\\');
84 PrintInfo(L
"Open(" PERCENT_P L
"%s, \"%s\")\n", (UINTN
) This
,
85 IS_ROOT(File
)?L
" <ROOT>":L
"", Name
);
87 /* Fail unless opening read-only */
88 if (Mode
!= EFI_FILE_MODE_READ
) {
89 PrintWarning(L
"File '%s' can only be opened in read-only mode\n", Name
);
90 return EFI_WRITE_PROTECTED
;
93 /* Additional failures */
94 if ((StrCmp(Name
, L
"..") == 0) && IS_ROOT(File
)) {
95 PrintInfo(L
"Trying to open <ROOT>'s parent\n");
99 /* See if we're trying to reopen current (which the EFI Shell insists on doing) */
100 if ((*Name
== 0) || (StrCmp(Name
, L
".") == 0)) {
101 PrintInfo(L
" Reopening %s\n", IS_ROOT(File
)?L
"<ROOT>":FileName(File
));
104 PrintInfo(L
" RET: " PERCENT_P L
"\n", (UINTN
) *New
);
108 /* If we have an absolute path, don't bother completing with the parent */
112 strcpya(path
, File
->path
);
114 /* Add delimiter if needed */
115 if ((len
== 0) || (path
[len
-1] != '/'))
119 /* Copy the rest of the path (converted to UTF-8) */
120 Status
= Utf16ToUtf8NoAlloc(Name
, &path
[len
], sizeof(path
) - len
);
121 if (EFI_ERROR(Status
)) {
122 PrintStatusError(Status
, L
"Could not convert path to UTF-8");
125 /* Convert the delimiters */
126 for (i
= strlena(path
) - 1 ; i
>= len
; i
--) {
131 /* We only want to handle with absolute paths */
133 /* Find out if we're dealing with root by removing the junk */
134 CopyPathRelative(&clean_path
[1], path
, MAX_PATH
- 1);
135 if (clean_path
[1] == 0) {
136 /* We're dealing with the root */
137 PrintInfo(L
" Reopening <ROOT>\n");
138 *New
= &File
->FileSystem
->RootFile
->EfiFile
;
139 /* Must make sure that DirIndex is reset too (NB: no concurrent access!) */
140 File
->FileSystem
->RootFile
->DirIndex
= 0;
141 PrintInfo(L
" RET: " PERCENT_P L
"\n", (UINTN
) *New
);
145 // TODO: eventually we should seek for already opened files and increase RefCount
146 /* Allocate and initialise an instance of a file */
147 Status
= GrubCreateFile(&NewFile
, File
->FileSystem
);
148 if (EFI_ERROR(Status
)) {
149 PrintStatusError(Status
, L
"Could not instantiate file");
153 NewFile
->path
= AllocatePool(strlena(clean_path
)+1);
154 if (NewFile
->path
== NULL
) {
155 GrubDestroyFile(NewFile
);
156 PrintError(L
"Could not instantiate path\n");
157 return EFI_OUT_OF_RESOURCES
;
159 strcpya(NewFile
->path
, clean_path
);
161 /* Isolate the basename and dirname */
162 for (i
= strlena(clean_path
) - 1; i
>= 0; i
--) {
163 if (clean_path
[i
] == '/') {
168 dirname
= (i
<= 0) ? "/" : clean_path
;
169 NewFile
->basename
= &NewFile
->path
[i
+1];
171 /* Find if we're working with a directory and fill the grub timestamp */
172 Status
= GrubDir(NewFile
, dirname
, InfoHook
, (VOID
*) NewFile
);
173 if (EFI_ERROR(Status
)) {
174 if (Status
!= EFI_NOT_FOUND
)
175 PrintStatusError(Status
, L
"Could not get file attributes for '%s'", Name
);
176 FreePool(NewFile
->path
);
177 GrubDestroyFile(NewFile
);
181 /* Finally we can call on GRUB open() if it's a regular file */
182 if (!NewFile
->IsDir
) {
183 Status
= GrubOpen(NewFile
);
184 if (EFI_ERROR(Status
)) {
185 if (Status
!= EFI_NOT_FOUND
)
186 PrintStatusError(Status
, L
"Could not open file '%s'", Name
);
187 FreePool(NewFile
->path
);
188 GrubDestroyFile(NewFile
);
194 *New
= &NewFile
->EfiFile
;
196 PrintInfo(L
" RET: " PERCENT_P L
"\n", (UINTN
) *New
);
201 static EFI_STATUS EFIAPI
202 FileOpenEx(EFI_FILE_HANDLE This
, EFI_FILE_HANDLE
*New
, CHAR16
*Name
,
203 UINT64 Mode
, UINT64 Attributes
, EFI_FILE_IO_TOKEN
*Token
)
205 return FileOpen(This
, New
, Name
, Mode
, Attributes
);
212 * @v This File handle
213 * @ret Status EFI status code
215 static EFI_STATUS EFIAPI
216 FileClose(EFI_FILE_HANDLE This
)
218 EFI_GRUB_FILE
*File
= _CR(This
, EFI_GRUB_FILE
, EfiFile
);
220 PrintInfo(L
"Close(" PERCENT_P L
"|'%s') %s\n", (UINTN
) This
, FileName(File
),
221 IS_ROOT(File
)?L
"<ROOT>":L
"");
223 /* Nothing to do it this is the root */
227 if (--File
->RefCount
== 0) {
228 /* Close the file if it's a regular one */
231 /* NB: basename points into File->path and does not need to be freed */
232 if (File
->path
!= NULL
)
233 FreePool(File
->path
);
234 GrubDestroyFile(File
);
241 * Close and delete file
243 * @v This File handle
244 * @ret Status EFI status code
246 static EFI_STATUS EFIAPI
247 FileDelete(EFI_FILE_HANDLE This
)
249 EFI_GRUB_FILE
*File
= _CR(This
, EFI_GRUB_FILE
, EfiFile
);
251 PrintError(L
"Cannot delete '%s'\n", FileName(File
));
256 /* Warn of failure to delete */
257 return EFI_WARN_DELETE_FAILURE
;
260 /* GRUB uses a callback for each directory entry, whereas EFI uses repeated
261 * firmware generated calls to FileReadDir() to get the info for each entry,
262 * so we have to reconcile the twos. For now, we'll re-issue a call to GRUB
263 * dir(), and run through all the entries (to find the one we
264 * are interested in) multiple times. Maybe later we'll try to optimize this
265 * by building a one-off chained list of entries that we can parse...
268 DirHook(const CHAR8
*name
, const GRUB_DIRHOOK_INFO
*DirInfo
, VOID
*Data
)
271 EFI_FILE_INFO
*Info
= (EFI_FILE_INFO
*) Data
;
272 INT64
*Index
= (INT64
*) &Info
->FileSize
;
273 CHAR8
*filename
= (CHAR8
*) (UINTN
) Info
->PhysicalSize
;
274 EFI_TIME Time
= { 1970, 01, 01, 00, 00, 00, 0, 0, 0, 0, 0};
276 // Eliminate '.' or '..'
277 if ((name
[0] == '.') && ((name
[1] == 0) || ((name
[1] == '.') && (name
[2] == 0))))
280 /* Ignore any entry that doesn't match our index */
284 strcpya(filename
, name
);
286 Status
= Utf8ToUtf16NoAlloc(filename
, Info
->FileName
, (INTN
)(Info
->Size
- sizeof(EFI_FILE_INFO
)));
287 if (EFI_ERROR(Status
)) {
288 if (Status
!= EFI_BUFFER_TOO_SMALL
)
289 PrintStatusError(Status
, L
"Could not convert directory entry to UTF-8");
290 return (INT32
) Status
;
292 /* The Info struct size already accounts for the extra NUL */
293 Info
->Size
= sizeof(*Info
) + StrLen(Info
->FileName
) * sizeof(CHAR16
);
295 // Oh, and of course GRUB uses a 32 bit signed mtime value (seriously, wtf guys?!?)
296 if (DirInfo
->MtimeSet
)
297 GrubTimeToEfiTime(DirInfo
->Mtime
, &Time
);
298 CopyMem(&Info
->CreateTime
, &Time
, sizeof(Time
));
299 CopyMem(&Info
->LastAccessTime
, &Time
, sizeof(Time
));
300 CopyMem(&Info
->ModificationTime
, &Time
, sizeof(Time
));
302 Info
->Attribute
= EFI_FILE_READ_ONLY
;
304 Info
->Attribute
|= EFI_FILE_DIRECTORY
;
310 * Read directory entry
313 * @v Len Length to read
314 * @v Data Data buffer
315 * @ret Status EFI status code
318 FileReadDir(EFI_GRUB_FILE
*File
, UINTN
*Len
, VOID
*Data
)
320 EFI_FILE_INFO
*Info
= (EFI_FILE_INFO
*) Data
;
322 /* We temporarily repurpose the FileSize as a *signed* entry index */
323 INT64
*Index
= (INT64
*) &Info
->FileSize
;
324 /* And PhysicalSize as a pointer to our filename */
325 CHAR8
**basename
= (CHAR8
**) &Info
->PhysicalSize
;
326 CHAR8 path
[MAX_PATH
];
327 EFI_GRUB_FILE
*TmpFile
= NULL
;
330 /* Unless we can fit our maximum size, forget it */
331 if (*Len
< sizeof(EFI_FILE_INFO
)) {
332 *Len
= MINIMUM_INFO_LENGTH
;
333 return EFI_BUFFER_TOO_SMALL
;
336 /* Populate our Info template */
339 *Index
= File
->DirIndex
;
340 strcpya(path
, File
->path
);
342 if (path
[len
-1] != '/')
344 *basename
= &path
[len
];
346 /* Invoke GRUB's directory listing */
347 Status
= GrubDir(File
, File
->path
, DirHook
, Data
);
349 /* No more entries */
354 if (EFI_ERROR(Status
)) {
355 if (Status
== EFI_BUFFER_TOO_SMALL
) {
356 *Len
= MINIMUM_INFO_LENGTH
;
358 PrintStatusError(Status
, L
"Directory listing failed");
363 /* Our Index/FileSize must be reset */
365 Info
->PhysicalSize
= 0;
367 /* For regular files, we still need to fill the size */
368 if (!(Info
->Attribute
& EFI_FILE_DIRECTORY
)) {
369 /* Open the file and read its size */
370 Status
= GrubCreateFile(&TmpFile
, File
->FileSystem
);
371 if (EFI_ERROR(Status
)) {
372 PrintStatusError(Status
, L
"Unable to create temporary file");
375 TmpFile
->path
= path
;
377 Status
= GrubOpen(TmpFile
);
378 if (EFI_ERROR(Status
)) {
379 // TODO: EFI_NO_MAPPING is returned for links...
380 PrintStatusError(Status
, L
"Unable to obtain the size of '%s'", Info
->FileName
);
381 /* Non fatal error */
383 Info
->FileSize
= GrubGetFileSize(TmpFile
);
384 Info
->PhysicalSize
= GrubGetFileSize(TmpFile
);
387 GrubDestroyFile(TmpFile
);
390 *Len
= (UINTN
) Info
->Size
;
391 /* Advance to the next entry */
394 // PrintInfo(L" Entry[%d]: '%s' %s\n", File->DirIndex-1, Info->FileName,
395 // (Info->Attribute&EFI_FILE_DIRECTORY)?L"<DIR>":L"");
403 * @v This File handle
404 * @v Len Length to read
405 * @v Data Data buffer
406 * @ret Status EFI status code
408 static EFI_STATUS EFIAPI
409 FileRead(EFI_FILE_HANDLE This
, UINTN
*Len
, VOID
*Data
)
411 EFI_GRUB_FILE
*File
= _CR(This
, EFI_GRUB_FILE
, EfiFile
);
413 PrintInfo(L
"Read(" PERCENT_P L
"|'%s', %d) %s\n", (UINTN
) This
, FileName(File
),
414 *Len
, File
->IsDir
?L
"<DIR>":L
"");
416 /* If this is a directory, then fetch the directory entries */
418 return FileReadDir(File
, Len
, Data
);
420 return GrubRead(File
, Data
, Len
);
424 static EFI_STATUS EFIAPI
425 FileReadEx(IN EFI_FILE_PROTOCOL
*This
, IN OUT EFI_FILE_IO_TOKEN
*Token
)
427 return FileRead(This
, &(Token
->BufferSize
), Token
->Buffer
);
433 * @v This File handle
434 * @v Len Length to write
435 * @v Data Data buffer
436 * @ret Status EFI status code
438 static EFI_STATUS EFIAPI
439 FileWrite(EFI_FILE_HANDLE This
, UINTN
*Len
, VOID
*Data
)
441 EFI_GRUB_FILE
*File
= _CR(This
, EFI_GRUB_FILE
, EfiFile
);
443 PrintError(L
"Cannot write to '%s'\n", FileName(File
));
444 return EFI_WRITE_PROTECTED
;
448 static EFI_STATUS EFIAPI
449 FileWriteEx(IN EFI_FILE_PROTOCOL
*This
, IN OUT EFI_FILE_IO_TOKEN
*Token
)
451 return FileWrite(This
, &(Token
->BufferSize
), Token
->Buffer
);
457 * @v This File handle
458 * @v Position New file position
459 * @ret Status EFI status code
461 static EFI_STATUS EFIAPI
462 FileSetPosition(EFI_FILE_HANDLE This
, UINT64 Position
)
464 EFI_GRUB_FILE
*File
= _CR(This
, EFI_GRUB_FILE
, EfiFile
);
467 PrintInfo(L
"SetPosition(" PERCENT_P L
"|'%s', %lld) %s\n", (UINTN
) This
,
468 FileName(File
), Position
, (File
->IsDir
)?L
"<DIR>":L
"");
470 /* If this is a directory, reset the Index to the start */
473 return EFI_INVALID_PARAMETER
;
478 /* Fail if we attempt to seek past the end of the file (since
479 * we do not support writes).
481 FileSize
= GrubGetFileSize(File
);
482 if (Position
> FileSize
) {
483 PrintError(L
"'%s': Cannot seek to #%llx of %llx\n",
484 FileName(File
), Position
, FileSize
);
485 return EFI_UNSUPPORTED
;
489 GrubSetFileOffset(File
, Position
);
490 PrintDebug(L
"'%s': Position set to %llx\n",
491 FileName(File
), Position
);
499 * @v This File handle
500 * @ret Position New file position
501 * @ret Status EFI status code
503 static EFI_STATUS EFIAPI
504 FileGetPosition(EFI_FILE_HANDLE This
, UINT64
*Position
)
506 EFI_GRUB_FILE
*File
= _CR(This
, EFI_GRUB_FILE
, EfiFile
);
508 PrintInfo(L
"GetPosition(" PERCENT_P L
"|'%s', %lld)\n", (UINTN
) This
, FileName(File
));
511 *Position
= File
->DirIndex
;
513 *Position
= GrubGetFileOffset(File
);
518 * Get file information
520 * @v This File handle
521 * @v Type Type of information
524 * @ret Status EFI status code
526 static EFI_STATUS EFIAPI
527 FileGetInfo(EFI_FILE_HANDLE This
, EFI_GUID
*Type
, UINTN
*Len
, VOID
*Data
)
530 EFI_GRUB_FILE
*File
= _CR(This
, EFI_GRUB_FILE
, EfiFile
);
531 EFI_FILE_SYSTEM_INFO
*FSInfo
= (EFI_FILE_SYSTEM_INFO
*) Data
;
532 EFI_FILE_INFO
*Info
= (EFI_FILE_INFO
*) Data
;
533 EFI_FILE_SYSTEM_VOLUME_LABEL_INFO
*VLInfo
= (EFI_FILE_SYSTEM_VOLUME_LABEL_INFO
*)Data
;
538 PrintInfo(L
"GetInfo(" PERCENT_P L
"|'%s', %d) %s\n", (UINTN
) This
,
539 FileName(File
), *Len
, File
->IsDir
?L
"<DIR>":L
"");
541 /* Determine information to return */
542 if (CompareMem(Type
, &gEfiFileInfoGuid
, sizeof(*Type
)) == 0) {
544 /* Fill file information */
545 PrintExtra(L
"Get regular file information\n");
546 if (*Len
< sizeof(EFI_FILE_INFO
)) {
547 *Len
= MINIMUM_INFO_LENGTH
;
548 return EFI_BUFFER_TOO_SMALL
;
551 ZeroMem(Data
, sizeof(EFI_FILE_INFO
));
553 Info
->Attribute
= EFI_FILE_READ_ONLY
;
554 GrubTimeToEfiTime(File
->Mtime
, &Time
);
555 CopyMem(&Info
->CreateTime
, &Time
, sizeof(Time
));
556 CopyMem(&Info
->LastAccessTime
, &Time
, sizeof(Time
));
557 CopyMem(&Info
->ModificationTime
, &Time
, sizeof(Time
));
560 Info
->Attribute
|= EFI_FILE_DIRECTORY
;
562 Info
->FileSize
= GrubGetFileSize(File
);
563 Info
->PhysicalSize
= GrubGetFileSize(File
);
566 tmpLen
= (UINTN
)(Info
->Size
- sizeof(EFI_FILE_INFO
) - 1);
567 Status
= Utf8ToUtf16NoAllocUpdateLen(File
->basename
, Info
->FileName
, &tmpLen
);
568 if (EFI_ERROR(Status
)) {
569 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
570 PrintStatusError(Status
, L
"Could not convert basename to UTF-16");
572 *Len
= MINIMUM_INFO_LENGTH
;
577 /* The Info struct size already accounts for the extra NUL */
578 Info
->Size
= sizeof(EFI_FILE_INFO
) + tmpLen
;
579 *Len
= (INTN
)Info
->Size
;
582 } else if (CompareMem(Type
, &gEfiFileSystemInfoGuid
, sizeof(*Type
)) == 0) {
584 /* Get file system information */
585 PrintExtra(L
"Get file system information\n");
586 if (*Len
< sizeof(EFI_FILE_SYSTEM_INFO
)) {
587 *Len
= MINIMUM_FS_INFO_LENGTH
;
588 return EFI_BUFFER_TOO_SMALL
;
591 ZeroMem(Data
, sizeof(EFI_FILE_INFO
));
593 FSInfo
->ReadOnly
= 1;
594 /* NB: This should really be cluster size, but we don't have access to that */
595 if (File
->FileSystem
->BlockIo2
!= NULL
) {
596 FSInfo
->BlockSize
= File
->FileSystem
->BlockIo2
->Media
->BlockSize
;
598 FSInfo
->BlockSize
= File
->FileSystem
->BlockIo
->Media
->BlockSize
;
600 if (FSInfo
->BlockSize
== 0) {
601 PrintWarning(L
"Corrected Media BlockSize\n");
602 FSInfo
->BlockSize
= 512;
604 if (File
->FileSystem
->BlockIo2
!= NULL
) {
605 FSInfo
->VolumeSize
= (File
->FileSystem
->BlockIo2
->Media
->LastBlock
+ 1) *
608 FSInfo
->VolumeSize
= (File
->FileSystem
->BlockIo
->Media
->LastBlock
+ 1) *
611 /* No idea if we can easily get this for GRUB, and the device is RO anyway */
612 FSInfo
->FreeSpace
= 0;
614 Status
= GrubLabel(File
, &label
);
615 if (EFI_ERROR(Status
)) {
616 PrintStatusError(Status
, L
"Could not read disk label");
617 FSInfo
->VolumeLabel
[0] = 0;
618 *Len
= sizeof(EFI_FILE_SYSTEM_INFO
);
620 tmpLen
= (INTN
)(FSInfo
->Size
- sizeof(EFI_FILE_SYSTEM_INFO
) - 1);
621 Status
= Utf8ToUtf16NoAllocUpdateLen(label
, FSInfo
->VolumeLabel
, &tmpLen
);
622 if (EFI_ERROR(Status
)) {
623 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
624 PrintStatusError(Status
, L
"Could not convert label to UTF-16");
626 *Len
= MINIMUM_FS_INFO_LENGTH
;
630 FSInfo
->Size
= sizeof(EFI_FILE_SYSTEM_INFO
) - 1 + tmpLen
;
631 *Len
= (INTN
)FSInfo
->Size
;
635 } else if (CompareMem(Type
, &gEfiFileSystemVolumeLabelInfoIdGuid
, sizeof(*Type
)) == 0) {
637 /* Get the volume label */
638 Status
= GrubLabel(File
, &label
);
639 if (EFI_ERROR(Status
)) {
640 PrintStatusError(Status
, L
"Could not read disk label");
643 Status
= Utf8ToUtf16NoAllocUpdateLen(label
, VLInfo
->VolumeLabel
, Len
);
644 if (EFI_ERROR(Status
)) {
645 if (Status
!= EFI_BUFFER_TOO_SMALL
)
646 PrintStatusError(Status
, L
"Could not convert label to UTF-16");
654 Print(L
"'%s': Cannot get information of type ", FileName(File
));
657 return EFI_UNSUPPORTED
;
663 * Set file information
665 * @v This File handle
666 * @v Type Type of information
669 * @ret Status EFI status code
671 static EFI_STATUS EFIAPI
672 FileSetInfo(EFI_FILE_HANDLE This
, EFI_GUID
*Type
, UINTN Len
, VOID
*Data
)
674 EFI_GRUB_FILE
*File
= _CR(This
, EFI_GRUB_FILE
, EfiFile
);
676 Print(L
"Cannot set information of type ");
678 Print(L
" for file '%s'\n", FileName(File
));
680 return EFI_WRITE_PROTECTED
;
684 * Flush file modified data
686 * @v This File handle
687 * @v Type Type of information
690 * @ret Status EFI status code
692 static EFI_STATUS EFIAPI
693 FileFlush(EFI_FILE_HANDLE This
)
695 EFI_GRUB_FILE
*File
= _CR(This
, EFI_GRUB_FILE
, EfiFile
);
697 PrintInfo(L
"Flush(" PERCENT_P L
"|'%s')\n", (UINTN
) This
, FileName(File
));
702 static EFI_STATUS EFIAPI
703 FileFlushEx(EFI_FILE_HANDLE This
, EFI_FILE_IO_TOKEN
*Token
)
705 return FileFlush(This
);
709 * Open root directory
711 * @v This EFI simple file system
712 * @ret Root File handle for the root directory
713 * @ret Status EFI status code
716 FileOpenVolume(EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*This
, EFI_FILE_HANDLE
*Root
)
718 EFI_FS
*FSInstance
= _CR(This
, EFI_FS
, FileIoInterface
);
720 PrintInfo(L
"OpenVolume\n");
721 *Root
= &FSInstance
->RootFile
->EfiFile
;
727 * Install the EFI simple file system protocol
728 * If successful this call instantiates a new FS#: drive, that is made
729 * available on the next 'map -r'. Note that all this call does is add
730 * the FS protocol. OpenVolume won't be called until a process tries
731 * to access a file or the root directory on the volume.
734 FSInstall(EFI_FS
*This
, EFI_HANDLE ControllerHandle
)
738 /* Check if it's a filesystem we can handle */
739 if (!GrubFSProbe(This
))
740 return EFI_UNSUPPORTED
;
742 PrintInfo(L
"FSInstall: %s\n", This
->DevicePathString
);
744 /* Initialize the root handle */
745 Status
= GrubCreateFile(&This
->RootFile
, This
);
746 if (EFI_ERROR(Status
)) {
747 PrintStatusError(Status
, L
"Could not create root file");
751 /* Setup the EFI part */
752 This
->RootFile
->EfiFile
.Revision
= EFI_FILE_PROTOCOL_REVISION2
;
753 This
->RootFile
->EfiFile
.Open
= FileOpen
;
754 This
->RootFile
->EfiFile
.Close
= FileClose
;
755 This
->RootFile
->EfiFile
.Delete
= FileDelete
;
756 This
->RootFile
->EfiFile
.Read
= FileRead
;
757 This
->RootFile
->EfiFile
.Write
= FileWrite
;
758 This
->RootFile
->EfiFile
.GetPosition
= FileGetPosition
;
759 This
->RootFile
->EfiFile
.SetPosition
= FileSetPosition
;
760 This
->RootFile
->EfiFile
.GetInfo
= FileGetInfo
;
761 This
->RootFile
->EfiFile
.SetInfo
= FileSetInfo
;
762 This
->RootFile
->EfiFile
.Flush
= FileFlush
;
763 This
->RootFile
->EfiFile
.OpenEx
= FileOpenEx
;
764 This
->RootFile
->EfiFile
.ReadEx
= FileReadEx
;
765 This
->RootFile
->EfiFile
.WriteEx
= FileWriteEx
;
766 This
->RootFile
->EfiFile
.FlushEx
= FileFlushEx
;
768 /* Setup the other attributes */
769 This
->RootFile
->path
= "/";
770 This
->RootFile
->basename
= &This
->RootFile
->path
[1];
771 This
->RootFile
->IsDir
= TRUE
;
773 /* Install the simple file system protocol. */
774 Status
= BS
->InstallMultipleProtocolInterfaces(&ControllerHandle
,
775 &gEfiSimpleFileSystemProtocolGuid
, &This
->FileIoInterface
,
777 if (EFI_ERROR(Status
)) {
778 PrintStatusError(Status
, L
"Could not install simple file system protocol");
785 /* Uninstall EFI simple file system protocol */
787 FSUninstall(EFI_FS
*This
, EFI_HANDLE ControllerHandle
)
789 PrintInfo(L
"FSUninstall: %s\n", This
->DevicePathString
);
791 BS
->UninstallMultipleProtocolInterfaces(ControllerHandle
,
792 &gEfiSimpleFileSystemProtocolGuid
, &This
->FileIoInterface
,