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.
894 lines
23 KiB
894 lines
23 KiB
/********************************************************************/
|
|
/** Copyright(c) 1989 Microsoft Corporation. **/
|
|
/********************************************************************/
|
|
|
|
//***
|
|
//
|
|
// Filename: volume.c
|
|
//
|
|
// Description: This module contains support routines for the volume
|
|
// category API's for the AFP server service
|
|
//
|
|
// History:
|
|
// June 11,1992. NarenG Created original version.
|
|
//
|
|
#include "afpsvcp.h"
|
|
|
|
static HANDLE hmutexInvalidVolume;
|
|
|
|
// Invalid volume structure
|
|
//
|
|
typedef struct _AFP_BADVOLUME {
|
|
|
|
LPWSTR lpwsName;
|
|
|
|
LPWSTR lpwsPath;
|
|
|
|
DWORD cbVariableData; // Number of bytes of name+path.
|
|
|
|
struct _AFP_BADVOLUME * Next;
|
|
|
|
} AFP_BADVOLUME, * PAFP_BADVOLUME;
|
|
|
|
// Singly linked list of invalid volumes
|
|
//
|
|
typedef struct _AFP_INVALID_VOLUMES {
|
|
|
|
DWORD cbTotalData;
|
|
|
|
PAFP_BADVOLUME Head;
|
|
|
|
} AFP_INVALID_VOLUMES;
|
|
|
|
static AFP_INVALID_VOLUMES InvalidVolumeList;
|
|
|
|
|
|
//**
|
|
//
|
|
// Call: AfpAdminrVolumeEnum
|
|
//
|
|
// Returns: NO_ERROR
|
|
// ERROR_ACCESS_DENIED
|
|
// non-zero returns from AfpServerIOCtrlGetInfo
|
|
//
|
|
// Description: This routine communicates with the AFP FSD to implement
|
|
// the AfpAdminrVolumeEnum function.
|
|
//
|
|
DWORD
|
|
AfpAdminrVolumeEnum(
|
|
IN AFP_SERVER_HANDLE hServer,
|
|
IN OUT PVOLUME_INFO_CONTAINER pInfoStruct,
|
|
IN DWORD dwPreferedMaximumLength,
|
|
OUT LPDWORD lpdwTotalEntries,
|
|
IN OUT LPDWORD lpdwResumeHandle OPTIONAL
|
|
)
|
|
{
|
|
AFP_REQUEST_PACKET AfpSrp;
|
|
DWORD dwRetCode=0;
|
|
DWORD dwAccessStatus=0;
|
|
|
|
|
|
// Check if caller has access
|
|
//
|
|
if ( dwRetCode = AfpSecObjAccessCheck( AFPSVC_ALL_ACCESS, &dwAccessStatus))
|
|
{
|
|
AFP_PRINT(( "SFMSVC: AfpAdminrVolumeEnum, AfpSecObjAccessCheck failed %ld\n",dwRetCode));
|
|
AfpLogEvent( AFPLOG_CANT_CHECK_ACCESS,
|
|
0, NULL, dwRetCode, EVENTLOG_ERROR_TYPE );
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
|
|
if ( dwAccessStatus )
|
|
{
|
|
AFP_PRINT(( "SFMSVC: AfpAdminrVolumeEnum, AfpSecObjAccessCheck returned %ld\n",dwAccessStatus));
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
|
|
// Set up request packet and make IOCTL to the FSD
|
|
//
|
|
AfpSrp.dwRequestCode = OP_VOLUME_ENUM;
|
|
AfpSrp.dwApiType = AFP_API_TYPE_ENUM;
|
|
AfpSrp.Type.Enum.cbOutputBufSize = dwPreferedMaximumLength;
|
|
|
|
// If resume handle was not passed then we set it to zero, cause caller
|
|
// wants all information starting from the beginning.
|
|
//
|
|
if ( lpdwResumeHandle )
|
|
AfpSrp.Type.Enum.EnumRequestPkt.erqp_Index = *lpdwResumeHandle;
|
|
else
|
|
AfpSrp.Type.Enum.EnumRequestPkt.erqp_Index = 0;
|
|
|
|
dwRetCode = AfpServerIOCtrlGetInfo( &AfpSrp );
|
|
|
|
if ( dwRetCode != ERROR_MORE_DATA && dwRetCode != NO_ERROR )
|
|
return( dwRetCode );
|
|
|
|
*lpdwTotalEntries = AfpSrp.Type.Enum.dwTotalAvail;
|
|
pInfoStruct->pBuffer =(PAFP_VOLUME_INFO)(AfpSrp.Type.Enum.pOutputBuf);
|
|
pInfoStruct->dwEntriesRead = AfpSrp.Type.Enum.dwEntriesRead;
|
|
|
|
if ( lpdwResumeHandle )
|
|
*lpdwResumeHandle = AfpSrp.Type.Enum.EnumRequestPkt.erqp_Index;
|
|
|
|
// Convert all offsets to pointers
|
|
//
|
|
AfpBufOffsetToPointer( (LPBYTE)(pInfoStruct->pBuffer),
|
|
pInfoStruct->dwEntriesRead,
|
|
AFP_VOLUME_STRUCT );
|
|
|
|
return( dwRetCode );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: AfpAdminrVolumeSetInfo
|
|
//
|
|
// Returns: NO_ERROR
|
|
// ERROR_ACCESS_DENIED
|
|
// non-zero returns from AfpServerIOCtrl
|
|
//
|
|
// Description: This routine communicates with the AFP FSD to implement
|
|
// the AfpAdminVolumeSetInfo function.
|
|
//
|
|
DWORD
|
|
AfpAdminrVolumeSetInfo(
|
|
IN AFP_SERVER_HANDLE hServer,
|
|
IN PAFP_VOLUME_INFO pAfpVolumeInfo,
|
|
IN DWORD dwParmNum
|
|
)
|
|
{
|
|
AFP_REQUEST_PACKET AfpSrp;
|
|
DWORD dwRetCode=0;
|
|
LPBYTE pAfpVolumeInfoSR = NULL;
|
|
DWORD cbAfpVolumeInfoSRSize;
|
|
DWORD dwAccessStatus=0;
|
|
|
|
|
|
// Check if caller has access
|
|
//
|
|
if ( dwRetCode = AfpSecObjAccessCheck( AFPSVC_ALL_ACCESS, &dwAccessStatus))
|
|
{
|
|
AFP_PRINT(( "SFMSVC: AfpAdminrVolumeSetInfo, AfpSecObjAccessCheck failed %ld\n",dwRetCode));
|
|
AfpLogEvent( AFPLOG_CANT_CHECK_ACCESS, 0, NULL,
|
|
dwRetCode, EVENTLOG_ERROR_TYPE );
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
|
|
if ( dwAccessStatus )
|
|
{
|
|
AFP_PRINT(( "SFMSVC: AfpAdminrVolumeSetInfo, AfpSecObjAccessCheck returned %ld\n",dwAccessStatus));
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
|
|
// MUTEX start
|
|
//
|
|
WaitForSingleObject( AfpGlobals.hmutexVolume, INFINITE );
|
|
|
|
// This loop is used to allow break's instead of goto's to be used
|
|
// on an error condition.
|
|
//
|
|
do {
|
|
|
|
dwRetCode = NO_ERROR;
|
|
|
|
// Make this buffer self-relative.
|
|
//
|
|
if ( dwRetCode = AfpBufMakeFSDRequest((LPBYTE)pAfpVolumeInfo,
|
|
sizeof(SETINFOREQPKT),
|
|
AFP_VOLUME_STRUCT,
|
|
&pAfpVolumeInfoSR,
|
|
&cbAfpVolumeInfoSRSize ))
|
|
break;
|
|
|
|
// Make IOCTL to set info
|
|
//
|
|
AfpSrp.dwRequestCode = OP_VOLUME_SET_INFO;
|
|
AfpSrp.dwApiType = AFP_API_TYPE_SETINFO;
|
|
AfpSrp.Type.SetInfo.pInputBuf = pAfpVolumeInfoSR;
|
|
AfpSrp.Type.SetInfo.cbInputBufSize = cbAfpVolumeInfoSRSize;
|
|
AfpSrp.Type.SetInfo.dwParmNum = dwParmNum;
|
|
|
|
if ( dwRetCode = AfpServerIOCtrl( &AfpSrp ) )
|
|
break;
|
|
|
|
// Now IOCTL the FSD to get information to set in the registry
|
|
// The input buffer for a GetInfo type call should point to a volume
|
|
// structure with the volume name filled in. Since we already have
|
|
// this from the previos SetInfo call, we use the same buffer with
|
|
// the pointer advances by sizeof(SETINFOREQPKT) bytes.
|
|
//
|
|
AfpSrp.dwRequestCode = OP_VOLUME_GET_INFO;
|
|
AfpSrp.dwApiType = AFP_API_TYPE_GETINFO;
|
|
AfpSrp.Type.GetInfo.pInputBuf = pAfpVolumeInfoSR +
|
|
sizeof(SETINFOREQPKT);
|
|
AfpSrp.Type.GetInfo.cbInputBufSize = cbAfpVolumeInfoSRSize -
|
|
sizeof(SETINFOREQPKT);
|
|
|
|
if ( dwRetCode = AfpServerIOCtrlGetInfo( &AfpSrp ) )
|
|
break;
|
|
|
|
// Update the registry if the IOCTL was successful
|
|
//
|
|
AfpBufOffsetToPointer( AfpSrp.Type.GetInfo.pOutputBuf,
|
|
1,
|
|
AFP_VOLUME_STRUCT
|
|
);
|
|
|
|
dwRetCode = AfpRegVolumeSetInfo( AfpSrp.Type.GetInfo.pOutputBuf );
|
|
|
|
LocalFree( AfpSrp.Type.GetInfo.pOutputBuf );
|
|
|
|
} while( FALSE );
|
|
|
|
// MUTEX end
|
|
//
|
|
ReleaseMutex( AfpGlobals.hmutexVolume );
|
|
|
|
if ( pAfpVolumeInfoSR )
|
|
LocalFree( pAfpVolumeInfoSR );
|
|
|
|
return( dwRetCode );
|
|
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: AfpAdminrVolumeDelete
|
|
//
|
|
// Returns: NO_ERROR
|
|
// ERROR_ACCESS_DENIED
|
|
// non-zero returns from AfpServerIOCtrl
|
|
//
|
|
// Description: This routine communicates with the AFP FSD to implement
|
|
// the AfpAdminVolumeDelete function.
|
|
//
|
|
DWORD
|
|
AfpAdminrVolumeDelete(
|
|
IN AFP_SERVER_HANDLE hServer,
|
|
IN LPWSTR lpwsVolumeName
|
|
)
|
|
{
|
|
AFP_REQUEST_PACKET AfpSrp;
|
|
PAFP_VOLUME_INFO pAfpVolumeInfoSR;
|
|
AFP_VOLUME_INFO AfpVolumeInfo;
|
|
DWORD cbAfpVolumeInfoSRSize;
|
|
DWORD dwRetCode=0;
|
|
DWORD dwAccessStatus=0;
|
|
|
|
// Check if caller has access
|
|
//
|
|
if ( dwRetCode = AfpSecObjAccessCheck( AFPSVC_ALL_ACCESS, &dwAccessStatus))
|
|
{
|
|
AFP_PRINT(( "SFMSVC: AfpAdminrVolumeDelete, AfpSecObjAccessCheck failed %ld\n",dwRetCode));
|
|
AfpLogEvent( AFPLOG_CANT_CHECK_ACCESS, 0, NULL,
|
|
dwRetCode, EVENTLOG_ERROR_TYPE );
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
|
|
if ( dwAccessStatus )
|
|
{
|
|
AFP_PRINT(( "SFMSVC: AfpAdminrVolumeDelete, AfpSecObjAccessCheck returned %ld\n",dwAccessStatus));
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
|
|
// Delete FSD request expects a AFP_VOLUME_INFO structure with only
|
|
// the volume name field filled in.
|
|
//
|
|
AfpVolumeInfo.afpvol_name = lpwsVolumeName;
|
|
AfpVolumeInfo.afpvol_password = NULL;
|
|
AfpVolumeInfo.afpvol_path = NULL;
|
|
|
|
// MUTEX start
|
|
//
|
|
WaitForSingleObject( AfpGlobals.hmutexVolume, INFINITE );
|
|
|
|
// This loop is used to allow break's instead of goto's to be used
|
|
// on an error condition.
|
|
//
|
|
do {
|
|
|
|
dwRetCode = NO_ERROR;
|
|
|
|
// Make this buffer self-relative.
|
|
//
|
|
if ( dwRetCode = AfpBufMakeFSDRequest((LPBYTE)&AfpVolumeInfo,
|
|
0,
|
|
AFP_VOLUME_STRUCT,
|
|
(LPBYTE*)&pAfpVolumeInfoSR,
|
|
&cbAfpVolumeInfoSRSize ) )
|
|
break;
|
|
|
|
// IOCTL the FSD to delete the volume
|
|
//
|
|
AfpSrp.dwRequestCode = OP_VOLUME_DELETE;
|
|
AfpSrp.dwApiType = AFP_API_TYPE_DELETE;
|
|
AfpSrp.Type.Delete.pInputBuf = pAfpVolumeInfoSR;
|
|
AfpSrp.Type.Delete.cbInputBufSize = cbAfpVolumeInfoSRSize;
|
|
|
|
dwRetCode = AfpServerIOCtrl( &AfpSrp );
|
|
|
|
LocalFree( pAfpVolumeInfoSR );
|
|
|
|
if ( dwRetCode )
|
|
break;
|
|
|
|
// Update the registry if the IOCTL was successful
|
|
//
|
|
dwRetCode = AfpRegVolumeDelete( lpwsVolumeName );
|
|
|
|
} while( FALSE );
|
|
|
|
// MUTEX end
|
|
//
|
|
ReleaseMutex( AfpGlobals.hmutexVolume );
|
|
|
|
return( dwRetCode );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: AfpAdminrVolumeAdd
|
|
//
|
|
// Returns: NO_ERROR
|
|
// ERROR_ACCESS_DENIED
|
|
// non-zero returns from AfpServerIOCtrl
|
|
//
|
|
// Description: This routine communicates with the AFP FSD to implement
|
|
// the AfpAdminVolumeAdd function.
|
|
//
|
|
DWORD
|
|
AfpAdminrVolumeAdd(
|
|
IN AFP_SERVER_HANDLE hServer,
|
|
IN PAFP_VOLUME_INFO pAfpVolumeInfo
|
|
)
|
|
{
|
|
AFP_REQUEST_PACKET AfpSrp;
|
|
DWORD dwRetCode=0, dwLastDstCharIndex = 0;
|
|
PAFP_VOLUME_INFO pAfpVolumeInfoSR = NULL;
|
|
DWORD cbAfpVolumeInfoSRSize;
|
|
DWORD dwAccessStatus=0;
|
|
BOOL fCopiedIcon = FALSE;
|
|
WCHAR wchSrcIconPath[MAX_PATH];
|
|
WCHAR wchDstIconPath[MAX_PATH + AFPSERVER_VOLUME_ICON_FILE_SIZE + 1 + (sizeof(AFPSERVER_RESOURCE_STREAM)/sizeof(WCHAR))];
|
|
WCHAR wchServerIconFile[AFPSERVER_VOLUME_ICON_FILE_SIZE] = AFPSERVER_VOLUME_ICON_FILE;
|
|
|
|
// Check if caller has access
|
|
//
|
|
if ( dwRetCode = AfpSecObjAccessCheck( AFPSVC_ALL_ACCESS, &dwAccessStatus))
|
|
{
|
|
AFP_PRINT(( "SFMSVC: AfpAdminrVolumeAdd, AfpSecObjAccessCheck failed %ld\n",dwRetCode));
|
|
AfpLogEvent( AFPLOG_CANT_CHECK_ACCESS, 0,
|
|
NULL, dwRetCode, EVENTLOG_ERROR_TYPE );
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
|
|
if ( dwAccessStatus )
|
|
{
|
|
AFP_PRINT(( "SFMSVC: AfpAdminrVolumeAdd, AfpSecObjAccessCheck returned %ld\n",dwAccessStatus));
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
|
|
if ( pAfpVolumeInfo == NULL)
|
|
{
|
|
AFP_PRINT(( "SFMSVC: AfpAdminrVolumeAdd, pAfpVolumeInfo == NULL\n"));
|
|
return( ERROR_INVALID_DATA );
|
|
}
|
|
|
|
// MUTEX start
|
|
//
|
|
WaitForSingleObject( AfpGlobals.hmutexVolume, INFINITE );
|
|
|
|
// This loop is used to allow break's instead of goto's to be used
|
|
// on an error condition.
|
|
//
|
|
do {
|
|
|
|
// Copy the server icon to the volume root
|
|
//
|
|
|
|
// Construct a path to the NTSFM volume custom icon
|
|
//
|
|
if ( GetSystemDirectory( wchSrcIconPath, MAX_PATH ) )
|
|
{
|
|
wcscat( wchSrcIconPath, AFP_DEF_VOLICON_SRCNAME );
|
|
|
|
if ( pAfpVolumeInfo->afpvol_path == NULL )
|
|
{
|
|
AFP_PRINT(( "SFMSVC: AfpAdminrVolumeAdd, pAfpVolumeInfo->afpvol_path == NULL\n"));
|
|
dwRetCode = ERROR_INVALID_DATA;
|
|
break;
|
|
}
|
|
|
|
// Construct a path to the destination volume "Icon<0D>" file
|
|
//
|
|
wcscpy( wchDstIconPath, pAfpVolumeInfo->afpvol_path );
|
|
|
|
if ( wcslen(wchDstIconPath) == 0 )
|
|
{
|
|
AFP_PRINT(( "SFMSVC: AfpAdminrVolumeAdd, wcslen(wchDstIconPath) == 0\n"));
|
|
dwRetCode = ERROR_INVALID_DATA;
|
|
break;
|
|
}
|
|
|
|
if (wchDstIconPath[wcslen(wchDstIconPath) - 1] != TEXT('\\'))
|
|
{
|
|
wcscat( wchDstIconPath, TEXT("\\") );
|
|
}
|
|
wcscat( wchDstIconPath, wchServerIconFile );
|
|
// Keep track of end of name without the resource fork tacked on
|
|
//
|
|
dwLastDstCharIndex = wcslen(wchDstIconPath);
|
|
wcscat( wchDstIconPath, AFPSERVER_RESOURCE_STREAM );
|
|
|
|
// Copy the icon file to the root of the volume (do not overwrite)
|
|
//
|
|
if ((fCopiedIcon = CopyFile( wchSrcIconPath, wchDstIconPath, TRUE )) ||
|
|
(GetLastError() == ERROR_FILE_EXISTS))
|
|
{
|
|
pAfpVolumeInfo->afpvol_props_mask |= AFP_VOLUME_HAS_CUSTOM_ICON;
|
|
|
|
// Make sure the file is hidden
|
|
SetFileAttributes( wchDstIconPath,
|
|
FILE_ATTRIBUTE_HIDDEN |
|
|
FILE_ATTRIBUTE_ARCHIVE );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwRetCode = GetLastError ();
|
|
break;
|
|
}
|
|
|
|
// Make this buffer self-relative.
|
|
//
|
|
if ( dwRetCode = AfpBufMakeFSDRequest( (LPBYTE)pAfpVolumeInfo,
|
|
0,
|
|
AFP_VOLUME_STRUCT,
|
|
(LPBYTE*)&pAfpVolumeInfoSR,
|
|
&cbAfpVolumeInfoSRSize ) )
|
|
break;
|
|
|
|
// IOCTL the FSD to add the volume
|
|
//
|
|
AfpSrp.dwRequestCode = OP_VOLUME_ADD;
|
|
AfpSrp.dwApiType = AFP_API_TYPE_ADD;
|
|
AfpSrp.Type.Add.pInputBuf = pAfpVolumeInfoSR;
|
|
AfpSrp.Type.Add.cbInputBufSize = cbAfpVolumeInfoSRSize;
|
|
|
|
dwRetCode = AfpServerIOCtrl( &AfpSrp );
|
|
|
|
// Don't allow icon bit to be written to the registry if it was set
|
|
pAfpVolumeInfo->afpvol_props_mask &= ~AFP_VOLUME_HAS_CUSTOM_ICON;
|
|
|
|
if ( dwRetCode )
|
|
{
|
|
// Delete the icon file we just copied if the volume add failed
|
|
//
|
|
if ( fCopiedIcon )
|
|
{
|
|
// Truncate the resource fork name so we delete the whole file
|
|
wchDstIconPath[dwLastDstCharIndex] = 0;
|
|
DeleteFile( wchDstIconPath );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// Update the registry if the IOCTL was successful
|
|
//
|
|
dwRetCode = AfpRegVolumeAdd( pAfpVolumeInfo );
|
|
|
|
if ( dwRetCode )
|
|
break;
|
|
|
|
// Delete this volume if it exists in the invalid volume list
|
|
//
|
|
AfpDeleteInvalidVolume( pAfpVolumeInfo->afpvol_name );
|
|
|
|
} while( FALSE );
|
|
|
|
// MUTEX end
|
|
//
|
|
ReleaseMutex( AfpGlobals.hmutexVolume );
|
|
|
|
if ( pAfpVolumeInfoSR != NULL )
|
|
LocalFree( pAfpVolumeInfoSR );
|
|
|
|
return( dwRetCode );
|
|
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: AfpAdminrVolumeGetInfo
|
|
//
|
|
// Returns: NO_ERROR
|
|
// ERROR_ACCESS_DENIED
|
|
// non-zero returns from AfpServerIOCtrlGetInfo
|
|
//
|
|
// Description: This routine communicates with the AFP FSD to implement
|
|
// the AfpAdminVolumeGetInfo function.
|
|
//
|
|
DWORD
|
|
AfpAdminrVolumeGetInfo(
|
|
IN AFP_SERVER_HANDLE hServer,
|
|
IN LPWSTR lpwsVolumeName,
|
|
OUT PAFP_VOLUME_INFO* ppAfpVolumeInfo
|
|
)
|
|
{
|
|
AFP_REQUEST_PACKET AfpSrp;
|
|
PAFP_VOLUME_INFO pAfpVolumeInfoSR;
|
|
AFP_VOLUME_INFO AfpVolumeInfo;
|
|
DWORD cbAfpVolumeInfoSRSize;
|
|
DWORD dwRetCode=0;
|
|
DWORD dwAccessStatus=0;
|
|
|
|
// Check if caller has access
|
|
//
|
|
if ( dwRetCode = AfpSecObjAccessCheck( AFPSVC_ALL_ACCESS, &dwAccessStatus))
|
|
{
|
|
AFP_PRINT(( "SFMSVC: AfpAdminrVolumeGetInfo, AfpSecObjAccessCheck failed %ld\n",dwRetCode));
|
|
AfpLogEvent( AFPLOG_CANT_CHECK_ACCESS, 0, NULL,
|
|
dwRetCode, EVENTLOG_ERROR_TYPE );
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
|
|
if ( dwAccessStatus )
|
|
{
|
|
AFP_PRINT(( "SFMSVC: AfpAdminrVolumeGetInfo, AfpSecObjAccessCheck returned %ld\n",dwAccessStatus));
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
|
|
|
|
// MUTEX start
|
|
//
|
|
WaitForSingleObject( AfpGlobals.hmutexVolume, INFINITE );
|
|
|
|
// This loop is used to allow break's instead of goto's to be used
|
|
// on an error condition.
|
|
//
|
|
do {
|
|
|
|
dwRetCode = NO_ERROR;
|
|
|
|
// Get info FSD request expects a AFP_VOLUME_INFO structure with only
|
|
// the volume name field filled in.
|
|
//
|
|
AfpVolumeInfo.afpvol_name = lpwsVolumeName;
|
|
AfpVolumeInfo.afpvol_password = NULL;
|
|
AfpVolumeInfo.afpvol_path = NULL;
|
|
|
|
// Make this buffer self-relative.
|
|
//
|
|
if ( dwRetCode = AfpBufMakeFSDRequest((LPBYTE)&AfpVolumeInfo,
|
|
0,
|
|
AFP_VOLUME_STRUCT,
|
|
(LPBYTE*)&pAfpVolumeInfoSR,
|
|
&cbAfpVolumeInfoSRSize ) )
|
|
break;
|
|
|
|
AfpSrp.dwRequestCode = OP_VOLUME_GET_INFO;
|
|
AfpSrp.dwApiType = AFP_API_TYPE_GETINFO;
|
|
AfpSrp.Type.GetInfo.pInputBuf = pAfpVolumeInfoSR;
|
|
AfpSrp.Type.GetInfo.cbInputBufSize = cbAfpVolumeInfoSRSize;
|
|
|
|
dwRetCode = AfpServerIOCtrlGetInfo( &AfpSrp );
|
|
|
|
if ( dwRetCode != ERROR_MORE_DATA && dwRetCode != NO_ERROR )
|
|
break;
|
|
|
|
LocalFree( pAfpVolumeInfoSR );
|
|
|
|
*ppAfpVolumeInfo = AfpSrp.Type.GetInfo.pOutputBuf;
|
|
|
|
// Convert all offsets to pointers
|
|
//
|
|
AfpBufOffsetToPointer( (LPBYTE)*ppAfpVolumeInfo, 1, AFP_VOLUME_STRUCT);
|
|
|
|
} while( FALSE );
|
|
|
|
// MUTEX end
|
|
//
|
|
ReleaseMutex( AfpGlobals.hmutexVolume );
|
|
|
|
return( dwRetCode );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: AfpAdminrInvalidVolumeEnum
|
|
//
|
|
// Returns: NO_ERROR
|
|
// ERROR_ACCESS_DENIED
|
|
//
|
|
// Description: This routine will return a list of all invalid volumes. This
|
|
// List is stored in a cache that is local to this module.
|
|
//
|
|
DWORD
|
|
AfpAdminrInvalidVolumeEnum(
|
|
IN AFP_SERVER_HANDLE hServer,
|
|
IN OUT PVOLUME_INFO_CONTAINER pInfoStruct
|
|
)
|
|
{
|
|
DWORD dwRetCode=0;
|
|
DWORD dwAccessStatus=0;
|
|
PAFP_VOLUME_INFO pOutputBuf;
|
|
PAFP_VOLUME_INFO pOutputWalker;
|
|
WCHAR * pwchVariableData;
|
|
PAFP_BADVOLUME pAfpBadVolWalker;
|
|
|
|
|
|
// Check if caller has access
|
|
//
|
|
if ( dwRetCode = AfpSecObjAccessCheck( AFPSVC_ALL_ACCESS, &dwAccessStatus))
|
|
{
|
|
AFP_PRINT(( "SFMSVC: AfpAdminrInvalidVolumeEnum, AfpSecObjAccessCheck failed %ld\n",dwRetCode));
|
|
AfpLogEvent( AFPLOG_CANT_CHECK_ACCESS, 0, NULL,
|
|
dwRetCode, EVENTLOG_ERROR_TYPE );
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
|
|
if ( dwAccessStatus )
|
|
{
|
|
AFP_PRINT(( "SFMSVC: AfpAdminrInvalidVolumeEnum, AfpSecObjAccessCheck returned %ld\n",dwAccessStatus));
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
|
|
// MUTEX start
|
|
//
|
|
WaitForSingleObject( hmutexInvalidVolume, INFINITE );
|
|
|
|
// Allocate enough space to hold all the information.
|
|
//
|
|
pOutputBuf = MIDL_user_allocate( InvalidVolumeList.cbTotalData );
|
|
|
|
if ( pOutputBuf == NULL ){
|
|
ReleaseMutex( hmutexInvalidVolume );
|
|
return( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
|
|
ZeroMemory( pOutputBuf, InvalidVolumeList.cbTotalData );
|
|
|
|
// Variable data begins from the end of the buffer.
|
|
//
|
|
pwchVariableData=(WCHAR*)((ULONG_PTR)pOutputBuf+InvalidVolumeList.cbTotalData);
|
|
|
|
// Walk the list and create the array of volume structures
|
|
//
|
|
for( pAfpBadVolWalker = InvalidVolumeList.Head,
|
|
pInfoStruct->dwEntriesRead = 0,
|
|
pOutputWalker = pOutputBuf;
|
|
|
|
pAfpBadVolWalker != NULL;
|
|
|
|
pOutputWalker++,
|
|
(pInfoStruct->dwEntriesRead)++,
|
|
pAfpBadVolWalker = pAfpBadVolWalker->Next ) {
|
|
|
|
pwchVariableData -= (STRLEN(pAfpBadVolWalker->lpwsName) + 1);
|
|
|
|
STRCPY( (LPWSTR)pwchVariableData, pAfpBadVolWalker->lpwsName );
|
|
|
|
pOutputWalker->afpvol_name = (LPWSTR)pwchVariableData;
|
|
|
|
if ( pAfpBadVolWalker->lpwsPath != NULL ) {
|
|
|
|
pwchVariableData -=( STRLEN(pAfpBadVolWalker->lpwsPath)+1 );
|
|
|
|
STRCPY( (LPWSTR)pwchVariableData, pAfpBadVolWalker->lpwsPath );
|
|
|
|
pOutputWalker->afpvol_path = (LPWSTR)pwchVariableData;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// MUTEX end
|
|
//
|
|
ReleaseMutex( hmutexInvalidVolume );
|
|
|
|
pInfoStruct->pBuffer = pOutputBuf;
|
|
|
|
return( dwRetCode );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: AfpAdminrInvalidVolumeDelete
|
|
//
|
|
// Returns: NO_ERROR
|
|
// ERROR_ACCESS_DENIED
|
|
//
|
|
// Description: This routine will remove an invalid volume from the registry
|
|
// and the list of invalid volumes.
|
|
//
|
|
DWORD
|
|
AfpAdminrInvalidVolumeDelete(
|
|
IN AFP_SERVER_HANDLE hServer,
|
|
IN LPWSTR lpwsVolumeName
|
|
)
|
|
{
|
|
DWORD dwRetCode=0;
|
|
DWORD dwAccessStatus=0;
|
|
|
|
// Check if caller has access
|
|
//
|
|
if ( dwRetCode = AfpSecObjAccessCheck( AFPSVC_ALL_ACCESS, &dwAccessStatus))
|
|
{
|
|
AFP_PRINT(( "SFMSVC: AfpAdminrInvalidVolumeDelete, AfpSecObjAccessCheck failed %ld\n",dwRetCode));
|
|
AfpLogEvent( AFPLOG_CANT_CHECK_ACCESS, 0, NULL,
|
|
dwRetCode, EVENTLOG_ERROR_TYPE );
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
|
|
if ( dwAccessStatus )
|
|
{
|
|
AFP_PRINT(( "SFMSVC: AfpAdminrInvalidVolumeDelete, AfpSecObjAccessCheck returned %ld\n",dwAccessStatus));
|
|
return( ERROR_ACCESS_DENIED );
|
|
}
|
|
|
|
|
|
// Remove this volume from the registry
|
|
//
|
|
if ( dwRetCode = AfpRegVolumeDelete( lpwsVolumeName ) ) {
|
|
|
|
if ( dwRetCode == ERROR_FILE_NOT_FOUND )
|
|
dwRetCode = (DWORD)AFPERR_VolumeNonExist;
|
|
}
|
|
|
|
// MUTEX start
|
|
//
|
|
WaitForSingleObject( hmutexInvalidVolume, INFINITE );
|
|
|
|
AfpDeleteInvalidVolume( lpwsVolumeName );
|
|
|
|
// MUTEX end
|
|
//
|
|
ReleaseMutex( hmutexInvalidVolume );
|
|
|
|
return( dwRetCode );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: AfpAddInvalidVolume
|
|
//
|
|
// Returns: none
|
|
//
|
|
// Description: Will add a volume structure to a sigly linked list of volumes.
|
|
//
|
|
VOID
|
|
AfpAddInvalidVolume(
|
|
IN LPWSTR lpwsName,
|
|
IN LPWSTR lpwsPath
|
|
)
|
|
{
|
|
DWORD dwRetCode = NO_ERROR;
|
|
WCHAR* pwchVariableData = NULL;
|
|
PAFP_BADVOLUME pAfpVolumeInfo = NULL;
|
|
DWORD cbVariableData;
|
|
|
|
// MUTEX start
|
|
//
|
|
WaitForSingleObject( hmutexInvalidVolume, INFINITE );
|
|
|
|
do {
|
|
|
|
cbVariableData = (STRLEN(lpwsName)+1) * sizeof(WCHAR);
|
|
|
|
if ( lpwsPath != NULL )
|
|
cbVariableData += ( (STRLEN(lpwsPath)+1)*sizeof(WCHAR) );
|
|
|
|
pwchVariableData = (WCHAR*)LocalAlloc( LPTR, cbVariableData );
|
|
|
|
if ( pwchVariableData == NULL ) {
|
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
pAfpVolumeInfo = (PAFP_BADVOLUME)LocalAlloc( LPTR,
|
|
sizeof(AFP_BADVOLUME));
|
|
if ( pAfpVolumeInfo == NULL ) {
|
|
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
// Add the volume strucutre
|
|
//
|
|
pAfpVolumeInfo->Next = InvalidVolumeList.Head;
|
|
|
|
InvalidVolumeList.Head = pAfpVolumeInfo;
|
|
|
|
// Add the name and the path
|
|
//
|
|
STRCPY( (LPWSTR)pwchVariableData, lpwsName );
|
|
pAfpVolumeInfo->lpwsName = (LPWSTR)pwchVariableData;
|
|
|
|
if ( lpwsPath != NULL ) {
|
|
|
|
pwchVariableData += ( STRLEN( lpwsName ) + 1);
|
|
STRCPY( (LPWSTR)pwchVariableData, lpwsPath );
|
|
pAfpVolumeInfo->lpwsPath = (LPWSTR)pwchVariableData;
|
|
}
|
|
|
|
pAfpVolumeInfo->cbVariableData = cbVariableData;
|
|
|
|
InvalidVolumeList.cbTotalData += ( sizeof( AFP_VOLUME_INFO ) +
|
|
cbVariableData );
|
|
|
|
} while( FALSE );
|
|
|
|
if ( dwRetCode != NO_ERROR ) {
|
|
|
|
if ( pAfpVolumeInfo != NULL )
|
|
LocalFree( pAfpVolumeInfo );
|
|
|
|
if ( pwchVariableData != NULL ) {
|
|
LocalFree( pwchVariableData );
|
|
}
|
|
}
|
|
|
|
// MUTEX end
|
|
//
|
|
ReleaseMutex( hmutexInvalidVolume );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: AfpDeleteInvalidVolume
|
|
//
|
|
// Returns: none
|
|
//
|
|
// Description: Will delete a volume structure from the list of invalid
|
|
// volumes, if it is found.
|
|
//
|
|
VOID
|
|
AfpDeleteInvalidVolume(
|
|
IN LPWSTR lpwsVolumeName
|
|
)
|
|
{
|
|
PAFP_BADVOLUME pTmp;
|
|
PAFP_BADVOLUME pBadVolWalker;
|
|
|
|
// Walk the list and delete the volume structure
|
|
//
|
|
if ( InvalidVolumeList.Head != NULL ) {
|
|
|
|
if ( STRICMP( InvalidVolumeList.Head->lpwsName, lpwsVolumeName ) == 0 ){
|
|
|
|
pTmp = InvalidVolumeList.Head;
|
|
|
|
InvalidVolumeList.cbTotalData -= ( sizeof( AFP_VOLUME_INFO )
|
|
+ pTmp->cbVariableData );
|
|
|
|
InvalidVolumeList.Head = pTmp->Next;
|
|
|
|
LocalFree( pTmp->lpwsName );
|
|
LocalFree( pTmp );
|
|
}
|
|
else {
|
|
|
|
for( pBadVolWalker = InvalidVolumeList.Head;
|
|
pBadVolWalker->Next != NULL;
|
|
pBadVolWalker = pBadVolWalker->Next ) {
|
|
|
|
if ( STRICMP( pBadVolWalker->Next->lpwsName, lpwsVolumeName )
|
|
== 0 ) {
|
|
|
|
pTmp = pBadVolWalker->Next;
|
|
|
|
InvalidVolumeList.cbTotalData -= ( sizeof( AFP_VOLUME_INFO )
|
|
+ pTmp->cbVariableData );
|
|
|
|
pBadVolWalker->Next = pTmp->Next;
|
|
|
|
LocalFree( pTmp->lpwsName );
|
|
LocalFree( pTmp);
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|