update for HEAD-2003091401
[reactos.git] / lib / kernel32 / file / file.c
index 79061ad..7c62d0f 100644 (file)
@@ -25,6 +25,9 @@ WINBOOL bIsFileApiAnsi = TRUE; // set the file api to ansi or oem
 
 /* FUNCTIONS ****************************************************************/
 
+/*
+ * @implemented
+ */
 VOID STDCALL
 SetFileApisToOEM(VOID)
 {
@@ -32,6 +35,9 @@ SetFileApisToOEM(VOID)
 }
 
 
+/*
+ * @implemented
+ */
 VOID STDCALL
 SetFileApisToANSI(VOID)
 {
@@ -39,6 +45,9 @@ SetFileApisToANSI(VOID)
 }
 
 
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 AreFileApisANSI(VOID)
 {
@@ -46,6 +55,9 @@ AreFileApisANSI(VOID)
 }
 
 
+/*
+ * @implemented
+ */
 HFILE STDCALL
 OpenFile(LPCSTR lpFileName,
         LPOFSTRUCT lpReOpenBuff,
@@ -148,6 +160,9 @@ OpenFile(LPCSTR lpFileName,
 }
 
 
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 FlushFileBuffers(HANDLE hFile)
 {
@@ -170,6 +185,9 @@ FlushFileBuffers(HANDLE hFile)
 }
 
 
+/*
+ * @implemented
+ */
 DWORD STDCALL
 SetFilePointer(HANDLE hFile,
               LONG lDistanceToMove,
@@ -242,81 +260,84 @@ SetFilePointer(HANDLE hFile,
 }
 
 
+/*
+ * @implemented
+ */
 DWORD STDCALL
 GetFileType(HANDLE hFile)
 {
-   FILE_FS_DEVICE_INFORMATION DeviceInfo;
-   IO_STATUS_BLOCK StatusBlock;
-   NTSTATUS Status;
-
-   /* get real handle */
-   switch ((ULONG)hFile)
-     {
-       case STD_INPUT_HANDLE:
-         hFile = NtCurrentPeb()->ProcessParameters->hStdInput;
-
-         break;
-
-       case STD_OUTPUT_HANDLE:
-         hFile = NtCurrentPeb()->ProcessParameters->hStdOutput;
-
-         break;
-
-       case STD_ERROR_HANDLE:
-         hFile = NtCurrentPeb()->ProcessParameters->hStdError;
-
-         break;
-     }
-
-   /* check console handles */
-   if (IsConsoleHandle(hFile))
-     {
-//     if (VerifyConsoleHandle(hFile))
-         return FILE_TYPE_CHAR;
-     }
-
-   Status = NtQueryVolumeInformationFile(hFile,
-                                        &StatusBlock,
-                                        &DeviceInfo,
-                                        sizeof(FILE_FS_DEVICE_INFORMATION),
-                                        FileFsDeviceInformation);
-   if (!NT_SUCCESS(Status))
-     {
-       SetLastErrorByStatus(Status);
-       return FILE_TYPE_UNKNOWN;
-     }
-
-   switch (DeviceInfo.DeviceType)
-     {
-       case FILE_DEVICE_CD_ROM:
-       case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
-       case FILE_DEVICE_CONTROLLER:
-       case FILE_DEVICE_DATALINK:
-       case FILE_DEVICE_DFS:
-       case FILE_DEVICE_DISK:
-       case FILE_DEVICE_DISK_FILE_SYSTEM:
-       case FILE_DEVICE_VIRTUAL_DISK:
-         return FILE_TYPE_DISK;
-
-       case FILE_DEVICE_KEYBOARD:
-       case FILE_DEVICE_MOUSE:
-       case FILE_DEVICE_NULL:
-       case FILE_DEVICE_PARALLEL_PORT:
-       case FILE_DEVICE_PRINTER:
-       case FILE_DEVICE_SERIAL_PORT:
-       case FILE_DEVICE_SCREEN:
-       case FILE_DEVICE_SOUND:
-       case FILE_DEVICE_MODEM:
-         return FILE_TYPE_CHAR;
-
-       case FILE_DEVICE_NAMED_PIPE:
-         return FILE_TYPE_PIPE;
-     }
-
-   return FILE_TYPE_UNKNOWN;
+  FILE_FS_DEVICE_INFORMATION DeviceInfo;
+  IO_STATUS_BLOCK StatusBlock;
+  NTSTATUS Status;
+
+  /* Get real handle */
+  switch ((ULONG)hFile)
+    {
+      case STD_INPUT_HANDLE:
+       hFile = NtCurrentPeb()->ProcessParameters->hStdInput;
+       break;
+
+      case STD_OUTPUT_HANDLE:
+       hFile = NtCurrentPeb()->ProcessParameters->hStdOutput;
+       break;
+
+      case STD_ERROR_HANDLE:
+       hFile = NtCurrentPeb()->ProcessParameters->hStdError;
+       break;
+    }
+
+  /* Check for console handle */
+  if (IsConsoleHandle(hFile))
+    {
+      if (VerifyConsoleIoHandle(hFile))
+       return FILE_TYPE_CHAR;
+    }
+
+  Status = NtQueryVolumeInformationFile(hFile,
+                                       &StatusBlock,
+                                       &DeviceInfo,
+                                       sizeof(FILE_FS_DEVICE_INFORMATION),
+                                       FileFsDeviceInformation);
+  if (!NT_SUCCESS(Status))
+    {
+      SetLastErrorByStatus(Status);
+      return FILE_TYPE_UNKNOWN;
+    }
+
+  switch (DeviceInfo.DeviceType)
+    {
+      case FILE_DEVICE_CD_ROM:
+      case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
+      case FILE_DEVICE_CONTROLLER:
+      case FILE_DEVICE_DATALINK:
+      case FILE_DEVICE_DFS:
+      case FILE_DEVICE_DISK:
+      case FILE_DEVICE_DISK_FILE_SYSTEM:
+      case FILE_DEVICE_VIRTUAL_DISK:
+       return FILE_TYPE_DISK;
+
+      case FILE_DEVICE_KEYBOARD:
+      case FILE_DEVICE_MOUSE:
+      case FILE_DEVICE_NULL:
+      case FILE_DEVICE_PARALLEL_PORT:
+      case FILE_DEVICE_PRINTER:
+      case FILE_DEVICE_SERIAL_PORT:
+      case FILE_DEVICE_SCREEN:
+      case FILE_DEVICE_SOUND:
+      case FILE_DEVICE_MODEM:
+       return FILE_TYPE_CHAR;
+
+      case FILE_DEVICE_NAMED_PIPE:
+       return FILE_TYPE_PIPE;
+    }
+
+  return FILE_TYPE_UNKNOWN;
 }
 
 
+/*
+ * @implemented
+ */
 DWORD STDCALL
 GetFileSize(HANDLE hFile,
            LPDWORD lpFileSizeHigh)
@@ -349,6 +370,9 @@ GetFileSize(HANDLE hFile,
 }
 
 
+/*
+ * @implemented
+ */
 DWORD STDCALL
 GetCompressedFileSizeA(LPCSTR lpFileName,
                       LPDWORD lpFileSizeHigh)
@@ -379,6 +403,9 @@ GetCompressedFileSizeA(LPCSTR lpFileName,
 }
 
 
+/*
+ * @implemented
+ */
 DWORD STDCALL
 GetCompressedFileSizeW(LPCWSTR lpFileName,
                       LPDWORD lpFileSizeHigh)
@@ -416,6 +443,9 @@ GetCompressedFileSizeW(LPCWSTR lpFileName,
 }
 
 
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 GetFileInformationByHandle(HANDLE hFile,
                           LPBY_HANDLE_FILE_INFORMATION lpFileInformation)
@@ -495,12 +525,135 @@ GetFileInformationByHandle(HANDLE hFile,
 }
 
 
+/*
+ * @implemented
+ */
+BOOL STDCALL
+GetFileAttributesExW(LPCWSTR lpFileName, 
+                    GET_FILEEX_INFO_LEVELS fInfoLevelId, 
+                    LPVOID lpFileInformation)
+{
+  FILE_NETWORK_OPEN_INFORMATION FileInformation;
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  IO_STATUS_BLOCK IoStatusBlock;
+  UNICODE_STRING FileName;
+  HANDLE FileHandle;
+  NTSTATUS Status;
+  WIN32_FILE_ATTRIBUTE_DATA* FileAttributeData;
+
+  DPRINT ("GetFileAttributesExW(%S) called\n", lpFileName);
+
+
+  if (fInfoLevelId != GetFileExInfoStandard || lpFileInformation == NULL)
+  {
+     SetLastError(ERROR_INVALID_PARAMETER);
+     return FALSE;
+  }
+
+  /* Validate and translate the filename */
+  if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFileName,
+                                    &FileName,
+                                    NULL,
+                                    NULL))
+    {
+      DPRINT ("Invalid path\n");
+      SetLastError (ERROR_BAD_PATHNAME);
+      return FALSE;
+    }
+
+  /* build the object attributes */
+  InitializeObjectAttributes (&ObjectAttributes,
+                             &FileName,
+                             OBJ_CASE_INSENSITIVE,
+                             NULL,
+                             NULL);
+
+  /* Open the file */
+  Status = NtOpenFile (&FileHandle,
+                      SYNCHRONIZE | FILE_READ_ATTRIBUTES,
+                      &ObjectAttributes,
+                      &IoStatusBlock,
+                      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                      FILE_SYNCHRONOUS_IO_NONALERT);
+  RtlFreeUnicodeString (&FileName);
+  if (!NT_SUCCESS (Status))
+    {
+      DPRINT ("NtOpenFile() failed (Status %lx)\n", Status);
+      SetLastErrorByStatus (Status);
+      return FALSE;
+    }
+
+  /* Get file attributes */
+  Status = NtQueryInformationFile (FileHandle,
+                                  &IoStatusBlock,
+                                  &FileInformation,
+                                  sizeof(FILE_NETWORK_OPEN_INFORMATION),
+                                  FileNetworkOpenInformation);
+  NtClose (FileHandle);
+
+  if (!NT_SUCCESS (Status))
+    {
+      DPRINT ("NtQueryInformationFile() failed (Status %lx)\n", Status);
+      SetLastErrorByStatus (Status);
+      return FALSE;
+    }
+
+  FileAttributeData = (WIN32_FILE_ATTRIBUTE_DATA*)lpFileInformation;
+  FileAttributeData->dwFileAttributes = FileInformation.FileAttributes;
+  FileAttributeData->ftCreationTime.dwLowDateTime = FileInformation.CreationTime.u.LowPart;
+  FileAttributeData->ftCreationTime.dwHighDateTime = FileInformation.CreationTime.u.HighPart;
+  FileAttributeData->ftLastAccessTime.dwLowDateTime = FileInformation.LastAccessTime.u.LowPart;
+  FileAttributeData->ftLastAccessTime.dwHighDateTime = FileInformation.LastAccessTime.u.HighPart;
+  FileAttributeData->ftLastWriteTime.dwLowDateTime = FileInformation.LastWriteTime.u.LowPart;
+  FileAttributeData->ftLastWriteTime.dwHighDateTime = FileInformation.LastWriteTime.u.HighPart;
+  FileAttributeData->nFileSizeLow = FileInformation.EndOfFile.u.LowPart;
+  FileAttributeData->nFileSizeHigh = FileInformation.EndOfFile.u.HighPart;
+
+  return TRUE;
+}
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+GetFileAttributesExA(LPCSTR lpFileName,
+                    GET_FILEEX_INFO_LEVELS fInfoLevelId, 
+                    LPVOID lpFileInformation)
+{
+       UNICODE_STRING FileNameU;
+       ANSI_STRING FileName;
+       BOOL Result;
+       RtlInitAnsiString (&FileName,
+                          (LPSTR)lpFileName);
+
+       /* convert ansi (or oem) string to unicode */
+       if (bIsFileApiAnsi)
+               RtlAnsiStringToUnicodeString (&FileNameU,
+                                             &FileName,
+                                             TRUE);
+       else
+               RtlOemStringToUnicodeString (&FileNameU,
+                                            &FileName,
+                                            TRUE);
+
+        Result = GetFileAttributesExW(FileNameU.Buffer, fInfoLevelId, lpFileInformation);
+
+       RtlFreeUnicodeString (&FileNameU);
+
+       return Result;
+}
+
+
+/*
+ * @implemented
+ */
 DWORD STDCALL
 GetFileAttributesA(LPCSTR lpFileName)
 {
+        WIN32_FILE_ATTRIBUTE_DATA FileAttributeData;
        UNICODE_STRING FileNameU;
        ANSI_STRING FileName;
-       WINBOOL Result;
+       BOOL Result;
 
        RtlInitAnsiString (&FileName,
                           (LPSTR)lpFileName);
@@ -515,132 +668,144 @@ GetFileAttributesA(LPCSTR lpFileName)
                                             &FileName,
                                             TRUE);
 
