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.

889 lines
28 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. /* File: fsobject.cpp
  3. Description: Contains member function definitions for class FSObject and
  4. it's derived subclasses.
  5. Revision History:
  6. Date Description Programmer
  7. -------- --------------------------------------------------- ----------
  8. 05/22/96 Initial creation. BrianAu
  9. */
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #include "pch.h" // PCH
  12. #pragma hdrstop
  13. #include "dskquota.h"
  14. #include "fsobject.h"
  15. #include "pathstr.h"
  16. //
  17. // Verify that build is UNICODE.
  18. //
  19. #if !defined(UNICODE)
  20. # error This module must be compiled UNICODE.
  21. #endif
  22. ///////////////////////////////////////////////////////////////////////////////
  23. /* Function: FSObject::~FSObject
  24. Description: Destructor. Frees object's name buffer.
  25. Arguments: None.
  26. Returns: Nothing.
  27. Revision History:
  28. Date Description Programmer
  29. -------- --------------------------------------------------- ----------
  30. 05/22/96 Initial creation. BrianAu
  31. */
  32. ///////////////////////////////////////////////////////////////////////////////
  33. FSObject::~FSObject(
  34. VOID
  35. )
  36. {
  37. DBGTRACE((DM_CONTROL, DL_MID, TEXT("FSObject::~FSObject")));
  38. }
  39. ///////////////////////////////////////////////////////////////////////////////
  40. /* Function: FSObject::AddRef
  41. Description: Increments object reference count.
  42. Note this is not a member of IUnknown; but it works the same.
  43. Arguments: None.
  44. Returns: New reference count value.
  45. Revision History:
  46. Date Description Programmer
  47. -------- --------------------------------------------------- ----------
  48. 05/22/96 Initial creation. BrianAu
  49. */
  50. ///////////////////////////////////////////////////////////////////////////////
  51. ULONG
  52. FSObject::AddRef(
  53. VOID
  54. )
  55. {
  56. DBGTRACE((DM_CONTROL, DL_LOW, TEXT("FSObject::AddRef")));
  57. DBGPRINT((DM_CONTROL, DL_LOW, TEXT("\t0x%08X %d -> %d"),
  58. this, m_cRef, m_cRef + 1));
  59. ULONG ulReturn = m_cRef + 1;
  60. InterlockedIncrement(&m_cRef);
  61. return ulReturn;
  62. }
  63. ///////////////////////////////////////////////////////////////////////////////
  64. /* Function: FSObject::Release
  65. Description: Decrements object reference count. If count drops to 0,
  66. object is deleted. Note this is not a member of IUnknown; but it
  67. works the same.
  68. Arguments: None.
  69. Returns: New reference count value.
  70. Revision History:
  71. Date Description Programmer
  72. -------- --------------------------------------------------- ----------
  73. 05/22/96 Initial creation. BrianAu
  74. */
  75. ///////////////////////////////////////////////////////////////////////////////
  76. ULONG
  77. FSObject::Release(
  78. VOID
  79. )
  80. {
  81. DBGTRACE((DM_CONTROL, DL_LOW, TEXT("FSObject::Release")));
  82. DBGPRINT((DM_CONTROL, DL_LOW, TEXT("\t0x%08X %d -> %d"),
  83. this, m_cRef, m_cRef - 1));
  84. ULONG ulReturn = m_cRef - 1;
  85. if (InterlockedDecrement(&m_cRef) == 0)
  86. {
  87. delete this;
  88. ulReturn = 0;
  89. }
  90. return ulReturn;
  91. }
  92. ///////////////////////////////////////////////////////////////////////////////
  93. /* Function: FSObject::ObjectSupportsQuotas
  94. Description: Determine a file system object's type (and locality) from
  95. it's name string.
  96. Arguments:
  97. pszFSObjName - Volume root name. (i.e. "C:\", "\\scratch\scratch").
  98. Returns:
  99. S_OK - Success. Supports quotas.
  100. ERROR_NOT_SUPPORTED (hr) - File system doesn't support quotas.
  101. Other win32 error - Couldn't get volume information.
  102. Revision History:
  103. Date Description Programmer
  104. -------- --------------------------------------------------- ----------
  105. 05/24/96 Initial creation. BrianAu
  106. 08/16/96 Added pSupportsQuotas. BrianAu
  107. 12/05/96 Disabled check for $DeadMeat volume label. BrianAu
  108. Leave the code in place for a while. I'll remove
  109. it later when we're sure it's not needed.
  110. 07/03/97 Changed name from ObjectTypeFromName. BrianAu
  111. Changed logic to indicate reason for not supporting
  112. quotas.
  113. */
  114. ///////////////////////////////////////////////////////////////////////////////
  115. HRESULT
  116. FSObject::ObjectSupportsQuotas(
  117. LPCTSTR pszFSObjName
  118. )
  119. {
  120. DBGTRACE((DM_CONTROL, DL_MID, TEXT("FSObject::ObjectSupportsQuotas")));
  121. DBGPRINT((DM_CONTROL, DL_MID, TEXT("\tobject = \"%s\""), pszFSObjName ? pszFSObjName : TEXT("<null>")));
  122. HRESULT hr = E_FAIL;
  123. DWORD dwFileSysFlags = 0;
  124. TCHAR szFileSysName[MAX_PATH];
  125. DBGASSERT((NULL != pszFSObjName));
  126. if (GetVolumeInformation(
  127. pszFSObjName,
  128. NULL, 0,
  129. NULL, 0,
  130. &dwFileSysFlags,
  131. szFileSysName,
  132. ARRAYSIZE(szFileSysName)))
  133. {
  134. //
  135. // Does the file system support quotas?
  136. //
  137. if (0 != (dwFileSysFlags & FILE_VOLUME_QUOTAS))
  138. {
  139. //
  140. // Yes, it does.
  141. //
  142. hr = S_OK;
  143. DBGPRINT((DM_CONTROL, DL_LOW, TEXT("Vol \"%s\" supports quotas"), pszFSObjName));
  144. }
  145. else
  146. {
  147. //
  148. // Doesn't support quotas.
  149. //
  150. hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
  151. DBGPRINT((DM_CONTROL, DL_HIGH, TEXT("File system \"%s\" on \"%s\" doesn't support quotas."),
  152. szFileSysName, pszFSObjName));
  153. }
  154. }
  155. else
  156. {
  157. DWORD dwErr = GetLastError();
  158. hr = HRESULT_FROM_WIN32(dwErr);
  159. DBGERROR((TEXT("Error %d calling GetVolumeInformation for \"%s\""), dwErr, pszFSObjName));
  160. }
  161. return hr;
  162. }
  163. ///////////////////////////////////////////////////////////////////////////////
  164. /* Function: FSObject::Create
  165. Description: 2 overloaded functions.
  166. Static functions for creating a File System object of the
  167. proper type. Clients call Create with an object name string or
  168. a reference to an existing FSObject instance.
  169. Arguments:
  170. pszFSObjName - Address of volume root string.
  171. ppNewObject - Address of FSObject pointer to accept the address of the
  172. new file system object.
  173. ObjToClone - Reference to file system object to be cloned.
  174. Returns:
  175. NOERROR - Success.
  176. E_OUTOFMEMORY - Insufficient memory.
  177. ERROR_ACCESS_DENIED (hr) - Insufficient access to open device.
  178. ERROR_FILE_NOT_FOUND (hr) - Disk device not found.
  179. ERROR_INVALID_NAME (hr) - Object name is invalid.
  180. ERROR_NOT_SUPPORTED (hr) - Volume doesn't support quotas.
  181. Revision History:
  182. Date Description Programmer
  183. -------- --------------------------------------------------- ----------
  184. 05/23/96 Initial creation. BrianAu
  185. 09/05/96 Added exception handling. BrianAu
  186. */
  187. ///////////////////////////////////////////////////////////////////////////////
  188. HRESULT
  189. FSObject::Create(
  190. LPCTSTR pszFSObjName,
  191. DWORD dwAccess,
  192. FSObject **ppNewObject
  193. )
  194. {
  195. DBGTRACE((DM_CONTROL, DL_MID, TEXT("FSObject::Create")));
  196. DBGPRINT((DM_CONTROL, DL_MID, TEXT("\tVol = \"%s\""), pszFSObjName ? pszFSObjName : TEXT("<null>")));
  197. HRESULT hr = NOERROR;
  198. DBGASSERT((NULL != pszFSObjName));
  199. DBGASSERT((NULL != ppNewObject));
  200. *ppNewObject = NULL;
  201. FSObject *pNewObject = NULL;
  202. try
  203. {
  204. hr = FSObject::ObjectSupportsQuotas(pszFSObjName);
  205. if (SUCCEEDED(hr))
  206. {
  207. hr = FSObject_CreateLocalVolume(pszFSObjName, &pNewObject);
  208. if (SUCCEEDED(hr))
  209. {
  210. //
  211. // Do any subclass-specific initialization.
  212. // i.e.: Volume opens the volume device.
  213. //
  214. hr = pNewObject->Initialize(dwAccess);
  215. if (SUCCEEDED(hr))
  216. {
  217. //
  218. // Return ptr to caller.
  219. //
  220. DBGPRINT((DM_CONTROL, DL_MID, TEXT("FSObject created")));
  221. pNewObject->AddRef();
  222. *ppNewObject = pNewObject;
  223. }
  224. else
  225. {
  226. DBGPRINT((DM_CONTROL, DL_MID, TEXT("FSObject create FAILED with error 0x%08X"), hr));
  227. delete pNewObject;
  228. pNewObject = NULL;
  229. }
  230. }
  231. }
  232. }
  233. catch(CAllocException& e)
  234. {
  235. DBGERROR((TEXT("Insufficient memory exception")));
  236. delete pNewObject; // Will also free name if necessary.
  237. hr = E_OUTOFMEMORY;
  238. }
  239. return hr;
  240. }
  241. //
  242. // Version to clone an existing FSObject.
  243. //
  244. HRESULT
  245. FSObject::Create(
  246. const FSObject& ObjectToClone,
  247. FSObject **ppNewObject
  248. )
  249. {
  250. return FSObject::Create(ObjectToClone.m_strFSObjName,
  251. ObjectToClone.m_dwAccessRights,
  252. ppNewObject);
  253. }
  254. ///////////////////////////////////////////////////////////////////////////////
  255. /* Function: FSObject::GetName
  256. Description: Retrieves the file system object's name string.
  257. Arguments:
  258. pszBuffer - Address of buffer to accept name string.
  259. cchBuffer - Size of destination buffer in characters.
  260. Returns:
  261. NOERROR - Success.
  262. ERROR_INSUFFICIENT_BUFFER - Destination buffer is too small for name.
  263. Revision History:
  264. Date Description Programmer
  265. -------- --------------------------------------------------- ----------
  266. 05/24/96 Initial creation. BrianAu
  267. */
  268. ///////////////////////////////////////////////////////////////////////////////
  269. HRESULT FSObject::GetName(LPTSTR pszBuffer, ULONG cchBuffer) const
  270. {
  271. HRESULT hr = NOERROR;
  272. DBGASSERT((NULL != pszBuffer));
  273. if ((ULONG)m_strFSObjName.Length() < cchBuffer)
  274. lstrcpyn(pszBuffer, m_strFSObjName, cchBuffer);
  275. else
  276. {
  277. *pszBuffer = TEXT('\0');
  278. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  279. }
  280. return hr;
  281. }
  282. //
  283. // This function was created to fix bug 365936.
  284. // Class FSObject has a CPath member who's constructor
  285. // can throw CAllocException. Because of this, we
  286. // need to isolate this construction operation from
  287. // other FSObject code so that we don't try to delete
  288. // an FSObject object that has already been destroyed
  289. // by the constructor's call stack unwinding process.
  290. //
  291. HRESULT
  292. FSObject_CreateLocalVolume(
  293. LPCTSTR pszVolumeName,
  294. FSObject **ppObject
  295. )
  296. {
  297. HRESULT hr = S_OK;
  298. *ppObject = NULL;
  299. try
  300. {
  301. FSObject *pNewObject = new FSLocalVolume(pszVolumeName);
  302. *ppObject = pNewObject;
  303. }
  304. catch(CAllocException& e)
  305. {
  306. hr = E_OUTOFMEMORY;
  307. }
  308. return hr;
  309. }
  310. ///////////////////////////////////////////////////////////////////////////////
  311. /* Function: FSVolume::~FSVolume
  312. Description: Destructor. Closes volume handle.
  313. Arguments: None.
  314. Returns: Nothing.
  315. Revision History:
  316. Date Description Programmer
  317. -------- --------------------------------------------------- ----------
  318. 05/24/96 Initial creation. BrianAu
  319. */
  320. ///////////////////////////////////////////////////////////////////////////////
  321. FSVolume::~FSVolume(
  322. VOID
  323. )
  324. {
  325. DBGTRACE((DM_CONTROL, DL_MID, TEXT("FSVolume::~FSVolume")));
  326. if (INVALID_HANDLE_VALUE != m_hVolume)
  327. CloseHandle(m_hVolume);
  328. }
  329. ///////////////////////////////////////////////////////////////////////////////
  330. /* Function: FSVolume::Initialize
  331. Description: Initializes a volume object by opening the NTFS volume.
  332. Arguments:
  333. dwAccess - Desired access. GENERIC_READ, GENERIC_WRITE.
  334. Returns:
  335. NOERROR - Success.
  336. ERROR_ACCESS_DENIED (hr) - Insufficient access to open device.
  337. ERROR_FILE_NOT_FOUND (hr) - Disk device not found.
  338. ERROR_INVALID_NAME (hr) - Invalid path string.
  339. Revision History:
  340. Date Description Programmer
  341. -------- --------------------------------------------------- ----------
  342. 05/24/96 Initial creation. BrianAu
  343. 08/11/96 Added access right handling. BrianAu
  344. 08/16/96 Added device name formatting. BrianAu
  345. 07/03/97 Changed so caller passes in desired access. BrianAu
  346. */
  347. ///////////////////////////////////////////////////////////////////////////////
  348. HRESULT FSVolume::Initialize(
  349. DWORD dwAccess
  350. )
  351. {
  352. DBGTRACE((DM_CONTROL, DL_MID, TEXT("FSVolume::Initialize")));
  353. DBGPRINT((DM_CONTROL, DL_MID, TEXT("\tdwAccess = 0x%08X"), dwAccess));
  354. HRESULT hr = NOERROR;
  355. //
  356. // Close the device if it's open.
  357. //
  358. if (INVALID_HANDLE_VALUE != m_hVolume)
  359. CloseHandle(m_hVolume);
  360. //
  361. // Create a path to the actual quota file on the volume.
  362. // This string is appended to the existing "volume name" we already
  363. // have.
  364. //
  365. CPath strQuotaFile(m_strFSObjName);
  366. strQuotaFile.AddBackslash();
  367. strQuotaFile += CString("$Extend\\$Quota:$Q:$INDEX_ALLOCATION");
  368. m_hVolume = CreateFile(strQuotaFile,
  369. dwAccess,
  370. FILE_SHARE_READ | FILE_SHARE_WRITE,
  371. NULL,
  372. OPEN_EXISTING,
  373. FILE_FLAG_BACKUP_SEMANTICS,
  374. NULL);
  375. if (INVALID_HANDLE_VALUE == m_hVolume)
  376. {
  377. //
  378. // Couldn't open device because...
  379. // 1. I/O error
  380. // 2. File (device) not found.
  381. // 3. Access denied.
  382. //
  383. DWORD dwErr = GetLastError();
  384. hr = HRESULT_FROM_WIN32(dwErr);
  385. DBGERROR((TEXT("Error %d opening quota file \"%s\""), dwErr, strQuotaFile.Cstr()));
  386. }
  387. else
  388. {
  389. //
  390. // Save access granted to caller. Will be used to validate
  391. // operation requests later.
  392. //
  393. DBGPRINT((DM_CONTROL, DL_MID, TEXT("Quota file \"%s\" open with access 0x%08X"), strQuotaFile.Cstr(), dwAccess));
  394. m_dwAccessRights = dwAccess;
  395. }
  396. return hr;
  397. }
  398. ///////////////////////////////////////////////////////////////////////////////
  399. /* Function: FSVolume::QueryObjectQuotaInformation
  400. Description: Retrieves quota information for the volume. This includes
  401. default quota threshold, default quota limit and system control flags.
  402. Arguments:
  403. poi - Address of object information buffer. This type contains
  404. a subset of the information in FILE_FS_CONTROL_INFORMATION
  405. (defined in ntioapi.h).
  406. Returns:
  407. NOERROR - Success.
  408. ERROR_ACCESS_DENIED (hr) - No READ access to quota device.
  409. Other - NTFS subsystem failure result.
  410. Revision History:
  411. Date Description Programmer
  412. -------- --------------------------------------------------- ----------
  413. 05/24/96 Initial creation. BrianAu
  414. 08/11/96 Added access control. BrianAu
  415. */
  416. ///////////////////////////////////////////////////////////////////////////////
  417. HRESULT
  418. FSVolume::QueryObjectQuotaInformation(
  419. PDISKQUOTA_FSOBJECT_INFORMATION poi
  420. )
  421. {
  422. DBGTRACE((DM_CONTROL, DL_MID, TEXT("FSVolume::QueryObjectQuotaInformation")));
  423. HRESULT hr = E_FAIL;
  424. if (!GrantedAccess(GENERIC_READ))
  425. {
  426. DBGPRINT((DM_CONTROL, DL_MID, TEXT("Access denied reading quota info")));
  427. hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  428. }
  429. else
  430. {
  431. NTSTATUS status = STATUS_SUCCESS;
  432. IO_STATUS_BLOCK iosb;
  433. FILE_FS_CONTROL_INFORMATION ControlInfo;
  434. status = NtQueryVolumeInformationFile(
  435. m_hVolume,
  436. &iosb,
  437. &ControlInfo,
  438. sizeof(ControlInfo),
  439. FileFsControlInformation);
  440. if (STATUS_SUCCESS == status)
  441. {
  442. //
  443. // Update caller's buffer with quota control data.
  444. //
  445. poi->DefaultQuotaThreshold = ControlInfo.DefaultQuotaThreshold.QuadPart;
  446. poi->DefaultQuotaLimit = ControlInfo.DefaultQuotaLimit.QuadPart;
  447. poi->FileSystemControlFlags = ControlInfo.FileSystemControlFlags;
  448. hr = NOERROR;
  449. }
  450. else
  451. {
  452. DBGERROR((TEXT("NtQueryVolumeInformationFile failed with NTSTATUS 0x%08X"), status));
  453. hr = HResultFromNtStatus(status);
  454. }
  455. }
  456. return hr;
  457. }
  458. ///////////////////////////////////////////////////////////////////////////////
  459. /* Function: FSVolume::SetObjectQuotaInformation
  460. Description: Writes new quota information to the volume. This includes
  461. default quota threshold, default quota limit and system control flags.
  462. Arguments:
  463. poi - Address of object information buffer. This type contains
  464. a subset of the information in FILE_FS_CONTROL_INFORMATION
  465. (defined in ntioapi.h).
  466. dwChangeMask - Mask specifying which elements in *poi to write to disk.
  467. Can be any combination of:
  468. FSObject::ChangeState
  469. FSObject::ChangeLogFlags
  470. FSObject::ChangeThreshold
  471. FSObject::ChangeLimit
  472. Returns:
  473. NOERROR - Success.
  474. ERROR_ACCESS_DENIED (hr) - No WRITE access to quota device.
  475. Other - NTFS subsystem failure result.
  476. Revision History:
  477. Date Description Programmer
  478. -------- --------------------------------------------------- ----------
  479. 05/24/96 Initial creation. BrianAu
  480. 08/11/96 Added access control. BrianAu
  481. */
  482. ///////////////////////////////////////////////////////////////////////////////
  483. HRESULT
  484. FSVolume::SetObjectQuotaInformation(
  485. PDISKQUOTA_FSOBJECT_INFORMATION poi,
  486. DWORD dwChangeMask
  487. ) const
  488. {
  489. DBGTRACE((DM_CONTROL, DL_MID, TEXT("FSVolume::SetObjectQuotaInformation")));
  490. HRESULT hr = E_FAIL;
  491. if (!GrantedAccess(GENERIC_WRITE))
  492. {
  493. DBGPRINT((DM_CONTROL, DL_MID, TEXT("Access denied setting quota info")));
  494. hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  495. }
  496. else
  497. {
  498. NTSTATUS status = STATUS_SUCCESS;
  499. IO_STATUS_BLOCK iosb;
  500. FILE_FS_CONTROL_INFORMATION ControlInfo;
  501. //
  502. // First read current info from disk.
  503. // Then replace whatever we're changing.
  504. //
  505. status = NtQueryVolumeInformationFile(
  506. m_hVolume,
  507. &iosb,
  508. &ControlInfo,
  509. sizeof(ControlInfo),
  510. FileFsControlInformation);
  511. if (STATUS_SUCCESS == status)
  512. {
  513. //
  514. // Only alter those values specified in dwChangeMask.
  515. //
  516. if (FSObject::ChangeState & dwChangeMask)
  517. {
  518. ControlInfo.FileSystemControlFlags &= ~DISKQUOTA_STATE_MASK;
  519. ControlInfo.FileSystemControlFlags |= (poi->FileSystemControlFlags & DISKQUOTA_STATE_MASK);
  520. }
  521. if (FSObject::ChangeLogFlags & dwChangeMask)
  522. {
  523. ControlInfo.FileSystemControlFlags &= ~DISKQUOTA_LOGFLAG_MASK;
  524. ControlInfo.FileSystemControlFlags |= (poi->FileSystemControlFlags & DISKQUOTA_LOGFLAG_MASK);
  525. }
  526. if (FSObject::ChangeThreshold & dwChangeMask)
  527. {
  528. ControlInfo.DefaultQuotaThreshold.QuadPart = poi->DefaultQuotaThreshold;
  529. }
  530. if (FSObject::ChangeLimit & dwChangeMask)
  531. {
  532. ControlInfo.DefaultQuotaLimit.QuadPart = poi->DefaultQuotaLimit;
  533. }
  534. status = NtSetVolumeInformationFile(
  535. m_hVolume,
  536. &iosb,
  537. &ControlInfo,
  538. sizeof(ControlInfo),
  539. FileFsControlInformation);
  540. if (STATUS_SUCCESS == status)
  541. {
  542. hr = NOERROR;
  543. }
  544. else
  545. {
  546. DBGERROR((TEXT("NtSetVolumeInformationFile failed with NTSTATUS = 0x%08X"), status));
  547. hr = HResultFromNtStatus(status);
  548. }
  549. }
  550. else
  551. {
  552. DBGERROR((TEXT("NtQueryVolumeInformationFile failed with NTSTATUS = 0x%08X"), status));
  553. hr = HResultFromNtStatus(status);
  554. }
  555. }
  556. return hr;
  557. }
  558. ///////////////////////////////////////////////////////////////////////////////
  559. /* Function: FSVolume::QueryUserQuotaInformation
  560. Description: Retrieves user quota information for the volume. This includes
  561. quota threshold and quota limit. This function works like an enumerator.
  562. Repeated calls will return multiple user records.
  563. Arguments:
  564. pBuffer - Address of buffer to receive quota information.
  565. cbBuffer - Number of bytes in buffer.
  566. bReturnSingleEntry - TRUE = Return only one record from quota file.
  567. FALSE = Return as many whole entries as possible
  568. in buffer.
  569. pSidList [optional] - Address of SID list identifying users to obtain
  570. information for. Specify NULL to include all users.
  571. cbSidList [optional] - Number of bytes in sid list. Ignored if pSidList
  572. is NULL.
  573. pStartSid [optional] - Address of SID identifying which user is to start
  574. the enumeration. Specify NULL to start with current user in
  575. enumeration.
  576. bRestartScan - TRUE = restart scan from first user in the SID list or
  577. the entire file if pSidList is NULL.
  578. FALSE = Continue enumeration from current user record.
  579. Returns:
  580. NOERROR - Success.
  581. ERROR_NO_MORE_ITEMS - Read last entry in quota file.
  582. ERROR_ACCESS_DENIED (hr) - No READ access to quota device.
  583. Other - Quota subsystem error.
  584. Revision History:
  585. Date Description Programmer
  586. -------- --------------------------------------------------- ----------
  587. 05/24/96 Initial creation. BrianAu
  588. 08/11/96 Added access control. BrianAu
  589. */
  590. ///////////////////////////////////////////////////////////////////////////////
  591. HRESULT
  592. FSVolume::QueryUserQuotaInformation(
  593. PVOID pBuffer,
  594. ULONG cbBuffer,
  595. BOOL bReturnSingleEntry,
  596. PVOID pSidList,
  597. ULONG cbSidList,
  598. PSID pStartSid,
  599. BOOL bRestartScan
  600. )
  601. {
  602. DBGTRACE((DM_CONTROL, DL_MID, TEXT("FSVolume::QueryUserQuotaInformation")));
  603. HRESULT hr = E_FAIL;
  604. DBGASSERT((NULL != pBuffer));
  605. if (!GrantedAccess(GENERIC_READ))
  606. {
  607. DBGPRINT((DM_CONTROL, DL_MID, TEXT("Access denied querying user quota info")));
  608. hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  609. }
  610. else
  611. {
  612. NTSTATUS status = STATUS_SUCCESS;
  613. IO_STATUS_BLOCK iosb;
  614. status = NtQueryQuotaInformationFile(
  615. m_hVolume,
  616. &iosb,
  617. pBuffer,
  618. cbBuffer,
  619. (BOOLEAN)bReturnSingleEntry,
  620. pSidList,
  621. cbSidList,
  622. pStartSid,
  623. (BOOLEAN)bRestartScan);
  624. switch(status)
  625. {
  626. case STATUS_SUCCESS:
  627. hr = NOERROR;
  628. break;
  629. default:
  630. DBGERROR((TEXT("NtQueryQuotaInformationFile failed with NTSTATUS 0x%08X"), status));
  631. //
  632. // Fall through...
  633. //
  634. case STATUS_NO_MORE_ENTRIES:
  635. hr = HResultFromNtStatus(status);
  636. break;
  637. }
  638. }
  639. return hr;
  640. }
  641. ///////////////////////////////////////////////////////////////////////////////
  642. /* Function: FSVolume::SetUserQuotaInformation
  643. Description: Writes new user quota information to the volume. This includes
  644. quota threshold, and quota limit.
  645. Arguments:
  646. pBuffer - Address of buffer containing quota information.
  647. cbBuffer - Number of bytes of data in buffer.
  648. Returns:
  649. NOERROR - Success.
  650. ERROR_ACCESS_DENIED (hr) - No WRITE access to quota device.
  651. Or tried to set limit on Administrator.
  652. Other - Quota subsystem error.
  653. Revision History:
  654. Date Description Programmer
  655. -------- --------------------------------------------------- ----------
  656. 05/24/96 Initial creation. BrianAu
  657. 08/11/96 Added access control. BrianAu
  658. */
  659. ///////////////////////////////////////////////////////////////////////////////
  660. HRESULT
  661. FSVolume::SetUserQuotaInformation(
  662. PVOID pBuffer,
  663. ULONG cbBuffer
  664. ) const
  665. {
  666. DBGTRACE((DM_CONTROL, DL_MID, TEXT("FSVolume::SetUserQuotaInformation")));
  667. HRESULT hr = NOERROR;
  668. DBGASSERT((NULL != pBuffer));
  669. if (!GrantedAccess(GENERIC_WRITE))
  670. {
  671. DBGPRINT((DM_CONTROL, DL_MID, TEXT("Access denied setting user quota info")));
  672. hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  673. }
  674. else
  675. {
  676. NTSTATUS status = STATUS_SUCCESS;
  677. IO_STATUS_BLOCK iosb;
  678. status = NtSetQuotaInformationFile(
  679. m_hVolume,
  680. &iosb,
  681. pBuffer,
  682. cbBuffer);
  683. if (STATUS_SUCCESS == status)
  684. {
  685. hr = NOERROR;
  686. }
  687. else
  688. {
  689. DBGERROR((TEXT("NtSetQuotaInformationFile failed with NTSTATUS 0x%08X"), status));
  690. hr = HResultFromNtStatus(status);
  691. }
  692. }
  693. return hr;
  694. }
  695. //
  696. // Convert an NTSTATUS value to an HRESULT.
  697. // This is a simple attempt at converting the most common NTSTATUS values that
  698. // might be returned from NtQueryxxxxx and NTSetxxxxxx functions. If I've missed
  699. // some obvious ones, go ahead and add them.
  700. //
  701. HRESULT
  702. FSObject::HResultFromNtStatus(
  703. NTSTATUS status
  704. )
  705. {
  706. HRESULT hr = E_FAIL; // Default if none matched.
  707. static const struct
  708. {
  709. NTSTATUS status;
  710. HRESULT hr;
  711. } rgXref[] = {
  712. { STATUS_SUCCESS, NOERROR },
  713. { STATUS_INVALID_PARAMETER, E_INVALIDARG },
  714. { STATUS_NO_MORE_ENTRIES, HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) },
  715. { STATUS_ACCESS_DENIED, HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) },
  716. { STATUS_BUFFER_TOO_SMALL, HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) },
  717. { STATUS_BUFFER_OVERFLOW, HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW) },
  718. { STATUS_INVALID_HANDLE, HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE) },
  719. { STATUS_INVALID_DEVICE_REQUEST, HRESULT_FROM_WIN32(ERROR_BAD_DEVICE) },
  720. { STATUS_FILE_INVALID, HRESULT_FROM_WIN32(ERROR_DEVICE_NOT_AVAILABLE) }};
  721. for (int i = 0; i < ARRAYSIZE(rgXref); i++)
  722. {
  723. if (rgXref[i].status == status)
  724. {
  725. hr = rgXref[i].hr;
  726. break;
  727. }
  728. }
  729. return hr;
  730. }