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.

1341 lines
41 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. /* File: enumuser.cpp
  3. Description: Contains member function definitions for class DiskQuotaUserEnum.
  4. The DiskQuotaUserEnum object is provided to enumerate the users in a
  5. volume's quota information file. The caller instantiates an enumerator
  6. through IDiskQuotaControl::CreateDiskQuotaUserEnum(). The enumerator's
  7. interface IEnumDiskQuotaUsers supports the normal OLE 2 enumeration
  8. functions Next(), Skip(), Reset() and Clone().
  9. Revision History:
  10. Date Description Programmer
  11. -------- --------------------------------------------------- ----------
  12. 05/22/96 Initial creation. BrianAu
  13. */
  14. ///////////////////////////////////////////////////////////////////////////////
  15. #include "pch.h" // PCH
  16. #pragma hdrstop
  17. #include "user.h"
  18. #include "userenum.h"
  19. //
  20. // Verify that build is UNICODE.
  21. //
  22. #if !defined(UNICODE)
  23. # error This module must be compiled UNICODE.
  24. #endif
  25. ///////////////////////////////////////////////////////////////////////////////
  26. /* Function: DiskQuotaUserEnum::DiskQuotaUserEnum
  27. Description: Constructor.
  28. Arguments:
  29. pFSObject - Pointer to an existing "file system" object.
  30. It is through this object that the enumerator accesses the ntioapi
  31. functions. A pointer to this file system object is also passed
  32. on to contained user objects so they may refresh their data when
  33. required.
  34. pQuotaController - Pointer to an IDiskQuotaControl interface that we'll
  35. AddRef(). The control object is who provides the "name changed"
  36. notification mechanism. It needs to stay around as long as the
  37. enumerator is alive.
  38. pSidNameResolver - Pointer to an ISidNameResolver interface that will
  39. be used to resolve user SIDs to account names. The resolver object
  40. is initially instantiated by the quota controller.
  41. Returns: Nothing.
  42. Revision History:
  43. Date Description Programmer
  44. -------- --------------------------------------------------- ----------
  45. 05/22/96 Initial creation. BrianAu
  46. 08/15/97 Moved pQuotaControl, pSidNameResolver and pFSObject BrianAu
  47. arguments from Initialize() to ctor. Needed so
  48. that ref counting is correct.
  49. */
  50. ///////////////////////////////////////////////////////////////////////////////
  51. DiskQuotaUserEnum::DiskQuotaUserEnum(
  52. PDISKQUOTA_CONTROL pQuotaController,
  53. PSID_NAME_RESOLVER pSidNameResolver,
  54. FSObject *pFSObject
  55. ) : m_cRef(0),
  56. m_pbBuffer(NULL),
  57. m_pbCurrent(NULL),
  58. m_cbBuffer(0),
  59. m_pSidList(NULL),
  60. m_cbSidList(0),
  61. m_bEOF(FALSE),
  62. m_bSingleUser(FALSE),
  63. m_bInitialized(FALSE),
  64. m_bRestartScan(TRUE),
  65. m_fNameResolution(DISKQUOTA_USERNAME_RESOLVE_NONE),
  66. m_pFSObject(pFSObject),
  67. m_pQuotaController(pQuotaController),
  68. m_pSidNameResolver(pSidNameResolver)
  69. {
  70. DBGTRACE((DM_USER, DL_HIGH, TEXT("DiskQuotaUserEnum::DiskQuotaUserEnum")));
  71. if (NULL != m_pQuotaController)
  72. m_pQuotaController->AddRef();
  73. if (NULL != m_pSidNameResolver)
  74. m_pSidNameResolver->AddRef();
  75. if (NULL != m_pFSObject)
  76. m_pFSObject->AddRef();
  77. InterlockedIncrement(&g_cRefThisDll);
  78. }
  79. ///////////////////////////////////////////////////////////////////////////////
  80. /* Function: DiskQuotaUserEnum::~DiskQuotaUserEnum
  81. Description: Destructor. Destroys the enumerator's internal buffers and
  82. releases any held interface pointers.
  83. Arguments: None.
  84. Returns: Nothing.
  85. Revision History:
  86. Date Description Programmer
  87. -------- --------------------------------------------------- ----------
  88. 05/22/96 Initial creation. BrianAu
  89. */
  90. ///////////////////////////////////////////////////////////////////////////////
  91. DiskQuotaUserEnum::~DiskQuotaUserEnum(void)
  92. {
  93. DBGTRACE((DM_USER, DL_HIGH, TEXT("DiskQuotaUserEnum::~DiskQuotaUserEnum")));
  94. if (NULL != m_pFSObject)
  95. m_pFSObject->Release();
  96. //
  97. // Order is important here. Release the resolver before the controller.
  98. //
  99. if (NULL != m_pSidNameResolver)
  100. m_pSidNameResolver->Release();
  101. if (NULL != m_pQuotaController)
  102. m_pQuotaController->Release();
  103. delete [] m_pbBuffer;
  104. delete [] m_pSidList;
  105. InterlockedDecrement(&g_cRefThisDll);
  106. }
  107. ///////////////////////////////////////////////////////////////////////////////
  108. /* Function: DiskQuotaUserEnum::QueryInterface
  109. Description: Obtain pointer to IUnknown or IEnumDiskQuotaUser. Note that
  110. referenced object is uninitialized. Recipient of interface pointer
  111. must call Initialize() member function before object is usable.
  112. Arguments:
  113. riid - Reference to requested interface ID. IID_IUnknown and
  114. IID_IEnumDiskQuotaUser are recognized.
  115. ppvOut - Address of interface pointer variable to accept the
  116. returned interface pointer.
  117. Returns:
  118. NO_ERROR - Success.
  119. E_NOINTERFACE - Requested interface not supported.
  120. E_INVALIDARG - ppvOut argument is NULL.
  121. Revision History:
  122. Date Description Programmer
  123. -------- --------------------------------------------------- ----------
  124. 05/22/96 Initial creation. BrianAu
  125. */
  126. ///////////////////////////////////////////////////////////////////////////////
  127. STDMETHODIMP
  128. DiskQuotaUserEnum::QueryInterface(
  129. REFIID riid,
  130. LPVOID *ppvOut
  131. )
  132. {
  133. HRESULT hResult = E_NOINTERFACE;
  134. if (NULL == ppvOut)
  135. return E_INVALIDARG;
  136. *ppvOut = NULL;
  137. if (IID_IUnknown == riid || IID_IEnumDiskQuotaUsers == riid)
  138. {
  139. //
  140. // Interface supported.
  141. //
  142. *ppvOut = this;
  143. ((LPUNKNOWN)*ppvOut)->AddRef();
  144. hResult = NOERROR;
  145. }
  146. return hResult;
  147. }
  148. ///////////////////////////////////////////////////////////////////////////////
  149. /* Function: DiskQuotaUserEnum::AddRef
  150. Description: Increments object reference count.
  151. Arguments: None.
  152. Returns: New reference count value.
  153. Revision History:
  154. Date Description Programmer
  155. -------- --------------------------------------------------- ----------
  156. 05/22/96 Initial creation. BrianAu
  157. */
  158. ///////////////////////////////////////////////////////////////////////////////
  159. STDMETHODIMP_(ULONG)
  160. DiskQuotaUserEnum::AddRef(
  161. VOID
  162. )
  163. {
  164. ULONG ulReturn = m_cRef + 1;
  165. DBGPRINT((DM_COM, DL_HIGH, TEXT("DiskQuotaUserEnum::AddRef, 0x%08X %d -> %d"),
  166. this, ulReturn - 1, ulReturn));
  167. InterlockedIncrement(&m_cRef);
  168. return ulReturn;
  169. }
  170. ///////////////////////////////////////////////////////////////////////////////
  171. /* Function: DiskQuotaUserEnum::Release
  172. Description: Decrements object reference count. If count drops to 0,
  173. object is deleted.
  174. Arguments: None.
  175. Returns: New reference count value.
  176. Revision History:
  177. Date Description Programmer
  178. -------- --------------------------------------------------- ----------
  179. 05/22/96 Initial creation. BrianAu
  180. */
  181. ///////////////////////////////////////////////////////////////////////////////
  182. STDMETHODIMP_(ULONG)
  183. DiskQuotaUserEnum::Release(
  184. VOID
  185. )
  186. {
  187. ULONG ulReturn = m_cRef - 1;
  188. DBGPRINT((DM_COM, DL_HIGH, TEXT("DiskQuotaUserEnum::Release, 0x%08X %d -> %d"),
  189. this, ulReturn + 1, ulReturn));
  190. if (InterlockedDecrement(&m_cRef) == 0)
  191. {
  192. delete this;
  193. ulReturn = 0;
  194. }
  195. return ulReturn;
  196. }
  197. ///////////////////////////////////////////////////////////////////////////////
  198. /* Function: DiskQuotaUserEnum::Initialize
  199. Description: Initializes a new enumerator object.
  200. This member function is overloaded to provide two
  201. implementations. The first accepts explicit arguments for
  202. initialization. This member is intended for creating a new unique
  203. enumerator through IDiskQuotaControl::CreateEnumUsers. The
  204. second implementation merely accepts a reference to an existing
  205. EnumUsers object. This member is intended to support the function
  206. IEnumDiskQuotaUser::Clone().
  207. Arguments:
  208. fNameResolution - Method of SID-to-name resolution. Can be one of the
  209. following:
  210. DISKQUOTA_USERNAME_RESOLVE_NONE
  211. DISKQUOTA_USERNAME_RESOLVE_SYNC
  212. DISKQUOTA_USERNAME_RESOLVE_ASYNC
  213. cbBuffer [optional] - Size in bytes of the internal buffer used in
  214. calls to the NTIOAPI functions. Default is ENUMUSER_BUF_LEN.
  215. rgpSids [optional] - Pointer to a list of SID pointers. If
  216. provided, only those users with SIDs included in the list are
  217. returned. This argument may be NULL in which case ALL users are
  218. included. Any element containing a NULL pointer will terminate
  219. the list.
  220. cpSids [optional] - If pSidList is not NULL, this arg contains
  221. the count of entries in rgpSids. If rgpSids is not NULL and this
  222. argument contains 0, rgpSids is assumed to contain a terminating
  223. NULL pointer entry.
  224. UserEnum - Reference to an existing DiskQuotaUserEnum object. The new
  225. object opens a connection to the same volume as the object being
  226. cloned. The new object maintains a separate buffer for transfer
  227. of data from the NTIOAPI system.
  228. Returns:
  229. NO_ERROR - Success.
  230. S_FALSE - Already initialized.
  231. E_OUTOFMEMORY - Insufficient memory.
  232. ERROR_INVALID_SID (hr) - A SID in rgpSids was invalid.
  233. Revision History:
  234. Date Description Programmer
  235. -------- --------------------------------------------------- ----------
  236. 05/22/96 Initial creation. BrianAu
  237. */
  238. ///////////////////////////////////////////////////////////////////////////////
  239. HRESULT
  240. DiskQuotaUserEnum::Initialize(
  241. DWORD fNameResolution,
  242. DWORD cbBuffer,
  243. PSID *rgpSids,
  244. DWORD cpSids
  245. )
  246. {
  247. HRESULT hResult = NO_ERROR;
  248. if (m_bInitialized)
  249. {
  250. hResult = S_FALSE;
  251. }
  252. else
  253. {
  254. try
  255. {
  256. //
  257. // Create an internal buffer for data transfer from the ntioapi.
  258. //
  259. m_pbBuffer = new BYTE [cbBuffer];
  260. m_cbBuffer = cbBuffer;
  261. if (NULL != rgpSids)
  262. {
  263. //
  264. // A list of SID pointers was provided.
  265. // Initialize the SID list structure.
  266. // Can throw OutOfMemory.
  267. //
  268. m_bSingleUser = (cpSids == 1);
  269. hResult = InitializeSidList(rgpSids, cpSids);
  270. }
  271. if (SUCCEEDED(hResult))
  272. {
  273. //
  274. // Must have an independent instance of the controller's file system
  275. // object. The NTIOAPI functions maintain an enumeration context
  276. // for each open handle. Therefore, each user enumerator must have a
  277. // unique file handle to the NTIOAPI object.
  278. // I say this because it appears tempting to just keep a copy of the
  279. // controller's FSObject pointer and AddRef it.
  280. //
  281. // This create-n-swap is sort of slimy. We originally got a
  282. // ptr to the caller's FSObject in the ctor. However, now we want
  283. // to create our own FSObject. Create a copy and release the original.
  284. //
  285. FSObject *pFsoTemp = m_pFSObject;
  286. m_pFSObject = NULL;
  287. hResult = FSObject::Create(*pFsoTemp, &m_pFSObject);
  288. pFsoTemp->Release();
  289. if (SUCCEEDED(hResult))
  290. {
  291. m_fNameResolution = fNameResolution;
  292. m_bInitialized = TRUE;
  293. }
  294. }
  295. }
  296. catch(CAllocException& e)
  297. {
  298. hResult = E_OUTOFMEMORY;
  299. }
  300. }
  301. return hResult;
  302. }
  303. HRESULT
  304. DiskQuotaUserEnum::Initialize(
  305. const DiskQuotaUserEnum& UserEnum
  306. )
  307. {
  308. HRESULT hResult = NO_ERROR;
  309. try
  310. {
  311. //
  312. // Initialize the new enumerator without a SID list.
  313. // If the enumerator being copied has a SID list, we
  314. // don't want to re-create a list of SID pointers for Initialize()
  315. // so we defer this for InitializeSidList. InitializeSidList
  316. // has an overloaded version that accepts a pointer to an existing
  317. // SIDLIST structure and merely copies the bytes.
  318. //
  319. hResult = Initialize(UserEnum.m_fNameResolution,
  320. UserEnum.m_cbBuffer,
  321. NULL,
  322. 0);
  323. if (SUCCEEDED(hResult) && NULL != UserEnum.m_pSidList)
  324. {
  325. m_bSingleUser = UserEnum.m_bSingleUser;
  326. hResult = InitializeSidList(UserEnum.m_pSidList,
  327. UserEnum.m_cbSidList);
  328. }
  329. }
  330. catch(CAllocException& e)
  331. {
  332. hResult = E_OUTOFMEMORY;
  333. }
  334. return hResult;
  335. }
  336. ///////////////////////////////////////////////////////////////////////////////
  337. /* Function: DiskQuotaUserEnum::InitializeSidList
  338. Description: Initializes the m_pSidList member of the enumerator.
  339. The method comes in two overloaded forms. The first accepts a pointer
  340. to an existing SIDLIST structure and merely creates a new copy.
  341. The second form accepts the address of an array of SID pointers and
  342. generates a new SIDLIST structure.
  343. Arguments:
  344. pSidList - Address of an existing SIDLIST structure to be copied.
  345. cbSidList - Number of bytes in the SIDLIST structure.
  346. rgpSids - Pointer to a list of SID pointers. If provided, only those
  347. users with SIDs included in the list are returned. This argument
  348. may be NULL in which case ALL users are included. Any element
  349. containing a NULL pointer will terminate the list.
  350. cpSids - If pSidList is not NULL, this arg contains the count of
  351. entries in rgpSids. If rgpSids is not NULL and this argument
  352. contains 0, rgpSids is assumed to contain a terminating NULL
  353. pointer entry.
  354. Returns:
  355. NO_ERROR - Success.
  356. ERROR_INVALID_SID (hr) - A SID in rgpSids was invalid.
  357. Exceptions: OutOfMemory.
  358. Revision History:
  359. Date Description Programmer
  360. -------- --------------------------------------------------- ----------
  361. 08/13/96 Initial creation. BrianAu
  362. */
  363. ///////////////////////////////////////////////////////////////////////////////
  364. HRESULT
  365. DiskQuotaUserEnum::InitializeSidList(
  366. PSIDLIST pSidList,
  367. DWORD cbSidList
  368. )
  369. {
  370. HRESULT hResult = NO_ERROR;
  371. DBGASSERT((NULL != pSidList));
  372. DBGASSERT((0 < cbSidList));
  373. //
  374. // Create a buffer for the SID list copy.
  375. //
  376. m_pSidList = (PSIDLIST)new BYTE[cbSidList];
  377. //
  378. // Copy the enumerator's SID list.
  379. //
  380. CopyMemory(m_pSidList, pSidList, cbSidList);
  381. m_cbSidList = cbSidList;
  382. return hResult;
  383. }
  384. HRESULT
  385. DiskQuotaUserEnum::InitializeSidList(
  386. PSID *rgpSids,
  387. DWORD cpSids
  388. )
  389. {
  390. HRESULT hResult = NO_ERROR;
  391. DBGASSERT((NULL != rgpSids));
  392. DBGASSERT((0 < cpSids));
  393. //
  394. // Create a SIDLIST structure from the array of SID pointers.
  395. // Can throw OutOfMemory.
  396. //
  397. hResult = CreateSidList(rgpSids, cpSids, &m_pSidList, &m_cbSidList);
  398. if (FAILED(hResult))
  399. {
  400. DBGASSERT((NULL == m_pSidList));
  401. DBGASSERT((0 == m_cbSidList));
  402. }
  403. return hResult;
  404. }
  405. ///////////////////////////////////////////////////////////////////////////////
  406. /* Function: DiskQuotaUserEnum::QueryQuotaInformation
  407. Description: Provides a simple wrapper around the NTIOAPI function
  408. QueryQuotaInformationFile. The function adds value by providing
  409. the address and size of the enumerator's data buffer.
  410. Note that the QueryQuotaInformationFile interface in NTIOAPI
  411. functions as an enumerator itself. Repeated calls enumerate
  412. user quota data much the same way the Next() function does in an OLE
  413. enumerator interface. Data is returned in a byte buffer as a series
  414. of variable-length quota records.
  415. Arguments:
  416. bReturnSingleEntry [optional] - TRUE if only a single entry is
  417. desired. FALSE if multiple records are desired. Default is
  418. FALSE.
  419. pSidList [optional] - Pointer to a list of SIDs. If provided, the
  420. data returned is only for those users included in the SID list.
  421. Default is NULL.
  422. cbSidList [optional] - If SidList is not NULL, contains length
  423. of SidList in bytes. Default is 0.
  424. pStartSid [optional] - Pointer to SID in SID list where scan is to
  425. start if bRestartScan is TRUE. Default is NULL.
  426. bRestartScan [optional] - TRUE = restart enumeration at first user
  427. or user pointed to by StartSid in SidList (if provided).
  428. FALSE = continue enumeration from current point.
  429. Default is FALSE.
  430. Returns:
  431. NO_ERROR - Success.
  432. ERROR_NO_MORE_ITEMS - No more user records.
  433. Revision History:
  434. Date Description Programmer
  435. -------- --------------------------------------------------- ----------
  436. 05/22/96 Initial creation. BrianAu
  437. */
  438. ///////////////////////////////////////////////////////////////////////////////
  439. HRESULT
  440. DiskQuotaUserEnum::QueryQuotaInformation(
  441. BOOL bReturnSingleEntry,
  442. PVOID pSidList,
  443. ULONG cbSidList,
  444. PSID pStartSid,
  445. BOOL bRestartScan
  446. )
  447. {
  448. HRESULT hResult = NO_ERROR;
  449. if (bRestartScan)
  450. {
  451. //
  452. // Reset EOF flag if restarting enumerator scan.
  453. //
  454. m_bEOF = FALSE;
  455. }
  456. if (!m_bEOF)
  457. {
  458. ZeroMemory(m_pbBuffer, m_cbBuffer);
  459. hResult = m_pFSObject->QueryUserQuotaInformation(
  460. m_pbBuffer,
  461. m_cbBuffer,
  462. bReturnSingleEntry,
  463. pSidList,
  464. cbSidList,
  465. pStartSid,
  466. bRestartScan);
  467. if (ERROR_SUCCESS == HRESULT_CODE(hResult) || ERROR_NO_MORE_ITEMS == HRESULT_CODE(hResult))
  468. {
  469. //
  470. // The enumeration logic changed between Win2000 and WinXP.
  471. // On Win2000, NTFS will return ERROR_NO_MORE_ITEMS on the last
  472. // buffer returned that contains data. On WinXP, this error
  473. // code is returned on the first buffer that returns NO data.
  474. // To handle both cases, we zero out the buffer before reading data
  475. // and inspect the SidLength value in the first record to determine
  476. // if the buffer contains any data. If the sid length is 0, we
  477. // can assume the buffer is empty.
  478. //
  479. hResult = NO_ERROR;
  480. }
  481. }
  482. else
  483. {
  484. //
  485. // There REALLY are no more entries.
  486. //
  487. hResult = HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
  488. }
  489. return hResult;
  490. }
  491. ///////////////////////////////////////////////////////////////////////////////
  492. /* Function: DiskQuotaUserEnum::CreateUserObject
  493. Description: Creates a new DiskQuotaUser object from the quota information
  494. retrieved through QueryQuotaInformation. The caller provides a pointer
  495. to the start of the desired quota info record to be used for
  496. initialization.
  497. Arguments:
  498. pfqi - Pointer to the quota information record used for initialization.
  499. ppOut - Address of interface pointer variable to accept the user object's
  500. IDiskQuotaUser interface pointer.
  501. Returns:
  502. NO_ERROR - Success.
  503. E_INVALIDARG - pfqi or ppOut arg is NULL.
  504. E_UNEXPECTED - Unexpected error.
  505. Revision History:
  506. Date Description Programmer
  507. -------- --------------------------------------------------- ----------
  508. 05/22/96 Initial creation. BrianAu
  509. 09/05/96 Added exception handling. BrianAu
  510. */
  511. ///////////////////////////////////////////////////////////////////////////////
  512. HRESULT
  513. DiskQuotaUserEnum::CreateUserObject(
  514. PFILE_QUOTA_INFORMATION pfqi,
  515. PDISKQUOTA_USER *ppOut
  516. )
  517. {
  518. HRESULT hResult = NO_ERROR;
  519. if (NULL == pfqi || NULL == ppOut)
  520. return E_INVALIDARG;
  521. //
  522. // Create the user object and get the IDiskQuotaUser interface pointer.
  523. // This pointer is what is given to the caller.
  524. //
  525. m_pFSObject->AddRef();
  526. DiskQuotaUser *pUser = new DiskQuotaUser(m_pFSObject);
  527. //
  528. // Initialize the new user object using the buffered quota data pointed to
  529. // by pfqi.
  530. //
  531. hResult = pUser->Initialize(pfqi);
  532. if (SUCCEEDED(hResult))
  533. {
  534. hResult = pUser->QueryInterface(IID_IDiskQuotaUser, (LPVOID *)ppOut);
  535. }
  536. if (FAILED(hResult))
  537. {
  538. //
  539. // Either Initialize or QueryInterface failed. Delete the object.
  540. //
  541. delete pUser;
  542. pUser = NULL;
  543. }
  544. return hResult;
  545. }
  546. ///////////////////////////////////////////////////////////////////////////////
  547. /* Function: DiskQuotaUserEnum::GetNextUser
  548. Description: Creates a new user object from the "current" record in the
  549. quota information buffer. A pointer to the object's IDiskQuotaUser
  550. interface is returned and the "current" record pointer in the
  551. quota information buffer is advanced to the next user record.
  552. Arguments:
  553. ppOut [optional] - Address of interface pointer variable to receive
  554. address of user object's IDiskQuotaUserInterface pointer. If this
  555. argument is NULL, the new user object is not created. This is
  556. useful for skipping items in the enumeration.
  557. Returns:
  558. NO_ERROR - Success.
  559. E_DISKQUOTA_INVALID_SID - User record's SID is invalid.
  560. ERROR_NO_MORE_ITEMS - No more users.
  561. Revision History:
  562. Date Description Programmer
  563. -------- --------------------------------------------------- ----------
  564. 05/22/96 Initial creation. BrianAu
  565. */
  566. ///////////////////////////////////////////////////////////////////////////////
  567. HRESULT
  568. DiskQuotaUserEnum::GetNextUser(
  569. PDISKQUOTA_USER *ppOut
  570. )
  571. {
  572. PFILE_QUOTA_INFORMATION pfqi = (PFILE_QUOTA_INFORMATION)m_pbCurrent;
  573. HRESULT hResult = NO_ERROR;
  574. //
  575. // If m_pbCurrent is NULL, this is the first request for data.
  576. // If pfqi->NextEntryOffset is 0, we need to read another buffer of data.
  577. //
  578. if (NULL == m_pbCurrent)
  579. {
  580. //
  581. // No more user entries in buffer.
  582. // Read quota information into m_pbBuffer.
  583. // Use SID list if we have one.
  584. //
  585. hResult = QueryQuotaInformation(m_bSingleUser, // Single user?
  586. m_pSidList, // SID list.
  587. m_cbSidList, // SID list length.
  588. 0, // Start SID,
  589. m_bRestartScan); // Restart scan?
  590. if (SUCCEEDED(hResult))
  591. {
  592. //
  593. // New information in buffer. Reset record pointers.
  594. //
  595. m_pbCurrent = m_pbBuffer;
  596. m_bRestartScan = FALSE;
  597. pfqi = (PFILE_QUOTA_INFORMATION)m_pbCurrent;
  598. }
  599. }
  600. if (SUCCEEDED(hResult))
  601. {
  602. //
  603. // We have a valid pointer into the buffer of user quota data.
  604. //
  605. if (NULL != ppOut)
  606. {
  607. if (0 != pfqi->SidLength)
  608. {
  609. //
  610. // Caller provided a user interface pointer variable.
  611. // Create a new user record. This can throw OutOfMemory.
  612. //
  613. hResult = CreateUserObject(pfqi, ppOut);
  614. }
  615. else
  616. {
  617. m_bEOF = TRUE;
  618. hResult = HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
  619. }
  620. }
  621. if (0 != pfqi->NextEntryOffset)
  622. m_pbCurrent += pfqi->NextEntryOffset; // Advance to next user.
  623. else
  624. m_pbCurrent = NULL; // Reset to trigger quota file read.
  625. }
  626. return hResult;
  627. }
  628. ///////////////////////////////////////////////////////////////////////////////
  629. /* Function: DiskQuotaUserEnum::Next
  630. Description: Retrieve the next cUsers records from the volume's quota
  631. information file. If the enumerator was created with a SidList,
  632. only those users contained in the SidList are included in the
  633. enumeration. Repeated calls to Next() continue to enumerate
  634. successive quota users. The Reset() function may be used to
  635. reset the enumerator to the start of the enumeration.
  636. Arguments:
  637. cUsers - Number of elements in paUsers array.
  638. pUser - Array of IDiskQuotaUser pointers. Must provide space for
  639. cUsers pointers. Upon return, each element of this array contains
  640. an interface pointer to a DiskQuotaUser object.
  641. pcCreated [optional] - Address of DWORD to accept the count of user
  642. object interface pointers returned in pUser. Note that any
  643. array locations equal to or beyond the value returned in
  644. pcCreated are invalid and set to NULL.
  645. Returns:
  646. S_OK - Success. Enumerated number of requested users.
  647. S_FALSE - End of enumeration encountered. Returning less than
  648. cUsers records.
  649. E_INVALIDARG - pUser arg is NULL.
  650. Revision History:
  651. Date Description Programmer
  652. -------- --------------------------------------------------- ----------
  653. 05/22/96 Initial creation. BrianAu
  654. */
  655. ///////////////////////////////////////////////////////////////////////////////
  656. HRESULT
  657. DiskQuotaUserEnum::Next(
  658. DWORD cUsers, // Number of elements in array.
  659. PDISKQUOTA_USER *pUser, // Dest array for quota user interface ptrs.
  660. DWORD *pcCreated // Return number created.
  661. )
  662. {
  663. HRESULT hResult = S_OK;
  664. UINT i = 0; // Index into user caller's array.
  665. UINT cCreated = 0;
  666. if (NULL == pUser)
  667. return E_INVALIDARG;
  668. if (NULL != pcCreated)
  669. *pcCreated = 0;
  670. try
  671. {
  672. IDiskQuotaUser *pNextUser = NULL; // Ptr to new user.
  673. //
  674. // Enumerate user records until one of the following:
  675. // 1. Failure.
  676. // 2. No more users.
  677. // 3. Enumerated requested count.
  678. //
  679. while(SUCCEEDED(hResult) && cUsers > 0)
  680. {
  681. //
  682. // Create new user object. This can throw OutOfMemory.
  683. //
  684. hResult = GetNextUser(&pNextUser);
  685. if (SUCCEEDED(hResult))
  686. {
  687. //
  688. // User records come from the quota file containing only a SID.
  689. // We must ask the SidNameResolver to locate the corresponding
  690. // account name. If client wants names synchronously, we block
  691. // here until account name is found. User object will contain
  692. // account name.
  693. // If client wants names asynchronously, the user object is handed
  694. // off to the resolver for background processing. We continue on.
  695. // If the client implemented the IDiskQuotaEvents interface and
  696. // called IConnectionPoint::Advise, it will receive a
  697. // OnUserNameChange notification when the name is finally resolved.
  698. // If user doesn't want user name resolved, don't do either.
  699. // This would be the case if the client already has the SID/Name
  700. // pair and just wants user objects.
  701. //
  702. switch(m_fNameResolution)
  703. {
  704. case DISKQUOTA_USERNAME_RESOLVE_ASYNC:
  705. m_pSidNameResolver->FindUserNameAsync(pNextUser);
  706. break;
  707. case DISKQUOTA_USERNAME_RESOLVE_SYNC:
  708. m_pSidNameResolver->FindUserName(pNextUser);
  709. break;
  710. case DISKQUOTA_USERNAME_RESOLVE_NONE:
  711. default:
  712. break;
  713. }
  714. //
  715. // Note: Ref count for pUser already incremented in
  716. // DiskQuotaUser::QueryInterface.
  717. //
  718. *pUser = pNextUser;
  719. pUser++;
  720. cUsers--;
  721. cCreated++;
  722. }
  723. }
  724. if (NULL != pcCreated)
  725. *pcCreated = cCreated; // If requested, return number of users created.
  726. if (cUsers > 0)
  727. {
  728. //
  729. // Less than requested number of users were retrieved.
  730. //
  731. hResult = S_FALSE;
  732. while(cUsers > 0)
  733. {
  734. //
  735. // Set any un-filled array elements to NULL.
  736. //
  737. *pUser = NULL;
  738. pUser++;
  739. cUsers--;
  740. }
  741. }
  742. }
  743. catch(CAllocException& e)
  744. {
  745. hResult = E_OUTOFMEMORY;
  746. }
  747. if (FAILED(hResult))
  748. {
  749. //
  750. // Release any user objects already created.
  751. //
  752. for (i = 0; i < cCreated; i++)
  753. {
  754. PDISKQUOTA_USER pu = *(pUser + i);
  755. if (NULL != pu)
  756. {
  757. pu->Release();
  758. *(pUser + i) = NULL;
  759. }
  760. }
  761. *pcCreated = 0;
  762. }
  763. return hResult;
  764. }
  765. ///////////////////////////////////////////////////////////////////////////////
  766. /* Function: DiskQuotaUserEnum::Skip
  767. Description: Skips a specified number of users in the user enumeration.
  768. Arguments:
  769. cUsers - Number of users to skip.
  770. Returns:
  771. S_OK - Success. Skipped number of requested users.
  772. S_FALSE - End of enumeration encountered. Skipped less than
  773. cUsers records.
  774. Revision History:
  775. Date Description Programmer
  776. -------- --------------------------------------------------- ----------
  777. 05/22/96 Initial creation. BrianAu
  778. */
  779. ///////////////////////////////////////////////////////////////////////////////
  780. HRESULT
  781. DiskQuotaUserEnum::Skip(
  782. DWORD cUsers
  783. )
  784. {
  785. while(cUsers > 0 && SUCCEEDED(GetNextUser(NULL)))
  786. {
  787. cUsers--;
  788. }
  789. return cUsers == 0 ? S_OK : S_FALSE;
  790. }
  791. ///////////////////////////////////////////////////////////////////////////////
  792. /* Function: DiskQuotaUserEnum::Reset
  793. Description: Resets the enumerator object so that the next call to Next()
  794. starts enumerating at the beginning of the enumeration.
  795. Arguments: None.
  796. Returns:
  797. Always returns S_OK.
  798. Revision History:
  799. Date Description Programmer
  800. -------- --------------------------------------------------- ----------
  801. 05/22/96 Initial creation. BrianAu
  802. 02/09/99 Changed so we just reset m_pbCurrent and BrianAu
  803. m_bRestartScan.
  804. */
  805. ///////////////////////////////////////////////////////////////////////////////
  806. STDMETHODIMP
  807. DiskQuotaUserEnum::Reset(
  808. VOID
  809. )
  810. {
  811. m_pbCurrent = NULL;
  812. m_bRestartScan = TRUE;
  813. return S_OK;
  814. }
  815. ///////////////////////////////////////////////////////////////////////////////
  816. /* Function: DiskQuotaUserEnum::Clone
  817. Description: Creates a duplicate of the enumerator object and returns
  818. a pointer to the new object's IEnumDiskQuotaUser interface.
  819. Arguments:
  820. ppOut - Address of interface pointer variable to accept the pointer
  821. to the new object's IEnumDiskQuotaUser interface.
  822. Returns:
  823. NO_ERROR - Success.
  824. E_OUTOFMEMORY - Insufficient memory to create new enumerator.
  825. E_INVALIDARG - ppOut arg was NULL.
  826. Revision History:
  827. Date Description Programmer
  828. -------- --------------------------------------------------- ----------
  829. 05/22/96 Initial creation. BrianAu
  830. */
  831. ///////////////////////////////////////////////////////////////////////////////
  832. STDMETHODIMP
  833. DiskQuotaUserEnum::Clone(
  834. PENUM_DISKQUOTA_USERS *ppOut
  835. )
  836. {
  837. HRESULT hResult = NO_ERROR;
  838. if (NULL == ppOut)
  839. return E_INVALIDARG;
  840. try
  841. {
  842. DiskQuotaUserEnum *pUserEnum = new DiskQuotaUserEnum(
  843. m_pQuotaController,
  844. m_pSidNameResolver,
  845. m_pFSObject);
  846. hResult = pUserEnum->Initialize(*this);
  847. if (SUCCEEDED(hResult))
  848. {
  849. hResult = pUserEnum->QueryInterface(IID_IEnumDiskQuotaUsers,
  850. (LPVOID *)ppOut);
  851. }
  852. if (FAILED(hResult))
  853. {
  854. //
  855. // Either Initialize or QueryInterface failed.
  856. //
  857. delete pUserEnum;
  858. pUserEnum = NULL;
  859. }
  860. }
  861. catch(CAllocException& e)
  862. {
  863. hResult = E_OUTOFMEMORY;
  864. }
  865. return hResult;
  866. }
  867. DiskQuotaUserCollection::DiskQuotaUserCollection(
  868. PDISKQUOTA_CONTROL pController,
  869. DWORD fNameResolution
  870. ) : m_cRef(0),
  871. m_pController(pController),
  872. m_pEnum(NULL),
  873. m_fNameResolution(fNameResolution)
  874. {
  875. if (NULL != m_pController)
  876. {
  877. m_pController->AddRef();
  878. }
  879. }
  880. DiskQuotaUserCollection::~DiskQuotaUserCollection(
  881. VOID
  882. )
  883. {
  884. if (NULL != m_pEnum)
  885. {
  886. m_pEnum->Release();
  887. }
  888. if (NULL != m_pController)
  889. {
  890. m_pController->Release();
  891. }
  892. }
  893. HRESULT
  894. DiskQuotaUserCollection::Initialize(
  895. VOID
  896. )
  897. {
  898. HRESULT hr = S_FALSE; // Assume already initialized.
  899. if (NULL == m_pEnum)
  900. {
  901. if (NULL == m_pController)
  902. {
  903. hr = E_UNEXPECTED;
  904. }
  905. else
  906. {
  907. hr = m_pController->CreateEnumUsers(NULL,
  908. 0,
  909. m_fNameResolution,
  910. &m_pEnum);
  911. }
  912. }
  913. return hr;
  914. }
  915. ///////////////////////////////////////////////////////////////////////////////
  916. /* Function: DiskQuotaUserCollection::QueryInterface
  917. Description: Obtain pointer to IUnknown or IEnumDiskQuotaUserVARIANTs.
  918. Arguments:
  919. riid - Reference to requested interface ID.
  920. ppvOut - Address of interface pointer variable to accept the
  921. returned interface pointer.
  922. Returns:
  923. NO_ERROR - Success.
  924. E_NOINTERFACE - Requested interface not supported.
  925. E_INVALIDARG - ppvOut argument is NULL.
  926. Revision History:
  927. Date Description Programmer
  928. -------- --------------------------------------------------- ----------
  929. 08/22/97 Initial creation. BrianAu
  930. */
  931. ///////////////////////////////////////////////////////////////////////////////
  932. STDMETHODIMP
  933. DiskQuotaUserCollection::QueryInterface(
  934. REFIID riid,
  935. LPVOID *ppvOut
  936. )
  937. {
  938. HRESULT hResult = E_NOINTERFACE;
  939. if (NULL == ppvOut)
  940. return E_INVALIDARG;
  941. *ppvOut = NULL;
  942. if (IID_IUnknown == riid ||
  943. IID_IEnumVARIANT == riid)
  944. {
  945. //
  946. // Interface supported.
  947. //
  948. *ppvOut = this;
  949. ((LPUNKNOWN)*ppvOut)->AddRef();
  950. hResult = NOERROR;
  951. }
  952. return hResult;
  953. }
  954. ///////////////////////////////////////////////////////////////////////////////
  955. /* Function: DiskQuotaUserCollection::AddRef
  956. Description: Increments object reference count.
  957. Arguments: None.
  958. Returns: New reference count value.
  959. Revision History:
  960. Date Description Programmer
  961. -------- --------------------------------------------------- ----------
  962. 08/22/97 Initial creation. BrianAu
  963. */
  964. ///////////////////////////////////////////////////////////////////////////////
  965. STDMETHODIMP_(ULONG)
  966. DiskQuotaUserCollection::AddRef(
  967. VOID
  968. )
  969. {
  970. ULONG ulReturn = m_cRef + 1;
  971. DBGPRINT((DM_COM, DL_HIGH, TEXT("DiskQuotaUserCollection::AddRef, 0x%08X %d -> %d"),
  972. this, ulReturn - 1, ulReturn));
  973. InterlockedIncrement(&m_cRef);
  974. return ulReturn;
  975. }
  976. ///////////////////////////////////////////////////////////////////////////////
  977. /* Function: DiskQuotaUserCollection::Release
  978. Description: Decrements object reference count. If count drops to 0,
  979. object is deleted.
  980. Arguments: None.
  981. Returns: New reference count value.
  982. Revision History:
  983. Date Description Programmer
  984. -------- --------------------------------------------------- ----------
  985. 08/22/97 Initial creation. BrianAu
  986. */
  987. ///////////////////////////////////////////////////////////////////////////////
  988. STDMETHODIMP_(ULONG)
  989. DiskQuotaUserCollection::Release(
  990. VOID
  991. )
  992. {
  993. ULONG ulReturn = m_cRef - 1;
  994. DBGPRINT((DM_COM, DL_HIGH, TEXT("DiskQuotaUserCollection::Release, 0x%08X %d -> %d"),
  995. this, ulReturn + 1, ulReturn));
  996. if (InterlockedDecrement(&m_cRef) == 0)
  997. {
  998. delete this;
  999. ulReturn = 0;
  1000. }
  1001. return ulReturn;
  1002. }
  1003. STDMETHODIMP
  1004. DiskQuotaUserCollection::Next(
  1005. DWORD cUsers,
  1006. VARIANT *rgvar,
  1007. DWORD *pcUsersFetched
  1008. )
  1009. {
  1010. HRESULT hr = E_UNEXPECTED;
  1011. try
  1012. {
  1013. if (NULL == pcUsersFetched && 1 < cUsers)
  1014. {
  1015. //
  1016. // If pcUsersFetched is NULL, cUsers must be 1.
  1017. //
  1018. hr = E_INVALIDARG;
  1019. }
  1020. else
  1021. {
  1022. DWORD cEnumerated = 0;
  1023. PDISKQUOTA_USER *prgUsers = new PDISKQUOTA_USER[cUsers];
  1024. if (NULL != prgUsers)
  1025. {
  1026. hr = m_pEnum->Next(cUsers, prgUsers, &cEnumerated);
  1027. if (SUCCEEDED(hr))
  1028. {
  1029. for (INT i = 0; i < (INT)cEnumerated; i++)
  1030. {
  1031. VariantInit(&rgvar[i]);
  1032. IDispatch *pIDisp = NULL;
  1033. hr = prgUsers[i]->QueryInterface(IID_IDispatch, (LPVOID *)&pIDisp);
  1034. if (SUCCEEDED(hr))
  1035. {
  1036. V_VT(&rgvar[i]) = VT_DISPATCH;
  1037. V_DISPATCH(&rgvar[i]) = pIDisp;
  1038. }
  1039. prgUsers[i]->Release();
  1040. }
  1041. }
  1042. delete[] prgUsers;
  1043. }
  1044. if (NULL != pcUsersFetched)
  1045. {
  1046. *pcUsersFetched = cEnumerated;
  1047. }
  1048. }
  1049. }
  1050. catch(CAllocException& e)
  1051. {
  1052. hr = E_OUTOFMEMORY;
  1053. }
  1054. return hr;
  1055. }
  1056. STDMETHODIMP
  1057. DiskQuotaUserCollection::Skip(
  1058. DWORD cUsers
  1059. )
  1060. {
  1061. return m_pEnum->Skip(cUsers);
  1062. }
  1063. STDMETHODIMP
  1064. DiskQuotaUserCollection::Reset(
  1065. void
  1066. )
  1067. {
  1068. return m_pEnum->Reset();
  1069. }
  1070. STDMETHODIMP
  1071. DiskQuotaUserCollection::Clone(
  1072. IEnumVARIANT **ppEnum
  1073. )
  1074. {
  1075. HRESULT hr = E_FAIL;
  1076. try
  1077. {
  1078. DiskQuotaUserCollection *pEnum = new DiskQuotaUserCollection(m_pController,
  1079. m_fNameResolution);
  1080. if (NULL != pEnum)
  1081. {
  1082. hr = pEnum->Initialize();
  1083. if (SUCCEEDED(hr))
  1084. {
  1085. hr = pEnum->QueryInterface(IID_IEnumVARIANT, (LPVOID *)ppEnum);
  1086. }
  1087. else
  1088. {
  1089. delete pEnum;
  1090. }
  1091. }
  1092. }
  1093. catch(CAllocException& me)
  1094. {
  1095. hr = E_OUTOFMEMORY;
  1096. }
  1097. return hr;
  1098. }