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.

3320 lines
104 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. /* File: control.cpp
  3. Description: Contains member function definitions for class DiskQuotaControl.
  4. This class is the main point of focus for managing disk quota information
  5. through the DSKQUOTA library. The user creates an instance of a
  6. DiskQuotaControl object through CoCreateInstance and manages quota
  7. information through it's IDiskQuotaControl interface.
  8. Revision History:
  9. Date Description Programmer
  10. -------- --------------------------------------------------- ----------
  11. 05/22/96 Initial creation. BrianAu
  12. */
  13. ///////////////////////////////////////////////////////////////////////////////
  14. #include "pch.h" // PCH
  15. #pragma hdrstop
  16. #include "connect.h"
  17. #include "control.h"
  18. #include "guidsp.h" // Private GUIDs.
  19. #include "registry.h"
  20. #include "sidcache.h"
  21. #include "userbat.h"
  22. #include "userenum.h"
  23. #include "resource.h" // For IDS_NO_LIMIT.
  24. #include <oleauto.h> // OLE automation
  25. #include <comutil.h>
  26. #include <sddl.h>
  27. //
  28. // Verify that build is UNICODE.
  29. //
  30. #if !defined(UNICODE)
  31. # error This module must be compiled UNICODE.
  32. #endif
  33. //
  34. // Size of user enumerator's buffer. Thought about this being a reg entry.
  35. // Didn't make a lot of sense.
  36. //
  37. const UINT ENUMUSER_BUF_LEN = 2048;
  38. //
  39. // To add support for a new connection point type, just add a new IID to this
  40. // array. Also add a corresponding enumeration constant in the DiskQuotaControl
  41. // class declaration that identifies the location of the conn pt IID in
  42. // m_rgpIConnPtsSupported[].
  43. //
  44. const IID * const DiskQuotaControl::m_rgpIConnPtsSupported[] = { &IID_IDiskQuotaEvents,
  45. &IID_DIDiskQuotaControlEvents };
  46. ///////////////////////////////////////////////////////////////////////////////
  47. /* Function: DiskQuotaControl::DiskQuotaControl
  48. Description: Constructor.
  49. Arguments: None.
  50. Returns: Nothing.
  51. Revision History:
  52. Date Description Programmer
  53. -------- --------------------------------------------------- ----------
  54. 05/22/96 Initial creation. BrianAu
  55. 08/15/97 Added m_bInitialized member. BrianAu
  56. */
  57. ///////////////////////////////////////////////////////////////////////////////
  58. DiskQuotaControl::DiskQuotaControl(
  59. VOID
  60. ) : m_cRef(0),
  61. m_bInitialized(FALSE),
  62. m_pFSObject(NULL),
  63. m_dwFlags(0),
  64. m_pSidNameResolver(NULL),
  65. m_rgConnPts(NULL),
  66. m_cConnPts(0),
  67. m_llDefaultQuotaThreshold(0),
  68. m_llDefaultQuotaLimit(0)
  69. {
  70. DBGTRACE((DM_CONTROL, DL_MID, TEXT("DiskQuotaControl::DiskQuotaControl")));
  71. InterlockedIncrement(&g_cRefThisDll);
  72. }
  73. ///////////////////////////////////////////////////////////////////////////////
  74. /* Function: DiskQuotaControl::~DiskQuotaControl
  75. Description: Destructor. Releases FSObject pointer.
  76. Arguments: None.
  77. Returns: Nothing.
  78. Revision History:
  79. Date Description Programmer
  80. -------- --------------------------------------------------- ----------
  81. 05/22/96 Initial creation. BrianAu
  82. */
  83. ///////////////////////////////////////////////////////////////////////////////
  84. DiskQuotaControl::~DiskQuotaControl(
  85. VOID
  86. )
  87. {
  88. DBGTRACE((DM_CONTROL, DL_MID, TEXT("DiskQuotaControl::~DiskQuotaControl")));
  89. //
  90. // See the comment in NotifyUserNameChanged for a discussion on the
  91. // use of this mutex. In short, it prevents a deadlock between
  92. // the resolver's thread and a client receiving a name-change
  93. // notification. The wait here is INFINITE while the corresponding
  94. // wait in NotifyUserNameChanged is limited.
  95. //
  96. AutoLockMutex lock(m_mutex, INFINITE);
  97. if (NULL != m_pFSObject)
  98. {
  99. m_pFSObject->Release();
  100. m_pFSObject = NULL;
  101. }
  102. ShutdownNameResolution();
  103. if (NULL != m_rgConnPts)
  104. {
  105. for (UINT i = 0; i < m_cConnPts; i++)
  106. {
  107. if (NULL != m_rgConnPts[i])
  108. {
  109. m_rgConnPts[i]->Release();
  110. m_rgConnPts[i] = NULL;
  111. }
  112. }
  113. delete[] m_rgConnPts;
  114. }
  115. InterlockedDecrement(&g_cRefThisDll);
  116. }
  117. ///////////////////////////////////////////////////////////////////////////////
  118. /* Function: DiskQuotaControl::QueryInterface
  119. Description: Returns an interface pointer to the object's IUnknown,
  120. IDiskQuotaControl or IConnectionPointContainer interface. The object
  121. referenced by the returned interface pointer is uninitialized. The
  122. recipient of the pointer must call Initialize() before the object is
  123. usable.
  124. Arguments:
  125. riid - Reference to requested interface ID.
  126. ppvOut - Address of interface pointer variable to accept interface ptr.
  127. Returns:
  128. NOERROR - Success.
  129. E_NOINTERFACE - Requested interface not supported.
  130. E_INVALIDARG - ppvOut argument was NULL.
  131. Revision History:
  132. Date Description Programmer
  133. -------- --------------------------------------------------- ----------
  134. 05/22/96 Initial creation. BrianAu
  135. */
  136. ///////////////////////////////////////////////////////////////////////////////
  137. STDMETHODIMP
  138. DiskQuotaControl::QueryInterface(
  139. REFIID riid,
  140. LPVOID *ppvOut
  141. )
  142. {
  143. DBGTRACE((DM_CONTROL, DL_MID, TEXT("DiskQuotaControl::QueryInterface")));
  144. DBGPRINTIID(DM_CONTROL, DL_MID, riid);
  145. if (NULL == ppvOut)
  146. return E_INVALIDARG;
  147. HRESULT hr = E_NOINTERFACE;
  148. try
  149. {
  150. *ppvOut = NULL;
  151. if (IID_IUnknown == riid ||
  152. IID_IDiskQuotaControl == riid)
  153. {
  154. *ppvOut = this;
  155. }
  156. else if (IID_IConnectionPointContainer == riid)
  157. {
  158. hr = InitConnectionPoints();
  159. if (SUCCEEDED(hr))
  160. {
  161. *ppvOut = static_cast<IConnectionPointContainer *>(this);
  162. }
  163. }
  164. else if (IID_IDispatch == riid ||
  165. IID_DIDiskQuotaControl == riid)
  166. {
  167. DiskQuotaControlDisp *pQCDisp = new DiskQuotaControlDisp(static_cast<PDISKQUOTA_CONTROL>(this));
  168. *ppvOut = static_cast<DIDiskQuotaControl *>(pQCDisp);
  169. }
  170. if (NULL != *ppvOut)
  171. {
  172. ((LPUNKNOWN)*ppvOut)->AddRef();
  173. hr = NOERROR;
  174. }
  175. }
  176. catch(CAllocException& e)
  177. {
  178. DBGERROR((TEXT("Insufficient memory exception")));
  179. *ppvOut = NULL;
  180. hr = E_OUTOFMEMORY;
  181. }
  182. return hr;
  183. }
  184. ///////////////////////////////////////////////////////////////////////////////
  185. /* Function: DiskQuotaControl::AddRef
  186. Description: Increments object reference count.
  187. Arguments: None.
  188. Returns: New reference count value.
  189. Revision History:
  190. Date Description Programmer
  191. -------- --------------------------------------------------- ----------
  192. 05/22/96 Initial creation. BrianAu
  193. */
  194. ///////////////////////////////////////////////////////////////////////////////
  195. STDMETHODIMP_(ULONG)
  196. DiskQuotaControl::AddRef(
  197. VOID
  198. )
  199. {
  200. DBGTRACE((DM_CONTROL, DL_LOW, TEXT("DiskQuotaControl::AddRef")));
  201. DBGPRINT((DM_CONTROL, DL_LOW, TEXT("\t0x%08X %d -> %d"),
  202. this, m_cRef, m_cRef + 1));
  203. ULONG ulReturn = m_cRef + 1;
  204. InterlockedIncrement(&m_cRef);
  205. return ulReturn;
  206. }
  207. ///////////////////////////////////////////////////////////////////////////////
  208. /* Function: DiskQuotaControl::Release
  209. Description: Decrements object reference count. If count drops to 0,
  210. object is deleted.
  211. Arguments: None.
  212. Returns: New reference count value.
  213. Revision History:
  214. Date Description Programmer
  215. -------- --------------------------------------------------- ----------
  216. 05/22/96 Initial creation. BrianAu
  217. */
  218. ///////////////////////////////////////////////////////////////////////////////
  219. STDMETHODIMP_(ULONG)
  220. DiskQuotaControl::Release(
  221. VOID
  222. )
  223. {
  224. DBGTRACE((DM_CONTROL, DL_LOW, TEXT("DiskQuotaControl::Release")));
  225. DBGPRINT((DM_CONTROL, DL_LOW, TEXT("\t0x%08X %d -> %d"),
  226. this, m_cRef, m_cRef - 1));
  227. ULONG ulReturn = m_cRef - 1;
  228. if (InterlockedDecrement(&m_cRef) == 0)
  229. {
  230. delete this;
  231. ulReturn = 0;
  232. }
  233. return ulReturn;
  234. }
  235. ///////////////////////////////////////////////////////////////////////////////
  236. /* Function: DiskQuotaControl::Initialize
  237. Description: Initializes a quota controller object by opening the NTFS
  238. "device" associated with the quota information. The caller passes the
  239. name of an NTFS volume device to open. A C++ object is created which
  240. encapsulates the required NTFS functionality. This object is known
  241. as a "file system object" or FSObject.
  242. Currently, NTFS only supports quotas on volumes. However, there is
  243. talk of providing quotas for directories in the future. This library
  244. has been designed with this expansion in mind.
  245. By using an object hierarchy to represent the FSObject,
  246. we are able to shield the quota control object from differences
  247. in NTIO API functions dealing with volumes, directories and both
  248. local and remote flavors of both.
  249. Arguments:
  250. pszPath - Name of NTFS path to open.
  251. bReadWrite - TRUE = Read/write.
  252. FALSE = Read only.
  253. Returns:
  254. NOERROR - Success.
  255. E_INVALIDARG - pszPath arg was NULL.
  256. E_OUTOFMEMORY - Insufficient memory.
  257. E_UNEXPECTED - Unexpected exception.
  258. E_FAIL - Error getting volume information.
  259. ERROR_ACCESS_DENIED (hr) - Insufficient access to open FS object.
  260. ERROR_FILE_NOT_FOUND (hr) - Specified volume doesn't exist.
  261. ERROR_PATH_NOT_FOUND (hr) - Specified volume doesn't exist.
  262. ERROR_BAD_PATHNAME (hr) - Invalid path name provided.
  263. ERROR_INVALID_NAME (hr) - Invalid path name provided.
  264. ERROR_NOT_SUPPORTED (hr) - Quotas not supported by volume.
  265. ERROR_ALREADY_INITIALIZED (hr) - Controller is already initialized.
  266. Revision History:
  267. Date Description Programmer
  268. -------- --------------------------------------------------- ----------
  269. 05/22/96 Initial creation. BrianAu
  270. 06/06/96 Added ansi-unicode thunk. BrianAu
  271. 06/11/96 Added return of access granted value. BrianAu
  272. 09/05/96 Added exception handling. BrianAu
  273. 09/23/96 Take a "lazy" position on creating the BrianAu
  274. SidNameResolver object. Should only create it when
  275. it will be needed (user enumeration). Moved
  276. creation from here to CreateEnumUsers.
  277. 07/03/97 Added dwAccess argument. BrianAu
  278. 08/15/97 Added "already initialized" check. BrianAu
  279. Removed InitializeA().
  280. */
  281. ///////////////////////////////////////////////////////////////////////////////
  282. STDMETHODIMP
  283. DiskQuotaControl::Initialize(
  284. LPCWSTR pszPath,
  285. BOOL bReadWrite
  286. )
  287. {
  288. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::Initialize")));
  289. DBGPRINT((DM_CONTROL, DL_MID, TEXT("\tpath = \"%s\", bReadWrite = %d"),
  290. pszPath ? pszPath : TEXT("<null>"), bReadWrite));
  291. HRESULT hr = NOERROR;
  292. if (m_bInitialized)
  293. {
  294. //
  295. // Controller has already been initialized.
  296. // Re-initialization is not allowed.
  297. //
  298. hr = HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED);
  299. }
  300. else
  301. {
  302. if (NULL == pszPath)
  303. return E_INVALIDARG;
  304. try
  305. {
  306. DWORD dwAccess = GENERIC_READ | (bReadWrite ? GENERIC_WRITE : 0);
  307. hr = FSObject::Create(pszPath,
  308. dwAccess,
  309. &m_pFSObject);
  310. m_bInitialized = SUCCEEDED(hr);
  311. }
  312. catch(CAllocException& e)
  313. {
  314. DBGERROR((TEXT("Insufficient memory exception")));
  315. hr = E_OUTOFMEMORY;
  316. }
  317. }
  318. return hr;
  319. }
  320. ///////////////////////////////////////////////////////////////////////////////
  321. /* Function: DiskQuotaControl::CreateEnumUsers
  322. Description: Create a new enumerator object for enumerating over the users
  323. in a volume's quota information file. The returned interface supports
  324. the normal OLE 2 enumeration members Next(), Reset(), Skip() and Clone().
  325. Arguments:
  326. rgpSids [optional] - Pointer to a list of SID pointers. If
  327. provided, only those users with SIDs included in the list are
  328. returned. This argument may be NULL in which case ALL users are
  329. included. Any element containing a NULL pointer will terminate
  330. the list.
  331. cpSids [optional] - If pSidList is not NULL, this arg contains
  332. the count of entries in rgpSids. If rgpSids is not NULL and this
  333. argument contains 0, rgpSids is assumed to contain a terminating
  334. NULL pointer entry.
  335. fNameResolution - Can be one of the following:
  336. DISKQUOTA_USERNAME_RESOLVE_NONE
  337. DISKQUOTA_USERNAME_RESOLVE_SYNC
  338. DISKQUOTA_USERNAME_RESOLVE_ASYNC
  339. ppEnum - Address of interface variable to accept the IEnumDiskQuotaUser
  340. interface pointer.
  341. Returns:
  342. NOERROR - Success.
  343. E_INVALIDARG - ppEnum arg is NULL.
  344. E_OUTOFMEMORY - Insufficient memory to create enumerator object.
  345. ERROR_ACCESS_DENIED (hr) - Need READ access to create enumerator.
  346. ERROR_NOT_READY (hr) - Object not initialized.
  347. Revision History:
  348. Date Description Programmer
  349. -------- --------------------------------------------------- ----------
  350. 05/22/96 Initial creation. BrianAu
  351. 08/11/96 Added access control. BrianAu
  352. 09/05/96 Added exception handling. BrianAu
  353. 09/23/96 Added lazy creation of SidNameResolver object. BrianAu
  354. Moved it from InitializeW().
  355. */
  356. ///////////////////////////////////////////////////////////////////////////////
  357. HRESULT
  358. DiskQuotaControl::CreateEnumUsers(
  359. PSID *rgpSids,
  360. DWORD cpSids,
  361. DWORD fNameResolution,
  362. IEnumDiskQuotaUsers **ppEnum
  363. )
  364. {
  365. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::CreateEnumUsers")));
  366. HRESULT hr = E_FAIL;
  367. if (!m_bInitialized)
  368. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  369. if (NULL == ppEnum)
  370. return E_INVALIDARG;
  371. if (!m_pFSObject->GrantedAccess(GENERIC_READ))
  372. {
  373. hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  374. }
  375. else
  376. {
  377. DiskQuotaUserEnum *pEnumUsers = NULL;
  378. try
  379. {
  380. if (NULL == m_pSidNameResolver)
  381. {
  382. //
  383. // If there's no SID/Name resolver object, create one.
  384. // We do this "as needed" because user enumeration is
  385. // the only controller function that requires a resolver.
  386. // If the client doesn't need a resolver, why create one?
  387. //
  388. SidNameResolver *pResolver = NULL;
  389. //
  390. // Create user SID/Name resolver object.
  391. //
  392. pResolver = new SidNameResolver(*this);
  393. hr = pResolver->QueryInterface(IID_ISidNameResolver,
  394. (LPVOID *)&m_pSidNameResolver);
  395. if (SUCCEEDED(hr))
  396. {
  397. hr = m_pSidNameResolver->Initialize();
  398. if (FAILED(hr))
  399. {
  400. //
  401. // If resolver initialization fails, we can assume
  402. // that the resolver's thread hasn't been created so
  403. // it's OK to just call Release() instead of
  404. // Shutdown() followed by Release(). This is strongly
  405. // dependent on the initialization logic in the resolver's
  406. // Initialize method. There's a comment there also.
  407. //
  408. m_pSidNameResolver->Release();
  409. m_pSidNameResolver = NULL;
  410. pResolver = NULL;
  411. }
  412. }
  413. }
  414. if (NULL != m_pSidNameResolver)
  415. {
  416. //
  417. // Create and initialize the enumerator object.
  418. //
  419. pEnumUsers = new DiskQuotaUserEnum(static_cast<IDiskQuotaControl *>(this),
  420. m_pSidNameResolver,
  421. m_pFSObject);
  422. //
  423. // This can throw OutOfMemory.
  424. //
  425. hr = pEnumUsers->Initialize(fNameResolution,
  426. ENUMUSER_BUF_LEN,
  427. rgpSids,
  428. cpSids);
  429. if (SUCCEEDED(hr))
  430. {
  431. hr = pEnumUsers->QueryInterface(IID_IEnumDiskQuotaUsers,
  432. (LPVOID *)ppEnum);
  433. }
  434. else
  435. {
  436. //
  437. // Something failed after enumerator object was created.
  438. //
  439. delete pEnumUsers;
  440. }
  441. }
  442. }
  443. catch(CAllocException& e)
  444. {
  445. DBGERROR((TEXT("Insufficient memory exception")));
  446. delete pEnumUsers;
  447. hr = E_OUTOFMEMORY;
  448. }
  449. }
  450. return hr;
  451. }
  452. ///////////////////////////////////////////////////////////////////////////////
  453. /* Function: DiskQuotaControl::CreateUserBatch
  454. Description: Create a new user batch control object. Batch control is
  455. provided to take advantage of the inherent batching properties of the
  456. NTIOAPI. If many user records are being altered at one time, it is
  457. much more efficient to mark each of the users for "deferred update",
  458. submit each user object to the batch and then flush the batch to disk.
  459. Arguments:
  460. ppUserBatch - Address of interface variable to accept the IDiskQuotaUserBatch
  461. interface pointer.
  462. Returns:
  463. NOERROR - Success.
  464. E_INVALIDARG - ppOut arg is NULL.
  465. E_OUTOFMEMORY - Insufficient memory to create batch object.
  466. ERROR_ACCESS_DENIED (hr) - Need WRITE access to create batch.
  467. ERROR_NOT_READY (hr) - Object not initialized.
  468. Revision History:
  469. Date Description Programmer
  470. -------- --------------------------------------------------- ----------
  471. 06/06/96 Initial creation. BrianAu
  472. 08/11/96 Added access control. BrianAu
  473. 09/05/96 Added exception handling. BrianAu
  474. */
  475. ///////////////////////////////////////////////////////////////////////////////
  476. STDMETHODIMP
  477. DiskQuotaControl::CreateUserBatch(
  478. PDISKQUOTA_USER_BATCH *ppUserBatch
  479. )
  480. {
  481. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::CreateUserBatch")));
  482. HRESULT hr = NOERROR;
  483. if (!m_bInitialized)
  484. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  485. if (NULL == ppUserBatch)
  486. return E_INVALIDARG;
  487. if (!m_pFSObject->GrantedAccess(GENERIC_WRITE))
  488. {
  489. hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  490. }
  491. else
  492. {
  493. try
  494. {
  495. DiskQuotaUserBatch *pUserBatch = new DiskQuotaUserBatch(m_pFSObject);
  496. hr = pUserBatch->QueryInterface(IID_IDiskQuotaUserBatch,
  497. (LPVOID *)ppUserBatch);
  498. }
  499. catch(CAllocException& e) // From new or m_UserList ctor.
  500. {
  501. DBGERROR((TEXT("Insufficient memory exception")));
  502. hr = E_OUTOFMEMORY;
  503. }
  504. }
  505. return hr;
  506. }
  507. ///////////////////////////////////////////////////////////////////////////////
  508. /* Function: DiskQuotaControl::AddUserSid
  509. Description: Adds a new user to the volume's quota information file.
  510. If successful, returns an interface to the new user object. When
  511. the caller is finished with the interface, they must call Release()
  512. through that interface pointer. Uses the default limit and threshold.
  513. Arguments:
  514. pSid - Pointer to single SID structure.
  515. fNameResolution - Method of SID-to-name resolution. Can be one of the
  516. following:
  517. DISKQUOTA_USERNAME_RESOLVE_NONE
  518. DISKQUOTA_USERNAME_RESOLVE_SYNC
  519. DISKQUOTA_USERNAME_RESOLVE_ASYNC
  520. ppUser - Address of interface pointer variable to accept
  521. pointer to the new user object's IDiskQuotaUser interface.
  522. Returns:
  523. SUCCESS - Success.
  524. S_FALSE - User already exists. Not added.
  525. E_OUTOFMEMORY - Insufficient memory.
  526. E_UNEXPECTED - Unexpected exception.
  527. E_INVALIDARG - pSid or ppUser were NULL.
  528. ERROR_NOT_READY (hr) - Object not initialized.
  529. Revision History:
  530. Date Description Programmer
  531. -------- --------------------------------------------------- ----------
  532. 05/22/96 Initial creation. BrianAu
  533. 09/30/96 Added implementation. Was E_NOTIMPL. BrianAu
  534. */
  535. ///////////////////////////////////////////////////////////////////////////////
  536. STDMETHODIMP
  537. DiskQuotaControl::AddUserSid(
  538. PSID pSid,
  539. DWORD fNameResolution,
  540. PDISKQUOTA_USER *ppUser
  541. )
  542. {
  543. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::AddUserSid")));
  544. HRESULT hr = E_FAIL;
  545. PDISKQUOTA_USER pIUser = NULL;
  546. if (!m_bInitialized)
  547. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  548. if (NULL == pSid || NULL == ppUser)
  549. return E_INVALIDARG;
  550. LONGLONG llLimit = 0;
  551. LONGLONG llThreshold = 0;
  552. LONGLONG llUsed = 0;
  553. *ppUser = NULL;
  554. //
  555. // Check to see if the user already exists in the quota file.
  556. //
  557. try
  558. {
  559. hr = FindUserSid(pSid,
  560. DISKQUOTA_USERNAME_RESOLVE_NONE,
  561. &pIUser);
  562. if (SUCCEEDED(hr))
  563. {
  564. //
  565. // The NTIOAPI says the user exists.
  566. // We'll need the quota info to determine if we
  567. // still allow addition of the "new" user. This is needed because
  568. // of the weird way the NTIOAPI enumerates users. If you ask it to
  569. // enumerate specified user(s), the returned information will include
  570. // info for users that do not have (but could have) a record in the
  571. // quota file. Since the quota system allows automatic addition of
  572. // users, it considers any users with write access to have a record
  573. // in the quota file. Such users are returned with a quota threshold
  574. // and limit of 0. Therefore, we treat records marked for deletion
  575. // or those with 0 used, 0 limit and 0 threshold as "non existing".
  576. // I use the term "ghost" for these users.
  577. //
  578. pIUser->GetQuotaLimit(&llLimit);
  579. pIUser->GetQuotaThreshold(&llThreshold);
  580. pIUser->GetQuotaUsed(&llUsed);
  581. ULARGE_INTEGER a,b,c;
  582. a.QuadPart = llLimit;
  583. b.QuadPart = llThreshold;
  584. c.QuadPart = llUsed;
  585. DBGPRINT((DM_CONTROL, DL_LOW, TEXT("Found user: Limit = 0x%08X 0x%08X, Threshold = 0x%08X 0x%08X, Used = 0x%08X 0x%08X"),
  586. a.HighPart, a.LowPart, b.HighPart, b.LowPart, c.HighPart, c.LowPart));
  587. BOOL bIsGhost = ((MARK4DEL == llLimit) ||
  588. ( 0 == llLimit &&
  589. 0 == llThreshold &&
  590. 0 == llUsed));
  591. if (!bIsGhost)
  592. {
  593. //
  594. // User already exists.
  595. //
  596. hr = S_FALSE;
  597. }
  598. else
  599. {
  600. DWORD cbSid = GetLengthSid(pSid);
  601. //
  602. // User not in quota file OR in quota file but marked for deletion.
  603. // Just set it's limit and threshold to the volume defaults.
  604. //
  605. pIUser->SetQuotaThreshold(m_llDefaultQuotaThreshold, TRUE);
  606. hr = pIUser->SetQuotaLimit(m_llDefaultQuotaLimit, TRUE);
  607. if (SUCCEEDED(hr) && NULL != m_pSidNameResolver)
  608. {
  609. //
  610. // We have a good user object and have set the quota parameters.
  611. // Get the user's domain, name and full name from the network DC
  612. // using the resolution type specified by the caller.
  613. //
  614. switch(fNameResolution)
  615. {
  616. case DISKQUOTA_USERNAME_RESOLVE_ASYNC:
  617. m_pSidNameResolver->FindUserNameAsync(pIUser);
  618. break;
  619. case DISKQUOTA_USERNAME_RESOLVE_SYNC:
  620. m_pSidNameResolver->FindUserName(pIUser);
  621. break;
  622. case DISKQUOTA_USERNAME_RESOLVE_NONE:
  623. default:
  624. break;
  625. }
  626. }
  627. }
  628. *ppUser = pIUser;
  629. }
  630. }
  631. catch(CAllocException& e)
  632. {
  633. DBGERROR((TEXT("Insufficient memory exception")));
  634. hr = E_OUTOFMEMORY;
  635. }
  636. if (FAILED(hr))
  637. {
  638. *ppUser = NULL;
  639. if (NULL != pIUser)
  640. {
  641. pIUser->Release();
  642. }
  643. }
  644. return hr;
  645. }
  646. STDMETHODIMP
  647. DiskQuotaControl::AddUserName(
  648. LPCWSTR pszLogonName,
  649. DWORD fNameResolution,
  650. PDISKQUOTA_USER *ppUser
  651. )
  652. {
  653. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::AddUserName")));
  654. if (!m_bInitialized)
  655. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  656. if (NULL == pszLogonName || NULL == ppUser)
  657. return E_INVALIDARG;
  658. HRESULT hr = E_FAIL;
  659. try
  660. {
  661. BYTE Sid[MAX_SID_LEN];
  662. DWORD cbSid = sizeof(Sid);
  663. SID_NAME_USE eSidUse;
  664. if (SUCCEEDED(m_NTDS.LookupAccountByName(NULL, // system
  665. pszLogonName, // key
  666. NULL, // no container ret
  667. NULL, // no display name ret
  668. &Sid[0],
  669. &cbSid,
  670. &eSidUse)))
  671. {
  672. hr = AddUserSid(&Sid[0], fNameResolution, ppUser);
  673. }
  674. else
  675. {
  676. hr = HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER);
  677. }
  678. }
  679. catch(CAllocException& e)
  680. {
  681. DBGERROR((TEXT("Insufficient memory exception")));
  682. hr = E_OUTOFMEMORY;
  683. }
  684. return hr;
  685. }
  686. ///////////////////////////////////////////////////////////////////////////////
  687. /* Function: DiskQuotaControl::ShutdownNameResolution
  688. Description: Release the SID/Name resolver. This terminates the
  689. resolver thread for clients who don't want to wait for the controller
  690. object to be destroyed. Note that subsequent calls to CreateEnumUsers,
  691. AddUserSid, AddUserName, FindUserSid or FindUserName can restart
  692. the resolver.
  693. Arguments: None.
  694. Returns: Always returns NOERROR
  695. Revision History:
  696. Date Description Programmer
  697. -------- --------------------------------------------------- ----------
  698. 08/29/97 Initial creation. BrianAu
  699. */
  700. ///////////////////////////////////////////////////////////////////////////////
  701. STDMETHODIMP
  702. DiskQuotaControl::ShutdownNameResolution(
  703. VOID
  704. )
  705. {
  706. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::ShutdownNameResolution")));
  707. if (NULL != m_pSidNameResolver)
  708. {
  709. //
  710. // Shutdown and release the resolver.
  711. // Since it's running on it's own thread, we must wait for the thread
  712. // to exit.
  713. // Note that if the thread is off resolving a name from the DC, this could
  714. // take a bit.
  715. //
  716. m_pSidNameResolver->Shutdown(TRUE); // TRUE == Wait for thread exit.
  717. m_pSidNameResolver->Release();
  718. m_pSidNameResolver = NULL;
  719. }
  720. return NOERROR;
  721. }
  722. ///////////////////////////////////////////////////////////////////////////////
  723. /* Function: DiskQuotaControl::GiveUserNameResolutionPriority
  724. Description: A very long name for a very simple function.
  725. This function merely finds the user object in the name resolver's
  726. input queue and moves it to the head of the queue.
  727. Arguments:
  728. pUser - Address of interface pointer for the user object's
  729. IDiskQuotaUser interface.
  730. Returns:
  731. NOERROR - Success.
  732. S_FALSE - User object not in resolver queue.
  733. E_OUTOFMEMORY - Insufficient memory.
  734. E_INVALIDARG - pUser is NULL.
  735. E_UNEXPECTED - Unexpected error. Caught an exception or the
  736. Sid-Name resolver hasn't been created.
  737. ERROR_NOT_READY (hr) - Object not initialized.
  738. Revision History:
  739. Date Description Programmer
  740. -------- --------------------------------------------------- ----------
  741. 05/18/97 Initial creation. BrianAu
  742. */
  743. ///////////////////////////////////////////////////////////////////////////////
  744. STDMETHODIMP
  745. DiskQuotaControl::GiveUserNameResolutionPriority(
  746. PDISKQUOTA_USER pUser
  747. )
  748. {
  749. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::GiveUserNameResolutionPriority")));
  750. HRESULT hr = E_UNEXPECTED;
  751. if (!m_bInitialized)
  752. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  753. if (NULL == pUser)
  754. return E_INVALIDARG;
  755. //
  756. // SidNameResolver::PromoteUserToQueueHeader catches exceptions and
  757. // converts them to HRESULTs. No need for try-catch block here.
  758. //
  759. if (NULL != m_pSidNameResolver)
  760. {
  761. hr = m_pSidNameResolver->PromoteUserToQueueHead(pUser);
  762. }
  763. return hr;
  764. }
  765. ///////////////////////////////////////////////////////////////////////////////
  766. /* Function: DiskQuotaControl::FindUserSid
  767. Description: Finds a single user record in a volume's quota information
  768. file. Returns an interface to the corresponding user object. When
  769. the caller is finished with the interface, they must call Release()
  770. through that interface pointer.
  771. >>>>>>>>> IMPORTANT NOTE <<<<<<<<<
  772. This method will return a user object even if there is no quota
  773. record for the user in the quota file. While that may sound
  774. strange, it is consistent with the idea of automatic user addition
  775. and default quota settings. If there is currently no user record
  776. for the requested user, and the user would be added to the quota
  777. file if they were to request disk space, the returned user object
  778. will have a quota threshold of 0 and a quota limit of 0.
  779. Arguments:
  780. pSid - Pointer to single SID structure identifying the user.
  781. fNameResolution - Can be one of the following:
  782. DISKQUOTA_USERNAME_RESOLVE_NONE
  783. DISKQUOTA_USERNAME_RESOLVE_SYNC
  784. DISKQUOTA_USERNAME_RESOLVE_ASYNC
  785. ppUser - Address of interface pointer variable to accept pointer to
  786. the user object's IDiskQuotaUser interface.
  787. Returns:
  788. NOERROR - Success.
  789. E_INVALIDARG - Either pSid or ppUser were NULL.
  790. E_OUTOFMEMORY - Insufficient memory.
  791. E_UNEXPECTED - Unexpected exception.
  792. ERROR_INVALID_SID (hr) - Invalid SID.
  793. ERROR_ACCESS_DENIED (hr) - No READ access to quota device.
  794. ERROR_NO_SUCH_USER (hr) - User not found in volume's quota information.
  795. ERROR_NOT_READY (hr) - Object not initialized.
  796. Revision History:
  797. Date Description Programmer
  798. -------- --------------------------------------------------- ----------
  799. 05/22/96 Initial creation. BrianAu
  800. 08/14/96 Changed name from FindUser to FindUserSid to BrianAu
  801. accomodate the addition of the FindUserName
  802. methods. No change in functionality.
  803. 09/05/96 Added exception handling. BrianAu
  804. */
  805. ///////////////////////////////////////////////////////////////////////////////
  806. STDMETHODIMP
  807. DiskQuotaControl::FindUserSid(
  808. PSID pSid,
  809. DWORD fNameResolution,
  810. PDISKQUOTA_USER *ppUser
  811. )
  812. {
  813. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::FindUserSid")));
  814. HRESULT hr = NOERROR;
  815. if (!m_bInitialized)
  816. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  817. if (NULL == pSid || NULL == ppUser)
  818. return E_INVALIDARG;
  819. if (!m_pFSObject->GrantedAccess(GENERIC_READ))
  820. {
  821. hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  822. }
  823. else
  824. {
  825. if (!IsValidSid(pSid))
  826. {
  827. hr = HRESULT_FROM_WIN32(ERROR_INVALID_SID);
  828. }
  829. else
  830. {
  831. PENUM_DISKQUOTA_USERS pEnumUsers = NULL;
  832. try
  833. {
  834. DWORD cbSid = GetLengthSid(pSid);
  835. *ppUser = NULL;
  836. //
  837. // Create a user enumerator for the user's SID.
  838. // Can throw OutOfMemory.
  839. //
  840. hr = CreateEnumUsers(&pSid, 1, fNameResolution, &pEnumUsers);
  841. if (SUCCEEDED(hr))
  842. {
  843. DWORD dwUsersFound = 0;
  844. PDISKQUOTA_USER pUser = NULL;
  845. //
  846. // Enumerate 1 record to get the user's info.
  847. // Only one record required since the enumerator object
  848. // was created from a single SID. Can throw OutOfMemory.
  849. //
  850. hr = pEnumUsers->Next(1, &pUser, &dwUsersFound);
  851. if (S_OK == hr)
  852. {
  853. //
  854. // Return user object interface to caller.
  855. //
  856. *ppUser = pUser;
  857. }
  858. else if (S_FALSE == hr)
  859. {
  860. //
  861. // Note: We should never hit this.
  862. // The quota system always returns a user record
  863. // for a user SID. If the record doesn't currently
  864. // exist, one with default limit and threshold is
  865. // returned. This is consistent with the idea
  866. // of automatic user record addition implemented
  867. // by the NTFS quota system. Just in case we do,
  868. // I want to return something intelligent.
  869. //
  870. hr = HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER);
  871. }
  872. }
  873. }
  874. catch(CAllocException& e)
  875. {
  876. DBGERROR((TEXT("Insufficient memory exception")));
  877. hr = E_OUTOFMEMORY;
  878. }
  879. if (NULL != pEnumUsers)
  880. {
  881. //
  882. // Release the enumerator.
  883. //
  884. pEnumUsers->Release();
  885. }
  886. }
  887. }
  888. return hr;
  889. }
  890. ///////////////////////////////////////////////////////////////////////////////
  891. /* Function: DiskQuotaControl::FindUserName
  892. Description: Finds a single user record in a volume's quota information
  893. file. Returns an interface to the corresponding user object. When
  894. the caller is finished with the interface, they must call Release()
  895. through that interface pointer.
  896. If the name is not already cached in the SidNameCache, the function
  897. queries the network domain controller. This operation may take some
  898. time (on the order of 0 - 10 seconds).
  899. Arguments:
  900. pszLogonName - Address of user's logon name string.
  901. i.e. "REDMOND\brianau" or "[email protected]"
  902. ppUser - Address of interface pointer variable to accept pointer to
  903. the user object's IDiskQuotaUser interface.
  904. Returns:
  905. NOERROR - Success.
  906. E_INVALIDARG - Name string is blank or NUL ptr was passed.
  907. E_OUTOFMEMORY - Insufficient memory.
  908. E_UNEXPECTED - Unexpected exception.
  909. ERROR_ACCESS_DENIED (hr) - No READ access to quota device.
  910. ERROR_NO_SUCH_USER (hr) - User not found in quota file.
  911. ERROR_NOT_READY (hr) - Object not initialized.
  912. Revision History:
  913. Date Description Programmer
  914. -------- --------------------------------------------------- ----------
  915. 08/14/96 Initial creation. BrianAu
  916. 09/05/96 Added domain name string. BrianAu
  917. Added exception handling.
  918. 08/15/97 Removed ANSI version. BrianAu
  919. */
  920. ///////////////////////////////////////////////////////////////////////////////
  921. STDMETHODIMP
  922. DiskQuotaControl::FindUserName(
  923. LPCWSTR pszLogonName,
  924. PDISKQUOTA_USER *ppUser
  925. )
  926. {
  927. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::FindUserName")));
  928. HRESULT hr = E_FAIL; // Assume failure.
  929. BOOL bAskDomainController = TRUE;
  930. if (!m_bInitialized)
  931. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  932. if (NULL == pszLogonName || NULL == ppUser)
  933. return E_INVALIDARG;
  934. if (TEXT('\0') == *pszLogonName)
  935. return E_INVALIDARG;
  936. //
  937. // Check for client's access to quota file before we do any
  938. // time-expensive operations.
  939. //
  940. if (!m_pFSObject->GrantedAccess(GENERIC_READ))
  941. {
  942. hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  943. }
  944. else
  945. {
  946. PSID pSid = NULL; // For cache query.
  947. SID Sid[MAX_SID_LEN]; // For DC query.
  948. //
  949. // These nested try-catch blocks look really gross and may
  950. // be unnecessary. I should probably just punt if one of the
  951. // inner blocks really does throw an exception and return
  952. // E_UNEXPECTED instead of trying to continue. [brianau]
  953. //
  954. try
  955. {
  956. SidNameCache *pSidCache;
  957. hr = SidNameCache_Get(&pSidCache);
  958. if (SUCCEEDED(hr))
  959. {
  960. //
  961. // See if the SID/Name pair is in the cache.
  962. //
  963. try
  964. {
  965. hr = pSidCache->Lookup(pszLogonName, &pSid);
  966. if (SUCCEEDED(hr))
  967. {
  968. //
  969. // We have a SID. No need to ask DC.
  970. //
  971. bAskDomainController = FALSE;
  972. }
  973. }
  974. catch(CAllocException& e)
  975. {
  976. //
  977. // Just catch the exception.
  978. // This will cause us to go to the DC for the SID.
  979. //
  980. DBGERROR((TEXT("C++ exception during SID cache lookup in FindUserName")));
  981. pSid = &Sid[0];
  982. }
  983. }
  984. if (bAskDomainController)
  985. {
  986. DBGASSERT((FAILED(hr)));
  987. //
  988. // Still don't have a SID. Ask the DC.
  989. // This can take some time (Ho Hum.........)
  990. //
  991. CString strDisplayName;
  992. CString strContainerName;
  993. SID_NAME_USE eUse;
  994. DWORD cbSid = sizeof(Sid);
  995. if (SUCCEEDED(m_NTDS.LookupAccountByName(NULL,
  996. pszLogonName,
  997. &strContainerName,
  998. &strDisplayName,
  999. &Sid[0],
  1000. &cbSid,
  1001. &eUse)))
  1002. {
  1003. pSid = &Sid[0];
  1004. //
  1005. // Add it to the cache for later use.
  1006. //
  1007. if (NULL != pSidCache)
  1008. {
  1009. pSidCache->Add(&Sid[0],
  1010. strContainerName,
  1011. pszLogonName,
  1012. strDisplayName);
  1013. }
  1014. hr = NOERROR;
  1015. }
  1016. }
  1017. if (SUCCEEDED(hr))
  1018. {
  1019. //
  1020. // We have a SID.
  1021. // Now create the actual user object using FindUserSid().
  1022. //
  1023. hr = FindUserSid(pSid, DISKQUOTA_USERNAME_RESOLVE_SYNC, ppUser);
  1024. }
  1025. }
  1026. catch(CAllocException& e)
  1027. {
  1028. DBGERROR((TEXT("Insufficient memory exception")));
  1029. hr = E_OUTOFMEMORY;
  1030. }
  1031. if (&Sid[0] != pSid)
  1032. {
  1033. //
  1034. // We received a heap-allocated SID from SidNameCache::Lookup.
  1035. // Need to free the buffer.
  1036. //
  1037. delete[] pSid;
  1038. }
  1039. }
  1040. return hr;
  1041. }
  1042. ///////////////////////////////////////////////////////////////////////////////
  1043. /* Function: DiskQuotaControl::DeleteUser
  1044. Description: Deletes a user from a volume's quota information and quota
  1045. tracking. The IDiskQuotaUser pointer may be obtained either through
  1046. enumeration or DiskQuotaControl::FindUser().
  1047. NOTE: At this time, we're not sure how (or if) deletion will be done.
  1048. This function remains un-implemented until we figure it out.
  1049. Arguments:
  1050. pUser - Pointer to quota user object's IDiskQuotaUser interface.
  1051. Returns:
  1052. NOERROR - Success.
  1053. E_OUTOFMEMORY - Insufficient memory.
  1054. E_UNEXPECTED - Unexpected exception.
  1055. E_FAIL - NTIO error writing user data.
  1056. E_INVALIDARG - pUser argument was NULL.
  1057. ERROR_FILE_EXISTS (hr) - Couldn't delete. User still has bytes charge.
  1058. ERROR_ACCESS_DENIED (hr) - Insufficient access.
  1059. ERROR_NOT_READY (hr) - Object not initialized.
  1060. Revision History:
  1061. Date Description Programmer
  1062. -------- --------------------------------------------------- ----------
  1063. 05/22/96 Initial creation. BrianAu
  1064. 09/28/96 Added implementation. Was E_NOTIMPL. BrianAu
  1065. */
  1066. ///////////////////////////////////////////////////////////////////////////////
  1067. STDMETHODIMP
  1068. DiskQuotaControl::DeleteUser(
  1069. PDISKQUOTA_USER pUser
  1070. )
  1071. {
  1072. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::DeleteUser")));
  1073. HRESULT hr = NOERROR;
  1074. if (!m_bInitialized)
  1075. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  1076. if (NULL == pUser)
  1077. return E_INVALIDARG;
  1078. try
  1079. {
  1080. LONGLONG llValue;
  1081. //
  1082. // Invalidate user object to force a refresh of data from the
  1083. // quota file. Want to make sure this is current information before
  1084. // we tell the caller that the user can't be deleted.
  1085. //
  1086. pUser->Invalidate();
  1087. hr = pUser->GetQuotaUsed(&llValue);
  1088. if (SUCCEEDED(hr))
  1089. {
  1090. if (0 == llValue)
  1091. {
  1092. //
  1093. // User has 0 bytes in use. OK to delete.
  1094. // Write -2 to user's limit and threshold.
  1095. //
  1096. pUser->SetQuotaThreshold(MARK4DEL, TRUE);
  1097. hr = pUser->SetQuotaLimit(MARK4DEL, TRUE);
  1098. }
  1099. else
  1100. {
  1101. hr = HRESULT_FROM_WIN32(ERROR_FILE_EXISTS);
  1102. }
  1103. }
  1104. }
  1105. catch(CAllocException& e)
  1106. {
  1107. DBGERROR((TEXT("Insufficient memory exception")));
  1108. hr = E_OUTOFMEMORY;
  1109. }
  1110. return hr;
  1111. }
  1112. ///////////////////////////////////////////////////////////////////////////////
  1113. /* Function: DiskQuotaControl::QueryQuotaInformation
  1114. Description: Read quota information from disk to member variables.
  1115. Arguments: None.
  1116. Returns:
  1117. NOERROR - Success.
  1118. E_FAIL - Any other error.
  1119. ERROR_ACCESS_DENIED (hr) - No READ access to quota device.
  1120. Revision History:
  1121. Date Description Programmer
  1122. -------- --------------------------------------------------- ----------
  1123. 05/23/96 Initial creation. BrianAu
  1124. */
  1125. ///////////////////////////////////////////////////////////////////////////////
  1126. HRESULT
  1127. DiskQuotaControl::QueryQuotaInformation(
  1128. VOID
  1129. )
  1130. {
  1131. DBGTRACE((DM_CONTROL, DL_LOW, TEXT("DiskQuotaControl::QueryQuotaInformation")));
  1132. HRESULT hr = NOERROR;
  1133. DISKQUOTA_FSOBJECT_INFORMATION Info;
  1134. hr = m_pFSObject->QueryObjectQuotaInformation(&Info);
  1135. if (SUCCEEDED(hr))
  1136. {
  1137. m_llDefaultQuotaThreshold = Info.DefaultQuotaThreshold;
  1138. m_llDefaultQuotaLimit = Info.DefaultQuotaLimit;
  1139. m_dwFlags = (Info.FileSystemControlFlags & DISKQUOTA_FLAGS_MASK);
  1140. }
  1141. return hr;
  1142. }
  1143. ///////////////////////////////////////////////////////////////////////////////
  1144. /* Function: DiskQuotaControl::SetQuotaInformation
  1145. Description: Writes quota information from member variables to disk.
  1146. Arguments:
  1147. dwChangeMask - A bit mask with one or more of the following bits set:
  1148. FSObject::ChangeState
  1149. FSObject::ChangeLogFlags
  1150. FSObject::ChangeThreshold
  1151. FSObject::ChangeLimit
  1152. Returns:
  1153. NOERROR - Success.
  1154. ERROR_ACCESS_DENIED (hr) - No WRITE access to quota device.
  1155. E_FAIL - Any other error.
  1156. Revision History:
  1157. Date Description Programmer
  1158. -------- --------------------------------------------------- ----------
  1159. 05/23/96 Initial creation. BrianAu
  1160. */
  1161. ///////////////////////////////////////////////////////////////////////////////
  1162. HRESULT
  1163. DiskQuotaControl::SetQuotaInformation(
  1164. DWORD dwChangeMask
  1165. )
  1166. {
  1167. DBGTRACE((DM_CONTROL, DL_LOW, TEXT("DiskQuotaControl::SetQuotaInformation")));
  1168. HRESULT hr = NOERROR;
  1169. DISKQUOTA_FSOBJECT_INFORMATION Info;
  1170. Info.DefaultQuotaThreshold = m_llDefaultQuotaThreshold;
  1171. Info.DefaultQuotaLimit = m_llDefaultQuotaLimit;
  1172. Info.FileSystemControlFlags = m_dwFlags;
  1173. hr = m_pFSObject->SetObjectQuotaInformation(&Info, dwChangeMask);
  1174. return hr;
  1175. }
  1176. ///////////////////////////////////////////////////////////////////////////////
  1177. /* Function: DiskQuotaControl::SetDefaultQuotaThreshold
  1178. Description: Sets the default quota threshold value applied to new user
  1179. quota records. Value is in bytes.
  1180. Arguments:
  1181. llThreshold - Threshold value.
  1182. Returns:
  1183. NOERROR - Success.
  1184. ERROR_ACCESS_DENIED (hr) - No WRITE access to quota device.
  1185. ERROR_NOT_READY (hr) - Object not initialized.
  1186. ERROR_INVALID_PARAMETER - llThreshold was less than -2.
  1187. E_FAIL - Any other error.
  1188. Revision History:
  1189. Date Description Programmer
  1190. -------- --------------------------------------------------- ----------
  1191. 05/23/96 Initial creation. BrianAu
  1192. 11/11/98 Added check for value < -2. BrianAu
  1193. */
  1194. ///////////////////////////////////////////////////////////////////////////////
  1195. STDMETHODIMP
  1196. DiskQuotaControl::SetDefaultQuotaThreshold(
  1197. LONGLONG llThreshold
  1198. )
  1199. {
  1200. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::SetDefaultQuotaThreshold")));
  1201. HRESULT hr = NOERROR;
  1202. if (!m_bInitialized)
  1203. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  1204. if (MARK4DEL > llThreshold)
  1205. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  1206. m_llDefaultQuotaThreshold = llThreshold;
  1207. hr = SetQuotaInformation(FSObject::ChangeThreshold);
  1208. return hr;
  1209. }
  1210. ///////////////////////////////////////////////////////////////////////////////
  1211. /* Function: DiskQuotaControl::SetDefaultQuotaLimit
  1212. Description: Sets the default quota limit value applied to new user
  1213. quota records. Value is in bytes.
  1214. Arguments:
  1215. llThreshold - Limit value.
  1216. Returns:
  1217. NOERROR - Success.
  1218. ERROR_ACCESS_DENIED (hr) - No WRITE access to quota device.
  1219. ERORR_NOT_READY (hr) - Object not initialized.
  1220. ERROR_INVALID_PARAMETER - llLimit was less than -2.
  1221. E_FAIL - Any other error.
  1222. Revision History:
  1223. Date Description Programmer
  1224. -------- --------------------------------------------------- ----------
  1225. 05/23/96 Initial creation. BrianAu
  1226. 11/11/98 Added check for value < -2. BrianAu
  1227. */
  1228. ///////////////////////////////////////////////////////////////////////////////
  1229. STDMETHODIMP
  1230. DiskQuotaControl::SetDefaultQuotaLimit(
  1231. LONGLONG llLimit
  1232. )
  1233. {
  1234. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::SetDefaultQuotaLimit")));
  1235. HRESULT hr = NOERROR;
  1236. if (!m_bInitialized)
  1237. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  1238. if (MARK4DEL > llLimit)
  1239. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  1240. m_llDefaultQuotaLimit = llLimit;
  1241. hr = SetQuotaInformation(FSObject::ChangeLimit);
  1242. return hr;
  1243. }
  1244. ///////////////////////////////////////////////////////////////////////////////
  1245. /* Function: DiskQuotaControl::GetDefaultQuotaItem
  1246. Description: Retrieves one of the default quota items (limit, threshold)
  1247. applied to new user quota records. Value is in bytes.
  1248. Arguments:
  1249. pllItem - Address of item (limit, threshold, used) value item to
  1250. retrieve (member variable).
  1251. pllValueOut - Address of LONGLONG variable to receive value.
  1252. Returns:
  1253. NOERROR - Success.
  1254. E_INVALIDARG - pdwLowPart or pdwHighPart is NULL.
  1255. E_UNEXPECTED - Unexpected exception.
  1256. E_OUTOFMEMORY - Insufficient memory.
  1257. ERROR_ACCESS_DENIED (hr) - No READ access to quota device.
  1258. E_FAIL - Any other error.
  1259. Revision History:
  1260. Date Description Programmer
  1261. -------- --------------------------------------------------- ----------
  1262. 05/23/96 Initial creation. BrianAu
  1263. */
  1264. ///////////////////////////////////////////////////////////////////////////////
  1265. HRESULT
  1266. DiskQuotaControl::GetDefaultQuotaItem(
  1267. PLONGLONG pllItem,
  1268. PLONGLONG pllValueOut
  1269. )
  1270. {
  1271. DBGTRACE((DM_CONTROL, DL_LOW, TEXT("DiskQuotaControl::GetDefaultQuotaItem")));
  1272. HRESULT hr = NOERROR;
  1273. if (NULL == pllItem || NULL == pllValueOut)
  1274. return E_INVALIDARG;
  1275. try
  1276. {
  1277. hr = QueryQuotaInformation();
  1278. if (SUCCEEDED(hr))
  1279. {
  1280. *pllValueOut = *pllItem;
  1281. }
  1282. }
  1283. catch(CAllocException& e)
  1284. {
  1285. DBGERROR((TEXT("Insufficient memory exception")));
  1286. hr = E_OUTOFMEMORY;
  1287. }
  1288. return hr;
  1289. }
  1290. ///////////////////////////////////////////////////////////////////////////////
  1291. /* Function: DiskQuotaControl::GetDefaultQuotaThreshold
  1292. Description: Retrieves the default quota threshold applied to new user
  1293. quota records. Value is in bytes.
  1294. Arguments:
  1295. pllThreshold - Address of LONGLONG to receive threshold value.
  1296. Returns:
  1297. NOERROR - Success.
  1298. E_INVALIDARG - pdwLowPart or pdwHighPart is NULL.
  1299. E_UNEXPECTED - Unexpected exception.
  1300. E_OUTOFMEMORY - Insufficient memory.
  1301. ERROR_ACCESS_DENIED (hr) - No READ access to quota device.
  1302. ERROR_NOT_READY (hr) - Object not initialized.
  1303. E_FAIL - Any other error.
  1304. Revision History:
  1305. Date Description Programmer
  1306. -------- --------------------------------------------------- ----------
  1307. 05/23/96 Initial creation. BrianAu
  1308. */
  1309. ///////////////////////////////////////////////////////////////////////////////
  1310. STDMETHODIMP
  1311. DiskQuotaControl::GetDefaultQuotaThreshold(
  1312. PLONGLONG pllThreshold
  1313. )
  1314. {
  1315. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::GetDefaultQuotaThreshold")));
  1316. if (!m_bInitialized)
  1317. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  1318. return GetDefaultQuotaItem(&m_llDefaultQuotaThreshold, pllThreshold);
  1319. }
  1320. STDMETHODIMP
  1321. DiskQuotaControl::GetDefaultQuotaThresholdText(
  1322. LPWSTR pszText,
  1323. DWORD cchText
  1324. )
  1325. {
  1326. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::GetDefaultQuotaThresholdText")));
  1327. if (NULL == pszText)
  1328. return E_INVALIDARG;
  1329. LONGLONG llValue;
  1330. HRESULT hr = GetDefaultQuotaThreshold(&llValue);
  1331. if (SUCCEEDED(hr))
  1332. {
  1333. if (NOLIMIT == llValue)
  1334. {
  1335. LoadString(g_hInstDll, IDS_NO_LIMIT, pszText, cchText);
  1336. }
  1337. else
  1338. {
  1339. XBytes::FormatByteCountForDisplay(llValue, pszText, cchText);
  1340. }
  1341. }
  1342. return hr;
  1343. }
  1344. ///////////////////////////////////////////////////////////////////////////////
  1345. /* Function: DiskQuotaControl::GetDefaultQuotaLimit
  1346. Description: Retrieves the default quota limit applied to new user
  1347. quota records. Value is in bytes.
  1348. Arguments:
  1349. pllThreshold - Address of LONGLONG to receive limit value.
  1350. Returns:
  1351. NOERROR - Success.
  1352. E_INVALIDARG - pdwLowPart or pdwHighPart is NULL.
  1353. E_UNEXPECTED - Unexpected exception.
  1354. E_OUTOFMEMORY - Insufficient memory.
  1355. ERROR_ACCESS_DENIED (hr) - No READ access to quota device.
  1356. ERROR_NOT_READY (hr) - Object not initialized.
  1357. E_FAIL - Any other error. // BUBUG: conflict?
  1358. Revision History:
  1359. Date Description Programmer
  1360. -------- --------------------------------------------------- ----------
  1361. 05/23/96 Initial creation. BrianAu
  1362. */
  1363. ///////////////////////////////////////////////////////////////////////////////
  1364. STDMETHODIMP
  1365. DiskQuotaControl::GetDefaultQuotaLimit(
  1366. PLONGLONG pllLimit
  1367. )
  1368. {
  1369. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::GetDefaultQuotaLimit")));
  1370. if (!m_bInitialized)
  1371. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  1372. return GetDefaultQuotaItem(&m_llDefaultQuotaLimit, pllLimit);
  1373. }
  1374. STDMETHODIMP
  1375. DiskQuotaControl::GetDefaultQuotaLimitText(
  1376. LPWSTR pszText,
  1377. DWORD cchText
  1378. )
  1379. {
  1380. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::GetDefaultQuotaLimitText")));
  1381. if (NULL == pszText)
  1382. return E_INVALIDARG;
  1383. LONGLONG llValue;
  1384. HRESULT hr = GetDefaultQuotaLimit(&llValue);
  1385. if (SUCCEEDED(hr))
  1386. {
  1387. if (NOLIMIT == llValue)
  1388. {
  1389. LoadString(g_hInstDll, IDS_NO_LIMIT, pszText, cchText);
  1390. }
  1391. else
  1392. {
  1393. XBytes::FormatByteCountForDisplay(llValue, pszText, cchText);
  1394. }
  1395. }
  1396. return hr;
  1397. }
  1398. ///////////////////////////////////////////////////////////////////////////////
  1399. /* Function: DiskQuotaControl::GetQuotaState
  1400. Description: Retrieve the state of the quota system.
  1401. Arguments:
  1402. pdwState - Address of DWORD to accept the quota state value.
  1403. Returned value is formatted as follows:
  1404. Bit(s) Definition
  1405. ------- ---------------------------------------------------
  1406. 00-01 0 = Disabled (DISKQUOTA_STATE_DISABLED)
  1407. 1 = Tracking (DISKQUOTA_STATE_TRACK)
  1408. 2 = Enforcing (DISKQUOTA_STATE_ENFORCE)
  1409. 3 = Invalid value.
  1410. 02-07 Reserved
  1411. 08 1 = Quota file incomplete.
  1412. 09 1 = Rebuilding quota file.
  1413. 10-31 Reserved.
  1414. Use the macros defined in dskquota.h to query the
  1415. values and bits in this state DWORD.
  1416. Returns:
  1417. NOERROR - Success.
  1418. E_INVALIDARG - pdwState arg is NULL.
  1419. E_UNEXPECTED - Unexpected exception.
  1420. E_OUTOFMEMORY - Insufficient memory.
  1421. ERROR_ACCESS_DENIED (hr) - No READ access to quota device.
  1422. ERROR_NOT_READY (hr) - Object not initialized.
  1423. E_FAIL - Any other error.
  1424. Revision History:
  1425. Date Description Programmer
  1426. -------- --------------------------------------------------- ----------
  1427. 06/02/96 Initial creation. BrianAu
  1428. 08/19/96 Added DISKQUOTA_FILEFLAG_MASK. BrianAu
  1429. */
  1430. ///////////////////////////////////////////////////////////////////////////////
  1431. STDMETHODIMP
  1432. DiskQuotaControl::GetQuotaState(
  1433. LPDWORD pdwState
  1434. )
  1435. {
  1436. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::GetQuotaState")));
  1437. HRESULT hr = NOERROR;
  1438. if (!m_bInitialized)
  1439. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  1440. if (NULL == pdwState)
  1441. return E_INVALIDARG;
  1442. try
  1443. {
  1444. hr = QueryQuotaInformation();
  1445. if (SUCCEEDED(hr))
  1446. {
  1447. DWORD dwMask = DISKQUOTA_STATE_MASK | DISKQUOTA_FILEFLAG_MASK;
  1448. *pdwState = (m_dwFlags & dwMask);
  1449. }
  1450. }
  1451. catch(CAllocException& e)
  1452. {
  1453. DBGERROR((TEXT("Insufficient memory exception")));
  1454. hr = E_OUTOFMEMORY;
  1455. }
  1456. return hr;
  1457. }
  1458. ///////////////////////////////////////////////////////////////////////////////
  1459. /* Function: DiskQuotaControl::SetQuotaState
  1460. Description: Sets the quota state flags in the volume's quota info file.
  1461. The quota state may be one of the following:
  1462. - Disabled.
  1463. - Tracking quotas (no enforcement).
  1464. - Enforcing quota limits.
  1465. Arguments:
  1466. dwState - New state of quota system. The bits in this DWORD are
  1467. defined as follows:
  1468. Bit(s) Definition
  1469. ------- ---------------------------------------------------
  1470. 00-01 0 = Disabled (DISKQUOTA_STATE_DISABLED)
  1471. 1 = Tracking (DISKQUOTA_STATE_TRACK)
  1472. 2 = Enforcing (DISKQUOTA_STATE_ENFORCE)
  1473. 3 = Invalid value.
  1474. 02-07 Reserved
  1475. 08 1 = Quota file incomplete (read only)
  1476. 09 1 = Rebuilding quota file (read only)
  1477. 10-31 Reserved.
  1478. Use the macros defined in dskquota.h to set the
  1479. values and bits in this state DWORD.
  1480. Returns:
  1481. NOERROR - Success.
  1482. E_INVALIDARG - Invalid state value.
  1483. E_UNEXPECTED - Unexpected exception.
  1484. E_OUTOFMEMORY - Insufficient memory.
  1485. ERROR_ACCESS_DENIED (hr) - No WRITE access to quota device.
  1486. ERROR_NOT_READY (hr) - Object not initialized.
  1487. E_FAIL - Any other error.
  1488. Revision History:
  1489. Date Description Programmer
  1490. -------- --------------------------------------------------- ----------
  1491. 06/02/96 Initial creation. BrianAu
  1492. */
  1493. ///////////////////////////////////////////////////////////////////////////////
  1494. STDMETHODIMP
  1495. DiskQuotaControl::SetQuotaState(
  1496. DWORD dwState
  1497. )
  1498. {
  1499. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::SetQuotaState")));
  1500. HRESULT hr = NOERROR;
  1501. if (!m_bInitialized)
  1502. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  1503. try
  1504. {
  1505. if (dwState <= DISKQUOTA_STATE_MASK)
  1506. {
  1507. m_dwFlags &= ~DISKQUOTA_STATE_MASK; // Clear current state bits.
  1508. m_dwFlags |= dwState; // Set new state bits.
  1509. hr = SetQuotaInformation(FSObject::ChangeState);
  1510. }
  1511. else
  1512. {
  1513. hr = E_INVALIDARG;
  1514. }
  1515. }
  1516. catch(CAllocException& e)
  1517. {
  1518. DBGERROR((TEXT("Insufficient memory exception")));
  1519. hr = E_OUTOFMEMORY;
  1520. }
  1521. return hr;
  1522. }
  1523. ///////////////////////////////////////////////////////////////////////////////
  1524. /* Function: DiskQuotaControl::GetQuotaLogFlags
  1525. Description: Retrieve the state of the quota logging system.
  1526. Arguments:
  1527. pdwFlags - Address of DWORD to accept the quota logging flags.
  1528. The bits in the flags DWORD are defined as follows:
  1529. Bit(s) Definition
  1530. ------- ---------------------------------------------------
  1531. 00 1 = Logging user threshold violations.
  1532. 01 1 = Logging user limit violations.
  1533. 02 1 = Logging volume threshold violations.
  1534. 03 1 = Logging volume limit violations.
  1535. 04-31 Reserved.
  1536. Use the macros defined in dskquota.h to query the
  1537. values and bits in this flags DWORD.
  1538. Returns:
  1539. NOERROR - Success.
  1540. E_INVALIDARG - pdwFlags arg is NULL.
  1541. E_UNEXPECTED - Unexpected exception.
  1542. E_OUTOFMEMORY - Insufficient memory.
  1543. ERROR_ACCESS_DENIED (hr) - No READ access to quota device.
  1544. ERROR_NOT_READY (hr) - Object not initialized.
  1545. E_FAIL - Any other error.
  1546. Revision History:
  1547. Date Description Programmer
  1548. -------- --------------------------------------------------- ----------
  1549. 06/02/96 Initial creation. BrianAu
  1550. */
  1551. ///////////////////////////////////////////////////////////////////////////////
  1552. STDMETHODIMP
  1553. DiskQuotaControl::GetQuotaLogFlags(
  1554. LPDWORD pdwFlags
  1555. )
  1556. {
  1557. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::GetQuotaLogFlags")));
  1558. HRESULT hr = NOERROR;
  1559. if (!m_bInitialized)
  1560. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  1561. if (NULL == pdwFlags)
  1562. return E_INVALIDARG;
  1563. try
  1564. {
  1565. hr = QueryQuotaInformation();
  1566. if (SUCCEEDED(hr))
  1567. {
  1568. *pdwFlags = ((m_dwFlags & DISKQUOTA_LOGFLAG_MASK) >> DISKQUOTA_LOGFLAG_SHIFT);
  1569. }
  1570. }
  1571. catch(CAllocException& e)
  1572. {
  1573. DBGERROR((TEXT("Insufficient memory exception")));
  1574. hr = E_OUTOFMEMORY;
  1575. }
  1576. return hr;
  1577. }
  1578. ///////////////////////////////////////////////////////////////////////////////
  1579. /* Function: DiskQuotaControl::SetQuotaLogFlags
  1580. Description: Sets the quota logging state flags in the volume's quota
  1581. info file.
  1582. Arguments:
  1583. dwFlags - New state of quota logging.
  1584. The bits in the flags DWORD are defined as follows:
  1585. Bit(s) Definition
  1586. ------- ---------------------------------------------------
  1587. 00 1 = Logging user threshold violations.
  1588. 01 1 = Logging user limit violations.
  1589. 02 1 = Logging volume threshold violations.
  1590. 03 1 = Logging volume limit violations.
  1591. 04-31 Reserved.
  1592. Use the macros defined in dskquota.h to set the
  1593. values and bits in this flags DWORD.
  1594. Returns:
  1595. NOERROR - Success.
  1596. E_UNEXPECTED - Unexpected exception.
  1597. E_OUTOFMEMORY - Insufficient memory.
  1598. ERROR_ACCESS_DENIED (hr) - No WRITE access to quota device.
  1599. ERROR_NOT_READY (hr) - Object not initialized.
  1600. E_FAIL - Any other error.
  1601. Revision History:
  1602. Date Description Programmer
  1603. -------- --------------------------------------------------- ----------
  1604. 06/02/96 Initial creation. BrianAu
  1605. */
  1606. ///////////////////////////////////////////////////////////////////////////////
  1607. STDMETHODIMP
  1608. DiskQuotaControl::SetQuotaLogFlags(
  1609. DWORD dwFlags
  1610. )
  1611. {
  1612. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::SetQuotaLogFlags")));
  1613. HRESULT hr = NOERROR;
  1614. if (!m_bInitialized)
  1615. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  1616. try
  1617. {
  1618. m_dwFlags &= ~DISKQUOTA_LOGFLAG_MASK;
  1619. m_dwFlags |= (dwFlags << DISKQUOTA_LOGFLAG_SHIFT);
  1620. hr = SetQuotaInformation(FSObject::ChangeLogFlags);
  1621. }
  1622. catch(CAllocException& e)
  1623. {
  1624. DBGERROR((TEXT("Insufficient memory exception")));
  1625. hr = E_OUTOFMEMORY;
  1626. }
  1627. return hr;
  1628. }
  1629. ///////////////////////////////////////////////////////////////////////////////
  1630. /* Function: DiskQuotaControl::InitConnectionPoints
  1631. Description: Private function for initializing the connection point
  1632. objects supported by IConnectionPointContainer. Called from
  1633. DiskQuotaControl::Initialize(). To add a new connection point
  1634. type, merely add a new record to the m_rgConnPtDesc[] array in the
  1635. DiskQuotaControl class declaration. All of the other related code
  1636. in DiskQuotaControl will adjust to it automatically.
  1637. Arguments: None.
  1638. Returns:
  1639. NOERROR - Success.
  1640. E_UNEXPECTED - A connection point pointer was non-NULL.
  1641. Exceptions: OutOfMemory.
  1642. Revision History:
  1643. Date Description Programmer
  1644. -------- --------------------------------------------------- ----------
  1645. 06/19/96 Initial creation. BrianAu
  1646. 09/05/96 Added exception handling. BrianAu
  1647. */
  1648. ///////////////////////////////////////////////////////////////////////////////
  1649. HRESULT
  1650. DiskQuotaControl::InitConnectionPoints(
  1651. VOID
  1652. )
  1653. {
  1654. DBGTRACE((DM_CONTROL, DL_MID, TEXT("DiskQuotaControl::InitConnectionPoints")));
  1655. if (NULL != m_rgConnPts)
  1656. {
  1657. //
  1658. // Already initialized.
  1659. //
  1660. return NOERROR;
  1661. }
  1662. HRESULT hr = NOERROR;
  1663. ConnectionPoint *pConnPt = NULL;
  1664. m_cConnPts = ARRAYSIZE(m_rgpIConnPtsSupported);
  1665. try
  1666. {
  1667. m_rgConnPts = new PCONNECTIONPOINT[m_cConnPts];
  1668. //
  1669. // For each of the connection point IIDs in m_rgpIConnPtsSupported[]...
  1670. //
  1671. for (UINT i = 0; i < m_cConnPts && SUCCEEDED(hr); i++)
  1672. {
  1673. m_rgConnPts[i] = NULL;
  1674. //
  1675. // Create connection point object and query for IConnectionPoint interface.
  1676. //
  1677. pConnPt = new ConnectionPoint(static_cast<IConnectionPointContainer *>(this),
  1678. *m_rgpIConnPtsSupported[i]);
  1679. hr = pConnPt->QueryInterface(IID_IConnectionPoint, (LPVOID *)&m_rgConnPts[i]);
  1680. if (FAILED(hr))
  1681. {
  1682. //
  1683. // Either Initialize or QI failed.
  1684. //
  1685. delete pConnPt;
  1686. pConnPt = NULL;
  1687. }
  1688. }
  1689. }
  1690. catch(CAllocException& e)
  1691. {
  1692. delete pConnPt;
  1693. hr = E_OUTOFMEMORY;
  1694. }
  1695. return hr;
  1696. }
  1697. ///////////////////////////////////////////////////////////////////////////////
  1698. /* Function: DiskQuotaControl::FindConnectionPoint
  1699. Description: Queries the quota control object for a specific connection
  1700. point type. If that type is supported, a pointer to the connection
  1701. point's IConnectionPoint interface is returned.
  1702. Arguments:
  1703. riid - Interface ID of desired connection point interface.
  1704. Supported interfaces:
  1705. IID_IDiskQuotaUserEvents
  1706. - OnNameChanged()
  1707. Returns:
  1708. NOERROR - Success.
  1709. E_INVALIDARG - ppConnPtOut arg is NULL.
  1710. E_NOINTERFACE - Requested interface is not supported.
  1711. E_UNEXPECTED - Connection point object pointer is NULL.
  1712. Revision History:
  1713. Date Description Programmer
  1714. -------- --------------------------------------------------- ----------
  1715. 06/19/96 Initial creation. BrianAu
  1716. */
  1717. ///////////////////////////////////////////////////////////////////////////////
  1718. STDMETHODIMP
  1719. DiskQuotaControl::FindConnectionPoint(
  1720. REFIID riid,
  1721. IConnectionPoint **ppConnPtOut
  1722. )
  1723. {
  1724. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::FindConnectionPoint")));
  1725. DBGPRINTIID(DM_CONTROL, DL_HIGH, riid);
  1726. HRESULT hr = E_NOINTERFACE;
  1727. if (NULL == ppConnPtOut)
  1728. return E_INVALIDARG;
  1729. *ppConnPtOut = NULL;
  1730. for (UINT i = 0; i < m_cConnPts && NULL == *ppConnPtOut; i++)
  1731. {
  1732. if (*m_rgpIConnPtsSupported[i] == riid)
  1733. {
  1734. if (NULL != m_rgConnPts[i])
  1735. {
  1736. //
  1737. // We have an IID match.
  1738. // Now get the conn pt interface pointer.
  1739. //
  1740. hr = m_rgConnPts[i]->QueryInterface(IID_IConnectionPoint, (LPVOID *)ppConnPtOut);
  1741. }
  1742. else
  1743. {
  1744. hr = E_UNEXPECTED;
  1745. break;
  1746. }
  1747. }
  1748. }
  1749. return hr;
  1750. }
  1751. ///////////////////////////////////////////////////////////////////////////////
  1752. /* Function: DiskQuotaControl::EnumConnectionPoints
  1753. Description: Creates a connection point enumerator object.
  1754. Using this object, the client can enumerate through all of the
  1755. connection point interfaces supported by the quota controller.
  1756. Arguments:
  1757. ppEnum - Address of interface pointer variable to receive the
  1758. IEnumConnectionPoints interface.
  1759. Returns:
  1760. NOERROR - Success.
  1761. E_OUTOFMEMORY - Insufficient memory to create object(s).
  1762. E_INVALIDARG - ppEnum arg was NULL.
  1763. Revision History:
  1764. Date Description Programmer
  1765. -------- --------------------------------------------------- ----------
  1766. 06/19/96 Initial creation. BrianAu
  1767. */
  1768. ///////////////////////////////////////////////////////////////////////////////
  1769. STDMETHODIMP
  1770. DiskQuotaControl::EnumConnectionPoints(
  1771. IEnumConnectionPoints **ppEnum
  1772. )
  1773. {
  1774. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::EnumConnectionPoints")));
  1775. HRESULT hr = NOERROR;
  1776. if (NULL == ppEnum)
  1777. return E_INVALIDARG;
  1778. PCONNECTIONPOINT rgCP[ARRAYSIZE(m_rgpIConnPtsSupported)];
  1779. ConnectionPointEnum *pEnum = NULL;
  1780. *ppEnum = NULL;
  1781. for (UINT i = 0; i < m_cConnPts; i++)
  1782. {
  1783. //
  1784. // Make a copy of each connection point pointer
  1785. // to give to the enumerator's Initialize() method.
  1786. //
  1787. m_rgConnPts[i]->AddRef();
  1788. rgCP[i] = m_rgConnPts[i];
  1789. }
  1790. try
  1791. {
  1792. pEnum = new ConnectionPointEnum(static_cast<IConnectionPointContainer *>(this),
  1793. m_cConnPts, rgCP);
  1794. hr = pEnum->QueryInterface(IID_IEnumConnectionPoints, (LPVOID *)ppEnum);
  1795. }
  1796. catch(CAllocException& e)
  1797. {
  1798. DBGERROR((TEXT("Insufficient memory exception")));
  1799. hr = E_OUTOFMEMORY;
  1800. }
  1801. if (FAILED(hr) && NULL != pEnum)
  1802. {
  1803. delete pEnum;
  1804. *ppEnum = NULL;
  1805. }
  1806. return hr;
  1807. }
  1808. ///////////////////////////////////////////////////////////////////////////////
  1809. /* Function: DiskQuotaControl::InvalidateSidNameCache
  1810. Description: Invalidates the contents of the SidNameCache so that future
  1811. requests for account names from the cache must be resolved through
  1812. the DC. As names are resolved, they are again added to the cache.
  1813. Arguments: None.
  1814. Returns:
  1815. NOERROR - Cache invalidated.
  1816. E_OUTOFMEMORY - Insufficient memory.
  1817. E_UNEXPECTED - Unexpected exception.
  1818. E_FAIL - No cache object available or couldn't get lock on
  1819. cache files. Either way, cache wasn't invalidated.
  1820. ERROR_NOT_READY (hr) - Object not initialized.
  1821. Revision History:
  1822. Date Description Programmer
  1823. -------- --------------------------------------------------- ----------
  1824. 07/24/96 Initial creation. BrianAu
  1825. 09/20/96 Updated for new cache design. BrianAu
  1826. */
  1827. ///////////////////////////////////////////////////////////////////////////////
  1828. STDMETHODIMP
  1829. DiskQuotaControl::InvalidateSidNameCache(
  1830. VOID
  1831. )
  1832. {
  1833. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::InvalidateSidNameCache")));
  1834. if (!m_bInitialized)
  1835. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  1836. SidNameCache *pCache;
  1837. HRESULT hr = SidNameCache_Get(&pCache);
  1838. if (SUCCEEDED(hr))
  1839. {
  1840. if (!pCache->Clear())
  1841. {
  1842. hr = E_FAIL;
  1843. }
  1844. }
  1845. return hr;
  1846. }
  1847. ///////////////////////////////////////////////////////////////////////////////
  1848. /* Function: DiskQuotaControl::NotifyUserNameChanged
  1849. Description: Notify all user IDiskQuotaControl Event connections that a
  1850. user's name has changed.
  1851. Arguments:
  1852. pUser - Address of user object's IDiskQuotaUser interface.
  1853. Returns:
  1854. NOERROR - Success.
  1855. E_OUTOFMEMORY - Insufficient memory to create enumerator.
  1856. Revision History:
  1857. Date Description Programmer
  1858. -------- --------------------------------------------------- ----------
  1859. 07/22/96 Initial creation. BrianAu
  1860. 08/25/97 Added support for IPropertyNotifySink BrianAu
  1861. */
  1862. ///////////////////////////////////////////////////////////////////////////////
  1863. HRESULT
  1864. DiskQuotaControl::NotifyUserNameChanged(
  1865. PDISKQUOTA_USER pUser
  1866. )
  1867. {
  1868. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::NotifyUserNameChanged")));
  1869. HRESULT hr = NOERROR;
  1870. PCONNECTIONPOINT pConnPt = NULL;
  1871. bool bAbort = false;
  1872. INT rgiConnPt[] = { ConnPt_iQuotaEvents,
  1873. ConnPt_iQuotaEventsDisp };
  1874. for (INT i = 0; i < ARRAYSIZE(rgiConnPt) && !bAbort; i++)
  1875. {
  1876. if (NULL != (pConnPt = m_rgConnPts[ rgiConnPt[i] ]))
  1877. {
  1878. PENUMCONNECTIONS pEnum = NULL;
  1879. pConnPt->AddRef();
  1880. hr = pConnPt->EnumConnections(&pEnum);
  1881. if (SUCCEEDED(hr))
  1882. {
  1883. CONNECTDATA cd;
  1884. while(!bAbort && NOERROR == pEnum->Next(1, &cd, NULL))
  1885. {
  1886. DBGASSERT((NULL != cd.pUnk));
  1887. LPUNKNOWN pEventSink = NULL;
  1888. hr = cd.pUnk->QueryInterface(*(m_rgpIConnPtsSupported[ rgiConnPt[i] ]),
  1889. (LPVOID *)&pEventSink);
  1890. //
  1891. // Guard with a critical section mutex. The NT5 quota UI
  1892. // may deadlock after closing the details view window
  1893. // without this critical section. It's possible, other
  1894. // clients of the quota controller could do the same.
  1895. // Here's what happens:
  1896. // The controller calls OnUserNameChanged which
  1897. // is implemented by the DetailsView object. This
  1898. // function updates the details view for the specified
  1899. // quota user. Update involves sending/posting
  1900. // messages to the listview object. On destruction
  1901. // of the listview window (user closing the window),
  1902. // the quota controller is released. If the
  1903. // DetailsView held the last ref count to the
  1904. // controller, the controller commands the SID/Name
  1905. // resolver to shutdown. The resolver's Shutdown
  1906. // command posts a WM_QUIT to the resolver's input
  1907. // queue and blocks until the resolver's thread
  1908. // exits normally. The problem is that the DetailsView
  1909. // thread is blocked waiting for the resolver's thread
  1910. // to exit but the resolver's thread is blocked
  1911. // because the DetailsView thread can't process it's
  1912. // listview update messages. This results in deadlock.
  1913. // This critical section prevents this.
  1914. //
  1915. if (SUCCEEDED(hr))
  1916. {
  1917. if (WAIT_OBJECT_0 != m_mutex.Wait(2000))
  1918. {
  1919. //
  1920. // DiskQuotaControl dtor must own this mutex.
  1921. // Since the control is being destroyed, no sense in
  1922. // continuing.
  1923. //
  1924. DBGERROR((TEXT("Mutex timeout in DiskQuotaControl::NotifyUserNameChanged")));
  1925. bAbort = true;
  1926. }
  1927. else
  1928. {
  1929. AutoLockMutex lock(m_mutex); // Exception-safe release.
  1930. try
  1931. {
  1932. //
  1933. // Calling client code. Handle any exceptions.
  1934. //
  1935. switch(rgiConnPt[i])
  1936. {
  1937. case ConnPt_iQuotaEvents:
  1938. hr = ((PDISKQUOTA_EVENTS)pEventSink)->OnUserNameChanged(pUser);
  1939. break;
  1940. case ConnPt_iQuotaEventsDisp:
  1941. {
  1942. IDispatch *pEventDisp = NULL;
  1943. hr = pEventSink->QueryInterface(IID_IDispatch, (LPVOID *)&pEventDisp);
  1944. if (SUCCEEDED(hr))
  1945. {
  1946. IDispatch *pUserDisp = NULL;
  1947. hr = pUser->QueryInterface(IID_IDispatch, (LPVOID *)&pUserDisp);
  1948. if (SUCCEEDED(hr))
  1949. {
  1950. UINT uArgErr;
  1951. VARIANTARG va;
  1952. DISPPARAMS params;
  1953. VariantClear(&va);
  1954. V_VT(&va) = VT_DISPATCH;
  1955. V_DISPATCH(&va) = pUserDisp;
  1956. params.rgvarg = &va;
  1957. params.rgdispidNamedArgs = NULL;
  1958. params.cArgs = 1;
  1959. params.cNamedArgs = 0;
  1960. hr = pEventDisp->Invoke(DISPID_DISKQUOTAEVENTS_USERNAMECHANGED,
  1961. IID_NULL,
  1962. GetThreadLocale(),
  1963. DISPATCH_METHOD,
  1964. &params,
  1965. NULL,
  1966. NULL,
  1967. &uArgErr);
  1968. if (FAILED(hr))
  1969. {
  1970. DBGERROR((TEXT("Error 0x%08X firing async notification event with IDispatch::Invoke"), hr));
  1971. }
  1972. pUserDisp->Release();
  1973. }
  1974. else
  1975. {
  1976. DBGERROR((TEXT("Error 0x%08X getting IDispatch interface from user object for async notification."), hr));
  1977. }
  1978. pEventDisp->Release();
  1979. }
  1980. else
  1981. {
  1982. DBGERROR((TEXT("Error 0x%08X getting IDispatch interface from connection point for async notification."), hr));
  1983. }
  1984. break;
  1985. }
  1986. default:
  1987. //
  1988. // Shouldn't hit this.
  1989. //
  1990. DBGERROR((TEXT("Invalid connection point ID")));
  1991. break;
  1992. }
  1993. }
  1994. catch(CAllocException& e)
  1995. {
  1996. //
  1997. // Ignore an allocation exception and try to continue.
  1998. //
  1999. }
  2000. }
  2001. pEventSink->Release();
  2002. }
  2003. cd.pUnk->Release();
  2004. }
  2005. pEnum->Release();
  2006. }
  2007. pConnPt->Release();
  2008. }
  2009. }
  2010. return hr;
  2011. }
  2012. DiskQuotaControlDisp::DiskQuotaControlDisp(
  2013. PDISKQUOTA_CONTROL pQC
  2014. ) : m_cRef(0),
  2015. m_pQC(pQC),
  2016. m_pUserEnum(NULL)
  2017. {
  2018. DBGTRACE((DM_CONTROL, DL_MID, TEXT("DiskQuotaControlDisp::DiskQuotaControlDisp")));
  2019. if (NULL != m_pQC)
  2020. {
  2021. m_pQC->AddRef();
  2022. }
  2023. //
  2024. // This is the default resolution style for OLE automation.
  2025. // I've used ASYNC as the default so it won't hang the caller
  2026. // on enumeration if many of the names aren't resolved.
  2027. // If they want sync resolution, they can set the
  2028. // UserNameResolution property.
  2029. //
  2030. m_fOleAutoNameResolution = DISKQUOTA_USERNAME_RESOLVE_ASYNC;
  2031. m_Dispatch.Initialize(static_cast<IDispatch *>(this),
  2032. LIBID_DiskQuotaTypeLibrary,
  2033. IID_DIDiskQuotaControl,
  2034. L"DSKQUOTA.DLL");
  2035. }
  2036. DiskQuotaControlDisp::~DiskQuotaControlDisp(
  2037. VOID
  2038. )
  2039. {
  2040. DBGTRACE((DM_CONTROL, DL_MID, TEXT("DiskQuotaControlDisp::~DiskQuotaControlDisp")));
  2041. if (NULL != m_pUserEnum)
  2042. {
  2043. m_pUserEnum->Release();
  2044. }
  2045. if (NULL != m_pQC)
  2046. {
  2047. m_pQC->Release();
  2048. }
  2049. }
  2050. STDMETHODIMP_(ULONG)
  2051. DiskQuotaControlDisp::AddRef(
  2052. VOID
  2053. )
  2054. {
  2055. DBGTRACE((DM_CONTROL, DL_LOW, TEXT("DiskQuotaControlDisp::AddRef")));
  2056. DBGPRINT((DM_CONTROL, DL_LOW, TEXT("\t0x%08X %d -> %d"),
  2057. this, m_cRef, m_cRef + 1));
  2058. ULONG ulReturn = m_cRef + 1;
  2059. InterlockedIncrement(&m_cRef);
  2060. return ulReturn;
  2061. }
  2062. STDMETHODIMP_(ULONG)
  2063. DiskQuotaControlDisp::Release(
  2064. VOID
  2065. )
  2066. {
  2067. DBGTRACE((DM_CONTROL, DL_LOW, TEXT("DiskQuotaControlDisp::Release")));
  2068. DBGPRINT((DM_CONTROL, DL_LOW, TEXT("\t0x%08X %d -> %d"),
  2069. this, m_cRef, m_cRef - 1));
  2070. ULONG ulReturn = m_cRef - 1;
  2071. if (InterlockedDecrement(&m_cRef) == 0)
  2072. {
  2073. delete this;
  2074. ulReturn = 0;
  2075. }
  2076. return ulReturn;
  2077. }
  2078. STDMETHODIMP
  2079. DiskQuotaControlDisp::QueryInterface(
  2080. REFIID riid,
  2081. LPVOID *ppvOut
  2082. )
  2083. {
  2084. DBGTRACE((DM_CONTROL, DL_MID, TEXT("DiskQuotaControlDisp::QueryInterface")));
  2085. DBGPRINTIID(DM_CONTROL, DL_MID, riid);
  2086. HRESULT hr = E_NOINTERFACE;
  2087. if (NULL == ppvOut)
  2088. return E_INVALIDARG;
  2089. *ppvOut = NULL;
  2090. if (IID_IUnknown == riid)
  2091. {
  2092. *ppvOut = this;
  2093. }
  2094. else if (IID_IDispatch == riid)
  2095. {
  2096. *ppvOut = static_cast<IDispatch *>(this);
  2097. }
  2098. else if (IID_DIDiskQuotaControl == riid)
  2099. {
  2100. *ppvOut = static_cast<DIDiskQuotaControl *>(this);
  2101. }
  2102. else if (IID_IDiskQuotaControl == riid ||
  2103. IID_IConnectionPointContainer == riid)
  2104. {
  2105. //
  2106. // Return the quota controller's vtable interface.
  2107. // This allows code to "typecast" (COM-style) between
  2108. // the dispatch interface and vtable interface.
  2109. //
  2110. return m_pQC->QueryInterface(riid, ppvOut);
  2111. }
  2112. if (NULL != *ppvOut)
  2113. {
  2114. ((LPUNKNOWN)*ppvOut)->AddRef();
  2115. hr = NOERROR;
  2116. }
  2117. return hr;
  2118. }
  2119. //
  2120. // IDispatch::GetIDsOfNames
  2121. //
  2122. STDMETHODIMP
  2123. DiskQuotaControlDisp::GetIDsOfNames(
  2124. REFIID riid,
  2125. OLECHAR **rgszNames,
  2126. UINT cNames,
  2127. LCID lcid,
  2128. DISPID *rgDispId
  2129. )
  2130. {
  2131. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::GetIDsOfNames")));
  2132. //
  2133. // Let our dispatch object handle this.
  2134. //
  2135. return m_Dispatch.GetIDsOfNames(riid,
  2136. rgszNames,
  2137. cNames,
  2138. lcid,
  2139. rgDispId);
  2140. }
  2141. //
  2142. // IDispatch::GetTypeInfo
  2143. //
  2144. STDMETHODIMP
  2145. DiskQuotaControlDisp::GetTypeInfo(
  2146. UINT iTInfo,
  2147. LCID lcid,
  2148. ITypeInfo **ppTypeInfo
  2149. )
  2150. {
  2151. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::GetTypeInfo")));
  2152. //
  2153. // Let our dispatch object handle this.
  2154. //
  2155. return m_Dispatch.GetTypeInfo(iTInfo, lcid, ppTypeInfo);
  2156. }
  2157. //
  2158. // IDispatch::GetTypeInfoCount
  2159. //
  2160. STDMETHODIMP
  2161. DiskQuotaControlDisp::GetTypeInfoCount(
  2162. UINT *pctinfo
  2163. )
  2164. {
  2165. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::GetTypeInfoCount")));
  2166. //
  2167. // Let our dispatch object handle this.
  2168. //
  2169. return m_Dispatch.GetTypeInfoCount(pctinfo);
  2170. }
  2171. //
  2172. // IDispatch::Invoke
  2173. //
  2174. STDMETHODIMP
  2175. DiskQuotaControlDisp::Invoke(
  2176. DISPID dispIdMember,
  2177. REFIID riid,
  2178. LCID lcid,
  2179. WORD wFlags,
  2180. DISPPARAMS *pDispParams,
  2181. VARIANT *pVarResult,
  2182. EXCEPINFO *pExcepInfo,
  2183. UINT *puArgErr
  2184. )
  2185. {
  2186. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::Invoke")));
  2187. //
  2188. // Let our dispatch object handle this.
  2189. //
  2190. return m_Dispatch.Invoke(dispIdMember,
  2191. riid,
  2192. lcid,
  2193. wFlags,
  2194. pDispParams,
  2195. pVarResult,
  2196. pExcepInfo,
  2197. puArgErr);
  2198. }
  2199. //
  2200. // Dispatch property "QuotaState" (put)
  2201. //
  2202. // Sets the state of the quota system on the volume.
  2203. // See DiskQuotaControl::SetQuotaState for details.
  2204. //
  2205. // Valid states: 0 = Disabled.
  2206. // 1 = Tracking
  2207. // 2 = Enforcing
  2208. STDMETHODIMP
  2209. DiskQuotaControlDisp::put_QuotaState(
  2210. QuotaStateConstants State
  2211. )
  2212. {
  2213. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::put_QuotaState")));
  2214. if (dqStateMaxValue < State)
  2215. {
  2216. //
  2217. // State can only be 0, 1 or 2.
  2218. //
  2219. return E_INVALIDARG;
  2220. }
  2221. //
  2222. // No exception handling required.
  2223. // DiskQuotaControl::SetQuotaState handles exceptions.
  2224. //
  2225. return m_pQC->SetQuotaState(State);
  2226. }
  2227. //
  2228. // Dispatch property "QuotaState" (get)
  2229. //
  2230. // Retrieves the state of the quota system on the volume.
  2231. // See DiskQuotaControl::GetQuotaState for details.
  2232. //
  2233. // State returned: 0 = Disabled.
  2234. // 1 = Tracking
  2235. // 2 = Enforcing
  2236. //
  2237. STDMETHODIMP
  2238. DiskQuotaControlDisp::get_QuotaState(
  2239. QuotaStateConstants *pState
  2240. )
  2241. {
  2242. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::get_QuotaState")));
  2243. DWORD dwState;
  2244. //
  2245. // No exception handling required.
  2246. // DiskQuotaControl::GetQuotaState handles exceptions.
  2247. //
  2248. HRESULT hr = m_pQC->GetQuotaState(&dwState);
  2249. if (SUCCEEDED(hr))
  2250. {
  2251. *pState = (QuotaStateConstants)(dwState & DISKQUOTA_STATE_MASK);
  2252. }
  2253. return hr;
  2254. }
  2255. //
  2256. // Dispatch property "QuotaFileIncomplete" (get)
  2257. //
  2258. // Determines if the state of the quota file is "incomplete".
  2259. //
  2260. STDMETHODIMP
  2261. DiskQuotaControlDisp::get_QuotaFileIncomplete(
  2262. VARIANT_BOOL *pbIncomplete
  2263. )
  2264. {
  2265. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::get_QuotaFileIncomplete")));
  2266. DWORD dwState;
  2267. //
  2268. // No exception handling required.
  2269. // DiskQuotaControl::GetQuotaState handles exceptions.
  2270. //
  2271. HRESULT hr = m_pQC->GetQuotaState(&dwState);
  2272. if (SUCCEEDED(hr))
  2273. {
  2274. *pbIncomplete = DISKQUOTA_FILE_INCOMPLETE(dwState) ? VARIANT_TRUE : VARIANT_FALSE;
  2275. }
  2276. return hr;
  2277. }
  2278. //
  2279. // Dispatch property "QuotaFileRebuilding" (get)
  2280. //
  2281. // Determines if the state of the quota file is "rebuilding".
  2282. //
  2283. STDMETHODIMP
  2284. DiskQuotaControlDisp::get_QuotaFileRebuilding(
  2285. VARIANT_BOOL *pbRebuilding
  2286. )
  2287. {
  2288. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::get_QuotaFileRebuilding")));
  2289. DWORD dwState;
  2290. //
  2291. // No exception handling required.
  2292. // DiskQuotaControl::GetQuotaState handles exceptions.
  2293. //
  2294. HRESULT hr = m_pQC->GetQuotaState(&dwState);
  2295. if (SUCCEEDED(hr))
  2296. {
  2297. *pbRebuilding = DISKQUOTA_FILE_REBUILDING(dwState) ? VARIANT_TRUE : VARIANT_FALSE;
  2298. }
  2299. return hr;
  2300. }
  2301. //
  2302. // Dispatch property "LogQuotaThreshold" (put)
  2303. //
  2304. // Sets the "log warning threshold" flag on the volume.
  2305. //
  2306. STDMETHODIMP
  2307. DiskQuotaControlDisp::put_LogQuotaThreshold(
  2308. VARIANT_BOOL bLog
  2309. )
  2310. {
  2311. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::put_LogQuotaThreshold")));
  2312. DWORD dwFlags;
  2313. //
  2314. // No exception handling required.
  2315. // DiskQuotaControl::GetQuotaLogFlags and SetQuotaLogFlags handle
  2316. // exceptions.
  2317. //
  2318. HRESULT hr = m_pQC->GetQuotaLogFlags(&dwFlags);
  2319. if (SUCCEEDED(hr))
  2320. {
  2321. hr = m_pQC->SetQuotaLogFlags(DISKQUOTA_SET_LOG_USER_THRESHOLD(dwFlags, VARIANT_TRUE == bLog));
  2322. }
  2323. return hr;
  2324. }
  2325. //
  2326. // Dispatch property "LogQuotaThreshold" (get)
  2327. //
  2328. // Retrieves the "log warning threshold" flag on the volume.
  2329. //
  2330. STDMETHODIMP
  2331. DiskQuotaControlDisp::get_LogQuotaThreshold(
  2332. VARIANT_BOOL *pbLog
  2333. )
  2334. {
  2335. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::get_LogQuotaThreshold")));
  2336. DWORD dwFlags;
  2337. //
  2338. // No exception handling required.
  2339. // DiskQuotaControl::GetQuotaLogFlags handles exceptions.
  2340. //
  2341. HRESULT hr = m_pQC->GetQuotaLogFlags(&dwFlags);
  2342. if (SUCCEEDED(hr))
  2343. {
  2344. *pbLog = DISKQUOTA_IS_LOGGED_USER_THRESHOLD(dwFlags) ? VARIANT_TRUE : VARIANT_FALSE;
  2345. }
  2346. return hr;
  2347. }
  2348. //
  2349. // Dispatch property "LogQuotaLimit" (put)
  2350. //
  2351. // Sets the "log quota limit" flag on the volume.
  2352. //
  2353. STDMETHODIMP
  2354. DiskQuotaControlDisp::put_LogQuotaLimit(
  2355. VARIANT_BOOL bLog
  2356. )
  2357. {
  2358. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::put_LogQuotaLimit")));
  2359. DWORD dwFlags;
  2360. //
  2361. // No exception handling required.
  2362. // DiskQuotaControl::GetQuotaLogFlags handles exceptions.
  2363. //
  2364. HRESULT hr = m_pQC->GetQuotaLogFlags(&dwFlags);
  2365. if (SUCCEEDED(hr))
  2366. {
  2367. hr = m_pQC->SetQuotaLogFlags(DISKQUOTA_SET_LOG_USER_LIMIT(dwFlags, VARIANT_TRUE == bLog));
  2368. }
  2369. return hr;
  2370. }
  2371. //
  2372. // Dispatch property "LogQuotaLimit" (get)
  2373. //
  2374. // Retrieves the "log quota limit" flag on the volume.
  2375. //
  2376. STDMETHODIMP
  2377. DiskQuotaControlDisp::get_LogQuotaLimit(
  2378. VARIANT_BOOL *pbLog
  2379. )
  2380. {
  2381. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::get_LogQuotaLimit")));
  2382. DWORD dwFlags;
  2383. //
  2384. // No exception handling required.
  2385. // DiskQuotaControl::GetQuotaLogFlags handles exceptions.
  2386. //
  2387. HRESULT hr = m_pQC->GetQuotaLogFlags(&dwFlags);
  2388. if (SUCCEEDED(hr))
  2389. {
  2390. *pbLog = DISKQUOTA_IS_LOGGED_USER_LIMIT(dwFlags) ? VARIANT_TRUE : VARIANT_FALSE;
  2391. }
  2392. return hr;
  2393. }
  2394. //
  2395. // Dispatch property "DefaultQuotaThreshold" (put)
  2396. //
  2397. // Sets the default quota threshold on the volume.
  2398. //
  2399. STDMETHODIMP
  2400. DiskQuotaControlDisp::put_DefaultQuotaThreshold(
  2401. double Threshold
  2402. )
  2403. {
  2404. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::put_DefaultQuotaThreshold")));
  2405. if (MAXLONGLONG < Threshold)
  2406. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  2407. //
  2408. // No exception handling required.
  2409. // DiskQuotaControl::GetDefaultQuotaThreshold handles exceptions.
  2410. //
  2411. return m_pQC->SetDefaultQuotaThreshold((LONGLONG)Threshold);
  2412. }
  2413. //
  2414. // Dispatch property "DefaultQuotaThreshold" (get)
  2415. //
  2416. // Retrieves the default quota threshold on the volume.
  2417. //
  2418. STDMETHODIMP
  2419. DiskQuotaControlDisp::get_DefaultQuotaThreshold(
  2420. double *pThreshold
  2421. )
  2422. {
  2423. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::get_DefaultQuotaThreshold")));
  2424. LONGLONG llTemp;
  2425. //
  2426. // No exception handling required.
  2427. // DiskQuotaControl::GetDefaultQuotaThreshold handles exceptions.
  2428. //
  2429. HRESULT hr = m_pQC->GetDefaultQuotaThreshold(&llTemp);
  2430. if (SUCCEEDED(hr))
  2431. {
  2432. *pThreshold = (double)llTemp;
  2433. }
  2434. return hr;
  2435. }
  2436. STDMETHODIMP
  2437. DiskQuotaControlDisp::get_DefaultQuotaThresholdText(
  2438. BSTR *pThresholdText
  2439. )
  2440. {
  2441. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::get_DefaultQuotaThresholdText")));
  2442. TCHAR szValue[40];
  2443. HRESULT hr;
  2444. hr = m_pQC->GetDefaultQuotaThresholdText(szValue, ARRAYSIZE(szValue));
  2445. if (SUCCEEDED(hr))
  2446. {
  2447. *pThresholdText = SysAllocString(szValue);
  2448. if (NULL == *pThresholdText)
  2449. {
  2450. hr = E_OUTOFMEMORY;
  2451. }
  2452. }
  2453. return hr;
  2454. }
  2455. //
  2456. // Dispatch property "DefaultQuotaLimit" (put)
  2457. //
  2458. // Sets the default quota limit on the volume.
  2459. //
  2460. STDMETHODIMP
  2461. DiskQuotaControlDisp::put_DefaultQuotaLimit(
  2462. double Limit
  2463. )
  2464. {
  2465. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::put_DefaultQuotaLimit")));
  2466. if (MAXLONGLONG < Limit)
  2467. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  2468. //
  2469. // No exception handling required.
  2470. // DiskQuotaControl::SetDefaultQuotaLimit handles exceptions.
  2471. //
  2472. return m_pQC->SetDefaultQuotaLimit((LONGLONG)Limit);
  2473. }
  2474. //
  2475. // Dispatch property "DefaultQuotaLimit" (get)
  2476. //
  2477. // Retrieves the default quota limit on the volume.
  2478. //
  2479. STDMETHODIMP
  2480. DiskQuotaControlDisp::get_DefaultQuotaLimit(
  2481. double *pLimit
  2482. )
  2483. {
  2484. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::get_DefaultQuotaLimit")));
  2485. LONGLONG llTemp;
  2486. //
  2487. // No exception handling required.
  2488. // DiskQuotaControl::GetDefaultQuotaLimit handles exceptions.
  2489. //
  2490. HRESULT hr = m_pQC->GetDefaultQuotaLimit(&llTemp);
  2491. if (SUCCEEDED(hr))
  2492. {
  2493. *pLimit = (double)llTemp;
  2494. }
  2495. return hr;
  2496. }
  2497. STDMETHODIMP
  2498. DiskQuotaControlDisp::get_DefaultQuotaLimitText(
  2499. BSTR *pLimitText
  2500. )
  2501. {
  2502. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::get_DefaultQuotaLimitText")));
  2503. TCHAR szValue[40];
  2504. HRESULT hr = m_pQC->GetDefaultQuotaLimitText(szValue, ARRAYSIZE(szValue));
  2505. if (SUCCEEDED(hr))
  2506. {
  2507. *pLimitText = SysAllocString(szValue);
  2508. if (NULL == *pLimitText)
  2509. {
  2510. hr = E_OUTOFMEMORY;
  2511. }
  2512. }
  2513. return hr;
  2514. }
  2515. STDMETHODIMP
  2516. DiskQuotaControlDisp::put_UserNameResolution(
  2517. UserNameResolutionConstants ResolutionType
  2518. )
  2519. {
  2520. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::put_UserNameResolution")));
  2521. if (dqResolveMaxValue < ResolutionType)
  2522. {
  2523. return E_INVALIDARG;
  2524. }
  2525. m_fOleAutoNameResolution = (DWORD)ResolutionType;
  2526. return NOERROR;
  2527. }
  2528. STDMETHODIMP
  2529. DiskQuotaControlDisp::get_UserNameResolution(
  2530. UserNameResolutionConstants *pResolutionType
  2531. )
  2532. {
  2533. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::get_UserNameResolution")));
  2534. if (NULL == pResolutionType)
  2535. return E_INVALIDARG;
  2536. *pResolutionType = (UserNameResolutionConstants)m_fOleAutoNameResolution;
  2537. return NOERROR;
  2538. }
  2539. //
  2540. // Dispatch method "Initialize"
  2541. //
  2542. // Initializes the quota control object for a given path and
  2543. // access mode. See DiskQuotaControl::Initialize for details.
  2544. //
  2545. STDMETHODIMP
  2546. DiskQuotaControlDisp::Initialize(
  2547. BSTR path,
  2548. VARIANT_BOOL bReadWrite
  2549. )
  2550. {
  2551. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::Initialize")));
  2552. //
  2553. // No exception handling required.
  2554. // DiskQuotaControl::Initialize handles exceptions.
  2555. //
  2556. return m_pQC->Initialize(reinterpret_cast<LPCWSTR>(path), VARIANT_TRUE == bReadWrite);
  2557. }
  2558. //
  2559. // Dispatch method "AddUser"
  2560. //
  2561. // Adds new user quota record.
  2562. // See DiskQuotaControl::AddUserName for details.
  2563. //
  2564. STDMETHODIMP
  2565. DiskQuotaControlDisp::AddUser(
  2566. BSTR LogonName,
  2567. DIDiskQuotaUser **ppUser
  2568. )
  2569. {
  2570. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::AddUser")));
  2571. //
  2572. // No exception handling required.
  2573. // DiskQuotaControl::AddUserName handles exceptions.
  2574. //
  2575. PDISKQUOTA_USER pUser = NULL;
  2576. HRESULT hr = m_pQC->AddUserName(reinterpret_cast<LPCWSTR>(LogonName),
  2577. m_fOleAutoNameResolution,
  2578. &pUser);
  2579. if (SUCCEEDED(hr))
  2580. {
  2581. //
  2582. // Retrieve the user object's IDispatch interface.
  2583. //
  2584. hr = pUser->QueryInterface(IID_IDispatch, (LPVOID *)ppUser);
  2585. pUser->Release();
  2586. }
  2587. return hr;
  2588. }
  2589. //
  2590. // Dispatch method "DeleteUser"
  2591. //
  2592. // Marks a user quota record for deletion.
  2593. // See DiskQuotaControl::DeleteUser for details.
  2594. //
  2595. STDMETHODIMP
  2596. DiskQuotaControlDisp::DeleteUser(
  2597. DIDiskQuotaUser *pUser
  2598. )
  2599. {
  2600. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::DeleteUser")));
  2601. HRESULT hr = E_INVALIDARG;
  2602. if (NULL != pUser)
  2603. {
  2604. //
  2605. // No exception handling required.
  2606. // DiskQuotaControl::DeleteUser handles exceptions.
  2607. //
  2608. PDISKQUOTA_USER pUserToDelete = NULL;
  2609. hr = pUser->QueryInterface(IID_IDiskQuotaUser, (LPVOID *)&pUserToDelete);
  2610. if (SUCCEEDED(hr))
  2611. {
  2612. hr = m_pQC->DeleteUser(pUserToDelete);
  2613. pUserToDelete->Release();
  2614. }
  2615. }
  2616. return hr;
  2617. }
  2618. //
  2619. // Dispatch method "FindUser"
  2620. //
  2621. // Locates a user quota entry based on the user's name strings.
  2622. // Creates a corresponding user object and returns it to the caller.
  2623. // See DiskQuotaControl::FindUserName for details.
  2624. //
  2625. STDMETHODIMP
  2626. DiskQuotaControlDisp::FindUser(
  2627. BSTR LogonName,
  2628. DIDiskQuotaUser **ppUser
  2629. )
  2630. {
  2631. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::FindUser")));
  2632. //
  2633. // No exception handling required.
  2634. // DiskQuotaControl::FindUserName handles exceptions.
  2635. //
  2636. HRESULT hr = NOERROR;
  2637. LPCWSTR pszName = reinterpret_cast<LPCWSTR>(LogonName);
  2638. PSID psid = NULL;
  2639. PDISKQUOTA_USER pUser = NULL;
  2640. if (ConvertStringSidToSid(pszName, &psid))
  2641. {
  2642. hr = m_pQC->FindUserSid(psid,
  2643. m_fOleAutoNameResolution,
  2644. &pUser);
  2645. LocalFree(psid);
  2646. psid = NULL;
  2647. }
  2648. else
  2649. {
  2650. hr = m_pQC->FindUserName(pszName, &pUser);
  2651. }
  2652. if (SUCCEEDED(hr))
  2653. {
  2654. DBGASSERT((NULL != pUser));
  2655. //
  2656. // Query for the user's IDispatch interface and release the pointer
  2657. // we received from FindUserName.
  2658. //
  2659. hr = pUser->QueryInterface(IID_IDispatch, (LPVOID *)ppUser);
  2660. pUser->Release();
  2661. }
  2662. return hr;
  2663. }
  2664. //
  2665. // Dispatch method "InvalidateSidNameCache"
  2666. //
  2667. // Invalidates the SID/Name cache.
  2668. // See DiskQuotaControl::InvalidateSidNameCache for details.
  2669. //
  2670. STDMETHODIMP
  2671. DiskQuotaControlDisp::InvalidateSidNameCache(
  2672. void
  2673. )
  2674. {
  2675. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::InvalidateSidNameCache")));
  2676. //
  2677. // No exception handling required.
  2678. // DiskQuotaControl::InvalidateSidNameCache handles exceptions.
  2679. //
  2680. return m_pQC->InvalidateSidNameCache();
  2681. }
  2682. //
  2683. // Dispatch method "GiveUserNameResolutionPriority"
  2684. //
  2685. // Promotes a user object to the front of the SID/Name resolver's input queue.
  2686. // See DiskQuotaControl::GiveUserNameResolutionPriority.
  2687. //
  2688. STDMETHODIMP
  2689. DiskQuotaControlDisp::GiveUserNameResolutionPriority(
  2690. DIDiskQuotaUser *pUser
  2691. )
  2692. {
  2693. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::GiveUserNameResolutionPriority")));
  2694. HRESULT hr = E_INVALIDARG;
  2695. if (NULL != pUser)
  2696. {
  2697. //
  2698. // No exception handling required.
  2699. // DiskQuotaControl::GiveUserNameResolutionPriority handles exceptions.
  2700. //
  2701. PDISKQUOTA_USER pUserToPromote = NULL;
  2702. hr = pUser->QueryInterface(IID_IDiskQuotaUser, (LPVOID *)&pUserToPromote);
  2703. if (SUCCEEDED(hr))
  2704. {
  2705. hr = m_pQC->GiveUserNameResolutionPriority(pUserToPromote);
  2706. pUserToPromote->Release();
  2707. }
  2708. }
  2709. return hr;
  2710. }
  2711. //
  2712. // This function is called by an automation controller when a new enumerator is
  2713. // required. In particular, Visual Basic calls it when it encounters a
  2714. // "for each" loop. The name "_NewEnum" is hard-wired and can't change.
  2715. //
  2716. STDMETHODIMP
  2717. DiskQuotaControlDisp::_NewEnum(
  2718. IDispatch **ppEnum
  2719. )
  2720. {
  2721. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::_NewEnum")));
  2722. HRESULT hr = E_INVALIDARG;
  2723. if (NULL != ppEnum)
  2724. {
  2725. try
  2726. {
  2727. //
  2728. // Create a Collection object using the current settings for
  2729. // name resolution.
  2730. //
  2731. DiskQuotaUserCollection *pCollection = new DiskQuotaUserCollection(m_pQC,
  2732. m_fOleAutoNameResolution);
  2733. hr = pCollection->Initialize();
  2734. if (SUCCEEDED(hr))
  2735. {
  2736. //
  2737. // The caller of _NewEnum (probably VB) wants the IEnumVARIANT
  2738. // interface.
  2739. //
  2740. hr = pCollection->QueryInterface(IID_IEnumVARIANT, (LPVOID *)ppEnum);
  2741. }
  2742. else
  2743. {
  2744. delete pCollection;
  2745. }
  2746. }
  2747. catch(CAllocException& e)
  2748. {
  2749. DBGERROR((TEXT("Insufficient memory exception")));
  2750. hr = E_OUTOFMEMORY;
  2751. }
  2752. }
  2753. return hr;
  2754. }
  2755. //
  2756. // Shutdown the SID/Name resolver. Note that this happens automatically
  2757. // when the control object is destroyed.
  2758. //
  2759. STDMETHODIMP
  2760. DiskQuotaControlDisp::ShutdownNameResolution(
  2761. VOID
  2762. )
  2763. {
  2764. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::ShutdownNameResolution")));
  2765. return m_pQC->ShutdownNameResolution();
  2766. }
  2767. //
  2768. // Given a logon name in SAM-compatible or UPN format, translate
  2769. // the name to the corresponding account's SID. The returned SID is
  2770. // formatted as a string.
  2771. //
  2772. STDMETHODIMP
  2773. DiskQuotaControlDisp::TranslateLogonNameToSID(
  2774. BSTR LogonName,
  2775. BSTR *psid
  2776. )
  2777. {
  2778. NTDS ntds;
  2779. BYTE sid[MAX_SID_LEN];
  2780. SID_NAME_USE eSidUse;
  2781. DWORD cbSid = ARRAYSIZE(sid);
  2782. HRESULT hr = ntds.LookupAccountByName(NULL,
  2783. reinterpret_cast<LPCWSTR>(LogonName),
  2784. NULL,
  2785. NULL,
  2786. sid,
  2787. &cbSid,
  2788. &eSidUse);
  2789. if (SUCCEEDED(hr))
  2790. {
  2791. LPTSTR pszSid = NULL;
  2792. if (ConvertSidToStringSid((PSID)sid, &pszSid))
  2793. {
  2794. *psid = SysAllocString(pszSid);
  2795. if (NULL == *psid)
  2796. {
  2797. hr = E_OUTOFMEMORY;
  2798. }
  2799. LocalFree(pszSid);
  2800. pszSid = NULL;
  2801. }
  2802. else
  2803. {
  2804. hr = HRESULT_FROM_WIN32(GetLastError());
  2805. }
  2806. }
  2807. return hr;
  2808. }