411 lines
13 KiB
C
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 |