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