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
;
254 } else if (PrivateFile
->IsRootDirectory
) {
257 RealFileName
= PrivateFile
->FileName
;
260 TempPointer
= RealFileName
;
261 while (*TempPointer
) {
262 if (*TempPointer
== '/') {
263 RealFileName
= TempPointer
+ 1;
269 Size
= SIZE_OF_EFI_FILE_INFO
;
270 NameSize
= AsciiStrSize (RealFileName
) * 2;
271 ResultSize
= Size
+ NameSize
;
273 if (*BufferSize
< ResultSize
) {
274 *BufferSize
= ResultSize
;
275 return EFI_BUFFER_TOO_SMALL
;
277 if (stat (FileName
== NULL
? PrivateFile
->FileName
: FileName
, &buf
) < 0) {
278 return EFI_DEVICE_ERROR
;
281 Status
= EFI_SUCCESS
;
284 ZeroMem (Info
, ResultSize
);
286 Info
->Size
= ResultSize
;
287 Info
->FileSize
= buf
.st_size
;
288 Info
->PhysicalSize
= MultU64x32 (buf
.st_blocks
, buf
.st_blksize
);
290 PosixSystemTimeToEfiTime (buf
.st_ctime
, &Info
->CreateTime
);
291 PosixSystemTimeToEfiTime (buf
.st_atime
, &Info
->LastAccessTime
);
292 PosixSystemTimeToEfiTime (buf
.st_mtime
, &Info
->ModificationTime
);
294 if (!(buf
.st_mode
& S_IWUSR
)) {
295 Info
->Attribute
|= EFI_FILE_READ_ONLY
;
298 if (S_ISDIR(buf
.st_mode
)) {
299 Info
->Attribute
|= EFI_FILE_DIRECTORY
;
303 BufferFileName
= (CHAR16
*)((CHAR8
*) Buffer
+ Size
);
304 while (*RealFileName
) {
305 *BufferFileName
++ = *RealFileName
++;
309 *BufferSize
= ResultSize
;
319 if (Buffer
== NULL
|| Length
== 0) {
323 if (*(UINT8
*) Buffer
!= 0) {
328 if (!CompareMem (Buffer
, (UINT8
*) Buffer
+ 1, Length
- 1)) {
339 Opens a new file relative to the source file's location.
341 @param This The protocol instance pointer.
342 @param NewHandle Returns File Handle for FileName.
343 @param FileName Null terminated string. "\", ".", and ".." are supported.
344 @param OpenMode Open mode for file.
345 @param Attributes Only used for EFI_FILE_MODE_CREATE.
347 @retval EFI_SUCCESS The device was opened.
348 @retval EFI_NOT_FOUND The specified file could not be found on the device.
349 @retval EFI_NO_MEDIA The device has no media.
350 @retval EFI_MEDIA_CHANGED The media has changed.
351 @retval EFI_DEVICE_ERROR The device reported an error.
352 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
353 @retval EFI_ACCESS_DENIED The service denied access to the file.
354 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
355 @retval EFI_VOLUME_FULL The volume is full.
360 IN EFI_FILE_PROTOCOL
*This
,
361 OUT EFI_FILE_PROTOCOL
**NewHandle
,
367 EFI_FILE_PROTOCOL
*Root
;
368 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
369 EMU_EFI_FILE_PRIVATE
*NewPrivateFile
;
370 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*PrivateRoot
;
379 BOOLEAN TrailingDash
;
387 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
388 PrivateRoot
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile
->SimpleFileSystem
);
389 NewPrivateFile
= NULL
;
390 Status
= EFI_OUT_OF_RESOURCES
;
393 // BUGBUG: assume an open of root
394 // if current location, return current data
396 TrailingDash
= FALSE
;
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 if (FileName
[StrLen (FileName
) - 1] == L
'\\') {
407 FileName
[StrLen (FileName
) - 1] = 0;
411 // Attempt to open the file
413 NewPrivateFile
= malloc (sizeof (EMU_EFI_FILE_PRIVATE
));
414 if (NewPrivateFile
== NULL
) {
418 CopyMem (NewPrivateFile
, PrivateFile
, sizeof (EMU_EFI_FILE_PRIVATE
));
420 NewPrivateFile
->FileName
= malloc (AsciiStrSize (PrivateFile
->FileName
) + 1 + StrLen (FileName
) + 1);
421 if (NewPrivateFile
->FileName
== NULL
) {
425 if (*FileName
== L
'\\') {
426 AsciiStrCpy (NewPrivateFile
->FileName
, PrivateRoot
->FilePath
);
430 AsciiStrCpy (NewPrivateFile
->FileName
, PrivateFile
->FileName
);
433 Dst
= NewPrivateFile
->FileName
+ AsciiStrLen (NewPrivateFile
->FileName
);
434 GuardPointer
= NewPrivateFile
->FileName
+ AsciiStrLen (PrivateRoot
->FilePath
);
436 // Convert unicode to ascii and '\' to '/'
449 // Get rid of . and .., except leading . or ..
453 // GuardPointer protect simplefilesystem root path not be destroyed
457 while (!LoopFinish
) {
460 for (ParseFileName
= GuardPointer
; *ParseFileName
; ParseFileName
++) {
461 if (*ParseFileName
== '.' &&
462 (*(ParseFileName
+ 1) == 0 || *(ParseFileName
+ 1) == '/') &&
463 *(ParseFileName
- 1) == '/'
469 CutPrefix (ParseFileName
- 1, 2);
474 if (*ParseFileName
== '.' &&
475 *(ParseFileName
+ 1) == '.' &&
476 (*(ParseFileName
+ 2) == 0 || *(ParseFileName
+ 2) == '/') &&
477 *(ParseFileName
- 1) == '/'
483 while (ParseFileName
!= GuardPointer
) {
486 if (*ParseFileName
== '/') {
492 // cut /.. and its left directory
494 CutPrefix (ParseFileName
, Count
);
501 if (AsciiStrCmp (NewPrivateFile
->FileName
, PrivateRoot
->FilePath
) == 0) {
502 NewPrivateFile
->IsRootDirectory
= TRUE
;
503 free (NewPrivateFile
->FileName
);
504 free (NewPrivateFile
);
508 RealFileName
= NewPrivateFile
->FileName
+ AsciiStrLen(NewPrivateFile
->FileName
) - 1;
509 while (RealFileName
> NewPrivateFile
->FileName
&& *RealFileName
!= '/') {
513 TempChar
= *(RealFileName
- 1);
514 *(RealFileName
- 1) = 0;
515 *(RealFileName
- 1) = TempChar
;
519 // Test whether file or directory
521 NewPrivateFile
->IsRootDirectory
= FALSE
;
522 NewPrivateFile
->fd
= -1;
523 NewPrivateFile
->Dir
= NULL
;
524 if (OpenMode
& EFI_FILE_MODE_CREATE
) {
525 if (Attributes
& EFI_FILE_DIRECTORY
) {
526 NewPrivateFile
->IsDirectoryPath
= TRUE
;
528 NewPrivateFile
->IsDirectoryPath
= FALSE
;
531 res
= stat (NewPrivateFile
->FileName
, &finfo
);
532 if (res
== 0 && S_ISDIR(finfo
.st_mode
)) {
533 NewPrivateFile
->IsDirectoryPath
= TRUE
;
535 NewPrivateFile
->IsDirectoryPath
= FALSE
;
539 if (OpenMode
& EFI_FILE_MODE_WRITE
) {
540 NewPrivateFile
->IsOpenedByRead
= FALSE
;
542 NewPrivateFile
->IsOpenedByRead
= TRUE
;
545 Status
= EFI_SUCCESS
;
548 // deal with directory
550 if (NewPrivateFile
->IsDirectoryPath
) {
551 if ((OpenMode
& EFI_FILE_MODE_CREATE
)) {
553 // Create a directory
555 if (mkdir (NewPrivateFile
->FileName
, 0777) != 0) {
556 if (errno
!= EEXIST
) {
557 //free (TempFileName);
558 Status
= EFI_ACCESS_DENIED
;
564 NewPrivateFile
->Dir
= opendir (NewPrivateFile
->FileName
);
565 if (NewPrivateFile
->Dir
== NULL
) {
566 if (errno
== EACCES
) {
567 Status
= EFI_ACCESS_DENIED
;
569 Status
= EFI_NOT_FOUND
;
579 NewPrivateFile
->fd
= open (
580 NewPrivateFile
->FileName
,
581 ((OpenMode
& EFI_FILE_MODE_CREATE
) ? O_CREAT
: 0) | (NewPrivateFile
->IsOpenedByRead
? O_RDONLY
: O_RDWR
),
584 if (NewPrivateFile
->fd
< 0) {
585 if (errno
== ENOENT
) {
586 Status
= EFI_NOT_FOUND
;
588 Status
= EFI_ACCESS_DENIED
;
593 if ((OpenMode
& EFI_FILE_MODE_CREATE
) && Status
== EFI_SUCCESS
) {
599 Status
= PosixFileGetInfo (&NewPrivateFile
->EfiFile
, &gEfiFileInfoGuid
, &InfoSize
, Info
);
600 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
601 Status
= EFI_DEVICE_ERROR
;
605 Info
= malloc (InfoSize
);
610 Status
= PosixFileGetInfo (&NewPrivateFile
->EfiFile
, &gEfiFileInfoGuid
, &InfoSize
, Info
);
611 if (EFI_ERROR (Status
)) {
615 Info
->Attribute
= Attributes
;
616 PosixFileSetInfo (&NewPrivateFile
->EfiFile
, &gEfiFileInfoGuid
, InfoSize
, Info
);
623 FileName
[StrLen (FileName
) + 1] = 0;
624 FileName
[StrLen (FileName
)] = L
'\\';
627 if (EFI_ERROR (Status
)) {
628 if (NewPrivateFile
) {
629 if (NewPrivateFile
->FileName
) {
630 free (NewPrivateFile
->FileName
);
633 free (NewPrivateFile
);
636 *NewHandle
= &NewPrivateFile
->EfiFile
;
645 Close the file handle
647 @param This Protocol instance pointer.
649 @retval EFI_SUCCESS The device was opened.
654 IN EFI_FILE_PROTOCOL
*This
657 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
659 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
661 if (PrivateFile
->fd
>= 0) {
662 close (PrivateFile
->fd
);
664 if (PrivateFile
->Dir
!= NULL
) {
665 closedir (PrivateFile
->Dir
);
668 PrivateFile
->fd
= -1;
669 PrivateFile
->Dir
= NULL
;
671 if (PrivateFile
->FileName
) {
672 free (PrivateFile
->FileName
);
682 Close and delete the file handle.
684 @param This Protocol instance pointer.
686 @retval EFI_SUCCESS The device was opened.
687 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.
692 IN EFI_FILE_PROTOCOL
*This
696 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
698 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
699 Status
= EFI_WARN_DELETE_FAILURE
;
701 if (PrivateFile
->IsDirectoryPath
) {
702 if (PrivateFile
->Dir
!= NULL
) {
703 closedir (PrivateFile
->Dir
);
704 PrivateFile
->Dir
= NULL
;
707 if (rmdir (PrivateFile
->FileName
) == 0) {
708 Status
= EFI_SUCCESS
;
711 close (PrivateFile
->fd
);
712 PrivateFile
->fd
= -1;
714 if (!PrivateFile
->IsOpenedByRead
) {
715 if (!unlink (PrivateFile
->FileName
)) {
716 Status
= EFI_SUCCESS
;
721 free (PrivateFile
->FileName
);
729 Read data from the file.
731 @param This Protocol instance pointer.
732 @param BufferSize On input size of buffer, on output amount of data in buffer.
733 @param Buffer The buffer in which data is read.
735 @retval EFI_SUCCESS Data was read.
736 @retval EFI_NO_MEDIA The device has no media.
737 @retval EFI_DEVICE_ERROR The device reported an error.
738 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
739 @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size.
744 IN EFI_FILE_PROTOCOL
*This
,
745 IN OUT UINTN
*BufferSize
,
749 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
758 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
760 if (!PrivateFile
->IsDirectoryPath
) {
761 if (PrivateFile
->fd
< 0) {
762 Status
= EFI_DEVICE_ERROR
;
766 Res
= read (PrivateFile
->fd
, Buffer
, *BufferSize
);
768 Status
= EFI_DEVICE_ERROR
;
772 Status
= EFI_SUCCESS
;
777 // Read on a directory.
779 if (PrivateFile
->Dir
== NULL
) {
780 Status
= EFI_DEVICE_ERROR
;
784 if (PrivateFile
->Dirent
== NULL
) {
785 PrivateFile
->Dirent
= readdir (PrivateFile
->Dir
);
786 if (PrivateFile
->Dirent
== NULL
) {
788 Status
= EFI_SUCCESS
;
793 Size
= SIZE_OF_EFI_FILE_INFO
;
794 NameSize
= AsciiStrLen (PrivateFile
->Dirent
->d_name
) + 1;
795 ResultSize
= Size
+ 2 * NameSize
;
797 if (*BufferSize
< ResultSize
) {
798 *BufferSize
= ResultSize
;
799 Status
= EFI_BUFFER_TOO_SMALL
;
802 Status
= EFI_SUCCESS
;
804 *BufferSize
= ResultSize
;
806 FullFileName
= malloc (AsciiStrLen(PrivateFile
->FileName
) + 1 + NameSize
);
807 if (FullFileName
== NULL
) {
808 Status
= EFI_OUT_OF_RESOURCES
;
812 AsciiStrCpy (FullFileName
, PrivateFile
->FileName
);
813 AsciiStrCat (FullFileName
, "/");
814 AsciiStrCat (FullFileName
, PrivateFile
->Dirent
->d_name
);
815 Status
= UnixSimpleFileSystemFileInfo (
823 PrivateFile
->Dirent
= NULL
;
832 Write data to a file.
834 @param This Protocol instance pointer.
835 @param BufferSize On input size of buffer, on output amount of data in buffer.
836 @param Buffer The buffer in which data to write.
838 @retval EFI_SUCCESS Data was written.
839 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
840 @retval EFI_NO_MEDIA The device has no media.
841 @retval EFI_DEVICE_ERROR The device reported an error.
842 @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
843 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
844 @retval EFI_WRITE_PROTECTED The device is write protected.
845 @retval EFI_ACCESS_DENIED The file was open for read only.
846 @retval EFI_VOLUME_FULL The volume is full.
851 IN EFI_FILE_PROTOCOL
*This
,
852 IN OUT UINTN
*BufferSize
,
856 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
860 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
862 if (PrivateFile
->fd
< 0) {
863 return EFI_DEVICE_ERROR
;
866 if (PrivateFile
->IsDirectoryPath
) {
867 return EFI_UNSUPPORTED
;
870 if (PrivateFile
->IsOpenedByRead
) {
871 return EFI_ACCESS_DENIED
;
874 Res
= write (PrivateFile
->fd
, Buffer
, *BufferSize
);
875 if (Res
== (UINTN
)-1) {
876 return ErrnoToEfiStatus ();
886 Set a files current position
888 @param This Protocol instance pointer.
889 @param Position Byte position from the start of the file.
891 @retval EFI_SUCCESS Data was written.
892 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
896 PosixFileSetPossition (
897 IN EFI_FILE_PROTOCOL
*This
,
901 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
904 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
906 if (PrivateFile
->IsDirectoryPath
) {
908 return EFI_UNSUPPORTED
;
911 if (PrivateFile
->Dir
== NULL
) {
912 return EFI_DEVICE_ERROR
;
914 rewinddir (PrivateFile
->Dir
);
917 if (Position
== (UINT64
) -1) {
918 Pos
= lseek (PrivateFile
->fd
, 0, SEEK_END
);
920 Pos
= lseek (PrivateFile
->fd
, Position
, SEEK_SET
);
922 if (Pos
== (off_t
)-1) {
923 return ErrnoToEfiStatus ();
932 Get a file's current position
934 @param This Protocol instance pointer.
935 @param Position Byte position from the start of the file.
937 @retval EFI_SUCCESS Data was written.
938 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..
942 PosixFileGetPossition (
943 IN EFI_FILE_PROTOCOL
*This
,
948 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
950 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
952 if (PrivateFile
->IsDirectoryPath
) {
953 Status
= EFI_UNSUPPORTED
;
955 *Position
= (UINT64
)lseek (PrivateFile
->fd
, 0, SEEK_CUR
);
956 Status
= (*Position
== (UINT64
) -1) ? ErrnoToEfiStatus () : EFI_SUCCESS
;
964 Get information about a file.
966 @param This Protocol instance pointer.
967 @param InformationType Type of information to return in Buffer.
968 @param BufferSize On input size of buffer, on output amount of data in buffer.
969 @param Buffer The buffer to return data.
971 @retval EFI_SUCCESS Data was returned.
972 @retval EFI_UNSUPPORTED InformationType is not supported.
973 @retval EFI_NO_MEDIA The device has no media.
974 @retval EFI_DEVICE_ERROR The device reported an error.
975 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
976 @retval EFI_WRITE_PROTECTED The device is write protected.
977 @retval EFI_ACCESS_DENIED The file was open for read only.
978 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
983 IN EFI_FILE_PROTOCOL
*This
,
984 IN EFI_GUID
*InformationType
,
985 IN OUT UINTN
*BufferSize
,
990 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
991 EFI_FILE_SYSTEM_INFO
*FileSystemInfoBuffer
;
993 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*PrivateRoot
;
996 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
997 PrivateRoot
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile
->SimpleFileSystem
);
999 Status
= EFI_SUCCESS
;
1000 if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
1001 Status
= UnixSimpleFileSystemFileInfo (PrivateFile
, NULL
, BufferSize
, Buffer
);
1002 } else if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
1003 if (*BufferSize
< SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
)) {
1004 *BufferSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
);
1005 return EFI_BUFFER_TOO_SMALL
;
1008 UnixStatus
= statfs (PrivateFile
->FileName
, &buf
);
1009 if (UnixStatus
< 0) {
1010 return EFI_DEVICE_ERROR
;
1013 FileSystemInfoBuffer
= (EFI_FILE_SYSTEM_INFO
*) Buffer
;
1014 FileSystemInfoBuffer
->Size
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
);
1015 FileSystemInfoBuffer
->ReadOnly
= FALSE
;
1020 FileSystemInfoBuffer
->VolumeSize
= MultU64x32 (buf
.f_blocks
, buf
.f_bsize
);
1021 FileSystemInfoBuffer
->FreeSpace
= MultU64x32 (buf
.f_bavail
, buf
.f_bsize
);
1022 FileSystemInfoBuffer
->BlockSize
= buf
.f_bsize
;
1025 StrCpy ((CHAR16
*) FileSystemInfoBuffer
->VolumeLabel
, PrivateRoot
->VolumeLabel
);
1026 *BufferSize
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
);
1028 } else if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
1029 if (*BufferSize
< StrSize (PrivateRoot
->VolumeLabel
)) {
1030 *BufferSize
= StrSize (PrivateRoot
->VolumeLabel
);
1031 return EFI_BUFFER_TOO_SMALL
;
1034 StrCpy ((CHAR16
*) Buffer
, PrivateRoot
->VolumeLabel
);
1035 *BufferSize
= StrSize (PrivateRoot
->VolumeLabel
);
1044 Set information about a file
1046 @param File Protocol instance pointer.
1047 @param InformationType Type of information in Buffer.
1048 @param BufferSize Size of buffer.
1049 @param Buffer The data to write.
1051 @retval EFI_SUCCESS Data was returned.
1052 @retval EFI_UNSUPPORTED InformationType is not supported.
1053 @retval EFI_NO_MEDIA The device has no media.
1054 @retval EFI_DEVICE_ERROR The device reported an error.
1055 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1056 @retval EFI_WRITE_PROTECTED The device is write protected.
1057 @retval EFI_ACCESS_DENIED The file was open for read only.
1062 IN EFI_FILE_PROTOCOL
*This
,
1063 IN EFI_GUID
*InformationType
,
1064 IN UINTN BufferSize
,
1068 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*PrivateRoot
;
1069 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
1070 EFI_FILE_INFO
*OldFileInfo
;
1071 EFI_FILE_INFO
*NewFileInfo
;
1075 struct stat OldAttr
;
1079 BOOLEAN AttrChangeFlag
;
1080 BOOLEAN NameChangeFlag
;
1081 BOOLEAN SizeChangeFlag
;
1082 BOOLEAN TimeChangeFlag
;
1083 struct tm NewLastAccessSystemTime
;
1084 struct tm NewLastWriteSystemTime
;
1085 EFI_FILE_SYSTEM_INFO
*NewFileSystemInfo
;
1086 CHAR8
*AsciiFilePtr
;
1087 CHAR16
*UnicodeFilePtr
;
1089 struct utimbuf Utime
;
1092 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
1093 PrivateRoot
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile
->SimpleFileSystem
);
1095 Status
= EFI_UNSUPPORTED
;
1096 OldFileInfo
= NewFileInfo
= NULL
;
1097 OldFileName
= NewFileName
= NULL
;
1098 AttrChangeFlag
= NameChangeFlag
= SizeChangeFlag
= TimeChangeFlag
= FALSE
;
1101 // Set file system information.
1103 if (CompareGuid (InformationType
, &gEfiFileSystemInfoGuid
)) {
1104 if (BufferSize
< (SIZE_OF_EFI_FILE_SYSTEM_INFO
+ StrSize (PrivateRoot
->VolumeLabel
))) {
1105 Status
= EFI_BAD_BUFFER_SIZE
;
1109 NewFileSystemInfo
= (EFI_FILE_SYSTEM_INFO
*) Buffer
;
1111 free (PrivateRoot
->VolumeLabel
);
1113 PrivateRoot
->VolumeLabel
= malloc (StrSize (NewFileSystemInfo
->VolumeLabel
));
1114 if (PrivateRoot
->VolumeLabel
== NULL
) {
1118 StrCpy (PrivateRoot
->VolumeLabel
, NewFileSystemInfo
->VolumeLabel
);
1120 Status
= EFI_SUCCESS
;
1125 // Set volume label information.
1127 if (CompareGuid (InformationType
, &gEfiFileSystemVolumeLabelInfoIdGuid
)) {
1128 if (BufferSize
< StrSize (PrivateRoot
->VolumeLabel
)) {
1129 Status
= EFI_BAD_BUFFER_SIZE
;
1133 StrCpy (PrivateRoot
->VolumeLabel
, (CHAR16
*) Buffer
);
1135 Status
= EFI_SUCCESS
;
1139 if (!CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
1140 Status
= EFI_UNSUPPORTED
;
1144 if (BufferSize
< SIZE_OF_EFI_FILE_INFO
) {
1145 Status
= EFI_BAD_BUFFER_SIZE
;
1150 // Set file/directory information.
1154 // Check for invalid set file information parameters.
1156 NewFileInfo
= (EFI_FILE_INFO
*) Buffer
;
1157 if (NewFileInfo
->Size
<= sizeof (EFI_FILE_INFO
) ||
1158 (NewFileInfo
->Attribute
&~(EFI_FILE_VALID_ATTR
)) ||
1159 (sizeof (UINTN
) == 4 && NewFileInfo
->Size
> 0xFFFFFFFF)
1161 Status
= EFI_INVALID_PARAMETER
;
1166 // Get current file information so we can determine what kind
1167 // of change request this is.
1170 Status
= UnixSimpleFileSystemFileInfo (PrivateFile
, NULL
, &OldInfoSize
, NULL
);
1171 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1172 Status
= EFI_DEVICE_ERROR
;
1176 OldFileInfo
= malloc (OldInfoSize
);
1177 if (OldFileInfo
== NULL
) {
1181 Status
= UnixSimpleFileSystemFileInfo (PrivateFile
, NULL
, &OldInfoSize
, OldFileInfo
);
1182 if (EFI_ERROR (Status
)) {
1186 OldFileName
= malloc (AsciiStrSize (PrivateFile
->FileName
));
1187 if (OldFileInfo
== NULL
) {
1191 AsciiStrCpy (OldFileName
, PrivateFile
->FileName
);
1194 // Make full pathname from new filename and rootpath.
1196 if (NewFileInfo
->FileName
[0] == '\\') {
1197 NewFileName
= malloc (AsciiStrLen (PrivateRoot
->FilePath
) + 1 + StrLen (NewFileInfo
->FileName
) + 1);
1198 if (NewFileName
== NULL
) {
1202 AsciiStrCpy (NewFileName
, PrivateRoot
->FilePath
);
1203 AsciiFilePtr
= NewFileName
+ AsciiStrLen(NewFileName
);
1204 UnicodeFilePtr
= NewFileInfo
->FileName
+ 1;
1205 *AsciiFilePtr
++ ='/';
1207 NewFileName
= malloc (AsciiStrLen (PrivateFile
->FileName
) + 2 + StrLen (NewFileInfo
->FileName
) + 1);
1208 if (NewFileName
== NULL
) {
1212 AsciiStrCpy (NewFileName
, PrivateRoot
->FilePath
);
1213 AsciiFilePtr
= NewFileName
+ AsciiStrLen(NewFileName
);
1214 if ((AsciiFilePtr
[-1] != '/') && (NewFileInfo
->FileName
[0] != '/')) {
1215 // make sure there is a / between Root FilePath and NewFileInfo Filename
1216 AsciiFilePtr
[0] = '/';
1217 AsciiFilePtr
[1] = '\0';
1220 UnicodeFilePtr
= NewFileInfo
->FileName
;
1222 // Convert to ascii.
1223 while (*UnicodeFilePtr
) {
1224 *AsciiFilePtr
++ = *UnicodeFilePtr
++;
1229 // Is there an attribute change request?
1231 if (NewFileInfo
->Attribute
!= OldFileInfo
->Attribute
) {
1232 if ((NewFileInfo
->Attribute
& EFI_FILE_DIRECTORY
) != (OldFileInfo
->Attribute
& EFI_FILE_DIRECTORY
)) {
1233 Status
= EFI_INVALID_PARAMETER
;
1237 AttrChangeFlag
= TRUE
;
1241 // Is there a name change request?
1242 // bugbug: - Should really use EFI_UNICODE_COLLATION_PROTOCOL
1244 if (StrCmp (NewFileInfo
->FileName
, OldFileInfo
->FileName
)) {
1245 NameChangeFlag
= TRUE
;
1249 // Is there a size change request?
1251 if (NewFileInfo
->FileSize
!= OldFileInfo
->FileSize
) {
1252 SizeChangeFlag
= TRUE
;
1256 // Is there a time stamp change request?
1258 if (!IsZero (&NewFileInfo
->CreateTime
, sizeof (EFI_TIME
)) &&
1259 CompareMem (&NewFileInfo
->CreateTime
, &OldFileInfo
->CreateTime
, sizeof (EFI_TIME
))
1261 TimeChangeFlag
= TRUE
;
1262 } else if (!IsZero (&NewFileInfo
->LastAccessTime
, sizeof (EFI_TIME
)) &&
1263 CompareMem (&NewFileInfo
->LastAccessTime
, &OldFileInfo
->LastAccessTime
, sizeof (EFI_TIME
))
1265 TimeChangeFlag
= TRUE
;
1266 } else if (!IsZero (&NewFileInfo
->ModificationTime
, sizeof (EFI_TIME
)) &&
1267 CompareMem (&NewFileInfo
->ModificationTime
, &OldFileInfo
->ModificationTime
, sizeof (EFI_TIME
))
1269 TimeChangeFlag
= TRUE
;
1273 // All done if there are no change requests being made.
1275 if (!(AttrChangeFlag
|| NameChangeFlag
|| SizeChangeFlag
|| TimeChangeFlag
)) {
1276 Status
= EFI_SUCCESS
;
1281 // Set file or directory information.
1283 if (stat (OldFileName
, &OldAttr
) != 0) {
1284 Status
= ErrnoToEfiStatus ();
1291 if (NameChangeFlag
) {
1293 // Close the handles first
1295 if (PrivateFile
->IsOpenedByRead
) {
1296 Status
= EFI_ACCESS_DENIED
;
1300 for (CharPointer
= NewFileName
; *CharPointer
!= 0 && *CharPointer
!= L
'/'; CharPointer
++) {
1303 if (*CharPointer
!= 0) {
1304 Status
= EFI_ACCESS_DENIED
;
1308 UnixStatus
= rename (OldFileName
, NewFileName
);
1309 if (UnixStatus
== 0) {
1313 free (PrivateFile
->FileName
);
1315 PrivateFile
->FileName
= malloc (AsciiStrSize (NewFileName
));
1316 if (PrivateFile
->FileName
== NULL
) {
1320 AsciiStrCpy (PrivateFile
->FileName
, NewFileName
);
1322 Status
= EFI_DEVICE_ERROR
;
1330 if (SizeChangeFlag
) {
1331 if (PrivateFile
->IsDirectoryPath
) {
1332 Status
= EFI_UNSUPPORTED
;
1336 if (PrivateFile
->IsOpenedByRead
|| OldFileInfo
->Attribute
& EFI_FILE_READ_ONLY
) {
1337 Status
= EFI_ACCESS_DENIED
;
1341 if (ftruncate (PrivateFile
->fd
, NewFileInfo
->FileSize
) != 0) {
1342 Status
= ErrnoToEfiStatus ();
1351 if (TimeChangeFlag
) {
1352 NewLastAccessSystemTime
.tm_year
= NewFileInfo
->LastAccessTime
.Year
;
1353 NewLastAccessSystemTime
.tm_mon
= NewFileInfo
->LastAccessTime
.Month
;
1354 NewLastAccessSystemTime
.tm_mday
= NewFileInfo
->LastAccessTime
.Day
;
1355 NewLastAccessSystemTime
.tm_hour
= NewFileInfo
->LastAccessTime
.Hour
;
1356 NewLastAccessSystemTime
.tm_min
= NewFileInfo
->LastAccessTime
.Minute
;
1357 NewLastAccessSystemTime
.tm_sec
= NewFileInfo
->LastAccessTime
.Second
;
1358 NewLastAccessSystemTime
.tm_isdst
= 0;
1360 Utime
.actime
= mktime (&NewLastAccessSystemTime
);
1362 NewLastWriteSystemTime
.tm_year
= NewFileInfo
->ModificationTime
.Year
;
1363 NewLastWriteSystemTime
.tm_mon
= NewFileInfo
->ModificationTime
.Month
;
1364 NewLastWriteSystemTime
.tm_mday
= NewFileInfo
->ModificationTime
.Day
;
1365 NewLastWriteSystemTime
.tm_hour
= NewFileInfo
->ModificationTime
.Hour
;
1366 NewLastWriteSystemTime
.tm_min
= NewFileInfo
->ModificationTime
.Minute
;
1367 NewLastWriteSystemTime
.tm_sec
= NewFileInfo
->ModificationTime
.Second
;
1368 NewLastWriteSystemTime
.tm_isdst
= 0;
1370 Utime
.modtime
= mktime (&NewLastWriteSystemTime
);
1372 if (Utime
.actime
== (time_t)-1 || Utime
.modtime
== (time_t)-1) {
1376 if (utime (PrivateFile
->FileName
, &Utime
) == -1) {
1377 Status
= ErrnoToEfiStatus ();
1383 // No matter about AttrChangeFlag, Attribute must be set.
1384 // Because operation before may cause attribute change.
1386 NewAttr
= OldAttr
.st_mode
;
1388 if (NewFileInfo
->Attribute
& EFI_FILE_READ_ONLY
) {
1389 NewAttr
&= ~(S_IRUSR
| S_IRGRP
| S_IROTH
);
1394 if (chmod (NewFileName
, NewAttr
) != 0) {
1395 Status
= ErrnoToEfiStatus ();
1399 if (OldFileInfo
!= NULL
) {
1403 if (OldFileName
!= NULL
) {
1407 if (NewFileName
!= NULL
) {
1416 Flush data back for the file handle.
1418 @param This Protocol instance pointer.
1420 @retval EFI_SUCCESS Data was written.
1421 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
1422 @retval EFI_NO_MEDIA The device has no media.
1423 @retval EFI_DEVICE_ERROR The device reported an error.
1424 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1425 @retval EFI_WRITE_PROTECTED The device is write protected.
1426 @retval EFI_ACCESS_DENIED The file was open for read only.
1427 @retval EFI_VOLUME_FULL The volume is full.
1432 IN EFI_FILE_PROTOCOL
*This
1435 EMU_EFI_FILE_PRIVATE
*PrivateFile
;
1438 PrivateFile
= EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This
);
1440 if (PrivateFile
->IsDirectoryPath
) {
1441 return EFI_UNSUPPORTED
;
1444 if (PrivateFile
->IsOpenedByRead
) {
1445 return EFI_ACCESS_DENIED
;
1448 if (PrivateFile
->fd
< 0) {
1449 return EFI_DEVICE_ERROR
;
1452 if (fsync (PrivateFile
->fd
) != 0) {
1453 return ErrnoToEfiStatus ();
1462 PosixFileSystmeThunkOpen (
1463 IN EMU_IO_THUNK_PROTOCOL
*This
1466 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*Private
;
1469 if (This
->Private
!= NULL
) {
1470 return EFI_ALREADY_STARTED
;
1473 if (!CompareGuid (This
->Protocol
, &gEfiSimpleFileSystemProtocolGuid
)) {
1474 return EFI_UNSUPPORTED
;
1477 Private
= malloc (sizeof (EMU_SIMPLE_FILE_SYSTEM_PRIVATE
));
1478 if (Private
== NULL
) {
1479 return EFI_OUT_OF_RESOURCES
;
1482 Private
->FilePath
= malloc (StrLen (This
->ConfigString
) + 1);
1483 if (Private
->FilePath
== NULL
) {
1485 return EFI_OUT_OF_RESOURCES
;
1488 // Convert Unicode to Ascii
1489 for (i
= 0; This
->ConfigString
[i
] != 0; i
++) {
1490 Private
->FilePath
[i
] = This
->ConfigString
[i
];
1492 Private
->FilePath
[i
] = 0;
1495 Private
->VolumeLabel
= malloc (StrSize (L
"EFI_EMULATED"));
1496 if (Private
->VolumeLabel
== NULL
) {
1497 free (Private
->FilePath
);
1499 return EFI_OUT_OF_RESOURCES
;
1501 StrCpy (Private
->VolumeLabel
, L
"EFI_EMULATED");
1503 Private
->Signature
= EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE
;
1504 Private
->Thunk
= This
;
1505 CopyMem (&Private
->SimpleFileSystem
, &gPosixFileSystemProtocol
, sizeof (Private
->SimpleFileSystem
));
1506 Private
->FileHandlesOpen
= FALSE
;
1508 This
->Interface
= &Private
->SimpleFileSystem
;
1509 This
->Private
= Private
;
1515 PosixFileSystmeThunkClose (
1516 IN EMU_IO_THUNK_PROTOCOL
*This
1519 EMU_SIMPLE_FILE_SYSTEM_PRIVATE
*Private
;
1521 if (!CompareGuid (This
->Protocol
, &gEfiSimpleFileSystemProtocolGuid
)) {
1522 return EFI_UNSUPPORTED
;
1525 Private
= This
->Private
;
1527 if (Private
->FileHandlesOpen
) {
1529 // Close only supported if all the EFI_FILE_HANDLEs have been closed.
1531 return EFI_NOT_READY
;
1534 if (This
->Private
!= NULL
) {
1535 if (Private
->VolumeLabel
!= NULL
) {
1536 free (Private
->VolumeLabel
);
1538 free (This
->Private
);
1539 This
->Private
= NULL
;
1546 EMU_IO_THUNK_PROTOCOL gPosixFileSystemThunkIo
= {
1547 &gEfiSimpleFileSystemProtocolGuid
,
1551 GasketPosixFileSystmeThunkOpen
,
1552 GasketPosixFileSystmeThunkClose
,