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