419 lines
10 KiB
C++
419 lines
10 KiB
C++
|
|
||
|
//+==========================================================================
|
||
|
//
|
||
|
// File: CDir.cxx
|
||
|
//
|
||
|
// Purpose: Define the CDirectory class.
|
||
|
//
|
||
|
// This class is used to represent a directory name.
|
||
|
// Along with maintaining the name, it can determine
|
||
|
// the type of FileSystem.
|
||
|
//
|
||
|
//+==========================================================================
|
||
|
|
||
|
|
||
|
// --------
|
||
|
// Includes
|
||
|
// --------
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
#include <wchar.h>
|
||
|
#include <wtypes.h>
|
||
|
|
||
|
#include "CFMEx.hxx"
|
||
|
#include "CDir.hxx"
|
||
|
|
||
|
|
||
|
//+------------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: CDirectory::Initialize (no arguments)
|
||
|
//
|
||
|
// Synopsis: Generate a directory name, using the TEMP environment
|
||
|
// variable, and use it to initialize this object.
|
||
|
//
|
||
|
// Inputs: None.
|
||
|
//
|
||
|
// Outputs: TRUE if the function succeeds, FALSE otherwise.
|
||
|
//
|
||
|
//+------------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CDirectory::Initialize()
|
||
|
{
|
||
|
// ---------------
|
||
|
// Local Variables
|
||
|
// ---------------
|
||
|
|
||
|
// Assume failure for now.
|
||
|
BOOL bSuccess = FALSE;
|
||
|
|
||
|
// The TEMP environment variable.
|
||
|
WCHAR wszSystemTempPath[ MAX_PATH + sizeof( L'\0' )];
|
||
|
|
||
|
// Reset the error code.
|
||
|
m_lError = 0L;
|
||
|
|
||
|
// ----------
|
||
|
// Get %TEMP%
|
||
|
// ----------
|
||
|
|
||
|
if( !GetTempPath( MAX_PATH,
|
||
|
wszSystemTempPath )
|
||
|
)
|
||
|
{
|
||
|
m_lError = GetLastError();
|
||
|
EXIT( L"GetTempPath() failed (%d)" );
|
||
|
}
|
||
|
|
||
|
// ----------------------
|
||
|
// Initialize this object
|
||
|
// ----------------------
|
||
|
|
||
|
// Initialize using the temporary path. We must never pass a NULL here,
|
||
|
// or we'll cause an infinite recursion.
|
||
|
|
||
|
if( wszSystemTempPath == NULL )
|
||
|
EXIT( L"Invalid temporary path" );
|
||
|
bSuccess = Initialize( wszSystemTempPath );
|
||
|
|
||
|
// ----
|
||
|
// Exit
|
||
|
// ----
|
||
|
|
||
|
Exit:
|
||
|
|
||
|
return( bSuccess );
|
||
|
|
||
|
}
|
||
|
|
||
|
//+-----------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: CDirectory::Initialize (with an ANSI string)
|
||
|
//
|
||
|
// Synopsis: This function converts the ANSI string to a Unicode
|
||
|
// string, then initializes the object with it.
|
||
|
//
|
||
|
// Inputs: A Unicode string.
|
||
|
//
|
||
|
// Outputs: TRUE if the function succeeds, FALSE otherwise.
|
||
|
//
|
||
|
//+-----------------------------------------------------------------------
|
||
|
|
||
|
BOOL CDirectory::Initialize( LPCSTR szDirectory )
|
||
|
{
|
||
|
// ---------------
|
||
|
// Local Variables
|
||
|
// ---------------
|
||
|
|
||
|
// Assume failure.
|
||
|
BOOL bSuccess = FALSE;
|
||
|
|
||
|
// A buffer for the Unicode path
|
||
|
WCHAR wszDirectory[ MAX_UNICODE_PATH + sizeof( L'\0' )];
|
||
|
|
||
|
// -----
|
||
|
// Begin
|
||
|
// -----
|
||
|
|
||
|
// Initialize the error code.
|
||
|
m_lError = 0L;
|
||
|
|
||
|
|
||
|
// If we were givin a NULL path, use the version of Initialize
|
||
|
// that requires no path.
|
||
|
|
||
|
if( szDirectory == NULL )
|
||
|
{
|
||
|
bSuccess = Initialize();
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
// Convert the Ansi name to Unicode.
|
||
|
|
||
|
if( m_lError = (long) AnsiToUnicode( szDirectory,
|
||
|
wszDirectory,
|
||
|
strlen( szDirectory )
|
||
|
)
|
||
|
)
|
||
|
{
|
||
|
EXIT( L"Unable to convert directory to Unicode" );
|
||
|
}
|
||
|
|
||
|
// Initialize using the temporary path. We must never pass a NULL here,
|
||
|
// or we'll cause an infinite recursion.
|
||
|
|
||
|
if( wszDirectory == NULL )
|
||
|
EXIT( L"Invalid Directory (internal error)" );
|
||
|
bSuccess = Initialize( wszDirectory );
|
||
|
|
||
|
// ----
|
||
|
// Exit
|
||
|
// ----
|
||
|
|
||
|
Exit:
|
||
|
|
||
|
return( bSuccess );
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-----------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: CDirectory::Initialize (with a Unicode string)
|
||
|
//
|
||
|
// Synopsis: This function is the only form of Initialize
|
||
|
// (there are several variations of the Initialize member)
|
||
|
// which really initializes the object. It stores the
|
||
|
// directory name, and determines the type of filesystem
|
||
|
// on which it resides.
|
||
|
//
|
||
|
// Inputs: A Unicode string.
|
||
|
//
|
||
|
// Outputs: TRUE if the function succeeds, FALSE otherwise.
|
||
|
//
|
||
|
//+-----------------------------------------------------------------------
|
||
|
|
||
|
BOOL CDirectory::Initialize( LPCWSTR wszDirectory )
|
||
|
{
|
||
|
|
||
|
// ---------------
|
||
|
// Local Variables
|
||
|
// ---------------
|
||
|
|
||
|
// Assume failure.
|
||
|
BOOL bSuccess = FALSE;
|
||
|
|
||
|
// Buffers for the root of the path and for the volume name.
|
||
|
WCHAR wszDirectoryRoot[ MAX_PATH + sizeof( L'\0' )];
|
||
|
WCHAR wszVolumeName[ MAX_PATH + sizeof( L'\0' )];
|
||
|
|
||
|
// Parameters to GetVolumeInformation which we won't use.
|
||
|
DWORD dwMaxComponentLength = 0L;
|
||
|
DWORD dwFileSystemFlags = 0L;
|
||
|
|
||
|
// -----
|
||
|
// Begin
|
||
|
// -----
|
||
|
|
||
|
// Initialize the error code.
|
||
|
m_lError = 0L;
|
||
|
|
||
|
// If we were given a NULL path, use the variation of Initialization()
|
||
|
// which does not require one. Note that we will then be called again,
|
||
|
// but this time with a path.
|
||
|
|
||
|
if( wszDirectory == NULL )
|
||
|
{
|
||
|
bSuccess = Initialize();
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
// Validate the path.
|
||
|
|
||
|
if( wcslen( wszDirectory ) > MAX_PATH )
|
||
|
{
|
||
|
m_lError = wcslen( wszDirectory );
|
||
|
EXIT( L"Input path is too long (%d)\n" );
|
||
|
}
|
||
|
|
||
|
// Save the path to our member buffer
|
||
|
|
||
|
wcscpy( m_wszDirectory, wszDirectory );
|
||
|
|
||
|
|
||
|
// ------------------------
|
||
|
// Get the file system name
|
||
|
// ------------------------
|
||
|
|
||
|
// Get the root path to the directory.
|
||
|
|
||
|
wcscpy( wszDirectoryRoot, wszDirectory );
|
||
|
MakeRoot( wszDirectoryRoot );
|
||
|
|
||
|
// Get the volume information, which will include the filesystem name.
|
||
|
|
||
|
if( !GetVolumeInformation( wszDirectoryRoot, // Root path name.
|
||
|
wszVolumeName, // Buffer for volume name
|
||
|
MAX_PATH, // Length of the above buffer
|
||
|
NULL, // Buffer for serial number
|
||
|
// Longest filename length.
|
||
|
&dwMaxComponentLength,
|
||
|
&dwFileSystemFlags, // Compression, etc.
|
||
|
m_wszFileSystemName,// Buffer for the FS name.
|
||
|
MAX_PATH ) // Length of above buffer
|
||
|
)
|
||
|
{
|
||
|
m_lError = GetLastError();
|
||
|
EXIT( L"GetVolumeInformation() failed" );
|
||
|
}
|
||
|
|
||
|
|
||
|
// Determine the file system type from the name.
|
||
|
|
||
|
if( !wcscmp( m_wszFileSystemName, L"FAT" ))
|
||
|
m_FileSystemType = fstFAT;
|
||
|
|
||
|
else if( !wcscmp( m_wszFileSystemName, L"NTFS" ))
|
||
|
m_FileSystemType = fstNTFS;
|
||
|
|
||
|
else if( !wcscmp( m_wszFileSystemName, L"OFS" ))
|
||
|
m_FileSystemType = fstOFS;
|
||
|
|
||
|
else
|
||
|
m_FileSystemType = fstUnknown;
|
||
|
|
||
|
bSuccess = TRUE;
|
||
|
|
||
|
// ----
|
||
|
// Exit
|
||
|
// ----
|
||
|
|
||
|
Exit:
|
||
|
|
||
|
DisplayErrors( bSuccess, L"CDirectory::Initialize( wszDirectory )" );
|
||
|
return( bSuccess );
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// GetRootLength
|
||
|
//
|
||
|
// This routine was simply copied from private\windows\shell\shelldll\tracker.cxx,
|
||
|
// and should not be modified here.
|
||
|
//
|
||
|
|
||
|
unsigned
|
||
|
CDirectory::GetRootLength(const WCHAR *pwszPath)
|
||
|
{
|
||
|
ULONG cwcRoot = 0;
|
||
|
m_lError = 0L;
|
||
|
|
||
|
if (pwszPath == 0)
|
||
|
pwszPath = L"";
|
||
|
|
||
|
if (*pwszPath == L'\\')
|
||
|
{
|
||
|
// If the first character is a path separator (backslash), this
|
||
|
// must be a UNC drive designator which must be of the form:
|
||
|
// <path-separator><path-separator>(<alnum>+)
|
||
|
// <path-separator>(<alnum>+)<path-separator>
|
||
|
//
|
||
|
// This covers drives like these: \\worf\scratch\ and
|
||
|
// \\savik\win4dev\.
|
||
|
//
|
||
|
pwszPath++;
|
||
|
cwcRoot++;
|
||
|
|
||
|
BOOL fMachine = FALSE;
|
||
|
BOOL fShare = FALSE;
|
||
|
|
||
|
if (*pwszPath == L'\\')
|
||
|
{
|
||
|
cwcRoot++;
|
||
|
pwszPath++;
|
||
|
|
||
|
while (*pwszPath != '\0' && *pwszPath != L'\\')
|
||
|
{
|
||
|
cwcRoot++;
|
||
|
pwszPath++;
|
||
|
|
||
|
fMachine = TRUE;
|
||
|
}
|
||
|
|
||
|
if (*pwszPath == L'\\')
|
||
|
{
|
||
|
cwcRoot++;
|
||
|
pwszPath++;
|
||
|
|
||
|
while (*pwszPath != '\0' && *pwszPath != L'\\')
|
||
|
{
|
||
|
cwcRoot++;
|
||
|
pwszPath++;
|
||
|
|
||
|
fShare = TRUE;
|
||
|
}
|
||
|
|
||
|
// If there weren't any characters in the machine or
|
||
|
// share portions of the UNC name, then the drive
|
||
|
// designator is bogus.
|
||
|
//
|
||
|
if (!fMachine || !fShare)
|
||
|
{
|
||
|
cwcRoot = 0;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cwcRoot = 0;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cwcRoot = 0;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
if (iswalpha(*pwszPath))
|
||
|
{
|
||
|
// If the first character is an alphanumeric, we must have
|
||
|
// a drive designator of this form:
|
||
|
// (<alnum>)+<drive-separator><path-separator>
|
||
|
//
|
||
|
// This covers drives like these: a:\, c:\, etc
|
||
|
//
|
||
|
|
||
|
pwszPath++;
|
||
|
cwcRoot++;
|
||
|
|
||
|
if (*pwszPath == L':')
|
||
|
{
|
||
|
cwcRoot++;
|
||
|
pwszPath++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cwcRoot = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If we have counted one or more characters in the root and these
|
||
|
// are followed by a component separator, we need to add the separator
|
||
|
// to the root length. Otherwise this is not a valid root and we need
|
||
|
// to return a length of zero.
|
||
|
//
|
||
|
if ((cwcRoot > 0) && (*pwszPath == L'\\'))
|
||
|
{
|
||
|
cwcRoot++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cwcRoot = 0;
|
||
|
}
|
||
|
|
||
|
return (cwcRoot);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// MakeRoot
|
||
|
//
|
||
|
// This routine was simply copied from private\windows\shell\shelldll\tracker.cxx,
|
||
|
// and should not be modified here.
|
||
|
//
|
||
|
|
||
|
|
||
|
VOID
|
||
|
CDirectory::MakeRoot(WCHAR *pwszPath)
|
||
|
{
|
||
|
unsigned rootlength = GetRootLength(pwszPath);
|
||
|
m_lError = 0L;
|
||
|
|
||
|
if (rootlength)
|
||
|
{
|
||
|
pwszPath[rootlength] = L'\0';
|
||
|
}
|
||
|
}
|
||
|
|