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
PosixOpenVolume(IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL * This,OUT EFI_FILE_PROTOCOL ** Root)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
ErrnoToEfiStatus()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
CutPrefix(IN CHAR8 * Str,IN UINTN Count)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
PosixSystemTimeToEfiTime(IN time_t SystemTime,OUT EFI_TIME * Time)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
UnixSimpleFileSystemFileInfo(EMU_EFI_FILE_PRIVATE * PrivateFile,IN CHAR8 * FileName,IN OUT UINTN * BufferSize,OUT VOID * Buffer)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
IsZero(IN VOID * Buffer,IN UINTN Length)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
PosixFileOpen(IN EFI_FILE_PROTOCOL * This,OUT EFI_FILE_PROTOCOL ** NewHandle,IN CHAR16 * FileName,IN UINT64 OpenMode,IN UINT64 Attributes)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
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   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
PosixFileWrite(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,IN VOID * Buffer)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
PosixFileSetPossition(IN EFI_FILE_PROTOCOL * This,IN UINT64 Position)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
PosixFileGetPossition(IN EFI_FILE_PROTOCOL * This,OUT UINT64 * Position)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
PosixFileGetInfo(IN EFI_FILE_PROTOCOL * This,IN EFI_GUID * InformationType,IN OUT UINTN * BufferSize,OUT VOID * Buffer)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
PosixFileSetInfo(IN EFI_FILE_PROTOCOL * This,IN EFI_GUID * InformationType,IN UINTN BufferSize,IN VOID * Buffer)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
PosixFileFlush(IN EFI_FILE_PROTOCOL * This)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
PosixFileSystmeThunkOpen(IN EMU_IO_THUNK_PROTOCOL * This)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
PosixFileSystmeThunkClose(IN EMU_IO_THUNK_PROTOCOL * This)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 
1588