windows-nt/Source/XPSP1/NT/shell/osshell/version/ifhelp.c
2020-09-26 16:20:57 +08:00

289 lines
7 KiB
C

#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include "verpriv.h"
#include "wchar.h"
/* Determine if a file is in use by Windows
*/
BOOL FileInUse(LPWSTR lpszFilePath, LPWSTR lpszFileName)
{
HANDLE hFile;
BOOL bResult = FALSE;
//
// Attempt to open the file exclusively.
//
hFile = CreateFile(lpszFilePath,
GENERIC_WRITE | GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE) {
//
// If the last error is access denied,
// then the file is in use by someone
// else. Return TRUE in this case.
//
if (GetLastError() == ERROR_SHARING_VIOLATION)
bResult = TRUE;
} else {
//
// CreateFile successfully opened the file.
// Close the handle and return FALSE.
//
CloseHandle(hFile);
}
return bResult;
}
/* Take a Dir and Filename and make a full path from them
*/
DWORD MakeFileName(LPWSTR lpDst, LPWSTR lpDir, LPWSTR lpFile, int cchDst)
{
DWORD wDirLen;
WCHAR cTemp;
wcsncpy(lpDst, lpDir, cchDst);
lpDst[cchDst-1] = TEXT('\0');
wDirLen=wcslen(lpDst);
if ( wDirLen && (cTemp=*(lpDst+wDirLen-1))!=TEXT('\\') && cTemp!=TEXT(':'))
lpDst[wDirLen++] = TEXT('\\');
wcsncpy(lpDst+wDirLen, lpFile, cchDst - wDirLen);
lpDst[cchDst-1] = TEXT('\0');
return(wDirLen);
}
/* Given a filename and a list of directories, find the first directory
* that contains the file, and copy it into the buffer. Note that in the
* library version, you can give an environment style path, but not in the
* DLL version.
*/
INT
GetDirOfFile(LPWSTR lpszFileName,
LPWSTR lpszPathName,
DWORD wSize,
LPWSTR *lplpszDirs)
{
WCHAR szFileName[_MAX_PATH];
HANDLE hfRes;
INT nFileLen = 0;
INT nPathLen = 0;
BOOL bDoDefaultOpen = TRUE;
LPWSTR *lplpFirstDir;
LPWSTR lpszDir;
nFileLen = wcslen(lpszFileName);
for (lplpFirstDir=lplpszDirs; *lplpFirstDir && bDoDefaultOpen;
++lplpFirstDir)
{
lpszDir = *lplpFirstDir;
if (nFileLen+wcslen(lpszDir) >= _MAX_PATH-1)
continue;
MakeFileName(szFileName, lpszDir, lpszFileName, ARRAYSIZE(szFileName));
TryOpen:
nPathLen = 0; // Re-init for this path.
if ((hfRes = CreateFile(szFileName, GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN, NULL)) != (HANDLE)-1)
{
CloseHandle(hfRes);
for (lpszDir=szFileName; *lpszDir; lpszDir++)
if (*lpszDir == TEXT('\\'))
nPathLen = (INT)(lpszDir - (LPWSTR)szFileName);
/* This gets rid of the '\' if this is not the root of a drive
*/
if (nPathLen <= 3)
++nPathLen;
/* Account for the terminating NULL, and make sure wSize is in bounds
* then NULL terminate the string in the appropriate place so that
* we can just do an wcscpy.
*/
--wSize;
szFileName[(int)wSize<nPathLen ? wSize : nPathLen] = 0;
wcscpy(lpszPathName, szFileName);
return(nPathLen);
}
}
if (bDoDefaultOpen)
{
bDoDefaultOpen = FALSE;
wcscpy(szFileName, lpszFileName);
goto TryOpen;
}
return(0);
}
#define GetWindowsDir(x,y,z) GetWindowsDirectory(y,z)
#define GetSystemDir(x,y,z) GetSystemDirectory(y,z)
DWORD
APIENTRY
VerFindFileW(
DWORD wFlags,
LPWSTR lpszFileName,
LPWSTR lpszWinDir,
LPWSTR lpszAppDir,
LPWSTR lpszCurDir,
PUINT puCurDirLen,
LPWSTR lpszDestDir,
PUINT puDestDirLen
)
{
static WORD wSharedDirLen = 0;
static WCHAR gszSharedDir[_MAX_PATH];
WCHAR szSysDir[_MAX_PATH], cTemp;
WCHAR szWinDir[_MAX_PATH];
WCHAR szCurDir[_MAX_PATH];
LPWSTR lpszDir, lpszDirs[4];
WORD wDestLen, wWinLen, wRetVal = 0, wTemp;
int nRet;
#ifdef WX86
// Save a copy of the 'from Wx86' flag and clear it.
BOOLEAN UseKnownWx86Dll = NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll;
NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll = FALSE;
#endif
/* We want to really look in the Windows directory; we don't trust the app
*/
GetWindowsDir(lpszWinDir ? lpszWinDir : "", szWinDir, _MAX_PATH);
lpszWinDir = szWinDir;
#ifdef WX86
NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll = UseKnownWx86Dll;
#endif
if(!GetSystemDir( lpszWinDir, szSysDir, _MAX_PATH))
wcscpy(szSysDir, lpszWinDir);
#ifdef WX86
NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll = FALSE;
#endif
if (wFlags & VFFF_ISSHAREDFILE) {
lpszDirs[0] = lpszWinDir;
lpszDirs[1] = szSysDir;
lpszDirs[2] = lpszAppDir;
} else {
lpszDirs[0] = lpszAppDir;
lpszDirs[1] = lpszWinDir;
lpszDirs[2] = szSysDir;
}
lpszDirs[3] = NULL;
if (!(wTemp=(WORD)GetDirOfFile(lpszFileName, szCurDir, _MAX_PATH, lpszDirs)))
*szCurDir = 0;
if (*puCurDirLen > wTemp)
wcscpy(lpszCurDir, szCurDir);
else
wRetVal |= VFF_BUFFTOOSMALL;
*puCurDirLen = wTemp + 1;
if (lpszDestDir)
{
if (wFlags & VFFF_ISSHAREDFILE)
{
if (!wSharedDirLen)
{
if ((wWinLen = (WORD)wcslen(lpszWinDir)) &&
*(lpszWinDir-1)==TEXT('\\'))
{
if (szSysDir[wWinLen-1] == TEXT('\\'))
goto doCompare;
}
else if (szSysDir[wWinLen] == TEXT('\\'))
{
doCompare:
cTemp = szSysDir[wWinLen];
szSysDir[wWinLen] = 0;
nRet = _wcsicmp(lpszWinDir, szSysDir);
szSysDir[wWinLen] = cTemp;
if(nRet)
goto doCopyWinDir;
wcscpy(gszSharedDir, szSysDir);
}
else
{
doCopyWinDir:
wcscpy(gszSharedDir, lpszWinDir);
}
wSharedDirLen = (WORD)wcslen(gszSharedDir);
}
wDestLen = wSharedDirLen;
lpszDir = gszSharedDir;
}
else
{
wDestLen = (WORD)wcslen(lpszAppDir);
lpszDir = lpszAppDir;
}
if (*puDestDirLen > wDestLen)
{
wcscpy(lpszDestDir, lpszDir);
if ((wWinLen = (WORD)wcslen(lpszDestDir)) &&
*(lpszDestDir-1)==TEXT('\\'))
lpszDestDir[wWinLen-1] = 0;
if (_wcsicmp(lpszCurDir, lpszDestDir))
wRetVal |= VFF_CURNEDEST;
}
else
wRetVal |= VFF_BUFFTOOSMALL;
*puDestDirLen = wDestLen + 1;
}
if (*szCurDir)
{
MakeFileName(szSysDir, szCurDir, lpszFileName, ARRAYSIZE(szSysDir));
if (FileInUse(szSysDir, lpszFileName))
wRetVal |= VFF_FILEINUSE;
}
return(wRetVal);
}
/*
* DWORD
* APIENTRY
* VerLanguageNameW(
* DWORD wLang,
* LPWSTR szLang,
* DWORD wSize)
*
* This routine was moved to NLSLIB.LIB so that it uses the WINNLS.RC file.
* NLSLIB.LIB is part of KERNEL32.DLL.
*/