--- /dev/null
+/*++ @file\r
+ Support OS native directory access.\r
+\r
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+**/\r
+\r
+#include "WinHost.h"\r
+\r
+\r
+#define WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE SIGNATURE_32 ('N', 'T', 'f', 's')\r
+\r
+typedef struct {\r
+ UINTN Signature;\r
+ EMU_IO_THUNK_PROTOCOL *Thunk;\r
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL SimpleFileSystem;\r
+ CHAR16 *FilePath;\r
+ CHAR16 *VolumeLabel;\r
+} WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE;\r
+\r
+#define WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS(a) \\r
+ CR (a, \\r
+ WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE, \\r
+ SimpleFileSystem, \\r
+ WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE \\r
+ )\r
+\r
+\r
+#define WIN_NT_EFI_FILE_PRIVATE_SIGNATURE SIGNATURE_32 ('l', 'o', 'f', 's')\r
+\r
+typedef struct {\r
+ UINTN Signature;\r
+ EMU_IO_THUNK_PROTOCOL *Thunk;\r
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;\r
+ EFI_FILE_PROTOCOL EfiFile;\r
+ HANDLE LHandle;\r
+ HANDLE DirHandle;\r
+ BOOLEAN IsRootDirectory;\r
+ BOOLEAN IsDirectoryPath;\r
+ BOOLEAN IsOpenedByRead;\r
+ CHAR16 *FilePath;\r
+ WCHAR *FileName;\r
+ BOOLEAN IsValidFindBuf;\r
+ WIN32_FIND_DATA FindBuf;\r
+} WIN_NT_EFI_FILE_PRIVATE;\r
+\r
+#define WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS(a) \\r
+ CR (a, \\r
+ WIN_NT_EFI_FILE_PRIVATE, \\r
+ EfiFile, \\r
+ WIN_NT_EFI_FILE_PRIVATE_SIGNATURE \\r
+ )\r
+\r
+extern EFI_FILE_PROTOCOL gWinNtFileProtocol;\r
+extern EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gWinNtFileSystemProtocol;\r
+\r
+EFI_STATUS\r
+WinNtFileGetInfo (\r
+ IN EFI_FILE_PROTOCOL *This,\r
+ IN EFI_GUID *InformationType,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+EFI_STATUS\r
+WinNtFileSetInfo (\r
+ IN EFI_FILE_PROTOCOL *This,\r
+ IN EFI_GUID *InformationType,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ );\r
+\r
+\r
+\r
+CHAR16 *\r
+EfiStrChr (\r
+ IN CHAR16 *Str,\r
+ IN CHAR16 Chr\r
+)\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Locate the first occurance of a character in a string.\r
+\r
+Arguments:\r
+\r
+ Str - Pointer to NULL terminated unicode string.\r
+ Chr - Character to locate.\r
+\r
+Returns:\r
+\r
+ If Str is NULL, then NULL is returned.\r
+ If Chr is not contained in Str, then NULL is returned.\r
+ If Chr is contained in Str, then a pointer to the first occurance of Chr in Str is returned.\r
+\r
+--*/\r
+{\r
+ if (Str == NULL) {\r
+ return Str;\r
+ }\r
+\r
+ while (*Str != '\0' && *Str != Chr) {\r
+ ++Str;\r
+ }\r
+\r
+ return (*Str == Chr) ? Str : NULL;\r
+}\r
+\r
+\r
+\r
+BOOLEAN\r
+IsZero (\r
+ IN VOID *Buffer,\r
+ IN UINTN Length\r
+ )\r
+{\r
+ if (Buffer == NULL || Length == 0) {\r
+ return FALSE;\r
+ }\r
+\r
+ if (*(UINT8 *) Buffer != 0) {\r
+ return FALSE;\r
+ }\r
+\r
+ if (Length > 1) {\r
+ if (!CompareMem (Buffer, (UINT8 *) Buffer + 1, Length - 1)) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+VOID\r
+CutPrefix (\r
+ IN CHAR16 *Str,\r
+ IN UINTN Count\r
+ )\r
+{\r
+ CHAR16 *Pointer;\r
+\r
+ if (StrLen (Str) < Count) {\r
+ ASSERT (0);\r
+ }\r
+\r
+ if (Count != 0) {\r
+ for (Pointer = Str; *(Pointer + Count); Pointer++) {\r
+ *Pointer = *(Pointer + Count);\r
+ }\r
+\r
+ *Pointer = *(Pointer + Count);\r
+ }\r
+}\r
+/**\r
+ Open the root directory on a volume.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Root Returns an Open file handle for the root directory\r
+\r
+ @retval EFI_SUCCESS The device was opened.\r
+ @retval EFI_UNSUPPORTED This volume does not support the file system.\r
+ @retval EFI_NO_MEDIA The device has no media.\r
+ @retval EFI_DEVICE_ERROR The device reported an error.\r
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+ @retval EFI_ACCESS_DENIED The service denied access to the file.\r
+ @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtOpenVolume (\r
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,\r
+ OUT EFI_FILE_PROTOCOL **Root\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *Private;\r
+ WIN_NT_EFI_FILE_PRIVATE *PrivateFile;\r
+ CHAR16 *TempFileName;\r
+ UINTN Size;\r
+\r
+ if (This == NULL || Root == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ PrivateFile = AllocatePool (sizeof (WIN_NT_EFI_FILE_PRIVATE));\r
+ if (PrivateFile == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ PrivateFile->FileName = AllocatePool (StrSize (Private->FilePath));\r
+ if (PrivateFile->FileName == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ PrivateFile->FilePath = AllocatePool (StrSize (Private->FilePath));\r
+ if (PrivateFile->FilePath == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ StrCpy (PrivateFile->FilePath, Private->FilePath);\r
+ StrCpy (PrivateFile->FileName, PrivateFile->FilePath);\r
+ PrivateFile->Signature = WIN_NT_EFI_FILE_PRIVATE_SIGNATURE;\r
+ PrivateFile->Thunk = Private->Thunk;\r
+ PrivateFile->SimpleFileSystem = This;\r
+ PrivateFile->IsRootDirectory = TRUE;\r
+ PrivateFile->IsDirectoryPath = TRUE;\r
+ PrivateFile->IsOpenedByRead = TRUE;\r
+ CopyMem (&PrivateFile->EfiFile, &gWinNtFileProtocol, sizeof (gWinNtFileProtocol));\r
+ PrivateFile->IsValidFindBuf = FALSE;\r
+\r
+ //\r
+ // Set DirHandle\r
+ //\r
+ PrivateFile->DirHandle = CreateFile (\r
+ PrivateFile->FilePath,\r
+ GENERIC_READ,\r
+ FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+ NULL,\r
+ OPEN_EXISTING,\r
+ FILE_FLAG_BACKUP_SEMANTICS,\r
+ NULL\r
+ );\r
+\r
+ if (PrivateFile->DirHandle == INVALID_HANDLE_VALUE) {\r
+ Status = EFI_NOT_FOUND;\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Find the first file under it\r
+ //\r
+ Size = StrSize (PrivateFile->FilePath);\r
+ Size += StrSize (L"\\*");\r
+ TempFileName = AllocatePool (Size);\r
+ if (TempFileName == NULL) {\r
+ goto Done;\r
+ }\r
+ StrCpy (TempFileName, PrivateFile->FilePath);\r
+ StrCat (TempFileName, L"\\*");\r
+\r
+ PrivateFile->LHandle = FindFirstFile (TempFileName, &PrivateFile->FindBuf);\r
+ FreePool (TempFileName);\r
+\r
+ if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) {\r
+ PrivateFile->IsValidFindBuf = FALSE;\r
+ } else {\r
+ PrivateFile->IsValidFindBuf = TRUE;\r
+ }\r
+ *Root = &PrivateFile->EfiFile;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+Done:\r
+ if (EFI_ERROR (Status)) {\r
+ if (PrivateFile) {\r
+ if (PrivateFile->FileName) {\r
+ FreePool (PrivateFile->FileName);\r
+ }\r
+\r
+ if (PrivateFile->FilePath) {\r
+ FreePool (PrivateFile->FilePath);\r
+ }\r
+\r
+ FreePool (PrivateFile);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Count the number of Leading Dot in FileNameToken.\r
+\r
+ @param FileNameToken A string representing a token in the path name.\r
+\r
+ @return UINTN The number of leading dot in the name.\r
+\r
+**/\r
+UINTN\r
+CountLeadingDots (\r
+ IN CONST CHAR16 * FileNameToken\r
+)\r
+{\r
+ UINTN Num;\r
+\r
+ Num = 0;\r
+ while (*FileNameToken == L'.') {\r
+ Num++;\r
+ FileNameToken++;\r
+ }\r
+\r
+ return Num;\r
+}\r
+\r
+\r
+BOOLEAN\r
+IsFileNameTokenValid (\r
+ IN CONST CHAR16 * FileNameToken\r
+)\r
+{\r
+ UINTN Num;\r
+ if (StrStr (FileNameToken, L"/") != NULL) {\r
+ //\r
+ // No L'/' in file name.\r
+ //\r
+ return FALSE;\r
+ } else {\r
+ //\r
+ // If Token has all dot, the number should not exceed 2\r
+ //\r
+ Num = CountLeadingDots (FileNameToken);\r
+\r
+ if (Num == StrLen (FileNameToken)) {\r
+ //\r
+ // If the FileNameToken only contains a number of L'.'.\r
+ //\r
+ if (Num > 2) {\r
+ return FALSE;\r
+ }\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+/**\r
+ Return the first string token found in the indirect pointer a String named by FileName.\r
+\r
+ On input, FileName is a indirect pointer pointing to a String.\r
+ On output, FileName is a updated to point to the next character after the first\r
+ found L"\" or NULL if there is no L"\" found.\r
+\r
+ @param FileName A indirect pointer pointing to a FileName.\r
+\r
+ @return Token The first string token found before a L"\".\r
+\r
+**/\r
+CHAR16 *\r
+GetNextFileNameToken (\r
+ IN OUT CONST CHAR16 ** FileName\r
+)\r
+{\r
+ CHAR16 *SlashPos;\r
+ CHAR16 *Token;\r
+ UINTN Offset;\r
+ ASSERT (**FileName != L'\\');\r
+ ASSERT (**FileName != L'\0');\r
+\r
+ SlashPos = StrStr (*FileName, L"\\");\r
+ if (SlashPos == NULL) {\r
+ Token = AllocateCopyPool (StrSize (*FileName), *FileName);\r
+ *FileName = NULL;\r
+ } else {\r
+ Offset = SlashPos - *FileName;\r
+ Token = AllocateZeroPool ((Offset + 1) * sizeof (CHAR16));\r
+ StrnCpy (Token, *FileName, Offset);\r
+ //\r
+ // Point *FileName to the next character after L'\'.\r
+ //\r
+ *FileName = *FileName + Offset + 1;\r
+ //\r
+ // If *FileName is an empty string, then set *FileName to NULL\r
+ //\r
+ if (**FileName == L'\0') {\r
+ *FileName = NULL;\r
+ }\r
+ }\r
+\r
+ return Token;\r
+}\r
+\r
+\r
+/**\r
+ Check if a FileName contains only Valid Characters.\r
+\r
+ If FileName contains only a single L'\', return TRUE.\r
+ If FileName contains two adjacent L'\', return FALSE.\r
+ If FileName conatins L'/' , return FALSE.\r
+ If FielName contains more than two dots seperated with other FileName characters\r
+ by L'\', return FALSE. For example, L'.\...\filename.txt' is invalid path name. But L'..TwoDots\filename.txt' is valid path name.\r
+\r
+ @param FileName The File Name String to check.\r
+\r
+ @return TRUE FileName only contains valid characters.\r
+ @return FALSE FileName contains at least one invalid character.\r
+\r
+**/\r
+\r
+BOOLEAN\r
+IsFileNameValid (\r
+ IN CONST CHAR16 *FileName\r
+ )\r
+{\r
+ CHAR16 *Token;\r
+ BOOLEAN Valid;\r
+\r
+ //\r
+ // If FileName is just L'\', then it is a valid pathname.\r
+ //\r
+ if (StrCmp (FileName, L"\\") == 0) {\r
+ return TRUE;\r
+ }\r
+ //\r
+ // We don't support two or more adjacent L'\'.\r
+ //\r
+ if (StrStr (FileName, L"\\\\") != NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Is FileName has a leading L"\", skip to next character.\r
+ //\r
+ if (FileName [0] == L'\\') {\r
+ FileName++;\r
+ }\r
+\r
+ do {\r
+ Token = GetNextFileNameToken (&FileName);\r
+ Valid = IsFileNameTokenValid (Token);\r
+ FreePool (Token);\r
+\r
+ if (!Valid)\r
+ return FALSE;\r
+ } while (FileName != NULL);\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+/**\r
+ Opens a new file relative to the source file's location.\r
+\r
+ @param This The protocol instance pointer.\r
+ @param NewHandle Returns File Handle for FileName.\r
+ @param FileName Null terminated string. "\", ".", and ".." are supported.\r
+ @param OpenMode Open mode for file.\r
+ @param Attributes Only used for EFI_FILE_MODE_CREATE.\r
+\r
+ @retval EFI_SUCCESS The device was opened.\r
+ @retval EFI_NOT_FOUND The specified file could not be found on the device.\r
+ @retval EFI_NO_MEDIA The device has no media.\r
+ @retval EFI_MEDIA_CHANGED The media has changed.\r
+ @retval EFI_DEVICE_ERROR The device reported an error.\r
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+ @retval EFI_ACCESS_DENIED The service denied access to the file.\r
+ @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.\r
+ @retval EFI_VOLUME_FULL The volume is full.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtFileOpen (\r
+ IN EFI_FILE_PROTOCOL *This,\r
+ OUT EFI_FILE_PROTOCOL **NewHandle,\r
+ IN CHAR16 *FileName,\r
+ IN UINT64 OpenMode,\r
+ IN UINT64 Attributes\r
+ )\r
+{\r
+ WIN_NT_EFI_FILE_PRIVATE *PrivateFile;\r
+ WIN_NT_EFI_FILE_PRIVATE *NewPrivateFile;\r
+ WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;\r
+ EFI_STATUS Status;\r
+ CHAR16 *RealFileName;\r
+ CHAR16 *TempFileName;\r
+ CHAR16 *ParseFileName;\r
+ CHAR16 *GuardPointer;\r
+ CHAR16 TempChar;\r
+ DWORD LastError;\r
+ UINTN Count;\r
+ BOOLEAN LoopFinish;\r
+ UINTN InfoSize;\r
+ EFI_FILE_INFO *Info;\r
+ UINTN Size;\r
+\r
+\r
+ //\r
+ // Init local variables\r
+ //\r
+ PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
+ PrivateRoot = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);\r
+ NewPrivateFile = NULL;\r
+\r
+ //\r
+ // Allocate buffer for FileName as the passed in FileName may be read only\r
+ //\r
+ TempFileName = AllocatePool (StrSize (FileName));\r
+ if (TempFileName == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ StrCpy (TempFileName, FileName);\r
+ FileName = TempFileName;\r
+\r
+ if (FileName[StrLen (FileName) - 1] == L'\\') {\r
+ FileName[StrLen (FileName) - 1] = 0;\r
+ }\r
+\r
+ //\r
+ // If file name does not equal to "." or ".." and not trailed with "\..",\r
+ // then we trim the leading/trailing blanks and trailing dots\r
+ //\r
+ if (StrCmp (FileName, L".") != 0 && StrCmp (FileName, L"..") != 0 &&\r
+ ((StrLen (FileName) >= 3) ? (StrCmp (&FileName[StrLen (FileName) - 3], L"\\..") != 0) : TRUE)) {\r
+ //\r
+ // Trim leading blanks\r
+ //\r
+ Count = 0;\r
+ for (TempFileName = FileName;\r
+ *TempFileName != 0 && *TempFileName == L' ';\r
+ TempFileName++) {\r
+ Count++;\r
+ }\r
+ CutPrefix (FileName, Count);\r
+ //\r
+ // Trim trailing blanks\r
+ //\r
+ for (TempFileName = FileName + StrLen (FileName) - 1;\r
+ TempFileName >= FileName && (*TempFileName == L' ');\r
+ TempFileName--) {\r
+ ;\r
+ }\r
+ *(TempFileName + 1) = 0;\r
+ }\r
+\r
+ //\r
+ // Attempt to open the file\r
+ //\r
+ NewPrivateFile = AllocatePool (sizeof (WIN_NT_EFI_FILE_PRIVATE));\r
+ if (NewPrivateFile == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ CopyMem (NewPrivateFile, PrivateFile, sizeof (WIN_NT_EFI_FILE_PRIVATE));\r
+\r
+ NewPrivateFile->FilePath = AllocatePool (StrSize (PrivateFile->FileName));\r
+ if (NewPrivateFile->FilePath == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ if (PrivateFile->IsDirectoryPath) {\r
+ StrCpy (NewPrivateFile->FilePath, PrivateFile->FileName);\r
+ } else {\r
+ StrCpy (NewPrivateFile->FilePath, PrivateFile->FilePath);\r
+ }\r
+\r
+ Size = StrSize (NewPrivateFile->FilePath);\r
+ Size += StrSize (L"\\");\r
+ Size += StrSize (FileName);\r
+ NewPrivateFile->FileName = AllocatePool (Size);\r
+ if (NewPrivateFile->FileName == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ if (*FileName == L'\\') {\r
+ StrCpy (NewPrivateFile->FileName, PrivateRoot->FilePath);\r
+ StrCat (NewPrivateFile->FileName, L"\\");\r
+ StrCat (NewPrivateFile->FileName, FileName + 1);\r
+ } else {\r
+ StrCpy (NewPrivateFile->FileName, NewPrivateFile->FilePath);\r
+ if (StrCmp (FileName, L"") != 0) {\r
+ //\r
+ // In case the filename becomes empty, especially after trimming dots and blanks\r
+ //\r
+ StrCat (NewPrivateFile->FileName, L"\\");\r
+ StrCat (NewPrivateFile->FileName, FileName);\r
+ }\r
+ }\r
+\r
+ if (!IsFileNameValid (NewPrivateFile->FileName)) {\r
+ Status = EFI_NOT_FOUND;\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Get rid of . and .., except leading . or ..\r
+ //\r
+\r
+ //\r
+ // GuardPointer protect simplefilesystem root path not be destroyed\r
+ //\r
+ GuardPointer = NewPrivateFile->FileName + StrLen (PrivateRoot->FilePath);\r
+\r
+ LoopFinish = FALSE;\r
+\r
+ while (!LoopFinish) {\r
+\r
+ LoopFinish = TRUE;\r
+\r
+ for (ParseFileName = GuardPointer; *ParseFileName; ParseFileName++) {\r
+ if (*ParseFileName == L'.' &&\r
+ (*(ParseFileName + 1) == 0 || *(ParseFileName + 1) == L'\\') &&\r
+ *(ParseFileName - 1) == L'\\'\r
+ ) {\r
+\r
+ //\r
+ // cut \.\r
+ //\r
+ CutPrefix (ParseFileName - 1, 2);\r
+ LoopFinish = FALSE;\r
+ break;\r
+ }\r
+\r
+ if (*ParseFileName == L'.' &&\r
+ *(ParseFileName + 1) == L'.' &&\r
+ (*(ParseFileName + 2) == 0 || *(ParseFileName + 2) == L'\\') &&\r
+ *(ParseFileName - 1) == L'\\'\r
+ ) {\r
+\r
+ ParseFileName--;\r
+ Count = 3;\r
+\r
+ while (ParseFileName != GuardPointer) {\r
+ ParseFileName--;\r
+ Count++;\r
+ if (*ParseFileName == L'\\') {\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // cut \.. and its left directory\r
+ //\r
+ CutPrefix (ParseFileName, Count);\r
+ LoopFinish = FALSE;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ RealFileName = NewPrivateFile->FileName;\r
+ while (EfiStrChr (RealFileName, L'\\') != NULL) {\r
+ RealFileName = EfiStrChr (RealFileName, L'\\') + 1;\r
+ }\r
+\r
+ TempChar = 0;\r
+ if (RealFileName != NewPrivateFile->FileName) {\r
+ TempChar = *(RealFileName - 1);\r
+ *(RealFileName - 1) = 0;\r
+ }\r
+\r
+ FreePool (NewPrivateFile->FilePath);\r
+ NewPrivateFile->FilePath = NULL;\r
+ NewPrivateFile->FilePath = AllocatePool (StrSize (NewPrivateFile->FileName));\r
+ if (NewPrivateFile->FilePath == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ StrCpy (NewPrivateFile->FilePath, NewPrivateFile->FileName);\r
+ if (TempChar != 0) {\r
+ *(RealFileName - 1) = TempChar;\r
+ }\r
+\r
+ NewPrivateFile->IsRootDirectory = FALSE;\r
+\r
+ //\r
+ // Test whether file or directory\r
+ //\r
+ if (OpenMode & EFI_FILE_MODE_CREATE) {\r
+ if (Attributes & EFI_FILE_DIRECTORY) {\r
+ NewPrivateFile->IsDirectoryPath = TRUE;\r
+ } else {\r
+ NewPrivateFile->IsDirectoryPath = FALSE;\r
+ }\r
+ } else {\r
+ NewPrivateFile->LHandle = CreateFile (\r
+ NewPrivateFile->FileName,\r
+ GENERIC_READ,\r
+ FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+ NULL,\r
+ OPEN_EXISTING,\r
+ 0,\r
+ NULL\r
+ );\r
+\r
+ if (NewPrivateFile->LHandle != INVALID_HANDLE_VALUE) {\r
+ NewPrivateFile->IsDirectoryPath = FALSE;\r
+ CloseHandle (NewPrivateFile->LHandle);\r
+ } else {\r
+ NewPrivateFile->IsDirectoryPath = TRUE;\r
+ }\r
+\r
+ NewPrivateFile->LHandle = INVALID_HANDLE_VALUE;\r
+ }\r
+\r
+ if (OpenMode & EFI_FILE_MODE_WRITE) {\r
+ NewPrivateFile->IsOpenedByRead = FALSE;\r
+ } else {\r
+ NewPrivateFile->IsOpenedByRead = TRUE;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // deal with directory\r
+ //\r
+ if (NewPrivateFile->IsDirectoryPath) {\r
+\r
+ Size = StrSize (NewPrivateFile->FileName);\r
+ Size += StrSize (L"\\*");\r
+ TempFileName = AllocatePool (Size);\r
+ if (TempFileName == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ StrCpy (TempFileName, NewPrivateFile->FileName);\r
+\r
+ if ((OpenMode & EFI_FILE_MODE_CREATE)) {\r
+ //\r
+ // Create a directory\r
+ //\r
+ if (!CreateDirectory (TempFileName, NULL)) {\r
+\r
+ LastError = GetLastError ();\r
+ if (LastError != ERROR_ALREADY_EXISTS) {\r
+ FreePool (TempFileName);\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Done;\r
+ }\r
+ }\r
+ }\r
+\r
+ NewPrivateFile->DirHandle = CreateFile (\r
+ TempFileName,\r
+ NewPrivateFile->IsOpenedByRead ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE),\r
+ FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+ NULL,\r
+ OPEN_EXISTING,\r
+ FILE_FLAG_BACKUP_SEMANTICS,\r
+ NULL\r
+ );\r
+\r
+ if (NewPrivateFile->DirHandle == INVALID_HANDLE_VALUE) {\r
+\r
+ NewPrivateFile->DirHandle = CreateFile (\r
+ TempFileName,\r
+ GENERIC_READ,\r
+ FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+ NULL,\r
+ OPEN_EXISTING,\r
+ FILE_FLAG_BACKUP_SEMANTICS,\r
+ NULL\r
+ );\r
+\r
+ if (NewPrivateFile->DirHandle != INVALID_HANDLE_VALUE) {\r
+ CloseHandle (NewPrivateFile->DirHandle);\r
+ NewPrivateFile->DirHandle = INVALID_HANDLE_VALUE;\r
+ Status = EFI_ACCESS_DENIED;\r
+ } else {\r
+ Status = EFI_NOT_FOUND;\r
+ }\r
+\r
+ FreePool (TempFileName);\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Find the first file under it\r
+ //\r
+ StrCat (TempFileName, L"\\*");\r
+ NewPrivateFile->LHandle = FindFirstFile (TempFileName, &NewPrivateFile->FindBuf);\r
+ FreePool (TempFileName);\r
+\r
+ if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) {\r
+ NewPrivateFile->IsValidFindBuf = FALSE;\r
+ } else {\r
+ NewPrivateFile->IsValidFindBuf = TRUE;\r
+ }\r
+ } else {\r
+ //\r
+ // deal with file\r
+ //\r
+ if (!NewPrivateFile->IsOpenedByRead) {\r
+ NewPrivateFile->LHandle = CreateFile (\r
+ NewPrivateFile->FileName,\r
+ GENERIC_READ | GENERIC_WRITE,\r
+ FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+ NULL,\r
+ (OpenMode & EFI_FILE_MODE_CREATE) ? OPEN_ALWAYS : OPEN_EXISTING,\r
+ 0,\r
+ NULL\r
+ );\r
+\r
+ if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) {\r
+ NewPrivateFile->LHandle = CreateFile (\r
+ NewPrivateFile->FileName,\r
+ GENERIC_READ,\r
+ FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+ NULL,\r
+ OPEN_EXISTING,\r
+ 0,\r
+ NULL\r
+ );\r
+\r
+ if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) {\r
+ Status = EFI_NOT_FOUND;\r
+ } else {\r
+ Status = EFI_ACCESS_DENIED;\r
+ CloseHandle (NewPrivateFile->LHandle);\r
+ NewPrivateFile->LHandle = INVALID_HANDLE_VALUE;\r
+ }\r
+ }\r
+ } else {\r
+ NewPrivateFile->LHandle = CreateFile (\r
+ NewPrivateFile->FileName,\r
+ GENERIC_READ,\r
+ FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+ NULL,\r
+ OPEN_EXISTING,\r
+ 0,\r
+ NULL\r
+ );\r
+\r
+ if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) {\r
+ Status = EFI_NOT_FOUND;\r
+ }\r
+ }\r
+ }\r
+\r
+ if ((OpenMode & EFI_FILE_MODE_CREATE) && Status == EFI_SUCCESS) {\r
+ //\r
+ // Set the attribute\r
+ //\r
+ InfoSize = 0;\r
+ Info = NULL;\r
+\r
+ Status = WinNtFileGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info);\r
+\r
+ if (Status != EFI_BUFFER_TOO_SMALL) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Done;\r
+ }\r
+\r
+ Info = AllocatePool (InfoSize);\r
+ if (Info == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ Status = WinNtFileGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (Info);\r
+ goto Done;\r
+ }\r
+\r
+ Info->Attribute = Attributes;\r
+\r
+ WinNtFileSetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, InfoSize, Info);\r
+ FreePool (Info);\r
+ }\r
+\r
+Done:\r
+ FreePool (FileName);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ if (NewPrivateFile) {\r
+ if (NewPrivateFile->FileName) {\r
+ FreePool (NewPrivateFile->FileName);\r
+ }\r
+\r
+ if (NewPrivateFile->FilePath) {\r
+ FreePool (NewPrivateFile->FilePath);\r
+ }\r
+\r
+ FreePool (NewPrivateFile);\r
+ }\r
+ } else {\r
+ *NewHandle = &NewPrivateFile->EfiFile;\r
+ if (StrCmp (NewPrivateFile->FileName, PrivateRoot->FilePath) == 0) {\r
+ NewPrivateFile->IsRootDirectory = TRUE;\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Close the file handle\r
+\r
+ @param This Protocol instance pointer.\r
+\r
+ @retval EFI_SUCCESS The device was opened.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtFileClose (\r
+ IN EFI_FILE_PROTOCOL *This\r
+ )\r
+{\r
+ WIN_NT_EFI_FILE_PRIVATE *PrivateFile;\r
+\r
+ PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) {\r
+ if (PrivateFile->IsDirectoryPath) {\r
+ FindClose (PrivateFile->LHandle);\r
+ } else {\r
+ CloseHandle (PrivateFile->LHandle);\r
+ }\r
+\r
+ PrivateFile->LHandle = INVALID_HANDLE_VALUE;\r
+ }\r
+\r
+ if (PrivateFile->IsDirectoryPath && PrivateFile->DirHandle != INVALID_HANDLE_VALUE) {\r
+ CloseHandle (PrivateFile->DirHandle);\r
+ PrivateFile->DirHandle = INVALID_HANDLE_VALUE;\r
+ }\r
+\r
+ if (PrivateFile->FileName) {\r
+ FreePool (PrivateFile->FileName);\r
+ }\r
+\r
+ if (PrivateFile->FilePath) {\r
+ FreePool (PrivateFile->FilePath);\r
+ }\r
+\r
+ FreePool (PrivateFile);\r
+\r
+ return EFI_SUCCESS;\r
+\r
+}\r
+\r
+\r
+/**\r
+ Close and delete the file handle.\r
+\r
+ @param This Protocol instance pointer.\r
+\r
+ @retval EFI_SUCCESS The device was opened.\r
+ @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtFileDelete (\r
+ IN EFI_FILE_PROTOCOL *This\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ WIN_NT_EFI_FILE_PRIVATE *PrivateFile;\r
+\r
+ PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ Status = EFI_WARN_DELETE_FAILURE;\r
+\r
+ if (PrivateFile->IsDirectoryPath) {\r
+ if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) {\r
+ FindClose (PrivateFile->LHandle);\r
+ }\r
+\r
+ if (PrivateFile->DirHandle != INVALID_HANDLE_VALUE) {\r
+ CloseHandle (PrivateFile->DirHandle);\r
+ PrivateFile->DirHandle = INVALID_HANDLE_VALUE;\r
+ }\r
+\r
+ if (RemoveDirectory (PrivateFile->FileName)) {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ } else {\r
+ CloseHandle (PrivateFile->LHandle);\r
+ PrivateFile->LHandle = INVALID_HANDLE_VALUE;\r
+\r
+ if (!PrivateFile->IsOpenedByRead) {\r
+ if (DeleteFile (PrivateFile->FileName)) {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+\r
+ FreePool (PrivateFile->FileName);\r
+ FreePool (PrivateFile->FilePath);\r
+ FreePool (PrivateFile);\r
+\r
+ return Status;\r
+}\r
+\r
+VOID\r
+WinNtSystemTimeToEfiTime (\r
+ IN SYSTEMTIME *SystemTime,\r
+ IN TIME_ZONE_INFORMATION *TimeZone,\r
+ OUT EFI_TIME *Time\r
+)\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ SystemTime - TODO: add argument description\r
+ TimeZone - TODO: add argument description\r
+ Time - TODO: add argument description\r
+\r
+Returns:\r
+\r
+ TODO: add return values\r
+\r
+--*/\r
+{\r
+ Time->Year = (UINT16)SystemTime->wYear;\r
+ Time->Month = (UINT8)SystemTime->wMonth;\r
+ Time->Day = (UINT8)SystemTime->wDay;\r
+ Time->Hour = (UINT8)SystemTime->wHour;\r
+ Time->Minute = (UINT8)SystemTime->wMinute;\r
+ Time->Second = (UINT8)SystemTime->wSecond;\r
+ Time->Nanosecond = (UINT32)SystemTime->wMilliseconds * 1000000;\r
+ Time->TimeZone = (INT16)TimeZone->Bias;\r
+\r
+ if (TimeZone->StandardDate.wMonth) {\r
+ Time->Daylight = EFI_TIME_ADJUST_DAYLIGHT;\r
+ }\r
+}\r
+\r
+/**\r
+ Convert the FileTime to EfiTime.\r
+\r
+ @param PrivateFile Pointer to WIN_NT_EFI_FILE_PRIVATE.\r
+ @param TimeZone Pointer to the current time zone.\r
+ @param FileTime Pointer to file time.\r
+ @param EfiTime Pointer to EFI time.\r
+**/\r
+VOID\r
+WinNtFileTimeToEfiTime (\r
+ IN CONST WIN_NT_EFI_FILE_PRIVATE *PrivateFile,\r
+ IN TIME_ZONE_INFORMATION *TimeZone,\r
+ IN CONST FILETIME *FileTime,\r
+ OUT EFI_TIME *EfiTime\r
+)\r
+{\r
+ FILETIME TempFileTime;\r
+ SYSTEMTIME SystemTime;\r
+\r
+ FileTimeToLocalFileTime (FileTime, &TempFileTime);\r
+ FileTimeToSystemTime (&TempFileTime, &SystemTime);\r
+ WinNtSystemTimeToEfiTime (&SystemTime, TimeZone, EfiTime);\r
+}\r
+\r
+\r
+/**\r
+ Read data from the file.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param BufferSize On input size of buffer, on output amount of data in buffer.\r
+ @param Buffer The buffer in which data is read.\r
+\r
+ @retval EFI_SUCCESS Data was read.\r
+ @retval EFI_NO_MEDIA The device has no media.\r
+ @retval EFI_DEVICE_ERROR The device reported an error.\r
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+ @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtFileRead (\r
+ IN EFI_FILE_PROTOCOL *This,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ WIN_NT_EFI_FILE_PRIVATE *PrivateFile;\r
+ EFI_STATUS Status;\r
+ UINTN Size;\r
+ UINTN NameSize;\r
+ UINTN ResultSize;\r
+ UINTN Index;\r
+ EFI_FILE_INFO *Info;\r
+ WCHAR *pw;\r
+ TIME_ZONE_INFORMATION TimeZone;\r
+ EFI_FILE_INFO *FileInfo;\r
+ UINT64 Pos;\r
+ UINT64 FileSize;\r
+ UINTN FileInfoSize;\r
+\r
+ PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Done;\r
+ }\r
+\r
+ if (!PrivateFile->IsDirectoryPath) {\r
+\r
+ if (This->GetPosition (This, &Pos) != EFI_SUCCESS) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Done;\r
+ }\r
+\r
+ FileInfoSize = SIZE_OF_EFI_FILE_SYSTEM_INFO;\r
+ FileInfo = AllocatePool (FileInfoSize);\r
+\r
+ Status = This->GetInfo (\r
+ This,\r
+ &gEfiFileInfoGuid,\r
+ &FileInfoSize,\r
+ FileInfo\r
+ );\r
+\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ FreePool (FileInfo);\r
+ FileInfo = AllocatePool (FileInfoSize);\r
+ Status = This->GetInfo (\r
+ This,\r
+ &gEfiFileInfoGuid,\r
+ &FileInfoSize,\r
+ FileInfo\r
+ );\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Done;\r
+ }\r
+\r
+ FileSize = FileInfo->FileSize;\r
+\r
+ FreePool (FileInfo);\r
+\r
+ if (Pos >= FileSize) {\r
+ *BufferSize = 0;\r
+ if (Pos == FileSize) {\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ } else {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ Status = ReadFile (\r
+ PrivateFile->LHandle,\r
+ Buffer,\r
+ (DWORD)*BufferSize,\r
+ (LPDWORD)BufferSize,\r
+ NULL\r
+ ) ? EFI_SUCCESS : EFI_DEVICE_ERROR;\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Read on a directory. Perform a find next\r
+ //\r
+ if (!PrivateFile->IsValidFindBuf) {\r
+ *BufferSize = 0;\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ }\r
+\r
+ Size = SIZE_OF_EFI_FILE_INFO;\r
+\r
+ NameSize = StrSize (PrivateFile->FindBuf.cFileName);\r
+\r
+ ResultSize = Size + NameSize;\r
+\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+\r
+ if (*BufferSize >= ResultSize) {\r
+ Status = EFI_SUCCESS;\r
+\r
+ Info = Buffer;\r
+ ZeroMem (Info, ResultSize);\r
+\r
+ Info->Size = ResultSize;\r
+\r
+ GetTimeZoneInformation (&TimeZone);\r
+ WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &PrivateFile->FindBuf.ftCreationTime, &Info->CreateTime);\r
+ WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &PrivateFile->FindBuf.ftLastAccessTime, &Info->LastAccessTime);\r
+ WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &PrivateFile->FindBuf.ftLastWriteTime, &Info->ModificationTime);\r
+\r
+ Info->FileSize = PrivateFile->FindBuf.nFileSizeLow;\r
+\r
+ Info->PhysicalSize = PrivateFile->FindBuf.nFileSizeLow;\r
+\r
+ if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) {\r
+ Info->Attribute |= EFI_FILE_ARCHIVE;\r
+ }\r
+\r
+ if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {\r
+ Info->Attribute |= EFI_FILE_HIDDEN;\r
+ }\r
+\r
+ if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {\r
+ Info->Attribute |= EFI_FILE_SYSTEM;\r
+ }\r
+\r
+ if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {\r
+ Info->Attribute |= EFI_FILE_READ_ONLY;\r
+ }\r
+\r
+ if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {\r
+ Info->Attribute |= EFI_FILE_DIRECTORY;\r
+ }\r
+\r
+ NameSize = NameSize / sizeof (WCHAR);\r
+\r
+ pw = (WCHAR *)(((CHAR8 *)Buffer) + Size);\r
+\r
+ for (Index = 0; Index < NameSize; Index++) {\r
+ pw[Index] = PrivateFile->FindBuf.cFileName[Index];\r
+ }\r
+\r
+ if (FindNextFile (PrivateFile->LHandle, &PrivateFile->FindBuf)) {\r
+ PrivateFile->IsValidFindBuf = TRUE;\r
+ } else {\r
+ PrivateFile->IsValidFindBuf = FALSE;\r
+ }\r
+ }\r
+\r
+ *BufferSize = ResultSize;\r
+\r
+Done:\r
+ return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Write data to a file.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param BufferSize On input size of buffer, on output amount of data in buffer.\r
+ @param Buffer The buffer in which data to write.\r
+\r
+ @retval EFI_SUCCESS Data was written.\r
+ @retval EFI_UNSUPPORTED Writes to Open directory are not supported.\r
+ @retval EFI_NO_MEDIA The device has no media.\r
+ @retval EFI_DEVICE_ERROR The device reported an error.\r
+ @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.\r
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+ @retval EFI_WRITE_PROTECTED The device is write protected.\r
+ @retval EFI_ACCESS_DENIED The file was open for read only.\r
+ @retval EFI_VOLUME_FULL The volume is full.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtFileWrite (\r
+ IN EFI_FILE_PROTOCOL *This,\r
+ IN OUT UINTN *BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ WIN_NT_EFI_FILE_PRIVATE *PrivateFile;\r
+ EFI_STATUS Status;\r
+\r
+ PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Done;\r
+ }\r
+\r
+ if (PrivateFile->IsDirectoryPath) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+\r
+ if (PrivateFile->IsOpenedByRead) {\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Done;\r
+ }\r
+\r
+ Status = WriteFile (\r
+ PrivateFile->LHandle,\r
+ Buffer,\r
+ (DWORD)*BufferSize,\r
+ (LPDWORD)BufferSize,\r
+ NULL\r
+ ) ? EFI_SUCCESS : EFI_DEVICE_ERROR;\r
+\r
+Done:\r
+ return Status;\r
+\r
+ //\r
+ // bugbug: need to access windows error reporting\r
+ //\r
+}\r
+\r
+\r
+\r
+/**\r
+ Set a files current position\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Position Byte position from the start of the file.\r
+\r
+ @retval EFI_SUCCESS Data was written.\r
+ @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtFileSetPossition (\r
+ IN EFI_FILE_PROTOCOL *This,\r
+ IN UINT64 Position\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ WIN_NT_EFI_FILE_PRIVATE *PrivateFile;\r
+ UINT32 PosLow;\r
+ UINT32 PosHigh;\r
+ CHAR16 *FileName;\r
+ UINTN Size;\r
+\r
+ PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (PrivateFile->IsDirectoryPath) {\r
+ if (Position != 0) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+\r
+ Size = StrSize (PrivateFile->FileName);\r
+ Size += StrSize (L"\\*");\r
+ FileName = AllocatePool (Size);\r
+ if (FileName == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ StrCpy (FileName, PrivateFile->FileName);\r
+ StrCat (FileName, L"\\*");\r
+\r
+ if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) {\r
+ FindClose (PrivateFile->LHandle);\r
+ }\r
+\r
+ PrivateFile->LHandle = FindFirstFile (FileName, &PrivateFile->FindBuf);\r
+\r
+ if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) {\r
+ PrivateFile->IsValidFindBuf = FALSE;\r
+ } else {\r
+ PrivateFile->IsValidFindBuf = TRUE;\r
+ }\r
+\r
+ FreePool (FileName);\r
+\r
+ Status = (PrivateFile->LHandle == INVALID_HANDLE_VALUE) ? EFI_DEVICE_ERROR : EFI_SUCCESS;\r
+ } else {\r
+ if (Position == (UINT64)-1) {\r
+ PosLow = SetFilePointer (PrivateFile->LHandle, (ULONG)0, NULL, FILE_END);\r
+ } else {\r
+ PosHigh = (UINT32)RShiftU64 (Position, 32);\r
+\r
+ PosLow = SetFilePointer (PrivateFile->LHandle, (ULONG)Position, (PLONG)&PosHigh, FILE_BEGIN);\r
+ }\r
+\r
+ Status = (PosLow == 0xFFFFFFFF) ? EFI_DEVICE_ERROR : EFI_SUCCESS;\r
+ }\r
+\r
+Done:\r
+ return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Get a file's current position\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Position Byte position from the start of the file.\r
+\r
+ @retval EFI_SUCCESS Data was written.\r
+ @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtFileGetPossition (\r
+ IN EFI_FILE_PROTOCOL *This,\r
+ OUT UINT64 *Position\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ WIN_NT_EFI_FILE_PRIVATE *PrivateFile;\r
+ INT32 PositionHigh;\r
+ UINT64 PosHigh64;\r
+\r
+ PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ PositionHigh = 0;\r
+ PosHigh64 = 0;\r
+\r
+ if (PrivateFile->IsDirectoryPath) {\r
+\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+\r
+ } else {\r
+\r
+ PositionHigh = 0;\r
+ *Position = SetFilePointer (\r
+ PrivateFile->LHandle,\r
+ 0,\r
+ (PLONG)&PositionHigh,\r
+ FILE_CURRENT\r
+ );\r
+\r
+ Status = *Position == 0xffffffff ? EFI_DEVICE_ERROR : EFI_SUCCESS;\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ PosHigh64 = PositionHigh;\r
+ *Position += LShiftU64 (PosHigh64, 32);\r
+ }\r
+\r
+Done:\r
+ return Status;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+WinNtSimpleFileSystemFileInfo (\r
+ IN WIN_NT_EFI_FILE_PRIVATE *PrivateFile,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+)\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ PrivateFile - TODO: add argument description\r
+ BufferSize - TODO: add argument description\r
+ Buffer - TODO: add argument description\r
+\r
+Returns:\r
+\r
+ TODO: add return values\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Size;\r
+ UINTN NameSize;\r
+ UINTN ResultSize;\r
+ EFI_FILE_INFO *Info;\r
+ BY_HANDLE_FILE_INFORMATION FileInfo;\r
+ CHAR16 *RealFileName;\r
+ CHAR16 *TempPointer;\r
+ TIME_ZONE_INFORMATION TimeZone;\r
+\r
+ Size = SIZE_OF_EFI_FILE_INFO;\r
+\r
+ RealFileName = PrivateFile->FileName;\r
+ TempPointer = RealFileName;\r
+ while (*TempPointer) {\r
+ if (*TempPointer == '\\') {\r
+ RealFileName = TempPointer + 1;\r
+ }\r
+\r
+ TempPointer++;\r
+ }\r
+ NameSize = StrSize (RealFileName);\r
+\r
+ ResultSize = Size + NameSize;\r
+\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ if (*BufferSize >= ResultSize) {\r
+ Status = EFI_SUCCESS;\r
+\r
+ Info = Buffer;\r
+ ZeroMem (Info, ResultSize);\r
+\r
+ Info->Size = ResultSize;\r
+ GetFileInformationByHandle (\r
+ PrivateFile->IsDirectoryPath ? PrivateFile->DirHandle : PrivateFile->LHandle,\r
+ &FileInfo\r
+ );\r
+ Info->FileSize = FileInfo.nFileSizeLow;\r
+ Info->PhysicalSize = Info->FileSize;\r
+\r
+ GetTimeZoneInformation (&TimeZone);\r
+ WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &FileInfo.ftCreationTime, &Info->CreateTime);\r
+ WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &FileInfo.ftLastAccessTime, &Info->LastAccessTime);\r
+ WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &FileInfo.ftLastWriteTime, &Info->ModificationTime);\r
+\r
+ if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) {\r
+ Info->Attribute |= EFI_FILE_ARCHIVE;\r
+ }\r
+\r
+ if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {\r
+ Info->Attribute |= EFI_FILE_HIDDEN;\r
+ }\r
+\r
+ if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {\r
+ Info->Attribute |= EFI_FILE_READ_ONLY;\r
+ }\r
+\r
+ if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {\r
+ Info->Attribute |= EFI_FILE_SYSTEM;\r
+ }\r
+\r
+ if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {\r
+ Info->Attribute |= EFI_FILE_DIRECTORY;\r
+ }\r
+\r
+ if (PrivateFile->IsDirectoryPath) {\r
+ Info->Attribute |= EFI_FILE_DIRECTORY;\r
+ }\r
+\r
+ if (PrivateFile->IsRootDirectory) {\r
+ *((CHAR8 *)Buffer + Size) = 0;\r
+ } else {\r
+ CopyMem ((CHAR8 *)Buffer + Size, RealFileName, NameSize);\r
+ }\r
+ }\r
+\r
+ *BufferSize = ResultSize;\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Get information about a file.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param InformationType Type of information to return in Buffer.\r
+ @param BufferSize On input size of buffer, on output amount of data in buffer.\r
+ @param Buffer The buffer to return data.\r
+\r
+ @retval EFI_SUCCESS Data was returned.\r
+ @retval EFI_UNSUPPORTED InformationType is not supported.\r
+ @retval EFI_NO_MEDIA The device has no media.\r
+ @retval EFI_DEVICE_ERROR The device reported an error.\r
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+ @retval EFI_WRITE_PROTECTED The device is write protected.\r
+ @retval EFI_ACCESS_DENIED The file was open for read only.\r
+ @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtFileGetInfo (\r
+ IN EFI_FILE_PROTOCOL *This,\r
+ IN EFI_GUID *InformationType,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ WIN_NT_EFI_FILE_PRIVATE *PrivateFile;\r
+ EFI_FILE_SYSTEM_INFO *FileSystemInfoBuffer;\r
+ UINT32 SectorsPerCluster;\r
+ UINT32 BytesPerSector;\r
+ UINT32 FreeClusters;\r
+ UINT32 TotalClusters;\r
+ UINT32 BytesPerCluster;\r
+ CHAR16 *DriveName;\r
+ BOOLEAN DriveNameFound;\r
+ BOOL NtStatus;\r
+ UINTN Index;\r
+ WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;\r
+\r
+ if (This == NULL || InformationType == NULL || BufferSize == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
+ PrivateRoot = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);\r
+\r
+ Status = EFI_UNSUPPORTED;\r
+\r
+ if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {\r
+ Status = WinNtSimpleFileSystemFileInfo (PrivateFile, BufferSize, Buffer);\r
+ }\r
+\r
+ if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {\r
+ if (*BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel)) {\r
+ *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ goto Done;\r
+ }\r
+\r
+ FileSystemInfoBuffer = (EFI_FILE_SYSTEM_INFO *)Buffer;\r
+ FileSystemInfoBuffer->Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);\r
+ FileSystemInfoBuffer->ReadOnly = FALSE;\r
+\r
+ //\r
+ // Try to get the drive name\r
+ //\r
+ DriveNameFound = FALSE;\r
+ DriveName = AllocatePool (StrSize (PrivateFile->FilePath) + 1);\r
+ if (DriveName == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ StrCpy (DriveName, PrivateFile->FilePath);\r
+ for (Index = 0; DriveName[Index] != 0 && DriveName[Index] != ':'; Index++) {\r
+ ;\r
+ }\r
+\r
+ if (DriveName[Index] == ':') {\r
+ DriveName[Index + 1] = '\\';\r
+ DriveName[Index + 2] = 0;\r
+ DriveNameFound = TRUE;\r
+ } else if (DriveName[0] == '\\' && DriveName[1] == '\\') {\r
+ for (Index = 2; DriveName[Index] != 0 && DriveName[Index] != '\\'; Index++) {\r
+ ;\r
+ }\r
+\r
+ if (DriveName[Index] == '\\') {\r
+ DriveNameFound = TRUE;\r
+ for (Index++; DriveName[Index] != 0 && DriveName[Index] != '\\'; Index++) {\r
+ ;\r
+ }\r
+\r
+ DriveName[Index] = '\\';\r
+ DriveName[Index + 1] = 0;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Try GetDiskFreeSpace first\r
+ //\r
+ NtStatus = GetDiskFreeSpace (\r
+ DriveNameFound ? DriveName : NULL,\r
+ (LPDWORD)&SectorsPerCluster,\r
+ (LPDWORD)&BytesPerSector,\r
+ (LPDWORD)&FreeClusters,\r
+ (LPDWORD)&TotalClusters\r
+ );\r
+ if (DriveName) {\r
+ FreePool (DriveName);\r
+ }\r
+\r
+ if (NtStatus) {\r
+ //\r
+ // Succeeded\r
+ //\r
+ BytesPerCluster = BytesPerSector * SectorsPerCluster;\r
+ FileSystemInfoBuffer->VolumeSize = MultU64x32 (TotalClusters, BytesPerCluster);\r
+ FileSystemInfoBuffer->FreeSpace = MultU64x32 (FreeClusters, BytesPerCluster);\r
+ FileSystemInfoBuffer->BlockSize = BytesPerCluster;\r
+\r
+ } else {\r
+ //\r
+ // try GetDiskFreeSpaceEx then\r
+ //\r
+ FileSystemInfoBuffer->BlockSize = 0;\r
+ NtStatus = GetDiskFreeSpaceEx (\r
+ PrivateFile->FilePath,\r
+ (PULARGE_INTEGER)(&FileSystemInfoBuffer->FreeSpace),\r
+ (PULARGE_INTEGER)(&FileSystemInfoBuffer->VolumeSize),\r
+ NULL\r
+ );\r
+ if (!NtStatus) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ StrCpy ((CHAR16 *)FileSystemInfoBuffer->VolumeLabel, PrivateRoot->VolumeLabel);\r
+ *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+ if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {\r
+ if (*BufferSize < StrSize (PrivateRoot->VolumeLabel)) {\r
+ *BufferSize = StrSize (PrivateRoot->VolumeLabel);\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ goto Done;\r
+ }\r
+\r
+ StrCpy ((CHAR16 *)Buffer, PrivateRoot->VolumeLabel);\r
+ *BufferSize = StrSize (PrivateRoot->VolumeLabel);\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+Done:\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Set information about a file\r
+\r
+ @param File Protocol instance pointer.\r
+ @param InformationType Type of information in Buffer.\r
+ @param BufferSize Size of buffer.\r
+ @param Buffer The data to write.\r
+\r
+ @retval EFI_SUCCESS Data was returned.\r
+ @retval EFI_UNSUPPORTED InformationType is not supported.\r
+ @retval EFI_NO_MEDIA The device has no media.\r
+ @retval EFI_DEVICE_ERROR The device reported an error.\r
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+ @retval EFI_WRITE_PROTECTED The device is write protected.\r
+ @retval EFI_ACCESS_DENIED The file was open for read only.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtFileSetInfo (\r
+ IN EFI_FILE_PROTOCOL *This,\r
+ IN EFI_GUID *InformationType,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;\r
+ WIN_NT_EFI_FILE_PRIVATE *PrivateFile;\r
+ EFI_FILE_INFO *OldFileInfo;\r
+ EFI_FILE_INFO *NewFileInfo;\r
+ EFI_STATUS Status;\r
+ UINTN OldInfoSize;\r
+ INTN NtStatus;\r
+ UINT32 NewAttr;\r
+ UINT32 OldAttr;\r
+ CHAR16 *OldFileName;\r
+ CHAR16 *NewFileName;\r
+ CHAR16 *TempFileName;\r
+ CHAR16 *CharPointer;\r
+ BOOLEAN AttrChangeFlag;\r
+ BOOLEAN NameChangeFlag;\r
+ BOOLEAN SizeChangeFlag;\r
+ BOOLEAN TimeChangeFlag;\r
+ UINT64 CurPos;\r
+ SYSTEMTIME NewCreationSystemTime;\r
+ SYSTEMTIME NewLastAccessSystemTime;\r
+ SYSTEMTIME NewLastWriteSystemTime;\r
+ FILETIME NewCreationFileTime;\r
+ FILETIME NewLastAccessFileTime;\r
+ FILETIME NewLastWriteFileTime;\r
+ WIN32_FIND_DATA FindBuf;\r
+ EFI_FILE_SYSTEM_INFO *NewFileSystemInfo;\r
+ UINTN Size;\r
+\r
+ //\r
+ // Initialise locals.\r
+ //\r
+ PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
+ PrivateRoot = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);\r
+\r
+ Status = EFI_UNSUPPORTED;\r
+ OldFileInfo = NewFileInfo = NULL;\r
+ OldFileName = NewFileName = NULL;\r
+ AttrChangeFlag = NameChangeFlag = SizeChangeFlag = TimeChangeFlag = FALSE;\r
+\r
+ //\r
+ // Set file system information.\r
+ //\r
+ if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {\r
+ NewFileSystemInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;\r
+ if (BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (NewFileSystemInfo->VolumeLabel)) {\r
+ Status = EFI_BAD_BUFFER_SIZE;\r
+ goto Done;\r
+ }\r
+\r
+\r
+ FreePool (PrivateRoot->VolumeLabel);\r
+ PrivateRoot->VolumeLabel = AllocatePool (StrSize (NewFileSystemInfo->VolumeLabel));\r
+ if (PrivateRoot->VolumeLabel == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ StrCpy (PrivateRoot->VolumeLabel, NewFileSystemInfo->VolumeLabel);\r
+\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Set volume label information.\r
+ //\r
+ if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {\r
+ if (BufferSize < StrSize (PrivateRoot->VolumeLabel)) {\r
+ Status = EFI_BAD_BUFFER_SIZE;\r
+ goto Done;\r
+ }\r
+\r
+ StrCpy (PrivateRoot->VolumeLabel, (CHAR16 *)Buffer);\r
+\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ }\r
+\r
+ if (!CompareGuid (InformationType, &gEfiFileInfoGuid)) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+\r
+ if (BufferSize < SIZE_OF_EFI_FILE_INFO) {\r
+ Status = EFI_BAD_BUFFER_SIZE;\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Set file/directory information.\r
+ //\r
+\r
+ //\r
+ // Check for invalid set file information parameters.\r
+ //\r
+ NewFileInfo = (EFI_FILE_INFO *)Buffer;\r
+\r
+ if ((NewFileInfo->Size <= SIZE_OF_EFI_FILE_INFO) ||\r
+ (NewFileInfo->Attribute &~(EFI_FILE_VALID_ATTR)) ||\r
+ (sizeof (UINTN) == 4 && NewFileInfo->Size > 0xFFFFFFFF)\r
+ ) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // bugbug: - This is not safe. We need something like EfiStrMaxSize()\r
+ // that would have an additional parameter that would be the size\r
+ // of the string array just in case there are no NULL characters in\r
+ // the string array.\r
+ //\r
+ //\r
+ // Get current file information so we can determine what kind\r
+ // of change request this is.\r
+ //\r
+ OldInfoSize = 0;\r
+ Status = WinNtSimpleFileSystemFileInfo (PrivateFile, &OldInfoSize, NULL);\r
+\r
+ if (Status != EFI_BUFFER_TOO_SMALL) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Done;\r
+ }\r
+\r
+ OldFileInfo = AllocatePool (OldInfoSize);\r
+ if (OldFileInfo == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ Status = WinNtSimpleFileSystemFileInfo (PrivateFile, &OldInfoSize, OldFileInfo);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ OldFileName = AllocatePool (StrSize (PrivateFile->FileName));\r
+ if (OldFileName == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ StrCpy (OldFileName, PrivateFile->FileName);\r
+\r
+ //\r
+ // Make full pathname from new filename and rootpath.\r
+ //\r
+ if (NewFileInfo->FileName[0] == '\\') {\r
+ Size = StrSize (PrivateRoot->FilePath);\r
+ Size += StrSize (L"\\");\r
+ Size += StrSize (NewFileInfo->FileName);\r
+ NewFileName = AllocatePool (Size);\r
+ if (NewFileName == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ StrCpy (NewFileName, PrivateRoot->FilePath);\r
+ StrCat (NewFileName, L"\\");\r
+ StrCat (NewFileName, NewFileInfo->FileName + 1);\r
+ } else {\r
+ Size = StrSize (PrivateFile->FilePath);\r
+ Size += StrSize (L"\\");\r
+ Size += StrSize (NewFileInfo->FileName);\r
+ NewFileName = AllocatePool (Size);\r
+ if (NewFileName == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ StrCpy (NewFileName, PrivateFile->FilePath);\r
+ StrCat (NewFileName, L"\\");\r
+ StrCat (NewFileName, NewFileInfo->FileName);\r
+ }\r
+\r
+ //\r
+ // Is there an attribute change request?\r
+ //\r
+ if (NewFileInfo->Attribute != OldFileInfo->Attribute) {\r
+ if ((NewFileInfo->Attribute & EFI_FILE_DIRECTORY) != (OldFileInfo->Attribute & EFI_FILE_DIRECTORY)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+\r
+ AttrChangeFlag = TRUE;\r
+ }\r
+\r
+ //\r
+ // Is there a name change request?\r
+ // bugbug: - Need EfiStrCaseCmp()\r
+ //\r
+ if (StrCmp (NewFileInfo->FileName, OldFileInfo->FileName)) {\r
+ NameChangeFlag = TRUE;\r
+ }\r
+\r
+ //\r
+ // Is there a size change request?\r
+ //\r
+ if (NewFileInfo->FileSize != OldFileInfo->FileSize) {\r
+ SizeChangeFlag = TRUE;\r
+ }\r
+\r
+ //\r
+ // Is there a time stamp change request?\r
+ //\r
+ if (!IsZero (&NewFileInfo->CreateTime, sizeof (EFI_TIME)) &&\r
+ CompareMem (&NewFileInfo->CreateTime, &OldFileInfo->CreateTime, sizeof (EFI_TIME))\r
+ ) {\r
+ TimeChangeFlag = TRUE;\r
+ } else if (!IsZero (&NewFileInfo->LastAccessTime, sizeof (EFI_TIME)) &&\r
+ CompareMem (&NewFileInfo->LastAccessTime, &OldFileInfo->LastAccessTime, sizeof (EFI_TIME))\r
+ ) {\r
+ TimeChangeFlag = TRUE;\r
+ } else if (!IsZero (&NewFileInfo->ModificationTime, sizeof (EFI_TIME)) &&\r
+ CompareMem (&NewFileInfo->ModificationTime, &OldFileInfo->ModificationTime, sizeof (EFI_TIME))\r
+ ) {\r
+ TimeChangeFlag = TRUE;\r
+ }\r
+\r
+ //\r
+ // All done if there are no change requests being made.\r
+ //\r
+ if (!(AttrChangeFlag || NameChangeFlag || SizeChangeFlag || TimeChangeFlag)) {\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Set file or directory information.\r
+ //\r
+ OldAttr = GetFileAttributes (OldFileName);\r
+\r
+ //\r
+ // Name change.\r
+ //\r
+ if (NameChangeFlag) {\r
+ //\r
+ // Close the handles first\r
+ //\r
+ if (PrivateFile->IsOpenedByRead) {\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Done;\r
+ }\r
+\r
+ for (CharPointer = NewFileName; *CharPointer != 0 && *CharPointer != L'/'; CharPointer++) {\r
+ }\r
+\r
+ if (*CharPointer != 0) {\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Done;\r
+ }\r
+\r
+ if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) {\r
+ if (PrivateFile->IsDirectoryPath) {\r
+ FindClose (PrivateFile->LHandle);\r
+ } else {\r
+ CloseHandle (PrivateFile->LHandle);\r
+ PrivateFile->LHandle = INVALID_HANDLE_VALUE;\r
+ }\r
+ }\r
+\r
+ if (PrivateFile->IsDirectoryPath && PrivateFile->DirHandle != INVALID_HANDLE_VALUE) {\r
+ CloseHandle (PrivateFile->DirHandle);\r
+ PrivateFile->DirHandle = INVALID_HANDLE_VALUE;\r
+ }\r
+\r
+ NtStatus = MoveFile (OldFileName, NewFileName);\r
+\r
+ if (NtStatus) {\r
+ //\r
+ // modify file name\r
+ //\r
+ FreePool (PrivateFile->FileName);\r
+\r
+ PrivateFile->FileName = AllocatePool (StrSize (NewFileName));\r
+ if (PrivateFile->FileName == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ StrCpy (PrivateFile->FileName, NewFileName);\r
+\r
+ Size = StrSize (NewFileName);\r
+ Size += StrSize (L"\\*");\r
+ TempFileName = AllocatePool (Size);\r
+\r
+ StrCpy (TempFileName, NewFileName);\r
+\r
+ if (!PrivateFile->IsDirectoryPath) {\r
+ PrivateFile->LHandle = CreateFile (\r
+ TempFileName,\r
+ PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,\r
+ FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+ NULL,\r
+ OPEN_EXISTING,\r
+ 0,\r
+ NULL\r
+ );\r
+\r
+ FreePool (TempFileName);\r
+\r
+ //\r
+ // Flush buffers just in case\r
+ //\r
+ if (FlushFileBuffers (PrivateFile->LHandle) == 0) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Done;\r
+ }\r
+ } else {\r
+ PrivateFile->DirHandle = CreateFile (\r
+ TempFileName,\r
+ PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,\r
+ FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+ NULL,\r
+ OPEN_EXISTING,\r
+ FILE_FLAG_BACKUP_SEMANTICS,\r
+ NULL\r
+ );\r
+\r
+ StrCat (TempFileName, L"\\*");\r
+ PrivateFile->LHandle = FindFirstFile (TempFileName, &FindBuf);\r
+\r
+ FreePool (TempFileName);\r
+ }\r
+ } else {\r
+ Status = EFI_ACCESS_DENIED;\r
+ Reopen:;\r
+\r
+ NtStatus = SetFileAttributes (OldFileName, OldAttr);\r
+\r
+ if (!NtStatus) {\r
+ goto Done;\r
+ }\r
+\r
+ Size = StrSize (OldFileName);\r
+ Size += StrSize (L"\\*");\r
+ TempFileName = AllocatePool (Size);\r
+\r
+ StrCpy (TempFileName, OldFileName);\r
+\r
+ if (!PrivateFile->IsDirectoryPath) {\r
+ PrivateFile->LHandle = CreateFile (\r
+ TempFileName,\r
+ PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,\r
+ FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+ NULL,\r
+ OPEN_EXISTING,\r
+ 0,\r
+ NULL\r
+ );\r
+ } else {\r
+ PrivateFile->DirHandle = CreateFile (\r
+ TempFileName,\r
+ PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,\r
+ FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+ NULL,\r
+ OPEN_EXISTING,\r
+ FILE_FLAG_BACKUP_SEMANTICS,\r
+ NULL\r
+ );\r
+\r
+ StrCat (TempFileName, L"\\*");\r
+ PrivateFile->LHandle = FindFirstFile (TempFileName, &FindBuf);\r
+ }\r
+\r
+ FreePool (TempFileName);\r
+\r
+ goto Done;\r
+\r
+ }\r
+ }\r
+\r
+ //\r
+ // Size change\r
+ //\r
+ if (SizeChangeFlag) {\r
+ if (PrivateFile->IsDirectoryPath) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+\r
+ if (PrivateFile->IsOpenedByRead || OldFileInfo->Attribute & EFI_FILE_READ_ONLY) {\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Done;\r
+ }\r
+\r
+ Status = This->GetPosition (This, &CurPos);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ Status = This->SetPosition (This, NewFileInfo->FileSize);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ if (SetEndOfFile (PrivateFile->LHandle) == 0) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Done;\r
+ }\r
+\r
+ Status = This->SetPosition (This, CurPos);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Time change\r
+ //\r
+ if (TimeChangeFlag) {\r
+\r
+ NewCreationSystemTime.wYear = NewFileInfo->CreateTime.Year;\r
+ NewCreationSystemTime.wMonth = NewFileInfo->CreateTime.Month;\r
+ NewCreationSystemTime.wDay = NewFileInfo->CreateTime.Day;\r
+ NewCreationSystemTime.wHour = NewFileInfo->CreateTime.Hour;\r
+ NewCreationSystemTime.wMinute = NewFileInfo->CreateTime.Minute;\r
+ NewCreationSystemTime.wSecond = NewFileInfo->CreateTime.Second;\r
+ NewCreationSystemTime.wMilliseconds = 0;\r
+\r
+ if (!SystemTimeToFileTime (\r
+ &NewCreationSystemTime,\r
+ &NewCreationFileTime\r
+ )) {\r
+ goto Done;\r
+ }\r
+\r
+ if (!LocalFileTimeToFileTime (\r
+ &NewCreationFileTime,\r
+ &NewCreationFileTime\r
+ )) {\r
+ goto Done;\r
+ }\r
+\r
+ NewLastAccessSystemTime.wYear = NewFileInfo->LastAccessTime.Year;\r
+ NewLastAccessSystemTime.wMonth = NewFileInfo->LastAccessTime.Month;\r
+ NewLastAccessSystemTime.wDay = NewFileInfo->LastAccessTime.Day;\r
+ NewLastAccessSystemTime.wHour = NewFileInfo->LastAccessTime.Hour;\r
+ NewLastAccessSystemTime.wMinute = NewFileInfo->LastAccessTime.Minute;\r
+ NewLastAccessSystemTime.wSecond = NewFileInfo->LastAccessTime.Second;\r
+ NewLastAccessSystemTime.wMilliseconds = 0;\r
+\r
+ if (!SystemTimeToFileTime (\r
+ &NewLastAccessSystemTime,\r
+ &NewLastAccessFileTime\r
+ )) {\r
+ goto Done;\r
+ }\r
+\r
+ if (!LocalFileTimeToFileTime (\r
+ &NewLastAccessFileTime,\r
+ &NewLastAccessFileTime\r
+ )) {\r
+ goto Done;\r
+ }\r
+\r
+ NewLastWriteSystemTime.wYear = NewFileInfo->ModificationTime.Year;\r
+ NewLastWriteSystemTime.wMonth = NewFileInfo->ModificationTime.Month;\r
+ NewLastWriteSystemTime.wDay = NewFileInfo->ModificationTime.Day;\r
+ NewLastWriteSystemTime.wHour = NewFileInfo->ModificationTime.Hour;\r
+ NewLastWriteSystemTime.wMinute = NewFileInfo->ModificationTime.Minute;\r
+ NewLastWriteSystemTime.wSecond = NewFileInfo->ModificationTime.Second;\r
+ NewLastWriteSystemTime.wMilliseconds = 0;\r
+\r
+ if (!SystemTimeToFileTime (\r
+ &NewLastWriteSystemTime,\r
+ &NewLastWriteFileTime\r
+ )) {\r
+ goto Done;\r
+ }\r
+\r
+ if (!LocalFileTimeToFileTime (\r
+ &NewLastWriteFileTime,\r
+ &NewLastWriteFileTime\r
+ )) {\r
+ goto Done;\r
+ }\r
+\r
+ if (!SetFileTime (\r
+ PrivateFile->IsDirectoryPath ? PrivateFile->DirHandle : PrivateFile->LHandle,\r
+ &NewCreationFileTime,\r
+ &NewLastAccessFileTime,\r
+ &NewLastWriteFileTime\r
+ )) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Done;\r
+ }\r
+\r
+ }\r
+\r
+ //\r
+ // No matter about AttrChangeFlag, Attribute must be set.\r
+ // Because operation before may cause attribute change.\r
+ //\r
+ NewAttr = OldAttr;\r
+\r
+ if (NewFileInfo->Attribute & EFI_FILE_ARCHIVE) {\r
+ NewAttr |= FILE_ATTRIBUTE_ARCHIVE;\r
+ } else {\r
+ NewAttr &= ~FILE_ATTRIBUTE_ARCHIVE;\r
+ }\r
+\r
+ if (NewFileInfo->Attribute & EFI_FILE_HIDDEN) {\r
+ NewAttr |= FILE_ATTRIBUTE_HIDDEN;\r
+ } else {\r
+ NewAttr &= ~FILE_ATTRIBUTE_HIDDEN;\r
+ }\r
+\r
+ if (NewFileInfo->Attribute & EFI_FILE_SYSTEM) {\r
+ NewAttr |= FILE_ATTRIBUTE_SYSTEM;\r
+ } else {\r
+ NewAttr &= ~FILE_ATTRIBUTE_SYSTEM;\r
+ }\r
+\r
+ if (NewFileInfo->Attribute & EFI_FILE_READ_ONLY) {\r
+ NewAttr |= FILE_ATTRIBUTE_READONLY;\r
+ } else {\r
+ NewAttr &= ~FILE_ATTRIBUTE_READONLY;\r
+ }\r
+\r
+ NtStatus = SetFileAttributes (NewFileName, NewAttr);\r
+\r
+ if (!NtStatus) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Reopen;\r
+ }\r
+\r
+Done:\r
+ if (OldFileInfo != NULL) {\r
+ FreePool (OldFileInfo);\r
+ }\r
+\r
+ if (OldFileName != NULL) {\r
+ FreePool (OldFileName);\r
+ }\r
+\r
+ if (NewFileName != NULL) {\r
+ FreePool (NewFileName);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Flush data back for the file handle.\r
+\r
+ @param This Protocol instance pointer.\r
+\r
+ @retval EFI_SUCCESS Data was written.\r
+ @retval EFI_UNSUPPORTED Writes to Open directory are not supported.\r
+ @retval EFI_NO_MEDIA The device has no media.\r
+ @retval EFI_DEVICE_ERROR The device reported an error.\r
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+ @retval EFI_WRITE_PROTECTED The device is write protected.\r
+ @retval EFI_ACCESS_DENIED The file was open for read only.\r
+ @retval EFI_VOLUME_FULL The volume is full.\r
+\r
+**/\r
+EFI_STATUS\r
+WinNtFileFlush (\r
+ IN EFI_FILE_PROTOCOL *This\r
+ )\r
+{\r
+ BY_HANDLE_FILE_INFORMATION FileInfo;\r
+ WIN_NT_EFI_FILE_PRIVATE *PrivateFile;\r
+ EFI_STATUS Status;\r
+\r
+ PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Done;\r
+ }\r
+\r
+ if (PrivateFile->IsDirectoryPath) {\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ }\r
+\r
+ if (PrivateFile->IsOpenedByRead) {\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Done;\r
+ }\r
+\r
+ GetFileInformationByHandle (PrivateFile->LHandle, &FileInfo);\r
+\r
+ if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Done;\r
+ }\r
+\r
+ Status = FlushFileBuffers (PrivateFile->LHandle) ? EFI_SUCCESS : EFI_DEVICE_ERROR;\r
+\r
+Done:\r
+ return Status;\r
+ //\r
+ // bugbug: - Use Windows error reporting.\r
+ //\r
+\r
+}\r
+\r
+\r
+\r
+EFI_STATUS\r
+WinNtFileSystmeThunkOpen (\r
+ IN EMU_IO_THUNK_PROTOCOL *This\r
+ )\r
+{\r
+ WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *Private;\r
+\r
+ Private = AllocateZeroPool (sizeof (*Private));\r
+ if (Private == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Private->FilePath = AllocateCopyPool (StrSize (This->ConfigString), This->ConfigString);\r
+ if (Private->FilePath == NULL) {\r
+ FreePool (Private);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Private->VolumeLabel = AllocateCopyPool (StrSize (L"EFI_EMULATED"), L"EFI_EMULATED");\r
+ if (Private->VolumeLabel == NULL) {\r
+ FreePool (Private->FilePath);\r
+ FreePool (Private);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Private->Signature = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE;\r
+ Private->Thunk = This;\r
+ CopyMem (&Private->SimpleFileSystem, &gWinNtFileSystemProtocol, sizeof (Private->SimpleFileSystem));\r
+\r
+ This->Interface = &Private->SimpleFileSystem;\r
+ This->Private = Private;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+WinNtFileSystmeThunkClose (\r
+ IN EMU_IO_THUNK_PROTOCOL *This\r
+ )\r
+{\r
+ WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *Private;\r
+\r
+ Private = This->Private;\r
+ ASSERT (Private != NULL);\r
+\r
+ if (Private->VolumeLabel != NULL) {\r
+ FreePool (Private->VolumeLabel);\r
+ }\r
+ if (Private->FilePath != NULL) {\r
+ FreePool (Private->FilePath);\r
+ }\r
+ FreePool (Private);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_FILE_PROTOCOL gWinNtFileProtocol = {\r
+ EFI_FILE_REVISION,\r
+ WinNtFileOpen,\r
+ WinNtFileClose,\r
+ WinNtFileDelete,\r
+ WinNtFileRead,\r
+ WinNtFileWrite,\r
+ WinNtFileGetPossition,\r
+ WinNtFileSetPossition,\r
+ WinNtFileGetInfo,\r
+ WinNtFileSetInfo,\r
+ WinNtFileFlush\r
+};\r
+\r
+EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gWinNtFileSystemProtocol = {\r
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,\r
+ WinNtOpenVolume\r
+};\r
+\r
+\r
+EMU_IO_THUNK_PROTOCOL mWinNtFileSystemThunkIo = {\r
+ &gEfiSimpleFileSystemProtocolGuid,\r
+ NULL,\r
+ NULL,\r
+ 0,\r
+ WinNtFileSystmeThunkOpen,\r
+ WinNtFileSystmeThunkClose,\r
+ NULL\r
+};\r
+\r
+\r