-       Result = GetFileAttributesW (FileNameU.Buffer);
+        Result = GetFileAttributesExW(FileNameU.Buffer, GetFileExInfoStandard, &FileAttributeData);
 
        RtlFreeUnicodeString (&FileNameU);
 
-       return Result;
+       return Result ? FileAttributeData.dwFileAttributes : 0xffffffff;
 }
 
 
+/*
+ * @implemented
+ */
 DWORD STDCALL
 GetFileAttributesW(LPCWSTR lpFileName)
 {
-   IO_STATUS_BLOCK IoStatusBlock;
-   FILE_BASIC_INFORMATION FileBasic;
-   HANDLE hFile;
-   NTSTATUS errCode;
+  WIN32_FILE_ATTRIBUTE_DATA FileAttributeData;
+  BOOL Result;
 
-   hFile = CreateFileW(lpFileName,
-                      FILE_READ_ATTRIBUTES,
-                      FILE_SHARE_READ,
-                      NULL,
-                      OPEN_EXISTING,
-                      FILE_ATTRIBUTE_NORMAL,
-                      NULL);
-   if (hFile == INVALID_HANDLE_VALUE)
-     {
-       return 0xFFFFFFFF;
-     }
+  DPRINT ("GetFileAttributeW(%S) called\n", lpFileName);
 
-   errCode = NtQueryInformationFile(hFile,
-                                   &IoStatusBlock,
-                                   &FileBasic,
-                                   sizeof(FILE_BASIC_INFORMATION),
-                                   FileBasicInformation);
-   if (!NT_SUCCESS(errCode))
-     {
-       CloseHandle(hFile);
-       SetLastErrorByStatus(errCode);
-       return 0xFFFFFFFF;
-     }
-   CloseHandle(hFile);
-   return (DWORD)FileBasic.FileAttributes;
-}
+  Result = GetFileAttributesExW(lpFileName, GetFileExInfoStandard, &FileAttributeData);
 
