2 POSIX Pthreads to emulate APs and implement threads
4 Copyright (c) 2011, Apple Inc. All rights reserved.
5 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 \
32 #define EMU_EFI_FILE_PRIVATE_SIGNATURE SIGNATURE_32 ('E', 'P', 'f', 'i')
36 EMU_IO_THUNK_PROTOCOL
*Thunk
;
37 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*SimpleFileSystem
;
38 EFI_FILE_PROTOCOL EfiFile
;
41 BOOLEAN IsRootDirectory
;
42 BOOLEAN IsDirectoryPath
;
43 BOOLEAN IsOpenedByRead
;
45 struct dirent
*Dirent
;
46 } EMU_EFI_FILE_PRIVATE
;
48 #define EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS(a) \
50 EMU_EFI_FILE_PRIVATE, \
52 EMU_EFI_FILE_PRIVATE_SIGNATURE \
57 IN EFI_FILE_PROTOCOL
*This
,
58 IN EFI_GUID
*InformationType
,
59 IN OUT UINTN
*BufferSize
,
65 IN EFI_FILE_PROTOCOL
*This
,
66 IN EFI_GUID
*InformationType
,
72 EFI_FILE_PROTOCOL gPosixFileProtocol
= {
76 GasketPosixFileDelete
,
79 GasketPosixFileGetPossition
,
80 GasketPosixFileSetPossition
,
81 GasketPosixFileGetInfo
,
82 GasketPosixFileSetInfo
,
86 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gPosixFileSystemProtocol
= {
87 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
,
88 GasketPosixOpenVolume
,
93 Open the root directory on a volume.
95 @param This Protocol instance pointer.
96 @param Root Returns an Open file handle for the root directory
98 @retval EFI_SUCCESS The device was opened.
99 @retval EFI_UNSUPPORTED This volume does not support the file system.
100 @retval EFI_NO_MEDIA The device has no media.
101 @retval EFI_DEVICE_ERROR The device reported an error.
102 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
103 @retval EFI_ACCESS_DENIED The service denied access to the file.
104 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
109 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*This
,
110 OUT EFI_FILE_PROTOCOL
**Root
114 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*Private
;
115 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
117 Private
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (This
);
119 Status
= EFI_OUT_OF_RESOURCES
;
120 PrivateFile
= malloc (sizeof (EMU_EFI_FILE_PRIVATE
));
121 if (PrivateFile
== NULL
) {
125 PrivateFile
->FileName
= malloc (AsciiStrSize (Private
->FilePath
));
126 if (PrivateFile
->FileName
== NULL
) {
129 AsciiStrCpy (PrivateFile
->FileName
, Private
->FilePath
);
131 PrivateFile
->Signature
= EMU_EFI_FILE_PRIVATE_SIGNATURE
;
132 PrivateFile
->Thunk
= Private
->Thunk
;
133 PrivateFile
->SimpleFileSystem
= This
;
134 PrivateFile
->IsRootDirectory
= TRUE
;
135 PrivateFile
->IsDirectoryPath
= TRUE
;
136 PrivateFile
->IsOpenedByRead
= TRUE
;
138 CopyMem (&PrivateFile
->EfiFile
, &gPosixFileProtocol
, sizeof (EFI_FILE_PROTOCOL
));
140 PrivateFile
->fd
= -1;
141 PrivateFile
->Dir
= NULL
;
142 PrivateFile
->Dirent
= NULL
;
144 *Root
= &PrivateFile
->EfiFile
;
146 PrivateFile
->Dir
= opendir (PrivateFile
->FileName
);
147 if (PrivateFile
->Dir
== NULL
) {
148 Status
= EFI_ACCESS_DENIED
;
150 Status
= EFI_SUCCESS
;
154 if (EFI_ERROR (Status
)) {
155 if (PrivateFile
!= NULL
) {
156 if (PrivateFile
->FileName
!= NULL
) {
157 free (PrivateFile
->FileName
);
175 return EFI_ACCESS_DENIED
;
179 return EFI_VOLUME_FULL
;
182 return EFI_DEVICE_ERROR
;
194 if (AsciiStrLen (Str
) < Count
) {
198 for (Pointer
= Str
; *(Pointer
+ Count
); Pointer
++) {
199 *Pointer
= *(Pointer
+ Count
);
202 *Pointer
= *(Pointer
+ Count
);
207 PosixSystemTimeToEfiTime (
208 IN
time_t SystemTime
,
214 tm
= gmtime (&SystemTime
);
215 Time
->Year
= tm
->tm_year
;
216 Time
->Month
= tm
->tm_mon
+ 1;
217 Time
->Day
= tm
->tm_mday
;
218 Time
->Hour
= tm
->tm_hour
;
219 Time
->Minute
= tm
->tm_min
;
220 Time
->Second
= tm
->tm_sec
;
221 Time
->Nanosecond
= 0;
223 Time
->TimeZone
= timezone
;
224 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
;
271 if (stat (FileName
== NULL
? PrivateFile
->FileName
: FileName
, &buf
) < 0) {
272 return EFI_DEVICE_ERROR
;
275 Status
= EFI_SUCCESS
;
278 ZeroMem (Info
, ResultSize
);
280 Info
->Size
= ResultSize
;
281 Info
->FileSize
= buf
.st_size
;
282 Info
->PhysicalSize
= MultU64x32 (buf
.st_blocks
, buf
.st_blksize
);
284 PosixSystemTimeToEfiTime (buf
.st_ctime
, &Info
->CreateTime
);
285 PosixSystemTimeToEfiTime (buf
.st_atime
, &Info
->LastAccessTime
);
286 PosixSystemTimeToEfiTime (buf
.st_mtime
, &Info
->ModificationTime
);
288 if (!(buf
.st_mode
& S_IWUSR
)) {
289 Info
->Attribute
|= EFI_FILE_READ_ONLY
;
292 if (S_ISDIR(buf
.st_mode
)) {
293 Info
->Attribute
|= EFI_FILE_DIRECTORY
;
297 BufferFileName
= (CHAR16
*)((CHAR8
*) Buffer
+ Size
);
298 while (*RealFileName
) {
299 *BufferFileName
++ = *RealFileName
++;
303 *BufferSize
= ResultSize
;
313 if (Buffer
== NULL
|| Length
== 0) {
317 if (*(UINT8
*) Buffer
!= 0) {
322 if (!CompareMem (Buffer
, (UINT8
*) Buffer
+ 1, Length
- 1)) {
333 Opens a new file relative to the source file's location.
335 @param This The protocol instance pointer.
336 @param NewHandle Returns File Handle for FileName.
337 @param FileName Null terminated string. "\", ".", and ".." are supported.
338 @param OpenMode Open mode for file.
339 @param Attributes Only used for EFI_FILE_MODE_CREATE.
341 @retval EFI_SUCCESS The device was opened.
342 @retval EFI_NOT_FOUND The specified file could not be found on the device.
343 @retval EFI_NO_MEDIA The device has no media.
344 @retval EFI_MEDIA_CHANGED The media has changed.
345 @retval EFI_DEVICE_ERROR The device reported an error.
346 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
347 @retval EFI_ACCESS_DENIED The service denied access to the file.
348 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
349 @retval EFI_VOLUME_FULL The volume is full.
354 IN EFI_FILE_PROTOCOL
*This
,
355 OUT EFI_FILE_PROTOCOL
**NewHandle
,
361 EFI_FILE_PROTOCOL
*Root
;
362 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
363 EMU_EFI_FILE_PRIVATE
*NewPrivateFile
;
364 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*PrivateRoot
;
373 BOOLEAN TrailingDash
;
381 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
382 PrivateRoot
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile
->SimpleFileSystem
);
383 NewPrivateFile
= NULL
;
384 Status
= EFI_OUT_OF_RESOURCES
;
387 // BUGBUG: assume an open of root
388 // if current location, return current data
390 TrailingDash
= FALSE
;
391 if ((StrCmp (FileName
, L
"\\") == 0) ||
392 (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 NewPrivateFile
->FileName
= malloc (AsciiStrSize (PrivateFile
->FileName
) + 1 + StrLen (FileName
) + 1);
415 if (NewPrivateFile
->FileName
== NULL
) {
419 if (*FileName
== L
'\\') {
420 AsciiStrCpy (NewPrivateFile
->FileName
, PrivateRoot
->FilePath
);
424 AsciiStrCpy (NewPrivateFile
->FileName
, PrivateFile
->FileName
);
427 Dst
= NewPrivateFile
->FileName
+ AsciiStrLen (NewPrivateFile
->FileName
);
428 GuardPointer
= NewPrivateFile
->FileName
+ AsciiStrLen (PrivateRoot
->FilePath
);
430 // Convert unicode to ascii and '\' to '/'
443 // Get rid of . and .., except leading . or ..
447 // GuardPointer protect simplefilesystem root path not be destroyed
451 while (!LoopFinish
) {
454 for (ParseFileName
= GuardPointer
; *ParseFileName
; ParseFileName
++) {
455 if (*ParseFileName
== '.' &&
456 (*(ParseFileName
+ 1) == 0 || *(ParseFileName
+ 1) == '/') &&
457 *(ParseFileName
- 1) == '/'
463 CutPrefix (ParseFileName
- 1, 2);
468 if (*ParseFileName
== '.' &&
469 *(ParseFileName
+ 1) == '.' &&
470 (*(ParseFileName
+ 2) == 0 || *(ParseFileName
+ 2) == '/') &&
471 *(ParseFileName
- 1) == '/'
477 while (ParseFileName
!= GuardPointer
) {
480 if (*ParseFileName
== '/') {
486 // cut /.. and its left directory
488 CutPrefix (ParseFileName
, Count
);
495 if (AsciiStrCmp (NewPrivateFile
->FileName
, PrivateRoot
->FilePath
) == 0) {
496 NewPrivateFile
->IsRootDirectory
= TRUE
;
497 free (NewPrivateFile
->FileName
);
498 free (NewPrivateFile
);
502 RealFileName
= NewPrivateFile
->FileName
+ AsciiStrLen(NewPrivateFile
->FileName
) - 1;
503 while (RealFileName
> NewPrivateFile
->FileName
&& *RealFileName
!= '/') {
507 TempChar
= *(RealFileName
- 1);
508 *(RealFileName
- 1) = 0;
509 *(RealFileName
- 1) = TempChar
;
513 // Test whether file or directory
515 NewPrivateFile
->IsRootDirectory
= FALSE
;
516 NewPrivateFile
->fd
= -1;
517 NewPrivateFile
->Dir
= NULL
;
518 if (OpenMode
& EFI_FILE_MODE_CREATE
) {
519 if (Attributes
& EFI_FILE_DIRECTORY
) {
520 NewPrivateFile
->IsDirectoryPath
= TRUE
;
522 NewPrivateFile
->IsDirectoryPath
= FALSE
;
525 res
= stat (NewPrivateFile
->FileName
, &finfo
);
526 if (res
== 0 && S_ISDIR(finfo
.st_mode
)) {
527 NewPrivateFile
->IsDirectoryPath
= TRUE
;
529 NewPrivateFile
->IsDirectoryPath
= FALSE
;
533 if (OpenMode
& EFI_FILE_MODE_WRITE
) {
534 NewPrivateFile
->IsOpenedByRead
= FALSE
;
536 NewPrivateFile
->IsOpenedByRead
= TRUE
;
539 Status
= EFI_SUCCESS
;
542 // deal with directory
544 if (NewPrivateFile
->IsDirectoryPath
) {
545 if ((OpenMode
& EFI_FILE_MODE_CREATE
)) {
547 // Create a directory
549 if (mkdir (NewPrivateFile
->FileName
, 0777) != 0) {
550 if (errno
!= EEXIST
) {
551 //free (TempFileName);
552 Status
= EFI_ACCESS_DENIED
;
558 NewPrivateFile
->Dir
= opendir (NewPrivateFile
->FileName
);
559 if (NewPrivateFile
->Dir
== NULL
) {
560 if (errno
== EACCES
) {
561 Status
= EFI_ACCESS_DENIED
;
563 Status
= EFI_NOT_FOUND
;
573 NewPrivateFile
->fd
= open (
574 NewPrivateFile
->FileName
,
575 ((OpenMode
& EFI_FILE_MODE_CREATE
) ? O_CREAT
: 0) | (NewPrivateFile
->IsOpenedByRead
? O_RDONLY
: O_RDWR
),
578 if (NewPrivateFile
->fd
< 0) {
579 if (errno
== ENOENT
) {
580 Status
= EFI_NOT_FOUND
;
582 Status
= EFI_ACCESS_DENIED
;
587 if ((OpenMode
& EFI_FILE_MODE_CREATE
) && Status
== EFI_SUCCESS
) {
593 Status
= PosixFileGetInfo (&NewPrivateFile
->EfiFile
, &gEfiFileInfoGuid
, &InfoSize
, Info
);
594 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
595 Status
= EFI_DEVICE_ERROR
;
599 Info
= malloc (InfoSize
);
604 Status
= PosixFileGetInfo (&NewPrivateFile
->EfiFile
, &gEfiFileInfoGuid
, &InfoSize
, Info
);
605 if (EFI_ERROR (Status
)) {
609 Info
->Attribute
= Attributes
;
610 PosixFileSetInfo (&NewPrivateFile
->EfiFile
, &gEfiFileInfoGuid
, InfoSize
, Info
);
617 FileName
[StrLen (FileName
) + 1] = 0;
618 FileName
[StrLen (FileName
)] = L
'\\';
621 if (EFI_ERROR (Status
)) {
622 if (NewPrivateFile
) {
623 if (NewPrivateFile
->FileName
) {
624 free (NewPrivateFile
->FileName
);
627 free (NewPrivateFile
);
630 *NewHandle
= &NewPrivateFile
->EfiFile
;
639 Close the file handle
641 @param This Protocol instance pointer.
643 @retval EFI_SUCCESS The device was opened.
648 IN EFI_FILE_PROTOCOL
*This
651 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
653 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
655 if (PrivateFile
->fd
>= 0) {
656 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
);
676 Close and delete the file handle.
678 @param This Protocol instance pointer.
680 @retval EFI_SUCCESS The device was opened.
681 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.
686 IN EFI_FILE_PROTOCOL
*This
690 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
692 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
693 Status
= EFI_WARN_DELETE_FAILURE
;
695 if (PrivateFile
->IsDirectoryPath
) {
696 if (PrivateFile
->Dir
!= NULL
) {
697 closedir (PrivateFile
->Dir
);
698 PrivateFile
->Dir
= NULL
;
701 if (rmdir (PrivateFile
->FileName
) == 0) {
702 Status
= EFI_SUCCESS
;
705 close (PrivateFile
->fd
);
706 PrivateFile
->fd
= -1;
708 if (!PrivateFile
->IsOpenedByRead
) {
709 if (!unlink (PrivateFile
->FileName
)) {
710 Status
= EFI_SUCCESS
;
715 free (PrivateFile
->FileName
);
723 Read data from the file.
725 @param This Protocol instance pointer.
726 @param BufferSize On input size of buffer, on output amount of data in buffer.
727 @param Buffer The buffer in which data is read.
729 @retval EFI_SUCCESS Data was read.
730 @retval EFI_NO_MEDIA The device has no media.
731 @retval EFI_DEVICE_ERROR The device reported an error.
732 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
733 @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size.
738 IN EFI_FILE_PROTOCOL
*This
,
739 IN OUT UINTN
*BufferSize
,
743 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
752 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
754 if (!PrivateFile
->IsDirectoryPath
) {
755 if (PrivateFile
->fd
< 0) {
756 Status
= EFI_DEVICE_ERROR
;
760 Res
= read (PrivateFile
->fd
, Buffer
, *BufferSize
);
762 Status
= EFI_DEVICE_ERROR
;
766 Status
= EFI_SUCCESS
;
771 // Read on a directory.
773 if (PrivateFile
->Dir
== NULL
) {
774 Status
= EFI_DEVICE_ERROR
;
778 if (PrivateFile
->Dirent
== NULL
) {
779 PrivateFile
->Dirent
= readdir (PrivateFile
->Dir
);
780 if (PrivateFile
->Dirent
== NULL
) {
782 Status
= EFI_SUCCESS
;
787 Size
= SIZE_OF_EFI_FILE_INFO
;
788 NameSize
= AsciiStrLen (PrivateFile
->Dirent
->d_name
) + 1;
789 ResultSize
= Size
+ 2 * NameSize
;
791 if (*BufferSize
< ResultSize
) {
792 *BufferSize
= ResultSize
;
793 Status
= EFI_BUFFER_TOO_SMALL
;
796 Status
= EFI_SUCCESS
;
798 *BufferSize
= ResultSize
;
800 FullFileName
= malloc (AsciiStrLen(PrivateFile
->FileName
) + 1 + NameSize
);
801 if (FullFileName
== NULL
) {
802 Status
= EFI_OUT_OF_RESOURCES
;
806 AsciiStrCpy (FullFileName
, PrivateFile
->FileName
);
807 AsciiStrCat (FullFileName
, "/");
808 AsciiStrCat (FullFileName
, PrivateFile
->Dirent
->d_name
);
809 Status
= UnixSimpleFileSystemFileInfo (
817 PrivateFile
->Dirent
= NULL
;
826 Write data to a file.
828 @param This Protocol instance pointer.
829 @param BufferSize On input size of buffer, on output amount of data in buffer.
830 @param Buffer The buffer in which data to write.
832 @retval EFI_SUCCESS Data was written.
833 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
834 @retval EFI_NO_MEDIA The device has no media.
835 @retval EFI_DEVICE_ERROR The device reported an error.
836 @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
837 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
838 @retval EFI_WRITE_PROTECTED The device is write protected.
839 @retval EFI_ACCESS_DENIED The file was open for read only.
840 @retval EFI_VOLUME_FULL The volume is full.
845 IN EFI_FILE_PROTOCOL
*This
,
846 IN OUT UINTN
*BufferSize
,
850 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
854 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
856 if (PrivateFile
->fd
< 0) {
857 return EFI_DEVICE_ERROR
;
860 if (PrivateFile
->IsDirectoryPath
) {
861 return EFI_UNSUPPORTED
;
864 if (PrivateFile
->IsOpenedByRead
) {
865 return EFI_ACCESS_DENIED
;
868 Res
= write (PrivateFile
->fd
, Buffer
, *BufferSize
);
869 if (Res
== (UINTN
)-1) {
870 return ErrnoToEfiStatus ();
880 Set a files current position
882 @param This Protocol instance pointer.
883 @param Position Byte position from the start of the file.
885 @retval EFI_SUCCESS Data was written.
886 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
890 PosixFileSetPossition (
891 IN EFI_FILE_PROTOCOL
*This
,
895 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
898 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
900 if (PrivateFile
->IsDirectoryPath
) {
902 return EFI_UNSUPPORTED
;
905 if (PrivateFile
->Dir
== NULL
) {
906 return EFI_DEVICE_ERROR
;
908 rewinddir (PrivateFile
->Dir
);
911 if (Position
== (UINT64
) -1) {
912 Pos
= lseek (PrivateFile
->fd
, 0, SEEK_END
);
914 Pos
= lseek (PrivateFile
->fd
, Position
, SEEK_SET
);
916 if (Pos
== (off_t
)-1) {
917 return ErrnoToEfiStatus ();
926 Get a file's current position
928 @param This Protocol instance pointer.
929 @param Position Byte position from the start of the file.
931 @retval EFI_SUCCESS Data was written.
932 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..
936 PosixFileGetPossition (
937 IN EFI_FILE_PROTOCOL
*This
,
942 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
944 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
946 if (PrivateFile
->IsDirectoryPath
) {
947 Status
= EFI_UNSUPPORTED
;
949 *Position
= (UINT64
)lseek (PrivateFile
->fd
, 0, SEEK_CUR
);
950 Status
= (*Position
== (UINT64
) -1) ? ErrnoToEfiStatus () : EFI_SUCCESS
;
958 Get information about a file.
960 @param This Protocol instance pointer.
961 @param InformationType Type of information to return in Buffer.
962 @param BufferSize On input size of buffer, on output amount of data in buffer.
963 @param Buffer The buffer to return data.
965 @retval EFI_SUCCESS Data was returned.
966 @retval EFI_UNSUPPORTED InformationType is not supported.
967 @retval EFI_NO_MEDIA The device has no media.
968 @retval EFI_DEVICE_ERROR The device reported an error.
969 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
970 @retval EFI_WRITE_PROTECTED The device is write protected.
971 @retval EFI_ACCESS_DENIED The file was open for read only.
972 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
977 IN EFI_FILE_PROTOCOL
*This
,
978 IN EFI_GUID
*InformationType
,
979 IN OUT UINTN
*BufferSize
,
984 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
985 EFI_FILE_SYSTEM_INFO
*FileSystemInfoBuffer
;
987 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*PrivateRoot
;
990 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
991 PrivateRoot
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile
->SimpleFileSystem
);
993 Status
= EFI_SUCCESS
;
994 if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
995 Status
= UnixSimpleFileSystemFileInfo (PrivateFile
, NULL
, BufferSize
, Buffer
);
996 } else if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
997 if (*BufferSize
< SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
)) {
998 *BufferSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
);
999 return EFI_BUFFER_TOO_SMALL
;
1002 UnixStatus
= statfs (PrivateFile
->FileName
, &buf
);
1003 if (UnixStatus
< 0) {
1004 return EFI_DEVICE_ERROR
;
1007 FileSystemInfoBuffer
= (EFI_FILE_SYSTEM_INFO
*) Buffer
;
1008 FileSystemInfoBuffer
->Size
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
);
1009 FileSystemInfoBuffer
->ReadOnly
= FALSE
;
1014 FileSystemInfoBuffer
->VolumeSize
= MultU64x32 (buf
.f_blocks
, buf
.f_bsize
);
1015 FileSystemInfoBuffer
->FreeSpace
= MultU64x32 (buf
.f_bavail
, buf
.f_bsize
);
1016 FileSystemInfoBuffer
->BlockSize
= buf
.f_bsize
;
1019 StrCpy ((CHAR16
*) FileSystemInfoBuffer
->VolumeLabel
, PrivateRoot
->VolumeLabel
);
1020 *BufferSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
);
1022 } else if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
1023 if (*BufferSize
< StrSize (PrivateRoot
->VolumeLabel
)) {
1024 *BufferSize
= StrSize (PrivateRoot
->VolumeLabel
);
1025 return EFI_BUFFER_TOO_SMALL
;
1028 StrCpy ((CHAR16
*) Buffer
, PrivateRoot
->VolumeLabel
);
1029 *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
) {
1112 StrCpy (PrivateRoot
->VolumeLabel
, NewFileSystemInfo
->VolumeLabel
);
1114 Status
= EFI_SUCCESS
;
1119 // Set volume label information.
1121 if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
1122 if (BufferSize
< StrSize (PrivateRoot
->VolumeLabel
)) {
1123 Status
= EFI_BAD_BUFFER_SIZE
;
1127 StrCpy (PrivateRoot
->VolumeLabel
, (CHAR16
*) Buffer
);
1129 Status
= EFI_SUCCESS
;
1133 if (!CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
1134 Status
= EFI_UNSUPPORTED
;
1138 if (BufferSize
< SIZE_OF_EFI_FILE_INFO
) {
1139 Status
= EFI_BAD_BUFFER_SIZE
;
1144 // Set file/directory information.
1148 // Check for invalid set file information parameters.
1150 NewFileInfo
= (EFI_FILE_INFO
*) Buffer
;
1151 if (NewFileInfo
->Size
<= sizeof (EFI_FILE_INFO
) ||
1152 (NewFileInfo
->Attribute
&~(EFI_FILE_VALID_ATTR
)) ||
1153 (sizeof (UINTN
) == 4 && NewFileInfo
->Size
> 0xFFFFFFFF)
1155 Status
= EFI_INVALID_PARAMETER
;
1160 // Get current file information so we can determine what kind
1161 // of change request this is.
1164 Status
= UnixSimpleFileSystemFileInfo (PrivateFile
, NULL
, &OldInfoSize
, NULL
);
1165 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1166 Status
= EFI_DEVICE_ERROR
;
1170 OldFileInfo
= malloc (OldInfoSize
);
1171 if (OldFileInfo
== NULL
) {
1175 Status
= UnixSimpleFileSystemFileInfo (PrivateFile
, NULL
, &OldInfoSize
, OldFileInfo
);
1176 if (EFI_ERROR (Status
)) {
1180 OldFileName
= malloc (AsciiStrSize (PrivateFile
->FileName
));
1181 if (OldFileInfo
== NULL
) {
1185 AsciiStrCpy (OldFileName
, PrivateFile
->FileName
);
1188 // Make full pathname from new filename and rootpath.
1190 if (NewFileInfo
->FileName
[0] == '\\') {
1191 NewFileName
= malloc (AsciiStrLen (PrivateRoot
->FilePath
) + 1 + StrLen (NewFileInfo
->FileName
) + 1);
1192 if (NewFileName
== NULL
) {
1196 AsciiStrCpy (NewFileName
, PrivateRoot
->FilePath
);
1197 AsciiFilePtr
= NewFileName
+ AsciiStrLen(NewFileName
);
1198 UnicodeFilePtr
= NewFileInfo
->FileName
+ 1;
1199 *AsciiFilePtr
++ ='/';
1201 NewFileName
= malloc (AsciiStrLen (PrivateFile
->FileName
) + 2 + StrLen (NewFileInfo
->FileName
) + 1);
1202 if (NewFileName
== NULL
) {
1206 AsciiStrCpy (NewFileName
, PrivateRoot
->FilePath
);
1207 AsciiFilePtr
= NewFileName
+ AsciiStrLen(NewFileName
);
1208 if ((AsciiFilePtr
[-1] != '/') && (NewFileInfo
->FileName
[0] != '/')) {
1209 // make sure there is a / between Root FilePath and NewFileInfo Filename
1210 AsciiFilePtr
[0] = '/';
1211 AsciiFilePtr
[1] = '\0';
1214 UnicodeFilePtr
= NewFileInfo
->FileName
;
1216 // Convert to ascii.
1217 while (*UnicodeFilePtr
) {
1218 *AsciiFilePtr
++ = *UnicodeFilePtr
++;
1223 // Is there an attribute change request?
1225 if (NewFileInfo
->Attribute
!= OldFileInfo
->Attribute
) {
1226 if ((NewFileInfo
->Attribute
& EFI_FILE_DIRECTORY
) != (OldFileInfo
->Attribute
& EFI_FILE_DIRECTORY
)) {
1227 Status
= EFI_INVALID_PARAMETER
;
1231 AttrChangeFlag
= TRUE
;
1235 // Is there a name change request?
1236 // bugbug: - Should really use EFI_UNICODE_COLLATION_PROTOCOL
1238 if (StrCmp (NewFileInfo
->FileName
, OldFileInfo
->FileName
)) {
1239 NameChangeFlag
= TRUE
;
1243 // Is there a size change request?
1245 if (NewFileInfo
->FileSize
!= OldFileInfo
->FileSize
) {
1246 SizeChangeFlag
= TRUE
;
1250 // Is there a time stamp change request?
1252 if (!IsZero (&NewFileInfo
->CreateTime
, sizeof (EFI_TIME
)) &&
1253 CompareMem (&NewFileInfo
->CreateTime
, &OldFileInfo
->CreateTime
, sizeof (EFI_TIME
))
1255 TimeChangeFlag
= TRUE
;
1256 } else if (!IsZero (&NewFileInfo
->LastAccessTime
, sizeof (EFI_TIME
)) &&
1257 CompareMem (&NewFileInfo
->LastAccessTime
, &OldFileInfo
->LastAccessTime
, sizeof (EFI_TIME
))
1259 TimeChangeFlag
= TRUE
;
1260 } else if (!IsZero (&NewFileInfo
->ModificationTime
, sizeof (EFI_TIME
)) &&
1261 CompareMem (&NewFileInfo
->ModificationTime
, &OldFileInfo
->ModificationTime
, sizeof (EFI_TIME
))
1263 TimeChangeFlag
= TRUE
;
1267 // All done if there are no change requests being made.
1269 if (!(AttrChangeFlag
|| NameChangeFlag
|| SizeChangeFlag
|| TimeChangeFlag
)) {
1270 Status
= EFI_SUCCESS
;
1275 // Set file or directory information.
1277 if (stat (OldFileName
, &OldAttr
) != 0) {
1278 Status
= ErrnoToEfiStatus ();
1285 if (NameChangeFlag
) {
1287 // Close the handles first
1289 if (PrivateFile
->IsOpenedByRead
) {
1290 Status
= EFI_ACCESS_DENIED
;
1294 for (CharPointer
= NewFileName
; *CharPointer
!= 0 && *CharPointer
!= L
'/'; CharPointer
++) {
1297 if (*CharPointer
!= 0) {
1298 Status
= EFI_ACCESS_DENIED
;
1302 UnixStatus
= rename (OldFileName
, NewFileName
);
1303 if (UnixStatus
== 0) {
1307 free (PrivateFile
->FileName
);
1309 PrivateFile
->FileName
= malloc (AsciiStrSize (NewFileName
));
1310 if (PrivateFile
->FileName
== NULL
) {
1314 AsciiStrCpy (PrivateFile
->FileName
, NewFileName
);
1316 Status
= EFI_DEVICE_ERROR
;
1324 if (SizeChangeFlag
) {
1325 if (PrivateFile
->IsDirectoryPath
) {
1326 Status
= EFI_UNSUPPORTED
;
1330 if (PrivateFile
->IsOpenedByRead
|| OldFileInfo
->Attribute
& EFI_FILE_READ_ONLY
) {
1331 Status
= EFI_ACCESS_DENIED
;
1335 if (ftruncate (PrivateFile
->fd
, NewFileInfo
->FileSize
) != 0) {
1336 Status
= ErrnoToEfiStatus ();
1345 if (TimeChangeFlag
) {
1346 NewLastAccessSystemTime
.tm_year
= NewFileInfo
->LastAccessTime
.Year
;
1347 NewLastAccessSystemTime
.tm_mon
= NewFileInfo
->LastAccessTime
.Month
;
1348 NewLastAccessSystemTime
.tm_mday
= NewFileInfo
->LastAccessTime
.Day
;
1349 NewLastAccessSystemTime
.tm_hour
= NewFileInfo
->LastAccessTime
.Hour
;
1350 NewLastAccessSystemTime
.tm_min
= NewFileInfo
->LastAccessTime
.Minute
;
1351 NewLastAccessSystemTime
.tm_sec
= NewFileInfo
->LastAccessTime
.Second
;
1352 NewLastAccessSystemTime
.tm_isdst
= 0;
1354 Utime
.actime
= mktime (&NewLastAccessSystemTime
);
1356 NewLastWriteSystemTime
.tm_year
= NewFileInfo
->ModificationTime
.Year
;
1357 NewLastWriteSystemTime
.tm_mon
= NewFileInfo
->ModificationTime
.Month
;
1358 NewLastWriteSystemTime
.tm_mday
= NewFileInfo
->ModificationTime
.Day
;
1359 NewLastWriteSystemTime
.tm_hour
= NewFileInfo
->ModificationTime
.Hour
;
1360 NewLastWriteSystemTime
.tm_min
= NewFileInfo
->ModificationTime
.Minute
;
1361 NewLastWriteSystemTime
.tm_sec
= NewFileInfo
->ModificationTime
.Second
;
1362 NewLastWriteSystemTime
.tm_isdst
= 0;
1364 Utime
.modtime
= mktime (&NewLastWriteSystemTime
);
1366 if (Utime
.actime
== (time_t)-1 || Utime
.modtime
== (time_t)-1) {
1370 if (utime (PrivateFile
->FileName
, &Utime
) == -1) {
1371 Status
= ErrnoToEfiStatus ();
1377 // No matter about AttrChangeFlag, Attribute must be set.
1378 // Because operation before may cause attribute change.
1380 NewAttr
= OldAttr
.st_mode
;
1382 if (NewFileInfo
->Attribute
& EFI_FILE_READ_ONLY
) {
1383 NewAttr
&= ~(S_IRUSR
| S_IRGRP
| S_IROTH
);
1388 if (chmod (NewFileName
, NewAttr
) != 0) {
1389 Status
= ErrnoToEfiStatus ();
1393 if (OldFileInfo
!= NULL
) {
1397 if (OldFileName
!= NULL
) {
1401 if (NewFileName
!= NULL
) {
1410 Flush data back for the file handle.
1412 @param This Protocol instance pointer.
1414 @retval EFI_SUCCESS Data was written.
1415 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
1416 @retval EFI_NO_MEDIA The device has no media.
1417 @retval EFI_DEVICE_ERROR The device reported an error.
1418 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1419 @retval EFI_WRITE_PROTECTED The device is write protected.
1420 @retval EFI_ACCESS_DENIED The file was open for read only.
1421 @retval EFI_VOLUME_FULL The volume is full.
1426 IN EFI_FILE_PROTOCOL
*This
1429 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
1432 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
1434 if (PrivateFile
->IsDirectoryPath
) {
1435 return EFI_UNSUPPORTED
;
1438 if (PrivateFile
->IsOpenedByRead
) {
1439 return EFI_ACCESS_DENIED
;
1442 if (PrivateFile
->fd
< 0) {
1443 return EFI_DEVICE_ERROR
;
1446 if (fsync (PrivateFile
->fd
) != 0) {
1447 return ErrnoToEfiStatus ();
1456 PosixFileSystmeThunkOpen (
1457 IN EMU_IO_THUNK_PROTOCOL
*This
1460 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*Private
;
1463 if (This
->Private
!= NULL
) {
1464 return EFI_ALREADY_STARTED
;
1467 if (!CompareGuid (This
->Protocol
, &gEfiSimpleFileSystemProtocolGuid
)) {
1468 return EFI_UNSUPPORTED
;
1471 Private
= malloc (sizeof (EMU_SIMPLE_FILE_SYSTEM_PRIVATE
));
1472 if (Private
== NULL
) {
1473 return EFI_OUT_OF_RESOURCES
;
1476 Private
->FilePath
= malloc (StrLen (This
->ConfigString
) + 1);
1477 if (Private
->FilePath
== NULL
) {
1479 return EFI_OUT_OF_RESOURCES
;
1482 // Convert Unicode to Ascii
1483 for (i
= 0; This
->ConfigString
[i
] != 0; i
++) {
1484 Private
->FilePath
[i
] = This
->ConfigString
[i
];
1486 Private
->FilePath
[i
] = 0;
1489 Private
->VolumeLabel
= malloc (StrSize (L
"EFI_EMULATED"));
1490 if (Private
->VolumeLabel
== NULL
) {
1491 free (Private
->FilePath
);
1493 return EFI_OUT_OF_RESOURCES
;
1495 StrCpy (Private
->VolumeLabel
, L
"EFI_EMULATED");
1497 Private
->Signature
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE
;
1498 Private
->Thunk
= This
;
1499 CopyMem (&Private
->SimpleFileSystem
, &gPosixFileSystemProtocol
, sizeof (Private
->SimpleFileSystem
));
1500 Private
->FileHandlesOpen
= FALSE
;
1502 This
->Interface
= &Private
->SimpleFileSystem
;
1503 This
->Private
= Private
;
1509 PosixFileSystmeThunkClose (
1510 IN EMU_IO_THUNK_PROTOCOL
*This
1513 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*Private
;
1515 if (!CompareGuid (This
->Protocol
, &gEfiSimpleFileSystemProtocolGuid
)) {
1516 return EFI_UNSUPPORTED
;
1519 Private
= This
->Private
;
1521 if (Private
->FileHandlesOpen
) {
1523 // Close only supported if all the EFI_FILE_HANDLEs have been closed.
1525 return EFI_NOT_READY
;
1528 if (This
->Private
!= NULL
) {
1529 if (Private
->VolumeLabel
!= NULL
) {
1530 free (Private
->VolumeLabel
);
1532 free (This
->Private
);
1533 This
->Private
= NULL
;
1540 EMU_IO_THUNK_PROTOCOL gPosixFileSystemThunkIo
= {
1541 &gEfiSimpleFileSystemProtocolGuid
,
1545 GasketPosixFileSystmeThunkOpen
,
1546 GasketPosixFileSystmeThunkClose
,