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