]> git.proxmox.com Git - mirror_edk2.git/blame - EmulatorPkg/Win/Host/WinFileSystem.c
EmbeddedPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / EmulatorPkg / Win / Host / WinFileSystem.c
CommitLineData
56502bf1
RN
1/*++ @file\r
2 Support OS native directory access.\r
3\r
4Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\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 "WinHost.h"\r
17\r
18\r
19#define WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE SIGNATURE_32 ('N', 'T', '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 CHAR16 *FilePath;\r
26 CHAR16 *VolumeLabel;\r
27} WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE;\r
28\r
29#define WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS(a) \\r
30 CR (a, \\r
31 WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE, \\r
32 SimpleFileSystem, \\r
33 WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE \\r
34 )\r
35\r
36\r
37#define WIN_NT_EFI_FILE_PRIVATE_SIGNATURE SIGNATURE_32 ('l', 'o', 'f', 's')\r
38\r
39typedef struct {\r
40 UINTN Signature;\r
41 EMU_IO_THUNK_PROTOCOL *Thunk;\r
42 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;\r
43 EFI_FILE_PROTOCOL EfiFile;\r
44 HANDLE LHandle;\r
45 HANDLE DirHandle;\r
46 BOOLEAN IsRootDirectory;\r
47 BOOLEAN IsDirectoryPath;\r
48 BOOLEAN IsOpenedByRead;\r
49 CHAR16 *FilePath;\r
50 WCHAR *FileName;\r
51 BOOLEAN IsValidFindBuf;\r
52 WIN32_FIND_DATA FindBuf;\r
53} WIN_NT_EFI_FILE_PRIVATE;\r
54\r
55#define WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS(a) \\r
56 CR (a, \\r
57 WIN_NT_EFI_FILE_PRIVATE, \\r
58 EfiFile, \\r
59 WIN_NT_EFI_FILE_PRIVATE_SIGNATURE \\r
60 )\r
61\r
62extern EFI_FILE_PROTOCOL gWinNtFileProtocol;\r
63extern EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gWinNtFileSystemProtocol;\r
64\r
65EFI_STATUS\r
66WinNtFileGetInfo (\r
67 IN EFI_FILE_PROTOCOL *This,\r
68 IN EFI_GUID *InformationType,\r
69 IN OUT UINTN *BufferSize,\r
70 OUT VOID *Buffer\r
71 );\r
72\r
73EFI_STATUS\r
74WinNtFileSetInfo (\r
75 IN EFI_FILE_PROTOCOL *This,\r
76 IN EFI_GUID *InformationType,\r
77 IN UINTN BufferSize,\r
78 IN VOID *Buffer\r
79 );\r
80\r
81\r
82\r
83CHAR16 *\r
84EfiStrChr (\r
85 IN CHAR16 *Str,\r
86 IN CHAR16 Chr\r
87)\r
88/*++\r
89\r
90Routine Description:\r
91\r
92 Locate the first occurance of a character in a string.\r
93\r
94Arguments:\r
95\r
96 Str - Pointer to NULL terminated unicode string.\r
97 Chr - Character to locate.\r
98\r
99Returns:\r
100\r
101 If Str is NULL, then NULL is returned.\r
102 If Chr is not contained in Str, then NULL is returned.\r
103 If Chr is contained in Str, then a pointer to the first occurance of Chr in Str is returned.\r
104\r
105--*/\r
106{\r
107 if (Str == NULL) {\r
108 return Str;\r
109 }\r
110\r
111 while (*Str != '\0' && *Str != Chr) {\r
112 ++Str;\r
113 }\r
114\r
115 return (*Str == Chr) ? Str : NULL;\r
116}\r
117\r
118\r
119\r
120BOOLEAN\r
121IsZero (\r
122 IN VOID *Buffer,\r
123 IN UINTN Length\r
124 )\r
125{\r
126 if (Buffer == NULL || Length == 0) {\r
127 return FALSE;\r
128 }\r
129\r
130 if (*(UINT8 *) Buffer != 0) {\r
131 return FALSE;\r
132 }\r
133\r
134 if (Length > 1) {\r
135 if (!CompareMem (Buffer, (UINT8 *) Buffer + 1, Length - 1)) {\r
136 return FALSE;\r
137 }\r
138 }\r
139\r
140 return TRUE;\r
141}\r
142\r
143VOID\r
144CutPrefix (\r
145 IN CHAR16 *Str,\r
146 IN UINTN Count\r
147 )\r
148{\r
149 CHAR16 *Pointer;\r
150\r
151 if (StrLen (Str) < Count) {\r
152 ASSERT (0);\r
153 }\r
154\r
155 if (Count != 0) {\r
156 for (Pointer = Str; *(Pointer + Count); Pointer++) {\r
157 *Pointer = *(Pointer + Count);\r
158 }\r
159\r
160 *Pointer = *(Pointer + Count);\r
161 }\r
162}\r
163/**\r
164 Open the root directory on a volume.\r
165\r
166 @param This Protocol instance pointer.\r
167 @param Root Returns an Open file handle for the root directory\r
168\r
169 @retval EFI_SUCCESS The device was opened.\r
170 @retval EFI_UNSUPPORTED This volume does not support the file system.\r
171 @retval EFI_NO_MEDIA The device has no media.\r
172 @retval EFI_DEVICE_ERROR The device reported an error.\r
173 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
174 @retval EFI_ACCESS_DENIED The service denied access to the file.\r
175 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.\r
176\r
177**/\r
178EFI_STATUS\r
179WinNtOpenVolume (\r
180 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,\r
181 OUT EFI_FILE_PROTOCOL **Root\r
182 )\r
183{\r
184 EFI_STATUS Status;\r
185 WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *Private;\r
186 WIN_NT_EFI_FILE_PRIVATE *PrivateFile;\r
187 CHAR16 *TempFileName;\r
188 UINTN Size;\r
189\r
190 if (This == NULL || Root == NULL) {\r
191 return EFI_INVALID_PARAMETER;\r
192 }\r
193\r
194 Private = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (This);\r
195\r
196 PrivateFile = AllocatePool (sizeof (WIN_NT_EFI_FILE_PRIVATE));\r
197 if (PrivateFile == NULL) {\r
198 Status = EFI_OUT_OF_RESOURCES;\r
199 goto Done;\r
200 }\r
201\r
202 PrivateFile->FileName = AllocatePool (StrSize (Private->FilePath));\r
203 if (PrivateFile->FileName == NULL) {\r
204 Status = EFI_OUT_OF_RESOURCES;\r
205 goto Done;\r
206 }\r
207\r
208 PrivateFile->FilePath = AllocatePool (StrSize (Private->FilePath));\r
209 if (PrivateFile->FilePath == NULL) {\r
210 Status = EFI_OUT_OF_RESOURCES;\r
211 goto Done;\r
212 }\r
213\r
214 StrCpy (PrivateFile->FilePath, Private->FilePath);\r
215 StrCpy (PrivateFile->FileName, PrivateFile->FilePath);\r
216 PrivateFile->Signature = WIN_NT_EFI_FILE_PRIVATE_SIGNATURE;\r
217 PrivateFile->Thunk = Private->Thunk;\r
218 PrivateFile->SimpleFileSystem = This;\r
219 PrivateFile->IsRootDirectory = TRUE;\r
220 PrivateFile->IsDirectoryPath = TRUE;\r
221 PrivateFile->IsOpenedByRead = TRUE;\r
222 CopyMem (&PrivateFile->EfiFile, &gWinNtFileProtocol, sizeof (gWinNtFileProtocol));\r
223 PrivateFile->IsValidFindBuf = FALSE;\r
224\r
225 //\r
226 // Set DirHandle\r
227 //\r
228 PrivateFile->DirHandle = CreateFile (\r
229 PrivateFile->FilePath,\r
230 GENERIC_READ,\r
231 FILE_SHARE_READ | FILE_SHARE_WRITE,\r
232 NULL,\r
233 OPEN_EXISTING,\r
234 FILE_FLAG_BACKUP_SEMANTICS,\r
235 NULL\r
236 );\r
237\r
238 if (PrivateFile->DirHandle == INVALID_HANDLE_VALUE) {\r
239 Status = EFI_NOT_FOUND;\r
240 goto Done;\r
241 }\r
242\r
243 //\r
244 // Find the first file under it\r
245 //\r
246 Size = StrSize (PrivateFile->FilePath);\r
247 Size += StrSize (L"\\*");\r
248 TempFileName = AllocatePool (Size);\r
249 if (TempFileName == NULL) {\r
250 goto Done;\r
251 }\r
252 StrCpy (TempFileName, PrivateFile->FilePath);\r
253 StrCat (TempFileName, L"\\*");\r
254\r
255 PrivateFile->LHandle = FindFirstFile (TempFileName, &PrivateFile->FindBuf);\r
256 FreePool (TempFileName);\r
257\r
258 if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) {\r
259 PrivateFile->IsValidFindBuf = FALSE;\r
260 } else {\r
261 PrivateFile->IsValidFindBuf = TRUE;\r
262 }\r
263 *Root = &PrivateFile->EfiFile;\r
264\r
265 Status = EFI_SUCCESS;\r
266\r
267Done:\r
268 if (EFI_ERROR (Status)) {\r
269 if (PrivateFile) {\r
270 if (PrivateFile->FileName) {\r
271 FreePool (PrivateFile->FileName);\r
272 }\r
273\r
274 if (PrivateFile->FilePath) {\r
275 FreePool (PrivateFile->FilePath);\r
276 }\r
277\r
278 FreePool (PrivateFile);\r
279 }\r
280 }\r
281\r
282 return Status;\r
283}\r
284\r
285/**\r
286 Count the number of Leading Dot in FileNameToken.\r
287\r
288 @param FileNameToken A string representing a token in the path name.\r
289\r
290 @return UINTN The number of leading dot in the name.\r
291\r
292**/\r
293UINTN\r
294CountLeadingDots (\r
295 IN CONST CHAR16 * FileNameToken\r
296)\r
297{\r
298 UINTN Num;\r
299\r
300 Num = 0;\r
301 while (*FileNameToken == L'.') {\r
302 Num++;\r
303 FileNameToken++;\r
304 }\r
305\r
306 return Num;\r
307}\r
308\r
309\r
310BOOLEAN\r
311IsFileNameTokenValid (\r
312 IN CONST CHAR16 * FileNameToken\r
313)\r
314{\r
315 UINTN Num;\r
316 if (StrStr (FileNameToken, L"/") != NULL) {\r
317 //\r
318 // No L'/' in file name.\r
319 //\r
320 return FALSE;\r
321 } else {\r
322 //\r
323 // If Token has all dot, the number should not exceed 2\r
324 //\r
325 Num = CountLeadingDots (FileNameToken);\r
326\r
327 if (Num == StrLen (FileNameToken)) {\r
328 //\r
329 // If the FileNameToken only contains a number of L'.'.\r
330 //\r
331 if (Num > 2) {\r
332 return FALSE;\r
333 }\r
334 }\r
335 }\r
336\r
337 return TRUE;\r
338}\r
339\r
340\r
341/**\r
342 Return the first string token found in the indirect pointer a String named by FileName.\r
343\r
344 On input, FileName is a indirect pointer pointing to a String.\r
345 On output, FileName is a updated to point to the next character after the first\r
346 found L"\" or NULL if there is no L"\" found.\r
347\r
348 @param FileName A indirect pointer pointing to a FileName.\r
349\r
350 @return Token The first string token found before a L"\".\r
351\r
352**/\r
353CHAR16 *\r
354GetNextFileNameToken (\r
355 IN OUT CONST CHAR16 ** FileName\r
356)\r
357{\r
358 CHAR16 *SlashPos;\r
359 CHAR16 *Token;\r
360 UINTN Offset;\r
361 ASSERT (**FileName != L'\\');\r
362 ASSERT (**FileName != L'\0');\r
363\r
364 SlashPos = StrStr (*FileName, L"\\");\r
365 if (SlashPos == NULL) {\r
366 Token = AllocateCopyPool (StrSize (*FileName), *FileName);\r
367 *FileName = NULL;\r
368 } else {\r
369 Offset = SlashPos - *FileName;\r
370 Token = AllocateZeroPool ((Offset + 1) * sizeof (CHAR16));\r
371 StrnCpy (Token, *FileName, Offset);\r
372 //\r
373 // Point *FileName to the next character after L'\'.\r
374 //\r
375 *FileName = *FileName + Offset + 1;\r
376 //\r
377 // If *FileName is an empty string, then set *FileName to NULL\r
378 //\r
379 if (**FileName == L'\0') {\r
380 *FileName = NULL;\r
381 }\r
382 }\r
383\r
384 return Token;\r
385}\r
386\r
387\r
388/**\r
389 Check if a FileName contains only Valid Characters.\r
390\r
391 If FileName contains only a single L'\', return TRUE.\r
392 If FileName contains two adjacent L'\', return FALSE.\r
393 If FileName conatins L'/' , return FALSE.\r
394 If FielName contains more than two dots seperated with other FileName characters\r
395 by L'\', return FALSE. For example, L'.\...\filename.txt' is invalid path name. But L'..TwoDots\filename.txt' is valid path name.\r
396\r
397 @param FileName The File Name String to check.\r
398\r
399 @return TRUE FileName only contains valid characters.\r
400 @return FALSE FileName contains at least one invalid character.\r
401\r
402**/\r
403\r
404BOOLEAN\r
405IsFileNameValid (\r
406 IN CONST CHAR16 *FileName\r
407 )\r
408{\r
409 CHAR16 *Token;\r
410 BOOLEAN Valid;\r
411\r
412 //\r
413 // If FileName is just L'\', then it is a valid pathname.\r
414 //\r
415 if (StrCmp (FileName, L"\\") == 0) {\r
416 return TRUE;\r
417 }\r
418 //\r
419 // We don't support two or more adjacent L'\'.\r
420 //\r
421 if (StrStr (FileName, L"\\\\") != NULL) {\r
422 return FALSE;\r
423 }\r
424\r
425 //\r
426 // Is FileName has a leading L"\", skip to next character.\r
427 //\r
428 if (FileName [0] == L'\\') {\r
429 FileName++;\r
430 }\r
431\r
432 do {\r
433 Token = GetNextFileNameToken (&FileName);\r
434 Valid = IsFileNameTokenValid (Token);\r
435 FreePool (Token);\r
436\r
437 if (!Valid)\r
438 return FALSE;\r
439 } while (FileName != NULL);\r
440\r
441 return TRUE;\r
442}\r
443\r
444\r
445/**\r
446 Opens a new file relative to the source file's location.\r
447\r
448 @param This The protocol instance pointer.\r
449 @param NewHandle Returns File Handle for FileName.\r
450 @param FileName Null terminated string. "\", ".", and ".." are supported.\r
451 @param OpenMode Open mode for file.\r
452 @param Attributes Only used for EFI_FILE_MODE_CREATE.\r
453\r
454 @retval EFI_SUCCESS The device was opened.\r
455 @retval EFI_NOT_FOUND The specified file could not be found on the device.\r
456 @retval EFI_NO_MEDIA The device has no media.\r
457 @retval EFI_MEDIA_CHANGED The media has changed.\r
458 @retval EFI_DEVICE_ERROR The device reported an error.\r
459 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
460 @retval EFI_ACCESS_DENIED The service denied access to the file.\r
461 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.\r
462 @retval EFI_VOLUME_FULL The volume is full.\r
463\r
464**/\r
465EFI_STATUS\r
466WinNtFileOpen (\r
467 IN EFI_FILE_PROTOCOL *This,\r
468 OUT EFI_FILE_PROTOCOL **NewHandle,\r
469 IN CHAR16 *FileName,\r
470 IN UINT64 OpenMode,\r
471 IN UINT64 Attributes\r
472 )\r
473{\r
474 WIN_NT_EFI_FILE_PRIVATE *PrivateFile;\r
475 WIN_NT_EFI_FILE_PRIVATE *NewPrivateFile;\r
476 WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;\r
477 EFI_STATUS Status;\r
478 CHAR16 *RealFileName;\r
479 CHAR16 *TempFileName;\r
480 CHAR16 *ParseFileName;\r
481 CHAR16 *GuardPointer;\r
482 CHAR16 TempChar;\r
483 DWORD LastError;\r
484 UINTN Count;\r
485 BOOLEAN LoopFinish;\r
486 UINTN InfoSize;\r
487 EFI_FILE_INFO *Info;\r
488 UINTN Size;\r
489\r
490\r
491 //\r
492 // Init local variables\r
493 //\r
494 PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
495 PrivateRoot = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);\r
496 NewPrivateFile = NULL;\r
497\r
498 //\r
499 // Allocate buffer for FileName as the passed in FileName may be read only\r
500 //\r
501 TempFileName = AllocatePool (StrSize (FileName));\r
502 if (TempFileName == NULL) {\r
503 return EFI_OUT_OF_RESOURCES;\r
504 }\r
505 StrCpy (TempFileName, FileName);\r
506 FileName = TempFileName;\r
507\r
508 if (FileName[StrLen (FileName) - 1] == L'\\') {\r
509 FileName[StrLen (FileName) - 1] = 0;\r
510 }\r
511\r
512 //\r
513 // If file name does not equal to "." or ".." and not trailed with "\..",\r
514 // then we trim the leading/trailing blanks and trailing dots\r
515 //\r
516 if (StrCmp (FileName, L".") != 0 && StrCmp (FileName, L"..") != 0 &&\r
517 ((StrLen (FileName) >= 3) ? (StrCmp (&FileName[StrLen (FileName) - 3], L"\\..") != 0) : TRUE)) {\r
518 //\r
519 // Trim leading blanks\r
520 //\r
521 Count = 0;\r
522 for (TempFileName = FileName;\r
523 *TempFileName != 0 && *TempFileName == L' ';\r
524 TempFileName++) {\r
525 Count++;\r
526 }\r
527 CutPrefix (FileName, Count);\r
528 //\r
529 // Trim trailing blanks\r
530 //\r
531 for (TempFileName = FileName + StrLen (FileName) - 1;\r
532 TempFileName >= FileName && (*TempFileName == L' ');\r
533 TempFileName--) {\r
534 ;\r
535 }\r
536 *(TempFileName + 1) = 0;\r
537 }\r
538\r
539 //\r
540 // Attempt to open the file\r
541 //\r
542 NewPrivateFile = AllocatePool (sizeof (WIN_NT_EFI_FILE_PRIVATE));\r
543 if (NewPrivateFile == NULL) {\r
544 Status = EFI_OUT_OF_RESOURCES;\r
545 goto Done;\r
546 }\r
547\r
548 CopyMem (NewPrivateFile, PrivateFile, sizeof (WIN_NT_EFI_FILE_PRIVATE));\r
549\r
550 NewPrivateFile->FilePath = AllocatePool (StrSize (PrivateFile->FileName));\r
551 if (NewPrivateFile->FilePath == NULL) {\r
552 Status = EFI_OUT_OF_RESOURCES;\r
553 goto Done;\r
554 }\r
555\r
556 if (PrivateFile->IsDirectoryPath) {\r
557 StrCpy (NewPrivateFile->FilePath, PrivateFile->FileName);\r
558 } else {\r
559 StrCpy (NewPrivateFile->FilePath, PrivateFile->FilePath);\r
560 }\r
561\r
562 Size = StrSize (NewPrivateFile->FilePath);\r
563 Size += StrSize (L"\\");\r
564 Size += StrSize (FileName);\r
565 NewPrivateFile->FileName = AllocatePool (Size);\r
566 if (NewPrivateFile->FileName == NULL) {\r
567 Status = EFI_OUT_OF_RESOURCES;\r
568 goto Done;\r
569 }\r
570\r
571 if (*FileName == L'\\') {\r
572 StrCpy (NewPrivateFile->FileName, PrivateRoot->FilePath);\r
573 StrCat (NewPrivateFile->FileName, L"\\");\r
574 StrCat (NewPrivateFile->FileName, FileName + 1);\r
575 } else {\r
576 StrCpy (NewPrivateFile->FileName, NewPrivateFile->FilePath);\r
577 if (StrCmp (FileName, L"") != 0) {\r
578 //\r
579 // In case the filename becomes empty, especially after trimming dots and blanks\r
580 //\r
581 StrCat (NewPrivateFile->FileName, L"\\");\r
582 StrCat (NewPrivateFile->FileName, FileName);\r
583 }\r
584 }\r
585\r
586 if (!IsFileNameValid (NewPrivateFile->FileName)) {\r
587 Status = EFI_NOT_FOUND;\r
588 goto Done;\r
589 }\r
590\r
591 //\r
592 // Get rid of . and .., except leading . or ..\r
593 //\r
594\r
595 //\r
596 // GuardPointer protect simplefilesystem root path not be destroyed\r
597 //\r
598 GuardPointer = NewPrivateFile->FileName + StrLen (PrivateRoot->FilePath);\r
599\r
600 LoopFinish = FALSE;\r
601\r
602 while (!LoopFinish) {\r
603\r
604 LoopFinish = TRUE;\r
605\r
606 for (ParseFileName = GuardPointer; *ParseFileName; ParseFileName++) {\r
607 if (*ParseFileName == L'.' &&\r
608 (*(ParseFileName + 1) == 0 || *(ParseFileName + 1) == L'\\') &&\r
609 *(ParseFileName - 1) == L'\\'\r
610 ) {\r
611\r
612 //\r
613 // cut \.\r
614 //\r
615 CutPrefix (ParseFileName - 1, 2);\r
616 LoopFinish = FALSE;\r
617 break;\r
618 }\r
619\r
620 if (*ParseFileName == L'.' &&\r
621 *(ParseFileName + 1) == L'.' &&\r
622 (*(ParseFileName + 2) == 0 || *(ParseFileName + 2) == L'\\') &&\r
623 *(ParseFileName - 1) == L'\\'\r
624 ) {\r
625\r
626 ParseFileName--;\r
627 Count = 3;\r
628\r
629 while (ParseFileName != GuardPointer) {\r
630 ParseFileName--;\r
631 Count++;\r
632 if (*ParseFileName == L'\\') {\r
633 break;\r
634 }\r
635 }\r
636\r
637 //\r
638 // cut \.. and its left directory\r
639 //\r
640 CutPrefix (ParseFileName, Count);\r
641 LoopFinish = FALSE;\r
642 break;\r
643 }\r
644 }\r
645 }\r
646\r
647 RealFileName = NewPrivateFile->FileName;\r
648 while (EfiStrChr (RealFileName, L'\\') != NULL) {\r
649 RealFileName = EfiStrChr (RealFileName, L'\\') + 1;\r
650 }\r
651\r
652 TempChar = 0;\r
653 if (RealFileName != NewPrivateFile->FileName) {\r
654 TempChar = *(RealFileName - 1);\r
655 *(RealFileName - 1) = 0;\r
656 }\r
657\r
658 FreePool (NewPrivateFile->FilePath);\r
659 NewPrivateFile->FilePath = NULL;\r
660 NewPrivateFile->FilePath = AllocatePool (StrSize (NewPrivateFile->FileName));\r
661 if (NewPrivateFile->FilePath == NULL) {\r
662 Status = EFI_OUT_OF_RESOURCES;\r
663 goto Done;\r
664 }\r
665\r
666 StrCpy (NewPrivateFile->FilePath, NewPrivateFile->FileName);\r
667 if (TempChar != 0) {\r
668 *(RealFileName - 1) = TempChar;\r
669 }\r
670\r
671 NewPrivateFile->IsRootDirectory = FALSE;\r
672\r
673 //\r
674 // Test whether file or directory\r
675 //\r
676 if (OpenMode & EFI_FILE_MODE_CREATE) {\r
677 if (Attributes & EFI_FILE_DIRECTORY) {\r
678 NewPrivateFile->IsDirectoryPath = TRUE;\r
679 } else {\r
680 NewPrivateFile->IsDirectoryPath = FALSE;\r
681 }\r
682 } else {\r
683 NewPrivateFile->LHandle = CreateFile (\r
684 NewPrivateFile->FileName,\r
685 GENERIC_READ,\r
686 FILE_SHARE_READ | FILE_SHARE_WRITE,\r
687 NULL,\r
688 OPEN_EXISTING,\r
689 0,\r
690 NULL\r
691 );\r
692\r
693 if (NewPrivateFile->LHandle != INVALID_HANDLE_VALUE) {\r
694 NewPrivateFile->IsDirectoryPath = FALSE;\r
695 CloseHandle (NewPrivateFile->LHandle);\r
696 } else {\r
697 NewPrivateFile->IsDirectoryPath = TRUE;\r
698 }\r
699\r
700 NewPrivateFile->LHandle = INVALID_HANDLE_VALUE;\r
701 }\r
702\r
703 if (OpenMode & EFI_FILE_MODE_WRITE) {\r
704 NewPrivateFile->IsOpenedByRead = FALSE;\r
705 } else {\r
706 NewPrivateFile->IsOpenedByRead = TRUE;\r
707 }\r
708\r
709 Status = EFI_SUCCESS;\r
710\r
711 //\r
712 // deal with directory\r
713 //\r
714 if (NewPrivateFile->IsDirectoryPath) {\r
715\r
716 Size = StrSize (NewPrivateFile->FileName);\r
717 Size += StrSize (L"\\*");\r
718 TempFileName = AllocatePool (Size);\r
719 if (TempFileName == NULL) {\r
720 Status = EFI_OUT_OF_RESOURCES;\r
721 goto Done;\r
722 }\r
723\r
724 StrCpy (TempFileName, NewPrivateFile->FileName);\r
725\r
726 if ((OpenMode & EFI_FILE_MODE_CREATE)) {\r
727 //\r
728 // Create a directory\r
729 //\r
730 if (!CreateDirectory (TempFileName, NULL)) {\r
731\r
732 LastError = GetLastError ();\r
733 if (LastError != ERROR_ALREADY_EXISTS) {\r
734 FreePool (TempFileName);\r
735 Status = EFI_ACCESS_DENIED;\r
736 goto Done;\r
737 }\r
738 }\r
739 }\r
740\r
741 NewPrivateFile->DirHandle = CreateFile (\r
742 TempFileName,\r
743 NewPrivateFile->IsOpenedByRead ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE),\r
744 FILE_SHARE_READ | FILE_SHARE_WRITE,\r
745 NULL,\r
746 OPEN_EXISTING,\r
747 FILE_FLAG_BACKUP_SEMANTICS,\r
748 NULL\r
749 );\r
750\r
751 if (NewPrivateFile->DirHandle == INVALID_HANDLE_VALUE) {\r
752\r
753 NewPrivateFile->DirHandle = CreateFile (\r
754 TempFileName,\r
755 GENERIC_READ,\r
756 FILE_SHARE_READ | FILE_SHARE_WRITE,\r
757 NULL,\r
758 OPEN_EXISTING,\r
759 FILE_FLAG_BACKUP_SEMANTICS,\r
760 NULL\r
761 );\r
762\r
763 if (NewPrivateFile->DirHandle != INVALID_HANDLE_VALUE) {\r
764 CloseHandle (NewPrivateFile->DirHandle);\r
765 NewPrivateFile->DirHandle = INVALID_HANDLE_VALUE;\r
766 Status = EFI_ACCESS_DENIED;\r
767 } else {\r
768 Status = EFI_NOT_FOUND;\r
769 }\r
770\r
771 FreePool (TempFileName);\r
772 goto Done;\r
773 }\r
774\r
775 //\r
776 // Find the first file under it\r
777 //\r
778 StrCat (TempFileName, L"\\*");\r
779 NewPrivateFile->LHandle = FindFirstFile (TempFileName, &NewPrivateFile->FindBuf);\r
780 FreePool (TempFileName);\r
781\r
782 if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) {\r
783 NewPrivateFile->IsValidFindBuf = FALSE;\r
784 } else {\r
785 NewPrivateFile->IsValidFindBuf = TRUE;\r
786 }\r
787 } else {\r
788 //\r
789 // deal with file\r
790 //\r
791 if (!NewPrivateFile->IsOpenedByRead) {\r
792 NewPrivateFile->LHandle = CreateFile (\r
793 NewPrivateFile->FileName,\r
794 GENERIC_READ | GENERIC_WRITE,\r
795 FILE_SHARE_READ | FILE_SHARE_WRITE,\r
796 NULL,\r
797 (OpenMode & EFI_FILE_MODE_CREATE) ? OPEN_ALWAYS : OPEN_EXISTING,\r
798 0,\r
799 NULL\r
800 );\r
801\r
802 if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) {\r
803 NewPrivateFile->LHandle = CreateFile (\r
804 NewPrivateFile->FileName,\r
805 GENERIC_READ,\r
806 FILE_SHARE_READ | FILE_SHARE_WRITE,\r
807 NULL,\r
808 OPEN_EXISTING,\r
809 0,\r
810 NULL\r
811 );\r
812\r
813 if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) {\r
814 Status = EFI_NOT_FOUND;\r
815 } else {\r
816 Status = EFI_ACCESS_DENIED;\r
817 CloseHandle (NewPrivateFile->LHandle);\r
818 NewPrivateFile->LHandle = INVALID_HANDLE_VALUE;\r
819 }\r
820 }\r
821 } else {\r
822 NewPrivateFile->LHandle = CreateFile (\r
823 NewPrivateFile->FileName,\r
824 GENERIC_READ,\r
825 FILE_SHARE_READ | FILE_SHARE_WRITE,\r
826 NULL,\r
827 OPEN_EXISTING,\r
828 0,\r
829 NULL\r
830 );\r
831\r
832 if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) {\r
833 Status = EFI_NOT_FOUND;\r
834 }\r
835 }\r
836 }\r
837\r
838 if ((OpenMode & EFI_FILE_MODE_CREATE) && Status == EFI_SUCCESS) {\r
839 //\r
840 // Set the attribute\r
841 //\r
842 InfoSize = 0;\r
843 Info = NULL;\r
844\r
845 Status = WinNtFileGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info);\r
846\r
847 if (Status != EFI_BUFFER_TOO_SMALL) {\r
848 Status = EFI_DEVICE_ERROR;\r
849 goto Done;\r
850 }\r
851\r
852 Info = AllocatePool (InfoSize);\r
853 if (Info == NULL) {\r
854 Status = EFI_OUT_OF_RESOURCES;\r
855 goto Done;\r
856 }\r
857\r
858 Status = WinNtFileGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info);\r
859\r
860 if (EFI_ERROR (Status)) {\r
861 FreePool (Info);\r
862 goto Done;\r
863 }\r
864\r
865 Info->Attribute = Attributes;\r
866\r
867 WinNtFileSetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, InfoSize, Info);\r
868 FreePool (Info);\r
869 }\r
870\r
871Done:\r
872 FreePool (FileName);\r
873\r
874 if (EFI_ERROR (Status)) {\r
875 if (NewPrivateFile) {\r
876 if (NewPrivateFile->FileName) {\r
877 FreePool (NewPrivateFile->FileName);\r
878 }\r
879\r
880 if (NewPrivateFile->FilePath) {\r
881 FreePool (NewPrivateFile->FilePath);\r
882 }\r
883\r
884 FreePool (NewPrivateFile);\r
885 }\r
886 } else {\r
887 *NewHandle = &NewPrivateFile->EfiFile;\r
888 if (StrCmp (NewPrivateFile->FileName, PrivateRoot->FilePath) == 0) {\r
889 NewPrivateFile->IsRootDirectory = TRUE;\r
890 }\r
891 }\r
892\r
893 return Status;\r
894}\r
895\r
896\r
897\r
898/**\r
899 Close the file handle\r
900\r
901 @param This Protocol instance pointer.\r
902\r
903 @retval EFI_SUCCESS The device was opened.\r
904\r
905**/\r
906EFI_STATUS\r
907WinNtFileClose (\r
908 IN EFI_FILE_PROTOCOL *This\r
909 )\r
910{\r
911 WIN_NT_EFI_FILE_PRIVATE *PrivateFile;\r
912\r
913 PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
914\r
915 if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) {\r
916 if (PrivateFile->IsDirectoryPath) {\r
917 FindClose (PrivateFile->LHandle);\r
918 } else {\r
919 CloseHandle (PrivateFile->LHandle);\r
920 }\r
921\r
922 PrivateFile->LHandle = INVALID_HANDLE_VALUE;\r
923 }\r
924\r
925 if (PrivateFile->IsDirectoryPath && PrivateFile->DirHandle != INVALID_HANDLE_VALUE) {\r
926 CloseHandle (PrivateFile->DirHandle);\r
927 PrivateFile->DirHandle = INVALID_HANDLE_VALUE;\r
928 }\r
929\r
930 if (PrivateFile->FileName) {\r
931 FreePool (PrivateFile->FileName);\r
932 }\r
933\r
934 if (PrivateFile->FilePath) {\r
935 FreePool (PrivateFile->FilePath);\r
936 }\r
937\r
938 FreePool (PrivateFile);\r
939\r
940 return EFI_SUCCESS;\r
941\r
942}\r
943\r
944\r
945/**\r
946 Close and delete the file handle.\r
947\r
948 @param This Protocol instance pointer.\r
949\r
950 @retval EFI_SUCCESS The device was opened.\r
951 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.\r
952\r
953**/\r
954EFI_STATUS\r
955WinNtFileDelete (\r
956 IN EFI_FILE_PROTOCOL *This\r
957 )\r
958{\r
959 EFI_STATUS Status;\r
960 WIN_NT_EFI_FILE_PRIVATE *PrivateFile;\r
961\r
962 PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
963\r
964 Status = EFI_WARN_DELETE_FAILURE;\r
965\r
966 if (PrivateFile->IsDirectoryPath) {\r
967 if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) {\r
968 FindClose (PrivateFile->LHandle);\r
969 }\r
970\r
971 if (PrivateFile->DirHandle != INVALID_HANDLE_VALUE) {\r
972 CloseHandle (PrivateFile->DirHandle);\r
973 PrivateFile->DirHandle = INVALID_HANDLE_VALUE;\r
974 }\r
975\r
976 if (RemoveDirectory (PrivateFile->FileName)) {\r
977 Status = EFI_SUCCESS;\r
978 }\r
979 } else {\r
980 CloseHandle (PrivateFile->LHandle);\r
981 PrivateFile->LHandle = INVALID_HANDLE_VALUE;\r
982\r
983 if (!PrivateFile->IsOpenedByRead) {\r
984 if (DeleteFile (PrivateFile->FileName)) {\r
985 Status = EFI_SUCCESS;\r
986 }\r
987 }\r
988 }\r
989\r
990 FreePool (PrivateFile->FileName);\r
991 FreePool (PrivateFile->FilePath);\r
992 FreePool (PrivateFile);\r
993\r
994 return Status;\r
995}\r
996\r
997VOID\r
998WinNtSystemTimeToEfiTime (\r
999 IN SYSTEMTIME *SystemTime,\r
1000 IN TIME_ZONE_INFORMATION *TimeZone,\r
1001 OUT EFI_TIME *Time\r
1002)\r
1003/*++\r
1004\r
1005Routine Description:\r
1006\r
1007 TODO: Add function description\r
1008\r
1009Arguments:\r
1010\r
1011 SystemTime - TODO: add argument description\r
1012 TimeZone - TODO: add argument description\r
1013 Time - TODO: add argument description\r
1014\r
1015Returns:\r
1016\r
1017 TODO: add return values\r
1018\r
1019--*/\r
1020{\r
1021 Time->Year = (UINT16)SystemTime->wYear;\r
1022 Time->Month = (UINT8)SystemTime->wMonth;\r
1023 Time->Day = (UINT8)SystemTime->wDay;\r
1024 Time->Hour = (UINT8)SystemTime->wHour;\r
1025 Time->Minute = (UINT8)SystemTime->wMinute;\r
1026 Time->Second = (UINT8)SystemTime->wSecond;\r
1027 Time->Nanosecond = (UINT32)SystemTime->wMilliseconds * 1000000;\r
1028 Time->TimeZone = (INT16)TimeZone->Bias;\r
1029\r
1030 if (TimeZone->StandardDate.wMonth) {\r
1031 Time->Daylight = EFI_TIME_ADJUST_DAYLIGHT;\r
1032 }\r
1033}\r
1034\r
1035/**\r
1036 Convert the FileTime to EfiTime.\r
1037\r
1038 @param PrivateFile Pointer to WIN_NT_EFI_FILE_PRIVATE.\r
1039 @param TimeZone Pointer to the current time zone.\r
1040 @param FileTime Pointer to file time.\r
1041 @param EfiTime Pointer to EFI time.\r
1042**/\r
1043VOID\r
1044WinNtFileTimeToEfiTime (\r
1045 IN CONST WIN_NT_EFI_FILE_PRIVATE *PrivateFile,\r
1046 IN TIME_ZONE_INFORMATION *TimeZone,\r
1047 IN CONST FILETIME *FileTime,\r
1048 OUT EFI_TIME *EfiTime\r
1049)\r
1050{\r
1051 FILETIME TempFileTime;\r
1052 SYSTEMTIME SystemTime;\r
1053\r
1054 FileTimeToLocalFileTime (FileTime, &TempFileTime);\r
1055 FileTimeToSystemTime (&TempFileTime, &SystemTime);\r
1056 WinNtSystemTimeToEfiTime (&SystemTime, TimeZone, EfiTime);\r
1057}\r
1058\r
1059\r
1060/**\r
1061 Read data from the file.\r
1062\r
1063 @param This Protocol instance pointer.\r
1064 @param BufferSize On input size of buffer, on output amount of data in buffer.\r
1065 @param Buffer The buffer in which data is read.\r
1066\r
1067 @retval EFI_SUCCESS Data was read.\r
1068 @retval EFI_NO_MEDIA The device has no media.\r
1069 @retval EFI_DEVICE_ERROR The device reported an error.\r
1070 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1071 @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size.\r
1072\r
1073**/\r
1074EFI_STATUS\r
1075WinNtFileRead (\r
1076 IN EFI_FILE_PROTOCOL *This,\r
1077 IN OUT UINTN *BufferSize,\r
1078 OUT VOID *Buffer\r
1079 )\r
1080{\r
1081 WIN_NT_EFI_FILE_PRIVATE *PrivateFile;\r
1082 EFI_STATUS Status;\r
1083 UINTN Size;\r
1084 UINTN NameSize;\r
1085 UINTN ResultSize;\r
1086 UINTN Index;\r
1087 EFI_FILE_INFO *Info;\r
1088 WCHAR *pw;\r
1089 TIME_ZONE_INFORMATION TimeZone;\r
1090 EFI_FILE_INFO *FileInfo;\r
1091 UINT64 Pos;\r
1092 UINT64 FileSize;\r
1093 UINTN FileInfoSize;\r
1094\r
1095 PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
1096\r
1097 if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) {\r
1098 Status = EFI_DEVICE_ERROR;\r
1099 goto Done;\r
1100 }\r
1101\r
1102 if (!PrivateFile->IsDirectoryPath) {\r
1103\r
1104 if (This->GetPosition (This, &Pos) != EFI_SUCCESS) {\r
1105 Status = EFI_DEVICE_ERROR;\r
1106 goto Done;\r
1107 }\r
1108\r
1109 FileInfoSize = SIZE_OF_EFI_FILE_SYSTEM_INFO;\r
1110 FileInfo = AllocatePool (FileInfoSize);\r
1111\r
1112 Status = This->GetInfo (\r
1113 This,\r
1114 &gEfiFileInfoGuid,\r
1115 &FileInfoSize,\r
1116 FileInfo\r
1117 );\r
1118\r
1119 if (Status == EFI_BUFFER_TOO_SMALL) {\r
1120 FreePool (FileInfo);\r
1121 FileInfo = AllocatePool (FileInfoSize);\r
1122 Status = This->GetInfo (\r
1123 This,\r
1124 &gEfiFileInfoGuid,\r
1125 &FileInfoSize,\r
1126 FileInfo\r
1127 );\r
1128 }\r
1129\r
1130 if (EFI_ERROR (Status)) {\r
1131 Status = EFI_DEVICE_ERROR;\r
1132 goto Done;\r
1133 }\r
1134\r
1135 FileSize = FileInfo->FileSize;\r
1136\r
1137 FreePool (FileInfo);\r
1138\r
1139 if (Pos >= FileSize) {\r
1140 *BufferSize = 0;\r
1141 if (Pos == FileSize) {\r
1142 Status = EFI_SUCCESS;\r
1143 goto Done;\r
1144 } else {\r
1145 Status = EFI_DEVICE_ERROR;\r
1146 goto Done;\r
1147 }\r
1148 }\r
1149\r
1150 Status = ReadFile (\r
1151 PrivateFile->LHandle,\r
1152 Buffer,\r
1153 (DWORD)*BufferSize,\r
1154 (LPDWORD)BufferSize,\r
1155 NULL\r
1156 ) ? EFI_SUCCESS : EFI_DEVICE_ERROR;\r
1157 goto Done;\r
1158 }\r
1159\r
1160 //\r
1161 // Read on a directory. Perform a find next\r
1162 //\r
1163 if (!PrivateFile->IsValidFindBuf) {\r
1164 *BufferSize = 0;\r
1165 Status = EFI_SUCCESS;\r
1166 goto Done;\r
1167 }\r
1168\r
1169 Size = SIZE_OF_EFI_FILE_INFO;\r
1170\r
1171 NameSize = StrSize (PrivateFile->FindBuf.cFileName);\r
1172\r
1173 ResultSize = Size + NameSize;\r
1174\r
1175 Status = EFI_BUFFER_TOO_SMALL;\r
1176\r
1177 if (*BufferSize >= ResultSize) {\r
1178 Status = EFI_SUCCESS;\r
1179\r
1180 Info = Buffer;\r
1181 ZeroMem (Info, ResultSize);\r
1182\r
1183 Info->Size = ResultSize;\r
1184\r
1185 GetTimeZoneInformation (&TimeZone);\r
1186 WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &PrivateFile->FindBuf.ftCreationTime, &Info->CreateTime);\r
1187 WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &PrivateFile->FindBuf.ftLastAccessTime, &Info->LastAccessTime);\r
1188 WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &PrivateFile->FindBuf.ftLastWriteTime, &Info->ModificationTime);\r
1189\r
1190 Info->FileSize = PrivateFile->FindBuf.nFileSizeLow;\r
1191\r
1192 Info->PhysicalSize = PrivateFile->FindBuf.nFileSizeLow;\r
1193\r
1194 if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) {\r
1195 Info->Attribute |= EFI_FILE_ARCHIVE;\r
1196 }\r
1197\r
1198 if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {\r
1199 Info->Attribute |= EFI_FILE_HIDDEN;\r
1200 }\r
1201\r
1202 if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {\r
1203 Info->Attribute |= EFI_FILE_SYSTEM;\r
1204 }\r
1205\r
1206 if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {\r
1207 Info->Attribute |= EFI_FILE_READ_ONLY;\r
1208 }\r
1209\r
1210 if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {\r
1211 Info->Attribute |= EFI_FILE_DIRECTORY;\r
1212 }\r
1213\r
1214 NameSize = NameSize / sizeof (WCHAR);\r
1215\r
1216 pw = (WCHAR *)(((CHAR8 *)Buffer) + Size);\r
1217\r
1218 for (Index = 0; Index < NameSize; Index++) {\r
1219 pw[Index] = PrivateFile->FindBuf.cFileName[Index];\r
1220 }\r
1221\r
1222 if (FindNextFile (PrivateFile->LHandle, &PrivateFile->FindBuf)) {\r
1223 PrivateFile->IsValidFindBuf = TRUE;\r
1224 } else {\r
1225 PrivateFile->IsValidFindBuf = FALSE;\r
1226 }\r
1227 }\r
1228\r
1229 *BufferSize = ResultSize;\r
1230\r
1231Done:\r
1232 return Status;\r
1233}\r
1234\r
1235\r
1236\r
1237/**\r
1238 Write data to a file.\r
1239\r
1240 @param This Protocol instance pointer.\r
1241 @param BufferSize On input size of buffer, on output amount of data in buffer.\r
1242 @param Buffer The buffer in which data to write.\r
1243\r
1244 @retval EFI_SUCCESS Data was written.\r
1245 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.\r
1246 @retval EFI_NO_MEDIA The device has no media.\r
1247 @retval EFI_DEVICE_ERROR The device reported an error.\r
1248 @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.\r
1249 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1250 @retval EFI_WRITE_PROTECTED The device is write protected.\r
1251 @retval EFI_ACCESS_DENIED The file was open for read only.\r
1252 @retval EFI_VOLUME_FULL The volume is full.\r
1253\r
1254**/\r
1255EFI_STATUS\r
1256WinNtFileWrite (\r
1257 IN EFI_FILE_PROTOCOL *This,\r
1258 IN OUT UINTN *BufferSize,\r
1259 IN VOID *Buffer\r
1260 )\r
1261{\r
1262 WIN_NT_EFI_FILE_PRIVATE *PrivateFile;\r
1263 EFI_STATUS Status;\r
1264\r
1265 PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
1266\r
1267 if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) {\r
1268 Status = EFI_DEVICE_ERROR;\r
1269 goto Done;\r
1270 }\r
1271\r
1272 if (PrivateFile->IsDirectoryPath) {\r
1273 Status = EFI_UNSUPPORTED;\r
1274 goto Done;\r
1275 }\r
1276\r
1277 if (PrivateFile->IsOpenedByRead) {\r
1278 Status = EFI_ACCESS_DENIED;\r
1279 goto Done;\r
1280 }\r
1281\r
1282 Status = WriteFile (\r
1283 PrivateFile->LHandle,\r
1284 Buffer,\r
1285 (DWORD)*BufferSize,\r
1286 (LPDWORD)BufferSize,\r
1287 NULL\r
1288 ) ? EFI_SUCCESS : EFI_DEVICE_ERROR;\r
1289\r
1290Done:\r
1291 return Status;\r
1292\r
1293 //\r
1294 // bugbug: need to access windows error reporting\r
1295 //\r
1296}\r
1297\r
1298\r
1299\r
1300/**\r
1301 Set a files current position\r
1302\r
1303 @param This Protocol instance pointer.\r
1304 @param Position Byte position from the start of the file.\r
1305\r
1306 @retval EFI_SUCCESS Data was written.\r
1307 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.\r
1308\r
1309**/\r
1310EFI_STATUS\r
1311WinNtFileSetPossition (\r
1312 IN EFI_FILE_PROTOCOL *This,\r
1313 IN UINT64 Position\r
1314 )\r
1315{\r
1316 EFI_STATUS Status;\r
1317 WIN_NT_EFI_FILE_PRIVATE *PrivateFile;\r
1318 UINT32 PosLow;\r
1319 UINT32 PosHigh;\r
1320 CHAR16 *FileName;\r
1321 UINTN Size;\r
1322\r
1323 PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
1324\r
1325 if (PrivateFile->IsDirectoryPath) {\r
1326 if (Position != 0) {\r
1327 Status = EFI_UNSUPPORTED;\r
1328 goto Done;\r
1329 }\r
1330\r
1331 Size = StrSize (PrivateFile->FileName);\r
1332 Size += StrSize (L"\\*");\r
1333 FileName = AllocatePool (Size);\r
1334 if (FileName == NULL) {\r
1335 Status = EFI_OUT_OF_RESOURCES;\r
1336 goto Done;\r
1337 }\r
1338\r
1339 StrCpy (FileName, PrivateFile->FileName);\r
1340 StrCat (FileName, L"\\*");\r
1341\r
1342 if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) {\r
1343 FindClose (PrivateFile->LHandle);\r
1344 }\r
1345\r
1346 PrivateFile->LHandle = FindFirstFile (FileName, &PrivateFile->FindBuf);\r
1347\r
1348 if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) {\r
1349 PrivateFile->IsValidFindBuf = FALSE;\r
1350 } else {\r
1351 PrivateFile->IsValidFindBuf = TRUE;\r
1352 }\r
1353\r
1354 FreePool (FileName);\r
1355\r
1356 Status = (PrivateFile->LHandle == INVALID_HANDLE_VALUE) ? EFI_DEVICE_ERROR : EFI_SUCCESS;\r
1357 } else {\r
1358 if (Position == (UINT64)-1) {\r
1359 PosLow = SetFilePointer (PrivateFile->LHandle, (ULONG)0, NULL, FILE_END);\r
1360 } else {\r
1361 PosHigh = (UINT32)RShiftU64 (Position, 32);\r
1362\r
1363 PosLow = SetFilePointer (PrivateFile->LHandle, (ULONG)Position, (PLONG)&PosHigh, FILE_BEGIN);\r
1364 }\r
1365\r
1366 Status = (PosLow == 0xFFFFFFFF) ? EFI_DEVICE_ERROR : EFI_SUCCESS;\r
1367 }\r
1368\r
1369Done:\r
1370 return Status;\r
1371}\r
1372\r
1373\r
1374\r
1375/**\r
1376 Get a file's current position\r
1377\r
1378 @param This Protocol instance pointer.\r
1379 @param Position Byte position from the start of the file.\r
1380\r
1381 @retval EFI_SUCCESS Data was written.\r
1382 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..\r
1383\r
1384**/\r
1385EFI_STATUS\r
1386WinNtFileGetPossition (\r
1387 IN EFI_FILE_PROTOCOL *This,\r
1388 OUT UINT64 *Position\r
1389 )\r
1390{\r
1391 EFI_STATUS Status;\r
1392 WIN_NT_EFI_FILE_PRIVATE *PrivateFile;\r
1393 INT32 PositionHigh;\r
1394 UINT64 PosHigh64;\r
1395\r
1396 PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
1397\r
1398 PositionHigh = 0;\r
1399 PosHigh64 = 0;\r
1400\r
1401 if (PrivateFile->IsDirectoryPath) {\r
1402\r
1403 Status = EFI_UNSUPPORTED;\r
1404 goto Done;\r
1405\r
1406 } else {\r
1407\r
1408 PositionHigh = 0;\r
1409 *Position = SetFilePointer (\r
1410 PrivateFile->LHandle,\r
1411 0,\r
1412 (PLONG)&PositionHigh,\r
1413 FILE_CURRENT\r
1414 );\r
1415\r
1416 Status = *Position == 0xffffffff ? EFI_DEVICE_ERROR : EFI_SUCCESS;\r
1417 if (EFI_ERROR (Status)) {\r
1418 goto Done;\r
1419 }\r
1420\r
1421 PosHigh64 = PositionHigh;\r
1422 *Position += LShiftU64 (PosHigh64, 32);\r
1423 }\r
1424\r
1425Done:\r
1426 return Status;\r
1427}\r
1428\r
1429\r
1430EFI_STATUS\r
1431WinNtSimpleFileSystemFileInfo (\r
1432 IN WIN_NT_EFI_FILE_PRIVATE *PrivateFile,\r
1433 IN OUT UINTN *BufferSize,\r
1434 OUT VOID *Buffer\r
1435)\r
1436/*++\r
1437\r
1438Routine Description:\r
1439\r
1440 TODO: Add function description\r
1441\r
1442Arguments:\r
1443\r
1444 PrivateFile - TODO: add argument description\r
1445 BufferSize - TODO: add argument description\r
1446 Buffer - TODO: add argument description\r
1447\r
1448Returns:\r
1449\r
1450 TODO: add return values\r
1451\r
1452--*/\r
1453{\r
1454 EFI_STATUS Status;\r
1455 UINTN Size;\r
1456 UINTN NameSize;\r
1457 UINTN ResultSize;\r
1458 EFI_FILE_INFO *Info;\r
1459 BY_HANDLE_FILE_INFORMATION FileInfo;\r
1460 CHAR16 *RealFileName;\r
1461 CHAR16 *TempPointer;\r
1462 TIME_ZONE_INFORMATION TimeZone;\r
1463\r
1464 Size = SIZE_OF_EFI_FILE_INFO;\r
1465\r
1466 RealFileName = PrivateFile->FileName;\r
1467 TempPointer = RealFileName;\r
1468 while (*TempPointer) {\r
1469 if (*TempPointer == '\\') {\r
1470 RealFileName = TempPointer + 1;\r
1471 }\r
1472\r
1473 TempPointer++;\r
1474 }\r
1475 NameSize = StrSize (RealFileName);\r
1476\r
1477 ResultSize = Size + NameSize;\r
1478\r
1479 Status = EFI_BUFFER_TOO_SMALL;\r
1480 if (*BufferSize >= ResultSize) {\r
1481 Status = EFI_SUCCESS;\r
1482\r
1483 Info = Buffer;\r
1484 ZeroMem (Info, ResultSize);\r
1485\r
1486 Info->Size = ResultSize;\r
1487 GetFileInformationByHandle (\r
1488 PrivateFile->IsDirectoryPath ? PrivateFile->DirHandle : PrivateFile->LHandle,\r
1489 &FileInfo\r
1490 );\r
1491 Info->FileSize = FileInfo.nFileSizeLow;\r
1492 Info->PhysicalSize = Info->FileSize;\r
1493\r
1494 GetTimeZoneInformation (&TimeZone);\r
1495 WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &FileInfo.ftCreationTime, &Info->CreateTime);\r
1496 WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &FileInfo.ftLastAccessTime, &Info->LastAccessTime);\r
1497 WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &FileInfo.ftLastWriteTime, &Info->ModificationTime);\r
1498\r
1499 if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) {\r
1500 Info->Attribute |= EFI_FILE_ARCHIVE;\r
1501 }\r
1502\r
1503 if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {\r
1504 Info->Attribute |= EFI_FILE_HIDDEN;\r
1505 }\r
1506\r
1507 if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {\r
1508 Info->Attribute |= EFI_FILE_READ_ONLY;\r
1509 }\r
1510\r
1511 if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {\r
1512 Info->Attribute |= EFI_FILE_SYSTEM;\r
1513 }\r
1514\r
1515 if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {\r
1516 Info->Attribute |= EFI_FILE_DIRECTORY;\r
1517 }\r
1518\r
1519 if (PrivateFile->IsDirectoryPath) {\r
1520 Info->Attribute |= EFI_FILE_DIRECTORY;\r
1521 }\r
1522\r
1523 if (PrivateFile->IsRootDirectory) {\r
1524 *((CHAR8 *)Buffer + Size) = 0;\r
1525 } else {\r
1526 CopyMem ((CHAR8 *)Buffer + Size, RealFileName, NameSize);\r
1527 }\r
1528 }\r
1529\r
1530 *BufferSize = ResultSize;\r
1531 return Status;\r
1532}\r
1533\r
1534/**\r
1535 Get information about a file.\r
1536\r
1537 @param This Protocol instance pointer.\r
1538 @param InformationType Type of information to return in Buffer.\r
1539 @param BufferSize On input size of buffer, on output amount of data in buffer.\r
1540 @param Buffer The buffer to return data.\r
1541\r
1542 @retval EFI_SUCCESS Data was returned.\r
1543 @retval EFI_UNSUPPORTED InformationType is not supported.\r
1544 @retval EFI_NO_MEDIA The device has no media.\r
1545 @retval EFI_DEVICE_ERROR The device reported an error.\r
1546 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1547 @retval EFI_WRITE_PROTECTED The device is write protected.\r
1548 @retval EFI_ACCESS_DENIED The file was open for read only.\r
1549 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.\r
1550\r
1551**/\r
1552EFI_STATUS\r
1553WinNtFileGetInfo (\r
1554 IN EFI_FILE_PROTOCOL *This,\r
1555 IN EFI_GUID *InformationType,\r
1556 IN OUT UINTN *BufferSize,\r
1557 OUT VOID *Buffer\r
1558 )\r
1559{\r
1560 EFI_STATUS Status;\r
1561 WIN_NT_EFI_FILE_PRIVATE *PrivateFile;\r
1562 EFI_FILE_SYSTEM_INFO *FileSystemInfoBuffer;\r
1563 UINT32 SectorsPerCluster;\r
1564 UINT32 BytesPerSector;\r
1565 UINT32 FreeClusters;\r
1566 UINT32 TotalClusters;\r
1567 UINT32 BytesPerCluster;\r
1568 CHAR16 *DriveName;\r
1569 BOOLEAN DriveNameFound;\r
1570 BOOL NtStatus;\r
1571 UINTN Index;\r
1572 WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;\r
1573\r
1574 if (This == NULL || InformationType == NULL || BufferSize == NULL) {\r
1575 return EFI_INVALID_PARAMETER;\r
1576 }\r
1577\r
1578 PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
1579 PrivateRoot = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);\r
1580\r
1581 Status = EFI_UNSUPPORTED;\r
1582\r
1583 if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {\r
1584 Status = WinNtSimpleFileSystemFileInfo (PrivateFile, BufferSize, Buffer);\r
1585 }\r
1586\r
1587 if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {\r
1588 if (*BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel)) {\r
1589 *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);\r
1590 Status = EFI_BUFFER_TOO_SMALL;\r
1591 goto Done;\r
1592 }\r
1593\r
1594 FileSystemInfoBuffer = (EFI_FILE_SYSTEM_INFO *)Buffer;\r
1595 FileSystemInfoBuffer->Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);\r
1596 FileSystemInfoBuffer->ReadOnly = FALSE;\r
1597\r
1598 //\r
1599 // Try to get the drive name\r
1600 //\r
1601 DriveNameFound = FALSE;\r
1602 DriveName = AllocatePool (StrSize (PrivateFile->FilePath) + 1);\r
1603 if (DriveName == NULL) {\r
1604 Status = EFI_OUT_OF_RESOURCES;\r
1605 goto Done;\r
1606 }\r
1607\r
1608 StrCpy (DriveName, PrivateFile->FilePath);\r
1609 for (Index = 0; DriveName[Index] != 0 && DriveName[Index] != ':'; Index++) {\r
1610 ;\r
1611 }\r
1612\r
1613 if (DriveName[Index] == ':') {\r
1614 DriveName[Index + 1] = '\\';\r
1615 DriveName[Index + 2] = 0;\r
1616 DriveNameFound = TRUE;\r
1617 } else if (DriveName[0] == '\\' && DriveName[1] == '\\') {\r
1618 for (Index = 2; DriveName[Index] != 0 && DriveName[Index] != '\\'; Index++) {\r
1619 ;\r
1620 }\r
1621\r
1622 if (DriveName[Index] == '\\') {\r
1623 DriveNameFound = TRUE;\r
1624 for (Index++; DriveName[Index] != 0 && DriveName[Index] != '\\'; Index++) {\r
1625 ;\r
1626 }\r
1627\r
1628 DriveName[Index] = '\\';\r
1629 DriveName[Index + 1] = 0;\r
1630 }\r
1631 }\r
1632\r
1633 //\r
1634 // Try GetDiskFreeSpace first\r
1635 //\r
1636 NtStatus = GetDiskFreeSpace (\r
1637 DriveNameFound ? DriveName : NULL,\r
1638 (LPDWORD)&SectorsPerCluster,\r
1639 (LPDWORD)&BytesPerSector,\r
1640 (LPDWORD)&FreeClusters,\r
1641 (LPDWORD)&TotalClusters\r
1642 );\r
1643 if (DriveName) {\r
1644 FreePool (DriveName);\r
1645 }\r
1646\r
1647 if (NtStatus) {\r
1648 //\r
1649 // Succeeded\r
1650 //\r
1651 BytesPerCluster = BytesPerSector * SectorsPerCluster;\r
1652 FileSystemInfoBuffer->VolumeSize = MultU64x32 (TotalClusters, BytesPerCluster);\r
1653 FileSystemInfoBuffer->FreeSpace = MultU64x32 (FreeClusters, BytesPerCluster);\r
1654 FileSystemInfoBuffer->BlockSize = BytesPerCluster;\r
1655\r
1656 } else {\r
1657 //\r
1658 // try GetDiskFreeSpaceEx then\r
1659 //\r
1660 FileSystemInfoBuffer->BlockSize = 0;\r
1661 NtStatus = GetDiskFreeSpaceEx (\r
1662 PrivateFile->FilePath,\r
1663 (PULARGE_INTEGER)(&FileSystemInfoBuffer->FreeSpace),\r
1664 (PULARGE_INTEGER)(&FileSystemInfoBuffer->VolumeSize),\r
1665 NULL\r
1666 );\r
1667 if (!NtStatus) {\r
1668 Status = EFI_DEVICE_ERROR;\r
1669 goto Done;\r
1670 }\r
1671 }\r
1672\r
1673 StrCpy ((CHAR16 *)FileSystemInfoBuffer->VolumeLabel, PrivateRoot->VolumeLabel);\r
1674 *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);\r
1675 Status = EFI_SUCCESS;\r
1676 }\r
1677\r
1678 if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {\r
1679 if (*BufferSize < StrSize (PrivateRoot->VolumeLabel)) {\r
1680 *BufferSize = StrSize (PrivateRoot->VolumeLabel);\r
1681 Status = EFI_BUFFER_TOO_SMALL;\r
1682 goto Done;\r
1683 }\r
1684\r
1685 StrCpy ((CHAR16 *)Buffer, PrivateRoot->VolumeLabel);\r
1686 *BufferSize = StrSize (PrivateRoot->VolumeLabel);\r
1687 Status = EFI_SUCCESS;\r
1688 }\r
1689\r
1690Done:\r
1691 return Status;\r
1692}\r
1693\r
1694\r
1695/**\r
1696 Set information about a file\r
1697\r
1698 @param File Protocol instance pointer.\r
1699 @param InformationType Type of information in Buffer.\r
1700 @param BufferSize Size of buffer.\r
1701 @param Buffer The data to write.\r
1702\r
1703 @retval EFI_SUCCESS Data was returned.\r
1704 @retval EFI_UNSUPPORTED InformationType is not supported.\r
1705 @retval EFI_NO_MEDIA The device has no media.\r
1706 @retval EFI_DEVICE_ERROR The device reported an error.\r
1707 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1708 @retval EFI_WRITE_PROTECTED The device is write protected.\r
1709 @retval EFI_ACCESS_DENIED The file was open for read only.\r
1710\r
1711**/\r
1712EFI_STATUS\r
1713WinNtFileSetInfo (\r
1714 IN EFI_FILE_PROTOCOL *This,\r
1715 IN EFI_GUID *InformationType,\r
1716 IN UINTN BufferSize,\r
1717 IN VOID *Buffer\r
1718 )\r
1719{\r
1720 WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;\r
1721 WIN_NT_EFI_FILE_PRIVATE *PrivateFile;\r
1722 EFI_FILE_INFO *OldFileInfo;\r
1723 EFI_FILE_INFO *NewFileInfo;\r
1724 EFI_STATUS Status;\r
1725 UINTN OldInfoSize;\r
1726 INTN NtStatus;\r
1727 UINT32 NewAttr;\r
1728 UINT32 OldAttr;\r
1729 CHAR16 *OldFileName;\r
1730 CHAR16 *NewFileName;\r
1731 CHAR16 *TempFileName;\r
1732 CHAR16 *CharPointer;\r
1733 BOOLEAN AttrChangeFlag;\r
1734 BOOLEAN NameChangeFlag;\r
1735 BOOLEAN SizeChangeFlag;\r
1736 BOOLEAN TimeChangeFlag;\r
1737 UINT64 CurPos;\r
1738 SYSTEMTIME NewCreationSystemTime;\r
1739 SYSTEMTIME NewLastAccessSystemTime;\r
1740 SYSTEMTIME NewLastWriteSystemTime;\r
1741 FILETIME NewCreationFileTime;\r
1742 FILETIME NewLastAccessFileTime;\r
1743 FILETIME NewLastWriteFileTime;\r
1744 WIN32_FIND_DATA FindBuf;\r
1745 EFI_FILE_SYSTEM_INFO *NewFileSystemInfo;\r
1746 UINTN Size;\r
1747\r
1748 //\r
1749 // Initialise locals.\r
1750 //\r
1751 PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
1752 PrivateRoot = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);\r
1753\r
1754 Status = EFI_UNSUPPORTED;\r
1755 OldFileInfo = NewFileInfo = NULL;\r
1756 OldFileName = NewFileName = NULL;\r
1757 AttrChangeFlag = NameChangeFlag = SizeChangeFlag = TimeChangeFlag = FALSE;\r
1758\r
1759 //\r
1760 // Set file system information.\r
1761 //\r
1762 if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {\r
1763 NewFileSystemInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;\r
1764 if (BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (NewFileSystemInfo->VolumeLabel)) {\r
1765 Status = EFI_BAD_BUFFER_SIZE;\r
1766 goto Done;\r
1767 }\r
1768\r
1769\r
1770 FreePool (PrivateRoot->VolumeLabel);\r
1771 PrivateRoot->VolumeLabel = AllocatePool (StrSize (NewFileSystemInfo->VolumeLabel));\r
1772 if (PrivateRoot->VolumeLabel == NULL) {\r
1773 Status = EFI_OUT_OF_RESOURCES;\r
1774 goto Done;\r
1775 }\r
1776\r
1777 StrCpy (PrivateRoot->VolumeLabel, NewFileSystemInfo->VolumeLabel);\r
1778\r
1779 Status = EFI_SUCCESS;\r
1780 goto Done;\r
1781 }\r
1782\r
1783 //\r
1784 // Set volume label information.\r
1785 //\r
1786 if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {\r
1787 if (BufferSize < StrSize (PrivateRoot->VolumeLabel)) {\r
1788 Status = EFI_BAD_BUFFER_SIZE;\r
1789 goto Done;\r
1790 }\r
1791\r
1792 StrCpy (PrivateRoot->VolumeLabel, (CHAR16 *)Buffer);\r
1793\r
1794 Status = EFI_SUCCESS;\r
1795 goto Done;\r
1796 }\r
1797\r
1798 if (!CompareGuid (InformationType, &gEfiFileInfoGuid)) {\r
1799 Status = EFI_UNSUPPORTED;\r
1800 goto Done;\r
1801 }\r
1802\r
1803 if (BufferSize < SIZE_OF_EFI_FILE_INFO) {\r
1804 Status = EFI_BAD_BUFFER_SIZE;\r
1805 goto Done;\r
1806 }\r
1807\r
1808 //\r
1809 // Set file/directory information.\r
1810 //\r
1811\r
1812 //\r
1813 // Check for invalid set file information parameters.\r
1814 //\r
1815 NewFileInfo = (EFI_FILE_INFO *)Buffer;\r
1816\r
1817 if ((NewFileInfo->Size <= SIZE_OF_EFI_FILE_INFO) ||\r
1818 (NewFileInfo->Attribute &~(EFI_FILE_VALID_ATTR)) ||\r
1819 (sizeof (UINTN) == 4 && NewFileInfo->Size > 0xFFFFFFFF)\r
1820 ) {\r
1821 Status = EFI_INVALID_PARAMETER;\r
1822 goto Done;\r
1823 }\r
1824\r
1825 //\r
1826 // bugbug: - This is not safe. We need something like EfiStrMaxSize()\r
1827 // that would have an additional parameter that would be the size\r
1828 // of the string array just in case there are no NULL characters in\r
1829 // the string array.\r
1830 //\r
1831 //\r
1832 // Get current file information so we can determine what kind\r
1833 // of change request this is.\r
1834 //\r
1835 OldInfoSize = 0;\r
1836 Status = WinNtSimpleFileSystemFileInfo (PrivateFile, &OldInfoSize, NULL);\r
1837\r
1838 if (Status != EFI_BUFFER_TOO_SMALL) {\r
1839 Status = EFI_DEVICE_ERROR;\r
1840 goto Done;\r
1841 }\r
1842\r
1843 OldFileInfo = AllocatePool (OldInfoSize);\r
1844 if (OldFileInfo == NULL) {\r
1845 Status = EFI_OUT_OF_RESOURCES;\r
1846 goto Done;\r
1847 }\r
1848\r
1849 Status = WinNtSimpleFileSystemFileInfo (PrivateFile, &OldInfoSize, OldFileInfo);\r
1850\r
1851 if (EFI_ERROR (Status)) {\r
1852 goto Done;\r
1853 }\r
1854\r
1855 OldFileName = AllocatePool (StrSize (PrivateFile->FileName));\r
1856 if (OldFileName == NULL) {\r
1857 Status = EFI_OUT_OF_RESOURCES;\r
1858 goto Done;\r
1859 }\r
1860\r
1861 StrCpy (OldFileName, PrivateFile->FileName);\r
1862\r
1863 //\r
1864 // Make full pathname from new filename and rootpath.\r
1865 //\r
1866 if (NewFileInfo->FileName[0] == '\\') {\r
1867 Size = StrSize (PrivateRoot->FilePath);\r
1868 Size += StrSize (L"\\");\r
1869 Size += StrSize (NewFileInfo->FileName);\r
1870 NewFileName = AllocatePool (Size);\r
1871 if (NewFileName == NULL) {\r
1872 Status = EFI_OUT_OF_RESOURCES;\r
1873 goto Done;\r
1874 }\r
1875\r
1876 StrCpy (NewFileName, PrivateRoot->FilePath);\r
1877 StrCat (NewFileName, L"\\");\r
1878 StrCat (NewFileName, NewFileInfo->FileName + 1);\r
1879 } else {\r
1880 Size = StrSize (PrivateFile->FilePath);\r
1881 Size += StrSize (L"\\");\r
1882 Size += StrSize (NewFileInfo->FileName);\r
1883 NewFileName = AllocatePool (Size);\r
1884 if (NewFileName == NULL) {\r
1885 Status = EFI_OUT_OF_RESOURCES;\r
1886 goto Done;\r
1887 }\r
1888\r
1889 StrCpy (NewFileName, PrivateFile->FilePath);\r
1890 StrCat (NewFileName, L"\\");\r
1891 StrCat (NewFileName, NewFileInfo->FileName);\r
1892 }\r
1893\r
1894 //\r
1895 // Is there an attribute change request?\r
1896 //\r
1897 if (NewFileInfo->Attribute != OldFileInfo->Attribute) {\r
1898 if ((NewFileInfo->Attribute & EFI_FILE_DIRECTORY) != (OldFileInfo->Attribute & EFI_FILE_DIRECTORY)) {\r
1899 Status = EFI_INVALID_PARAMETER;\r
1900 goto Done;\r
1901 }\r
1902\r
1903 AttrChangeFlag = TRUE;\r
1904 }\r
1905\r
1906 //\r
1907 // Is there a name change request?\r
1908 // bugbug: - Need EfiStrCaseCmp()\r
1909 //\r
1910 if (StrCmp (NewFileInfo->FileName, OldFileInfo->FileName)) {\r
1911 NameChangeFlag = TRUE;\r
1912 }\r
1913\r
1914 //\r
1915 // Is there a size change request?\r
1916 //\r
1917 if (NewFileInfo->FileSize != OldFileInfo->FileSize) {\r
1918 SizeChangeFlag = TRUE;\r
1919 }\r
1920\r
1921 //\r
1922 // Is there a time stamp change request?\r
1923 //\r
1924 if (!IsZero (&NewFileInfo->CreateTime, sizeof (EFI_TIME)) &&\r
1925 CompareMem (&NewFileInfo->CreateTime, &OldFileInfo->CreateTime, sizeof (EFI_TIME))\r
1926 ) {\r
1927 TimeChangeFlag = TRUE;\r
1928 } else if (!IsZero (&NewFileInfo->LastAccessTime, sizeof (EFI_TIME)) &&\r
1929 CompareMem (&NewFileInfo->LastAccessTime, &OldFileInfo->LastAccessTime, sizeof (EFI_TIME))\r
1930 ) {\r
1931 TimeChangeFlag = TRUE;\r
1932 } else if (!IsZero (&NewFileInfo->ModificationTime, sizeof (EFI_TIME)) &&\r
1933 CompareMem (&NewFileInfo->ModificationTime, &OldFileInfo->ModificationTime, sizeof (EFI_TIME))\r
1934 ) {\r
1935 TimeChangeFlag = TRUE;\r
1936 }\r
1937\r
1938 //\r
1939 // All done if there are no change requests being made.\r
1940 //\r
1941 if (!(AttrChangeFlag || NameChangeFlag || SizeChangeFlag || TimeChangeFlag)) {\r
1942 Status = EFI_SUCCESS;\r
1943 goto Done;\r
1944 }\r
1945\r
1946 //\r
1947 // Set file or directory information.\r
1948 //\r
1949 OldAttr = GetFileAttributes (OldFileName);\r
1950\r
1951 //\r
1952 // Name change.\r
1953 //\r
1954 if (NameChangeFlag) {\r
1955 //\r
1956 // Close the handles first\r
1957 //\r
1958 if (PrivateFile->IsOpenedByRead) {\r
1959 Status = EFI_ACCESS_DENIED;\r
1960 goto Done;\r
1961 }\r
1962\r
1963 for (CharPointer = NewFileName; *CharPointer != 0 && *CharPointer != L'/'; CharPointer++) {\r
1964 }\r
1965\r
1966 if (*CharPointer != 0) {\r
1967 Status = EFI_ACCESS_DENIED;\r
1968 goto Done;\r
1969 }\r
1970\r
1971 if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) {\r
1972 if (PrivateFile->IsDirectoryPath) {\r
1973 FindClose (PrivateFile->LHandle);\r
1974 } else {\r
1975 CloseHandle (PrivateFile->LHandle);\r
1976 PrivateFile->LHandle = INVALID_HANDLE_VALUE;\r
1977 }\r
1978 }\r
1979\r
1980 if (PrivateFile->IsDirectoryPath && PrivateFile->DirHandle != INVALID_HANDLE_VALUE) {\r
1981 CloseHandle (PrivateFile->DirHandle);\r
1982 PrivateFile->DirHandle = INVALID_HANDLE_VALUE;\r
1983 }\r
1984\r
1985 NtStatus = MoveFile (OldFileName, NewFileName);\r
1986\r
1987 if (NtStatus) {\r
1988 //\r
1989 // modify file name\r
1990 //\r
1991 FreePool (PrivateFile->FileName);\r
1992\r
1993 PrivateFile->FileName = AllocatePool (StrSize (NewFileName));\r
1994 if (PrivateFile->FileName == NULL) {\r
1995 Status = EFI_OUT_OF_RESOURCES;\r
1996 goto Done;\r
1997 }\r
1998\r
1999 StrCpy (PrivateFile->FileName, NewFileName);\r
2000\r
2001 Size = StrSize (NewFileName);\r
2002 Size += StrSize (L"\\*");\r
2003 TempFileName = AllocatePool (Size);\r
2004\r
2005 StrCpy (TempFileName, NewFileName);\r
2006\r
2007 if (!PrivateFile->IsDirectoryPath) {\r
2008 PrivateFile->LHandle = CreateFile (\r
2009 TempFileName,\r
2010 PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,\r
2011 FILE_SHARE_READ | FILE_SHARE_WRITE,\r
2012 NULL,\r
2013 OPEN_EXISTING,\r
2014 0,\r
2015 NULL\r
2016 );\r
2017\r
2018 FreePool (TempFileName);\r
2019\r
2020 //\r
2021 // Flush buffers just in case\r
2022 //\r
2023 if (FlushFileBuffers (PrivateFile->LHandle) == 0) {\r
2024 Status = EFI_DEVICE_ERROR;\r
2025 goto Done;\r
2026 }\r
2027 } else {\r
2028 PrivateFile->DirHandle = CreateFile (\r
2029 TempFileName,\r
2030 PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,\r
2031 FILE_SHARE_READ | FILE_SHARE_WRITE,\r
2032 NULL,\r
2033 OPEN_EXISTING,\r
2034 FILE_FLAG_BACKUP_SEMANTICS,\r
2035 NULL\r
2036 );\r
2037\r
2038 StrCat (TempFileName, L"\\*");\r
2039 PrivateFile->LHandle = FindFirstFile (TempFileName, &FindBuf);\r
2040\r
2041 FreePool (TempFileName);\r
2042 }\r
2043 } else {\r
2044 Status = EFI_ACCESS_DENIED;\r
2045 Reopen:;\r
2046\r
2047 NtStatus = SetFileAttributes (OldFileName, OldAttr);\r
2048\r
2049 if (!NtStatus) {\r
2050 goto Done;\r
2051 }\r
2052\r
2053 Size = StrSize (OldFileName);\r
2054 Size += StrSize (L"\\*");\r
2055 TempFileName = AllocatePool (Size);\r
2056\r
2057 StrCpy (TempFileName, OldFileName);\r
2058\r
2059 if (!PrivateFile->IsDirectoryPath) {\r
2060 PrivateFile->LHandle = CreateFile (\r
2061 TempFileName,\r
2062 PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,\r
2063 FILE_SHARE_READ | FILE_SHARE_WRITE,\r
2064 NULL,\r
2065 OPEN_EXISTING,\r
2066 0,\r
2067 NULL\r
2068 );\r
2069 } else {\r
2070 PrivateFile->DirHandle = CreateFile (\r
2071 TempFileName,\r
2072 PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,\r
2073 FILE_SHARE_READ | FILE_SHARE_WRITE,\r
2074 NULL,\r
2075 OPEN_EXISTING,\r
2076 FILE_FLAG_BACKUP_SEMANTICS,\r
2077 NULL\r
2078 );\r
2079\r
2080 StrCat (TempFileName, L"\\*");\r
2081 PrivateFile->LHandle = FindFirstFile (TempFileName, &FindBuf);\r
2082 }\r
2083\r
2084 FreePool (TempFileName);\r
2085\r
2086 goto Done;\r
2087\r
2088 }\r
2089 }\r
2090\r
2091 //\r
2092 // Size change\r
2093 //\r
2094 if (SizeChangeFlag) {\r
2095 if (PrivateFile->IsDirectoryPath) {\r
2096 Status = EFI_UNSUPPORTED;\r
2097 goto Done;\r
2098 }\r
2099\r
2100 if (PrivateFile->IsOpenedByRead || OldFileInfo->Attribute & EFI_FILE_READ_ONLY) {\r
2101 Status = EFI_ACCESS_DENIED;\r
2102 goto Done;\r
2103 }\r
2104\r
2105 Status = This->GetPosition (This, &CurPos);\r
2106 if (EFI_ERROR (Status)) {\r
2107 goto Done;\r
2108 }\r
2109\r
2110 Status = This->SetPosition (This, NewFileInfo->FileSize);\r
2111 if (EFI_ERROR (Status)) {\r
2112 goto Done;\r
2113 }\r
2114\r
2115 if (SetEndOfFile (PrivateFile->LHandle) == 0) {\r
2116 Status = EFI_DEVICE_ERROR;\r
2117 goto Done;\r
2118 }\r
2119\r
2120 Status = This->SetPosition (This, CurPos);\r
2121 if (EFI_ERROR (Status)) {\r
2122 goto Done;\r
2123 }\r
2124 }\r
2125\r
2126 //\r
2127 // Time change\r
2128 //\r
2129 if (TimeChangeFlag) {\r
2130\r
2131 NewCreationSystemTime.wYear = NewFileInfo->CreateTime.Year;\r
2132 NewCreationSystemTime.wMonth = NewFileInfo->CreateTime.Month;\r
2133 NewCreationSystemTime.wDay = NewFileInfo->CreateTime.Day;\r
2134 NewCreationSystemTime.wHour = NewFileInfo->CreateTime.Hour;\r
2135 NewCreationSystemTime.wMinute = NewFileInfo->CreateTime.Minute;\r
2136 NewCreationSystemTime.wSecond = NewFileInfo->CreateTime.Second;\r
2137 NewCreationSystemTime.wMilliseconds = 0;\r
2138\r
2139 if (!SystemTimeToFileTime (\r
2140 &NewCreationSystemTime,\r
2141 &NewCreationFileTime\r
2142 )) {\r
2143 goto Done;\r
2144 }\r
2145\r
2146 if (!LocalFileTimeToFileTime (\r
2147 &NewCreationFileTime,\r
2148 &NewCreationFileTime\r
2149 )) {\r
2150 goto Done;\r
2151 }\r
2152\r
2153 NewLastAccessSystemTime.wYear = NewFileInfo->LastAccessTime.Year;\r
2154 NewLastAccessSystemTime.wMonth = NewFileInfo->LastAccessTime.Month;\r
2155 NewLastAccessSystemTime.wDay = NewFileInfo->LastAccessTime.Day;\r
2156 NewLastAccessSystemTime.wHour = NewFileInfo->LastAccessTime.Hour;\r
2157 NewLastAccessSystemTime.wMinute = NewFileInfo->LastAccessTime.Minute;\r
2158 NewLastAccessSystemTime.wSecond = NewFileInfo->LastAccessTime.Second;\r
2159 NewLastAccessSystemTime.wMilliseconds = 0;\r
2160\r
2161 if (!SystemTimeToFileTime (\r
2162 &NewLastAccessSystemTime,\r
2163 &NewLastAccessFileTime\r
2164 )) {\r
2165 goto Done;\r
2166 }\r
2167\r
2168 if (!LocalFileTimeToFileTime (\r
2169 &NewLastAccessFileTime,\r
2170 &NewLastAccessFileTime\r
2171 )) {\r
2172 goto Done;\r
2173 }\r
2174\r
2175 NewLastWriteSystemTime.wYear = NewFileInfo->ModificationTime.Year;\r
2176 NewLastWriteSystemTime.wMonth = NewFileInfo->ModificationTime.Month;\r
2177 NewLastWriteSystemTime.wDay = NewFileInfo->ModificationTime.Day;\r
2178 NewLastWriteSystemTime.wHour = NewFileInfo->ModificationTime.Hour;\r
2179 NewLastWriteSystemTime.wMinute = NewFileInfo->ModificationTime.Minute;\r
2180 NewLastWriteSystemTime.wSecond = NewFileInfo->ModificationTime.Second;\r
2181 NewLastWriteSystemTime.wMilliseconds = 0;\r
2182\r
2183 if (!SystemTimeToFileTime (\r
2184 &NewLastWriteSystemTime,\r
2185 &NewLastWriteFileTime\r
2186 )) {\r
2187 goto Done;\r
2188 }\r
2189\r
2190 if (!LocalFileTimeToFileTime (\r
2191 &NewLastWriteFileTime,\r
2192 &NewLastWriteFileTime\r
2193 )) {\r
2194 goto Done;\r
2195 }\r
2196\r
2197 if (!SetFileTime (\r
2198 PrivateFile->IsDirectoryPath ? PrivateFile->DirHandle : PrivateFile->LHandle,\r
2199 &NewCreationFileTime,\r
2200 &NewLastAccessFileTime,\r
2201 &NewLastWriteFileTime\r
2202 )) {\r
2203 Status = EFI_DEVICE_ERROR;\r
2204 goto Done;\r
2205 }\r
2206\r
2207 }\r
2208\r
2209 //\r
2210 // No matter about AttrChangeFlag, Attribute must be set.\r
2211 // Because operation before may cause attribute change.\r
2212 //\r
2213 NewAttr = OldAttr;\r
2214\r
2215 if (NewFileInfo->Attribute & EFI_FILE_ARCHIVE) {\r
2216 NewAttr |= FILE_ATTRIBUTE_ARCHIVE;\r
2217 } else {\r
2218 NewAttr &= ~FILE_ATTRIBUTE_ARCHIVE;\r
2219 }\r
2220\r
2221 if (NewFileInfo->Attribute & EFI_FILE_HIDDEN) {\r
2222 NewAttr |= FILE_ATTRIBUTE_HIDDEN;\r
2223 } else {\r
2224 NewAttr &= ~FILE_ATTRIBUTE_HIDDEN;\r
2225 }\r
2226\r
2227 if (NewFileInfo->Attribute & EFI_FILE_SYSTEM) {\r
2228 NewAttr |= FILE_ATTRIBUTE_SYSTEM;\r
2229 } else {\r
2230 NewAttr &= ~FILE_ATTRIBUTE_SYSTEM;\r
2231 }\r
2232\r
2233 if (NewFileInfo->Attribute & EFI_FILE_READ_ONLY) {\r
2234 NewAttr |= FILE_ATTRIBUTE_READONLY;\r
2235 } else {\r
2236 NewAttr &= ~FILE_ATTRIBUTE_READONLY;\r
2237 }\r
2238\r
2239 NtStatus = SetFileAttributes (NewFileName, NewAttr);\r
2240\r
2241 if (!NtStatus) {\r
2242 Status = EFI_DEVICE_ERROR;\r
2243 goto Reopen;\r
2244 }\r
2245\r
2246Done:\r
2247 if (OldFileInfo != NULL) {\r
2248 FreePool (OldFileInfo);\r
2249 }\r
2250\r
2251 if (OldFileName != NULL) {\r
2252 FreePool (OldFileName);\r
2253 }\r
2254\r
2255 if (NewFileName != NULL) {\r
2256 FreePool (NewFileName);\r
2257 }\r
2258\r
2259 return Status;\r
2260}\r
2261\r
2262\r
2263/**\r
2264 Flush data back for the file handle.\r
2265\r
2266 @param This Protocol instance pointer.\r
2267\r
2268 @retval EFI_SUCCESS Data was written.\r
2269 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.\r
2270 @retval EFI_NO_MEDIA The device has no media.\r
2271 @retval EFI_DEVICE_ERROR The device reported an error.\r
2272 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
2273 @retval EFI_WRITE_PROTECTED The device is write protected.\r
2274 @retval EFI_ACCESS_DENIED The file was open for read only.\r
2275 @retval EFI_VOLUME_FULL The volume is full.\r
2276\r
2277**/\r
2278EFI_STATUS\r
2279WinNtFileFlush (\r
2280 IN EFI_FILE_PROTOCOL *This\r
2281 )\r
2282{\r
2283 BY_HANDLE_FILE_INFORMATION FileInfo;\r
2284 WIN_NT_EFI_FILE_PRIVATE *PrivateFile;\r
2285 EFI_STATUS Status;\r
2286\r
2287 PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
2288\r
2289 if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) {\r
2290 Status = EFI_DEVICE_ERROR;\r
2291 goto Done;\r
2292 }\r
2293\r
2294 if (PrivateFile->IsDirectoryPath) {\r
2295 Status = EFI_SUCCESS;\r
2296 goto Done;\r
2297 }\r
2298\r
2299 if (PrivateFile->IsOpenedByRead) {\r
2300 Status = EFI_ACCESS_DENIED;\r
2301 goto Done;\r
2302 }\r
2303\r
2304 GetFileInformationByHandle (PrivateFile->LHandle, &FileInfo);\r
2305\r
2306 if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {\r
2307 Status = EFI_ACCESS_DENIED;\r
2308 goto Done;\r
2309 }\r
2310\r
2311 Status = FlushFileBuffers (PrivateFile->LHandle) ? EFI_SUCCESS : EFI_DEVICE_ERROR;\r
2312\r
2313Done:\r
2314 return Status;\r
2315 //\r
2316 // bugbug: - Use Windows error reporting.\r
2317 //\r
2318\r
2319}\r
2320\r
2321\r
2322\r
2323EFI_STATUS\r
2324WinNtFileSystmeThunkOpen (\r
2325 IN EMU_IO_THUNK_PROTOCOL *This\r
2326 )\r
2327{\r
2328 WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *Private;\r
2329\r
2330 Private = AllocateZeroPool (sizeof (*Private));\r
2331 if (Private == NULL) {\r
2332 return EFI_OUT_OF_RESOURCES;\r
2333 }\r
2334\r
2335 Private->FilePath = AllocateCopyPool (StrSize (This->ConfigString), This->ConfigString);\r
2336 if (Private->FilePath == NULL) {\r
2337 FreePool (Private);\r
2338 return EFI_OUT_OF_RESOURCES;\r
2339 }\r
2340\r
2341 Private->VolumeLabel = AllocateCopyPool (StrSize (L"EFI_EMULATED"), L"EFI_EMULATED");\r
2342 if (Private->VolumeLabel == NULL) {\r
2343 FreePool (Private->FilePath);\r
2344 FreePool (Private);\r
2345 return EFI_OUT_OF_RESOURCES;\r
2346 }\r
2347\r
2348 Private->Signature = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE;\r
2349 Private->Thunk = This;\r
2350 CopyMem (&Private->SimpleFileSystem, &gWinNtFileSystemProtocol, sizeof (Private->SimpleFileSystem));\r
2351\r
2352 This->Interface = &Private->SimpleFileSystem;\r
2353 This->Private = Private;\r
2354 return EFI_SUCCESS;\r
2355}\r
2356\r
2357\r
2358EFI_STATUS\r
2359WinNtFileSystmeThunkClose (\r
2360 IN EMU_IO_THUNK_PROTOCOL *This\r
2361 )\r
2362{\r
2363 WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *Private;\r
2364\r
2365 Private = This->Private;\r
2366 ASSERT (Private != NULL);\r
2367\r
2368 if (Private->VolumeLabel != NULL) {\r
2369 FreePool (Private->VolumeLabel);\r
2370 }\r
2371 if (Private->FilePath != NULL) {\r
2372 FreePool (Private->FilePath);\r
2373 }\r
2374 FreePool (Private);\r
2375 return EFI_SUCCESS;\r
2376}\r
2377\r
2378\r
2379EFI_FILE_PROTOCOL gWinNtFileProtocol = {\r
2380 EFI_FILE_REVISION,\r
2381 WinNtFileOpen,\r
2382 WinNtFileClose,\r
2383 WinNtFileDelete,\r
2384 WinNtFileRead,\r
2385 WinNtFileWrite,\r
2386 WinNtFileGetPossition,\r
2387 WinNtFileSetPossition,\r
2388 WinNtFileGetInfo,\r
2389 WinNtFileSetInfo,\r
2390 WinNtFileFlush\r
2391};\r
2392\r
2393EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gWinNtFileSystemProtocol = {\r
2394 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,\r
2395 WinNtOpenVolume\r
2396};\r
2397\r
2398\r
2399EMU_IO_THUNK_PROTOCOL mWinNtFileSystemThunkIo = {\r
2400 &gEfiSimpleFileSystemProtocolGuid,\r
2401 NULL,\r
2402 NULL,\r
2403 0,\r
2404 WinNtFileSystmeThunkOpen,\r
2405 WinNtFileSystmeThunkClose,\r
2406 NULL\r
2407};\r
2408\r
2409\r