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
) {
130 AsciiStrCpy (PrivateFile
->FileName
, Private
->FilePath
);
132 PrivateFile
->Signature
= EMU_EFI_FILE_PRIVATE_SIGNATURE
;
133 PrivateFile
->Thunk
= Private
->Thunk
;
134 PrivateFile
->SimpleFileSystem
= This
;
135 PrivateFile
->IsRootDirectory
= TRUE
;
136 PrivateFile
->IsDirectoryPath
= TRUE
;
137 PrivateFile
->IsOpenedByRead
= TRUE
;
139 CopyMem (&PrivateFile
->EfiFile
, &gPosixFileProtocol
, sizeof (EFI_FILE_PROTOCOL
));
141 PrivateFile
->fd
= -1;
142 PrivateFile
->Dir
= NULL
;
143 PrivateFile
->Dirent
= NULL
;
145 *Root
= &PrivateFile
->EfiFile
;
147 PrivateFile
->Dir
= opendir (PrivateFile
->FileName
);
148 if (PrivateFile
->Dir
== NULL
) {
149 Status
= EFI_ACCESS_DENIED
;
151 Status
= EFI_SUCCESS
;
155 if (EFI_ERROR (Status
)) {
156 if (PrivateFile
!= NULL
) {
157 if (PrivateFile
->FileName
!= NULL
) {
158 free (PrivateFile
->FileName
);
176 return EFI_ACCESS_DENIED
;
180 return EFI_VOLUME_FULL
;
183 return EFI_DEVICE_ERROR
;
195 if (AsciiStrLen (Str
) < Count
) {
199 for (Pointer
= Str
; *(Pointer
+ Count
); Pointer
++) {
200 *Pointer
= *(Pointer
+ Count
);
203 *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);
230 UnixSimpleFileSystemFileInfo (
231 EMU_EFI_FILE_PRIVATE
*PrivateFile
,
233 IN OUT UINTN
*BufferSize
,
244 CHAR16
*BufferFileName
;
247 if (FileName
!= NULL
) {
248 RealFileName
= FileName
;
249 } else if (PrivateFile
->IsRootDirectory
) {
252 RealFileName
= PrivateFile
->FileName
;
255 TempPointer
= RealFileName
;
256 while (*TempPointer
) {
257 if (*TempPointer
== '/') {
258 RealFileName
= TempPointer
+ 1;
264 Size
= SIZE_OF_EFI_FILE_INFO
;
265 NameSize
= AsciiStrSize (RealFileName
) * 2;
266 ResultSize
= Size
+ NameSize
;
268 if (*BufferSize
< ResultSize
) {
269 *BufferSize
= ResultSize
;
270 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
;
298 BufferFileName
= (CHAR16
*)((CHAR8
*) Buffer
+ Size
);
299 while (*RealFileName
) {
300 *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)) {
334 Opens a new file relative to the source file's location.
336 @param This The protocol instance pointer.
337 @param NewHandle Returns File Handle for FileName.
338 @param FileName Null terminated string. "\", ".", and ".." are supported.
339 @param OpenMode Open mode for file.
340 @param Attributes Only used for EFI_FILE_MODE_CREATE.
342 @retval EFI_SUCCESS The device was opened.
343 @retval EFI_NOT_FOUND The specified file could not be found on the device.
344 @retval EFI_NO_MEDIA The device has no media.
345 @retval EFI_MEDIA_CHANGED The media has changed.
346 @retval EFI_DEVICE_ERROR The device reported an error.
347 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
348 @retval EFI_ACCESS_DENIED The service denied access to the file.
349 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
350 @retval EFI_VOLUME_FULL The volume is full.
355 IN EFI_FILE_PROTOCOL
*This
,
356 OUT EFI_FILE_PROTOCOL
**NewHandle
,
362 EFI_FILE_PROTOCOL
*Root
;
363 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
364 EMU_EFI_FILE_PRIVATE
*NewPrivateFile
;
365 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*PrivateRoot
;
374 BOOLEAN TrailingDash
;
382 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
383 PrivateRoot
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile
->SimpleFileSystem
);
384 NewPrivateFile
= NULL
;
385 Status
= EFI_OUT_OF_RESOURCES
;
388 // BUGBUG: assume an open of root
389 // if current location, return current data
391 TrailingDash
= FALSE
;
392 if ((StrCmp (FileName
, L
"\\") == 0) ||
393 (StrCmp (FileName
, L
".") == 0 && PrivateFile
->IsRootDirectory
)) {
395 Status
= PosixOpenVolume (PrivateFile
->SimpleFileSystem
, &Root
);
396 NewPrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (Root
);
400 if (FileName
[StrLen (FileName
) - 1] == L
'\\') {
402 FileName
[StrLen (FileName
) - 1] = 0;
406 // Attempt to open the file
408 NewPrivateFile
= malloc (sizeof (EMU_EFI_FILE_PRIVATE
));
409 if (NewPrivateFile
== NULL
) {
413 CopyMem (NewPrivateFile
, PrivateFile
, sizeof (EMU_EFI_FILE_PRIVATE
));
415 NewPrivateFile
->FileName
= malloc (AsciiStrSize (PrivateFile
->FileName
) + 1 + StrLen (FileName
) + 1);
416 if (NewPrivateFile
->FileName
== NULL
) {
420 if (*FileName
== L
'\\') {
421 AsciiStrCpy (NewPrivateFile
->FileName
, PrivateRoot
->FilePath
);
425 AsciiStrCpy (NewPrivateFile
->FileName
, PrivateFile
->FileName
);
428 Dst
= NewPrivateFile
->FileName
+ AsciiStrLen (NewPrivateFile
->FileName
);
429 GuardPointer
= NewPrivateFile
->FileName
+ AsciiStrLen (PrivateRoot
->FilePath
);
431 // Convert unicode to ascii and '\' to '/'
444 // Get rid of . and .., except leading . or ..
448 // GuardPointer protect simplefilesystem root path not be destroyed
452 while (!LoopFinish
) {
455 for (ParseFileName
= GuardPointer
; *ParseFileName
; ParseFileName
++) {
456 if (*ParseFileName
== '.' &&
457 (*(ParseFileName
+ 1) == 0 || *(ParseFileName
+ 1) == '/') &&
458 *(ParseFileName
- 1) == '/'
464 CutPrefix (ParseFileName
- 1, 2);
469 if (*ParseFileName
== '.' &&
470 *(ParseFileName
+ 1) == '.' &&
471 (*(ParseFileName
+ 2) == 0 || *(ParseFileName
+ 2) == '/') &&
472 *(ParseFileName
- 1) == '/'
478 while (ParseFileName
!= GuardPointer
) {
481 if (*ParseFileName
== '/') {
487 // cut /.. and its left directory
489 CutPrefix (ParseFileName
, Count
);
496 if (AsciiStrCmp (NewPrivateFile
->FileName
, PrivateRoot
->FilePath
) == 0) {
497 NewPrivateFile
->IsRootDirectory
= TRUE
;
498 free (NewPrivateFile
->FileName
);
499 free (NewPrivateFile
);
503 RealFileName
= NewPrivateFile
->FileName
+ AsciiStrLen(NewPrivateFile
->FileName
) - 1;
504 while (RealFileName
> NewPrivateFile
->FileName
&& *RealFileName
!= '/') {
508 TempChar
= *(RealFileName
- 1);
509 *(RealFileName
- 1) = 0;
510 *(RealFileName
- 1) = TempChar
;
514 // Test whether file or directory
516 NewPrivateFile
->IsRootDirectory
= FALSE
;
517 NewPrivateFile
->fd
= -1;
518 NewPrivateFile
->Dir
= NULL
;
519 if (OpenMode
& EFI_FILE_MODE_CREATE
) {
520 if (Attributes
& EFI_FILE_DIRECTORY
) {
521 NewPrivateFile
->IsDirectoryPath
= TRUE
;
523 NewPrivateFile
->IsDirectoryPath
= FALSE
;
526 res
= stat (NewPrivateFile
->FileName
, &finfo
);
527 if (res
== 0 && S_ISDIR(finfo
.st_mode
)) {
528 NewPrivateFile
->IsDirectoryPath
= TRUE
;
530 NewPrivateFile
->IsDirectoryPath
= FALSE
;
534 if (OpenMode
& EFI_FILE_MODE_WRITE
) {
535 NewPrivateFile
->IsOpenedByRead
= FALSE
;
537 NewPrivateFile
->IsOpenedByRead
= TRUE
;
540 Status
= EFI_SUCCESS
;
543 // deal with directory
545 if (NewPrivateFile
->IsDirectoryPath
) {
546 if ((OpenMode
& EFI_FILE_MODE_CREATE
)) {
548 // Create a directory
550 if (mkdir (NewPrivateFile
->FileName
, 0777) != 0) {
551 if (errno
!= EEXIST
) {
552 //free (TempFileName);
553 Status
= EFI_ACCESS_DENIED
;
559 NewPrivateFile
->Dir
= opendir (NewPrivateFile
->FileName
);
560 if (NewPrivateFile
->Dir
== NULL
) {
561 if (errno
== EACCES
) {
562 Status
= EFI_ACCESS_DENIED
;
564 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
;
640 Close the file handle
642 @param This Protocol instance pointer.
644 @retval EFI_SUCCESS The device was opened.
649 IN EFI_FILE_PROTOCOL
*This
652 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
654 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
656 if (PrivateFile
->fd
>= 0) {
657 close (PrivateFile
->fd
);
659 if (PrivateFile
->Dir
!= NULL
) {
660 closedir (PrivateFile
->Dir
);
663 PrivateFile
->fd
= -1;
664 PrivateFile
->Dir
= NULL
;
666 if (PrivateFile
->FileName
) {
667 free (PrivateFile
->FileName
);
677 Close and delete the file handle.
679 @param This Protocol instance pointer.
681 @retval EFI_SUCCESS The device was opened.
682 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.
687 IN EFI_FILE_PROTOCOL
*This
691 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
693 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
694 Status
= EFI_WARN_DELETE_FAILURE
;
696 if (PrivateFile
->IsDirectoryPath
) {
697 if (PrivateFile
->Dir
!= NULL
) {
698 closedir (PrivateFile
->Dir
);
699 PrivateFile
->Dir
= NULL
;
702 if (rmdir (PrivateFile
->FileName
) == 0) {
703 Status
= EFI_SUCCESS
;
706 close (PrivateFile
->fd
);
707 PrivateFile
->fd
= -1;
709 if (!PrivateFile
->IsOpenedByRead
) {
710 if (!unlink (PrivateFile
->FileName
)) {
711 Status
= EFI_SUCCESS
;
716 free (PrivateFile
->FileName
);
724 Read data from the file.
726 @param This Protocol instance pointer.
727 @param BufferSize On input size of buffer, on output amount of data in buffer.
728 @param Buffer The buffer in which data is read.
730 @retval EFI_SUCCESS Data was read.
731 @retval EFI_NO_MEDIA The device has no media.
732 @retval EFI_DEVICE_ERROR The device reported an error.
733 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
734 @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size.
739 IN EFI_FILE_PROTOCOL
*This
,
740 IN OUT UINTN
*BufferSize
,
744 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
753 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
755 if (!PrivateFile
->IsDirectoryPath
) {
756 if (PrivateFile
->fd
< 0) {
757 Status
= EFI_DEVICE_ERROR
;
761 Res
= read (PrivateFile
->fd
, Buffer
, *BufferSize
);
763 Status
= EFI_DEVICE_ERROR
;
767 Status
= EFI_SUCCESS
;
772 // Read on a directory.
774 if (PrivateFile
->Dir
== NULL
) {
775 Status
= EFI_DEVICE_ERROR
;
779 if (PrivateFile
->Dirent
== NULL
) {
780 PrivateFile
->Dirent
= readdir (PrivateFile
->Dir
);
781 if (PrivateFile
->Dirent
== NULL
) {
783 Status
= EFI_SUCCESS
;
788 Size
= SIZE_OF_EFI_FILE_INFO
;
789 NameSize
= AsciiStrLen (PrivateFile
->Dirent
->d_name
) + 1;
790 ResultSize
= Size
+ 2 * NameSize
;
792 if (*BufferSize
< ResultSize
) {
793 *BufferSize
= ResultSize
;
794 Status
= EFI_BUFFER_TOO_SMALL
;
797 Status
= EFI_SUCCESS
;
799 *BufferSize
= ResultSize
;
801 FullFileName
= malloc (AsciiStrLen(PrivateFile
->FileName
) + 1 + NameSize
);
802 if (FullFileName
== NULL
) {
803 Status
= EFI_OUT_OF_RESOURCES
;
807 AsciiStrCpy (FullFileName
, PrivateFile
->FileName
);
808 AsciiStrCat (FullFileName
, "/");
809 AsciiStrCat (FullFileName
, PrivateFile
->Dirent
->d_name
);
810 Status
= UnixSimpleFileSystemFileInfo (
818 PrivateFile
->Dirent
= NULL
;
827 Write data to a file.
829 @param This Protocol instance pointer.
830 @param BufferSize On input size of buffer, on output amount of data in buffer.
831 @param Buffer The buffer in which data to write.
833 @retval EFI_SUCCESS Data was written.
834 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
835 @retval EFI_NO_MEDIA The device has no media.
836 @retval EFI_DEVICE_ERROR The device reported an error.
837 @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
838 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
839 @retval EFI_WRITE_PROTECTED The device is write protected.
840 @retval EFI_ACCESS_DENIED The file was open for read only.
841 @retval EFI_VOLUME_FULL The volume is full.
846 IN EFI_FILE_PROTOCOL
*This
,
847 IN OUT UINTN
*BufferSize
,
851 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
855 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
857 if (PrivateFile
->fd
< 0) {
858 return EFI_DEVICE_ERROR
;
861 if (PrivateFile
->IsDirectoryPath
) {
862 return EFI_UNSUPPORTED
;
865 if (PrivateFile
->IsOpenedByRead
) {
866 return EFI_ACCESS_DENIED
;
869 Res
= write (PrivateFile
->fd
, Buffer
, *BufferSize
);
870 if (Res
== (UINTN
)-1) {
871 return ErrnoToEfiStatus ();
881 Set a files current position
883 @param This Protocol instance pointer.
884 @param Position Byte position from the start of the file.
886 @retval EFI_SUCCESS Data was written.
887 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
891 PosixFileSetPossition (
892 IN EFI_FILE_PROTOCOL
*This
,
896 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
899 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
901 if (PrivateFile
->IsDirectoryPath
) {
903 return EFI_UNSUPPORTED
;
906 if (PrivateFile
->Dir
== NULL
) {
907 return EFI_DEVICE_ERROR
;
909 rewinddir (PrivateFile
->Dir
);
912 if (Position
== (UINT64
) -1) {
913 Pos
= lseek (PrivateFile
->fd
, 0, SEEK_END
);
915 Pos
= lseek (PrivateFile
->fd
, Position
, SEEK_SET
);
917 if (Pos
== (off_t
)-1) {
918 return ErrnoToEfiStatus ();
927 Get a file's current position
929 @param This Protocol instance pointer.
930 @param Position Byte position from the start of the file.
932 @retval EFI_SUCCESS Data was written.
933 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..
937 PosixFileGetPossition (
938 IN EFI_FILE_PROTOCOL
*This
,
943 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
945 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
947 if (PrivateFile
->IsDirectoryPath
) {
948 Status
= EFI_UNSUPPORTED
;
950 *Position
= (UINT64
)lseek (PrivateFile
->fd
, 0, SEEK_CUR
);
951 Status
= (*Position
== (UINT64
) -1) ? ErrnoToEfiStatus () : EFI_SUCCESS
;
959 Get information about a file.
961 @param This Protocol instance pointer.
962 @param InformationType Type of information to return in Buffer.
963 @param BufferSize On input size of buffer, on output amount of data in buffer.
964 @param Buffer The buffer to return data.
966 @retval EFI_SUCCESS Data was returned.
967 @retval EFI_UNSUPPORTED InformationType is not supported.
968 @retval EFI_NO_MEDIA The device has no media.
969 @retval EFI_DEVICE_ERROR The device reported an error.
970 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
971 @retval EFI_WRITE_PROTECTED The device is write protected.
972 @retval EFI_ACCESS_DENIED The file was open for read only.
973 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
978 IN EFI_FILE_PROTOCOL
*This
,
979 IN EFI_GUID
*InformationType
,
980 IN OUT UINTN
*BufferSize
,
985 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
986 EFI_FILE_SYSTEM_INFO
*FileSystemInfoBuffer
;
988 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*PrivateRoot
;
991 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
992 PrivateRoot
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile
->SimpleFileSystem
);
994 Status
= EFI_SUCCESS
;
995 if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
996 Status
= UnixSimpleFileSystemFileInfo (PrivateFile
, NULL
, BufferSize
, Buffer
);
997 } else if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
998 if (*BufferSize
< SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
)) {
999 *BufferSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
);
1000 return EFI_BUFFER_TOO_SMALL
;
1003 UnixStatus
= statfs (PrivateFile
->FileName
, &buf
);
1004 if (UnixStatus
< 0) {
1005 return EFI_DEVICE_ERROR
;
1008 FileSystemInfoBuffer
= (EFI_FILE_SYSTEM_INFO
*) Buffer
;
1009 FileSystemInfoBuffer
->Size
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
);
1010 FileSystemInfoBuffer
->ReadOnly
= FALSE
;
1015 FileSystemInfoBuffer
->VolumeSize
= MultU64x32 (buf
.f_blocks
, buf
.f_bsize
);
1016 FileSystemInfoBuffer
->FreeSpace
= MultU64x32 (buf
.f_bavail
, buf
.f_bsize
);
1017 FileSystemInfoBuffer
->BlockSize
= buf
.f_bsize
;
1020 StrCpy ((CHAR16
*) FileSystemInfoBuffer
->VolumeLabel
, PrivateRoot
->VolumeLabel
);
1021 *BufferSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
);
1023 } else if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
1024 if (*BufferSize
< StrSize (PrivateRoot
->VolumeLabel
)) {
1025 *BufferSize
= StrSize (PrivateRoot
->VolumeLabel
);
1026 return EFI_BUFFER_TOO_SMALL
;
1029 StrCpy ((CHAR16
*) Buffer
, PrivateRoot
->VolumeLabel
);
1030 *BufferSize
= StrSize (PrivateRoot
->VolumeLabel
);
1039 Set information about a file
1041 @param File Protocol instance pointer.
1042 @param InformationType Type of information in Buffer.
1043 @param BufferSize Size of buffer.
1044 @param Buffer The data to write.
1046 @retval EFI_SUCCESS Data was returned.
1047 @retval EFI_UNSUPPORTED InformationType is not supported.
1048 @retval EFI_NO_MEDIA The device has no media.
1049 @retval EFI_DEVICE_ERROR The device reported an error.
1050 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1051 @retval EFI_WRITE_PROTECTED The device is write protected.
1052 @retval EFI_ACCESS_DENIED The file was open for read only.
1057 IN EFI_FILE_PROTOCOL
*This
,
1058 IN EFI_GUID
*InformationType
,
1059 IN UINTN BufferSize
,
1063 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*PrivateRoot
;
1064 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
1065 EFI_FILE_INFO
*OldFileInfo
;
1066 EFI_FILE_INFO
*NewFileInfo
;
1070 struct stat OldAttr
;
1074 BOOLEAN AttrChangeFlag
;
1075 BOOLEAN NameChangeFlag
;
1076 BOOLEAN SizeChangeFlag
;
1077 BOOLEAN TimeChangeFlag
;
1078 struct tm NewLastAccessSystemTime
;
1079 struct tm NewLastWriteSystemTime
;
1080 EFI_FILE_SYSTEM_INFO
*NewFileSystemInfo
;
1081 CHAR8
*AsciiFilePtr
;
1082 CHAR16
*UnicodeFilePtr
;
1084 struct utimbuf Utime
;
1087 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
1088 PrivateRoot
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile
->SimpleFileSystem
);
1090 Status
= EFI_UNSUPPORTED
;
1091 OldFileInfo
= NewFileInfo
= NULL
;
1092 OldFileName
= NewFileName
= NULL
;
1093 AttrChangeFlag
= NameChangeFlag
= SizeChangeFlag
= TimeChangeFlag
= FALSE
;
1096 // Set file system information.
1098 if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
1099 if (BufferSize
< (SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
))) {
1100 Status
= EFI_BAD_BUFFER_SIZE
;
1104 NewFileSystemInfo
= (EFI_FILE_SYSTEM_INFO
*) Buffer
;
1106 free (PrivateRoot
->VolumeLabel
);
1108 PrivateRoot
->VolumeLabel
= malloc (StrSize (NewFileSystemInfo
->VolumeLabel
));
1109 if (PrivateRoot
->VolumeLabel
== NULL
) {
1113 StrCpy (PrivateRoot
->VolumeLabel
, NewFileSystemInfo
->VolumeLabel
);
1115 Status
= EFI_SUCCESS
;
1120 // Set volume label information.
1122 if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
1123 if (BufferSize
< StrSize (PrivateRoot
->VolumeLabel
)) {
1124 Status
= EFI_BAD_BUFFER_SIZE
;
1128 StrCpy (PrivateRoot
->VolumeLabel
, (CHAR16
*) Buffer
);
1130 Status
= EFI_SUCCESS
;
1134 if (!CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
1135 Status
= EFI_UNSUPPORTED
;
1139 if (BufferSize
< SIZE_OF_EFI_FILE_INFO
) {
1140 Status
= EFI_BAD_BUFFER_SIZE
;
1145 // Set file/directory information.
1149 // Check for invalid set file information parameters.
1151 NewFileInfo
= (EFI_FILE_INFO
*) Buffer
;
1152 if (NewFileInfo
->Size
<= sizeof (EFI_FILE_INFO
) ||
1153 (NewFileInfo
->Attribute
&~(EFI_FILE_VALID_ATTR
)) ||
1154 (sizeof (UINTN
) == 4 && NewFileInfo
->Size
> 0xFFFFFFFF)
1156 Status
= EFI_INVALID_PARAMETER
;
1161 // Get current file information so we can determine what kind
1162 // of change request this is.
1165 Status
= UnixSimpleFileSystemFileInfo (PrivateFile
, NULL
, &OldInfoSize
, NULL
);
1166 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1167 Status
= EFI_DEVICE_ERROR
;
1171 OldFileInfo
= malloc (OldInfoSize
);
1172 if (OldFileInfo
== NULL
) {
1176 Status
= UnixSimpleFileSystemFileInfo (PrivateFile
, NULL
, &OldInfoSize
, OldFileInfo
);
1177 if (EFI_ERROR (Status
)) {
1181 OldFileName
= malloc (AsciiStrSize (PrivateFile
->FileName
));
1182 if (OldFileInfo
== NULL
) {
1186 AsciiStrCpy (OldFileName
, PrivateFile
->FileName
);
1189 // Make full pathname from new filename and rootpath.
1191 if (NewFileInfo
->FileName
[0] == '\\') {
1192 NewFileName
= malloc (AsciiStrLen (PrivateRoot
->FilePath
) + 1 + StrLen (NewFileInfo
->FileName
) + 1);
1193 if (NewFileName
== NULL
) {
1197 AsciiStrCpy (NewFileName
, PrivateRoot
->FilePath
);
1198 AsciiFilePtr
= NewFileName
+ AsciiStrLen(NewFileName
);
1199 UnicodeFilePtr
= NewFileInfo
->FileName
+ 1;
1200 *AsciiFilePtr
++ ='/';
1202 NewFileName
= malloc (AsciiStrLen (PrivateFile
->FileName
) + 2 + StrLen (NewFileInfo
->FileName
) + 1);
1203 if (NewFileName
== NULL
) {
1207 AsciiStrCpy (NewFileName
, PrivateRoot
->FilePath
);
1208 AsciiFilePtr
= NewFileName
+ AsciiStrLen(NewFileName
);
1209 if ((AsciiFilePtr
[-1] != '/') && (NewFileInfo
->FileName
[0] != '/')) {
1210 // make sure there is a / between Root FilePath and NewFileInfo Filename
1211 AsciiFilePtr
[0] = '/';
1212 AsciiFilePtr
[1] = '\0';
1215 UnicodeFilePtr
= NewFileInfo
->FileName
;
1217 // Convert to ascii.
1218 while (*UnicodeFilePtr
) {
1219 *AsciiFilePtr
++ = *UnicodeFilePtr
++;
1224 // Is there an attribute change request?
1226 if (NewFileInfo
->Attribute
!= OldFileInfo
->Attribute
) {
1227 if ((NewFileInfo
->Attribute
& EFI_FILE_DIRECTORY
) != (OldFileInfo
->Attribute
& EFI_FILE_DIRECTORY
)) {
1228 Status
= EFI_INVALID_PARAMETER
;
1232 AttrChangeFlag
= TRUE
;
1236 // Is there a name change request?
1237 // bugbug: - Should really use EFI_UNICODE_COLLATION_PROTOCOL
1239 if (StrCmp (NewFileInfo
->FileName
, OldFileInfo
->FileName
)) {
1240 NameChangeFlag
= TRUE
;
1244 // Is there a size change request?
1246 if (NewFileInfo
->FileSize
!= OldFileInfo
->FileSize
) {
1247 SizeChangeFlag
= TRUE
;
1251 // Is there a time stamp change request?
1253 if (!IsZero (&NewFileInfo
->CreateTime
, sizeof (EFI_TIME
)) &&
1254 CompareMem (&NewFileInfo
->CreateTime
, &OldFileInfo
->CreateTime
, sizeof (EFI_TIME
))
1256 TimeChangeFlag
= TRUE
;
1257 } else if (!IsZero (&NewFileInfo
->LastAccessTime
, sizeof (EFI_TIME
)) &&
1258 CompareMem (&NewFileInfo
->LastAccessTime
, &OldFileInfo
->LastAccessTime
, sizeof (EFI_TIME
))
1260 TimeChangeFlag
= TRUE
;
1261 } else if (!IsZero (&NewFileInfo
->ModificationTime
, sizeof (EFI_TIME
)) &&
1262 CompareMem (&NewFileInfo
->ModificationTime
, &OldFileInfo
->ModificationTime
, sizeof (EFI_TIME
))
1264 TimeChangeFlag
= TRUE
;
1268 // All done if there are no change requests being made.
1270 if (!(AttrChangeFlag
|| NameChangeFlag
|| SizeChangeFlag
|| TimeChangeFlag
)) {
1271 Status
= EFI_SUCCESS
;
1276 // Set file or directory information.
1278 if (stat (OldFileName
, &OldAttr
) != 0) {
1279 Status
= ErrnoToEfiStatus ();
1286 if (NameChangeFlag
) {
1288 // Close the handles first
1290 if (PrivateFile
->IsOpenedByRead
) {
1291 Status
= EFI_ACCESS_DENIED
;
1295 for (CharPointer
= NewFileName
; *CharPointer
!= 0 && *CharPointer
!= L
'/'; CharPointer
++) {
1298 if (*CharPointer
!= 0) {
1299 Status
= EFI_ACCESS_DENIED
;
1303 UnixStatus
= rename (OldFileName
, NewFileName
);
1304 if (UnixStatus
== 0) {
1308 free (PrivateFile
->FileName
);
1310 PrivateFile
->FileName
= malloc (AsciiStrSize (NewFileName
));
1311 if (PrivateFile
->FileName
== NULL
) {
1315 AsciiStrCpy (PrivateFile
->FileName
, NewFileName
);
1317 Status
= EFI_DEVICE_ERROR
;
1325 if (SizeChangeFlag
) {
1326 if (PrivateFile
->IsDirectoryPath
) {
1327 Status
= EFI_UNSUPPORTED
;
1331 if (PrivateFile
->IsOpenedByRead
|| OldFileInfo
->Attribute
& EFI_FILE_READ_ONLY
) {
1332 Status
= EFI_ACCESS_DENIED
;
1336 if (ftruncate (PrivateFile
->fd
, NewFileInfo
->FileSize
) != 0) {
1337 Status
= ErrnoToEfiStatus ();
1346 if (TimeChangeFlag
) {
1347 NewLastAccessSystemTime
.tm_year
= NewFileInfo
->LastAccessTime
.Year
;
1348 NewLastAccessSystemTime
.tm_mon
= NewFileInfo
->LastAccessTime
.Month
;
1349 NewLastAccessSystemTime
.tm_mday
= NewFileInfo
->LastAccessTime
.Day
;
1350 NewLastAccessSystemTime
.tm_hour
= NewFileInfo
->LastAccessTime
.Hour
;
1351 NewLastAccessSystemTime
.tm_min
= NewFileInfo
->LastAccessTime
.Minute
;
1352 NewLastAccessSystemTime
.tm_sec
= NewFileInfo
->LastAccessTime
.Second
;
1353 NewLastAccessSystemTime
.tm_isdst
= 0;
1355 Utime
.actime
= mktime (&NewLastAccessSystemTime
);
1357 NewLastWriteSystemTime
.tm_year
= NewFileInfo
->ModificationTime
.Year
;
1358 NewLastWriteSystemTime
.tm_mon
= NewFileInfo
->ModificationTime
.Month
;
1359 NewLastWriteSystemTime
.tm_mday
= NewFileInfo
->ModificationTime
.Day
;
1360 NewLastWriteSystemTime
.tm_hour
= NewFileInfo
->ModificationTime
.Hour
;
1361 NewLastWriteSystemTime
.tm_min
= NewFileInfo
->ModificationTime
.Minute
;
1362 NewLastWriteSystemTime
.tm_sec
= NewFileInfo
->ModificationTime
.Second
;
1363 NewLastWriteSystemTime
.tm_isdst
= 0;
1365 Utime
.modtime
= mktime (&NewLastWriteSystemTime
);
1367 if (Utime
.actime
== (time_t)-1 || Utime
.modtime
== (time_t)-1) {
1371 if (utime (PrivateFile
->FileName
, &Utime
) == -1) {
1372 Status
= ErrnoToEfiStatus ();
1378 // No matter about AttrChangeFlag, Attribute must be set.
1379 // Because operation before may cause attribute change.
1381 NewAttr
= OldAttr
.st_mode
;
1383 if (NewFileInfo
->Attribute
& EFI_FILE_READ_ONLY
) {
1384 NewAttr
&= ~(S_IRUSR
| S_IRGRP
| S_IROTH
);
1389 if (chmod (NewFileName
, NewAttr
) != 0) {
1390 Status
= ErrnoToEfiStatus ();
1394 if (OldFileInfo
!= NULL
) {
1398 if (OldFileName
!= NULL
) {
1402 if (NewFileName
!= NULL
) {
1411 Flush data back for the file handle.
1413 @param This Protocol instance pointer.
1415 @retval EFI_SUCCESS Data was written.
1416 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
1417 @retval EFI_NO_MEDIA The device has no media.
1418 @retval EFI_DEVICE_ERROR The device reported an error.
1419 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1420 @retval EFI_WRITE_PROTECTED The device is write protected.
1421 @retval EFI_ACCESS_DENIED The file was open for read only.
1422 @retval EFI_VOLUME_FULL The volume is full.
1427 IN EFI_FILE_PROTOCOL
*This
1430 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
1433 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
1435 if (PrivateFile
->IsDirectoryPath
) {
1436 return EFI_UNSUPPORTED
;
1439 if (PrivateFile
->IsOpenedByRead
) {
1440 return EFI_ACCESS_DENIED
;
1443 if (PrivateFile
->fd
< 0) {
1444 return EFI_DEVICE_ERROR
;
1447 if (fsync (PrivateFile
->fd
) != 0) {
1448 return ErrnoToEfiStatus ();
1457 PosixFileSystmeThunkOpen (
1458 IN EMU_IO_THUNK_PROTOCOL
*This
1461 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*Private
;
1464 if (This
->Private
!= NULL
) {
1465 return EFI_ALREADY_STARTED
;
1468 if (!CompareGuid (This
->Protocol
, &gEfiSimpleFileSystemProtocolGuid
)) {
1469 return EFI_UNSUPPORTED
;
1472 Private
= malloc (sizeof (EMU_SIMPLE_FILE_SYSTEM_PRIVATE
));
1473 if (Private
== NULL
) {
1474 return EFI_OUT_OF_RESOURCES
;
1477 Private
->FilePath
= malloc (StrLen (This
->ConfigString
) + 1);
1478 if (Private
->FilePath
== NULL
) {
1480 return EFI_OUT_OF_RESOURCES
;
1483 // Convert Unicode to Ascii
1484 for (i
= 0; This
->ConfigString
[i
] != 0; i
++) {
1485 Private
->FilePath
[i
] = This
->ConfigString
[i
];
1487 Private
->FilePath
[i
] = 0;
1490 Private
->VolumeLabel
= malloc (StrSize (L
"EFI_EMULATED"));
1491 if (Private
->VolumeLabel
== NULL
) {
1492 free (Private
->FilePath
);
1494 return EFI_OUT_OF_RESOURCES
;
1496 StrCpy (Private
->VolumeLabel
, L
"EFI_EMULATED");
1498 Private
->Signature
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE
;
1499 Private
->Thunk
= This
;
1500 CopyMem (&Private
->SimpleFileSystem
, &gPosixFileSystemProtocol
, sizeof (Private
->SimpleFileSystem
));
1501 Private
->FileHandlesOpen
= FALSE
;
1503 This
->Interface
= &Private
->SimpleFileSystem
;
1504 This
->Private
= Private
;
1510 PosixFileSystmeThunkClose (
1511 IN EMU_IO_THUNK_PROTOCOL
*This
1514 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*Private
;
1516 if (!CompareGuid (This
->Protocol
, &gEfiSimpleFileSystemProtocolGuid
)) {
1517 return EFI_UNSUPPORTED
;
1520 Private
= This
->Private
;
1522 if (Private
->FileHandlesOpen
) {
1524 // Close only supported if all the EFI_FILE_HANDLEs have been closed.
1526 return EFI_NOT_READY
;
1529 if (This
->Private
!= NULL
) {
1530 if (Private
->VolumeLabel
!= NULL
) {
1531 free (Private
->VolumeLabel
);
1533 free (This
->Private
);
1534 This
->Private
= NULL
;
1541 EMU_IO_THUNK_PROTOCOL gPosixFileSystemThunkIo
= {
1542 &gEfiSimpleFileSystemProtocolGuid
,
1546 GasketPosixFileSystmeThunkOpen
,
1547 GasketPosixFileSystmeThunkClose
,