]> git.proxmox.com Git - mirror_edk2.git/blame - InOsEmuPkg/Unix/Sec/PosixFileSystem.c
InOsEmuPkg: Make XIP work properly
[mirror_edk2.git] / InOsEmuPkg / Unix / Sec / PosixFileSystem.c
CommitLineData
949f388f 1/*++ @file
2 POSIX Pthreads to emulate APs and implement threads
3
4Copyright (c) 2011, Apple Inc. All rights reserved.
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution. The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13
14**/
15
16#include "SecMain.h"
17
18
19#define EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE SIGNATURE_32 ('E', 'P', 'f', 's')
20
21typedef struct {
22 UINTN Signature;
23 EMU_IO_THUNK_PROTOCOL *Thunk;
24 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL SimpleFileSystem;
25 CHAR8 *FilePath;
26 CHAR16 *VolumeLabel;
27 BOOLEAN FileHandlesOpen;
28} EMU_SIMPLE_FILE_SYSTEM_PRIVATE;
29
30#define EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS(a) \
31 CR (a, \
32 EMU_SIMPLE_FILE_SYSTEM_PRIVATE, \
33 SimpleFileSystem, \
34 EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE \
35 )
36
37
38#define EMU_EFI_FILE_PRIVATE_SIGNATURE SIGNATURE_32 ('E', 'P', 'f', 'i')
39
40typedef struct {
41 UINTN Signature;
42 EMU_IO_THUNK_PROTOCOL *Thunk;
43 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
44 EFI_FILE_PROTOCOL EfiFile;
45 int fd;
46 DIR *Dir;
47 BOOLEAN IsRootDirectory;
48 BOOLEAN IsDirectoryPath;
49 BOOLEAN IsOpenedByRead;
50 char *FileName;
51 struct dirent *Dirent;
52} EMU_EFI_FILE_PRIVATE;
53
54#define EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS(a) \
55 CR (a, \
56 EMU_EFI_FILE_PRIVATE, \
57 EfiFile, \
58 EMU_EFI_FILE_PRIVATE_SIGNATURE \
59 )
60
61EFI_STATUS
62PosixFileGetInfo (
63 IN EFI_FILE_PROTOCOL *This,
64 IN EFI_GUID *InformationType,
65 IN OUT UINTN *BufferSize,
66 OUT VOID *Buffer
67 );
68
69EFI_STATUS
70PosixFileSetInfo (
71 IN EFI_FILE_PROTOCOL *This,
72 IN EFI_GUID *InformationType,
73 IN UINTN BufferSize,
74 IN VOID *Buffer
75 );
76
77
78EFI_FILE_PROTOCOL gPosixFileProtocol = {
79 EFI_FILE_REVISION,
80 GasketPosixFileOpen,
81 GasketPosixFileCLose,
82 GasketPosixFileDelete,
83 GasketPosixFileRead,
84 GasketPosixFileWrite,
85 GasketPosixFileGetPossition,
86 GasketPosixFileSetPossition,
87 GasketPosixFileGetInfo,
88 GasketPosixFileSetInfo,
89 GasketPosixFileFlush
90};
91
92EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gPosixFileSystemProtocol = {
93 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
94 GasketPosixOpenVolume,
95};
96
97
98/**
99 Open the root directory on a volume.
100
101 @param This Protocol instance pointer.
102 @param Root Returns an Open file handle for the root directory
103
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.
111
112**/
113EFI_STATUS
114PosixOpenVolume (
115 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
116 OUT EFI_FILE_PROTOCOL **Root
117 )
118{
119 EFI_STATUS Status;
120 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *Private;
121 EMU_EFI_FILE_PRIVATE *PrivateFile;
122
123 Private = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (This);
124
125 Status = EFI_OUT_OF_RESOURCES;
126 PrivateFile = malloc (sizeof (EMU_EFI_FILE_PRIVATE));
127 if (PrivateFile == NULL) {
128 goto Done;
129 }
130
131 PrivateFile->FileName = malloc (AsciiStrSize (Private->FilePath));
132 if (PrivateFile->FileName == NULL) {
133 goto Done;
134 }
135 AsciiStrCpy (PrivateFile->FileName, Private->FilePath);
136
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;
143
144 CopyMem (&PrivateFile->EfiFile, &gPosixFileProtocol, sizeof (EFI_FILE_PROTOCOL));
145
146 PrivateFile->fd = -1;
147 PrivateFile->Dir = NULL;
148 PrivateFile->Dirent = NULL;
149
150 *Root = &PrivateFile->EfiFile;
151
152 PrivateFile->Dir = opendir (PrivateFile->FileName);
153 if (PrivateFile->Dir == NULL) {
154 Status = EFI_ACCESS_DENIED;
155 } else {
156 Status = EFI_SUCCESS;
157 }
158
159Done:
160 if (EFI_ERROR (Status)) {
161 if (PrivateFile != NULL) {
162 if (PrivateFile->FileName != NULL) {
163 free (PrivateFile->FileName);
164 }
165
166 free (PrivateFile);
167 }
168
169 *Root = NULL;
170 }
171
172 return Status;
173}
174
175
176EFI_STATUS
177ErrnoToEfiStatus ()
178{
179 switch (errno) {
180 case EACCES:
181 return EFI_ACCESS_DENIED;
182
183 case EDQUOT:
184 case ENOSPC:
185 return EFI_VOLUME_FULL;
186
187 default:
188 return EFI_DEVICE_ERROR;
189 }
190}
191
192VOID
193CutPrefix (
194 IN CHAR8 *Str,
195 IN UINTN Count
196 )
197{
198 CHAR8 *Pointer;
199
200 if (AsciiStrLen (Str) < Count) {
201 ASSERT (0);
202 }
203
204 for (Pointer = Str; *(Pointer + Count); Pointer++) {
205 *Pointer = *(Pointer + Count);
206 }
207
208 *Pointer = *(Pointer + Count);
209}
210
211
212VOID
213PosixSystemTimeToEfiTime (
214 IN time_t SystemTime,
215 OUT EFI_TIME *Time
216 )
217{
218 struct tm *tm;
219
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;
228
229 Time->TimeZone = timezone;
230 Time->Daylight = (daylight ? EFI_TIME_ADJUST_DAYLIGHT : 0) | (tm->tm_isdst > 0 ? EFI_TIME_IN_DAYLIGHT : 0);
231}
232
233
234EFI_STATUS
235UnixSimpleFileSystemFileInfo (
236 EMU_EFI_FILE_PRIVATE *PrivateFile,
237 IN CHAR8 *FileName,
238 IN OUT UINTN *BufferSize,
239 OUT VOID *Buffer
240 )
241{
242 EFI_STATUS Status;
243 UINTN Size;
244 UINTN NameSize;
245 UINTN ResultSize;
246 EFI_FILE_INFO *Info;
247 CHAR8 *RealFileName;
248 CHAR8 *TempPointer;
249 CHAR16 *BufferFileName;
250 struct stat buf;
251
252 if (FileName != NULL) {
253 RealFileName = FileName;
254 }
255 else if (PrivateFile->IsRootDirectory) {
256 RealFileName = "";
257 } else {
258 RealFileName = PrivateFile->FileName;
259 }
260
261 TempPointer = RealFileName;
262 while (*TempPointer) {
263 if (*TempPointer == '/') {
264 RealFileName = TempPointer + 1;
265 }
266
267 TempPointer++;
268 }
269
270 Size = SIZE_OF_EFI_FILE_INFO;
271 NameSize = AsciiStrSize (RealFileName) * 2;
272 ResultSize = Size + NameSize;
273
274 if (*BufferSize < ResultSize) {
275 *BufferSize = ResultSize;
276 return EFI_BUFFER_TOO_SMALL;
277 }
278 if (stat (FileName == NULL ? PrivateFile->FileName : FileName, &buf) < 0) {
279 return EFI_DEVICE_ERROR;
280 }
281
282 Status = EFI_SUCCESS;
283
284 Info = Buffer;
285 ZeroMem (Info, ResultSize);
286
287 Info->Size = ResultSize;
288 Info->FileSize = buf.st_size;
289 Info->PhysicalSize = MultU64x32 (buf.st_blocks, buf.st_blksize);
290
291 PosixSystemTimeToEfiTime (buf.st_ctime, &Info->CreateTime);
292 PosixSystemTimeToEfiTime (buf.st_atime, &Info->LastAccessTime);
293 PosixSystemTimeToEfiTime (buf.st_mtime, &Info->ModificationTime);
294
295 if (!(buf.st_mode & S_IWUSR)) {
296 Info->Attribute |= EFI_FILE_READ_ONLY;
297 }
298
299 if (S_ISDIR(buf.st_mode)) {
300 Info->Attribute |= EFI_FILE_DIRECTORY;
301 }
302
303
304 BufferFileName = (CHAR16 *)((CHAR8 *) Buffer + Size);
305 while (*RealFileName) {
306 *BufferFileName++ = *RealFileName++;
307 }
308 *BufferFileName = 0;
309
310 *BufferSize = ResultSize;
311 return Status;
312}
313
314BOOLEAN
315IsZero (
316 IN VOID *Buffer,
317 IN UINTN Length
318 )
319{
320 if (Buffer == NULL || Length == 0) {
321 return FALSE;
322 }
323
324 if (*(UINT8 *) Buffer != 0) {
325 return FALSE;
326 }
327
328 if (Length > 1) {
329 if (!CompareMem (Buffer, (UINT8 *) Buffer + 1, Length - 1)) {
330 return FALSE;
331 }
332 }
333
334 return TRUE;
335}
336
337
338
339/**
340 Opens a new file relative to the source file's location.
341
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.
347
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.
357
358**/
359EFI_STATUS
360PosixFileOpen (
361 IN EFI_FILE_PROTOCOL *This,
362 OUT EFI_FILE_PROTOCOL **NewHandle,
363 IN CHAR16 *FileName,
364 IN UINT64 OpenMode,
365 IN UINT64 Attributes
366 )
367{
368 EFI_FILE_PROTOCOL *Root;
369 EMU_EFI_FILE_PRIVATE *PrivateFile;
370 EMU_EFI_FILE_PRIVATE *NewPrivateFile;
371 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;
372 EFI_STATUS Status;
373 CHAR16 *Src;
374 char *Dst;
375 CHAR8 *RealFileName;
376 char *ParseFileName;
377 char *GuardPointer;
378 CHAR8 TempChar;
379 UINTN Count;
380 BOOLEAN TrailingDash;
381 BOOLEAN LoopFinish;
382 UINTN InfoSize;
383 EFI_FILE_INFO *Info;
384 struct stat finfo;
385 int res;
386
387
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;
392
393 //
394 // BUGBUG: assume an open of root
395 // if current location, return current data
396 //
397 if ((StrCmp (FileName, L"\\") == 0) ||
398 (StrCmp (FileName, L".") == 0 && PrivateFile->IsRootDirectory)) {
399OpenRoot:
400 Status = PosixOpenVolume (PrivateFile->SimpleFileSystem, &Root);
401 NewPrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (Root);
402 goto Done;
403 }
404
405 TrailingDash = FALSE;
406 if (FileName[StrLen (FileName) - 1] == L'\\') {
407 TrailingDash = TRUE;
408 FileName[StrLen (FileName) - 1] = 0;
409 }
410
411 //
412 // Attempt to open the file
413 //
414 NewPrivateFile = malloc (sizeof (EMU_EFI_FILE_PRIVATE));
415 if (NewPrivateFile == NULL) {
416 goto Done;
417 }
418
419 CopyMem (NewPrivateFile, PrivateFile, sizeof (EMU_EFI_FILE_PRIVATE));
420
421 NewPrivateFile->FileName = malloc (AsciiStrSize (PrivateFile->FileName) + 1 + StrLen (FileName) + 1);
422 if (NewPrivateFile->FileName == NULL) {
423 goto Done;
424 }
425
426 if (*FileName == L'\\') {
427 AsciiStrCpy (NewPrivateFile->FileName, PrivateRoot->FilePath);
428 // Skip first '\'.
429 Src = FileName + 1;
430 } else {
431 AsciiStrCpy (NewPrivateFile->FileName, PrivateFile->FileName);
432 Src = FileName;
433 }
434 Dst = NewPrivateFile->FileName + AsciiStrLen (NewPrivateFile->FileName);
435 GuardPointer = NewPrivateFile->FileName + AsciiStrLen (PrivateRoot->FilePath);
436 *Dst++ = '/';
437 // Convert unicode to ascii and '\' to '/'
438 while (*Src) {
439 if (*Src == '\\') {
440 *Dst++ = '/';
441 } else {
442 *Dst++ = *Src;
443 }
444 Src++;
445 }
446 *Dst = 0;
447
448
449 //
450 // Get rid of . and .., except leading . or ..
451 //
452
453 //
454 // GuardPointer protect simplefilesystem root path not be destroyed
455 //
456
457 LoopFinish = FALSE;
458 while (!LoopFinish) {
459 LoopFinish = TRUE;
460
461 for (ParseFileName = GuardPointer; *ParseFileName; ParseFileName++) {
462 if (*ParseFileName == '.' &&
463 (*(ParseFileName + 1) == 0 || *(ParseFileName + 1) == '/') &&
464 *(ParseFileName - 1) == '/'
465 ) {
466
467 //
468 // cut /.
469 //
470 CutPrefix (ParseFileName - 1, 2);
471 LoopFinish = FALSE;
472 break;
473 }
474
475 if (*ParseFileName == '.' &&
476 *(ParseFileName + 1) == '.' &&
477 (*(ParseFileName + 2) == 0 || *(ParseFileName + 2) == '/') &&
478 *(ParseFileName - 1) == '/'
479 ) {
480
481 ParseFileName--;
482 Count = 3;
483
484 while (ParseFileName != GuardPointer) {
485 ParseFileName--;
486 Count++;
487 if (*ParseFileName == '/') {
488 break;
489 }
490 }
491
492 //
493 // cut /.. and its left directory
494 //
495 CutPrefix (ParseFileName, Count);
496 LoopFinish = FALSE;
497 break;
498 }
499 }
500 }
501
502 if (AsciiStrCmp (NewPrivateFile->FileName, PrivateRoot->FilePath) == 0) {
503 NewPrivateFile->IsRootDirectory = TRUE;
504 free (NewPrivateFile->FileName);
505 free (NewPrivateFile);
506 goto OpenRoot;
507 }
508
509 RealFileName = NewPrivateFile->FileName + AsciiStrLen(NewPrivateFile->FileName) - 1;
510 while (RealFileName > NewPrivateFile->FileName && *RealFileName != '/') {
511 RealFileName--;
512 }
513
514 TempChar = *(RealFileName - 1);
515 *(RealFileName - 1) = 0;
516 *(RealFileName - 1) = TempChar;
517
518
519 //
520 // Test whether file or directory
521 //
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;
528 } else {
529 NewPrivateFile->IsDirectoryPath = FALSE;
530 }
531 } else {
532 res = stat (NewPrivateFile->FileName, &finfo);
533 if (res == 0 && S_ISDIR(finfo.st_mode)) {
534 NewPrivateFile->IsDirectoryPath = TRUE;
535 } else {
536 NewPrivateFile->IsDirectoryPath = FALSE;
537 }
538 }
539
540 if (OpenMode & EFI_FILE_MODE_WRITE) {
541 NewPrivateFile->IsOpenedByRead = FALSE;
542 } else {
543 NewPrivateFile->IsOpenedByRead = TRUE;
544 }
545
546 Status = EFI_SUCCESS;
547
548 //
549 // deal with directory
550 //
551 if (NewPrivateFile->IsDirectoryPath) {
552 if ((OpenMode & EFI_FILE_MODE_CREATE)) {
553 //
554 // Create a directory
555 //
556 if (mkdir (NewPrivateFile->FileName, 0777) != 0) {
557 if (errno != EEXIST) {
558 //free (TempFileName);
559 Status = EFI_ACCESS_DENIED;
560 goto Done;
561 }
562 }
563 }
564
565 NewPrivateFile->Dir = opendir (NewPrivateFile->FileName);
566 if (NewPrivateFile->Dir == NULL) {
567 if (errno == EACCES) {
568 Status = EFI_ACCESS_DENIED;
569 } else {
570 Status = EFI_NOT_FOUND;
571 }
572
573 goto Done;
574 }
575
576 } else {
577 //
578 // deal with file
579 //
580 NewPrivateFile->fd = open (
581 NewPrivateFile->FileName,
582 ((OpenMode & EFI_FILE_MODE_CREATE) ? O_CREAT : 0) | (NewPrivateFile->IsOpenedByRead ? O_RDONLY : O_RDWR),
583 0666
584 );
585 if (NewPrivateFile->fd < 0) {
586 if (errno == ENOENT) {
587 Status = EFI_NOT_FOUND;
588 } else {
589 Status = EFI_ACCESS_DENIED;
590 }
591 }
592 }
593
594 if ((OpenMode & EFI_FILE_MODE_CREATE) && Status == EFI_SUCCESS) {
595 //
596 // Set the attribute
597 //
598 InfoSize = 0;
599 Info = NULL;
600 Status = PosixFileGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info);
601 if (Status != EFI_BUFFER_TOO_SMALL) {
602 Status = EFI_DEVICE_ERROR;
603 goto Done;
604 }
605
606 Info = malloc (InfoSize);
607 if (Info == NULL) {
608 goto Done;
609 }
610
611 Status = PosixFileGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info);
612 if (EFI_ERROR (Status)) {
613 goto Done;
614 }
615
616 Info->Attribute = Attributes;
617 PosixFileSetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, InfoSize, Info);
618
619 free (Info);
620 }
621
622Done: ;
623 if (TrailingDash) {
624 FileName[StrLen (FileName) + 1] = 0;
625 FileName[StrLen (FileName)] = L'\\';
626 }
627
628 if (EFI_ERROR (Status)) {
629 if (NewPrivateFile) {
630 if (NewPrivateFile->FileName) {
631 free (NewPrivateFile->FileName);
632 }
633
634 free (NewPrivateFile);
635 }
636 } else {
637 *NewHandle = &NewPrivateFile->EfiFile;
638 }
639
640 return Status;
641}
642
643
644
645/**
646 Close the file handle
647
648 @param This Protocol instance pointer.
649
650 @retval EFI_SUCCESS The device was opened.
651
652**/
653EFI_STATUS
654PosixFileCLose (
655 IN EFI_FILE_PROTOCOL *This
656 )
657{
658 EMU_EFI_FILE_PRIVATE *PrivateFile;
659
660 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
661
662 if (PrivateFile->fd >= 0) {
663 close (PrivateFile->fd);
664 }
665 if (PrivateFile->Dir != NULL) {
666 closedir (PrivateFile->Dir);
667 }
668
669 PrivateFile->fd = -1;
670 PrivateFile->Dir = NULL;
671
672 if (PrivateFile->FileName) {
673 free (PrivateFile->FileName);
674 }
675
676 free (PrivateFile);
677
678 return EFI_SUCCESS;
679}
680
681
682/**
683 Close and delete the file handle.
684
685 @param This Protocol instance pointer.
686
687 @retval EFI_SUCCESS The device was opened.
688 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.
689
690**/
691EFI_STATUS
692PosixFileDelete (
693 IN EFI_FILE_PROTOCOL *This
694 )
695{
696 EFI_STATUS Status;
697 EMU_EFI_FILE_PRIVATE *PrivateFile;
698
699 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
700 Status = EFI_WARN_DELETE_FAILURE;
701
702 if (PrivateFile->IsDirectoryPath) {
703 if (PrivateFile->Dir != NULL) {
704 closedir (PrivateFile->Dir);
705 PrivateFile->Dir = NULL;
706 }
707
708 if (rmdir (PrivateFile->FileName) == 0) {
709 Status = EFI_SUCCESS;
710 }
711 } else {
712 close (PrivateFile->fd);
713 PrivateFile->fd = -1;
714
715 if (!PrivateFile->IsOpenedByRead) {
716 if (!unlink (PrivateFile->FileName)) {
717 Status = EFI_SUCCESS;
718 }
719 }
720 }
721
722 free (PrivateFile->FileName);
723 free (PrivateFile);
724
725 return Status;
726}
727
728
729/**
730 Read data from the file.
731
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.
735
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.
741
742**/
743EFI_STATUS
744PosixFileRead (
745 IN EFI_FILE_PROTOCOL *This,
746 IN OUT UINTN *BufferSize,
747 OUT VOID *Buffer
748 )
749{
750 EMU_EFI_FILE_PRIVATE *PrivateFile;
751 EFI_STATUS Status;
752 int Res;
753 UINTN Size;
754 UINTN NameSize;
755 UINTN ResultSize;
756 CHAR8 *FullFileName;
757
758
759 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
760
761 if (!PrivateFile->IsDirectoryPath) {
762 if (PrivateFile->fd < 0) {
763 Status = EFI_DEVICE_ERROR;
764 goto Done;
765 }
766
767 Res = read (PrivateFile->fd, Buffer, *BufferSize);
768 if (Res < 0) {
769 Status = EFI_DEVICE_ERROR;
770 goto Done;
771 }
772 *BufferSize = Res;
773 Status = EFI_SUCCESS;
774 goto Done;
775 }
776
777 //
778 // Read on a directory.
779 //
780 if (PrivateFile->Dir == NULL) {
781 Status = EFI_DEVICE_ERROR;
782 goto Done;
783 }
784
785 if (PrivateFile->Dirent == NULL) {
786 PrivateFile->Dirent = readdir (PrivateFile->Dir);
787 if (PrivateFile->Dirent == NULL) {
788 *BufferSize = 0;
789 Status = EFI_SUCCESS;
790 goto Done;
791 }
792 }
793
794 Size = SIZE_OF_EFI_FILE_INFO;
795 NameSize = AsciiStrLen (PrivateFile->Dirent->d_name) + 1;
796 ResultSize = Size + 2 * NameSize;
797
798 if (*BufferSize < ResultSize) {
799 *BufferSize = ResultSize;
800 Status = EFI_BUFFER_TOO_SMALL;
801 goto Done;
802 }
803 Status = EFI_SUCCESS;
804
805 *BufferSize = ResultSize;
806
807 FullFileName = malloc (AsciiStrLen(PrivateFile->FileName) + 1 + NameSize);
808 if (FullFileName == NULL) {
809 Status = EFI_OUT_OF_RESOURCES;
810 goto Done;
811 }
812
813 AsciiStrCpy (FullFileName, PrivateFile->FileName);
814 AsciiStrCat (FullFileName, "/");
815 AsciiStrCat (FullFileName, PrivateFile->Dirent->d_name);
816 Status = UnixSimpleFileSystemFileInfo (
817 PrivateFile,
818 FullFileName,
819 BufferSize,
820 Buffer
821 );
822 free (FullFileName);
823
824 PrivateFile->Dirent = NULL;
825
826Done:
827 return Status;
828}
829
830
831
832/**
833 Write data to a file.
834
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.
838
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.
848
849**/
850EFI_STATUS
851PosixFileWrite (
852 IN EFI_FILE_PROTOCOL *This,
853 IN OUT UINTN *BufferSize,
854 IN VOID *Buffer
855 )
856{
857 EMU_EFI_FILE_PRIVATE *PrivateFile;
858 int Res;
859
860
861 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
862
863 if (PrivateFile->fd < 0) {
864 return EFI_DEVICE_ERROR;
865 }
866
867 if (PrivateFile->IsDirectoryPath) {
868 return EFI_UNSUPPORTED;
869 }
870
871 if (PrivateFile->IsOpenedByRead) {
872 return EFI_ACCESS_DENIED;
873 }
874
875 Res = write (PrivateFile->fd, Buffer, *BufferSize);
876 if (Res == (UINTN)-1) {
877 return ErrnoToEfiStatus ();
878 }
879
880 *BufferSize = Res;
881 return EFI_SUCCESS;
882}
883
884
885
886/**
887 Set a files current position
888
889 @param This Protocol instance pointer.
890 @param Position Byte position from the start of the file.
891
892 @retval EFI_SUCCESS Data was written.
893 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
894
895**/
896EFI_STATUS
897PosixFileSetPossition (
898 IN EFI_FILE_PROTOCOL *This,
899 IN UINT64 Position
900 )
901{
902 EMU_EFI_FILE_PRIVATE *PrivateFile;
903 off_t Pos;
904
905 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
906
907 if (PrivateFile->IsDirectoryPath) {
908 if (Position != 0) {
909 return EFI_UNSUPPORTED;
910 }
911
912 if (PrivateFile->Dir == NULL) {
913 return EFI_DEVICE_ERROR;
914 }
915 rewinddir (PrivateFile->Dir);
916 return EFI_SUCCESS;
917 } else {
918 if (Position == (UINT64) -1) {
919 Pos = lseek (PrivateFile->fd, 0, SEEK_END);
920 } else {
921 Pos = lseek (PrivateFile->fd, Position, SEEK_SET);
922 }
923 if (Pos == (off_t)-1) {
924 return ErrnoToEfiStatus ();
925 }
926 return EFI_SUCCESS;
927 }
928}
929
930
931
932/**
933 Get a file's current position
934
935 @param This Protocol instance pointer.
936 @param Position Byte position from the start of the file.
937
938 @retval EFI_SUCCESS Data was written.
939 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..
940
941**/
942EFI_STATUS
943PosixFileGetPossition (
944 IN EFI_FILE_PROTOCOL *This,
945 OUT UINT64 *Position
946 )
947{
948 EFI_STATUS Status;
949 EMU_EFI_FILE_PRIVATE *PrivateFile;
950
951 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
952
953 if (PrivateFile->IsDirectoryPath) {
954 Status = EFI_UNSUPPORTED;
955 } else {
956 *Position = (UINT64)lseek (PrivateFile->fd, 0, SEEK_CUR);
957 Status = (*Position == (UINT64) -1) ? ErrnoToEfiStatus () : EFI_SUCCESS;
958 }
959
960 return Status;
961}
962
963
964/**
965 Get information about a file.
966
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.
971
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.
980
981**/
982EFI_STATUS
983PosixFileGetInfo (
984 IN EFI_FILE_PROTOCOL *This,
985 IN EFI_GUID *InformationType,
986 IN OUT UINTN *BufferSize,
987 OUT VOID *Buffer
988 )
989{
990 EFI_STATUS Status;
991 EMU_EFI_FILE_PRIVATE *PrivateFile;
992 EFI_FILE_SYSTEM_INFO *FileSystemInfoBuffer;
993 int UnixStatus;
994 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;
995 struct statfs buf;
996
997 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
998 PrivateRoot = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);
999
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;
1007 }
1008
1009 UnixStatus = statfs (PrivateFile->FileName, &buf);
1010 if (UnixStatus < 0) {
1011 return EFI_DEVICE_ERROR;
1012 }
1013
1014 FileSystemInfoBuffer = (EFI_FILE_SYSTEM_INFO *) Buffer;
1015 FileSystemInfoBuffer->Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);
1016 FileSystemInfoBuffer->ReadOnly = FALSE;
1017
1018 //
1019 // Succeeded
1020 //
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;
1024
1025
1026 StrCpy ((CHAR16 *) FileSystemInfoBuffer->VolumeLabel, PrivateRoot->VolumeLabel);
1027 *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);
1028
1029 } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
1030 if (*BufferSize < StrSize (PrivateRoot->VolumeLabel)) {
1031 *BufferSize = StrSize (PrivateRoot->VolumeLabel);
1032 return EFI_BUFFER_TOO_SMALL;
1033 }
1034
1035 StrCpy ((CHAR16 *) Buffer, PrivateRoot->VolumeLabel);
1036 *BufferSize = StrSize (PrivateRoot->VolumeLabel);
1037
1038 }
1039
1040 return Status;
1041}
1042
1043
1044/**
1045 Set information about a file
1046
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.
1051
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.
1059
1060**/
1061EFI_STATUS
1062PosixFileSetInfo (
1063 IN EFI_FILE_PROTOCOL *This,
1064 IN EFI_GUID *InformationType,
1065 IN UINTN BufferSize,
1066 IN VOID *Buffer
1067 )
1068{
1069 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;
1070 EMU_EFI_FILE_PRIVATE *PrivateFile;
1071 EFI_FILE_INFO *OldFileInfo;
1072 EFI_FILE_INFO *NewFileInfo;
1073 EFI_STATUS Status;
1074 UINTN OldInfoSize;
1075 mode_t NewAttr;
1076 struct stat OldAttr;
1077 CHAR8 *OldFileName;
1078 CHAR8 *NewFileName;
1079 CHAR8 *CharPointer;
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;
1089 int UnixStatus;
1090 struct utimbuf Utime;
1091
1092
1093 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
1094 PrivateRoot = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);
1095 errno = 0;
1096 Status = EFI_UNSUPPORTED;
1097 OldFileInfo = NewFileInfo = NULL;
1098 OldFileName = NewFileName = NULL;
1099 AttrChangeFlag = NameChangeFlag = SizeChangeFlag = TimeChangeFlag = FALSE;
1100
1101 //
1102 // Set file system information.
1103 //
1104 if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
1105 if (BufferSize < (SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel))) {
1106 Status = EFI_BAD_BUFFER_SIZE;
1107 goto Done;
1108 }
1109
1110 NewFileSystemInfo = (EFI_FILE_SYSTEM_INFO *) Buffer;
1111
1112 free (PrivateRoot->VolumeLabel);
1113
1114 PrivateRoot->VolumeLabel = malloc (StrSize (NewFileSystemInfo->VolumeLabel));
1115 if (PrivateRoot->VolumeLabel == NULL) {
1116 goto Done;
1117 }
1118
1119 StrCpy (PrivateRoot->VolumeLabel, NewFileSystemInfo->VolumeLabel);
1120
1121 Status = EFI_SUCCESS;
1122 goto Done;
1123 }
1124
1125 //
1126 // Set volume label information.
1127 //
1128 if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
1129 if (BufferSize < StrSize (PrivateRoot->VolumeLabel)) {
1130 Status = EFI_BAD_BUFFER_SIZE;
1131 goto Done;
1132 }
1133
1134 StrCpy (PrivateRoot->VolumeLabel, (CHAR16 *) Buffer);
1135
1136 Status = EFI_SUCCESS;
1137 goto Done;
1138 }
1139
1140 if (!CompareGuid (InformationType, &gEfiFileInfoGuid)) {
1141 Status = EFI_UNSUPPORTED;
1142 goto Done;
1143 }
1144
1145 if (BufferSize < SIZE_OF_EFI_FILE_INFO) {
1146 Status = EFI_BAD_BUFFER_SIZE;
1147 goto Done;
1148 }
1149
1150 //
1151 // Set file/directory information.
1152 //
1153
1154 //
1155 // Check for invalid set file information parameters.
1156 //
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)
1161 ) {
1162 Status = EFI_INVALID_PARAMETER;
1163 goto Done;
1164 }
1165
1166 //
1167 // Get current file information so we can determine what kind
1168 // of change request this is.
1169 //
1170 OldInfoSize = 0;
1171 Status = UnixSimpleFileSystemFileInfo (PrivateFile, NULL, &OldInfoSize, NULL);
1172 if (Status != EFI_BUFFER_TOO_SMALL) {
1173 Status = EFI_DEVICE_ERROR;
1174 goto Done;
1175 }
1176
1177 OldFileInfo = malloc (OldInfoSize);
1178 if (OldFileInfo == NULL) {
1179 goto Done;
1180 }
1181
1182 Status = UnixSimpleFileSystemFileInfo (PrivateFile, NULL, &OldInfoSize, OldFileInfo);
1183 if (EFI_ERROR (Status)) {
1184 goto Done;
1185 }
1186
1187 OldFileName = malloc (AsciiStrSize (PrivateFile->FileName));
1188 if (OldFileInfo == NULL) {
1189 goto Done;
1190 }
1191
1192 AsciiStrCpy (OldFileName, PrivateFile->FileName);
1193
1194 //
1195 // Make full pathname from new filename and rootpath.
1196 //
1197 if (NewFileInfo->FileName[0] == '\\') {
1198 NewFileName = malloc (AsciiStrLen (PrivateRoot->FilePath) + 1 + StrLen (NewFileInfo->FileName) + 1);
1199 if (NewFileName == NULL) {
1200 goto Done;
1201 }
1202
1203 AsciiStrCpy (NewFileName, PrivateRoot->FilePath);
1204 AsciiFilePtr = NewFileName + AsciiStrLen(NewFileName);
1205 UnicodeFilePtr = NewFileInfo->FileName + 1;
1206 *AsciiFilePtr++ ='/';
1207 } else {
1208 NewFileName = malloc (AsciiStrLen (PrivateFile->FileName) + 2 + StrLen (NewFileInfo->FileName) + 1);
1209 if (NewFileName == NULL) {
1210 goto Done;
1211 }
1212
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';
1219 AsciiFilePtr++;
1220 }
1221 UnicodeFilePtr = NewFileInfo->FileName;
1222 }
1223 // Convert to ascii.
1224 while (*UnicodeFilePtr) {
1225 *AsciiFilePtr++ = *UnicodeFilePtr++;
1226 }
1227 *AsciiFilePtr = 0;
1228
1229 //
1230 // Is there an attribute change request?
1231 //
1232 if (NewFileInfo->Attribute != OldFileInfo->Attribute) {
1233 if ((NewFileInfo->Attribute & EFI_FILE_DIRECTORY) != (OldFileInfo->Attribute & EFI_FILE_DIRECTORY)) {
1234 Status = EFI_INVALID_PARAMETER;
1235 goto Done;
1236 }
1237
1238 AttrChangeFlag = TRUE;
1239 }
1240
1241 //
1242 // Is there a name change request?
1243 // bugbug: - Should really use EFI_UNICODE_COLLATION_PROTOCOL
1244 //
1245 if (StrCmp (NewFileInfo->FileName, OldFileInfo->FileName)) {
1246 NameChangeFlag = TRUE;
1247 }
1248
1249 //
1250 // Is there a size change request?
1251 //
1252 if (NewFileInfo->FileSize != OldFileInfo->FileSize) {
1253 SizeChangeFlag = TRUE;
1254 }
1255
1256 //
1257 // Is there a time stamp change request?
1258 //
1259 if (!IsZero (&NewFileInfo->CreateTime, sizeof (EFI_TIME)) &&
1260 CompareMem (&NewFileInfo->CreateTime, &OldFileInfo->CreateTime, sizeof (EFI_TIME))
1261 ) {
1262 TimeChangeFlag = TRUE;
1263 } else if (!IsZero (&NewFileInfo->LastAccessTime, sizeof (EFI_TIME)) &&
1264 CompareMem (&NewFileInfo->LastAccessTime, &OldFileInfo->LastAccessTime, sizeof (EFI_TIME))
1265 ) {
1266 TimeChangeFlag = TRUE;
1267 } else if (!IsZero (&NewFileInfo->ModificationTime, sizeof (EFI_TIME)) &&
1268 CompareMem (&NewFileInfo->ModificationTime, &OldFileInfo->ModificationTime, sizeof (EFI_TIME))
1269 ) {
1270 TimeChangeFlag = TRUE;
1271 }
1272
1273 //
1274 // All done if there are no change requests being made.
1275 //
1276 if (!(AttrChangeFlag || NameChangeFlag || SizeChangeFlag || TimeChangeFlag)) {
1277 Status = EFI_SUCCESS;
1278 goto Done;
1279 }
1280
1281 //
1282 // Set file or directory information.
1283 //
1284 if (stat (OldFileName, &OldAttr) != 0) {
1285 Status = ErrnoToEfiStatus ();
1286 goto Done;
1287 }
1288
1289 //
1290 // Name change.
1291 //
1292 if (NameChangeFlag) {
1293 //
1294 // Close the handles first
1295 //
1296 if (PrivateFile->IsOpenedByRead) {
1297 Status = EFI_ACCESS_DENIED;
1298 goto Done;
1299 }
1300
1301 for (CharPointer = NewFileName; *CharPointer != 0 && *CharPointer != L'/'; CharPointer++) {
1302 }
1303
1304 if (*CharPointer != 0) {
1305 Status = EFI_ACCESS_DENIED;
1306 goto Done;
1307 }
1308
1309 UnixStatus = rename (OldFileName, NewFileName);
1310 if (UnixStatus == 0) {
1311 //
1312 // modify file name
1313 //
1314 free (PrivateFile->FileName);
1315
1316 PrivateFile->FileName = malloc (AsciiStrSize (NewFileName));
1317 if (PrivateFile->FileName == NULL) {
1318 goto Done;
1319 }
1320
1321 AsciiStrCpy (PrivateFile->FileName, NewFileName);
1322 } else {
1323 Status = EFI_DEVICE_ERROR;
1324 goto Done;
1325 }
1326 }
1327
1328 //
1329 // Size change
1330 //
1331 if (SizeChangeFlag) {
1332 if (PrivateFile->IsDirectoryPath) {
1333 Status = EFI_UNSUPPORTED;
1334 goto Done;
1335 }
1336
1337 if (PrivateFile->IsOpenedByRead || OldFileInfo->Attribute & EFI_FILE_READ_ONLY) {
1338 Status = EFI_ACCESS_DENIED;
1339 goto Done;
1340 }
1341
1342 if (ftruncate (PrivateFile->fd, NewFileInfo->FileSize) != 0) {
1343 Status = ErrnoToEfiStatus ();
1344 goto Done;
1345 }
1346
1347 }
1348
1349 //
1350 // Time change
1351 //
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;
1360
1361 Utime.actime = mktime (&NewLastAccessSystemTime);
1362
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;
1370
1371 Utime.modtime = mktime (&NewLastWriteSystemTime);
1372
1373 if (Utime.actime == (time_t)-1 || Utime.modtime == (time_t)-1) {
1374 goto Done;
1375 }
1376
1377 if (utime (PrivateFile->FileName, &Utime) == -1) {
1378 Status = ErrnoToEfiStatus ();
1379 goto Done;
1380 }
1381 }
1382
1383 //
1384 // No matter about AttrChangeFlag, Attribute must be set.
1385 // Because operation before may cause attribute change.
1386 //
1387 NewAttr = OldAttr.st_mode;
1388
1389 if (NewFileInfo->Attribute & EFI_FILE_READ_ONLY) {
1390 NewAttr &= ~(S_IRUSR | S_IRGRP | S_IROTH);
1391 } else {
1392 NewAttr |= S_IRUSR;
1393 }
1394
1395 if (chmod (NewFileName, NewAttr) != 0) {
1396 Status = ErrnoToEfiStatus ();
1397 }
1398
1399Done:
1400 if (OldFileInfo != NULL) {
1401 free (OldFileInfo);
1402 }
1403
1404 if (OldFileName != NULL) {
1405 free (OldFileName);
1406 }
1407
1408 if (NewFileName != NULL) {
1409 free (NewFileName);
1410 }
1411
1412 return Status;
1413}
1414
1415
1416/**
1417 Flush data back for the file handle.
1418
1419 @param This Protocol instance pointer.
1420
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.
1429
1430**/
1431EFI_STATUS
1432PosixFileFlush (
1433 IN EFI_FILE_PROTOCOL *This
1434 )
1435{
1436 EMU_EFI_FILE_PRIVATE *PrivateFile;
1437
1438
1439 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
1440
1441 if (PrivateFile->IsDirectoryPath) {
1442 return EFI_UNSUPPORTED;
1443 }
1444
1445 if (PrivateFile->IsOpenedByRead) {
1446 return EFI_ACCESS_DENIED;
1447 }
1448
1449 if (PrivateFile->fd < 0) {
1450 return EFI_DEVICE_ERROR;
1451 }
1452
1453 if (fsync (PrivateFile->fd) != 0) {
1454 return ErrnoToEfiStatus ();
1455 }
1456
1457 return EFI_SUCCESS;
1458}
1459
1460
1461
1462EFI_STATUS
1463PosixFileSystmeThunkOpen (
1464 IN EMU_IO_THUNK_PROTOCOL *This
1465 )
1466{
1467 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *Private;
1468 UINTN i;
1469
1470 if (This->Private != NULL) {
1471 return EFI_ALREADY_STARTED;
1472 }
1473
1474 if (!CompareGuid (This->Protocol, &gEfiSimpleFileSystemProtocolGuid)) {
1475 return EFI_UNSUPPORTED;
1476 }
1477
1478 Private = malloc (sizeof (EMU_SIMPLE_FILE_SYSTEM_PRIVATE));
1479 if (Private == NULL) {
1480 return EFI_OUT_OF_RESOURCES;
1481 }
1482
1483 Private->FilePath = malloc (StrLen (This->ConfigString) + 1);
1484 if (Private->FilePath == NULL) {
1485 free (Private);
1486 return EFI_OUT_OF_RESOURCES;
1487 }
1488
1489 // Convert Unicode to Ascii
1490 for (i = 0; This->ConfigString[i] != 0; i++) {
1491 Private->FilePath[i] = This->ConfigString[i];
1492 }
1493 Private->FilePath[i] = 0;
1494
1495
0c493bf4 1496 Private->VolumeLabel = malloc (StrSize (L"EFI_EMULATED"));
949f388f 1497 if (Private->VolumeLabel == NULL) {
1498 free (Private->FilePath);
1499 free (Private);
1500 return EFI_OUT_OF_RESOURCES;
1501 }
1502 StrCpy (Private->VolumeLabel, L"EFI_EMULATED");
1503
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;
1508
1509 This->Interface = &Private->SimpleFileSystem;
1510 This->Private = Private;
1511 return EFI_SUCCESS;
1512}
1513
1514
1515EFI_STATUS
1516PosixFileSystmeThunkClose (
1517 IN EMU_IO_THUNK_PROTOCOL *This
1518 )
1519{
1520 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *Private;
1521
1522 if (!CompareGuid (This->Protocol, &gEfiSimpleFileSystemProtocolGuid)) {
1523 return EFI_UNSUPPORTED;
1524 }
1525
1526 Private = This->Private;
1527
1528 if (Private->FileHandlesOpen) {
1529 //
1530 // Close only supported if all the EFI_FILE_HANDLEs have been closed.
1531 //
1532 return EFI_NOT_READY;
1533 }
1534
1535 if (This->Private != NULL) {
033d0e5f 1536 if (Private->VolumeLabel != NULL) {
949f388f 1537 free (Private->VolumeLabel);
1538 }
1539 free (This->Private);
1540 }
1541
1542 return EFI_SUCCESS;
1543}
1544
1545
1546EMU_IO_THUNK_PROTOCOL gPosixFileSystemThunkIo = {
1547 &gEfiSimpleFileSystemProtocolGuid,
1548 NULL,
1549 NULL,
1550 0,
1551 GasketPosixFileSystmeThunkOpen,
1552 GasketPosixFileSystmeThunkClose,
1553 NULL
1554};
1555
1556