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