]> git.proxmox.com Git - mirror_edk2.git/blame - InOsEmuPkg/Unix/Sec/PosixFileSystem.c
Clarify the requirements for the Destination parameter of UnicodeStrToAsciiStr.
[mirror_edk2.git] / InOsEmuPkg / Unix / Sec / PosixFileSystem.c
CommitLineData
949f388f 1/*++ @file
2 POSIX Pthreads to emulate APs and implement threads
3
4Copyright (c) 2011, Apple Inc. All rights reserved.
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution. The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13
14**/
15
16#include "SecMain.h"
17
18
19#define EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE SIGNATURE_32 ('E', 'P', 'f', 's')
20
21typedef struct {
22 UINTN Signature;
23 EMU_IO_THUNK_PROTOCOL *Thunk;
24 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL SimpleFileSystem;
25 CHAR8 *FilePath;
26 CHAR16 *VolumeLabel;
27 BOOLEAN FileHandlesOpen;
28} EMU_SIMPLE_FILE_SYSTEM_PRIVATE;
29
30#define EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS(a) \
31 CR (a, \
32 EMU_SIMPLE_FILE_SYSTEM_PRIVATE, \
33 SimpleFileSystem, \
34 EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE \
35 )
36
37
38#define EMU_EFI_FILE_PRIVATE_SIGNATURE SIGNATURE_32 ('E', 'P', 'f', 'i')
39
40typedef struct {
41 UINTN Signature;
42 EMU_IO_THUNK_PROTOCOL *Thunk;
43 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
44 EFI_FILE_PROTOCOL EfiFile;
45 int fd;
46 DIR *Dir;
47 BOOLEAN IsRootDirectory;
48 BOOLEAN IsDirectoryPath;
49 BOOLEAN IsOpenedByRead;
50 char *FileName;
51 struct dirent *Dirent;
52} EMU_EFI_FILE_PRIVATE;
53
54#define EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS(a) \
55 CR (a, \
56 EMU_EFI_FILE_PRIVATE, \
57 EfiFile, \
58 EMU_EFI_FILE_PRIVATE_SIGNATURE \
59 )
60
61EFI_STATUS
62PosixFileGetInfo (
63 IN EFI_FILE_PROTOCOL *This,
64 IN EFI_GUID *InformationType,
65 IN OUT UINTN *BufferSize,
66 OUT VOID *Buffer
67 );
68
69EFI_STATUS
70PosixFileSetInfo (
71 IN EFI_FILE_PROTOCOL *This,
72 IN EFI_GUID *InformationType,
73 IN UINTN BufferSize,
74 IN VOID *Buffer
75 );
76
77
78EFI_FILE_PROTOCOL gPosixFileProtocol = {
79 EFI_FILE_REVISION,
80 GasketPosixFileOpen,
81 GasketPosixFileCLose,
82 GasketPosixFileDelete,
83 GasketPosixFileRead,
84 GasketPosixFileWrite,
85 GasketPosixFileGetPossition,
86 GasketPosixFileSetPossition,
87 GasketPosixFileGetInfo,
88 GasketPosixFileSetInfo,
89 GasketPosixFileFlush
90};
91
92EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gPosixFileSystemProtocol = {
93 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
94 GasketPosixOpenVolume,
95};
96
97
98/**
99 Open the root directory on a volume.
100
101 @param This Protocol instance pointer.
102 @param Root Returns an Open file handle for the root directory
103
104 @retval EFI_SUCCESS The device was opened.
105 @retval EFI_UNSUPPORTED This volume does not support the file system.
106 @retval EFI_NO_MEDIA The device has no media.
107 @retval EFI_DEVICE_ERROR The device reported an error.
108 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
109 @retval EFI_ACCESS_DENIED The service denied access to the file.
110 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
111
112**/
113EFI_STATUS
114PosixOpenVolume (
115 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
116 OUT EFI_FILE_PROTOCOL **Root
117 )
118{
119 EFI_STATUS Status;
120 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *Private;
121 EMU_EFI_FILE_PRIVATE *PrivateFile;
122
123 Private = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (This);
124
125 Status = EFI_OUT_OF_RESOURCES;
126 PrivateFile = malloc (sizeof (EMU_EFI_FILE_PRIVATE));
127 if (PrivateFile == NULL) {
128 goto Done;
129 }
130
131 PrivateFile->FileName = malloc (AsciiStrSize (Private->FilePath));
132 if (PrivateFile->FileName == NULL) {
133 goto Done;
134 }
135 AsciiStrCpy (PrivateFile->FileName, Private->FilePath);
136
137 PrivateFile->Signature = EMU_EFI_FILE_PRIVATE_SIGNATURE;
138 PrivateFile->Thunk = Private->Thunk;
139 PrivateFile->SimpleFileSystem = This;
140 PrivateFile->IsRootDirectory = TRUE;
141 PrivateFile->IsDirectoryPath = TRUE;
142 PrivateFile->IsOpenedByRead = TRUE;
143
144 CopyMem (&PrivateFile->EfiFile, &gPosixFileProtocol, sizeof (EFI_FILE_PROTOCOL));
145
146 PrivateFile->fd = -1;
147 PrivateFile->Dir = NULL;
148 PrivateFile->Dirent = NULL;
149
150 *Root = &PrivateFile->EfiFile;
151
152 PrivateFile->Dir = opendir (PrivateFile->FileName);
153 if (PrivateFile->Dir == NULL) {
154 Status = EFI_ACCESS_DENIED;
155 } else {
156 Status = EFI_SUCCESS;
157 }
158
159Done:
160 if (EFI_ERROR (Status)) {
161 if (PrivateFile != NULL) {
162 if (PrivateFile->FileName != NULL) {
163 free (PrivateFile->FileName);
164 }
165
166 free (PrivateFile);
167 }
168
169 *Root = NULL;
170 }
171
172 return Status;
173}
174
175
176EFI_STATUS
177ErrnoToEfiStatus ()
178{
179 switch (errno) {
180 case EACCES:
181 return EFI_ACCESS_DENIED;
182
183 case EDQUOT:
184 case ENOSPC:
185 return EFI_VOLUME_FULL;
186
187 default:
188 return EFI_DEVICE_ERROR;
189 }
190}
191
192VOID
193CutPrefix (
194 IN CHAR8 *Str,
195 IN UINTN Count
196 )
197{
198 CHAR8 *Pointer;
199
200 if (AsciiStrLen (Str) < Count) {
201 ASSERT (0);
202 }
203
204 for (Pointer = Str; *(Pointer + Count); Pointer++) {
205 *Pointer = *(Pointer + Count);
206 }
207
208 *Pointer = *(Pointer + Count);
209}
210
211
212VOID
213PosixSystemTimeToEfiTime (
214 IN time_t SystemTime,
215 OUT EFI_TIME *Time
216 )
217{
218 struct tm *tm;
219
220 tm = gmtime (&SystemTime);
221 Time->Year = tm->tm_year;
222 Time->Month = tm->tm_mon + 1;
223 Time->Day = tm->tm_mday;
224 Time->Hour = tm->tm_hour;
225 Time->Minute = tm->tm_min;
226 Time->Second = tm->tm_sec;
227 Time->Nanosecond = 0;
228
229 Time->TimeZone = timezone;
230 Time->Daylight = (daylight ? EFI_TIME_ADJUST_DAYLIGHT : 0) | (tm->tm_isdst > 0 ? EFI_TIME_IN_DAYLIGHT : 0);
231}
232
233
234EFI_STATUS
235UnixSimpleFileSystemFileInfo (
236 EMU_EFI_FILE_PRIVATE *PrivateFile,
237 IN CHAR8 *FileName,
238 IN OUT UINTN *BufferSize,
239 OUT VOID *Buffer
240 )
241{
242 EFI_STATUS Status;
243 UINTN Size;
244 UINTN NameSize;
245 UINTN ResultSize;
246 EFI_FILE_INFO *Info;
247 CHAR8 *RealFileName;
248 CHAR8 *TempPointer;
249 CHAR16 *BufferFileName;
250 struct stat buf;
251
252 if (FileName != NULL) {
253 RealFileName = FileName;
c8f62f95 254 } else if (PrivateFile->IsRootDirectory) {
949f388f 255 RealFileName = "";
256 } else {
257 RealFileName = PrivateFile->FileName;
258 }
259
260 TempPointer = RealFileName;
261 while (*TempPointer) {
262 if (*TempPointer == '/') {
263 RealFileName = TempPointer + 1;
264 }
265
266 TempPointer++;
267 }
268
269 Size = SIZE_OF_EFI_FILE_INFO;
270 NameSize = AsciiStrSize (RealFileName) * 2;
271 ResultSize = Size + NameSize;
272
273 if (*BufferSize < ResultSize) {
274 *BufferSize = ResultSize;
275 return EFI_BUFFER_TOO_SMALL;
276 }
277 if (stat (FileName == NULL ? PrivateFile->FileName : FileName, &buf) < 0) {
278 return EFI_DEVICE_ERROR;
279 }
280
281 Status = EFI_SUCCESS;
282
283 Info = Buffer;
284 ZeroMem (Info, ResultSize);
285
286 Info->Size = ResultSize;
287 Info->FileSize = buf.st_size;
288 Info->PhysicalSize = MultU64x32 (buf.st_blocks, buf.st_blksize);
289
290 PosixSystemTimeToEfiTime (buf.st_ctime, &Info->CreateTime);
291 PosixSystemTimeToEfiTime (buf.st_atime, &Info->LastAccessTime);
292 PosixSystemTimeToEfiTime (buf.st_mtime, &Info->ModificationTime);
293
294 if (!(buf.st_mode & S_IWUSR)) {
295 Info->Attribute |= EFI_FILE_READ_ONLY;
296 }
297
298 if (S_ISDIR(buf.st_mode)) {
299 Info->Attribute |= EFI_FILE_DIRECTORY;
300 }
301
302
303 BufferFileName = (CHAR16 *)((CHAR8 *) Buffer + Size);
304 while (*RealFileName) {
305 *BufferFileName++ = *RealFileName++;
306 }
307 *BufferFileName = 0;
308
309 *BufferSize = ResultSize;
310 return Status;
311}
312
313BOOLEAN
314IsZero (
315 IN VOID *Buffer,
316 IN UINTN Length
317 )
318{
319 if (Buffer == NULL || Length == 0) {
320 return FALSE;
321 }
322
323 if (*(UINT8 *) Buffer != 0) {
324 return FALSE;
325 }
326
327 if (Length > 1) {
328 if (!CompareMem (Buffer, (UINT8 *) Buffer + 1, Length - 1)) {
329 return FALSE;
330 }
331 }
332
333 return TRUE;
334}
335
336
337
338/**
339 Opens a new file relative to the source file's location.
340
341 @param This The protocol instance pointer.
342 @param NewHandle Returns File Handle for FileName.
343 @param FileName Null terminated string. "\", ".", and ".." are supported.
344 @param OpenMode Open mode for file.
345 @param Attributes Only used for EFI_FILE_MODE_CREATE.
346
347 @retval EFI_SUCCESS The device was opened.
348 @retval EFI_NOT_FOUND The specified file could not be found on the device.
349 @retval EFI_NO_MEDIA The device has no media.
350 @retval EFI_MEDIA_CHANGED The media has changed.
351 @retval EFI_DEVICE_ERROR The device reported an error.
352 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
353 @retval EFI_ACCESS_DENIED The service denied access to the file.
354 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
355 @retval EFI_VOLUME_FULL The volume is full.
356
357**/
358EFI_STATUS
359PosixFileOpen (
360 IN EFI_FILE_PROTOCOL *This,
361 OUT EFI_FILE_PROTOCOL **NewHandle,
362 IN CHAR16 *FileName,
363 IN UINT64 OpenMode,
364 IN UINT64 Attributes
365 )
366{
367 EFI_FILE_PROTOCOL *Root;
368 EMU_EFI_FILE_PRIVATE *PrivateFile;
369 EMU_EFI_FILE_PRIVATE *NewPrivateFile;
370 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;
371 EFI_STATUS Status;
372 CHAR16 *Src;
373 char *Dst;
374 CHAR8 *RealFileName;
375 char *ParseFileName;
376 char *GuardPointer;
377 CHAR8 TempChar;
378 UINTN Count;
379 BOOLEAN TrailingDash;
380 BOOLEAN LoopFinish;
381 UINTN InfoSize;
382 EFI_FILE_INFO *Info;
383 struct stat finfo;
384 int res;
385
386
387 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
388 PrivateRoot = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);
389 NewPrivateFile = NULL;
390 Status = EFI_OUT_OF_RESOURCES;
391
392 //
393 // BUGBUG: assume an open of root
394 // if current location, return current data
395 //
396 if ((StrCmp (FileName, L"\\") == 0) ||
397 (StrCmp (FileName, L".") == 0 && PrivateFile->IsRootDirectory)) {
398OpenRoot:
399 Status = PosixOpenVolume (PrivateFile->SimpleFileSystem, &Root);
400 NewPrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (Root);
401 goto Done;
402 }
403
404 TrailingDash = FALSE;
405 if (FileName[StrLen (FileName) - 1] == L'\\') {
406 TrailingDash = TRUE;
407 FileName[StrLen (FileName) - 1] = 0;
408 }
409
410 //
411 // Attempt to open the file
412 //
413 NewPrivateFile = malloc (sizeof (EMU_EFI_FILE_PRIVATE));
414 if (NewPrivateFile == NULL) {
415 goto Done;
416 }
417
418 CopyMem (NewPrivateFile, PrivateFile, sizeof (EMU_EFI_FILE_PRIVATE));
419
420 NewPrivateFile->FileName = malloc (AsciiStrSize (PrivateFile->FileName) + 1 + StrLen (FileName) + 1);
421 if (NewPrivateFile->FileName == NULL) {
422 goto Done;
423 }
424
425 if (*FileName == L'\\') {
426 AsciiStrCpy (NewPrivateFile->FileName, PrivateRoot->FilePath);
427 // Skip first '\'.
428 Src = FileName + 1;
429 } else {
430 AsciiStrCpy (NewPrivateFile->FileName, PrivateFile->FileName);
431 Src = FileName;
432 }
433 Dst = NewPrivateFile->FileName + AsciiStrLen (NewPrivateFile->FileName);
434 GuardPointer = NewPrivateFile->FileName + AsciiStrLen (PrivateRoot->FilePath);
435 *Dst++ = '/';
436 // Convert unicode to ascii and '\' to '/'
437 while (*Src) {
438 if (*Src == '\\') {
439 *Dst++ = '/';
440 } else {
441 *Dst++ = *Src;
442 }
443 Src++;
444 }
445 *Dst = 0;
446
447
448 //
449 // Get rid of . and .., except leading . or ..
450 //
451
452 //
453 // GuardPointer protect simplefilesystem root path not be destroyed
454 //
455
456 LoopFinish = FALSE;
457 while (!LoopFinish) {
458 LoopFinish = TRUE;
459
460 for (ParseFileName = GuardPointer; *ParseFileName; ParseFileName++) {
461 if (*ParseFileName == '.' &&
462 (*(ParseFileName + 1) == 0 || *(ParseFileName + 1) == '/') &&
463 *(ParseFileName - 1) == '/'
464 ) {
465
466 //
467 // cut /.
468 //
469 CutPrefix (ParseFileName - 1, 2);
470 LoopFinish = FALSE;
471 break;
472 }
473
474 if (*ParseFileName == '.' &&
475 *(ParseFileName + 1) == '.' &&
476 (*(ParseFileName + 2) == 0 || *(ParseFileName + 2) == '/') &&
477 *(ParseFileName - 1) == '/'
478 ) {
479
480 ParseFileName--;
481 Count = 3;
482
483 while (ParseFileName != GuardPointer) {
484 ParseFileName--;
485 Count++;
486 if (*ParseFileName == '/') {
487 break;
488 }
489 }
490
491 //
492 // cut /.. and its left directory
493 //
494 CutPrefix (ParseFileName, Count);
495 LoopFinish = FALSE;
496 break;
497 }
498 }
499 }
500
501 if (AsciiStrCmp (NewPrivateFile->FileName, PrivateRoot->FilePath) == 0) {
502 NewPrivateFile->IsRootDirectory = TRUE;
503 free (NewPrivateFile->FileName);
504 free (NewPrivateFile);
505 goto OpenRoot;
506 }
507
508 RealFileName = NewPrivateFile->FileName + AsciiStrLen(NewPrivateFile->FileName) - 1;
509 while (RealFileName > NewPrivateFile->FileName && *RealFileName != '/') {
510 RealFileName--;
511 }
512
513 TempChar = *(RealFileName - 1);
514 *(RealFileName - 1) = 0;
515 *(RealFileName - 1) = TempChar;
516
517
518 //
519 // Test whether file or directory
520 //
521 NewPrivateFile->IsRootDirectory = FALSE;
522 NewPrivateFile->fd = -1;
523 NewPrivateFile->Dir = NULL;
524 if (OpenMode & EFI_FILE_MODE_CREATE) {
525 if (Attributes & EFI_FILE_DIRECTORY) {
526 NewPrivateFile->IsDirectoryPath = TRUE;
527 } else {
528 NewPrivateFile->IsDirectoryPath = FALSE;
529 }
530 } else {
531 res = stat (NewPrivateFile->FileName, &finfo);
532 if (res == 0 && S_ISDIR(finfo.st_mode)) {
533 NewPrivateFile->IsDirectoryPath = TRUE;
534 } else {
535 NewPrivateFile->IsDirectoryPath = FALSE;
536 }
537 }
538
539 if (OpenMode & EFI_FILE_MODE_WRITE) {
540 NewPrivateFile->IsOpenedByRead = FALSE;
541 } else {
542 NewPrivateFile->IsOpenedByRead = TRUE;
543 }
544
545 Status = EFI_SUCCESS;
546
547 //
548 // deal with directory
549 //
550 if (NewPrivateFile->IsDirectoryPath) {
551 if ((OpenMode & EFI_FILE_MODE_CREATE)) {
552 //
553 // Create a directory
554 //
555 if (mkdir (NewPrivateFile->FileName, 0777) != 0) {
556 if (errno != EEXIST) {
557 //free (TempFileName);
558 Status = EFI_ACCESS_DENIED;
559 goto Done;
560 }
561 }
562 }
563
564 NewPrivateFile->Dir = opendir (NewPrivateFile->FileName);
565 if (NewPrivateFile->Dir == NULL) {
566 if (errno == EACCES) {
567 Status = EFI_ACCESS_DENIED;
568 } else {
569 Status = EFI_NOT_FOUND;
570 }
571
572 goto Done;
573 }
574
575 } else {
576 //
577 // deal with file
578 //
579 NewPrivateFile->fd = open (
580 NewPrivateFile->FileName,
581 ((OpenMode & EFI_FILE_MODE_CREATE) ? O_CREAT : 0) | (NewPrivateFile->IsOpenedByRead ? O_RDONLY : O_RDWR),
582 0666
583 );
584 if (NewPrivateFile->fd < 0) {
585 if (errno == ENOENT) {
586 Status = EFI_NOT_FOUND;
587 } else {
588 Status = EFI_ACCESS_DENIED;
589 }
590 }
591 }
592
593 if ((OpenMode & EFI_FILE_MODE_CREATE) && Status == EFI_SUCCESS) {
594 //
595 // Set the attribute
596 //
597 InfoSize = 0;
598 Info = NULL;
599 Status = PosixFileGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info);
600 if (Status != EFI_BUFFER_TOO_SMALL) {
601 Status = EFI_DEVICE_ERROR;
602 goto Done;
603 }
604
605 Info = malloc (InfoSize);
606 if (Info == NULL) {
607 goto Done;
608 }
609
610 Status = PosixFileGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info);
611 if (EFI_ERROR (Status)) {
612 goto Done;
613 }
614
615 Info->Attribute = Attributes;
616 PosixFileSetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, InfoSize, Info);
617
618 free (Info);
619 }
620
621Done: ;
622 if (TrailingDash) {
623 FileName[StrLen (FileName) + 1] = 0;
624 FileName[StrLen (FileName)] = L'\\';
625 }
626
627 if (EFI_ERROR (Status)) {
628 if (NewPrivateFile) {
629 if (NewPrivateFile->FileName) {
630 free (NewPrivateFile->FileName);
631 }
632
633 free (NewPrivateFile);
634 }
635 } else {
636 *NewHandle = &NewPrivateFile->EfiFile;
637 }
638
639 return Status;
640}
641
642
643
644/**
645 Close the file handle
646
647 @param This Protocol instance pointer.
648
649 @retval EFI_SUCCESS The device was opened.
650
651**/
652EFI_STATUS
653PosixFileCLose (
654 IN EFI_FILE_PROTOCOL *This
655 )
656{
657 EMU_EFI_FILE_PRIVATE *PrivateFile;
658
659 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
660
661 if (PrivateFile->fd >= 0) {
662 close (PrivateFile->fd);
663 }
664 if (PrivateFile->Dir != NULL) {
665 closedir (PrivateFile->Dir);
666 }
667
668 PrivateFile->fd = -1;
669 PrivateFile->Dir = NULL;
670
671 if (PrivateFile->FileName) {
672 free (PrivateFile->FileName);
673 }
674
675 free (PrivateFile);
676
677 return EFI_SUCCESS;
678}
679
680
681/**
682 Close and delete the file handle.
683
684 @param This Protocol instance pointer.
685
686 @retval EFI_SUCCESS The device was opened.
687 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.
688
689**/
690EFI_STATUS
691PosixFileDelete (
692 IN EFI_FILE_PROTOCOL *This
693 )
694{
695 EFI_STATUS Status;
696 EMU_EFI_FILE_PRIVATE *PrivateFile;
697
698 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
699 Status = EFI_WARN_DELETE_FAILURE;
700
701 if (PrivateFile->IsDirectoryPath) {
702 if (PrivateFile->Dir != NULL) {
703 closedir (PrivateFile->Dir);
704 PrivateFile->Dir = NULL;
705 }
706
707 if (rmdir (PrivateFile->FileName) == 0) {
708 Status = EFI_SUCCESS;
709 }
710 } else {
711 close (PrivateFile->fd);
712 PrivateFile->fd = -1;
713
714 if (!PrivateFile->IsOpenedByRead) {
715 if (!unlink (PrivateFile->FileName)) {
716 Status = EFI_SUCCESS;
717 }
718 }
719 }
720
721 free (PrivateFile->FileName);
722 free (PrivateFile);
723
724 return Status;
725}
726
727
728/**
729 Read data from the file.
730
731 @param This Protocol instance pointer.
732 @param BufferSize On input size of buffer, on output amount of data in buffer.
733 @param Buffer The buffer in which data is read.
734
735 @retval EFI_SUCCESS Data was read.
736 @retval EFI_NO_MEDIA The device has no media.
737 @retval EFI_DEVICE_ERROR The device reported an error.
738 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
739 @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size.
740
741**/
742EFI_STATUS
743PosixFileRead (
744 IN EFI_FILE_PROTOCOL *This,
745 IN OUT UINTN *BufferSize,
746 OUT VOID *Buffer
747 )
748{
749 EMU_EFI_FILE_PRIVATE *PrivateFile;
750 EFI_STATUS Status;
751 int Res;
752 UINTN Size;
753 UINTN NameSize;
754 UINTN ResultSize;
755 CHAR8 *FullFileName;
756
757
758 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
759
760 if (!PrivateFile->IsDirectoryPath) {
761 if (PrivateFile->fd < 0) {
762 Status = EFI_DEVICE_ERROR;
763 goto Done;
764 }
765
766 Res = read (PrivateFile->fd, Buffer, *BufferSize);
767 if (Res < 0) {
768 Status = EFI_DEVICE_ERROR;
769 goto Done;
770 }
771 *BufferSize = Res;
772 Status = EFI_SUCCESS;
773 goto Done;
774 }
775
776 //
777 // Read on a directory.
778 //
779 if (PrivateFile->Dir == NULL) {
780 Status = EFI_DEVICE_ERROR;
781 goto Done;
782 }
783
784 if (PrivateFile->Dirent == NULL) {
785 PrivateFile->Dirent = readdir (PrivateFile->Dir);
786 if (PrivateFile->Dirent == NULL) {
787 *BufferSize = 0;
788 Status = EFI_SUCCESS;
789 goto Done;
790 }
791 }
792
793 Size = SIZE_OF_EFI_FILE_INFO;
794 NameSize = AsciiStrLen (PrivateFile->Dirent->d_name) + 1;
795 ResultSize = Size + 2 * NameSize;
796
797 if (*BufferSize < ResultSize) {
798 *BufferSize = ResultSize;
799 Status = EFI_BUFFER_TOO_SMALL;
800 goto Done;
801 }
802 Status = EFI_SUCCESS;
803
804 *BufferSize = ResultSize;
805
806 FullFileName = malloc (AsciiStrLen(PrivateFile->FileName) + 1 + NameSize);
807 if (FullFileName == NULL) {
808 Status = EFI_OUT_OF_RESOURCES;
809 goto Done;
810 }
811
812 AsciiStrCpy (FullFileName, PrivateFile->FileName);
813 AsciiStrCat (FullFileName, "/");
814 AsciiStrCat (FullFileName, PrivateFile->Dirent->d_name);
815 Status = UnixSimpleFileSystemFileInfo (
816 PrivateFile,
817 FullFileName,
818 BufferSize,
819 Buffer
820 );
821 free (FullFileName);
822
823 PrivateFile->Dirent = NULL;
824
825Done:
826 return Status;
827}
828
829
830
831/**
832 Write data to a file.
833
834 @param This Protocol instance pointer.
835 @param BufferSize On input size of buffer, on output amount of data in buffer.
836 @param Buffer The buffer in which data to write.
837
838 @retval EFI_SUCCESS Data was written.
839 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
840 @retval EFI_NO_MEDIA The device has no media.
841 @retval EFI_DEVICE_ERROR The device reported an error.
842 @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
843 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
844 @retval EFI_WRITE_PROTECTED The device is write protected.
845 @retval EFI_ACCESS_DENIED The file was open for read only.
846 @retval EFI_VOLUME_FULL The volume is full.
847
848**/
849EFI_STATUS
850PosixFileWrite (
851 IN EFI_FILE_PROTOCOL *This,
852 IN OUT UINTN *BufferSize,
853 IN VOID *Buffer
854 )
855{
856 EMU_EFI_FILE_PRIVATE *PrivateFile;
857 int Res;
858
859
860 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
861
862 if (PrivateFile->fd < 0) {
863 return EFI_DEVICE_ERROR;
864 }
865
866 if (PrivateFile->IsDirectoryPath) {
867 return EFI_UNSUPPORTED;
868 }
869
870 if (PrivateFile->IsOpenedByRead) {
871 return EFI_ACCESS_DENIED;
872 }
873
874 Res = write (PrivateFile->fd, Buffer, *BufferSize);
875 if (Res == (UINTN)-1) {
876 return ErrnoToEfiStatus ();
877 }
878
879 *BufferSize = Res;
880 return EFI_SUCCESS;
881}
882
883
884
885/**
886 Set a files current position
887
888 @param This Protocol instance pointer.
889 @param Position Byte position from the start of the file.
890
891 @retval EFI_SUCCESS Data was written.
892 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
893
894**/
895EFI_STATUS
896PosixFileSetPossition (
897 IN EFI_FILE_PROTOCOL *This,
898 IN UINT64 Position
899 )
900{
901 EMU_EFI_FILE_PRIVATE *PrivateFile;
902 off_t Pos;
903
904 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
905
906 if (PrivateFile->IsDirectoryPath) {
907 if (Position != 0) {
908 return EFI_UNSUPPORTED;
909 }
910
911 if (PrivateFile->Dir == NULL) {
912 return EFI_DEVICE_ERROR;
913 }
914 rewinddir (PrivateFile->Dir);
915 return EFI_SUCCESS;
916 } else {
917 if (Position == (UINT64) -1) {
918 Pos = lseek (PrivateFile->fd, 0, SEEK_END);
919 } else {
920 Pos = lseek (PrivateFile->fd, Position, SEEK_SET);
921 }
922 if (Pos == (off_t)-1) {
923 return ErrnoToEfiStatus ();
924 }
925 return EFI_SUCCESS;
926 }
927}
928
929
930
931/**
932 Get a file's current position
933
934 @param This Protocol instance pointer.
935 @param Position Byte position from the start of the file.
936
937 @retval EFI_SUCCESS Data was written.
938 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..
939
940**/
941EFI_STATUS
942PosixFileGetPossition (
943 IN EFI_FILE_PROTOCOL *This,
944 OUT UINT64 *Position
945 )
946{
947 EFI_STATUS Status;
948 EMU_EFI_FILE_PRIVATE *PrivateFile;
949
950 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
951
952 if (PrivateFile->IsDirectoryPath) {
953 Status = EFI_UNSUPPORTED;
954 } else {
955 *Position = (UINT64)lseek (PrivateFile->fd, 0, SEEK_CUR);
956 Status = (*Position == (UINT64) -1) ? ErrnoToEfiStatus () : EFI_SUCCESS;
957 }
958
959 return Status;
960}
961
962
963/**
964 Get information about a file.
965
966 @param This Protocol instance pointer.
967 @param InformationType Type of information to return in Buffer.
968 @param BufferSize On input size of buffer, on output amount of data in buffer.
969 @param Buffer The buffer to return data.
970
971 @retval EFI_SUCCESS Data was returned.
972 @retval EFI_UNSUPPORTED InformationType is not supported.
973 @retval EFI_NO_MEDIA The device has no media.
974 @retval EFI_DEVICE_ERROR The device reported an error.
975 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
976 @retval EFI_WRITE_PROTECTED The device is write protected.
977 @retval EFI_ACCESS_DENIED The file was open for read only.
978 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
979
980**/
981EFI_STATUS
982PosixFileGetInfo (
983 IN EFI_FILE_PROTOCOL *This,
984 IN EFI_GUID *InformationType,
985 IN OUT UINTN *BufferSize,
986 OUT VOID *Buffer
987 )
988{
989 EFI_STATUS Status;
990 EMU_EFI_FILE_PRIVATE *PrivateFile;
991 EFI_FILE_SYSTEM_INFO *FileSystemInfoBuffer;
992 int UnixStatus;
993 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;
994 struct statfs buf;
995
996 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
997 PrivateRoot = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);
998
999 Status = EFI_SUCCESS;
1000 if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
1001 Status = UnixSimpleFileSystemFileInfo (PrivateFile, NULL, BufferSize, Buffer);
1002 } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
1003 if (*BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel)) {
1004 *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);
1005 return EFI_BUFFER_TOO_SMALL;
1006 }
1007
1008 UnixStatus = statfs (PrivateFile->FileName, &buf);
1009 if (UnixStatus < 0) {
1010 return EFI_DEVICE_ERROR;
1011 }
1012
1013 FileSystemInfoBuffer = (EFI_FILE_SYSTEM_INFO *) Buffer;
1014 FileSystemInfoBuffer->Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);
1015 FileSystemInfoBuffer->ReadOnly = FALSE;
1016
1017 //
1018 // Succeeded
1019 //
1020 FileSystemInfoBuffer->VolumeSize = MultU64x32 (buf.f_blocks, buf.f_bsize);
1021 FileSystemInfoBuffer->FreeSpace = MultU64x32 (buf.f_bavail, buf.f_bsize);
1022 FileSystemInfoBuffer->BlockSize = buf.f_bsize;
1023
1024
1025 StrCpy ((CHAR16 *) FileSystemInfoBuffer->VolumeLabel, PrivateRoot->VolumeLabel);
1026 *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);
1027
1028 } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
1029 if (*BufferSize < StrSize (PrivateRoot->VolumeLabel)) {
1030 *BufferSize = StrSize (PrivateRoot->VolumeLabel);
1031 return EFI_BUFFER_TOO_SMALL;
1032 }
1033
1034 StrCpy ((CHAR16 *) Buffer, PrivateRoot->VolumeLabel);
1035 *BufferSize = StrSize (PrivateRoot->VolumeLabel);
1036
1037 }
1038
1039 return Status;
1040}
1041
1042
1043/**
1044 Set information about a file
1045
1046 @param File Protocol instance pointer.
1047 @param InformationType Type of information in Buffer.
1048 @param BufferSize Size of buffer.
1049 @param Buffer The data to write.
1050
1051 @retval EFI_SUCCESS Data was returned.
1052 @retval EFI_UNSUPPORTED InformationType is not supported.
1053 @retval EFI_NO_MEDIA The device has no media.
1054 @retval EFI_DEVICE_ERROR The device reported an error.
1055 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1056 @retval EFI_WRITE_PROTECTED The device is write protected.
1057 @retval EFI_ACCESS_DENIED The file was open for read only.
1058
1059**/
1060EFI_STATUS
1061PosixFileSetInfo (
1062 IN EFI_FILE_PROTOCOL *This,
1063 IN EFI_GUID *InformationType,
1064 IN UINTN BufferSize,
1065 IN VOID *Buffer
1066 )
1067{
1068 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;
1069 EMU_EFI_FILE_PRIVATE *PrivateFile;
1070 EFI_FILE_INFO *OldFileInfo;
1071 EFI_FILE_INFO *NewFileInfo;
1072 EFI_STATUS Status;
1073 UINTN OldInfoSize;
1074 mode_t NewAttr;
1075 struct stat OldAttr;
1076 CHAR8 *OldFileName;
1077 CHAR8 *NewFileName;
1078 CHAR8 *CharPointer;
1079 BOOLEAN AttrChangeFlag;
1080 BOOLEAN NameChangeFlag;
1081 BOOLEAN SizeChangeFlag;
1082 BOOLEAN TimeChangeFlag;
1083 struct tm NewLastAccessSystemTime;
1084 struct tm NewLastWriteSystemTime;
1085 EFI_FILE_SYSTEM_INFO *NewFileSystemInfo;
1086 CHAR8 *AsciiFilePtr;
1087 CHAR16 *UnicodeFilePtr;
1088 int UnixStatus;
1089 struct utimbuf Utime;
1090
1091
1092 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
1093 PrivateRoot = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);
1094 errno = 0;
1095 Status = EFI_UNSUPPORTED;
1096 OldFileInfo = NewFileInfo = NULL;
1097 OldFileName = NewFileName = NULL;
1098 AttrChangeFlag = NameChangeFlag = SizeChangeFlag = TimeChangeFlag = FALSE;
1099
1100 //
1101 // Set file system information.
1102 //
1103 if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
1104 if (BufferSize < (SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel))) {
1105 Status = EFI_BAD_BUFFER_SIZE;
1106 goto Done;
1107 }
1108
1109 NewFileSystemInfo = (EFI_FILE_SYSTEM_INFO *) Buffer;
1110
1111 free (PrivateRoot->VolumeLabel);
1112
1113 PrivateRoot->VolumeLabel = malloc (StrSize (NewFileSystemInfo->VolumeLabel));
1114 if (PrivateRoot->VolumeLabel == NULL) {
1115 goto Done;
1116 }
1117
1118 StrCpy (PrivateRoot->VolumeLabel, NewFileSystemInfo->VolumeLabel);
1119
1120 Status = EFI_SUCCESS;
1121 goto Done;
1122 }
1123
1124 //
1125 // Set volume label information.
1126 //
1127 if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
1128 if (BufferSize < StrSize (PrivateRoot->VolumeLabel)) {
1129 Status = EFI_BAD_BUFFER_SIZE;
1130 goto Done;
1131 }
1132
1133 StrCpy (PrivateRoot->VolumeLabel, (CHAR16 *) Buffer);
1134
1135 Status = EFI_SUCCESS;
1136 goto Done;
1137 }
1138
1139 if (!CompareGuid (InformationType, &gEfiFileInfoGuid)) {
1140 Status = EFI_UNSUPPORTED;
1141 goto Done;
1142 }
1143
1144 if (BufferSize < SIZE_OF_EFI_FILE_INFO) {
1145 Status = EFI_BAD_BUFFER_SIZE;
1146 goto Done;
1147 }
1148
1149 //
1150 // Set file/directory information.
1151 //
1152
1153 //
1154 // Check for invalid set file information parameters.
1155 //
1156 NewFileInfo = (EFI_FILE_INFO *) Buffer;
1157 if (NewFileInfo->Size <= sizeof (EFI_FILE_INFO) ||
1158 (NewFileInfo->Attribute &~(EFI_FILE_VALID_ATTR)) ||
1159 (sizeof (UINTN) == 4 && NewFileInfo->Size > 0xFFFFFFFF)
1160 ) {
1161 Status = EFI_INVALID_PARAMETER;
1162 goto Done;
1163 }
1164
1165 //
1166 // Get current file information so we can determine what kind
1167 // of change request this is.
1168 //
1169 OldInfoSize = 0;
1170 Status = UnixSimpleFileSystemFileInfo (PrivateFile, NULL, &OldInfoSize, NULL);
1171 if (Status != EFI_BUFFER_TOO_SMALL) {
1172 Status = EFI_DEVICE_ERROR;
1173 goto Done;
1174 }
1175
1176 OldFileInfo = malloc (OldInfoSize);
1177 if (OldFileInfo == NULL) {
1178 goto Done;
1179 }
1180
1181 Status = UnixSimpleFileSystemFileInfo (PrivateFile, NULL, &OldInfoSize, OldFileInfo);
1182 if (EFI_ERROR (Status)) {
1183 goto Done;
1184 }
1185
1186 OldFileName = malloc (AsciiStrSize (PrivateFile->FileName));
1187 if (OldFileInfo == NULL) {
1188 goto Done;
1189 }
1190
1191 AsciiStrCpy (OldFileName, PrivateFile->FileName);
1192
1193 //
1194 // Make full pathname from new filename and rootpath.
1195 //
1196 if (NewFileInfo->FileName[0] == '\\') {
1197 NewFileName = malloc (AsciiStrLen (PrivateRoot->FilePath) + 1 + StrLen (NewFileInfo->FileName) + 1);
1198 if (NewFileName == NULL) {
1199 goto Done;
1200 }
1201
1202 AsciiStrCpy (NewFileName, PrivateRoot->FilePath);
1203 AsciiFilePtr = NewFileName + AsciiStrLen(NewFileName);
1204 UnicodeFilePtr = NewFileInfo->FileName + 1;
1205 *AsciiFilePtr++ ='/';
1206 } else {
1207 NewFileName = malloc (AsciiStrLen (PrivateFile->FileName) + 2 + StrLen (NewFileInfo->FileName) + 1);
1208 if (NewFileName == NULL) {
1209 goto Done;
1210 }
1211
1212 AsciiStrCpy (NewFileName, PrivateRoot->FilePath);
1213 AsciiFilePtr = NewFileName + AsciiStrLen(NewFileName);
1214 if ((AsciiFilePtr[-1] != '/') && (NewFileInfo->FileName[0] != '/')) {
1215 // make sure there is a / between Root FilePath and NewFileInfo Filename
1216 AsciiFilePtr[0] = '/';
1217 AsciiFilePtr[1] = '\0';
1218 AsciiFilePtr++;
1219 }
1220 UnicodeFilePtr = NewFileInfo->FileName;
1221 }
1222 // Convert to ascii.
1223 while (*UnicodeFilePtr) {
1224 *AsciiFilePtr++ = *UnicodeFilePtr++;
1225 }
1226 *AsciiFilePtr = 0;
1227
1228 //
1229 // Is there an attribute change request?
1230 //
1231 if (NewFileInfo->Attribute != OldFileInfo->Attribute) {
1232 if ((NewFileInfo->Attribute & EFI_FILE_DIRECTORY) != (OldFileInfo->Attribute & EFI_FILE_DIRECTORY)) {
1233 Status = EFI_INVALID_PARAMETER;
1234 goto Done;
1235 }
1236
1237 AttrChangeFlag = TRUE;
1238 }
1239
1240 //
1241 // Is there a name change request?
1242 // bugbug: - Should really use EFI_UNICODE_COLLATION_PROTOCOL
1243 //
1244 if (StrCmp (NewFileInfo->FileName, OldFileInfo->FileName)) {
1245 NameChangeFlag = TRUE;
1246 }
1247
1248 //
1249 // Is there a size change request?
1250 //
1251 if (NewFileInfo->FileSize != OldFileInfo->FileSize) {
1252 SizeChangeFlag = TRUE;
1253 }
1254
1255 //
1256 // Is there a time stamp change request?
1257 //
1258 if (!IsZero (&NewFileInfo->CreateTime, sizeof (EFI_TIME)) &&
1259 CompareMem (&NewFileInfo->CreateTime, &OldFileInfo->CreateTime, sizeof (EFI_TIME))
1260 ) {
1261 TimeChangeFlag = TRUE;
1262 } else if (!IsZero (&NewFileInfo->LastAccessTime, sizeof (EFI_TIME)) &&
1263 CompareMem (&NewFileInfo->LastAccessTime, &OldFileInfo->LastAccessTime, sizeof (EFI_TIME))
1264 ) {
1265 TimeChangeFlag = TRUE;
1266 } else if (!IsZero (&NewFileInfo->ModificationTime, sizeof (EFI_TIME)) &&
1267 CompareMem (&NewFileInfo->ModificationTime, &OldFileInfo->ModificationTime, sizeof (EFI_TIME))
1268 ) {
1269 TimeChangeFlag = TRUE;
1270 }
1271
1272 //
1273 // All done if there are no change requests being made.
1274 //
1275 if (!(AttrChangeFlag || NameChangeFlag || SizeChangeFlag || TimeChangeFlag)) {
1276 Status = EFI_SUCCESS;
1277 goto Done;
1278 }
1279
1280 //
1281 // Set file or directory information.
1282 //
1283 if (stat (OldFileName, &OldAttr) != 0) {
1284 Status = ErrnoToEfiStatus ();
1285 goto Done;
1286 }
1287
1288 //
1289 // Name change.
1290 //
1291 if (NameChangeFlag) {
1292 //
1293 // Close the handles first
1294 //
1295 if (PrivateFile->IsOpenedByRead) {
1296 Status = EFI_ACCESS_DENIED;
1297 goto Done;
1298 }
1299
1300 for (CharPointer = NewFileName; *CharPointer != 0 && *CharPointer != L'/'; CharPointer++) {
1301 }
1302
1303 if (*CharPointer != 0) {
1304 Status = EFI_ACCESS_DENIED;
1305 goto Done;
1306 }
1307
1308 UnixStatus = rename (OldFileName, NewFileName);
1309 if (UnixStatus == 0) {
1310 //
1311 // modify file name
1312 //
1313 free (PrivateFile->FileName);
1314
1315 PrivateFile->FileName = malloc (AsciiStrSize (NewFileName));
1316 if (PrivateFile->FileName == NULL) {
1317 goto Done;
1318 }
1319
1320 AsciiStrCpy (PrivateFile->FileName, NewFileName);
1321 } else {
1322 Status = EFI_DEVICE_ERROR;
1323 goto Done;
1324 }
1325 }
1326
1327 //
1328 // Size change
1329 //
1330 if (SizeChangeFlag) {
1331 if (PrivateFile->IsDirectoryPath) {
1332 Status = EFI_UNSUPPORTED;
1333 goto Done;
1334 }
1335
1336 if (PrivateFile->IsOpenedByRead || OldFileInfo->Attribute & EFI_FILE_READ_ONLY) {
1337 Status = EFI_ACCESS_DENIED;
1338 goto Done;
1339 }
1340
1341 if (ftruncate (PrivateFile->fd, NewFileInfo->FileSize) != 0) {
1342 Status = ErrnoToEfiStatus ();
1343 goto Done;
1344 }
1345
1346 }
1347
1348 //
1349 // Time change
1350 //
1351 if (TimeChangeFlag) {
1352 NewLastAccessSystemTime.tm_year = NewFileInfo->LastAccessTime.Year;
1353 NewLastAccessSystemTime.tm_mon = NewFileInfo->LastAccessTime.Month;
1354 NewLastAccessSystemTime.tm_mday = NewFileInfo->LastAccessTime.Day;
1355 NewLastAccessSystemTime.tm_hour = NewFileInfo->LastAccessTime.Hour;
1356 NewLastAccessSystemTime.tm_min = NewFileInfo->LastAccessTime.Minute;
1357 NewLastAccessSystemTime.tm_sec = NewFileInfo->LastAccessTime.Second;
1358 NewLastAccessSystemTime.tm_isdst = 0;
1359
1360 Utime.actime = mktime (&NewLastAccessSystemTime);
1361
1362 NewLastWriteSystemTime.tm_year = NewFileInfo->ModificationTime.Year;
1363 NewLastWriteSystemTime.tm_mon = NewFileInfo->ModificationTime.Month;
1364 NewLastWriteSystemTime.tm_mday = NewFileInfo->ModificationTime.Day;
1365 NewLastWriteSystemTime.tm_hour = NewFileInfo->ModificationTime.Hour;
1366 NewLastWriteSystemTime.tm_min = NewFileInfo->ModificationTime.Minute;
1367 NewLastWriteSystemTime.tm_sec = NewFileInfo->ModificationTime.Second;
1368 NewLastWriteSystemTime.tm_isdst = 0;
1369
1370 Utime.modtime = mktime (&NewLastWriteSystemTime);
1371
1372 if (Utime.actime == (time_t)-1 || Utime.modtime == (time_t)-1) {
1373 goto Done;
1374 }
1375
1376 if (utime (PrivateFile->FileName, &Utime) == -1) {
1377 Status = ErrnoToEfiStatus ();
1378 goto Done;
1379 }
1380 }
1381
1382 //
1383 // No matter about AttrChangeFlag, Attribute must be set.
1384 // Because operation before may cause attribute change.
1385 //
1386 NewAttr = OldAttr.st_mode;
1387
1388 if (NewFileInfo->Attribute & EFI_FILE_READ_ONLY) {
1389 NewAttr &= ~(S_IRUSR | S_IRGRP | S_IROTH);
1390 } else {
1391 NewAttr |= S_IRUSR;
1392 }
1393
1394 if (chmod (NewFileName, NewAttr) != 0) {
1395 Status = ErrnoToEfiStatus ();
1396 }
1397
1398Done:
1399 if (OldFileInfo != NULL) {
1400 free (OldFileInfo);
1401 }
1402
1403 if (OldFileName != NULL) {
1404 free (OldFileName);
1405 }
1406
1407 if (NewFileName != NULL) {
1408 free (NewFileName);
1409 }
1410
1411 return Status;
1412}
1413
1414
1415/**
1416 Flush data back for the file handle.
1417
1418 @param This Protocol instance pointer.
1419
1420 @retval EFI_SUCCESS Data was written.
1421 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
1422 @retval EFI_NO_MEDIA The device has no media.
1423 @retval EFI_DEVICE_ERROR The device reported an error.
1424 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1425 @retval EFI_WRITE_PROTECTED The device is write protected.
1426 @retval EFI_ACCESS_DENIED The file was open for read only.
1427 @retval EFI_VOLUME_FULL The volume is full.
1428
1429**/
1430EFI_STATUS
1431PosixFileFlush (
1432 IN EFI_FILE_PROTOCOL *This
1433 )
1434{
1435 EMU_EFI_FILE_PRIVATE *PrivateFile;
1436
1437
1438 PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
1439
1440 if (PrivateFile->IsDirectoryPath) {
1441 return EFI_UNSUPPORTED;
1442 }
1443
1444 if (PrivateFile->IsOpenedByRead) {
1445 return EFI_ACCESS_DENIED;
1446 }
1447
1448 if (PrivateFile->fd < 0) {
1449 return EFI_DEVICE_ERROR;
1450 }
1451
1452 if (fsync (PrivateFile->fd) != 0) {
1453 return ErrnoToEfiStatus ();
1454 }
1455
1456 return EFI_SUCCESS;
1457}
1458
1459
1460
1461EFI_STATUS
1462PosixFileSystmeThunkOpen (
1463 IN EMU_IO_THUNK_PROTOCOL *This
1464 )
1465{
1466 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *Private;
1467 UINTN i;
1468
1469 if (This->Private != NULL) {
1470 return EFI_ALREADY_STARTED;
1471 }
1472
1473 if (!CompareGuid (This->Protocol, &gEfiSimpleFileSystemProtocolGuid)) {
1474 return EFI_UNSUPPORTED;
1475 }
1476
1477 Private = malloc (sizeof (EMU_SIMPLE_FILE_SYSTEM_PRIVATE));
1478 if (Private == NULL) {
1479 return EFI_OUT_OF_RESOURCES;
1480 }
1481
1482 Private->FilePath = malloc (StrLen (This->ConfigString) + 1);
1483 if (Private->FilePath == NULL) {
1484 free (Private);
1485 return EFI_OUT_OF_RESOURCES;
1486 }
1487
1488 // Convert Unicode to Ascii
1489 for (i = 0; This->ConfigString[i] != 0; i++) {
1490 Private->FilePath[i] = This->ConfigString[i];
1491 }
1492 Private->FilePath[i] = 0;
1493
1494
0c493bf4 1495 Private->VolumeLabel = malloc (StrSize (L"EFI_EMULATED"));
949f388f 1496 if (Private->VolumeLabel == NULL) {
1497 free (Private->FilePath);
1498 free (Private);
1499 return EFI_OUT_OF_RESOURCES;
1500 }
1501 StrCpy (Private->VolumeLabel, L"EFI_EMULATED");
1502
1503 Private->Signature = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE;
1504 Private->Thunk = This;
1505 CopyMem (&Private->SimpleFileSystem, &gPosixFileSystemProtocol, sizeof (Private->SimpleFileSystem));
1506 Private->FileHandlesOpen = FALSE;
1507
1508 This->Interface = &Private->SimpleFileSystem;
1509 This->Private = Private;
1510 return EFI_SUCCESS;
1511}
1512
1513
1514EFI_STATUS
1515PosixFileSystmeThunkClose (
1516 IN EMU_IO_THUNK_PROTOCOL *This
1517 )
1518{
1519 EMU_SIMPLE_FILE_SYSTEM_PRIVATE *Private;
1520
1521 if (!CompareGuid (This->Protocol, &gEfiSimpleFileSystemProtocolGuid)) {
1522 return EFI_UNSUPPORTED;
1523 }
1524
1525 Private = This->Private;
1526
1527 if (Private->FileHandlesOpen) {
1528 //
1529 // Close only supported if all the EFI_FILE_HANDLEs have been closed.
1530 //
1531 return EFI_NOT_READY;
1532 }
1533
1534 if (This->Private != NULL) {
033d0e5f 1535 if (Private->VolumeLabel != NULL) {
949f388f 1536 free (Private->VolumeLabel);
1537 }
1538 free (This->Private);
21ce7a41 1539 This->Private = NULL;
949f388f 1540 }
1541
1542 return EFI_SUCCESS;
1543}
1544
1545
1546EMU_IO_THUNK_PROTOCOL gPosixFileSystemThunkIo = {
1547 &gEfiSimpleFileSystemProtocolGuid,
1548 NULL,
1549 NULL,
1550 0,
1551 GasketPosixFileSystmeThunkOpen,
1552 GasketPosixFileSystmeThunkClose,
1553 NULL
1554};
1555
1556