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