mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
702 lines
18 KiB
702 lines
18 KiB
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name :
|
|
|
|
vvolume.cxx
|
|
|
|
Abstract:
|
|
|
|
Defines functions for virtual volumes used by all servers.
|
|
|
|
|
|
Author:
|
|
|
|
Murali R. Krishnan ( MuraliK ) 27-Oct-1994
|
|
|
|
Project:
|
|
|
|
Gopher Server DLL
|
|
|
|
Functions Exported:
|
|
|
|
DWORD TsInitializeVVolumes( OUT PHKEY phkeyReg,
|
|
IN LPCTSTR lpszSubKey)
|
|
|
|
DWORD TsCleanupVVolumes( IN HKEY phkeyReg)
|
|
|
|
BOOL TsGetPathRealForVirtual( IN LPVOID lpvReserved,
|
|
IN const STR & pstrVPath,
|
|
OUT STR * pstrRealPath,
|
|
OUT LPDWORD lpdwFileSystem)
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
/*
|
|
Implementation of Virtual Volumes:
|
|
|
|
There is a mapping between the virtual volume and real volume.
|
|
Administrator establishes the mapping. The server uses this
|
|
mapping to associate a virtual path name with the real path name.
|
|
|
|
We store this associations in a list locally now.
|
|
Later this will be moved into tcpsvcs.dll
|
|
|
|
*/
|
|
|
|
|
|
/************************************************************
|
|
* Include Headers
|
|
************************************************************/
|
|
|
|
# ifdef __cplusplus
|
|
extern "C" {
|
|
# endif // __cplusplus
|
|
|
|
# include <nt.h>
|
|
# include <ntrtl.h>
|
|
# include <nturtl.h>
|
|
|
|
# ifdef __cplusplus
|
|
};
|
|
# endif // __cplusplus
|
|
|
|
# include "tsunami.hxx"
|
|
# include "vvolume.h"
|
|
# include <tchar.h>
|
|
|
|
# include "dbgutil.h"
|
|
|
|
/************************************************************
|
|
* Static Variables
|
|
************************************************************/
|
|
|
|
//
|
|
// These global variables should be organized properly once
|
|
// we move into tcpsvcs.dll NYI
|
|
//
|
|
|
|
static LIST_ENTRY g_lVRAssoc; // list of Virtual-Real associations
|
|
static BOOL g_fVRInited = FALSE;
|
|
|
|
# define MAX_FILE_SYSTEM_NAME_SIZE ( 100)
|
|
|
|
|
|
/************************************************************
|
|
* Local Type definitions
|
|
************************************************************/
|
|
|
|
# define MAX_VR_VIRTUAL_NAME_LEN ( 20)
|
|
# define MAX_VR_REAL_NAME_LEN ( 80)
|
|
|
|
class VR_VOLUMES_INFO {
|
|
|
|
private:
|
|
|
|
TCHAR m_pszVirtual[MAX_VR_VIRTUAL_NAME_LEN]; // virtual volume name
|
|
TCHAR m_pszRealPath[MAX_VR_REAL_NAME_LEN]; // path for the real volume
|
|
DWORD m_dwFileSystem;
|
|
DWORD m_dwFlags;
|
|
BOOL m_fValid; // is this data valid?
|
|
|
|
public:
|
|
|
|
VR_VOLUMES_INFO( const TCHAR * pszVirtual,
|
|
const TCHAR * pszReal,
|
|
DWORD dwFileSystem,
|
|
DWORD dwFlags);
|
|
|
|
~VR_VOLUMES_INFO( VOID)
|
|
{ }
|
|
|
|
const TCHAR * GetVirtualName( VOID) const
|
|
{ return m_pszVirtual; }
|
|
|
|
const TCHAR * GetRealName( VOID) const
|
|
{ return m_pszRealPath; }
|
|
|
|
DWORD GetFileSystem( VOID) const
|
|
{ return m_dwFileSystem; }
|
|
|
|
DWORD GetFlags( VOID) const
|
|
{ return m_dwFlags; }
|
|
|
|
BOOL IsValid( VOID) const
|
|
{ return m_fValid; }
|
|
|
|
//
|
|
// Following are added since we use ntrtl List structures
|
|
// ( will not be required if we use templated lists of C++)
|
|
//
|
|
|
|
public:
|
|
LIST_ENTRY m_listEntry;
|
|
|
|
LIST_ENTRY & GetListEntry( VOID)
|
|
{ return m_listEntry; }
|
|
|
|
}; // class VR_VOLUMES_INFO
|
|
|
|
typedef VR_VOLUMES_INFO * LPVR_VOLUMES_INFO;
|
|
|
|
|
|
VR_VOLUMES_INFO::VR_VOLUMES_INFO(
|
|
const TCHAR * pszVirtual,
|
|
const TCHAR * pszReal,
|
|
DWORD dwFileSystem,
|
|
DWORD dwFlags)
|
|
{
|
|
if ( _tcslen( pszVirtual) >= MAX_VR_VIRTUAL_NAME_LEN ||
|
|
_tcslen( pszReal) >= MAX_VR_REAL_NAME_LEN
|
|
) {
|
|
|
|
m_fValid = FALSE;
|
|
}
|
|
|
|
_tcscpy( m_pszVirtual, pszVirtual);
|
|
_tcscpy( m_pszRealPath, pszReal);
|
|
|
|
// Use GetVolumeInformation( ) to set the file system. NYI
|
|
|
|
m_dwFileSystem = dwFileSystem;
|
|
m_dwFlags = dwFlags;
|
|
|
|
m_fValid = TRUE;
|
|
} // VR_VOLUMES_INFO::VR_VOLUMES_INFO()
|
|
|
|
|
|
|
|
/************************************************************
|
|
* Functions
|
|
************************************************************/
|
|
|
|
|
|
static DWORD
|
|
GetFileSystemType( IN LPCTSTR pszRealPath,
|
|
OUT LPDWORD lpdwFileSystem,
|
|
OUT LPDWORD lpdwFlags)
|
|
/*++
|
|
Gets file system specific information for a given path.
|
|
It uses GetVolumeInfomration() to query the file system type
|
|
and file system flags.
|
|
On success the flags and file system type are returned in
|
|
passed in pointers.
|
|
|
|
Arguments:
|
|
|
|
pszRealPath pointer to buffer containing path for which
|
|
we are inquiring the file system details.
|
|
|
|
lpdwFileSystem
|
|
pointer to buffer to fill in the type of file system.
|
|
|
|
lpdwFlags
|
|
pointer to buffer to fill in the flags for this volume.
|
|
|
|
Returns:
|
|
NO_ERROR on success and Win32 error code if any error.
|
|
|
|
--*/
|
|
{
|
|
TCHAR rgchBuf[MAX_FILE_SYSTEM_NAME_SIZE];
|
|
TCHAR rgchRoot[11];
|
|
int i;
|
|
DWORD dwReturn = ERROR_PATH_NOT_FOUND;
|
|
|
|
if ( pszRealPath == NULL ||
|
|
lpdwFileSystem == NULL ||
|
|
lpdwFlags == NULL) {
|
|
|
|
return ( ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
memset( (void *) rgchRoot, 0, 11*sizeof( TCHAR));
|
|
|
|
*lpdwFileSystem = FS_ERROR;
|
|
*lpdwFlags = 0;
|
|
|
|
//
|
|
// Copy just the root directory to rgchRoot for querying
|
|
//
|
|
|
|
for( i = 0; i < 9 && pszRealPath[i] != TEXT('\0'); i++) {
|
|
|
|
if ( (rgchRoot[i] = pszRealPath[i]) == TEXT( ':')) {
|
|
|
|
break;
|
|
}
|
|
} // for
|
|
|
|
if ( rgchRoot[i] != TEXT( ':')) {
|
|
|
|
//
|
|
// we could not find the root directory.
|
|
// return with error value
|
|
//
|
|
return ( ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
rgchRoot[i+1] = TEXT('\\'); // terminate the drive spec with \
|
|
rgchRoot[i+2] = TEXT('\0'); // terminate the drive spec with null char
|
|
|
|
DBG_LOG( " GetVolumeInformation( %s :%d) i = %d\n",
|
|
rgchRoot, strlen( rgchRoot), i);
|
|
|
|
if ( GetVolumeInformation( rgchRoot, // lpRootPathName
|
|
NULL, // lpVolumeNameBuffer
|
|
0, // length of volume name buffer
|
|
NULL, // lpdwVolSerialNumber
|
|
NULL, // lpdwMaxComponentLength
|
|
lpdwFlags, // lpdwSystemFlags
|
|
rgchBuf, // lpFileSystemNameBuff
|
|
MAX_FILE_SYSTEM_NAME_SIZE
|
|
)
|
|
) {
|
|
|
|
dwReturn = NO_ERROR;
|
|
|
|
if ( strcmp( rgchBuf, "FAT") == 0) {
|
|
|
|
*lpdwFileSystem = FS_FAT;
|
|
} else
|
|
if ( strcmp( rgchBuf, "NTFS") == 0) {
|
|
|
|
*lpdwFileSystem = FS_NTFS;
|
|
} else
|
|
if ( strcmp( rgchBuf, "HPFS") == 0) {
|
|
|
|
*lpdwFileSystem = FS_HPFS;
|
|
} else
|
|
if ( strcmp( rgchBuf, "OFS") == 0) {
|
|
|
|
*lpdwFileSystem = FS_OFS;
|
|
} else {
|
|
|
|
dwReturn = ERROR_PATH_NOT_FOUND;
|
|
}
|
|
|
|
} else {
|
|
|
|
|
|
DBG_LOG( " GetVolumeInformation( %s) failed with error %d\n",
|
|
rgchRoot, GetLastError());
|
|
}
|
|
|
|
DBG_LOG( " Got File system name for %s as : %s\n", pszRealPath, rgchBuf);
|
|
|
|
return ( dwReturn);
|
|
} // GetFileSystemType()
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
TsInitializeVVolumes( IN OUT LPVOID lpv,
|
|
IN LPCTSTR lpszRegSubKey)
|
|
/*++
|
|
TsInitializeVVolumes()
|
|
|
|
Initializes local data structures and loads virtual volumes
|
|
information from HKEY_LOCAL_MACHINE registry using
|
|
supplied subkey.
|
|
|
|
If the the association is already initialized, it is cleaned
|
|
up and new contents from registry are read.
|
|
|
|
Arguments:
|
|
|
|
lpv pointer to void ( NOW).
|
|
Later on this may become pointer to SERVICE_INFO.
|
|
|
|
lpszRegSubKey sub key for registry location containing
|
|
virtual volumes information.
|
|
|
|
Returns:
|
|
|
|
NO_ERROR on sucess.
|
|
Otherwise returns Win32 error code
|
|
|
|
--*/
|
|
{
|
|
|
|
DWORD dwErrorCode;
|
|
DWORD dwFileSystem;
|
|
DWORD dwFlags;
|
|
UINT index;
|
|
DWORD cbReal;
|
|
DWORD cchVirtual;
|
|
DWORD dwType;
|
|
LPVR_VOLUMES_INFO lpvr;
|
|
HKEY hkeyReg = NULL;
|
|
TCHAR rgchVirtual[MAX_VR_VIRTUAL_NAME_LEN];
|
|
TCHAR rgchReal[MAX_VR_REAL_NAME_LEN];
|
|
|
|
|
|
DBG_LOG( "Entering TsInitializeVVolumes( %08x, %s)\n", lpv, lpszRegSubKey);
|
|
//
|
|
// Open a key to the registry entry we want
|
|
//
|
|
dwErrorCode = RegOpenKeyEx( HKEY_LOCAL_MACHINE, // handle to key
|
|
lpszRegSubKey, // name of subkey
|
|
0, // reserved
|
|
KEY_ALL_ACCESS, // security mask
|
|
& hkeyReg); // handle to open key
|
|
|
|
if ( dwErrorCode != NO_ERROR) {
|
|
|
|
//
|
|
// Unable to open key to registry
|
|
//
|
|
|
|
return ( dwErrorCode);
|
|
}
|
|
|
|
if ( g_fVRInited) {
|
|
|
|
//
|
|
// cleanup old stuff before proceeding to reinitialize
|
|
// the contents of VR mapping
|
|
//
|
|
|
|
PLIST_ENTRY pl = &g_lVRAssoc;
|
|
|
|
DBG_LOG( " TsInitVVolumes() Cleaning up old stuff\n");
|
|
|
|
for( pl = g_lVRAssoc.Flink;
|
|
pl != &g_lVRAssoc;
|
|
) {
|
|
|
|
lpvr = CONTAINING_RECORD( pl, VR_VOLUMES_INFO, m_listEntry);
|
|
|
|
pl = pl->Flink; // get the next record pointer
|
|
|
|
delete lpvr; // delete this record
|
|
} // for
|
|
|
|
g_fVRInited = FALSE;
|
|
|
|
}
|
|
|
|
InitializeListHead( &g_lVRAssoc);
|
|
|
|
//
|
|
// Loop through enumerating the data present under the given key
|
|
// and store them as the virtual/real mappings locally
|
|
//
|
|
|
|
for( index = 0;
|
|
/* No Condition specified */ TRUE ;
|
|
index++
|
|
) {
|
|
|
|
cchVirtual = sizeof( rgchVirtual);
|
|
cbReal = sizeof( rgchReal) * sizeof( TCHAR);
|
|
|
|
dwErrorCode = RegEnumValue(
|
|
hkeyReg, // handle of key to query
|
|
index, // index of value to query
|
|
rgchVirtual, // pointer to value string
|
|
&cchVirtual, // pointer for length of virtual string
|
|
0, // reserved
|
|
&dwType, // pointer for storing type
|
|
(LPBYTE ) rgchReal, // pointer to real path name
|
|
&cbReal // pointer for length of real path
|
|
);
|
|
|
|
DBG_LOG( "TsInitVVolume() Read Virt ( %s) = Real ( %s)\n",
|
|
rgchVirtual, rgchReal);
|
|
|
|
ASSERT( dwType == REG_SZ);
|
|
|
|
if ( dwErrorCode != NO_ERROR) {
|
|
|
|
//
|
|
// Possibly some error
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
dwErrorCode = GetFileSystemType( rgchReal,
|
|
&dwFileSystem,
|
|
&dwFlags);
|
|
if ( dwErrorCode != NO_ERROR) {
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Valid contents -- copy to local association structure
|
|
// and add to the list of associations
|
|
//
|
|
|
|
//
|
|
// Checking for validity of volume name NYI
|
|
//
|
|
|
|
// No duplicates checking done here NYI
|
|
|
|
lpvr = new VR_VOLUMES_INFO( rgchVirtual,
|
|
rgchReal,
|
|
dwFileSystem,
|
|
dwFlags);
|
|
|
|
if ( lpvr == NULL ||
|
|
!lpvr->IsValid()) {
|
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// add to list of VR volume associations
|
|
//
|
|
|
|
InsertTailList( &g_lVRAssoc, &lpvr->GetListEntry());
|
|
|
|
} // for
|
|
|
|
|
|
if ( dwErrorCode == ERROR_NO_MORE_ITEMS ||
|
|
dwErrorCode == NO_ERROR ) {
|
|
|
|
//
|
|
// Valid termination of above loop. Set g_fVRInited
|
|
//
|
|
|
|
dwErrorCode = NO_ERROR;
|
|
g_fVRInited = TRUE;
|
|
} else {
|
|
|
|
// an error exit.
|
|
g_fVRInited = FALSE;
|
|
}
|
|
|
|
if( hkeyReg != NULL ) {
|
|
|
|
DWORD dwerr = RegCloseKey( hkeyReg);
|
|
|
|
ASSERT( dwerr == NO_ERROR);
|
|
}
|
|
|
|
//
|
|
// retrun
|
|
//
|
|
|
|
return ( dwErrorCode);
|
|
|
|
} // TsInitializeVVolumes()
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
TsCleanupVVolumes( IN OUT LPVOID lpv)
|
|
/*++
|
|
|
|
TsCleanupVVolumes()
|
|
|
|
Cleansup local data structures associated with virtual volumes
|
|
for given service.
|
|
|
|
Arguments:
|
|
|
|
lpv pointer to void ( NOW).
|
|
Later on this may become pointer to SERVICE_INFO.
|
|
|
|
Returns:
|
|
|
|
NO_ERROR on sucess and
|
|
Win32 error code if there are any errors
|
|
|
|
--*/
|
|
{
|
|
LPVR_VOLUMES_INFO lpvr;
|
|
|
|
if ( g_fVRInited) {
|
|
|
|
//
|
|
// cleanup old stuff before proceeding to reinitialize
|
|
// the contents of VR mapping
|
|
//
|
|
|
|
PLIST_ENTRY pl = &g_lVRAssoc;
|
|
|
|
for( pl = g_lVRAssoc.Flink;
|
|
pl != &g_lVRAssoc;
|
|
) {
|
|
|
|
lpvr = CONTAINING_RECORD( pl, VR_VOLUMES_INFO, m_listEntry);
|
|
|
|
pl = pl->Flink; // get the next record pointer
|
|
|
|
delete lpvr; // delete this record
|
|
} // for
|
|
|
|
g_fVRInited = FALSE;
|
|
|
|
}
|
|
|
|
return ( NO_ERROR);
|
|
|
|
} // TsCleanupVVolumes()
|
|
|
|
|
|
|
|
BOOL
|
|
TsGetPathRealFromVirtual( IN LPVOID lpv,
|
|
IN LPCTSTR pszVPath,
|
|
OUT LPCTSTR * ppszRealPrefix,
|
|
OUT LPCTSTR * ppszRealSuffix,
|
|
OUT LPDWORD lpdwFileSystem)
|
|
/*++
|
|
|
|
TsGetPathRealFromVirtual()
|
|
|
|
Arguments:
|
|
|
|
lpv pointer to void ( NOW).
|
|
Later on this may become pointer to SERVICE_INFO.
|
|
|
|
pszVPath pointer to null terminated string containing the
|
|
virtual path. The components in path
|
|
are to be separated by "\".
|
|
|
|
ppszRealPrefix pointer to buffer to store a pointer to
|
|
null terminated string ( read-only) containing
|
|
the prefix for real volume. The real path prefix
|
|
does not end in a "\".
|
|
|
|
ppszRealSuffix pointer to buffer to store a pointer tp
|
|
null terminated string ( read-only) containing
|
|
the suffix of the virtual path supplied after
|
|
removing the virtual path components.
|
|
The real suffix string starts with a leading "\".
|
|
|
|
lpdwFileSystem
|
|
pointer to buffer to store the type of file
|
|
system to which the real volume belongs to.
|
|
If NULL the file system type is not stored.
|
|
|
|
Returns:
|
|
|
|
TRUE if a successful mapping is found and virtual -to -real
|
|
mapping exists.
|
|
FALSE if there is no mapping and sets error to ERROR_PATH_NOT_FOUND.
|
|
Parameters ppszRealPrefix, ppszRealSuffix and lpdwFileSystem
|
|
get null values on no match
|
|
If there are any errors. Use GetLastError() for other errors.
|
|
|
|
Note:
|
|
|
|
This function DOES NOT do any allocation of its own.
|
|
It returns read only pointers to both the prefix and suffix
|
|
on successful matching and it is upto the caller to
|
|
use them appropriately or allocate space.
|
|
Attempt to write into these read-only pointers may corrupt
|
|
the mappings.
|
|
|
|
Example:
|
|
|
|
Given foo --> d:\test,
|
|
for /foo/bar/this we get
|
|
RealPrefix = d:\test
|
|
RealSuffix = \bar\this
|
|
|
|
History:
|
|
|
|
MuraliK (Created) 27-Oct-1994
|
|
|
|
Limitations:
|
|
|
|
The mapping assumes that the virtual volume name is contained
|
|
within the first component
|
|
--*/
|
|
{
|
|
LPTSTR prealSuffix;
|
|
PLIST_ENTRY pl;
|
|
LPVR_VOLUMES_INFO lpvr;
|
|
UINT cchVname;
|
|
|
|
if ( !g_fVRInited ||
|
|
pszVPath == NULL ||
|
|
ppszRealPrefix == NULL ||
|
|
ppszRealSuffix == NULL
|
|
) {
|
|
|
|
SetLastError( ERROR_INVALID_PARAMETER);
|
|
return ( FALSE);
|
|
}
|
|
|
|
if ( *pszVPath == TEXT('\\')) {
|
|
pszVPath++; // skip the leading "\"
|
|
}
|
|
|
|
*ppszRealPrefix = NULL;
|
|
*ppszRealSuffix = NULL;
|
|
if ( lpdwFileSystem != NULL) {
|
|
*lpdwFileSystem = FS_ERROR;
|
|
}
|
|
|
|
//
|
|
// Split virtual path into virtual volume name and suffix
|
|
//
|
|
|
|
prealSuffix = _tcschr( pszVPath, TEXT( '\\'));
|
|
|
|
cchVname = ( prealSuffix == NULL) ?
|
|
_tcslen( pszVPath): // is entire length
|
|
( prealSuffix - pszVPath); // is only portion
|
|
|
|
//
|
|
// Loop through and compare with each association in the list
|
|
//
|
|
|
|
for( pl = g_lVRAssoc.Flink;
|
|
pl != &g_lVRAssoc;
|
|
pl = pl->Flink
|
|
) {
|
|
|
|
lpvr = CONTAINING_RECORD( pl, VR_VOLUMES_INFO, m_listEntry);
|
|
|
|
if ( _tcsncmp( lpvr->GetVirtualName(),
|
|
pszVPath, cchVname) == 0
|
|
) {
|
|
|
|
//
|
|
// Found the associating real path name
|
|
// Set all values and return
|
|
//
|
|
|
|
*ppszRealPrefix = lpvr->GetRealName();
|
|
*ppszRealSuffix = prealSuffix;
|
|
|
|
if ( lpdwFileSystem != NULL) {
|
|
*lpdwFileSystem = lpvr->GetFileSystem();
|
|
}
|
|
|
|
return ( TRUE);
|
|
}
|
|
|
|
} // for
|
|
|
|
|
|
//
|
|
// Completely scanned the list. Virtual path is not found.
|
|
// Return error
|
|
//
|
|
|
|
SetLastError( ERROR_PATH_NOT_FOUND);
|
|
return ( FALSE);
|
|
|
|
} // TsGetPathRealFromVirtual()
|
|
|
|
|
|
|
|
|
|
/************************ End of File ***********************/
|