Windows2000/private/shell/shell32/futil.c
2020-09-30 17:12:32 +02:00

411 lines
13 KiB
C

#include "shellprv.h"
#pragma hdrstop
#include "netview.h"
// drivesx.c
DWORD PathGetClusterSize(LPCTSTR pszPath);
// mtpt.cpp
STDAPI_(void) CMtPt_InvalidateAllMtPts();
STDAPI_(void) CMtPt_InvalidateDriveType(int iDrive);
const TCHAR c_szAutoRun[] = TEXT("AutoRun");
static int rgiDriveType[26] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1
};
// A corresponding array which indicates whether or not the drivetype cache has the LFN and ACL bits.
static int rgiHasNetFlags[26] = { 0 };
// get connection information including disconnected drives
// in:
// lpDev device name "A:" "LPT1:", etc.
// bConvertClosed
// if FALSE closed or error drives will be converted to WN_SUCCESS return codes.
// if TRUE return not connected and error state values (ie, the caller knows about not connected and error state drives)
// BUGBUG: we need to add cbPath to the output buffer
// out:
// lpPath filled with net name if return is WN_SUCCESS (or not connected/error)
// returns:
// WN_* error code
DWORD GetConnection(LPCTSTR lpDev, LPTSTR lpPath, UINT cchPath, BOOL bConvertClosed)
{
DWORD err;
int iType;
iType = DriveType(DRIVEID(lpDev));
if (iType == DRIVE_CDROM)
return WN_NOT_CONNECTED;
err = SHWNetGetConnection((LPTSTR)lpDev, lpPath, &cchPath);
if (!bConvertClosed)
if (err == WN_CONNECTION_CLOSED || err == WN_DEVICE_ERROR)
err = WN_SUCCESS;
return err;
}
// this is called for every drive at init time so it must be sure to not trigget things like the phantom B: drive support
// in:
// iDrive zero based drive number (0 = A, 1 = B)
// returns:
// 0 not a net drive
// 1 is a net drive, properly connected
// 2 disconnected/error state connection
int WINAPI IsNetDrive(int iDrive)
{
DWORD err;
TCHAR szDrive[4];
TCHAR szConn[MAX_PATH]; // this really should be WNBD_MAX_LENGTH
// but this change would have to be many everywhere
if ((iDrive >= 0) && (iDrive < 26))
{
PathBuildRoot(szDrive, iDrive);
err = GetConnection(szDrive, szConn, ARRAYSIZE(szConn), TRUE);
if (err == WN_SUCCESS)
return 1;
if (err == WN_CONNECTION_CLOSED || err == WN_DEVICE_ERROR)
if ((GetLogicalDrives() & (1 << iDrive)) == 0)
return 2;
}
return 0;
}
typedef BOOL (WINAPI* PFNISPATHSHARED)(IN LPCTSTR lpPath,IN BOOL fRefresh);
#ifdef UNICODE
#define SHARE_ENTRY "IsPathSharedW" // Win NT UNICODE
#else // UNICODE
#ifdef WINNT
#define SHARE_ENTRY "IsPathSharedA" // Win NT Ansi
#else // WINNT
#define SHARE_ENTRY "IsPathShared" // Win 95
#endif // WINNT
#endif // UNICODE
HMODULE g_hmodShare = (HMODULE)-1;
PFNISPATHSHARED g_pfnIsPathShared = NULL;
// ask the share provider if this path is shared
BOOL IsShared(LPNCTSTR pszPath, BOOL fUpdateCache)
{
TCHAR szPath[MAX_PATH];
// See if we have already tried to load this in this context
if (g_hmodShare == (HMODULE)-1)
{
LONG cb = SIZEOF(szPath);
g_hmodShare = NULL; // asume failure
SHRegQueryValue(HKEY_CLASSES_ROOT, TEXT("Network\\SharingHandler"), szPath, &cb);
if (szPath[0])
{
g_hmodShare = LoadLibrary(szPath);
if (g_hmodShare)
g_pfnIsPathShared = (PFNISPATHSHARED)GetProcAddress(g_hmodShare, SHARE_ENTRY);
}
}
if (g_pfnIsPathShared)
{
#ifdef ALIGNMENT_SCENARIO
ualstrcpyn(szPath, pszPath, ARRAYSIZE(szPath));
return g_pfnIsPathShared(szPath, fUpdateCache);
#else
return g_pfnIsPathShared(pszPath, fUpdateCache);
#endif
}
return FALSE;
}
// invalidate the DriveType cache for one entry, or all
void WINAPI InvalidateDriveType(int iDrive)
{
if (iDrive < 0)
{
// invalidate all drives
#ifndef DEBUG
RegDeleteKey(HKEY_CLASSES_ROOT, c_szAutoRun);
#endif
// Clear these values under the critical section, so any pair will always be in sync
CMtPt_InvalidateAllMtPts();
}
else if (iDrive < 26)
{
TCHAR szDrive[10];
SHFILEINFO sfi;
int iIcon=0;
// invalidate a single drive, if the icon for a drive changes send a notify so links can update..
// Handle the case where the drive was a unavailable net drive...
if ((rgiDriveType[iDrive] != -1) && ((rgiDriveType[iDrive] & ~DRIVE_TYPE) != ~DRIVE_TYPE) && (((rgiDriveType[iDrive] & DRIVE_TYPE) >= DRIVE_REMOVABLE) || (rgiDriveType[iDrive] & DRIVE_NETUNAVAIL)))
{
PathBuildRoot(szDrive, iDrive);
SHGetFileInfo(szDrive, 0, &sfi, SIZEOF(sfi), SHGFI_SYSICONINDEX);
iIcon = sfi.iIcon;
}
// Clear these values under the critical section, so they'll always be in sync with each other
CMtPt_InvalidateDriveType(iDrive);
if (iIcon != 0)
{
SHGetFileInfo(szDrive, 0, &sfi, SIZEOF(sfi), SHGFI_SYSICONINDEX);
if (iIcon != sfi.iIcon && (rgiDriveType[iDrive] & ~DRIVE_TYPE) != ~DRIVE_TYPE && (rgiDriveType[iDrive] & DRIVE_TYPE) >= DRIVE_REMOVABLE)
{
TraceMsg(TF_PATH, "InvalidateDriveType: sending icon change for %s (%d => %d)", szDrive, iIcon, sfi.iIcon);
SHChangeNotify(SHCNE_UPDATEIMAGE, SHCNF_DWORD, (LPCVOID)IntToPtr( iIcon ), NULL);
}
}
}
}
#ifdef TRACK_DEFAULT_DRIVE
// we may want to instance this data in the future
// so keep it in this structure
typedef struct {
PHASHITEM rphiPaths[27]; // [26] is for the no default drive case
int iDefaultDrive;
} CURRENTDIR_DATA, *LPCURRENTDIR_DATA;
CURRENTDIR_DATA cdd = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, -1
};
// returns:
// the default drive 0 = A, 1 = B, 2 = C... or
// -1 if the default is a UNC type name (no drive associated)
// if no default was previously set the
// window drive is used as the default
int WINAPI GetDefaultDrive(void)
{
return cdd.iDefaultDrive;
}
// in:
// iDrive number 0 = A, 1 = B, 2 = C to set as default
// -1 for no default drive (UNC name is default)
// returns:
// previous default drive
int WINAPI SetDefaultDrive(int iDrive)
{
int iOldDrive;
iOldDrive = GetDefaultDrive();
if (iDrive >= 0 && iDrive < 26)
cdd.iDefaultDrive = iDrive;
else
cdd.iDefaultDrive = -1;
return iOldDrive;
}
// in:
// iDrive 0 = A, 1 = B, ... or
// -1 for UNC type path
// returns:
// lpPath fully qualified path (ANSI string)
void WINAPI GetDefaultDirectory(int iDrive, LPTSTR lpPath)
{
if (iDrive < 0 || iDrive >= 26)
iDrive = 26;
if (cdd.rphiPaths[iDrive])
GetHashItemName(NULL, cdd.rphiPaths[iDrive], lpPath, MAX_PATH);
else
PathBuildRoot(lpPath, iDrive);
}
// in:
// lpPath fully qualified path (ANSI string)
// note:
// this does not set the default drive, if you need to change that it must be done explicitly
int WINAPI SetDefaultDirectory(LPCTSTR lpPath)
{
PHASHITEM phiPath;
int iDrive;
iDrive = DRIVEID(lpPath);
if (iDrive < 0 || iDrive >= 26)
iDrive = 26;
phiPath = AddHashItem(NULL, lpPath);
if (phiPath) {
if (cdd.rphiPaths[iDrive])
DeleteHashItem(NULL, cdd.rphiPaths[iDrive]);
cdd.rphiPaths[iDrive] = phiPath;
return TRUE;
}
return FALSE;
}
#endif
#ifdef WINNT
#define ROUND_TO_CLUSER(qw, dwCluster) ((((qw) + (dwCluster) - 1) / dwCluster) * dwCluster)
// GetCompresedFileSize is NT only, so we only implement the SHGetCompressedFileSizeW version.
// This will return the size of the file on disk rounded to the cluster size.
STDAPI_(DWORD) SHGetCompressedFileSizeW(LPCWSTR pszFileName, LPDWORD pFileSizeHigh)
{
DWORD dwClusterSize;
ULARGE_INTEGER ulSizeOnDisk;
if (!pszFileName || !pszFileName[0])
{
ASSERT(FALSE);
*pFileSizeHigh = 0;
return 0;
}
dwClusterSize = PathGetClusterSize(pszFileName);
ulSizeOnDisk.LowPart = GetCompressedFileSizeW(pszFileName, &ulSizeOnDisk.HighPart);
if ((ulSizeOnDisk.LowPart == (DWORD)-1) && (GetLastError() != NO_ERROR))
{
WIN32_FILE_ATTRIBUTE_DATA fad;
TraceMsg(TF_WARNING, "GetCompressedFileSize failed on %s (lasterror = %x)", pszFileName, GetLastError());
if (GetFileAttributesExW(pszFileName, GetFileExInfoStandard, &fad))
{
// use the normal size, but round it to the cluster size
ulSizeOnDisk.LowPart = fad.nFileSizeLow;
ulSizeOnDisk.HighPart = fad.nFileSizeHigh;
ROUND_TO_CLUSER(ulSizeOnDisk.QuadPart, dwClusterSize);
}
else
{
// since both GetCompressedFileSize and GetFileAttributesEx failed, we just return zero
ulSizeOnDisk.QuadPart = 0;
}
}
// for files < one cluster, GetCompressedFileSize returns real size so we need to round it up to one cluster
if (ulSizeOnDisk.QuadPart < dwClusterSize)
{
ulSizeOnDisk.QuadPart = dwClusterSize;
}
*pFileSizeHigh = ulSizeOnDisk.HighPart;
return ulSizeOnDisk.LowPart;
}
#endif
// if we are not on NT, we need a fn pointer so we can try to getprocaddress GetDiskFreeSpaceExA.
#ifndef WINNT
// Make sure this is perinstance
#pragma data_seg(DATASEG_PERINSTANCE)
typedef BOOL (*PFNGETDISKFREESPACEEXA)(LPCSTR lpDirectoryName, PULARGE_INTEGER lpFreeBytesAvailableToCaller, PULARGE_INTEGER lpTotalNumberOfBytes, PULARGE_INTEGER lpTotalNumberOfFreeBytes);
PFNGETDISKFREESPACEEXA g_pfnGetDiskFreeSpaceExA = (PFNGETDISKFREESPACEEXA)-1;
#pragma data_seg()
#endif // not WINNT
STDAPI_(BOOL) SHGetDiskFreeSpaceEx(LPCTSTR pszDirectoryName, PULARGE_INTEGER pulFreeBytesAvailableToCaller, PULARGE_INTEGER pulTotalNumberOfBytes, PULARGE_INTEGER pulTotalNumberOfFreeBytes)
{
#ifdef WINNT
// on NT just call the real API
return GetDiskFreeSpaceEx(pszDirectoryName, pulFreeBytesAvailableToCaller, pulTotalNumberOfBytes, pulTotalNumberOfFreeBytes);
#else
// this case is implicitly ANSI, since we are not running on NT.
// We will be call the ANSI GetDiskFreeSpaceEx if it exists.
// If it does not exist (meaning we are running on win95 gold), we call the old GetDiskFreeSpace and do the math.
if (g_pfnGetDiskFreeSpaceExA == (PFNGETDISKFREESPACEEXA) -1)
{
HMODULE hmod = GetModuleHandle(TEXT("KERNEL32"));
if (hmod)
g_pfnGetDiskFreeSpaceExA = (PFNGETDISKFREESPACEEXA)GetProcAddress(hmod, "GetDiskFreeSpaceExA");
else
g_pfnGetDiskFreeSpaceExA = NULL;
}
if (g_pfnGetDiskFreeSpaceExA)
{
// found the real API, so use it
return g_pfnGetDiskFreeSpaceExA(pszDirectoryName, pulFreeBytesAvailableToCaller, pulTotalNumberOfBytes, pulTotalNumberOfFreeBytes);
}
else
{
// could not find a GetDiskFreeSpaceExA in kernel32, must be on
// win95 gold (not OSR2 or later...), need to do the math
DWORD dwSectorsPerCluster;
DWORD dwBytesPerSector;
DWORD dwNumberOfFreeClusters;
DWORD dwTotalNumberOfClusters;
if (GetDiskFreeSpaceA(pszDirectoryName, &dwSectorsPerCluster, &dwBytesPerSector, &dwNumberOfFreeClusters, &dwTotalNumberOfClusters))
{
pulTotalNumberOfBytes->QuadPart = ((ULONGLONG)dwTotalNumberOfClusters) * ((ULONGLONG)dwSectorsPerCluster) * ((ULONGLONG)dwBytesPerSector);
pulTotalNumberOfFreeBytes->QuadPart = ((ULONGLONG)dwNumberOfFreeClusters) * ((ULONGLONG)dwSectorsPerCluster) * ((ULONGLONG)dwBytesPerSector);
// we are on win95, so NO quotas
pulFreeBytesAvailableToCaller->QuadPart = pulTotalNumberOfFreeBytes->QuadPart;
return TRUE;
}
return FALSE;
}
#endif
}
#ifdef UNICODE
BOOL SHGetDiskFreeSpaceExA(LPCSTR pszDirectoryName, PULARGE_INTEGER pulFreeBytesAvailableToCaller, PULARGE_INTEGER pulTotalNumberOfBytes, PULARGE_INTEGER pulTotalNumberOfFreeBytes)
{
WCHAR wszDirectoryName[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, pszDirectoryName, -1, wszDirectoryName, SIZECHARS(wszDirectoryName));
return SHGetDiskFreeSpaceEx(wszDirectoryName, pulFreeBytesAvailableToCaller, pulTotalNumberOfBytes, pulTotalNumberOfFreeBytes);
}
#else
BOOL SHGetDiskFreeSpaceExW(LPCWSTR pszDirectoryName, PULARGE_INTEGER pulFreeBytesAvailableToCaller, PULARGE_INTEGER pulTotalNumberOfBytes, PULARGE_INTEGER pulTotalNumberOfFreeBytes)
{
CHAR aszDirectoryName[MAX_PATH];
SHUnicodeToAnsi(pszDirectoryName, aszDirectoryName, SIZECHARS(aszDirectoryName));
return SHGetDiskFreeSpaceEx(aszDirectoryName, pulFreeBytesAvailableToCaller, pulTotalNumberOfBytes, pulTotalNumberOfFreeBytes);
}
#endif