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

309 lines
9.2 KiB
C

#include "shellprv.h"
#pragma hdrstop
#include <ntimage.h>
#include <ntrtl.h>
static DWORD s_dwThreadIDSuspendNotify = 0;
STDAPI_(BOOL) SuspendSHNotify()
{
DWORD dwID = GetCurrentThreadId();
DWORD dwOldID = InterlockedCompareExchange(&s_dwThreadIDSuspendNotify, dwID, 0);
return (dwOldID == 0);
}
STDAPI_(BOOL) ResumeSHNotify()
{
DWORD dwID = GetCurrentThreadId();
DWORD dwOldID = InterlockedCompareExchange(&s_dwThreadIDSuspendNotify, 0, dwID);
return (dwOldID == dwID);
}
STDAPI_(BOOL) SHMoveFile(LPCTSTR pszExisting, LPCTSTR pszNew, LONG lEvent)
{
BOOL res;
// CreateDirectory fails if the directory name being created does
// not have room for an 8.3 name to be tagged onto the end of it,
// i.e., lstrlen(new_directory_name)+12 must be less or equal to MAX_PATH.
// However, NT does not impose this restriction on MoveFile -- which the
// shell sometimes uses to manipulate directory names. So, in order to
// maintain consistency, we now check the length of the name before we
// move the directory...
if (IsDirPathTooLongForCreateDir(pszNew) &&
(GetFileAttributes(pszExisting) & FILE_ATTRIBUTE_DIRECTORY))
{
SetLastError(ERROR_FILENAME_EXCED_RANGE);
res = FALSE;
}
else
{
res = MoveFile(pszExisting, pszNew);
if (FALSE == res)
{
// If we couldn't move the file, see if it had the readonly or system attributes.
// If so, clear them, move the file, and set them back on the destination
DWORD dwAttributes = GetFileAttributes(pszExisting);
if (-1 != dwAttributes && (dwAttributes & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
{
if (SetFileAttributes(pszExisting, dwAttributes & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
{
res = MoveFile(pszExisting, pszNew);
if (res)
{
SetFileAttributes(pszNew, dwAttributes);
}
else
{
SetFileAttributes(pszExisting, dwAttributes); // if move failed, return attributes.
}
}
}
}
}
if (res && s_dwThreadIDSuspendNotify != GetCurrentThreadId())
{
SHChangeNotify(lEvent, SHCNF_PATH, pszExisting, pszNew);
}
return res;
}
STDAPI_(BOOL) Win32MoveFile(LPCTSTR pszExisting, LPCTSTR pszNew, BOOL fDir)
{
return SHMoveFile(pszExisting, pszNew, fDir ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM);
}
STDAPI_(BOOL) Win32DeleteFilePidl(LPCTSTR pszFileName, LPCITEMIDLIST pidlFile)
{
BOOL res = DeleteFile(pszFileName);
if (FALSE == res)
{
// If we couldn't delete the file, see if it has the readonly or
// system bits set. If so, clear them and try again
DWORD dwAttributes = GetFileAttributes(pszFileName);
if (-1 != dwAttributes && (dwAttributes & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
{
if (SetFileAttributes(pszFileName, dwAttributes & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
{
res = DeleteFile(pszFileName);
}
}
}
if (res && s_dwThreadIDSuspendNotify != GetCurrentThreadId())
{
if (pidlFile)
{
SHChangeNotify(SHCNE_DELETE, SHCNF_IDLIST, pidlFile, NULL);
}
else
{
SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, pszFileName, NULL);
}
}
return res;
}
STDAPI_(BOOL) Win32DeleteFile(LPCTSTR pszFileName)
{
return Win32DeleteFilePidl(pszFileName, NULL);
}
STDAPI_(BOOL) Win32CreateDirectory(LPCTSTR pszPath, LPSECURITY_ATTRIBUTES lpsa)
{
BOOL res = CreateDirectory(pszPath, lpsa);
if (res && s_dwThreadIDSuspendNotify != GetCurrentThreadId())
{
SHChangeNotify(SHCNE_MKDIR, SHCNF_PATH, pszPath, NULL);
}
return res;
}
//
// Some filesystems (like NTFS, perchance) actually pay attention to
// the readonly bit on folders. So, in order to pretend we're sort of
// FAT and dumb, we clear the attribute before trying to delete the
// directory.
//
STDAPI_(BOOL) Win32RemoveDirectory(LPCTSTR pszDir)
{
BOOL res = RemoveDirectory(pszDir);
if (FALSE == res)
{
DWORD dwAttr = GetFileAttributes(pszDir);
if ((-1 != dwAttr) && (dwAttr & FILE_ATTRIBUTE_READONLY))
{
dwAttr &= ~FILE_ATTRIBUTE_READONLY;
SetFileAttributes(pszDir, dwAttr);
res = RemoveDirectory(pszDir);
}
}
if (res && s_dwThreadIDSuspendNotify != GetCurrentThreadId())
{
SHChangeNotify(SHCNE_RMDIR, SHCNF_PATH, pszDir, NULL);
}
return res;
}
STDAPI_(HANDLE) Win32CreateFile(LPCTSTR pszFileName, DWORD dwAttrib)
{
HANDLE hFile = CreateFile(pszFileName, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, CREATE_ALWAYS, dwAttrib & FILE_ATTRIBUTE_VALID_FLAGS,
NULL);
if (INVALID_HANDLE_VALUE != hFile && s_dwThreadIDSuspendNotify != GetCurrentThreadId())
{
SHChangeNotify(SHCNE_CREATE, SHCNF_PATH, pszFileName, NULL);
}
return hFile;
}
STDAPI_(BOOL) CreateWriteCloseFile(HWND hwnd, LPCTSTR pszFile, void *pData, DWORD cbData)
{
BOOL bRet;
HANDLE hfile = Win32CreateFile(pszFile, 0);
if (hfile != INVALID_HANDLE_VALUE)
{
if (cbData)
{
DWORD dwBytesWritten;
WriteFile(hfile, pData, cbData, &dwBytesWritten, 0);
}
CloseHandle(hfile);
bRet = TRUE;
}
else
{
TCHAR szPath[MAX_PATH];
lstrcpyn(szPath, pszFile, ARRAYSIZE(szPath));
PathRemoveExtension(szPath);
SHSysErrorMessageBox(hwnd, NULL, IDS_CANNOTCREATEFILE,
GetLastError(), PathFindFileName(szPath),
MB_OK | MB_ICONEXCLAMATION);
bRet = FALSE;
}
return bRet;
}
#undef SHGetProcessDword
STDAPI_(DWORD) SHGetProcessDword(DWORD idProcess, LONG iIndex)
{
return 0;
}
STDAPI_(BOOL) SHSetShellWindowEx(HWND hwnd, HWND hwndChild)
{
return SetShellWindowEx(hwnd, hwndChild);
}
#define ISEXETSAWARE_MAX_IMAGESIZE (4 * 1024) // allocate at most a 4k block to hold the image header (eg 1 page on x86)
//
// this is a function that takes a full path to an executable and returns whether or not
// the exe has the TS_AWARE bit set in the image header
//
STDAPI_(BOOL) IsExeTSAware(LPCTSTR pszExe)
{
BOOL bRet = FALSE;
HANDLE hFile = CreateFile(pszExe,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
DWORD cbImageSize = GetFileSize(hFile, NULL);
LPBYTE pBuffer;
if (cbImageSize > ISEXETSAWARE_MAX_IMAGESIZE)
{
// 64k should be enough to get the image header for everything...
cbImageSize = ISEXETSAWARE_MAX_IMAGESIZE;
}
pBuffer = LocalAlloc(LPTR, cbImageSize);
if (pBuffer)
{
HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY | SEC_IMAGE, 0, cbImageSize, NULL);
if (hMap)
{
// map the first 4k of the file in
LPBYTE pFileMapping = (LPBYTE)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, cbImageSize);
if (pFileMapping)
{
_try
{
memcpy(pBuffer, pFileMapping, cbImageSize);
}
_except(UnhandledExceptionFilter(GetExceptionInformation()))
{
// We hit an exception while copying! doh!
LocalFree(pBuffer);
pBuffer = NULL;
}
UnmapViewOfFile(pFileMapping);
}
else
{
LocalFree(pBuffer);
pBuffer = NULL;
}
CloseHandle(hMap);
}
else
{
LocalFree(pBuffer);
pBuffer = NULL;
}
if (pBuffer)
{
PIMAGE_NT_HEADERS pImageNTHeader;
// NOTE: this should work ok for 64-bit images too, since both the IMAGE_NT_HEADERS and the IMAGE_NT_HEADERS64
// structs have a ->Signature and ->OptionalHeader that is identical up to the DllCharacteristics offset.
pImageNTHeader = RtlImageNtHeader(pBuffer);
if (pImageNTHeader)
{
if (pImageNTHeader->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE)
{
// yes, this is a TSAWARE executable!
bRet = TRUE;
}
}
LocalFree(pBuffer);
}
}
CloseHandle(hFile);
}
return bRet;
}