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

459 lines
12 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000.
  5. //
  6. // File: statprop.cxx
  7. //
  8. // Contents: Code that encapsulates the stat property set on Nt file systems
  9. //
  10. //----------------------------------------------------------------------------
  11. #include <pch.cxx>
  12. #pragma hdrstop
  13. #include <ntopen.hxx>
  14. #include "statprop.hxx"
  15. //+---------------------------------------------------------------------------
  16. //
  17. // Construction/Destruction
  18. //
  19. //----------------------------------------------------------------------------
  20. //+---------------------------------------------------------------------------
  21. //
  22. // Member: CStatPropertyStorage::CStatPropertyStorage
  23. //
  24. // Synopsis: Construct a stat property enumerator by querying the
  25. // basic information from a handle
  26. //
  27. // Arguments: [FileHandle] - handle
  28. //
  29. // History: 10-Dec-97 KyleP Sum up streams to compute file size.
  30. //
  31. //----------------------------------------------------------------------------
  32. CStatPropertyStorage::CStatPropertyStorage( HANDLE FileHandle, unsigned cPathLength )
  33. : _RefCount( 1 ),
  34. _xBuf( (unsigned int)(1 +
  35. ( sizeof FILE_ALL_INFORMATION / sizeof LONGLONG ) +
  36. ( __max(
  37. (MAX_PATH * sizeof WCHAR) / sizeof LONGLONG,
  38. (cPathLength * sizeof WCHAR) / sizeof LONGLONG ) ) ) )
  39. {
  40. //
  41. // We use the FileAllInformation info level which is a bit of overkill,
  42. // but it has all the information we need to enumerate the properties.
  43. //
  44. IO_STATUS_BLOCK IoStatus;
  45. NTSTATUS Status = NtQueryInformationFile( FileHandle, // File handle
  46. &IoStatus, // I/O Status
  47. _xBuf.Get(), // Buffer
  48. _xBuf.SizeOf(), // Buffer size
  49. FileAllInformation );
  50. Win4Assert( STATUS_DATATYPE_MISALIGNMENT != Status );
  51. if ( !NT_SUCCESS(Status) )
  52. {
  53. ciDebugOut(( DEB_IERROR, "Error 0x%x querying file info\n",
  54. Status ));
  55. QUIETTHROW( CException( Status ));
  56. }
  57. //
  58. // Null-terminate in scratch buffer just beyond path
  59. //
  60. WCHAR * pwcsPathName = GetInfo().NameInformation.FileName;
  61. pwcsPathName[GetInfo().NameInformation.FileNameLength/sizeof(WCHAR)] = 0;
  62. //
  63. // Setup filename by looking for a '\'
  64. //
  65. _FileName = pwcsPathName;
  66. for ( int i = GetInfo().NameInformation.FileNameLength/sizeof(WCHAR) - 1; i >= 0; i-- )
  67. {
  68. if ( pwcsPathName[i] == L'\\' )
  69. {
  70. _FileName = &pwcsPathName[i+1];
  71. break;
  72. }
  73. }
  74. //
  75. // No longer necessary to sum the streams, now that CNSS uses sparse files to make
  76. // docfiles look larger. Using CiNtFileSize results in different file sizes depending
  77. // on which tool is used to look at the size (e.g. CI and 'dir' report differently).
  78. //
  79. #if 0
  80. //
  81. // Get the real file size (all streams)
  82. //
  83. LONGLONG llSize = CiNtFileSize( FileHandle );
  84. if ( -1 != llSize )
  85. GetInfo().StandardInformation.EndOfFile.QuadPart = llSize;
  86. #endif
  87. }
  88. //+---------------------------------------------------------------------------
  89. //
  90. // IUnknown method implementations
  91. //
  92. //----------------------------------------------------------------------------
  93. //+---------------------------------------------------------------------------
  94. //
  95. // Member: CStatPropertyStorage::QueryInterface
  96. //
  97. // Synopsis: Supports IID_IUnknown and IID_IPropertyStorage
  98. //
  99. // Arguments: [riid] - desired interface id
  100. // [ppvObject] - output interface pointer
  101. //
  102. //----------------------------------------------------------------------------
  103. STDMETHODIMP CStatPropertyStorage::QueryInterface(
  104. REFIID riid,
  105. void **ppvObject)
  106. {
  107. Win4Assert( 0 != ppvObject );
  108. if ( IID_IPropertyStorage == riid )
  109. *ppvObject = (void *)((IPropertyStorage *)this);
  110. else if ( IID_IUnknown == riid )
  111. *ppvObject = (void *)((IUnknown *)this);
  112. else
  113. {
  114. *ppvObject = 0;
  115. return E_NOINTERFACE;
  116. }
  117. AddRef();
  118. return S_OK;
  119. } //QueryInterface
  120. //+---------------------------------------------------------------------------
  121. //
  122. // Member: CStatPropertyStorage::AddRef
  123. //
  124. //----------------------------------------------------------------------------
  125. STDMETHODIMP_(ULONG) CStatPropertyStorage::AddRef()
  126. {
  127. return InterlockedIncrement(&_RefCount);
  128. } // AddRef
  129. //+---------------------------------------------------------------------------
  130. //
  131. // Member: CStatPropertyStorage::Release
  132. //
  133. //----------------------------------------------------------------------------
  134. STDMETHODIMP_(ULONG) CStatPropertyStorage::Release()
  135. {
  136. Win4Assert( _RefCount > 0 );
  137. LONG RefCount = InterlockedDecrement(&_RefCount);
  138. if ( RefCount <= 0 )
  139. delete this;
  140. return (ULONG) RefCount;
  141. } // Release
  142. //+---------------------------------------------------------------------------
  143. //
  144. // Member: CStatPropertyStorage::ReadMultiple
  145. //
  146. // Synopsis:
  147. //
  148. // Arguments:
  149. //
  150. // Returns: S_OK if successful
  151. //
  152. //
  153. //----------------------------------------------------------------------------
  154. STDMETHODIMP CStatPropertyStorage::ReadMultiple (
  155. THIS_ ULONG cpspec,
  156. const PROPSPEC __RPC_FAR rgpspec[ ],
  157. PROPVARIANT __RPC_FAR rgpropvar[ ] )
  158. {
  159. //
  160. // Walk through the prop specs looking for PID-identified
  161. // properties
  162. //
  163. for (ULONG i = 0; i < cpspec; i++) {
  164. //
  165. // String named properties are not found
  166. //
  167. PROPID PropertyId;
  168. if (rgpspec[i].ulKind == PRSPEC_LPWSTR) {
  169. PropertyId = 0xFFFFFFFF;
  170. } else {
  171. PropertyId = rgpspec[i].propid;
  172. }
  173. //
  174. // Fetch the appropriate property value
  175. //
  176. switch (PropertyId) {
  177. case PID_STG_SIZE:
  178. rgpropvar[i].vt = VT_I8;
  179. rgpropvar[i].hVal = GetInfo().StandardInformation.EndOfFile;
  180. break;
  181. case PID_STG_NAME:
  182. rgpropvar[i].vt = VT_LPWSTR;
  183. rgpropvar[i].pwszVal =
  184. (WCHAR *) CoTaskMemAlloc( (wcslen( _FileName ) + 1) * sizeof( WCHAR ));
  185. if ( 0 == rgpropvar[i].pwszVal )
  186. return E_OUTOFMEMORY;
  187. wcscpy( rgpropvar[i].pwszVal, _FileName );
  188. break;
  189. case PID_STG_ATTRIBUTES:
  190. rgpropvar[i].vt = VT_UI4;
  191. rgpropvar[i].ulVal = GetInfo().BasicInformation.FileAttributes;
  192. break;
  193. case PID_STG_WRITETIME:
  194. rgpropvar[i].vt = VT_FILETIME;
  195. rgpropvar[i].filetime =
  196. *(UNALIGNED FILETIME *)&GetInfo().BasicInformation.LastWriteTime.QuadPart;
  197. break;
  198. case PID_STG_CREATETIME:
  199. rgpropvar[i].vt = VT_FILETIME;
  200. rgpropvar[i].filetime =
  201. *(UNALIGNED FILETIME *)&GetInfo().BasicInformation.CreationTime.QuadPart;
  202. break;
  203. case PID_STG_ACCESSTIME:
  204. rgpropvar[i].vt = VT_FILETIME;
  205. rgpropvar[i].filetime =
  206. *(UNALIGNED FILETIME *)&GetInfo().BasicInformation.LastAccessTime.QuadPart;
  207. break;
  208. case PID_STG_CHANGETIME:
  209. rgpropvar[i].vt = VT_FILETIME;
  210. rgpropvar[i].filetime =
  211. *(UNALIGNED FILETIME *)&GetInfo().BasicInformation.ChangeTime.QuadPart;
  212. break;
  213. //
  214. // No other properties exist. They are Not Found.
  215. //
  216. default:
  217. rgpropvar[i].vt = VT_EMPTY;
  218. }
  219. }
  220. return S_OK;
  221. } //ReadMultiple
  222. //+---------------------------------------------------------------------------
  223. //
  224. // Member: CStatPropertyStorage::Enum
  225. //
  226. // Synopsis:
  227. //
  228. // Arguments:
  229. //
  230. // Returns: S_OK if successful
  231. //
  232. //
  233. //----------------------------------------------------------------------------
  234. STDMETHODIMP CStatPropertyStorage::Enum (
  235. THIS_ IEnumSTATPROPSTG __RPC_FAR *__RPC_FAR *ppenum )
  236. {
  237. *ppenum = new CStatPropertyEnum( IsNTFS() );
  238. return S_OK;
  239. }
  240. //+---------------------------------------------------------------------------
  241. //
  242. // IUnknown method implementations
  243. //
  244. //----------------------------------------------------------------------------
  245. //+---------------------------------------------------------------------------
  246. //
  247. // Member: CStatPropertyEnum::QueryInterface
  248. //
  249. // Synopsis: Supports IID_IUnknown and IID_IEnumSTATPROPSTG
  250. //
  251. // Arguments: [riid] - desired interface id
  252. // [ppvObject] - output interface pointer
  253. //
  254. //----------------------------------------------------------------------------
  255. STDMETHODIMP CStatPropertyEnum::QueryInterface(
  256. REFIID riid,
  257. void **ppvObject)
  258. {
  259. Win4Assert( 0 != ppvObject );
  260. if ( IID_IEnumSTATPROPSTG == riid )
  261. *ppvObject = (void *)((IEnumSTATPROPSTG *)this);
  262. else if ( IID_IUnknown == riid )
  263. *ppvObject = (void *)((IUnknown *)this);
  264. else
  265. {
  266. *ppvObject = 0;
  267. return E_NOINTERFACE;
  268. }
  269. AddRef();
  270. return S_OK;
  271. } //QueryInterface
  272. //+---------------------------------------------------------------------------
  273. //
  274. // Member: CStatPropertyEnum::AddRef
  275. //
  276. //----------------------------------------------------------------------------
  277. STDMETHODIMP_(ULONG) CStatPropertyEnum::AddRef()
  278. {
  279. return InterlockedIncrement(&_RefCount);
  280. } // AddRef
  281. //+---------------------------------------------------------------------------
  282. //
  283. // Member: CStatPropertyEnum::Release
  284. //
  285. //----------------------------------------------------------------------------
  286. STDMETHODIMP_(ULONG) CStatPropertyEnum::Release()
  287. {
  288. Win4Assert( _RefCount > 0 );
  289. LONG RefCount = InterlockedDecrement(&_RefCount);
  290. if ( RefCount <= 0 )
  291. delete this;
  292. return RefCount;
  293. } // Release
  294. //+---------------------------------------------------------------------------
  295. //
  296. // IEnumSTATPROPSTG method implementations
  297. //
  298. //----------------------------------------------------------------------------
  299. //+---------------------------------------------------------------------------
  300. //
  301. // Member: CStatPropertyEnum::Enum
  302. //
  303. // Synopsis: Enumerate through the stat properties
  304. //
  305. // Arguments: [celt] - maximum number of elements to return
  306. // [rgelt] - output stat structures
  307. // [pceltFetched] - number of elements returned
  308. //
  309. //----------------------------------------------------------------------------
  310. STDMETHODIMP CStatPropertyEnum::Next(
  311. ULONG celt,
  312. STATPROPSTG __RPC_FAR *rgelt,
  313. ULONG __RPC_FAR *pceltFetched )
  314. {
  315. //
  316. // We update the user's counter in place. Start it off at zero
  317. //
  318. *pceltFetched = 0;
  319. //
  320. // While we have more elements to return
  321. //
  322. while (celt--)
  323. {
  324. //
  325. // No stat properties have names
  326. //
  327. rgelt->lpwstrName = NULL;
  328. //
  329. // Retrieve the appropriate value from the enumeration
  330. //
  331. switch (_Index++)
  332. {
  333. case 0:
  334. rgelt->propid = PID_STG_CHANGETIME;
  335. rgelt->vt = VT_FILETIME;
  336. break;
  337. case 1:
  338. rgelt->propid = PID_STG_SIZE;
  339. rgelt->vt = VT_I8;
  340. break;
  341. case 2:
  342. rgelt->propid = PID_STG_NAME;
  343. rgelt->vt = VT_LPWSTR;
  344. break;
  345. case 3:
  346. rgelt->propid = PID_STG_ATTRIBUTES;
  347. rgelt->vt = VT_UI4;
  348. break;
  349. case 4:
  350. rgelt->propid = PID_STG_WRITETIME;
  351. rgelt->vt = VT_FILETIME;
  352. break;
  353. case 5:
  354. rgelt->propid = PID_STG_CREATETIME;
  355. rgelt->vt = VT_FILETIME;
  356. break;
  357. case 6:
  358. rgelt->propid = PID_STG_ACCESSTIME;
  359. rgelt->vt = VT_FILETIME;
  360. break;
  361. default:
  362. celt = 0;
  363. return S_OK;
  364. }
  365. //
  366. // Note that we have fetched a value and advance to the next
  367. // one.
  368. //
  369. (*pceltFetched)++;
  370. rgelt++;
  371. }
  372. return S_OK;
  373. }