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 *
EfiStrChr(IN CHAR16 * Str,IN CHAR16 Chr)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
IsZero(IN VOID * Buffer,IN UINTN Length)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
CutPrefix(IN CHAR16 * Str,IN UINTN Count)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
WinNtOpenVolume(IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL * This,OUT EFI_FILE_PROTOCOL ** Root)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
CountLeadingDots(IN CONST CHAR16 * FileNameToken)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
IsFileNameTokenValid(IN CONST CHAR16 * FileNameToken)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 *
GetNextFileNameToken(IN OUT CONST CHAR16 ** FileName)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 FileName contains more than two dots separated 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
IsFileNameValid(IN CONST CHAR16 * FileName)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
WinNtFileOpen(IN EFI_FILE_PROTOCOL * This,OUT EFI_FILE_PROTOCOL ** NewHandle,IN CHAR16 * FileName,IN UINT64 OpenMode,IN UINT64 Attributes)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
WinNtFileClose(IN EFI_FILE_PROTOCOL * This)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
WinNtFileDelete(IN EFI_FILE_PROTOCOL * This)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
WinNtSystemTimeToEfiTime(IN SYSTEMTIME * SystemTime,IN TIME_ZONE_INFORMATION * TimeZone,OUT EFI_TIME * Time)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
WinNtFileTimeToEfiTime(IN CONST WIN_NT_EFI_FILE_PRIVATE * PrivateFile,IN TIME_ZONE_INFORMATION * TimeZone,IN CONST FILETIME * FileTime,OUT EFI_TIME * EfiTime)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
WinNtFileRead(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,OUT VOID * Buffer)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
WinNtFileWrite(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,IN VOID * Buffer)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
WinNtFileSetPossition(IN EFI_FILE_PROTOCOL * This,IN UINT64 Position)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
WinNtFileGetPossition(IN EFI_FILE_PROTOCOL * This,OUT UINT64 * Position)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
WinNtSimpleFileSystemFileInfo(IN WIN_NT_EFI_FILE_PRIVATE * PrivateFile,IN OUT UINTN * BufferSize,OUT VOID * Buffer)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
WinNtFileGetInfo(IN EFI_FILE_PROTOCOL * This,IN EFI_GUID * InformationType,IN OUT UINTN * BufferSize,OUT VOID * Buffer)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
WinNtFileSetInfo(IN EFI_FILE_PROTOCOL * This,IN EFI_GUID * InformationType,IN UINTN BufferSize,IN VOID * Buffer)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
WinNtFileFlush(IN EFI_FILE_PROTOCOL * This)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
WinNtFileSystmeThunkOpen(IN EMU_IO_THUNK_PROTOCOL * This)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
WinNtFileSystmeThunkClose(IN EMU_IO_THUNK_PROTOCOL * This)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 
2446