Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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