* 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
*/
/* INCLUDES *****************************************************************/
#include <k32.h>
-#include <wine/debug.h>
-
-WINE_DEFAULT_DEBUG_CHANNEL(kernel32file);
+#define NDEBUG
+#include <debug.h>
+DEBUG_CHANNEL(kernel32file);
/* GLOBALS ******************************************************************/
{
DWORD ret;
+ /* destLen should never exceed MAX_PATH */
+ if (destLen > MAX_PATH) destLen = MAX_PATH;
+
ret = bIsFileApiAnsi? RtlUnicodeStringToAnsiSize(SourceU) : RtlUnicodeStringToOemSize(SourceU);
/* ret incl. nullchar */
* @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;
}
/***********************************************************************
* 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;
}
* @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;
}
* @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;
}
)
{
HANDLE hReplaced = NULL, hReplacement = NULL;
- UNICODE_STRING NtReplacedName, NtReplacementName;
+ UNICODE_STRING NtReplacedName = { 0, 0, NULL };
+ UNICODE_STRING NtReplacementName = { 0, 0, NULL };
DWORD Error = ERROR_SUCCESS;
NTSTATUS Status;
BOOL Ret = FALSE;
if (hReplacement) NtClose(hReplacement);
if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
- RtlFreeUnicodeString(&NtReplacementName);
- RtlFreeUnicodeString(&NtReplacedName);
+ if (NtReplacementName.Buffer)
+ RtlFreeHeap(GetProcessHeap(), 0, NtReplacementName.Buffer);
+ if (NtReplacedName.Buffer)
+ RtlFreeHeap(GetProcessHeap(), 0, NtReplacedName.Buffer);
/* If there was an error, set the error code */
if(!Ret)