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