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