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
< MINIMUM_INFO_LENGTH
) {
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 PrintStatusError(Status
, L
"Directory listing failed");
359 /* Our Index/FileSize must be reset */
361 Info
->PhysicalSize
= 0;
363 /* For regular files, we still need to fill the size */
364 if (!(Info
->Attribute
& EFI_FILE_DIRECTORY
)) {
365 /* Open the file and read its size */
366 Status
= GrubCreateFile(&TmpFile
, File
->FileSystem
);
367 if (EFI_ERROR(Status
)) {
368 PrintStatusError(Status
, L
"Unable to create temporary file");
371 TmpFile
->path
= path
;
373 Status
= GrubOpen(TmpFile
);
374 if (EFI_ERROR(Status
)) {
375 // TODO: EFI_NO_MAPPING is returned for links...
376 PrintStatusError(Status
, L
"Unable to obtain the size of '%s'", Info
->FileName
);
377 /* Non fatal error */
379 Info
->FileSize
= GrubGetFileSize(TmpFile
);
380 Info
->PhysicalSize
= GrubGetFileSize(TmpFile
);
383 GrubDestroyFile(TmpFile
);
386 *Len
= (UINTN
) Info
->Size
;
387 /* Advance to the next entry */
390 // PrintInfo(L" Entry[%d]: '%s' %s\n", File->DirIndex-1, Info->FileName,
391 // (Info->Attribute&EFI_FILE_DIRECTORY)?L"<DIR>":L"");
399 * @v This File handle
400 * @v Len Length to read
401 * @v Data Data buffer
402 * @ret Status EFI status code
404 static EFI_STATUS EFIAPI
405 FileRead(EFI_FILE_HANDLE This
, UINTN
*Len
, VOID
*Data
)
407 EFI_GRUB_FILE
*File
= _CR(This
, EFI_GRUB_FILE
, EfiFile
);
409 PrintInfo(L
"Read(" PERCENT_P L
"|'%s', %d) %s\n", (UINTN
) This
, FileName(File
),
410 *Len
, File
->IsDir
?L
"<DIR>":L
"");
412 /* If this is a directory, then fetch the directory entries */
414 return FileReadDir(File
, Len
, Data
);
416 return GrubRead(File
, Data
, Len
);
420 static EFI_STATUS EFIAPI
421 FileReadEx(IN EFI_FILE_PROTOCOL
*This
, IN OUT EFI_FILE_IO_TOKEN
*Token
)
423 return FileRead(This
, &(Token
->BufferSize
), Token
->Buffer
);
429 * @v This File handle
430 * @v Len Length to write
431 * @v Data Data buffer
432 * @ret Status EFI status code
434 static EFI_STATUS EFIAPI
435 FileWrite(EFI_FILE_HANDLE This
, UINTN
*Len
, VOID
*Data
)
437 EFI_GRUB_FILE
*File
= _CR(This
, EFI_GRUB_FILE
, EfiFile
);
439 PrintError(L
"Cannot write to '%s'\n", FileName(File
));
440 return EFI_WRITE_PROTECTED
;
444 static EFI_STATUS EFIAPI
445 FileWriteEx(IN EFI_FILE_PROTOCOL
*This
, IN OUT EFI_FILE_IO_TOKEN
*Token
)
447 return FileWrite(This
, &(Token
->BufferSize
), Token
->Buffer
);
453 * @v This File handle
454 * @v Position New file position
455 * @ret Status EFI status code
457 static EFI_STATUS EFIAPI
458 FileSetPosition(EFI_FILE_HANDLE This
, UINT64 Position
)
460 EFI_GRUB_FILE
*File
= _CR(This
, EFI_GRUB_FILE
, EfiFile
);
463 PrintInfo(L
"SetPosition(" PERCENT_P L
"|'%s', %lld) %s\n", (UINTN
) This
,
464 FileName(File
), Position
, (File
->IsDir
)?L
"<DIR>":L
"");
466 /* If this is a directory, reset the Index to the start */
469 return EFI_INVALID_PARAMETER
;
474 /* Fail if we attempt to seek past the end of the file (since
475 * we do not support writes).
477 FileSize
= GrubGetFileSize(File
);
478 if (Position
> FileSize
) {
479 PrintError(L
"'%s': Cannot seek to #%llx of %llx\n",
480 FileName(File
), Position
, FileSize
);
481 return EFI_UNSUPPORTED
;
485 GrubSetFileOffset(File
, Position
);
486 PrintDebug(L
"'%s': Position set to %llx\n",
487 FileName(File
), Position
);
495 * @v This File handle
496 * @ret Position New file position
497 * @ret Status EFI status code
499 static EFI_STATUS EFIAPI
500 FileGetPosition(EFI_FILE_HANDLE This
, UINT64
*Position
)
502 EFI_GRUB_FILE
*File
= _CR(This
, EFI_GRUB_FILE
, EfiFile
);
504 PrintInfo(L
"GetPosition(" PERCENT_P L
"|'%s', %lld)\n", (UINTN
) This
, FileName(File
));
507 *Position
= File
->DirIndex
;
509 *Position
= GrubGetFileOffset(File
);
514 * Get file information
516 * @v This File handle
517 * @v Type Type of information
520 * @ret Status EFI status code
522 static EFI_STATUS EFIAPI
523 FileGetInfo(EFI_FILE_HANDLE This
, EFI_GUID
*Type
, UINTN
*Len
, VOID
*Data
)
526 EFI_GRUB_FILE
*File
= _CR(This
, EFI_GRUB_FILE
, EfiFile
);
527 EFI_FILE_SYSTEM_INFO
*FSInfo
= (EFI_FILE_SYSTEM_INFO
*) Data
;
528 EFI_FILE_INFO
*Info
= (EFI_FILE_INFO
*) Data
;
529 EFI_FILE_SYSTEM_VOLUME_LABEL_INFO
*VLInfo
= (EFI_FILE_SYSTEM_VOLUME_LABEL_INFO
*)Data
;
534 PrintInfo(L
"GetInfo(" PERCENT_P L
"|'%s', %d) %s\n", (UINTN
) This
,
535 FileName(File
), *Len
, File
->IsDir
?L
"<DIR>":L
"");
537 /* Determine information to return */
538 if (CompareMem(Type
, &gEfiFileInfoGuid
, sizeof(*Type
)) == 0) {
540 /* Fill file information */
541 PrintExtra(L
"Get regular file information\n");
542 if (*Len
< MINIMUM_INFO_LENGTH
) {
543 *Len
= MINIMUM_INFO_LENGTH
;
544 return EFI_BUFFER_TOO_SMALL
;
547 ZeroMem(Data
, sizeof(EFI_FILE_INFO
));
549 Info
->Attribute
= EFI_FILE_READ_ONLY
;
550 GrubTimeToEfiTime(File
->Mtime
, &Time
);
551 CopyMem(&Info
->CreateTime
, &Time
, sizeof(Time
));
552 CopyMem(&Info
->LastAccessTime
, &Time
, sizeof(Time
));
553 CopyMem(&Info
->ModificationTime
, &Time
, sizeof(Time
));
556 Info
->Attribute
|= EFI_FILE_DIRECTORY
;
558 Info
->FileSize
= GrubGetFileSize(File
);
559 Info
->PhysicalSize
= GrubGetFileSize(File
);
562 tmpLen
= (UINTN
)(Info
->Size
- sizeof(EFI_FILE_INFO
) - 1);
563 Status
= Utf8ToUtf16NoAllocUpdateLen(File
->basename
, Info
->FileName
, &tmpLen
);
564 if (EFI_ERROR(Status
)) {
565 if (Status
!= EFI_BUFFER_TOO_SMALL
)
566 PrintStatusError(Status
, L
"Could not convert basename to UTF-16");
570 /* The Info struct size already accounts for the extra NUL */
571 Info
->Size
= sizeof(EFI_FILE_INFO
) + tmpLen
;
572 *Len
= (INTN
)Info
->Size
;
575 } else if (CompareMem(Type
, &gEfiFileSystemInfoGuid
, sizeof(*Type
)) == 0) {
577 /* Get file system information */
578 PrintExtra(L
"Get file system information\n");
579 if (*Len
< MINIMUM_FS_INFO_LENGTH
) {
580 *Len
= MINIMUM_FS_INFO_LENGTH
;
581 return EFI_BUFFER_TOO_SMALL
;
584 ZeroMem(Data
, sizeof(EFI_FILE_INFO
));
586 FSInfo
->ReadOnly
= 1;
587 /* NB: This should really be cluster size, but we don't have access to that */
588 if (File
->FileSystem
->BlockIo2
!= NULL
) {
589 FSInfo
->BlockSize
= File
->FileSystem
->BlockIo2
->Media
->BlockSize
;
591 FSInfo
->BlockSize
= File
->FileSystem
->BlockIo
->Media
->BlockSize
;
593 if (FSInfo
->BlockSize
== 0) {
594 PrintWarning(L
"Corrected Media BlockSize\n");
595 FSInfo
->BlockSize
= 512;
597 if (File
->FileSystem
->BlockIo2
!= NULL
) {
598 FSInfo
->VolumeSize
= (File
->FileSystem
->BlockIo2
->Media
->LastBlock
+ 1) *
601 FSInfo
->VolumeSize
= (File
->FileSystem
->BlockIo
->Media
->LastBlock
+ 1) *
604 /* No idea if we can easily get this for GRUB, and the device is RO anyway */
605 FSInfo
->FreeSpace
= 0;
607 Status
= GrubLabel(File
, &label
);
608 if (EFI_ERROR(Status
)) {
609 PrintStatusError(Status
, L
"Could not read disk label");
610 FSInfo
->VolumeLabel
[0] = 0;
611 *Len
= sizeof(EFI_FILE_SYSTEM_INFO
);
613 tmpLen
= (INTN
)(FSInfo
->Size
- sizeof(EFI_FILE_SYSTEM_INFO
) - 1);
614 Status
= Utf8ToUtf16NoAllocUpdateLen(label
, FSInfo
->VolumeLabel
, &tmpLen
);
615 if (EFI_ERROR(Status
)) {
616 if (Status
!= EFI_BUFFER_TOO_SMALL
)
617 PrintStatusError(Status
, L
"Could not convert label to UTF-16");
620 FSInfo
->Size
= sizeof(EFI_FILE_SYSTEM_INFO
) - 1 + tmpLen
;
621 *Len
= (INTN
)FSInfo
->Size
;
625 } else if (CompareMem(Type
, &gEfiFileSystemVolumeLabelInfoIdGuid
, sizeof(*Type
)) == 0) {
627 /* Get the volume label */
628 Status
= GrubLabel(File
, &label
);
629 if (EFI_ERROR(Status
)) {
630 PrintStatusError(Status
, L
"Could not read disk label");
633 Status
= Utf8ToUtf16NoAllocUpdateLen(label
, VLInfo
->VolumeLabel
, Len
);
634 if (EFI_ERROR(Status
)) {
635 if (Status
!= EFI_BUFFER_TOO_SMALL
)
636 PrintStatusError(Status
, L
"Could not convert label to UTF-16");
644 Print(L
"'%s': Cannot get information of type ", FileName(File
));
647 return EFI_UNSUPPORTED
;
653 * Set file information
655 * @v This File handle
656 * @v Type Type of information
659 * @ret Status EFI status code
661 static EFI_STATUS EFIAPI
662 FileSetInfo(EFI_FILE_HANDLE This
, EFI_GUID
*Type
, UINTN Len
, VOID
*Data
)
664 EFI_GRUB_FILE
*File
= _CR(This
, EFI_GRUB_FILE
, EfiFile
);
666 Print(L
"Cannot set information of type ");
668 Print(L
" for file '%s'\n", FileName(File
));
670 return EFI_WRITE_PROTECTED
;
674 * Flush file modified data
676 * @v This File handle
677 * @v Type Type of information
680 * @ret Status EFI status code
682 static EFI_STATUS EFIAPI
683 FileFlush(EFI_FILE_HANDLE This
)
685 EFI_GRUB_FILE
*File
= _CR(This
, EFI_GRUB_FILE
, EfiFile
);
687 PrintInfo(L
"Flush(" PERCENT_P L
"|'%s')\n", (UINTN
) This
, FileName(File
));
692 static EFI_STATUS EFIAPI
693 FileFlushEx(EFI_FILE_HANDLE This
, EFI_FILE_IO_TOKEN
*Token
)
695 return FileFlush(This
);
699 * Open root directory
701 * @v This EFI simple file system
702 * @ret Root File handle for the root directory
703 * @ret Status EFI status code
706 FileOpenVolume(EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*This
, EFI_FILE_HANDLE
*Root
)
708 EFI_FS
*FSInstance
= _CR(This
, EFI_FS
, FileIoInterface
);
710 PrintInfo(L
"OpenVolume\n");
711 *Root
= &FSInstance
->RootFile
->EfiFile
;
717 * Install the EFI simple file system protocol
718 * If successful this call instantiates a new FS#: drive, that is made
719 * available on the next 'map -r'. Note that all this call does is add
720 * the FS protocol. OpenVolume won't be called until a process tries
721 * to access a file or the root directory on the volume.
724 FSInstall(EFI_FS
*This
, EFI_HANDLE ControllerHandle
)
728 /* Check if it's a filesystem we can handle */
729 if (!GrubFSProbe(This
))
730 return EFI_UNSUPPORTED
;
732 PrintInfo(L
"FSInstall: %s\n", This
->DevicePathString
);
734 /* Initialize the root handle */
735 Status
= GrubCreateFile(&This
->RootFile
, This
);
736 if (EFI_ERROR(Status
)) {
737 PrintStatusError(Status
, L
"Could not create root file");
741 /* Setup the EFI part */
742 This
->RootFile
->EfiFile
.Revision
= EFI_FILE_PROTOCOL_REVISION2
;
743 This
->RootFile
->EfiFile
.Open
= FileOpen
;
744 This
->RootFile
->EfiFile
.Close
= FileClose
;
745 This
->RootFile
->EfiFile
.Delete
= FileDelete
;
746 This
->RootFile
->EfiFile
.Read
= FileRead
;
747 This
->RootFile
->EfiFile
.Write
= FileWrite
;
748 This
->RootFile
->EfiFile
.GetPosition
= FileGetPosition
;
749 This
->RootFile
->EfiFile
.SetPosition
= FileSetPosition
;
750 This
->RootFile
->EfiFile
.GetInfo
= FileGetInfo
;
751 This
->RootFile
->EfiFile
.SetInfo
= FileSetInfo
;
752 This
->RootFile
->EfiFile
.Flush
= FileFlush
;
753 This
->RootFile
->EfiFile
.OpenEx
= FileOpenEx
;
754 This
->RootFile
->EfiFile
.ReadEx
= FileReadEx
;
755 This
->RootFile
->EfiFile
.WriteEx
= FileWriteEx
;
756 This
->RootFile
->EfiFile
.FlushEx
= FileFlushEx
;
758 /* Setup the other attributes */
759 This
->RootFile
->path
= "/";
760 This
->RootFile
->basename
= &This
->RootFile
->path
[1];
761 This
->RootFile
->IsDir
= TRUE
;
763 /* Install the simple file system protocol. */
764 Status
= BS
->InstallMultipleProtocolInterfaces(&ControllerHandle
,
765 &gEfiSimpleFileSystemProtocolGuid
, &This
->FileIoInterface
,
767 if (EFI_ERROR(Status
)) {
768 PrintStatusError(Status
, L
"Could not install simple file system protocol");
775 /* Uninstall EFI simple file system protocol */
777 FSUninstall(EFI_FS
*This
, EFI_HANDLE ControllerHandle
)
779 PrintInfo(L
"FSUninstall: %s\n", This
->DevicePathString
);
781 BS
->UninstallMultipleProtocolInterfaces(ControllerHandle
,
782 &gEfiSimpleFileSystemProtocolGuid
, &This
->FileIoInterface
,