+  return Result ? FileAttributeData.dwFileAttributes : 0xffffffff;
+}
 
 WINBOOL STDCALL
 SetFileAttributesA(LPCSTR lpFileName,
                   DWORD dwFileAttributes)
 {
-   UNICODE_STRING FileNameU;
-   ANSI_STRING FileName;
-   WINBOOL Result;
+  UNICODE_STRING FileNameU;
+  ANSI_STRING FileName;
+  WINBOOL Result;
 
-   RtlInitAnsiString(&FileName,
+  RtlInitAnsiString (&FileName,
                     (LPSTR)lpFileName);
 
-   /* convert ansi (or oem) string to unicode */
-   if (bIsFileApiAnsi)
-     RtlAnsiStringToUnicodeString(&FileNameU,
+  /* convert ansi (or oem) string to unicode */
+  if (bIsFileApiAnsi)
+    RtlAnsiStringToUnicodeString (&FileNameU,
                                  &FileName,
                                  TRUE);
    else
-     RtlOemStringToUnicodeString(&FileNameU,
+    RtlOemStringToUnicodeString (&FileNameU,
                                 &FileName,
                                 TRUE);
 
-   Result = SetFileAttributesW(FileNameU.Buffer,
+  Result = SetFileAttributesW (FileNameU.Buffer,
                               dwFileAttributes);
 
-   RtlFreeUnicodeString(&FileNameU);
+  RtlFreeUnicodeString (&FileNameU);
 
-   return Result;
+  return Result;
 }
 
 
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 SetFileAttributesW(LPCWSTR lpFileName,
                   DWORD dwFileAttributes)
 {
-   IO_STATUS_BLOCK IoStatusBlock;
-   FILE_BASIC_INFORMATION FileBasic;
-   HANDLE hFile;
-   NTSTATUS errCode;
-   
-   hFile = CreateFileW(lpFileName,
-                      FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
-                      FILE_SHARE_READ,
-                      NULL,
-                      OPEN_EXISTING,
-                      FILE_ATTRIBUTE_NORMAL,
-                      NULL);
-   if (INVALID_HANDLE_VALUE == hFile)
-     {
-       DPRINT("SetFileAttributes CreateFileW failed with code %d\n", GetLastError());
-       return FALSE;
-     }
+  FILE_BASIC_INFORMATION FileInformation;
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  IO_STATUS_BLOCK IoStatusBlock;
+  UNICODE_STRING FileName;
+  HANDLE FileHandle;
+  NTSTATUS Status;
+
+  DPRINT ("SetFileAttributeW(%S, 0x%lx) called\n", lpFileName, dwFileAttributes);
+
+  /* Validate and translate the filename */
+  if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFileName,
+                                    &FileName,
+                                    NULL,
+                                    NULL))
+    {
+      DPRINT ("Invalid path\n");
+      SetLastError (ERROR_BAD_PATHNAME);
+      return FALSE;
+    }
+  DPRINT ("FileName: \'%wZ\'\n", &FileName);
+
+  /* build the object attributes */
+  InitializeObjectAttributes (&ObjectAttributes,
+                             &FileName,
+                             OBJ_CASE_INSENSITIVE,
+                             NULL,
+                             NULL);
+
+  /* Open the file */
+  Status = NtOpenFile (&FileHandle,
+                      SYNCHRONIZE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
+                      &ObjectAttributes,
+                      &IoStatusBlock,
+                      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                      FILE_SYNCHRONOUS_IO_NONALERT);
+  RtlFreeUnicodeString (&FileName);
+  if (!NT_SUCCESS (Status))
+    {
+      DPRINT ("NtOpenFile() failed (Status %lx)\n", Status);
+      SetLastErrorByStatus (Status);
+      return FALSE;
+    }
 
-   errCode = NtQueryInformationFile(hFile,
-                                   &IoStatusBlock,
-                                   &FileBasic,
-                                   sizeof(FILE_BASIC_INFORMATION),
-                                   FileBasicInformation);
-   if (!NT_SUCCESS(errCode))
-     {
-       CloseHandle(hFile);
-       DPRINT("SetFileAttributes NtQueryInformationFile failed with status 0x%08x\n", errCode);
-       SetLastErrorByStatus(errCode);
-       return FALSE;
-     }
-   FileBasic.FileAttributes = dwFileAttributes;
-   errCode = NtSetInformationFile(hFile,
+  Status = NtQueryInformationFile(FileHandle,
                                  &IoStatusBlock,
-                                 &FileBasic,
+                                 &FileInformation,
                                  sizeof(FILE_BASIC_INFORMATION),
                                  FileBasicInformation);
-   if (!NT_SUCCESS(errCode))
-     {
-       CloseHandle(hFile);
-       DPRINT("SetFileAttributes NtSetInformationFile failed with status 0x%08x\n", errCode);
-       SetLastErrorByStatus(errCode);
-       return FALSE;
-     }
-   CloseHandle(hFile);
-   return TRUE;
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT ("SetFileAttributes NtQueryInformationFile failed with status 0x%08x\n", Status);
+      NtClose (FileHandle);
+      SetLastErrorByStatus (Status);
+      return FALSE;
+    }
+
+  FileInformation.FileAttributes = dwFileAttributes;
+  Status = NtSetInformationFile(FileHandle,
+                               &IoStatusBlock,
+                               &FileInformation,
+                               sizeof(FILE_BASIC_INFORMATION),
+                               FileBasicInformation);
+  NtClose (FileHandle);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT ("SetFileAttributes NtSetInformationFile failed with status 0x%08x\n", Status);
+      SetLastErrorByStatus (Status);
+      return FALSE;
+    }
+
+  return TRUE;
 }
 
 
+/*
+ * @implemented
+ */
 UINT STDCALL
 GetTempFileNameA(LPCSTR lpPathName,
                 LPCSTR lpPrefixString,
@@ -686,6 +851,9 @@ GetTempFileNameA(LPCSTR lpPathName,
 }
 
 
+/*
+ * @implemented
+ */
 UINT STDCALL
 GetTempFileNameW(LPCWSTR lpPathName,
                 LPCWSTR lpPrefixString,
@@ -695,7 +863,7 @@ GetTempFileNameW(LPCWSTR lpPathName,
    HANDLE hFile;
    UINT unique = uUnique;
    UINT len;
-   const WCHAR *format = L"%.*S\\~%.3S%4.4x.TMP";
+   const WCHAR *format = L"%.*s\\~%.3s%4.4x.TMP";
    
    DPRINT("GetTempFileNameW(lpPathName %S, lpPrefixString %.*S, "
          "uUnique %x, lpTempFileName %x)\n", lpPathName, 4, 
@@ -731,6 +899,9 @@ GetTempFileNameW(LPCWSTR lpPathName,
 }
 
 
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 GetFileTime(HANDLE hFile,
            LPFILETIME lpCreationTime,
@@ -763,6 +934,9 @@ GetFileTime(HANDLE hFile,
 }
 
 
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 SetFileTime(HANDLE hFile,
            CONST FILETIME *lpCreationTime,
@@ -809,8 +983,10 @@ SetFileTime(HANDLE hFile,
 
 
 /*
-The caller must have opened the file with the DesiredAccess FILE_WRITE_DATA flag set.
-*/
+ * The caller must have opened the file with the DesiredAccess FILE_WRITE_DATA flag set.
+ *
+ * @implemented
+ */
 WINBOOL STDCALL
 SetEndOfFile(HANDLE hFile)
 {