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