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 "Host.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
PosixOpenVolume(IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL * This,OUT EFI_FILE_PROTOCOL ** Root)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
ErrnoToEfiStatus()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
CutPrefix(IN CHAR8 * Str,IN UINTN Count)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
PosixSystemTimeToEfiTime(IN time_t SystemTime,OUT EFI_TIME * Time)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
UnixSimpleFileSystemFileInfo(EMU_EFI_FILE_PRIVATE * PrivateFile,IN CHAR8 * FileName,IN OUT UINTN * BufferSize,OUT VOID * Buffer)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 } else if (PrivateFile->IsRootDirectory) {
255 RealFileName = "";
256 } else {
257 RealFileName = PrivateFile->FileName;
258 }
259
260 TempPointer = RealFileName;
261 while (*TempPointer) {
262 if (*TempPointer == '/') {
263 RealFileName = TempPointer + 1;
264 }
265
266 TempPointer++;
267 }
268
269 Size = SIZE_OF_EFI_FILE_INFO;
270 NameSize = AsciiStrSize (RealFileName) * 2;
271 ResultSize = Size + NameSize;
272
273 if (*BufferSize < ResultSize) {
274 *BufferSize = ResultSize;
275 return EFI_BUFFER_TOO_SMALL;
276 }
277 if (stat (FileName == NULL ? PrivateFile->FileName : FileName, &buf) < 0) {
278 return EFI_DEVICE_ERROR;
279 }
280
281 Status = EFI_SUCCESS;
282
283 Info = Buffer;
284 ZeroMem (Info, ResultSize);
285
286 Info->Size = ResultSize;
287 Info->FileSize = buf.st_size;
288 Info->PhysicalSize = MultU64x32 (buf.st_blocks, buf.st_blksize);
289
290 PosixSystemTimeToEfiTime (buf.st_ctime, &Info->CreateTime);
291 PosixSystemTimeToEfiTime (buf.st_atime, &Info->LastAccessTime);
292 PosixSystemTimeToEfiTime (buf.st_mtime, &Info->ModificationTime);
293
294 if (!(buf.st_mode & S_IWUSR)) {
295 Info->Attribute |= EFI_FILE_READ_ONLY;
296 }
297
298 if (S_ISDIR(buf.st_mode)) {
299 Info->Attribute |= EFI_FILE_DIRECTORY;
300 }
301
302
303 BufferFileName = (CHAR16 *)((CHAR8 *) Buffer + Size);
304 while (*RealFileName) {
305 *BufferFileName++ = *RealFileName++;
306 }
307 *BufferFileName = 0;
308
309 *BufferSize = ResultSize;
310 return Status;
311 }
312
313 BOOLEAN
IsZero(IN VOID * Buffer,IN UINTN Length)314 IsZero (
315 IN VOID *Buffer,
316 IN UINTN Length
317 )
318 {
319 if (Buffer == NULL || Length == 0) {
320 return FALSE;
321 }
322
323 if (*(UINT8 *) Buffer != 0) {
324 return FALSE;
325 }
326
327 if (Length > 1) {
328 if (!CompareMem (Buffer, (UINT8 *) Buffer + 1, Length - 1)) {
329 return FALSE;
330 }
331 }
332
333 return TRUE;
334 }
335
336
337
338 /**
339 Opens a new file relative to the source file's location.
340
341 @param This The protocol instance pointer.
342 @param NewHandle Returns File Handle for FileName.
343 @param FileName Null terminated string. "\", ".", and ".." are supported.
344 @param OpenMode Open mode for file.
345 @param Attributes Only used for EFI_FILE_MODE_CREATE.
346
347 @retval EFI_SUCCESS The device was opened.
348 @retval EFI_NOT_FOUND The specified file could not be found on the device.
349 @retval EFI_NO_MEDIA The device has no media.
350 @retval EFI_MEDIA_CHANGED The media has changed.
351 @retval EFI_DEVICE_ERROR The device reported an error.
352 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
353 @retval EFI_ACCESS_DENIED The service denied access to the file.
354 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
355 @retval EFI_VOLUME_FULL The volume is full.
356
357 **/
358 EFI_STATUS
PosixFileOpen(IN EFI_FILE_PROTOCOL * This,OUT EFI_FILE_PROTOCOL ** NewHandle,IN CHAR16 * FileName,IN UINT64 OpenMode,IN UINT64 Attributes)359 PosixFileOpen (
360 IN EFI_FILE_PROTOCOL *This,
361 OUT EFI_FILE_PROTOCOL **NewHandle,
362 IN CHAR16 *FileName,
363 IN UINT64 OpenMode,
364 IN UINT64 Attributes
365 )
366 {
367 EFI_FILE_PROTOCOL *Root;
368 EMU_EFI_FILE_PRIVATE *PrivateFile;
369 EMU_EFI_FILE_PRIVATE *NewPrivateFile;
370 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;
371 EFI_STATUS Status;
372 CHAR16 *Src;
373 char *Dst;
374 CHAR8 *RealFileName;
375 char *ParseFileName;
376 char *GuardPointer;
377 CHAR8 TempChar;
378 UINTN Count;
379 BOOLEAN TrailingDash;
380 BOOLEAN LoopFinish;
381 UINTN InfoSize;
382 EFI_FILE_INFO *Info;
383 struct stat finfo;
384 int res;
385
386
387 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
388 PrivateRoot = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);
389 NewPrivateFile = NULL;
390 Status = EFI_OUT_OF_RESOURCES;
391
392 //
393 // BUGBUG: assume an open of root
394 // if current location, return current data
395 //
396 TrailingDash = FALSE;
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 if (FileName[StrLen (FileName) - 1] == L'\\') {
406 TrailingDash = TRUE;
407 FileName[StrLen (FileName) - 1] = 0;
408 }
409
410 //
411 // Attempt to open the file
412 //
413 NewPrivateFile = malloc (sizeof (EMU_EFI_FILE_PRIVATE));
414 if (NewPrivateFile == NULL) {
415 goto Done;
416 }
417
418 CopyMem (NewPrivateFile, PrivateFile, sizeof (EMU_EFI_FILE_PRIVATE));
419
420 NewPrivateFile->FileName = malloc (AsciiStrSize (PrivateFile->FileName) + 1 + StrLen (FileName) + 1);
421 if (NewPrivateFile->FileName == NULL) {
422 goto Done;
423 }
424
425 if (*FileName == L'\\') {
426 AsciiStrCpy (NewPrivateFile->FileName, PrivateRoot->FilePath);
427 // Skip first '\'.
428 Src = FileName + 1;
429 } else {
430 AsciiStrCpy (NewPrivateFile->FileName, 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
PosixFileCLose(IN EFI_FILE_PROTOCOL * This)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
PosixFileDelete(IN EFI_FILE_PROTOCOL * This)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
PosixFileRead(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,OUT VOID * Buffer)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
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 FullFileName = malloc (AsciiStrLen(PrivateFile->FileName) + 1 + NameSize);
807 if (FullFileName == NULL) {
808 Status = EFI_OUT_OF_RESOURCES;
809 goto Done;
810 }
811
812 AsciiStrCpy (FullFileName, PrivateFile->FileName);
813 AsciiStrCat (FullFileName, "/");
814 AsciiStrCat (FullFileName, PrivateFile->Dirent->d_name);
815 Status = UnixSimpleFileSystemFileInfo (
816 PrivateFile,
817 FullFileName,
818 BufferSize,
819 Buffer
820 );
821 free (FullFileName);
822
823 PrivateFile->Dirent = NULL;
824
825 Done:
826 return Status;
827 }
828
829
830
831 /**
832 Write data to a file.
833
834 @param This Protocol instance pointer.
835 @param BufferSize On input size of buffer, on output amount of data in buffer.
836 @param Buffer The buffer in which data to write.
837
838 @retval EFI_SUCCESS Data was written.
839 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
840 @retval EFI_NO_MEDIA The device has no media.
841 @retval EFI_DEVICE_ERROR The device reported an error.
842 @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
843 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
844 @retval EFI_WRITE_PROTECTED The device is write protected.
845 @retval EFI_ACCESS_DENIED The file was open for read only.
846 @retval EFI_VOLUME_FULL The volume is full.
847
848 **/
849 EFI_STATUS
PosixFileWrite(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,IN VOID * Buffer)850 PosixFileWrite (
851 IN EFI_FILE_PROTOCOL *This,
852 IN OUT UINTN *BufferSize,
853 IN VOID *Buffer
854 )
855 {
856 EMU_EFI_FILE_PRIVATE *PrivateFile;
857 int Res;
858
859
860 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
861
862 if (PrivateFile->fd < 0) {
863 return EFI_DEVICE_ERROR;
864 }
865
866 if (PrivateFile->IsDirectoryPath) {
867 return EFI_UNSUPPORTED;
868 }
869
870 if (PrivateFile->IsOpenedByRead) {
871 return EFI_ACCESS_DENIED;
872 }
873
874 Res = write (PrivateFile->fd, Buffer, *BufferSize);
875 if (Res == (UINTN)-1) {
876 return ErrnoToEfiStatus ();
877 }
878
879 *BufferSize = Res;
880 return EFI_SUCCESS;
881 }
882
883
884
885 /**
886 Set a files current position
887
888 @param This Protocol instance pointer.
889 @param Position Byte position from the start of the file.
890
891 @retval EFI_SUCCESS Data was written.
892 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
893
894 **/
895 EFI_STATUS
PosixFileSetPossition(IN EFI_FILE_PROTOCOL * This,IN UINT64 Position)896 PosixFileSetPossition (
897 IN EFI_FILE_PROTOCOL *This,
898 IN UINT64 Position
899 )
900 {
901 EMU_EFI_FILE_PRIVATE *PrivateFile;
902 off_t Pos;
903
904 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
905
906 if (PrivateFile->IsDirectoryPath) {
907 if (Position != 0) {
908 return EFI_UNSUPPORTED;
909 }
910
911 if (PrivateFile->Dir == NULL) {
912 return EFI_DEVICE_ERROR;
913 }
914 rewinddir (PrivateFile->Dir);
915 return EFI_SUCCESS;
916 } else {
917 if (Position == (UINT64) -1) {
918 Pos = lseek (PrivateFile->fd, 0, SEEK_END);
919 } else {
920 Pos = lseek (PrivateFile->fd, Position, SEEK_SET);
921 }
922 if (Pos == (off_t)-1) {
923 return ErrnoToEfiStatus ();
924 }
925 return EFI_SUCCESS;
926 }
927 }
928
929
930
931 /**
932 Get a file's current position
933
934 @param This Protocol instance pointer.
935 @param Position Byte position from the start of the file.
936
937 @retval EFI_SUCCESS Data was written.
938 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..
939
940 **/
941 EFI_STATUS
PosixFileGetPossition(IN EFI_FILE_PROTOCOL * This,OUT UINT64 * Position)942 PosixFileGetPossition (
943 IN EFI_FILE_PROTOCOL *This,
944 OUT UINT64 *Position
945 )
946 {
947 EFI_STATUS Status;
948 EMU_EFI_FILE_PRIVATE *PrivateFile;
949
950 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
951
952 if (PrivateFile->IsDirectoryPath) {
953 Status = EFI_UNSUPPORTED;
954 } else {
955 *Position = (UINT64)lseek (PrivateFile->fd, 0, SEEK_CUR);
956 Status = (*Position == (UINT64) -1) ? ErrnoToEfiStatus () : EFI_SUCCESS;
957 }
958
959 return Status;
960 }
961
962
963 /**
964 Get information about a file.
965
966 @param This Protocol instance pointer.
967 @param InformationType Type of information to return in Buffer.
968 @param BufferSize On input size of buffer, on output amount of data in buffer.
969 @param Buffer The buffer to return data.
970
971 @retval EFI_SUCCESS Data was returned.
972 @retval EFI_UNSUPPORTED InformationType is not supported.
973 @retval EFI_NO_MEDIA The device has no media.
974 @retval EFI_DEVICE_ERROR The device reported an error.
975 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
976 @retval EFI_WRITE_PROTECTED The device is write protected.
977 @retval EFI_ACCESS_DENIED The file was open for read only.
978 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
979
980 **/
981 EFI_STATUS
PosixFileGetInfo(IN EFI_FILE_PROTOCOL * This,IN EFI_GUID * InformationType,IN OUT UINTN * BufferSize,OUT VOID * Buffer)982 PosixFileGetInfo (
983 IN EFI_FILE_PROTOCOL *This,
984 IN EFI_GUID *InformationType,
985 IN OUT UINTN *BufferSize,
986 OUT VOID *Buffer
987 )
988 {
989 EFI_STATUS Status;
990 EMU_EFI_FILE_PRIVATE *PrivateFile;
991 EFI_FILE_SYSTEM_INFO *FileSystemInfoBuffer;
992 int UnixStatus;
993 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;
994 struct statfs buf;
995
996 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
997 PrivateRoot = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);
998
999 Status = EFI_SUCCESS;
1000 if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
1001 Status = UnixSimpleFileSystemFileInfo (PrivateFile, NULL, BufferSize, Buffer);
1002 } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
1003 if (*BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel)) {
1004 *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);
1005 return EFI_BUFFER_TOO_SMALL;
1006 }
1007
1008 UnixStatus = statfs (PrivateFile->FileName, &buf);
1009 if (UnixStatus < 0) {
1010 return EFI_DEVICE_ERROR;
1011 }
1012
1013 FileSystemInfoBuffer = (EFI_FILE_SYSTEM_INFO *) Buffer;
1014 FileSystemInfoBuffer->Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);
1015 FileSystemInfoBuffer->ReadOnly = FALSE;
1016
1017 //
1018 // Succeeded
1019 //
1020 FileSystemInfoBuffer->VolumeSize = MultU64x32 (buf.f_blocks, buf.f_bsize);
1021 FileSystemInfoBuffer->FreeSpace = MultU64x32 (buf.f_bavail, buf.f_bsize);
1022 FileSystemInfoBuffer->BlockSize = buf.f_bsize;
1023
1024
1025 StrCpy ((CHAR16 *) FileSystemInfoBuffer->VolumeLabel, PrivateRoot->VolumeLabel);
1026 *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);
1027
1028 } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
1029 if (*BufferSize < StrSize (PrivateRoot->VolumeLabel)) {
1030 *BufferSize = StrSize (PrivateRoot->VolumeLabel);
1031 return EFI_BUFFER_TOO_SMALL;
1032 }
1033
1034 StrCpy ((CHAR16 *) Buffer, PrivateRoot->VolumeLabel);
1035 *BufferSize = StrSize (PrivateRoot->VolumeLabel);
1036
1037 }
1038
1039 return Status;
1040 }
1041
1042
1043 /**
1044 Set information about a file
1045
1046 @param File Protocol instance pointer.
1047 @param InformationType Type of information in Buffer.
1048 @param BufferSize Size of buffer.
1049 @param Buffer The data to write.
1050
1051 @retval EFI_SUCCESS Data was returned.
1052 @retval EFI_UNSUPPORTED InformationType is not supported.
1053 @retval EFI_NO_MEDIA The device has no media.
1054 @retval EFI_DEVICE_ERROR The device reported an error.
1055 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1056 @retval EFI_WRITE_PROTECTED The device is write protected.
1057 @retval EFI_ACCESS_DENIED The file was open for read only.
1058
1059 **/
1060 EFI_STATUS
PosixFileSetInfo(IN EFI_FILE_PROTOCOL * This,IN EFI_GUID * InformationType,IN UINTN BufferSize,IN VOID * Buffer)1061 PosixFileSetInfo (
1062 IN EFI_FILE_PROTOCOL *This,
1063 IN EFI_GUID *InformationType,
1064 IN UINTN BufferSize,
1065 IN VOID *Buffer
1066 )
1067 {
1068 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;
1069 EMU_EFI_FILE_PRIVATE *PrivateFile;
1070 EFI_FILE_INFO *OldFileInfo;
1071 EFI_FILE_INFO *NewFileInfo;
1072 EFI_STATUS Status;
1073 UINTN OldInfoSize;
1074 mode_t NewAttr;
1075 struct stat OldAttr;
1076 CHAR8 *OldFileName;
1077 CHAR8 *NewFileName;
1078 CHAR8 *CharPointer;
1079 BOOLEAN AttrChangeFlag;
1080 BOOLEAN NameChangeFlag;
1081 BOOLEAN SizeChangeFlag;
1082 BOOLEAN TimeChangeFlag;
1083 struct tm NewLastAccessSystemTime;
1084 struct tm NewLastWriteSystemTime;
1085 EFI_FILE_SYSTEM_INFO *NewFileSystemInfo;
1086 CHAR8 *AsciiFilePtr;
1087 CHAR16 *UnicodeFilePtr;
1088 int UnixStatus;
1089 struct utimbuf Utime;
1090
1091
1092 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
1093 PrivateRoot = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);
1094 errno = 0;
1095 Status = EFI_UNSUPPORTED;
1096 OldFileInfo = NewFileInfo = NULL;
1097 OldFileName = NewFileName = NULL;
1098 AttrChangeFlag = NameChangeFlag = SizeChangeFlag = TimeChangeFlag = FALSE;
1099
1100 //
1101 // Set file system information.
1102 //
1103 if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
1104 if (BufferSize < (SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel))) {
1105 Status = EFI_BAD_BUFFER_SIZE;
1106 goto Done;
1107 }
1108
1109 NewFileSystemInfo = (EFI_FILE_SYSTEM_INFO *) Buffer;
1110
1111 free (PrivateRoot->VolumeLabel);
1112
1113 PrivateRoot->VolumeLabel = malloc (StrSize (NewFileSystemInfo->VolumeLabel));
1114 if (PrivateRoot->VolumeLabel == NULL) {
1115 goto Done;
1116 }
1117
1118 StrCpy (PrivateRoot->VolumeLabel, NewFileSystemInfo->VolumeLabel);
1119
1120 Status = EFI_SUCCESS;
1121 goto Done;
1122 }
1123
1124 //
1125 // Set volume label information.
1126 //
1127 if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
1128 if (BufferSize < StrSize (PrivateRoot->VolumeLabel)) {
1129 Status = EFI_BAD_BUFFER_SIZE;
1130 goto Done;
1131 }
1132
1133 StrCpy (PrivateRoot->VolumeLabel, (CHAR16 *) Buffer);
1134
1135 Status = EFI_SUCCESS;
1136 goto Done;
1137 }
1138
1139 if (!CompareGuid (InformationType, &gEfiFileInfoGuid)) {
1140 Status = EFI_UNSUPPORTED;
1141 goto Done;
1142 }
1143
1144 if (BufferSize < SIZE_OF_EFI_FILE_INFO) {
1145 Status = EFI_BAD_BUFFER_SIZE;
1146 goto Done;
1147 }
1148
1149 //
1150 // Set file/directory information.
1151 //
1152
1153 //
1154 // Check for invalid set file information parameters.
1155 //
1156 NewFileInfo = (EFI_FILE_INFO *) Buffer;
1157 if (NewFileInfo->Size <= sizeof (EFI_FILE_INFO) ||
1158 (NewFileInfo->Attribute &~(EFI_FILE_VALID_ATTR)) ||
1159 (sizeof (UINTN) == 4 && NewFileInfo->Size > 0xFFFFFFFF)
1160 ) {
1161 Status = EFI_INVALID_PARAMETER;
1162 goto Done;
1163 }
1164
1165 //
1166 // Get current file information so we can determine what kind
1167 // of change request this is.
1168 //
1169 OldInfoSize = 0;
1170 Status = UnixSimpleFileSystemFileInfo (PrivateFile, NULL, &OldInfoSize, NULL);
1171 if (Status != EFI_BUFFER_TOO_SMALL) {
1172 Status = EFI_DEVICE_ERROR;
1173 goto Done;
1174 }
1175
1176 OldFileInfo = malloc (OldInfoSize);
1177 if (OldFileInfo == NULL) {
1178 goto Done;
1179 }
1180
1181 Status = UnixSimpleFileSystemFileInfo (PrivateFile, NULL, &OldInfoSize, OldFileInfo);
1182 if (EFI_ERROR (Status)) {
1183 goto Done;
1184 }
1185
1186 OldFileName = malloc (AsciiStrSize (PrivateFile->FileName));
1187 if (OldFileInfo == NULL) {
1188 goto Done;
1189 }
1190
1191 AsciiStrCpy (OldFileName, PrivateFile->FileName);
1192
1193 //
1194 // Make full pathname from new filename and rootpath.
1195 //
1196 if (NewFileInfo->FileName[0] == '\\') {
1197 NewFileName = malloc (AsciiStrLen (PrivateRoot->FilePath) + 1 + StrLen (NewFileInfo->FileName) + 1);
1198 if (NewFileName == NULL) {
1199 goto Done;
1200 }
1201
1202 AsciiStrCpy (NewFileName, PrivateRoot->FilePath);
1203 AsciiFilePtr = NewFileName + AsciiStrLen(NewFileName);
1204 UnicodeFilePtr = NewFileInfo->FileName + 1;
1205 *AsciiFilePtr++ ='/';
1206 } else {
1207 NewFileName = malloc (AsciiStrLen (PrivateFile->FileName) + 2 + StrLen (NewFileInfo->FileName) + 1);
1208 if (NewFileName == NULL) {
1209 goto Done;
1210 }
1211
1212 AsciiStrCpy (NewFileName, PrivateRoot->FilePath);
1213 AsciiFilePtr = NewFileName + AsciiStrLen(NewFileName);
1214 if ((AsciiFilePtr[-1] != '/') && (NewFileInfo->FileName[0] != '/')) {
1215 // make sure there is a / between Root FilePath and NewFileInfo Filename
1216 AsciiFilePtr[0] = '/';
1217 AsciiFilePtr[1] = '\0';
1218 AsciiFilePtr++;
1219 }
1220 UnicodeFilePtr = NewFileInfo->FileName;
1221 }
1222 // Convert to ascii.
1223 while (*UnicodeFilePtr) {
1224 *AsciiFilePtr++ = *UnicodeFilePtr++;
1225 }
1226 *AsciiFilePtr = 0;
1227
1228 //
1229 // Is there an attribute change request?
1230 //
1231 if (NewFileInfo->Attribute != OldFileInfo->Attribute) {
1232 if ((NewFileInfo->Attribute & EFI_FILE_DIRECTORY) != (OldFileInfo->Attribute & EFI_FILE_DIRECTORY)) {
1233 Status = EFI_INVALID_PARAMETER;
1234 goto Done;
1235 }
1236
1237 AttrChangeFlag = TRUE;
1238 }
1239
1240 //
1241 // Is there a name change request?
1242 // bugbug: - Should really use EFI_UNICODE_COLLATION_PROTOCOL
1243 //
1244 if (StrCmp (NewFileInfo->FileName, OldFileInfo->FileName)) {
1245 NameChangeFlag = TRUE;
1246 }
1247
1248 //
1249 // Is there a size change request?
1250 //
1251 if (NewFileInfo->FileSize != OldFileInfo->FileSize) {
1252 SizeChangeFlag = TRUE;
1253 }
1254
1255 //
1256 // Is there a time stamp change request?
1257 //
1258 if (!IsZero (&NewFileInfo->CreateTime, sizeof (EFI_TIME)) &&
1259 CompareMem (&NewFileInfo->CreateTime, &OldFileInfo->CreateTime, sizeof (EFI_TIME))
1260 ) {
1261 TimeChangeFlag = TRUE;
1262 } else if (!IsZero (&NewFileInfo->LastAccessTime, sizeof (EFI_TIME)) &&
1263 CompareMem (&NewFileInfo->LastAccessTime, &OldFileInfo->LastAccessTime, sizeof (EFI_TIME))
1264 ) {
1265 TimeChangeFlag = TRUE;
1266 } else if (!IsZero (&NewFileInfo->ModificationTime, sizeof (EFI_TIME)) &&
1267 CompareMem (&NewFileInfo->ModificationTime, &OldFileInfo->ModificationTime, sizeof (EFI_TIME))
1268 ) {
1269 TimeChangeFlag = TRUE;
1270 }
1271
1272 //
1273 // All done if there are no change requests being made.
1274 //
1275 if (!(AttrChangeFlag || NameChangeFlag || SizeChangeFlag || TimeChangeFlag)) {
1276 Status = EFI_SUCCESS;
1277 goto Done;
1278 }
1279
1280 //
1281 // Set file or directory information.
1282 //
1283 if (stat (OldFileName, &OldAttr) != 0) {
1284 Status = ErrnoToEfiStatus ();
1285 goto Done;
1286 }
1287
1288 //
1289 // Name change.
1290 //
1291 if (NameChangeFlag) {
1292 //
1293 // Close the handles first
1294 //
1295 if (PrivateFile->IsOpenedByRead) {
1296 Status = EFI_ACCESS_DENIED;
1297 goto Done;
1298 }
1299
1300 for (CharPointer = NewFileName; *CharPointer != 0 && *CharPointer != L'/'; CharPointer++) {
1301 }
1302
1303 if (*CharPointer != 0) {
1304 Status = EFI_ACCESS_DENIED;
1305 goto Done;
1306 }
1307
1308 UnixStatus = rename (OldFileName, NewFileName);
1309 if (UnixStatus == 0) {
1310 //
1311 // modify file name
1312 //
1313 free (PrivateFile->FileName);
1314
1315 PrivateFile->FileName = malloc (AsciiStrSize (NewFileName));
1316 if (PrivateFile->FileName == NULL) {
1317 goto Done;
1318 }
1319
1320 AsciiStrCpy (PrivateFile->FileName, NewFileName);
1321 } else {
1322 Status = EFI_DEVICE_ERROR;
1323 goto Done;
1324 }
1325 }
1326
1327 //
1328 // Size change
1329 //
1330 if (SizeChangeFlag) {
1331 if (PrivateFile->IsDirectoryPath) {
1332 Status = EFI_UNSUPPORTED;
1333 goto Done;
1334 }
1335
1336 if (PrivateFile->IsOpenedByRead || OldFileInfo->Attribute & EFI_FILE_READ_ONLY) {
1337 Status = EFI_ACCESS_DENIED;
1338 goto Done;
1339 }
1340
1341 if (ftruncate (PrivateFile->fd, NewFileInfo->FileSize) != 0) {
1342 Status = ErrnoToEfiStatus ();
1343 goto Done;
1344 }
1345
1346 }
1347
1348 //
1349 // Time change
1350 //
1351 if (TimeChangeFlag) {
1352 NewLastAccessSystemTime.tm_year = NewFileInfo->LastAccessTime.Year;
1353 NewLastAccessSystemTime.tm_mon = NewFileInfo->LastAccessTime.Month;
1354 NewLastAccessSystemTime.tm_mday = NewFileInfo->LastAccessTime.Day;
1355 NewLastAccessSystemTime.tm_hour = NewFileInfo->LastAccessTime.Hour;
1356 NewLastAccessSystemTime.tm_min = NewFileInfo->LastAccessTime.Minute;
1357 NewLastAccessSystemTime.tm_sec = NewFileInfo->LastAccessTime.Second;
1358 NewLastAccessSystemTime.tm_isdst = 0;
1359
1360 Utime.actime = mktime (&NewLastAccessSystemTime);
1361
1362 NewLastWriteSystemTime.tm_year = NewFileInfo->ModificationTime.Year;
1363 NewLastWriteSystemTime.tm_mon = NewFileInfo->ModificationTime.Month;
1364 NewLastWriteSystemTime.tm_mday = NewFileInfo->ModificationTime.Day;
1365 NewLastWriteSystemTime.tm_hour = NewFileInfo->ModificationTime.Hour;
1366 NewLastWriteSystemTime.tm_min = NewFileInfo->ModificationTime.Minute;
1367 NewLastWriteSystemTime.tm_sec = NewFileInfo->ModificationTime.Second;
1368 NewLastWriteSystemTime.tm_isdst = 0;
1369
1370 Utime.modtime = mktime (&NewLastWriteSystemTime);
1371
1372 if (Utime.actime == (time_t)-1 || Utime.modtime == (time_t)-1) {
1373 goto Done;
1374 }
1375
1376 if (utime (PrivateFile->FileName, &Utime) == -1) {
1377 Status = ErrnoToEfiStatus ();
1378 goto Done;
1379 }
1380 }
1381
1382 //
1383 // No matter about AttrChangeFlag, Attribute must be set.
1384 // Because operation before may cause attribute change.
1385 //
1386 NewAttr = OldAttr.st_mode;
1387
1388 if (NewFileInfo->Attribute & EFI_FILE_READ_ONLY) {
1389 NewAttr &= ~(S_IRUSR | S_IRGRP | S_IROTH);
1390 } else {
1391 NewAttr |= S_IRUSR;
1392 }
1393
1394 if (chmod (NewFileName, NewAttr) != 0) {
1395 Status = ErrnoToEfiStatus ();
1396 }
1397
1398 Done:
1399 if (OldFileInfo != NULL) {
1400 free (OldFileInfo);
1401 }
1402
1403 if (OldFileName != NULL) {
1404 free (OldFileName);
1405 }
1406
1407 if (NewFileName != NULL) {
1408 free (NewFileName);
1409 }
1410
1411 return Status;
1412 }
1413
1414
1415 /**
1416 Flush data back for the file handle.
1417
1418 @param This Protocol instance pointer.
1419
1420 @retval EFI_SUCCESS Data was written.
1421 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
1422 @retval EFI_NO_MEDIA The device has no media.
1423 @retval EFI_DEVICE_ERROR The device reported an error.
1424 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1425 @retval EFI_WRITE_PROTECTED The device is write protected.
1426 @retval EFI_ACCESS_DENIED The file was open for read only.
1427 @retval EFI_VOLUME_FULL The volume is full.
1428
1429 **/
1430 EFI_STATUS
PosixFileFlush(IN EFI_FILE_PROTOCOL * This)1431 PosixFileFlush (
1432 IN EFI_FILE_PROTOCOL *This
1433 )
1434 {
1435 EMU_EFI_FILE_PRIVATE *PrivateFile;
1436
1437
1438 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
1439
1440 if (PrivateFile->IsDirectoryPath) {
1441 return EFI_UNSUPPORTED;
1442 }
1443
1444 if (PrivateFile->IsOpenedByRead) {
1445 return EFI_ACCESS_DENIED;
1446 }
1447
1448 if (PrivateFile->fd < 0) {
1449 return EFI_DEVICE_ERROR;
1450 }
1451
1452 if (fsync (PrivateFile->fd) != 0) {
1453 return ErrnoToEfiStatus ();
1454 }
1455
1456 return EFI_SUCCESS;
1457 }
1458
1459
1460
1461 EFI_STATUS
PosixFileSystmeThunkOpen(IN EMU_IO_THUNK_PROTOCOL * This)1462 PosixFileSystmeThunkOpen (
1463 IN EMU_IO_THUNK_PROTOCOL *This
1464 )
1465 {
1466 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *Private;
1467 UINTN i;
1468
1469 if (This->Private != NULL) {
1470 return EFI_ALREADY_STARTED;
1471 }
1472
1473 if (!CompareGuid (This->Protocol, &gEfiSimpleFileSystemProtocolGuid)) {
1474 return EFI_UNSUPPORTED;
1475 }
1476
1477 Private = malloc (sizeof (EMU_SIMPLE_FILE_SYSTEM_PRIVATE));
1478 if (Private == NULL) {
1479 return EFI_OUT_OF_RESOURCES;
1480 }
1481
1482 Private->FilePath = malloc (StrLen (This->ConfigString) + 1);
1483 if (Private->FilePath == NULL) {
1484 free (Private);
1485 return EFI_OUT_OF_RESOURCES;
1486 }
1487
1488 // Convert Unicode to Ascii
1489 for (i = 0; This->ConfigString[i] != 0; i++) {
1490 Private->FilePath[i] = This->ConfigString[i];
1491 }
1492 Private->FilePath[i] = 0;
1493
1494
1495 Private->VolumeLabel = malloc (StrSize (L"EFI_EMULATED"));
1496 if (Private->VolumeLabel == NULL) {
1497 free (Private->FilePath);
1498 free (Private);
1499 return EFI_OUT_OF_RESOURCES;
1500 }
1501 StrCpy (Private->VolumeLabel, L"EFI_EMULATED");
1502
1503 Private->Signature = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE;
1504 Private->Thunk = This;
1505 CopyMem (&Private->SimpleFileSystem, &gPosixFileSystemProtocol, sizeof (Private->SimpleFileSystem));
1506 Private->FileHandlesOpen = FALSE;
1507
1508 This->Interface = &Private->SimpleFileSystem;
1509 This->Private = Private;
1510 return EFI_SUCCESS;
1511 }
1512
1513
1514 EFI_STATUS
PosixFileSystmeThunkClose(IN EMU_IO_THUNK_PROTOCOL * This)1515 PosixFileSystmeThunkClose (
1516 IN EMU_IO_THUNK_PROTOCOL *This
1517 )
1518 {
1519 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *Private;
1520
1521 if (!CompareGuid (This->Protocol, &gEfiSimpleFileSystemProtocolGuid)) {
1522 return EFI_UNSUPPORTED;
1523 }
1524
1525 Private = This->Private;
1526
1527 if (Private->FileHandlesOpen) {
1528 //
1529 // Close only supported if all the EFI_FILE_HANDLEs have been closed.
1530 //
1531 return EFI_NOT_READY;
1532 }
1533
1534 if (This->Private != NULL) {
1535 if (Private->VolumeLabel != NULL) {
1536 free (Private->VolumeLabel);
1537 }
1538 free (This->Private);
1539 This->Private = NULL;
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
1557