Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3316 lines
107 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. ASSERT( 0 != g_cRefThisDll );
  116. InterlockedDecrement(&g_cRefThisDll);
  117. }
  118. ///////////////////////////////////////////////////////////////////////////////
  119. /* Function: DiskQuotaControl::QueryInterface
  120. Description: Returns an interface pointer to the object's IUnknown,
  121. IDiskQuotaControl or IConnectionPointContainer interface. The object
  122. referenced by the returned interface pointer is uninitialized. The
  123. recipient of the pointer must call Initialize() before the object is
  124. usable.
  125. Arguments:
  126. riid - Reference to requested interface ID.
  127. ppvOut - Address of interface pointer variable to accept interface ptr.
  128. Returns:
  129. NOERROR - Success.
  130. E_NOINTERFACE - Requested interface not supported.
  131. E_INVALIDARG - ppvOut argument was NULL.
  132. Revision History:
  133. Date Description Programmer
  134. -------- --------------------------------------------------- ----------
  135. 05/22/96 Initial creation. BrianAu
  136. */
  137. ///////////////////////////////////////////////////////////////////////////////
  138. STDMETHODIMP
  139. DiskQuotaControl::QueryInterface(
  140. REFIID riid,
  141. LPVOID *ppvOut
  142. )
  143. {
  144. DBGTRACE((DM_CONTROL, DL_MID, TEXT("DiskQuotaControl::QueryInterface")));
  145. DBGPRINTIID(DM_CONTROL, DL_MID, riid);
  146. if (NULL == ppvOut)
  147. return E_INVALIDARG;
  148. HRESULT hr = E_NOINTERFACE;
  149. try
  150. {
  151. *ppvOut = NULL;
  152. if (IID_IUnknown == riid ||
  153. IID_IDiskQuotaControl == riid)
  154. {
  155. *ppvOut = this;
  156. }
  157. else if (IID_IConnectionPointContainer == riid)
  158. {
  159. hr = InitConnectionPoints();
  160. if (SUCCEEDED(hr))
  161. {
  162. *ppvOut = static_cast<IConnectionPointContainer *>(this);
  163. }
  164. }
  165. else if (IID_IDispatch == riid ||
  166. IID_DIDiskQuotaControl == riid)
  167. {
  168. DiskQuotaControlDisp *pQCDisp = new DiskQuotaControlDisp(static_cast<PDISKQUOTA_CONTROL>(this));
  169. *ppvOut = static_cast<DIDiskQuotaControl *>(pQCDisp);
  170. }
  171. if (NULL != *ppvOut)
  172. {
  173. ((LPUNKNOWN)*ppvOut)->AddRef();
  174. hr = NOERROR;
  175. }
  176. }
  177. catch(CAllocException& e)
  178. {
  179. DBGERROR((TEXT("Insufficient memory exception")));
  180. *ppvOut = NULL;
  181. hr = E_OUTOFMEMORY;
  182. }
  183. return hr;
  184. }
  185. ///////////////////////////////////////////////////////////////////////////////
  186. /* Function: DiskQuotaControl::AddRef
  187. Description: Increments object reference count.
  188. Arguments: None.
  189. Returns: New reference count value.
  190. Revision History:
  191. Date Description Programmer
  192. -------- --------------------------------------------------- ----------
  193. 05/22/96 Initial creation. BrianAu
  194. */
  195. ///////////////////////////////////////////////////////////////////////////////
  196. STDMETHODIMP_(ULONG)
  197. DiskQuotaControl::AddRef(
  198. VOID
  199. )
  200. {
  201. DBGTRACE((DM_CONTROL, DL_LOW, TEXT("DiskQuotaControl::AddRef")));
  202. ULONG cRef = InterlockedIncrement(&m_cRef);
  203. DBGPRINT((DM_CONTROL, DL_LOW, TEXT("\t0x%08X %d -> %d"), this, cRef - 1, cRef ));
  204. return cRef;
  205. }
  206. ///////////////////////////////////////////////////////////////////////////////
  207. /* Function: DiskQuotaControl::Release
  208. Description: Decrements object reference count. If count drops to 0,
  209. object is deleted.
  210. Arguments: None.
  211. Returns: New reference count value.
  212. Revision History:
  213. Date Description Programmer
  214. -------- --------------------------------------------------- ----------
  215. 05/22/96 Initial creation. BrianAu
  216. */
  217. ///////////////////////////////////////////////////////////////////////////////
  218. STDMETHODIMP_(ULONG)
  219. DiskQuotaControl::Release(
  220. VOID
  221. )
  222. {
  223. DBGTRACE((DM_CONTROL, DL_LOW, TEXT("DiskQuotaControl::Release")));
  224. DBGPRINT((DM_CONTROL, DL_LOW, TEXT("\t0x%08X %d -> %d"),
  225. this, m_cRef, m_cRef - 1));
  226. ASSERT( 0 != m_cRef );
  227. ULONG cRef = InterlockedDecrement(&m_cRef);
  228. if ( 0 == cRef )
  229. {
  230. delete this;
  231. }
  232. return cRef;
  233. }
  234. ///////////////////////////////////////////////////////////////////////////////
  235. /* Function: DiskQuotaControl::Initialize
  236. Description: Initializes a quota controller object by opening the NTFS
  237. "device" associated with the quota information. The caller passes the
  238. name of an NTFS volume device to open. A C++ object is created which
  239. encapsulates the required NTFS functionality. This object is known
  240. as a "file system object" or FSObject.
  241. Currently, NTFS only supports quotas on volumes. However, there is
  242. talk of providing quotas for directories in the future. This library
  243. has been designed with this expansion in mind.
  244. By using an object hierarchy to represent the FSObject,
  245. we are able to shield the quota control object from differences
  246. in NTIO API functions dealing with volumes, directories and both
  247. local and remote flavors of both.
  248. Arguments:
  249. pszPath - Name of NTFS path to open.
  250. bReadWrite - TRUE = Read/write.
  251. FALSE = Read only.
  252. Returns:
  253. NOERROR - Success.
  254. E_INVALIDARG - pszPath arg was NULL.
  255. E_OUTOFMEMORY - Insufficient memory.
  256. E_UNEXPECTED - Unexpected exception.
  257. E_FAIL - Error getting volume information.
  258. ERROR_ACCESS_DENIED (hr) - Insufficient access to open FS object.
  259. ERROR_FILE_NOT_FOUND (hr) - Specified volume doesn't exist.
  260. ERROR_PATH_NOT_FOUND (hr) - Specified volume doesn't exist.
  261. ERROR_BAD_PATHNAME (hr) - Invalid path name provided.
  262. ERROR_INVALID_NAME (hr) - Invalid path name provided.
  263. ERROR_NOT_SUPPORTED (hr) - Quotas not supported by volume.
  264. ERROR_ALREADY_INITIALIZED (hr) - Controller is already initialized.
  265. Revision History:
  266. Date Description Programmer
  267. -------- --------------------------------------------------- ----------
  268. 05/22/96 Initial creation. BrianAu
  269. 06/06/96 Added ansi-unicode thunk. BrianAu
  270. 06/11/96 Added return of access granted value. BrianAu
  271. 09/05/96 Added exception handling. BrianAu
  272. 09/23/96 Take a "lazy" position on creating the BrianAu
  273. SidNameResolver object. Should only create it when
  274. it will be needed (user enumeration). Moved
  275. creation from here to CreateEnumUsers.
  276. 07/03/97 Added dwAccess argument. BrianAu
  277. 08/15/97 Added "already initialized" check. BrianAu
  278. Removed InitializeA().
  279. */
  280. ///////////////////////////////////////////////////////////////////////////////
  281. STDMETHODIMP
  282. DiskQuotaControl::Initialize(
  283. LPCWSTR pszPath,
  284. BOOL bReadWrite
  285. )
  286. {
  287. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::Initialize")));
  288. DBGPRINT((DM_CONTROL, DL_MID, TEXT("\tpath = \"%s\", bReadWrite = %d"),
  289. pszPath ? pszPath : TEXT("<null>"), bReadWrite));
  290. HRESULT hr = NOERROR;
  291. if (m_bInitialized)
  292. {
  293. //
  294. // Controller has already been initialized.
  295. // Re-initialization is not allowed.
  296. //
  297. hr = HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED);
  298. }
  299. else
  300. {
  301. if (NULL == pszPath)
  302. return E_INVALIDARG;
  303. try
  304. {
  305. DWORD dwAccess = GENERIC_READ | (bReadWrite ? GENERIC_WRITE : 0);
  306. hr = FSObject::Create(pszPath,
  307. dwAccess,
  308. &m_pFSObject);
  309. m_bInitialized = SUCCEEDED(hr);
  310. }
  311. catch(CAllocException& e)
  312. {
  313. DBGERROR((TEXT("Insufficient memory exception")));
  314. hr = E_OUTOFMEMORY;
  315. }
  316. }
  317. return hr;
  318. }
  319. ///////////////////////////////////////////////////////////////////////////////
  320. /* Function: DiskQuotaControl::CreateEnumUsers
  321. Description: Create a new enumerator object for enumerating over the users
  322. in a volume's quota information file. The returned interface supports
  323. the normal OLE 2 enumeration members Next(), Reset(), Skip() and Clone().
  324. Arguments:
  325. rgpSids [optional] - Pointer to a list of SID pointers. If
  326. provided, only those users with SIDs included in the list are
  327. returned. This argument may be NULL in which case ALL users are
  328. included. Any element containing a NULL pointer will terminate
  329. the list.
  330. cpSids [optional] - If pSidList is not NULL, this arg contains
  331. the count of entries in rgpSids. If rgpSids is not NULL and this
  332. argument contains 0, rgpSids is assumed to contain a terminating
  333. NULL pointer entry.
  334. fNameResolution - Can be one of the following:
  335. DISKQUOTA_USERNAME_RESOLVE_NONE
  336. DISKQUOTA_USERNAME_RESOLVE_SYNC
  337. DISKQUOTA_USERNAME_RESOLVE_ASYNC
  338. ppEnum - Address of interface variable to accept the IEnumDiskQuotaUser
  339. interface pointer.
  340. Returns:
  341. NOERROR - Success.
  342. E_INVALIDARG - ppEnum arg is NULL.
  343. E_OUTOFMEMORY - Insufficient memory to create enumerator object.
  344. ERROR_ACCESS_DENIED (hr) - Need READ access to create enumerator.
  345. ERROR_NOT_READY (hr) - Object not initialized.
  346. Revision History:
  347. Date Description Programmer
  348. -------- --------------------------------------------------- ----------
  349. 05/22/96 Initial creation. BrianAu
  350. 08/11/96 Added access control. BrianAu
  351. 09/05/96 Added exception handling. BrianAu
  352. 09/23/96 Added lazy creation of SidNameResolver object. BrianAu
  353. Moved it from InitializeW().
  354. */
  355. ///////////////////////////////////////////////////////////////////////////////
  356. HRESULT
  357. DiskQuotaControl::CreateEnumUsers(
  358. PSID *rgpSids,
  359. DWORD cpSids,
  360. DWORD fNameResolution,
  361. IEnumDiskQuotaUsers **ppEnum
  362. )
  363. {
  364. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::CreateEnumUsers")));
  365. HRESULT hr = E_FAIL;
  366. if (!m_bInitialized)
  367. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  368. if (NULL == ppEnum)
  369. return E_INVALIDARG;
  370. if (!m_pFSObject->GrantedAccess(GENERIC_READ))
  371. {
  372. hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  373. }
  374. else
  375. {
  376. DiskQuotaUserEnum *pEnumUsers = NULL;
  377. try
  378. {
  379. if (NULL == m_pSidNameResolver)
  380. {
  381. //
  382. // If there's no SID/Name resolver object, create one.
  383. // We do this "as needed" because user enumeration is
  384. // the only controller function that requires a resolver.
  385. // If the client doesn't need a resolver, why create one?
  386. //
  387. SidNameResolver *pResolver = NULL;
  388. //
  389. // Create user SID/Name resolver object.
  390. //
  391. pResolver = new SidNameResolver(*this);
  392. hr = pResolver->QueryInterface(IID_ISidNameResolver,
  393. (LPVOID *)&m_pSidNameResolver);
  394. if (SUCCEEDED(hr))
  395. {
  396. hr = m_pSidNameResolver->Initialize();
  397. if (FAILED(hr))
  398. {
  399. //
  400. // If resolver initialization fails, we can assume
  401. // that the resolver's thread hasn't been created so
  402. // it's OK to just call Release() instead of
  403. // Shutdown() followed by Release(). This is strongly
  404. // dependent on the initialization logic in the resolver's
  405. // Initialize method. There's a comment there also.
  406. //
  407. m_pSidNameResolver->Release();
  408. m_pSidNameResolver = NULL;
  409. pResolver = NULL;
  410. }
  411. }
  412. }
  413. if (NULL != m_pSidNameResolver)
  414. {
  415. //
  416. // Create and initialize the enumerator object.
  417. //
  418. pEnumUsers = new DiskQuotaUserEnum(static_cast<IDiskQuotaControl *>(this),
  419. m_pSidNameResolver,
  420. m_pFSObject);
  421. //
  422. // This can throw OutOfMemory.
  423. //
  424. hr = pEnumUsers->Initialize(fNameResolution,
  425. ENUMUSER_BUF_LEN,
  426. rgpSids,
  427. cpSids);
  428. if (SUCCEEDED(hr))
  429. {
  430. hr = pEnumUsers->QueryInterface(IID_IEnumDiskQuotaUsers,
  431. (LPVOID *)ppEnum);
  432. }
  433. else
  434. {
  435. //
  436. // Something failed after enumerator object was created.
  437. //
  438. delete pEnumUsers;
  439. }
  440. }
  441. }
  442. catch(CAllocException& e)
  443. {
  444. DBGERROR((TEXT("Insufficient memory exception")));
  445. delete pEnumUsers;
  446. hr = E_OUTOFMEMORY;
  447. }
  448. }
  449. return hr;
  450. }
  451. ///////////////////////////////////////////////////////////////////////////////
  452. /* Function: DiskQuotaControl::CreateUserBatch
  453. Description: Create a new user batch control object. Batch control is
  454. provided to take advantage of the inherent batching properties of the
  455. NTIOAPI. If many user records are being altered at one time, it is
  456. much more efficient to mark each of the users for "deferred update",
  457. submit each user object to the batch and then flush the batch to disk.
  458. Arguments:
  459. ppUserBatch - Address of interface variable to accept the IDiskQuotaUserBatch
  460. interface pointer.
  461. Returns:
  462. NOERROR - Success.
  463. E_INVALIDARG - ppOut arg is NULL.
  464. E_OUTOFMEMORY - Insufficient memory to create batch object.
  465. ERROR_ACCESS_DENIED (hr) - Need WRITE access to create batch.
  466. ERROR_NOT_READY (hr) - Object not initialized.
  467. Revision History:
  468. Date Description Programmer
  469. -------- --------------------------------------------------- ----------
  470. 06/06/96 Initial creation. BrianAu
  471. 08/11/96 Added access control. BrianAu
  472. 09/05/96 Added exception handling. BrianAu
  473. */
  474. ///////////////////////////////////////////////////////////////////////////////
  475. STDMETHODIMP
  476. DiskQuotaControl::CreateUserBatch(
  477. PDISKQUOTA_USER_BATCH *ppUserBatch
  478. )
  479. {
  480. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::CreateUserBatch")));
  481. HRESULT hr = NOERROR;
  482. if (!m_bInitialized)
  483. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  484. if (NULL == ppUserBatch)
  485. return E_INVALIDARG;
  486. if (!m_pFSObject->GrantedAccess(GENERIC_WRITE))
  487. {
  488. hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  489. }
  490. else
  491. {
  492. try
  493. {
  494. DiskQuotaUserBatch *pUserBatch = new DiskQuotaUserBatch(m_pFSObject);
  495. hr = pUserBatch->QueryInterface(IID_IDiskQuotaUserBatch,
  496. (LPVOID *)ppUserBatch);
  497. }
  498. catch(CAllocException& e) // From new or m_UserList ctor.
  499. {
  500. DBGERROR((TEXT("Insufficient memory exception")));
  501. hr = E_OUTOFMEMORY;
  502. }
  503. }
  504. return hr;
  505. }
  506. ///////////////////////////////////////////////////////////////////////////////
  507. /* Function: DiskQuotaControl::AddUserSid
  508. Description: Adds a new user to the volume's quota information file.
  509. If successful, returns an interface to the new user object. When
  510. the caller is finished with the interface, they must call Release()
  511. through that interface pointer. Uses the default limit and threshold.
  512. Arguments:
  513. pSid - Pointer to single SID structure.
  514. fNameResolution - Method of SID-to-name resolution. Can be one of the
  515. following:
  516. DISKQUOTA_USERNAME_RESOLVE_NONE
  517. DISKQUOTA_USERNAME_RESOLVE_SYNC
  518. DISKQUOTA_USERNAME_RESOLVE_ASYNC
  519. ppUser - Address of interface pointer variable to accept
  520. pointer to the new user object's IDiskQuotaUser interface.
  521. Returns:
  522. SUCCESS - Success.
  523. S_FALSE - User already exists. Not added.
  524. E_OUTOFMEMORY - Insufficient memory.
  525. E_UNEXPECTED - Unexpected exception.
  526. E_INVALIDARG - pSid or ppUser were NULL.
  527. ERROR_NOT_READY (hr) - Object not initialized.
  528. Revision History:
  529. Date Description Programmer
  530. -------- --------------------------------------------------- ----------
  531. 05/22/96 Initial creation. BrianAu
  532. 09/30/96 Added implementation. Was E_NOTIMPL. BrianAu
  533. */
  534. ///////////////////////////////////////////////////////////////////////////////
  535. STDMETHODIMP
  536. DiskQuotaControl::AddUserSid(
  537. PSID pSid,
  538. DWORD fNameResolution,
  539. PDISKQUOTA_USER *ppUser
  540. )
  541. {
  542. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::AddUserSid")));
  543. HRESULT hr = E_FAIL;
  544. PDISKQUOTA_USER pIUser = NULL;
  545. if (!m_bInitialized)
  546. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  547. if (NULL == pSid || NULL == ppUser)
  548. return E_INVALIDARG;
  549. LONGLONG llLimit = 0;
  550. LONGLONG llThreshold = 0;
  551. LONGLONG llUsed = 0;
  552. *ppUser = NULL;
  553. //
  554. // Check to see if the user already exists in the quota file.
  555. //
  556. try
  557. {
  558. hr = FindUserSid(pSid,
  559. DISKQUOTA_USERNAME_RESOLVE_NONE,
  560. &pIUser);
  561. if (SUCCEEDED(hr))
  562. {
  563. //
  564. // The NTIOAPI says the user exists.
  565. // We'll need the quota info to determine if we
  566. // still allow addition of the "new" user. This is needed because
  567. // of the weird way the NTIOAPI enumerates users. If you ask it to
  568. // enumerate specified user(s), the returned information will include
  569. // info for users that do not have (but could have) a record in the
  570. // quota file. Since the quota system allows automatic addition of
  571. // users, it considers any users with write access to have a record
  572. // in the quota file. Such users are returned with a quota threshold
  573. // and limit of 0. Therefore, we treat records marked for deletion
  574. // or those with 0 used, 0 limit and 0 threshold as "non existing".
  575. // I use the term "ghost" for these users.
  576. //
  577. pIUser->GetQuotaLimit(&llLimit);
  578. pIUser->GetQuotaThreshold(&llThreshold);
  579. pIUser->GetQuotaUsed(&llUsed);
  580. ULARGE_INTEGER a,b,c;
  581. a.QuadPart = llLimit;
  582. b.QuadPart = llThreshold;
  583. c.QuadPart = llUsed;
  584. DBGPRINT((DM_CONTROL, DL_LOW, TEXT("Found user: Limit = 0x%08X 0x%08X, Threshold = 0x%08X 0x%08X, Used = 0x%08X 0x%08X"),
  585. a.HighPart, a.LowPart, b.HighPart, b.LowPart, c.HighPart, c.LowPart));
  586. BOOL bIsGhost = ((MARK4DEL == llLimit) ||
  587. ( 0 == llLimit &&
  588. 0 == llThreshold &&
  589. 0 == llUsed));
  590. if (!bIsGhost)
  591. {
  592. //
  593. // User already exists.
  594. //
  595. hr = S_FALSE;
  596. }
  597. else
  598. {
  599. DWORD cbSid = GetLengthSid(pSid);
  600. //
  601. // User not in quota file OR in quota file but marked for deletion.
  602. // Just set it's limit and threshold to the volume defaults.
  603. //
  604. pIUser->SetQuotaThreshold(m_llDefaultQuotaThreshold, TRUE);
  605. hr = pIUser->SetQuotaLimit(m_llDefaultQuotaLimit, TRUE);
  606. if (SUCCEEDED(hr) && NULL != m_pSidNameResolver)
  607. {
  608. //
  609. // We have a good user object and have set the quota parameters.
  610. // Get the user's domain, name and full name from the network DC
  611. // using the resolution type specified by the caller.
  612. //
  613. switch(fNameResolution)
  614. {
  615. case DISKQUOTA_USERNAME_RESOLVE_ASYNC:
  616. m_pSidNameResolver->FindUserNameAsync(pIUser);
  617. break;
  618. case DISKQUOTA_USERNAME_RESOLVE_SYNC:
  619. m_pSidNameResolver->FindUserName(pIUser);
  620. break;
  621. case DISKQUOTA_USERNAME_RESOLVE_NONE:
  622. default:
  623. break;
  624. }
  625. }
  626. }
  627. *ppUser = pIUser;
  628. }
  629. }
  630. catch(CAllocException& e)
  631. {
  632. DBGERROR((TEXT("Insufficient memory exception")));
  633. hr = E_OUTOFMEMORY;
  634. }
  635. if (FAILED(hr))
  636. {
  637. *ppUser = NULL;
  638. if (NULL != pIUser)
  639. {
  640. pIUser->Release();
  641. }
  642. }
  643. return hr;
  644. }
  645. STDMETHODIMP
  646. DiskQuotaControl::AddUserName(
  647. LPCWSTR pszLogonName,
  648. DWORD fNameResolution,
  649. PDISKQUOTA_USER *ppUser
  650. )
  651. {
  652. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::AddUserName")));
  653. if (!m_bInitialized)
  654. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  655. if (NULL == pszLogonName || NULL == ppUser)
  656. return E_INVALIDARG;
  657. HRESULT hr = E_FAIL;
  658. try
  659. {
  660. BYTE Sid[MAX_SID_LEN];
  661. DWORD cbSid = sizeof(Sid);
  662. SID_NAME_USE eSidUse;
  663. if (SUCCEEDED(m_NTDS.LookupAccountByName(NULL, // system
  664. pszLogonName, // key
  665. NULL, // no container ret
  666. NULL, // no display name ret
  667. &Sid[0],
  668. &cbSid,
  669. &eSidUse)))
  670. {
  671. hr = AddUserSid(&Sid[0], fNameResolution, ppUser);
  672. }
  673. else
  674. {
  675. hr = HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER);
  676. }
  677. }
  678. catch(CAllocException& e)
  679. {
  680. DBGERROR((TEXT("Insufficient memory exception")));
  681. hr = E_OUTOFMEMORY;
  682. }
  683. return hr;
  684. }
  685. ///////////////////////////////////////////////////////////////////////////////
  686. /* Function: DiskQuotaControl::ShutdownNameResolution
  687. Description: Release the SID/Name resolver. This terminates the
  688. resolver thread for clients who don't want to wait for the controller
  689. object to be destroyed. Note that subsequent calls to CreateEnumUsers,
  690. AddUserSid, AddUserName, FindUserSid or FindUserName can restart
  691. the resolver.
  692. Arguments: None.
  693. Returns: Always returns NOERROR
  694. Revision History:
  695. Date Description Programmer
  696. -------- --------------------------------------------------- ----------
  697. 08/29/97 Initial creation. BrianAu
  698. */
  699. ///////////////////////////////////////////////////////////////////////////////
  700. STDMETHODIMP
  701. DiskQuotaControl::ShutdownNameResolution(
  702. VOID
  703. )
  704. {
  705. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::ShutdownNameResolution")));
  706. if (NULL != m_pSidNameResolver)
  707. {
  708. //
  709. // Shutdown and release the resolver.
  710. // Since it's running on it's own thread, we must wait for the thread
  711. // to exit.
  712. // Note that if the thread is off resolving a name from the DC, this could
  713. // take a bit.
  714. //
  715. m_pSidNameResolver->Shutdown(TRUE); // TRUE == Wait for thread exit.
  716. m_pSidNameResolver->Release();
  717. m_pSidNameResolver = NULL;
  718. }
  719. return NOERROR;
  720. }
  721. ///////////////////////////////////////////////////////////////////////////////
  722. /* Function: DiskQuotaControl::GiveUserNameResolutionPriority
  723. Description: A very long name for a very simple function.
  724. This function merely finds the user object in the name resolver's
  725. input queue and moves it to the head of the queue.
  726. Arguments:
  727. pUser - Address of interface pointer for the user object's
  728. IDiskQuotaUser interface.
  729. Returns:
  730. NOERROR - Success.
  731. S_FALSE - User object not in resolver queue.
  732. E_OUTOFMEMORY - Insufficient memory.
  733. E_INVALIDARG - pUser is NULL.
  734. E_UNEXPECTED - Unexpected error. Caught an exception or the
  735. Sid-Name resolver hasn't been created.
  736. ERROR_NOT_READY (hr) - Object not initialized.
  737. Revision History:
  738. Date Description Programmer
  739. -------- --------------------------------------------------- ----------
  740. 05/18/97 Initial creation. BrianAu
  741. */
  742. ///////////////////////////////////////////////////////////////////////////////
  743. STDMETHODIMP
  744. DiskQuotaControl::GiveUserNameResolutionPriority(
  745. PDISKQUOTA_USER pUser
  746. )
  747. {
  748. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::GiveUserNameResolutionPriority")));
  749. HRESULT hr = E_UNEXPECTED;
  750. if (!m_bInitialized)
  751. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  752. if (NULL == pUser)
  753. return E_INVALIDARG;
  754. //
  755. // SidNameResolver::PromoteUserToQueueHeader catches exceptions and
  756. // converts them to HRESULTs. No need for try-catch block here.
  757. //
  758. if (NULL != m_pSidNameResolver)
  759. {
  760. hr = m_pSidNameResolver->PromoteUserToQueueHead(pUser);
  761. }
  762. return hr;
  763. }
  764. ///////////////////////////////////////////////////////////////////////////////
  765. /* Function: DiskQuotaControl::FindUserSid
  766. Description: Finds a single user record in a volume's quota information
  767. file. Returns an interface to the corresponding user object. When
  768. the caller is finished with the interface, they must call Release()
  769. through that interface pointer.
  770. >>>>>>>>> IMPORTANT NOTE <<<<<<<<<
  771. This method will return a user object even if there is no quota
  772. record for the user in the quota file. While that may sound
  773. strange, it is consistent with the idea of automatic user addition
  774. and default quota settings. If there is currently no user record
  775. for the requested user, and the user would be added to the quota
  776. file if they were to request disk space, the returned user object
  777. will have a quota threshold of 0 and a quota limit of 0.
  778. Arguments:
  779. pSid - Pointer to single SID structure identifying the user.
  780. fNameResolution - Can be one of the following:
  781. DISKQUOTA_USERNAME_RESOLVE_NONE
  782. DISKQUOTA_USERNAME_RESOLVE_SYNC
  783. DISKQUOTA_USERNAME_RESOLVE_ASYNC
  784. ppUser - Address of interface pointer variable to accept pointer to
  785. the user object's IDiskQuotaUser interface.
  786. Returns:
  787. NOERROR - Success.
  788. E_INVALIDARG - Either pSid or ppUser were NULL.
  789. E_OUTOFMEMORY - Insufficient memory.
  790. E_UNEXPECTED - Unexpected exception.
  791. ERROR_INVALID_SID (hr) - Invalid SID.
  792. ERROR_ACCESS_DENIED (hr) - No READ access to quota device.
  793. ERROR_NO_SUCH_USER (hr) - User not found in volume's quota information.
  794. ERROR_NOT_READY (hr) - Object not initialized.
  795. Revision History:
  796. Date Description Programmer
  797. -------- --------------------------------------------------- ----------
  798. 05/22/96 Initial creation. BrianAu
  799. 08/14/96 Changed name from FindUser to FindUserSid to BrianAu
  800. accomodate the addition of the FindUserName
  801. methods. No change in functionality.
  802. 09/05/96 Added exception handling. BrianAu
  803. */
  804. ///////////////////////////////////////////////////////////////////////////////
  805. STDMETHODIMP
  806. DiskQuotaControl::FindUserSid(
  807. PSID pSid,
  808. DWORD fNameResolution,
  809. PDISKQUOTA_USER *ppUser
  810. )
  811. {
  812. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::FindUserSid")));
  813. HRESULT hr = NOERROR;
  814. if (!m_bInitialized)
  815. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  816. if (NULL == pSid || NULL == ppUser)
  817. return E_INVALIDARG;
  818. if (!m_pFSObject->GrantedAccess(GENERIC_READ))
  819. {
  820. hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  821. }
  822. else
  823. {
  824. if (!IsValidSid(pSid))
  825. {
  826. hr = HRESULT_FROM_WIN32(ERROR_INVALID_SID);
  827. }
  828. else
  829. {
  830. PENUM_DISKQUOTA_USERS pEnumUsers = NULL;
  831. try
  832. {
  833. DWORD cbSid = GetLengthSid(pSid);
  834. *ppUser = NULL;
  835. //
  836. // Create a user enumerator for the user's SID.
  837. // Can throw OutOfMemory.
  838. //
  839. hr = CreateEnumUsers(&pSid, 1, fNameResolution, &pEnumUsers);
  840. if (SUCCEEDED(hr))
  841. {
  842. DWORD dwUsersFound = 0;
  843. PDISKQUOTA_USER pUser = NULL;
  844. //
  845. // Enumerate 1 record to get the user's info.
  846. // Only one record required since the enumerator object
  847. // was created from a single SID. Can throw OutOfMemory.
  848. //
  849. hr = pEnumUsers->Next(1, &pUser, &dwUsersFound);
  850. if (S_OK == hr)
  851. {
  852. //
  853. // Return user object interface to caller.
  854. //
  855. *ppUser = pUser;
  856. }
  857. else if (S_FALSE == hr)
  858. {
  859. //
  860. // Note: We should never hit this.
  861. // The quota system always returns a user record
  862. // for a user SID. If the record doesn't currently
  863. // exist, one with default limit and threshold is
  864. // returned. This is consistent with the idea
  865. // of automatic user record addition implemented
  866. // by the NTFS quota system. Just in case we do,
  867. // I want to return something intelligent.
  868. //
  869. hr = HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER);
  870. }
  871. }
  872. }
  873. catch(CAllocException& e)
  874. {
  875. DBGERROR((TEXT("Insufficient memory exception")));
  876. hr = E_OUTOFMEMORY;
  877. }
  878. if (NULL != pEnumUsers)
  879. {
  880. //
  881. // Release the enumerator.
  882. //
  883. pEnumUsers->Release();
  884. }
  885. }
  886. }
  887. return hr;
  888. }
  889. ///////////////////////////////////////////////////////////////////////////////
  890. /* Function: DiskQuotaControl::FindUserName
  891. Description: Finds a single user record in a volume's quota information
  892. file. Returns an interface to the corresponding user object. When
  893. the caller is finished with the interface, they must call Release()
  894. through that interface pointer.
  895. If the name is not already cached in the SidNameCache, the function
  896. queries the network domain controller. This operation may take some
  897. time (on the order of 0 - 10 seconds).
  898. Arguments:
  899. pszLogonName - Address of user's logon name string.
  900. i.e. "REDMOND\brianau" or "[email protected]"
  901. ppUser - Address of interface pointer variable to accept pointer to
  902. the user object's IDiskQuotaUser interface.
  903. Returns:
  904. NOERROR - Success.
  905. E_INVALIDARG - Name string is blank or NUL ptr was passed.
  906. E_OUTOFMEMORY - Insufficient memory.
  907. E_UNEXPECTED - Unexpected exception.
  908. ERROR_ACCESS_DENIED (hr) - No READ access to quota device.
  909. ERROR_NO_SUCH_USER (hr) - User not found in quota file.
  910. ERROR_NOT_READY (hr) - Object not initialized.
  911. Revision History:
  912. Date Description Programmer
  913. -------- --------------------------------------------------- ----------
  914. 08/14/96 Initial creation. BrianAu
  915. 09/05/96 Added domain name string. BrianAu
  916. Added exception handling.
  917. 08/15/97 Removed ANSI version. BrianAu
  918. */
  919. ///////////////////////////////////////////////////////////////////////////////
  920. STDMETHODIMP
  921. DiskQuotaControl::FindUserName(
  922. LPCWSTR pszLogonName,
  923. PDISKQUOTA_USER *ppUser
  924. )
  925. {
  926. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::FindUserName")));
  927. HRESULT hr = E_FAIL; // Assume failure.
  928. BOOL bAskDomainController = TRUE;
  929. if (!m_bInitialized)
  930. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  931. if (NULL == pszLogonName || NULL == ppUser)
  932. return E_INVALIDARG;
  933. if (TEXT('\0') == *pszLogonName)
  934. return E_INVALIDARG;
  935. //
  936. // Check for client's access to quota file before we do any
  937. // time-expensive operations.
  938. //
  939. if (!m_pFSObject->GrantedAccess(GENERIC_READ))
  940. {
  941. hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  942. }
  943. else
  944. {
  945. PSID pSid = NULL; // For cache query.
  946. SID Sid[MAX_SID_LEN]; // For DC query.
  947. //
  948. // These nested try-catch blocks look really gross and may
  949. // be unnecessary. I should probably just punt if one of the
  950. // inner blocks really does throw an exception and return
  951. // E_UNEXPECTED instead of trying to continue. [brianau]
  952. //
  953. try
  954. {
  955. SidNameCache *pSidCache;
  956. hr = SidNameCache_Get(&pSidCache);
  957. if (SUCCEEDED(hr))
  958. {
  959. //
  960. // See if the SID/Name pair is in the cache.
  961. //
  962. try
  963. {
  964. hr = pSidCache->Lookup(pszLogonName, &pSid);
  965. if (SUCCEEDED(hr))
  966. {
  967. //
  968. // We have a SID. No need to ask DC.
  969. //
  970. bAskDomainController = FALSE;
  971. }
  972. }
  973. catch(CAllocException& e)
  974. {
  975. //
  976. // Just catch the exception.
  977. // This will cause us to go to the DC for the SID.
  978. //
  979. DBGERROR((TEXT("C++ exception during SID cache lookup in FindUserName")));
  980. pSid = &Sid[0];
  981. }
  982. }
  983. if (bAskDomainController)
  984. {
  985. DBGASSERT((FAILED(hr)));
  986. //
  987. // Still don't have a SID. Ask the DC.
  988. // This can take some time (Ho Hum.........)
  989. //
  990. CString strDisplayName;
  991. CString strContainerName;
  992. SID_NAME_USE eUse;
  993. DWORD cbSid = sizeof(Sid);
  994. if (SUCCEEDED(m_NTDS.LookupAccountByName(NULL,
  995. pszLogonName,
  996. &strContainerName,
  997. &strDisplayName,
  998. &Sid[0],
  999. &cbSid,
  1000. &eUse)))
  1001. {
  1002. pSid = &Sid[0];
  1003. //
  1004. // Add it to the cache for later use.
  1005. //
  1006. if (NULL != pSidCache)
  1007. {
  1008. pSidCache->Add(&Sid[0],
  1009. strContainerName,
  1010. pszLogonName,
  1011. strDisplayName);
  1012. }
  1013. hr = NOERROR;
  1014. }
  1015. }
  1016. if (SUCCEEDED(hr))
  1017. {
  1018. //
  1019. // We have a SID.
  1020. // Now create the actual user object using FindUserSid().
  1021. //
  1022. hr = FindUserSid(pSid, DISKQUOTA_USERNAME_RESOLVE_SYNC, ppUser);
  1023. }
  1024. }
  1025. catch(CAllocException& e)
  1026. {
  1027. DBGERROR((TEXT("Insufficient memory exception")));
  1028. hr = E_OUTOFMEMORY;
  1029. }
  1030. if (&Sid[0] != pSid)
  1031. {
  1032. //
  1033. // We received a heap-allocated SID from SidNameCache::Lookup.
  1034. // Need to free the buffer.
  1035. //
  1036. delete[] pSid;
  1037. }
  1038. }
  1039. return hr;
  1040. }
  1041. ///////////////////////////////////////////////////////////////////////////////
  1042. /* Function: DiskQuotaControl::DeleteUser
  1043. Description: Deletes a user from a volume's quota information and quota
  1044. tracking. The IDiskQuotaUser pointer may be obtained either through
  1045. enumeration or DiskQuotaControl::FindUser().
  1046. NOTE: At this time, we're not sure how (or if) deletion will be done.
  1047. This function remains un-implemented until we figure it out.
  1048. Arguments:
  1049. pUser - Pointer to quota user object's IDiskQuotaUser interface.
  1050. Returns:
  1051. NOERROR - Success.
  1052. E_OUTOFMEMORY - Insufficient memory.
  1053. E_UNEXPECTED - Unexpected exception.
  1054. E_FAIL - NTIO error writing user data.
  1055. E_INVALIDARG - pUser argument was NULL.
  1056. ERROR_FILE_EXISTS (hr) - Couldn't delete. User still has bytes charge.
  1057. ERROR_ACCESS_DENIED (hr) - Insufficient access.
  1058. ERROR_NOT_READY (hr) - Object not initialized.
  1059. Revision History:
  1060. Date Description Programmer
  1061. -------- --------------------------------------------------- ----------
  1062. 05/22/96 Initial creation. BrianAu
  1063. 09/28/96 Added implementation. Was E_NOTIMPL. BrianAu
  1064. */
  1065. ///////////////////////////////////////////////////////////////////////////////
  1066. STDMETHODIMP
  1067. DiskQuotaControl::DeleteUser(
  1068. PDISKQUOTA_USER pUser
  1069. )
  1070. {
  1071. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControl::DeleteUser")));
  1072. HRESULT hr = NOERROR;
  1073. if (!m_bInitialized)
  1074. return HRESULT_FROM_WIN32(ERROR_NOT_READY);
  1075. if (NULL == pUser)
  1076. return E_INVALIDARG;
  1077. try
  1078. {
  1079. LONGLONG llValue;
  1080. //
  1081. // Invalidate user object to force a refresh of data from the
  1082. // quota file. Want to make sure this is current information before
  1083. // we tell the caller that the user can't be deleted.
  1084. //
  1085. pUser->Invalidate();
  1086. hr = pUser->GetQuotaUsed(&llValue);
  1087. if (SUCCEEDED(hr))
  1088. {
  1089. if (0 == llValue)
  1090. {
  1091. //
  1092. // User has 0 bytes in use. OK to delete.
  1093. // Note that we leave the quota threshold unchanged.
  1094. // If setting the limit fails, we want to leave the
  1095. // threshold in its current state.
  1096. //
  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. ULONG cRef = InterlockedIncrement(&m_cRef);
  2057. DBGPRINT((DM_CONTROL, DL_LOW, TEXT("\t0x%08X %d -> %d"), this, cRef - 1, cRef ));
  2058. return cRef;
  2059. }
  2060. STDMETHODIMP_(ULONG)
  2061. DiskQuotaControlDisp::Release(
  2062. VOID
  2063. )
  2064. {
  2065. DBGTRACE((DM_CONTROL, DL_LOW, TEXT("DiskQuotaControlDisp::Release")));
  2066. ASSERT( 0 != m_cRef );
  2067. ULONG cRef = InterlockedDecrement(&m_cRef);
  2068. DBGPRINT((DM_CONTROL, DL_LOW, TEXT("\t0x%08X %d -> %d"), this, cRef + 1, cRef ));
  2069. if ( 0 == cRef )
  2070. {
  2071. delete this;
  2072. }
  2073. return cRef;
  2074. }
  2075. STDMETHODIMP
  2076. DiskQuotaControlDisp::QueryInterface(
  2077. REFIID riid,
  2078. LPVOID *ppvOut
  2079. )
  2080. {
  2081. DBGTRACE((DM_CONTROL, DL_MID, TEXT("DiskQuotaControlDisp::QueryInterface")));
  2082. DBGPRINTIID(DM_CONTROL, DL_MID, riid);
  2083. HRESULT hr = E_NOINTERFACE;
  2084. if (NULL == ppvOut)
  2085. return E_INVALIDARG;
  2086. *ppvOut = NULL;
  2087. if (IID_IUnknown == riid)
  2088. {
  2089. *ppvOut = this;
  2090. }
  2091. else if (IID_IDispatch == riid)
  2092. {
  2093. *ppvOut = static_cast<IDispatch *>(this);
  2094. }
  2095. else if (IID_DIDiskQuotaControl == riid)
  2096. {
  2097. *ppvOut = static_cast<DIDiskQuotaControl *>(this);
  2098. }
  2099. else if (IID_IDiskQuotaControl == riid ||
  2100. IID_IConnectionPointContainer == riid)
  2101. {
  2102. //
  2103. // Return the quota controller's vtable interface.
  2104. // This allows code to "typecast" (COM-style) between
  2105. // the dispatch interface and vtable interface.
  2106. //
  2107. return m_pQC->QueryInterface(riid, ppvOut);
  2108. }
  2109. if (NULL != *ppvOut)
  2110. {
  2111. ((LPUNKNOWN)*ppvOut)->AddRef();
  2112. hr = NOERROR;
  2113. }
  2114. return hr;
  2115. }
  2116. //
  2117. // IDispatch::GetIDsOfNames
  2118. //
  2119. STDMETHODIMP
  2120. DiskQuotaControlDisp::GetIDsOfNames(
  2121. REFIID riid,
  2122. OLECHAR **rgszNames,
  2123. UINT cNames,
  2124. LCID lcid,
  2125. DISPID *rgDispId
  2126. )
  2127. {
  2128. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::GetIDsOfNames")));
  2129. //
  2130. // Let our dispatch object handle this.
  2131. //
  2132. return m_Dispatch.GetIDsOfNames(riid,
  2133. rgszNames,
  2134. cNames,
  2135. lcid,
  2136. rgDispId);
  2137. }
  2138. //
  2139. // IDispatch::GetTypeInfo
  2140. //
  2141. STDMETHODIMP
  2142. DiskQuotaControlDisp::GetTypeInfo(
  2143. UINT iTInfo,
  2144. LCID lcid,
  2145. ITypeInfo **ppTypeInfo
  2146. )
  2147. {
  2148. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::GetTypeInfo")));
  2149. //
  2150. // Let our dispatch object handle this.
  2151. //
  2152. return m_Dispatch.GetTypeInfo(iTInfo, lcid, ppTypeInfo);
  2153. }
  2154. //
  2155. // IDispatch::GetTypeInfoCount
  2156. //
  2157. STDMETHODIMP
  2158. DiskQuotaControlDisp::GetTypeInfoCount(
  2159. UINT *pctinfo
  2160. )
  2161. {
  2162. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::GetTypeInfoCount")));
  2163. //
  2164. // Let our dispatch object handle this.
  2165. //
  2166. return m_Dispatch.GetTypeInfoCount(pctinfo);
  2167. }
  2168. //
  2169. // IDispatch::Invoke
  2170. //
  2171. STDMETHODIMP
  2172. DiskQuotaControlDisp::Invoke(
  2173. DISPID dispIdMember,
  2174. REFIID riid,
  2175. LCID lcid,
  2176. WORD wFlags,
  2177. DISPPARAMS *pDispParams,
  2178. VARIANT *pVarResult,
  2179. EXCEPINFO *pExcepInfo,
  2180. UINT *puArgErr
  2181. )
  2182. {
  2183. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::Invoke")));
  2184. //
  2185. // Let our dispatch object handle this.
  2186. //
  2187. return m_Dispatch.Invoke(dispIdMember,
  2188. riid,
  2189. lcid,
  2190. wFlags,
  2191. pDispParams,
  2192. pVarResult,
  2193. pExcepInfo,
  2194. puArgErr);
  2195. }
  2196. //
  2197. // Dispatch property "QuotaState" (put)
  2198. //
  2199. // Sets the state of the quota system on the volume.
  2200. // See DiskQuotaControl::SetQuotaState for details.
  2201. //
  2202. // Valid states: 0 = Disabled.
  2203. // 1 = Tracking
  2204. // 2 = Enforcing
  2205. STDMETHODIMP
  2206. DiskQuotaControlDisp::put_QuotaState(
  2207. QuotaStateConstants State
  2208. )
  2209. {
  2210. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::put_QuotaState")));
  2211. if (dqStateMaxValue < State)
  2212. {
  2213. //
  2214. // State can only be 0, 1 or 2.
  2215. //
  2216. return E_INVALIDARG;
  2217. }
  2218. //
  2219. // No exception handling required.
  2220. // DiskQuotaControl::SetQuotaState handles exceptions.
  2221. //
  2222. return m_pQC->SetQuotaState(State);
  2223. }
  2224. //
  2225. // Dispatch property "QuotaState" (get)
  2226. //
  2227. // Retrieves the state of the quota system on the volume.
  2228. // See DiskQuotaControl::GetQuotaState for details.
  2229. //
  2230. // State returned: 0 = Disabled.
  2231. // 1 = Tracking
  2232. // 2 = Enforcing
  2233. //
  2234. STDMETHODIMP
  2235. DiskQuotaControlDisp::get_QuotaState(
  2236. QuotaStateConstants *pState
  2237. )
  2238. {
  2239. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::get_QuotaState")));
  2240. DWORD dwState;
  2241. //
  2242. // No exception handling required.
  2243. // DiskQuotaControl::GetQuotaState handles exceptions.
  2244. //
  2245. HRESULT hr = m_pQC->GetQuotaState(&dwState);
  2246. if (SUCCEEDED(hr))
  2247. {
  2248. *pState = (QuotaStateConstants)(dwState & DISKQUOTA_STATE_MASK);
  2249. }
  2250. return hr;
  2251. }
  2252. //
  2253. // Dispatch property "QuotaFileIncomplete" (get)
  2254. //
  2255. // Determines if the state of the quota file is "incomplete".
  2256. //
  2257. STDMETHODIMP
  2258. DiskQuotaControlDisp::get_QuotaFileIncomplete(
  2259. VARIANT_BOOL *pbIncomplete
  2260. )
  2261. {
  2262. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::get_QuotaFileIncomplete")));
  2263. DWORD dwState;
  2264. //
  2265. // No exception handling required.
  2266. // DiskQuotaControl::GetQuotaState handles exceptions.
  2267. //
  2268. HRESULT hr = m_pQC->GetQuotaState(&dwState);
  2269. if (SUCCEEDED(hr))
  2270. {
  2271. *pbIncomplete = DISKQUOTA_FILE_INCOMPLETE(dwState) ? VARIANT_TRUE : VARIANT_FALSE;
  2272. }
  2273. return hr;
  2274. }
  2275. //
  2276. // Dispatch property "QuotaFileRebuilding" (get)
  2277. //
  2278. // Determines if the state of the quota file is "rebuilding".
  2279. //
  2280. STDMETHODIMP
  2281. DiskQuotaControlDisp::get_QuotaFileRebuilding(
  2282. VARIANT_BOOL *pbRebuilding
  2283. )
  2284. {
  2285. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::get_QuotaFileRebuilding")));
  2286. DWORD dwState;
  2287. //
  2288. // No exception handling required.
  2289. // DiskQuotaControl::GetQuotaState handles exceptions.
  2290. //
  2291. HRESULT hr = m_pQC->GetQuotaState(&dwState);
  2292. if (SUCCEEDED(hr))
  2293. {
  2294. *pbRebuilding = DISKQUOTA_FILE_REBUILDING(dwState) ? VARIANT_TRUE : VARIANT_FALSE;
  2295. }
  2296. return hr;
  2297. }
  2298. //
  2299. // Dispatch property "LogQuotaThreshold" (put)
  2300. //
  2301. // Sets the "log warning threshold" flag on the volume.
  2302. //
  2303. STDMETHODIMP
  2304. DiskQuotaControlDisp::put_LogQuotaThreshold(
  2305. VARIANT_BOOL bLog
  2306. )
  2307. {
  2308. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::put_LogQuotaThreshold")));
  2309. DWORD dwFlags;
  2310. //
  2311. // No exception handling required.
  2312. // DiskQuotaControl::GetQuotaLogFlags and SetQuotaLogFlags handle
  2313. // exceptions.
  2314. //
  2315. HRESULT hr = m_pQC->GetQuotaLogFlags(&dwFlags);
  2316. if (SUCCEEDED(hr))
  2317. {
  2318. hr = m_pQC->SetQuotaLogFlags(DISKQUOTA_SET_LOG_USER_THRESHOLD(dwFlags, VARIANT_TRUE == bLog));
  2319. }
  2320. return hr;
  2321. }
  2322. //
  2323. // Dispatch property "LogQuotaThreshold" (get)
  2324. //
  2325. // Retrieves the "log warning threshold" flag on the volume.
  2326. //
  2327. STDMETHODIMP
  2328. DiskQuotaControlDisp::get_LogQuotaThreshold(
  2329. VARIANT_BOOL *pbLog
  2330. )
  2331. {
  2332. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::get_LogQuotaThreshold")));
  2333. DWORD dwFlags;
  2334. //
  2335. // No exception handling required.
  2336. // DiskQuotaControl::GetQuotaLogFlags handles exceptions.
  2337. //
  2338. HRESULT hr = m_pQC->GetQuotaLogFlags(&dwFlags);
  2339. if (SUCCEEDED(hr))
  2340. {
  2341. *pbLog = DISKQUOTA_IS_LOGGED_USER_THRESHOLD(dwFlags) ? VARIANT_TRUE : VARIANT_FALSE;
  2342. }
  2343. return hr;
  2344. }
  2345. //
  2346. // Dispatch property "LogQuotaLimit" (put)
  2347. //
  2348. // Sets the "log quota limit" flag on the volume.
  2349. //
  2350. STDMETHODIMP
  2351. DiskQuotaControlDisp::put_LogQuotaLimit(
  2352. VARIANT_BOOL bLog
  2353. )
  2354. {
  2355. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::put_LogQuotaLimit")));
  2356. DWORD dwFlags;
  2357. //
  2358. // No exception handling required.
  2359. // DiskQuotaControl::GetQuotaLogFlags handles exceptions.
  2360. //
  2361. HRESULT hr = m_pQC->GetQuotaLogFlags(&dwFlags);
  2362. if (SUCCEEDED(hr))
  2363. {
  2364. hr = m_pQC->SetQuotaLogFlags(DISKQUOTA_SET_LOG_USER_LIMIT(dwFlags, VARIANT_TRUE == bLog));
  2365. }
  2366. return hr;
  2367. }
  2368. //
  2369. // Dispatch property "LogQuotaLimit" (get)
  2370. //
  2371. // Retrieves the "log quota limit" flag on the volume.
  2372. //
  2373. STDMETHODIMP
  2374. DiskQuotaControlDisp::get_LogQuotaLimit(
  2375. VARIANT_BOOL *pbLog
  2376. )
  2377. {
  2378. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::get_LogQuotaLimit")));
  2379. DWORD dwFlags;
  2380. //
  2381. // No exception handling required.
  2382. // DiskQuotaControl::GetQuotaLogFlags handles exceptions.
  2383. //
  2384. HRESULT hr = m_pQC->GetQuotaLogFlags(&dwFlags);
  2385. if (SUCCEEDED(hr))
  2386. {
  2387. *pbLog = DISKQUOTA_IS_LOGGED_USER_LIMIT(dwFlags) ? VARIANT_TRUE : VARIANT_FALSE;
  2388. }
  2389. return hr;
  2390. }
  2391. //
  2392. // Dispatch property "DefaultQuotaThreshold" (put)
  2393. //
  2394. // Sets the default quota threshold on the volume.
  2395. //
  2396. STDMETHODIMP
  2397. DiskQuotaControlDisp::put_DefaultQuotaThreshold(
  2398. double Threshold
  2399. )
  2400. {
  2401. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::put_DefaultQuotaThreshold")));
  2402. if (MAXLONGLONG < Threshold)
  2403. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  2404. //
  2405. // No exception handling required.
  2406. // DiskQuotaControl::GetDefaultQuotaThreshold handles exceptions.
  2407. //
  2408. return m_pQC->SetDefaultQuotaThreshold((LONGLONG)Threshold);
  2409. }
  2410. //
  2411. // Dispatch property "DefaultQuotaThreshold" (get)
  2412. //
  2413. // Retrieves the default quota threshold on the volume.
  2414. //
  2415. STDMETHODIMP
  2416. DiskQuotaControlDisp::get_DefaultQuotaThreshold(
  2417. double *pThreshold
  2418. )
  2419. {
  2420. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::get_DefaultQuotaThreshold")));
  2421. LONGLONG llTemp;
  2422. //
  2423. // No exception handling required.
  2424. // DiskQuotaControl::GetDefaultQuotaThreshold handles exceptions.
  2425. //
  2426. HRESULT hr = m_pQC->GetDefaultQuotaThreshold(&llTemp);
  2427. if (SUCCEEDED(hr))
  2428. {
  2429. *pThreshold = (double)llTemp;
  2430. }
  2431. return hr;
  2432. }
  2433. STDMETHODIMP
  2434. DiskQuotaControlDisp::get_DefaultQuotaThresholdText(
  2435. BSTR *pThresholdText
  2436. )
  2437. {
  2438. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::get_DefaultQuotaThresholdText")));
  2439. TCHAR szValue[40];
  2440. HRESULT hr;
  2441. hr = m_pQC->GetDefaultQuotaThresholdText(szValue, ARRAYSIZE(szValue));
  2442. if (SUCCEEDED(hr))
  2443. {
  2444. *pThresholdText = SysAllocString(szValue);
  2445. if (NULL == *pThresholdText)
  2446. {
  2447. hr = E_OUTOFMEMORY;
  2448. }
  2449. }
  2450. return hr;
  2451. }
  2452. //
  2453. // Dispatch property "DefaultQuotaLimit" (put)
  2454. //
  2455. // Sets the default quota limit on the volume.
  2456. //
  2457. STDMETHODIMP
  2458. DiskQuotaControlDisp::put_DefaultQuotaLimit(
  2459. double Limit
  2460. )
  2461. {
  2462. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::put_DefaultQuotaLimit")));
  2463. if (MAXLONGLONG < Limit)
  2464. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  2465. //
  2466. // No exception handling required.
  2467. // DiskQuotaControl::SetDefaultQuotaLimit handles exceptions.
  2468. //
  2469. return m_pQC->SetDefaultQuotaLimit((LONGLONG)Limit);
  2470. }
  2471. //
  2472. // Dispatch property "DefaultQuotaLimit" (get)
  2473. //
  2474. // Retrieves the default quota limit on the volume.
  2475. //
  2476. STDMETHODIMP
  2477. DiskQuotaControlDisp::get_DefaultQuotaLimit(
  2478. double *pLimit
  2479. )
  2480. {
  2481. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::get_DefaultQuotaLimit")));
  2482. LONGLONG llTemp;
  2483. //
  2484. // No exception handling required.
  2485. // DiskQuotaControl::GetDefaultQuotaLimit handles exceptions.
  2486. //
  2487. HRESULT hr = m_pQC->GetDefaultQuotaLimit(&llTemp);
  2488. if (SUCCEEDED(hr))
  2489. {
  2490. *pLimit = (double)llTemp;
  2491. }
  2492. return hr;
  2493. }
  2494. STDMETHODIMP
  2495. DiskQuotaControlDisp::get_DefaultQuotaLimitText(
  2496. BSTR *pLimitText
  2497. )
  2498. {
  2499. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::get_DefaultQuotaLimitText")));
  2500. TCHAR szValue[40];
  2501. HRESULT hr = m_pQC->GetDefaultQuotaLimitText(szValue, ARRAYSIZE(szValue));
  2502. if (SUCCEEDED(hr))
  2503. {
  2504. *pLimitText = SysAllocString(szValue);
  2505. if (NULL == *pLimitText)
  2506. {
  2507. hr = E_OUTOFMEMORY;
  2508. }
  2509. }
  2510. return hr;
  2511. }
  2512. STDMETHODIMP
  2513. DiskQuotaControlDisp::put_UserNameResolution(
  2514. UserNameResolutionConstants ResolutionType
  2515. )
  2516. {
  2517. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::put_UserNameResolution")));
  2518. if (dqResolveMaxValue < ResolutionType)
  2519. {
  2520. return E_INVALIDARG;
  2521. }
  2522. m_fOleAutoNameResolution = (DWORD)ResolutionType;
  2523. return NOERROR;
  2524. }
  2525. STDMETHODIMP
  2526. DiskQuotaControlDisp::get_UserNameResolution(
  2527. UserNameResolutionConstants *pResolutionType
  2528. )
  2529. {
  2530. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::get_UserNameResolution")));
  2531. if (NULL == pResolutionType)
  2532. return E_INVALIDARG;
  2533. *pResolutionType = (UserNameResolutionConstants)m_fOleAutoNameResolution;
  2534. return NOERROR;
  2535. }
  2536. //
  2537. // Dispatch method "Initialize"
  2538. //
  2539. // Initializes the quota control object for a given path and
  2540. // access mode. See DiskQuotaControl::Initialize for details.
  2541. //
  2542. STDMETHODIMP
  2543. DiskQuotaControlDisp::Initialize(
  2544. BSTR path,
  2545. VARIANT_BOOL bReadWrite
  2546. )
  2547. {
  2548. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::Initialize")));
  2549. //
  2550. // No exception handling required.
  2551. // DiskQuotaControl::Initialize handles exceptions.
  2552. //
  2553. return m_pQC->Initialize(reinterpret_cast<LPCWSTR>(path), VARIANT_TRUE == bReadWrite);
  2554. }
  2555. //
  2556. // Dispatch method "AddUser"
  2557. //
  2558. // Adds new user quota record.
  2559. // See DiskQuotaControl::AddUserName for details.
  2560. //
  2561. STDMETHODIMP
  2562. DiskQuotaControlDisp::AddUser(
  2563. BSTR LogonName,
  2564. DIDiskQuotaUser **ppUser
  2565. )
  2566. {
  2567. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::AddUser")));
  2568. //
  2569. // No exception handling required.
  2570. // DiskQuotaControl::AddUserName handles exceptions.
  2571. //
  2572. PDISKQUOTA_USER pUser = NULL;
  2573. HRESULT hr = m_pQC->AddUserName(reinterpret_cast<LPCWSTR>(LogonName),
  2574. m_fOleAutoNameResolution,
  2575. &pUser);
  2576. if (SUCCEEDED(hr))
  2577. {
  2578. //
  2579. // Retrieve the user object's IDispatch interface.
  2580. //
  2581. hr = pUser->QueryInterface(IID_IDispatch, (LPVOID *)ppUser);
  2582. pUser->Release();
  2583. }
  2584. return hr;
  2585. }
  2586. //
  2587. // Dispatch method "DeleteUser"
  2588. //
  2589. // Marks a user quota record for deletion.
  2590. // See DiskQuotaControl::DeleteUser for details.
  2591. //
  2592. STDMETHODIMP
  2593. DiskQuotaControlDisp::DeleteUser(
  2594. DIDiskQuotaUser *pUser
  2595. )
  2596. {
  2597. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::DeleteUser")));
  2598. HRESULT hr = E_INVALIDARG;
  2599. if (NULL != pUser)
  2600. {
  2601. //
  2602. // No exception handling required.
  2603. // DiskQuotaControl::DeleteUser handles exceptions.
  2604. //
  2605. PDISKQUOTA_USER pUserToDelete = NULL;
  2606. hr = pUser->QueryInterface(IID_IDiskQuotaUser, (LPVOID *)&pUserToDelete);
  2607. if (SUCCEEDED(hr))
  2608. {
  2609. hr = m_pQC->DeleteUser(pUserToDelete);
  2610. pUserToDelete->Release();
  2611. }
  2612. }
  2613. return hr;
  2614. }
  2615. //
  2616. // Dispatch method "FindUser"
  2617. //
  2618. // Locates a user quota entry based on the user's name strings.
  2619. // Creates a corresponding user object and returns it to the caller.
  2620. // See DiskQuotaControl::FindUserName for details.
  2621. //
  2622. STDMETHODIMP
  2623. DiskQuotaControlDisp::FindUser(
  2624. BSTR LogonName,
  2625. DIDiskQuotaUser **ppUser
  2626. )
  2627. {
  2628. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::FindUser")));
  2629. //
  2630. // No exception handling required.
  2631. // DiskQuotaControl::FindUserName handles exceptions.
  2632. //
  2633. HRESULT hr = NOERROR;
  2634. LPCWSTR pszName = reinterpret_cast<LPCWSTR>(LogonName);
  2635. PSID psid = NULL;
  2636. PDISKQUOTA_USER pUser = NULL;
  2637. if (ConvertStringSidToSid(pszName, &psid))
  2638. {
  2639. hr = m_pQC->FindUserSid(psid,
  2640. m_fOleAutoNameResolution,
  2641. &pUser);
  2642. LocalFree(psid);
  2643. psid = NULL;
  2644. }
  2645. else
  2646. {
  2647. hr = m_pQC->FindUserName(pszName, &pUser);
  2648. }
  2649. if (SUCCEEDED(hr))
  2650. {
  2651. DBGASSERT((NULL != pUser));
  2652. //
  2653. // Query for the user's IDispatch interface and release the pointer
  2654. // we received from FindUserName.
  2655. //
  2656. hr = pUser->QueryInterface(IID_IDispatch, (LPVOID *)ppUser);
  2657. pUser->Release();
  2658. }
  2659. return hr;
  2660. }
  2661. //
  2662. // Dispatch method "InvalidateSidNameCache"
  2663. //
  2664. // Invalidates the SID/Name cache.
  2665. // See DiskQuotaControl::InvalidateSidNameCache for details.
  2666. //
  2667. STDMETHODIMP
  2668. DiskQuotaControlDisp::InvalidateSidNameCache(
  2669. void
  2670. )
  2671. {
  2672. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::InvalidateSidNameCache")));
  2673. //
  2674. // No exception handling required.
  2675. // DiskQuotaControl::InvalidateSidNameCache handles exceptions.
  2676. //
  2677. return m_pQC->InvalidateSidNameCache();
  2678. }
  2679. //
  2680. // Dispatch method "GiveUserNameResolutionPriority"
  2681. //
  2682. // Promotes a user object to the front of the SID/Name resolver's input queue.
  2683. // See DiskQuotaControl::GiveUserNameResolutionPriority.
  2684. //
  2685. STDMETHODIMP
  2686. DiskQuotaControlDisp::GiveUserNameResolutionPriority(
  2687. DIDiskQuotaUser *pUser
  2688. )
  2689. {
  2690. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::GiveUserNameResolutionPriority")));
  2691. HRESULT hr = E_INVALIDARG;
  2692. if (NULL != pUser)
  2693. {
  2694. //
  2695. // No exception handling required.
  2696. // DiskQuotaControl::GiveUserNameResolutionPriority handles exceptions.
  2697. //
  2698. PDISKQUOTA_USER pUserToPromote = NULL;
  2699. hr = pUser->QueryInterface(IID_IDiskQuotaUser, (LPVOID *)&pUserToPromote);
  2700. if (SUCCEEDED(hr))
  2701. {
  2702. hr = m_pQC->GiveUserNameResolutionPriority(pUserToPromote);
  2703. pUserToPromote->Release();
  2704. }
  2705. }
  2706. return hr;
  2707. }
  2708. //
  2709. // This function is called by an automation controller when a new enumerator is
  2710. // required. In particular, Visual Basic calls it when it encounters a
  2711. // "for each" loop. The name "_NewEnum" is hard-wired and can't change.
  2712. //
  2713. STDMETHODIMP
  2714. DiskQuotaControlDisp::_NewEnum(
  2715. IDispatch **ppEnum
  2716. )
  2717. {
  2718. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::_NewEnum")));
  2719. HRESULT hr = E_INVALIDARG;
  2720. if (NULL != ppEnum)
  2721. {
  2722. try
  2723. {
  2724. //
  2725. // Create a Collection object using the current settings for
  2726. // name resolution.
  2727. //
  2728. DiskQuotaUserCollection *pCollection = new DiskQuotaUserCollection(m_pQC,
  2729. m_fOleAutoNameResolution);
  2730. hr = pCollection->Initialize();
  2731. if (SUCCEEDED(hr))
  2732. {
  2733. //
  2734. // The caller of _NewEnum (probably VB) wants the IEnumVARIANT
  2735. // interface.
  2736. //
  2737. hr = pCollection->QueryInterface(IID_IEnumVARIANT, (LPVOID *)ppEnum);
  2738. }
  2739. else
  2740. {
  2741. delete pCollection;
  2742. }
  2743. }
  2744. catch(CAllocException& e)
  2745. {
  2746. DBGERROR((TEXT("Insufficient memory exception")));
  2747. hr = E_OUTOFMEMORY;
  2748. }
  2749. }
  2750. return hr;
  2751. }
  2752. //
  2753. // Shutdown the SID/Name resolver. Note that this happens automatically
  2754. // when the control object is destroyed.
  2755. //
  2756. STDMETHODIMP
  2757. DiskQuotaControlDisp::ShutdownNameResolution(
  2758. VOID
  2759. )
  2760. {
  2761. DBGTRACE((DM_CONTROL, DL_HIGH, TEXT("DiskQuotaControlDisp::ShutdownNameResolution")));
  2762. return m_pQC->ShutdownNameResolution();
  2763. }
  2764. //
  2765. // Given a logon name in SAM-compatible or UPN format, translate
  2766. // the name to the corresponding account's SID. The returned SID is
  2767. // formatted as a string.
  2768. //
  2769. STDMETHODIMP
  2770. DiskQuotaControlDisp::TranslateLogonNameToSID(
  2771. BSTR LogonName,
  2772. BSTR *psid
  2773. )
  2774. {
  2775. NTDS ntds;
  2776. BYTE sid[MAX_SID_LEN];
  2777. SID_NAME_USE eSidUse;
  2778. DWORD cbSid = ARRAYSIZE(sid);
  2779. HRESULT hr = ntds.LookupAccountByName(NULL,
  2780. reinterpret_cast<LPCWSTR>(LogonName),
  2781. NULL,
  2782. NULL,
  2783. sid,
  2784. &cbSid,
  2785. &eSidUse);
  2786. if (SUCCEEDED(hr))
  2787. {
  2788. LPTSTR pszSid = NULL;
  2789. if (ConvertSidToStringSid((PSID)sid, &pszSid))
  2790. {
  2791. *psid = SysAllocString(pszSid);
  2792. if (NULL == *psid)
  2793. {
  2794. hr = E_OUTOFMEMORY;
  2795. }
  2796. LocalFree(pszSid);
  2797. pszSid = NULL;
  2798. }
  2799. else
  2800. {
  2801. hr = HRESULT_FROM_WIN32(GetLastError());
  2802. }
  2803. }
  2804. return hr;
  2805. }