Author: ion Date: Sun Nov 6 02:00:56 2011 New Revision: 54309
URL: http://svn.reactos.org/svn/reactos?rev=54309&view=rev Log: [KERNEL32]: Move path-related APIs away from dir.c, and into path.c instead. [KERNEL32]: Fix SetDllDirectoryW: - Fail if ";" is in path - Use RtlCreateUnicodeString instead of manual string management -- if the allocation fails, do not free the current base directory string! Older API would always free the current directory string, even if setting up the new one failed. - Don't assume lpPathName is filled out, it can be NULL, and this means the DLL directory should be cleared. [KERNEL32]: Fix SetDllDirectoryA as above, additionally use RtlInitAnsiStringEx to protect against overflow, and use Basep8BitStringToUnicodeString, to add support for OEM paths instead of assuming ANSI. [KERNEL32]: GetDllDirectoryW: correctly NULL-terminate and check lengths [KERNEL32]: GetDllDirectoryA: same as above, plus use BasepUnicodeString* APIs to correctly support OEM paths instead of assuming ANSI. [KERNEL32]: NeedCurrentDirectoryForExePath(A/W): call internal BasepIsCurDirAllowedForPlainExeNames instead of converting from A->W, this isn't needed. [KERNEL32]: GetFullPathNameW just calls RtlGetFullPathName_U, no extra checks/etc are needed. Next steps are GetFullPathNameA, GetShort/LongPathNameA, GetShort/LongPathNameW, hoping to bring the wine test failures closer to zero.
Added: trunk/reactos/dll/win32/kernel32/client/path.c (with props) Modified: trunk/reactos/dll/win32/kernel32/CMakeLists.txt trunk/reactos/dll/win32/kernel32/client/file/dir.c trunk/reactos/dll/win32/kernel32/kernel32.rbuild
Modified: trunk/reactos/dll/win32/kernel32/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/CMakeLis... ============================================================================== --- trunk/reactos/dll/win32/kernel32/CMakeLists.txt [iso-8859-1] (original) +++ trunk/reactos/dll/win32/kernel32/CMakeLists.txt [iso-8859-1] Sun Nov 6 02:00:56 2011 @@ -20,6 +20,7 @@ client/heapmem.c client/job.c client/loader.c + client/path.c client/perfcnt.c client/power.c client/proc.c
Modified: trunk/reactos/dll/win32/kernel32/client/file/dir.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/client/f... ============================================================================== --- trunk/reactos/dll/win32/kernel32/client/file/dir.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/kernel32/client/file/dir.c [iso-8859-1] Sun Nov 6 02:00:56 2011 @@ -19,8 +19,6 @@ #define NDEBUG #include <debug.h> DEBUG_CHANNEL(kernel32file); - -UNICODE_STRING BaseDllDirectory = {0, 0, NULL};
/* FUNCTIONS *****************************************************************/
@@ -578,799 +576,4 @@ return TRUE; }
- -/* - * @implemented - */ -DWORD -WINAPI -GetFullPathNameA ( - LPCSTR lpFileName, - DWORD nBufferLength, - LPSTR lpBuffer, - LPSTR *lpFilePart - ) -{ - WCHAR BufferW[MAX_PATH]; - PWCHAR FileNameW; - DWORD ret; - LPWSTR FilePartW = NULL; - - TRACE("GetFullPathNameA(lpFileName %s, nBufferLength %d, lpBuffer %p, " - "lpFilePart %p)\n",lpFileName,nBufferLength,lpBuffer,lpFilePart); - - if (!(FileNameW = FilenameA2W(lpFileName, FALSE))) - return 0; - - ret = GetFullPathNameW(FileNameW, MAX_PATH, BufferW, &FilePartW); - - if (!ret) - return 0; - - if (ret > MAX_PATH) - { - SetLastError(ERROR_FILENAME_EXCED_RANGE); - return 0; - } - - ret = FilenameW2A_FitOrFail(lpBuffer, nBufferLength, BufferW, ret+1); - - if (ret < nBufferLength && lpFilePart) - { - /* if the path closed with '', FilePart is NULL */ - if (!FilePartW) - *lpFilePart=NULL; - else - *lpFilePart = (FilePartW - BufferW) + lpBuffer; - } - - TRACE("GetFullPathNameA ret: lpBuffer %s lpFilePart %s\n", - lpBuffer, (lpFilePart == NULL) ? "NULL" : *lpFilePart); - - return ret; -} - - -/* - * @implemented - */ -DWORD -WINAPI -GetFullPathNameW ( - LPCWSTR lpFileName, - DWORD nBufferLength, - LPWSTR lpBuffer, - LPWSTR *lpFilePart - ) -{ - ULONG Length; - - TRACE("GetFullPathNameW(lpFileName %S, nBufferLength %d, lpBuffer %p, " - "lpFilePart %p)\n",lpFileName,nBufferLength,lpBuffer,lpFilePart); - - Length = RtlGetFullPathName_U ((LPWSTR)lpFileName, - nBufferLength * sizeof(WCHAR), - lpBuffer, - lpFilePart); - - TRACE("GetFullPathNameW ret: lpBuffer %S lpFilePart %S Length %ld\n", - lpBuffer, (lpFilePart == NULL) ? L"NULL" : *lpFilePart, Length / sizeof(WCHAR)); - - if (!lpFileName) - { -#if (WINVER >= _WIN32_WINNT_WIN7) - SetLastError(ERROR_INVALID_PARAMETER); -#endif - return 0; - } - - return Length/sizeof(WCHAR); -} - - -/* - * NOTE: Copied from Wine. - * @implemented - */ -DWORD -WINAPI -GetShortPathNameA ( - LPCSTR longpath, - LPSTR shortpath, - DWORD shortlen - ) -{ - PWCHAR LongPathW; - WCHAR ShortPathW[MAX_PATH]; - DWORD ret; - - if (!longpath) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - - if (!(LongPathW = FilenameA2W(longpath, FALSE))) - return 0; - - ret = GetShortPathNameW(LongPathW, ShortPathW, MAX_PATH); - - if (!ret) - return 0; - - if (ret > MAX_PATH) - { - SetLastError(ERROR_FILENAME_EXCED_RANGE); - return 0; - } - - return FilenameW2A_FitOrFail(shortpath, shortlen, ShortPathW, ret+1); -} - - -/* - * NOTE: Copied from Wine. - * @implemented - */ -DWORD -WINAPI -GetShortPathNameW ( - LPCWSTR longpath, - LPWSTR shortpath, - DWORD shortlen - ) -{ - WCHAR tmpshortpath[MAX_PATH]; - LPCWSTR p; - DWORD sp = 0, lp = 0; - DWORD tmplen; - WIN32_FIND_DATAW wfd; - HANDLE goit; - UNICODE_STRING ustr; - WCHAR ustr_buf[8+1+3+1]; - - TRACE("GetShortPathNameW: %S\n",longpath); - - if (!longpath) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - if (!longpath[0]) - { - SetLastError(ERROR_BAD_PATHNAME); - return 0; - } - - /* check for drive letter */ - if (longpath[0] != '/' && longpath[1] == ':' ) - { - tmpshortpath[0] = longpath[0]; - tmpshortpath[1] = ':'; - sp = lp = 2; - } - - ustr.Buffer = ustr_buf; - ustr.Length = 0; - ustr.MaximumLength = sizeof(ustr_buf); - - while (longpath[lp]) - { - /* check for path delimiters and reproduce them */ - if (longpath[lp] == '\' || longpath[lp] == '/') - { - if (!sp || tmpshortpath[sp-1] != '\') - { - /* strip double "\" */ - tmpshortpath[sp] = '\'; - sp++; - } - tmpshortpath[sp] = 0; /* terminate string */ - lp++; - continue; - } - - for (p = longpath + lp; *p && *p != '/' && *p != '\'; p++); - tmplen = p - (longpath + lp); - lstrcpynW(tmpshortpath + sp, longpath + lp, tmplen + 1); - /* Check, if the current element is a valid dos name */ - if (tmplen <= 8+1+3) - { - BOOLEAN spaces; - memcpy(ustr_buf, longpath + lp, tmplen * sizeof(WCHAR)); - ustr_buf[tmplen] = '\0'; - ustr.Length = (USHORT)tmplen * sizeof(WCHAR); - if (RtlIsNameLegalDOS8Dot3(&ustr, NULL, &spaces) && !spaces) - { - sp += tmplen; - lp += tmplen; - continue; - } - } - - /* Check if the file exists and use the existing short file name */ - goit = FindFirstFileW(tmpshortpath, &wfd); - if (goit == INVALID_HANDLE_VALUE) goto notfound; - FindClose(goit); - lstrcpyW(tmpshortpath + sp, wfd.cAlternateFileName); - sp += lstrlenW(tmpshortpath + sp); - lp += tmplen; - } - tmpshortpath[sp] = 0; - - tmplen = lstrlenW(tmpshortpath) + 1; - if (tmplen <= shortlen) - { - lstrcpyW(shortpath, tmpshortpath); - tmplen--; /* length without 0 */ - } - - return tmplen; - - notfound: - SetLastError ( ERROR_FILE_NOT_FOUND ); - return 0; -} - - -/* - * @implemented - */ -DWORD -WINAPI -SearchPathA ( - LPCSTR lpPath, - LPCSTR lpFileName, - LPCSTR lpExtension, - DWORD nBufferLength, - LPSTR lpBuffer, - LPSTR *lpFilePart - ) -{ - UNICODE_STRING PathU = { 0, 0, NULL }; - UNICODE_STRING FileNameU = { 0, 0, NULL }; - UNICODE_STRING ExtensionU = { 0, 0, NULL }; - UNICODE_STRING BufferU = { 0, 0, NULL }; - ANSI_STRING Path; - ANSI_STRING FileName; - ANSI_STRING Extension; - ANSI_STRING Buffer; - PWCHAR FilePartW; - DWORD RetValue = 0; - NTSTATUS Status = STATUS_SUCCESS; - - if (!lpFileName) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - - RtlInitAnsiString (&Path, - (LPSTR)lpPath); - RtlInitAnsiString (&FileName, - (LPSTR)lpFileName); - RtlInitAnsiString (&Extension, - (LPSTR)lpExtension); - - /* convert ansi (or oem) strings to unicode */ - if (bIsFileApiAnsi) - { - Status = RtlAnsiStringToUnicodeString (&PathU, - &Path, - TRUE); - if (!NT_SUCCESS(Status)) - goto Cleanup; - - Status = RtlAnsiStringToUnicodeString (&FileNameU, - &FileName, - TRUE); - if (!NT_SUCCESS(Status)) - goto Cleanup; - - Status = RtlAnsiStringToUnicodeString (&ExtensionU, - &Extension, - TRUE); - if (!NT_SUCCESS(Status)) - goto Cleanup; - } - else - { - Status = RtlOemStringToUnicodeString (&PathU, - &Path, - TRUE); - if (!NT_SUCCESS(Status)) - goto Cleanup; - Status = RtlOemStringToUnicodeString (&FileNameU, - &FileName, - TRUE); - if (!NT_SUCCESS(Status)) - goto Cleanup; - - Status = RtlOemStringToUnicodeString (&ExtensionU, - &Extension, - TRUE); - if (!NT_SUCCESS(Status)) - goto Cleanup; - } - - BufferU.MaximumLength = min(nBufferLength * sizeof(WCHAR), USHRT_MAX); - BufferU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (), - 0, - BufferU.MaximumLength); - if (BufferU.Buffer == NULL) - { - Status = STATUS_NO_MEMORY; - goto Cleanup; - } - - Buffer.MaximumLength = min(nBufferLength, USHRT_MAX); - Buffer.Buffer = lpBuffer; - - RetValue = SearchPathW (NULL == lpPath ? NULL : PathU.Buffer, - NULL == lpFileName ? NULL : FileNameU.Buffer, - NULL == lpExtension ? NULL : ExtensionU.Buffer, - nBufferLength, - BufferU.Buffer, - &FilePartW); - - if (0 != RetValue) - { - BufferU.Length = wcslen(BufferU.Buffer) * sizeof(WCHAR); - /* convert ansi (or oem) string to unicode */ - if (bIsFileApiAnsi) - Status = RtlUnicodeStringToAnsiString(&Buffer, - &BufferU, - FALSE); - else - Status = RtlUnicodeStringToOemString(&Buffer, - &BufferU, - FALSE); - - if (NT_SUCCESS(Status) && Buffer.Buffer) - { - /* nul-terminate ascii string */ - Buffer.Buffer[BufferU.Length / sizeof(WCHAR)] = '\0'; - - if (NULL != lpFilePart && BufferU.Length != 0) - { - *lpFilePart = strrchr (lpBuffer, '\') + 1; - } - } - } - -Cleanup: - RtlFreeHeap (RtlGetProcessHeap (), - 0, - PathU.Buffer); - RtlFreeHeap (RtlGetProcessHeap (), - 0, - FileNameU.Buffer); - RtlFreeHeap (RtlGetProcessHeap (), - 0, - ExtensionU.Buffer); - RtlFreeHeap (RtlGetProcessHeap (), - 0, - BufferU.Buffer); - - if (!NT_SUCCESS(Status)) - { - BaseSetLastNTError(Status); - return 0; - } - - return RetValue; -} - - -/*********************************************************************** - * ContainsPath (Wine name: contains_pathW) - * - * Check if the file name contains a path; helper for SearchPathW. - * A relative path is not considered a path unless it starts with ./ or ../ - */ -static -BOOL -ContainsPath(LPCWSTR name) -{ - if (RtlDetermineDosPathNameType_U(name) != RtlPathTypeRelative) return TRUE; - if (name[0] != '.') return FALSE; - if (name[1] == '/' || name[1] == '\' || name[1] == '\0') return TRUE; - return (name[1] == '.' && (name[2] == '/' || name[2] == '\')); -} - - -/* - * @implemented - */ -DWORD -WINAPI -SearchPathW(LPCWSTR lpPath, - LPCWSTR lpFileName, - LPCWSTR lpExtension, - DWORD nBufferLength, - LPWSTR lpBuffer, - LPWSTR *lpFilePart) -{ - DWORD ret = 0; - - if (!lpFileName || !lpFileName[0]) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - - /* If the name contains an explicit path, ignore the path */ - if (ContainsPath(lpFileName)) - { - /* try first without extension */ - if (RtlDoesFileExists_U(lpFileName)) - return GetFullPathNameW(lpFileName, nBufferLength, lpBuffer, lpFilePart); - - if (lpExtension) - { - LPCWSTR p = wcsrchr(lpFileName, '.'); - if (p && !strchr((const char *)p, '/') && !wcschr( p, '\' )) - lpExtension = NULL; /* Ignore the specified extension */ - } - - /* Allocate a buffer for the file name and extension */ - if (lpExtension) - { - LPWSTR tmp; - DWORD len = wcslen(lpFileName) + wcslen(lpExtension); - - if (!(tmp = RtlAllocateHeap(RtlGetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)))) - { - SetLastError(ERROR_OUTOFMEMORY); - return 0; - } - wcscpy(tmp, lpFileName); - wcscat(tmp, lpExtension); - if (RtlDoesFileExists_U(tmp)) - ret = GetFullPathNameW(tmp, nBufferLength, lpBuffer, lpFilePart); - RtlFreeHeap(RtlGetProcessHeap(), 0, tmp); - } - } - else if (lpPath && lpPath[0]) /* search in the specified path */ - { - ret = RtlDosSearchPath_U(lpPath, - lpFileName, - lpExtension, - nBufferLength * sizeof(WCHAR), - lpBuffer, - lpFilePart) / sizeof(WCHAR); - } - else /* search in the default path */ - { - WCHAR *DllPath = GetDllLoadPath(NULL); - - if (DllPath) - { - ret = RtlDosSearchPath_U(DllPath, - lpFileName, - lpExtension, - nBufferLength * sizeof(WCHAR), - lpBuffer, - lpFilePart) / sizeof(WCHAR); - RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath); - } - else - { - SetLastError(ERROR_OUTOFMEMORY); - return 0; - } - } - - if (!ret) SetLastError(ERROR_FILE_NOT_FOUND); - - return ret; -} - -/* - * @implemented - */ -BOOL -WINAPI -SetDllDirectoryW( - LPCWSTR lpPathName - ) -{ - UNICODE_STRING PathName; - - RtlInitUnicodeString(&PathName, lpPathName); - - RtlEnterCriticalSection(&BaseDllDirectoryLock); - if(PathName.Length > 0) - { - if(PathName.Length + sizeof(WCHAR) <= BaseDllDirectory.MaximumLength) - { - RtlCopyUnicodeString(&BaseDllDirectory, &PathName); - } - else - { - RtlFreeUnicodeString(&BaseDllDirectory); - if(!(BaseDllDirectory.Buffer = (PWSTR)RtlAllocateHeap(RtlGetProcessHeap(), - 0, - PathName.Length + sizeof(WCHAR)))) - { - RtlLeaveCriticalSection(&BaseDllDirectoryLock); - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return FALSE; - } - BaseDllDirectory.Length = 0; - BaseDllDirectory.MaximumLength = PathName.Length + sizeof(WCHAR); - - RtlCopyUnicodeString(&BaseDllDirectory, &PathName); - } - } - else - { - RtlFreeUnicodeString(&BaseDllDirectory); - } - RtlLeaveCriticalSection(&BaseDllDirectoryLock); - - return TRUE; -} - -/* - * @implemented - */ -BOOL -WINAPI -SetDllDirectoryA( - LPCSTR lpPathName /* can be NULL */ - ) -{ - PWCHAR PathNameW=NULL; - - if(lpPathName) - { - if (!(PathNameW = FilenameA2W(lpPathName, FALSE))) - return FALSE; - } - - return SetDllDirectoryW(PathNameW); -} - -/* - * @implemented - */ -DWORD -WINAPI -GetDllDirectoryW( - DWORD nBufferLength, - LPWSTR lpBuffer - ) -{ - DWORD Ret; - - RtlEnterCriticalSection(&BaseDllDirectoryLock); - if(nBufferLength > 0) - { - Ret = BaseDllDirectory.Length / sizeof(WCHAR); - if(Ret > nBufferLength - 1) - { - Ret = nBufferLength - 1; - } - - if(Ret > 0) - { - RtlCopyMemory(lpBuffer, BaseDllDirectory.Buffer, Ret * sizeof(WCHAR)); - } - lpBuffer[Ret] = L'\0'; - } - else - { - /* include termination character, even if the string is empty! */ - Ret = (BaseDllDirectory.Length / sizeof(WCHAR)) + 1; - } - RtlLeaveCriticalSection(&BaseDllDirectoryLock); - - return Ret; -} - -/* - * @implemented - */ -DWORD -WINAPI -GetDllDirectoryA( - DWORD nBufferLength, - LPSTR lpBuffer - ) -{ - WCHAR BufferW[MAX_PATH]; - DWORD ret; - - ret = GetDllDirectoryW(MAX_PATH, BufferW); - - if (!ret) - return 0; - - if (ret > MAX_PATH) - { - SetLastError(ERROR_FILENAME_EXCED_RANGE); - return 0; - } - - return FilenameW2A_FitOrFail(lpBuffer, nBufferLength, BufferW, ret+1); -} - - -/* - * @implemented - */ -BOOL WINAPI -NeedCurrentDirectoryForExePathW(LPCWSTR ExeName) -{ - static const WCHAR env_name[] = {'N','o','D','e','f','a','u','l','t', - 'C','u','r','r','e','n','t', - 'D','i','r','e','c','t','o','r','y', - 'I','n','E','x','e','P','a','t','h',0}; - WCHAR env_val; - - /* MSDN mentions some 'registry location'. We do not use registry. */ - FIXME("(%s): partial stub\n", debugstr_w(ExeName)); - - if (wcschr(ExeName, L'\')) - return TRUE; - - /* Check the existence of the variable, not value */ - if (!GetEnvironmentVariableW( env_name, &env_val, 1 )) - return TRUE; - - return FALSE; -} - - -/* - * @implemented - */ -BOOL WINAPI -NeedCurrentDirectoryForExePathA(LPCSTR ExeName) -{ - WCHAR *ExeNameW; - - if (!(ExeNameW = FilenameA2W(ExeName, FALSE))) - return TRUE; - - return NeedCurrentDirectoryForExePathW(ExeNameW); -} - - - - - -/*********************************************************************** - * @implemented - * - * GetLongPathNameW (KERNEL32.@) - * - * NOTES - * observed (Win2000): - * shortpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0 - * shortpath="": LastError=ERROR_PATH_NOT_FOUND, ret=0 - */ -DWORD WINAPI GetLongPathNameW( LPCWSTR shortpath, LPWSTR longpath, DWORD longlen ) -{ -#define MAX_PATHNAME_LEN 1024 - - WCHAR tmplongpath[MAX_PATHNAME_LEN]; - LPCWSTR p; - DWORD sp = 0, lp = 0; - DWORD tmplen; - BOOL unixabsolute; - WIN32_FIND_DATAW wfd; - HANDLE goit; - - if (!shortpath) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - if (!shortpath[0]) - { - SetLastError(ERROR_PATH_NOT_FOUND); - return 0; - } - - TRACE("GetLongPathNameW(%s,%p,%ld)\n", shortpath, longpath, longlen); - - if (shortpath[0] == '\' && shortpath[1] == '\') - { - WARN("ERR: UNC pathname %s\n", shortpath); - lstrcpynW( longpath, shortpath, longlen ); - return wcslen(longpath); - } - unixabsolute = (shortpath[0] == '/'); - /* check for drive letter */ - if (!unixabsolute && shortpath[1] == ':' ) - { - tmplongpath[0] = shortpath[0]; - tmplongpath[1] = ':'; - lp = sp = 2; - } - - while (shortpath[sp]) - { - /* check for path delimiters and reproduce them */ - if (shortpath[sp] == '\' || shortpath[sp] == '/') - { - if (!lp || tmplongpath[lp-1] != '\') - { - /* strip double "\" */ - tmplongpath[lp++] = '\'; - } - tmplongpath[lp] = 0; /* terminate string */ - sp++; - continue; - } - - p = shortpath + sp; - if (sp == 0 && p[0] == '.' && (p[1] == '/' || p[1] == '\')) - { - tmplongpath[lp++] = *p++; - tmplongpath[lp++] = *p++; - } - for (; *p && *p != '/' && *p != '\'; p++); - tmplen = p - (shortpath + sp); - lstrcpynW(tmplongpath + lp, shortpath + sp, tmplen + 1); - /* Check if the file exists and use the existing file name */ - goit = FindFirstFileW(tmplongpath, &wfd); - if (goit == INVALID_HANDLE_VALUE) - { - TRACE("not found %s!\n", tmplongpath); - SetLastError ( ERROR_FILE_NOT_FOUND ); - return 0; - } - FindClose(goit); - wcscpy(tmplongpath + lp, wfd.cFileName); - lp += wcslen(tmplongpath + lp); - sp += tmplen; - } - tmplen = wcslen(shortpath) - 1; - if ((shortpath[tmplen] == '/' || shortpath[tmplen] == '\') && - (tmplongpath[lp - 1] != '/' && tmplongpath[lp - 1] != '\')) - tmplongpath[lp++] = shortpath[tmplen]; - tmplongpath[lp] = 0; - - tmplen = wcslen(tmplongpath) + 1; - if (tmplen <= longlen) - { - wcscpy(longpath, tmplongpath); - TRACE("returning %s\n", longpath); - tmplen--; /* length without 0 */ - } - - return tmplen; -} - - - -/*********************************************************************** - * GetLongPathNameA (KERNEL32.@) - */ -DWORD WINAPI GetLongPathNameA( LPCSTR shortpath, LPSTR longpath, DWORD longlen ) -{ - WCHAR *shortpathW; - WCHAR longpathW[MAX_PATH]; - DWORD ret; - - TRACE("GetLongPathNameA %s, %i\n",shortpath,longlen ); - - if (!(shortpathW = FilenameA2W( shortpath, FALSE ))) - return 0; - - ret = GetLongPathNameW(shortpathW, longpathW, MAX_PATH); - - if (!ret) return 0; - if (ret > MAX_PATH) - { - SetLastError(ERROR_FILENAME_EXCED_RANGE); - return 0; - } - - return FilenameW2A_FitOrFail(longpath, longlen, longpathW, ret+1 ); -} - /* EOF */
Added: trunk/reactos/dll/win32/kernel32/client/path.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/client/p... ============================================================================== --- trunk/reactos/dll/win32/kernel32/client/path.c (added) +++ trunk/reactos/dll/win32/kernel32/client/path.c [iso-8859-1] Sun Nov 6 02:00:56 2011 @@ -1,0 +1,817 @@ +/* + * PROJECT: ReactOS Win32 Base API + * LICENSE: GPL - See COPYING in the top level directory + * FILE: dll/win32/kernel32/client/path.c + * PURPOSE: Handles path APIs + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES *******************************************************************/ + +#include <k32.h> + +#define NDEBUG +#include <debug.h> + +/* GLOBALS ********************************************************************/ + +UNICODE_STRING BaseDllDirectory; +UNICODE_STRING NoDefaultCurrentDirectoryInExePath = RTL_CONSTANT_STRING(L"NoDefaultCurrentDirectoryInExePath"); + +/* FUNCTIONS ******************************************************************/ + +BOOL +WINAPI +BasepIsCurDirAllowedForPlainExeNames(VOID) +{ + NTSTATUS Status; + UNICODE_STRING EmptyString; + + RtlInitEmptyUnicodeString(&EmptyString, NULL, 0); + Status = RtlQueryEnvironmentVariable_U(0, + &NoDefaultCurrentDirectoryInExePath, + &EmptyString); + return NT_SUCCESS(Status); +} + +/* + * @implemented + */ +BOOL +WINAPI +SetDllDirectoryW(IN LPCWSTR lpPathName) +{ + UNICODE_STRING OldDirectory, DllDirectory; + + if (lpPathName) + { + if (wcschr(lpPathName, ';')) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if (!RtlCreateUnicodeString(&DllDirectory, lpPathName)) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; + } + } + else + { + RtlInitUnicodeString(&DllDirectory, 0); + } + + RtlEnterCriticalSection(&BaseDllDirectoryLock); + + OldDirectory = BaseDllDirectory; + BaseDllDirectory = DllDirectory; + + RtlLeaveCriticalSection(&BaseDllDirectoryLock); + + RtlFreeUnicodeString(&OldDirectory); + return 1; +} + +/* + * @implemented + */ +BOOL +WINAPI +SetDllDirectoryA(IN LPCSTR lpPathName) +{ + ANSI_STRING AnsiDllDirectory; + UNICODE_STRING OldDirectory, DllDirectory; + NTSTATUS Status; + + if (lpPathName) + { + if (strchr(lpPathName, ';')) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + Status = RtlInitAnsiStringEx(&AnsiDllDirectory, lpPathName); + if (NT_SUCCESS(Status)) + { + Status = Basep8BitStringToUnicodeString(&DllDirectory, + &AnsiDllDirectory, + TRUE); + } + + if (!NT_SUCCESS(Status)) + { + BaseSetLastNTError(Status); + return 0; + } + } + else + { + RtlInitUnicodeString(&DllDirectory, 0); + } + + RtlEnterCriticalSection(&BaseDllDirectoryLock); + + OldDirectory = BaseDllDirectory; + BaseDllDirectory = DllDirectory; + + RtlLeaveCriticalSection(&BaseDllDirectoryLock); + + RtlFreeUnicodeString(&OldDirectory); + return 1; +} + +/* + * @implemented + */ +DWORD +WINAPI +GetDllDirectoryW(IN DWORD nBufferLength, + OUT LPWSTR lpBuffer) +{ + ULONG Length; + + RtlEnterCriticalSection(&BaseDllDirectoryLock); + + if ((nBufferLength * sizeof(WCHAR)) > BaseDllDirectory.Length) + { + RtlCopyMemory(lpBuffer, BaseDllDirectory.Buffer, BaseDllDirectory.Length); + Length = BaseDllDirectory.Length / sizeof(WCHAR); + lpBuffer[Length] = UNICODE_NULL; + } + else + { + Length = (BaseDllDirectory.Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR); + if (lpBuffer) *lpBuffer = UNICODE_NULL; + } + + RtlLeaveCriticalSection(&BaseDllDirectoryLock); + return Length; +} + +/* + * @implemented + */ +DWORD +WINAPI +GetDllDirectoryA(IN DWORD nBufferLength, + OUT LPSTR lpBuffer) +{ + NTSTATUS Status; + ANSI_STRING AnsiDllDirectory; + ULONG Length; + + RtlInitEmptyAnsiString(&AnsiDllDirectory, lpBuffer, 0); + + RtlEnterCriticalSection(&BaseDllDirectoryLock); + + Length = BasepUnicodeStringTo8BitSize(&BaseDllDirectory); + if (Length > nBufferLength) + { + Status = STATUS_SUCCESS; + if (lpBuffer) *lpBuffer = ANSI_NULL; + } + else + { + --Length; + Status = BasepUnicodeStringTo8BitString(&AnsiDllDirectory, + &BaseDllDirectory, + FALSE); + } + + RtlLeaveCriticalSection(&BaseDllDirectoryLock); + + if (!NT_SUCCESS(Status)) + { + BaseSetLastNTError(Status); + Length = 0; + if (lpBuffer) *lpBuffer = ANSI_NULL; + } + + return Length; +} + +/* + * @implemented + */ +BOOL +WINAPI +NeedCurrentDirectoryForExePathW(IN LPCWSTR ExeName) +{ + if (wcschr(ExeName, '\')) return TRUE; + + return BasepIsCurDirAllowedForPlainExeNames(); +} + +/* + * @implemented + */ +BOOL +WINAPI +NeedCurrentDirectoryForExePathA(IN LPCSTR ExeName) +{ + if (strchr(ExeName, '\')) return TRUE; + + return BasepIsCurDirAllowedForPlainExeNames(); +} + +/* + * @implemented + */ +DWORD +WINAPI +GetFullPathNameA ( + LPCSTR lpFileName, + DWORD nBufferLength, + LPSTR lpBuffer, + LPSTR *lpFilePart + ) +{ + WCHAR BufferW[MAX_PATH]; + PWCHAR FileNameW; + DWORD ret; + LPWSTR FilePartW = NULL; + + DPRINT("GetFullPathNameA(lpFileName %s, nBufferLength %d, lpBuffer %p, " + "lpFilePart %p)\n",lpFileName,nBufferLength,lpBuffer,lpFilePart); + + if (!(FileNameW = FilenameA2W(lpFileName, FALSE))) + return 0; + + ret = GetFullPathNameW(FileNameW, MAX_PATH, BufferW, &FilePartW); + + if (!ret) + return 0; + + if (ret > MAX_PATH) + { + SetLastError(ERROR_FILENAME_EXCED_RANGE); + return 0; + } + + ret = FilenameW2A_FitOrFail(lpBuffer, nBufferLength, BufferW, ret+1); + + if (ret < nBufferLength && lpFilePart) + { + /* if the path closed with '', FilePart is NULL */ + if (!FilePartW) + *lpFilePart=NULL; + else + *lpFilePart = (FilePartW - BufferW) + lpBuffer; + } + + DPRINT("GetFullPathNameA ret: lpBuffer %s lpFilePart %s\n", + lpBuffer, (lpFilePart == NULL) ? "NULL" : *lpFilePart); + + return ret; +} + + +/* + * @implemented + */ +DWORD +WINAPI +GetFullPathNameW(IN LPCWSTR lpFileName, + IN DWORD nBufferLength, + IN LPWSTR lpBuffer, + OUT LPWSTR *lpFilePart) +{ + return RtlGetFullPathName_U((LPWSTR)lpFileName, + nBufferLength * sizeof(WCHAR), + lpBuffer, + lpFilePart) / sizeof(WCHAR); +} + + +/* + * NOTE: Copied from Wine. + * @implemented + */ +DWORD +WINAPI +GetShortPathNameA ( + LPCSTR longpath, + LPSTR shortpath, + DWORD shortlen + ) +{ + PWCHAR LongPathW; + WCHAR ShortPathW[MAX_PATH]; + DWORD ret; + + if (!longpath) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + if (!(LongPathW = FilenameA2W(longpath, FALSE))) + return 0; + + ret = GetShortPathNameW(LongPathW, ShortPathW, MAX_PATH); + + if (!ret) + return 0; + + if (ret > MAX_PATH) + { + SetLastError(ERROR_FILENAME_EXCED_RANGE); + return 0; + } + + return FilenameW2A_FitOrFail(shortpath, shortlen, ShortPathW, ret+1); +} + + +/* + * NOTE: Copied from Wine. + * @implemented + */ +DWORD +WINAPI +GetShortPathNameW ( + LPCWSTR longpath, + LPWSTR shortpath, + DWORD shortlen + ) +{ + WCHAR tmpshortpath[MAX_PATH]; + LPCWSTR p; + DWORD sp = 0, lp = 0; + DWORD tmplen; + WIN32_FIND_DATAW wfd; + HANDLE goit; + UNICODE_STRING ustr; + WCHAR ustr_buf[8+1+3+1]; + + DPRINT("GetShortPathNameW: %S\n",longpath); + + if (!longpath) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + if (!longpath[0]) + { + SetLastError(ERROR_BAD_PATHNAME); + return 0; + } + + /* check for drive letter */ + if (longpath[0] != '/' && longpath[1] == ':' ) + { + tmpshortpath[0] = longpath[0]; + tmpshortpath[1] = ':'; + sp = lp = 2; + } + + ustr.Buffer = ustr_buf; + ustr.Length = 0; + ustr.MaximumLength = sizeof(ustr_buf); + + while (longpath[lp]) + { + /* check for path delimiters and reproduce them */ + if (longpath[lp] == '\' || longpath[lp] == '/') + { + if (!sp || tmpshortpath[sp-1] != '\') + { + /* strip double "\" */ + tmpshortpath[sp] = '\'; + sp++; + } + tmpshortpath[sp] = 0; /* terminate string */ + lp++; + continue; + } + + for (p = longpath + lp; *p && *p != '/' && *p != '\'; p++); + tmplen = p - (longpath + lp); + lstrcpynW(tmpshortpath + sp, longpath + lp, tmplen + 1); + /* Check, if the current element is a valid dos name */ + if (tmplen <= 8+1+3) + { + BOOLEAN spaces; + memcpy(ustr_buf, longpath + lp, tmplen * sizeof(WCHAR)); + ustr_buf[tmplen] = '\0'; + ustr.Length = (USHORT)tmplen * sizeof(WCHAR); + if (RtlIsNameLegalDOS8Dot3(&ustr, NULL, &spaces) && !spaces) + { + sp += tmplen; + lp += tmplen; + continue; + } + } + + /* Check if the file exists and use the existing short file name */ + goit = FindFirstFileW(tmpshortpath, &wfd); + if (goit == INVALID_HANDLE_VALUE) goto notfound; + FindClose(goit); + lstrcpyW(tmpshortpath + sp, wfd.cAlternateFileName); + sp += lstrlenW(tmpshortpath + sp); + lp += tmplen; + } + tmpshortpath[sp] = 0; + + tmplen = lstrlenW(tmpshortpath) + 1; + if (tmplen <= shortlen) + { + lstrcpyW(shortpath, tmpshortpath); + tmplen--; /* length without 0 */ + } + + return tmplen; + + notfound: + SetLastError ( ERROR_FILE_NOT_FOUND ); + return 0; +} + + +/* + * @implemented + */ +DWORD +WINAPI +SearchPathA ( + LPCSTR lpPath, + LPCSTR lpFileName, + LPCSTR lpExtension, + DWORD nBufferLength, + LPSTR lpBuffer, + LPSTR *lpFilePart + ) +{ + UNICODE_STRING PathU = { 0, 0, NULL }; + UNICODE_STRING FileNameU = { 0, 0, NULL }; + UNICODE_STRING ExtensionU = { 0, 0, NULL }; + UNICODE_STRING BufferU = { 0, 0, NULL }; + ANSI_STRING Path; + ANSI_STRING FileName; + ANSI_STRING Extension; + ANSI_STRING Buffer; + PWCHAR FilePartW; + DWORD RetValue = 0; + NTSTATUS Status = STATUS_SUCCESS; + + if (!lpFileName) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + RtlInitAnsiString (&Path, + (LPSTR)lpPath); + RtlInitAnsiString (&FileName, + (LPSTR)lpFileName); + RtlInitAnsiString (&Extension, + (LPSTR)lpExtension); + + /* convert ansi (or oem) strings to unicode */ + if (bIsFileApiAnsi) + { + Status = RtlAnsiStringToUnicodeString (&PathU, + &Path, + TRUE); + if (!NT_SUCCESS(Status)) + goto Cleanup; + + Status = RtlAnsiStringToUnicodeString (&FileNameU, + &FileName, + TRUE); + if (!NT_SUCCESS(Status)) + goto Cleanup; + + Status = RtlAnsiStringToUnicodeString (&ExtensionU, + &Extension, + TRUE); + if (!NT_SUCCESS(Status)) + goto Cleanup; + } + else + { + Status = RtlOemStringToUnicodeString (&PathU, + &Path, + TRUE); + if (!NT_SUCCESS(Status)) + goto Cleanup; + Status = RtlOemStringToUnicodeString (&FileNameU, + &FileName, + TRUE); + if (!NT_SUCCESS(Status)) + goto Cleanup; + + Status = RtlOemStringToUnicodeString (&ExtensionU, + &Extension, + TRUE); + if (!NT_SUCCESS(Status)) + goto Cleanup; + } + + BufferU.MaximumLength = min(nBufferLength * sizeof(WCHAR), USHRT_MAX); + BufferU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (), + 0, + BufferU.MaximumLength); + if (BufferU.Buffer == NULL) + { + Status = STATUS_NO_MEMORY; + goto Cleanup; + } + + Buffer.MaximumLength = min(nBufferLength, USHRT_MAX); + Buffer.Buffer = lpBuffer; + + RetValue = SearchPathW (NULL == lpPath ? NULL : PathU.Buffer, + NULL == lpFileName ? NULL : FileNameU.Buffer, + NULL == lpExtension ? NULL : ExtensionU.Buffer, + nBufferLength, + BufferU.Buffer, + &FilePartW); + + if (0 != RetValue) + { + BufferU.Length = wcslen(BufferU.Buffer) * sizeof(WCHAR); + /* convert ansi (or oem) string to unicode */ + if (bIsFileApiAnsi) + Status = RtlUnicodeStringToAnsiString(&Buffer, + &BufferU, + FALSE); + else + Status = RtlUnicodeStringToOemString(&Buffer, + &BufferU, + FALSE); + + if (NT_SUCCESS(Status) && Buffer.Buffer) + { + /* nul-terminate ascii string */ + Buffer.Buffer[BufferU.Length / sizeof(WCHAR)] = '\0'; + + if (NULL != lpFilePart && BufferU.Length != 0) + { + *lpFilePart = strrchr (lpBuffer, '\') + 1; + } + } + } + +Cleanup: + RtlFreeHeap (RtlGetProcessHeap (), + 0, + PathU.Buffer); + RtlFreeHeap (RtlGetProcessHeap (), + 0, + FileNameU.Buffer); + RtlFreeHeap (RtlGetProcessHeap (), + 0, + ExtensionU.Buffer); + RtlFreeHeap (RtlGetProcessHeap (), + 0, + BufferU.Buffer); + + if (!NT_SUCCESS(Status)) + { + BaseSetLastNTError(Status); + return 0; + } + + return RetValue; +} + + +/*********************************************************************** + * ContainsPath (Wine name: contains_pathW) + * + * Check if the file name contains a path; helper for SearchPathW. + * A relative path is not considered a path unless it starts with ./ or ../ + */ +static +BOOL +ContainsPath(LPCWSTR name) +{ + if (RtlDetermineDosPathNameType_U(name) != RtlPathTypeRelative) return TRUE; + if (name[0] != '.') return FALSE; + if (name[1] == '/' || name[1] == '\' || name[1] == '\0') return TRUE; + return (name[1] == '.' && (name[2] == '/' || name[2] == '\')); +} + + +/* + * @implemented + */ +DWORD +WINAPI +SearchPathW(LPCWSTR lpPath, + LPCWSTR lpFileName, + LPCWSTR lpExtension, + DWORD nBufferLength, + LPWSTR lpBuffer, + LPWSTR *lpFilePart) +{ + DWORD ret = 0; + + if (!lpFileName || !lpFileName[0]) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + /* If the name contains an explicit path, ignore the path */ + if (ContainsPath(lpFileName)) + { + /* try first without extension */ + if (RtlDoesFileExists_U(lpFileName)) + return GetFullPathNameW(lpFileName, nBufferLength, lpBuffer, lpFilePart); + + if (lpExtension) + { + LPCWSTR p = wcsrchr(lpFileName, '.'); + if (p && !strchr((const char *)p, '/') && !wcschr( p, '\' )) + lpExtension = NULL; /* Ignore the specified extension */ + } + + /* Allocate a buffer for the file name and extension */ + if (lpExtension) + { + LPWSTR tmp; + DWORD len = wcslen(lpFileName) + wcslen(lpExtension); + + if (!(tmp = RtlAllocateHeap(RtlGetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)))) + { + SetLastError(ERROR_OUTOFMEMORY); + return 0; + } + wcscpy(tmp, lpFileName); + wcscat(tmp, lpExtension); + if (RtlDoesFileExists_U(tmp)) + ret = GetFullPathNameW(tmp, nBufferLength, lpBuffer, lpFilePart); + RtlFreeHeap(RtlGetProcessHeap(), 0, tmp); + } + } + else if (lpPath && lpPath[0]) /* search in the specified path */ + { + ret = RtlDosSearchPath_U(lpPath, + lpFileName, + lpExtension, + nBufferLength * sizeof(WCHAR), + lpBuffer, + lpFilePart) / sizeof(WCHAR); + } + else /* search in the default path */ + { + WCHAR *DllPath = GetDllLoadPath(NULL); + + if (DllPath) + { + ret = RtlDosSearchPath_U(DllPath, + lpFileName, + lpExtension, + nBufferLength * sizeof(WCHAR), + lpBuffer, + lpFilePart) / sizeof(WCHAR); + RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath); + } + else + { + SetLastError(ERROR_OUTOFMEMORY); + return 0; + } + } + + if (!ret) SetLastError(ERROR_FILE_NOT_FOUND); + + return ret; +} + +/*********************************************************************** + * @implemented + * + * GetLongPathNameW (KERNEL32.@) + * + * NOTES + * observed (Win2000): + * shortpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0 + * shortpath="": LastError=ERROR_PATH_NOT_FOUND, ret=0 + */ +DWORD WINAPI GetLongPathNameW( LPCWSTR shortpath, LPWSTR longpath, DWORD longlen ) +{ +#define MAX_PATHNAME_LEN 1024 + + WCHAR tmplongpath[MAX_PATHNAME_LEN]; + LPCWSTR p; + DWORD sp = 0, lp = 0; + DWORD tmplen; + BOOL unixabsolute; + WIN32_FIND_DATAW wfd; + HANDLE goit; + + if (!shortpath) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + if (!shortpath[0]) + { + SetLastError(ERROR_PATH_NOT_FOUND); + return 0; + } + + DPRINT("GetLongPathNameW(%s,%p,%ld)\n", shortpath, longpath, longlen); + + if (shortpath[0] == '\' && shortpath[1] == '\') + { + DPRINT1("ERR: UNC pathname %s\n", shortpath); + lstrcpynW( longpath, shortpath, longlen ); + return wcslen(longpath); + } + unixabsolute = (shortpath[0] == '/'); + /* check for drive letter */ + if (!unixabsolute && shortpath[1] == ':' ) + { + tmplongpath[0] = shortpath[0]; + tmplongpath[1] = ':'; + lp = sp = 2; + } + + while (shortpath[sp]) + { + /* check for path delimiters and reproduce them */ + if (shortpath[sp] == '\' || shortpath[sp] == '/') + { + if (!lp || tmplongpath[lp-1] != '\') + { + /* strip double "\" */ + tmplongpath[lp++] = '\'; + } + tmplongpath[lp] = 0; /* terminate string */ + sp++; + continue; + } + + p = shortpath + sp; + if (sp == 0 && p[0] == '.' && (p[1] == '/' || p[1] == '\')) + { + tmplongpath[lp++] = *p++; + tmplongpath[lp++] = *p++; + } + for (; *p && *p != '/' && *p != '\'; p++); + tmplen = p - (shortpath + sp); + lstrcpynW(tmplongpath + lp, shortpath + sp, tmplen + 1); + /* Check if the file exists and use the existing file name */ + goit = FindFirstFileW(tmplongpath, &wfd); + if (goit == INVALID_HANDLE_VALUE) + { + DPRINT("not found %s!\n", tmplongpath); + SetLastError ( ERROR_FILE_NOT_FOUND ); + return 0; + } + FindClose(goit); + wcscpy(tmplongpath + lp, wfd.cFileName); + lp += wcslen(tmplongpath + lp); + sp += tmplen; + } + tmplen = wcslen(shortpath) - 1; + if ((shortpath[tmplen] == '/' || shortpath[tmplen] == '\') && + (tmplongpath[lp - 1] != '/' && tmplongpath[lp - 1] != '\')) + tmplongpath[lp++] = shortpath[tmplen]; + tmplongpath[lp] = 0; + + tmplen = wcslen(tmplongpath) + 1; + if (tmplen <= longlen) + { + wcscpy(longpath, tmplongpath); + DPRINT("returning %s\n", longpath); + tmplen--; /* length without 0 */ + } + + return tmplen; +} + + + +/*********************************************************************** + * GetLongPathNameA (KERNEL32.@) + */ +DWORD WINAPI GetLongPathNameA( LPCSTR shortpath, LPSTR longpath, DWORD longlen ) +{ + WCHAR *shortpathW; + WCHAR longpathW[MAX_PATH]; + DWORD ret; + + DPRINT("GetLongPathNameA %s, %i\n",shortpath,longlen ); + + if (!(shortpathW = FilenameA2W( shortpath, FALSE ))) + return 0; + + ret = GetLongPathNameW(shortpathW, longpathW, MAX_PATH); + + if (!ret) return 0; + if (ret > MAX_PATH) + { + SetLastError(ERROR_FILENAME_EXCED_RANGE); + return 0; + } + + return FilenameW2A_FitOrFail(longpath, longlen, longpathW, ret+1 ); +} + +/* EOF */
Propchange: trunk/reactos/dll/win32/kernel32/client/path.c ------------------------------------------------------------------------------ svn:eol-style = native
Modified: trunk/reactos/dll/win32/kernel32/kernel32.rbuild URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/kernel32... ============================================================================== --- trunk/reactos/dll/win32/kernel32/kernel32.rbuild [iso-8859-1] (original) +++ trunk/reactos/dll/win32/kernel32/kernel32.rbuild [iso-8859-1] Sun Nov 6 02:00:56 2011 @@ -37,6 +37,7 @@ <file>heapmem.c</file> <file>job.c</file> <file>loader.c</file> + <file>path.c</file> <file>perfcnt.c</file> <file>power.c</file> <file>proc.c</file>