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
13 #define EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE SIGNATURE_32 ('E', 'P', 'f', 's')
17 EMU_IO_THUNK_PROTOCOL
*Thunk
;
18 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL SimpleFileSystem
;
21 BOOLEAN FileHandlesOpen
;
22 } EMU_SIMPLE_FILE_SYSTEM_PRIVATE
;
24 #define EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS(a) \
26 EMU_SIMPLE_FILE_SYSTEM_PRIVATE, \
28 EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE \
31 #define EMU_EFI_FILE_PRIVATE_SIGNATURE SIGNATURE_32 ('E', 'P', 'f', 'i')
35 EMU_IO_THUNK_PROTOCOL
*Thunk
;
36 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*SimpleFileSystem
;
37 EFI_FILE_PROTOCOL EfiFile
;
40 BOOLEAN IsRootDirectory
;
41 BOOLEAN IsDirectoryPath
;
42 BOOLEAN IsOpenedByRead
;
44 struct dirent
*Dirent
;
45 } EMU_EFI_FILE_PRIVATE
;
47 #define EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS(a) \
49 EMU_EFI_FILE_PRIVATE, \
51 EMU_EFI_FILE_PRIVATE_SIGNATURE \
56 IN EFI_FILE_PROTOCOL
*This
,
57 IN EFI_GUID
*InformationType
,
58 IN OUT UINTN
*BufferSize
,
64 IN EFI_FILE_PROTOCOL
*This
,
65 IN EFI_GUID
*InformationType
,
70 EFI_FILE_PROTOCOL gPosixFileProtocol
= {
74 GasketPosixFileDelete
,
77 GasketPosixFileGetPossition
,
78 GasketPosixFileSetPossition
,
79 GasketPosixFileGetInfo
,
80 GasketPosixFileSetInfo
,
84 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gPosixFileSystemProtocol
= {
85 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
,
86 GasketPosixOpenVolume
,
90 Open the root directory on a volume.
92 @param This Protocol instance pointer.
93 @param Root Returns an Open file handle for the root directory
95 @retval EFI_SUCCESS The device was opened.
96 @retval EFI_UNSUPPORTED This volume does not support the file system.
97 @retval EFI_NO_MEDIA The device has no media.
98 @retval EFI_DEVICE_ERROR The device reported an error.
99 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
100 @retval EFI_ACCESS_DENIED The service denied access to the file.
101 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
106 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*This
,
107 OUT EFI_FILE_PROTOCOL
**Root
111 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*Private
;
112 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
114 Private
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (This
);
116 Status
= EFI_OUT_OF_RESOURCES
;
117 PrivateFile
= malloc (sizeof (EMU_EFI_FILE_PRIVATE
));
118 if (PrivateFile
== NULL
) {
122 PrivateFile
->FileName
= malloc (AsciiStrSize (Private
->FilePath
));
123 if (PrivateFile
->FileName
== NULL
) {
128 PrivateFile
->FileName
,
129 AsciiStrSize (Private
->FilePath
),
133 PrivateFile
->Signature
= EMU_EFI_FILE_PRIVATE_SIGNATURE
;
134 PrivateFile
->Thunk
= Private
->Thunk
;
135 PrivateFile
->SimpleFileSystem
= This
;
136 PrivateFile
->IsRootDirectory
= TRUE
;
137 PrivateFile
->IsDirectoryPath
= TRUE
;
138 PrivateFile
->IsOpenedByRead
= TRUE
;
140 CopyMem (&PrivateFile
->EfiFile
, &gPosixFileProtocol
, sizeof (EFI_FILE_PROTOCOL
));
142 PrivateFile
->fd
= -1;
143 PrivateFile
->Dir
= NULL
;
144 PrivateFile
->Dirent
= NULL
;
146 *Root
= &PrivateFile
->EfiFile
;
148 PrivateFile
->Dir
= opendir (PrivateFile
->FileName
);
149 if (PrivateFile
->Dir
== NULL
) {
150 Status
= EFI_ACCESS_DENIED
;
152 Status
= EFI_SUCCESS
;
156 if (EFI_ERROR (Status
)) {
157 if (PrivateFile
!= NULL
) {
158 if (PrivateFile
->FileName
!= NULL
) {
159 free (PrivateFile
->FileName
);
177 return EFI_ACCESS_DENIED
;
181 return EFI_VOLUME_FULL
;
184 return EFI_DEVICE_ERROR
;
196 if (AsciiStrLen (Str
) < Count
) {
200 for (Pointer
= Str
; *(Pointer
+ Count
); Pointer
++) {
201 *Pointer
= *(Pointer
+ Count
);
204 *Pointer
= *(Pointer
+ Count
);
208 PosixSystemTimeToEfiTime (
209 IN
time_t SystemTime
,
215 tm
= gmtime (&SystemTime
);
216 Time
->Year
= tm
->tm_year
;
217 Time
->Month
= tm
->tm_mon
+ 1;
218 Time
->Day
= tm
->tm_mday
;
219 Time
->Hour
= tm
->tm_hour
;
220 Time
->Minute
= tm
->tm_min
;
221 Time
->Second
= tm
->tm_sec
;
222 Time
->Nanosecond
= 0;
224 Time
->TimeZone
= timezone
/ 60;
225 Time
->Daylight
= (daylight
? EFI_TIME_ADJUST_DAYLIGHT
: 0) | (tm
->tm_isdst
> 0 ? EFI_TIME_IN_DAYLIGHT
: 0);
229 UnixSimpleFileSystemFileInfo (
230 EMU_EFI_FILE_PRIVATE
*PrivateFile
,
232 IN OUT UINTN
*BufferSize
,
243 CHAR16
*BufferFileName
;
246 if (FileName
!= NULL
) {
247 RealFileName
= FileName
;
248 } else if (PrivateFile
->IsRootDirectory
) {
251 RealFileName
= PrivateFile
->FileName
;
254 TempPointer
= RealFileName
;
255 while (*TempPointer
) {
256 if (*TempPointer
== '/') {
257 RealFileName
= TempPointer
+ 1;
263 Size
= SIZE_OF_EFI_FILE_INFO
;
264 NameSize
= AsciiStrSize (RealFileName
) * 2;
265 ResultSize
= Size
+ NameSize
;
267 if (*BufferSize
< ResultSize
) {
268 *BufferSize
= ResultSize
;
269 return EFI_BUFFER_TOO_SMALL
;
272 if (stat ((FileName
== NULL
) ? PrivateFile
->FileName
: FileName
, &buf
) < 0) {
273 return EFI_DEVICE_ERROR
;
276 Status
= EFI_SUCCESS
;
279 ZeroMem (Info
, ResultSize
);
281 Info
->Size
= ResultSize
;
282 Info
->FileSize
= buf
.st_size
;
283 Info
->PhysicalSize
= MultU64x32 (buf
.st_blocks
, buf
.st_blksize
);
285 PosixSystemTimeToEfiTime (buf
.st_ctime
, &Info
->CreateTime
);
286 PosixSystemTimeToEfiTime (buf
.st_atime
, &Info
->LastAccessTime
);
287 PosixSystemTimeToEfiTime (buf
.st_mtime
, &Info
->ModificationTime
);
289 if (!(buf
.st_mode
& S_IWUSR
)) {
290 Info
->Attribute
|= EFI_FILE_READ_ONLY
;
293 if (S_ISDIR (buf
.st_mode
)) {
294 Info
->Attribute
|= EFI_FILE_DIRECTORY
;
297 BufferFileName
= (CHAR16
*)((CHAR8
*)Buffer
+ Size
);
298 while (*RealFileName
) {
299 *BufferFileName
++ = *RealFileName
++;
304 *BufferSize
= ResultSize
;
314 if ((Buffer
== NULL
) || (Length
== 0)) {
318 if (*(UINT8
*)Buffer
!= 0) {
323 if (!CompareMem (Buffer
, (UINT8
*)Buffer
+ 1, Length
- 1)) {
332 Opens a new file relative to the source file's location.
334 @param This The protocol instance pointer.
335 @param NewHandle Returns File Handle for FileName.
336 @param FileName Null terminated string. "\", ".", and ".." are supported.
337 @param OpenMode Open mode for file.
338 @param Attributes Only used for EFI_FILE_MODE_CREATE.
340 @retval EFI_SUCCESS The device was opened.
341 @retval EFI_NOT_FOUND The specified file could not be found on the device.
342 @retval EFI_NO_MEDIA The device has no media.
343 @retval EFI_MEDIA_CHANGED The media has changed.
344 @retval EFI_DEVICE_ERROR The device reported an error.
345 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
346 @retval EFI_ACCESS_DENIED The service denied access to the file.
347 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
348 @retval EFI_VOLUME_FULL The volume is full.
353 IN EFI_FILE_PROTOCOL
*This
,
354 OUT EFI_FILE_PROTOCOL
**NewHandle
,
360 EFI_FILE_PROTOCOL
*Root
;
361 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
362 EMU_EFI_FILE_PRIVATE
*NewPrivateFile
;
363 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*PrivateRoot
;
372 BOOLEAN TrailingDash
;
380 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
381 PrivateRoot
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile
->SimpleFileSystem
);
382 NewPrivateFile
= NULL
;
383 Status
= EFI_OUT_OF_RESOURCES
;
386 // BUGBUG: assume an open of root
387 // if current location, return current data
389 TrailingDash
= FALSE
;
390 if ((StrCmp (FileName
, L
"\\") == 0) ||
391 ((StrCmp (FileName
, L
".") == 0) && PrivateFile
->IsRootDirectory
))
394 Status
= PosixOpenVolume (PrivateFile
->SimpleFileSystem
, &Root
);
395 NewPrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (Root
);
399 if (FileName
[StrLen (FileName
) - 1] == L
'\\') {
401 FileName
[StrLen (FileName
) - 1] = 0;
405 // Attempt to open the file
407 NewPrivateFile
= malloc (sizeof (EMU_EFI_FILE_PRIVATE
));
408 if (NewPrivateFile
== NULL
) {
412 CopyMem (NewPrivateFile
, PrivateFile
, sizeof (EMU_EFI_FILE_PRIVATE
));
414 Size
= AsciiStrSize (PrivateFile
->FileName
) + 1 + StrLen (FileName
) + 1;
415 NewPrivateFile
->FileName
= malloc (Size
);
416 if (NewPrivateFile
->FileName
== NULL
) {
420 if (*FileName
== L
'\\') {
421 AsciiStrCpyS (NewPrivateFile
->FileName
, Size
, PrivateRoot
->FilePath
);
425 AsciiStrCpyS (NewPrivateFile
->FileName
, Size
, PrivateFile
->FileName
);
429 Dst
= NewPrivateFile
->FileName
+ AsciiStrLen (NewPrivateFile
->FileName
);
430 GuardPointer
= NewPrivateFile
->FileName
+ AsciiStrLen (PrivateRoot
->FilePath
);
432 // Convert unicode to ascii and '\' to '/'
446 // Get rid of . and .., except leading . or ..
450 // GuardPointer protect simplefilesystem root path not be destroyed
454 while (!LoopFinish
) {
457 for (ParseFileName
= GuardPointer
; *ParseFileName
; ParseFileName
++) {
458 if ((*ParseFileName
== '.') &&
459 ((*(ParseFileName
+ 1) == 0) || (*(ParseFileName
+ 1) == '/')) &&
460 (*(ParseFileName
- 1) == '/')
466 CutPrefix (ParseFileName
- 1, 2);
471 if ((*ParseFileName
== '.') &&
472 (*(ParseFileName
+ 1) == '.') &&
473 ((*(ParseFileName
+ 2) == 0) || (*(ParseFileName
+ 2) == '/')) &&
474 (*(ParseFileName
- 1) == '/')
480 while (ParseFileName
!= GuardPointer
) {
483 if (*ParseFileName
== '/') {
489 // cut /.. and its left directory
491 CutPrefix (ParseFileName
, Count
);
498 if (AsciiStrCmp (NewPrivateFile
->FileName
, PrivateRoot
->FilePath
) == 0) {
499 NewPrivateFile
->IsRootDirectory
= TRUE
;
500 free (NewPrivateFile
->FileName
);
501 free (NewPrivateFile
);
505 RealFileName
= NewPrivateFile
->FileName
+ AsciiStrLen (NewPrivateFile
->FileName
) - 1;
506 while (RealFileName
> NewPrivateFile
->FileName
&& *RealFileName
!= '/') {
510 TempChar
= *(RealFileName
- 1);
511 *(RealFileName
- 1) = 0;
512 *(RealFileName
- 1) = TempChar
;
515 // Test whether file or directory
517 NewPrivateFile
->IsRootDirectory
= FALSE
;
518 NewPrivateFile
->fd
= -1;
519 NewPrivateFile
->Dir
= NULL
;
520 if (OpenMode
& EFI_FILE_MODE_CREATE
) {
521 if (Attributes
& EFI_FILE_DIRECTORY
) {
522 NewPrivateFile
->IsDirectoryPath
= TRUE
;
524 NewPrivateFile
->IsDirectoryPath
= FALSE
;
527 res
= stat (NewPrivateFile
->FileName
, &finfo
);
528 if ((res
== 0) && S_ISDIR (finfo
.st_mode
)) {
529 NewPrivateFile
->IsDirectoryPath
= TRUE
;
531 NewPrivateFile
->IsDirectoryPath
= FALSE
;
535 if (OpenMode
& EFI_FILE_MODE_WRITE
) {
536 NewPrivateFile
->IsOpenedByRead
= FALSE
;
538 NewPrivateFile
->IsOpenedByRead
= TRUE
;
541 Status
= EFI_SUCCESS
;
544 // deal with directory
546 if (NewPrivateFile
->IsDirectoryPath
) {
547 if ((OpenMode
& EFI_FILE_MODE_CREATE
)) {
549 // Create a directory
551 if (mkdir (NewPrivateFile
->FileName
, 0777) != 0) {
552 if (errno
!= EEXIST
) {
553 // free (TempFileName);
554 Status
= EFI_ACCESS_DENIED
;
560 NewPrivateFile
->Dir
= opendir (NewPrivateFile
->FileName
);
561 if (NewPrivateFile
->Dir
== NULL
) {
562 if (errno
== EACCES
) {
563 Status
= EFI_ACCESS_DENIED
;
565 Status
= EFI_NOT_FOUND
;
574 NewPrivateFile
->fd
= open (
575 NewPrivateFile
->FileName
,
576 ((OpenMode
& EFI_FILE_MODE_CREATE
) ? O_CREAT
: 0) | (NewPrivateFile
->IsOpenedByRead
? O_RDONLY
: O_RDWR
),
579 if (NewPrivateFile
->fd
< 0) {
580 if (errno
== ENOENT
) {
581 Status
= EFI_NOT_FOUND
;
583 Status
= EFI_ACCESS_DENIED
;
588 if ((OpenMode
& EFI_FILE_MODE_CREATE
) && (Status
== EFI_SUCCESS
)) {
594 Status
= PosixFileGetInfo (&NewPrivateFile
->EfiFile
, &gEfiFileInfoGuid
, &InfoSize
, Info
);
595 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
596 Status
= EFI_DEVICE_ERROR
;
600 Info
= malloc (InfoSize
);
605 Status
= PosixFileGetInfo (&NewPrivateFile
->EfiFile
, &gEfiFileInfoGuid
, &InfoSize
, Info
);
606 if (EFI_ERROR (Status
)) {
610 Info
->Attribute
= Attributes
;
611 PosixFileSetInfo (&NewPrivateFile
->EfiFile
, &gEfiFileInfoGuid
, InfoSize
, Info
);
618 FileName
[StrLen (FileName
) + 1] = 0;
619 FileName
[StrLen (FileName
)] = L
'\\';
622 if (EFI_ERROR (Status
)) {
623 if (NewPrivateFile
) {
624 if (NewPrivateFile
->FileName
) {
625 free (NewPrivateFile
->FileName
);
628 free (NewPrivateFile
);
631 *NewHandle
= &NewPrivateFile
->EfiFile
;
638 Close the file handle
640 @param This Protocol instance pointer.
642 @retval EFI_SUCCESS The device was opened.
647 IN EFI_FILE_PROTOCOL
*This
650 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
652 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
654 if (PrivateFile
->fd
>= 0) {
655 close (PrivateFile
->fd
);
658 if (PrivateFile
->Dir
!= NULL
) {
659 closedir (PrivateFile
->Dir
);
662 PrivateFile
->fd
= -1;
663 PrivateFile
->Dir
= NULL
;
665 if (PrivateFile
->FileName
) {
666 free (PrivateFile
->FileName
);
675 Close and delete the file handle.
677 @param This Protocol instance pointer.
679 @retval EFI_SUCCESS The device was opened.
680 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.
685 IN EFI_FILE_PROTOCOL
*This
689 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
691 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
692 Status
= EFI_WARN_DELETE_FAILURE
;
694 if (PrivateFile
->IsDirectoryPath
) {
695 if (PrivateFile
->Dir
!= NULL
) {
696 closedir (PrivateFile
->Dir
);
697 PrivateFile
->Dir
= NULL
;
700 if (rmdir (PrivateFile
->FileName
) == 0) {
701 Status
= EFI_SUCCESS
;
704 close (PrivateFile
->fd
);
705 PrivateFile
->fd
= -1;
707 if (!PrivateFile
->IsOpenedByRead
) {
708 if (!unlink (PrivateFile
->FileName
)) {
709 Status
= EFI_SUCCESS
;
714 free (PrivateFile
->FileName
);
721 Read data from the file.
723 @param This Protocol instance pointer.
724 @param BufferSize On input size of buffer, on output amount of data in buffer.
725 @param Buffer The buffer in which data is read.
727 @retval EFI_SUCCESS Data was read.
728 @retval EFI_NO_MEDIA The device has no media.
729 @retval EFI_DEVICE_ERROR The device reported an error.
730 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
731 @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size.
736 IN EFI_FILE_PROTOCOL
*This
,
737 IN OUT UINTN
*BufferSize
,
741 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
748 UINTN FullFileNameSize
;
750 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
752 if (!PrivateFile
->IsDirectoryPath
) {
753 if (PrivateFile
->fd
< 0) {
754 Status
= EFI_DEVICE_ERROR
;
758 Res
= read (PrivateFile
->fd
, Buffer
, *BufferSize
);
760 Status
= EFI_DEVICE_ERROR
;
765 Status
= EFI_SUCCESS
;
770 // Read on a directory.
772 if (PrivateFile
->Dir
== NULL
) {
773 Status
= EFI_DEVICE_ERROR
;
777 if (PrivateFile
->Dirent
== NULL
) {
778 PrivateFile
->Dirent
= readdir (PrivateFile
->Dir
);
779 if (PrivateFile
->Dirent
== NULL
) {
781 Status
= EFI_SUCCESS
;
786 Size
= SIZE_OF_EFI_FILE_INFO
;
787 NameSize
= AsciiStrLen (PrivateFile
->Dirent
->d_name
) + 1;
788 ResultSize
= Size
+ 2 * NameSize
;
790 if (*BufferSize
< ResultSize
) {
791 *BufferSize
= ResultSize
;
792 Status
= EFI_BUFFER_TOO_SMALL
;
796 Status
= EFI_SUCCESS
;
798 *BufferSize
= ResultSize
;
800 FullFileNameSize
= AsciiStrLen (PrivateFile
->FileName
) + 1 + NameSize
;
801 FullFileName
= malloc (FullFileNameSize
);
802 if (FullFileName
== NULL
) {
803 Status
= EFI_OUT_OF_RESOURCES
;
807 AsciiStrCpyS (FullFileName
, FullFileNameSize
, PrivateFile
->FileName
);
808 AsciiStrCatS (FullFileName
, FullFileNameSize
, "/");
809 AsciiStrCatS (FullFileName
, FullFileNameSize
, PrivateFile
->Dirent
->d_name
);
810 Status
= UnixSimpleFileSystemFileInfo (
818 PrivateFile
->Dirent
= NULL
;
825 Write data to a file.
827 @param This Protocol instance pointer.
828 @param BufferSize On input size of buffer, on output amount of data in buffer.
829 @param Buffer The buffer in which data to write.
831 @retval EFI_SUCCESS Data was written.
832 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
833 @retval EFI_NO_MEDIA The device has no media.
834 @retval EFI_DEVICE_ERROR The device reported an error.
835 @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
836 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
837 @retval EFI_WRITE_PROTECTED The device is write protected.
838 @retval EFI_ACCESS_DENIED The file was open for read only.
839 @retval EFI_VOLUME_FULL The volume is full.
844 IN EFI_FILE_PROTOCOL
*This
,
845 IN OUT UINTN
*BufferSize
,
849 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
852 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
854 if (PrivateFile
->fd
< 0) {
855 return EFI_DEVICE_ERROR
;
858 if (PrivateFile
->IsDirectoryPath
) {
859 return EFI_UNSUPPORTED
;
862 if (PrivateFile
->IsOpenedByRead
) {
863 return EFI_ACCESS_DENIED
;
866 Res
= write (PrivateFile
->fd
, Buffer
, *BufferSize
);
867 if (Res
== (UINTN
)-1) {
868 return ErrnoToEfiStatus ();
876 Set a files current position
878 @param This Protocol instance pointer.
879 @param Position Byte position from the start of the file.
881 @retval EFI_SUCCESS Data was written.
882 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
886 PosixFileSetPossition (
887 IN EFI_FILE_PROTOCOL
*This
,
891 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
894 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
896 if (PrivateFile
->IsDirectoryPath
) {
898 return EFI_UNSUPPORTED
;
901 if (PrivateFile
->Dir
== NULL
) {
902 return EFI_DEVICE_ERROR
;
905 rewinddir (PrivateFile
->Dir
);
908 if (Position
== (UINT64
)-1) {
909 Pos
= lseek (PrivateFile
->fd
, 0, SEEK_END
);
911 Pos
= lseek (PrivateFile
->fd
, Position
, SEEK_SET
);
914 if (Pos
== (off_t
)-1) {
915 return ErrnoToEfiStatus ();
923 Get a file's current position
925 @param This Protocol instance pointer.
926 @param Position Byte position from the start of the file.
928 @retval EFI_SUCCESS Data was written.
929 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..
933 PosixFileGetPossition (
934 IN EFI_FILE_PROTOCOL
*This
,
939 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
941 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
943 if (PrivateFile
->IsDirectoryPath
) {
944 Status
= EFI_UNSUPPORTED
;
946 *Position
= (UINT64
)lseek (PrivateFile
->fd
, 0, SEEK_CUR
);
947 Status
= (*Position
== (UINT64
)-1) ? ErrnoToEfiStatus () : EFI_SUCCESS
;
954 Get information about a file.
956 @param This Protocol instance pointer.
957 @param InformationType Type of information to return in Buffer.
958 @param BufferSize On input size of buffer, on output amount of data in buffer.
959 @param Buffer The buffer to return data.
961 @retval EFI_SUCCESS Data was returned.
962 @retval EFI_UNSUPPORTED InformationType is not supported.
963 @retval EFI_NO_MEDIA The device has no media.
964 @retval EFI_DEVICE_ERROR The device reported an error.
965 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
966 @retval EFI_WRITE_PROTECTED The device is write protected.
967 @retval EFI_ACCESS_DENIED The file was open for read only.
968 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
973 IN EFI_FILE_PROTOCOL
*This
,
974 IN EFI_GUID
*InformationType
,
975 IN OUT UINTN
*BufferSize
,
980 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
981 EFI_FILE_SYSTEM_INFO
*FileSystemInfoBuffer
;
983 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*PrivateRoot
;
986 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
987 PrivateRoot
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile
->SimpleFileSystem
);
989 Status
= EFI_SUCCESS
;
990 if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
991 Status
= UnixSimpleFileSystemFileInfo (PrivateFile
, NULL
, BufferSize
, Buffer
);
992 } else if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
993 if (*BufferSize
< SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
)) {
994 *BufferSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
);
995 return EFI_BUFFER_TOO_SMALL
;
998 UnixStatus
= statfs (PrivateFile
->FileName
, &buf
);
999 if (UnixStatus
< 0) {
1000 return EFI_DEVICE_ERROR
;
1003 FileSystemInfoBuffer
= (EFI_FILE_SYSTEM_INFO
*)Buffer
;
1004 FileSystemInfoBuffer
->Size
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
);
1005 FileSystemInfoBuffer
->ReadOnly
= FALSE
;
1010 FileSystemInfoBuffer
->VolumeSize
= MultU64x32 (buf
.f_blocks
, buf
.f_bsize
);
1011 FileSystemInfoBuffer
->FreeSpace
= MultU64x32 (buf
.f_bavail
, buf
.f_bsize
);
1012 FileSystemInfoBuffer
->BlockSize
= buf
.f_bsize
;
1015 (CHAR16
*)FileSystemInfoBuffer
->VolumeLabel
,
1016 (*BufferSize
- SIZE_OF_EFI_FILE_SYSTEM_INFO
) / sizeof (CHAR16
),
1017 PrivateRoot
->VolumeLabel
1019 *BufferSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
);
1020 } else if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
1021 if (*BufferSize
< StrSize (PrivateRoot
->VolumeLabel
)) {
1022 *BufferSize
= StrSize (PrivateRoot
->VolumeLabel
);
1023 return EFI_BUFFER_TOO_SMALL
;
1028 *BufferSize
/ sizeof (CHAR16
),
1029 PrivateRoot
->VolumeLabel
1031 *BufferSize
= StrSize (PrivateRoot
->VolumeLabel
);
1038 Set information about a file
1040 @param File Protocol instance pointer.
1041 @param InformationType Type of information in Buffer.
1042 @param BufferSize Size of buffer.
1043 @param Buffer The data to write.
1045 @retval EFI_SUCCESS Data was returned.
1046 @retval EFI_UNSUPPORTED InformationType is not supported.
1047 @retval EFI_NO_MEDIA The device has no media.
1048 @retval EFI_DEVICE_ERROR The device reported an error.
1049 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1050 @retval EFI_WRITE_PROTECTED The device is write protected.
1051 @retval EFI_ACCESS_DENIED The file was open for read only.
1056 IN EFI_FILE_PROTOCOL
*This
,
1057 IN EFI_GUID
*InformationType
,
1058 IN UINTN BufferSize
,
1062 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*PrivateRoot
;
1063 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
1064 EFI_FILE_INFO
*OldFileInfo
;
1065 EFI_FILE_INFO
*NewFileInfo
;
1069 struct stat OldAttr
;
1073 BOOLEAN AttrChangeFlag
;
1074 BOOLEAN NameChangeFlag
;
1075 BOOLEAN SizeChangeFlag
;
1076 BOOLEAN TimeChangeFlag
;
1077 struct tm NewLastAccessSystemTime
;
1078 struct tm NewLastWriteSystemTime
;
1079 EFI_FILE_SYSTEM_INFO
*NewFileSystemInfo
;
1080 CHAR8
*AsciiFilePtr
;
1081 CHAR16
*UnicodeFilePtr
;
1083 struct utimbuf Utime
;
1086 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
1087 PrivateRoot
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile
->SimpleFileSystem
);
1089 Status
= EFI_UNSUPPORTED
;
1090 OldFileInfo
= NewFileInfo
= NULL
;
1091 OldFileName
= NewFileName
= NULL
;
1092 AttrChangeFlag
= NameChangeFlag
= SizeChangeFlag
= TimeChangeFlag
= FALSE
;
1095 // Set file system information.
1097 if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
1098 if (BufferSize
< (SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
))) {
1099 Status
= EFI_BAD_BUFFER_SIZE
;
1103 NewFileSystemInfo
= (EFI_FILE_SYSTEM_INFO
*)Buffer
;
1105 free (PrivateRoot
->VolumeLabel
);
1107 PrivateRoot
->VolumeLabel
= malloc (StrSize (NewFileSystemInfo
->VolumeLabel
));
1108 if (PrivateRoot
->VolumeLabel
== NULL
) {
1113 PrivateRoot
->VolumeLabel
,
1114 StrSize (NewFileSystemInfo
->VolumeLabel
) / sizeof (CHAR16
),
1115 NewFileSystemInfo
->VolumeLabel
1118 Status
= EFI_SUCCESS
;
1123 // Set volume label information.
1125 if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
1126 if (BufferSize
< StrSize (PrivateRoot
->VolumeLabel
)) {
1127 Status
= EFI_BAD_BUFFER_SIZE
;
1132 PrivateRoot
->VolumeLabel
,
1133 StrSize (PrivateRoot
->VolumeLabel
) / sizeof (CHAR16
),
1137 Status
= EFI_SUCCESS
;
1141 if (!CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
1142 Status
= EFI_UNSUPPORTED
;
1146 if (BufferSize
< SIZE_OF_EFI_FILE_INFO
) {
1147 Status
= EFI_BAD_BUFFER_SIZE
;
1152 // Set file/directory information.
1156 // Check for invalid set file information parameters.
1158 NewFileInfo
= (EFI_FILE_INFO
*)Buffer
;
1159 if ((NewFileInfo
->Size
<= sizeof (EFI_FILE_INFO
)) ||
1160 (NewFileInfo
->Attribute
&~(EFI_FILE_VALID_ATTR
)) ||
1161 ((sizeof (UINTN
) == 4) && (NewFileInfo
->Size
> 0xFFFFFFFF))
1164 Status
= EFI_INVALID_PARAMETER
;
1169 // Get current file information so we can determine what kind
1170 // of change request this is.
1173 Status
= UnixSimpleFileSystemFileInfo (PrivateFile
, NULL
, &OldInfoSize
, NULL
);
1174 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1175 Status
= EFI_DEVICE_ERROR
;
1179 OldFileInfo
= malloc (OldInfoSize
);
1180 if (OldFileInfo
== NULL
) {
1184 Status
= UnixSimpleFileSystemFileInfo (PrivateFile
, NULL
, &OldInfoSize
, OldFileInfo
);
1185 if (EFI_ERROR (Status
)) {
1189 OldFileName
= malloc (AsciiStrSize (PrivateFile
->FileName
));
1190 if (OldFileInfo
== NULL
) {
1196 AsciiStrSize (PrivateFile
->FileName
),
1197 PrivateFile
->FileName
1201 // Make full pathname from new filename and rootpath.
1203 if (NewFileInfo
->FileName
[0] == '\\') {
1204 Size
= AsciiStrLen (PrivateRoot
->FilePath
) + 1 + StrLen (NewFileInfo
->FileName
) + 1;
1205 NewFileName
= malloc (Size
);
1206 if (NewFileName
== NULL
) {
1210 AsciiStrCpyS (NewFileName
, Size
, PrivateRoot
->FilePath
);
1211 AsciiFilePtr
= NewFileName
+ AsciiStrLen (NewFileName
);
1212 UnicodeFilePtr
= NewFileInfo
->FileName
+ 1;
1213 *AsciiFilePtr
++ = '/';
1215 Size
= AsciiStrLen (PrivateFile
->FileName
) + 2 + StrLen (NewFileInfo
->FileName
) + 1;
1216 NewFileName
= malloc (Size
);
1217 if (NewFileName
== NULL
) {
1221 AsciiStrCpyS (NewFileName
, Size
, PrivateRoot
->FilePath
);
1222 AsciiFilePtr
= NewFileName
+ AsciiStrLen (NewFileName
);
1223 if ((AsciiFilePtr
[-1] != '/') && (NewFileInfo
->FileName
[0] != '/')) {
1224 // make sure there is a / between Root FilePath and NewFileInfo Filename
1225 AsciiFilePtr
[0] = '/';
1226 AsciiFilePtr
[1] = '\0';
1230 UnicodeFilePtr
= NewFileInfo
->FileName
;
1233 // Convert to ascii.
1234 while (*UnicodeFilePtr
) {
1235 *AsciiFilePtr
++ = *UnicodeFilePtr
++;
1241 // Is there an attribute change request?
1243 if (NewFileInfo
->Attribute
!= OldFileInfo
->Attribute
) {
1244 if ((NewFileInfo
->Attribute
& EFI_FILE_DIRECTORY
) != (OldFileInfo
->Attribute
& EFI_FILE_DIRECTORY
)) {
1245 Status
= EFI_INVALID_PARAMETER
;
1249 AttrChangeFlag
= TRUE
;
1253 // Is there a name change request?
1254 // bugbug: - Should really use EFI_UNICODE_COLLATION_PROTOCOL
1256 if (StrCmp (NewFileInfo
->FileName
, OldFileInfo
->FileName
)) {
1257 NameChangeFlag
= TRUE
;
1261 // Is there a size change request?
1263 if (NewFileInfo
->FileSize
!= OldFileInfo
->FileSize
) {
1264 SizeChangeFlag
= TRUE
;
1268 // Is there a time stamp change request?
1270 if (!IsZero (&NewFileInfo
->CreateTime
, sizeof (EFI_TIME
)) &&
1271 CompareMem (&NewFileInfo
->CreateTime
, &OldFileInfo
->CreateTime
, sizeof (EFI_TIME
))
1274 TimeChangeFlag
= TRUE
;
1275 } else if (!IsZero (&NewFileInfo
->LastAccessTime
, sizeof (EFI_TIME
)) &&
1276 CompareMem (&NewFileInfo
->LastAccessTime
, &OldFileInfo
->LastAccessTime
, sizeof (EFI_TIME
))
1279 TimeChangeFlag
= TRUE
;
1280 } else if (!IsZero (&NewFileInfo
->ModificationTime
, sizeof (EFI_TIME
)) &&
1281 CompareMem (&NewFileInfo
->ModificationTime
, &OldFileInfo
->ModificationTime
, sizeof (EFI_TIME
))
1284 TimeChangeFlag
= TRUE
;
1288 // All done if there are no change requests being made.
1290 if (!(AttrChangeFlag
|| NameChangeFlag
|| SizeChangeFlag
|| TimeChangeFlag
)) {
1291 Status
= EFI_SUCCESS
;
1296 // Set file or directory information.
1298 if (stat (OldFileName
, &OldAttr
) != 0) {
1299 Status
= ErrnoToEfiStatus ();
1306 if (NameChangeFlag
) {
1308 // Close the handles first
1310 if (PrivateFile
->IsOpenedByRead
) {
1311 Status
= EFI_ACCESS_DENIED
;
1315 for (CharPointer
= NewFileName
; *CharPointer
!= 0 && *CharPointer
!= L
'/'; CharPointer
++) {
1318 if (*CharPointer
!= 0) {
1319 Status
= EFI_ACCESS_DENIED
;
1323 UnixStatus
= rename (OldFileName
, NewFileName
);
1324 if (UnixStatus
== 0) {
1328 free (PrivateFile
->FileName
);
1330 PrivateFile
->FileName
= malloc (AsciiStrSize (NewFileName
));
1331 if (PrivateFile
->FileName
== NULL
) {
1336 PrivateFile
->FileName
,
1337 AsciiStrSize (NewFileName
),
1341 Status
= EFI_DEVICE_ERROR
;
1349 if (SizeChangeFlag
) {
1350 if (PrivateFile
->IsDirectoryPath
) {
1351 Status
= EFI_UNSUPPORTED
;
1355 if (PrivateFile
->IsOpenedByRead
|| OldFileInfo
->Attribute
& EFI_FILE_READ_ONLY
) {
1356 Status
= EFI_ACCESS_DENIED
;
1360 if (ftruncate (PrivateFile
->fd
, NewFileInfo
->FileSize
) != 0) {
1361 Status
= ErrnoToEfiStatus ();
1369 if (TimeChangeFlag
) {
1370 NewLastAccessSystemTime
.tm_year
= NewFileInfo
->LastAccessTime
.Year
;
1371 NewLastAccessSystemTime
.tm_mon
= NewFileInfo
->LastAccessTime
.Month
;
1372 NewLastAccessSystemTime
.tm_mday
= NewFileInfo
->LastAccessTime
.Day
;
1373 NewLastAccessSystemTime
.tm_hour
= NewFileInfo
->LastAccessTime
.Hour
;
1374 NewLastAccessSystemTime
.tm_min
= NewFileInfo
->LastAccessTime
.Minute
;
1375 NewLastAccessSystemTime
.tm_sec
= NewFileInfo
->LastAccessTime
.Second
;
1376 NewLastAccessSystemTime
.tm_isdst
= 0;
1378 Utime
.actime
= mktime (&NewLastAccessSystemTime
);
1380 NewLastWriteSystemTime
.tm_year
= NewFileInfo
->ModificationTime
.Year
;
1381 NewLastWriteSystemTime
.tm_mon
= NewFileInfo
->ModificationTime
.Month
;
1382 NewLastWriteSystemTime
.tm_mday
= NewFileInfo
->ModificationTime
.Day
;
1383 NewLastWriteSystemTime
.tm_hour
= NewFileInfo
->ModificationTime
.Hour
;
1384 NewLastWriteSystemTime
.tm_min
= NewFileInfo
->ModificationTime
.Minute
;
1385 NewLastWriteSystemTime
.tm_sec
= NewFileInfo
->ModificationTime
.Second
;
1386 NewLastWriteSystemTime
.tm_isdst
= 0;
1388 Utime
.modtime
= mktime (&NewLastWriteSystemTime
);
1390 if ((Utime
.actime
== (time_t)-1) || (Utime
.modtime
== (time_t)-1)) {
1394 if (utime (PrivateFile
->FileName
, &Utime
) == -1) {
1395 Status
= ErrnoToEfiStatus ();
1401 // No matter about AttrChangeFlag, Attribute must be set.
1402 // Because operation before may cause attribute change.
1404 NewAttr
= OldAttr
.st_mode
;
1406 if (NewFileInfo
->Attribute
& EFI_FILE_READ_ONLY
) {
1407 NewAttr
&= ~(S_IRUSR
| S_IRGRP
| S_IROTH
);
1412 if (chmod (NewFileName
, NewAttr
) != 0) {
1413 Status
= ErrnoToEfiStatus ();
1417 if (OldFileInfo
!= NULL
) {
1421 if (OldFileName
!= NULL
) {
1425 if (NewFileName
!= NULL
) {
1433 Flush data back for the file handle.
1435 @param This Protocol instance pointer.
1437 @retval EFI_SUCCESS Data was written.
1438 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
1439 @retval EFI_NO_MEDIA The device has no media.
1440 @retval EFI_DEVICE_ERROR The device reported an error.
1441 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1442 @retval EFI_WRITE_PROTECTED The device is write protected.
1443 @retval EFI_ACCESS_DENIED The file was open for read only.
1444 @retval EFI_VOLUME_FULL The volume is full.
1449 IN EFI_FILE_PROTOCOL
*This
1452 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
1454 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
1456 if (PrivateFile
->IsDirectoryPath
) {
1457 return EFI_UNSUPPORTED
;
1460 if (PrivateFile
->IsOpenedByRead
) {
1461 return EFI_ACCESS_DENIED
;
1464 if (PrivateFile
->fd
< 0) {
1465 return EFI_DEVICE_ERROR
;
1468 if (fsync (PrivateFile
->fd
) != 0) {
1469 return ErrnoToEfiStatus ();
1476 PosixFileSystmeThunkOpen (
1477 IN EMU_IO_THUNK_PROTOCOL
*This
1480 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*Private
;
1483 if (This
->Private
!= NULL
) {
1484 return EFI_ALREADY_STARTED
;
1487 if (!CompareGuid (This
->Protocol
, &gEfiSimpleFileSystemProtocolGuid
)) {
1488 return EFI_UNSUPPORTED
;
1491 Private
= malloc (sizeof (EMU_SIMPLE_FILE_SYSTEM_PRIVATE
));
1492 if (Private
== NULL
) {
1493 return EFI_OUT_OF_RESOURCES
;
1496 Private
->FilePath
= malloc (StrLen (This
->ConfigString
) + 1);
1497 if (Private
->FilePath
== NULL
) {
1499 return EFI_OUT_OF_RESOURCES
;
1502 // Convert Unicode to Ascii
1503 for (i
= 0; This
->ConfigString
[i
] != 0; i
++) {
1504 Private
->FilePath
[i
] = This
->ConfigString
[i
];
1507 Private
->FilePath
[i
] = 0;
1509 Private
->VolumeLabel
= malloc (StrSize (L
"EFI_EMULATED"));
1510 if (Private
->VolumeLabel
== NULL
) {
1511 free (Private
->FilePath
);
1513 return EFI_OUT_OF_RESOURCES
;
1517 Private
->VolumeLabel
,
1518 StrSize (L
"EFI_EMULATED") / sizeof (CHAR16
),
1522 Private
->Signature
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE
;
1523 Private
->Thunk
= This
;
1524 CopyMem (&Private
->SimpleFileSystem
, &gPosixFileSystemProtocol
, sizeof (Private
->SimpleFileSystem
));
1525 Private
->FileHandlesOpen
= FALSE
;
1527 This
->Interface
= &Private
->SimpleFileSystem
;
1528 This
->Private
= Private
;
1533 PosixFileSystmeThunkClose (
1534 IN EMU_IO_THUNK_PROTOCOL
*This
1537 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*Private
;
1539 if (!CompareGuid (This
->Protocol
, &gEfiSimpleFileSystemProtocolGuid
)) {
1540 return EFI_UNSUPPORTED
;
1543 Private
= This
->Private
;
1545 if (Private
->FileHandlesOpen
) {
1547 // Close only supported if all the EFI_FILE_HANDLEs have been closed.
1549 return EFI_NOT_READY
;
1552 if (This
->Private
!= NULL
) {
1553 if (Private
->VolumeLabel
!= NULL
) {
1554 free (Private
->VolumeLabel
);
1557 free (This
->Private
);
1558 This
->Private
= NULL
;
1564 EMU_IO_THUNK_PROTOCOL gPosixFileSystemThunkIo
= {
1565 &gEfiSimpleFileSystemProtocolGuid
,
1569 GasketPosixFileSystmeThunkOpen
,
1570 GasketPosixFileSystmeThunkClose
,