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