2 POSIX Pthreads to emulate APs and implement threads
4 Copyright (c) 2011, Apple Inc. All rights reserved.
5 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
14 #define EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE SIGNATURE_32 ('E', 'P', 'f', 's')
18 EMU_IO_THUNK_PROTOCOL
*Thunk
;
19 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL SimpleFileSystem
;
22 BOOLEAN FileHandlesOpen
;
23 } EMU_SIMPLE_FILE_SYSTEM_PRIVATE
;
25 #define EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS(a) \
27 EMU_SIMPLE_FILE_SYSTEM_PRIVATE, \
29 EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE \
33 #define EMU_EFI_FILE_PRIVATE_SIGNATURE SIGNATURE_32 ('E', 'P', 'f', 'i')
37 EMU_IO_THUNK_PROTOCOL
*Thunk
;
38 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*SimpleFileSystem
;
39 EFI_FILE_PROTOCOL EfiFile
;
42 BOOLEAN IsRootDirectory
;
43 BOOLEAN IsDirectoryPath
;
44 BOOLEAN IsOpenedByRead
;
46 struct dirent
*Dirent
;
47 } EMU_EFI_FILE_PRIVATE
;
49 #define EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS(a) \
51 EMU_EFI_FILE_PRIVATE, \
53 EMU_EFI_FILE_PRIVATE_SIGNATURE \
58 IN EFI_FILE_PROTOCOL
*This
,
59 IN EFI_GUID
*InformationType
,
60 IN OUT UINTN
*BufferSize
,
66 IN EFI_FILE_PROTOCOL
*This
,
67 IN EFI_GUID
*InformationType
,
73 EFI_FILE_PROTOCOL gPosixFileProtocol
= {
77 GasketPosixFileDelete
,
80 GasketPosixFileGetPossition
,
81 GasketPosixFileSetPossition
,
82 GasketPosixFileGetInfo
,
83 GasketPosixFileSetInfo
,
87 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gPosixFileSystemProtocol
= {
88 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
,
89 GasketPosixOpenVolume
,
94 Open the root directory on a volume.
96 @param This Protocol instance pointer.
97 @param Root Returns an Open file handle for the root directory
99 @retval EFI_SUCCESS The device was opened.
100 @retval EFI_UNSUPPORTED This volume does not support the file system.
101 @retval EFI_NO_MEDIA The device has no media.
102 @retval EFI_DEVICE_ERROR The device reported an error.
103 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
104 @retval EFI_ACCESS_DENIED The service denied access to the file.
105 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
110 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*This
,
111 OUT EFI_FILE_PROTOCOL
**Root
115 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*Private
;
116 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
118 Private
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (This
);
120 Status
= EFI_OUT_OF_RESOURCES
;
121 PrivateFile
= malloc (sizeof (EMU_EFI_FILE_PRIVATE
));
122 if (PrivateFile
== NULL
) {
126 PrivateFile
->FileName
= malloc (AsciiStrSize (Private
->FilePath
));
127 if (PrivateFile
->FileName
== NULL
) {
131 PrivateFile
->FileName
,
132 AsciiStrSize (Private
->FilePath
),
136 PrivateFile
->Signature
= EMU_EFI_FILE_PRIVATE_SIGNATURE
;
137 PrivateFile
->Thunk
= Private
->Thunk
;
138 PrivateFile
->SimpleFileSystem
= This
;
139 PrivateFile
->IsRootDirectory
= TRUE
;
140 PrivateFile
->IsDirectoryPath
= TRUE
;
141 PrivateFile
->IsOpenedByRead
= TRUE
;
143 CopyMem (&PrivateFile
->EfiFile
, &gPosixFileProtocol
, sizeof (EFI_FILE_PROTOCOL
));
145 PrivateFile
->fd
= -1;
146 PrivateFile
->Dir
= NULL
;
147 PrivateFile
->Dirent
= NULL
;
149 *Root
= &PrivateFile
->EfiFile
;
151 PrivateFile
->Dir
= opendir (PrivateFile
->FileName
);
152 if (PrivateFile
->Dir
== NULL
) {
153 Status
= EFI_ACCESS_DENIED
;
155 Status
= EFI_SUCCESS
;
159 if (EFI_ERROR (Status
)) {
160 if (PrivateFile
!= NULL
) {
161 if (PrivateFile
->FileName
!= NULL
) {
162 free (PrivateFile
->FileName
);
180 return EFI_ACCESS_DENIED
;
184 return EFI_VOLUME_FULL
;
187 return EFI_DEVICE_ERROR
;
199 if (AsciiStrLen (Str
) < Count
) {
203 for (Pointer
= Str
; *(Pointer
+ Count
); Pointer
++) {
204 *Pointer
= *(Pointer
+ Count
);
207 *Pointer
= *(Pointer
+ Count
);
212 PosixSystemTimeToEfiTime (
213 IN
time_t SystemTime
,
219 tm
= gmtime (&SystemTime
);
220 Time
->Year
= tm
->tm_year
;
221 Time
->Month
= tm
->tm_mon
+ 1;
222 Time
->Day
= tm
->tm_mday
;
223 Time
->Hour
= tm
->tm_hour
;
224 Time
->Minute
= tm
->tm_min
;
225 Time
->Second
= tm
->tm_sec
;
226 Time
->Nanosecond
= 0;
228 Time
->TimeZone
= timezone
/ 60;
229 Time
->Daylight
= (daylight
? EFI_TIME_ADJUST_DAYLIGHT
: 0) | (tm
->tm_isdst
> 0 ? EFI_TIME_IN_DAYLIGHT
: 0);
234 UnixSimpleFileSystemFileInfo (
235 EMU_EFI_FILE_PRIVATE
*PrivateFile
,
237 IN OUT UINTN
*BufferSize
,
248 CHAR16
*BufferFileName
;
251 if (FileName
!= NULL
) {
252 RealFileName
= FileName
;
253 } else if (PrivateFile
->IsRootDirectory
) {
256 RealFileName
= PrivateFile
->FileName
;
259 TempPointer
= RealFileName
;
260 while (*TempPointer
) {
261 if (*TempPointer
== '/') {
262 RealFileName
= TempPointer
+ 1;
268 Size
= SIZE_OF_EFI_FILE_INFO
;
269 NameSize
= AsciiStrSize (RealFileName
) * 2;
270 ResultSize
= Size
+ NameSize
;
272 if (*BufferSize
< ResultSize
) {
273 *BufferSize
= ResultSize
;
274 return EFI_BUFFER_TOO_SMALL
;
276 if (stat (FileName
== NULL
? PrivateFile
->FileName
: FileName
, &buf
) < 0) {
277 return EFI_DEVICE_ERROR
;
280 Status
= EFI_SUCCESS
;
283 ZeroMem (Info
, ResultSize
);
285 Info
->Size
= ResultSize
;
286 Info
->FileSize
= buf
.st_size
;
287 Info
->PhysicalSize
= MultU64x32 (buf
.st_blocks
, buf
.st_blksize
);
289 PosixSystemTimeToEfiTime (buf
.st_ctime
, &Info
->CreateTime
);
290 PosixSystemTimeToEfiTime (buf
.st_atime
, &Info
->LastAccessTime
);
291 PosixSystemTimeToEfiTime (buf
.st_mtime
, &Info
->ModificationTime
);
293 if (!(buf
.st_mode
& S_IWUSR
)) {
294 Info
->Attribute
|= EFI_FILE_READ_ONLY
;
297 if (S_ISDIR(buf
.st_mode
)) {
298 Info
->Attribute
|= EFI_FILE_DIRECTORY
;
302 BufferFileName
= (CHAR16
*)((CHAR8
*) Buffer
+ Size
);
303 while (*RealFileName
) {
304 *BufferFileName
++ = *RealFileName
++;
308 *BufferSize
= ResultSize
;
318 if (Buffer
== NULL
|| Length
== 0) {
322 if (*(UINT8
*) Buffer
!= 0) {
327 if (!CompareMem (Buffer
, (UINT8
*) Buffer
+ 1, Length
- 1)) {
338 Opens a new file relative to the source file's location.
340 @param This The protocol instance pointer.
341 @param NewHandle Returns File Handle for FileName.
342 @param FileName Null terminated string. "\", ".", and ".." are supported.
343 @param OpenMode Open mode for file.
344 @param Attributes Only used for EFI_FILE_MODE_CREATE.
346 @retval EFI_SUCCESS The device was opened.
347 @retval EFI_NOT_FOUND The specified file could not be found on the device.
348 @retval EFI_NO_MEDIA The device has no media.
349 @retval EFI_MEDIA_CHANGED The media has changed.
350 @retval EFI_DEVICE_ERROR The device reported an error.
351 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
352 @retval EFI_ACCESS_DENIED The service denied access to the file.
353 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
354 @retval EFI_VOLUME_FULL The volume is full.
359 IN EFI_FILE_PROTOCOL
*This
,
360 OUT EFI_FILE_PROTOCOL
**NewHandle
,
366 EFI_FILE_PROTOCOL
*Root
;
367 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
368 EMU_EFI_FILE_PRIVATE
*NewPrivateFile
;
369 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*PrivateRoot
;
378 BOOLEAN TrailingDash
;
386 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
387 PrivateRoot
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile
->SimpleFileSystem
);
388 NewPrivateFile
= NULL
;
389 Status
= EFI_OUT_OF_RESOURCES
;
392 // BUGBUG: assume an open of root
393 // if current location, return current data
395 TrailingDash
= FALSE
;
396 if ((StrCmp (FileName
, L
"\\") == 0) ||
397 (StrCmp (FileName
, L
".") == 0 && PrivateFile
->IsRootDirectory
)) {
399 Status
= PosixOpenVolume (PrivateFile
->SimpleFileSystem
, &Root
);
400 NewPrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (Root
);
404 if (FileName
[StrLen (FileName
) - 1] == L
'\\') {
406 FileName
[StrLen (FileName
) - 1] = 0;
410 // Attempt to open the file
412 NewPrivateFile
= malloc (sizeof (EMU_EFI_FILE_PRIVATE
));
413 if (NewPrivateFile
== NULL
) {
417 CopyMem (NewPrivateFile
, PrivateFile
, sizeof (EMU_EFI_FILE_PRIVATE
));
419 Size
= AsciiStrSize (PrivateFile
->FileName
) + 1 + StrLen (FileName
) + 1;
420 NewPrivateFile
->FileName
= malloc (Size
);
421 if (NewPrivateFile
->FileName
== NULL
) {
425 if (*FileName
== L
'\\') {
426 AsciiStrCpyS (NewPrivateFile
->FileName
, Size
, PrivateRoot
->FilePath
);
430 AsciiStrCpyS (NewPrivateFile
->FileName
, Size
, PrivateFile
->FileName
);
433 Dst
= NewPrivateFile
->FileName
+ AsciiStrLen (NewPrivateFile
->FileName
);
434 GuardPointer
= NewPrivateFile
->FileName
+ AsciiStrLen (PrivateRoot
->FilePath
);
436 // Convert unicode to ascii and '\' to '/'
449 // Get rid of . and .., except leading . or ..
453 // GuardPointer protect simplefilesystem root path not be destroyed
457 while (!LoopFinish
) {
460 for (ParseFileName
= GuardPointer
; *ParseFileName
; ParseFileName
++) {
461 if (*ParseFileName
== '.' &&
462 (*(ParseFileName
+ 1) == 0 || *(ParseFileName
+ 1) == '/') &&
463 *(ParseFileName
- 1) == '/'
469 CutPrefix (ParseFileName
- 1, 2);
474 if (*ParseFileName
== '.' &&
475 *(ParseFileName
+ 1) == '.' &&
476 (*(ParseFileName
+ 2) == 0 || *(ParseFileName
+ 2) == '/') &&
477 *(ParseFileName
- 1) == '/'
483 while (ParseFileName
!= GuardPointer
) {
486 if (*ParseFileName
== '/') {
492 // cut /.. and its left directory
494 CutPrefix (ParseFileName
, Count
);
501 if (AsciiStrCmp (NewPrivateFile
->FileName
, PrivateRoot
->FilePath
) == 0) {
502 NewPrivateFile
->IsRootDirectory
= TRUE
;
503 free (NewPrivateFile
->FileName
);
504 free (NewPrivateFile
);
508 RealFileName
= NewPrivateFile
->FileName
+ AsciiStrLen(NewPrivateFile
->FileName
) - 1;
509 while (RealFileName
> NewPrivateFile
->FileName
&& *RealFileName
!= '/') {
513 TempChar
= *(RealFileName
- 1);
514 *(RealFileName
- 1) = 0;
515 *(RealFileName
- 1) = TempChar
;
519 // Test whether file or directory
521 NewPrivateFile
->IsRootDirectory
= FALSE
;
522 NewPrivateFile
->fd
= -1;
523 NewPrivateFile
->Dir
= NULL
;
524 if (OpenMode
& EFI_FILE_MODE_CREATE
) {
525 if (Attributes
& EFI_FILE_DIRECTORY
) {
526 NewPrivateFile
->IsDirectoryPath
= TRUE
;
528 NewPrivateFile
->IsDirectoryPath
= FALSE
;
531 res
= stat (NewPrivateFile
->FileName
, &finfo
);
532 if (res
== 0 && S_ISDIR(finfo
.st_mode
)) {
533 NewPrivateFile
->IsDirectoryPath
= TRUE
;
535 NewPrivateFile
->IsDirectoryPath
= FALSE
;
539 if (OpenMode
& EFI_FILE_MODE_WRITE
) {
540 NewPrivateFile
->IsOpenedByRead
= FALSE
;
542 NewPrivateFile
->IsOpenedByRead
= TRUE
;
545 Status
= EFI_SUCCESS
;
548 // deal with directory
550 if (NewPrivateFile
->IsDirectoryPath
) {
551 if ((OpenMode
& EFI_FILE_MODE_CREATE
)) {
553 // Create a directory
555 if (mkdir (NewPrivateFile
->FileName
, 0777) != 0) {
556 if (errno
!= EEXIST
) {
557 //free (TempFileName);
558 Status
= EFI_ACCESS_DENIED
;
564 NewPrivateFile
->Dir
= opendir (NewPrivateFile
->FileName
);
565 if (NewPrivateFile
->Dir
== NULL
) {
566 if (errno
== EACCES
) {
567 Status
= EFI_ACCESS_DENIED
;
569 Status
= EFI_NOT_FOUND
;
579 NewPrivateFile
->fd
= open (
580 NewPrivateFile
->FileName
,
581 ((OpenMode
& EFI_FILE_MODE_CREATE
) ? O_CREAT
: 0) | (NewPrivateFile
->IsOpenedByRead
? O_RDONLY
: O_RDWR
),
584 if (NewPrivateFile
->fd
< 0) {
585 if (errno
== ENOENT
) {
586 Status
= EFI_NOT_FOUND
;
588 Status
= EFI_ACCESS_DENIED
;
593 if ((OpenMode
& EFI_FILE_MODE_CREATE
) && Status
== EFI_SUCCESS
) {
599 Status
= PosixFileGetInfo (&NewPrivateFile
->EfiFile
, &gEfiFileInfoGuid
, &InfoSize
, Info
);
600 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
601 Status
= EFI_DEVICE_ERROR
;
605 Info
= malloc (InfoSize
);
610 Status
= PosixFileGetInfo (&NewPrivateFile
->EfiFile
, &gEfiFileInfoGuid
, &InfoSize
, Info
);
611 if (EFI_ERROR (Status
)) {
615 Info
->Attribute
= Attributes
;
616 PosixFileSetInfo (&NewPrivateFile
->EfiFile
, &gEfiFileInfoGuid
, InfoSize
, Info
);
623 FileName
[StrLen (FileName
) + 1] = 0;
624 FileName
[StrLen (FileName
)] = L
'\\';
627 if (EFI_ERROR (Status
)) {
628 if (NewPrivateFile
) {
629 if (NewPrivateFile
->FileName
) {
630 free (NewPrivateFile
->FileName
);
633 free (NewPrivateFile
);
636 *NewHandle
= &NewPrivateFile
->EfiFile
;
645 Close the file handle
647 @param This Protocol instance pointer.
649 @retval EFI_SUCCESS The device was opened.
654 IN EFI_FILE_PROTOCOL
*This
657 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
659 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
661 if (PrivateFile
->fd
>= 0) {
662 close (PrivateFile
->fd
);
664 if (PrivateFile
->Dir
!= NULL
) {
665 closedir (PrivateFile
->Dir
);
668 PrivateFile
->fd
= -1;
669 PrivateFile
->Dir
= NULL
;
671 if (PrivateFile
->FileName
) {
672 free (PrivateFile
->FileName
);
682 Close and delete the file handle.
684 @param This Protocol instance pointer.
686 @retval EFI_SUCCESS The device was opened.
687 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.
692 IN EFI_FILE_PROTOCOL
*This
696 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
698 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
699 Status
= EFI_WARN_DELETE_FAILURE
;
701 if (PrivateFile
->IsDirectoryPath
) {
702 if (PrivateFile
->Dir
!= NULL
) {
703 closedir (PrivateFile
->Dir
);
704 PrivateFile
->Dir
= NULL
;
707 if (rmdir (PrivateFile
->FileName
) == 0) {
708 Status
= EFI_SUCCESS
;
711 close (PrivateFile
->fd
);
712 PrivateFile
->fd
= -1;
714 if (!PrivateFile
->IsOpenedByRead
) {
715 if (!unlink (PrivateFile
->FileName
)) {
716 Status
= EFI_SUCCESS
;
721 free (PrivateFile
->FileName
);
729 Read data from the file.
731 @param This Protocol instance pointer.
732 @param BufferSize On input size of buffer, on output amount of data in buffer.
733 @param Buffer The buffer in which data is read.
735 @retval EFI_SUCCESS Data was read.
736 @retval EFI_NO_MEDIA The device has no media.
737 @retval EFI_DEVICE_ERROR The device reported an error.
738 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
739 @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size.
744 IN EFI_FILE_PROTOCOL
*This
,
745 IN OUT UINTN
*BufferSize
,
749 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
756 UINTN FullFileNameSize
;
758 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
760 if (!PrivateFile
->IsDirectoryPath
) {
761 if (PrivateFile
->fd
< 0) {
762 Status
= EFI_DEVICE_ERROR
;
766 Res
= read (PrivateFile
->fd
, Buffer
, *BufferSize
);
768 Status
= EFI_DEVICE_ERROR
;
772 Status
= EFI_SUCCESS
;
777 // Read on a directory.
779 if (PrivateFile
->Dir
== NULL
) {
780 Status
= EFI_DEVICE_ERROR
;
784 if (PrivateFile
->Dirent
== NULL
) {
785 PrivateFile
->Dirent
= readdir (PrivateFile
->Dir
);
786 if (PrivateFile
->Dirent
== NULL
) {
788 Status
= EFI_SUCCESS
;
793 Size
= SIZE_OF_EFI_FILE_INFO
;
794 NameSize
= AsciiStrLen (PrivateFile
->Dirent
->d_name
) + 1;
795 ResultSize
= Size
+ 2 * NameSize
;
797 if (*BufferSize
< ResultSize
) {
798 *BufferSize
= ResultSize
;
799 Status
= EFI_BUFFER_TOO_SMALL
;
802 Status
= EFI_SUCCESS
;
804 *BufferSize
= ResultSize
;
806 FullFileNameSize
= AsciiStrLen(PrivateFile
->FileName
) + 1 + NameSize
;
807 FullFileName
= malloc (FullFileNameSize
);
808 if (FullFileName
== NULL
) {
809 Status
= EFI_OUT_OF_RESOURCES
;
813 AsciiStrCpyS (FullFileName
, FullFileNameSize
, PrivateFile
->FileName
);
814 AsciiStrCatS (FullFileName
, FullFileNameSize
, "/");
815 AsciiStrCatS (FullFileName
, FullFileNameSize
, PrivateFile
->Dirent
->d_name
);
816 Status
= UnixSimpleFileSystemFileInfo (
824 PrivateFile
->Dirent
= NULL
;
833 Write data to a file.
835 @param This Protocol instance pointer.
836 @param BufferSize On input size of buffer, on output amount of data in buffer.
837 @param Buffer The buffer in which data to write.
839 @retval EFI_SUCCESS Data was written.
840 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
841 @retval EFI_NO_MEDIA The device has no media.
842 @retval EFI_DEVICE_ERROR The device reported an error.
843 @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
844 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
845 @retval EFI_WRITE_PROTECTED The device is write protected.
846 @retval EFI_ACCESS_DENIED The file was open for read only.
847 @retval EFI_VOLUME_FULL The volume is full.
852 IN EFI_FILE_PROTOCOL
*This
,
853 IN OUT UINTN
*BufferSize
,
857 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
861 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
863 if (PrivateFile
->fd
< 0) {
864 return EFI_DEVICE_ERROR
;
867 if (PrivateFile
->IsDirectoryPath
) {
868 return EFI_UNSUPPORTED
;
871 if (PrivateFile
->IsOpenedByRead
) {
872 return EFI_ACCESS_DENIED
;
875 Res
= write (PrivateFile
->fd
, Buffer
, *BufferSize
);
876 if (Res
== (UINTN
)-1) {
877 return ErrnoToEfiStatus ();
887 Set a files current position
889 @param This Protocol instance pointer.
890 @param Position Byte position from the start of the file.
892 @retval EFI_SUCCESS Data was written.
893 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
897 PosixFileSetPossition (
898 IN EFI_FILE_PROTOCOL
*This
,
902 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
905 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
907 if (PrivateFile
->IsDirectoryPath
) {
909 return EFI_UNSUPPORTED
;
912 if (PrivateFile
->Dir
== NULL
) {
913 return EFI_DEVICE_ERROR
;
915 rewinddir (PrivateFile
->Dir
);
918 if (Position
== (UINT64
) -1) {
919 Pos
= lseek (PrivateFile
->fd
, 0, SEEK_END
);
921 Pos
= lseek (PrivateFile
->fd
, Position
, SEEK_SET
);
923 if (Pos
== (off_t
)-1) {
924 return ErrnoToEfiStatus ();
933 Get a file's current position
935 @param This Protocol instance pointer.
936 @param Position Byte position from the start of the file.
938 @retval EFI_SUCCESS Data was written.
939 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..
943 PosixFileGetPossition (
944 IN EFI_FILE_PROTOCOL
*This
,
949 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
951 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
953 if (PrivateFile
->IsDirectoryPath
) {
954 Status
= EFI_UNSUPPORTED
;
956 *Position
= (UINT64
)lseek (PrivateFile
->fd
, 0, SEEK_CUR
);
957 Status
= (*Position
== (UINT64
) -1) ? ErrnoToEfiStatus () : EFI_SUCCESS
;
965 Get information about a file.
967 @param This Protocol instance pointer.
968 @param InformationType Type of information to return in Buffer.
969 @param BufferSize On input size of buffer, on output amount of data in buffer.
970 @param Buffer The buffer to return data.
972 @retval EFI_SUCCESS Data was returned.
973 @retval EFI_UNSUPPORTED InformationType is not supported.
974 @retval EFI_NO_MEDIA The device has no media.
975 @retval EFI_DEVICE_ERROR The device reported an error.
976 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
977 @retval EFI_WRITE_PROTECTED The device is write protected.
978 @retval EFI_ACCESS_DENIED The file was open for read only.
979 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
984 IN EFI_FILE_PROTOCOL
*This
,
985 IN EFI_GUID
*InformationType
,
986 IN OUT UINTN
*BufferSize
,
991 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
992 EFI_FILE_SYSTEM_INFO
*FileSystemInfoBuffer
;
994 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*PrivateRoot
;
997 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
998 PrivateRoot
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile
->SimpleFileSystem
);
1000 Status
= EFI_SUCCESS
;
1001 if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
1002 Status
= UnixSimpleFileSystemFileInfo (PrivateFile
, NULL
, BufferSize
, Buffer
);
1003 } else if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
1004 if (*BufferSize
< SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
)) {
1005 *BufferSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
);
1006 return EFI_BUFFER_TOO_SMALL
;
1009 UnixStatus
= statfs (PrivateFile
->FileName
, &buf
);
1010 if (UnixStatus
< 0) {
1011 return EFI_DEVICE_ERROR
;
1014 FileSystemInfoBuffer
= (EFI_FILE_SYSTEM_INFO
*) Buffer
;
1015 FileSystemInfoBuffer
->Size
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
);
1016 FileSystemInfoBuffer
->ReadOnly
= FALSE
;
1021 FileSystemInfoBuffer
->VolumeSize
= MultU64x32 (buf
.f_blocks
, buf
.f_bsize
);
1022 FileSystemInfoBuffer
->FreeSpace
= MultU64x32 (buf
.f_bavail
, buf
.f_bsize
);
1023 FileSystemInfoBuffer
->BlockSize
= buf
.f_bsize
;
1027 (CHAR16
*) FileSystemInfoBuffer
->VolumeLabel
,
1028 (*BufferSize
- SIZE_OF_EFI_FILE_SYSTEM_INFO
) / sizeof (CHAR16
),
1029 PrivateRoot
->VolumeLabel
1031 *BufferSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
);
1033 } else if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
1034 if (*BufferSize
< StrSize (PrivateRoot
->VolumeLabel
)) {
1035 *BufferSize
= StrSize (PrivateRoot
->VolumeLabel
);
1036 return EFI_BUFFER_TOO_SMALL
;
1041 *BufferSize
/ sizeof (CHAR16
),
1042 PrivateRoot
->VolumeLabel
1044 *BufferSize
= StrSize (PrivateRoot
->VolumeLabel
);
1053 Set information about a file
1055 @param File Protocol instance pointer.
1056 @param InformationType Type of information in Buffer.
1057 @param BufferSize Size of buffer.
1058 @param Buffer The data to write.
1060 @retval EFI_SUCCESS Data was returned.
1061 @retval EFI_UNSUPPORTED InformationType is not supported.
1062 @retval EFI_NO_MEDIA The device has no media.
1063 @retval EFI_DEVICE_ERROR The device reported an error.
1064 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1065 @retval EFI_WRITE_PROTECTED The device is write protected.
1066 @retval EFI_ACCESS_DENIED The file was open for read only.
1071 IN EFI_FILE_PROTOCOL
*This
,
1072 IN EFI_GUID
*InformationType
,
1073 IN UINTN BufferSize
,
1077 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*PrivateRoot
;
1078 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
1079 EFI_FILE_INFO
*OldFileInfo
;
1080 EFI_FILE_INFO
*NewFileInfo
;
1084 struct stat OldAttr
;
1088 BOOLEAN AttrChangeFlag
;
1089 BOOLEAN NameChangeFlag
;
1090 BOOLEAN SizeChangeFlag
;
1091 BOOLEAN TimeChangeFlag
;
1092 struct tm NewLastAccessSystemTime
;
1093 struct tm NewLastWriteSystemTime
;
1094 EFI_FILE_SYSTEM_INFO
*NewFileSystemInfo
;
1095 CHAR8
*AsciiFilePtr
;
1096 CHAR16
*UnicodeFilePtr
;
1098 struct utimbuf Utime
;
1101 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
1102 PrivateRoot
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile
->SimpleFileSystem
);
1104 Status
= EFI_UNSUPPORTED
;
1105 OldFileInfo
= NewFileInfo
= NULL
;
1106 OldFileName
= NewFileName
= NULL
;
1107 AttrChangeFlag
= NameChangeFlag
= SizeChangeFlag
= TimeChangeFlag
= FALSE
;
1110 // Set file system information.
1112 if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
1113 if (BufferSize
< (SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
))) {
1114 Status
= EFI_BAD_BUFFER_SIZE
;
1118 NewFileSystemInfo
= (EFI_FILE_SYSTEM_INFO
*) Buffer
;
1120 free (PrivateRoot
->VolumeLabel
);
1122 PrivateRoot
->VolumeLabel
= malloc (StrSize (NewFileSystemInfo
->VolumeLabel
));
1123 if (PrivateRoot
->VolumeLabel
== NULL
) {
1128 PrivateRoot
->VolumeLabel
,
1129 StrSize (NewFileSystemInfo
->VolumeLabel
) / sizeof (CHAR16
),
1130 NewFileSystemInfo
->VolumeLabel
1133 Status
= EFI_SUCCESS
;
1138 // Set volume label information.
1140 if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
1141 if (BufferSize
< StrSize (PrivateRoot
->VolumeLabel
)) {
1142 Status
= EFI_BAD_BUFFER_SIZE
;
1147 PrivateRoot
->VolumeLabel
,
1148 StrSize (PrivateRoot
->VolumeLabel
) / sizeof (CHAR16
),
1152 Status
= EFI_SUCCESS
;
1156 if (!CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
1157 Status
= EFI_UNSUPPORTED
;
1161 if (BufferSize
< SIZE_OF_EFI_FILE_INFO
) {
1162 Status
= EFI_BAD_BUFFER_SIZE
;
1167 // Set file/directory information.
1171 // Check for invalid set file information parameters.
1173 NewFileInfo
= (EFI_FILE_INFO
*) Buffer
;
1174 if (NewFileInfo
->Size
<= sizeof (EFI_FILE_INFO
) ||
1175 (NewFileInfo
->Attribute
&~(EFI_FILE_VALID_ATTR
)) ||
1176 (sizeof (UINTN
) == 4 && NewFileInfo
->Size
> 0xFFFFFFFF)
1178 Status
= EFI_INVALID_PARAMETER
;
1183 // Get current file information so we can determine what kind
1184 // of change request this is.
1187 Status
= UnixSimpleFileSystemFileInfo (PrivateFile
, NULL
, &OldInfoSize
, NULL
);
1188 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1189 Status
= EFI_DEVICE_ERROR
;
1193 OldFileInfo
= malloc (OldInfoSize
);
1194 if (OldFileInfo
== NULL
) {
1198 Status
= UnixSimpleFileSystemFileInfo (PrivateFile
, NULL
, &OldInfoSize
, OldFileInfo
);
1199 if (EFI_ERROR (Status
)) {
1203 OldFileName
= malloc (AsciiStrSize (PrivateFile
->FileName
));
1204 if (OldFileInfo
== NULL
) {
1210 AsciiStrSize (PrivateFile
->FileName
),
1211 PrivateFile
->FileName
1215 // Make full pathname from new filename and rootpath.
1217 if (NewFileInfo
->FileName
[0] == '\\') {
1218 Size
= AsciiStrLen (PrivateRoot
->FilePath
) + 1 + StrLen (NewFileInfo
->FileName
) + 1;
1219 NewFileName
= malloc (Size
);
1220 if (NewFileName
== NULL
) {
1224 AsciiStrCpyS (NewFileName
, Size
, PrivateRoot
->FilePath
);
1225 AsciiFilePtr
= NewFileName
+ AsciiStrLen(NewFileName
);
1226 UnicodeFilePtr
= NewFileInfo
->FileName
+ 1;
1227 *AsciiFilePtr
++ ='/';
1229 Size
= AsciiStrLen (PrivateFile
->FileName
) + 2 + StrLen (NewFileInfo
->FileName
) + 1;
1230 NewFileName
= malloc (Size
);
1231 if (NewFileName
== NULL
) {
1235 AsciiStrCpyS (NewFileName
, Size
, PrivateRoot
->FilePath
);
1236 AsciiFilePtr
= NewFileName
+ AsciiStrLen(NewFileName
);
1237 if ((AsciiFilePtr
[-1] != '/') && (NewFileInfo
->FileName
[0] != '/')) {
1238 // make sure there is a / between Root FilePath and NewFileInfo Filename
1239 AsciiFilePtr
[0] = '/';
1240 AsciiFilePtr
[1] = '\0';
1243 UnicodeFilePtr
= NewFileInfo
->FileName
;
1245 // Convert to ascii.
1246 while (*UnicodeFilePtr
) {
1247 *AsciiFilePtr
++ = *UnicodeFilePtr
++;
1252 // Is there an attribute change request?
1254 if (NewFileInfo
->Attribute
!= OldFileInfo
->Attribute
) {
1255 if ((NewFileInfo
->Attribute
& EFI_FILE_DIRECTORY
) != (OldFileInfo
->Attribute
& EFI_FILE_DIRECTORY
)) {
1256 Status
= EFI_INVALID_PARAMETER
;
1260 AttrChangeFlag
= TRUE
;
1264 // Is there a name change request?
1265 // bugbug: - Should really use EFI_UNICODE_COLLATION_PROTOCOL
1267 if (StrCmp (NewFileInfo
->FileName
, OldFileInfo
->FileName
)) {
1268 NameChangeFlag
= TRUE
;
1272 // Is there a size change request?
1274 if (NewFileInfo
->FileSize
!= OldFileInfo
->FileSize
) {
1275 SizeChangeFlag
= TRUE
;
1279 // Is there a time stamp change request?
1281 if (!IsZero (&NewFileInfo
->CreateTime
, sizeof (EFI_TIME
)) &&
1282 CompareMem (&NewFileInfo
->CreateTime
, &OldFileInfo
->CreateTime
, sizeof (EFI_TIME
))
1284 TimeChangeFlag
= TRUE
;
1285 } else if (!IsZero (&NewFileInfo
->LastAccessTime
, sizeof (EFI_TIME
)) &&
1286 CompareMem (&NewFileInfo
->LastAccessTime
, &OldFileInfo
->LastAccessTime
, sizeof (EFI_TIME
))
1288 TimeChangeFlag
= TRUE
;
1289 } else if (!IsZero (&NewFileInfo
->ModificationTime
, sizeof (EFI_TIME
)) &&
1290 CompareMem (&NewFileInfo
->ModificationTime
, &OldFileInfo
->ModificationTime
, sizeof (EFI_TIME
))
1292 TimeChangeFlag
= TRUE
;
1296 // All done if there are no change requests being made.
1298 if (!(AttrChangeFlag
|| NameChangeFlag
|| SizeChangeFlag
|| TimeChangeFlag
)) {
1299 Status
= EFI_SUCCESS
;
1304 // Set file or directory information.
1306 if (stat (OldFileName
, &OldAttr
) != 0) {
1307 Status
= ErrnoToEfiStatus ();
1314 if (NameChangeFlag
) {
1316 // Close the handles first
1318 if (PrivateFile
->IsOpenedByRead
) {
1319 Status
= EFI_ACCESS_DENIED
;
1323 for (CharPointer
= NewFileName
; *CharPointer
!= 0 && *CharPointer
!= L
'/'; CharPointer
++) {
1326 if (*CharPointer
!= 0) {
1327 Status
= EFI_ACCESS_DENIED
;
1331 UnixStatus
= rename (OldFileName
, NewFileName
);
1332 if (UnixStatus
== 0) {
1336 free (PrivateFile
->FileName
);
1338 PrivateFile
->FileName
= malloc (AsciiStrSize (NewFileName
));
1339 if (PrivateFile
->FileName
== NULL
) {
1344 PrivateFile
->FileName
,
1345 AsciiStrSize (NewFileName
),
1349 Status
= EFI_DEVICE_ERROR
;
1357 if (SizeChangeFlag
) {
1358 if (PrivateFile
->IsDirectoryPath
) {
1359 Status
= EFI_UNSUPPORTED
;
1363 if (PrivateFile
->IsOpenedByRead
|| OldFileInfo
->Attribute
& EFI_FILE_READ_ONLY
) {
1364 Status
= EFI_ACCESS_DENIED
;
1368 if (ftruncate (PrivateFile
->fd
, NewFileInfo
->FileSize
) != 0) {
1369 Status
= ErrnoToEfiStatus ();
1378 if (TimeChangeFlag
) {
1379 NewLastAccessSystemTime
.tm_year
= NewFileInfo
->LastAccessTime
.Year
;
1380 NewLastAccessSystemTime
.tm_mon
= NewFileInfo
->LastAccessTime
.Month
;
1381 NewLastAccessSystemTime
.tm_mday
= NewFileInfo
->LastAccessTime
.Day
;
1382 NewLastAccessSystemTime
.tm_hour
= NewFileInfo
->LastAccessTime
.Hour
;
1383 NewLastAccessSystemTime
.tm_min
= NewFileInfo
->LastAccessTime
.Minute
;
1384 NewLastAccessSystemTime
.tm_sec
= NewFileInfo
->LastAccessTime
.Second
;
1385 NewLastAccessSystemTime
.tm_isdst
= 0;
1387 Utime
.actime
= mktime (&NewLastAccessSystemTime
);
1389 NewLastWriteSystemTime
.tm_year
= NewFileInfo
->ModificationTime
.Year
;
1390 NewLastWriteSystemTime
.tm_mon
= NewFileInfo
->ModificationTime
.Month
;
1391 NewLastWriteSystemTime
.tm_mday
= NewFileInfo
->ModificationTime
.Day
;
1392 NewLastWriteSystemTime
.tm_hour
= NewFileInfo
->ModificationTime
.Hour
;
1393 NewLastWriteSystemTime
.tm_min
= NewFileInfo
->ModificationTime
.Minute
;
1394 NewLastWriteSystemTime
.tm_sec
= NewFileInfo
->ModificationTime
.Second
;
1395 NewLastWriteSystemTime
.tm_isdst
= 0;
1397 Utime
.modtime
= mktime (&NewLastWriteSystemTime
);
1399 if (Utime
.actime
== (time_t)-1 || Utime
.modtime
== (time_t)-1) {
1403 if (utime (PrivateFile
->FileName
, &Utime
) == -1) {
1404 Status
= ErrnoToEfiStatus ();
1410 // No matter about AttrChangeFlag, Attribute must be set.
1411 // Because operation before may cause attribute change.
1413 NewAttr
= OldAttr
.st_mode
;
1415 if (NewFileInfo
->Attribute
& EFI_FILE_READ_ONLY
) {
1416 NewAttr
&= ~(S_IRUSR
| S_IRGRP
| S_IROTH
);
1421 if (chmod (NewFileName
, NewAttr
) != 0) {
1422 Status
= ErrnoToEfiStatus ();
1426 if (OldFileInfo
!= NULL
) {
1430 if (OldFileName
!= NULL
) {
1434 if (NewFileName
!= NULL
) {
1443 Flush data back for the file handle.
1445 @param This Protocol instance pointer.
1447 @retval EFI_SUCCESS Data was written.
1448 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
1449 @retval EFI_NO_MEDIA The device has no media.
1450 @retval EFI_DEVICE_ERROR The device reported an error.
1451 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1452 @retval EFI_WRITE_PROTECTED The device is write protected.
1453 @retval EFI_ACCESS_DENIED The file was open for read only.
1454 @retval EFI_VOLUME_FULL The volume is full.
1459 IN EFI_FILE_PROTOCOL
*This
1462 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
1465 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
1467 if (PrivateFile
->IsDirectoryPath
) {
1468 return EFI_UNSUPPORTED
;
1471 if (PrivateFile
->IsOpenedByRead
) {
1472 return EFI_ACCESS_DENIED
;
1475 if (PrivateFile
->fd
< 0) {
1476 return EFI_DEVICE_ERROR
;
1479 if (fsync (PrivateFile
->fd
) != 0) {
1480 return ErrnoToEfiStatus ();
1489 PosixFileSystmeThunkOpen (
1490 IN EMU_IO_THUNK_PROTOCOL
*This
1493 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*Private
;
1496 if (This
->Private
!= NULL
) {
1497 return EFI_ALREADY_STARTED
;
1500 if (!CompareGuid (This
->Protocol
, &gEfiSimpleFileSystemProtocolGuid
)) {
1501 return EFI_UNSUPPORTED
;
1504 Private
= malloc (sizeof (EMU_SIMPLE_FILE_SYSTEM_PRIVATE
));
1505 if (Private
== NULL
) {
1506 return EFI_OUT_OF_RESOURCES
;
1509 Private
->FilePath
= malloc (StrLen (This
->ConfigString
) + 1);
1510 if (Private
->FilePath
== NULL
) {
1512 return EFI_OUT_OF_RESOURCES
;
1515 // Convert Unicode to Ascii
1516 for (i
= 0; This
->ConfigString
[i
] != 0; i
++) {
1517 Private
->FilePath
[i
] = This
->ConfigString
[i
];
1519 Private
->FilePath
[i
] = 0;
1522 Private
->VolumeLabel
= malloc (StrSize (L
"EFI_EMULATED"));
1523 if (Private
->VolumeLabel
== NULL
) {
1524 free (Private
->FilePath
);
1526 return EFI_OUT_OF_RESOURCES
;
1529 Private
->VolumeLabel
,
1530 StrSize (L
"EFI_EMULATED") / sizeof (CHAR16
),
1534 Private
->Signature
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE
;
1535 Private
->Thunk
= This
;
1536 CopyMem (&Private
->SimpleFileSystem
, &gPosixFileSystemProtocol
, sizeof (Private
->SimpleFileSystem
));
1537 Private
->FileHandlesOpen
= FALSE
;
1539 This
->Interface
= &Private
->SimpleFileSystem
;
1540 This
->Private
= Private
;
1546 PosixFileSystmeThunkClose (
1547 IN EMU_IO_THUNK_PROTOCOL
*This
1550 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*Private
;
1552 if (!CompareGuid (This
->Protocol
, &gEfiSimpleFileSystemProtocolGuid
)) {
1553 return EFI_UNSUPPORTED
;
1556 Private
= This
->Private
;
1558 if (Private
->FileHandlesOpen
) {
1560 // Close only supported if all the EFI_FILE_HANDLEs have been closed.
1562 return EFI_NOT_READY
;
1565 if (This
->Private
!= NULL
) {
1566 if (Private
->VolumeLabel
!= NULL
) {
1567 free (Private
->VolumeLabel
);
1569 free (This
->Private
);
1570 This
->Private
= NULL
;
1577 EMU_IO_THUNK_PROTOCOL gPosixFileSystemThunkIo
= {
1578 &gEfiSimpleFileSystemProtocolGuid
,
1582 GasketPosixFileSystmeThunkOpen
,
1583 GasketPosixFileSystmeThunkClose
,