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