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.

4265 lines
116 KiB

  1. // Copyright (c) 1996-1999 Microsoft Corporation
  2. //+-------------------------------------------------------------------------
  3. //
  4. // trkwks.hxx
  5. //
  6. // Definitions local to this directory.
  7. //
  8. //--------------------------------------------------------------------------
  9. #ifndef _TRKWKS_HXX_
  10. #define _TRKWKS_HXX_
  11. #include "trklib.hxx"
  12. #include "wksconfig.hxx"
  13. #include <trkwks.h>
  14. #include <trksvr.h>
  15. #include <mountmgr.h> // MOUNTMGR_CHANGE_NOTIFY_INFO, MOUNTDEV_MOUNTED_DEVICE_GUID
  16. //
  17. // General defines
  18. //
  19. extern const GUID s_guidLogSignature;
  20. #ifndef EVENT_SOURCE_DEFINED
  21. #define EVENT_SOURCE_DEFINED
  22. const extern TCHAR* g_ptszEventSource INIT( TEXT("Distributed Link Tracking Client") );
  23. #endif
  24. TRKSVR_MESSAGE_PRIORITY
  25. GetSvrMessagePriority(
  26. LONGLONG llLastDue,
  27. LONGLONG llPeriod ); // pass in in seconds
  28. //+----------------------------------------------------------------------------
  29. //
  30. // CDirectoryName
  31. //
  32. // This class just holds a directory name, and offers a method
  33. // to create one from a file name.
  34. //
  35. //+----------------------------------------------------------------------------
  36. class CDirectoryName
  37. {
  38. private:
  39. // Name of the directory.
  40. TCHAR _tsz[ MAX_PATH + 1 ];
  41. public:
  42. // Assumes that ptszFile is an absolute path (either Win32
  43. // or NT).
  44. inline BOOL SetFromFileName( const TCHAR *ptszFile );
  45. inline operator const TCHAR *() const;
  46. };
  47. // Infer the directory name from a file name.
  48. inline BOOL
  49. CDirectoryName::SetFromFileName( const TCHAR *ptszFile )
  50. {
  51. // Compose the directory name by copying the path, finding its last
  52. // whack, and replacing it with a terminator.
  53. TCHAR *ptcTmp = NULL;
  54. _tcscpy( _tsz, ptszFile );
  55. ptcTmp = _tcsrchr( _tsz, TEXT('\\') );
  56. if(NULL == ptcTmp)
  57. {
  58. TrkLog((TRKDBG_ERROR, TEXT("Can't get directory name for (%s)"),
  59. ptszFile));
  60. return( FALSE );
  61. }
  62. *ptcTmp = TEXT('\0');
  63. return( TRUE );
  64. }
  65. // Return the directory name
  66. inline
  67. CDirectoryName::operator const TCHAR *() const
  68. {
  69. return( _tsz );
  70. }
  71. //+-------------------------------------------------------------------------
  72. //
  73. // CSecureFile
  74. //
  75. // A file only accessible to admins/system
  76. //
  77. // This class maintains the file handle. Note that
  78. // the file is opened asynchronous.
  79. //
  80. //--------------------------------------------------------------------------
  81. class CSecureFile
  82. {
  83. public:
  84. inline CSecureFile();
  85. inline ~CSecureFile();
  86. inline void Initialize();
  87. // Open/close/create operations
  88. inline BOOL IsOpen() const;
  89. inline void CloseFile();
  90. NTSTATUS CreateAlwaysSecureFile(const TCHAR * ptszFile);
  91. NTSTATUS CreateSecureDirectory( const TCHAR *ptszDirectory );
  92. NTSTATUS OpenExistingSecureFile( const TCHAR * ptszFile, BOOL fReadOnly );
  93. NTSTATUS RenameSecureFile( const TCHAR *ptszFile );
  94. // Win32 operations
  95. inline DWORD GetFileSize(LPDWORD lpFileSizeHigh = NULL);
  96. inline BOOL SetEndOfFile();
  97. inline DWORD SetFilePointer(LONG lDistanceToMove,
  98. PLONG lpDistanceToMoveHigh,
  99. DWORD dwMoveMethod);
  100. inline BOOL ReadFile( LPVOID lpBuffer,
  101. DWORD nNumberOfBytesToRead,
  102. LPDWORD lpNumberOfBytesRead,
  103. LPOVERLAPPED lpOverlapped = NULL);
  104. inline BOOL WriteFile(LPCVOID lpBuffer,
  105. DWORD nNumberOfBytesToWrite,
  106. LPDWORD lpNumberOfBytesWritten,
  107. LPOVERLAPPED lpOverlapped = NULL);
  108. protected:
  109. inline LONG Lock();
  110. inline LONG Unlock();
  111. protected:
  112. // Handle to the file.
  113. HANDLE _hFile;
  114. // Critical section for this class.
  115. CCriticalSection _csSecureFile;
  116. LONG _cLocks;
  117. }; // class CSecureFile
  118. inline
  119. CSecureFile::CSecureFile()
  120. {
  121. _hFile = NULL;
  122. _cLocks = 0;
  123. }
  124. inline void
  125. CSecureFile::Initialize()
  126. {
  127. // This routine can be called multiple times, since the log
  128. // file may be re-opened.
  129. if( !_csSecureFile.IsInitialized() )
  130. _csSecureFile.Initialize();
  131. }
  132. inline
  133. CSecureFile::~CSecureFile()
  134. {
  135. TrkAssert( _hFile == NULL );
  136. _csSecureFile.UnInitialize();
  137. }
  138. // Take the critical section
  139. inline LONG
  140. CSecureFile::Lock()
  141. {
  142. return InterlockedIncrement( &_cLocks );
  143. }
  144. // Leave the critical section
  145. inline LONG
  146. CSecureFile::Unlock()
  147. {
  148. LONG cLocks = _cLocks;
  149. InterlockedDecrement( &_cLocks );
  150. return( cLocks );
  151. }
  152. // Is _hFile open?
  153. inline BOOL
  154. CSecureFile::IsOpen() const
  155. {
  156. return(_hFile != NULL);
  157. }
  158. // Close _hFile
  159. inline void
  160. CSecureFile::CloseFile() // doesn't raise
  161. {
  162. LONG cLocks = Lock();
  163. __try
  164. {
  165. if( IsOpen() )
  166. NtClose( _hFile );
  167. }
  168. __except( BreakOnDebuggableException() )
  169. {
  170. TrkLog(( TRKDBG_ERROR, TEXT("Exception %08x in CSecureFile::CloseFile"), GetExceptionCode() ));
  171. }
  172. _hFile = NULL;
  173. #if DBG
  174. TrkVerify( Unlock() == cLocks );
  175. #else
  176. Unlock();
  177. #endif
  178. }
  179. // Ge the size of the file
  180. inline DWORD
  181. CSecureFile::GetFileSize(LPDWORD lpFileSizeHigh)
  182. {
  183. DWORD dwSize;
  184. LONG cLocks = Lock();
  185. {
  186. TrkAssert(IsOpen());
  187. dwSize = ::GetFileSize(_hFile, lpFileSizeHigh);
  188. }
  189. #if DBG
  190. TrkVerify( Unlock() == cLocks );
  191. #else
  192. Unlock();
  193. #endif
  194. return( dwSize );
  195. }
  196. // Set the size of the file
  197. inline BOOL
  198. CSecureFile::SetEndOfFile()
  199. {
  200. BOOL fReturn;
  201. LONG cLocks = Lock();
  202. {
  203. TrkAssert(IsOpen());
  204. fReturn = ::SetEndOfFile(_hFile);
  205. }
  206. #if DBG
  207. TrkVerify( Unlock() == cLocks );
  208. #else
  209. Unlock();
  210. #endif
  211. return( fReturn );
  212. }
  213. // Seek _hFile
  214. inline DWORD
  215. CSecureFile::SetFilePointer(LONG lDistanceToMove,
  216. PLONG lpDistanceToMoveHigh,
  217. DWORD dwMoveMethod)
  218. {
  219. DWORD dwReturn;
  220. LONG cLocks = Lock();
  221. {
  222. TrkAssert(IsOpen());
  223. dwReturn = ::SetFilePointer(_hFile, lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod);
  224. }
  225. #if DBG
  226. TrkVerify( Unlock() == cLocks );
  227. #else
  228. Unlock();
  229. #endif
  230. return( dwReturn );
  231. }
  232. // Read from _hFile
  233. inline BOOL
  234. CSecureFile::ReadFile( LPVOID lpBuffer,
  235. DWORD nNumberOfBytesToRead,
  236. LPDWORD lpNumberOfBytesRead,
  237. LPOVERLAPPED lpOverlapped)
  238. {
  239. BOOL fReturn;
  240. LONG cLocks = Lock();
  241. __try
  242. {
  243. TrkAssert(IsOpen());
  244. fReturn = ::ReadFile( _hFile,
  245. lpBuffer,
  246. nNumberOfBytesToRead,
  247. lpNumberOfBytesRead,
  248. lpOverlapped);
  249. }
  250. __finally
  251. {
  252. #if DBG
  253. TrkVerify( Unlock() == cLocks );
  254. #else
  255. Unlock();
  256. #endif
  257. }
  258. return( fReturn );
  259. }
  260. // Write to _hFile
  261. inline BOOL
  262. CSecureFile::WriteFile(LPCVOID lpBuffer,
  263. DWORD nNumberOfBytesToWrite,
  264. LPDWORD lpNumberOfBytesWritten,
  265. LPOVERLAPPED lpOverlapped)
  266. {
  267. BOOL fReturn;
  268. LONG cLocks = Lock();
  269. {
  270. TrkAssert(IsOpen());
  271. fReturn = ::WriteFile(_hFile,
  272. lpBuffer,
  273. nNumberOfBytesToWrite,
  274. lpNumberOfBytesWritten,
  275. lpOverlapped);
  276. }
  277. #if DBG
  278. TrkVerify( Unlock() == cLocks );
  279. #else
  280. Unlock();
  281. #endif
  282. return( fReturn );
  283. }
  284. //+-------------------------------------------------------------------------
  285. //
  286. // PRobustlyCreateableFile
  287. //
  288. // Abstraction of what makes a file robustly creatable
  289. //
  290. // Deals with creating the temporary file names used
  291. // when creating a file (or recreating a corrupt file)
  292. // and the transacted file rename operation (MoveFile)
  293. //
  294. //--------------------------------------------------------------------------
  295. enum RCF_RESULT
  296. {
  297. CORRUPT, // file closed after being found to be corrupt
  298. NOT_FOUND, // file not found
  299. OK // file now open after being validated as not corrupt
  300. // All other conditions result in an exception..
  301. };
  302. class PRobustlyCreateableFile
  303. {
  304. protected:
  305. void RobustlyCreateFile( const TCHAR * ptszFile, TCHAR tcVolumeDriveLetter );
  306. void RobustlyDeleteFile( const TCHAR * ptszFile );
  307. virtual RCF_RESULT OpenExistingFile( const TCHAR * ptszFile ) = 0;
  308. virtual void CreateAlwaysFile( const TCHAR * ptszTempFile ) = 0;
  309. };
  310. //+-------------------------------------------------------------------------
  311. //
  312. // CLogMoveMessage
  313. //
  314. // Structure for logging moves in the log
  315. //
  316. //--------------------------------------------------------------------------
  317. class CLogMoveMessage
  318. {
  319. public:
  320. CLogMoveMessage( const MOVE_MESSAGE & MoveMessage );
  321. // The link source's birth ID.
  322. CDomainRelativeObjId _droidBirth;
  323. // The link source's droid before the move.
  324. CDomainRelativeObjId _droidCurrent;
  325. // The link source's droid after the move.
  326. CDomainRelativeObjId _droidNew;
  327. // The machine to which the link source was moved.
  328. CMachineId _mcidNew;
  329. };
  330. inline
  331. CLogMoveMessage::CLogMoveMessage( const MOVE_MESSAGE & MoveMessage ) :
  332. _droidCurrent(
  333. CVolumeId(MoveMessage.SourceVolumeId), // LINK_TRACKING_INFORMATION
  334. CObjId(FOB_OBJECTID, MoveMessage.SourceObjectId) ), // FILE_OBJECTID_BUFFER
  335. _droidNew(
  336. CVolumeId(MoveMessage.TargetVolumeId), // LINK_TRACKING_INFORMATION
  337. CObjId(MoveMessage.TargetObjectId) ), // GUID
  338. _droidBirth(
  339. CVolumeId(MoveMessage.SourceObjectId), // FILE_OBJECTID_BUFFER
  340. CObjId(FOB_BIRTHID, MoveMessage.SourceObjectId) ), // FILE_OBJECTID_BUFFER
  341. _mcidNew( MoveMessage.MachineId )
  342. {
  343. }
  344. //+----------------------------------------------------------------------------
  345. //
  346. // Log-related structures
  347. //
  348. //+----------------------------------------------------------------------------
  349. //
  350. // The Tracking (Workstation) move notification log is used to cache
  351. // move notifications. We write to this log during the move, then
  352. // asynchronously copy the notifications up to the Tracking (Server)
  353. // service (the DC).
  354. //
  355. // The first sector of the log file is used for a header. There
  356. // is a primary header, and an 'extended' header. The extended
  357. // header area is used as a general storage area by clients
  358. // of CLogFile.
  359. //
  360. // The rest of the file is composed of a doubly-linked list of
  361. // move notifications. Each notification is always wholly within
  362. // a sector, so we can assume that a notification is always written
  363. // atomically. Every time we write a move notification, we need to
  364. // update some log meta-data. Instead of writing this to the log
  365. // header, which would require us to do two sector writes and
  366. // therefore require us to add transactioning, we write the meta
  367. // data to an "entry header", which is at the end of each sector.
  368. // So each of the sectors beyond sector 0 has a few move notifications
  369. // and an entry-header.
  370. //
  371. // If necessary we can grow the log file, initializing the new area as
  372. // a linked list, and linking it into the existing list. The structure
  373. // is shown below.
  374. //
  375. // +------------------------------+ <---+
  376. // | Log Header | |
  377. // | | |
  378. // | -------------------------- | |
  379. // | | +---- Sector 0
  380. // | Extended Header: | |
  381. // | Log Info | |
  382. // | Volume Persistent Info | |
  383. // | | |
  384. // +------------------------------+ <---+
  385. // | | |
  386. // | Log Move Notification | |
  387. // | | |
  388. // | -------------------------- | |
  389. // | | |
  390. // | Log Move Notification | |
  391. // | | |
  392. // | -------------------------- | +---- Sectors 1 - n
  393. // | | |
  394. // | Log Move Notification | |
  395. // | | |
  396. // | -------------------------- | |
  397. // | | |
  398. // | Log Entry Header | |
  399. // +------------------------------+ |
  400. // * |
  401. // * |
  402. // *
  403. //
  404. // There are four classes which combine to provide access to the log
  405. // file. The outermost class is CLog, and it is through this class
  406. // that most of the code accesses the log. CLog, though, relies
  407. // on the CLogFile class to maintain the physical layout of the file;
  408. // CLog understands, e.g., move notifications, while CLogFile just
  409. // understands the header and the linked-list of log entries.
  410. // CLogFile relies on the CLogFileHeader and CLogFileSector helper
  411. // classes.
  412. //
  413. // PerfBug: Note that if we ever modify this log format,
  414. // we should get rid of the source volid from the move
  415. // notification entries (or some other similar optimization);
  416. // since a log applies to a volume, the volid is usually
  417. // redundant.
  418. // The format (version) of the log is in major/minor form
  419. // (16 bits for each). Incrementing the minor revision level
  420. // indicates a change to the log that is compatible with
  421. // downlevel versions. Such versions, though, should set
  422. // the DownlevelDirtied flag in the header to indicate that
  423. // uplevel versions may need to do a cleanup.
  424. #define CLOG_MAJOR_FORMAT 0x1
  425. #define CLOG_MINOR_FORMAT 0x0
  426. #define CLOG_FORMAT ( (CLOG_MAJOR_FORMAT<<16) | CLOG_MINOR_FORMAT )
  427. inline WORD
  428. GetLogMajorFormat( DWORD dw )
  429. {
  430. return( dw >> 16 );
  431. }
  432. inline WORD
  433. GetLogMinorFormat( DWORD dw )
  434. {
  435. return( dw & 0xFFFF );
  436. }
  437. // A LogIndex is a zero-based index of log entries
  438. // in the *physical* file. It cannot, for example, be advanced simply
  439. // by incrementing, it must be advanced by traversing the linked-list.
  440. typedef unsigned long LogIndex; // ilog
  441. // Types of an entry in the log
  442. typedef enum enumLE_TYPE
  443. {
  444. LE_TYPE_UNINITIALIZED = 0,
  445. LE_TYPE_EMPTY = 1,
  446. LE_TYPE_MOVE = 2
  447. } LE_TYPE;
  448. // A move notification structure shows all the necessary
  449. // information about a move; where it was born, where it
  450. // was a moment ago, and where it's moved to. This
  451. // structure is written to the workstation tracking log.
  452. // BUGBUG: Use a compression (lookup table) so that in the
  453. // typical case where all the volids are the same, we don't
  454. // need to use 16 bytes here.
  455. typedef struct // lmn
  456. {
  457. // Type (empty or move)
  458. LE_TYPE type;
  459. // Sequence number for this entry, used to keep
  460. // in sync with trksvr.
  461. SequenceNumber seq;
  462. // Reserved for future use
  463. DWORD iVolIdCurrent;
  464. // Object ID before the move.
  465. CObjId objidCurrent;
  466. // Droid after the move.
  467. CDomainRelativeObjId droidNew;
  468. // Machine to which the file was moved.
  469. CMachineId mcidNew;
  470. // Birth ID of the link source.
  471. CDomainRelativeObjId droidBirth;
  472. // Time of the move.
  473. DWORD DateWritten;
  474. // Reserved for future use.
  475. DWORD dwReserved;
  476. } LogMoveNotification;
  477. // The LogHeader structure is maintained by CLogFile, and
  478. // stores general data about the log has a whole.
  479. // This structure is always stored at the very beginning of the file.
  480. // If the shutdown bit is not set, then CLogFile performs a recovery.
  481. // Clients of CLogFile (i.e. CLog) then have an opportunity to perform
  482. // their own recovery.
  483. #define NUM_HEADER_SECTORS 1
  484. enum ELogHeaderFlags
  485. {
  486. PROPER_SHUTDOWN = 0x1, // Indicates log shutdown properly
  487. DOWNLEVEL_DIRTIED = 0x2 // Indicates a downlevel implemetation touched log.
  488. };
  489. typedef struct _LogHeader
  490. {
  491. GUID guidSignature; // Signature for the log
  492. DWORD dwFormat; // Version of the log
  493. DWORD dwFlags; // ELogHeaderFlags enum
  494. DWORD dwReserved;
  495. // The 'expand' sub-structure holds the dimensions of
  496. // a log before it's expanded. If we crash during the
  497. // expand, we'll use this info to restore the log to it's
  498. // pre-expansion shape.
  499. struct
  500. {
  501. LogIndex ilogStart;
  502. LogIndex ilogEnd;
  503. ULONG cbFile;
  504. } expand;
  505. inline BOOL IsShutdown( ) const
  506. {
  507. return( 0 != (dwFlags & PROPER_SHUTDOWN) );
  508. }
  509. inline BOOL IsDownlevelDirtied( ) const
  510. {
  511. return( 0 != (dwFlags & DOWNLEVEL_DIRTIED) );
  512. }
  513. } LogHeader;
  514. // The LogInfo structure is used by the workstation service to store
  515. // the runtime log information. This information can also be
  516. // determined by reading through the log, so this is really a
  517. // cache of information. Since this data can be re-calculated
  518. // (albeit slowly), we don't bother to write it to disk every time
  519. // we update it. It's just used to save some time during an Open
  520. // in the normal case where the log was previously shutdown properly.
  521. // This structure is stored in the log header, after the LogHeader
  522. // structure, as part of the 'extended' log header area.
  523. typedef struct _LogInfo
  524. {
  525. LogIndex ilogStart; // The beginning of the linked-list
  526. LogIndex ilogEnd; // The end of the linked-list
  527. LogIndex ilogWrite; // The next entry to be written
  528. LogIndex ilogRead; // The next entry to be read
  529. LogIndex ilogLast; // The most entry most recently written
  530. SequenceNumber seqNext; // The new seq num to use
  531. SequenceNumber seqLastRead; // The seq num of entry[ilogRead-1]
  532. } LogInfo;
  533. // The VolumePersistentInfo structure is stored in the log
  534. // header, also as part of the 'extended' log header area,
  535. // and allows us to detect when a volume has been moved or
  536. // a machine has been renamed. In such an event, the password
  537. // allows us to re-claim the volume with the DC.
  538. typedef struct _VolumePersistentInfo
  539. {
  540. CMachineId machine;
  541. CVolumeId volid;
  542. CVolumeSecret secret;
  543. CFILETIME cftLastRefresh;
  544. CFILETIME cftEnterNotOwned;
  545. BOOL fDoMakeAllOidsReborn;
  546. BOOL fNotCreated;
  547. void Initialize()
  548. {
  549. memset(this, 0, sizeof(struct _VolumePersistentInfo));
  550. machine = CMachineId();
  551. volid = CVolumeId();
  552. secret = CVolumeSecret();
  553. cftLastRefresh = cftEnterNotOwned = CFILETIME(0);
  554. //fDoMakeAllOidsReborn = fNotCreated = FALSE;
  555. }
  556. BOOL operator == (const struct _VolumePersistentInfo & volinfo) const
  557. {
  558. return( machine == volinfo.machine
  559. &&
  560. volid == volinfo.volid
  561. &&
  562. secret == volinfo.secret
  563. &&
  564. cftLastRefresh == volinfo.cftLastRefresh
  565. &&
  566. cftEnterNotOwned == volinfo.cftEnterNotOwned
  567. );
  568. }
  569. BOOL operator != (const struct _VolumePersistentInfo & volinfo) const
  570. {
  571. return( !(*this == volinfo) );
  572. }
  573. } VolumePersistentInfo;
  574. // These defines determine how the ExtendedHeader area is divied up.
  575. // (We'll ensure that this doesn't exceed 512 - sizeof(LogHeader) bytes,
  576. // and assume that sectors are always >= 512).
  577. #define CVOLUME_HEADER_START 0
  578. #define CVOLUME_HEADER_LENGTH sizeof(VolumePersistentInfo)
  579. #define CLOG_LOGINFO_START (CVOLUME_HEADER_START + CVOLUME_HEADER_LENGTH)
  580. #define CLOG_LOGINFO_LENGTH sizeof(LogInfo)
  581. #define CB_EXTENDED_HEADER ( CLOG_LOGINFO_START + CLOG_LOGINFO_LENGTH )
  582. // We require that the volume's sector size be at least 256
  583. #define MIN_LOG_SECTOR_SIZE 256
  584. // The following structure defines a header which is conceptually
  585. // associate with an entry. When a client writes to an entry
  586. // header, all previous entry headers are considered invalid.
  587. // In truth, this header is stored per-sector rather than
  588. // per-entry, but this is opaque to the client (CLogFile).
  589. typedef struct _LogEntryHeader
  590. {
  591. LogIndex ilogRead; // Next record to be uploaded to the server
  592. SequenceNumber seq; // Next sequence number to use (during a write)
  593. DWORD rgdwReserved[2];
  594. } LogEntryHeader;
  595. // An entry in the log. CLogFile sees LogEntry, CLog only sees the 'move' field.
  596. // The log is composed of a header sector (with LogHeader and the extended
  597. // header area), followed by a linked-list of LogEntry's.
  598. typedef struct tagLogEntry // le
  599. {
  600. LogIndex ilogNext;
  601. LogIndex ilogPrevious;
  602. LogMoveNotification move;
  603. } LogEntry;
  604. // Types of flushes
  605. #define FLUSH_IF_DIRTY 0
  606. #define FLUSH_UNCONDITIONALLY 1
  607. #define FLUSH_TO_CACHE 0
  608. #define FLUSH_THROUGH_CACHE 2
  609. //+----------------------------------------------------------------------------
  610. //
  611. // Class: CLogFileHeader
  612. //
  613. // This class represents the header portion of the log file. It is used
  614. // exclusively by CLogFile, and therefore provides no thread-safety mechanisms
  615. // of its own.
  616. //
  617. // The dirty bit is automatically maintained, and flushes are automatic,
  618. // though the caller may still make explicit flushes.
  619. //
  620. //+----------------------------------------------------------------------------
  621. #define C_LOG_FILE_HEADER_SECTORS 1
  622. class CLogFileHeader
  623. {
  624. // ------------
  625. // Construction
  626. // ------------
  627. public:
  628. CLogFileHeader()
  629. {
  630. memset( this, 0, sizeof(*this) );
  631. _hFile = NULL;
  632. }
  633. ~CLogFileHeader()
  634. {
  635. UnInitialize();
  636. }
  637. // --------------
  638. // Initialization
  639. // --------------
  640. public:
  641. void Initialize( ULONG cbSector );
  642. void UnInitialize();
  643. // ---------------
  644. // Exposed Methods
  645. // ---------------
  646. public:
  647. void OnCreate( HANDLE hFile );
  648. void OnOpen( HANDLE hFile );
  649. BOOL IsOpen() const;
  650. BOOL IsDirty() const;
  651. void OnClose();
  652. void SetShutdown( BOOL fShutdown = TRUE );
  653. void SetDirty( BOOL fDirty = TRUE );
  654. GUID GetSignature() const;
  655. DWORD GetFormat() const;
  656. WORD GetMajorFormat() const;
  657. WORD GetMinorFormat() const;
  658. void SetDownlevelDirtied();
  659. ULONG NumSectors() const;
  660. BOOL IsShutdown() const;
  661. void Flush( );
  662. void SetExpansionData( ULONG cbLogFile, ULONG ilogStart, ULONG ilogEnd );
  663. void ClearExpansionData();
  664. BOOL IsExpansionDataClear();
  665. BOOL ExpansionInProgress() const;
  666. ULONG GetPreExpansionSize() const;
  667. LogIndex GetPreExpansionStart() const;
  668. LogIndex GetPreExpansionEnd() const;
  669. void ReadExtended( ULONG iOffset, void *pv, ULONG cb );
  670. void WriteExtended( ULONG iOffset, const void *pv, ULONG cb );
  671. // ----------------
  672. // Internal Methods
  673. // ----------------
  674. private:
  675. void LoadHeader( HANDLE hFile );
  676. void RaiseIfNotOpen() const;
  677. // --------------
  678. // Internal State
  679. // --------------
  680. private:
  681. // Should the header be flushed?
  682. BOOL _fDirty:1;
  683. // The underlying log file. This is only non-NULL if the header has
  684. // been successfully loaded.
  685. HANDLE _hFile;
  686. // The beginning of the sector containing the header
  687. LogHeader *_plogheader;
  688. // The extended portion of the header (points within the buffer
  689. // pointed to by _plogheader).
  690. void *_pextendedheader;
  691. // The size of the header sector.
  692. ULONG _cbSector;
  693. };
  694. // ----------------------
  695. // CLogFileHeader inlines
  696. // ----------------------
  697. // How many sectors are used by the header?
  698. inline ULONG
  699. CLogFileHeader::NumSectors() const
  700. {
  701. return( C_LOG_FILE_HEADER_SECTORS );
  702. }
  703. inline void
  704. CLogFileHeader::RaiseIfNotOpen() const
  705. {
  706. if( NULL == _plogheader || !IsOpen() )
  707. TrkRaiseWin32Error( ERROR_OPEN_FAILED );
  708. }
  709. // Set the shutdown flag
  710. inline void
  711. CLogFileHeader::SetShutdown( BOOL fShutdown )
  712. {
  713. RaiseIfNotOpen();
  714. // If this is a new shutdown state, we must flush to disk.
  715. if( _plogheader->IsShutdown() && !fShutdown
  716. ||
  717. !_plogheader->IsShutdown() && fShutdown )
  718. {
  719. if( fShutdown )
  720. _plogheader->dwFlags |= PROPER_SHUTDOWN;
  721. else
  722. _plogheader->dwFlags &= ~PROPER_SHUTDOWN;
  723. _fDirty = TRUE;
  724. Flush();
  725. }
  726. }
  727. // Get the log signature
  728. inline GUID
  729. CLogFileHeader::GetSignature() const
  730. {
  731. RaiseIfNotOpen();
  732. return( _plogheader->guidSignature );
  733. }
  734. // Get the format version of the log
  735. inline DWORD
  736. CLogFileHeader::GetFormat() const
  737. {
  738. RaiseIfNotOpen();
  739. return( _plogheader->dwFormat );
  740. }
  741. inline WORD
  742. CLogFileHeader::GetMajorFormat() const
  743. {
  744. RaiseIfNotOpen();
  745. return( _plogheader->dwFormat >> 16 );
  746. }
  747. inline WORD
  748. CLogFileHeader::GetMinorFormat() const
  749. {
  750. RaiseIfNotOpen();
  751. return( _plogheader->dwFormat & 0xFFFF );
  752. }
  753. // Show that the log file has been touched by a downlevel
  754. // implementation (i.e. one that supported the same major
  755. // version level, but an older minor version level).
  756. inline void
  757. CLogFileHeader::SetDownlevelDirtied()
  758. {
  759. // The act of setting this bit doesn't itself make
  760. // the header dirty.
  761. RaiseIfNotOpen();
  762. _plogheader->dwFlags |= DOWNLEVEL_DIRTIED;
  763. }
  764. // Has the log been properly shut down?
  765. inline BOOL
  766. CLogFileHeader::IsShutdown() const
  767. {
  768. RaiseIfNotOpen();
  769. return( _plogheader->IsShutdown() );
  770. }
  771. // Was the log closed while an expansion was in progress?
  772. inline BOOL
  773. CLogFileHeader::ExpansionInProgress() const
  774. {
  775. RaiseIfNotOpen();
  776. return( 0 != _plogheader->expand.cbFile );
  777. }
  778. // How big was the log before the expansion started?
  779. inline ULONG
  780. CLogFileHeader::GetPreExpansionSize() const
  781. {
  782. RaiseIfNotOpen();
  783. return( _plogheader->expand.cbFile );
  784. }
  785. // Where did the log start before the expansion started?
  786. inline LogIndex
  787. CLogFileHeader::GetPreExpansionStart() const
  788. {
  789. RaiseIfNotOpen();
  790. return( _plogheader->expand.ilogStart );
  791. }
  792. // Where did the log end before the expansion started?
  793. inline LogIndex
  794. CLogFileHeader::GetPreExpansionEnd() const
  795. {
  796. RaiseIfNotOpen();
  797. return( _plogheader->expand.ilogEnd );
  798. }
  799. // Clear the expansion data and flush it to the disk
  800. // (called after an expansion).
  801. inline void
  802. CLogFileHeader::ClearExpansionData()
  803. {
  804. RaiseIfNotOpen();
  805. memset( &_plogheader->expand, 0, sizeof(_plogheader->expand) );
  806. Flush( );
  807. }
  808. // Is there no expansion data?
  809. inline BOOL
  810. CLogFileHeader::IsExpansionDataClear()
  811. {
  812. RaiseIfNotOpen();
  813. if(_plogheader->expand.ilogStart == 0 &&
  814. _plogheader->expand.ilogEnd == 0 &&
  815. _plogheader->expand.cbFile == 0)
  816. {
  817. return TRUE;
  818. }
  819. return FALSE;
  820. }
  821. // Handle a file create event
  822. inline void
  823. CLogFileHeader::OnCreate( HANDLE hFile )
  824. {
  825. TrkAssert( NULL == _hFile );
  826. TrkAssert( NULL != hFile );
  827. TrkAssert( NULL != _plogheader );
  828. // Initialize the header
  829. memset( _plogheader, 0, _cbSector );
  830. _plogheader->dwFormat = CLOG_FORMAT;
  831. _plogheader->guidSignature = s_guidLogSignature;
  832. _hFile = hFile;
  833. SetDirty();
  834. }
  835. // Handle a file Open event
  836. inline void
  837. CLogFileHeader::OnOpen( HANDLE hFile )
  838. {
  839. #if DBG
  840. TrkAssert( NULL == _hFile );
  841. TrkAssert( NULL != hFile );
  842. #endif
  843. LoadHeader( hFile );
  844. }
  845. // Is the file open?
  846. inline BOOL
  847. CLogFileHeader::IsOpen() const
  848. {
  849. return( NULL != _hFile );
  850. }
  851. // Is the file dirty?
  852. inline BOOL
  853. CLogFileHeader::IsDirty() const
  854. {
  855. return( _fDirty );
  856. }
  857. // Handle a file Close event
  858. inline void
  859. CLogFileHeader::OnClose()
  860. {
  861. #if DBG
  862. if( _fDirty )
  863. TrkLog(( TRKDBG_ERROR, TEXT("LogFileHeader closed while dirty") ));
  864. #endif
  865. _fDirty = FALSE;
  866. _hFile = NULL;
  867. }
  868. // Set/clear the dirty bit
  869. inline void
  870. CLogFileHeader::SetDirty( BOOL fDirty )
  871. {
  872. _fDirty = fDirty;
  873. if( _fDirty )
  874. SetShutdown( FALSE );
  875. }
  876. //+----------------------------------------------------------------------------
  877. //
  878. // Class: CLogFileSector
  879. //
  880. // This class represents the sectors of the log file, and is used exclusively
  881. // by the CLogFile class. Therefore, it provides no thread-safety mechanisms
  882. // of its own.
  883. //
  884. // The dirty bit and flushes are maintained automatically, though the caller
  885. // may still make explicite flushes.
  886. //
  887. //+----------------------------------------------------------------------------
  888. class CLogFileSector
  889. {
  890. // ------------
  891. // Construction
  892. // ------------
  893. public:
  894. CLogFileSector()
  895. {
  896. memset( this, 0, sizeof(*this) );
  897. _hFile = NULL;
  898. }
  899. ~CLogFileSector()
  900. {
  901. UnInitialize();
  902. }
  903. // --------------
  904. // Initialization
  905. // --------------
  906. public:
  907. void Initialize( ULONG cSkipSectors, ULONG cbSector );
  908. void UnInitialize();
  909. // ---------------
  910. // Exposed Methods
  911. // ---------------
  912. public:
  913. void SetDirty( BOOL fDirty = TRUE );
  914. void Flush( );
  915. ULONG NumEntries() const;
  916. void OnCreate( HANDLE hFile );
  917. void OnOpen( HANDLE hFile );
  918. BOOL IsOpen() const;
  919. BOOL IsDirty() const;
  920. void OnClose();
  921. void InitSectorHeader();
  922. LogEntry *GetLogEntry( LogIndex ilogEntry ); // Sets the dirty flag
  923. const LogEntry *ReadLogEntry( LogIndex ilogEntry ); // Doesn't set dirty
  924. void WriteMoveNotification( LogIndex ilogEntry, const LogMoveNotification &lmn );
  925. LogEntryHeader ReadEntryHeader( LogIndex ilogEntry );
  926. void WriteEntryHeader( LogIndex ilogEntry, LogEntryHeader entryheader );
  927. // ----------------
  928. // Internal Methods
  929. // ----------------
  930. private:
  931. void LoadSector( LogIndex ilogEntry );
  932. void RaiseIfNotOpen() const;
  933. // --------------
  934. // Internal State
  935. // --------------
  936. private:
  937. // Is _pvSector valid?
  938. BOOL _fValid:1;
  939. // Are we dirty?
  940. BOOL _fDirty:1;
  941. // A handle to the log file
  942. HANDLE _hFile;
  943. // How many sectors aren't we allowed to use at
  944. // the front of the log file?
  945. ULONG _cSkipSectors;
  946. // The size of the sector, and the number of entries it can hold
  947. ULONG _cbSector;
  948. ULONG _cEntriesPerSector;
  949. // The index of the entry which is at the front
  950. // of _pvSector
  951. LogIndex _ilogCurrentFirst;
  952. // Points to the loaded sector (when _fValid)
  953. void *_pvSector;
  954. // Points to the entry header of the valid sector
  955. LogEntryHeader *_pEntryHeader;
  956. };
  957. // ------------------
  958. // CLogSector Inlines
  959. // ------------------
  960. // Called when a log file is created.
  961. inline void
  962. CLogFileSector::OnCreate( HANDLE hFile )
  963. {
  964. OnOpen( hFile );
  965. }
  966. inline void
  967. CLogFileSector::RaiseIfNotOpen() const
  968. {
  969. if( NULL == _pvSector || !IsOpen() )
  970. TrkRaiseWin32Error( ERROR_OPEN_FAILED );
  971. }
  972. // Called when a log file is opened.
  973. inline void
  974. CLogFileSector::OnOpen( HANDLE hFile )
  975. {
  976. #if DBG
  977. TrkAssert( NULL != _pvSector );
  978. TrkAssert( NULL == _hFile );
  979. TrkAssert( NULL != hFile );
  980. #endif
  981. _hFile = hFile;
  982. }
  983. inline BOOL
  984. CLogFileSector::IsOpen() const
  985. {
  986. return( NULL != _hFile );
  987. }
  988. inline void
  989. CLogFileSector::InitSectorHeader()
  990. {
  991. if( NULL != _pEntryHeader )
  992. memset( _pEntryHeader, 0, sizeof(*_pEntryHeader) );
  993. }
  994. inline BOOL
  995. CLogFileSector::IsDirty() const
  996. {
  997. return( _fDirty );
  998. }
  999. // Called when a log file is closed
  1000. inline void
  1001. CLogFileSector::OnClose()
  1002. {
  1003. #if DBG
  1004. if( _fDirty )
  1005. TrkLog(( TRKDBG_ERROR, TEXT("LogFileSector closed while dirty") ));
  1006. #endif
  1007. _fDirty = FALSE;
  1008. _hFile = NULL;
  1009. _fValid = FALSE;
  1010. }
  1011. // Set the dirty bit
  1012. inline void
  1013. CLogFileSector::SetDirty( BOOL fDirty )
  1014. {
  1015. RaiseIfNotOpen();
  1016. _fDirty = fDirty;
  1017. }
  1018. // Read & return the requested log entry. Note that the
  1019. // sector is now considered dirty (unlike ReadLogEntry)
  1020. inline LogEntry*
  1021. CLogFileSector::GetLogEntry( LogIndex ilogEntry )
  1022. {
  1023. TrkAssert( _pvSector );
  1024. RaiseIfNotOpen();
  1025. LoadSector( ilogEntry );
  1026. SetDirty();
  1027. return( &static_cast<LogEntry*>(_pvSector)[ ilogEntry - _ilogCurrentFirst ] );
  1028. }
  1029. // Read & return the requested log entry. The sector
  1030. // is not subsequently considered dirty (unlike GetLogEntry)
  1031. inline const LogEntry*
  1032. CLogFileSector::ReadLogEntry( LogIndex ilogEntry )
  1033. {
  1034. TrkAssert( _pvSector );
  1035. RaiseIfNotOpen();
  1036. LoadSector( ilogEntry );
  1037. return( &static_cast<const LogEntry*>(_pvSector)[ ilogEntry - _ilogCurrentFirst ] );
  1038. }
  1039. // Write an entry header
  1040. inline void
  1041. CLogFileSector::WriteEntryHeader( LogIndex ilogEntry, LogEntryHeader entryheader )
  1042. {
  1043. TrkAssert( _pvSector );
  1044. RaiseIfNotOpen();
  1045. LoadSector( ilogEntry );
  1046. *_pEntryHeader = entryheader;
  1047. SetDirty();
  1048. }
  1049. // Read an entry header
  1050. inline LogEntryHeader
  1051. CLogFileSector::ReadEntryHeader( LogIndex ilogEntry )
  1052. {
  1053. RaiseIfNotOpen();
  1054. LoadSector( ilogEntry );
  1055. return( *_pEntryHeader );
  1056. }
  1057. // Write a move notification
  1058. inline void
  1059. CLogFileSector::WriteMoveNotification( LogIndex ilogEntry, const LogMoveNotification &lmn )
  1060. {
  1061. RaiseIfNotOpen();
  1062. GetLogEntry( ilogEntry )->move = lmn;
  1063. SetDirty();
  1064. }
  1065. // How many entries can fit in a sector?
  1066. inline ULONG
  1067. CLogFileSector::NumEntries() const
  1068. {
  1069. return( _cEntriesPerSector );
  1070. }
  1071. //+-------------------------------------------------------------------------
  1072. //
  1073. // Class: CLogFile
  1074. //
  1075. // Purpose: This class represents the file which contains the
  1076. // Tracking/Workstation move notification log. Clients
  1077. // of this class may request one entry or header at a time,
  1078. // using based on a log entry index.
  1079. //
  1080. // Entries in the log file are joined by a linked-list,
  1081. // so this class includes methods that clients use to
  1082. // advance their log entry index (i.e., traverse the list).
  1083. //
  1084. // Notes: CLogFile reads/writes a sector at a time for reliability.
  1085. // When a client modifies a log entry in one sector, then
  1086. // attempts to access another sector, CLogFile automatically
  1087. // flushes the changes. This is dependent, however, on the
  1088. // client properly calling the SetDirty method whenever it
  1089. // changes a log entry or header.
  1090. //
  1091. // CLogFile implements no thread-safety mechanism; rather
  1092. // it relies on the caller. This is acceptable in the
  1093. // link-tracking design, because CLog is wholely-owned
  1094. // by CVolume, which synchronizes with a mutex.
  1095. //
  1096. //--------------------------------------------------------------------------
  1097. class CTestLog;
  1098. class PTimerCallback;
  1099. class PLogFileNotify
  1100. {
  1101. public:
  1102. virtual void OnHandlesMustClose() = 0;
  1103. };
  1104. // The CLogFile class declaration
  1105. class CLogFile : public CSecureFile,
  1106. protected PRobustlyCreateableFile,
  1107. public PWorkItem
  1108. {
  1109. // Give full access to the unit test & dltadmin.
  1110. friend class CTestLog;
  1111. friend BOOL EmptyLogFile( LONG iVol );
  1112. // ------------
  1113. // Construction
  1114. // ------------
  1115. public:
  1116. CLogFile()
  1117. {
  1118. _pcTrkWksConfiguration = NULL;
  1119. _cbLogSector = 0;
  1120. _cbLogFile = 0;
  1121. _cEntriesInFile = 0;
  1122. _tcVolume = TEXT('?');
  1123. _ptszVolumeDeviceName = NULL;
  1124. _heventOplock = INVALID_HANDLE_VALUE;
  1125. _hRegisterWaitForSingleObjectEx = NULL;
  1126. _fWriteProtected = TRUE;
  1127. }
  1128. ~CLogFile()
  1129. {
  1130. UnInitialize();
  1131. }
  1132. // --------------
  1133. // Initialization
  1134. // --------------
  1135. public:
  1136. void Initialize( const TCHAR *ptszVolumeDeviceName,
  1137. const CTrkWksConfiguration *pcTrkWksConfiguration,
  1138. PLogFileNotify *pLogFileNotify,
  1139. TCHAR tcVolume
  1140. );
  1141. void UnInitialize();
  1142. // ---------------
  1143. // Exposed Methods
  1144. // ---------------
  1145. public:
  1146. enum AdjustLimitEnum
  1147. {
  1148. ADJUST_WITHIN_LIMIT = 1,
  1149. ADJUST_WITHOUT_LIMIT = 2
  1150. };
  1151. void AdjustLogIndex( LogIndex *pilog, LONG iDelta,
  1152. AdjustLimitEnum adjustLimitEnum = ADJUST_WITHOUT_LIMIT,
  1153. LogIndex ilogLimit = 0 );
  1154. void ReadMoveNotification( LogIndex ilogEntry, LogMoveNotification *plmn );
  1155. void WriteMoveNotification( LogIndex ilogEntry,
  1156. const LogMoveNotification &lmn,
  1157. const LogEntryHeader &entryheader );
  1158. LogEntryHeader
  1159. ReadEntryHeader( LogIndex ilogEntry );
  1160. void WriteEntryHeader( LogIndex ilogEntry, const LogEntryHeader &EntryHeader );
  1161. void ReadExtendedHeader( ULONG iOffset, void *pv, ULONG cb );
  1162. void WriteExtendedHeader( ULONG iOffset, const void *pv, ULONG cb );
  1163. void Expand( LogIndex ilogStart );
  1164. BOOL IsMaxSize() const;
  1165. BOOL IsDirty() const;
  1166. BOOL IsWriteProtected() const;
  1167. ULONG NumEntriesInFile() const;
  1168. BOOL IsShutdown() const;
  1169. void SetShutdown( BOOL fShutdown );
  1170. void Flush( );
  1171. void Delete();
  1172. void ActivateLogFile();
  1173. void SetOplock();
  1174. void RegisterOplockWithThreadPool();
  1175. void UnregisterOplockFromThreadPool( HANDLE hCompletionEvent = (HANDLE)-1 );
  1176. void Close( ); // Doesn't raise
  1177. void DoWork(); // PWorkItem override
  1178. // ----------------
  1179. // Internal Methods
  1180. // ----------------
  1181. protected:
  1182. virtual void
  1183. CreateAlwaysFile( const TCHAR * ptszFile );
  1184. virtual RCF_RESULT
  1185. OpenExistingFile( const TCHAR * ptszFile );
  1186. private:
  1187. void CloseLog(); // Doesn't raise
  1188. void GetSize();
  1189. void InitializeLogEntries( LogIndex ilogFirst, LogIndex ilogLast );
  1190. ULONG CalcNumEntriesInFile( );
  1191. ULONG NumEntriesPerSector();
  1192. BOOL SetSize( DWORD cbLogFile );
  1193. BOOL Validate( );
  1194. // --------------
  1195. // Internal State
  1196. // --------------
  1197. private:
  1198. // Is the volume write-protected?
  1199. BOOL _fWriteProtected:1;
  1200. // The name of the file
  1201. const TCHAR *_ptszVolumeDeviceName;
  1202. // Configuration parameters for the log
  1203. const CTrkWksConfiguration
  1204. *_pcTrkWksConfiguration;
  1205. // Events are raises to the following notify handler
  1206. PLogFileNotify *_pLogFileNotify;
  1207. // Size of sectors for the volume containing the log
  1208. DWORD _cbLogSector;
  1209. // Size of the log file.
  1210. DWORD _cbLogFile;
  1211. // The number of entries in the file
  1212. DWORD _cEntriesInFile;
  1213. // The volume on which this log is stored.
  1214. TCHAR _tcVolume;
  1215. // Classes to control the header and sectors
  1216. CLogFileHeader _header;
  1217. CLogFileSector _sector;
  1218. // Handles used to oplock the log file
  1219. HANDLE _heventOplock;
  1220. HANDLE _hRegisterWaitForSingleObjectEx;
  1221. IO_STATUS_BLOCK _iosbOplock;
  1222. }; // class CLogFile
  1223. // Open/create the log file
  1224. inline void
  1225. CLogFile::ActivateLogFile()
  1226. {
  1227. if( !IsOpen( ) )
  1228. {
  1229. TCHAR tszLogFile[ MAX_PATH + 1 ];
  1230. _tcscpy( tszLogFile, _ptszVolumeDeviceName );
  1231. _tcscat( tszLogFile, s_tszLogFileName );
  1232. RobustlyCreateFile(tszLogFile, _tcVolume );
  1233. }
  1234. }
  1235. // Mark the file as having been successfully shut down.
  1236. inline void
  1237. CLogFile::SetShutdown( BOOL fShutdown )
  1238. {
  1239. _header.SetShutdown( fShutdown );
  1240. if( fShutdown )
  1241. Flush();
  1242. }
  1243. // Is the log file dirty?
  1244. inline BOOL
  1245. CLogFile::IsDirty() const
  1246. {
  1247. return( _sector.IsDirty() || _header.IsDirty() );
  1248. }
  1249. // Flush to disk
  1250. inline void
  1251. CLogFile::Flush( )
  1252. {
  1253. if( IsOpen() && IsDirty() )
  1254. {
  1255. _sector.Flush();
  1256. _header.Flush();
  1257. FlushFileBuffers( _hFile );
  1258. }
  1259. }
  1260. // How many move notification entries can this file hold?
  1261. inline ULONG
  1262. CLogFile::NumEntriesInFile() const
  1263. {
  1264. return( _cEntriesInFile );
  1265. }
  1266. // Determine the number of entries this file can hold, given the size
  1267. // of the file.
  1268. inline ULONG
  1269. CLogFile::CalcNumEntriesInFile( )
  1270. {
  1271. if( (_cbLogFile/_cbLogSector) <= _header.NumSectors() )
  1272. {
  1273. TrkLog(( TRKDBG_ERROR, TEXT("Corrupt log on %c: _cbLogFile=%lu, _cbLogSector=%lu"),
  1274. _tcVolume, _cbLogFile, _cbLogSector ));
  1275. TrkRaiseException( TRK_E_CORRUPT_LOG );
  1276. }
  1277. // The number of entries is the non-header file size times the
  1278. // number of entries in a sector.
  1279. _cEntriesInFile = ( (_cbLogFile / _cbLogSector) - _header.NumSectors() )
  1280. *
  1281. _sector.NumEntries();
  1282. return( _cEntriesInFile );
  1283. }
  1284. // How many move notification entries can we fit in a single
  1285. // disk sector.
  1286. inline ULONG
  1287. CLogFile::NumEntriesPerSector()
  1288. {
  1289. return _sector.NumEntries();
  1290. }
  1291. // Is this file already as big as we're allowed to make it?
  1292. inline BOOL
  1293. CLogFile::IsMaxSize() const
  1294. {
  1295. return _cbLogFile + _cbLogSector > _pcTrkWksConfiguration->GetMaxLogKB() * 1024;
  1296. }
  1297. inline BOOL
  1298. CLogFile::IsWriteProtected() const
  1299. {
  1300. return _fWriteProtected;
  1301. }
  1302. // Is the file currently in the proper-shutdown state?
  1303. inline BOOL
  1304. CLogFile::IsShutdown() const
  1305. {
  1306. return( _header.IsShutdown() );
  1307. }
  1308. // Called when it's time to close the log (we don't want to hold
  1309. // the log open indefinitely, because it locks the volume).
  1310. inline void
  1311. CLogFile::Close() // doesn't raise
  1312. {
  1313. CloseLog();
  1314. }
  1315. // Delete the underlying log file
  1316. inline void
  1317. CLogFile::Delete()
  1318. {
  1319. TCHAR tszLogFile[ MAX_PATH + 1 ];
  1320. CloseLog();
  1321. _tcscpy( tszLogFile, _ptszVolumeDeviceName );
  1322. _tcscat( tszLogFile, s_tszLogFileName );
  1323. RobustlyDeleteFile( tszLogFile );
  1324. }
  1325. //+-------------------------------------------------------------------------
  1326. //
  1327. // Class: CLog
  1328. //
  1329. // Purpose: This class implements the tracking workstation log.
  1330. //
  1331. // Notes: CLog implements no thread-safety mechanism; rather
  1332. // it relies on the caller. This is acceptable in the
  1333. // link-tracking design, because CLog is wholely-owned
  1334. // by CVolume, which synchronizes with a mutex.
  1335. //
  1336. //--------------------------------------------------------------------------
  1337. // Prototype for a callback class. CLog calls this class whenever
  1338. // it has new information.
  1339. class PLogCallback
  1340. {
  1341. public:
  1342. virtual void OnEntriesAvailable() = 0;
  1343. };
  1344. // The CLog declaration
  1345. class CLog
  1346. {
  1347. // Give the unit test full control.
  1348. friend class CTestLog;
  1349. //
  1350. // The log may contain entries for objects that have not actually
  1351. // moved off the machine. This can occur when the log is written
  1352. // with a move notification but the source machine
  1353. // crashes before the source is deleted. If the source still exists
  1354. // on the machine, the we need to delete the entry from the log
  1355. // before it gets notified to the DC. I.e. the update to the
  1356. // log should somehow be transacted with the move.
  1357. //
  1358. // ------------
  1359. // Construction
  1360. // ------------
  1361. public:
  1362. CLog()
  1363. {
  1364. _fDirty = FALSE;
  1365. memset( &_loginfo, 0, sizeof(_loginfo) );
  1366. _pcLogFile = NULL;
  1367. _pcTrkWksConfiguration = NULL;
  1368. _pLogCallback = NULL;
  1369. }
  1370. ~CLog() { }
  1371. // --------------
  1372. // Initialization
  1373. // --------------
  1374. public:
  1375. void Initialize( PLogCallback *pLogCallback,
  1376. const CTrkWksConfiguration *pcTrkWksConfig,
  1377. CLogFile *pcLogFile );
  1378. void Flush( ); // Flushes only to cache
  1379. // ---------------
  1380. // Exposed Methods
  1381. // ---------------
  1382. public:
  1383. void Append( const CVolumeId &volidCurrent,
  1384. const CObjId &objidCurrent,
  1385. const CDomainRelativeObjId &droidNew,
  1386. const CMachineId &mcidNew,
  1387. const CDomainRelativeObjId &droidBirth);
  1388. void Read( CObjId rgobjidCurrent[],
  1389. CDomainRelativeObjId rgdroidBirth[],
  1390. CDomainRelativeObjId rgdroidNew[],
  1391. SequenceNumber *pseqFirst,
  1392. IN OUT ULONG *pcRead);
  1393. SequenceNumber
  1394. GetNextSeqNumber( ) const; // Required not to raise
  1395. BOOL Search(const CObjId &objidCurrent,
  1396. CDomainRelativeObjId *pdroidNew,
  1397. CMachineId *pmcidNew,
  1398. CDomainRelativeObjId *pdroidBirth);
  1399. BOOL Seek( const SequenceNumber &seq );
  1400. void Seek( int nOrigin, int iSeek );
  1401. // ----------------
  1402. // Internal Methods
  1403. // ----------------
  1404. private:
  1405. DWORD AgeOf( ULONG ilogEntry );
  1406. LogInfo QueryLogInfo();
  1407. void GenerateDefaultLogInfo( LogIndex ilogEnd );
  1408. void ExpandLog();
  1409. BOOL IsEmpty() const;
  1410. BOOL IsFull() const;
  1411. BOOL IsRead() const; // Has the whole log been read?
  1412. BOOL IsRead( LogIndex ilog ); // Has this entry been read?
  1413. void SetDirty( BOOL fDirty );
  1414. BOOL IsOldEnoughToOverwrite( ULONG iLogEntry );
  1415. void WriteEntryHeader();
  1416. BOOL Search(SequenceNumber seqSearch, ULONG *piLogEntry );
  1417. BOOL DoSearch( BOOL fSearchUsingSeq,
  1418. SequenceNumber seqSearch, // Use this if fSearchUsingSeq
  1419. const CObjId &objidCurrent, // Use this if !fSearchUsingSeq
  1420. ULONG *piFound,
  1421. CDomainRelativeObjId *pdroidNew,
  1422. CMachineId *pmcidNew,
  1423. CDomainRelativeObjId *pdroidBirth );
  1424. // -----
  1425. // State
  1426. // -----
  1427. private:
  1428. // Should we do anything in a flush?
  1429. BOOL _fDirty:1;
  1430. // The object which represents the log file. We never directly access
  1431. // the underlying file.
  1432. CLogFile *_pcLogFile;
  1433. // Meta-data for the log, which is also written to the log header
  1434. LogInfo _loginfo;
  1435. // Who to call when we have data to be read.
  1436. PLogCallback *_pLogCallback;
  1437. // Configuration information (e.g., max log size)
  1438. const CTrkWksConfiguration
  1439. *_pcTrkWksConfiguration;
  1440. };
  1441. // ------------
  1442. // CLog Inlines
  1443. // ------------
  1444. // Can this entry be overwritten?
  1445. inline BOOL
  1446. CLog::IsOldEnoughToOverwrite( ULONG iLogEntry )
  1447. {
  1448. return( AgeOf(iLogEntry) >= _pcTrkWksConfiguration->GetLogOverwriteAge() );
  1449. }
  1450. // How old is this entry, in TrkTimeUnits?
  1451. inline DWORD
  1452. CLog::AgeOf( ULONG ilogEntry )
  1453. {
  1454. CFILETIME cftNow;
  1455. LogMoveNotification lmn;
  1456. _pcLogFile->ReadMoveNotification( ilogEntry, &lmn );
  1457. return TrkTimeUnits(cftNow) - lmn.DateWritten;
  1458. }
  1459. // Is the current log too full to add another entry?
  1460. inline BOOL
  1461. CLog::IsFull() const
  1462. {
  1463. return( _loginfo.ilogWrite == _loginfo.ilogEnd );
  1464. }
  1465. // Are there no entries in the log?
  1466. inline BOOL
  1467. CLog::IsEmpty() const
  1468. {
  1469. return( _loginfo.ilogWrite == _loginfo.ilogStart );
  1470. }
  1471. // SetDirty must be called before making a change to _loginfo. It
  1472. // marks the logfile as not properly shutdown, and if this is the first time it's
  1473. // been marked as such, it will do a flush of the logfile header.
  1474. inline void
  1475. CLog::SetDirty( BOOL fDirty )
  1476. {
  1477. _fDirty = fDirty;
  1478. if( _fDirty )
  1479. _pcLogFile->SetShutdown( FALSE );
  1480. }
  1481. // Has everything in the log been read?
  1482. inline BOOL
  1483. CLog::IsRead() const
  1484. {
  1485. return( _loginfo.ilogWrite == _loginfo.ilogRead );
  1486. }
  1487. // Get the next sequence number which will be used
  1488. inline SequenceNumber
  1489. CLog::GetNextSeqNumber( ) const // Never raises
  1490. {
  1491. return( _loginfo.seqNext );
  1492. }
  1493. // Write the header data to the current headers (both the data that goes
  1494. // to the log header, and the data that goes to the header of the
  1495. // last entry).
  1496. inline void
  1497. CLog::WriteEntryHeader()
  1498. {
  1499. LogEntryHeader entryheader;
  1500. entryheader = _pcLogFile->ReadEntryHeader( _loginfo.ilogLast );
  1501. entryheader.ilogRead = _loginfo.ilogRead;
  1502. entryheader.seq = _loginfo.seqNext;
  1503. _pcLogFile->WriteEntryHeader( _loginfo.ilogLast, entryheader );
  1504. }
  1505. //-------------------------------------------------------------------//
  1506. // //
  1507. // CObjIdIndexChangeNotifier //
  1508. // //
  1509. //-------------------------------------------------------------------//
  1510. class CVolume;
  1511. class PObjIdIndexChangedCallback
  1512. {
  1513. public:
  1514. virtual void NotifyAddOrDelete( ULONG Action, const CDomainRelativeObjId & droidBirth ) = 0;
  1515. };
  1516. enum EAggressiveness
  1517. {
  1518. AGGRESSIVE = 1,
  1519. PASSIVE
  1520. };
  1521. const ULONG MAX_FS_OBJID_NOTIFICATIONS = 4;
  1522. class CObjIdIndexChangeNotifier : public PWorkItem
  1523. {
  1524. public:
  1525. CObjIdIndexChangeNotifier() : _fInitialized(FALSE),
  1526. _hCompletionEvent(NULL),
  1527. _hRegisterWaitForSingleObjectEx(NULL),
  1528. _hDir(INVALID_HANDLE_VALUE)
  1529. {
  1530. IFDBG( _tcscpy( _tszWorkItemSig, TEXT("CObjIdIndexChangeNotifier") ));
  1531. }
  1532. void Initialize(
  1533. TCHAR *ptszVolumeDeviceName,
  1534. PObjIdIndexChangedCallback * pObjIdIndexChangedCallback,
  1535. CVolume * pVolumeForTunnelNotification );
  1536. void UnInitialize();
  1537. BOOL AsyncListen( );
  1538. void StopListeningAndClose();
  1539. inline BOOL IsOpen() const;
  1540. // PWorkItem
  1541. void DoWork();
  1542. private:
  1543. void StartListening();
  1544. friend void OverlappedCompletionRoutine(
  1545. DWORD dwErrorCode,
  1546. DWORD dwNumberOfBytesTransfered,
  1547. LPOVERLAPPED lpOverlapped
  1548. );
  1549. /*
  1550. void OverlappedCompletionRoutine(
  1551. DWORD dwErrorCode,
  1552. DWORD dwNumberOfBytesTransfered
  1553. );
  1554. */
  1555. private:
  1556. BOOL _fInitialized:1;
  1557. public:
  1558. // Handle to the object ID index directory.
  1559. // Hack: this is public so that we can use it to register
  1560. // for PNP notification.
  1561. HANDLE _hDir;
  1562. private:
  1563. // Event we use in the async ReadDirectoryChanges call.
  1564. HANDLE _hCompletionEvent;
  1565. // Thread pool registration handle (for the above event).
  1566. HANDLE _hRegisterWaitForSingleObjectEx;
  1567. // Name of the volume (in mount manager format)
  1568. TCHAR * _ptszVolumeDeviceName;
  1569. // Critsec for this class.
  1570. CCriticalSection _cs;
  1571. // This buffer is passed to the ReadDirectoryChanges call
  1572. // for the result of the read.
  1573. BYTE _Buffer[ MAX_FS_OBJID_NOTIFICATIONS *
  1574. (sizeof(FILE_NOTIFY_INFORMATION) +
  1575. sizeof(WCHAR) * (1+MAX_PATH)) ]; // FILE_NOTIFY_INFORMATION
  1576. // Dummy for the ReadDirectoryChanges call.
  1577. DWORD _dwDummyBytesReturned;
  1578. // Overlapped structure used in the ReadDirectoryChanges call.
  1579. OVERLAPPED _Overlapped;
  1580. // Who to call when we get a notification.
  1581. PObjIdIndexChangedCallback *
  1582. _pObjIdIndexChangedCallback;
  1583. // The volume for which we're watching the index.
  1584. CVolume * _pVolume;
  1585. // TrkWks configuration information.
  1586. const CTrkWksConfiguration *
  1587. _pTrkWksConfiguration;
  1588. };
  1589. inline BOOL
  1590. CObjIdIndexChangeNotifier::IsOpen() const
  1591. {
  1592. return( INVALID_HANDLE_VALUE != _hDir );
  1593. }
  1594. //-------------------------------------------------------------------
  1595. //
  1596. // Class: CVolume
  1597. //
  1598. // Purpose: This class represents a local volume, whether
  1599. // or not that volume is used for link-tracking.
  1600. // For trackable volumes, this class holds the
  1601. // move notification log (CLog). In fact, this class
  1602. // is persisted to the header of the log file.
  1603. //
  1604. //-------------------------------------------------------------------
  1605. class CDeletionsManager;
  1606. class CTestSync;
  1607. class CVolumeManager;
  1608. class CVolume : public PLogFileNotify
  1609. {
  1610. // ------------
  1611. // Construction
  1612. // ------------
  1613. public:
  1614. CVolume() : _VolQuotaReached( TEXT("VolQuotaReached") )
  1615. {
  1616. _fInitialized = FALSE;
  1617. _fDirty = FALSE;
  1618. _lRef = 1;
  1619. _lVolidUpdates = 0;
  1620. _fVolumeLocked
  1621. = _fVolumeDismounted
  1622. = _fDeleteSelfPending
  1623. = _fInSetVolIdOnVolume = FALSE;
  1624. _fDeleteLogAndReInitializeVolume = _fCloseAndReopenVolumeHandles = FALSE;
  1625. _fVolInfoInitialized = FALSE;
  1626. #if DBG
  1627. _cLocks = 0;
  1628. _cVolumes ++;
  1629. #endif
  1630. _cHandleLocks = 0;
  1631. _cCloseVolumeHandlesInProgress = 0;
  1632. }
  1633. ~CVolume()
  1634. {
  1635. TrkLog(( TRKDBG_LOG, TEXT("Destructing %c:"), VolChar(_iVol) ));
  1636. UnInitialize();
  1637. TrkAssert( _lRef == 0 );
  1638. #if DBG
  1639. _cVolumes --;
  1640. #endif
  1641. }
  1642. // --------------
  1643. // Initialization
  1644. // --------------
  1645. public:
  1646. BOOL Initialize( TCHAR *ptszVolumeName,
  1647. const CTrkWksConfiguration * pTrkWksConfiguration,
  1648. CVolumeManager *pVolMgr,
  1649. PLogCallback * pLogCallback,
  1650. PObjIdIndexChangedCallback * pDeletionsManager,
  1651. SERVICE_STATUS_HANDLE ssh
  1652. #if DBG
  1653. , CTestSync * pTunnelTest
  1654. #endif
  1655. );
  1656. void UnInitialize();
  1657. public:
  1658. enum CVOL_STATE
  1659. {
  1660. VOL_STATE_OWNED, // volume is VOL_STATE_OWNED
  1661. VOL_STATE_NOTOWNED, // volume is not VOL_STATE_OWNED
  1662. VOL_STATE_NOTCREATED, // volume is not created
  1663. VOL_STATE_UNKNOWN // volume is in VOL_STATE_UNKNOWN state
  1664. };
  1665. // ---------------
  1666. // Exposed Methods
  1667. // ---------------
  1668. public:
  1669. // add and release reference
  1670. ULONG AddRef();
  1671. ULONG Release();
  1672. // Operations on the Move Notification log
  1673. void Append( const CDomainRelativeObjId &droidCurrent,
  1674. const CDomainRelativeObjId &droidNew,
  1675. const CMachineId &mcidNew,
  1676. const CDomainRelativeObjId &droidBirth);
  1677. BOOL Search( const CDomainRelativeObjId & droidCurrent, CDomainRelativeObjId * pdroidNew,
  1678. CMachineId *pmcidNew, CDomainRelativeObjId * pdroidBirth );
  1679. enum EHandleChangeReason
  1680. {
  1681. VOLUME_LOCK_CHANGE,
  1682. VOLUME_MOUNT_CHANGE,
  1683. NO_VOLUME_CHANGE
  1684. };
  1685. void CloseVolumeHandles( HDEVNOTIFY hdnVolume = NULL,
  1686. EHandleChangeReason = NO_VOLUME_CHANGE ); // Doesn't raise
  1687. BOOL ReopenVolumeHandles();
  1688. void CloseAndReopenVolumeHandles();
  1689. void OnVolumeLock( HDEVNOTIFY hdnVolume );
  1690. void OnVolumeUnlock( HDEVNOTIFY hdnVolume );
  1691. void OnVolumeLockFailed( HDEVNOTIFY hdnVolume );
  1692. void OnVolumeMount( HDEVNOTIFY hdnVolume );
  1693. void OnVolumeDismount( HDEVNOTIFY hdnVolume );
  1694. void OnVolumeDismountFailed( HDEVNOTIFY hdnVolume );
  1695. // Get this volume's id, secret, and the machine id stored in the log.
  1696. const CVolumeId GetVolumeId( );
  1697. inline void SetVolIdInVolInfo( const CVolumeId &volid );
  1698. inline RPC_STATUS GenerateVolumeIdInVolInfo();
  1699. inline void GetVolumeSecret( CVolumeSecret *psecret );
  1700. inline void GetMachineId( CMachineId *pmcid );
  1701. inline BOOL EnumObjIds( CObjIdEnumerator *pobjidenum );
  1702. inline USHORT GetIndex() const;
  1703. inline const TCHAR* GetVolumeDeviceName() const;
  1704. // Load/unload from/to a SyncVolume request structure
  1705. BOOL LoadSyncVolume(TRKSVR_SYNC_VOLUME * pSyncVolume,
  1706. EAggressiveness eAggressiveness,
  1707. BOOL* pfSyncNeeded= NULL );
  1708. BOOL LoadQueryVolume( TRKSVR_SYNC_VOLUME * pQueryVolume );
  1709. BOOL UnloadSyncVolume( TRKSVR_SYNC_VOLUME * pSyncVolume );
  1710. BOOL UnloadQueryVolume( const TRKSVR_SYNC_VOLUME * pQueryVolume );
  1711. void Read( CObjId *pobjidCurrent,
  1712. CDomainRelativeObjId *pdroidBirth,
  1713. CDomainRelativeObjId *pdroidNew,
  1714. SequenceNumber *pseqFirst,
  1715. ULONG *pcNotifications);
  1716. BOOL Seek( SequenceNumber seq );
  1717. void Seek( int origin, int iSeek );
  1718. // inline void OnLogCloseTimer();
  1719. inline void OnObjIdIndexReopenTimer();
  1720. // Open a file on this volume by Object ID
  1721. BOOL OpenFile( const CObjId &objid,
  1722. ACCESS_MASK AccessMask,
  1723. ULONG ShareAccess,
  1724. HANDLE *ph);
  1725. LONG GetVolIndex()
  1726. { return( _iVol ); }
  1727. HRESULT OnRestore();
  1728. BOOL NotOwnedExpired();
  1729. void SetState(CVOL_STATE volstateTarget);
  1730. CVOL_STATE GetState();
  1731. void Refresh();
  1732. void FileActionIdNotTunnelled( FILE_OBJECTID_INFORMATION * poi );
  1733. void NotifyAddOrDelete( ULONG Action, const CObjId & objid );
  1734. inline void MarkForMakeAllOidsReborn();
  1735. inline void ClearMarkForMakeAllOidsReborn();
  1736. inline BOOL IsMarkedForMakeAllOidsReborn();
  1737. inline NTSTATUS SetVolIdOnVolume( const CVolumeId &volid );
  1738. inline NTSTATUS SetVolId( const TCHAR *ptszVolumeDeviceName, const CVolumeId &volid );
  1739. BOOL MakeAllOidsReborn();
  1740. void SetLocallyGeneratedVolId();
  1741. void Flush(BOOL fServiceShutdown = FALSE);
  1742. // PLogFileNotify override
  1743. void OnHandlesMustClose();
  1744. public:
  1745. // Debugging state
  1746. #if DBG
  1747. static int _cVolumes;
  1748. #endif
  1749. // ----------------
  1750. // Internal Methods
  1751. // ----------------
  1752. private:
  1753. void MarkSelfForDelete();
  1754. void DeleteAndReinitializeLog();
  1755. void DeleteLogAndReInitializeVolume();
  1756. void PrepareToReopenVolumeHandles( HDEVNOTIFY hdnVolume,
  1757. EHandleChangeReason eHandleChangeReason );
  1758. void VolumeSanityCheck( BOOL fVolIndexSetAlready = FALSE );
  1759. void LoadVolInfo();
  1760. void SaveVolInfo( );
  1761. ULONG Lock();
  1762. ULONG Unlock();
  1763. void AssertLocked();
  1764. void BreakIfRequested();
  1765. ULONG LockHandles();
  1766. ULONG UnlockHandles();
  1767. inline BOOL IsHandsOffVolumeMode() const;
  1768. inline BOOL IsWriteProtectedVolume() const;
  1769. inline void RaiseIfWriteProtectedVolume() const;
  1770. void RegisterPnPVolumeNotification();
  1771. void UnregisterPnPVolumeNotification();
  1772. // -----
  1773. // State
  1774. // -----
  1775. private:
  1776. // Has this class been initialized?
  1777. BOOL _fInitialized:1;
  1778. // Are we in need of a flush?
  1779. BOOL _fDirty:1;
  1780. // Have we called LoadVolInfo yet?
  1781. BOOL _fVolInfoInitialized:1;
  1782. // Are we in hands-off mode because the volume has been FSCTL_LOCK_VOLUME-ed?
  1783. BOOL _fVolumeLocked:1;
  1784. // And/or are we in hands-off mode because the volume has been FSCTL_DISMOUNT_VOLUME-ed?
  1785. BOOL _fVolumeDismounted:1;
  1786. // If true, then a final UnLock calls this->Release();
  1787. BOOL _fDeleteSelfPending:1;
  1788. // If true, we're in the middle of a SetVolIdOnVolume
  1789. BOOL _fInSetVolIdOnVolume:1;
  1790. // These flags are used to guarantee that we don't infinitely recurse.
  1791. BOOL _fDeleteLogAndReInitializeVolume:1;
  1792. BOOL _fCloseAndReopenVolumeHandles:1;
  1793. HANDLE _hVolume; // volume handle for tunnelling
  1794. // (relative FileReference opens)
  1795. // Configuration information
  1796. const CTrkWksConfiguration
  1797. *_pTrkWksConfiguration;
  1798. CVolumeManager *_pVolMgr;
  1799. // Volume index (0=>a:, 1=>b:, ...), -1 => no drive letter
  1800. LONG _iVol;
  1801. // Unmatched calls to Lock()
  1802. ULONG _cLocks;
  1803. ULONG _cHandleLocks;
  1804. // Mount manager volume name, without the trailing whack. E.g.
  1805. // \\?\Volume{guid}
  1806. TCHAR _tszVolumeDeviceName[ CCH_MAX_VOLUME_NAME + 1 ];
  1807. // Thread-safety
  1808. CCriticalSection _csVolume; // Required for any CVolume operation
  1809. CCriticalSection _csHandles; // Required to open/close all handles
  1810. // Information about the volume which is persisted (in the log)
  1811. VolumePersistentInfo
  1812. _volinfo;
  1813. // The log file and the log.
  1814. CLogFile _cLogFile;
  1815. CLog _cLog;
  1816. // This is used to count the updates to the volid.
  1817. // It is incremented before an update, and incremented
  1818. // again after the update. It is used by GetVolumeId
  1819. // to ensure we get a good volid without taking the lock.
  1820. LONG _lVolidUpdates;
  1821. // Reference count
  1822. long _lRef;
  1823. CObjIdIndexChangeNotifier
  1824. _ObjIdIndexChangeNotifier;
  1825. CVolumeSecret _tempSecret;
  1826. #if DBG
  1827. CTestSync * _pTunnelTest;
  1828. #endif
  1829. PLogCallback * _pLogCallback;
  1830. HDEVNOTIFY _hdnVolumeLock;
  1831. SERVICE_STATUS_HANDLE _ssh;
  1832. CRegBoolParameter _VolQuotaReached;
  1833. // See CloseVolumeHandles method for usage
  1834. long _cCloseVolumeHandlesInProgress;
  1835. }; // class CVolume
  1836. // Set a volume ID in the _volinfo structure.
  1837. inline void
  1838. CVolume::SetVolIdInVolInfo( const CVolumeId &volid )
  1839. {
  1840. // We have to update _lVolidUpdates before and
  1841. // after the update, to be thread-safe and avoid
  1842. // using a lock. Set GetVolumeId for a description.
  1843. InterlockedIncrement( &_lVolidUpdates );
  1844. _volinfo.volid = volid;
  1845. InterlockedIncrement( &_lVolidUpdates );
  1846. }
  1847. // Generate a new volume ID in the _volinfo structure.
  1848. inline RPC_STATUS
  1849. CVolume::GenerateVolumeIdInVolInfo( )
  1850. {
  1851. // We have to update _lVolidUpdates before and
  1852. // after the update, to be thread-safe and avoid
  1853. // using a lock. Set GetVolumeId for a description.
  1854. InterlockedIncrement( &_lVolidUpdates ); // See GetVolumeId
  1855. RPC_STATUS rpc_status = _volinfo.volid.UuidCreate();
  1856. InterlockedIncrement( &_lVolidUpdates ); // See GetVolumeId
  1857. return rpc_status;
  1858. }
  1859. // Get the volume's zero-relative drive letter index.
  1860. inline USHORT
  1861. CVolume::GetIndex() const
  1862. {
  1863. return(_iVol);
  1864. }
  1865. // Handle a volume-lock event
  1866. inline void
  1867. CVolume::OnVolumeLock( HDEVNOTIFY hdnVolume )
  1868. {
  1869. #if DBG
  1870. if( NULL == hdnVolume || _hdnVolumeLock == hdnVolume )
  1871. TrkLog(( TRKDBG_VOLUME, TEXT("Volume %c: is being locked"), VolChar(_iVol) ));
  1872. #endif
  1873. CloseVolumeHandles( hdnVolume, VOLUME_LOCK_CHANGE );
  1874. }
  1875. // Handle the external failure of a volume-lock event.
  1876. inline void
  1877. CVolume::OnVolumeLockFailed( HDEVNOTIFY hdnVolume )
  1878. {
  1879. #if DBG
  1880. if( NULL == hdnVolume || _hdnVolumeLock == hdnVolume )
  1881. TrkLog(( TRKDBG_VOLUME, TEXT("Volume %c: was not locked successfully"), VolChar(_iVol) ));
  1882. #endif
  1883. PrepareToReopenVolumeHandles( hdnVolume, VOLUME_LOCK_CHANGE );
  1884. }
  1885. // Call SetVolId, with the _fInSetVolIdOnVolume set during
  1886. // the call.
  1887. inline NTSTATUS
  1888. CVolume::SetVolIdOnVolume( const CVolumeId &volid )
  1889. {
  1890. NTSTATUS status;
  1891. TrkAssert( !_fInSetVolIdOnVolume );
  1892. _fInSetVolIdOnVolume = TRUE;
  1893. status = ::SetVolId( _tszVolumeDeviceName, volid );
  1894. _fInSetVolIdOnVolume = FALSE;
  1895. return status;
  1896. }
  1897. // This routine exists to ensure we don't accidentally call
  1898. // the global SetVolId from within CVolume (use SetVolIdOnVolume
  1899. // instead).
  1900. inline NTSTATUS
  1901. CVolume::SetVolId( const TCHAR *ptszVolumeDeviceName, const CVolumeId &volid )
  1902. {
  1903. TrkAssert( !TEXT("SetVolId called from CVolume") );
  1904. return SetVolIdOnVolume( volid );
  1905. }
  1906. // Is the volume currently locked or dismounted?
  1907. inline BOOL
  1908. CVolume::IsHandsOffVolumeMode() const
  1909. {
  1910. return( _fVolumeLocked || _fVolumeDismounted );
  1911. }
  1912. // Is the volume currently read-only?
  1913. inline BOOL
  1914. CVolume::IsWriteProtectedVolume() const
  1915. {
  1916. return _cLogFile.IsWriteProtected();
  1917. }
  1918. // Handle a volume-unlock event.
  1919. inline void
  1920. CVolume::OnVolumeUnlock( HDEVNOTIFY hdnVolume )
  1921. {
  1922. #if DBG
  1923. if( NULL == hdnVolume || _hdnVolumeLock == hdnVolume )
  1924. TrkLog(( TRKDBG_VOLUME, TEXT("Volume %c: unlocked"), VolChar(_iVol) ));
  1925. #endif
  1926. PrepareToReopenVolumeHandles( hdnVolume, VOLUME_LOCK_CHANGE );
  1927. }
  1928. // Handle a volume dismount event.
  1929. inline void
  1930. CVolume::OnVolumeDismount( HDEVNOTIFY hdnVolume )
  1931. {
  1932. #if DBG
  1933. if( _hdnVolumeLock == hdnVolume )
  1934. TrkLog(( TRKDBG_LOG, TEXT("Volume %c: dismounted"), VolChar(_iVol) ));
  1935. #endif
  1936. CloseVolumeHandles( hdnVolume, VOLUME_MOUNT_CHANGE );
  1937. }
  1938. // Handle the external failure of a volume-dismount event.
  1939. inline void
  1940. CVolume::OnVolumeDismountFailed( HDEVNOTIFY hdnVolume )
  1941. {
  1942. #if DBG
  1943. if( _hdnVolumeLock == hdnVolume )
  1944. TrkLog(( TRKDBG_LOG, TEXT("Volume %c: dismount failed"), VolChar(_iVol) ));
  1945. #endif
  1946. PrepareToReopenVolumeHandles( hdnVolume, VOLUME_MOUNT_CHANGE );
  1947. }
  1948. // Handle a volume-mount event.
  1949. inline void
  1950. CVolume::OnVolumeMount( HDEVNOTIFY hdnVolume )
  1951. {
  1952. #if DBG
  1953. if( _hdnVolumeLock == hdnVolume )
  1954. TrkLog(( TRKDBG_LOG, TEXT("Volume %c: mounted"), VolChar(_iVol) ));
  1955. #endif
  1956. PrepareToReopenVolumeHandles( hdnVolume, VOLUME_MOUNT_CHANGE );
  1957. }
  1958. // Get the volume device name (in mount manager format).
  1959. inline const TCHAR*
  1960. CVolume::GetVolumeDeviceName() const
  1961. {
  1962. return( _tszVolumeDeviceName );
  1963. }
  1964. // Get this volume's secret.
  1965. inline void
  1966. CVolume::GetVolumeSecret( CVolumeSecret *psecret )
  1967. {
  1968. Lock();
  1969. __try
  1970. {
  1971. *psecret = _volinfo.secret;
  1972. }
  1973. __finally
  1974. {
  1975. Unlock();
  1976. }
  1977. }
  1978. // Get the machine ID stored in the log of this volume (not necessarily
  1979. // the current machine ID).
  1980. inline void
  1981. CVolume::GetMachineId( CMachineId *pmcid )
  1982. {
  1983. Lock();
  1984. __try
  1985. {
  1986. *pmcid = _volinfo.machine;
  1987. }
  1988. __finally
  1989. {
  1990. Unlock();
  1991. }
  1992. }
  1993. // Enumerate the object IDs on this volume.
  1994. inline BOOL
  1995. CVolume::EnumObjIds( CObjIdEnumerator *pobjidenum )
  1996. {
  1997. Lock();
  1998. __try
  1999. {
  2000. if( !pobjidenum->Initialize( _tszVolumeDeviceName ))
  2001. {
  2002. TrkLog((TRKDBG_ERROR, TEXT("CObjIdEnumerator::Initialize failed") ));
  2003. TrkRaiseException( E_FAIL );
  2004. }
  2005. }
  2006. __finally
  2007. {
  2008. Unlock();
  2009. }
  2010. return( TRUE );
  2011. }
  2012. // Set a flag indicating that we should clear the birth IDs for all
  2013. // files on this volume. The actual clearing activity is performed
  2014. // asynchronously on another thread. This flag is written to the
  2015. // _volinfo in the log and flushed to the disk, so that we continue
  2016. // if the service is stopped before it is performed.
  2017. inline void
  2018. CVolume::MarkForMakeAllOidsReborn()
  2019. {
  2020. Lock();
  2021. __try
  2022. {
  2023. TrkLog(( TRKDBG_LOG, TEXT("Marking to make all OIDs reborn on %c:"), VolChar(_iVol) ));
  2024. _fDirty = TRUE;
  2025. _volinfo.fDoMakeAllOidsReborn = TRUE;
  2026. Flush();
  2027. }
  2028. __finally
  2029. {
  2030. Unlock();
  2031. }
  2032. }
  2033. // Has the above flag been set?
  2034. inline BOOL
  2035. CVolume::IsMarkedForMakeAllOidsReborn()
  2036. {
  2037. BOOL fDoMakeAllOidsReborn;
  2038. Lock();
  2039. fDoMakeAllOidsReborn = _volinfo.fDoMakeAllOidsReborn;
  2040. Unlock();
  2041. return fDoMakeAllOidsReborn;
  2042. }
  2043. // Raise an exception if this volume is write-protected. This method is
  2044. // called before any attempt to modify the volume (or to modify state that
  2045. // we eventually want to write to a volume).
  2046. inline void
  2047. CVolume::RaiseIfWriteProtectedVolume() const
  2048. {
  2049. if( IsWriteProtectedVolume() )
  2050. {
  2051. TrkLog(( TRKDBG_VOLUME, TEXT("Volume is write-protected") ));
  2052. TrkRaiseException( E_UNEXPECTED );
  2053. }
  2054. }
  2055. // Clear the above flag and flush.
  2056. inline void
  2057. CVolume::ClearMarkForMakeAllOidsReborn()
  2058. {
  2059. Lock();
  2060. __try
  2061. {
  2062. _fDirty = TRUE;
  2063. _volinfo.fDoMakeAllOidsReborn = FALSE;
  2064. Flush();
  2065. }
  2066. _finally
  2067. {
  2068. Unlock();
  2069. }
  2070. }
  2071. // Take the primary CVolume critsec.
  2072. inline ULONG
  2073. CVolume::Lock()
  2074. {
  2075. _csVolume.Enter();
  2076. return( _cLocks++ );
  2077. }
  2078. // Release the primary CVolume critsec.
  2079. inline ULONG
  2080. CVolume::Unlock()
  2081. {
  2082. TrkAssert( 0 < _cLocks );
  2083. ULONG cLocksNew = --_cLocks;
  2084. // If we just dropped the lock count down to zero, and
  2085. // we're marked to be deleted, then do a Release (to counter
  2086. // the AddRef done in MarkSelfForDelete). Ordinarily this will
  2087. // be the final release, and will cause the object to delete
  2088. // itself.
  2089. if( 0 == cLocksNew && _fDeleteSelfPending )
  2090. {
  2091. TrkLog(( TRKDBG_LOG, TEXT("Releasing %c: for delete (%d)"),
  2092. VolChar(_iVol), _lRef ));
  2093. // Clear the delete flag. This is necessary because the following
  2094. // Release isn't necessarily the last one. If another thread has
  2095. // a ref and is about to do a lock, we don't want its unlock to
  2096. // also do a release. At this point we're out of the volume manager's
  2097. // linked list, so when that thread does its final release, the object
  2098. // will be deleted successfully.
  2099. _fDeleteSelfPending = FALSE;
  2100. // Leave the critical section. We have to do this before the Release,
  2101. // because the Release will probably delete the critsec.
  2102. _csVolume.Leave();
  2103. // Do what is probably the final release.
  2104. Release();
  2105. }
  2106. else
  2107. _csVolume.Leave();
  2108. return( cLocksNew );
  2109. }
  2110. // Take the volume handle critsec
  2111. inline ULONG
  2112. CVolume::LockHandles()
  2113. {
  2114. _csHandles.Enter();
  2115. return( _cHandleLocks++ );
  2116. }
  2117. // Release the volume handle critsec
  2118. inline ULONG
  2119. CVolume::UnlockHandles()
  2120. {
  2121. ULONG cHandleLocks = --_cHandleLocks;
  2122. _csHandles.Leave();
  2123. return( cHandleLocks );
  2124. }
  2125. // Verify that the volume critsec has been taken.
  2126. inline void
  2127. CVolume::AssertLocked()
  2128. {
  2129. TrkAssert( _cLocks > 0 );
  2130. }
  2131. // This routine is called when an error occurs that should never
  2132. // happen, and we want to break into the debugger if the user
  2133. // has configured us to do so. This was added so that we could
  2134. // catch such occurrences in stress.
  2135. inline void
  2136. CVolume::BreakIfRequested()
  2137. {
  2138. #if DBG
  2139. if( _pTrkWksConfiguration->GetBreakOnErrors() )
  2140. DebugBreak();
  2141. #endif
  2142. }
  2143. //+----------------------------------------------------------------------------
  2144. //
  2145. // CVolumeNode
  2146. //
  2147. // A node in the volume manager's linked list of CVolume objects.
  2148. //
  2149. //+----------------------------------------------------------------------------
  2150. class CVolumeNode
  2151. {
  2152. public:
  2153. CVolumeNode() : _pVolume(NULL), _pNext(NULL) { }
  2154. CVolume * _pVolume;
  2155. CVolumeNode * _pNext;
  2156. };
  2157. //-----------------------------------------------------------------------------
  2158. //
  2159. // CDeletionsManager
  2160. //
  2161. // This class manages the deletions of link source files, wrt their object
  2162. // IDs. When a file has been deleted, it's a link source, and it's been moved
  2163. // across volumes, we must notify the DC (trksvr) so that it can remove
  2164. // that entry (in order to save space). We know a file has been moved across
  2165. // volumes because doing so sets a bit in the birth ID.
  2166. //
  2167. // If a file is deleted, but then recreated and therefore the objid is
  2168. // tunnelled, then we will initially believe that it needs to be deleted
  2169. // from trksvr, when in fact it doesn't. Another problem is that we may
  2170. // see a delete and send a delete-notify before the (move-notify that
  2171. // moved the file here) is sent.
  2172. //
  2173. // To handle these two problems and for batching performance, this
  2174. // deletions manager always holds on to delete-notifies for a minimum of 5
  2175. // minutes. This hueristic is intended to allow move-notifies to be received
  2176. // and processed by trksvr. And if an objid is tunnelled, it can be
  2177. // removed from the list of delete-notifies before it is sent to trksvr.
  2178. //
  2179. // The 5 minute delay is implemented by maintaining two linked-lists.
  2180. // When we discover that a link source has been deleted, that birth ID
  2181. // gets added to the "latest" list and a 5 minute timer is started.
  2182. // When the timer goes off, that list (which may now have more delete-
  2183. // notifies in it) is switched to the "oldest" list, and another 5 minute
  2184. // timer is started. During that 5 minutes, any new delete-notifies
  2185. // are added to the "latest" list. When that timer goes off, the
  2186. // items in the "oldest" list are sent to trksvr, the list entries are freed,
  2187. // and the "latest" items are moved to the "oldest" list.
  2188. //
  2189. //-----------------------------------------------------------------------------
  2190. class CTrkWksSvc;
  2191. class CDeletionsManager :
  2192. public PTimerCallback,
  2193. public PObjIdIndexChangedCallback
  2194. {
  2195. public:
  2196. CDeletionsManager() : _fInitialized(FALSE) { }
  2197. void Initialize( const CTrkWksConfiguration *pconfigWks);
  2198. void UnInitialize();
  2199. void NotifyAddOrDelete( ULONG Action, const CDomainRelativeObjId & droid );
  2200. TimerContinuation Timer( ULONG ulTimerId );
  2201. private:
  2202. enum DELTIMERID
  2203. {
  2204. DELTIMER_DELETE_NOTIFY = 1
  2205. };
  2206. PTimerCallback::TimerContinuation
  2207. OnDeleteNotifyTimeout();
  2208. void FreeDeletions( DROID_LIST_ELEMENT *pStop = NULL );
  2209. private:
  2210. // Has Initialize been called?
  2211. BOOL _fInitialized:1;
  2212. // Critsec to protect this class.
  2213. CCriticalSection _csDeletions;
  2214. // List of recent and old deletions. If either
  2215. // is non-NULL, then the timer should be running.
  2216. DROID_LIST_ELEMENT* _pLatestDeletions;
  2217. DROID_LIST_ELEMENT* _pOldestDeletions;
  2218. ULONG _cLatestDeletions;
  2219. // When this timer fires, we send the old deletions to
  2220. // trksvr, and move the "latest" entries to the "oldest" list.
  2221. CNewTimer _timerDeletions;
  2222. // TrkWks configuration information.
  2223. const CTrkWksConfiguration
  2224. *_pconfigWks;
  2225. }; // class CDeletionsManager
  2226. //-------------------------------------------------------------------
  2227. //
  2228. // CVolumeManager
  2229. //
  2230. // This class maintains all the CVolume's on the machine (in a
  2231. // linked list).
  2232. //
  2233. //-------------------------------------------------------------------
  2234. #define CVOLUMEMANAGER_SIG 'GMLV' // VLMG
  2235. #define CVOLUMEMANAGER_SIGDEL 'gMlV' // VlMg
  2236. class CVolume;
  2237. class CVolumeNode;
  2238. class CVolumeManager :
  2239. public PTimerCallback,
  2240. public PWorkItem
  2241. {
  2242. friend class CVolumeEnumerator;
  2243. // ------------
  2244. // Construction
  2245. // ------------
  2246. public:
  2247. inline CVolumeManager();
  2248. inline ~CVolumeManager();
  2249. // --------------
  2250. // Initialization
  2251. // --------------
  2252. public:
  2253. void Initialize(
  2254. CTrkWksSvc * pTrkWks,
  2255. const CTrkWksConfiguration *pTrkWksConfiguration,
  2256. PLogCallback * pLogCallback,
  2257. SERVICE_STATUS_HANDLE ssh
  2258. #if DBG
  2259. , CTestSync * pTunnelTest
  2260. #endif
  2261. );
  2262. void InitializeDomainObjects();
  2263. void StartDomainTimers();
  2264. void UnInitialize();
  2265. void UnInitializeDomainObjects();
  2266. void OnVolumeToBeReopened();
  2267. // ---------------
  2268. // Exposed Methods
  2269. // ---------------
  2270. public:
  2271. void Append(
  2272. const CDomainRelativeObjId &droidCurrent,
  2273. const CDomainRelativeObjId &droidNew,
  2274. const CMachineId &mcidNew,
  2275. const CDomainRelativeObjId &droidBirth);
  2276. ULONG GetVolumeIds( CVolumeId * pVolumeIds, ULONG cMax );
  2277. HRESULT Search( DWORD Restrictions,
  2278. const CDomainRelativeObjId & droidBirthLast,
  2279. const CDomainRelativeObjId & droidLast,
  2280. CDomainRelativeObjId * pdroidBirthNext,
  2281. CDomainRelativeObjId * pdroidNext,
  2282. CMachineId * pmcidNext,
  2283. TCHAR * ptszLocalPath );
  2284. void Seek( CVolumeId vol, SequenceNumber seq );
  2285. CVolume * FindVolume( const CVolumeId &vol );
  2286. CVolume * FindVolume( const TCHAR *ptszVolumeDeviceName );
  2287. void FlushAllVolumes( BOOL fServiceShutdown = TRUE );
  2288. CVolume * IsDuplicateVolId( CVolume *pvolCheck, const CVolumeId &volid );
  2289. HRESULT OnRestore();
  2290. enum EEnumType
  2291. {
  2292. ENUM_UNOPENED_VOLUMES = 1,
  2293. ENUM_OPENED_VOLUMES = 2
  2294. };
  2295. CVolumeEnumerator Enum( EEnumType eEnumType = ENUM_OPENED_VOLUMES );
  2296. BOOL IsLocal( const CVolumeId &vol );
  2297. HRESULT DcCallback(ULONG cVolumes, TRKSVR_SYNC_VOLUME* rgVolumes);
  2298. void CloseVolumeHandles( HDEVNOTIFY hdnVolume = NULL );
  2299. void SetReopenVolumeHandlesTimer();
  2300. BOOL ReopenVolumeHandles();
  2301. void ForceVolumeClaims();
  2302. void OnEntriesAvailable();
  2303. void RefreshVolumes( PLogCallback *pLogCallback, SERVICE_STATUS_HANDLE ssh
  2304. #if DBG
  2305. , CTestSync *pTunnelTest
  2306. #endif
  2307. );
  2308. void RemoveVolumeFromLinkedList( const CVolume *pvol );
  2309. inline void SetVolInitTimer();
  2310. inline void OnVolumeLock( HDEVNOTIFY hdnVolume );
  2311. inline void OnVolumeLockFailed( HDEVNOTIFY hdnVolume );
  2312. inline void OnVolumeUnlock( HDEVNOTIFY hdnVolume );
  2313. inline void OnVolumeMount( HDEVNOTIFY hdnVolume );
  2314. inline void OnVolumeDismount( HDEVNOTIFY hdnVolume );
  2315. inline void OnVolumeDismountFailed( HDEVNOTIFY hdnVolume );
  2316. // ----------------
  2317. // Internal Methods
  2318. // ----------------
  2319. private:
  2320. // SyncVolumes doesn't raise
  2321. BOOL SyncVolumes( EAggressiveness eAggressiveness,
  2322. CFILETIME cftLastDue = 0,
  2323. ULONG ulPeriodInSeconds = 0 );
  2324. BOOL CheckSequenceNumbers();
  2325. void InitializeVolumeList( const CTrkWksConfiguration *pTrkWksConfiguration,
  2326. PLogCallback *pLogCallback,
  2327. SERVICE_STATUS_HANDLE ssh
  2328. #if DBG
  2329. , CTestSync *pTunnelTest
  2330. #endif
  2331. );
  2332. enum EVolumeDeviceEvent
  2333. {
  2334. ON_VOLUME_LOCK,
  2335. ON_VOLUME_UNLOCK,
  2336. ON_VOLUME_LOCK_FAILED,
  2337. ON_VOLUME_MOUNT,
  2338. ON_VOLUME_DISMOUNT,
  2339. ON_VOLUME_DISMOUNT_FAILED
  2340. };
  2341. void VolumeDeviceEvent( HDEVNOTIFY hdnVolume, EVolumeDeviceEvent eVolumeDeviceEvent );
  2342. VOID CheckVolumeList();
  2343. // void OnLogCloseTimer();
  2344. PTimerCallback::TimerContinuation
  2345. OnVolumeTimer( DWORD dwTimerId );
  2346. TimerContinuation Timer( DWORD dwTimerId );
  2347. void DoWork(); // called when the lock volume event is signalled
  2348. void CleanUpOids();
  2349. void AddNodeToLinkedList( CVolumeNode *pVolNode );
  2350. // -----
  2351. // State
  2352. // -----
  2353. private:
  2354. ULONG _sig;
  2355. enum VOLTIMERID
  2356. {
  2357. VOLTIMER_FREQUENT = 1,
  2358. VOLTIMER_INFREQUENT = 2,
  2359. VOLTIMER_INIT = 3,
  2360. // VOLTIMER_LOG_CLOSE = 4,
  2361. VOLTIMER_OBJID_INDEX_REOPEN = 5,
  2362. VOLTIMER_REFRESH = 6,
  2363. VOLTIMER_NOTIFY = 7,
  2364. };
  2365. // Initialize has been called?
  2366. BOOL _fInitialized:1;
  2367. // Are we hesitating before sending refresh notifications?
  2368. BOOL _fRefreshHesitation:1;
  2369. // Are we in the delay before executing a frequent or infrequent task?
  2370. BOOL _fFrequentTaskHesitation:1;
  2371. BOOL _fInfrequentTaskHesitation:1;
  2372. // The following is set once ReopenVolumeHandles has been called
  2373. // at least once (they are not opened in the Initialize method; they
  2374. // must be opened on an IO thread). Until this flag is set, the Enum
  2375. // method will not return any volumes.
  2376. BOOL _fVolumesHaveBeenOpenedOnce:1;
  2377. // When this timer goes off, we check for things like whether
  2378. // we can get out of the not-owned state.
  2379. CNewTimer _timerFrequentTasks;
  2380. // When this timer goes off, we check to see if we're in sync
  2381. // with the trksvr.
  2382. CNewTimer _timerInfrequentTasks;
  2383. // When this timer goes off, the volumes need to be
  2384. // (re) initialized for some reason (e.g. service start).
  2385. CNewTimer _timerVolumeInit;
  2386. // When this timer goes off, we should try to reopen the
  2387. // volume handles.
  2388. CNewTimer _timerObjIdIndexReopen;
  2389. // When this timer fires, we refresh our entries in trksvr
  2390. CNewTimer _timerRefresh;
  2391. // When this timer fires, we send move notifications to trksvr
  2392. // from the volume logs.
  2393. CNewTimer _timerNotify;
  2394. // Use this counter to ensure we only have one sync/refresh
  2395. // volume operation in progress at a time.
  2396. LONG _cSyncVolumesInProgress;
  2397. LONG _cRefreshVolumesInProgress;
  2398. // This is used with Begin/EndSingleInstanceTask in
  2399. // ReopenVolumeHandles so that we don't do that routine
  2400. // simultaneously in multiple threads.
  2401. LONG _cReopenVolumeHandles;
  2402. // Set this event if there is a volume that needs to be
  2403. // reopened.
  2404. HANDLE _heventVolumeToBeReopened;
  2405. HANDLE _hRegisterWaitForSingleObjectEx;
  2406. // This object watches the oid index for interesting deletes.
  2407. CDeletionsManager _deletions;
  2408. // Trkwks service configuration values.
  2409. const CTrkWksConfiguration
  2410. *_pTrkWksConfiguration;
  2411. CTrkWksSvc *_pTrkWks;
  2412. // Linked list of CVolume's.
  2413. CVolumeNode * _pVolumeNodeListHead; // linked list of CVolumes
  2414. CCriticalSection _csVolumeNodeList; // and a critsec to protect it.
  2415. // The list of volumes that are being synced with trksvr.
  2416. CVolume* _rgVolumesToUpdate[ NUM_VOLUMES ];
  2417. HDEVNOTIFY _hdnVolumeLock;
  2418. };
  2419. inline
  2420. CVolumeManager::CVolumeManager()
  2421. {
  2422. _sig = CVOLUMEMANAGER_SIG;
  2423. _fInitialized = FALSE;
  2424. _pVolumeNodeListHead = NULL;
  2425. _fFrequentTaskHesitation = FALSE;
  2426. _fVolumesHaveBeenOpenedOnce = FALSE;
  2427. _fInfrequentTaskHesitation = FALSE;
  2428. _fRefreshHesitation = FALSE;
  2429. _cReopenVolumeHandles = 0;
  2430. _cSyncVolumesInProgress = _cRefreshVolumesInProgress = 0;
  2431. _heventVolumeToBeReopened = NULL;
  2432. IFDBG( _tcscpy( _tszWorkItemSig, TEXT("CVolumeManager") ));
  2433. }
  2434. inline
  2435. CVolumeManager::~CVolumeManager()
  2436. {
  2437. UnInitialize();
  2438. _sig = CVOLUMEMANAGER_SIGDEL;
  2439. }
  2440. // When a volume needs to be reopend, set an event
  2441. // so that the reopen can happen on a worker thread.
  2442. inline void
  2443. CVolumeManager::OnVolumeToBeReopened()
  2444. {
  2445. TrkVerify( SetEvent( _heventVolumeToBeReopened ));
  2446. }
  2447. inline void
  2448. CVolumeManager::OnVolumeLock( HDEVNOTIFY hdnVolume )
  2449. {
  2450. //CloseAllVolumeHandles( hdnVolume );
  2451. VolumeDeviceEvent( hdnVolume, ON_VOLUME_LOCK );
  2452. }
  2453. inline void
  2454. CVolumeManager::OnVolumeUnlock( HDEVNOTIFY hdnVolume )
  2455. {
  2456. //FindAndSetReopenVolume( hdnVolume );
  2457. VolumeDeviceEvent( hdnVolume, ON_VOLUME_UNLOCK );
  2458. }
  2459. inline void
  2460. CVolumeManager::OnVolumeLockFailed( HDEVNOTIFY hdnVolume )
  2461. {
  2462. //FindAndSetReopenVolume( hdnVolume );
  2463. VolumeDeviceEvent( hdnVolume, ON_VOLUME_LOCK_FAILED );
  2464. }
  2465. inline void
  2466. CVolumeManager::OnVolumeMount( HDEVNOTIFY hdnVolume )
  2467. {
  2468. VolumeDeviceEvent( hdnVolume, ON_VOLUME_MOUNT );
  2469. }
  2470. inline void
  2471. CVolumeManager::OnVolumeDismount( HDEVNOTIFY hdnVolume )
  2472. {
  2473. VolumeDeviceEvent( hdnVolume, ON_VOLUME_DISMOUNT );
  2474. }
  2475. inline void
  2476. CVolumeManager::OnVolumeDismountFailed( HDEVNOTIFY hdnVolume )
  2477. {
  2478. VolumeDeviceEvent( hdnVolume, ON_VOLUME_DISMOUNT_FAILED );
  2479. }
  2480. // This timer is set by CTrkWksSvc when it tries to do a MoveNotify
  2481. // and gets TRK_E_SERVER_TOO_BUSY.
  2482. inline void
  2483. CVolumeManager::SetVolInitTimer()
  2484. {
  2485. if( !_pTrkWksConfiguration->_fIsWorkgroup )
  2486. {
  2487. _timerVolumeInit.SetSingleShot();
  2488. TrkLog(( TRKDBG_LOG, TEXT("VolInit timer: %s"),
  2489. (const TCHAR*)CDebugString( _timerVolumeInit ) ));
  2490. }
  2491. }
  2492. //-------------------------------------------------------------------
  2493. //
  2494. // CVolumeEnumerator
  2495. //
  2496. // This class performs an enumeration of the volumes on this machine.
  2497. //
  2498. //-------------------------------------------------------------------
  2499. class CVolumeEnumerator
  2500. {
  2501. // ------------
  2502. // Construction
  2503. // ------------
  2504. public:
  2505. CVolumeEnumerator(CVolumeNode** pprgVol = NULL,
  2506. CCriticalSection *pcs = NULL )
  2507. : _ppVolumeNodeListHead(pprgVol),
  2508. _pcs(pcs),
  2509. _pVolNodeLast(NULL) {}
  2510. // ---------------
  2511. // Exposed Methods
  2512. // ---------------
  2513. public:
  2514. CVolume * GetNextVolume();
  2515. void UnInitialize() { _ppVolumeNodeListHead = NULL; _pcs = NULL; }
  2516. // -----
  2517. // State
  2518. // -----
  2519. private:
  2520. // Head of this linked list of volumes.
  2521. CVolumeNode **_ppVolumeNodeListHead;
  2522. // The critsec that protects the above list.
  2523. CCriticalSection *_pcs;
  2524. // Current seek position in the list.
  2525. CVolumeNode *_pVolNodeLast;
  2526. }; // class CVolumeEnumerator
  2527. //-------------------------------------------------------------------
  2528. //
  2529. // CAllVolumesObjIdEnumerator
  2530. //
  2531. // This class performs an enumeration of all object IDs on this
  2532. // machine.
  2533. //
  2534. //-------------------------------------------------------------------
  2535. class CAllVolumesObjIdEnumerator
  2536. {
  2537. public:
  2538. inline CAllVolumesObjIdEnumerator() { _pvol = NULL; }
  2539. inline ~CAllVolumesObjIdEnumerator() { UnInitialize(); }
  2540. inline void UnInitialize();
  2541. inline BOOL FindFirst( CVolumeManager *pVolMgr, CObjId * pobjid, CDomainRelativeObjId * pdroidBirth );
  2542. inline BOOL FindNext( CObjId * pobjid, CDomainRelativeObjId * pdroidBirth );
  2543. private:
  2544. inline BOOL FindFirstOnVolume( CObjId *pobjid, CDomainRelativeObjId *pdroidBirth );
  2545. private:
  2546. // A volume enumerator
  2547. CVolumeEnumerator _volenum;
  2548. // The object ID enumerator for the current volume.
  2549. CObjIdEnumerator _objidenum;
  2550. // The current volume.
  2551. CVolume *_pvol;
  2552. }; // class CAllVolumesObjIdEnumerator
  2553. inline void
  2554. CAllVolumesObjIdEnumerator::UnInitialize()
  2555. {
  2556. if( NULL != _pvol )
  2557. {
  2558. _pvol->Release();
  2559. _pvol = NULL;
  2560. }
  2561. _objidenum.UnInitialize();
  2562. _volenum.UnInitialize();
  2563. }
  2564. // Get the next entry in the enumeration.
  2565. inline BOOL
  2566. CAllVolumesObjIdEnumerator::FindNext( CObjId * pobjid, CDomainRelativeObjId * pdroid )
  2567. {
  2568. // See if there's another object ID on this volume.
  2569. if( _objidenum.FindNext( pobjid, pdroid ))
  2570. {
  2571. // Yes, there is.
  2572. if( pdroid->GetVolumeId().GetUserBitState() )
  2573. {
  2574. TrkLog(( TRKDBG_GARBAGE_COLLECT, TEXT("Refreshing file %s, %s"),
  2575. (const TCHAR*)CDebugString(*pobjid),
  2576. (const TCHAR*)CDebugString(*pdroid) ));
  2577. }
  2578. return( TRUE );
  2579. }
  2580. // There are no more object IDs on this volume. Move on
  2581. // to the next volume and return the first ID on that volue.
  2582. _objidenum.UnInitialize();
  2583. _pvol->Release();
  2584. _pvol = _volenum.GetNextVolume();
  2585. return( FindFirstOnVolume( pobjid, pdroid ));
  2586. }
  2587. // Restart the enumeration.
  2588. inline BOOL
  2589. CAllVolumesObjIdEnumerator::FindFirst( CVolumeManager *pVolMgr, CObjId * pobjid, CDomainRelativeObjId * pdroid )
  2590. {
  2591. _volenum = pVolMgr->Enum();
  2592. _pvol = _volenum.GetNextVolume();
  2593. return( FindFirstOnVolume( pobjid, pdroid ));
  2594. }
  2595. // Restart the object ID enueration on the current volume _pvol.
  2596. inline BOOL
  2597. CAllVolumesObjIdEnumerator::FindFirstOnVolume( CObjId *pobjid, CDomainRelativeObjId *pdroid )
  2598. {
  2599. if( NULL == _pvol || !_pvol->EnumObjIds( &_objidenum ) )
  2600. return( FALSE );
  2601. TrkLog(( TRKDBG_GARBAGE_COLLECT, TEXT("Refreshing volume %c: (%s)"),
  2602. VolChar(_pvol->GetIndex()), _pvol->GetVolumeDeviceName() ));
  2603. // Find the first object ID.
  2604. if( _objidenum.FindFirst( pobjid, pdroid ))
  2605. {
  2606. #if DBG
  2607. {
  2608. if( pdroid->GetVolumeId().GetUserBitState() )
  2609. TrkLog(( TRKDBG_GARBAGE_COLLECT, TEXT("Refreshing file %s, %s"),
  2610. (const TCHAR*)CDebugString(*pobjid),
  2611. (const TCHAR*)CDebugString(*pdroid) ));
  2612. }
  2613. #endif
  2614. return( TRUE );
  2615. }
  2616. else
  2617. {
  2618. // There weren't any object IDs on this volume. Move
  2619. // to the next volume.
  2620. _objidenum.UnInitialize();
  2621. _pvol->Release();
  2622. _pvol = _volenum.GetNextVolume();
  2623. return( FindFirstOnVolume( pobjid, pdroid ));
  2624. }
  2625. }
  2626. //-------------------------------------------------------------------//
  2627. // //
  2628. // CPersistentVolumeMap
  2629. //
  2630. // Not currently implemented.
  2631. //
  2632. //-------------------------------------------------------------------//
  2633. #ifdef VOL_REPL
  2634. #define PVM_VERSION 1
  2635. class CPersistentVolumeMap : private CVolumeMap,
  2636. private CSecureFile,
  2637. protected PRobustlyCreateableFile
  2638. {
  2639. public:
  2640. inline CPersistentVolumeMap();
  2641. inline ~CPersistentVolumeMap();
  2642. void Initialize();
  2643. void UnInitialize();
  2644. void CopyTo(DWORD * pcVolumes, VolumeMapEntry ** ppVolumeChanges);
  2645. BOOL FindVolume( const CVolumeId & volume, CMachineId * pmcid );
  2646. CFILETIME GetLastUpdateTime( );
  2647. void SetLastUpdateTime( const CFILETIME & cftFirstChange );
  2648. void Merge( CVolumeMap * pOther ); // destroys other
  2649. protected:
  2650. virtual RCF_RESULT OpenExistingFile( const TCHAR * ptszFile );
  2651. virtual void CreateAlwaysFile( const TCHAR * ptszTempFile );
  2652. private:
  2653. void Load();
  2654. void Save();
  2655. private:
  2656. CFILETIME _cft;
  2657. CCritcalSection _cs;
  2658. BOOL _fInitializeCalled;
  2659. BOOL _fMergeDirtiedMap;
  2660. };
  2661. inline
  2662. CPersistentVolumeMap::CPersistentVolumeMap() :
  2663. _fInitializeCalled(FALSE),
  2664. _fMergeDirtiedMap(FALSE)
  2665. {
  2666. }
  2667. inline
  2668. CPersistentVolumeMap::~CPersistentVolumeMap()
  2669. {
  2670. TrkAssert( !IsOpen() );
  2671. TrkAssert( !_fInitializeCalled );
  2672. }
  2673. #endif
  2674. //-------------------------------------------------------------------
  2675. //
  2676. // CPort
  2677. //
  2678. // This class represents the LPC port to which IO sends
  2679. // move notifications (in the context of MoveFile).
  2680. //
  2681. //-------------------------------------------------------------------
  2682. #define MOVE_BATCH_DUE_TIME 15 // 15 seconds
  2683. #define MAX_MOVE_BATCH_DUE_TIME (6 * 60 * 60) // 6 hours
  2684. class CWorkManager;
  2685. class CPort : private PWorkItem
  2686. {
  2687. public:
  2688. CPort() : _fInitializeCalled(FALSE)
  2689. {
  2690. IFDBG( _tcscpy( _tszWorkItemSig, TEXT("CPort") ));
  2691. }
  2692. ~CPort() { UnInitialize(); }
  2693. void Initialize( CTrkWksSvc *pTrkWks, DWORD dwThreadKeepAliveTime );
  2694. void UnInitialize();
  2695. void EnableKernelNotifications();
  2696. void DisableKernelNotifications();
  2697. private:
  2698. enum ENUM_ACCEPT_PORT
  2699. {
  2700. ACCEPT,
  2701. REJECT
  2702. };
  2703. NTSTATUS OnConnectionRequest( TRKWKS_PORT_CONNECT_REQUEST *pPortConnectRequest,
  2704. BOOL *pfStopPortThread );
  2705. BOOL RegisterWorkItemWithThreadPool();
  2706. // PWorkItem
  2707. void DoWork();
  2708. friend DWORD WINAPI
  2709. PortThreadStartRoutine(LPVOID lpThreadParameter);
  2710. private:
  2711. // Has Initialize been called?
  2712. BOOL _fInitializeCalled:1;
  2713. // Is the service stopping?
  2714. BOOL _fTerminating:1;
  2715. // Thread pool registration of _hListenPort
  2716. HANDLE _hRegisterWaitForSingleObjectEx;
  2717. // The listen handle (NtCreateWaitablePort)
  2718. HANDLE _hListenPort;
  2719. // The port handle (NtAcceptConnectPort)
  2720. HANDLE _hLpcPort;
  2721. // Syncrhonization with IO
  2722. HANDLE _hEvent;
  2723. // How long to keep a thread sitting on the
  2724. // NtReplyWaitReceivePortEx.
  2725. LARGE_INTEGER _ThreadKeepAliveTime;
  2726. CTrkWksSvc * _pTrkWks;
  2727. }; // class CPort
  2728. //-------------------------------------------------------------------
  2729. //
  2730. // CVolumeLocationCache
  2731. //
  2732. // This class maintains a cache of volid->mcid mappings that
  2733. // have been discovered by this service during this instance
  2734. // (i.e. it's not persisted). It's a circular cache, with
  2735. // timestamps on the entries in order to determine trust.
  2736. //
  2737. //-------------------------------------------------------------------
  2738. typedef struct
  2739. {
  2740. CVolumeId volid;
  2741. CMachineId mcid;
  2742. CFILETIME cft; // The time this entry was last updated
  2743. #if defined(_AXP64_)
  2744. //
  2745. // There is currently a bug in at least the axp64 compiler that requires
  2746. // this structure to be 8-byte aligned.
  2747. //
  2748. // The symptom of the failure is an alignment fault at
  2749. // ??0VolumeLocation@@QEA@XZ + 0x14.
  2750. //
  2751. PVOID Alignment;
  2752. #endif
  2753. } VolumeLocation;
  2754. #define MAX_CACHED_VOLUME_LOCATIONS 32
  2755. class CVolumeLocationCache
  2756. {
  2757. public:
  2758. CVolumeLocationCache() : _fInitialized(FALSE) {}
  2759. void Initialize( DWORD dwEntryLifetimeSeconds );
  2760. void UnInitialize();
  2761. BOOL FindVolume(const CVolumeId & volid, CMachineId * pmcid, BOOL *pfRecentEntry );
  2762. void AddVolume(const CVolumeId & volid, const CMachineId & mcid);
  2763. private:
  2764. int _FindVolume(const CVolumeId & volid);
  2765. private:
  2766. // Has Initialize been called?
  2767. BOOL _fInitialized;
  2768. // Critsec to protect this class.
  2769. CCriticalSection _cs;
  2770. // The array of volume entries
  2771. int _cVols;
  2772. VolumeLocation _vl[ MAX_CACHED_VOLUME_LOCATIONS ];
  2773. // The age after which an entry is considered old and
  2774. // not trustworthy.
  2775. CFILETIME _cftEntryLifetime;
  2776. };
  2777. //-------------------------------------------------------------------
  2778. //
  2779. // CEntropyRecorder
  2780. //
  2781. // This class maintains an array of "entropy"; randomly generated
  2782. // data. The source of the data is a munging of data from the
  2783. // performance counter. The source of the entropy (the times at
  2784. // which the performance counter is queried) as the assumed randomness
  2785. // in disk access times.
  2786. //
  2787. //-------------------------------------------------------------------
  2788. #define MAX_ENTROPY 256
  2789. class CEntropyRecorder
  2790. {
  2791. public:
  2792. CEntropyRecorder();
  2793. void Initialize();
  2794. void UnInitialize();
  2795. void Put();
  2796. BOOL InitializeSecret( CVolumeSecret * pSecret );
  2797. void ReturnUnusedSecret( CVolumeSecret * pSecret );
  2798. private:
  2799. BOOL GetEntropy( void * pv, ULONG cb );
  2800. void PutEntropy( BYTE b );
  2801. private:
  2802. // Has Initialize been called?
  2803. BOOL _fInitialized;
  2804. // Critsec to protect the array.
  2805. CCriticalSection _cs;
  2806. // Array of bytes, seek pointer, and max available
  2807. // bytes.
  2808. DWORD _iNext;
  2809. DWORD _cbTotalEntropy;
  2810. BYTE _abEntropy[MAX_ENTROPY];
  2811. };
  2812. inline
  2813. CEntropyRecorder::CEntropyRecorder()
  2814. {
  2815. _fInitialized = FALSE;
  2816. }
  2817. //+----------------------------------------------------------------------------
  2818. //
  2819. // CTrkWksRpcServer
  2820. //
  2821. // This class implements the RPC server code for the trkwks service.
  2822. //
  2823. //+----------------------------------------------------------------------------
  2824. class CTrkWksRpcServer : public CRpcServer
  2825. {
  2826. public:
  2827. void Initialize( SVCHOST_GLOBAL_DATA * pSvcsGlobalData, CTrkWksConfiguration *pTrkWksConfig );
  2828. void UnInitialize( SVCHOST_GLOBAL_DATA * pSvcsGlobalData );
  2829. };
  2830. //-------------------------------------------------------------------//
  2831. // //
  2832. // CTestSync - class to allow test synchronization //
  2833. // //
  2834. //-------------------------------------------------------------------//
  2835. #if DBG
  2836. class CTestSync
  2837. {
  2838. public:
  2839. CTestSync() : _hSemReached(NULL), _hSemWait(NULL), _hSemFlag(NULL) {}
  2840. ~CTestSync() { UnInitialize(); }
  2841. void Initialize(const TCHAR *ptszBaseName);
  2842. void UnInitialize();
  2843. void ReleaseAndWait();
  2844. private:
  2845. HANDLE _hSemFlag;
  2846. HANDLE _hSemReached;
  2847. HANDLE _hSemWait;
  2848. };
  2849. #endif // #if DBG
  2850. //-------------------------------------------------------------------//
  2851. //
  2852. // CMountManager
  2853. //
  2854. // Not currently implemented.
  2855. //
  2856. //-------------------------------------------------------------------//
  2857. #if 0
  2858. class CMountManager : public PWorkItem
  2859. {
  2860. public:
  2861. CMountManager()
  2862. {
  2863. _pTrkWksSvc = NULL;
  2864. _pVolMgr = NULL;
  2865. _hCompletionEvent = NULL;
  2866. _hMountManager = NULL;
  2867. _hRegisterWaitForSingleObjectEx = NULL;
  2868. IFDBG( _tcscpy( _tszWorkItemSig, TEXT("CMountManager") ));
  2869. }
  2870. void Initialize(CTrkWksSvc * pTrkWksSvc, CVolumeManager *pVolMgr );
  2871. void UnInitialize();
  2872. // PWorkItem overloads
  2873. virtual void DoWork(); // handle the signalled timer handle
  2874. private:
  2875. void AsyncListen();
  2876. private:
  2877. BOOL _fInitialized:1;
  2878. CTrkWksSvc * _pTrkWksSvc;
  2879. CVolumeManager * _pVolMgr;
  2880. MOUNTMGR_CHANGE_NOTIFY_INFO
  2881. _info;
  2882. HANDLE _hCompletionEvent;
  2883. HANDLE _hMountManager;
  2884. HANDLE _hRegisterWaitForSingleObjectEx;
  2885. };
  2886. #endif // #if 0
  2887. //-------------------------------------------------------------------
  2888. //
  2889. // CAvailableDc
  2890. //
  2891. // This class maintains a client-side binding handle to a DC
  2892. // in the domain. The CallAvailableDc method can be used
  2893. // to send a tracking message to that (or another if necessary)
  2894. // DC. If a DC becomes unavailable, it automatically attempts
  2895. // to fail over to one that is available.
  2896. //
  2897. //-------------------------------------------------------------------
  2898. class CAvailableDc : public CTrkRpcConfig
  2899. {
  2900. private:
  2901. CRpcClientBinding _rcDomain;
  2902. CMachineId _mcidDomain;
  2903. public:
  2904. CAvailableDc() {}
  2905. ~CAvailableDc() { UnInitialize(); }
  2906. void UnInitialize();
  2907. HRESULT CallAvailableDc(TRKSVR_MESSAGE_UNION *pMsg,
  2908. RC_AUTHENTICATE auth = INTEGRITY_AUTHENTICATION );
  2909. };
  2910. //-------------------------------------------------------------------//
  2911. // //
  2912. // GLOBALS
  2913. // //
  2914. //-------------------------------------------------------------------//
  2915. EXTERN CTrkWksSvc * g_ptrkwks INIT(NULL); // Used by RPC stubs
  2916. EXTERN LONG g_ctrkwks INIT(0); // Used to protect against multiple service instances
  2917. #define CTRKWKSSVC_SIG 'KWRT' // TRWK
  2918. #define CTRKWKSSVC_SIGDEL 'kWrT' // TrWk
  2919. #if DBG
  2920. EXTERN LONG g_cTrkWksRpcThreads INIT(0);
  2921. #endif
  2922. //-------------------------------------------------------------------//
  2923. //
  2924. // CDomainNameChangeNotify
  2925. //
  2926. // This class watches for notifications that the machine has
  2927. // been moved into a new domain. Such an event is actually
  2928. // dealt with in CTrkWksSvc.
  2929. //
  2930. //-------------------------------------------------------------------//
  2931. class CDomainNameChangeNotify : public PWorkItem
  2932. {
  2933. public:
  2934. CDomainNameChangeNotify() : _fInitialized(FALSE),
  2935. _hDomainNameChangeNotification(INVALID_HANDLE_VALUE),
  2936. _hRegisterWaitForSingleObjectEx(NULL)
  2937. {
  2938. IFDBG( _tcscpy( _tszWorkItemSig, TEXT("CDomainNameChangeNotify") ));
  2939. }
  2940. ~CDomainNameChangeNotify() { UnInitialize(); }
  2941. void Initialize();
  2942. void UnInitialize();
  2943. // Work manager callback
  2944. virtual void DoWork();
  2945. private:
  2946. BOOL _fInitialized;
  2947. // Handle from NetRegisterDomainNameChangeNotification
  2948. HANDLE _hDomainNameChangeNotification;
  2949. // Thread pool handle for registration of above handle
  2950. HANDLE _hRegisterWaitForSingleObjectEx;
  2951. }; // class CDomainNameChangeNotify
  2952. //+----------------------------------------------------------------------------
  2953. //
  2954. // CTrkWksSvc
  2955. //
  2956. // This is the primary class in the Tracking Service (trkwks).
  2957. // It contains a CVolumeManager object, which maintains a list of
  2958. // CVolume objects, one for each NTFS5 volume in the system.
  2959. //
  2960. // CTrkWksSvc also handles SCM requests, and maintains some maintenance
  2961. // timers (the move notification timer, which indicates that a set of move
  2962. // notifications should be sent to the DC, and the refresh timer, which
  2963. // indicates that the DC's tables should be updated to show which objects
  2964. // on this machine are still alive.
  2965. //
  2966. // This is also the class that receives two RPC requests. One is a mend request
  2967. // that comes from clients (in NT5 the shell is the only client). The client
  2968. // provides the IDs and we search for the new location of the link source.
  2969. // The second request is a search request that comes from the trkwks service
  2970. // on another machine (this call is made as part of its processing of a
  2971. // Mend request).
  2972. //
  2973. //+----------------------------------------------------------------------------
  2974. class CTrkWksSvc :
  2975. public IServiceHandler,
  2976. public PLogCallback,
  2977. public CTrkRpcConfig,
  2978. public PWorkItem
  2979. {
  2980. public: // Initialization
  2981. inline CTrkWksSvc();
  2982. inline ~CTrkWksSvc();
  2983. void Initialize( SVCHOST_GLOBAL_DATA * pSvcsGlobalData );
  2984. void UnInitialize(HRESULT hrStatusForServiceController);
  2985. public: // RPC interface
  2986. HRESULT CallSvrMessage( handle_t IDL_handle,
  2987. TRKSVR_MESSAGE_UNION * pMsg );
  2988. HRESULT GetBackup( DWORD * pcVolumes,
  2989. VolumeMapEntry ** ppVolumeChanges,
  2990. FILETIME * pft);
  2991. HRESULT GetFileTrackingInformation(
  2992. const CDomainRelativeObjId & droidCurrent,
  2993. TrkInfoScope scope,
  2994. TRK_FILE_TRACKING_INFORMATION_PIPE pipeFileInfo
  2995. );
  2996. HRESULT GetVolumeTrackingInformation(
  2997. const CVolumeId & volid,
  2998. TrkInfoScope scope,
  2999. TRK_VOLUME_TRACKING_INFORMATION_PIPE pipeVolInfo
  3000. );
  3001. HRESULT MendLink(
  3002. RPC_BINDING_HANDLE IDL_handle,
  3003. DWORD dwTickCountDeadline,
  3004. DWORD Restrictions,
  3005. const CDomainRelativeObjId &droidBirthLast,
  3006. const CDomainRelativeObjId &droidLast,
  3007. const CMachineId &mcidLast,
  3008. CDomainRelativeObjId * pdroidBirthNew,
  3009. CDomainRelativeObjId * pdroidNew,
  3010. CMachineId * pmcidNew,
  3011. ULONG * pcbPath,
  3012. WCHAR * wsz );
  3013. inline HRESULT OnRestore( );
  3014. HRESULT SearchMachine(
  3015. RPC_BINDING_HANDLE IDL_handle,
  3016. DWORD Restrictions,
  3017. const CDomainRelativeObjId &droidBirthLast,
  3018. const CDomainRelativeObjId &droidLast,
  3019. CDomainRelativeObjId * pdroidBirthNext,
  3020. CDomainRelativeObjId * pdroidNext,
  3021. CMachineId * pmcidNext,
  3022. TCHAR* ptszPath );
  3023. HRESULT SetVolumeId(
  3024. ULONG iVolume,
  3025. const CVolumeId VolId
  3026. );
  3027. HRESULT TriggerVolumeClaims(
  3028. ULONG cVolumes,
  3029. const CVolumeId *rgvolid
  3030. );
  3031. public:
  3032. // PWorkItem override
  3033. virtual void DoWork();
  3034. inline ULONG GetSignature() const;
  3035. inline const CTrkWksConfiguration &
  3036. GetConfig();
  3037. CMachineId GetDcName( BOOL fForce = FALSE );
  3038. // called by NT port for each message in NT port
  3039. // puts the entry in the move log and starts the DC notification timer
  3040. NTSTATUS OnPortNotification(const TRKWKS_REQUEST *pRequest);
  3041. // called by service controller from CSvcCtrlInterface
  3042. DWORD ServiceHandler(DWORD dwControl,
  3043. DWORD dwEventType,
  3044. PVOID EventData,
  3045. PVOID pData);
  3046. inline void RaiseIfStopped() const;
  3047. // PLogCallback overload
  3048. void OnEntriesAvailable();
  3049. // send all those log entries that haven't been acknowledged persisted by DC
  3050. PTimerCallback::TimerContinuation
  3051. OnMoveBatchTimeout( EAggressiveness eAggressiveness = PASSIVE );
  3052. // send ids of volumes and cross-volume-moved sources for refreshing DC data
  3053. PTimerCallback::TimerContinuation
  3054. OnRefreshTimeout( CFILETIME cftOriginalDueTime,
  3055. ULONG ulPeriodInSeconds );
  3056. // add volume changes from DC to the persistent volume list
  3057. void CallDcSyncVolumes(ULONG cVolumes, TRKSVR_SYNC_VOLUME rgSyncVolumes[] );
  3058. // called by the CVolumeManager in a timer
  3059. CEntropyRecorder _entropy;
  3060. friend HRESULT StubLnkSvrMessageCallback(TRKSVR_MESSAGE_UNION* pMsg);
  3061. inline void SetReopenVolumeHandlesTimer();
  3062. void OnDomainNameChange();
  3063. private:
  3064. enum SEARCH_FLAGS
  3065. {
  3066. SEARCH_FLAGS_DEFAULT = 0,
  3067. USE_SPECIFIED_MCID = 1,
  3068. DONT_USE_DC = 2
  3069. };
  3070. void InitializeProcessPrivileges() const;
  3071. void StartDomainTimers() {}; // Doesn't raise
  3072. void UnInitializeDomainObjects();
  3073. void CheckForDomainOrWorkgroup(); // Sets _configWks._fIsWorkgroup
  3074. HRESULT ConnectAndSearchDomain(
  3075. IN const CDomainRelativeObjId &droidBirthLast,
  3076. IN OUT DWORD *pRestrictions,
  3077. IN OUT CDomainRelativeObjId *pdroidLast,
  3078. OUT CMachineId *pmcidLast );
  3079. HRESULT OldConnectAndSearchDomain(
  3080. IN const CDomainRelativeObjId &droidBirthLast,
  3081. IN OUT CDomainRelativeObjId *pdroidLast,
  3082. OUT CMachineId *pmcidLast );
  3083. HRESULT ConnectAndSearchMachine(
  3084. RPC_BINDING_HANDLE IDL_handle,
  3085. const CMachineId & mcid,
  3086. IN OUT DWORD *pRestrictions,
  3087. IN OUT CDomainRelativeObjId *pdroidBirthLast,
  3088. IN OUT CDomainRelativeObjId *pdroidLast,
  3089. OUT CMachineId *pmcidLast,
  3090. TCHAR *tsz);
  3091. HRESULT FindAndSearchVolume(RPC_BINDING_HANDLE IDL_handle,
  3092. IN OUT DWORD *pRestrictions,
  3093. IN SEARCH_FLAGS SearchFlags,
  3094. IN OUT CDomainRelativeObjId *pdroidBirthLast,
  3095. IN OUT CDomainRelativeObjId *pdroidLast,
  3096. IN OUT CMachineId *pmcidLast,
  3097. TCHAR *ptsz);
  3098. HRESULT SearchChain(RPC_BINDING_HANDLE IDL_handle,
  3099. int cMaxReferrals,
  3100. DWORD dwTickCountDeadline,
  3101. IN OUT DWORD *pRestrictions,
  3102. IN SEARCH_FLAGS SearchFlags,
  3103. IN OUT SAllIDs *pallidsLast,
  3104. OUT TCHAR *ptsz);
  3105. private:
  3106. ULONG _sig;
  3107. // Has Initialize been called?
  3108. BOOL _fInitializeCalled:1;
  3109. // Keep track of the number of threads doing a move notification
  3110. // to trksvr (so that all but the first can NOOP).
  3111. LONG _cOnMoveBatchTimeout;
  3112. #if !TRK_OWN_PROCESS
  3113. SVCHOST_GLOBAL_DATA * _pSvcsGlobalData;
  3114. #endif
  3115. // LPC port from which IO move notifications are read.
  3116. CPort _port;
  3117. // CMountManager _mountmanager;
  3118. // Code to perform the work to make us an RPC server
  3119. CTrkWksRpcServer _rpc;
  3120. // Interactions with the SCM
  3121. CSvcCtrlInterface _svcctrl;
  3122. // TrkWks configuration parameters
  3123. CTrkWksConfiguration
  3124. _configWks;
  3125. // Test syncs to check race conditions
  3126. #if DBG
  3127. CTestSync _testsyncMoveBatch;
  3128. CTestSync _testsyncTunnel;
  3129. #endif
  3130. CVolumeManager _volumes;
  3131. //HDEVNOTIFY _hdnDeviceInterface;
  3132. #ifdef VOL_REPL
  3133. CPersistentVolumeMap
  3134. _persistentVolumeMap;
  3135. #endif
  3136. // Cache of volid->mcid mappings
  3137. CVolumeLocationCache
  3138. _volumeLocCache;
  3139. // If true, don't bother trying to send move notifications
  3140. // for a while (days).
  3141. CRegBoolParameter _MoveQuotaReached;
  3142. // Monitor for domain name changes (entering a new domain).
  3143. CDomainNameChangeNotify
  3144. _dnchnotify;
  3145. CCriticalSection _csDomainNameChangeNotify;
  3146. //COperationLog _OperationLog;
  3147. // Get an available DC for this domain for use in contacting
  3148. // trksvr.
  3149. CAvailableDc _adc;
  3150. // The latest found DC for this domain.
  3151. CMachineId _mcidDC;
  3152. CCriticalSection _csmcidDC;
  3153. }; // class CTrkWksSvc
  3154. // ----------------------
  3155. // CTrkWksSvc::CTrkWksSvc
  3156. // ----------------------
  3157. inline
  3158. CTrkWksSvc::CTrkWksSvc() :
  3159. _fInitializeCalled(FALSE),
  3160. _sig(CTRKWKSSVC_SIG),
  3161. _cOnMoveBatchTimeout(0),
  3162. _MoveQuotaReached( TEXT("MoveQuotaReached") )
  3163. {
  3164. //_hdnDeviceInterface = NULL;
  3165. }
  3166. // -----------------------
  3167. // CTrkWksSvc::~CTrkWksSvc
  3168. // -----------------------
  3169. inline
  3170. CTrkWksSvc::~CTrkWksSvc()
  3171. {
  3172. TrkAssert( 0 == _cOnMoveBatchTimeout );
  3173. _csmcidDC.UnInitialize();
  3174. _sig = CTRKWKSSVC_SIGDEL;
  3175. TrkAssert(!_fInitializeCalled);
  3176. }
  3177. inline void
  3178. CTrkWksSvc::SetReopenVolumeHandlesTimer()
  3179. {
  3180. _volumes.SetReopenVolumeHandlesTimer();
  3181. }
  3182. inline void
  3183. CTrkWksSvc::RaiseIfStopped( ) const
  3184. {
  3185. if( _svcctrl.IsStopping() )
  3186. TrkRaiseException( TRK_E_SERVICE_STOPPING );
  3187. }
  3188. inline const CTrkWksConfiguration &
  3189. CTrkWksSvc::GetConfig()
  3190. {
  3191. return(_configWks);
  3192. }
  3193. inline ULONG
  3194. CTrkWksSvc::GetSignature() const
  3195. {
  3196. return( _sig );
  3197. }
  3198. inline HRESULT
  3199. CTrkWksSvc::OnRestore( )
  3200. {
  3201. return(_volumes.OnRestore());
  3202. }
  3203. /*
  3204. class CTestLog : public PTimerCallback
  3205. {
  3206. public:
  3207. CTestLog( CTrkWksConfiguration *pTrkWksConfiguration, CWorkManager *pWorkManager );
  3208. public:
  3209. void ReInitialize();
  3210. void UnInitialize();
  3211. void CreateLog( PLogCallback *pLogCallback, BOOL fValidate = TRUE );
  3212. void OpenLog( PLogCallback *pLogCallback, BOOL fValidate = TRUE );
  3213. void CloseLog();
  3214. void Append( ULONG cMoves,
  3215. const CObjId rgobjidCurrent[],
  3216. const CDomainRelativeObjId rgdroidNew[],
  3217. const CDomainRelativeObjId rgdroidBirth[] );
  3218. void DelayUntilClose();
  3219. ULONG Read( ULONG cRead, CObjId rgobjidCurrent[], CDomainRelativeObjId rgobjidNew[],
  3220. CDomainRelativeObjId rgobjidBirth[], SequenceNumber *pseqFirst );
  3221. void ReadAndValidate( ULONG cToRead, ULONG cExpected,
  3222. const TRKSVR_MOVE_NOTIFICATION rgNotificationsExpected[],
  3223. TRKSVR_MOVE_NOTIFICATION rgNotificationsRead[],
  3224. SequenceNumber seqExpected );
  3225. void ReadExtendedHeader( ULONG iOffset, void *pv, ULONG cb );
  3226. void WriteExtendedHeader( ULONG iOffset, const void *pv, ULONG cb );
  3227. SequenceNumber
  3228. GetNextSeqNumber( );
  3229. BOOL Search( const CDomainRelativeObjId &droid, TRKSVR_MOVE_NOTIFICATION *pNotification );
  3230. void Seek( SequenceNumber seq );
  3231. void Seek( int origin, int iSeek );
  3232. LogIndex GetReadIndex();
  3233. LogIndex GetStartIndex();
  3234. LogIndex GetEndIndex();
  3235. const TCHAR *LogFileName();
  3236. void SetReadIndex( LogIndex ilogRead );
  3237. ULONG NumEntriesInFile( );
  3238. ULONG NumEntriesPerSector();
  3239. ULONG NumEntriesPerKB();
  3240. ULONG CBSector() const;
  3241. void Timer( DWORD dwTimerId );
  3242. ULONG DataSectorOffset() const;
  3243. BOOL IsEmpty();
  3244. public:
  3245. void ValidateLog();
  3246. ULONG GetCbLog();
  3247. void MakeEntryOld();
  3248. ULONG GetNumEntries();
  3249. void GenerateLogName();
  3250. private:
  3251. CLog _cLog;
  3252. CTrkWksConfiguration *_pTrkWksConfiguration;
  3253. CLogFile _cLogFile;
  3254. DWORD _cbSector;
  3255. TCHAR _tszLogFile[ MAX_PATH + 1 ];
  3256. CWorkManager *_pWorkManager;
  3257. CSimpleTimer _cSimpleTimer;
  3258. };
  3259. */
  3260. #endif // #ifndef _TRKWKS_HXX_