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