Source code of Windows XP (NT5)
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.

650 lines
16 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. FTMan
  5. File Name:
  6. Global.cpp
  7. Abstract:
  8. Implementation of useful global functions
  9. Author:
  10. Cristian Teodorescu October 29, 1998
  11. Notes:
  12. Revision History:
  13. --*/
  14. #include "stdafx.h"
  15. #include "FTUtil.h"
  16. #include "Global.h"
  17. #include "Item.h"
  18. #include "MainFrm.h"
  19. #include "Resource.h"
  20. #include <basetyps.h>
  21. #include <mountmgr.h>
  22. #include <winbase.h>
  23. #include <winioctl.h>
  24. #ifdef _DEBUG
  25. #define new DEBUG_NEW
  26. #undef THIS_FILE
  27. static char THIS_FILE[] = __FILE__;
  28. #endif
  29. ////////////////////////////////////////////////////////////////////////////
  30. // Display functions
  31. /*
  32. Global function: DisplaySystemErrorMessage
  33. Purpose: Display the last system error message prefixed ( or not ) with another string taken from
  34. our resources explaining the context of the failure
  35. Parameters: [IN] UINT unContextMsgID
  36. The ID of the string that must prefix the system error message. ID in resource.h
  37. Default is 0 which means that the system error shouldn't be prefixed
  38. Return value: TRUE if the functions succeeds
  39. */
  40. BOOL DisplaySystemErrorMessage( UINT unContextMsgID /* =0 */)
  41. {
  42. MY_TRY
  43. // Get the system error message
  44. LPVOID lpMsgBuf;
  45. if( !::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  46. NULL,
  47. GetLastError(),
  48. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  49. (LPTSTR) &lpMsgBuf,
  50. 0,
  51. NULL ) ) // Process any inserts in lpMsgBuf.
  52. return FALSE;
  53. CString str;
  54. if( unContextMsgID != 0) // The system error message must be prefixed with another string from the resources of this application
  55. if( !str.LoadString( unContextMsgID ) ) return FALSE;
  56. str += ((LPCTSTR)lpMsgBuf);
  57. LocalFree( lpMsgBuf );
  58. AfxMessageBox(str, MB_ICONSTOP);
  59. return TRUE;
  60. MY_CATCH_AND_THROW
  61. }
  62. /*
  63. Global function: DisplayStatusBarMessage (1)
  64. Purpose: Displays a message in the first pane of the main frame status bar
  65. Parameters: [IN] LPCTSTR lpszMsg
  66. The message to display
  67. Return value: TRUE if the functions succeeds
  68. */
  69. BOOL DisplayStatusBarMessage( LPCTSTR lpszMsg )
  70. {
  71. MY_TRY
  72. CStatusBar* pStatusBar = ((CMainFrame*)AfxGetMainWnd())->GetStatusBar();
  73. if( !pStatusBar )
  74. return FALSE;
  75. // Use the ID_SEPARATOR pane of the status bar
  76. return pStatusBar->SetPaneText( 5, lpszMsg );
  77. MY_CATCH_AND_THROW
  78. }
  79. /*
  80. Global function: DisplayStatusBarMessage (2)
  81. Purpose: Display a message in the first pane of the main frame status bar
  82. Parameters: [IN] UINT unMsgID
  83. Resource ID of the string to display
  84. Return value: TRUE if the functions succeeds
  85. */
  86. BOOL DisplayStatusBarMessage( UINT unMsgID )
  87. {
  88. MY_TRY
  89. CString str;
  90. str.LoadString(unMsgID);
  91. return DisplayStatusBarMessage(str);
  92. MY_CATCH_AND_THROW
  93. }
  94. /*
  95. Global function: FormatVolumeSize
  96. Purpose: Format the size of a volume in a "readable" way
  97. ( in GB, MB or KB depending on the size range )
  98. Parameters: [OUT] CString& strSize
  99. Reference to the string to receive the formatted size
  100. [IN] LONGLONG llSize
  101. The size to format ( in Bytes )
  102. Return value: -
  103. */
  104. void FormatVolumeSize( CString& strSize, LONGLONG llSize )
  105. {
  106. MY_TRY
  107. if( llSize >= 0x40000000 ) // 1GB = 2^30 B
  108. strSize.Format(_T("%.2f GB"), ((double)(llSize>>20))/((double)0x400));
  109. else if (llSize >= 0x100000 ) // 1MB = 2^20 B
  110. strSize.Format(_T("%.2f MB"), ((double)(llSize>>10))/((double)0x400));
  111. else
  112. strSize.Format(_T("%.2f KB"), ((double)llSize)/((double)0x400));
  113. MY_CATCH_AND_THROW
  114. }
  115. /*
  116. Global function: CopyW2Str
  117. Purpose: Copy a Unicode character array into a CString
  118. Parameters: [OUT] CString& strDest
  119. Reference to the string to receive the formatted size
  120. [IN] LPWSTR strSource
  121. Unicode character array to be copied
  122. [IN] ULONG ulLength
  123. The number of characters to copy
  124. Return value: -
  125. */
  126. void CopyW2Str( CString& strDest, LPWSTR strSource, ULONG ulLength )
  127. {
  128. MY_TRY
  129. LPTSTR lpstr = strDest.GetBuffer( ulLength + 1 );
  130. #ifdef UNICODE
  131. memcpy( lpstr, strSource, ulLength * sizeof(WCHAR ) );
  132. #else
  133. WideCharToMultiByte( CP_APP, 0, strSource, ulLength, lpstr, ulLength * sizeof(char), NULL, NULL );
  134. #endif
  135. lpstr[ulLength]=_T('\0');
  136. strDest.ReleaseBuffer();
  137. MY_CATCH_AND_THROW
  138. }
  139. /*
  140. Global function: CopyStr2W
  141. Purpose: Copy a CString content into a Unicode character array
  142. Parameters: [OUT] LPWSTR strDest
  143. Pointer to the buffer to receive the character array. It should be already allocated
  144. [IN] CString& strSource
  145. Reference to the string to be copied
  146. Return value: -
  147. */
  148. void CopyStr2W( LPWSTR strDest, CString& strSource )
  149. {
  150. MY_TRY
  151. LPTSTR lpstr = strSource.GetBuffer(0);
  152. int nSize = strSource.GetLength();
  153. #ifdef UNICODE
  154. memcpy( strDest, lpstr, nSize * sizeof(WCHAR) );
  155. #else
  156. MultiByteToWideChar( CP_APP, 0, lpstr, nSize, strDest, nSize * sizeof(WCHAR) );
  157. #endif
  158. strDest[nSize] = _T('\0');
  159. strSource.ReleaseBuffer();
  160. MY_CATCH_AND_THROW
  161. }
  162. /*
  163. Global function: OpenVolume
  164. Purpose: Open a volume given its name
  165. The name must be like this "\\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\"
  166. Parameters: [IN] CString& strVolumeName
  167. Volume name
  168. Return value: HANDLE
  169. Handle of the open volume. INVALID_HANDLE_VALUE if the operation failed
  170. */
  171. HANDLE OpenVolume( const CString& strVolumeName )
  172. {
  173. return CreateFile( strVolumeName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
  174. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE );
  175. }
  176. /*
  177. Global function: IsDOSName
  178. Purpose: Decides wether a name is a DOS name i.e. "\DosDevices\X:"
  179. Parameters: [IN] CString& str
  180. The name
  181. Return value: TRUE if it is a DOS name
  182. */
  183. BOOL IsDOSName( const CString& str )
  184. {
  185. MY_TRY
  186. // "\DosDevices\X:"
  187. return( ( str.GetLength() == 14 ) &&
  188. ( str.Left(12) == _T("\\DosDevices\\") ) &&
  189. ( str[13] == _T(':') ) );
  190. MY_CATCH_AND_THROW
  191. }
  192. /*
  193. Global function: IsVolumeName
  194. Purpose: Decides wether a name is a volume name i.e. "\??\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
  195. Parameters: [IN] CString& str
  196. The name
  197. Return value: TRUE if it is a volume name
  198. */
  199. BOOL IsVolumeName( const CString& str )
  200. {
  201. MY_TRY
  202. // "\??\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
  203. return( ( str.GetLength() == 48 ) &&
  204. ( str.Left(11) == _T("\\??\\Volume{") ) &&
  205. ( str[19] == _T('-') ) &&
  206. ( str[24] == _T('-') ) &&
  207. ( str[29] == _T('-') ) &&
  208. ( str[34] == _T('-') ) &&
  209. ( str[47] == _T('}') ) );
  210. MY_CATCH_AND_THROW
  211. }
  212. /*
  213. Global function: QueryDriveLetterAndVolumeName
  214. Purpose: Query the drive letter and the name of the volume given its NT Name
  215. The name will be like this: "\\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
  216. Parameters: [IN] CString& strNTName
  217. The NT name of the volume
  218. [OUT] TCHAR& cDriveLetter
  219. The drive letter of the volume
  220. [OUT] CString& strVolumeName
  221. The name ( to be used by FindFirst/FindNext ) of the volume
  222. Return value: TRUE if the function succeeded
  223. */
  224. BOOL QueryDriveLetterAndVolumeName( CString& strNTName, TCHAR& cDriveLetter, CString& strVolumeName )
  225. {
  226. MY_TRY
  227. cDriveLetter = _T('\0');
  228. strVolumeName = _T("");
  229. if( strNTName.IsEmpty() )
  230. return FALSE;
  231. HANDLE h;
  232. ULONG ulInputSize;
  233. PMOUNTMGR_MOUNT_POINT pInput;
  234. ULONG ulOutputSize;
  235. PMOUNTMGR_MOUNT_POINTS pOutput;
  236. ULONG ulBytes;
  237. BOOL bResult;
  238. USHORT unNTNameLength;
  239. // Open the mount manager
  240. h = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ,
  241. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
  242. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  243. INVALID_HANDLE_VALUE);
  244. if (h == INVALID_HANDLE_VALUE)
  245. {
  246. TRACE( _T("Error: Open mount manager failed in GetDriveLetterAndVolumeName\n") );
  247. return FALSE;
  248. }
  249. // Prepare the input structure
  250. unNTNameLength = (USHORT)strNTName.GetLength();
  251. ulInputSize = sizeof(MOUNTMGR_MOUNT_POINT) + ((unNTNameLength + 1)*sizeof(WCHAR));
  252. pInput = (PMOUNTMGR_MOUNT_POINT) LocalAlloc( 0, ulInputSize);
  253. if (!pInput)
  254. {
  255. TRACE( _T("Error: Memory allocation failure in GetDriveLetterAndVolumeName\n") );
  256. CloseHandle(h);
  257. return FALSE;
  258. }
  259. pInput->SymbolicLinkNameLength = 0;
  260. pInput->SymbolicLinkNameOffset = 0;
  261. pInput->UniqueIdOffset = 0;
  262. pInput->UniqueIdLength = 0;
  263. pInput->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  264. pInput->DeviceNameLength = unNTNameLength * sizeof(WCHAR);
  265. CopyStr2W( (LPWSTR) ((PUCHAR) pInput + pInput->DeviceNameOffset), strNTName );
  266. // Prepare the output structure
  267. ulOutputSize = sizeof(MOUNTMGR_MOUNT_POINTS) + 1024;
  268. pOutput = (PMOUNTMGR_MOUNT_POINTS) LocalAlloc( 0, ulOutputSize);
  269. if (!pOutput)
  270. {
  271. TRACE( _T("Error: Memory allocation failure in GetDriveLetterAndVolumeName\n") );
  272. CloseHandle(h);
  273. LocalFree(pInput);
  274. return FALSE;
  275. }
  276. bResult = DeviceIoControl( h, IOCTL_MOUNTMGR_QUERY_POINTS, pInput, ulInputSize,
  277. pOutput, ulOutputSize, &ulBytes, NULL);
  278. while (!bResult && GetLastError() == ERROR_MORE_DATA)
  279. {
  280. ulOutputSize = pOutput->Size;
  281. LocalFree( pOutput );
  282. pOutput = (PMOUNTMGR_MOUNT_POINTS)(LocalAlloc(0, ulOutputSize ));
  283. if (!pOutput)
  284. {
  285. TRACE( _T("Error: Memory Allocation failure in QueryMountPoints") );
  286. CloseHandle(h);
  287. LocalFree(pInput);
  288. return FALSE;
  289. }
  290. bResult = DeviceIoControl(h, IOCTL_MOUNTMGR_QUERY_POINTS, pInput, ulInputSize,
  291. pOutput, ulOutputSize, &ulBytes, NULL);
  292. }
  293. CloseHandle(h);
  294. LocalFree(pInput);
  295. if( !bResult )
  296. {
  297. TRACE( _T("Error: IOCTL_MOUNTMGR_QUERY_POINTS failure in GetDriveLetterAndVolumeName\n") );
  298. LocalFree(pOutput);
  299. return FALSE;
  300. }
  301. //CStringArray arrMountPointName;
  302. CString strMountPoint;
  303. for( ULONG i=0; i < pOutput->NumberOfMountPoints; i++ )
  304. {
  305. PMOUNTMGR_MOUNT_POINT pMountPoint = &(pOutput->MountPoints[i]);
  306. /*
  307. if (!point->SymbolicLinkNameOffset) {
  308. continue; }
  309. */
  310. CopyW2Str( strMountPoint, (LPWSTR)((PCHAR)pOutput + pMountPoint->SymbolicLinkNameOffset),
  311. pMountPoint->SymbolicLinkNameLength / sizeof(WCHAR) );
  312. if( IsDOSName( strMountPoint ) ) // i.e. "\DosDevices\X:"
  313. {
  314. // I got the drive letter
  315. cDriveLetter = strMountPoint[12];
  316. }
  317. else if ( IsVolumeName( strMountPoint ) ) // i.e. "\??\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
  318. {
  319. // I got the volume name !!!!
  320. strVolumeName = strMountPoint;
  321. // Make it like this : "\\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
  322. strVolumeName.SetAt( 1, _T('\\') );
  323. }
  324. }
  325. LocalFree(pOutput);
  326. return TRUE;
  327. MY_CATCH_AND_THROW
  328. }
  329. /*
  330. Global function: QueryMountListInPath
  331. Purpose: Query the mount manager for all mount paths of the given volumes in a certain path
  332. Each found mount path is added to the corresponding volume in array arrItems ( if any )
  333. Parameters: [IN] CString& strPath
  334. The path to search in
  335. [IN/OUT] CObArray& arrVolumesData
  336. Array of CItemData - Tree items ( volumes ) whose mount paths we are looking for
  337. Return value: -
  338. */
  339. void QueryMountListInPath( const CString& strPath, CObArray& arrVolumesData )
  340. {
  341. MY_TRY
  342. BOOL bResult;
  343. CString strVolName, strVolMountPoint, strMountPointPath;
  344. LPTSTR lpstr = strVolName.GetBuffer(MAX_PATH);
  345. bResult = GetVolumeNameForVolumeMountPoint( strPath, lpstr, MAX_PATH );
  346. strVolName.ReleaseBuffer();
  347. if( !bResult )
  348. return;
  349. // Cut the final backslash of the volume name and search it in the volumes array
  350. CString strVolName2 = strVolName.Left( strVolName.GetLength() - 1 );
  351. for( int i = 0; i < arrVolumesData.GetSize(); i++ )
  352. {
  353. CItemData* pData = (CItemData*)(arrVolumesData[i]);
  354. if( pData->GetVolumeName() == strVolName2 )
  355. {
  356. // Cut the final backslash of the path and add it to the volume's mount paths
  357. CString strPath2 = strPath.Left( strPath.GetLength() - 1 );
  358. pData->GetMountPaths().Add(strPath2);
  359. }
  360. }
  361. lpstr = strVolMountPoint.GetBuffer(MAX_PATH);
  362. HANDLE h = FindFirstVolumeMountPoint( strVolName, lpstr, MAX_PATH);
  363. strVolMountPoint.ReleaseBuffer();
  364. if( h == INVALID_HANDLE_VALUE )
  365. return;
  366. for( ; ; )
  367. {
  368. strMountPointPath = strPath + strVolMountPoint;
  369. QueryMountListInPath( strMountPointPath, arrVolumesData );
  370. lpstr = strVolMountPoint.GetBuffer(MAX_PATH);
  371. bResult = FindNextVolumeMountPoint( h, lpstr, MAX_PATH );
  372. strVolMountPoint.ReleaseBuffer();
  373. if( !bResult )
  374. break;
  375. }
  376. FindVolumeMountPointClose(h);
  377. MY_CATCH_AND_THROW
  378. }
  379. /*
  380. Global function: QueryMountList
  381. Purpose: Query the mount manager for all mount paths of the given volumes
  382. Each found mount path is added to the corresponding volume in array arrItems ( if any )
  383. Parameters: [IN/OUT] CObArray& arrVolumesData
  384. Array of CItemData - Tree items ( volumes ) whose mount paths we are looking for
  385. Return value: -
  386. */
  387. void QueryMountList( CObArray& arrVolumesData )
  388. {
  389. MY_TRY
  390. CString strName = _T("X:\\");
  391. for( TCHAR cDriveLetter = _T('A'); cDriveLetter <= _T('Z'); cDriveLetter++ )
  392. {
  393. strName.SetAt(0, cDriveLetter);
  394. QueryMountListInPath( strName, arrVolumesData );
  395. }
  396. MY_CATCH_AND_THROW
  397. }
  398. /*
  399. Global function: ConvertPartitionsToFT
  400. Purpose: Scans an array of CItemData and converts all physical partitions to
  401. FT partitions. Then return the logical volume ID's of all items in the array
  402. Parameters: [IN] CObArray& arrVolumeData
  403. The array of CItemData to scan
  404. [OUT] FT_LOGICAL_DISK_ID* arrVolID
  405. The array of logical volume ID's of all items from arrVolumeData
  406. ( arrVolID[i] is the logical volume ID of volume represented by arrVolumeData[i] )
  407. Return value: TRUE if all physical partitions are converted succesfully
  408. If one conversion fails then all previously converted partitions are deconverted
  409. */
  410. BOOL ConvertPartitionsToFT( CObArray& arrVolumeData, FT_LOGICAL_DISK_ID* arrVolID )
  411. {
  412. MY_TRY
  413. ASSERT( arrVolID );
  414. for( int i = 0; i < arrVolumeData.GetSize(); i++ )
  415. {
  416. CItemData* pData = (CItemData*)(arrVolumeData[i]);
  417. ASSERT(pData);
  418. if( pData->GetItemType() == IT_LogicalVolume )
  419. pData->GetVolumeID( arrVolID[i] );
  420. else if( pData->GetItemType() == IT_PhysicalPartition )
  421. {
  422. ASSERT( !pData->GetVolumeName().IsEmpty() );
  423. if( !FTPart( pData->GetVolumeName(),
  424. pData->GetDriveLetter(),
  425. &(arrVolID[i]) ) )
  426. {
  427. // Deconvert all partitions you've previously converted and return FALSE
  428. DeconvertPartitionsFromFT( arrVolumeData, arrVolID, i );
  429. return FALSE;
  430. }
  431. }
  432. else
  433. ASSERT(FALSE);
  434. }
  435. return TRUE;
  436. MY_CATCH_AND_THROW
  437. }
  438. /*
  439. Global function: DeconvertPartitionsFromFT
  440. Purpose: Scans an array of CItemData and deconverts all physical partitions from
  441. FT partitions.
  442. Parameters: [IN] CObArray& arrVolumeData
  443. The array of CItemData to scan
  444. [IN] FT_LOGICAL_DISK_ID* arrVolID
  445. The array of logical volume ID's of volumes from arrVolumeData
  446. ( arrVolID[i] is the logical volume ID of volume represented by arrVolumeData[i] )
  447. [IN] int nItems
  448. The number of items ( starting with offset zero ) to deconvert
  449. If nItems = -1 then all items in the array will be scanned and deconverted
  450. Return value: TRUE if all physical partitions are deconverted succesfully
  451. */
  452. BOOL DeconvertPartitionsFromFT( CObArray& arrVolumeData, FT_LOGICAL_DISK_ID* arrVolID, int nItems /* =-1 */ )
  453. {
  454. MY_TRY
  455. BOOL bResult = TRUE;
  456. if( nItems == -1 )
  457. nItems = (int)arrVolumeData.GetSize();
  458. for( int i = 0; i < nItems; i++ )
  459. {
  460. CItemData* pData = (CItemData*)(arrVolumeData[i]);
  461. ASSERT(pData);
  462. if( pData->GetItemType() == IT_PhysicalPartition )
  463. bResult = FTBreak( arrVolID[i] ) && bResult;
  464. }
  465. return bResult;
  466. MY_CATCH_AND_THROW
  467. }
  468. /*
  469. Global function: CheckAdministratorsMembership
  470. Purpose: Checks whether the current user is a member of the Administrators' group
  471. Parameters: [OUT] BOOL& bIsAdministrator
  472. Returns TRUE if the user is a member of the administrators group
  473. Return value: TRUE the check concluded successfully with a YES / NO answer
  474. */
  475. BOOL CheckAdministratorsMembership( BOOL& bIsAdministrator )
  476. {
  477. MY_TRY
  478. BYTE sidBuffer[100];
  479. PSID pSID = (PSID)&sidBuffer;
  480. SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
  481. // Create a SID for the BUILTIN\Administrators group.
  482. if( !AllocateAndInitializeSid( &SIDAuth, 2,
  483. SECURITY_BUILTIN_DOMAIN_RID,
  484. DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
  485. &pSID) )
  486. {
  487. TRACE(_T("Error in AllocateAndInitializeSid\n"));
  488. DisplaySystemErrorMessage( IDS_ERR_CHECK_ADMINISTRATOR );
  489. return FALSE;
  490. }
  491. if( !CheckTokenMembership( NULL, pSID, &bIsAdministrator ) )
  492. {
  493. TRACE(_T("Error in CheckTokenMembership\n"));
  494. DisplaySystemErrorMessage( IDS_ERR_CHECK_ADMINISTRATOR );
  495. return FALSE;
  496. }
  497. if (pSID)
  498. FreeSid(pSID);
  499. return TRUE;
  500. MY_CATCH_AND_THROW
  501. }
  502.