Leaked source code of windows server 2003
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.

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