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