[KERNEL32]
[reactos.git] / reactos / dll / win32 / kernel32 / file / file.c
index cdbafd0..7f0c044 100644 (file)
@@ -5,7 +5,7 @@
  * FILE:            lib/kernel32/file/file.c
  * PURPOSE:         Directory functions
  * PROGRAMMER:      Ariadne ( ariadne@xs4all.nl)
- *                 GetTempFileName is modified from WINE [ Alexandre Juiliard ]
+ *                  Pierre Schweitzer (pierre.schweitzer@reactos.org)
  * UPDATE HISTORY:
  *                  Created 01/11/98
  */
@@ -13,9 +13,9 @@
 /* INCLUDES *****************************************************************/
 
 #include <k32.h>
-#include <wine/debug.h>
-
-WINE_DEFAULT_DEBUG_CHANNEL(kernel32file);
+#define NDEBUG
+#include <debug.h>
+DEBUG_CHANNEL(kernel32file);
 
 /* GLOBALS ******************************************************************/
 
@@ -72,6 +72,9 @@ FilenameU2A_FitOrFail(
 {
    DWORD ret;
 
+   /* destLen should never exceed MAX_PATH */
+   if (destLen > MAX_PATH) destLen = MAX_PATH;
+
    ret = bIsFileApiAnsi? RtlUnicodeStringToAnsiSize(SourceU) : RtlUnicodeStringToOemSize(SourceU);
    /* ret incl. nullchar */
 
@@ -403,26 +406,26 @@ OpenFile(LPCSTR lpFileName,
  * @implemented
  */
 BOOL WINAPI
-FlushFileBuffers(HANDLE hFile)
+FlushFileBuffers(IN HANDLE hFile)
 {
-   NTSTATUS errCode;
-   IO_STATUS_BLOCK IoStatusBlock;
+    NTSTATUS Status;
+    IO_STATUS_BLOCK IoStatusBlock;
 
-   hFile = TranslateStdHandle(hFile);
+    hFile = TranslateStdHandle(hFile);
 
-   if (IsConsoleHandle(hFile))
-   {
-      return FALSE;
-   }
+    if (IsConsoleHandle(hFile))
+    {
+        return FlushConsoleInputBuffer(hFile);
+    }
 
-   errCode = NtFlushBuffersFile(hFile,
-                               &IoStatusBlock);
-   if (!NT_SUCCESS(errCode))
-     {
-       SetLastErrorByStatus(errCode);
-       return(FALSE);
-     }
-   return(TRUE);
+    Status = NtFlushBuffersFile(hFile,
+                                &IoStatusBlock);
+    if (!NT_SUCCESS(Status))
+    {
+        BaseSetLastNTError(Status);
+        return FALSE;
+    }
+    return TRUE;
 }
 
 
@@ -1209,83 +1212,205 @@ SetFileAttributesW(LPCWSTR lpFileName,
 /***********************************************************************
  *           GetTempFileNameA   (KERNEL32.@)
  */
-UINT WINAPI GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique, LPSTR buffer)
+UINT WINAPI
+GetTempFileNameA(IN LPCSTR lpPathName,
+                 IN LPCSTR lpPrefixString,
+                 IN UINT uUnique,
+                 OUT LPSTR lpTempFileName)
 {
-   WCHAR BufferW[MAX_PATH];
-   PWCHAR PathW;
-   WCHAR PrefixW[3+1];
-   UINT ret;
-
-   if (!(PathW = FilenameA2W(path, FALSE)))
-      return 0;
-
-   if (prefix)
-      FilenameA2W_N(PrefixW, 3+1, prefix, -1);
+    UINT ID;
+    NTSTATUS Status;
+    LPWSTR lpTempFileNameW;
+    PUNICODE_STRING lpPathNameW;
+    ANSI_STRING TempFileNameStringA;
+    UNICODE_STRING lpPrefixStringW, TempFileNameStringW;
+
+    /* Convert strings */
+    lpPathNameW = Basep8BitStringToStaticUnicodeString(lpPathName);
+    if (!lpPathNameW)
+    {
+        return 0;
+    }
 
-   ret = GetTempFileNameW(PathW, prefix ? PrefixW : NULL, unique, BufferW);
+    if (!Basep8BitStringToDynamicUnicodeString(&lpPrefixStringW, lpPrefixString))
+    {
+        return 0;
+    }
 
-   if (ret)
-      FilenameW2A_N(buffer, MAX_PATH, BufferW, -1);
+    lpTempFileNameW = RtlAllocateHeap(RtlGetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
+    if (!lpTempFileNameW)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        RtlFreeUnicodeString(&lpPrefixStringW);
+        return 0;
+    }
 
-   return ret;
-}
+    /* Call Unicode */
+    ID = GetTempFileNameW(lpPathNameW->Buffer, lpPrefixStringW.Buffer, uUnique, lpTempFileNameW);
+    if (ID)
+    {
+        RtlInitUnicodeString(&TempFileNameStringW, lpTempFileNameW);
+        TempFileNameStringA.Buffer = lpTempFileName;
+        TempFileNameStringA.MaximumLength = MAX_PATH;
+        Status = BasepUnicodeStringTo8BitString(&TempFileNameStringA, &TempFileNameStringW, FALSE);
+        if (!NT_SUCCESS(Status))
+        {
+            BaseSetLastNTError(Status);
+            ID = 0;
+        }
+    }
 
-/***********************************************************************
- *           GetTempFileNameW   (KERNEL32.@)
- */
-UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique, LPWSTR buffer )
+    /* Cleanup */
+    RtlFreeUnicodeString(&lpPrefixStringW);
+    RtlFreeHeap(RtlGetProcessHeap(), 0, lpTempFileNameW);
+    return ID;
+ }
+ /***********************************************************************
+  *           GetTempFileNameW   (KERNEL32.@)
+  */
+UINT WINAPI
+GetTempFileNameW(IN LPCWSTR lpPathName,
+                 IN LPCWSTR lpPrefixString,
+                 IN UINT uUnique,
+                 OUT LPWSTR lpTempFileName)
 {
-    static const WCHAR formatW[] = L"%x.tmp";
-
-    int i;
-    LPWSTR p;
+    CHAR * Let;
+    HANDLE TempFile;
+    UINT ID, Num = 0;
+    CHAR IDString[5];
+    WCHAR * TempFileName;
+    CSR_API_MESSAGE ApiMessage;
+    DWORD FileAttributes, LastError;
+    UNICODE_STRING PathNameString, PrefixString;
+    static const WCHAR Ext[] = { L'.', 't', 'm', 'p', UNICODE_NULL };
+
+    RtlInitUnicodeString(&PathNameString, lpPathName);
+    if (PathNameString.Length == 0 || PathNameString.Buffer[(PathNameString.Length / sizeof(WCHAR)) - 1] != L'\\')
+    {
+        PathNameString.Length += sizeof(WCHAR);
+    }
 
-    if ( !path || !buffer )
+    /* lpTempFileName must be able to contain: PathName, Prefix (3), number(4), .tmp(4) & \0(1)
+     * See: http://msdn.microsoft.com/en-us/library/aa364991%28v=vs.85%29.aspx
+     */
+    if (PathNameString.Length > (MAX_PATH - 3 - 4 - 4 - 1) * sizeof(WCHAR))
     {
-        SetLastError( ERROR_INVALID_PARAMETER );
+        SetLastError(ERROR_BUFFER_OVERFLOW);
         return 0;
     }
-
-    wcscpy( buffer, path );
-    p = buffer + wcslen(buffer);
-
-    /* add a \, if there isn't one  */
-    if ((p == buffer) || (p[-1] != '\\')) *p++ = '\\';
-
-    if ( prefix )
-        for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
-
-    unique &= 0xffff;
-
-    if (unique) swprintf( p, formatW, unique );
-    else
+    /* If PathName and TempFileName aren't the same buffer, move PathName to TempFileName */
+    if (lpPathName != lpTempFileName)
     {
-        /* get a "random" unique number and try to create the file */
-        HANDLE handle;
-        UINT num = GetTickCount() & 0xffff;
+        memmove(lpTempFileName, PathNameString.Buffer, PathNameString.Length);
+    }
 
-        if (!num) num = 1;
-        unique = num;
+    /* PathName MUST BE a path. Check it */
+    lpTempFileName[(PathNameString.Length / sizeof(WCHAR)) - 1] = UNICODE_NULL;
+    FileAttributes = GetFileAttributesW(lpTempFileName);
+    if (FileAttributes == INVALID_FILE_ATTRIBUTES)
+    {
+        /* Append a '\' if necessary */
+        lpTempFileName[(PathNameString.Length / sizeof(WCHAR)) - 1] = L'\\';
+        lpTempFileName[PathNameString.Length / sizeof(WCHAR)] = UNICODE_NULL;
+        FileAttributes = GetFileAttributesW(lpTempFileName);
+        if (FileAttributes == INVALID_FILE_ATTRIBUTES)
+        {
+            SetLastError(ERROR_DIRECTORY);
+            return 0;
+        }
+    }
+    if (!(FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+    {
+        SetLastError(ERROR_DIRECTORY);
+        return 0;
+    }
+    /* Make sure not to mix path & prefix */
+    lpTempFileName[(PathNameString.Length / sizeof(WCHAR)) - 1] = L'\\';
+    RtlInitUnicodeString(&PrefixString, lpPrefixString);
+    if (PrefixString.Length > 3 * sizeof(WCHAR))
+    {
+        PrefixString.Length = 3 * sizeof(WCHAR);
+    }
+    /* Append prefix to path */
+    TempFileName = lpTempFileName + PathNameString.Length / sizeof(WCHAR);
+    memmove(TempFileName, PrefixString.Buffer, PrefixString.Length);
+    TempFileName += PrefixString.Length / sizeof(WCHAR);
+    /* Then, generate filename */
+    do
+    {
+        /* If user didn't gave any ID, ask Csrss to give one */
+        if (!uUnique)
+        {
+            CsrClientCallServer(&ApiMessage, NULL, MAKE_CSR_API(GET_TEMP_FILE, CSR_NATIVE), sizeof(CSR_API_MESSAGE));
+            if (ApiMessage.Data.GetTempFile.UniqueID == 0)
+            {
+                Num++;
+                continue;
+            }
+            ID = ApiMessage.Data.GetTempFile.UniqueID;
+        }
+        else
+        {
+            ID = uUnique;
+        }
+        /* Convert that ID to wchar */
+        RtlIntegerToChar(ID, 0x10, sizeof(IDString), IDString);
+        Let = IDString;
         do
         {
-            swprintf( p, formatW, unique );
-            handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
-                                  CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
-            if (handle != INVALID_HANDLE_VALUE)
-            {  /* We created it */
-                TRACE("created %S\n", buffer);
-                CloseHandle( handle );
-                break;
+            *(TempFileName++) = RtlAnsiCharToUnicodeChar(&Let);
+        } while (*Let != 0);
+        /* Append extension & UNICODE_NULL */
+        memmove(TempFileName, Ext, sizeof(Ext) + sizeof(WCHAR));
+
+        /* If user provided its ID, just return */
+        if (uUnique)
+        {
+            return uUnique;
+        }
+
+        /* Then, try to create file */
+        if (!RtlIsDosDeviceName_U(lpTempFileName))
+        {
+            TempFile = CreateFileW(lpTempFileName,
+                                   GENERIC_READ,
+                                   0,
+                                   NULL,
+                                   CREATE_NEW,
+                                   FILE_ATTRIBUTE_NORMAL,
+                                   0);
+            if (TempFile != INVALID_HANDLE_VALUE)
+            {
+                NtClose(TempFile);
+                DPRINT("Temp file: %S\n", lpTempFileName);
+                return ID;
             }
-            if (GetLastError() != ERROR_FILE_EXISTS &&
-                GetLastError() != ERROR_SHARING_VIOLATION)
-                break;  /* No need to go on */
-            if (!(++unique & 0xffff)) unique = 1;
-        } while (unique != num);
-    }
 
-    TRACE("returning %S\n", buffer);
-    return unique;
+            LastError = GetLastError();
+            /* There is no need to recover from those errors, they would hit next step */
+            if (LastError == ERROR_INVALID_PARAMETER || LastError == ERROR_CANNOT_MAKE ||
+                LastError == ERROR_WRITE_PROTECT || LastError == ERROR_NETWORK_ACCESS_DENIED ||
+                LastError == ERROR_DISK_FULL || LastError == ERROR_INVALID_NAME ||
+                LastError == ERROR_BAD_PATHNAME || LastError == ERROR_NO_INHERITANCE ||
+                LastError == ERROR_DISK_CORRUPT ||
+                (LastError == ERROR_ACCESS_DENIED && NtCurrentTeb()->LastStatusValue != STATUS_FILE_IS_A_DIRECTORY))
+            {
+                break;
+            }
+        }
+        Num++;
+    } while (Num & 0xFFFF);
+    return 0;
 }
 
 
@@ -1296,40 +1421,51 @@ UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique, LPWSTR
  * @implemented
  */
 BOOL WINAPI
-GetFileTime(HANDLE hFile,
-           LPFILETIME lpCreationTime,
-           LPFILETIME lpLastAccessTime,
-           LPFILETIME lpLastWriteTime)
+GetFileTime(IN HANDLE hFile,
+            OUT LPFILETIME lpCreationTime OPTIONAL,
+            OUT LPFILETIME lpLastAccessTime OPTIONAL,
+            OUT LPFILETIME lpLastWriteTime OPTIONAL)
 {
-   IO_STATUS_BLOCK IoStatusBlock;
-   FILE_BASIC_INFORMATION FileBasic;
-   NTSTATUS Status;
+    NTSTATUS Status;
+    IO_STATUS_BLOCK IoStatusBlock;
+    FILE_BASIC_INFORMATION FileBasic;
 
-   if(IsConsoleHandle(hFile))
-   {
-     SetLastError(ERROR_INVALID_HANDLE);
-     return FALSE;
-   }
+    if(IsConsoleHandle(hFile))
+    {
+        BaseSetLastNTError(STATUS_INVALID_HANDLE);
+        return FALSE;
+    }
 
-   Status = NtQueryInformationFile(hFile,
-                                  &IoStatusBlock,
-                                  &FileBasic,
-                                  sizeof(FILE_BASIC_INFORMATION),
-                                  FileBasicInformation);
-   if (!NT_SUCCESS(Status))
-     {
-       SetLastErrorByStatus(Status);
-       return FALSE;
-     }
+    Status = NtQueryInformationFile(hFile,
+                                    &IoStatusBlock,
+                                    &FileBasic,
+                                    sizeof(FILE_BASIC_INFORMATION),
+                                    FileBasicInformation);
+    if (!NT_SUCCESS(Status))
+    {
+        BaseSetLastNTError(Status);
+        return FALSE;
+    }
 
-   if (lpCreationTime)
-     memcpy(lpCreationTime, &FileBasic.CreationTime, sizeof(FILETIME));
-   if (lpLastAccessTime)
-     memcpy(lpLastAccessTime, &FileBasic.LastAccessTime, sizeof(FILETIME));
-   if (lpLastWriteTime)
-     memcpy(lpLastWriteTime, &FileBasic.LastWriteTime, sizeof(FILETIME));
+    if (lpCreationTime)
+    {
+        lpCreationTime->dwLowDateTime = FileBasic.CreationTime.LowPart;
+        lpCreationTime->dwHighDateTime = FileBasic.CreationTime.HighPart;
+    }
 
-   return TRUE;
+    if (lpLastAccessTime)
+    {
+        lpLastAccessTime->dwLowDateTime = FileBasic.LastAccessTime.LowPart;
+        lpLastAccessTime->dwHighDateTime = FileBasic.LastAccessTime.HighPart;
+    }
+
+    if (lpLastWriteTime)
+    {
+        lpLastWriteTime->dwLowDateTime = FileBasic.LastWriteTime.LowPart;
+        lpLastWriteTime->dwHighDateTime = FileBasic.LastWriteTime.HighPart;
+    }
+
+    return TRUE;
 }
 
 
@@ -1337,53 +1473,53 @@ GetFileTime(HANDLE hFile,
  * @implemented
  */
 BOOL WINAPI
-SetFileTime(HANDLE hFile,
-           CONST FILETIME *lpCreationTime,
-           CONST FILETIME *lpLastAccessTime,
-           CONST FILETIME *lpLastWriteTime)
+SetFileTime(IN HANDLE hFile,
+            CONST FILETIME *lpCreationTime OPTIONAL,
+            CONST FILETIME *lpLastAccessTime OPTIONAL,
+            CONST FILETIME *lpLastWriteTime OPTIONAL)
 {
-   FILE_BASIC_INFORMATION FileBasic;
-   IO_STATUS_BLOCK IoStatusBlock;
-   NTSTATUS Status;
+    NTSTATUS Status;
+    IO_STATUS_BLOCK IoStatusBlock;
+    FILE_BASIC_INFORMATION FileBasic;
 
-   if(IsConsoleHandle(hFile))
-   {
-     SetLastError(ERROR_INVALID_HANDLE);
-     return FALSE;
-   }
+    if(IsConsoleHandle(hFile))
+    {
+        BaseSetLastNTError(STATUS_INVALID_HANDLE);
+        return FALSE;
+    }
 
-   Status = NtQueryInformationFile(hFile,
-                                  &IoStatusBlock,
-                                  &FileBasic,
-                                  sizeof(FILE_BASIC_INFORMATION),
-                                  FileBasicInformation);
-   if (!NT_SUCCESS(Status))
-     {
-       SetLastErrorByStatus(Status);
-       return FALSE;
-     }
+    memset(&FileBasic, 0, sizeof(FILE_BASIC_INFORMATION));
 
-   if (lpCreationTime)
-     memcpy(&FileBasic.CreationTime, lpCreationTime, sizeof(FILETIME));
-   if (lpLastAccessTime)
-     memcpy(&FileBasic.LastAccessTime, lpLastAccessTime, sizeof(FILETIME));
-   if (lpLastWriteTime)
-     memcpy(&FileBasic.LastWriteTime, lpLastWriteTime, sizeof(FILETIME));
-
-   // should i initialize changetime ???
-
-   Status = NtSetInformationFile(hFile,
-                                &IoStatusBlock,
-                                &FileBasic,
-                                sizeof(FILE_BASIC_INFORMATION),
-                                FileBasicInformation);
-   if (!NT_SUCCESS(Status))
-     {
-       SetLastErrorByStatus(Status);
-       return FALSE;
-     }
+    if (lpCreationTime)
+    {
+        FileBasic.CreationTime.LowPart = lpCreationTime->dwLowDateTime;
+        FileBasic.CreationTime.HighPart = lpCreationTime->dwHighDateTime;
+    }
 
-   return TRUE;
+    if (lpLastAccessTime)
+    {
+        FileBasic.LastAccessTime.LowPart = lpLastAccessTime->dwLowDateTime;
+        FileBasic.LastAccessTime.HighPart = lpLastAccessTime->dwHighDateTime;
+    }
+
+    if (lpLastWriteTime)
+    {
+        FileBasic.LastWriteTime.LowPart = lpLastWriteTime->dwLowDateTime;
+        FileBasic.LastWriteTime.HighPart = lpLastWriteTime->dwHighDateTime;
+    }
+
+    Status = NtSetInformationFile(hFile,
+                                  &IoStatusBlock,
+                                  &FileBasic,
+                                  sizeof(FILE_BASIC_INFORMATION),
+                                  FileBasicInformation);
+    if (!NT_SUCCESS(Status))
+    {
+        BaseSetLastNTError(Status);
+        return FALSE;
+    }
+
+    return TRUE;
 }