windows-nt/Source/XPSP1/NT/admin/snapin/dfsadmin/dfsshlex/dfspath.cpp
2020-09-26 16:20:57 +08:00

327 lines
10 KiB
C++

/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
DfsPath.cpp
Abstract:
This is the implementation file for Dfs Shell path handling modules for the Dfs Shell
Extension object.
Author:
Environment:
NT only.
--*/
#include <nt.h>
#include <ntrtl.h>
#include <ntioapi.h>
#include <nturtl.h>
#include <windef.h>
#include <winbase.h>
#include <lmerr.h>
#include <lmcons.h>
#include <lmdfs.h>
#include <lmapibuf.h>
#include <tchar.h>
#include "DfsPath.h"
//--------------------------------------------------------------------------------------------
//
// caller of this function must call free() on *o_ppszRemotePath
//
HRESULT GetRemotePath(
LPCTSTR i_pszPath,
PTSTR *o_ppszRemotePath
)
{
if (!i_pszPath || !*i_pszPath || !o_ppszRemotePath)
return E_INVALIDARG;
if (*o_ppszRemotePath)
free(*o_ppszRemotePath); // to prevent memory leak
UNICODE_STRING unicodePath;
RtlInitUnicodeString(&unicodePath, i_pszPath);
OBJECT_ATTRIBUTES ObjectAttributes;
InitializeObjectAttributes(&ObjectAttributes,
&unicodePath,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
HANDLE hFile = NULL;
IO_STATUS_BLOCK ioStatusBlock;
NTSTATUS ntStatus = NtOpenFile(&hFile,
SYNCHRONIZE,
&ObjectAttributes,
&ioStatusBlock,
FILE_SHARE_READ,
FILE_DIRECTORY_FILE);
if (!NT_SUCCESS(ntStatus))
return HRESULT_FROM_WIN32(ntStatus);
TCHAR buffer[MAX_PATH + sizeof(FILE_NAME_INFORMATION) + 1] = {0};
PFILE_NAME_INFORMATION pFileNameInfo = (PFILE_NAME_INFORMATION)buffer;
ntStatus = NtQueryInformationFile(hFile,
&ioStatusBlock,
pFileNameInfo,
sizeof(buffer) - sizeof(TCHAR), // leave room for the ending '\0'
FileNameInformation);
NtClose(hFile);
if (!NT_SUCCESS(ntStatus))
{
return HRESULT_FROM_WIN32(ntStatus);
}
UINT uiRequiredLength = (pFileNameInfo->FileNameLength / sizeof(TCHAR)) + 2; // +1 for prefix '\\', the other for the ending NULL
*o_ppszRemotePath = (PTSTR)calloc(uiRequiredLength, sizeof(TCHAR));
if (!*o_ppszRemotePath)
return E_OUTOFMEMORY;
// prepend a "\" as the Api puts only 1 "\" as in \dfsserver\dfsroot
(*o_ppszRemotePath)[0] = _T('\\');
RtlCopyMemory((BYTE*)&((*o_ppszRemotePath)[1]),
pFileNameInfo->FileName,
pFileNameInfo->FileNameLength);
return S_OK;
}
bool IsPathWithDriveLetter(LPCTSTR pszPath)
{
if (!pszPath || lstrlen(pszPath) < 3)
return false;
if (*(pszPath+1) == _T(':') &&
*(pszPath+2) == _T('\\') &&
(*pszPath >= _T('a') && *pszPath <= _T('z') ||
*pszPath >= _T('A') && *pszPath <= _T('Z')))
return true;
return false;
}
bool
IsDfsPath
(
LPTSTR i_lpszDirPath,
LPTSTR* o_plpszEntryPath,
LPDFS_ALTERNATES** o_pppDfsAlternates
)
/*++
Routine Description:
Checks if the give directory path is a Dfs Path.
If it is then it returns the largest Dfs entry path that matches
this directory.
Arguments:
i_lpszDirPath - The directory path.
o_plpszEntryPath - The largest Dfs entrypath is returned here.
if the dir path is not Dfs path then this is NULL.
o_pppDfsAlternates - If the path is a dfs path, then an array of pointers to the possible alternate
paths are returned here.
Return value:
true if the path is determined to be a Dfs Path
false if otherwise.
--*/
{
if (!i_lpszDirPath || !*i_lpszDirPath || !o_pppDfsAlternates || !o_plpszEntryPath)
{
return(false);
}
*o_pppDfsAlternates = NULL;
*o_plpszEntryPath = NULL;
PTSTR lpszSharePath = NULL; // this variable will hold the path in UNC format, and with an ending whack.
// Is the dir path of type d:\* or \\server\share\*?
if (_T('\\') == i_lpszDirPath[0])
{
// This is a UNC path.
lpszSharePath = (PTSTR)calloc(lstrlen(i_lpszDirPath) + 2, sizeof(TCHAR)); // + 2 to hold the ending whack and '\0'
if (!lpszSharePath)
return false; // out of memory
_tcscpy(lpszSharePath, i_lpszDirPath);
// will append the whack later if necessary
}
else if (!IsPathWithDriveLetter(i_lpszDirPath))
{
return false; // unknown path format
} else
{
// This is a drive based path.
TCHAR lpszDirPath[] = _T("\\??\\C:\\");
PTSTR lpszDrive = lpszDirPath + 4;
// Copy the drive letter,
*lpszDrive = *i_lpszDirPath;
// See if it is a remote drive. If not return false.
if (DRIVE_REMOTE != GetDriveType(lpszDrive))
return false;
PTSTR pszRemotePath = NULL;
if (FAILED(GetRemotePath(lpszDirPath, &pszRemotePath)))
return false;
lpszSharePath = (PTSTR)calloc(lstrlen(pszRemotePath) + lstrlen(i_lpszDirPath), sizeof(TCHAR));
// since we won't copy over the 2-drive-chars c:, this is long enough to hold the ending whack and '\0'
if (!lpszSharePath)
{
free(pszRemotePath);
return false; // out of memory
}
_tcscpy(lpszSharePath, pszRemotePath);
if (pszRemotePath[lstrlen(pszRemotePath) - 1] == _T('\\'))
_tcscat(lpszSharePath, i_lpszDirPath + 3);
else
_tcscat(lpszSharePath, i_lpszDirPath + 2);
// will append the whack later if necessary
free(pszRemotePath);
}
// Start from the end of the path taking a component at
// a time and see if it is a Dfs entry Path.
// now append the whack if necessary
// point lpszTemp at the ending whack
LPTSTR lpszTemp = lpszSharePath + _tcslen(lpszSharePath) - 1;
if (_T('\\') != *lpszTemp)
*(++lpszTemp) = _T('\\');
bool bIsDfsPath = false;
DWORD dwStatus = NERR_Success;
DFS_INFO_3* pDfsInfo3 = NULL;
while (lpszTemp > (lpszSharePath + 2))
{
*lpszTemp = _T('\0');
pDfsInfo3 = NULL;
dwStatus = NetDfsGetClientInfo(
lpszSharePath, // dir path as entrypath
NULL, // No server name required
NULL, // No share required
3L, // level 1
(LPBYTE *)&pDfsInfo3 // out buffer.
);
*lpszTemp = _T('\\'); // Restore Component.
if (NERR_Success == dwStatus)
{ // This component is a Dfs path.
// Copy entry path.
*o_plpszEntryPath = new TCHAR [_tcslen(lpszSharePath) + 1];
if (!*o_plpszEntryPath)
{
NetApiBufferFree(pDfsInfo3);
break;
}
_tcscpy(*o_plpszEntryPath, lpszSharePath);
// Allocate null terminated array for alternate pointers.
*o_pppDfsAlternates = new LPDFS_ALTERNATES[pDfsInfo3->NumberOfStorages + 1];
if (!*o_pppDfsAlternates)
{
NetApiBufferFree(pDfsInfo3);
delete[] *o_plpszEntryPath;
*o_plpszEntryPath = NULL;
break;
}
(*o_pppDfsAlternates)[pDfsInfo3->NumberOfStorages] = NULL;
// Allocate space for each alternate.
DWORD i = 0;
for (i = 0; i < pDfsInfo3->NumberOfStorages; i++)
{
(*o_pppDfsAlternates)[i] = new DFS_ALTERNATES;
if (NULL == (*o_pppDfsAlternates)[i])
{
for(int j = i-1; j >= 0; j--)
delete (*o_pppDfsAlternates)[j];
delete[] *o_pppDfsAlternates;
*o_pppDfsAlternates = NULL;
delete[] *o_plpszEntryPath;
*o_plpszEntryPath = NULL;
NetApiBufferFree(pDfsInfo3);
free(lpszSharePath);
return(false);
}
}
// Copy alternate paths.
for (i = 0; i < pDfsInfo3->NumberOfStorages; i++)
{
(*o_pppDfsAlternates)[i]->bstrServer = (pDfsInfo3->Storage[i]).ServerName;
(*o_pppDfsAlternates)[i]->bstrShare = (pDfsInfo3->Storage[i]).ShareName;
(*o_pppDfsAlternates)[i]->bstrAlternatePath = _T("\\\\");
(*o_pppDfsAlternates)[i]->bstrAlternatePath += (pDfsInfo3->Storage[i]).ServerName;
(*o_pppDfsAlternates)[i]->bstrAlternatePath += _T("\\");
(*o_pppDfsAlternates)[i]->bstrAlternatePath += (pDfsInfo3->Storage[i]).ShareName;
(*o_pppDfsAlternates)[i]->bstrAlternatePath += lpszTemp;
// remove the ending whack
(*o_pppDfsAlternates)[i]->bstrAlternatePath[_tcslen((*o_pppDfsAlternates)[i]->bstrAlternatePath) - 1] = _T('\0');
// Set replica state.
if ((pDfsInfo3->Storage[i]).State & DFS_STORAGE_STATE_ACTIVE)
{
(*o_pppDfsAlternates)[i]->ReplicaState = SHL_DFS_REPLICA_STATE_ACTIVE_UNKNOWN;
}
}
bIsDfsPath = true;
NetApiBufferFree(pDfsInfo3);
break;
}
// move lpszTemp backforward to the next whack
lpszTemp--;
while (_T('\\') != *lpszTemp && lpszTemp > (lpszSharePath + 2))
{
lpszTemp--;
}
}
if (lpszSharePath)
free(lpszSharePath);
return(bIsDfsPath);
}
//----------------------------------------------------------------------------------