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