2 POSIX Pthreads to emulate APs and implement threads
4 Copyright (c) 2011, Apple Inc. All rights reserved.
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 #define EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE SIGNATURE_32 ('E', 'P', 'f', 's')
23 EMU_IO_THUNK_PROTOCOL
*Thunk
;
24 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL SimpleFileSystem
;
27 BOOLEAN FileHandlesOpen
;
28 } EMU_SIMPLE_FILE_SYSTEM_PRIVATE
;
30 #define EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS(a) \
32 EMU_SIMPLE_FILE_SYSTEM_PRIVATE, \
34 EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE \
38 #define EMU_EFI_FILE_PRIVATE_SIGNATURE SIGNATURE_32 ('E', 'P', 'f', 'i')
42 EMU_IO_THUNK_PROTOCOL
*Thunk
;
43 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*SimpleFileSystem
;
44 EFI_FILE_PROTOCOL EfiFile
;
47 BOOLEAN IsRootDirectory
;
48 BOOLEAN IsDirectoryPath
;
49 BOOLEAN IsOpenedByRead
;
51 struct dirent
*Dirent
;
52 } EMU_EFI_FILE_PRIVATE
;
54 #define EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS(a) \
56 EMU_EFI_FILE_PRIVATE, \
58 EMU_EFI_FILE_PRIVATE_SIGNATURE \
63 IN EFI_FILE_PROTOCOL
*This
,
64 IN EFI_GUID
*InformationType
,
65 IN OUT UINTN
*BufferSize
,
71 IN EFI_FILE_PROTOCOL
*This
,
72 IN EFI_GUID
*InformationType
,
78 EFI_FILE_PROTOCOL gPosixFileProtocol
= {
82 GasketPosixFileDelete
,
85 GasketPosixFileGetPossition
,
86 GasketPosixFileSetPossition
,
87 GasketPosixFileGetInfo
,
88 GasketPosixFileSetInfo
,
92 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gPosixFileSystemProtocol
= {
93 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
,
94 GasketPosixOpenVolume
,
99 Open the root directory on a volume.
101 @param This Protocol instance pointer.
102 @param Root Returns an Open file handle for the root directory
104 @retval EFI_SUCCESS The device was opened.
105 @retval EFI_UNSUPPORTED This volume does not support the file system.
106 @retval EFI_NO_MEDIA The device has no media.
107 @retval EFI_DEVICE_ERROR The device reported an error.
108 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
109 @retval EFI_ACCESS_DENIED The service denied access to the file.
110 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
115 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*This
,
116 OUT EFI_FILE_PROTOCOL
**Root
120 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*Private
;
121 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
123 Private
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (This
);
125 Status
= EFI_OUT_OF_RESOURCES
;
126 PrivateFile
= malloc (sizeof (EMU_EFI_FILE_PRIVATE
));
127 if (PrivateFile
== NULL
) {
131 PrivateFile
->FileName
= malloc (AsciiStrSize (Private
->FilePath
));
132 if (PrivateFile
->FileName
== NULL
) {
135 AsciiStrCpy (PrivateFile
->FileName
, Private
->FilePath
);
137 PrivateFile
->Signature
= EMU_EFI_FILE_PRIVATE_SIGNATURE
;
138 PrivateFile
->Thunk
= Private
->Thunk
;
139 PrivateFile
->SimpleFileSystem
= This
;
140 PrivateFile
->IsRootDirectory
= TRUE
;
141 PrivateFile
->IsDirectoryPath
= TRUE
;
142 PrivateFile
->IsOpenedByRead
= TRUE
;
144 CopyMem (&PrivateFile
->EfiFile
, &gPosixFileProtocol
, sizeof (EFI_FILE_PROTOCOL
));
146 PrivateFile
->fd
= -1;
147 PrivateFile
->Dir
= NULL
;
148 PrivateFile
->Dirent
= NULL
;
150 *Root
= &PrivateFile
->EfiFile
;
152 PrivateFile
->Dir
= opendir (PrivateFile
->FileName
);
153 if (PrivateFile
->Dir
== NULL
) {
154 Status
= EFI_ACCESS_DENIED
;
156 Status
= EFI_SUCCESS
;
160 if (EFI_ERROR (Status
)) {
161 if (PrivateFile
!= NULL
) {
162 if (PrivateFile
->FileName
!= NULL
) {
163 free (PrivateFile
->FileName
);
181 return EFI_ACCESS_DENIED
;
185 return EFI_VOLUME_FULL
;
188 return EFI_DEVICE_ERROR
;
200 if (AsciiStrLen (Str
) < Count
) {
204 for (Pointer
= Str
; *(Pointer
+ Count
); Pointer
++) {
205 *Pointer
= *(Pointer
+ Count
);
208 *Pointer
= *(Pointer
+ Count
);
213 PosixSystemTimeToEfiTime (
214 IN
time_t SystemTime
,
220 tm
= gmtime (&SystemTime
);
221 Time
->Year
= tm
->tm_year
;
222 Time
->Month
= tm
->tm_mon
+ 1;
223 Time
->Day
= tm
->tm_mday
;
224 Time
->Hour
= tm
->tm_hour
;
225 Time
->Minute
= tm
->tm_min
;
226 Time
->Second
= tm
->tm_sec
;
227 Time
->Nanosecond
= 0;
229 Time
->TimeZone
= timezone
;
230 Time
->Daylight
= (daylight
? EFI_TIME_ADJUST_DAYLIGHT
: 0) | (tm
->tm_isdst
> 0 ? EFI_TIME_IN_DAYLIGHT
: 0);
235 UnixSimpleFileSystemFileInfo (
236 EMU_EFI_FILE_PRIVATE
*PrivateFile
,
238 IN OUT UINTN
*BufferSize
,
249 CHAR16
*BufferFileName
;
252 if (FileName
!= NULL
) {
253 RealFileName
= FileName
;
255 else if (PrivateFile
->IsRootDirectory
) {
258 RealFileName
= PrivateFile
->FileName
;
261 TempPointer
= RealFileName
;
262 while (*TempPointer
) {
263 if (*TempPointer
== '/') {
264 RealFileName
= TempPointer
+ 1;
270 Size
= SIZE_OF_EFI_FILE_INFO
;
271 NameSize
= AsciiStrSize (RealFileName
) * 2;
272 ResultSize
= Size
+ NameSize
;
274 if (*BufferSize
< ResultSize
) {
275 *BufferSize
= ResultSize
;
276 return EFI_BUFFER_TOO_SMALL
;
278 if (stat (FileName
== NULL
? PrivateFile
->FileName
: FileName
, &buf
) < 0) {
279 return EFI_DEVICE_ERROR
;
282 Status
= EFI_SUCCESS
;
285 ZeroMem (Info
, ResultSize
);
287 Info
->Size
= ResultSize
;
288 Info
->FileSize
= buf
.st_size
;
289 Info
->PhysicalSize
= MultU64x32 (buf
.st_blocks
, buf
.st_blksize
);
291 PosixSystemTimeToEfiTime (buf
.st_ctime
, &Info
->CreateTime
);
292 PosixSystemTimeToEfiTime (buf
.st_atime
, &Info
->LastAccessTime
);
293 PosixSystemTimeToEfiTime (buf
.st_mtime
, &Info
->ModificationTime
);
295 if (!(buf
.st_mode
& S_IWUSR
)) {
296 Info
->Attribute
|= EFI_FILE_READ_ONLY
;
299 if (S_ISDIR(buf
.st_mode
)) {
300 Info
->Attribute
|= EFI_FILE_DIRECTORY
;
304 BufferFileName
= (CHAR16
*)((CHAR8
*) Buffer
+ Size
);
305 while (*RealFileName
) {
306 *BufferFileName
++ = *RealFileName
++;
310 *BufferSize
= ResultSize
;
320 if (Buffer
== NULL
|| Length
== 0) {
324 if (*(UINT8
*) Buffer
!= 0) {
329 if (!CompareMem (Buffer
, (UINT8
*) Buffer
+ 1, Length
- 1)) {
340 Opens a new file relative to the source file's location.
342 @param This The protocol instance pointer.
343 @param NewHandle Returns File Handle for FileName.
344 @param FileName Null terminated string. "\", ".", and ".." are supported.
345 @param OpenMode Open mode for file.
346 @param Attributes Only used for EFI_FILE_MODE_CREATE.
348 @retval EFI_SUCCESS The device was opened.
349 @retval EFI_NOT_FOUND The specified file could not be found on the device.
350 @retval EFI_NO_MEDIA The device has no media.
351 @retval EFI_MEDIA_CHANGED The media has changed.
352 @retval EFI_DEVICE_ERROR The device reported an error.
353 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
354 @retval EFI_ACCESS_DENIED The service denied access to the file.
355 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
356 @retval EFI_VOLUME_FULL The volume is full.
361 IN EFI_FILE_PROTOCOL
*This
,
362 OUT EFI_FILE_PROTOCOL
**NewHandle
,
368 EFI_FILE_PROTOCOL
*Root
;
369 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
370 EMU_EFI_FILE_PRIVATE
*NewPrivateFile
;
371 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*PrivateRoot
;
380 BOOLEAN TrailingDash
;
388 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
389 PrivateRoot
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile
->SimpleFileSystem
);
390 NewPrivateFile
= NULL
;
391 Status
= EFI_OUT_OF_RESOURCES
;
394 // BUGBUG: assume an open of root
395 // if current location, return current data
397 if ((StrCmp (FileName
, L
"\\") == 0) ||
398 (StrCmp (FileName
, L
".") == 0 && PrivateFile
->IsRootDirectory
)) {
400 Status
= PosixOpenVolume (PrivateFile
->SimpleFileSystem
, &Root
);
401 NewPrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (Root
);
405 TrailingDash
= FALSE
;
406 if (FileName
[StrLen (FileName
) - 1] == L
'\\') {
408 FileName
[StrLen (FileName
) - 1] = 0;
412 // Attempt to open the file
414 NewPrivateFile
= malloc (sizeof (EMU_EFI_FILE_PRIVATE
));
415 if (NewPrivateFile
== NULL
) {
419 CopyMem (NewPrivateFile
, PrivateFile
, sizeof (EMU_EFI_FILE_PRIVATE
));
421 NewPrivateFile
->FileName
= malloc (AsciiStrSize (PrivateFile
->FileName
) + 1 + StrLen (FileName
) + 1);
422 if (NewPrivateFile
->FileName
== NULL
) {
426 if (*FileName
== L
'\\') {
427 AsciiStrCpy (NewPrivateFile
->FileName
, PrivateRoot
->FilePath
);
431 AsciiStrCpy (NewPrivateFile
->FileName
, PrivateFile
->FileName
);
434 Dst
= NewPrivateFile
->FileName
+ AsciiStrLen (NewPrivateFile
->FileName
);
435 GuardPointer
= NewPrivateFile
->FileName
+ AsciiStrLen (PrivateRoot
->FilePath
);
437 // Convert unicode to ascii and '\' to '/'
450 // Get rid of . and .., except leading . or ..
454 // GuardPointer protect simplefilesystem root path not be destroyed
458 while (!LoopFinish
) {
461 for (ParseFileName
= GuardPointer
; *ParseFileName
; ParseFileName
++) {
462 if (*ParseFileName
== '.' &&
463 (*(ParseFileName
+ 1) == 0 || *(ParseFileName
+ 1) == '/') &&
464 *(ParseFileName
- 1) == '/'
470 CutPrefix (ParseFileName
- 1, 2);
475 if (*ParseFileName
== '.' &&
476 *(ParseFileName
+ 1) == '.' &&
477 (*(ParseFileName
+ 2) == 0 || *(ParseFileName
+ 2) == '/') &&
478 *(ParseFileName
- 1) == '/'
484 while (ParseFileName
!= GuardPointer
) {
487 if (*ParseFileName
== '/') {
493 // cut /.. and its left directory
495 CutPrefix (ParseFileName
, Count
);
502 if (AsciiStrCmp (NewPrivateFile
->FileName
, PrivateRoot
->FilePath
) == 0) {
503 NewPrivateFile
->IsRootDirectory
= TRUE
;
504 free (NewPrivateFile
->FileName
);
505 free (NewPrivateFile
);
509 RealFileName
= NewPrivateFile
->FileName
+ AsciiStrLen(NewPrivateFile
->FileName
) - 1;
510 while (RealFileName
> NewPrivateFile
->FileName
&& *RealFileName
!= '/') {
514 TempChar
= *(RealFileName
- 1);
515 *(RealFileName
- 1) = 0;
516 *(RealFileName
- 1) = TempChar
;
520 // Test whether file or directory
522 NewPrivateFile
->IsRootDirectory
= FALSE
;
523 NewPrivateFile
->fd
= -1;
524 NewPrivateFile
->Dir
= NULL
;
525 if (OpenMode
& EFI_FILE_MODE_CREATE
) {
526 if (Attributes
& EFI_FILE_DIRECTORY
) {
527 NewPrivateFile
->IsDirectoryPath
= TRUE
;
529 NewPrivateFile
->IsDirectoryPath
= FALSE
;
532 res
= stat (NewPrivateFile
->FileName
, &finfo
);
533 if (res
== 0 && S_ISDIR(finfo
.st_mode
)) {
534 NewPrivateFile
->IsDirectoryPath
= TRUE
;
536 NewPrivateFile
->IsDirectoryPath
= FALSE
;
540 if (OpenMode
& EFI_FILE_MODE_WRITE
) {
541 NewPrivateFile
->IsOpenedByRead
= FALSE
;
543 NewPrivateFile
->IsOpenedByRead
= TRUE
;
546 Status
= EFI_SUCCESS
;
549 // deal with directory
551 if (NewPrivateFile
->IsDirectoryPath
) {
552 if ((OpenMode
& EFI_FILE_MODE_CREATE
)) {
554 // Create a directory
556 if (mkdir (NewPrivateFile
->FileName
, 0777) != 0) {
557 if (errno
!= EEXIST
) {
558 //free (TempFileName);
559 Status
= EFI_ACCESS_DENIED
;
565 NewPrivateFile
->Dir
= opendir (NewPrivateFile
->FileName
);
566 if (NewPrivateFile
->Dir
== NULL
) {
567 if (errno
== EACCES
) {
568 Status
= EFI_ACCESS_DENIED
;
570 Status
= EFI_NOT_FOUND
;
580 NewPrivateFile
->fd
= open (
581 NewPrivateFile
->FileName
,
582 ((OpenMode
& EFI_FILE_MODE_CREATE
) ? O_CREAT
: 0) | (NewPrivateFile
->IsOpenedByRead
? O_RDONLY
: O_RDWR
),
585 if (NewPrivateFile
->fd
< 0) {
586 if (errno
== ENOENT
) {
587 Status
= EFI_NOT_FOUND
;
589 Status
= EFI_ACCESS_DENIED
;
594 if ((OpenMode
& EFI_FILE_MODE_CREATE
) && Status
== EFI_SUCCESS
) {
600 Status
= PosixFileGetInfo (&NewPrivateFile
->EfiFile
, &gEfiFileInfoGuid
, &InfoSize
, Info
);
601 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
602 Status
= EFI_DEVICE_ERROR
;
606 Info
= malloc (InfoSize
);
611 Status
= PosixFileGetInfo (&NewPrivateFile
->EfiFile
, &gEfiFileInfoGuid
, &InfoSize
, Info
);
612 if (EFI_ERROR (Status
)) {
616 Info
->Attribute
= Attributes
;
617 PosixFileSetInfo (&NewPrivateFile
->EfiFile
, &gEfiFileInfoGuid
, InfoSize
, Info
);
624 FileName
[StrLen (FileName
) + 1] = 0;
625 FileName
[StrLen (FileName
)] = L
'\\';
628 if (EFI_ERROR (Status
)) {
629 if (NewPrivateFile
) {
630 if (NewPrivateFile
->FileName
) {
631 free (NewPrivateFile
->FileName
);
634 free (NewPrivateFile
);
637 *NewHandle
= &NewPrivateFile
->EfiFile
;
646 Close the file handle
648 @param This Protocol instance pointer.
650 @retval EFI_SUCCESS The device was opened.
655 IN EFI_FILE_PROTOCOL
*This
658 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
660 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
662 if (PrivateFile
->fd
>= 0) {
663 close (PrivateFile
->fd
);
665 if (PrivateFile
->Dir
!= NULL
) {
666 closedir (PrivateFile
->Dir
);
669 PrivateFile
->fd
= -1;
670 PrivateFile
->Dir
= NULL
;
672 if (PrivateFile
->FileName
) {
673 free (PrivateFile
->FileName
);
683 Close and delete the file handle.
685 @param This Protocol instance pointer.
687 @retval EFI_SUCCESS The device was opened.
688 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.
693 IN EFI_FILE_PROTOCOL
*This
697 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
699 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
700 Status
= EFI_WARN_DELETE_FAILURE
;
702 if (PrivateFile
->IsDirectoryPath
) {
703 if (PrivateFile
->Dir
!= NULL
) {
704 closedir (PrivateFile
->Dir
);
705 PrivateFile
->Dir
= NULL
;
708 if (rmdir (PrivateFile
->FileName
) == 0) {
709 Status
= EFI_SUCCESS
;
712 close (PrivateFile
->fd
);
713 PrivateFile
->fd
= -1;
715 if (!PrivateFile
->IsOpenedByRead
) {
716 if (!unlink (PrivateFile
->FileName
)) {
717 Status
= EFI_SUCCESS
;
722 free (PrivateFile
->FileName
);
730 Read data from the file.
732 @param This Protocol instance pointer.
733 @param BufferSize On input size of buffer, on output amount of data in buffer.
734 @param Buffer The buffer in which data is read.
736 @retval EFI_SUCCESS Data was read.
737 @retval EFI_NO_MEDIA The device has no media.
738 @retval EFI_DEVICE_ERROR The device reported an error.
739 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
740 @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size.
745 IN EFI_FILE_PROTOCOL
*This
,
746 IN OUT UINTN
*BufferSize
,
750 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
759 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
761 if (!PrivateFile
->IsDirectoryPath
) {
762 if (PrivateFile
->fd
< 0) {
763 Status
= EFI_DEVICE_ERROR
;
767 Res
= read (PrivateFile
->fd
, Buffer
, *BufferSize
);
769 Status
= EFI_DEVICE_ERROR
;
773 Status
= EFI_SUCCESS
;
778 // Read on a directory.
780 if (PrivateFile
->Dir
== NULL
) {
781 Status
= EFI_DEVICE_ERROR
;
785 if (PrivateFile
->Dirent
== NULL
) {
786 PrivateFile
->Dirent
= readdir (PrivateFile
->Dir
);
787 if (PrivateFile
->Dirent
== NULL
) {
789 Status
= EFI_SUCCESS
;
794 Size
= SIZE_OF_EFI_FILE_INFO
;
795 NameSize
= AsciiStrLen (PrivateFile
->Dirent
->d_name
) + 1;
796 ResultSize
= Size
+ 2 * NameSize
;
798 if (*BufferSize
< ResultSize
) {
799 *BufferSize
= ResultSize
;
800 Status
= EFI_BUFFER_TOO_SMALL
;
803 Status
= EFI_SUCCESS
;
805 *BufferSize
= ResultSize
;
807 FullFileName
= malloc (AsciiStrLen(PrivateFile
->FileName
) + 1 + NameSize
);
808 if (FullFileName
== NULL
) {
809 Status
= EFI_OUT_OF_RESOURCES
;
813 AsciiStrCpy (FullFileName
, PrivateFile
->FileName
);
814 AsciiStrCat (FullFileName
, "/");
815 AsciiStrCat (FullFileName
, PrivateFile
->Dirent
->d_name
);
816 Status
= UnixSimpleFileSystemFileInfo (
824 PrivateFile
->Dirent
= NULL
;
833 Write data to a file.
835 @param This Protocol instance pointer.
836 @param BufferSize On input size of buffer, on output amount of data in buffer.
837 @param Buffer The buffer in which data to write.
839 @retval EFI_SUCCESS Data was written.
840 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
841 @retval EFI_NO_MEDIA The device has no media.
842 @retval EFI_DEVICE_ERROR The device reported an error.
843 @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
844 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
845 @retval EFI_WRITE_PROTECTED The device is write protected.
846 @retval EFI_ACCESS_DENIED The file was open for read only.
847 @retval EFI_VOLUME_FULL The volume is full.
852 IN EFI_FILE_PROTOCOL
*This
,
853 IN OUT UINTN
*BufferSize
,
857 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
861 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
863 if (PrivateFile
->fd
< 0) {
864 return EFI_DEVICE_ERROR
;
867 if (PrivateFile
->IsDirectoryPath
) {
868 return EFI_UNSUPPORTED
;
871 if (PrivateFile
->IsOpenedByRead
) {
872 return EFI_ACCESS_DENIED
;
875 Res
= write (PrivateFile
->fd
, Buffer
, *BufferSize
);
876 if (Res
== (UINTN
)-1) {
877 return ErrnoToEfiStatus ();
887 Set a files current position
889 @param This Protocol instance pointer.
890 @param Position Byte position from the start of the file.
892 @retval EFI_SUCCESS Data was written.
893 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
897 PosixFileSetPossition (
898 IN EFI_FILE_PROTOCOL
*This
,
902 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
905 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
907 if (PrivateFile
->IsDirectoryPath
) {
909 return EFI_UNSUPPORTED
;
912 if (PrivateFile
->Dir
== NULL
) {
913 return EFI_DEVICE_ERROR
;
915 rewinddir (PrivateFile
->Dir
);
918 if (Position
== (UINT64
) -1) {
919 Pos
= lseek (PrivateFile
->fd
, 0, SEEK_END
);
921 Pos
= lseek (PrivateFile
->fd
, Position
, SEEK_SET
);
923 if (Pos
== (off_t
)-1) {
924 return ErrnoToEfiStatus ();
933 Get a file's current position
935 @param This Protocol instance pointer.
936 @param Position Byte position from the start of the file.
938 @retval EFI_SUCCESS Data was written.
939 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..
943 PosixFileGetPossition (
944 IN EFI_FILE_PROTOCOL
*This
,
949 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
951 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
953 if (PrivateFile
->IsDirectoryPath
) {
954 Status
= EFI_UNSUPPORTED
;
956 *Position
= (UINT64
)lseek (PrivateFile
->fd
, 0, SEEK_CUR
);
957 Status
= (*Position
== (UINT64
) -1) ? ErrnoToEfiStatus () : EFI_SUCCESS
;
965 Get information about a file.
967 @param This Protocol instance pointer.
968 @param InformationType Type of information to return in Buffer.
969 @param BufferSize On input size of buffer, on output amount of data in buffer.
970 @param Buffer The buffer to return data.
972 @retval EFI_SUCCESS Data was returned.
973 @retval EFI_UNSUPPORTED InformationType is not supported.
974 @retval EFI_NO_MEDIA The device has no media.
975 @retval EFI_DEVICE_ERROR The device reported an error.
976 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
977 @retval EFI_WRITE_PROTECTED The device is write protected.
978 @retval EFI_ACCESS_DENIED The file was open for read only.
979 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
984 IN EFI_FILE_PROTOCOL
*This
,
985 IN EFI_GUID
*InformationType
,
986 IN OUT UINTN
*BufferSize
,
991 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
992 EFI_FILE_SYSTEM_INFO
*FileSystemInfoBuffer
;
994 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*PrivateRoot
;
997 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
998 PrivateRoot
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile
->SimpleFileSystem
);
1000 Status
= EFI_SUCCESS
;
1001 if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
1002 Status
= UnixSimpleFileSystemFileInfo (PrivateFile
, NULL
, BufferSize
, Buffer
);
1003 } else if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
1004 if (*BufferSize
< SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
)) {
1005 *BufferSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
);
1006 return EFI_BUFFER_TOO_SMALL
;
1009 UnixStatus
= statfs (PrivateFile
->FileName
, &buf
);
1010 if (UnixStatus
< 0) {
1011 return EFI_DEVICE_ERROR
;
1014 FileSystemInfoBuffer
= (EFI_FILE_SYSTEM_INFO
*) Buffer
;
1015 FileSystemInfoBuffer
->Size
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
);
1016 FileSystemInfoBuffer
->ReadOnly
= FALSE
;
1021 FileSystemInfoBuffer
->VolumeSize
= MultU64x32 (buf
.f_blocks
, buf
.f_bsize
);
1022 FileSystemInfoBuffer
->FreeSpace
= MultU64x32 (buf
.f_bavail
, buf
.f_bsize
);
1023 FileSystemInfoBuffer
->BlockSize
= buf
.f_bsize
;
1026 StrCpy ((CHAR16
*) FileSystemInfoBuffer
->VolumeLabel
, PrivateRoot
->VolumeLabel
);
1027 *BufferSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
);
1029 } else if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
1030 if (*BufferSize
< StrSize (PrivateRoot
->VolumeLabel
)) {
1031 *BufferSize
= StrSize (PrivateRoot
->VolumeLabel
);
1032 return EFI_BUFFER_TOO_SMALL
;
1035 StrCpy ((CHAR16
*) Buffer
, PrivateRoot
->VolumeLabel
);
1036 *BufferSize
= StrSize (PrivateRoot
->VolumeLabel
);
1045 Set information about a file
1047 @param File Protocol instance pointer.
1048 @param InformationType Type of information in Buffer.
1049 @param BufferSize Size of buffer.
1050 @param Buffer The data to write.
1052 @retval EFI_SUCCESS Data was returned.
1053 @retval EFI_UNSUPPORTED InformationType is not supported.
1054 @retval EFI_NO_MEDIA The device has no media.
1055 @retval EFI_DEVICE_ERROR The device reported an error.
1056 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1057 @retval EFI_WRITE_PROTECTED The device is write protected.
1058 @retval EFI_ACCESS_DENIED The file was open for read only.
1063 IN EFI_FILE_PROTOCOL
*This
,
1064 IN EFI_GUID
*InformationType
,
1065 IN UINTN BufferSize
,
1069 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*PrivateRoot
;
1070 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
1071 EFI_FILE_INFO
*OldFileInfo
;
1072 EFI_FILE_INFO
*NewFileInfo
;
1076 struct stat OldAttr
;
1080 BOOLEAN AttrChangeFlag
;
1081 BOOLEAN NameChangeFlag
;
1082 BOOLEAN SizeChangeFlag
;
1083 BOOLEAN TimeChangeFlag
;
1084 struct tm NewLastAccessSystemTime
;
1085 struct tm NewLastWriteSystemTime
;
1086 EFI_FILE_SYSTEM_INFO
*NewFileSystemInfo
;
1087 CHAR8
*AsciiFilePtr
;
1088 CHAR16
*UnicodeFilePtr
;
1090 struct utimbuf Utime
;
1093 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
1094 PrivateRoot
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile
->SimpleFileSystem
);
1096 Status
= EFI_UNSUPPORTED
;
1097 OldFileInfo
= NewFileInfo
= NULL
;
1098 OldFileName
= NewFileName
= NULL
;
1099 AttrChangeFlag
= NameChangeFlag
= SizeChangeFlag
= TimeChangeFlag
= FALSE
;
1102 // Set file system information.
1104 if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
1105 if (BufferSize
< (SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
))) {
1106 Status
= EFI_BAD_BUFFER_SIZE
;
1110 NewFileSystemInfo
= (EFI_FILE_SYSTEM_INFO
*) Buffer
;
1112 free (PrivateRoot
->VolumeLabel
);
1114 PrivateRoot
->VolumeLabel
= malloc (StrSize (NewFileSystemInfo
->VolumeLabel
));
1115 if (PrivateRoot
->VolumeLabel
== NULL
) {
1119 StrCpy (PrivateRoot
->VolumeLabel
, NewFileSystemInfo
->VolumeLabel
);
1121 Status
= EFI_SUCCESS
;
1126 // Set volume label information.
1128 if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
1129 if (BufferSize
< StrSize (PrivateRoot
->VolumeLabel
)) {
1130 Status
= EFI_BAD_BUFFER_SIZE
;
1134 StrCpy (PrivateRoot
->VolumeLabel
, (CHAR16
*) Buffer
);
1136 Status
= EFI_SUCCESS
;
1140 if (!CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
1141 Status
= EFI_UNSUPPORTED
;
1145 if (BufferSize
< SIZE_OF_EFI_FILE_INFO
) {
1146 Status
= EFI_BAD_BUFFER_SIZE
;
1151 // Set file/directory information.
1155 // Check for invalid set file information parameters.
1157 NewFileInfo
= (EFI_FILE_INFO
*) Buffer
;
1158 if (NewFileInfo
->Size
<= sizeof (EFI_FILE_INFO
) ||
1159 (NewFileInfo
->Attribute
&~(EFI_FILE_VALID_ATTR
)) ||
1160 (sizeof (UINTN
) == 4 && NewFileInfo
->Size
> 0xFFFFFFFF)
1162 Status
= EFI_INVALID_PARAMETER
;
1167 // Get current file information so we can determine what kind
1168 // of change request this is.
1171 Status
= UnixSimpleFileSystemFileInfo (PrivateFile
, NULL
, &OldInfoSize
, NULL
);
1172 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1173 Status
= EFI_DEVICE_ERROR
;
1177 OldFileInfo
= malloc (OldInfoSize
);
1178 if (OldFileInfo
== NULL
) {
1182 Status
= UnixSimpleFileSystemFileInfo (PrivateFile
, NULL
, &OldInfoSize
, OldFileInfo
);
1183 if (EFI_ERROR (Status
)) {
1187 OldFileName
= malloc (AsciiStrSize (PrivateFile
->FileName
));
1188 if (OldFileInfo
== NULL
) {
1192 AsciiStrCpy (OldFileName
, PrivateFile
->FileName
);
1195 // Make full pathname from new filename and rootpath.
1197 if (NewFileInfo
->FileName
[0] == '\\') {
1198 NewFileName
= malloc (AsciiStrLen (PrivateRoot
->FilePath
) + 1 + StrLen (NewFileInfo
->FileName
) + 1);
1199 if (NewFileName
== NULL
) {
1203 AsciiStrCpy (NewFileName
, PrivateRoot
->FilePath
);
1204 AsciiFilePtr
= NewFileName
+ AsciiStrLen(NewFileName
);
1205 UnicodeFilePtr
= NewFileInfo
->FileName
+ 1;
1206 *AsciiFilePtr
++ ='/';
1208 NewFileName
= malloc (AsciiStrLen (PrivateFile
->FileName
) + 2 + StrLen (NewFileInfo
->FileName
) + 1);
1209 if (NewFileName
== NULL
) {
1213 AsciiStrCpy (NewFileName
, PrivateRoot
->FilePath
);
1214 AsciiFilePtr
= NewFileName
+ AsciiStrLen(NewFileName
);
1215 if ((AsciiFilePtr
[-1] != '/') && (NewFileInfo
->FileName
[0] != '/')) {
1216 // make sure there is a / between Root FilePath and NewFileInfo Filename
1217 AsciiFilePtr
[0] = '/';
1218 AsciiFilePtr
[1] = '\0';
1221 UnicodeFilePtr
= NewFileInfo
->FileName
;
1223 // Convert to ascii.
1224 while (*UnicodeFilePtr
) {
1225 *AsciiFilePtr
++ = *UnicodeFilePtr
++;
1230 // Is there an attribute change request?
1232 if (NewFileInfo
->Attribute
!= OldFileInfo
->Attribute
) {
1233 if ((NewFileInfo
->Attribute
& EFI_FILE_DIRECTORY
) != (OldFileInfo
->Attribute
& EFI_FILE_DIRECTORY
)) {
1234 Status
= EFI_INVALID_PARAMETER
;
1238 AttrChangeFlag
= TRUE
;
1242 // Is there a name change request?
1243 // bugbug: - Should really use EFI_UNICODE_COLLATION_PROTOCOL
1245 if (StrCmp (NewFileInfo
->FileName
, OldFileInfo
->FileName
)) {
1246 NameChangeFlag
= TRUE
;
1250 // Is there a size change request?
1252 if (NewFileInfo
->FileSize
!= OldFileInfo
->FileSize
) {
1253 SizeChangeFlag
= TRUE
;
1257 // Is there a time stamp change request?
1259 if (!IsZero (&NewFileInfo
->CreateTime
, sizeof (EFI_TIME
)) &&
1260 CompareMem (&NewFileInfo
->CreateTime
, &OldFileInfo
->CreateTime
, sizeof (EFI_TIME
))
1262 TimeChangeFlag
= TRUE
;
1263 } else if (!IsZero (&NewFileInfo
->LastAccessTime
, sizeof (EFI_TIME
)) &&
1264 CompareMem (&NewFileInfo
->LastAccessTime
, &OldFileInfo
->LastAccessTime
, sizeof (EFI_TIME
))
1266 TimeChangeFlag
= TRUE
;
1267 } else if (!IsZero (&NewFileInfo
->ModificationTime
, sizeof (EFI_TIME
)) &&
1268 CompareMem (&NewFileInfo
->ModificationTime
, &OldFileInfo
->ModificationTime
, sizeof (EFI_TIME
))
1270 TimeChangeFlag
= TRUE
;
1274 // All done if there are no change requests being made.
1276 if (!(AttrChangeFlag
|| NameChangeFlag
|| SizeChangeFlag
|| TimeChangeFlag
)) {
1277 Status
= EFI_SUCCESS
;
1282 // Set file or directory information.
1284 if (stat (OldFileName
, &OldAttr
) != 0) {
1285 Status
= ErrnoToEfiStatus ();
1292 if (NameChangeFlag
) {
1294 // Close the handles first
1296 if (PrivateFile
->IsOpenedByRead
) {
1297 Status
= EFI_ACCESS_DENIED
;
1301 for (CharPointer
= NewFileName
; *CharPointer
!= 0 && *CharPointer
!= L
'/'; CharPointer
++) {
1304 if (*CharPointer
!= 0) {
1305 Status
= EFI_ACCESS_DENIED
;
1309 UnixStatus
= rename (OldFileName
, NewFileName
);
1310 if (UnixStatus
== 0) {
1314 free (PrivateFile
->FileName
);
1316 PrivateFile
->FileName
= malloc (AsciiStrSize (NewFileName
));
1317 if (PrivateFile
->FileName
== NULL
) {
1321 AsciiStrCpy (PrivateFile
->FileName
, NewFileName
);
1323 Status
= EFI_DEVICE_ERROR
;
1331 if (SizeChangeFlag
) {
1332 if (PrivateFile
->IsDirectoryPath
) {
1333 Status
= EFI_UNSUPPORTED
;
1337 if (PrivateFile
->IsOpenedByRead
|| OldFileInfo
->Attribute
& EFI_FILE_READ_ONLY
) {
1338 Status
= EFI_ACCESS_DENIED
;
1342 if (ftruncate (PrivateFile
->fd
, NewFileInfo
->FileSize
) != 0) {
1343 Status
= ErrnoToEfiStatus ();
1352 if (TimeChangeFlag
) {
1353 NewLastAccessSystemTime
.tm_year
= NewFileInfo
->LastAccessTime
.Year
;
1354 NewLastAccessSystemTime
.tm_mon
= NewFileInfo
->LastAccessTime
.Month
;
1355 NewLastAccessSystemTime
.tm_mday
= NewFileInfo
->LastAccessTime
.Day
;
1356 NewLastAccessSystemTime
.tm_hour
= NewFileInfo
->LastAccessTime
.Hour
;
1357 NewLastAccessSystemTime
.tm_min
= NewFileInfo
->LastAccessTime
.Minute
;
1358 NewLastAccessSystemTime
.tm_sec
= NewFileInfo
->LastAccessTime
.Second
;
1359 NewLastAccessSystemTime
.tm_isdst
= 0;
1361 Utime
.actime
= mktime (&NewLastAccessSystemTime
);
1363 NewLastWriteSystemTime
.tm_year
= NewFileInfo
->ModificationTime
.Year
;
1364 NewLastWriteSystemTime
.tm_mon
= NewFileInfo
->ModificationTime
.Month
;
1365 NewLastWriteSystemTime
.tm_mday
= NewFileInfo
->ModificationTime
.Day
;
1366 NewLastWriteSystemTime
.tm_hour
= NewFileInfo
->ModificationTime
.Hour
;
1367 NewLastWriteSystemTime
.tm_min
= NewFileInfo
->ModificationTime
.Minute
;
1368 NewLastWriteSystemTime
.tm_sec
= NewFileInfo
->ModificationTime
.Second
;
1369 NewLastWriteSystemTime
.tm_isdst
= 0;
1371 Utime
.modtime
= mktime (&NewLastWriteSystemTime
);
1373 if (Utime
.actime
== (time_t)-1 || Utime
.modtime
== (time_t)-1) {
1377 if (utime (PrivateFile
->FileName
, &Utime
) == -1) {
1378 Status
= ErrnoToEfiStatus ();
1384 // No matter about AttrChangeFlag, Attribute must be set.
1385 // Because operation before may cause attribute change.
1387 NewAttr
= OldAttr
.st_mode
;
1389 if (NewFileInfo
->Attribute
& EFI_FILE_READ_ONLY
) {
1390 NewAttr
&= ~(S_IRUSR
| S_IRGRP
| S_IROTH
);
1395 if (chmod (NewFileName
, NewAttr
) != 0) {
1396 Status
= ErrnoToEfiStatus ();
1400 if (OldFileInfo
!= NULL
) {
1404 if (OldFileName
!= NULL
) {
1408 if (NewFileName
!= NULL
) {
1417 Flush data back for the file handle.
1419 @param This Protocol instance pointer.
1421 @retval EFI_SUCCESS Data was written.
1422 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
1423 @retval EFI_NO_MEDIA The device has no media.
1424 @retval EFI_DEVICE_ERROR The device reported an error.
1425 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1426 @retval EFI_WRITE_PROTECTED The device is write protected.
1427 @retval EFI_ACCESS_DENIED The file was open for read only.
1428 @retval EFI_VOLUME_FULL The volume is full.
1433 IN EFI_FILE_PROTOCOL
*This
1436 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
1439 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
1441 if (PrivateFile
->IsDirectoryPath
) {
1442 return EFI_UNSUPPORTED
;
1445 if (PrivateFile
->IsOpenedByRead
) {
1446 return EFI_ACCESS_DENIED
;
1449 if (PrivateFile
->fd
< 0) {
1450 return EFI_DEVICE_ERROR
;
1453 if (fsync (PrivateFile
->fd
) != 0) {
1454 return ErrnoToEfiStatus ();
1463 PosixFileSystmeThunkOpen (
1464 IN EMU_IO_THUNK_PROTOCOL
*This
1467 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*Private
;
1470 if (This
->Private
!= NULL
) {
1471 return EFI_ALREADY_STARTED
;
1474 if (!CompareGuid (This
->Protocol
, &gEfiSimpleFileSystemProtocolGuid
)) {
1475 return EFI_UNSUPPORTED
;
1478 Private
= malloc (sizeof (EMU_SIMPLE_FILE_SYSTEM_PRIVATE
));
1479 if (Private
== NULL
) {
1480 return EFI_OUT_OF_RESOURCES
;
1483 Private
->FilePath
= malloc (StrLen (This
->ConfigString
) + 1);
1484 if (Private
->FilePath
== NULL
) {
1486 return EFI_OUT_OF_RESOURCES
;
1489 // Convert Unicode to Ascii
1490 for (i
= 0; This
->ConfigString
[i
] != 0; i
++) {
1491 Private
->FilePath
[i
] = This
->ConfigString
[i
];
1493 Private
->FilePath
[i
] = 0;
1496 Private
->VolumeLabel
= malloc (StrLen (L
"EFI_EMULATED"));
1497 if (Private
->VolumeLabel
== NULL
) {
1498 free (Private
->FilePath
);
1500 return EFI_OUT_OF_RESOURCES
;
1502 StrCpy (Private
->VolumeLabel
, L
"EFI_EMULATED");
1504 Private
->Signature
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE
;
1505 Private
->Thunk
= This
;
1506 CopyMem (&Private
->SimpleFileSystem
, &gPosixFileSystemProtocol
, sizeof (Private
->SimpleFileSystem
));
1507 Private
->FileHandlesOpen
= FALSE
;
1509 This
->Interface
= &Private
->SimpleFileSystem
;
1510 This
->Private
= Private
;
1516 PosixFileSystmeThunkClose (
1517 IN EMU_IO_THUNK_PROTOCOL
*This
1520 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*Private
;
1522 if (!CompareGuid (This
->Protocol
, &gEfiSimpleFileSystemProtocolGuid
)) {
1523 return EFI_UNSUPPORTED
;
1526 Private
= This
->Private
;
1528 if (Private
->FileHandlesOpen
) {
1530 // Close only supported if all the EFI_FILE_HANDLEs have been closed.
1532 return EFI_NOT_READY
;
1535 if (This
->Private
!= NULL
) {
1536 if (Private
->VolumeLabel
== NULL
) {
1537 free (Private
->VolumeLabel
);
1539 free (This
->Private
);
1546 EMU_IO_THUNK_PROTOCOL gPosixFileSystemThunkIo
= {
1547 &gEfiSimpleFileSystemProtocolGuid
,
1551 GasketPosixFileSystmeThunkOpen
,
1552 GasketPosixFileSystmeThunkClose
,