42a361b53dc602d98709828a6f31ff1ab33e215c
[people/mcb30/edk2.git] / edk2 / EdkUnixPkg / Dxe / UnixThunk / Bus / SimpleFileSystem / UnixSimpleFileSystem.c
1 /*++\r
2 \r
3 Copyright (c) 2006, Intel Corporation                                                         \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8                                                                                           \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 Module Name:\r
13 \r
14   UnixSimpleFileSystem.c\r
15 \r
16 Abstract:\r
17 \r
18   Produce Simple File System abstractions for directories on your PC using Posix APIs.\r
19   The configuration of what devices to mount or emulate comes from UNIX \r
20   environment variables. The variables must be visible to the Microsoft* \r
21   Developer Studio for them to work.\r
22 \r
23   * Other names and brands may be claimed as the property of others.\r
24 \r
25 --*/\r
26 \r
27 #include "UnixSimpleFileSystem.h"\r
28 \r
29 EFI_DRIVER_BINDING_PROTOCOL gUnixSimpleFileSystemDriverBinding = {\r
30   UnixSimpleFileSystemDriverBindingSupported,\r
31   UnixSimpleFileSystemDriverBindingStart,\r
32   UnixSimpleFileSystemDriverBindingStop,\r
33   0x10,\r
34   NULL,\r
35   NULL\r
36 };\r
37 \r
38 \r
39 CHAR16 *\r
40 EfiStrChr (\r
41   IN CHAR16   *Str,\r
42   IN CHAR16   Chr\r
43   )\r
44 /*++\r
45 \r
46 Routine Description:\r
47 \r
48   Locate the first occurance of a character in a string.\r
49 \r
50 Arguments:\r
51 \r
52   Str - Pointer to NULL terminated unicode string.\r
53   Chr - Character to locate.\r
54 \r
55 Returns:\r
56 \r
57   If Str is NULL, then NULL is returned.\r
58   If Chr is not contained in Str, then NULL is returned.\r
59   If Chr is contained in Str, then a pointer to the first occurance of Chr in Str is returned.\r
60 \r
61 --*/\r
62 {\r
63   if (Str == NULL) {\r
64     return Str;\r
65   }\r
66 \r
67   while (*Str != '\0' && *Str != Chr) {\r
68     ++Str;\r
69   }\r
70 \r
71   return (*Str == Chr) ? Str : NULL;\r
72 }\r
73 \r
74 BOOLEAN\r
75 IsZero (\r
76   IN VOID   *Buffer,\r
77   IN UINTN  Length\r
78   )\r
79 /*++\r
80 \r
81 Routine Description:\r
82 \r
83   TODO: Add function description\r
84 \r
85 Arguments:\r
86 \r
87   Buffer  - TODO: add argument description\r
88   Length  - TODO: add argument description\r
89 \r
90 Returns:\r
91 \r
92   TODO: add return values\r
93 \r
94 --*/\r
95 {\r
96   if (Buffer == NULL || Length == 0) {\r
97     return FALSE;\r
98   }\r
99 \r
100   if (*(UINT8 *) Buffer != 0) {\r
101     return FALSE;\r
102   }\r
103 \r
104   if (Length > 1) {\r
105     if (!CompareMem (Buffer, (UINT8 *) Buffer + 1, Length - 1)) {\r
106       return FALSE;\r
107     }\r
108   }\r
109 \r
110   return TRUE;\r
111 }\r
112 \r
113 VOID\r
114 CutPrefix (\r
115   IN  CHAR8  *Str,\r
116   IN  UINTN   Count\r
117   )\r
118 /*++\r
119 \r
120 Routine Description:\r
121 \r
122   TODO: Add function description\r
123 \r
124 Arguments:\r
125 \r
126   Str   - TODO: add argument description\r
127   Count - TODO: add argument description\r
128 \r
129 Returns:\r
130 \r
131   TODO: add return values\r
132 \r
133 --*/\r
134 {\r
135   CHAR8  *Pointer;\r
136 \r
137   if (AsciiStrLen (Str) < Count) {\r
138     ASSERT (0);\r
139   }\r
140 \r
141   for (Pointer = Str; *(Pointer + Count); Pointer++) {\r
142     *Pointer = *(Pointer + Count);\r
143   }\r
144 \r
145   *Pointer = *(Pointer + Count);\r
146 }\r
147 \r
148 \r
149 \r
150 EFI_STATUS\r
151 EFIAPI\r
152 UnixSimpleFileSystemDriverBindingSupported (\r
153   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
154   IN  EFI_HANDLE                   ControllerHandle,\r
155   IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
156   )\r
157 /*++\r
158 \r
159 Routine Description:\r
160 \r
161   Check to see if the driver supports a given controller.\r
162 \r
163 Arguments:\r
164 \r
165   This                - A pointer to an instance of the EFI_DRIVER_BINDING_PROTOCOL.\r
166 \r
167   ControllerHandle    - EFI handle of the controller to test.\r
168 \r
169   RemainingDevicePath - Pointer to remaining portion of a device path.\r
170 \r
171 Returns:\r
172 \r
173   EFI_SUCCESS         - The device specified by ControllerHandle and RemainingDevicePath is supported by the driver\r
174                         specified by This.\r
175 \r
176   EFI_ALREADY_STARTED - The device specified by ControllerHandle and RemainingDevicePath is already being managed by\r
177                         the driver specified by This.\r
178 \r
179   EFI_ACCESS_DENIED   - The device specified by ControllerHandle and RemainingDevicePath is already being managed by\r
180                         a different driver or an application that requires exclusive access.\r
181 \r
182   EFI_UNSUPPORTED     - The device specified by ControllerHandle and RemainingDevicePath is not supported by the\r
183                         driver specified by This.\r
184 \r
185 --*/\r
186 {\r
187   EFI_STATUS              Status;\r
188   EFI_UNIX_IO_PROTOCOL  *UnixIo;\r
189 \r
190   //\r
191   // Open the IO Abstraction(s) needed to perform the supported test\r
192   //\r
193   Status = gBS->OpenProtocol (\r
194                   ControllerHandle,\r
195                   &gEfiUnixIoProtocolGuid,\r
196                   (VOID **)&UnixIo,\r
197                   This->DriverBindingHandle,\r
198                   ControllerHandle,\r
199                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
200                   );\r
201   if (EFI_ERROR (Status)) {\r
202     return Status;\r
203   }\r
204 \r
205   //\r
206   // Make sure GUID is for a File System handle.\r
207   //\r
208   Status = EFI_UNSUPPORTED;\r
209   if (CompareGuid (UnixIo->TypeGuid, &gEfiUnixFileSystemGuid)) {\r
210     Status = EFI_SUCCESS;\r
211   }\r
212 \r
213   //\r
214   // Close the I/O Abstraction(s) used to perform the supported test\r
215   //\r
216   gBS->CloseProtocol (\r
217         ControllerHandle,\r
218         &gEfiUnixIoProtocolGuid,\r
219         This->DriverBindingHandle,\r
220         ControllerHandle\r
221         );\r
222 \r
223   return Status;\r
224 }\r
225 \r
226 EFI_STATUS\r
227 EFIAPI\r
228 UnixSimpleFileSystemDriverBindingStart (\r
229   IN  EFI_DRIVER_BINDING_PROTOCOL   *This,\r
230   IN  EFI_HANDLE                    ControllerHandle,\r
231   IN  EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath\r
232   )\r
233 /*++\r
234 \r
235 Routine Description:\r
236 \r
237   Starts a device controller or a bus controller.\r
238 \r
239 Arguments:\r
240 \r
241   This                - A pointer to an instance of the EFI_DRIVER_BINDING_PROTOCOL.\r
242 \r
243   ControllerHandle    - EFI handle of the controller to start.\r
244 \r
245   RemainingDevicePath - Pointer to remaining portion of a device path.\r
246 \r
247 Returns:\r
248 \r
249   EFI_SUCCESS           - The device or bus controller has been started.\r
250 \r
251   EFI_DEVICE_ERROR      - The device could not be started due to a device failure.\r
252 \r
253   EFI_OUT_OF_RESOURCES  - The request could not be completed due to lack of resources.\r
254 \r
255 --*/\r
256 {\r
257   EFI_STATUS                        Status;\r
258   EFI_UNIX_IO_PROTOCOL            *UnixIo;\r
259   UNIX_SIMPLE_FILE_SYSTEM_PRIVATE *Private;\r
260   INTN i;
261 \r
262   Private = NULL;\r
263 \r
264   //\r
265   // Open the IO Abstraction(s) needed\r
266   //\r
267   Status = gBS->OpenProtocol (\r
268                   ControllerHandle,\r
269                   &gEfiUnixIoProtocolGuid,\r
270                   (VOID **)&UnixIo,\r
271                   This->DriverBindingHandle,\r
272                   ControllerHandle,\r
273                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
274                   );\r
275   if (EFI_ERROR (Status)) {\r
276     return Status;\r
277   }\r
278 \r
279   //\r
280   // Validate GUID\r
281   //\r
282   if (!CompareGuid (UnixIo->TypeGuid, &gEfiUnixFileSystemGuid)) {\r
283     Status = EFI_UNSUPPORTED;\r
284     goto Done;\r
285   }\r
286 \r
287   Status = gBS->AllocatePool (\r
288                   EfiBootServicesData,\r
289                   sizeof (UNIX_SIMPLE_FILE_SYSTEM_PRIVATE),\r
290                   (VOID **)&Private\r
291                   );\r
292   if (EFI_ERROR (Status)) {\r
293     goto Done;\r
294   }\r
295 \r
296   Private->Signature  = UNIX_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE;\r
297   Private->UnixThunk = UnixIo->UnixThunk;\r
298   Private->FilePath   = NULL;
299   Private->VolumeLabel = NULL;
300 \r
301   Status = gBS->AllocatePool (\r
302                   EfiBootServicesData,\r
303                   StrLen (UnixIo->EnvString) + 1,\r
304                   (VOID **)&Private->FilePath\r
305                   );\r
306 \r
307   if (EFI_ERROR (Status)) {\r
308     goto Done;\r
309   }\r
310
311   for (i = 0; UnixIo->EnvString[i] != 0; i++)
312     Private->FilePath[i] = UnixIo->EnvString[i];\r
313   Private->FilePath[i] = 0;
314 \r
315   Private->VolumeLabel      = NULL;\r
316   Status = gBS->AllocatePool (\r
317                   EfiBootServicesData,\r
318                   StrSize (L"EFI_EMULATED"),\r
319                   (VOID **)&Private->VolumeLabel\r
320                   );\r
321 \r
322   if (EFI_ERROR (Status)) {\r
323     goto Done;\r
324   }\r
325 \r
326   StrCpy (Private->VolumeLabel, L"EFI_EMULATED");\r
327 \r
328   Private->SimpleFileSystem.Revision    = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;\r
329   Private->SimpleFileSystem.OpenVolume  = UnixSimpleFileSystemOpenVolume;\r
330 \r
331   Private->ControllerNameTable = NULL;\r
332 \r
333   AddUnicodeString (\r
334     "eng",\r
335     gUnixSimpleFileSystemComponentName.SupportedLanguages,\r
336     &Private->ControllerNameTable,\r
337     UnixIo->EnvString\r
338     );\r
339 \r
340   Status = gBS->InstallMultipleProtocolInterfaces (\r
341                   &ControllerHandle,\r
342                   &gEfiSimpleFileSystemProtocolGuid,\r
343                   &Private->SimpleFileSystem,\r
344                   NULL\r
345                   );\r
346 \r
347 Done:\r
348   if (EFI_ERROR (Status)) {\r
349 \r
350     if (Private != NULL) {\r
351 \r
352       if (Private->VolumeLabel != NULL)
353         gBS->FreePool (Private->VolumeLabel);
354       if (Private->FilePath != NULL)
355         gBS->FreePool (Private->FilePath);
356       FreeUnicodeStringTable (Private->ControllerNameTable);\r
357 \r
358       gBS->FreePool (Private);\r
359     }\r
360 \r
361     gBS->CloseProtocol (\r
362           ControllerHandle,\r
363           &gEfiUnixIoProtocolGuid,\r
364           This->DriverBindingHandle,\r
365           ControllerHandle\r
366           );\r
367   }\r
368 \r
369   return Status;\r
370 }\r
371 \r
372 EFI_STATUS\r
373 EFIAPI\r
374 UnixSimpleFileSystemDriverBindingStop (\r
375   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
376   IN  EFI_HANDLE                   ControllerHandle,\r
377   IN  UINTN                        NumberOfChildren,\r
378   IN  EFI_HANDLE                   *ChildHandleBuffer\r
379   )\r
380 /*++\r
381 \r
382 Routine Description:\r
383 \r
384   TODO: Add function description\r
385 \r
386 Arguments:\r
387 \r
388   This              - A pointer to an instance of the EFI_DRIVER_BINDING_PROTOCOL.\r
389 \r
390   ControllerHandle  - A handle to the device to be stopped.\r
391 \r
392   NumberOfChildren  - The number of child device handles in ChildHandleBuffer.\r
393 \r
394   ChildHandleBuffer - An array of child device handles to be freed.\r
395 \r
396 Returns:\r
397 \r
398   EFI_SUCCESS       - The device has been stopped.\r
399 \r
400   EFI_DEVICE_ERROR  - The device could not be stopped due to a device failure.\r
401 \r
402 --*/\r
403 // TODO:    EFI_UNSUPPORTED - add return value to function comment\r
404 {\r
405   EFI_STATUS                        Status;\r
406   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *SimpleFileSystem;\r
407   UNIX_SIMPLE_FILE_SYSTEM_PRIVATE *Private;\r
408 \r
409   //\r
410   // Get our context back\r
411   //\r
412   Status = gBS->OpenProtocol (\r
413                   ControllerHandle,\r
414                   &gEfiSimpleFileSystemProtocolGuid,\r
415                   (VOID **)&SimpleFileSystem,\r
416                   This->DriverBindingHandle,\r
417                   ControllerHandle,\r
418                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
419                   );\r
420   if (EFI_ERROR (Status)) {\r
421     return EFI_UNSUPPORTED;\r
422   }\r
423 \r
424   Private = UNIX_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (SimpleFileSystem);\r
425 \r
426   //\r
427   // Uninstall the Simple File System Protocol from ControllerHandle\r
428   //\r
429   Status = gBS->UninstallMultipleProtocolInterfaces (\r
430                   ControllerHandle,\r
431                   &gEfiSimpleFileSystemProtocolGuid,\r
432                   &Private->SimpleFileSystem,\r
433                   NULL\r
434                   );\r
435   if (!EFI_ERROR (Status)) {\r
436     Status = gBS->CloseProtocol (\r
437                     ControllerHandle,\r
438                     &gEfiUnixIoProtocolGuid,\r
439                     This->DriverBindingHandle,\r
440                     ControllerHandle\r
441                     );\r
442   }\r
443 \r
444   if (!EFI_ERROR (Status)) {\r
445     //\r
446     // Free our instance data\r
447     //\r
448     FreeUnicodeStringTable (Private->ControllerNameTable);\r
449 \r
450     gBS->FreePool (Private);\r
451   }\r
452 \r
453   return Status;\r
454 }\r
455 \r
456 EFI_STATUS\r
457 EFIAPI\r
458 UnixSimpleFileSystemOpenVolume (\r
459   IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *This,\r
460   OUT EFI_FILE                        **Root\r
461   )\r
462 /*++\r
463 \r
464 Routine Description:\r
465 \r
466   Open the root directory on a volume.\r
467 \r
468 Arguments:\r
469 \r
470   This  - A pointer to the volume to open.\r
471 \r
472   Root  - A pointer to storage for the returned opened file handle of the root directory.\r
473 \r
474 Returns:\r
475 \r
476   EFI_SUCCESS           - The volume was opened.\r
477 \r
478   EFI_UNSUPPORTED       - The volume does not support the requested file system type.\r
479 \r
480   EFI_NO_MEDIA          - The device has no media.\r
481 \r
482   EFI_DEVICE_ERROR      - The device reported an error.\r
483 \r
484   EFI_VOLUME_CORRUPTED  - The file system structures are corrupted.\r
485 \r
486   EFI_ACCESS_DENIED     - The service denied access to the file.\r
487 \r
488   EFI_OUT_OF_RESOURCES  - The file volume could not be opened due to lack of resources.\r
489 \r
490   EFI_MEDIA_CHANGED     - The device has new media or the media is no longer supported.\r
491 \r
492 --*/\r
493 // TODO:    EFI_INVALID_PARAMETER - add return value to function comment\r
494 {\r
495   EFI_STATUS                        Status;\r
496   UNIX_SIMPLE_FILE_SYSTEM_PRIVATE *Private;\r
497   UNIX_EFI_FILE_PRIVATE           *PrivateFile;\r
498 \r
499   if (This == NULL || Root == NULL) {\r
500     return EFI_INVALID_PARAMETER;\r
501   }\r
502 \r
503   Private     = UNIX_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (This);\r
504 \r
505   PrivateFile = NULL;\r
506   Status = gBS->AllocatePool (\r
507                   EfiBootServicesData,\r
508                   sizeof (UNIX_EFI_FILE_PRIVATE),\r
509                   (VOID **)&PrivateFile\r
510                   );\r
511   if (EFI_ERROR (Status)) {\r
512     goto Done;\r
513   }\r
514 \r
515   PrivateFile->FileName = NULL;\r
516   Status = gBS->AllocatePool (\r
517                   EfiBootServicesData,\r
518                   AsciiStrSize (Private->FilePath),\r
519                   (VOID **)&PrivateFile->FileName\r
520                   );\r
521   if (EFI_ERROR (Status)) {\r
522     goto Done;\r
523   }\r
524 \r
525   AsciiStrCpy (PrivateFile->FileName, Private->FilePath);\r
526   PrivateFile->Signature            = UNIX_EFI_FILE_PRIVATE_SIGNATURE;\r
527   PrivateFile->UnixThunk           = Private->UnixThunk;\r
528   PrivateFile->SimpleFileSystem     = This;\r
529   PrivateFile->IsRootDirectory      = TRUE;\r
530   PrivateFile->IsDirectoryPath      = TRUE;\r
531   PrivateFile->IsOpenedByRead       = TRUE;\r
532   PrivateFile->EfiFile.Revision     = EFI_FILE_HANDLE_REVISION;\r
533   PrivateFile->EfiFile.Open         = UnixSimpleFileSystemOpen;\r
534   PrivateFile->EfiFile.Close        = UnixSimpleFileSystemClose;\r
535   PrivateFile->EfiFile.Delete       = UnixSimpleFileSystemDelete;\r
536   PrivateFile->EfiFile.Read         = UnixSimpleFileSystemRead;\r
537   PrivateFile->EfiFile.Write        = UnixSimpleFileSystemWrite;\r
538   PrivateFile->EfiFile.GetPosition  = UnixSimpleFileSystemGetPosition;\r
539   PrivateFile->EfiFile.SetPosition  = UnixSimpleFileSystemSetPosition;\r
540   PrivateFile->EfiFile.GetInfo      = UnixSimpleFileSystemGetInfo;\r
541   PrivateFile->EfiFile.SetInfo      = UnixSimpleFileSystemSetInfo;\r
542   PrivateFile->EfiFile.Flush        = UnixSimpleFileSystemFlush;\r
543   PrivateFile->fd                   = -1;
544   PrivateFile->Dir                  = NULL;
545   PrivateFile->Dirent               = NULL;
546   \r
547   *Root = &PrivateFile->EfiFile;\r
548 \r
549   PrivateFile->Dir = PrivateFile->UnixThunk->OpenDir(PrivateFile->FileName);
550 \r
551   if (PrivateFile->Dir == NULL) {
552     Status = EFI_ACCESS_DENIED;\r
553   }
554   else {
555     Status = EFI_SUCCESS;\r
556   }
557 \r
558 Done:\r
559   if (EFI_ERROR (Status)) {\r
560     if (PrivateFile) {\r
561       if (PrivateFile->FileName) {\r
562         gBS->FreePool (PrivateFile->FileName);\r
563       }\r
564 \r
565       gBS->FreePool (PrivateFile);\r
566     }\r
567   }\r
568 \r
569   return Status;\r
570 }\r
571 \r
572 EFI_STATUS\r
573 EFIAPI\r
574 UnixSimpleFileSystemOpen (\r
575   IN  EFI_FILE  *This,\r
576   OUT EFI_FILE  **NewHandle,\r
577   IN  CHAR16    *FileName,\r
578   IN  UINT64    OpenMode,\r
579   IN  UINT64    Attributes\r
580   )\r
581 /*++\r
582 \r
583 Routine Description:\r
584 \r
585   Open a file relative to the source file location.\r
586 \r
587 Arguments:\r
588 \r
589   This        - A pointer to the source file location.\r
590 \r
591   NewHandle   - Pointer to storage for the new file handle.\r
592 \r
593   FileName    - Pointer to the file name to be opened.\r
594 \r
595   OpenMode    - File open mode information.\r
596 \r
597   Attributes  - File creation attributes.\r
598 \r
599 Returns:\r
600 \r
601   EFI_SUCCESS           - The file was opened.\r
602 \r
603   EFI_NOT_FOUND         - The file could not be found in the volume.\r
604 \r
605   EFI_NO_MEDIA          - The device has no media.\r
606 \r
607   EFI_MEDIA_CHANGED     - The device has new media or the media is no longer supported.\r
608 \r
609   EFI_DEVICE_ERROR      - The device reported an error.\r
610 \r
611   EFI_VOLUME_CORRUPTED  - The file system structures are corrupted.\r
612 \r
613   EFI_WRITE_PROTECTED   - The volume or file is write protected.\r
614 \r
615   EFI_ACCESS_DENIED     - The service denied access to the file.\r
616 \r
617   EFI_OUT_OF_RESOURCES  - Not enough resources were available to open the file.\r
618 \r
619   EFI_VOLUME_FULL       - There is not enough space left to create the new file.\r
620 \r
621 --*/\r
622 // TODO:    EFI_INVALID_PARAMETER - add return value to function comment\r
623 // TODO:    EFI_INVALID_PARAMETER - add return value to function comment\r
624 // TODO:    EFI_INVALID_PARAMETER - add return value to function comment\r
625 // TODO:    EFI_INVALID_PARAMETER - add return value to function comment\r
626 {\r
627   EFI_FILE                          *Root;\r
628   UNIX_EFI_FILE_PRIVATE           *PrivateFile;\r
629   UNIX_EFI_FILE_PRIVATE           *NewPrivateFile;\r
630   UNIX_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;\r
631   EFI_STATUS                        Status;\r
632   CHAR16                            *Src;
633   char                              *Dst;
634   CHAR8                             *RealFileName;\r
635   //CHAR16                            *TempFileName;\r
636   char                              *ParseFileName;\r
637   char                              *GuardPointer;\r
638   CHAR8                             TempChar;\r
639   UINTN                             Count;\r
640   BOOLEAN                           TrailingDash;\r
641   BOOLEAN                           LoopFinish;\r
642   UINTN                             InfoSize;\r
643   EFI_FILE_INFO                     *Info;\r
644 \r
645   TrailingDash = FALSE;\r
646 \r
647   //\r
648   // Check for obvious invalid parameters.\r
649   //\r
650   if (This == NULL || NewHandle == NULL || FileName == NULL) {\r
651     return EFI_INVALID_PARAMETER;\r
652   }\r
653 \r
654   switch (OpenMode) {\r
655   case EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE:\r
656     if (Attributes &~EFI_FILE_VALID_ATTR) {\r
657       return EFI_INVALID_PARAMETER;\r
658     }\r
659 \r
660     if (Attributes & EFI_FILE_READ_ONLY) {\r
661       return EFI_INVALID_PARAMETER;\r
662     }\r
663 \r
664   //\r
665   // fall through\r
666   //\r
667   case EFI_FILE_MODE_READ:\r
668   case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE:\r
669     break;\r
670 \r
671   default:\r
672     return EFI_INVALID_PARAMETER;\r
673   }\r
674 \r
675   //\r
676   //\r
677   //\r
678   PrivateFile     = UNIX_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
679   PrivateRoot     = UNIX_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);\r
680   NewPrivateFile  = NULL;\r
681 \r
682   //\r
683   // BUGBUG: assume an open of root\r
684   // if current location, return current data\r
685   //\r
686   if (StrCmp (FileName, L"\\") == 0
687       || (StrCmp (FileName, L".") == 0 && PrivateFile->IsRootDirectory)) {\r
688     //\r
689     // BUGBUG: assume an open root\r
690     //\r
691 OpenRoot:\r
692     Status          = UnixSimpleFileSystemOpenVolume (PrivateFile->SimpleFileSystem, &Root);\r
693     NewPrivateFile  = UNIX_EFI_FILE_PRIVATE_DATA_FROM_THIS (Root);\r
694     goto Done;\r
695   }\r
696 \r
697   if (FileName[StrLen (FileName) - 1] == L'\\') {\r
698     TrailingDash                        = TRUE;\r
699     FileName[StrLen (FileName) - 1]  = 0;\r
700   }\r
701 \r
702   //\r
703   // Attempt to open the file\r
704   //\r
705   Status = gBS->AllocatePool (\r
706                   EfiBootServicesData,\r
707                   sizeof (UNIX_EFI_FILE_PRIVATE),\r
708                   (VOID **)&NewPrivateFile\r
709                   );\r
710 \r
711   if (EFI_ERROR (Status)) {\r
712     goto Done;\r
713   }\r
714 \r
715   CopyMem (NewPrivateFile, PrivateFile, sizeof (UNIX_EFI_FILE_PRIVATE));\r
716 \r
717   NewPrivateFile->FileName = NULL;\r
718   Status = gBS->AllocatePool (\r
719                   EfiBootServicesData,\r
720                   AsciiStrSize (PrivateFile->FileName) + 1 + StrLen (FileName) + 1,\r
721                   (VOID **)&NewPrivateFile->FileName\r
722                   );\r
723 \r
724   if (EFI_ERROR (Status)) {\r
725     goto Done;\r
726   }\r
727 \r
728   if (*FileName == L'\\') {\r
729     AsciiStrCpy (NewPrivateFile->FileName, PrivateRoot->FilePath);\r
730     // Skip first '\'.
731     Src = FileName + 1;
732   } else {\r
733     AsciiStrCpy (NewPrivateFile->FileName, PrivateFile->FileName);\r
734     Src = FileName;
735   }\r
736   Dst = NewPrivateFile->FileName + AsciiStrLen(NewPrivateFile->FileName);
737   GuardPointer = NewPrivateFile->FileName + AsciiStrLen(PrivateRoot->FilePath);
738   *Dst++ = '/';
739   // Convert unicode to ascii and '\' to '/'
740   while (*Src) {
741     if (*Src == '\\')
742       *Dst++ = '/';
743     else
744       *Dst++ = *Src;
745     Src++;
746   }
747   *Dst = 0;
748       
749 \r
750   //\r
751   // Get rid of . and .., except leading . or ..\r
752   //\r
753 \r
754   //\r
755   // GuardPointer protect simplefilesystem root path not be destroyed\r
756   //\r
757 \r
758   LoopFinish    = FALSE;\r
759 \r
760   while (!LoopFinish) {\r
761 \r
762     LoopFinish = TRUE;\r
763 \r
764     for (ParseFileName = GuardPointer; *ParseFileName; ParseFileName++) {\r
765       if (*ParseFileName == '.' &&\r
766           (*(ParseFileName + 1) == 0 || *(ParseFileName + 1) == '/') &&\r
767           *(ParseFileName - 1) == '/'\r
768           ) {\r
769 \r
770         //\r
771         // cut /.\r
772         //\r
773         CutPrefix (ParseFileName - 1, 2);\r
774         LoopFinish = FALSE;\r
775         break;\r
776       }\r
777 \r
778       if (*ParseFileName == '.' &&\r
779           *(ParseFileName + 1) == '.' &&\r
780           (*(ParseFileName + 2) == 0 || *(ParseFileName + 2) == '/') &&\r
781           *(ParseFileName - 1) == '/'\r
782           ) {\r
783 \r
784         ParseFileName--;\r
785         Count = 3;\r
786 \r
787         while (ParseFileName != GuardPointer) {\r
788           ParseFileName--;\r
789           Count++;\r
790           if (*ParseFileName == '/') {\r
791             break;\r
792           }\r
793         }\r
794 \r
795         //\r
796         // cut /.. and its left directory\r
797         //\r
798         CutPrefix (ParseFileName, Count);\r
799         LoopFinish = FALSE;\r
800         break;\r
801       }\r
802     }\r
803   }\r
804 \r
805   if (AsciiStrCmp (NewPrivateFile->FileName, PrivateRoot->FilePath) == 0) {\r
806     NewPrivateFile->IsRootDirectory = TRUE;\r
807     gBS->FreePool (NewPrivateFile->FileName);\r
808     gBS->FreePool (NewPrivateFile);\r
809     goto OpenRoot;\r
810   }\r
811 \r
812   RealFileName = NewPrivateFile->FileName + AsciiStrLen(NewPrivateFile->FileName) - 1;\r
813   while (RealFileName > NewPrivateFile->FileName && *RealFileName != '/')
814     RealFileName--;
815 \r
816   TempChar            = *(RealFileName - 1);\r
817   *(RealFileName - 1) = 0;\r
818 \r
819   *(RealFileName - 1)             = TempChar;\r
820 \r
821
822
823   //\r
824   // Test whether file or directory\r
825   //\r
826   NewPrivateFile->IsRootDirectory = FALSE;\r
827   NewPrivateFile->fd = -1;
828   NewPrivateFile->Dir = NULL;
829   if (OpenMode & EFI_FILE_MODE_CREATE) {\r
830     if (Attributes & EFI_FILE_DIRECTORY) {\r
831       NewPrivateFile->IsDirectoryPath = TRUE;\r
832     } else {\r
833       NewPrivateFile->IsDirectoryPath = FALSE;\r
834     }\r
835   } else {\r
836     struct stat finfo;
837     int res = NewPrivateFile->UnixThunk->Stat (NewPrivateFile->FileName, &finfo);
838     if (res == 0 && S_ISDIR(finfo.st_mode))
839       NewPrivateFile->IsDirectoryPath = TRUE;\r
840     else
841       NewPrivateFile->IsDirectoryPath = FALSE;\r
842   }\r
843 \r
844   if (OpenMode & EFI_FILE_MODE_WRITE) {\r
845     NewPrivateFile->IsOpenedByRead = FALSE;\r
846   } else {\r
847     NewPrivateFile->IsOpenedByRead = TRUE;\r
848   }\r
849 \r
850   Status = EFI_SUCCESS;\r
851 \r
852   //\r
853   // deal with directory\r
854   //\r
855   if (NewPrivateFile->IsDirectoryPath) {\r
856 \r
857     if ((OpenMode & EFI_FILE_MODE_CREATE)) {\r
858       //\r
859       // Create a directory\r
860       //\r
861       if (NewPrivateFile->UnixThunk->MkDir (NewPrivateFile->FileName, 0777) != 0) {\r
862         INTN LastError;
863 \r
864         LastError = PrivateFile->UnixThunk->GetErrno ();\r
865         if (LastError != EEXIST) {
866           //gBS->FreePool (TempFileName);\r
867           Status = EFI_ACCESS_DENIED;\r
868           goto Done;\r
869         }\r
870       }\r
871     }\r
872 \r
873     NewPrivateFile->Dir = NewPrivateFile->UnixThunk->OpenDir
874       (NewPrivateFile->FileName);
875 \r
876     if (NewPrivateFile->Dir == NULL) {
877       if (PrivateFile->UnixThunk->GetErrno () == EACCES) {
878         Status                    = EFI_ACCESS_DENIED;\r
879       } else {\r
880         Status = EFI_NOT_FOUND;\r
881       }\r
882 \r
883       goto Done;\r
884     }\r
885 \r
886   } else {\r
887     //\r
888     // deal with file\r
889     //\r
890     NewPrivateFile->fd = NewPrivateFile->UnixThunk->Open
891       (NewPrivateFile->FileName,\r
892        ((OpenMode & EFI_FILE_MODE_CREATE) ? O_CREAT : 0)
893        | (NewPrivateFile->IsOpenedByRead ? O_RDONLY : O_RDWR),
894        0666);
895     if (NewPrivateFile->fd < 0) {
896       if (PrivateFile->UnixThunk->GetErrno () == ENOENT) {
897         Status = EFI_NOT_FOUND;\r
898       } else {\r
899         Status = EFI_ACCESS_DENIED;\r
900       }\r
901     }\r
902   }\r
903 \r
904   if ((OpenMode & EFI_FILE_MODE_CREATE) && Status == EFI_SUCCESS) {\r
905     //\r
906     // Set the attribute\r
907     //\r
908     InfoSize  = 0;\r
909     Info      = NULL;\r
910 \r
911     Status    = UnixSimpleFileSystemGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info);\r
912 \r
913     if (Status != EFI_BUFFER_TOO_SMALL) {\r
914       Status = EFI_DEVICE_ERROR;\r
915       goto Done;\r
916     }\r
917 \r
918     Status = gBS->AllocatePool (\r
919                     EfiBootServicesData,\r
920                     InfoSize,\r
921                     (VOID **)&Info\r
922                     );\r
923 \r
924     if (EFI_ERROR (Status)) {\r
925       goto Done;\r
926     }\r
927 \r
928     Status = UnixSimpleFileSystemGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info);\r
929 \r
930     if (EFI_ERROR (Status)) {\r
931       goto Done;\r
932     }\r
933 \r
934     Info->Attribute = Attributes;\r
935 \r
936     UnixSimpleFileSystemSetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, InfoSize, Info);\r
937   }\r
938 \r
939 Done: ;\r
940   if (TrailingDash) {\r
941     FileName[StrLen (FileName) + 1]  = 0;\r
942     FileName[StrLen (FileName)]      = L'\\';\r
943   }\r
944 \r
945   if (EFI_ERROR (Status)) {\r
946     if (NewPrivateFile) {\r
947       if (NewPrivateFile->FileName) {\r
948         gBS->FreePool (NewPrivateFile->FileName);\r
949       }\r
950 \r
951       gBS->FreePool (NewPrivateFile);\r
952     }\r
953   } else {\r
954     *NewHandle = &NewPrivateFile->EfiFile;\r
955   }\r
956 \r
957   return Status;\r
958 }\r
959 \r
960 EFI_STATUS\r
961 EFIAPI\r
962 UnixSimpleFileSystemClose (\r
963   IN EFI_FILE  *This\r
964   )\r
965 /*++\r
966 \r
967 Routine Description:\r
968 \r
969   Close the specified file handle.\r
970 \r
971 Arguments:\r
972 \r
973   This  - Pointer to a returned opened file handle.\r
974 \r
975 Returns:\r
976 \r
977   EFI_SUCCESS - The file handle has been closed.\r
978 \r
979 --*/\r
980 // TODO:    EFI_INVALID_PARAMETER - add return value to function comment\r
981 {\r
982   UNIX_EFI_FILE_PRIVATE *PrivateFile;\r
983 \r
984   if (This == NULL) {\r
985     return EFI_INVALID_PARAMETER;\r
986   }\r
987 \r
988   PrivateFile = UNIX_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
989 \r
990   if (PrivateFile->fd >= 0) {
991     PrivateFile->UnixThunk->Close (PrivateFile->fd);\r
992   }
993   if (PrivateFile->Dir != NULL) {
994     PrivateFile->UnixThunk->CloseDir (PrivateFile->Dir);\r
995   }
996 \r
997   PrivateFile->fd = -1;
998   PrivateFile->Dir = NULL;
999 \r
1000   if (PrivateFile->FileName) {\r
1001     gBS->FreePool (PrivateFile->FileName);\r
1002   }\r
1003 \r
1004   gBS->FreePool (PrivateFile);\r
1005   return EFI_SUCCESS;\r
1006 }\r
1007 \r
1008 EFI_STATUS\r
1009 EFIAPI\r
1010 UnixSimpleFileSystemDelete (\r
1011   IN EFI_FILE  *This\r
1012   )\r
1013 /*++\r
1014 \r
1015 Routine Description:\r
1016 \r
1017   Close and delete a file.\r
1018 \r
1019 Arguments:\r
1020 \r
1021   This  - Pointer to a returned opened file handle.\r
1022 \r
1023 Returns:\r
1024 \r
1025   EFI_SUCCESS             - The file handle was closed and deleted.\r
1026 \r
1027   EFI_WARN_DELETE_FAILURE - The handle was closed but could not be deleted.\r
1028 \r
1029 --*/\r
1030 // TODO:    EFI_INVALID_PARAMETER - add return value to function comment\r
1031 {\r
1032   EFI_STATUS              Status;\r
1033   UNIX_EFI_FILE_PRIVATE *PrivateFile;\r
1034 \r
1035   if (This == NULL) {\r
1036     return EFI_INVALID_PARAMETER;\r
1037   }\r
1038 \r
1039   PrivateFile = UNIX_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
1040 \r
1041   Status      = EFI_WARN_DELETE_FAILURE;\r
1042 \r
1043   if (PrivateFile->IsDirectoryPath) {\r
1044     if (PrivateFile->Dir != NULL) {\r
1045       PrivateFile->UnixThunk->CloseDir (PrivateFile->Dir);\r
1046       PrivateFile->Dir = NULL;
1047     }\r
1048 \r
1049     if (PrivateFile->UnixThunk->RmDir (PrivateFile->FileName) == 0) {\r
1050       Status = EFI_SUCCESS;\r
1051     }\r
1052   } else {\r
1053     PrivateFile->UnixThunk->Close (PrivateFile->fd);\r
1054     PrivateFile->fd = -1;
1055 \r
1056     if (!PrivateFile->IsOpenedByRead) {\r
1057       if (!PrivateFile->UnixThunk->UnLink (PrivateFile->FileName)) {\r
1058         Status = EFI_SUCCESS;\r
1059       }\r
1060     }\r
1061   }\r
1062 \r
1063   gBS->FreePool (PrivateFile->FileName);\r
1064   gBS->FreePool (PrivateFile);\r
1065 \r
1066   return Status;\r
1067 }\r
1068 \r
1069 STATIC\r
1070 VOID\r
1071 UnixSystemTimeToEfiTime (\r
1072   EFI_UNIX_THUNK_PROTOCOL        *UnixThunk,\r
1073   IN time_t                 SystemTime,
1074   OUT EFI_TIME              *Time\r
1075   )\r
1076 /*++\r
1077 \r
1078 Routine Description:\r
1079 \r
1080   TODO: Add function description\r
1081 \r
1082 Arguments:\r
1083 \r
1084   SystemTime  - TODO: add argument description\r
1085   TimeZone    - TODO: add argument description\r
1086   Time        - TODO: add argument description\r
1087 \r
1088 Returns:\r
1089 \r
1090   TODO: add return values\r
1091 \r
1092 --*/\r
1093 {\r
1094   struct tm *tm;
1095   tm = UnixThunk->GmTime (&SystemTime);
1096   Time->Year   = tm->tm_year;
1097   Time->Month  = tm->tm_mon;
1098   Time->Day    = tm->tm_mday;
1099   Time->Hour   = tm->tm_hour;
1100   Time->Minute = tm->tm_min;
1101   Time->Second = tm->tm_sec;
1102   Time->Nanosecond  = 0;
1103
1104   Time->TimeZone    = UnixThunk->GetTimeZone ();
1105 \r
1106   if (UnixThunk->GetDayLight ()) {
1107     Time->Daylight = EFI_TIME_ADJUST_DAYLIGHT;\r
1108   }\r
1109 }\r
1110 \r
1111 STATIC\r
1112 EFI_STATUS\r
1113 UnixSimpleFileSystemFileInfo (\r
1114   UNIX_EFI_FILE_PRIVATE          *PrivateFile,\r
1115   IN     CHAR8                    *FileName,
1116   IN OUT UINTN                    *BufferSize,\r
1117   OUT    VOID                     *Buffer\r
1118   )\r
1119 /*++\r
1120 \r
1121 Routine Description:\r
1122 \r
1123   TODO: Add function description\r
1124 \r
1125 Arguments:\r
1126 \r
1127   PrivateFile - TODO: add argument description\r
1128   BufferSize  - TODO: add argument description\r
1129   Buffer      - TODO: add argument description\r
1130 \r
1131 Returns:\r
1132 \r
1133   TODO: add return values\r
1134 \r
1135 --*/\r
1136 {\r
1137   EFI_STATUS                  Status;\r
1138   UINTN                       Size;\r
1139   UINTN                       NameSize;\r
1140   UINTN                       ResultSize;\r
1141   EFI_FILE_INFO               *Info;\r
1142   CHAR8                      *RealFileName;\r
1143   CHAR8                      *TempPointer;\r
1144   CHAR16                      *BufferFileName;
1145   struct stat                 buf;
1146 \r
1147   if (FileName != NULL) {
1148     RealFileName = FileName;
1149   }
1150   else if (PrivateFile->IsRootDirectory) {\r
1151     RealFileName = "";
1152   } else {\r
1153     RealFileName  = PrivateFile->FileName;\r
1154   }
1155
1156   TempPointer   = RealFileName;\r
1157   while (*TempPointer) {\r
1158     if (*TempPointer == '/') {\r
1159       RealFileName = TempPointer + 1;\r
1160     }\r
1161 \r
1162     TempPointer++;\r
1163   }\r
1164
1165   Size        = SIZE_OF_EFI_FILE_INFO;\r
1166   NameSize    = AsciiStrSize (RealFileName) * 2;\r
1167   ResultSize  = Size + NameSize;\r
1168 \r
1169   if (*BufferSize < ResultSize) {\r
1170     *BufferSize = ResultSize;\r
1171     return EFI_BUFFER_TOO_SMALL;\r
1172   }
1173   if (PrivateFile->UnixThunk->Stat (
1174           FileName == NULL ? PrivateFile->FileName : FileName,
1175           &buf) < 0)
1176     return EFI_DEVICE_ERROR;
1177
1178   Status  = EFI_SUCCESS;\r
1179 \r
1180   Info    = Buffer;\r
1181   ZeroMem (Info, ResultSize);\r
1182 \r
1183   Info->Size = ResultSize;\r
1184   Info->FileSize      = buf.st_size;
1185   Info->PhysicalSize  = MultU64x32 (buf.st_blocks, buf.st_blksize);
1186 \r
1187   UnixSystemTimeToEfiTime (PrivateFile->UnixThunk, buf.st_ctime, &Info->CreateTime);
1188   UnixSystemTimeToEfiTime (PrivateFile->UnixThunk, buf.st_atime, &Info->LastAccessTime);
1189   UnixSystemTimeToEfiTime (PrivateFile->UnixThunk, buf.st_mtime, &Info->ModificationTime);
1190
1191   if (!(buf.st_mode & S_IWUSR)) {
1192     Info->Attribute |= EFI_FILE_READ_ONLY;\r
1193   }\r
1194 \r
1195   if (S_ISDIR(buf.st_mode)) {
1196     Info->Attribute |= EFI_FILE_DIRECTORY;\r
1197   }\r
1198 \r
1199 \r
1200   BufferFileName = (CHAR16 *)((CHAR8 *) Buffer + Size);
1201   while (*RealFileName)
1202     *BufferFileName++ = *RealFileName++;
1203   *BufferFileName = 0;
1204
1205   *BufferSize = ResultSize;\r
1206   return Status;\r
1207 }\r
1208 \r
1209 EFI_STATUS\r
1210 EFIAPI\r
1211 UnixSimpleFileSystemRead (\r
1212   IN     EFI_FILE  *This,\r
1213   IN OUT UINTN     *BufferSize,\r
1214   OUT    VOID      *Buffer\r
1215   )\r
1216 /*++\r
1217 \r
1218 Routine Description:\r
1219 \r
1220   Read data from a file.\r
1221 \r
1222 Arguments:\r
1223 \r
1224   This        - Pointer to a returned open file handle.\r
1225 \r
1226   BufferSize  - On input, the size of the Buffer.  On output, the number of bytes stored in the Buffer.\r
1227 \r
1228   Buffer      - Pointer to the first byte of the read Buffer.\r
1229 \r
1230 Returns:\r
1231 \r
1232   EFI_SUCCESS           - The data was read.\r
1233 \r
1234   EFI_NO_MEDIA          - The device has no media.\r
1235 \r
1236   EFI_DEVICE_ERROR      - The device reported an error.\r
1237 \r
1238   EFI_VOLUME_CORRUPTED  - The file system structures are corrupted.\r
1239 \r
1240   EFI_BUFFER_TOO_SMALL  - The supplied buffer size was too small to store the current directory entry.\r
1241                           *BufferSize has been updated with the size needed to complete the request.\r
1242 \r
1243 --*/\r
1244 // TODO:    EFI_INVALID_PARAMETER - add return value to function comment\r
1245 {\r
1246   UNIX_EFI_FILE_PRIVATE *PrivateFile;\r
1247   EFI_STATUS              Status;\r
1248   INTN                    Res;
1249   UINTN                   Size;\r
1250   UINTN                   NameSize;\r
1251   UINTN                   ResultSize;\r
1252   CHAR8                   *FullFileName;
1253 \r
1254   if (This == NULL || BufferSize == NULL || Buffer == NULL) {\r
1255     return EFI_INVALID_PARAMETER;\r
1256   }\r
1257 \r
1258   PrivateFile = UNIX_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
1259 \r
1260   if (!PrivateFile->IsDirectoryPath) {\r
1261 \r
1262     if (PrivateFile->fd < 0) {\r
1263       return EFI_DEVICE_ERROR;\r
1264     }\r
1265 \r
1266     Res = PrivateFile->UnixThunk->Read (\r
1267                                          PrivateFile->fd,\r
1268                                          Buffer,\r
1269                                          *BufferSize);
1270     if (Res < 0)
1271       return EFI_DEVICE_ERROR;
1272     *BufferSize = Res;
1273     return EFI_SUCCESS;
1274   }\r
1275 \r
1276   //\r
1277   // Read on a directory.
1278   //\r
1279   if (PrivateFile->Dir == NULL) {\r
1280     return EFI_DEVICE_ERROR;\r
1281   }\r
1282
1283   if (PrivateFile->Dirent == NULL) {
1284     PrivateFile->Dirent = PrivateFile->UnixThunk->ReadDir (PrivateFile->Dir);
1285     if (PrivateFile->Dirent == NULL) {
1286       *BufferSize = 0;\r
1287       return EFI_SUCCESS;\r
1288     }
1289   }
1290
1291   Size        = SIZE_OF_EFI_FILE_INFO;\r
1292   NameSize    = AsciiStrLen (PrivateFile->Dirent->d_name) + 1;
1293   ResultSize  = Size + 2 * NameSize;\r
1294 \r
1295   if (*BufferSize < ResultSize) {\r
1296     *BufferSize = ResultSize;\r
1297     return EFI_BUFFER_TOO_SMALL;\r
1298   }
1299   Status  = EFI_SUCCESS;\r
1300 \r
1301   *BufferSize = ResultSize;\r
1302
1303   Status = gBS->AllocatePool (\r
1304                   EfiBootServicesData,\r
1305                   AsciiStrLen(PrivateFile->FileName) + 1 + NameSize,
1306                   (VOID **)&FullFileName
1307                   );\r
1308 \r
1309   if (EFI_ERROR (Status)) {\r
1310     return Status;
1311   }\r
1312                   
1313   AsciiStrCpy(FullFileName, PrivateFile->FileName);
1314   AsciiStrCat(FullFileName, "/");
1315   AsciiStrCat(FullFileName, PrivateFile->Dirent->d_name);
1316   Status = UnixSimpleFileSystemFileInfo (PrivateFile,
1317                                           FullFileName,
1318                                           BufferSize,
1319                                           Buffer);
1320   gBS->FreePool (FullFileName);
1321 \r
1322   PrivateFile->Dirent = NULL;
1323 \r
1324   return Status;
1325 }\r
1326 \r
1327 EFI_STATUS\r
1328 EFIAPI\r
1329 UnixSimpleFileSystemWrite (\r
1330   IN     EFI_FILE  *This,\r
1331   IN OUT UINTN     *BufferSize,\r
1332   IN     VOID      *Buffer\r
1333   )\r
1334 /*++\r
1335 \r
1336 Routine Description:\r
1337 \r
1338   Write data to a file.\r
1339 \r
1340 Arguments:\r
1341 \r
1342   This        - Pointer to an opened file handle.\r
1343 \r
1344   BufferSize  - On input, the number of bytes in the Buffer to write to the file.  On output, the number of bytes\r
1345                 of data written to the file.\r
1346 \r
1347   Buffer      - Pointer to the first by of data in the buffer to write to the file.\r
1348 \r
1349 Returns:\r
1350 \r
1351   EFI_SUCCESS           - The data was written to the file.\r
1352 \r
1353   EFI_UNSUPPORTED       - Writes to an open directory are not supported.\r
1354 \r
1355   EFI_NO_MEDIA          - The device has no media.\r
1356 \r
1357   EFI_DEVICE_ERROR      - The device reported an error.\r
1358 \r
1359   EFI_VOLUME_CORRUPTED  - The file system structures are corrupt.\r
1360 \r
1361   EFI_WRITE_PROTECTED   - The file, directory, volume, or device is write protected.\r
1362 \r
1363   EFI_ACCESS_DENIED     - The file was opened read-only.\r
1364 \r
1365   EFI_VOLUME_FULL       - The volume is full.\r
1366 \r
1367 --*/\r
1368 // TODO:    EFI_INVALID_PARAMETER - add return value to function comment\r
1369 {\r
1370   UNIX_EFI_FILE_PRIVATE *PrivateFile;\r
1371   UINTN Res;
1372 \r
1373   if (This == NULL || BufferSize == NULL || Buffer == NULL) {\r
1374     return EFI_INVALID_PARAMETER;\r
1375   }\r
1376 \r
1377   PrivateFile = UNIX_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
1378 \r
1379   if (PrivateFile->fd < 0) {\r
1380     return EFI_DEVICE_ERROR;\r
1381   }\r
1382 \r
1383   if (PrivateFile->IsDirectoryPath) {\r
1384     return EFI_UNSUPPORTED;\r
1385   }\r
1386 \r
1387   if (PrivateFile->IsOpenedByRead) {\r
1388     return EFI_ACCESS_DENIED;\r
1389   }\r
1390 \r
1391   Res = PrivateFile->UnixThunk->Write (\r
1392                                         PrivateFile->fd,\r
1393                                         Buffer,\r
1394                                         *BufferSize);
1395   if (Res == (UINTN)-1)
1396     return EFI_DEVICE_ERROR;
1397   *BufferSize = Res;
1398   return EFI_SUCCESS;
1399 \r
1400   //\r
1401   // bugbug: need to access unix error reporting\r
1402   //\r
1403 }\r
1404 \r
1405 EFI_STATUS\r
1406 EFIAPI\r
1407 UnixSimpleFileSystemSetPosition (\r
1408   IN EFI_FILE  *This,\r
1409   IN UINT64    Position\r
1410   )\r
1411 /*++\r
1412 \r
1413 Routine Description:\r
1414 \r
1415   Set a file's current position.\r
1416 \r
1417 Arguments:\r
1418 \r
1419   This      - Pointer to an opened file handle.\r
1420 \r
1421   Position  - The byte position from the start of the file to set.\r
1422 \r
1423 Returns:\r
1424 \r
1425   EFI_SUCCESS     - The file position has been changed.\r
1426 \r
1427   EFI_UNSUPPORTED - The seek request for non-zero is not supported for directories.\r
1428 \r
1429 --*/\r
1430 // TODO:    EFI_INVALID_PARAMETER - add return value to function comment\r
1431 {\r
1432   EFI_STATUS              Status;\r
1433   UNIX_EFI_FILE_PRIVATE *PrivateFile;\r
1434   UINT64                  Pos;\r
1435 \r
1436   if (This == NULL) {\r
1437     return EFI_INVALID_PARAMETER;\r
1438   }\r
1439 \r
1440   PrivateFile = UNIX_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
1441 \r
1442   if (PrivateFile->IsDirectoryPath) {\r
1443     if (Position != 0) {\r
1444       return EFI_UNSUPPORTED;\r
1445     }\r
1446 \r
1447     if (PrivateFile->Dir == NULL) {
1448       return EFI_DEVICE_ERROR;
1449     }
1450     PrivateFile->UnixThunk->RewindDir (PrivateFile->Dir);
1451     return EFI_SUCCESS;\r
1452   } else {\r
1453     if (Position == (UINT64) -1) {\r
1454       Pos = PrivateFile->UnixThunk->Lseek (PrivateFile->fd, 0, SEEK_END);\r
1455     } else {\r
1456       Pos = PrivateFile->UnixThunk->Lseek (PrivateFile->fd, Position, SEEK_SET);\r
1457     }
1458     Status = (Pos == (UINT64) -1) ? EFI_DEVICE_ERROR : EFI_SUCCESS;\r
1459 \r
1460     return Status;\r
1461   }\r
1462 }\r
1463 \r
1464 EFI_STATUS\r
1465 EFIAPI\r
1466 UnixSimpleFileSystemGetPosition (\r
1467   IN  EFI_FILE  *This,\r
1468   OUT UINT64    *Position\r
1469   )\r
1470 /*++\r
1471 \r
1472 Routine Description:\r
1473 \r
1474   Get a file's current position.\r
1475 \r
1476 Arguments:\r
1477 \r
1478   This      - Pointer to an opened file handle.\r
1479 \r
1480   Position  - Pointer to storage for the current position.\r
1481 \r
1482 Returns:\r
1483 \r
1484   EFI_SUCCESS     - The file position has been reported.\r
1485 \r
1486   EFI_UNSUPPORTED - Not valid for directories.\r
1487 \r
1488 --*/\r
1489 // TODO:    EFI_INVALID_PARAMETER - add return value to function comment\r
1490 {\r
1491   UNIX_EFI_FILE_PRIVATE *PrivateFile;\r
1492 \r
1493   if (This == NULL || Position == NULL) {\r
1494     return EFI_INVALID_PARAMETER;\r
1495   }\r
1496 \r
1497   PrivateFile   = UNIX_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
1498 \r
1499   if (PrivateFile->IsDirectoryPath) {\r
1500     return EFI_UNSUPPORTED;\r
1501   } else {\r
1502     *Position = PrivateFile->UnixThunk->Lseek (PrivateFile->fd, 0, SEEK_CUR);
1503     return (*Position == (UINT64) -1) ? EFI_DEVICE_ERROR : EFI_SUCCESS;\r
1504   }\r
1505 }\r
1506 \r
1507 EFI_STATUS\r
1508 EFIAPI\r
1509 UnixSimpleFileSystemGetInfo (\r
1510   IN     EFI_FILE  *This,\r
1511   IN     EFI_GUID  *InformationType,\r
1512   IN OUT UINTN     *BufferSize,\r
1513   OUT    VOID      *Buffer\r
1514   )\r
1515 /*++\r
1516 \r
1517 Routine Description:\r
1518 \r
1519   Return information about a file or volume.\r
1520 \r
1521 Arguments:\r
1522 \r
1523   This            - Pointer to an opened file handle.\r
1524 \r
1525   InformationType - GUID describing the type of information to be returned.\r
1526 \r
1527   BufferSize      - On input, the size of the information buffer.  On output, the number of bytes written to the\r
1528                     information buffer.\r
1529 \r
1530   Buffer          - Pointer to the first byte of the information buffer.\r
1531 \r
1532 Returns:\r
1533 \r
1534   EFI_SUCCESS           - The requested information has been written into the buffer.\r
1535 \r
1536   EFI_UNSUPPORTED       - The InformationType is not known.\r
1537 \r
1538   EFI_NO_MEDIA          - The device has no media.\r
1539 \r
1540   EFI_DEVICE_ERROR      - The device reported an error.\r
1541 \r
1542   EFI_VOLUME_CORRUPTED  - The file system structures are corrupt.\r
1543 \r
1544   EFI_BUFFER_TOO_SMALL  - The buffer size was too small to contain the requested information.  The buffer size has\r
1545                           been updated with the size needed to complete the requested operation.\r
1546 \r
1547 --*/\r
1548 // TODO:    EFI_INVALID_PARAMETER - add return value to function comment\r
1549 {\r
1550   EFI_STATUS                        Status;\r
1551   UNIX_EFI_FILE_PRIVATE           *PrivateFile;\r
1552   EFI_FILE_SYSTEM_INFO              *FileSystemInfoBuffer;\r
1553   INTN                              UnixStatus;\r
1554   UNIX_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;\r
1555   struct statfs                     buf;
1556 \r
1557   if (This == NULL || InformationType == NULL || BufferSize == NULL) {\r
1558     return EFI_INVALID_PARAMETER;\r
1559   }\r
1560 \r
1561   PrivateFile = UNIX_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
1562   PrivateRoot = UNIX_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);\r
1563 \r
1564   Status      = EFI_UNSUPPORTED;\r
1565 \r
1566   if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {\r
1567     Status = UnixSimpleFileSystemFileInfo (PrivateFile, NULL, BufferSize, Buffer);\r
1568   }\r
1569   else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {\r
1570     if (*BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel)) {\r
1571       *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);\r
1572       return EFI_BUFFER_TOO_SMALL;\r
1573     }\r
1574 \r
1575     UnixStatus = PrivateFile->UnixThunk->StatFs (PrivateFile->FileName, &buf);
1576     if (UnixStatus < 0)
1577         return EFI_DEVICE_ERROR;\r
1578
1579     FileSystemInfoBuffer            = (EFI_FILE_SYSTEM_INFO *) Buffer;\r
1580     FileSystemInfoBuffer->Size      = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);\r
1581     FileSystemInfoBuffer->ReadOnly  = FALSE;\r
1582 \r
1583     //\r
1584     // Succeeded\r
1585     //\r
1586     FileSystemInfoBuffer->VolumeSize  = MultU64x32 (buf.f_blocks, buf.f_bsize);
1587     FileSystemInfoBuffer->FreeSpace   = MultU64x32 (buf.f_bavail, buf.f_bsize);
1588     FileSystemInfoBuffer->BlockSize   = buf.f_bsize;
1589 \r
1590 \r
1591     StrCpy ((CHAR16 *) FileSystemInfoBuffer->VolumeLabel, PrivateRoot->VolumeLabel);\r
1592     *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);\r
1593     Status      = EFI_SUCCESS;\r
1594   }\r
1595 \r
1596   else if (CompareGuid (InformationType,
1597                         &gEfiFileSystemVolumeLabelInfoIdGuid)) {\r
1598     if (*BufferSize < StrSize (PrivateRoot->VolumeLabel)) {\r
1599       *BufferSize = StrSize (PrivateRoot->VolumeLabel);\r
1600       return EFI_BUFFER_TOO_SMALL;\r
1601     }\r
1602 \r
1603     StrCpy ((CHAR16 *) Buffer, PrivateRoot->VolumeLabel);\r
1604     *BufferSize = StrSize (PrivateRoot->VolumeLabel);\r
1605     Status      = EFI_SUCCESS;\r
1606   }\r
1607 \r
1608   return Status;\r
1609 }\r
1610 \r
1611 EFI_STATUS\r
1612 EFIAPI\r
1613 UnixSimpleFileSystemSetInfo (\r
1614   IN EFI_FILE         *This,\r
1615   IN EFI_GUID         *InformationType,\r
1616   IN UINTN            BufferSize,\r
1617   IN VOID             *Buffer\r
1618   )\r
1619 /*++\r
1620 \r
1621 Routine Description:\r
1622 \r
1623   Set information about a file or volume.\r
1624 \r
1625 Arguments:\r
1626 \r
1627   This            - Pointer to an opened file handle.\r
1628 \r
1629   InformationType - GUID identifying the type of information to set.\r
1630 \r
1631   BufferSize      - Number of bytes of data in the information buffer.\r
1632 \r
1633   Buffer          - Pointer to the first byte of data in the information buffer.\r
1634 \r
1635 Returns:\r
1636 \r
1637   EFI_SUCCESS           - The file or volume information has been updated.\r
1638 \r
1639   EFI_UNSUPPORTED       - The information identifier is not recognised.\r
1640 \r
1641   EFI_NO_MEDIA          - The device has no media.\r
1642 \r
1643   EFI_DEVICE_ERROR      - The device reported an error.\r
1644 \r
1645   EFI_VOLUME_CORRUPTED  - The file system structures are corrupt.\r
1646 \r
1647   EFI_WRITE_PROTECTED   - The file, directory, volume, or device is write protected.\r
1648 \r
1649   EFI_ACCESS_DENIED     - The file was opened read-only.\r
1650 \r
1651   EFI_VOLUME_FULL       - The volume is full.\r
1652 \r
1653   EFI_BAD_BUFFER_SIZE   - The buffer size is smaller than the type indicated by InformationType.\r
1654 \r
1655 --*/\r
1656 // TODO:    EFI_INVALID_PARAMETER - add return value to function comment\r
1657 // TODO:    EFI_INVALID_PARAMETER - add return value to function comment\r
1658 {\r
1659   UNIX_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;\r
1660   UNIX_EFI_FILE_PRIVATE           *PrivateFile;\r
1661   EFI_FILE_INFO                     *OldFileInfo;\r
1662   EFI_FILE_INFO                     *NewFileInfo;\r
1663   EFI_STATUS                        Status;\r
1664   UINTN                             OldInfoSize;\r
1665   mode_t                            NewAttr;\r
1666   struct stat                       OldAttr;\r
1667   CHAR8                             *OldFileName;\r
1668   CHAR8                             *NewFileName;\r
1669   CHAR8                             *CharPointer;\r
1670   BOOLEAN                           AttrChangeFlag;\r
1671   BOOLEAN                           NameChangeFlag;\r
1672   BOOLEAN                           SizeChangeFlag;\r
1673   BOOLEAN                           TimeChangeFlag;\r
1674   struct tm                         NewLastAccessSystemTime;\r
1675   struct tm                         NewLastWriteSystemTime;\r
1676   EFI_FILE_SYSTEM_INFO              *NewFileSystemInfo;\r
1677   CHAR8                             *AsciiFilePtr;
1678   CHAR16                            *UnicodeFilePtr;
1679   INTN                              UnixStatus;
1680 \r
1681   //\r
1682   // Check for invalid parameters.\r
1683   //\r
1684   if (This == NULL || InformationType == NULL || BufferSize == 0 || Buffer == NULL) {\r
1685     return EFI_INVALID_PARAMETER;\r
1686   }\r
1687 \r
1688   //\r
1689   // Initialise locals.\r
1690   //\r
1691   PrivateFile               = UNIX_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
1692   PrivateRoot               = UNIX_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);\r
1693 \r
1694   Status                    = EFI_UNSUPPORTED;\r
1695   OldFileInfo               = NewFileInfo = NULL;\r
1696   OldFileName               = NewFileName = NULL;\r
1697   AttrChangeFlag = NameChangeFlag = SizeChangeFlag = TimeChangeFlag = FALSE;\r
1698 \r
1699   //\r
1700   // Set file system information.\r
1701   //\r
1702   if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {\r
1703     if (BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel)) {\r
1704       return EFI_BAD_BUFFER_SIZE;\r
1705     }\r
1706 \r
1707     NewFileSystemInfo = (EFI_FILE_SYSTEM_INFO *) Buffer;\r
1708 \r
1709     gBS->FreePool (PrivateRoot->VolumeLabel);\r
1710 \r
1711     PrivateRoot->VolumeLabel = NULL;\r
1712     Status = gBS->AllocatePool (\r
1713                     EfiBootServicesData,\r
1714                     StrSize (NewFileSystemInfo->VolumeLabel),\r
1715                     (VOID **)&PrivateRoot->VolumeLabel\r
1716                     );\r
1717 \r
1718     if (EFI_ERROR (Status)) {\r
1719       goto Done;\r
1720     }\r
1721 \r
1722     StrCpy (PrivateRoot->VolumeLabel, NewFileSystemInfo->VolumeLabel);\r
1723 \r
1724     return EFI_SUCCESS;\r
1725   }\r
1726 \r
1727   //\r
1728   // Set volume label information.\r
1729   //\r
1730   if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {\r
1731     if (BufferSize < StrSize (PrivateRoot->VolumeLabel)) {\r
1732       return EFI_BAD_BUFFER_SIZE;\r
1733     }\r
1734 \r
1735     StrCpy (PrivateRoot->VolumeLabel, (CHAR16 *) Buffer);\r
1736 \r
1737     return EFI_SUCCESS;\r
1738   }\r
1739 \r
1740   if (!CompareGuid (InformationType, &gEfiFileInfoGuid)) {\r
1741     return EFI_UNSUPPORTED;\r
1742   }\r
1743 \r
1744   if (BufferSize < SIZE_OF_EFI_FILE_INFO) {\r
1745     return EFI_BAD_BUFFER_SIZE;\r
1746   }\r
1747 \r
1748   //\r
1749   // Set file/directory information.\r
1750   //\r
1751 \r
1752   //\r
1753   // Check for invalid set file information parameters.\r
1754   //\r
1755   NewFileInfo = (EFI_FILE_INFO *) Buffer;\r
1756 \r
1757   if (NewFileInfo->Size <= sizeof (EFI_FILE_INFO) ||\r
1758       (NewFileInfo->Attribute &~(EFI_FILE_VALID_ATTR)) ||\r
1759       (sizeof (UINTN) == 4 && NewFileInfo->Size > 0xFFFFFFFF)\r
1760       ) {\r
1761     return EFI_INVALID_PARAMETER;\r
1762   }\r
1763 \r
1764   //\r
1765   // bugbug: - This is not safe.  We need something like EfiStrMaxSize()\r
1766   // that would have an additional parameter that would be the size\r
1767   // of the string array just in case there are no NULL characters in\r
1768   // the string array.\r
1769   //\r
1770   //\r
1771   // Get current file information so we can determine what kind\r
1772   // of change request this is.\r
1773   //\r
1774   OldInfoSize = 0;\r
1775   Status      = UnixSimpleFileSystemFileInfo (PrivateFile, NULL, &OldInfoSize, NULL);\r
1776 \r
1777   if (Status != EFI_BUFFER_TOO_SMALL) {\r
1778     Status = EFI_DEVICE_ERROR;\r
1779     goto Done;\r
1780   }\r
1781 \r
1782   Status = gBS->AllocatePool (EfiBootServicesData, OldInfoSize,
1783                               (VOID **)&OldFileInfo);\r
1784 \r
1785   if (EFI_ERROR (Status)) {\r
1786     goto Done;\r
1787   }\r
1788 \r
1789   Status = UnixSimpleFileSystemFileInfo (PrivateFile, NULL, &OldInfoSize, OldFileInfo);\r
1790 \r
1791   if (EFI_ERROR (Status)) {\r
1792     goto Done;\r
1793   }\r
1794 \r
1795   Status = gBS->AllocatePool (\r
1796                   EfiBootServicesData,\r
1797                   AsciiStrSize (PrivateFile->FileName),\r
1798                   (VOID **)&OldFileName\r
1799                   );\r
1800 \r
1801   if (EFI_ERROR (Status)) {\r
1802     goto Done;\r
1803   }\r
1804 \r
1805   AsciiStrCpy (OldFileName, PrivateFile->FileName);\r
1806 \r
1807   //\r
1808   // Make full pathname from new filename and rootpath.\r
1809   //\r
1810   if (NewFileInfo->FileName[0] == '\\') {\r
1811     Status = gBS->AllocatePool (\r
1812                     EfiBootServicesData,\r
1813                     AsciiStrLen (PrivateRoot->FilePath) + 1 + StrLen (NewFileInfo->FileName) + 1,\r
1814                     (VOID **)&NewFileName\r
1815                     );\r
1816 \r
1817     if (EFI_ERROR (Status)) {\r
1818       goto Done;\r
1819     }\r
1820 \r
1821     AsciiStrCpy (NewFileName, PrivateRoot->FilePath);\r
1822     AsciiFilePtr = NewFileName + AsciiStrLen(NewFileName);
1823     UnicodeFilePtr = NewFileInfo->FileName + 1;
1824     *AsciiFilePtr++ ='/';
1825   } else {\r
1826     Status = gBS->AllocatePool (\r
1827                     EfiBootServicesData,\r
1828                     AsciiStrLen (PrivateFile->FileName) + 1 + StrLen (NewFileInfo->FileName) + 1,\r
1829                     (VOID **)&NewFileName\r
1830                     );\r
1831 \r
1832     if (EFI_ERROR (Status)) {\r
1833       goto Done;\r
1834     }\r
1835 \r
1836     AsciiStrCpy (NewFileName, PrivateRoot->FilePath);\r
1837     AsciiFilePtr = NewFileName + AsciiStrLen(NewFileName);
1838     while (AsciiFilePtr > NewFileName && AsciiFilePtr[-1] != '/') {
1839       AsciiFilePtr--;
1840     }
1841     UnicodeFilePtr = NewFileInfo->FileName;
1842   }\r
1843   // Convert to ascii.
1844   while (*UnicodeFilePtr) {
1845     *AsciiFilePtr++ = *UnicodeFilePtr++;
1846   }
1847   *AsciiFilePtr = 0;
1848
1849 \r
1850   //\r
1851   // Is there an attribute change request?\r
1852   //\r
1853   if (NewFileInfo->Attribute != OldFileInfo->Attribute) {\r
1854     if ((NewFileInfo->Attribute & EFI_FILE_DIRECTORY) != (OldFileInfo->Attribute & EFI_FILE_DIRECTORY)) {\r
1855       Status = EFI_INVALID_PARAMETER;\r
1856       goto Done;\r
1857     }\r
1858 \r
1859     AttrChangeFlag = TRUE;\r
1860   }\r
1861 \r
1862   //\r
1863   // Is there a name change request?\r
1864   // bugbug: - Need EfiStrCaseCmp()\r
1865   //\r
1866   if (StrCmp (NewFileInfo->FileName, OldFileInfo->FileName)) {\r
1867     NameChangeFlag = TRUE;\r
1868   }\r
1869 \r
1870   //\r
1871   // Is there a size change request?\r
1872   //\r
1873   if (NewFileInfo->FileSize != OldFileInfo->FileSize) {\r
1874     SizeChangeFlag = TRUE;\r
1875   }\r
1876 \r
1877   //\r
1878   // Is there a time stamp change request?\r
1879   //\r
1880   if (!IsZero (&NewFileInfo->CreateTime, sizeof (EFI_TIME)) &&\r
1881       CompareMem (&NewFileInfo->CreateTime, &OldFileInfo->CreateTime, sizeof (EFI_TIME))\r
1882         ) {\r
1883     TimeChangeFlag = TRUE;\r
1884   } else if (!IsZero (&NewFileInfo->LastAccessTime, sizeof (EFI_TIME)) &&\r
1885            CompareMem (&NewFileInfo->LastAccessTime, &OldFileInfo->LastAccessTime, sizeof (EFI_TIME))\r
1886             ) {\r
1887     TimeChangeFlag = TRUE;\r
1888   } else if (!IsZero (&NewFileInfo->ModificationTime, sizeof (EFI_TIME)) &&\r
1889            CompareMem (&NewFileInfo->ModificationTime, &OldFileInfo->ModificationTime, sizeof (EFI_TIME))\r
1890             ) {\r
1891     TimeChangeFlag = TRUE;\r
1892   }\r
1893 \r
1894   //\r
1895   // All done if there are no change requests being made.\r
1896   //\r
1897   if (!(AttrChangeFlag || NameChangeFlag || SizeChangeFlag || TimeChangeFlag)) {\r
1898     Status = EFI_SUCCESS;\r
1899     goto Done;\r
1900   }\r
1901 \r
1902   //\r
1903   // Set file or directory information.\r
1904   //\r
1905   if (PrivateFile->UnixThunk->Stat (OldFileName, &OldAttr) != 0) {
1906     Status = EFI_DEVICE_ERROR;
1907     goto Done;
1908   }
1909 \r
1910   //\r
1911   // Name change.\r
1912   //\r
1913   if (NameChangeFlag) {\r
1914     //\r
1915     // Close the handles first\r
1916     //\r
1917     if (PrivateFile->IsOpenedByRead) {\r
1918       Status = EFI_ACCESS_DENIED;\r
1919       goto Done;\r
1920     }\r
1921 \r
1922     for (CharPointer = NewFileName; *CharPointer != 0 && *CharPointer != L'/'; CharPointer++) {\r
1923     }\r
1924 \r
1925     if (*CharPointer != 0) {\r
1926       Status = EFI_ACCESS_DENIED;\r
1927       goto Done;\r
1928     }\r
1929 \r
1930     UnixStatus = PrivateFile->UnixThunk->Rename (OldFileName, NewFileName);\r
1931 \r
1932     if (UnixStatus == 0) {\r
1933       //\r
1934       // modify file name\r
1935       //\r
1936       gBS->FreePool (PrivateFile->FileName);\r
1937 \r
1938       Status = gBS->AllocatePool (\r
1939                       EfiBootServicesData,\r
1940                       AsciiStrSize (NewFileName),\r
1941                       (VOID **)&PrivateFile->FileName\r
1942                       );\r
1943 \r
1944       if (EFI_ERROR (Status)) {\r
1945         goto Done;\r
1946       }\r
1947 \r
1948       AsciiStrCpy (PrivateFile->FileName, NewFileName);\r
1949     } else {\r
1950       Status    = EFI_DEVICE_ERROR;\r
1951       goto Done;\r
1952     }\r
1953   }\r
1954 \r
1955   //\r
1956   //  Size change\r
1957   //\r
1958   if (SizeChangeFlag) {\r
1959     if (PrivateFile->IsDirectoryPath) {\r
1960       Status = EFI_UNSUPPORTED;\r
1961       goto Done;\r
1962     }\r
1963 \r
1964     if (PrivateFile->IsOpenedByRead || OldFileInfo->Attribute & EFI_FILE_READ_ONLY) {\r
1965       Status = EFI_ACCESS_DENIED;\r
1966       goto Done;\r
1967     }\r
1968 \r
1969     if (PrivateFile->UnixThunk->FTruncate (PrivateFile->fd, NewFileInfo->FileSize) != 0) {\r
1970       Status = EFI_DEVICE_ERROR;\r
1971       goto Done;\r
1972     }\r
1973 \r
1974   }\r
1975 \r
1976   //\r
1977   // Time change\r
1978   //\r
1979   if (TimeChangeFlag) {\r
1980     struct utimbuf utime;
1981 \r
1982     NewLastAccessSystemTime.tm_year    = NewFileInfo->LastAccessTime.Year;\r
1983     NewLastAccessSystemTime.tm_mon     = NewFileInfo->LastAccessTime.Month;\r
1984     NewLastAccessSystemTime.tm_mday    = NewFileInfo->LastAccessTime.Day;\r
1985     NewLastAccessSystemTime.tm_hour    = NewFileInfo->LastAccessTime.Hour;\r
1986     NewLastAccessSystemTime.tm_min     = NewFileInfo->LastAccessTime.Minute;\r
1987     NewLastAccessSystemTime.tm_sec     = NewFileInfo->LastAccessTime.Second;\r
1988     NewLastAccessSystemTime.tm_isdst   = 0;
1989 \r
1990     utime.actime = PrivateFile->UnixThunk->MkTime (&NewLastAccessSystemTime);
1991
1992     NewLastWriteSystemTime.tm_year    = NewFileInfo->ModificationTime.Year;\r
1993     NewLastWriteSystemTime.tm_mon     = NewFileInfo->ModificationTime.Month;\r
1994     NewLastWriteSystemTime.tm_mday    = NewFileInfo->ModificationTime.Day;\r
1995     NewLastWriteSystemTime.tm_hour    = NewFileInfo->ModificationTime.Hour;\r
1996     NewLastWriteSystemTime.tm_min     = NewFileInfo->ModificationTime.Minute;\r
1997     NewLastWriteSystemTime.tm_sec     = NewFileInfo->ModificationTime.Second;\r
1998     NewLastWriteSystemTime.tm_isdst   = 0;
1999 \r
2000     utime.modtime = PrivateFile->UnixThunk->MkTime (&NewLastWriteSystemTime);
2001
2002     if (utime.actime == (time_t)-1 || utime.modtime == (time_t)-1) {
2003       goto Done;\r
2004     }\r
2005 \r
2006     if (PrivateFile->UnixThunk->UTime (PrivateFile->FileName, &utime) == -1) {
2007       goto Done;\r
2008     }\r
2009   }\r
2010 \r
2011   //\r
2012   // No matter about AttrChangeFlag, Attribute must be set.\r
2013   // Because operation before may cause attribute change.\r
2014   //\r
2015   NewAttr = OldAttr.st_mode;\r
2016 \r
2017   if (NewFileInfo->Attribute & EFI_FILE_READ_ONLY) {\r
2018     NewAttr &= ~(S_IRUSR | S_IRGRP | S_IROTH);
2019   } else {\r
2020     NewAttr |= S_IRUSR;
2021   }\r
2022 \r
2023   UnixStatus = PrivateFile->UnixThunk->Chmod (NewFileName, NewAttr);\r
2024 \r
2025   if (UnixStatus != 0) {\r
2026     Status    = EFI_DEVICE_ERROR;\r
2027   }\r
2028 \r
2029 Done:\r
2030   if (OldFileInfo != NULL) {\r
2031     gBS->FreePool (OldFileInfo);\r
2032   }\r
2033 \r
2034   if (OldFileName != NULL) {\r
2035     gBS->FreePool (OldFileName);\r
2036   }\r
2037 \r
2038   if (NewFileName != NULL) {\r
2039     gBS->FreePool (NewFileName);\r
2040   }\r
2041 \r
2042   return Status;\r
2043 }\r
2044 \r
2045 EFI_STATUS\r
2046 EFIAPI\r
2047 UnixSimpleFileSystemFlush (\r
2048   IN EFI_FILE  *This\r
2049   )\r
2050 /*++\r
2051 \r
2052 Routine Description:\r
2053 \r
2054   Flush all modified data to the media.\r
2055 \r
2056 Arguments:\r
2057 \r
2058   This  - Pointer to an opened file handle.\r
2059 \r
2060 Returns:\r
2061 \r
2062   EFI_SUCCESS           - The data has been flushed.\r
2063 \r
2064   EFI_NO_MEDIA          - The device has no media.\r
2065 \r
2066   EFI_DEVICE_ERROR      - The device reported an error.\r
2067 \r
2068   EFI_VOLUME_CORRUPTED  - The file system structures have been corrupted.\r
2069 \r
2070   EFI_WRITE_PROTECTED   - The file, directory, volume, or device is write protected.\r
2071 \r
2072   EFI_ACCESS_DENIED     - The file was opened read-only.\r
2073 \r
2074   EFI_VOLUME_FULL       - The volume is full.\r
2075 \r
2076 --*/\r
2077 // TODO:    EFI_INVALID_PARAMETER - add return value to function comment\r
2078 {\r
2079   UNIX_EFI_FILE_PRIVATE     *PrivateFile;\r
2080 \r
2081   if (This == NULL) {\r
2082     return EFI_INVALID_PARAMETER;\r
2083   }\r
2084 \r
2085   PrivateFile = UNIX_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
2086 \r
2087 \r
2088   if (PrivateFile->IsDirectoryPath) {\r
2089     return EFI_SUCCESS;\r
2090   }\r
2091 \r
2092   if (PrivateFile->IsOpenedByRead) {\r
2093     return EFI_ACCESS_DENIED;\r
2094   }\r
2095 \r
2096   if (PrivateFile->fd < 0) {
2097     return EFI_DEVICE_ERROR;\r
2098   }\r
2099
2100   return PrivateFile->UnixThunk->FSync (PrivateFile->fd) == 0 ? EFI_SUCCESS : EFI_DEVICE_ERROR;\r
2101 \r
2102   //\r
2103   // bugbug: - Use Unix error reporting.\r
2104   //\r
2105 }\r
2106 \r