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.

490 lines
14 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Copyright (C) Microsoft Corporation, 1991 - 1998
  4. //
  5. // File: dellog.cxx
  6. //
  7. // Contents: Deletion log for usns
  8. //
  9. // History: 28-Jul-97 SitaramR Created
  10. //
  11. //----------------------------------------------------------------------------
  12. #include <pch.cxx>
  13. #pragma hdrstop
  14. #include <mmstrm.hxx>
  15. #include "cicat.hxx"
  16. #include "dellog.hxx"
  17. const LONGLONG eSigDelLog = 0x64656c746e6c6f67i64; // Signature
  18. //+---------------------------------------------------------------------------
  19. //
  20. // Member: CFakeVolIdMap::CFakeVolIdMap
  21. //
  22. // Synopsis: Constructor
  23. //
  24. // History: 28-Jul-97 SitaramR Created
  25. //
  26. //----------------------------------------------------------------------------
  27. CFakeVolIdMap::CFakeVolIdMap()
  28. {
  29. for ( ULONG i=0; i<COUNT_SPECIAL_CHARS; i++)
  30. _aVolIdSpecial[i] = 0;
  31. }
  32. //+---------------------------------------------------------------------------
  33. //
  34. // Member: CFakeVolIdMap::VolIdToFakeVolId
  35. //
  36. // Synopsis: Converts a volume id to a fake volume id in the range
  37. // 0..RTL_MAX_DRIVE_LETTERS-1
  38. //
  39. // History: 28-Jul-97 SitaramR Created
  40. //
  41. // Notes: Drive letters in the range 'a' to 'z' are mapped by subtracting
  42. // 'a', which is the base volume id, i.e. they are in the range
  43. // 0..25 The volume id's for the remaining drive letters are
  44. // maintained in _aVolIdSpecial, and the fake volume ids for these
  45. // special drives are in the range 26..RTL_MAX_DRIVE_LETTERS-1.
  46. //
  47. //----------------------------------------------------------------------------
  48. ULONG CFakeVolIdMap::VolIdToFakeVolId( VOLUMEID volumeId )
  49. {
  50. //
  51. // Volume ids are obtained by the ascii value of the drive letter
  52. //
  53. Win4Assert( volumeId < 0xff );
  54. if ( volumeId >= VolumeIdBase
  55. && volumeId-VolumeIdBase < COUNT_ALPHABETS )
  56. {
  57. return volumeId-VolumeIdBase;
  58. }
  59. //
  60. // Lookup in _aVolIdSpecial
  61. //
  62. for ( ULONG i=0; i<COUNT_SPECIAL_CHARS; i++ )
  63. {
  64. if ( _aVolIdSpecial[i] == volumeId )
  65. return COUNT_ALPHABETS + i;
  66. }
  67. for ( i=0; i<COUNT_SPECIAL_CHARS; i++ )
  68. {
  69. if ( _aVolIdSpecial[i] == 0 )
  70. {
  71. _aVolIdSpecial[i] = volumeId;
  72. return COUNT_ALPHABETS + i;
  73. }
  74. }
  75. Win4Assert( !"Volume id map overflow" );
  76. return 0;
  77. }
  78. //+---------------------------------------------------------------------------
  79. //
  80. // Member: CFakeVolIdMap::FakeVolIdToVolId
  81. //
  82. // Synopsis: Converts a fake volume id in the range 0..RTL_MAX_DRIVE_LETTERS-1
  83. // to a real volume id
  84. //
  85. // History: 28-Jul-97 SitaramR Created
  86. //
  87. // Notes: See VolIdToFakeVolId for mapping info.
  88. //
  89. //----------------------------------------------------------------------------
  90. VOLUMEID CFakeVolIdMap::FakeVolIdToVolId( ULONG fakeVolId )
  91. {
  92. Win4Assert( fakeVolId < RTL_MAX_DRIVE_LETTERS );
  93. if ( fakeVolId < COUNT_ALPHABETS )
  94. return VolumeIdBase + fakeVolId;
  95. else
  96. return _aVolIdSpecial[fakeVolId-COUNT_ALPHABETS];
  97. }
  98. //+---------------------------------------------------------------------------
  99. //
  100. // Member: CDeletionLog::CDeletionLog
  101. //
  102. // Synopsis: Constructor
  103. //
  104. // Arguments: [fileIdMap] -- File id map
  105. // [cicat] -- Ci catalog
  106. //
  107. // History: 28-Jul-97 SitaramR Created
  108. //
  109. //----------------------------------------------------------------------------
  110. CDeletionLog::CDeletionLog( CFileIdMap & fileIdMap, CiCat& cicat )
  111. : _fileIdMap(fileIdMap),
  112. _cicat(cicat)
  113. {
  114. }
  115. //+---------------------------------------------------------------------------
  116. //
  117. // Member: CDeletionLog::FastInit
  118. //
  119. // Synopsis: Initialization
  120. //
  121. // Arguments: [pStorage] -- Ci storage
  122. // [pwcsCatDir] -- Catalog dir
  123. // [version] -- Version #
  124. //
  125. // History: 28-Jul-97 SitaramR Created
  126. // 02-Mar-98 KitmanH Used QueryDeletionlog to obtain a new
  127. // CMmStream
  128. //
  129. // Notes: The persistent format is <vol id><cEntries><entry 1>..<entry cEntries>
  130. // for each volume id, and each entry has <fileid><wid><usn>.
  131. //
  132. //----------------------------------------------------------------------------
  133. void CDeletionLog::FastInit( CiStorage * pStorage,
  134. ULONG version )
  135. {
  136. XPtr<PMmStream> sStrm( pStorage->QueryDeletionLog() );
  137. _xPersStream.Set( new CDynStream( sStrm.GetPointer() ) );
  138. sStrm.Acquire();
  139. _xPersStream->CheckVersion( *pStorage, version );
  140. ULONG cVolumes = _xPersStream->Count();
  141. _xPersStream->InitializeForRead();
  142. for ( ULONG i=0; i<cVolumes; i++ )
  143. {
  144. ULONG cbRead;
  145. LONGLONG llSig;
  146. cbRead = _xPersStream->Read( &llSig, sizeof(llSig) );
  147. if ( cbRead != sizeof(llSig) )
  148. FatalCorruption( cbRead, sizeof(llSig) );
  149. if ( eSigDelLog != llSig )
  150. {
  151. ciDebugOut(( DEB_ERROR,
  152. "CDeletionLog: Signature mismatch 0x%x:0x%x\n",
  153. lltoHighPart(llSig),
  154. lltoLowPart(llSig) ));
  155. FatalCorruption( 0, 0 );
  156. }
  157. VOLUMEID volumeId;
  158. cbRead = _xPersStream->Read( &volumeId, sizeof(VOLUMEID) );
  159. if ( cbRead != sizeof(VOLUMEID) )
  160. FatalCorruption( cbRead, sizeof(VOLUMEID) );
  161. ULONG cEntries;
  162. cbRead = _xPersStream->Read( &cEntries, sizeof(ULONG) );
  163. if ( cbRead != sizeof(ULONG) )
  164. FatalCorruption( cbRead, sizeof(ULONG) );
  165. for ( ULONG j=0; j<cEntries;j++ )
  166. {
  167. FILEID fileId;
  168. cbRead = _xPersStream->Read( &fileId, sizeof(FILEID) );
  169. if ( cbRead != sizeof(FILEID) )
  170. FatalCorruption( cbRead, sizeof(FILEID) );
  171. WORKID wid;
  172. cbRead = _xPersStream->Read( &wid, sizeof(WORKID) );
  173. if ( cbRead != sizeof(WORKID) )
  174. FatalCorruption( cbRead, sizeof(WORKID) );
  175. USN usn;
  176. cbRead = _xPersStream->Read( &usn, sizeof(USN) );
  177. if ( cbRead != sizeof(USN) )
  178. FatalCorruption( cbRead, sizeof(USN) );
  179. MarkForDeletion( volumeId,
  180. fileId,
  181. wid,
  182. usn );
  183. }
  184. }
  185. }
  186. //+---------------------------------------------------------------------------
  187. //
  188. // Member: CDeletionLog::ReInit
  189. //
  190. // Synopsis: Empties the deletion log
  191. //
  192. // History: 28-Jul-97 SitaramR Created
  193. //
  194. //----------------------------------------------------------------------------
  195. void CDeletionLog::ReInit( ULONG version )
  196. {
  197. CLock lock(_mutex);
  198. _xPersStream->SetVersion( version );
  199. for ( ULONG i=0; i<RTL_MAX_DRIVE_LETTERS; i++ )
  200. _aDelLogEntryList[i].Clear();
  201. Flush();
  202. }
  203. //+---------------------------------------------------------------------------
  204. //
  205. // Member: CDeletionLog::Flush
  206. //
  207. // Synopsis: Serializes the deletion log to disk
  208. //
  209. // History: 28-Jul-97 SitaramR Created
  210. //
  211. //----------------------------------------------------------------------------
  212. void CDeletionLog::Flush()
  213. {
  214. Win4Assert( !_xPersStream.IsNull() );
  215. CLock lock(_mutex);
  216. _xPersStream->InitializeForWrite( GetSize() );
  217. LONGLONG llSig = eSigDelLog;
  218. ULONG cVolumes = 0;
  219. for ( ULONG i=0; i<RTL_MAX_DRIVE_LETTERS; i++ )
  220. {
  221. if ( _aDelLogEntryList[i].Count() > 0 )
  222. {
  223. cVolumes++;
  224. _xPersStream->Write( &llSig, sizeof(llSig) );
  225. VOLUMEID volumeId = _fakeVolIdMap.FakeVolIdToVolId( i );
  226. _xPersStream->Write( &volumeId, sizeof(VOLUMEID) );
  227. ULONG cEntries = _aDelLogEntryList[i].Count();
  228. _xPersStream->Write( &cEntries, sizeof(ULONG) );
  229. #if CIDBG==1
  230. ULONG cEntriesInList = 0;
  231. USN usnPrev = 0;
  232. #endif
  233. for ( CDelLogEntryListIter entryListIter( _aDelLogEntryList[i] );
  234. !_aDelLogEntryList[i].AtEnd(entryListIter);
  235. _aDelLogEntryList[i].Advance( entryListIter) )
  236. {
  237. FILEID fileId = entryListIter->FileId();
  238. _xPersStream->Write( &fileId, sizeof(FILEID) );
  239. WORKID wid = entryListIter->WorkId();
  240. _xPersStream->Write( &wid, sizeof(WORKID) );
  241. USN usn = entryListIter->Usn();
  242. _xPersStream->Write( &usn, sizeof(USN) );
  243. #if CIDBG==1
  244. //
  245. // Check usn's are monotonically increasing
  246. //
  247. cEntriesInList++;
  248. Win4Assert( entryListIter->Usn() >= usnPrev );
  249. usnPrev = entryListIter->Usn();
  250. #endif
  251. }
  252. #if CIDBG==1
  253. Win4Assert( cEntriesInList == _aDelLogEntryList[i].Count() );
  254. #endif
  255. }
  256. }
  257. _xPersStream->SetCount( cVolumes );
  258. _xPersStream->Flush();
  259. }
  260. //+---------------------------------------------------------------------------
  261. //
  262. // Member: CDeletionLog::MarkForDeletion
  263. //
  264. // Synopsis: Adds a deletion entry
  265. //
  266. // History: 28-Jul-97 SitaramR Created
  267. //
  268. //----------------------------------------------------------------------------
  269. void CDeletionLog::MarkForDeletion( VOLUMEID volumeId,
  270. FILEID fileId,
  271. WORKID wid,
  272. USN usn )
  273. {
  274. CLock lock(_mutex);
  275. XPtr<CDelLogEntry> xEntry( new CDelLogEntry( fileId, wid, usn ) );
  276. ULONG fakeVolId = _fakeVolIdMap.VolIdToFakeVolId( volumeId );
  277. Win4Assert( fakeVolId < RTL_MAX_DRIVE_LETTERS );
  278. if ( _aDelLogEntryList[fakeVolId].Count() == 0 )
  279. {
  280. //
  281. // Empty list case
  282. //
  283. _aDelLogEntryList[fakeVolId].Queue( xEntry.Acquire() );
  284. }
  285. else
  286. {
  287. CDelLogEntry *pEntryLast = _aDelLogEntryList[fakeVolId].GetLast();
  288. if ( xEntry->Usn() > pEntryLast->Usn() )
  289. {
  290. //
  291. // If the usn is less than the last entry's usn, then it means that it
  292. // is a usn that is being replayed, and there is no need to add it
  293. // to the deletion log again.
  294. //
  295. _aDelLogEntryList[fakeVolId].Queue( xEntry.Acquire() );
  296. }
  297. }
  298. }
  299. //+---------------------------------------------------------------------------
  300. //
  301. // Member: CDeletionLog::ProcessChangesFlush
  302. //
  303. // Synopsis: Process the list of changes that has been flushed by
  304. // framework/changelog and do the actual deletes from
  305. // the file id map.
  306. //
  307. // Arguments: [usnFlushInfoList] -- List of changes flushed
  308. //
  309. // History: 28-Jul-97 SitaramR Created
  310. //
  311. //----------------------------------------------------------------------------
  312. void CDeletionLog::ProcessChangesFlush( CUsnFlushInfoList & usnFlushInfoList )
  313. {
  314. CLock lock( _mutex );
  315. for ( ULONG i=0; i<usnFlushInfoList.Count(); i++ )
  316. {
  317. CUsnFlushInfo *pFlushInfo = usnFlushInfoList.Get(i);
  318. ULONG fakeVolId = _fakeVolIdMap.VolIdToFakeVolId( pFlushInfo->VolumeId() );
  319. Win4Assert( fakeVolId < RTL_MAX_DRIVE_LETTERS );
  320. CDelLogEntryList& entryList = _aDelLogEntryList[fakeVolId];
  321. #if CIDBG==1
  322. USN usnPrev = 0;
  323. #endif
  324. CDelLogEntryListIter entryListIter( entryList );
  325. while ( !entryList.AtEnd( entryListIter ) )
  326. {
  327. CDelLogEntry *pEntry = entryListIter.GetEntry();
  328. entryList.Advance( entryListIter );
  329. #if CIDBG==1
  330. //
  331. // Check that usn's are monotonically increasing
  332. //
  333. Win4Assert( pEntry->Usn() >= usnPrev );
  334. usnPrev = pEntry->Usn();
  335. #endif
  336. if ( pEntry->Usn() <= pFlushInfo->UsnHighest() )
  337. {
  338. entryList.RemoveFromList( pEntry );
  339. _fileIdMap.Delete( pEntry->FileId(), pEntry->WorkId() );
  340. delete pEntry;
  341. }
  342. else
  343. {
  344. //
  345. // Since the list is in increasing usn order, we are done
  346. // with this volume id.
  347. //
  348. break;
  349. }
  350. }
  351. }
  352. }
  353. //+---------------------------------------------------------------------------
  354. //
  355. // Member: CDeletionLog::GetSize
  356. //
  357. // Synopsis: Returns the size of the serialized stream in bytes
  358. //
  359. // History: 28-Jul-97 SitaramR Created
  360. //
  361. //----------------------------------------------------------------------------
  362. ULONG CDeletionLog::GetSize()
  363. {
  364. //
  365. // Start with a slop factor
  366. //
  367. ULONG ulSize = 1024;
  368. for ( ULONG i=0; i<RTL_MAX_DRIVE_LETTERS; i++ )
  369. {
  370. ulSize += sizeof(VOLUMEID) // volume id field
  371. + sizeof(ULONG) // cEntries field
  372. + _aDelLogEntryList[i].Count() * sizeof(CDelLogEntry);
  373. }
  374. return ulSize;
  375. }
  376. //+---------------------------------------------------------------------------
  377. //
  378. // Member: CDeletionLog::FatalCorruption
  379. //
  380. // Synopsis: Handles deletion log corruption
  381. //
  382. // Arguments: [cbRead] -- Count of bytes read
  383. // [cbToRead] -- Count of bytes to read
  384. //
  385. // History: 28-Jul-97 SitaramR Created
  386. //
  387. //----------------------------------------------------------------------------
  388. void CDeletionLog::FatalCorruption( ULONG cbRead, ULONG cbToRead )
  389. {
  390. Win4Assert( !"Corrupt deletion log" );
  391. ciDebugOut(( DEB_ERROR,
  392. "CDeletionLog: read %d bytes instead of %d\n",
  393. cbRead,
  394. cbToRead ));
  395. PStorage & storage = _cicat.GetStorage();
  396. storage.ReportCorruptComponent( L"Deletion log" );
  397. THROW( CException( CI_CORRUPT_CATALOG ) );
  398. }