mirror of https://github.com/tongzx/nt5src
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.
462 lines
14 KiB
462 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 1991-1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
UNINAME.CXX
|
|
|
|
Abstract:
|
|
|
|
|
|
|
|
Author:
|
|
|
|
Dan Lafferty (danl) 24-Apr-1994
|
|
|
|
Environment:
|
|
|
|
User Mode -Win32
|
|
|
|
Revision History:
|
|
|
|
24-Apr-1994 danl
|
|
Created
|
|
|
|
05-May-1999 jschwart
|
|
Make provider addition/removal dynamic
|
|
|
|
--*/
|
|
|
|
//
|
|
// INCLUDES
|
|
//
|
|
|
|
#include "precomp.hxx"
|
|
#include <tstr.h> // STRLEN
|
|
|
|
//
|
|
// PROTOTYPES
|
|
//
|
|
DWORD
|
|
MprTranslateRemoteName(
|
|
LPREMOTE_NAME_INFOW pRemoteNameInfo,
|
|
LPDWORD lpBufferSize,
|
|
LPWSTR pRemoteName,
|
|
LPCWSTR pRemainingPath
|
|
);
|
|
|
|
|
|
DWORD
|
|
WNetGetUniversalNameW (
|
|
IN LPCTSTR lpLocalPath,
|
|
IN DWORD dwInfoLevel,
|
|
OUT LPVOID lpBuffer,
|
|
IN OUT LPDWORD lpBufferSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
lpLocalPath - This is a pointer to the string that contains the local path.
|
|
This is a path that contains a drive-letter prefixed path string.
|
|
"X:" is a valid local path. "X:\nt\system32" is a valid local path.
|
|
"\\popcorn\public\nt" is not a valid local path.
|
|
|
|
dwInfoLevel - This DWORD indicates what information is to be stored in
|
|
the return buffer. Currently the following levels are supported:
|
|
INFOLEVEL_UNIVERSAL_NAME
|
|
INFOLEVEL_REMOTE_NAME
|
|
|
|
lpBuffer - This is a pointer to the buffer where the requested information
|
|
is to be placed.
|
|
|
|
lpBufferSize - This is a pointer to the size of the buffer in bytes.
|
|
If the buffer is not large enough, then the required buffer size
|
|
Will be placed in this location upon return with WN_MORE_DATA.
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD status = WN_SUCCESS;
|
|
LPDWORD indexArray;
|
|
DWORD localArray[DEFAULT_MAX_PROVIDERS];
|
|
DWORD numProviders;
|
|
LPPROVIDER provider;
|
|
DWORD statusFlag = 0; // used to indicate major error types
|
|
BOOL fcnSupported = FALSE; // Is fcn supported by a provider?
|
|
DWORD i;
|
|
WCHAR pDriveLetter[4];
|
|
LPWSTR pRemoteName = (LPWSTR)((LPBYTE)lpBuffer + sizeof(REMOTE_NAME_INFOW));
|
|
|
|
//
|
|
// Validate the drive portion of the local path. Make sure its a valid
|
|
// device.
|
|
//
|
|
__try {
|
|
pDriveLetter[0] = lpLocalPath[0];
|
|
pDriveLetter[1] = lpLocalPath[1];
|
|
pDriveLetter[2] = L'\0';
|
|
if (MprDeviceType(pDriveLetter) != REDIR_DEVICE) {
|
|
status = WN_BAD_LOCALNAME;
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|
status = GetExceptionCode();
|
|
if (status != EXCEPTION_ACCESS_VIOLATION) {
|
|
MPR_LOG(ERROR,"WNetGetUniversalNameW:Unexpected Exception 0x%lx\n",status);
|
|
}
|
|
status = WN_BAD_POINTER;
|
|
}
|
|
|
|
if (status != WN_SUCCESS) {
|
|
SetLastError(status);
|
|
return(status);
|
|
}
|
|
|
|
if ((dwInfoLevel != UNIVERSAL_NAME_INFO_LEVEL) &&
|
|
(dwInfoLevel != REMOTE_NAME_INFO_LEVEL)) {
|
|
SetLastError(ERROR_INVALID_LEVEL);
|
|
return(ERROR_INVALID_LEVEL);
|
|
}
|
|
|
|
MprCheckProviders();
|
|
|
|
CProviderSharedLock PLock;
|
|
|
|
//
|
|
// Check to see if this is a remote drive to begin with. If not, we can
|
|
// fail it quickly.
|
|
//
|
|
pDriveLetter[2] = L'\\';
|
|
pDriveLetter[3] = L'\0';
|
|
if (GetDriveType(pDriveLetter) != DRIVE_REMOTE) {
|
|
status = WN_NOT_CONNECTED;
|
|
}
|
|
pDriveLetter[2] = L'\0';
|
|
|
|
if (status == WN_SUCCESS) {
|
|
|
|
INIT_IF_NECESSARY(NETWORK_LEVEL,status);
|
|
|
|
//
|
|
// Find the list of providers to call for this request.
|
|
//
|
|
indexArray = localArray;
|
|
|
|
status = MprFindCallOrder(
|
|
NULL,
|
|
&indexArray,
|
|
&numProviders,
|
|
NETWORK_TYPE);
|
|
|
|
if (status != WN_SUCCESS) {
|
|
SetLastError(status);
|
|
return(status);
|
|
}
|
|
|
|
//
|
|
// Loop through the list of providers until one answers the request,
|
|
// or the list is exhausted.
|
|
//
|
|
for (i=0; i<numProviders; i++) {
|
|
|
|
//
|
|
// Call the appropriate providers API entry point
|
|
// If the provider doesn't support GetUniversalName
|
|
// then see if that provider owns the connection by
|
|
// calling GetConnection.
|
|
//
|
|
provider = GlobalProviderInfo + indexArray[i];
|
|
|
|
if (provider->GetUniversalName != NULL) {
|
|
|
|
//--------------------------------------
|
|
// Call Provider with GetUniversalName
|
|
//--------------------------------------
|
|
|
|
fcnSupported = TRUE;
|
|
|
|
__try {
|
|
|
|
status = provider->GetUniversalName(
|
|
lpLocalPath,
|
|
dwInfoLevel,
|
|
lpBuffer,
|
|
lpBufferSize);
|
|
}
|
|
|
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|
status = GetExceptionCode();
|
|
if (status != EXCEPTION_ACCESS_VIOLATION) {
|
|
MPR_LOG(ERROR,"WNetGetUniversalNameW:Unexpected Exception 0x%lx\n",status);
|
|
}
|
|
status = WN_BAD_POINTER;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Try GetConnection for a Remote name. Note that we
|
|
// don't do this for a Universal name since providers
|
|
// are not required to support it (i.e., the name in
|
|
// the registry might not be universal).
|
|
//
|
|
else if ((dwInfoLevel == REMOTE_NAME_INFO_LEVEL) &&
|
|
(provider->GetConnection != NULL)) {
|
|
|
|
//--------------------------------------
|
|
// Call Provider with GetConnection
|
|
//--------------------------------------
|
|
DWORD buflen = 0;
|
|
|
|
__try {
|
|
|
|
if (*lpBufferSize > sizeof(REMOTE_NAME_INFOW)) {
|
|
//
|
|
// Remember, GetConnection is looking for the size of the
|
|
// buffer in characters - not bytes.
|
|
//
|
|
buflen = ((*lpBufferSize) - sizeof(REMOTE_NAME_INFOW))/sizeof(WCHAR);
|
|
}
|
|
|
|
status = provider->GetConnection(
|
|
pDriveLetter,
|
|
pRemoteName,
|
|
&buflen
|
|
);
|
|
|
|
if (status == WN_SUCCESS) {
|
|
|
|
//
|
|
// We got the RemoteName. See if there's enough room
|
|
// in the buffer for the portion of the local path that
|
|
// follows the drive letter and colon. If there's
|
|
// enough room, then store the remaining path in the
|
|
// buffer and fill in the structure.
|
|
//
|
|
status = MprTranslateRemoteName(
|
|
(LPREMOTE_NAME_INFOW)lpBuffer,
|
|
lpBufferSize,
|
|
pRemoteName,
|
|
&(lpLocalPath[2]));
|
|
|
|
fcnSupported = TRUE;
|
|
|
|
}
|
|
else if (status == WN_MORE_DATA) {
|
|
//
|
|
// The buflen we get back from GetConnection will account
|
|
// for the RemoteName portion, but not the remaining path
|
|
// portion. So we have to add that to the size calculation.
|
|
//
|
|
*lpBufferSize = sizeof(REMOTE_NAME_INFOW) +
|
|
(WCSSIZE(&(lpLocalPath[2]))) +
|
|
(buflen * sizeof(WCHAR));
|
|
|
|
fcnSupported = TRUE;
|
|
}
|
|
}
|
|
|
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|
status = GetExceptionCode();
|
|
if (status != EXCEPTION_ACCESS_VIOLATION) {
|
|
MPR_LOG(ERROR,"WNetGetUniversalNameW:Unexpected Exception 0x%lx\n",status);
|
|
}
|
|
status = WN_BAD_POINTER;
|
|
}
|
|
}
|
|
else {
|
|
//----------------------------------
|
|
// NEITHER FUNCTION IS SUPPORTED!
|
|
// Go to the next provider.
|
|
//----------------------------------
|
|
continue;
|
|
}
|
|
|
|
if (status == WN_NO_NETWORK) {
|
|
statusFlag |= NO_NET;
|
|
}
|
|
else if ((status == WN_NOT_CONNECTED) ||
|
|
(status == WN_BAD_LOCALNAME)){
|
|
//
|
|
// WN_NOT_CONNECTED means that lpLocalPath is not a
|
|
// redirected device for this provider.
|
|
//
|
|
statusFlag |= BAD_NAME;
|
|
}
|
|
else {
|
|
//
|
|
// If it wasn't one of those errors, then the provider
|
|
// must have accepted responsiblity for the request.
|
|
// so we exit and process the results. Note that the
|
|
// statusFlag is cleared because we want to ignore other
|
|
// error information that we gathered up until now.
|
|
//
|
|
statusFlag = 0;
|
|
break;
|
|
}
|
|
|
|
} // End for each provider.
|
|
|
|
if (fcnSupported == FALSE) {
|
|
//
|
|
// No providers in the list support the API function. Therefore,
|
|
// we assume that no networks are installed.
|
|
//
|
|
status = WN_NOT_SUPPORTED;
|
|
}
|
|
|
|
//
|
|
// If memory was allocated by MprFindCallOrder, free it.
|
|
//
|
|
if (indexArray != localArray) {
|
|
LocalFree(indexArray);
|
|
}
|
|
|
|
//
|
|
// Handle special errors.
|
|
//
|
|
if (statusFlag == (NO_NET | BAD_NAME)) {
|
|
//
|
|
// Check to see if there was a mix of special errors that occured.
|
|
// If so, pass back the combined error message. Otherwise, let the
|
|
// last error returned get passed back.
|
|
//
|
|
status = WN_NO_NET_OR_BAD_PATH;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle normal errors passed back from the provider
|
|
//
|
|
// NOTE: INIT_IF_NECESSARY may not have been executed by this point.
|
|
// Use caution when modifying code below. For example, this affects
|
|
// the behavior of MprGetRemoteName.
|
|
//
|
|
if (status != WN_SUCCESS)
|
|
{
|
|
if (status == WN_NOT_CONNECTED
|
|
&&
|
|
dwInfoLevel == REMOTE_NAME_INFO_LEVEL)
|
|
{
|
|
DWORD bufSize;
|
|
|
|
//
|
|
// If not connected, but there is an entry for the LocalName
|
|
// in the registry, then return the remote name that was stored
|
|
// with it. Note that we don't do this for a Universal name
|
|
// since providers are not required to support it (i.e., the
|
|
// name in the registry might not be universal).
|
|
//
|
|
bufSize = *lpBufferSize - sizeof(REMOTE_NAME_INFOW);
|
|
|
|
if (MprGetRemoteName(
|
|
pDriveLetter,
|
|
&bufSize,
|
|
pRemoteName,
|
|
&status)) {
|
|
|
|
if (status == WN_SUCCESS)
|
|
{
|
|
status = MprTranslateRemoteName(
|
|
(LPREMOTE_NAME_INFOW)lpBuffer,
|
|
lpBufferSize,
|
|
pRemoteName,
|
|
&(lpLocalPath[2]));
|
|
|
|
if (status == WN_SUCCESS)
|
|
{
|
|
status = WN_CONNECTION_CLOSED;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SetLastError(status);
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
DWORD
|
|
MprTranslateRemoteName(
|
|
LPREMOTE_NAME_INFOW pRemoteNameInfo,
|
|
LPDWORD lpBufferSize,
|
|
LPWSTR pRemoteName,
|
|
LPCWSTR pRemainingPath
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function adds the remaining path string to the buffer and places
|
|
the pointer to it into the structure.
|
|
|
|
|
|
Arguments:
|
|
|
|
pRemoteNameInfo - Pointer to a buffer which will contain the
|
|
REMOTE_NAME_INFO structure followed by the strings pointed
|
|
to in the structure.
|
|
|
|
lpBufferSize - Pointer to a DWORD that indicates the size of the
|
|
pRemoteNameInfo buffer.
|
|
|
|
pRemoteName - Pointer to the location in the pRemoteNameInfo buffer
|
|
where the remote name string can be placed.
|
|
|
|
pRemainingPath - Pointer to the remaining path string.
|
|
|
|
|
|
Return Value:
|
|
|
|
WN_MORE_DATA - If the buffer was not large enough to hold all the data.
|
|
When this is returned, the required buffer size is stored at the
|
|
location pointed to by lpBufferSize.
|
|
|
|
WN_SUCCESS - If the operation was completely successful.
|
|
|
|
Note:
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD bufSize = *lpBufferSize - sizeof(REMOTE_NAME_INFOW);
|
|
DWORD remoteNameLen;
|
|
DWORD remainingPathLen;
|
|
DWORD sizeRequired;
|
|
|
|
//
|
|
// We got the RemoteName. See if there's enough room
|
|
// in the buffer for the portion of the local path that
|
|
// follows the drive letter and colon. If there's
|
|
// enough room, then store the remaining path in the
|
|
// buffer and fill in the structure.
|
|
//
|
|
remoteNameLen = wcslen(pRemoteName);
|
|
remainingPathLen = wcslen(pRemainingPath);
|
|
|
|
sizeRequired = sizeof(REMOTE_NAME_INFOW) +
|
|
((remoteNameLen + remainingPathLen + 2) *
|
|
sizeof(WCHAR));
|
|
|
|
if (*lpBufferSize < sizeRequired) {
|
|
*lpBufferSize = sizeRequired;
|
|
return(WN_MORE_DATA);
|
|
}
|
|
else {
|
|
pRemoteNameInfo->lpUniversalName = NULL;
|
|
pRemoteNameInfo->lpConnectionName = pRemoteName;
|
|
pRemoteNameInfo->lpRemainingPath = pRemoteName+remoteNameLen+sizeof(WCHAR);
|
|
wcscpy(pRemoteNameInfo->lpRemainingPath, pRemainingPath);
|
|
}
|
|
return(WN_SUCCESS);
|
|
}
|
|
|