/*++ Function : PAL_GetPALDirectoryW Returns the fully qualified path name where the PALL DLL was loaded from. On failure it returns FALSE and sets the proper LastError code. --*/ BOOL PAL_GetPALDirectoryW(PathWCharString& lpDirectoryName) { LPCWSTR lpFullPathAndName = NULL; LPCWSTR lpEndPoint = NULL; BOOL bRet = FALSE; PERF_ENTRY(PAL_GetPALDirectoryW); MODSTRUCT *module = LOADGetPalLibrary(); if (!module) { SetLastError(ERROR_INTERNAL_ERROR); goto EXIT; } lpFullPathAndName = module->lib_name; if (lpFullPathAndName == NULL) { SetLastError(ERROR_INTERNAL_ERROR); goto EXIT; } lpEndPoint = PAL_wcsrchr( lpFullPathAndName, '/' ); if ( lpEndPoint ) { /* The path that we return is required to have the trailing slash on the end.*/ lpEndPoint++; if(!lpDirectoryName.Set(lpFullPathAndName,lpEndPoint - lpFullPathAndName)) { ASSERT( "The buffer was not large enough.\n" ); SetLastError( ERROR_INSUFFICIENT_BUFFER ); goto EXIT; } bRet = TRUE; } else { ASSERT( "Unable to determine the path.\n" ); /* Error path, should not be executed. */ SetLastError( ERROR_INTERNAL_ERROR ); } EXIT: PERF_EXIT(PAL_GetPALDirectoryW); return bRet; }
/*++ Function: _wsplitpath See MSDN doc. Notes : This implementation ignores drive letters as they should not be present. If the drive argument is non-NULL, it always returns an empty string. File names in which the only period is at the beginning (like .bashrc, but not .bashrc.bak), the file is treated as having no extension (fname is ".bashrc", ext is "") --*/ void __cdecl _wsplitpath( const wchar_16 *dospath, wchar_16 *drive, wchar_16 *dir, wchar_16 *fname, wchar_16 *ext) { WCHAR path[_MAX_PATH+1]; LPCWSTR slash_ptr = NULL; LPCWSTR period_ptr = NULL; INT size = 0; PERF_ENTRY(_wsplitpath); ENTRY("_wsplitpath (path=%p (%S), drive=%p, dir=%p, fname=%p, ext=%p)\n", path?path:W16_NULLSTRING, path?path:W16_NULLSTRING, drive, dir, fname, ext); /* Do performance intensive error checking only in debug builds. NOTE: This function must fail predictably across all platforms. Under Windows this function throw an access violation if NULL was passed in as the value for path. */ #if _DEBUG if ( !dospath ) { ERROR( "path cannot be NULL!\n" ); } #endif if( lstrlenW( dospath ) >= _MAX_PATH ) { ERROR("Path length is > _MAX_PATH (%d)!\n", _MAX_PATH); ON_ERROR; } PAL_wcscpy(path, dospath); FILEDosToUnixPathW(path); /* no drive letters in the PAL */ if( drive != NULL ) { drive[0] = 0; } /* find last path separator char */ slash_ptr = PAL_wcsrchr(path, '/'); if( slash_ptr == NULL ) { TRACE("No path separator in path\n"); slash_ptr = path - 1; } /* find extension separator, if any */ period_ptr = PAL_wcsrchr(path, '.'); /* make sure we only consider periods after the last path separator */ if( period_ptr < slash_ptr ) { period_ptr = NULL; } /* if the only period in the file is a leading period (denoting a hidden file), don't treat what follows as an extension */ if( period_ptr == slash_ptr+1 ) { period_ptr = NULL; } if( period_ptr == NULL ) { TRACE("No extension in path\n"); period_ptr = path + lstrlenW(path); } size = slash_ptr - path + 1; if( dir != NULL ) { INT i; if( (size + 1 ) > _MAX_DIR ) { ERROR("Directory component needs %d characters, _MAX_DIR is %d\n", size+1, _MAX_DIR); ON_ERROR; } memcpy(dir, path, size*sizeof(WCHAR)); dir[size] = 0; /* only allow / separators in returned path */ i = 0; while( dir[ i ] ) { if( dir[ i ] == '\\' ) { dir[i]='/'; } i++; } } size = period_ptr-slash_ptr-1; if( fname != NULL ) { if( (size+1) > _MAX_FNAME ) { ERROR("Filename component needs %d characters, _MAX_FNAME is %d\n", size+1, _MAX_FNAME); ON_ERROR; } memcpy(fname, slash_ptr+1, size*sizeof(WCHAR)); fname[size] = 0; } size = 1 + lstrlenW( period_ptr ); if( ext != NULL ) { if( size > _MAX_EXT ) { ERROR("Extension component needs %d characters, _MAX_EXT is %d\n", size, _MAX_EXT); ON_ERROR; } memcpy(ext, period_ptr, size*sizeof(WCHAR)); ext[size-1] = 0; } TRACE("Path components are '%S' '%S' '%S'\n", dir, fname, ext); done: LOGEXIT("_wsplitpath returns.\n"); PERF_EXIT(_wsplitpath); }
/*++ Function: SearchPathW See MSDN doc. PAL-specific notes : -lpPath must be non-NULL; path delimiters are platform-dependent (':' for Unix) -lpFileName must be non-NULL, may be an absolute path -lpExtension must be NULL -lpFilePart (if non-NULL) doesn't need to be used (but we do) --*/ DWORD PALAPI SearchPathW( IN LPCWSTR lpPath, IN LPCWSTR lpFileName, IN LPCWSTR lpExtension, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart ) { DWORD nRet = 0; WCHAR FullPath[MAX_PATH]; LPCWSTR pPathStart; LPCWSTR pPathEnd; size_t PathLength; size_t FileNameLength; DWORD dw; char AnsiPath[MAX_PATH]; WCHAR CanonicalPath[MAX_PATH]; PERF_ENTRY(SearchPathW); ENTRY("SearchPathW(lpPath=%p (%S), lpFileName=%p (%S), lpExtension=%p, " "nBufferLength=%u, lpBuffer=%p, lpFilePart=%p)\n", lpPath, lpPath, lpFileName, lpFileName, lpExtension, nBufferLength, lpBuffer, lpFilePart); /* validate parameters */ if(NULL == lpPath) { ASSERT("lpPath may not be NULL\n"); SetLastError(ERROR_INVALID_PARAMETER); goto done; } if(NULL == lpFileName) { ASSERT("lpFileName may not be NULL\n"); SetLastError(ERROR_INVALID_PARAMETER); goto done; } if(NULL != lpExtension) { ASSERT("lpExtension must be NULL, is %p instead\n", lpExtension); SetLastError(ERROR_INVALID_PARAMETER); goto done; } /* special case : if file name contains absolute path, don't search the provided path */ if('\\' == lpFileName[0] || '/' == lpFileName[0]) { /* Canonicalize the path to deal with back-to-back '/', etc. */ dw = GetFullPathNameW(lpFileName, MAX_PATH, CanonicalPath, NULL); if (dw == 0 || dw >= MAX_PATH) { WARN("couldn't canonicalize path <%S>, error is %#x. failing.\n", lpPath, GetLastError()); SetLastError(ERROR_INVALID_PARAMETER); goto done; } /* see if the file exists */ WideCharToMultiByte(CP_ACP, 0, CanonicalPath, -1, AnsiPath, MAX_PATH, NULL, NULL); if(0 == access(AnsiPath, F_OK)) { /* found it */ nRet = dw; } } else { LPCWSTR pNextPath; pNextPath = lpPath; FileNameLength = PAL_wcslen(lpFileName); while (*pNextPath) { pPathStart = pNextPath; /* get a pointer to the end of the first path in pPathStart */ pPathEnd = PAL_wcschr(pPathStart, ':'); if (!pPathEnd) { pPathEnd = pPathStart + PAL_wcslen(pPathStart); /* we want to break out of the loop after this pass, so let *pNextPath be '\0' */ pNextPath = pPathEnd; } else { /* point to the next component in the path string */ pNextPath = pPathEnd+1; } PathLength = pPathEnd-pPathStart; if (PathLength+FileNameLength+1 >= MAX_PATH) { /* The path+'/'+file length is too long. Skip it. */ WARN("path component %.*S is too long, skipping it\n", (int)PathLength, pPathStart); continue; } else if(0 == PathLength) { /* empty component : there were 2 consecutive ':' */ continue; } /* Construct a pathname by concatenating one path from lpPath, '/' and lpFileName */ memcpy(FullPath, pPathStart, PathLength*sizeof(WCHAR)); FullPath[PathLength] = '/'; PAL_wcscpy(&FullPath[PathLength+1], lpFileName); /* Canonicalize the path to deal with back-to-back '/', etc. */ dw = GetFullPathNameW(FullPath, MAX_PATH, CanonicalPath, NULL); if (dw == 0 || dw >= MAX_PATH) { /* Call failed - possibly low memory. Skip the path */ WARN("couldn't canonicalize path <%S>, error is %#x. " "skipping it\n", FullPath, GetLastError()); continue; } /* see if the file exists */ WideCharToMultiByte(CP_ACP, 0, CanonicalPath, -1, AnsiPath, MAX_PATH, NULL, NULL); if(0 == access(AnsiPath, F_OK)) { /* found it */ nRet = dw; break; } } } if (nRet == 0) { /* file not found anywhere; say so. in Windows, this always seems to say FILE_NOT_FOUND, even if path doesn't exist */ SetLastError(ERROR_FILE_NOT_FOUND); } else { /* find out the required buffer size, copy path to buffer if it's large enough */ nRet = PAL_wcslen(CanonicalPath)+1; if(nRet <= nBufferLength) { if(NULL == lpBuffer) { /* Windows merily crashes here, but let's not */ ERROR("caller told us buffer size was %d, but buffer is NULL\n", nBufferLength); SetLastError(ERROR_INVALID_PARAMETER); nRet = 0; goto done; } PAL_wcscpy(lpBuffer, CanonicalPath); /* don't include the null-terminator in the count if buffer was large enough */ nRet--; if(NULL != lpFilePart) { *lpFilePart = PAL_wcsrchr(lpBuffer, '/'); if(NULL == *lpFilePart) { ASSERT("no '/' in full path!\n"); } else { /* point to character after last '/' */ (*lpFilePart)++; } } } } done: LOGEXIT("SearchPathW returns DWORD %u\n", nRet); PERF_EXIT(SearchPathW); return nRet; }
/*++ Function : PAL_GetPALDirectoryW Returns the fully qualified path name where the PALL DLL was loaded from. On failure it returns FALSE and sets the proper LastError code. See rotor_pal.doc for more details. --*/ BOOL PALAPI PAL_GetPALDirectoryW( OUT LPWSTR lpDirectoryName, IN UINT cchDirectoryName ) { LPWSTR lpFullPathAndName = NULL; LPWSTR lpEndPoint = NULL; BOOL bRet = FALSE; PERF_ENTRY(PAL_GetPALDirectoryW); ENTRY( "PAL_GetPALDirectoryW( %p, %d )\n", lpDirectoryName, cchDirectoryName ); MODSTRUCT *module = LOADGetPalLibrary(); if (!module) { SetLastError(ERROR_INTERNAL_ERROR); goto EXIT; } lpFullPathAndName = module->lib_name; if (lpFullPathAndName == NULL) { SetLastError(ERROR_INTERNAL_ERROR); goto EXIT; } lpEndPoint = PAL_wcsrchr( lpFullPathAndName, '/' ); if ( lpEndPoint ) { /* The path that we return is required to have the trailing slash on the end.*/ lpEndPoint++; } if ( lpFullPathAndName && lpEndPoint && *lpEndPoint != '\0' ) { while ( cchDirectoryName - 1 && lpFullPathAndName != lpEndPoint ) { *lpDirectoryName = *lpFullPathAndName; lpFullPathAndName++; lpDirectoryName++; cchDirectoryName--; } if ( lpFullPathAndName == lpEndPoint ) { *lpDirectoryName = '\0'; bRet = TRUE; goto EXIT; } else { ASSERT( "The buffer was not large enough.\n" ); SetLastError( ERROR_INSUFFICIENT_BUFFER ); goto EXIT; } } else { ASSERT( "Unable to determine the path.\n" ); } /* Error path, should not be executed. */ SetLastError( ERROR_INTERNAL_ERROR ); EXIT: LOGEXIT( "PAL_GetPALDirectoryW returns BOOL %d.\n", bRet); PERF_EXIT(PAL_GetPALDirectoryW); return bRet; }