1887 lines
53 KiB
C
1887 lines
53 KiB
C
/*++
|
||
|
||
Copyright (c) 1994 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
DirUtils.C
|
||
|
||
Abstract:
|
||
|
||
directory, file, filename and network utility functions.
|
||
|
||
Author:
|
||
|
||
Bob Watson (a-robw)
|
||
|
||
Revision History:
|
||
|
||
24 Jun 94 Written
|
||
|
||
--*/
|
||
//
|
||
// Windows Include Files
|
||
//
|
||
|
||
#include <windows.h>
|
||
#include <stdio.h>
|
||
#include <malloc.h>
|
||
#include <tchar.h> // unicode macros
|
||
#include <stdlib.h> // string to number conversions
|
||
#include <lmcons.h> // lanman API constants
|
||
#include <lmerr.h> // lanman error returns
|
||
#include <lmshare.h> // sharing API prototypes
|
||
#include <lmapibuf.h> // lanman buffer API prototypes
|
||
#include <commdlg.h> // common dialog include
|
||
//
|
||
// app include files
|
||
//
|
||
#include "otnboot.h"
|
||
#include "otnbtdlg.h"
|
||
|
||
LPCTSTR
|
||
GetRootFromPath (
|
||
IN LPCTSTR szPath
|
||
)
|
||
{
|
||
static TCHAR szReturnBuffer[MAX_PATH];
|
||
LPTSTR szNextChar;
|
||
LONG lIndex;
|
||
|
||
if (IsUncPath(szPath)) {
|
||
// return server & share
|
||
lstrcpy (szReturnBuffer, cszDoubleBackslash);
|
||
szNextChar = &szReturnBuffer[2];
|
||
if (GetServerFromUnc (szPath, szNextChar)) {
|
||
lstrcat (szReturnBuffer, cszBackslash);
|
||
szNextChar = &szReturnBuffer[lstrlen(szReturnBuffer)];
|
||
if (GetShareFromUnc(szPath, szNextChar)) {
|
||
// append trailing backslash
|
||
lstrcat (szReturnBuffer, cszBackslash);
|
||
} else {
|
||
szReturnBuffer[0] = 0;
|
||
}
|
||
} else {
|
||
szReturnBuffer[0] = 0;
|
||
}
|
||
} else {
|
||
// dos path name
|
||
for (lIndex = 0; lIndex < 3; lIndex++) {
|
||
if (szPath[lIndex] > cSpace) {
|
||
szReturnBuffer[lIndex] = szPath[lIndex];
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
szReturnBuffer[lIndex] = 0;
|
||
}
|
||
return (LPCTSTR)&szReturnBuffer[0];
|
||
}
|
||
|
||
BOOL
|
||
GetShareFromUnc (
|
||
IN LPCTSTR szPath,
|
||
OUT LPTSTR szShare
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Parses a UNC path name and returns the Sharepoint name in the buffer
|
||
supplied by the caller. The buffer size is not checked and is
|
||
assumed to be at least (MAX_SHARENAME+1) characters
|
||
long.
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR szPath UNC path name to parse
|
||
|
||
OUT LPTSTR szShare buffer supplied by caller to receive the server
|
||
|
||
|
||
Return Value:
|
||
|
||
TRUE if a sharename is returned, otherwise...
|
||
FALSE if unable to parse out a share name
|
||
|
||
--*/
|
||
{
|
||
int nSlashCount = 0; // count of backslashes found in string
|
||
|
||
LPTSTR szPathPtr; // pointer to char in szPath
|
||
LPTSTR szSharePtr; // pointer to char in szShare
|
||
|
||
szPathPtr = (LPTSTR)szPath;
|
||
szSharePtr = szShare;
|
||
|
||
if (IsUncPath(szPath)) {
|
||
while (*szPathPtr != 0) {
|
||
if (nSlashCount < 3) {
|
||
if (*szPathPtr++ == cBackslash) nSlashCount++;
|
||
} else {
|
||
if (*szPathPtr == cBackslash) {
|
||
szPathPtr++;
|
||
break;
|
||
} else {
|
||
*szSharePtr++ = *szPathPtr++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
*szSharePtr = 0; // terminate share name
|
||
|
||
if (szSharePtr == szShare) {
|
||
return FALSE;
|
||
} else {
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
BOOL
|
||
GetNetPathInfo (
|
||
IN LPCTSTR szPath,
|
||
OUT LPTSTR szServer,
|
||
OUT LPTSTR szRemotePath
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Processes a path and returns the machine the files are on and the
|
||
local path on that machine. UNC, Redirected and local paths may
|
||
be processed by this routine. On remote machine paths (e.g.
|
||
redir'd dos paths and UNC paths on another machine) the shared
|
||
path on the remote machine is returned if there user has sufficient
|
||
permission to access that information. On local paths, the
|
||
local computer name and root path is returned.
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR szPath
|
||
the input path to analyze.
|
||
|
||
OUT LPTSTR szServer
|
||
the server/computername that the path references. The buffer size
|
||
is NOT checked and must be at least MAX_COMPUTERNAME_LENGTH+1 char's
|
||
long.
|
||
|
||
OUT LPTSTR szRemotePath
|
||
the path on the "szServer" machine that corresponds to the
|
||
input path. The buffer size is NOT checked and must be at least
|
||
MAX_PATH + 1 characters long.
|
||
|
||
Return Value:
|
||
|
||
TRUE if a path was processed and data returned
|
||
FALSE if an error occurred or unable to process the path
|
||
|
||
--*/
|
||
{
|
||
DWORD dwBufLen; // buffer length value used in fn. calls
|
||
DWORD dwStatus; // status value returned by fn. calls
|
||
TCHAR szShareName[NNLEN+1]; // net share name from path
|
||
LPTSTR szUncPath; // buffer to get path from redir'd drive
|
||
TCHAR szDrive[4]; // buffer to build drive string in
|
||
LPTSTR szSubDirs; // pointer to start of dirs not in share
|
||
LONG lBsCount; // count of backslashes found parsing UNC
|
||
BOOL bReturn = FALSE; // return valie
|
||
PSHARE_INFO_2 psi2Data; // pointer to Net data buffer
|
||
|
||
// check args
|
||
if ((szServer == NULL) || (szRemotePath == NULL)) {
|
||
// an invalid argument was passed
|
||
return FALSE;
|
||
}
|
||
|
||
szUncPath = GlobalAlloc (GPTR, MAX_PATH_BYTES);
|
||
|
||
if (szUncPath == NULL) {
|
||
*szServer = 0;
|
||
*szRemotePath = 0;
|
||
return FALSE;
|
||
}
|
||
|
||
// args ok, so take a look at the path passed in to process
|
||
if (IsUncPath(szPath)) {
|
||
// extract the server from the path string
|
||
if (GetServerFromUnc(szPath, szServer)) {
|
||
// that worked, so extract the share name.
|
||
if (GetShareFromUnc(szPath, szShareName)) {
|
||
// find end of UNC so sub dirs may be appended to final path
|
||
for (szSubDirs = (LPTSTR)szPath, lBsCount = 0;
|
||
(lBsCount < 4) && (*szSubDirs != 0);
|
||
szSubDirs++) {
|
||
if (*szSubDirs == cBackslash) lBsCount++;
|
||
}
|
||
// now look up the share on the server to get the
|
||
// source path on the server machine
|
||
if (NetShareGetInfo (szServer, (LPWSTR)szShareName, 2L, (LPBYTE *)&psi2Data) == NERR_Success) {
|
||
// successful call so copy the data to the user's buffer
|
||
lstrcpy (szRemotePath, psi2Data->shi2_path);
|
||
NetApiBufferFree (psi2Data);
|
||
// add this only if there's a subdir to append
|
||
if (*szSubDirs != 0) {
|
||
if (szRemotePath[lstrlen(szRemotePath)-1] != cBackslash)
|
||
lstrcat(szRemotePath, cszBackslash);
|
||
lstrcat (szRemotePath, szSubDirs);
|
||
}
|
||
bReturn = TRUE;
|
||
} else {
|
||
// unable to get path on server
|
||
*szRemotePath = 0;
|
||
bReturn = FALSE;
|
||
}
|
||
} else {
|
||
// unable to get parse share name
|
||
*szRemotePath = 0;
|
||
bReturn = FALSE;
|
||
}
|
||
} else {
|
||
// unable to parse server name
|
||
*szServer = 0;
|
||
*szRemotePath = 0;
|
||
bReturn = FALSE;
|
||
}
|
||
} else {
|
||
// it's a dos pathname so see if it's a redirected drive
|
||
if (OnRemoteDrive(szPath)) {
|
||
// yes it's been redirected so look up the information
|
||
// get drive letter of redirected drive
|
||
szDrive[0] = szPath[0];
|
||
szDrive[1] = szPath[1];
|
||
szDrive[2] = 0;
|
||
szSubDirs = (LPTSTR)&szPath[3];
|
||
dwBufLen = MAX_PATH;
|
||
dwStatus = WNetGetConnection (
|
||
szDrive,
|
||
szUncPath,
|
||
&dwBufLen);
|
||
if (dwStatus == NO_ERROR) {
|
||
// UNC of shared dir looked up ok, now proccess that to
|
||
// find the server and path on the server
|
||
if (GetServerFromUnc(szUncPath, szServer)) {
|
||
if (GetShareFromUnc(szUncPath, szShareName)) {
|
||
// now look up the share on the server
|
||
if (NetShareGetInfo (szServer, (LPWSTR)szShareName, 2L, (LPBYTE *)&psi2Data) == NERR_Success) {
|
||
// successful call so return pointer to path string
|
||
lstrcpy (szRemotePath, psi2Data->shi2_path);
|
||
NetApiBufferFree (psi2Data);
|
||
if (*szSubDirs != 0) {
|
||
if (szRemotePath[lstrlen(szRemotePath)-1] != cBackslash)
|
||
lstrcat(szRemotePath, cszBackslash);
|
||
lstrcat (szRemotePath, szSubDirs);
|
||
}
|
||
bReturn = TRUE;
|
||
} else {
|
||
// unable to get path on server
|
||
*szRemotePath = 0;
|
||
bReturn = FALSE;
|
||
}
|
||
} else {
|
||
// unable to get parse share name
|
||
*szRemotePath = 0;
|
||
bReturn = FALSE;
|
||
}
|
||
} else {
|
||
// unable to parse server name
|
||
*szServer = 0;
|
||
*szRemotePath = 0;
|
||
bReturn = FALSE;
|
||
}
|
||
}
|
||
} else {
|
||
// this is a local path so return the local machine name
|
||
// and the path passed in
|
||
dwBufLen = MAX_COMPUTERNAME_LENGTH+1;
|
||
GetComputerName (szServer, &dwBufLen);
|
||
lstrcpy (szRemotePath, szPath);
|
||
bReturn = TRUE;
|
||
}
|
||
}
|
||
|
||
FREE_IF_ALLOC (szUncPath);
|
||
return bReturn;
|
||
}
|
||
|
||
BOOL
|
||
ComputerPresent (
|
||
IN LPCTSTR szMachine
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Try to connect to the registry on the machine name in order to
|
||
determine if the machine is available on the network.
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR szMachine
|
||
computer name to try (must be in the form of \\machine)
|
||
|
||
Return Value:
|
||
|
||
TRUE "szMachine" is present
|
||
FALSE unable to connect to machine
|
||
|
||
--*/
|
||
{
|
||
LONG lStatus; // status of function call
|
||
HKEY hKey; // handle to registry key opened
|
||
|
||
lStatus = RegConnectRegistry (
|
||
(LPTSTR)szMachine,
|
||
HKEY_LOCAL_MACHINE,
|
||
&hKey);
|
||
|
||
if (lStatus == ERROR_SUCCESS) {
|
||
RegCloseKey (hKey);
|
||
return TRUE;
|
||
} else {
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
BOOL
|
||
GetServerFromUnc (
|
||
IN LPCTSTR szPath,
|
||
OUT LPTSTR szServer
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
reads a UNC path and returns the name of the server referenced in
|
||
the buffer provided by the caller
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR szPath
|
||
UNC path to parse
|
||
|
||
OUT LPTSTR szServer
|
||
buffer to receive name of server (must be large enough!)
|
||
|
||
Return Value:
|
||
|
||
TRUE if successful,
|
||
FALSE if not
|
||
|
||
--*/
|
||
{
|
||
LPTSTR szPathPtr; // pointer to char in szPath
|
||
LPTSTR szServPtr; // pointer to char in szServer
|
||
int nSlashCount = 0; // count of backslash chars found
|
||
|
||
szPathPtr = (LPTSTR)szPath;
|
||
szServPtr = szServer;
|
||
|
||
if (IsUncPath(szPath)) {
|
||
while (szPathPtr != 0) {
|
||
if (*szPathPtr == cBackslash) nSlashCount++;
|
||
if ((nSlashCount == 2) && (*szPathPtr != cBackslash)) {
|
||
*szServPtr++ = *szPathPtr;
|
||
} else {
|
||
if (nSlashCount == 3) break; // exit loop
|
||
}
|
||
szPathPtr++;
|
||
}
|
||
}
|
||
|
||
*szServPtr = 0; // terminate server name
|
||
|
||
if (szServPtr == szServer) {
|
||
return FALSE;
|
||
} else {
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
BOOL
|
||
LookupLocalShare (
|
||
IN LPCTSTR szDrivePath,
|
||
IN BOOL bExactMatch,
|
||
OUT LPTSTR szLocalPath,
|
||
IN PDWORD pdwBuffLen
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Searches registry to see if a file is already shared and returns
|
||
the UNC name of the path if it is. (note this function is
|
||
satisfied by the first match it finds, it doesn't try to
|
||
find the "Best" match, just "A" match.
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR szDrivePath
|
||
DOS file path to look up
|
||
|
||
IN BOOL bExactMatch
|
||
TRUE find a share that matches the szDrivePath EXACTLY
|
||
FALSE find a share that has any higher path in szDrivePath
|
||
(e.g. if c:\dir is shared as XXX, then XXX would satisfy
|
||
the lookup if the path was c:\dir\subdir\etc)
|
||
|
||
OUT LPTSTR szLocalPath
|
||
buffer to receive UNC version of path if a share exists
|
||
|
||
IN PDWORD pdwBuffLen
|
||
length of buffer referenced by szLocalPath
|
||
|
||
Return Value:
|
||
|
||
TRUE if a match is found,
|
||
FALSE if not
|
||
|
||
--*/
|
||
{
|
||
HKEY hkeyShareList; // handle to registry listing shares
|
||
LONG lStatus; // called function status return value
|
||
BOOL bReturn = FALSE; // routine status to return to caller
|
||
BOOL bMatch; // true when strings match
|
||
DWORD dwIndex; // index used to increment through search
|
||
LPTSTR szValueBuffer; // value name string to examine
|
||
LPTSTR szValueName; // value value string
|
||
DWORD dwBufferSize; // buffer length variable
|
||
DWORD dwNameSize; // Name Buffer size
|
||
DWORD dwDataType; // data type read from registry
|
||
|
||
LPTSTR szThisItem; // pointer to value in enumerated list of values
|
||
LPTSTR szThisItemChar; // char in name value to compare to path
|
||
LPTSTR szThisMatchChar; // matching character found
|
||
LPTSTR szFilePath; // pointer into path buffer where filename is
|
||
|
||
TCHAR szLocalMachine[MAX_COMPUTERNAME_LENGTH + 1];
|
||
|
||
szValueName = GlobalAlloc (GPTR, MAX_PATH_BYTES);
|
||
szValueBuffer = GlobalAlloc (GPTR, (SMALL_BUFFER_SIZE * sizeof(TCHAR)));
|
||
|
||
if ((szValueName != NULL) && (szValueBuffer != NULL)) {
|
||
// read the registry on the machine the user is
|
||
// running the app on, not the server
|
||
lStatus = RegOpenKeyEx (
|
||
HKEY_LOCAL_MACHINE,
|
||
cszLanmanServerShares,
|
||
0L,
|
||
KEY_READ,
|
||
&hkeyShareList);
|
||
|
||
if (lStatus == ERROR_SUCCESS) {
|
||
// loop through all values under this key until
|
||
// a match is found or all have been examined
|
||
dwIndex = 0;
|
||
dwIndex = 0;
|
||
dwNameSize = MAX_PATH;
|
||
dwBufferSize = SMALL_BUFFER_SIZE;
|
||
dwNameSize = MAX_PATH;
|
||
dwBufferSize = SMALL_BUFFER_SIZE;
|
||
while ((RegEnumValue(hkeyShareList, dwIndex,
|
||
szValueName, &dwNameSize,
|
||
0L, &dwDataType,
|
||
(LPBYTE)szValueBuffer, &dwBufferSize) == ERROR_SUCCESS) && !bReturn) {
|
||
// value read in so scan multi-sz returned to find path entry
|
||
for (szThisItem = szValueBuffer;
|
||
*szThisItem != 0;
|
||
szThisItem += (lstrlen(szThisItem)+1)) {
|
||
// compare the current entry to the "Path" string.
|
||
// if the characters don't match then exit the loop
|
||
// after the loop, if the match char == 0 then all
|
||
// characters in the "item" matched so this is the
|
||
// Path entry. otherwise, it's not the path so go to the
|
||
// the next item.
|
||
for (szThisItemChar = szThisItem, szThisMatchChar = (LPTSTR)cszPath;
|
||
(*szThisMatchChar != 0) && (*szThisItemChar != 0);
|
||
szThisItemChar++, szThisMatchChar++) {
|
||
if (*szThisMatchChar != *szThisItemChar) break;
|
||
}
|
||
if (*szThisMatchChar == 0) {
|
||
// this is a match so see what the path that is
|
||
// shared.
|
||
while (*szThisItemChar != cEqual) szThisItemChar++;
|
||
szThisItemChar++;
|
||
// szThisItemChar now points to the path that is shared
|
||
// compare it to the path that was passed in. if it matches,
|
||
// then return the local machine and share name in a UNC
|
||
// format
|
||
if (bExactMatch) {
|
||
if (lstrcmpi(szThisItemChar, szDrivePath) == 0) {
|
||
bMatch = TRUE;
|
||
} else {
|
||
bMatch = FALSE;
|
||
}
|
||
} else {
|
||
bMatch = MatchFirst(szThisItemChar, szDrivePath);
|
||
}
|
||
if (bMatch) {
|
||
// it's a match so format return value
|
||
dwBufferSize = MAX_COMPUTERNAME_LENGTH + 1;
|
||
GetComputerName(
|
||
szLocalMachine,
|
||
&dwBufferSize);
|
||
if (szLocalPath != NULL) {
|
||
//
|
||
// format name by replacing drive letter and colon
|
||
// with UNC format \\server\path
|
||
//
|
||
lstrcpy (szLocalPath, cszDoubleBackslash);
|
||
lstrcat (szLocalPath, szLocalMachine);
|
||
lstrcat (szLocalPath, cszBackslash);
|
||
lstrcat (szLocalPath, szValueName);
|
||
szFilePath = (LPTSTR)&szDrivePath[lstrlen(szThisItemChar)];
|
||
if (*szFilePath != cBackslash) lstrcat (szLocalPath, cszBackslash);
|
||
lstrcat (szLocalPath, szFilePath);
|
||
}
|
||
bReturn = TRUE;
|
||
}
|
||
} else {
|
||
// this is not the path entry so break and go to the
|
||
// next one.
|
||
}
|
||
}
|
||
|
||
// read next value
|
||
dwIndex++;
|
||
dwNameSize = MAX_PATH;
|
||
dwBufferSize = SMALL_BUFFER_SIZE;
|
||
}
|
||
RegCloseKey (hkeyShareList);
|
||
} else {
|
||
// unable to open registry key
|
||
bReturn = FALSE;
|
||
}
|
||
} else {
|
||
// unable to allocate memory
|
||
bReturn = FALSE;
|
||
}
|
||
|
||
FREE_IF_ALLOC (szValueName);
|
||
FREE_IF_ALLOC (szValueBuffer);
|
||
|
||
return bReturn;
|
||
}
|
||
|
||
BOOL
|
||
LookupRemotePath (
|
||
IN LPCTSTR szDrivePath,
|
||
OUT LPTSTR szRemotePath,
|
||
IN PDWORD pdwBuffLen
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Looks up a path on a remote server to see if a Dos file path is really
|
||
on a remote drive and returns the UNC path if it is.
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR szDrivePath
|
||
DOS file path to examine
|
||
|
||
OUT LPTSTR szRemotePath
|
||
buffer to get UNC version of path if one exists
|
||
|
||
IN PDWORD pdwBuffLen
|
||
length of szRemotePath buffer in bytes
|
||
|
||
Return Value:
|
||
|
||
TRUE if match found
|
||
FALSE if no match
|
||
|
||
--*/
|
||
{
|
||
HKEY hkeyNetDrive; // handle to registry describing remote drive
|
||
LONG lStatus; // function status returned by called fn's
|
||
LPTSTR szKeyName; // buffer to build name string in
|
||
TCHAR szLocalDrive[4]; // buffer to build local drive string in
|
||
LPTSTR szFilePath; // pointer into buffer where file path goes
|
||
DWORD dwValueType; // buffer for registry query
|
||
BOOL bReturn; // return value of this function
|
||
|
||
szKeyName = GlobalAlloc (GPTR, MAX_PATH_BYTES);
|
||
|
||
if (szKeyName == NULL) return FALSE;
|
||
|
||
lstrcpy (szKeyName, cszNetDriveListKeyName);
|
||
szLocalDrive[0] = szDrivePath[0];
|
||
szLocalDrive[1] = 0;
|
||
lstrcat (szKeyName, szLocalDrive);
|
||
szFilePath = (LPTSTR)&szDrivePath[2];
|
||
|
||
lStatus = RegOpenKeyEx (
|
||
HKEY_CURRENT_USER,
|
||
szKeyName,
|
||
0L,
|
||
KEY_READ,
|
||
&hkeyNetDrive);
|
||
|
||
if (lStatus == ERROR_SUCCESS) {
|
||
lStatus = RegQueryValueEx (
|
||
hkeyNetDrive,
|
||
(LPTSTR)cszRemotePathValue,
|
||
0L,
|
||
&dwValueType,
|
||
(LPBYTE)szRemotePath,
|
||
pdwBuffLen);
|
||
|
||
RegCloseKey (hkeyNetDrive);
|
||
|
||
if (lStatus == ERROR_SUCCESS) {
|
||
//append the rest of the path and exit
|
||
lstrcat (szRemotePath, szFilePath);
|
||
bReturn = TRUE;
|
||
} else {
|
||
bReturn = FALSE;
|
||
}
|
||
} else {
|
||
// unable to find drive or open key
|
||
bReturn = FALSE;
|
||
}
|
||
|
||
FREE_IF_ALLOC (szKeyName);
|
||
|
||
return bReturn;
|
||
}
|
||
|
||
BOOL
|
||
OnRemoteDrive (
|
||
IN LPCTSTR szPath
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns TRUE if drive referenced is a network drive as opposed to
|
||
on on the local machine
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR szPath
|
||
path to look up
|
||
|
||
Return Value:
|
||
|
||
TRUE if szPath references a remote drive
|
||
FALSE if szPath references a local drive
|
||
|
||
--*/
|
||
{
|
||
TCHAR szRootDir[4]; // drive string
|
||
TCHAR szServerName[MAX_COMPUTERNAME_LENGTH*2]; // server name buffer
|
||
TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH+1]; // local machine name
|
||
DWORD dwBufLen; // buffer len. var.
|
||
|
||
if (IsUncPath(szPath)) {
|
||
if (GetServerFromUnc(szPath, szServerName)) {
|
||
dwBufLen = MAX_COMPUTERNAME_LENGTH+1;
|
||
GetComputerName (szComputerName, &dwBufLen);
|
||
if (lstrcmpi(szServerName, szComputerName) == 0) {
|
||
// shared on this machine so not remote
|
||
return FALSE;
|
||
} else {
|
||
// not on this machine so it must be remote
|
||
return TRUE;
|
||
}
|
||
}
|
||
} else {
|
||
// check the DOS path
|
||
// see if this is a network or local drive
|
||
szRootDir[0] = szPath[0]; // letter
|
||
szRootDir[1] = szPath[1]; // colon
|
||
szRootDir[2] = cBackslash;
|
||
szRootDir[3] = 0;
|
||
|
||
if (GetDriveType(szRootDir) == DRIVE_REMOTE) {
|
||
return TRUE;
|
||
} else {
|
||
return FALSE;
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
DWORD
|
||
ComputeFreeSpace (
|
||
IN LPCTSTR szPath
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Function to return free space on drive referenced in path
|
||
(NOTE: assumes DOS file path specification)
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR szPath
|
||
Path including Drive to check free space of. (MUST BE A DOS
|
||
FILE Path)
|
||
|
||
Return Value:
|
||
|
||
Free space found in BYTES
|
||
|
||
--*/
|
||
{
|
||
DWORD dwSectorsPerCluster;
|
||
DWORD dwBytesPerSector;
|
||
DWORD dwFreeClusters;
|
||
DWORD dwClusters;
|
||
TCHAR szRoot[MAX_PATH]; // root dir of path
|
||
DWORD dwFreeBytes = 0;
|
||
|
||
UINT nErrorMode;
|
||
|
||
// disable windows error message popup
|
||
nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
|
||
|
||
lstrcpy (szRoot, GetRootFromPath(szPath));
|
||
if (lstrlen(szRoot) > 0) {
|
||
// we have a path to process so get info from the root
|
||
if (GetDiskFreeSpace(szRoot, &dwSectorsPerCluster,
|
||
&dwBytesPerSector, &dwFreeClusters, &dwClusters)) {
|
||
|
||
ULONGLONG ullFreeBytes;
|
||
|
||
ullFreeBytes =
|
||
(ULONGLONG)dwFreeClusters *
|
||
dwSectorsPerCluster * dwBytesPerSector;
|
||
|
||
dwFreeBytes = (DWORD) ullFreeBytes;
|
||
|
||
if( (ULONGLONG)dwFreeBytes != ullFreeBytes ) {
|
||
|
||
//
|
||
// Overflow has occured.
|
||
//
|
||
|
||
dwFreeBytes = 0xFFFFFFFF;
|
||
}
|
||
}
|
||
} else {
|
||
dwFreeBytes = 0xFFFFFFFF;
|
||
}
|
||
SetErrorMode (nErrorMode); // restore old error mode
|
||
return dwFreeBytes;
|
||
}
|
||
|
||
BOOL
|
||
IsShareNameUsed (
|
||
IN LPCTSTR szServerName,
|
||
IN LPCTSTR szShareName,
|
||
IN OUT PDWORD pdwType,
|
||
IN OUT LPTSTR pszPath
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Looks up a share name on a sever to determine if the name is in use
|
||
and if so, what type of directory is shared.
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR szServerName
|
||
server name to look up share name on (NULL == the local machine)
|
||
|
||
IN LPCTSTR szShareName
|
||
share name to look up
|
||
|
||
IN OUT PDWORD pdwType
|
||
buffer to return share type in options are:
|
||
NCDU_SHARE_IS_NOT_USED: name not found on server
|
||
NCDU_SHARE_IS_CLIENT_TREE: name is a client distribution tree
|
||
NCDU_SHARE_IS_SERVER_TOOLS: name is a server tool tree
|
||
NCDU_SHARE_IS_OTHER_DIR: name is shared to some other dir.
|
||
|
||
IN OUT LPTSTR pszPath
|
||
if path is shared, then this is the path on the server that
|
||
is shared
|
||
|
||
Return Value:
|
||
|
||
TRUE if share name is in use
|
||
FALSE if the share name is not found on the server.
|
||
|
||
--*/
|
||
{
|
||
LPTSTR szLocalPath; // local buffer to build path string in
|
||
LPTSTR szLocalName; // pointer into path where sharename starts
|
||
DWORD dwShareAttrib; // file attributes of share point
|
||
DWORD dwBufLen; // buffer length variable
|
||
BOOL bReturn = FALSE; // function return value
|
||
DWORD dwLocalType; // share dir type
|
||
PSHARE_INFO_2 psi2Data = NULL; // net info buffer pointer
|
||
LPTSTR szReturnPath
|
||
= (LPTSTR)cszEmptyString; // pointer to path string to return
|
||
|
||
szLocalPath = GlobalAlloc (GPTR, MAX_PATH_BYTES);
|
||
|
||
if (szLocalPath != NULL) {
|
||
// make share name into a UNC name using the appropriate machine
|
||
lstrcpy (szLocalPath, cszDoubleBackslash);
|
||
if (szServerName == NULL) {
|
||
dwBufLen = MAX_COMPUTERNAME_LENGTH + 1;
|
||
GetComputerName (&szLocalPath[2], &dwBufLen);
|
||
} else {
|
||
lstrcat (szLocalPath, szServerName);
|
||
}
|
||
lstrcat (szLocalPath, cszBackslash);
|
||
szLocalName = &szLocalPath[lstrlen(szLocalPath)];
|
||
lstrcpy (szLocalName, szShareName);
|
||
TrimSpaces (szLocalName);
|
||
|
||
// see if it's a valid path
|
||
dwShareAttrib = QuietGetFileAttributes (szLocalPath);
|
||
|
||
if (dwShareAttrib == 0xFFFFFFFF) {
|
||
// it's not a valid file or dir, so
|
||
bReturn = FALSE; // share name is not used
|
||
szReturnPath = (LPTSTR)cszEmptyString;
|
||
dwLocalType = NCDU_SHARE_IS_NOT_USED;
|
||
} else {
|
||
// it's a valid path so see if it's anything we want
|
||
bReturn = TRUE;
|
||
// terminate local path after server name for use in net API Call
|
||
*(szLocalName - 1) = 0;
|
||
// get share info
|
||
if (NetShareGetInfo ((LPWSTR)szLocalPath, (LPWSTR)szShareName,
|
||
2L, (LPBYTE *)&psi2Data) == NERR_Success) {
|
||
// successful call so return pointer to path string
|
||
szReturnPath = psi2Data->shi2_path;
|
||
} else {
|
||
// function failed so return empty path
|
||
szReturnPath = (LPTSTR)cszEmptyString;
|
||
}
|
||
// restore local path string
|
||
*(szLocalName - 1) = cBackslash;
|
||
// share is used, so see if it's a clients path
|
||
if (*szReturnPath != 0) {
|
||
if (ValidSharePath (szLocalPath) == 0) {
|
||
dwLocalType = NCDU_SHARE_IS_CLIENT_TREE;
|
||
} else if (ValidSrvToolsPath (szLocalPath) == 0) {
|
||
dwLocalType = NCDU_SHARE_IS_SERVER_TOOLS;
|
||
} else {
|
||
dwLocalType = NCDU_SHARE_IS_OTHER_DIR;
|
||
}
|
||
} else {
|
||
// no path name
|
||
bReturn = FALSE;
|
||
dwLocalType = NCDU_SHARE_IS_NOT_USED;
|
||
}
|
||
}
|
||
FREE_IF_ALLOC (szLocalPath);
|
||
} else {
|
||
// unable to allocate memory
|
||
bReturn = FALSE;
|
||
dwLocalType = 0;
|
||
}
|
||
|
||
if (pdwType != NULL) {
|
||
*pdwType = dwLocalType;
|
||
}
|
||
|
||
if (pszPath != NULL) {
|
||
lstrcpy (pszPath, szReturnPath);
|
||
}
|
||
// free buffer created by net call
|
||
if (psi2Data != NULL) NetApiBufferFree (psi2Data);
|
||
|
||
return bReturn;
|
||
}
|
||
|
||
DWORD
|
||
QuietGetFileAttributes (
|
||
IN LPCTSTR lpszFileName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads the attributes of the path in lpzsFileName without triggering
|
||
any Windows error dialog if there's an OS error (e.g. drive not
|
||
ready)
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR lpszFileName
|
||
path to retrieve attributes from
|
||
|
||
Return Value:
|
||
|
||
file attributes DWORD returned from GetFileAttributes or
|
||
0xFFFFFFFF if unable to open path.
|
||
|
||
--*/
|
||
{
|
||
DWORD dwReturn;
|
||
UINT nErrorMode;
|
||
|
||
// disable windows error message popup
|
||
nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
|
||
|
||
dwReturn = GetFileAttributes (lpszFileName);
|
||
|
||
SetErrorMode (nErrorMode); // restore old error mode
|
||
|
||
return dwReturn;
|
||
}
|
||
|
||
BOOL
|
||
GetSizeOfDirs (
|
||
IN LPCTSTR szPath,
|
||
IN BOOL bFlags,
|
||
IN OUT PDWORD pdwSize
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Scans a directory and optionally a subdirectory to total the sizes
|
||
of the files found.
|
||
|
||
NOTE: This function will only process files that are < 4GB in size
|
||
and dir paths that total less then 4GB total.
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR szPath
|
||
top dir or dir tree to scan.
|
||
|
||
IN BOOL bFlags
|
||
operation modification flags:
|
||
0 : specified path only.
|
||
GSOD_INCLUDE_SUBDIRS: include sub dirs
|
||
|
||
IN OUT PDWORD pdwSize
|
||
buffer to return size in.
|
||
|
||
Return Value:
|
||
|
||
TRUE size returned in pdwSize
|
||
FALSE error occurred
|
||
|
||
--*/
|
||
{
|
||
HANDLE hSearch;
|
||
HANDLE hFile;
|
||
WIN32_FIND_DATA fdSearch;
|
||
PDWORD pdwSizeBuffer;
|
||
DWORD dwLocalSize = 0;
|
||
DWORD dwPathAttrib;
|
||
BOOL bSearching;
|
||
LPTSTR szLocalPath;
|
||
LPTSTR szSearchPath;
|
||
LPTSTR szLocalFileName;
|
||
DWORD dwFileSizeLow;
|
||
DWORD dwFileSizeHigh;
|
||
LPTSTR szThisFileName;
|
||
BOOL bReturn;
|
||
//
|
||
// check path to see if it's a directory
|
||
//
|
||
dwPathAttrib = QuietGetFileAttributes (szPath);
|
||
// if an invalid attribute or it's not a directory then return FALSE and set error
|
||
if ((dwPathAttrib == 0xFFFFFFFF) ||
|
||
((dwPathAttrib & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY)) {
|
||
SetLastError (ERROR_BAD_PATHNAME);
|
||
return FALSE;
|
||
}
|
||
//
|
||
// Initialize size buffer
|
||
//
|
||
if (pdwSize == NULL) {
|
||
pdwSizeBuffer = &dwLocalSize;
|
||
} else {
|
||
pdwSizeBuffer = pdwSize;
|
||
}
|
||
// get a local buffer for the path
|
||
szSearchPath = GlobalAlloc (GPTR, MAX_PATH_BYTES);
|
||
szLocalPath = GlobalAlloc (GPTR, MAX_PATH_BYTES);
|
||
if ((szLocalPath != NULL) && (szSearchPath != NULL)) {
|
||
// make a local copy of the input path
|
||
lstrcpy (szLocalPath, szPath);
|
||
lstrcpy (szSearchPath, szLocalPath);
|
||
// make full path prefix for sub dir searches & filenames
|
||
if (szLocalPath[lstrlen(szLocalPath)-1] != cBackslash) lstrcat (szLocalPath, cszBackslash);
|
||
szLocalFileName = &szLocalPath[lstrlen(szLocalPath)];
|
||
// make wildcard path for searching this directory
|
||
lstrcat (szSearchPath, cszWildcardFile);
|
||
//
|
||
// start search of files in this path
|
||
//
|
||
hSearch = FindFirstFile (szSearchPath, &fdSearch);
|
||
if (hSearch != INVALID_HANDLE_VALUE) {
|
||
bSearching = TRUE;
|
||
while (bSearching) {
|
||
// if an alternate filename is defined, then use it, otherwise
|
||
// use the regular name
|
||
szThisFileName = ((fdSearch.cAlternateFileName[0] == 0) ?
|
||
fdSearch.cFileName : fdSearch.cAlternateFileName);
|
||
// if it's a dot or a dot dot (. or ..) dir, then skip
|
||
if (!DotOrDotDotDir(szThisFileName)) {
|
||
lstrcpy (szLocalFileName, szThisFileName);
|
||
// if it's a dir and the SUB DIR flag is set, then
|
||
// recurse through the next directory, otherwise
|
||
// get the file size of this file and continue
|
||
dwPathAttrib = QuietGetFileAttributes (szLocalPath);
|
||
if ((dwPathAttrib & FILE_ATTRIBUTE_DIRECTORY) ==
|
||
FILE_ATTRIBUTE_DIRECTORY) {
|
||
// this is a directory, so call this routine again
|
||
// if the sub-dir flag is set.
|
||
if ((bFlags & GSOD_INCLUDE_SUBDIRS) == GSOD_INCLUDE_SUBDIRS) {
|
||
if (!GetSizeOfDirs (szLocalPath, bFlags, pdwSizeBuffer)) {
|
||
// this call returned an errror so propogate it
|
||
// up the call stack and exit the loop here
|
||
bSearching = FALSE;
|
||
continue;
|
||
}
|
||
} else {
|
||
// the caller doesn't want sub dirs so ignore it
|
||
}
|
||
} else {
|
||
// this is a file so get the size of it and add
|
||
// it to the total
|
||
hFile = CreateFile (
|
||
szLocalPath,
|
||
GENERIC_READ,
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
NULL,
|
||
OPEN_EXISTING,
|
||
FILE_ATTRIBUTE_NORMAL,
|
||
NULL);
|
||
if (hFile != INVALID_HANDLE_VALUE) {
|
||
// then the file was opened successfully
|
||
// go get it's size and add it to the total
|
||
dwFileSizeLow = GetFileSize (hFile, &dwFileSizeHigh);
|
||
if (dwFileSizeLow != 0xFFFFFFFF) {
|
||
*pdwSizeBuffer += dwFileSizeLow;
|
||
}
|
||
// now close the file handle
|
||
CloseHandle (hFile);
|
||
} else {
|
||
// unable to open file so skip it
|
||
}
|
||
}
|
||
}
|
||
bSearching = FindNextFile (hSearch, &fdSearch);
|
||
}
|
||
FindClose (hSearch);
|
||
} else {
|
||
// unable to start search so return 0 size
|
||
}
|
||
bReturn = TRUE;
|
||
} else {
|
||
// unable to allocate memory
|
||
SetLastError (ERROR_OUTOFMEMORY);
|
||
bReturn = FALSE;
|
||
}
|
||
|
||
FREE_IF_ALLOC (szLocalPath);
|
||
FREE_IF_ALLOC (szSearchPath);
|
||
|
||
return bReturn;
|
||
}
|
||
|
||
BOOL
|
||
MediaPresent (
|
||
IN LPCTSTR szPath,
|
||
IN BOOL bPresentAndValid
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
determines if the specified path is present and available
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR szPath
|
||
path to examine (Must be a DOS path)
|
||
|
||
Return Value:
|
||
|
||
TRUE: path is available
|
||
FALSE: unable to find/open path
|
||
|
||
--*/
|
||
{
|
||
TCHAR szDev[8];
|
||
DWORD dwBytes = 0;
|
||
DWORD dwAttrib;
|
||
DWORD dwLastError = ERROR_SUCCESS;
|
||
BOOL bMediaPresent = FALSE;
|
||
UINT nErrorMode;
|
||
|
||
if (!IsUncPath(szPath)) {
|
||
// build device name string
|
||
szDev[0] = szPath[0];
|
||
szDev[1] = cColon;
|
||
szDev[2] = cBackslash;
|
||
szDev[3] = 0;
|
||
|
||
// disable windows error message popup
|
||
nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
|
||
|
||
dwAttrib = QuietGetFileAttributes (szDev);
|
||
if ((dwAttrib != 0xFFFFFFFF) && ((dwAttrib & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
|
||
// if the root dir is a dir, then it must be present and formatted
|
||
bMediaPresent = TRUE;
|
||
} else {
|
||
// otherwise see if it's present and not formatted or not present
|
||
dwLastError = GetLastError();
|
||
if (dwLastError == ERROR_NOT_READY) {
|
||
// then no disk in drive
|
||
bMediaPresent = FALSE;
|
||
} else if ((dwLastError == ERROR_FILE_NOT_FOUND) ||
|
||
#ifdef TERMSRV
|
||
(dwLastError == ERROR_UNRECOGNIZED_MEDIA) ||
|
||
(dwLastError == ERROR_SECTOR_NOT_FOUND)) {
|
||
#else // TERMSRV
|
||
(dwLastError == ERROR_UNRECOGNIZED_MEDIA)) {
|
||
#endif // TERMSRV
|
||
// then and UNFORMATTED disk is in drive
|
||
if (bPresentAndValid) {
|
||
// this isn't good enough if it's supposed to be formatted
|
||
bMediaPresent = FALSE;
|
||
} else {
|
||
// we're just looking for a disk so this is OK
|
||
bMediaPresent = TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
SetErrorMode (nErrorMode); // restore old error mode
|
||
} else {
|
||
// assume UNC path devices are present
|
||
bMediaPresent = TRUE;
|
||
}
|
||
return bMediaPresent;
|
||
}
|
||
|
||
BOOL
|
||
FileExists (
|
||
IN LPCTSTR szFileName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Opens the file to test for it's presences and returns TRUE if the
|
||
open was successful and FALSE if not.
|
||
|
||
Arguments:
|
||
|
||
file name to open
|
||
|
||
ReturnValue:
|
||
|
||
TRUE if file found
|
||
FALSE if not.
|
||
|
||
--*/
|
||
{
|
||
BOOL bMediaPresent;
|
||
UINT nDriveType;
|
||
DWORD dwAttr;
|
||
|
||
nDriveType = GetDriveType((LPTSTR)szFileName);
|
||
if ((nDriveType == DRIVE_REMOVABLE) || (nDriveType == DRIVE_CDROM)) {
|
||
// see if a formatted drive is really there
|
||
bMediaPresent = MediaPresent(szFileName, TRUE);
|
||
} else {
|
||
// if drive is not removable, then assume it's there
|
||
bMediaPresent = TRUE;
|
||
}
|
||
|
||
// try to get inforation on the file
|
||
dwAttr = QuietGetFileAttributes ((LPTSTR)szFileName);
|
||
if (dwAttr == 0xFFFFFFFF) {
|
||
// unable to obtain attributes, so assume it's not there
|
||
// or we can't access it
|
||
return FALSE;
|
||
} else {
|
||
// found, so close it and return TRUE
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
BOOL
|
||
IsBootDisk (
|
||
IN LPCTSTR szPath
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
examines the path (which should be the root dir of a floppy drive)
|
||
and looks for the "signature" files that indicate it's a bootable
|
||
(i.e. system) disk.
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR szPath
|
||
drive path to look at
|
||
|
||
Return Value:
|
||
|
||
TRUE if one of the signature files was found
|
||
FALSE if not.
|
||
|
||
--*/
|
||
{
|
||
TCHAR szDrive[16];
|
||
LPTSTR szTestFile;
|
||
LPTSTR *szTryFile;
|
||
|
||
szTestFile = GlobalAlloc (GPTR, MAX_PATH_BYTES);
|
||
|
||
if (szTestFile == NULL) {
|
||
SetLastError (ERROR_OUTOFMEMORY);
|
||
return FALSE; // unable to continue
|
||
}
|
||
|
||
if (!IsUncPath(szPath)) {
|
||
szDrive[0] = szPath[0]; // drive letter
|
||
szDrive[1] = szPath[1]; // colon
|
||
szDrive[2] = cBackslash;
|
||
szDrive[3] = 0; // terminator
|
||
|
||
for (szTryFile = (LPTSTR *)szBootIdFiles;
|
||
*szTryFile != NULL;
|
||
szTryFile++) {
|
||
|
||
lstrcpy (szTestFile, szDrive);
|
||
lstrcat (szTestFile, *szTryFile);
|
||
|
||
if (FileExists(szTestFile)) return TRUE;
|
||
}
|
||
// if we didn't bail out already, it must not be a bootable disk
|
||
return FALSE;
|
||
} else {
|
||
// unc path name automatically is not a bootable drive
|
||
return FALSE;
|
||
}
|
||
|
||
FREE_IF_ALLOC (szTestFile);
|
||
}
|
||
|
||
MEDIA_TYPE
|
||
GetDriveTypeFromPath (
|
||
IN LPCTSTR szPath
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
returns the drive type of the drive specified in the path argument
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR szPath
|
||
path on drive to examine
|
||
|
||
Return Value:
|
||
|
||
MEDIA_TYPE value identifying drive type
|
||
|
||
--*/
|
||
{
|
||
HANDLE hFloppy;
|
||
DWORD dwRetSize;
|
||
DISK_GEOMETRY dgFloppy;
|
||
TCHAR szDevicePath[16];
|
||
UINT nDriveType;
|
||
UINT nErrorMode;
|
||
|
||
nDriveType = GetDriveType((LPTSTR)szPath);
|
||
// see if this is a remote disk and exit if it is.
|
||
if (nDriveType == DRIVE_REMOTE) return Unknown;
|
||
|
||
if ((nDriveType == DRIVE_REMOVABLE) || (nDriveType == DRIVE_CDROM)) {
|
||
// see if it's a UNC path and return unknown if so
|
||
if (IsUncPath(szPath)) return Unknown;
|
||
|
||
// it should be local and a DOS pathname so
|
||
// make device name from path
|
||
|
||
szDevicePath[0] = cBackslash;
|
||
szDevicePath[1] = cBackslash;
|
||
szDevicePath[2] = cPeriod;
|
||
szDevicePath[3] = cBackslash;
|
||
szDevicePath[4] = szPath[0]; // drive letter
|
||
szDevicePath[5] = szPath[1]; // colon
|
||
szDevicePath[6] = 0; // null terminator
|
||
|
||
// disable windows error message popup
|
||
nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
|
||
|
||
// open device to get type
|
||
hFloppy = CreateFile (
|
||
szDevicePath,
|
||
GENERIC_READ,
|
||
(FILE_SHARE_READ | FILE_SHARE_WRITE),
|
||
NULL,
|
||
OPEN_EXISTING,
|
||
FILE_ATTRIBUTE_NORMAL,
|
||
NULL);
|
||
|
||
if (hFloppy != INVALID_HANDLE_VALUE) {
|
||
// get drive information
|
||
if (!DeviceIoControl (hFloppy,
|
||
IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
||
NULL, 0,
|
||
&dgFloppy,
|
||
sizeof(DISK_GEOMETRY),
|
||
&dwRetSize,
|
||
NULL) ){
|
||
// unable to get data so set to unknown
|
||
dgFloppy.MediaType = Unknown;
|
||
} // else return data from returned structure
|
||
CloseHandle (hFloppy);
|
||
} else {
|
||
// unable to open handle to device
|
||
dgFloppy.MediaType = Unknown;
|
||
}
|
||
SetErrorMode (nErrorMode); // reset error mode
|
||
}
|
||
return dgFloppy.MediaType;
|
||
}
|
||
|
||
BOOL
|
||
DotOrDotDotDir (
|
||
IN LPCTSTR szFileName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
examines the filename in the parameter list to see if it is one
|
||
of the default subdirectories (e.g. the . or the .. dirs). This
|
||
routine assumes that the argument is a filename only. (i.e. NO
|
||
PATH!)
|
||
|
||
Arguments:
|
||
|
||
Filename to compare
|
||
|
||
Return Value:
|
||
|
||
TRUE if filename is either the . or the .. dir
|
||
FALSE if it is any other string
|
||
|
||
--*/
|
||
{
|
||
if (szFileName != NULL) { // check for null parameter
|
||
if (lstrcmp(szFileName, cszDot) == 0) {
|
||
return TRUE; // it's the . dir
|
||
} else if (lstrcmp(szFileName, cszDotDot) == 0) {
|
||
return TRUE; // it's the .. dir
|
||
} else {
|
||
return FALSE; // it's neither
|
||
}
|
||
} else {
|
||
return FALSE; // null filename, so not a . or .. dir
|
||
}
|
||
}
|
||
|
||
UINT
|
||
ValidSharePath (
|
||
IN LPCTSTR szPath
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
examines the path to see if it contains the "signature" file
|
||
that identifies the path as as that of a valid client
|
||
distribution directory tree.
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR szPath
|
||
path to examine
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if it is
|
||
otherwise the ID of a string resource that describes
|
||
what was found and why it isn't a distribution tree
|
||
|
||
--*/
|
||
{
|
||
DWORD dwPathAttr;
|
||
UINT nReturn = 0;
|
||
|
||
LPTSTR szInfName;
|
||
|
||
szInfName = GlobalAlloc (GPTR, MAX_PATH_BYTES);
|
||
|
||
if (szInfName == NULL) {
|
||
SetLastError (ERROR_OUTOFMEMORY);
|
||
return NCDU_ERROR_NOMEMORY;
|
||
}
|
||
|
||
// validate share path by looking for INF file, display
|
||
// error box if necessary.
|
||
// Return 0 if valid
|
||
// return message string ID if not valid, for what ever reason.
|
||
//
|
||
dwPathAttr = QuietGetFileAttributes((LPTSTR)szPath);
|
||
if (dwPathAttr == 0xFFFFFFFF) {
|
||
// an error occured...
|
||
nReturn = NCDU_UNABLE_READ_DIR;
|
||
} else {
|
||
if ((dwPathAttr & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) {
|
||
// so far so good!
|
||
lstrcpy (szInfName, szPath);
|
||
if (szInfName[lstrlen(szInfName)-1] != cBackslash) lstrcat(szInfName, cszBackslash);
|
||
lstrcat (szInfName, cszAppInfName);
|
||
dwPathAttr = QuietGetFileAttributes(szInfName);
|
||
if (dwPathAttr != 0xFFFFFFFF) {
|
||
nReturn = 0;
|
||
} else {
|
||
nReturn = NCDU_NOT_DIST_TREE;
|
||
}
|
||
} else {
|
||
nReturn = NCDU_PATH_NOT_DIR;
|
||
}
|
||
}
|
||
|
||
FREE_IF_ALLOC (szInfName);
|
||
|
||
return (nReturn);
|
||
}
|
||
|
||
UINT
|
||
ValidSrvToolsPath (
|
||
IN LPCTSTR szPath
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
examines the path to see if it contains the "signature" file
|
||
that identifies the path as as that of a valid server tools
|
||
distribution directory tree.
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR szPath
|
||
path to examine
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if it is
|
||
otherwise the ID of a string resource that describes
|
||
what was found and why it isn't a server tools tree
|
||
|
||
--*/
|
||
{
|
||
UINT nReturn = 0;
|
||
DWORD dwAttrib;
|
||
|
||
LPTSTR szClientPath;
|
||
|
||
szClientPath = GlobalAlloc (GPTR, MAX_PATH_BYTES);
|
||
|
||
if (szClientPath == NULL) {
|
||
SetLastError (ERROR_OUTOFMEMORY);
|
||
return NCDU_ERROR_NOMEMORY;
|
||
}
|
||
|
||
// make local copy of the path
|
||
lstrcpy (szClientPath, szPath);
|
||
|
||
// get file attributes of dir path to make sure it's really a dir
|
||
dwAttrib = QuietGetFileAttributes (szClientPath);
|
||
if ((dwAttrib != 0xFFFFFFFF) && ((dwAttrib & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
|
||
if (szClientPath[lstrlen(szClientPath)-1] != cBackslash) lstrcat(szClientPath, cszBackslash);
|
||
lstrcat (szClientPath, cszSrvToolSigFile);
|
||
// now get the file attributes of the signature file to see if this is a valid path
|
||
dwAttrib = QuietGetFileAttributes (szClientPath);
|
||
if (dwAttrib != 0xFFFFFFFF) {
|
||
nReturn = 0;
|
||
} else {
|
||
nReturn = NCDU_NOT_TOOL_TREE;
|
||
}
|
||
} else {
|
||
nReturn = NCDU_PATH_NOT_DIR;
|
||
}
|
||
|
||
FREE_IF_ALLOC (szClientPath);
|
||
|
||
return (nReturn);
|
||
}
|
||
|
||
BOOL
|
||
IsPathADir (
|
||
IN LPCTSTR szPath
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Checks the path passed in to see if it's a directory or not
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR szPath
|
||
path to check
|
||
|
||
Return Value:
|
||
|
||
TRUE if path is a valid directory
|
||
FALSE if unable to find path or if path is not a directory
|
||
|
||
--*/
|
||
{
|
||
DWORD dwAttrib;
|
||
dwAttrib = QuietGetFileAttributes (szPath);
|
||
if ((dwAttrib != 0xffffffff) &&
|
||
((dwAttrib & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
|
||
return TRUE;
|
||
} else {
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
static
|
||
DWORD
|
||
GetSectorSize (
|
||
IN LPTSTR szDriveName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns the sector size in bytes of the disk drive specified in the
|
||
argument list.
|
||
|
||
Arguments:
|
||
|
||
IN LPTSTR szDriveName ASCIZ of drive to return data for (e.g. "C:")
|
||
|
||
Return Value:
|
||
|
||
size of disk sector in bytes,
|
||
0xFFFFFFFF ((DWORD)-1) if error, error retrieved using GetLastError()
|
||
|
||
--*/
|
||
{
|
||
BOOL bStatus;
|
||
LONG lReturn = 0xFFFFFFFF;
|
||
|
||
DWORD dwBytesReturned;
|
||
|
||
HANDLE hDrive;
|
||
|
||
DISK_GEOMETRY dgBuffer;
|
||
|
||
// open existing file (root drive)
|
||
|
||
hDrive = CreateFile (
|
||
szDriveName,
|
||
GENERIC_READ,
|
||
(FILE_SHARE_READ | FILE_SHARE_WRITE),
|
||
NULL,
|
||
OPEN_EXISTING,
|
||
0L,
|
||
NULL);
|
||
|
||
if (hDrive != INVALID_HANDLE_VALUE) {
|
||
// get disk inoformation
|
||
bStatus = DeviceIoControl(
|
||
hDrive,
|
||
IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
||
NULL,
|
||
0L,
|
||
&dgBuffer,
|
||
sizeof(dgBuffer),
|
||
&dwBytesReturned,
|
||
NULL);
|
||
|
||
// if data was returned by IOCTL, then return
|
||
// sector size other wise return error value
|
||
|
||
if (bStatus) {
|
||
lReturn = dgBuffer.BytesPerSector;
|
||
} else {
|
||
lReturn = 0xFFFFFFFF;
|
||
}
|
||
|
||
CloseHandle (hDrive); // don't forget to close the handle
|
||
|
||
} else {
|
||
// unable to open device
|
||
lReturn = 0xFFFFFFFF;
|
||
}
|
||
|
||
return lReturn;
|
||
}
|
||
|
||
static
|
||
LONG
|
||
CopyFatBootSectorToBuffer (
|
||
IN LPTSTR szBootDrive,
|
||
IN LPBYTE *pOutputBuffer
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Copies the first sector of the volume to the specified file
|
||
|
||
Arguments:
|
||
|
||
IN LPTSTR szBootDrive volume to locate boot sector on
|
||
IN LPBYTE *pOutputBuffer address of pointer to buffer created
|
||
|
||
Return Value:
|
||
|
||
Win 32 Status Value:
|
||
|
||
ERROR_SUCCESS The routine complete all operations normally
|
||
|
||
--*/
|
||
{
|
||
|
||
LONG lStatus = ERROR_SUCCESS;
|
||
BOOL bStatus = FALSE;
|
||
|
||
DWORD dwByteCount;
|
||
DWORD dwBytesRead;
|
||
|
||
HANDLE hDrive;
|
||
|
||
LPBYTE pBootSector;
|
||
|
||
dwByteCount = GetSectorSize (szBootDrive);
|
||
|
||
if (dwByteCount != 0xFFFFFFFF) {
|
||
// allocate buffer to read data into
|
||
pBootSector = (LPBYTE)GlobalAlloc(GPTR, dwByteCount);
|
||
} else {
|
||
pBootSector = NULL;
|
||
lStatus = GetLastError();
|
||
}
|
||
|
||
if (pBootSector != NULL) {
|
||
// if memory allocated successfully, then open drive
|
||
|
||
hDrive = CreateFile (
|
||
szBootDrive,
|
||
GENERIC_READ,
|
||
(FILE_SHARE_READ | FILE_SHARE_WRITE),
|
||
NULL,
|
||
OPEN_EXISTING,
|
||
FILE_ATTRIBUTE_NORMAL,
|
||
NULL);
|
||
|
||
if (hDrive != INVALID_HANDLE_VALUE) {
|
||
|
||
SetFilePointer (hDrive, 0, NULL, FILE_BEGIN); // go to beginning
|
||
|
||
bStatus = ReadFile (
|
||
hDrive,
|
||
pBootSector,
|
||
dwByteCount,
|
||
&dwBytesRead,
|
||
NULL);
|
||
|
||
if (bStatus) {
|
||
*pOutputBuffer = pBootSector;
|
||
lStatus = ERROR_SUCCESS;
|
||
} else {
|
||
// unable to read the file (drive) so return error
|
||
*pOutputBuffer = NULL;
|
||
lStatus = GetLastError();
|
||
}
|
||
// close handle now that we're done with it.
|
||
CloseHandle (hDrive);
|
||
} else {
|
||
// unable to open drive
|
||
*pOutputBuffer = NULL;
|
||
lStatus = GetLastError();
|
||
}
|
||
} else {
|
||
lStatus = ERROR_OUTOFMEMORY;
|
||
}
|
||
|
||
return lStatus;
|
||
}
|
||
|
||
DWORD
|
||
GetBootDiskDosVersion (
|
||
IN LPCTSTR szPath
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
examines the boot sector of the disk in the drive described in the
|
||
path variable and returns the MAJOR version of the OS that
|
||
formatted the disk.
|
||
|
||
Arguments:
|
||
|
||
IN LPCTSTR szPath
|
||
path containing drive to examine
|
||
|
||
|
||
Return Value:
|
||
|
||
Major version of MS-DOS that formatted the disk.
|
||
|
||
Zero is returned when:
|
||
-- the boot sector on the drive cannot be read
|
||
-- the drive is not a bootable drive
|
||
|
||
--*/
|
||
{
|
||
PDOS_BOOT_SECTOR pBootSector = NULL;
|
||
TCHAR szDrive[8];
|
||
DWORD dwReturn;
|
||
|
||
if (IsBootDisk(szPath)) {
|
||
szDrive[0] = cBackslash;
|
||
szDrive[1] = cBackslash;
|
||
szDrive[2] = cPeriod;
|
||
szDrive[3] = cBackslash;
|
||
szDrive[4] = szPath[0];
|
||
szDrive[5] = szPath[1];
|
||
szDrive[6] = 0;
|
||
szDrive[7] = 0;
|
||
|
||
if (CopyFatBootSectorToBuffer (
|
||
szDrive, (LPBYTE *)&pBootSector) == ERROR_SUCCESS) {
|
||
dwReturn = (pBootSector->bsOemName[5] - '0');
|
||
} else {
|
||
dwReturn = 0;
|
||
}
|
||
|
||
// free buffer allocated in CopyFatBootSectorToBuffer call.
|
||
FREE_IF_ALLOC (pBootSector);
|
||
} else {
|
||
dwReturn = 0;
|
||
}
|
||
return dwReturn;
|
||
}
|
||
|
||
DWORD
|
||
GetClusterSizeOfDisk (
|
||
IN LPCTSTR szPath
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
returns the cluster size (in bytes) of the disk in the path
|
||
|
||
Arguments:
|
||
|
||
Path containing disk drive to examine
|
||
|
||
Return Value:
|
||
|
||
cluster size (allocation unit size) of disk in bytes.
|
||
if the function cannot determine the cluster size, then
|
||
a value of 512 for floppy disk or 4096 for hard disks will
|
||
be returned.
|
||
|
||
--*/
|
||
{
|
||
DWORD dwSectorsPerCluster;
|
||
DWORD dwBytesPerSector;
|
||
DWORD dwFreeClusters;
|
||
DWORD dwClusters;
|
||
TCHAR szRoot[4]; // root dir of path
|
||
DWORD dwClusterSize = 0;
|
||
|
||
UINT nErrorMode;
|
||
|
||
// disable windows error message popup
|
||
nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
|
||
|
||
if (!IsUncPath(szPath)) {
|
||
szRoot[0] = szPath[0]; // drive letter
|
||
szRoot[1] = szPath[1]; // colon
|
||
szRoot[2] = cBackslash; // backslash
|
||
szRoot[3] = 0; // null terminator
|
||
|
||
if (GetDiskFreeSpace(szRoot, &dwSectorsPerCluster,
|
||
&dwBytesPerSector, &dwFreeClusters, &dwClusters)) {
|
||
dwClusterSize = dwSectorsPerCluster * dwBytesPerSector;
|
||
} else {
|
||
if (GetDriveType (szRoot) == DRIVE_FIXED) {
|
||
dwClusterSize = 4096;
|
||
} else {
|
||
dwClusterSize = 512;
|
||
}
|
||
}
|
||
} else {
|
||
dwClusterSize = 4096;
|
||
}
|
||
SetErrorMode (nErrorMode); // restore old error mode
|
||
return dwClusterSize;
|
||
}
|
||
|
||
DWORD
|
||
QuietGetFileSize (
|
||
IN LPCTSTR szPath
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns the size of the file passed in the arg list ( file sizz < 4GB)
|
||
while supressing any windows system error messages.
|
||
|
||
Arguments:
|
||
|
||
path to file to size
|
||
|
||
Return Value:
|
||
|
||
size of the file (if less then 4GB) or 0xFFFFFFFF if error
|
||
|
||
--*/
|
||
{
|
||
HANDLE hFile;
|
||
DWORD dwFileSizeLow, dwFileSizeHigh;
|
||
DWORD dwReturn;
|
||
UINT nErrorMode;
|
||
|
||
// disable windows error message popup
|
||
nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
|
||
|
||
// get the size of the file and add it to the total
|
||
hFile = CreateFile (
|
||
szPath,
|
||
GENERIC_READ,
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
NULL,
|
||
OPEN_EXISTING,
|
||
FILE_ATTRIBUTE_NORMAL,
|
||
NULL);
|
||
if (hFile != INVALID_HANDLE_VALUE) {
|
||
// then the file was opened successfully
|
||
// go get it's size
|
||
dwFileSizeLow = GetFileSize (hFile, &dwFileSizeHigh);
|
||
dwReturn = dwFileSizeLow;
|
||
// now close the file handle
|
||
CloseHandle (hFile);
|
||
} else {
|
||
// unable to open file so return error
|
||
dwReturn = 0xFFFFFFFF;
|
||
}
|
||
|
||
SetErrorMode (nErrorMode); // restore old error mode
|
||
|
||
return dwReturn;
|
||
}
|
||
|