/********************************************************************/ /** 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; } } } } }