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