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