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.

1965 lines
57 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. /* File: user.cpp
  3. Description: Contains member function definitions for class DiskQuotaUser.
  4. The DiskQuotaUser object represents a user's record in a volume's
  5. quota information file. The holder of a user object's IDiskQuotaUser
  6. interface can query and modify information for that user as security
  7. privileges permit. A user object is obtained through a UserEnumerator
  8. object (IEnumDiskQuotaUsers) which is itself obtained through
  9. IDiskQuotaControl::CreateEnumUsers().
  10. Revision History:
  11. Date Description Programmer
  12. -------- --------------------------------------------------- ----------
  13. 05/22/96 Initial creation. BrianAu
  14. 08/20/96 Added m_dwID member to DiskQuotaUser. BrianAu
  15. 09/05/96 Added exception handling. BrianAu
  16. 03/18/98 Replaced "domain", "name" and "full name" with BrianAu
  17. "container", "logon name" and "display name" to
  18. better match the actual contents. This was in
  19. reponse to making the quota UI DS-aware. The
  20. "logon name" is now a unique key as it contains
  21. both account name and domain-like information.
  22. i.e. "REDMOND\brianau" or "[email protected]".
  23. */
  24. ///////////////////////////////////////////////////////////////////////////////
  25. #include "pch.h" // PCH
  26. #pragma hdrstop
  27. #include <comutil.h>
  28. #include "user.h"
  29. #include "resource.h" // For IDS_NO_LIMIT.
  30. //
  31. // Verify that build is UNICODE.
  32. //
  33. #if !defined(UNICODE)
  34. # error This module must be compiled UNICODE.
  35. #endif
  36. //
  37. // Only one of these for all users. (static member).
  38. //
  39. LONG DiskQuotaUser::m_cUsersAlive = 0; // Cnt of users alive now.
  40. ULONG DiskQuotaUser::m_ulNextUniqueId = 0;
  41. HANDLE DiskQuotaUser::m_hMutex = NULL;
  42. DWORD DiskQuotaUser::m_dwMutexWaitTimeout = 5000; // 5 seconds.
  43. CArray<CString> DiskQuotaUser::m_ContainerNameCache;
  44. ///////////////////////////////////////////////////////////////////////////////
  45. /* Function: DiskQuotaUser::DiskQuotaUser
  46. Description: Constructor.
  47. Arguments:
  48. pFSObject - Pointer to "file system" object. It is through this pointer
  49. that the object accesses the ntioapi functions. Caller must call
  50. AddRef() for this pointer prior to calling Initialize().
  51. Returns: Nothing.
  52. Exceptions: OutOfMemory.
  53. Revision History:
  54. Date Description Programmer
  55. -------- --------------------------------------------------- ----------
  56. 05/22/96 Initial creation. BrianAu
  57. 09/05/96 Added domain name string. BrianAu
  58. */
  59. ///////////////////////////////////////////////////////////////////////////////
  60. DiskQuotaUser::DiskQuotaUser(
  61. FSObject *pFSObject
  62. ) : m_cRef(0),
  63. m_ulUniqueId(InterlockedIncrement((LONG *)&m_ulNextUniqueId)),
  64. m_pSid(NULL),
  65. m_pszLogonName(NULL),
  66. m_pszDisplayName(NULL),
  67. m_pFSObject(pFSObject),
  68. m_bNeedCacheUpdate(TRUE), // Data cache, not domain name cache.
  69. m_iContainerName(-1),
  70. m_dwAccountStatus(DISKQUOTA_USER_ACCOUNT_UNRESOLVED)
  71. {
  72. DBGTRACE((DM_USER, DL_HIGH, TEXT("DiskQuotaUser::DiskQuotaUser")));
  73. DBGPRINT((DM_USER, DL_HIGH, TEXT("\tthis = 0x%08X"), this));
  74. DBGASSERT((NULL != m_pFSObject));
  75. m_llQuotaUsed = 0;
  76. m_llQuotaThreshold = 0;
  77. m_llQuotaLimit = 0;
  78. //
  79. // Initialize the domain name cache and class-wide locking mutex.
  80. // These members are static so we only do it once.
  81. //
  82. InterlockedIncrement(&m_cUsersAlive);
  83. if (NULL == DiskQuotaUser::m_hMutex)
  84. {
  85. DiskQuotaUser::m_hMutex = CreateMutex(NULL, FALSE, NULL);
  86. m_ContainerNameCache.SetSize(25);
  87. m_ContainerNameCache.SetGrow(25);
  88. }
  89. }
  90. ///////////////////////////////////////////////////////////////////////////////
  91. /* Function: DiskQuotaUser::~DiskQuotaUser
  92. Description: Destructor
  93. Arguments: None.
  94. Returns: Nothing.
  95. Revision History:
  96. Date Description Programmer
  97. -------- --------------------------------------------------- ----------
  98. 05/22/96 Initial creation. BrianAu
  99. */
  100. ///////////////////////////////////////////////////////////////////////////////
  101. DiskQuotaUser::~DiskQuotaUser(
  102. VOID
  103. )
  104. {
  105. DBGTRACE((DM_USER, DL_HIGH, TEXT("DiskQuotaUser::~DiskQuotaUser")));
  106. DBGPRINT((DM_USER, DL_HIGH, TEXT("\tthis = 0x%08X"), this));
  107. Destroy();
  108. ASSERT( 0 != m_cUsersAlive );
  109. if (InterlockedDecrement(&m_cUsersAlive) == 0)
  110. {
  111. //
  112. // If active user count is 0, destroy the domain name cache and
  113. // class-wide mutex.
  114. //
  115. DestroyContainerNameCache();
  116. if (NULL != DiskQuotaUser::m_hMutex)
  117. {
  118. CloseHandle(DiskQuotaUser::m_hMutex);
  119. DiskQuotaUser::m_hMutex = NULL;
  120. }
  121. }
  122. }
  123. ///////////////////////////////////////////////////////////////////////////////
  124. /* Function: DiskQuotaUser::QueryInterface
  125. Description: Returns an interface pointer to the object's IUnknown or
  126. IDiskQuotaUser interface. Only IID_IUnknown and
  127. IID_IDiskQuotaUser are recognized. The object referenced by the
  128. returned interface pointer is uninitialized. The recipient of the
  129. pointer must call Initialize() before the object is usable.
  130. Arguments:
  131. riid - Reference to requested interface ID.
  132. ppvOut - Address of interface pointer variable to accept interface ptr.
  133. Returns:
  134. NOERROR - Success.
  135. E_NOINTERFACE - Requested interface not supported.
  136. E_INVALIDARG - ppvOut argument was NULL.
  137. Revision History:
  138. Date Description Programmer
  139. -------- --------------------------------------------------- ----------
  140. 05/22/96 Initial creation. BrianAu
  141. */
  142. ///////////////////////////////////////////////////////////////////////////////
  143. STDMETHODIMP
  144. DiskQuotaUser::QueryInterface(
  145. REFIID riid,
  146. LPVOID *ppvOut
  147. )
  148. {
  149. DBGTRACE((DM_USER, DL_MID, TEXT("DiskQuotaUser::QueryInterface")));
  150. DBGPRINTIID(DM_USER, DL_MID, riid);
  151. HRESULT hResult = E_NOINTERFACE;
  152. if (NULL == ppvOut)
  153. return E_INVALIDARG;
  154. try
  155. {
  156. *ppvOut = NULL;
  157. if (IID_IUnknown == riid ||
  158. IID_IDiskQuotaUser == riid)
  159. {
  160. *ppvOut = static_cast<IDiskQuotaUser *>(this);
  161. }
  162. else if (IID_IDispatch == riid ||
  163. IID_DIDiskQuotaUser == riid)
  164. {
  165. //
  166. // Create a disk quota user "dispatch" object to handle all of
  167. // the automation duties. This object takes a pointer to the real
  168. // user object so that it can call the real object to do the real
  169. // work. The reason we use a special "dispatch" object is so that
  170. // we can maintain identical names for dispatch and vtable methods
  171. // that perform the same function. Otherwise, if the DiskQuotaUser
  172. // object implements both IDiskQuotaUser and DIDiskQuotaUser methods,
  173. // we could not have two methods named Invalidate (one for vtable
  174. // and one for dispatch.
  175. //
  176. DiskQuotaUserDisp *pUserDisp = new DiskQuotaUserDisp(static_cast<PDISKQUOTA_USER>(this));
  177. *ppvOut = static_cast<DIDiskQuotaUser *>(pUserDisp);
  178. }
  179. if (NULL != *ppvOut)
  180. {
  181. ((LPUNKNOWN)*ppvOut)->AddRef();
  182. hResult = NOERROR;
  183. }
  184. }
  185. catch(CAllocException& e)
  186. {
  187. *ppvOut = NULL;
  188. hResult = E_OUTOFMEMORY;
  189. }
  190. return hResult;
  191. }
  192. ///////////////////////////////////////////////////////////////////////////////
  193. /* Function: DiskQuotaUser::AddRef
  194. Description: Increments object reference count.
  195. Arguments: None.
  196. Returns: New reference count value.
  197. Revision History:
  198. Date Description Programmer
  199. -------- --------------------------------------------------- ----------
  200. 05/22/96 Initial creation. BrianAu
  201. */
  202. ///////////////////////////////////////////////////////////////////////////////
  203. STDMETHODIMP_(ULONG)
  204. DiskQuotaUser::AddRef(
  205. VOID
  206. )
  207. {
  208. DBGTRACE((DM_USER, DL_LOW, TEXT("DiskQuotaUser::AddRef")));
  209. ULONG cRef = InterlockedIncrement(&m_cRef);
  210. DBGPRINT((DM_USER, DL_LOW, TEXT("\t0x%08X %d -> %d"), this, cRef - 1, cRef ));
  211. return cRef;
  212. }
  213. ///////////////////////////////////////////////////////////////////////////////
  214. /* Function: DiskQuotaUser::Release
  215. Description: Decrements object reference count. If count drops to 0,
  216. object is deleted.
  217. Arguments: None.
  218. Returns: New reference count value.
  219. Revision History:
  220. Date Description Programmer
  221. -------- --------------------------------------------------- ----------
  222. 05/22/96 Initial creation. BrianAu
  223. */
  224. ///////////////////////////////////////////////////////////////////////////////
  225. STDMETHODIMP_(ULONG)
  226. DiskQuotaUser::Release(
  227. VOID
  228. )
  229. {
  230. DBGTRACE((DM_USER, DL_LOW, TEXT("DiskQuotaUser::Release")));
  231. ASSERT( 0 != m_cRef );
  232. ULONG cRef = InterlockedDecrement(&m_cRef);
  233. DBGPRINT((DM_USER, DL_LOW, TEXT("\t0x%08X %d -> %d"), this, cRef + 1, cRef ));
  234. if ( 0 == cRef )
  235. {
  236. delete this;
  237. }
  238. return cRef;
  239. }
  240. ///////////////////////////////////////////////////////////////////////////////
  241. /* Function: DiskQuotaUser::Initialize
  242. Description: Initializes a new DiskQuotaUser object from a quota information
  243. record read from a volume's quota information file.
  244. Arguments:
  245. pfqi [optional] - Pointer to a record of type FILE_QUOTA_INFORMATION. If
  246. not NULL, the data from this record is used to initialize the new user
  247. object.
  248. Returns:
  249. NOERROR - Success.
  250. E_UNEXPECTED - SID buffer too small (shouldn't happen).
  251. ERROR_INVALID_SID (hr) - SID in quota information is invalid.
  252. ERROR_ACCESS_DENIED (hr) - Need READ access to quota device.
  253. Exceptions: OutOfMemory.
  254. Revision History:
  255. Date Description Programmer
  256. -------- --------------------------------------------------- ----------
  257. 05/22/96 Initial creation. BrianAu
  258. 08/11/96 Added access control. BrianAu
  259. 09/05/96 Added exception handling. BrianAu
  260. */
  261. ///////////////////////////////////////////////////////////////////////////////
  262. HRESULT
  263. DiskQuotaUser::Initialize(
  264. PFILE_QUOTA_INFORMATION pfqi
  265. )
  266. {
  267. HRESULT hResult = NOERROR;
  268. DBGASSERT((NULL != m_pFSObject));
  269. //
  270. // Need READ access to create a user object.
  271. //
  272. if (m_pFSObject->GrantedAccess(GENERIC_READ))
  273. {
  274. if (NULL != pfqi) // pfqi is optional.
  275. {
  276. if (0 < pfqi->SidLength && IsValidSid(&pfqi->Sid))
  277. {
  278. //
  279. // Allocate space for SID structure.
  280. //
  281. m_pSid = (PSID) new BYTE[pfqi->SidLength];
  282. //
  283. // Copy SID structure to object.
  284. //
  285. if (CopySid(pfqi->SidLength, m_pSid, &pfqi->Sid))
  286. {
  287. //
  288. // Initialize user's quota data values.
  289. // If error copying SID, don't bother with these.
  290. //
  291. m_llQuotaUsed = pfqi->QuotaUsed.QuadPart;
  292. m_llQuotaThreshold = pfqi->QuotaThreshold.QuadPart;
  293. m_llQuotaLimit = pfqi->QuotaLimit.QuadPart;
  294. }
  295. else
  296. {
  297. //
  298. // The only reason CopySid can fail is
  299. // STATUS_BUFFER_TOO_SMALL. Since we allocated the buffer
  300. // above, this should never fail.
  301. //
  302. DBGASSERT((FALSE));
  303. hResult = E_UNEXPECTED; // Error copying SID.
  304. }
  305. }
  306. else
  307. {
  308. DBGERROR((TEXT("DiskQuotaUser::Initialize - Invalid SID or Bad Sid Length (%d)"), pfqi->SidLength));
  309. hResult = HRESULT_FROM_WIN32(ERROR_INVALID_SID);
  310. }
  311. }
  312. }
  313. else
  314. hResult = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  315. return hResult;
  316. }
  317. ///////////////////////////////////////////////////////////////////////////////
  318. /* Function: DiskQuotaUser::Destroy
  319. Description: Destroys a user object by deleting its SID buffer and releasing
  320. its FSObject pointer.
  321. Arguments: None.
  322. Returns: Nothing.
  323. Revision History:
  324. Date Description Programmer
  325. -------- --------------------------------------------------- ----------
  326. 05/22/96 Initial creation. BrianAu
  327. 09/05/96 Added domain name string. BrianAu
  328. */
  329. ///////////////////////////////////////////////////////////////////////////////
  330. VOID DiskQuotaUser::Destroy(
  331. VOID
  332. )
  333. {
  334. //
  335. // Delete the SID buffer.
  336. //
  337. delete [] m_pSid;
  338. m_pSid = NULL;
  339. //
  340. // Delete the logon name buffer.
  341. //
  342. delete[] m_pszLogonName;
  343. m_pszLogonName = NULL;
  344. //
  345. // Delete the display name buffer.
  346. //
  347. delete[] m_pszDisplayName;
  348. m_pszDisplayName = NULL;
  349. if (NULL != m_pFSObject)
  350. {
  351. //
  352. // Release hold on File System object.
  353. //
  354. m_pFSObject->Release();
  355. m_pFSObject = NULL;
  356. }
  357. }
  358. ///////////////////////////////////////////////////////////////////////////////
  359. /* Function: DiskQuotaUser::DestroyContainerNameCache
  360. Description: Destroys the container name cache. Should only be called
  361. when there are not more active user objects. The container name cache
  362. is a static member of DiskQuotaUser.
  363. Arguments: None.
  364. Returns: Nothing.
  365. Revision History:
  366. Date Description Programmer
  367. -------- --------------------------------------------------- ----------
  368. 09/06/96 Initial creation. BrianAu
  369. */
  370. ///////////////////////////////////////////////////////////////////////////////
  371. VOID
  372. DiskQuotaUser::DestroyContainerNameCache(
  373. VOID
  374. )
  375. {
  376. //
  377. // Remove all container name strings from the cache. No need to lock
  378. // the cache object before clearing it. It will handle the locking
  379. // and unlocking.
  380. //
  381. m_ContainerNameCache.Clear();
  382. }
  383. //
  384. // Return user object's unique ID.
  385. //
  386. STDMETHODIMP
  387. DiskQuotaUser::GetID(
  388. ULONG *pulID
  389. )
  390. {
  391. *pulID = m_ulUniqueId;
  392. return NOERROR;
  393. }
  394. ///////////////////////////////////////////////////////////////////////////////
  395. /* Function: DiskQuotaUser::GetAccountStatus
  396. Description: Retrieves the account name resolution status for the
  397. user object.
  398. Arguments:
  399. pdwAccountStatus - Address of variable to recieve status. The following
  400. values (see dskquota.h) can be returned in this variable:
  401. DISKQUOTA_USER_ACCOUNT_RESOLVED
  402. DISKQUOTA_USER_ACCOUNT_UNAVAILABLE
  403. DISKQUOTA_USER_ACCOUNT_DELETED
  404. DISKQUOTA_USER_ACCOUNT_INVALID
  405. DISKQUOTA_USER_ACCOUNT_UNKNOWN
  406. DISKQUOTA_USER_ACCOUNT_UNRESOLVED
  407. Returns:
  408. NOERROR - Success.
  409. E_INVALIDARG - pdwAccountStatus arg is NULL.
  410. Revision History:
  411. Date Description Programmer
  412. -------- --------------------------------------------------- ----------
  413. 06/11/96 Initial creation. BrianAu
  414. */
  415. ///////////////////////////////////////////////////////////////////////////////
  416. STDMETHODIMP
  417. DiskQuotaUser::GetAccountStatus(
  418. LPDWORD pdwAccountStatus
  419. )
  420. {
  421. if (NULL == pdwAccountStatus)
  422. return E_INVALIDARG;
  423. *pdwAccountStatus = m_dwAccountStatus;
  424. return NOERROR;
  425. }
  426. ///////////////////////////////////////////////////////////////////////////////
  427. /* Function: DiskQuotaUser::SetName
  428. Description: Sets the account names of the user object.
  429. It is intended that the SidNameResolver object will call this member
  430. when it has resolved a user's SID into an account name. This function
  431. is not included in IDiskQuotaUser. Therefore, it is not for public
  432. consumption.
  433. Arguments:
  434. pszContainer - Address of buffer containing container name string.
  435. pszLogonName - Address of buffer containing user's logon name string.
  436. pszDisplayName - Address of buffer containing user's display name string.
  437. Returns:
  438. NOERROR - Success.
  439. E_INVALIDARG - pszName or pszDomain arg is NULL.
  440. E_OUTOFMEMORY - Insufficient memory.
  441. ERROR_LOCK_FAILED (hr) - Couldn't lock user object.
  442. Revision History:
  443. Date Description Programmer
  444. -------- --------------------------------------------------- ----------
  445. 06/11/96 Initial creation. BrianAu
  446. 09/05/96 Added domain name string. BrianAu
  447. 09/22/96 Added full name string. BrianAu
  448. 12/10/96 Added class-scope user lock. BrianAu
  449. 05/18/97 Removed access token. BrianAu
  450. */
  451. ///////////////////////////////////////////////////////////////////////////////
  452. STDMETHODIMP
  453. DiskQuotaUser::SetName(
  454. LPCWSTR pszContainer,
  455. LPCWSTR pszLogonName,
  456. LPCWSTR pszDisplayName
  457. )
  458. {
  459. HRESULT hResult = NOERROR;
  460. if (NULL == pszContainer || NULL == pszLogonName || NULL == pszDisplayName)
  461. return E_INVALIDARG;
  462. if (!DiskQuotaUser::Lock())
  463. {
  464. hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
  465. }
  466. else
  467. {
  468. //
  469. // Delete existing name buffer.
  470. //
  471. delete[] m_pszLogonName;
  472. m_pszLogonName = NULL;
  473. delete[] m_pszDisplayName;
  474. m_pszDisplayName = NULL;
  475. try
  476. {
  477. //
  478. // Save name and full name in user object.
  479. // Cache container string in container name cache and
  480. // save cache index in user object.
  481. //
  482. INT index = -1;
  483. m_pszLogonName = StringDup(pszLogonName);
  484. m_pszDisplayName = StringDup(pszDisplayName);
  485. CacheContainerName(pszContainer, &m_iContainerName);
  486. }
  487. catch(CAllocException& e)
  488. {
  489. hResult = E_OUTOFMEMORY;
  490. }
  491. DiskQuotaUser::ReleaseLock();
  492. }
  493. return hResult;
  494. }
  495. ///////////////////////////////////////////////////////////////////////////////
  496. /* Function: DiskQuotaUser::GetName
  497. Description: Retrieves the domain and account names from the user object.
  498. It is intended that the client of the user object will register
  499. a callback (event sink) with a DiskQuotaControl object. When the
  500. resolver has resolved the SID to an account name, the resolver will
  501. set the user object's name string and the client will be notified.
  502. The client then calls this method to get the user's name.
  503. Arguments:
  504. pszContainerBuffer - Address of destination buffer for container name string.
  505. cchContainerBuffer - Size of container destination buffer in characters.
  506. pszLogonNameBuffer - Address of destination buffer for logon name string.
  507. cchLogonNameBuffer - Size of logon name destination buffer in characters.
  508. pszDisplayNameBuffer - Address of destination buffer for display name string.
  509. cchDisplayNameBuffer - Size of display name destination buffer in characters.
  510. Returns:
  511. NOERROR - Success.
  512. ERROR_LOCK_FAILED (hr) - Failed to lock user object.
  513. Revision History:
  514. Date Description Programmer
  515. -------- --------------------------------------------------- ----------
  516. 06/11/96 Initial creation. BrianAu
  517. 09/05/96 Added domain name string. BrianAu
  518. 09/22/96 Added full name string. BrianAu
  519. 12/10/96 Added class-scope user lock. BrianAu
  520. */
  521. ///////////////////////////////////////////////////////////////////////////////
  522. STDMETHODIMP
  523. DiskQuotaUser::GetName(
  524. LPWSTR pszContainerBuffer,
  525. DWORD cchContainerBuffer,
  526. LPWSTR pszLogonNameBuffer,
  527. DWORD cchLogonNameBuffer,
  528. LPWSTR pszDisplayNameBuffer,
  529. DWORD cchDisplayNameBuffer
  530. )
  531. {
  532. HRESULT hResult = NOERROR;
  533. if (!DiskQuotaUser::Lock())
  534. {
  535. hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
  536. }
  537. else
  538. {
  539. if (NULL != pszContainerBuffer)
  540. {
  541. if (-1 != m_iContainerName)
  542. {
  543. GetCachedContainerName(m_iContainerName,
  544. pszContainerBuffer,
  545. cchContainerBuffer);
  546. }
  547. else
  548. lstrcpyn(pszContainerBuffer, TEXT(""), cchContainerBuffer);
  549. }
  550. if (NULL != pszLogonNameBuffer)
  551. {
  552. lstrcpyn(pszLogonNameBuffer,
  553. (NULL != m_pszLogonName) ? m_pszLogonName : TEXT(""),
  554. cchLogonNameBuffer);
  555. }
  556. if (NULL != pszDisplayNameBuffer)
  557. {
  558. lstrcpyn(pszDisplayNameBuffer,
  559. (NULL != m_pszDisplayName) ? m_pszDisplayName : TEXT(""),
  560. cchDisplayNameBuffer);
  561. }
  562. DiskQuotaUser::ReleaseLock();
  563. }
  564. return hResult;
  565. }
  566. ///////////////////////////////////////////////////////////////////////////////
  567. /* Function: DiskQuotaUser::GetSidLength
  568. Description: Retrieves the length of the user's SID in bytes.
  569. Arguments:
  570. pcbSid - Address of DWORD to accept SID length value.
  571. Returns:
  572. NOERROR - Success.
  573. E_INVALIDARG - pcbSid argument is NULL.
  574. ERROR_INVALID_SID (hr) - Invalid SID.
  575. ERROR_LOCK_FAILED (hr) - Couldn't lock user object.
  576. Revision History:
  577. Date Description Programmer
  578. -------- --------------------------------------------------- ----------
  579. 05/22/96 Initial creation. BrianAu
  580. 12/10/96 Added class-scope user lock. BrianAu
  581. */
  582. ///////////////////////////////////////////////////////////////////////////////
  583. STDMETHODIMP
  584. DiskQuotaUser::GetSidLength(
  585. LPDWORD pcbSid
  586. )
  587. {
  588. HRESULT hResult = NOERROR;
  589. if (NULL == pcbSid)
  590. return E_INVALIDARG;
  591. if (!DiskQuotaUser::Lock())
  592. {
  593. hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
  594. }
  595. else
  596. {
  597. if (NULL != m_pSid && IsValidSid(m_pSid))
  598. {
  599. *pcbSid = GetLengthSid(m_pSid);
  600. }
  601. else
  602. hResult = HRESULT_FROM_WIN32(ERROR_INVALID_SID);
  603. DiskQuotaUser::ReleaseLock();
  604. }
  605. return hResult;
  606. }
  607. ///////////////////////////////////////////////////////////////////////////////
  608. /* Function: DiskQuotaUser::GetSid
  609. Description: Retrieves the user's SID to a caller-provided buffer.
  610. The caller should call GetSidLength() to obtain the required buffer
  611. size before calling GetSid().
  612. Arguments:
  613. pSid - Address of destination buffer for SID. This argument type must
  614. be PBYTE to work with the MIDL compiler. Since PSID is really just
  615. LPVOID and since MIDL doesn't like pointers to void, we have to
  616. use something other than PSID.
  617. cbSidBuf - Size of destination buffer in bytes.
  618. Returns:
  619. NOERROR - Success.
  620. E_INVALIDARG - pSID is NULL.
  621. ERROR_INVALID_SID (hr) - User's SID is invalid.
  622. ERROR_INSUFFICIENT_BUFFER (hr) - Insufficient dest buffer size.
  623. ERROR_LOCK_FAILED (hr) - Couldn't lock user object.
  624. Revision History:
  625. Date Description Programmer
  626. -------- --------------------------------------------------- ----------
  627. 05/22/96 Initial creation. BrianAu
  628. 12/10/96 Added class-scope user lock. BrianAu
  629. */
  630. ///////////////////////////////////////////////////////////////////////////////
  631. STDMETHODIMP
  632. DiskQuotaUser::GetSid(
  633. PBYTE pSid,
  634. DWORD cbSidBuf
  635. )
  636. {
  637. HRESULT hResult = NOERROR;
  638. if (NULL == pSid)
  639. return E_INVALIDARG;
  640. if (!DiskQuotaUser::Lock())
  641. {
  642. hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
  643. }
  644. else
  645. {
  646. if (NULL != m_pSid && IsValidSid(m_pSid))
  647. {
  648. if (!CopySid(cbSidBuf, (PSID)pSid, m_pSid))
  649. {
  650. //
  651. // The only reason CopySid can fail is STATUS_BUFFER_TOO_SMALL.
  652. // Force status code to INSUFFICIENT_BUFFER.
  653. //
  654. DBGERROR((TEXT("ERROR in DiskQuotaUser::GetSid. CopySid() failed. Result = 0x%08X."),
  655. GetLastError()));
  656. hResult = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  657. }
  658. }
  659. else
  660. {
  661. DBGERROR((TEXT("ERROR in DiskQuotaUser::GetSid. Invalid SID.")));
  662. hResult = HRESULT_FROM_WIN32(ERROR_INVALID_SID);
  663. }
  664. DiskQuotaUser::ReleaseLock();
  665. }
  666. return hResult;
  667. }
  668. ///////////////////////////////////////////////////////////////////////////////
  669. /* Function: DiskQuotaUser::RefreshCachedInfo
  670. Description: Refreshes a user object's cached quota information from the
  671. volume's quota information file.
  672. Arguments: None.
  673. Returns:
  674. NOERROR - Success.
  675. ERROR_ACCESS_DENIED (hr) - No READ access to quota device.
  676. E_FAIL - Unexpected NTIOAPI error.
  677. This function can propagate errors from the NTIOAPI system. A few
  678. known ones are mapped to HResults in fsobject.cpp (see HResultFromNtStatus).
  679. All others are mapped to E_FAIL.
  680. Exceptions: OutOfMemory.
  681. Revision History:
  682. Date Description Programmer
  683. -------- --------------------------------------------------- ----------
  684. 06/05/96 Initial creation. BrianAu
  685. 09/05/96 Added exception handling. BrianAu
  686. */
  687. ///////////////////////////////////////////////////////////////////////////////
  688. HRESULT
  689. DiskQuotaUser::RefreshCachedInfo(
  690. VOID
  691. )
  692. {
  693. HRESULT hResult = NOERROR;
  694. DWORD cbBuffer = FILE_QUOTA_INFORMATION_MAX_LEN;
  695. PSIDLIST pSidList = NULL;
  696. DWORD cbSidList = 0;
  697. PSID pSids[] = { m_pSid, NULL };
  698. PBYTE pbBuffer = NULL;
  699. try
  700. {
  701. pbBuffer = new BYTE[cbBuffer];
  702. //
  703. // This can throw OutOfMemory.
  704. //
  705. hResult = CreateSidList(pSids, 0, &pSidList, &cbSidList);
  706. if (SUCCEEDED(hResult))
  707. {
  708. hResult = m_pFSObject->QueryUserQuotaInformation(
  709. pbBuffer, // Buffer to receive data.
  710. cbBuffer, // Buffer size in bytes.
  711. TRUE, // Single entry requested.
  712. pSidList, // Sid.
  713. cbSidList, // Length of Sid.
  714. NULL, // Starting Sid
  715. TRUE); // Start search at first user.
  716. if (SUCCEEDED(hResult) || ERROR_NO_MORE_ITEMS == HRESULT_CODE(hResult))
  717. {
  718. PFILE_QUOTA_INFORMATION pfqi = (PFILE_QUOTA_INFORMATION)pbBuffer;
  719. m_llQuotaUsed = pfqi->QuotaUsed.QuadPart;
  720. m_llQuotaThreshold = pfqi->QuotaThreshold.QuadPart;
  721. m_llQuotaLimit = pfqi->QuotaLimit.QuadPart;
  722. m_bNeedCacheUpdate = FALSE;
  723. //
  724. // Don't return ERROR_NO_MORE_ITEMS to caller.
  725. // They won't care.
  726. //
  727. hResult = NOERROR;
  728. }
  729. delete[] pSidList;
  730. }
  731. delete[] pbBuffer;
  732. }
  733. catch(CAllocException& e)
  734. {
  735. hResult = E_OUTOFMEMORY;
  736. delete[] pbBuffer;
  737. delete[] pSidList;
  738. }
  739. return hResult;
  740. }
  741. ///////////////////////////////////////////////////////////////////////////////
  742. /* Function: DiskQuotaUser::WriteCachedInfo
  743. Description: Writes quota information cached in a user object to the
  744. volume's quota information file.
  745. Arguments: None.
  746. Returns:
  747. NOERROR - Success.
  748. ERROR_ACCESS_DENIED (hr) - No WRITE access to quota device.
  749. E_FAIL - Some other NTIOAPI error.
  750. E_UNEXPECTED - CopySid failed.
  751. Revision History:
  752. Date Description Programmer
  753. -------- --------------------------------------------------- ----------
  754. 07/31/96 Initial creation. BrianAu
  755. */
  756. ///////////////////////////////////////////////////////////////////////////////
  757. HRESULT
  758. DiskQuotaUser::WriteCachedInfo(
  759. VOID
  760. )
  761. {
  762. HRESULT hResult = NOERROR;
  763. BYTE Buffer[FILE_QUOTA_INFORMATION_MAX_LEN];
  764. PFILE_QUOTA_INFORMATION pfqi = (PFILE_QUOTA_INFORMATION)Buffer;
  765. pfqi->NextEntryOffset = 0;
  766. pfqi->SidLength = GetLengthSid(m_pSid);
  767. pfqi->QuotaUsed.QuadPart = m_llQuotaUsed;
  768. pfqi->QuotaLimit.QuadPart = m_llQuotaLimit;
  769. pfqi->QuotaThreshold.QuadPart = m_llQuotaThreshold;
  770. if (CopySid(pfqi->SidLength, &(pfqi->Sid), m_pSid))
  771. hResult = m_pFSObject->SetUserQuotaInformation(pfqi, sizeof(Buffer));
  772. else
  773. hResult = E_UNEXPECTED;
  774. if (FAILED(hResult))
  775. {
  776. //
  777. // Something failed.
  778. // Invalidate cached information so next request reads from disk.
  779. //
  780. Invalidate();
  781. }
  782. return hResult;
  783. }
  784. ///////////////////////////////////////////////////////////////////////////////
  785. /* Function: DiskQuotaUser::GetQuotaInformation
  786. Description: Retrieves a user's quota limit, threshold and used quota
  787. values in a single method. Since the user interface is marshaled
  788. across thread boundaries, this can be a big performance improvement
  789. if you want all three values.
  790. Arguments:
  791. pbInfo - Address of destination buffer. Should be sized for structure
  792. DISKQUOTA_USER_INFORMATION.
  793. cbInfo - Number of bytes in destination buffer. Should be
  794. sizeof(DISKQUOTA_USER_INFORMATION).
  795. Returns:
  796. NOERROR - Success.
  797. E_INVALIDARG - pbInfo argument is NULL.
  798. E_OUTOFMEMORY - Insufficient memory.
  799. ERROR_INSUFFICIENT_BUFFER (hr) - Destination buffer is too small.
  800. ERROR_LOCK_FAILED (hr) - Couldn't lock user object.
  801. Revision History:
  802. Date Description Programmer
  803. -------- --------------------------------------------------- ----------
  804. 07/31/96 Initial creation. BrianAu
  805. 12/10/96 Added class-scope user lock. BrianAu
  806. */
  807. ///////////////////////////////////////////////////////////////////////////////
  808. STDMETHODIMP
  809. DiskQuotaUser::GetQuotaInformation(
  810. LPVOID pbInfo,
  811. DWORD cbInfo
  812. )
  813. {
  814. HRESULT hResult = NOERROR;
  815. if (NULL == pbInfo)
  816. return E_INVALIDARG;
  817. try
  818. {
  819. if (cbInfo < sizeof(DISKQUOTA_USER_INFORMATION))
  820. {
  821. hResult = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  822. }
  823. else
  824. {
  825. if (!DiskQuotaUser::Lock())
  826. {
  827. hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
  828. }
  829. else
  830. {
  831. //
  832. // Refresh cached info from disk if needed.
  833. // Can throw OutOfMemory.
  834. //
  835. if (m_bNeedCacheUpdate)
  836. hResult = RefreshCachedInfo();
  837. if (SUCCEEDED(hResult))
  838. {
  839. PDISKQUOTA_USER_INFORMATION pui = (PDISKQUOTA_USER_INFORMATION)pbInfo;
  840. pui->QuotaUsed = m_llQuotaUsed;
  841. pui->QuotaThreshold = m_llQuotaThreshold;
  842. pui->QuotaLimit = m_llQuotaLimit;
  843. }
  844. DiskQuotaUser::ReleaseLock();
  845. }
  846. }
  847. }
  848. catch(CAllocException& e)
  849. {
  850. hResult = E_OUTOFMEMORY;
  851. }
  852. return hResult;
  853. }
  854. STDMETHODIMP
  855. DiskQuotaUser::GetQuotaUsedText(
  856. LPWSTR pszText,
  857. DWORD cchText
  858. )
  859. {
  860. if (NULL == pszText)
  861. return E_INVALIDARG;
  862. LONGLONG llValue;
  863. HRESULT hr = GetQuotaUsed(&llValue);
  864. if (SUCCEEDED(hr))
  865. {
  866. if (NOLIMIT == llValue)
  867. {
  868. LoadString(g_hInstDll, IDS_NO_LIMIT, pszText, cchText);
  869. }
  870. else
  871. {
  872. XBytes::FormatByteCountForDisplay(llValue, pszText, cchText);
  873. }
  874. }
  875. return hr;
  876. }
  877. STDMETHODIMP
  878. DiskQuotaUser::GetQuotaThresholdText(
  879. LPWSTR pszText,
  880. DWORD cchText
  881. )
  882. {
  883. if (NULL == pszText)
  884. return E_INVALIDARG;
  885. LONGLONG llValue;
  886. HRESULT hr = GetQuotaThreshold(&llValue);
  887. if (SUCCEEDED(hr))
  888. {
  889. if (NOLIMIT == llValue)
  890. {
  891. LoadString(g_hInstDll, IDS_NO_LIMIT, pszText, cchText);
  892. }
  893. else
  894. {
  895. XBytes::FormatByteCountForDisplay(llValue, pszText, cchText);
  896. }
  897. }
  898. return hr;
  899. }
  900. STDMETHODIMP
  901. DiskQuotaUser::GetQuotaLimitText(
  902. LPWSTR pszText,
  903. DWORD cchText
  904. )
  905. {
  906. if (NULL == pszText)
  907. return E_INVALIDARG;
  908. LONGLONG llValue;
  909. HRESULT hr = GetQuotaLimit(&llValue);
  910. if (SUCCEEDED(hr))
  911. {
  912. if (NOLIMIT == llValue)
  913. {
  914. LoadString(g_hInstDll, IDS_NO_LIMIT, pszText, cchText);
  915. }
  916. else
  917. {
  918. XBytes::FormatByteCountForDisplay(llValue, pszText, cchText);
  919. }
  920. }
  921. return hr;
  922. }
  923. STDMETHODIMP
  924. DiskQuotaUser::SetQuotaThreshold(
  925. LONGLONG llThreshold,
  926. BOOL bWriteThrough
  927. )
  928. {
  929. if (MARK4DEL > llThreshold)
  930. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  931. return SetLargeIntegerQuotaItem(&m_llQuotaThreshold,
  932. llThreshold,
  933. bWriteThrough);
  934. }
  935. STDMETHODIMP
  936. DiskQuotaUser::SetQuotaLimit(
  937. LONGLONG llLimit,
  938. BOOL bWriteThrough
  939. )
  940. {
  941. if (MARK4DEL > llLimit)
  942. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  943. return SetLargeIntegerQuotaItem(&m_llQuotaLimit,
  944. llLimit,
  945. bWriteThrough);
  946. }
  947. ///////////////////////////////////////////////////////////////////////////////
  948. /* Function: DiskQuotaUser::GetLargeIntegerQuotaItem
  949. Description: Retrieves a single quota information item (used, limit,
  950. threshold) for the user. If the cached data is invalid, fresh data is
  951. read in from disk.
  952. Arguments:
  953. pllItem - Address of cached member item.
  954. pllValueOut - Address of LONGLONG to receive item's value.
  955. Returns:
  956. NOERROR - Success.
  957. E_INVALIDARG - Either pdwLowPart or pdwHighPart arg was NULL.
  958. E_OUTOFMEMORY - Insufficient memory.
  959. E_UNEXPECTED - Unexpected exception.
  960. ERROR_LOCK_FAILED (hr) - Couldn't lock user object.
  961. Revision History:
  962. Date Description Programmer
  963. -------- --------------------------------------------------- ----------
  964. 06/05/96 Initial creation. BrianAu
  965. 12/10/96 Added class-scope user lock. BrianAu
  966. */
  967. ///////////////////////////////////////////////////////////////////////////////
  968. HRESULT
  969. DiskQuotaUser::GetLargeIntegerQuotaItem(
  970. PLONGLONG pllItem,
  971. PLONGLONG pllValueOut
  972. )
  973. {
  974. HRESULT hResult = NOERROR;
  975. DBGASSERT((NULL != pllItem));
  976. if (NULL == pllItem || NULL == pllValueOut)
  977. return E_INVALIDARG;
  978. if (!DiskQuotaUser::Lock())
  979. {
  980. hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
  981. }
  982. else
  983. {
  984. if (m_bNeedCacheUpdate)
  985. try
  986. {
  987. hResult = RefreshCachedInfo();
  988. }
  989. catch(CAllocException& e)
  990. {
  991. hResult = E_OUTOFMEMORY;
  992. }
  993. if (SUCCEEDED(hResult))
  994. {
  995. *pllValueOut = *pllItem;
  996. }
  997. DiskQuotaUser::ReleaseLock();
  998. }
  999. return hResult;
  1000. }
  1001. ///////////////////////////////////////////////////////////////////////////////
  1002. /* Function: DiskQuotaUser::SetLargeIntegerQuotaItem
  1003. Description: Sets the quota information for a given quota item (limit or
  1004. threshold). If the bWriteThrough argument is TRUE, the information is
  1005. also written through to the volume's quota file. Otherwise, it is
  1006. just cached in the user object.
  1007. Arguments:
  1008. pllItem - Address of cached member item.
  1009. llValue - LONGLONG value to assign to member item.
  1010. bWriteThrough - TRUE = Write data through to disk.
  1011. FALSE = Only cache data in user object.
  1012. Returns:
  1013. NOERROR - Success.
  1014. ERROR_ACCESS_DENIED (hr) - No WRITE access to quota device.
  1015. ERROR_LOCK_FAILED (hr) - Couldn't lock user object.
  1016. E_FAIL - Some other NTIOAPI error.
  1017. Revision History:
  1018. Date Description Programmer
  1019. -------- --------------------------------------------------- ----------
  1020. 08/06/96 Initial creation. BrianAu
  1021. 12/10/96 Added class-scope user lock. BrianAu
  1022. */
  1023. ///////////////////////////////////////////////////////////////////////////////
  1024. HRESULT
  1025. DiskQuotaUser::SetLargeIntegerQuotaItem(
  1026. PLONGLONG pllItem,
  1027. LONGLONG llValue,
  1028. BOOL bWriteThrough)
  1029. {
  1030. DBGASSERT((NULL != pllItem));
  1031. HRESULT hResult = NOERROR;
  1032. if (!DiskQuotaUser::Lock())
  1033. {
  1034. hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
  1035. }
  1036. else
  1037. {
  1038. *pllItem = llValue;
  1039. if (bWriteThrough)
  1040. hResult = WriteCachedInfo();
  1041. DiskQuotaUser::ReleaseLock();
  1042. }
  1043. return hResult;
  1044. }
  1045. ///////////////////////////////////////////////////////////////////////////////
  1046. /* Function: DiskQuotaUser::CacheContainerName
  1047. Description: Class DiskQuotaUser maintains a static member that is
  1048. a cache of account container names. It is likely that there will be
  1049. few distinct container names in use on a volume. Therefore, there's
  1050. no need to store a container name for each user object. We cache the
  1051. names and store only an index into the cache in each user object.
  1052. This method adds a name to the cache and returns the index of the
  1053. name in the cache. If the name already exists in the cache,
  1054. it is not added.
  1055. Arguments:
  1056. pszContainer - Address of container name string to add to cache.
  1057. pCacheIndex [optional] - Address of integer variable to receive the
  1058. cache index of the container name string. May be NULL.
  1059. Returns:
  1060. S_OK - Success.
  1061. S_FALSE - Name already in cache.
  1062. E_FAIL - No cache object.
  1063. Exceptions: OutOfMemory.
  1064. Revision History:
  1065. Date Description Programmer
  1066. -------- --------------------------------------------------- ----------
  1067. 09/05/09 Initial creation. BrianAu
  1068. */
  1069. ///////////////////////////////////////////////////////////////////////////////
  1070. HRESULT
  1071. DiskQuotaUser::CacheContainerName(
  1072. LPCTSTR pszContainer,
  1073. INT *pCacheIndex
  1074. )
  1075. {
  1076. DBGASSERT((NULL != pszContainer));
  1077. HRESULT hResult = S_OK;
  1078. INT iCacheIndex = -1;
  1079. UINT cItems = 0;
  1080. m_ContainerNameCache.Lock();
  1081. cItems = m_ContainerNameCache.Count();
  1082. for (UINT i = 0; i < cItems; i++)
  1083. {
  1084. //
  1085. // See if the name is already in the cache.
  1086. //
  1087. if (0 == m_ContainerNameCache[i].Compare(pszContainer))
  1088. {
  1089. iCacheIndex = i;
  1090. hResult = S_FALSE; // Already cached.
  1091. break;
  1092. }
  1093. }
  1094. if (S_OK == hResult)
  1095. {
  1096. //
  1097. // Not in the cache. Add it.
  1098. //
  1099. try
  1100. {
  1101. m_ContainerNameCache.Append(CString(pszContainer));
  1102. iCacheIndex = m_ContainerNameCache.UpperBound();
  1103. }
  1104. catch(CAllocException& e)
  1105. {
  1106. hResult = E_OUTOFMEMORY;
  1107. }
  1108. }
  1109. m_ContainerNameCache.ReleaseLock();
  1110. if (NULL != pCacheIndex)
  1111. *pCacheIndex = iCacheIndex;
  1112. return hResult;
  1113. }
  1114. ///////////////////////////////////////////////////////////////////////////////
  1115. /* Function: DiskQuotaUser::GetCachedContainerName
  1116. Description: Retrieves an account container name string from the
  1117. container name cache.
  1118. Arguments:
  1119. iCacheIndex - User's index in domain name cache.
  1120. pszContainer - Destination buffer to receive container name string.
  1121. cchContainer - Number of characters in destination buffer.
  1122. Returns:
  1123. NOERROR - Success.
  1124. E_UNEXPECTED - No name at index iCacheIndex. Returns "" as name.
  1125. E_FAIL - No domain name cache object.
  1126. Revision History:
  1127. Date Description Programmer
  1128. -------- --------------------------------------------------- ----------
  1129. 09/05/96 Initial creation. BrianAu
  1130. */
  1131. ///////////////////////////////////////////////////////////////////////////////
  1132. HRESULT
  1133. DiskQuotaUser::GetCachedContainerName(
  1134. INT iCacheIndex,
  1135. LPTSTR pszContainer,
  1136. UINT cchContainer
  1137. )
  1138. {
  1139. DBGASSERT((NULL != pszContainer));
  1140. DBGASSERT((-1 != iCacheIndex));
  1141. HRESULT hResult = NOERROR;
  1142. m_ContainerNameCache.Lock();
  1143. DBGASSERT((iCacheIndex < m_ContainerNameCache.Count()));
  1144. lstrcpyn(pszContainer, m_ContainerNameCache[iCacheIndex], cchContainer);
  1145. m_ContainerNameCache.ReleaseLock();
  1146. return hResult;
  1147. }
  1148. ///////////////////////////////////////////////////////////////////////////////
  1149. /* Function: DiskQuotaUser::Lock
  1150. Description: Call this to obtain an exclusive lock to the user object.
  1151. In actuality, there is only one lock for all user objects so you're
  1152. really getting an exclusive lock to all users. Since there can be
  1153. a high number of users, it was decided to use a single class-wide
  1154. lock instead of a unique lock for each user object.
  1155. Arguments: None.
  1156. Returns:
  1157. TRUE = Obtained exclusive lock.
  1158. FALSE = Couldn't get a lock. Either mutex hasn't been created or
  1159. the mutex wait timeout expired, or the wait operation failed.
  1160. Either way, we couldn't get the lock.
  1161. Revision History:
  1162. Date Description Programmer
  1163. -------- --------------------------------------------------- ----------
  1164. 12/10/96 Initial creation. BrianAu
  1165. */
  1166. ///////////////////////////////////////////////////////////////////////////////
  1167. BOOL
  1168. DiskQuotaUser::Lock(
  1169. VOID
  1170. )
  1171. {
  1172. BOOL bResult = FALSE;
  1173. if (NULL != DiskQuotaUser::m_hMutex)
  1174. {
  1175. DWORD dwWaitResult = WaitForSingleObject(DiskQuotaUser::m_hMutex,
  1176. DiskQuotaUser::m_dwMutexWaitTimeout);
  1177. bResult = (WAIT_OBJECT_0 == dwWaitResult);
  1178. }
  1179. return bResult;
  1180. }
  1181. ///////////////////////////////////////////////////////////////////////////////
  1182. /* Function: DiskQuotaUser::ReleaseLock
  1183. Description: Call this to release a lock obtained with DiskQuotaUser::Lock.
  1184. Arguments: None.
  1185. Returns: Nothing.
  1186. Revision History:
  1187. Date Description Programmer
  1188. -------- --------------------------------------------------- ----------
  1189. 12/10/96 Initial creation. BrianAu
  1190. */
  1191. ///////////////////////////////////////////////////////////////////////////////
  1192. VOID
  1193. DiskQuotaUser::ReleaseLock(
  1194. VOID
  1195. )
  1196. {
  1197. if (NULL != DiskQuotaUser::m_hMutex)
  1198. {
  1199. ReleaseMutex(DiskQuotaUser::m_hMutex);
  1200. }
  1201. }
  1202. ///////////////////////////////////////////////////////////////////////////////
  1203. /* Function: DiskQuotaUser::SetAccountStatus
  1204. Description: Stores the status of the user's account in the user object.
  1205. User accounts may be "unresolved", "unavailable", "resolved",
  1206. "deleted", "invalid" or "unknown".
  1207. These states correspond to the values obtained
  1208. through LookupAccountSid.
  1209. Arguments:
  1210. dwStatus - DISKQUOTA_USER_ACCOUNT_UNRESOLVED
  1211. DISKQUOTA_USER_ACCOUNT_UNAVAILABLE
  1212. DISKQUOTA_USER_ACCOUNT_RESOLVED
  1213. DISKQUOTA_USER_ACCOUNT_DELETED
  1214. DISKQUOTA_USER_ACCOUNT_UNKNOWN
  1215. DISKQUOTA_USER_ACCOUNT_INVALID
  1216. Returns: Nothing.
  1217. Revision History:
  1218. Date Description Programmer
  1219. -------- --------------------------------------------------- ----------
  1220. 05/18/97 Initial creation. BrianAu
  1221. */
  1222. ///////////////////////////////////////////////////////////////////////////////
  1223. VOID
  1224. DiskQuotaUser::SetAccountStatus(
  1225. DWORD dwStatus
  1226. )
  1227. {
  1228. DBGASSERT((DISKQUOTA_USER_ACCOUNT_UNRESOLVED == dwStatus ||
  1229. DISKQUOTA_USER_ACCOUNT_UNAVAILABLE == dwStatus ||
  1230. DISKQUOTA_USER_ACCOUNT_RESOLVED == dwStatus ||
  1231. DISKQUOTA_USER_ACCOUNT_DELETED == dwStatus ||
  1232. DISKQUOTA_USER_ACCOUNT_INVALID == dwStatus ||
  1233. DISKQUOTA_USER_ACCOUNT_UNKNOWN == dwStatus));
  1234. m_dwAccountStatus = dwStatus;
  1235. }
  1236. //
  1237. // The following functions implement the DiskQuotaUser "dispatch" object that
  1238. // is created to handle OLE automation duties for the DiskQuotaUser object.
  1239. // The functions are all fairly basic and require little explanation.
  1240. // Therefore, I'll spare you the function headers. In most cases,
  1241. // the property and method functions call directly through to their
  1242. // corresponding functions in class DiskQuotaUser.
  1243. //
  1244. DiskQuotaUserDisp::DiskQuotaUserDisp(
  1245. PDISKQUOTA_USER pUser
  1246. ) : m_cRef(0),
  1247. m_pUser(pUser)
  1248. {
  1249. DBGTRACE((DM_USER, DL_HIGH, TEXT("DiskQuotaUserDisp::DiskQuotaUserDisp")));
  1250. DBGPRINT((DM_USER, DL_HIGH, TEXT("\tthis = 0x%08X"), this));
  1251. if (NULL != m_pUser)
  1252. {
  1253. m_pUser->AddRef();
  1254. }
  1255. m_Dispatch.Initialize(static_cast<IDispatch *>(this),
  1256. LIBID_DiskQuotaTypeLibrary,
  1257. IID_DIDiskQuotaUser,
  1258. L"DSKQUOTA.DLL");
  1259. }
  1260. DiskQuotaUserDisp::~DiskQuotaUserDisp(
  1261. VOID
  1262. )
  1263. {
  1264. DBGTRACE((DM_USER, DL_HIGH, TEXT("DiskQuotaUserDisp::~DiskQuotaUserDisp")));
  1265. DBGPRINT((DM_USER, DL_HIGH, TEXT("\tthis = 0x%08X"), this));
  1266. if (NULL != m_pUser)
  1267. {
  1268. m_pUser->Release();
  1269. }
  1270. }
  1271. STDMETHODIMP
  1272. DiskQuotaUserDisp::QueryInterface(
  1273. REFIID riid,
  1274. LPVOID *ppvOut
  1275. )
  1276. {
  1277. DBGTRACE((DM_USER, DL_MID, TEXT("DiskQuotaUserDisp::QueryInterface")));
  1278. DBGPRINTIID(DM_USER, DL_MID, riid);
  1279. HRESULT hResult = E_NOINTERFACE;
  1280. if (NULL == ppvOut)
  1281. return E_INVALIDARG;
  1282. *ppvOut = NULL;
  1283. if (IID_IUnknown == riid)
  1284. {
  1285. *ppvOut = this;
  1286. }
  1287. else if (IID_IDispatch == riid)
  1288. {
  1289. *ppvOut = static_cast<IDispatch *>(this);
  1290. }
  1291. else if (IID_DIDiskQuotaUser == riid)
  1292. {
  1293. *ppvOut = static_cast<DIDiskQuotaUser *>(this);
  1294. }
  1295. else if (IID_IDiskQuotaUser == riid)
  1296. {
  1297. //
  1298. // Return the quota user's vtable interface.
  1299. // This allows code to "typecast" (COM-style) between
  1300. // the dispatch interface and vtable interface.
  1301. //
  1302. return m_pUser->QueryInterface(riid, ppvOut);
  1303. }
  1304. if (NULL != *ppvOut)
  1305. {
  1306. ((LPUNKNOWN)*ppvOut)->AddRef();
  1307. hResult = NOERROR;
  1308. }
  1309. return hResult;
  1310. }
  1311. STDMETHODIMP_(ULONG)
  1312. DiskQuotaUserDisp::AddRef(
  1313. VOID
  1314. )
  1315. {
  1316. ULONG cRef = InterlockedIncrement(&m_cRef);
  1317. DBGPRINT((DM_COM, DL_HIGH, TEXT("DiskQuotaUserDisp::AddRef, 0x%08X %d -> %d"), this, cRef - 1, cRef ));
  1318. return cRef;
  1319. }
  1320. STDMETHODIMP_(ULONG)
  1321. DiskQuotaUserDisp::Release(
  1322. VOID
  1323. )
  1324. {
  1325. ASSERT( 0 != m_cRef );
  1326. ULONG cRef = InterlockedDecrement(&m_cRef);
  1327. DBGPRINT((DM_COM, DL_HIGH, TEXT("DiskQuotaUserDisp::Release, 0x%08X %d -> %d"),
  1328. this, cRef + 1, cRef));
  1329. if ( 0 == cRef )
  1330. {
  1331. delete this;
  1332. }
  1333. return cRef;
  1334. }
  1335. //
  1336. // IDispatch::GetIDsOfNames
  1337. //
  1338. STDMETHODIMP
  1339. DiskQuotaUserDisp::GetIDsOfNames(
  1340. REFIID riid,
  1341. OLECHAR **rgszNames,
  1342. UINT cNames,
  1343. LCID lcid,
  1344. DISPID *rgDispId
  1345. )
  1346. {
  1347. DBGTRACE((DM_USER, DL_LOW, TEXT("DiskQuotaUserDisp::GetIDsOfNames")));
  1348. //
  1349. // Let our dispatch object handle this.
  1350. //
  1351. return m_Dispatch.GetIDsOfNames(riid,
  1352. rgszNames,
  1353. cNames,
  1354. lcid,
  1355. rgDispId);
  1356. }
  1357. //
  1358. // IDispatch::GetTypeInfo
  1359. //
  1360. STDMETHODIMP
  1361. DiskQuotaUserDisp::GetTypeInfo(
  1362. UINT iTInfo,
  1363. LCID lcid,
  1364. ITypeInfo **ppTypeInfo
  1365. )
  1366. {
  1367. DBGTRACE((DM_USER, DL_LOW, TEXT("DiskQuotaUserDisp::GetTypeInfo")));
  1368. //
  1369. // Let our dispatch object handle this.
  1370. //
  1371. return m_Dispatch.GetTypeInfo(iTInfo, lcid, ppTypeInfo);
  1372. }
  1373. //
  1374. // IDispatch::GetTypeInfoCount
  1375. //
  1376. STDMETHODIMP
  1377. DiskQuotaUserDisp::GetTypeInfoCount(
  1378. UINT *pctinfo
  1379. )
  1380. {
  1381. DBGTRACE((DM_USER, DL_LOW, TEXT("DiskQuotaUserDisp::GetTypeInfoCount")));
  1382. //
  1383. // Let our dispatch object handle this.
  1384. //
  1385. return m_Dispatch.GetTypeInfoCount(pctinfo);
  1386. }
  1387. //
  1388. // IDispatch::Invoke
  1389. //
  1390. STDMETHODIMP
  1391. DiskQuotaUserDisp::Invoke(
  1392. DISPID dispIdMember,
  1393. REFIID riid,
  1394. LCID lcid,
  1395. WORD wFlags,
  1396. DISPPARAMS *pDispParams,
  1397. VARIANT *pVarResult,
  1398. EXCEPINFO *pExcepInfo,
  1399. UINT *puArgErr
  1400. )
  1401. {
  1402. DBGTRACE((DM_USER, DL_LOW, TEXT("DiskQuotaUserDisp::Invoke")));
  1403. DBGPRINT((DM_USER, DL_LOW, TEXT("DispId = %d"), dispIdMember));
  1404. DBGPRINTIID(DM_USER, DL_LOW, riid);
  1405. //
  1406. // Let our dispatch object handle this.
  1407. //
  1408. return m_Dispatch.Invoke(dispIdMember,
  1409. riid,
  1410. lcid,
  1411. wFlags,
  1412. pDispParams,
  1413. pVarResult,
  1414. pExcepInfo,
  1415. puArgErr);
  1416. }
  1417. //
  1418. // Return user object's unique ID.
  1419. //
  1420. STDMETHODIMP
  1421. DiskQuotaUserDisp::get_ID(
  1422. long *pID
  1423. )
  1424. {
  1425. return m_pUser->GetID((ULONG *)pID);
  1426. }
  1427. STDMETHODIMP
  1428. DiskQuotaUserDisp::get_AccountContainerName(
  1429. BSTR *pContainerName
  1430. )
  1431. {
  1432. TCHAR szName[MAX_DOMAIN] = { TEXT('\0') };
  1433. HRESULT hr = m_pUser->GetName(szName, ARRAYSIZE(szName),
  1434. NULL, 0,
  1435. NULL, 0);
  1436. if (SUCCEEDED(hr))
  1437. {
  1438. *pContainerName = SysAllocString(szName);
  1439. if (NULL == *pContainerName)
  1440. {
  1441. hr = E_OUTOFMEMORY;
  1442. }
  1443. }
  1444. return hr;
  1445. }
  1446. STDMETHODIMP
  1447. DiskQuotaUserDisp::get_LogonName(
  1448. BSTR *pLogonName
  1449. )
  1450. {
  1451. TCHAR szName[MAX_USERNAME] = { TEXT('\0') };
  1452. HRESULT hr = m_pUser->GetName(NULL, 0,
  1453. szName, ARRAYSIZE(szName),
  1454. NULL, 0);
  1455. if (SUCCEEDED(hr))
  1456. {
  1457. *pLogonName = SysAllocString(szName);
  1458. if (NULL == *pLogonName)
  1459. {
  1460. hr = E_OUTOFMEMORY;
  1461. }
  1462. }
  1463. return hr;
  1464. }
  1465. STDMETHODIMP
  1466. DiskQuotaUserDisp::get_DisplayName(
  1467. BSTR *pDisplayName
  1468. )
  1469. {
  1470. TCHAR szName[MAX_FULL_USERNAME] = { TEXT('\0') };
  1471. HRESULT hr = m_pUser->GetName(NULL, 0,
  1472. NULL, 0,
  1473. szName, ARRAYSIZE(szName));
  1474. if (SUCCEEDED(hr))
  1475. {
  1476. *pDisplayName = SysAllocString(szName);
  1477. if (NULL == *pDisplayName)
  1478. {
  1479. hr = E_OUTOFMEMORY;
  1480. }
  1481. }
  1482. return hr;
  1483. }
  1484. STDMETHODIMP
  1485. DiskQuotaUserDisp::get_QuotaThreshold(
  1486. double *pThreshold
  1487. )
  1488. {
  1489. LONGLONG llValue;
  1490. HRESULT hr = m_pUser->GetQuotaThreshold(&llValue);
  1491. if (SUCCEEDED(hr))
  1492. *pThreshold = (double)llValue;
  1493. return hr;
  1494. }
  1495. STDMETHODIMP
  1496. DiskQuotaUserDisp::put_QuotaThreshold(
  1497. double Threshold
  1498. )
  1499. {
  1500. if (MAXLONGLONG < Threshold)
  1501. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  1502. return m_pUser->SetQuotaThreshold((LONGLONG)Threshold, TRUE);
  1503. }
  1504. STDMETHODIMP
  1505. DiskQuotaUserDisp::get_QuotaThresholdText(
  1506. BSTR *pThresholdText
  1507. )
  1508. {
  1509. TCHAR szValue[40];
  1510. HRESULT hr = m_pUser->GetQuotaThresholdText(szValue, ARRAYSIZE(szValue));
  1511. if (SUCCEEDED(hr))
  1512. {
  1513. *pThresholdText = SysAllocString(szValue);
  1514. if (NULL == *pThresholdText)
  1515. {
  1516. hr = E_OUTOFMEMORY;
  1517. }
  1518. }
  1519. return hr;
  1520. }
  1521. STDMETHODIMP
  1522. DiskQuotaUserDisp::get_QuotaLimit(
  1523. double *pQuotaLimit
  1524. )
  1525. {
  1526. LONGLONG llValue;
  1527. HRESULT hr = m_pUser->GetQuotaLimit(&llValue);
  1528. if (SUCCEEDED(hr))
  1529. *pQuotaLimit = (double)llValue;
  1530. return hr;
  1531. }
  1532. STDMETHODIMP
  1533. DiskQuotaUserDisp::put_QuotaLimit(
  1534. double Limit
  1535. )
  1536. {
  1537. if (MAXLONGLONG < Limit)
  1538. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  1539. return m_pUser->SetQuotaLimit((LONGLONG)Limit, TRUE);
  1540. }
  1541. STDMETHODIMP
  1542. DiskQuotaUserDisp::get_QuotaLimitText(
  1543. BSTR *pLimitText
  1544. )
  1545. {
  1546. TCHAR szValue[40];
  1547. HRESULT hr = m_pUser->GetQuotaLimitText(szValue, ARRAYSIZE(szValue));
  1548. if (SUCCEEDED(hr))
  1549. {
  1550. *pLimitText = SysAllocString(szValue);
  1551. if (NULL == *pLimitText)
  1552. {
  1553. hr = E_OUTOFMEMORY;
  1554. }
  1555. }
  1556. return hr;
  1557. }
  1558. STDMETHODIMP
  1559. DiskQuotaUserDisp::get_QuotaUsed(
  1560. double *pUsed
  1561. )
  1562. {
  1563. LONGLONG llValue;
  1564. HRESULT hr = m_pUser->GetQuotaUsed(&llValue);
  1565. if (SUCCEEDED(hr))
  1566. *pUsed = (double)llValue;
  1567. return hr;
  1568. }
  1569. STDMETHODIMP
  1570. DiskQuotaUserDisp::get_QuotaUsedText(
  1571. BSTR *pUsedText
  1572. )
  1573. {
  1574. TCHAR szValue[40];
  1575. HRESULT hr = m_pUser->GetQuotaUsedText(szValue, ARRAYSIZE(szValue));
  1576. if (SUCCEEDED(hr))
  1577. {
  1578. *pUsedText = SysAllocString(szValue);
  1579. if (NULL == *pUsedText)
  1580. {
  1581. hr = E_OUTOFMEMORY;
  1582. }
  1583. }
  1584. return hr;
  1585. }
  1586. STDMETHODIMP
  1587. DiskQuotaUserDisp::get_AccountStatus(
  1588. AccountStatusConstants *pStatus
  1589. )
  1590. {
  1591. DWORD dwStatus;
  1592. HRESULT hr = m_pUser->GetAccountStatus(&dwStatus);
  1593. if (SUCCEEDED(hr))
  1594. {
  1595. *pStatus = (AccountStatusConstants)dwStatus;
  1596. }
  1597. return hr;
  1598. }
  1599. //
  1600. // Methods.
  1601. //
  1602. STDMETHODIMP
  1603. DiskQuotaUserDisp::Invalidate(
  1604. void
  1605. )
  1606. {
  1607. return m_pUser->Invalidate();
  1608. }