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.

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