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

6200 lines
166 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. reint.c
  5. Abstract:
  6. This file contains the fill and merge functions necessary for bot inward and outward
  7. synchronization of files and directories. It also contains generic database tree-traversal
  8. code. This is used by merge as well as DoLocalRename API.
  9. Tree Traversal:
  10. TraverseOneDirectory // traverses a subtree in the database
  11. Fill Functions:
  12. AttemptCacheFill Fills the entire cache or a particular share
  13. DoSparseFill Fills a particular file
  14. Merge Functions:
  15. ReintOneShare // reintegrate one share
  16. ReintAllShares // reintegrate all shares
  17. Author:
  18. Trent-Gray-Donald/Shishir Pardikar
  19. Environment:
  20. Win32 (user-mode) DLL
  21. Revision History:
  22. 1-1-94 original
  23. 4-4-97 removed all the entry points to exports.c
  24. reint.c
  25. --*/
  26. #include "pch.h"
  27. #pragma hdrstop
  28. #define UNICODE
  29. #ifndef DEBUG
  30. #undef VERBOSE
  31. #else
  32. #undef VERBOSE
  33. #define VERBOSE 1
  34. #endif
  35. #include <winioctl.h>
  36. #include "lib3.h"
  37. #include "shdsys.h"
  38. #include "reint.h"
  39. #include "utils.h"
  40. #include "resource.h"
  41. #include "traynoti.h"
  42. #include <dbt.h>
  43. #include "strings.h"
  44. #include "csc_bmpu.h"
  45. // this sets flags in a couple of headers to not include some defs.
  46. #define REINT
  47. #include "list.h"
  48. #include "merge.h"
  49. #include "recact.h"
  50. #include "recon.h" // reconnect shares dialog
  51. #include "reint.h"
  52. #include "aclapi.h"
  53. //
  54. // Defines
  55. //
  56. #define chNull '\0' // terminator
  57. #define BUFF_SIZE 64
  58. #define MAX_WAIT_PERIODS 1
  59. #define MAX_ATTEMPTS 1
  60. #define MAX_ATTEMPTS_SHARE 1
  61. #define MAX_ATTEMPTS_SHADOW 5
  62. #define MAX_SPARSE_FILL_RETRIES 4
  63. #define STATE_REINT_BEGIN 0
  64. #define STATE_REINT_CREATE_DIRS STATE_REINT_BEGIN
  65. #define STATE_REINT_FILES (STATE_REINT_CREATE_DIRS+1)
  66. #define STATE_REINT_END (STATE_REINT_FILES+1)
  67. #define MAX_EXCLUSION_STRING 1024
  68. // for some Registry queries, this is the max len buffer that I want back
  69. #define MAX_NAME_LEN 100
  70. #define MY_SZ_TRUE _TEXT("true")
  71. #define MY_SZ_FALSE _TEXT("false")
  72. #define SLOWLINK_SPEED 400 // in 100 bitspersec units
  73. // NB!!! these defines cannot be changed they are in the order in which
  74. // reintegration must proceed
  75. #define REINT_DELETE_FILES 0
  76. #define REINT_DELETE_DIRS 1
  77. #define REINT_CREATE_UPDATE_DIRS 2
  78. #define REINT_CREATE_UPDATE_FILES 3
  79. typedef struct tagREINT_INFO {
  80. int nCurrentState; // 0->deleting files, 1->deleting directories, 2->creating directoires
  81. // 3 ->creating files
  82. node *lpnodeInsertList; // reint errors
  83. LPCSCPROC lpfnMergeProgress;
  84. DWORD_PTR dwContext;
  85. DWORD dwFileSystemFlags; // From GetVolumeInformation, used to set ACCLs etc. if the
  86. // share is hosted on NTFS
  87. HSHARE hShare; // handle to the share being reintegrated
  88. ULONG ulPrincipalID;
  89. _TCHAR tzDrive[4]; // mapped drive to the remote path
  90. } REINT_INFO, *LPREINT_INFO;
  91. #define SPARSEFILL_SLEEP_TIME_FOR_WIN95 2000 // two seconds
  92. #define MAX_SPARSEFILL_SLEEP_TIME_FOR_WIN95 2 * 60 * 100 // two minutes
  93. #define DFS_ROOT_FILE_SYSTEM_FLAGS 0xffffffff
  94. //
  95. // Variables Global/Local
  96. //
  97. _TCHAR *vlpExclusionList = NULL;
  98. REINT_INFO vsRei; // global reint structure. NTRAID-455269-shishirp-1/31/2000 we should make this into a list
  99. // in order to allow multiple reintegrations on various shares
  100. unsigned long ulMinSparseFillPri = MIN_SPARSEFILL_PRI;
  101. int cntDelay=0;
  102. HANDLE vhShadow=NULL;
  103. BOOL vfTimerON = FALSE, vfAutoDeleteOrphans=TRUE;
  104. char vrgchBuff[1024], vrwBuff[4096], vrgchSrcName[350], vrgchDstName[300];
  105. unsigned vcntDirty=0, vcntStale=0, vcntSparse=0, vcntWaitDirty=0;
  106. LPFAILINFO lpheadFI = NULL;
  107. HCURSOR vhcursor=NULL;
  108. BOOL vfLogCopying=TRUE;
  109. LPCONNECTINFO vlpLogonConnectList = NULL;
  110. BOOL vfNeedPQTraversal = TRUE;
  111. DWORD vdwSparseStaleDetectionCounter = 0;
  112. _TCHAR vrgchCRLF[] = _TEXT("\r\n");
  113. _TCHAR tzStarDotStar[] = _TEXT("*");
  114. #pragma data_seg(DATASEG_READONLY)
  115. ERRMSG rgErrorTab[] =
  116. {
  117. ERROR_CREATE_CONFLICT, IDS_CREATE_CONFLICT
  118. ,ERROR_DELETE_CONFLICT, IDS_DELETE_CONFLICT
  119. ,ERROR_UPDATE_CONFLICT, IDS_UPDATE_CONFLICT
  120. ,ERROR_ATTRIBUTE_CONFLICT, IDS_ATTRIBUTE_CONFLICT
  121. };
  122. static const _TCHAR vszMachineName[]= _TEXT("System\\CurrentControlSet\\Control\\ComputerName\\ComputerName");
  123. static const _TCHAR vszComputerName[]=_TEXT("ComputerName");
  124. static const _TCHAR vszLogUNCPath[]=_TEXT("\\\\scratch\\scratch\\t-trentg\\logs\\");
  125. static const _TCHAR vszLogShare[]=_TEXT("\\\\scratch\\scratch");
  126. static const _TCHAR vszLocalLogPath[]=_TEXT("c:\\shadow.log");
  127. static const _TCHAR vszConflictDir[]=_TEXT("C:\\ConflictsWhileMerging");
  128. #pragma data_seg()
  129. AssertData;
  130. AssertError;
  131. //
  132. // Local prototypes
  133. //
  134. BOOL
  135. CheckForStalenessAndRefresh(
  136. HANDLE hShadowDB,
  137. _TCHAR *lptzDrive,
  138. LPCOPYPARAMS lpCP,
  139. _TCHAR * lpszFullPath,
  140. LPSHADOWINFO lpSI
  141. );
  142. BOOL
  143. StalenessCheck(
  144. BOOL hasBeenInited
  145. );
  146. VOID
  147. GetLogCopyStatus(
  148. VOID
  149. );
  150. VOID
  151. CopyLogToShare(
  152. VOID
  153. );
  154. VOID
  155. AppendToShareLog(
  156. HANDLE hLog
  157. );
  158. int
  159. PRIVATE
  160. AttemptReint(
  161. int forceLevel
  162. );
  163. VOID
  164. PRIVATE
  165. AddToReintList(
  166. LPCOPYPARAMS lpCP,
  167. LPSHADOWINFO lpSI,
  168. _TCHAR *szFileName
  169. );
  170. DWORD
  171. PRIVATE
  172. DoObjectEdit(
  173. HANDLE hShadowDB,
  174. _TCHAR * lpDrive,
  175. _TCHAR * lptzFullPath,
  176. LPCOPYPARAMS lpCP,
  177. LPSHADOWINFO lpSI,
  178. LPWIN32_FIND_DATA lpFind32Local,
  179. LPWIN32_FIND_DATA lpFind32Remote,
  180. int iShadowStatus,
  181. int iFileStatus,
  182. int uAction,
  183. DWORD dwFileSystemFlags,
  184. LPCSCPROC lpfnMergeProc,
  185. DWORD_PTR dwContext
  186. );
  187. DWORD
  188. PRIVATE
  189. DoCreateDir(
  190. HANDLE hShadowDB,
  191. _TCHAR * lpDrive,
  192. _TCHAR * lptzFullPath,
  193. LPCOPYPARAMS lpCP,
  194. LPSHADOWINFO lpSI,
  195. LPWIN32_FIND_DATA lpFind32Local,
  196. LPWIN32_FIND_DATA lpFind32Remote,
  197. int iShadowStatus,
  198. int iFileStatus,
  199. int uAction,
  200. DWORD dwFileSystemFlags,
  201. LPCSCPROC lpfnMergeProc,
  202. DWORD_PTR dwContext
  203. );
  204. DWORD
  205. PRIVATE
  206. CheckFileConflict(
  207. LPSHADOWINFO,
  208. LPWIN32_FIND_DATA
  209. );
  210. BOOL
  211. FCheckAncestor(
  212. node *lpnodeList,
  213. LPCOPYPARAMS lpCP
  214. );
  215. int
  216. PRIVATE
  217. StampReintLog(
  218. VOID
  219. );
  220. int
  221. PRIVATE
  222. LogReintError(
  223. DWORD,
  224. _TCHAR *,
  225. _TCHAR *);
  226. int
  227. PRIVATE
  228. WriteLog(
  229. _TCHAR *
  230. );
  231. DWORD
  232. PRIVATE
  233. MoveConflictingFile(
  234. LPCOPYPARAMS
  235. );
  236. DWORD
  237. PRIVATE
  238. GetUniqueName(
  239. _TCHAR *,
  240. _TCHAR *
  241. );
  242. VOID
  243. PRIVATE
  244. FormLocalNameFromRemoteName(
  245. _TCHAR *,
  246. _TCHAR *
  247. );
  248. DWORD
  249. PRIVATE
  250. InbCreateDir(
  251. _TCHAR * lpDir,
  252. DWORD dwAttr
  253. );
  254. int
  255. PRIVATE
  256. GetShadowByName(
  257. HSHADOW,
  258. _TCHAR *,
  259. LPWIN32_FIND_DATA,
  260. unsigned long *
  261. );
  262. _TCHAR *
  263. PRIVATE
  264. LpGetExclusionList(
  265. VOID
  266. );
  267. VOID
  268. PRIVATE
  269. ReleaseExclusionList(
  270. LPVOID
  271. );
  272. BOOL
  273. PRIVATE
  274. FSkipObject(
  275. HSHARE,
  276. HSHADOW,
  277. HSHADOW
  278. );
  279. int
  280. PRIVATE
  281. PurgeSkipQueue(
  282. BOOL,
  283. HSHARE,
  284. HSHADOW,
  285. HSHADOW
  286. );
  287. LPFAILINFO FAR *
  288. LplpFindFailInfo(
  289. HSHARE,
  290. HSHADOW,
  291. HSHADOW
  292. );
  293. VOID
  294. PRIVATE
  295. ReportStats(
  296. VOID
  297. );
  298. VOID
  299. PRIVATE
  300. CopyPQInfoToShadowInfo(
  301. LPPQPARAMS,
  302. LPSHADOWINFO
  303. );
  304. BOOL
  305. PRIVATE
  306. IsSlowLink(
  307. _TCHAR *
  308. );
  309. VOID
  310. PRIVATE
  311. InferReplicaReintStatus(
  312. LPSHADOWINFO lpSI,
  313. LPWIN32_FIND_DATA lpFind32Local, // shadow info
  314. LPWIN32_FIND_DATA lpFind32Remote, // if NULL, the remote doesn't exist
  315. int *lpiShadowStatus,
  316. int *lpiFileStatus,
  317. unsigned *lpuAction
  318. );
  319. BOOL
  320. GetRemoteWin32Info(
  321. _TCHAR *lptzDrive,
  322. LPCOPYPARAMS lpCP,
  323. LPWIN32_FIND_DATA lpFind32,
  324. BOOL *lpfExists
  325. );
  326. BOOL
  327. PRIVATE
  328. PerformOneReint(
  329. HANDLE hShadowDB,
  330. LPSECURITYINFO pShareSecurityInfo,
  331. _TCHAR * lpszDrive, // drive mapped to the UNC name of lpSI->hShare
  332. _TCHAR * lptzFullPath, // full UNC path
  333. LPCOPYPARAMS lpCP, // copy parameters
  334. LPSHADOWINFO lpSI, // shadowinfo structure
  335. LPWIN32_FIND_DATA lpFind32Local, // local win32 data
  336. LPWIN32_FIND_DATA lpFind32Remote, // remote win32 data, could be NULL
  337. DWORD dwErrorRemoteFind32,// error code while getting remote win32 data
  338. int iShadowStatus, // local copy status
  339. int iFileStatus, // remote file status
  340. unsigned uAction, // action to be taken
  341. DWORD dwFileSystemFlags, // CODE.IMPROVEMENT, why not just pass down REINT_INFO
  342. ULONG ulPrincipalID,
  343. LPCSCPROC lpfnMergeProgress, // instead of the three parameters?
  344. DWORD_PTR dwContext
  345. );
  346. ImpersonateALoggedOnUser(
  347. VOID
  348. );
  349. HANDLE
  350. CreateTmpFileWithSourceAcls(
  351. _TCHAR *lptzSrc,
  352. _TCHAR *lptzDst
  353. );
  354. BOOL
  355. HasMultipleStreams(
  356. _TCHAR *lpExistingFileName,
  357. BOOL *lpfTrueFalse
  358. );
  359. int
  360. PRIVATE
  361. CALLBACK
  362. RefreshProc(
  363. LPCONNECTINFO lpCI,
  364. DWORD dwCookie // LOWORD 0==Silently, 1== Give messages
  365. // HIWORD 0==Nuke UNC, 1==Nuke all if no ongoing open/finds
  366. // 2==Maximum force for shadow 3==Nuke ALL
  367. );
  368. BOOL
  369. CALLBACK
  370. ShdLogonProc(
  371. HWND hwnd,
  372. UINT msg,
  373. WPARAM wParam,
  374. LPARAM lParam
  375. )
  376. /*++
  377. Routine Description:
  378. Legacy code, used to be used in win9x implementation
  379. Arguments:
  380. Returns:
  381. Notes:
  382. --*/
  383. {
  384. switch(msg)
  385. {
  386. case WM_INITDIALOG:
  387. return TRUE;
  388. }
  389. return 0;
  390. }
  391. /**************************** Fill routines *********************************/
  392. int
  393. AttemptCacheFill (
  394. HSHARE hShareToSync,
  395. int type,
  396. BOOL fFullSync,
  397. ULONG ulPrincipalID,
  398. LPCSCPROC lpfnFillProgress,
  399. DWORD_PTR dwContext
  400. )
  401. /*++
  402. Routine Description:
  403. Routine called by the agent and the fill API to do filling on a share.
  404. Arguments:
  405. hShareToSync Represnts the share to fill. If 0, fill all shares
  406. type DO_ONE or DO_ALL. No one sets it to DO_ONE anymore
  407. fFullSync if TRUE, we do a staleness check as well
  408. ulPrincipalID ID of the principal as maintained in the shadow database
  409. used to avoid ssyncing files for which the currently logged
  410. on user doesn't have access
  411. lpfnFillProgress Callback function to report progress, can be NULL
  412. dwContext Callback context
  413. Returns:
  414. count of items done
  415. Notes:
  416. --*/
  417. {
  418. PQPARAMS sPQP;
  419. BOOL fFound = FALSE, fFoundBusy = FALSE, fAmAgent=FALSE, fNeedImpersonation=FALSE, fInodeTransaction=FALSE;
  420. BOOL fSparseStaleDetected = FALSE;
  421. SHADOWINFO sSI;
  422. SHAREINFO sSR;
  423. LPCOPYPARAMS lpCP = NULL;
  424. DWORD dwError = NO_ERROR, dwFillStartTick=0, dwCount=0, dwSleepCount=0, dwSparseStaleDetectionCounter=0xffff;
  425. HANDLE hShadowDB;
  426. int cntDone = 0;
  427. WIN32_FIND_DATA sFind32Local;
  428. _TCHAR szNameBuff[MAX_PATH+MAX_SERVER_SHARE_NAME_FOR_CSC+10], tzDrive[4];
  429. tzDrive[0] = 0;
  430. fAmAgent = (GetCurrentThreadId() == vdwCopyChunkThreadId);
  431. Assert(GetCurrentThreadId() != vdwAgentThreadId);
  432. // when the agent comes here to fill, if the vfNeedPQTraversal flag is set
  433. // we go ahead and traverse the priority Q.
  434. // Otherwise, we check with the record manager whether since the last time we looked
  435. // there has been any sparse or stale files encountered.
  436. // If what the agent gets from the record manager
  437. // is not the same as what the agent stored last time around
  438. // then we let him traverse the Q.
  439. // the whole idea here is to converse CPU cycles when
  440. // there is nothing to fill
  441. if (fAmAgent && !vfNeedPQTraversal)
  442. {
  443. GetSparseStaleDetectionCounter(INVALID_HANDLE_VALUE, &dwSparseStaleDetectionCounter);
  444. if (dwSparseStaleDetectionCounter == vdwSparseStaleDetectionCounter)
  445. {
  446. ReintKdPrint(FILL, ("Agent.fill: SparseStaleDetectionCounter =%d is unchanged, not filling\n", vdwSparseStaleDetectionCounter));
  447. return 0;
  448. }
  449. else
  450. {
  451. vfNeedPQTraversal = TRUE;
  452. vdwSparseStaleDetectionCounter = dwSparseStaleDetectionCounter;
  453. ReintKdPrint(FILL, ("**Agent.fill: SparseStaleDetectionCounter =%d is changed**\n", vdwSparseStaleDetectionCounter));
  454. }
  455. }
  456. if ((hShadowDB = OpenShadowDatabaseIO())==INVALID_HANDLE_VALUE)
  457. {
  458. goto bailout;
  459. }
  460. Assert(!(fFullSync && fAmAgent));
  461. lpCP = LpAllocCopyParams();
  462. if (!lpCP){
  463. ReintKdPrint(BADERRORS, ("Agent:Allocation of copyparam buffer failed\n"));
  464. goto bailout;
  465. }
  466. if (fFullSync && hShareToSync)
  467. {
  468. ULONG ulStatus;
  469. BOOL fIsDfsConnect;
  470. if(GetShareInfo(hShadowDB, hShareToSync, &sSR, &ulStatus)<= 0)
  471. {
  472. ReintKdPrint(BADERRORS, ("AttemptCacheFill: couldn't get status for server 0x%x\r\n", hShareToSync));
  473. goto bailout;
  474. }
  475. dwError = DWConnectNet(sSR.rgSharePath, tzDrive, NULL, NULL, NULL, CONNECT_INTERACTIVE, &fIsDfsConnect);
  476. if ((dwError != WN_SUCCESS) && (dwError != WN_CONNECTED_OTHER_PASSWORD) && (dwError != WN_CONNECTED_OTHER_PASSWORD_DEFAULT))
  477. {
  478. ReintKdPrint(BADERRORS, ("AttemptCacheFill: connect to %ls failed error=%d\r\n", sSR.rgSharePath, dwError));
  479. goto bailout;
  480. }
  481. }
  482. memset(&sPQP, 0, sizeof(PQPARAMS));
  483. memset(&sSI, 0, sizeof(SHADOWINFO));
  484. if (type == DO_ALL)
  485. {
  486. PurgeSkipQueue(TRUE, hShareToSync, 0, 0);
  487. }
  488. if(BeginPQEnum(hShadowDB, &sPQP) == 0) {
  489. goto bailout;
  490. }
  491. ReintKdPrint(FILL, ("Agent.fill:Started enumeration\n"));
  492. do {
  493. if (FAbortOperation())
  494. {
  495. cntDone = 0;
  496. goto bailout;
  497. }
  498. if (fInodeTransaction)
  499. {
  500. DoShadowMaintenance(hShadowDB, SHADOW_END_INODE_TRANSACTION);
  501. fInodeTransaction = FALSE;
  502. }
  503. if (fAmAgent)
  504. {
  505. Sleep(1); // Yield on NT because we are winlogon
  506. }
  507. if(!DoShadowMaintenance(hShadowDB, SHADOW_BEGIN_INODE_TRANSACTION))
  508. {
  509. ReintKdPrint(BADERRORS, ("AttemptCacheFill: failed to begin inode transaction, aborting\n"));
  510. break;
  511. }
  512. fInodeTransaction = TRUE;
  513. if(NextPriShadow(hShadowDB, &sPQP) == 0) {
  514. break;
  515. }
  516. if (++dwCount > 100000)
  517. {
  518. ReintKdPrint(BADERRORS, ("AttemptCacheFill: Aborting, more than 100000 entries!!!\n"));
  519. break;
  520. }
  521. if (!sPQP.hShadow) {
  522. break;
  523. }
  524. if (fAmAgent && !fSparseStaleDetected &&
  525. ((mShadowIsFile(sPQP.ulStatus) && (sPQP.ulStatus & SHADOW_SPARSE)) || // sparse file
  526. (sPQP.ulStatus & SHADOW_STALE))) // or stale file or dir
  527. {
  528. fSparseStaleDetected = TRUE;
  529. }
  530. if (!fFullSync && !(mShadowIsFile(sPQP.ulStatus) || (sPQP.ulStatus & SHADOW_STALE)))
  531. {
  532. continue;
  533. }
  534. if (hShareToSync && (hShareToSync != sPQP.hShare))
  535. {
  536. continue;
  537. }
  538. if (fAmAgent && FSkipObject(sPQP.hShare, 0, 0)){
  539. continue;
  540. }
  541. else if (mShadowNeedReint(sPQP.ulStatus)||
  542. mShadowOrphan(sPQP.ulStatus)||
  543. mShadowSuspect(sPQP.ulStatus)){
  544. continue;
  545. }
  546. if (fAmAgent && FSkipObject(sPQP.hShare, sPQP.hDir, sPQP.hShadow)) {
  547. continue;
  548. }
  549. // If we are not doing full sync then do only sparse filling
  550. // or filling stale directories
  551. // otherwise we also want to update the attributes and timestamps on
  552. // the directories
  553. if (fFullSync || (sPQP.ulStatus & (SHADOW_STALE|SHADOW_SPARSE))){
  554. if (fAmAgent)
  555. {
  556. if (!hdesktopUser)
  557. {
  558. if (!(sPQP.ulHintFlags & FLAG_CSC_HINT_PIN_SYSTEM))
  559. {
  560. ReintKdPrint(FILL, ("AttemptCacheFill: skipping fill till logon happens\n"));
  561. continue;
  562. }
  563. }
  564. }
  565. if (FAbortOperation())
  566. {
  567. cntDone = 0;
  568. goto bailout;
  569. }
  570. if (!GetShadowInfoEx(hShadowDB, sPQP.hDir, sPQP.hShadow,
  571. &sFind32Local, &sSI)){
  572. ReintKdPrint(BADERRORS, ("AttemptCacheFill: GetShadowInfoEx failed\n"));
  573. continue;
  574. }
  575. if (FAbortOperation())
  576. {
  577. cntDone = 0;
  578. goto bailout;
  579. }
  580. if(GetUNCPath(hShadowDB, sPQP.hShare, sPQP.hDir, sPQP.hShadow, lpCP)){
  581. // impersonate only if we are the agent and the file we are trying to
  582. // bring down is not pinned for system. This was for remoteboot feature
  583. // which doesn't exist any more.
  584. fNeedImpersonation = (fAmAgent && !(sPQP.ulHintFlags & FLAG_CSC_HINT_PIN_SYSTEM));
  585. if (!fNeedImpersonation ||
  586. (mShadowIsFile(sPQP.ulStatus) && SetAgentThreadImpersonation(sPQP.hDir, sPQP.hShadow, FALSE))||
  587. (!mShadowIsFile(sPQP.ulStatus) && ImpersonateALoggedOnUser()))
  588. {
  589. BOOL fStalenessCheck;
  590. // !!NB Stale must be dealt with first
  591. // because a sparse shadow can become stale
  592. // NB!!! we assume the limits because we know that
  593. // the database handles only that much size
  594. lstrcpy(szNameBuff, lpCP->lpSharePath);
  595. lstrcat(szNameBuff, lpCP->lpRemotePath);
  596. fStalenessCheck = (fFullSync || (sSI.uStatus & SHADOW_STALE));
  597. if (fStalenessCheck || (sSI.uStatus & SHADOW_SPARSE)) {
  598. dwError = DoSparseFill(hShadowDB, szNameBuff, tzDrive, &sSI, &sFind32Local, lpCP, fStalenessCheck, ulPrincipalID, lpfnFillProgress, dwContext);
  599. }
  600. if (fNeedImpersonation)
  601. {
  602. ResetAgentThreadImpersonation();
  603. }
  604. if (fAmAgent)
  605. {
  606. if (dwFillStartTick == 0)
  607. {
  608. dwFillStartTick = GetTickCount();
  609. ReintKdPrint(FILL, ("AttemptCacheFill: start tick count is %d ms\r\n", dwFillStartTick));
  610. }
  611. else
  612. {
  613. Assert(type != DO_ALL);
  614. // if we have been filling too long
  615. // comeback later
  616. if (((int)(GetTickCount() - (dwFillStartTick+dwSleepCount)) > WAIT_INTERVAL_ATTEMPT_MS/3))
  617. {
  618. ReintKdPrint(FILL, ("AttemptCacheFill: aborting, been filling for more than %d ms\r\n", WAIT_INTERVAL_ATTEMPT_MS/3));
  619. break;
  620. }
  621. }
  622. Sleep(200);
  623. dwSleepCount+=200;
  624. }
  625. }
  626. else
  627. {
  628. Assert(fAmAgent);
  629. Sleep(200);
  630. dwSleepCount+=200;
  631. // no one is allowed to read the entry
  632. // go on to fill other things
  633. continue;
  634. }
  635. }
  636. else
  637. {
  638. ReintKdPrint(BADERRORS, ("Agent: Shadow %08lx doesn't have an entry in the hierarchy \r\n", sPQP.hShadow));
  639. continue;
  640. }
  641. if (dwError == NO_ERROR) {
  642. cntDone += 1;
  643. }
  644. #if 0
  645. if (type == DO_ONE_OBJECT) {
  646. break;
  647. }
  648. #endif
  649. if (dwError == ERROR_OPERATION_ABORTED)
  650. {
  651. cntDone = 0;
  652. break;
  653. }
  654. }
  655. } while (sPQP.uPos);
  656. // if the agent traversed the entire PQ and didn't come across any item
  657. // that needed to be filled or refreshed, then we turnoff the global flag indicating
  658. // that we need priority Q traversal.
  659. // From here on, the agent will be driven by the SparseStaleDetectionCount
  660. if (fAmAgent)
  661. {
  662. // if even one sparse or stale was detected, traverse the queue again
  663. if (fSparseStaleDetected)
  664. {
  665. vfNeedPQTraversal = TRUE;
  666. }
  667. else if (!sPQP.uPos)
  668. {
  669. vfNeedPQTraversal = FALSE;
  670. ReintKdPrint(FILL, ("Agent.fill: No sparse stale entries found, going in querycount mode\r\n"));
  671. }
  672. }
  673. // Close the enumeration
  674. EndPQEnum(hShadowDB, &sPQP);
  675. bailout:
  676. if (fInodeTransaction)
  677. {
  678. DoShadowMaintenance(hShadowDB, SHADOW_END_INODE_TRANSACTION);
  679. fInodeTransaction = FALSE;
  680. }
  681. if (hShadowDB != INVALID_HANDLE_VALUE)
  682. {
  683. CloseShadowDatabaseIO(hShadowDB);
  684. }
  685. if (lpCP) {
  686. FreeCopyParams(lpCP);
  687. }
  688. if (tzDrive[0])
  689. {
  690. if(DWDisconnectDriveMappedNet(tzDrive, TRUE))
  691. {
  692. ReintKdPrint(BADERRORS, ("Failed disconnection of merge drive \r\n"));
  693. }
  694. else
  695. {
  696. ReintKdPrint(MERGE, ("Disconnected merge drive \r\n"));
  697. }
  698. }
  699. ReintKdPrint(FILL, ("Agent.fill:done cachefill\n"));
  700. return (cntDone);
  701. }
  702. DWORD
  703. DoRefresh(
  704. HANDLE hShadowDB,
  705. LPCOPYPARAMS lpCP,
  706. _TCHAR * lpszFullPath,
  707. LPSHADOWINFO lpSI,
  708. _TCHAR * lptzDrive
  709. )
  710. /*++
  711. Routine Description:
  712. Checks whether an item in the database has gone stale and if so, it refreshes it. If it is
  713. a file, it is truncated and marked SPARSE
  714. Arguments:
  715. Returns:
  716. Notes:
  717. --*/
  718. {
  719. DWORD dwError = 0xffffffff;
  720. if (!CheckForStalenessAndRefresh(hShadowDB, lptzDrive, lpCP, lpszFullPath, lpSI)) {
  721. dwError = GetLastError();
  722. }
  723. else
  724. {
  725. dwError = NO_ERROR;
  726. }
  727. if ((dwError != NOERROR) && IsNetDisconnected(dwError))
  728. {
  729. #ifdef DEBUG
  730. EnterSkipQueue(lpSI->hShare, lpSI->hDir, lpSI->hShadow, lpszFullPath);
  731. #else
  732. EnterSkipQueue(lpSI->hShare, lpSI->hDir, lpSI->hShadow);
  733. #endif //DEBUG
  734. }
  735. return (dwError);
  736. }
  737. /*********************** Merging related routines **************************/
  738. int
  739. TraverseOneDirectory(
  740. HANDLE hShadowDB,
  741. LPSECURITYINFO pShareSecurityInfo,
  742. HSHADOW hParentDir,
  743. HSHADOW hDir,
  744. LPTSTR lptzInputPath,
  745. TRAVERSEFUNC lpfnTraverseDir,
  746. LPVOID lpContext
  747. )
  748. /*++
  749. Routine Description:
  750. Generic routine that traverses a directory in the database recursively and issues a
  751. callback function to let callers do interesting things, such as merge or rename.
  752. Arguments:
  753. hShadowDB Handle to the redir for issuing ioctls
  754. hParentDir handle to the parent directory
  755. hDir handle to the directory to be traversed
  756. lptzInputPath full qualified path of the directory
  757. lpfnTraverseDir callback function to call at each step in the traversal
  758. lpContext callback context
  759. Returns:
  760. return code, whether continue, cancel etc.
  761. Notes:
  762. --*/
  763. {
  764. WIN32_FIND_DATA sFind32;
  765. SHADOWINFO sSI;
  766. int retCode = TOD_CONTINUE, lenInputPath = 0, retCodeSav;
  767. CSC_ENUMCOOKIE ulEnumCookie = NULL;
  768. Assert(lptzInputPath);
  769. lenInputPath = lstrlen(lptzInputPath);
  770. Assert(lenInputPath && (lenInputPath < MAX_PATH));
  771. ReintKdPrint(MERGE, ("Begin_Traverse directory %ls\r\n", lptzInputPath));
  772. sSI.hDir = hParentDir;
  773. sSI.hShadow = hDir;
  774. retCode = (lpfnTraverseDir)(hShadowDB, pShareSecurityInfo, lptzInputPath, TOD_CALLBACK_REASON_BEGIN, &sFind32, &sSI, lpContext);
  775. memset(&sFind32, 0, sizeof(sFind32));
  776. lstrcpy(sFind32.cFileName, tzStarDotStar);
  777. if(FindOpenShadow( hShadowDB, hDir, FINDOPEN_SHADOWINFO_ALL,
  778. &sFind32, &sSI))
  779. {
  780. if (FAbortOperation())
  781. {
  782. ReintKdPrint(MERGE, ("TraverseOneDirectory:Abort received\r\n"));
  783. SetLastError(ERROR_CANCELLED);
  784. goto bailout;
  785. }
  786. ulEnumCookie = sSI.uEnumCookie;
  787. do
  788. {
  789. int lenChildName;
  790. lenChildName = lstrlen(sFind32.cFileName);
  791. if (!lenChildName || ((lenInputPath+lenChildName+1) >= MAX_PATH))
  792. {
  793. ReintKdPrint(MERGE, ("TraverseOneDirectory: path exceeds max path or is invalid\r\n"));
  794. SetLastError(ERROR_INVALID_PARAMETER);
  795. retCode = TOD_ABORT;
  796. goto bailout;
  797. }
  798. lptzInputPath[lenInputPath] = _T('\\');
  799. lstrcpy(&lptzInputPath[lenInputPath+1], sFind32.cFileName);
  800. if (sFind32.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  801. {
  802. retCode = (lpfnTraverseDir)(hShadowDB, pShareSecurityInfo, lptzInputPath, TOD_CALLBACK_REASON_NEXT_ITEM, &sFind32, &sSI, lpContext);
  803. if (retCode == TOD_ABORT)
  804. {
  805. ReintKdPrint(MERGE, ("TraverseOneDirectory:Abort\r\n"));
  806. goto bailout;
  807. }
  808. retCode = TraverseOneDirectory(hShadowDB, pShareSecurityInfo, sSI.hDir, sSI.hShadow, lptzInputPath, lpfnTraverseDir, lpContext);
  809. }
  810. else
  811. {
  812. retCode = (lpfnTraverseDir)(hShadowDB, pShareSecurityInfo, lptzInputPath, TOD_CALLBACK_REASON_NEXT_ITEM, &sFind32, &sSI, lpContext);
  813. }
  814. lptzInputPath[lenInputPath] = 0;
  815. if (retCode == TOD_ABORT)
  816. {
  817. ReintKdPrint(MERGE, ("TraverseOneDirectory:Abort\r\n"));
  818. goto bailout;
  819. }
  820. } while(FindNextShadow(hShadowDB, ulEnumCookie, &sFind32, &sSI));
  821. }
  822. bailout:
  823. sSI.hDir = hParentDir;
  824. sSI.hShadow = hDir;
  825. retCodeSav = (lpfnTraverseDir)(hShadowDB, pShareSecurityInfo, lptzInputPath, TOD_CALLBACK_REASON_END, &sFind32, &sSI, lpContext);
  826. if (retCode != TOD_ABORT)
  827. {
  828. retCode = retCodeSav;
  829. }
  830. ReintKdPrint(MERGE, ("End_Traverse directory %ls\r\n", lptzInputPath));
  831. if (ulEnumCookie)
  832. {
  833. FindCloseShadow(hShadowDB, ulEnumCookie);
  834. }
  835. return retCode;
  836. }
  837. int
  838. ReintDirCallback(
  839. HANDLE hShadowDB,
  840. LPSECURITYINFO pShareSecurityInfo,
  841. LPTSTR lptzFullPath,
  842. DWORD dwCallbackReason,
  843. WIN32_FIND_DATA *lpFind32,
  844. SHADOWINFO *lpSI,
  845. LPREINT_INFO lpRei
  846. )
  847. /*++
  848. Routine Description:
  849. callback function used by ReintOneShare while calling TraverseOneDirectory. It is called
  850. on each step in the traversal. This routine issues call to do the merging
  851. Arguments:
  852. hShadowDB Handle to issue ioctls to the redir
  853. lptzFullPath fully qualified path to the item
  854. dwCallbackReason TOD_CALLBACK_REASON_XXX (BEGIN, NEXT_ITEM or END)
  855. lpFind32 local win32info
  856. lpSI other info such as priority, pincount etc.
  857. lpRei reintegration information context
  858. Returns:
  859. return code, whether continue, cancel etc.
  860. Notes:
  861. --*/
  862. {
  863. int retCode = TOD_CONTINUE;
  864. int iFileStatus, iShadowStatus;
  865. LPCOPYPARAMS lpCP = NULL;
  866. BOOL fInsertInList = FALSE, fIsFile;
  867. WIN32_FIND_DATA sFind32Remote, *lpFind32Remote = NULL;
  868. unsigned uAction;
  869. DWORD dwErrorRemote = ERROR_SUCCESS;
  870. if (dwCallbackReason != TOD_CALLBACK_REASON_NEXT_ITEM)
  871. {
  872. return TOD_CONTINUE;
  873. }
  874. if ( mShadowOrphan(lpSI->uStatus)||
  875. mShadowSuspect(lpSI->uStatus))
  876. {
  877. return TOD_CONTINUE;
  878. }
  879. if (!mShadowNeedReint(lpSI->uStatus))
  880. {
  881. return TOD_CONTINUE;
  882. }
  883. fIsFile = ((lpFind32->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0);
  884. switch (lpRei->nCurrentState)
  885. {
  886. case REINT_DELETE_FILES:
  887. if (!fIsFile || !mShadowDeleted(lpSI->uStatus))
  888. {
  889. return TOD_CONTINUE;
  890. }
  891. break;
  892. case REINT_DELETE_DIRS:
  893. if (fIsFile || !mShadowDeleted(lpSI->uStatus))
  894. {
  895. return TOD_CONTINUE;
  896. }
  897. break;
  898. case REINT_CREATE_UPDATE_FILES:
  899. if (!fIsFile)
  900. {
  901. return TOD_CONTINUE;
  902. }
  903. break;
  904. case REINT_CREATE_UPDATE_DIRS:
  905. if (fIsFile)
  906. {
  907. return TOD_CONTINUE;
  908. }
  909. break;
  910. default:
  911. Assert(FALSE);
  912. break;
  913. }
  914. #if 0
  915. if (!fStamped){
  916. StampReintLog();
  917. fStamped = TRUE;
  918. }
  919. #endif
  920. lpCP = LpAllocCopyParams();
  921. if (!lpCP){
  922. ReintKdPrint(BADERRORS, ("ReintDirCallback: Allocation of copyparam buffer failed\n"));
  923. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  924. retCode = TOD_ABORT;
  925. goto bailout;
  926. }
  927. if(!GetUNCPath(hShadowDB, lpSI->hShare, lpSI->hDir, lpSI->hShadow, lpCP)){
  928. ReintKdPrint(BADERRORS, ("ReintDirCallback: GetUNCPath failed\n"));
  929. Assert(FALSE);
  930. retCode = TOD_CONTINUE;
  931. goto bailout;
  932. }
  933. ReintKdPrint(MERGE, ("Merging local changes to <%ls%ls>\n", lpCP->lpSharePath, lpCP->lpRemotePath));
  934. fInsertInList = FALSE;
  935. lpFind32Remote = NULL;
  936. // if there is an insertion list, then check whether his ancestor
  937. // didn't fail in reintegration
  938. if (lpRei->lpnodeInsertList)
  939. {
  940. // if there is an acestor then we should put this guy in the list
  941. fInsertInList = FCheckAncestor(lpRei->lpnodeInsertList, lpCP);
  942. }
  943. // if we are not supposed to put him in the list then try getting
  944. // his win32 strucuture
  945. if (!fInsertInList)
  946. {
  947. BOOL fExists;
  948. ReintKdPrint(MERGE, ("getting Remote win32 Info \n"));
  949. if (!GetRemoteWin32Info(lpRei->tzDrive, lpCP, &sFind32Remote, &fExists) && (fExists == -1))
  950. {
  951. // NB: dwErrorRemote is set only when fExists is -1, ie there some error
  952. // besides the file not being there
  953. // some error happened while getting remote find32
  954. if (IsNetDisconnected(dwErrorRemote = GetLastError()))
  955. {
  956. #ifdef DEBUG
  957. EnterSkipQueue(lpSI->hShare, 0, 0, lpCP->lpSharePath);
  958. #else
  959. EnterSkipQueue(lpSI->hShare, 0, 0);
  960. #endif //DEBUG
  961. retCode = TOD_ABORT;
  962. ReintKdPrint(BADERRORS, ("ReintDirCallback: Error = %d NetDisconnected aborting\r\n", GetLastError()));
  963. goto bailout;
  964. }
  965. }
  966. // passing remote find32 only if it succeeded
  967. if (fExists == TRUE)
  968. {
  969. lpFind32Remote = &sFind32Remote;
  970. }
  971. Assert(!((fExists != -1) && (dwErrorRemote != NO_ERROR)));
  972. }
  973. else
  974. {
  975. ReintKdPrint(BADERRORS, ("ReintDirCallback: Inserting in failed list\r\n"));
  976. }
  977. // find out what needs to be done
  978. // this is one central place to infer all the stuff
  979. InferReplicaReintStatus(
  980. lpSI, // shadowinfo
  981. lpFind32, // win32 info for the shadow
  982. lpFind32Remote, // remote win32 info
  983. &iShadowStatus,
  984. &iFileStatus,
  985. &uAction
  986. );
  987. if (!fInsertInList)
  988. {
  989. ReintKdPrint(MERGE, ("Silently doing <%ls%ls>\n", lpCP->lpSharePath, lpCP->lpRemotePath));
  990. fInsertInList = (PerformOneReint(
  991. hShadowDB,
  992. pShareSecurityInfo,
  993. lpRei->tzDrive,
  994. lptzFullPath,
  995. lpCP,
  996. lpSI,
  997. lpFind32,
  998. lpFind32Remote,
  999. dwErrorRemote,
  1000. iShadowStatus,
  1001. iFileStatus,
  1002. uAction,
  1003. lpRei->dwFileSystemFlags,
  1004. lpRei->ulPrincipalID,
  1005. lpRei->lpfnMergeProgress,
  1006. lpRei->dwContext
  1007. ) == FALSE);
  1008. if (fInsertInList)
  1009. {
  1010. if (IsNetDisconnected(GetLastError()))
  1011. {
  1012. #ifdef DEBUG
  1013. EnterSkipQueue(lpSI->hShare, 0, 0, lpCP->lpSharePath);
  1014. #else
  1015. EnterSkipQueue(lpSI->hShare, 0, 0);
  1016. #endif //DEBUG
  1017. retCode = TOD_ABORT;
  1018. ReintKdPrint(BADERRORS, ("ReintDirCallback: Error = %d NetDisconnected aborting\r\n", GetLastError()));
  1019. goto bailout;
  1020. }
  1021. else if (GetLastError() == ERROR_OPERATION_ABORTED)
  1022. {
  1023. retCode = TOD_ABORT;
  1024. ReintKdPrint(BADERRORS, ("ReintDirCallback: operation aborted becuase of ERROR_OPERATION_ABORT\r\n"));
  1025. goto bailout;
  1026. }
  1027. }
  1028. else
  1029. {
  1030. retCode = TOD_CONTINUE;
  1031. }
  1032. }
  1033. else
  1034. {
  1035. ReintKdPrint(BADERRORS, ("ReintDirCallback: Was Inserted in failed list\r\n"));
  1036. }
  1037. bailout:
  1038. if (lpCP) {
  1039. FreeCopyParams(lpCP);
  1040. }
  1041. return retCode;
  1042. }
  1043. BOOL
  1044. PUBLIC
  1045. ReintOneShare(
  1046. HSHARE hShare,
  1047. HSHADOW hRoot, // root inode
  1048. _TCHAR *lpDomainName,
  1049. _TCHAR *lpUserName,
  1050. _TCHAR *lpPassword,
  1051. ULONG ulPrincipalID,
  1052. LPCSCPROC lpfnMergeProgress,
  1053. DWORD_PTR dwContext
  1054. )
  1055. /*++
  1056. Routine Description:
  1057. This is the workhorse routine that does the merging of a share which may have modifications
  1058. made while offline.
  1059. The routine, first checks whether any modifications have been done at all on this share.
  1060. Is so, then it gets a list of all the drive-mapped and explicit UNC connections made to
  1061. this share.
  1062. The routine then creates a special drive mapping to the share, done by passing in an
  1063. extended attribute flag CSC_BYPASS (defined in lmuse.h). This tells the redir
  1064. to bypass all CSC functionality.
  1065. It then deletes all the connections in the list gathered before making the EA based
  1066. connections.
  1067. The merge then proceeds by enumerating the share from the database. It uses, TraverseOneDirectory
  1068. routine and gives it ReintDirCallback routine as a callback with REINT_INFO as the context.
  1069. The directory travesal proceeds from the root of the share
  1070. At the end of the merge, the EA connection is deleted and the connections in the list are
  1071. reconnected.
  1072. Arguments:
  1073. hShare // Represents the share to merged
  1074. hRoot // the root inode for the share
  1075. lpDomainName // domain name for EA drivemapping (can be NULL)
  1076. lpUserName // username for EA drivemapping (can be NULL)
  1077. lpPassword // password for EA drivemapping (can be NULL)
  1078. ulPrinciaplID // the ID of the guy calling reint
  1079. lpfnMergeProgress // callback function for reporting progress
  1080. dwContext // callback context
  1081. Returns:
  1082. TRUE if successful. If FALSE, GetLastError returns the actual errorcode.
  1083. Notes:
  1084. The EA drivemap is passed back to the callback routine during the CSCPROC_REASON_BEGIN callback
  1085. so that the callback routine can use the same driveletter to bypass CSC for doing whatever
  1086. it needs to do on the server without having CSC get in it's way.
  1087. --*/
  1088. {
  1089. BOOL fConnected=FALSE, fDone = FALSE;
  1090. BOOL fStamped = FALSE, fInsertInList = FALSE, fBeginReint = FALSE, fDisabledShadowing = FALSE;
  1091. unsigned long ulStatus;
  1092. HANDLE hShadowDB;
  1093. SHAREINFO sSR;
  1094. SHADOWINFO sSI;
  1095. int iRet, i;
  1096. ULONG nRet = 0;
  1097. DWORD dwError, dwRet, dwMaxComponentLength=0;
  1098. TCHAR tzFullPath[MAX_PATH+1], tzDrive[4];
  1099. LPCONNECTINFO lpHead = NULL;
  1100. BOOL fIsDfsConnect = FALSE;
  1101. LPVOID lpContext = NULL;
  1102. DWORD dwDummy;
  1103. SECURITYINFO rgsSecurityInfo[CSC_MAXIMUM_NUMBER_OF_CACHED_PRINCIPAL_IDS];
  1104. LPSECURITYINFO pShareSecurityInfo = NULL;
  1105. // if reintegration is going on on a share, then ask him to stop
  1106. // NTRAID-455269-shishirp-1/31/2000 we should allow reintegration on multiple shares
  1107. if (vsRei.hShare)
  1108. {
  1109. ReintKdPrint(BADERRORS, ("ReintOneShare: reintegration is in progress\r\n"));
  1110. SetLastError(ERROR_SHARING_VIOLATION);
  1111. return FALSE;
  1112. }
  1113. // we enter a critical section because eventually we should allocate a reint_info strucuture
  1114. // and thread it in a list
  1115. EnterAgentCrit();
  1116. memset(&vsRei, 0, sizeof(vsRei));
  1117. vsRei.lpfnMergeProgress = lpfnMergeProgress;
  1118. vsRei.dwContext = dwContext;
  1119. vsRei.hShare = hShare;
  1120. vsRei.ulPrincipalID = ulPrincipalID;
  1121. LeaveAgentCrit();
  1122. memset(tzDrive, 0, sizeof(tzDrive));
  1123. if ((hShadowDB = OpenShadowDatabaseIO()) ==INVALID_HANDLE_VALUE)
  1124. {
  1125. ReintKdPrint(BADERRORS, ("ReintOneShare: failed to open database\r\n"));
  1126. return FALSE;
  1127. }
  1128. if(GetShareInfo(hShadowDB, hShare, &sSR, &ulStatus)<= 0)
  1129. {
  1130. ReintKdPrint(BADERRORS, ("ReintOneShare: couldn't get status for server 0x%x\r\n", hShare));
  1131. goto bailout;
  1132. }
  1133. dwDummy = sizeof(rgsSecurityInfo);
  1134. nRet = GetSecurityInfoForCSC(
  1135. hShadowDB,
  1136. 0,
  1137. hRoot,
  1138. rgsSecurityInfo,
  1139. &dwDummy);
  1140. if (nRet > 0)
  1141. pShareSecurityInfo = rgsSecurityInfo;
  1142. lstrcpy(tzFullPath, sSR.rgSharePath);
  1143. // this will modify the reint bit on the share if necessary
  1144. if(!CSCEnumForStatsInternal(sSR.rgSharePath, NULL, FALSE, TRUE, 0))
  1145. {
  1146. ReintKdPrint(MERGE, ("ReintOneShare: Couldn't get stats for %ls \r\n", sSR.rgSharePath));
  1147. goto bailout;
  1148. }
  1149. if (!(ulStatus & SHARE_REINT))
  1150. {
  1151. ReintKdPrint(MERGE, ("ReintOneShare: server %ls doesn't need reintegration\r\n", sSR.rgSharePath));
  1152. fDone = TRUE;
  1153. goto bailout;
  1154. }
  1155. if (!GetShadowInfoEx(INVALID_HANDLE_VALUE, 0, hRoot, NULL, &sSI)){
  1156. ReintKdPrint(BADERRORS, ("ReintOneShare: GetShadowInfoEx failed\n"));
  1157. goto bailout;
  1158. }
  1159. // put the share in reintegration mode
  1160. // if this is not marked system pinned, then it would be a blocking reint
  1161. // Putting the share in reintegration mode makes all open calls fail, except those
  1162. // done on the special EA drive mapping
  1163. // NB, beginreint is an async ioctl. This is the basis for cleanup
  1164. // when the thread does the merge dies
  1165. // All reint's are blocking reints.
  1166. if (!BeginReint(hShare, TRUE /*!(sSI.ulHintFlags & FLAG_CSC_HINT_PIN_SYSTEM)*/, &lpContext))
  1167. {
  1168. if (GetLastError() != ERROR_IO_PENDING)
  1169. {
  1170. ReintKdPrint(BADERRORS, ("ReintOneShare: Couldn't put server 0x%x in reintegration state\r\n", hShare));
  1171. goto bailout;
  1172. }
  1173. }
  1174. fBeginReint = TRUE;
  1175. // After putting the share in reintegration mode, we get the list of all
  1176. // connection to the share and delete them with maximum force.
  1177. // this ensures that no files are open after the share is put in reintegration mode
  1178. // Moreover any files that are open are only thorugh the EA drive mapping
  1179. // obtain the list of connections to this share.
  1180. // do this before making a the special CSC_BYPASS connection
  1181. // so that the list won't have it
  1182. FGetConnectionListEx(&lpHead, sSR.rgSharePath, FALSE, FALSE, NULL);
  1183. // now make the connection
  1184. ReintKdPrint(MERGE, ("CSC.ReintOneShare: Attempting to map drive letter to %ls \r\n", sSR.rgSharePath));
  1185. dwError = DWConnectNet(sSR.rgSharePath, tzDrive, lpDomainName, lpUserName, lpPassword, CONNECT_INTERACTIVE, &fIsDfsConnect);
  1186. if ((dwError != WN_SUCCESS) &&
  1187. (dwError != WN_CONNECTED_OTHER_PASSWORD_DEFAULT) &&
  1188. (dwError != WN_CONNECTED_OTHER_PASSWORD))
  1189. {
  1190. #ifdef DEBUG
  1191. EnterSkipQueue(hShare, 0, 0, sSR.rgSharePath);
  1192. #else
  1193. EnterSkipQueue(hShare, 0, 0);
  1194. #endif
  1195. SetLastError(dwError);
  1196. ReintKdPrint(BADERRORS, ("ReintOneShare: Error %d, couldn't connect to %ls\r\n", dwError, sSR.rgSharePath));
  1197. // clear the connection list and bailout
  1198. if (lpHead)
  1199. {
  1200. ClearConnectionList(&lpHead);
  1201. lpHead = NULL;
  1202. }
  1203. goto bailout;
  1204. }
  1205. fConnected = TRUE;
  1206. // if we have a connectionlist, disconnect all connections before attempting merge
  1207. // NB, this is done after the drivemapped connection is made, so that
  1208. // if there are special credentials on the server, they are maintained
  1209. // as there is always atelast one outstanding connection
  1210. if (lpHead)
  1211. {
  1212. DisconnectList(&lpHead, NULL, 0);
  1213. }
  1214. lstrcpy(vsRei.tzDrive, tzDrive);
  1215. tzDrive[2]='\\';tzDrive[3]=0;
  1216. ReintKdPrint(MERGE, ("CSC.ReintOneShare: mapped drive letter %ls IsDfs=%d\r\n", tzDrive, fIsDfsConnect));
  1217. vsRei.dwFileSystemFlags = 0;
  1218. // NTRAID#455273-shishirp-1/31/2000 we do getvolumeinfo only for non-dfs shares. This is because of a problem in
  1219. // the DFS code that doesn't bypass volume operations for CSC agent. GetVolumeInfo is not implemented
  1220. // by DFS
  1221. if (!fIsDfsConnect)
  1222. {
  1223. if(!GetVolumeInformation(tzDrive, NULL, 0, NULL, &dwMaxComponentLength, &vsRei.dwFileSystemFlags, NULL, 0))
  1224. {
  1225. ReintKdPrint(BADERRORS, ("CSC.ReintOneShare: failed to get volume info for %ls Error=%d\r\n", tzDrive, GetLastError()));
  1226. goto bailout;
  1227. }
  1228. }
  1229. else
  1230. {
  1231. vsRei.dwFileSystemFlags = DFS_ROOT_FILE_SYSTEM_FLAGS;
  1232. }
  1233. tzDrive[2]=0;
  1234. ReintKdPrint(MERGE, ("CSC.ReintOneShare: FileSystemFlags=%x \r\n", vsRei.dwFileSystemFlags));
  1235. if (lpfnMergeProgress)
  1236. {
  1237. WIN32_FIND_DATA *lpFT;
  1238. lpFT = (WIN32_FIND_DATA *)LocalAlloc(LPTR, sizeof(WIN32_FIND_DATA));
  1239. if (!lpFT)
  1240. {
  1241. ReintKdPrint(BADERRORS, ("ReintOneShare: Couldn't allocate find32 strucutre for callback \r\n"));
  1242. goto bailout;
  1243. }
  1244. lstrcpy(lpFT->cFileName, vsRei.tzDrive);
  1245. try
  1246. {
  1247. dwRet = (*lpfnMergeProgress)(sSR.rgSharePath, ulStatus, 0, 0, lpFT, CSCPROC_REASON_BEGIN, 0, 0, dwContext);
  1248. }
  1249. except(EXCEPTION_EXECUTE_HANDLER)
  1250. {
  1251. dwRet = CSCPROC_RETURN_ABORT;
  1252. }
  1253. LocalFree(lpFT);
  1254. if (dwRet != CSCPROC_RETURN_CONTINUE)
  1255. {
  1256. if (dwRet == CSCPROC_RETURN_ABORT)
  1257. {
  1258. SetLastError(ERROR_OPERATION_ABORTED);
  1259. }
  1260. else
  1261. {
  1262. SetLastError(ERROR_SUCCESS);
  1263. }
  1264. }
  1265. }
  1266. for (i=0; i<4; ++i)
  1267. {
  1268. // for now we don't do directory deletions
  1269. // we will fix this later
  1270. if (i==REINT_DELETE_DIRS)
  1271. {
  1272. continue;
  1273. }
  1274. vsRei.nCurrentState = i;
  1275. try
  1276. {
  1277. iRet = TraverseOneDirectory(
  1278. hShadowDB,
  1279. pShareSecurityInfo,
  1280. 0,
  1281. hRoot,
  1282. tzFullPath,
  1283. ReintDirCallback,
  1284. (LPVOID)&vsRei);
  1285. }
  1286. except(EXCEPTION_EXECUTE_HANDLER)
  1287. {
  1288. iRet = TOD_ABORT;
  1289. }
  1290. if (iRet == TOD_ABORT)
  1291. {
  1292. break;
  1293. }
  1294. }
  1295. if (iRet != TOD_ABORT)
  1296. {
  1297. if(!vsRei.lpnodeInsertList)
  1298. {
  1299. fDone = TRUE;
  1300. }
  1301. }
  1302. if (fDone) {
  1303. SetShareStatus(hShadowDB, hShare, (unsigned long)(~SHARE_REINT), SHADOW_FLAGS_AND);
  1304. }
  1305. bailout:
  1306. if (!fDone)
  1307. {
  1308. dwError = GetLastError();
  1309. }
  1310. #if 0
  1311. if (fIsDfsConnect)
  1312. {
  1313. DbgPrint("Nuking DFS connects On Close %ls \n", sSR.rgSharePath);
  1314. do
  1315. {
  1316. if(WNetCancelConnection2(sSR.rgSharePath, 0, TRUE) != NO_ERROR)
  1317. {
  1318. DbgPrint("Nuked On Close %ls Error=%d\n", sSR.rgSharePath, GetLastError());
  1319. break;
  1320. }
  1321. else
  1322. {
  1323. DbgPrint("Nuked On Close %ls \n", sSR.rgSharePath);
  1324. }
  1325. } while (TRUE);
  1326. }
  1327. #endif
  1328. EnterAgentCrit();
  1329. if (fBeginReint){
  1330. Assert(hShare == vsRei.hShare);
  1331. EndReint(hShare, lpContext);
  1332. vsRei.hShare = 0;
  1333. fBeginReint = FALSE;
  1334. if (lpfnMergeProgress)
  1335. {
  1336. try
  1337. {
  1338. dwRet = (*lpfnMergeProgress)(sSR.rgSharePath, ulStatus, 0, 0, NULL, CSCPROC_REASON_END, 0, 0, dwContext);
  1339. }
  1340. except(EXCEPTION_EXECUTE_HANDLER)
  1341. {
  1342. dwRet = CSCPROC_RETURN_ABORT;
  1343. }
  1344. }
  1345. }
  1346. if (fDisabledShadowing)
  1347. {
  1348. EnableShadowingForThisThread(hShadowDB);
  1349. }
  1350. CloseShadowDatabaseIO(hShadowDB);
  1351. if(vsRei.lpnodeInsertList) {
  1352. killList(vsRei.lpnodeInsertList);
  1353. }
  1354. // reestablish the connection list
  1355. // NB we do this before we disconnect the drive mapping
  1356. // so that if any special credentials stay because
  1357. // there is always one connection outstanding to the server
  1358. if (lpHead)
  1359. {
  1360. ReconnectList(&lpHead, NULL);
  1361. ClearConnectionList(&lpHead);
  1362. }
  1363. if (fConnected) {
  1364. if(DWDisconnectDriveMappedNet(vsRei.tzDrive, TRUE))
  1365. {
  1366. ReintKdPrint(BADERRORS, ("Failed disconnection of merge drive \r\n"));
  1367. }
  1368. else
  1369. {
  1370. ReintKdPrint(MERGE, ("Disconnected merge drive \r\n"));
  1371. }
  1372. }
  1373. memset(&vsRei, 0, sizeof(vsRei));
  1374. LeaveAgentCrit();
  1375. if (!fDone)
  1376. {
  1377. ReintKdPrint(BADERRORS, ("Failed merge dwError=%d\r\n", dwError));
  1378. SetLastError(dwError);
  1379. }
  1380. return (fDone);
  1381. }
  1382. /***************************************************************************
  1383. * enumerate all the shares, checking to see if the share needs to be
  1384. * merged before starting.
  1385. * Returns: # of shares that needed to be merged and were successfully done.
  1386. */
  1387. // HWND for parent for UI.
  1388. int
  1389. PUBLIC
  1390. ReintAllShares(
  1391. HWND hwndParent
  1392. )
  1393. /*++
  1394. Routine Description:
  1395. Arguments:
  1396. Returns:
  1397. Notes:
  1398. --*/
  1399. {
  1400. unsigned long ulStatus;
  1401. WIN32_FIND_DATA sFind32;
  1402. int iDone=0, iDoneOne;
  1403. SHADOWINFO sSI;
  1404. HANDLE hShadowDB;
  1405. CSC_ENUMCOOKIE ulEnumCookie=NULL;
  1406. if ((hShadowDB = OpenShadowDatabaseIO()) ==INVALID_HANDLE_VALUE)
  1407. {
  1408. return FALSE;
  1409. }
  1410. #if 0
  1411. if (!EnterAgentCrit()) {
  1412. ReintKdPrint(BADERRORS, ("ReintAllShares:Failed to enter critsect \r\n"));
  1413. return 0;
  1414. }
  1415. #endif
  1416. vhcursor = LoadCursor(NULL, IDC_WAIT);
  1417. memset(&sFind32, 0, sizeof(sFind32));
  1418. lstrcpy(sFind32.cFileName, tzStarDotStar);
  1419. if(FindOpenShadow( hShadowDB, 0, FINDOPEN_SHADOWINFO_ALL, &sFind32, &sSI)){
  1420. ulEnumCookie = sSI.uEnumCookie;
  1421. do {
  1422. if (FAbortOperation())
  1423. {
  1424. break;
  1425. }
  1426. if(GetShareStatus(hShadowDB, sSI.hShare, &ulStatus)) {
  1427. if(TRUE/*ulStatus & SHARE_REINT*/){ // OLDCODE
  1428. iDoneOne = ReintOneShare(sSI.hShare, sSI.hShadow, NULL, NULL, NULL, CSC_INVALID_PRINCIPAL_ID, NULL, 0);
  1429. if (iDoneOne > 0){
  1430. if (iDone >= 0)
  1431. ++iDone;
  1432. }
  1433. else if (iDoneOne < 0){
  1434. iDone = -1;
  1435. }
  1436. }
  1437. else {
  1438. ReintKdPrint(MERGE, ("server %d doesn't need reint.\n", sSI.hShare));
  1439. }
  1440. }
  1441. } while(FindNextShadow( hShadowDB, ulEnumCookie, &sFind32, &sSI));
  1442. FindCloseShadow(hShadowDB, ulEnumCookie);
  1443. }
  1444. #if 0
  1445. LeaveAgentCrit();
  1446. #endif
  1447. vhcursor = NULL;
  1448. CloseShadowDatabaseIO(hShadowDB);
  1449. return (iDone);
  1450. }
  1451. int
  1452. CheckDirtyShares(
  1453. VOID
  1454. )
  1455. /*++
  1456. Routine Description:
  1457. Arguments:
  1458. Returns:
  1459. Notes:
  1460. --*/
  1461. {
  1462. unsigned long ulStatus;
  1463. WIN32_FIND_DATA sFind32;
  1464. int cntDirty=0;
  1465. SHADOWINFO sSI;
  1466. HANDLE hShadowDB;
  1467. CSC_ENUMCOOKIE ulEnumCookie=NULL;
  1468. if ((hShadowDB = OpenShadowDatabaseIO()) ==INVALID_HANDLE_VALUE)
  1469. {
  1470. return 0;
  1471. }
  1472. memset(&sFind32, 0, sizeof(sFind32));
  1473. lstrcpy(sFind32.cFileName, tzStarDotStar);
  1474. if(FindOpenShadow( hShadowDB, 0, FINDOPEN_SHADOWINFO_ALL,
  1475. &sFind32, &sSI))
  1476. {
  1477. ulEnumCookie = sSI.uEnumCookie;
  1478. do {
  1479. if(GetShareStatus(hShadowDB, sSI.hShare, &ulStatus)) {
  1480. if(ulStatus & SHARE_REINT){
  1481. ++cntDirty;
  1482. }
  1483. }
  1484. } while(FindNextShadow(hShadowDB, ulEnumCookie, &sFind32, &sSI));
  1485. FindCloseShadow(hShadowDB, ulEnumCookie);
  1486. }
  1487. CloseShadowDatabaseIO(hShadowDB);
  1488. return cntDirty;
  1489. }
  1490. BOOL
  1491. GetRemoteWin32Info(
  1492. _TCHAR *lptzDrive,
  1493. LPCOPYPARAMS lpCP,
  1494. LPWIN32_FIND_DATA lpFind32,
  1495. BOOL *lpfExists
  1496. )
  1497. /*++
  1498. Routine Description:
  1499. Arguments:
  1500. Returns:
  1501. Notes:
  1502. --*/
  1503. {
  1504. _TCHAR * lpT = NULL;
  1505. BOOL fRet = FALSE;
  1506. _TCHAR tzDrive[4];
  1507. DWORD dwError = ERROR_SUCCESS;
  1508. *lpfExists = -1;
  1509. tzDrive[0] = 0;
  1510. lpT = AllocMem((lstrlen(lpCP->lpSharePath) + lstrlen(lpCP->lpRemotePath) + 2) * sizeof(_TCHAR));
  1511. if (lpT)
  1512. {
  1513. if (lptzDrive && lptzDrive[0])
  1514. {
  1515. lstrcpy(lpT, lptzDrive);
  1516. }
  1517. else
  1518. {
  1519. dwError = DWConnectNet(lpCP->lpSharePath, tzDrive, NULL, NULL, NULL, 0, NULL);
  1520. if ((dwError != WN_SUCCESS) && (dwError != WN_CONNECTED_OTHER_PASSWORD_DEFAULT))
  1521. {
  1522. tzDrive[0] = 0;
  1523. goto bailout;
  1524. }
  1525. lstrcpy(lpT, tzDrive);
  1526. }
  1527. lstrcat(lpT, lpCP->lpRemotePath);
  1528. fRet = GetWin32Info(lpT, lpFind32); // if this fails, GetLastError is properly set
  1529. if (fRet)
  1530. {
  1531. *lpfExists = TRUE;
  1532. }
  1533. else
  1534. {
  1535. dwError = GetLastError();
  1536. if ((dwError == ERROR_FILE_NOT_FOUND)||
  1537. (dwError == ERROR_PATH_NOT_FOUND)||
  1538. (dwError == ERROR_INVALID_PARAMETER)
  1539. )
  1540. {
  1541. *lpfExists = FALSE;
  1542. }
  1543. }
  1544. }
  1545. else
  1546. {
  1547. dwError = ERROR_NOT_ENOUGH_MEMORY;
  1548. }
  1549. bailout:
  1550. if (tzDrive[0])
  1551. {
  1552. if(DWDisconnectDriveMappedNet(tzDrive, TRUE))
  1553. {
  1554. ReintKdPrint(BADERRORS, ("Failed disconnection of remote drive \r\n"));
  1555. }
  1556. }
  1557. if (lpT)
  1558. {
  1559. FreeMem(lpT);
  1560. }
  1561. if (!fRet)
  1562. {
  1563. SetLastError(dwError);
  1564. }
  1565. return (fRet);
  1566. }
  1567. VOID
  1568. PRIVATE
  1569. InferReplicaReintStatus(
  1570. LPSHADOWINFO lpSI, // shadow info
  1571. LPWIN32_FIND_DATA lpFind32Local, // win32 info in the database
  1572. LPWIN32_FIND_DATA lpFind32Remote, // if NULL, the remote doesn't exist
  1573. int *lpiShadowStatus,
  1574. int *lpiFileStatus,
  1575. unsigned *lpuAction
  1576. )
  1577. /*++
  1578. Routine Description:
  1579. As the name sugggests, the routine find out what changes have occurred on the local replica
  1580. and whether there is a conflict with the original on the remote.
  1581. Arguments:
  1582. lpSI shadow info
  1583. lpFind32Local win32 info in the database
  1584. lpFind32Remote win32 info for the original if NULL, the original doesn't exist
  1585. lpiShadowStatus status of local replica returned
  1586. lpiFileStatus status of remote replica returned
  1587. lpuAction Action to be performed to do the merge returned
  1588. Returns:
  1589. -
  1590. Notes:
  1591. --*/
  1592. {
  1593. int iShadowStatus=SI_UNCHANGED, iFileStatus=SI_UNCHANGED;
  1594. unsigned int uAction=RAIA_TOOUT;
  1595. if(mShadowDeleted(lpSI->uStatus)){
  1596. iShadowStatus=SI_DELETED;
  1597. }
  1598. if(lpSI->uStatus & (SHADOW_DIRTY|SHADOW_TIME_CHANGE|SHADOW_ATTRIB_CHANGE)){
  1599. iShadowStatus=SI_CHANGED;
  1600. }
  1601. if(mShadowLocallyCreated(lpSI->uStatus)){
  1602. iShadowStatus=SI_NEW;
  1603. }
  1604. // no one should be calling this if there have been no offline changes
  1605. Assert(iShadowStatus != SI_UNCHANGED);
  1606. if(!lpFind32Remote){ // does the remote exist?
  1607. // No
  1608. // if the shadow was not locally created then it must have vanished from the share
  1609. if(iShadowStatus != SI_NEW) {
  1610. iFileStatus=SI_DELETED;
  1611. uAction = RAIA_MERGE;
  1612. ReintKdPrint(MERGE, ("<%ls> deleted at some stage\n", lpFind32Local->cFileName));
  1613. }
  1614. else {
  1615. // we mark the outside as not existing. We also have to
  1616. // create a file locally to get the insert to work right...
  1617. // don't forget to kill it later.
  1618. iFileStatus=SI_NOEXIST;
  1619. ReintKdPrint(MERGE, ("<%ls> will be created\n", lpFind32Local->cFileName));
  1620. }
  1621. }
  1622. else {
  1623. // check to see if server version has been touched
  1624. // NB the last accesstime field of the lpFind32Local contains the replica time
  1625. if ((lpFind32Local->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  1626. != (lpFind32Remote->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  1627. {
  1628. // dir became file or vice versa
  1629. iFileStatus=SI_CHANGED;
  1630. uAction = RAIA_MERGE;
  1631. }
  1632. else
  1633. {
  1634. if(CompareTimesAtDosTimePrecision(lpFind32Remote->ftLastWriteTime, //dst
  1635. lpFind32Local->ftLastAccessTime)) //src , does (dst-src)
  1636. {
  1637. // the timestamps don't match
  1638. // mark the remote as changed only if it is a file
  1639. // will do the directories quitely
  1640. if (!(lpFind32Remote->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  1641. {
  1642. iFileStatus=SI_CHANGED;
  1643. uAction = RAIA_MERGE;
  1644. ReintKdPrint(MERGE, ("<%ls> will be merged\n", lpFind32Local->cFileName));
  1645. }
  1646. }
  1647. }
  1648. }
  1649. *lpiShadowStatus = iShadowStatus;
  1650. *lpiFileStatus = iFileStatus;
  1651. *lpuAction = uAction;
  1652. }
  1653. BOOL
  1654. PRIVATE
  1655. PerformOneReint(
  1656. HANDLE hShadowDB,
  1657. LPSECURITYINFO pShareSecurityInfo,
  1658. _TCHAR * lpszDrive, // drive mapped to the UNC name of lpSI->hShare
  1659. _TCHAR * lptzFullPath, // full UNC path
  1660. LPCOPYPARAMS lpCP, // copy parameters
  1661. LPSHADOWINFO lpSI, // shadowinfo structure
  1662. LPWIN32_FIND_DATA lpFind32Local, // local win32 data
  1663. LPWIN32_FIND_DATA lpFind32Remote, // remote win32 data, could be NULL
  1664. DWORD dwErrorRemoteFind32,// error code while getting remote win32 data
  1665. int iShadowStatus, // local copy status
  1666. int iFileStatus, // remote file status
  1667. unsigned uAction, // action to be taken
  1668. DWORD dwFileSystemFlags, // CODE.IMPROVEMENT, why not just pass down REINT_INFO
  1669. ULONG ulPrincipalID,
  1670. LPCSCPROC lpfnMergeProgress, // instead of the three parameters?
  1671. DWORD_PTR dwContext
  1672. )
  1673. /*++
  1674. Routine Description:
  1675. Merges a filesystem object by calling the routine for the appropriate type of FS object.
  1676. We implement only files and directories for NT5. Also does callbacks for the UI.
  1677. Arguments:
  1678. hShadowDB Shadow Database handle
  1679. lpszDrive drive mapped to the UNC name of lpSI->hShare
  1680. lptzFullPath full UNC path
  1681. lpCP copy parameters containing various paths for the object being merged
  1682. lpSI shadowinfo structure for the object being merged
  1683. lpFind32Local local win32 data for the object being merged
  1684. lpFind32Remote remote win32 data for the object being merged, could be NULL
  1685. iShadowStatus local copy status
  1686. iFileStatus remote file status
  1687. uAction action to be taken
  1688. dwFileSystemFlags remote filesystem
  1689. ulPrincipalID principal ID in order to skip selectively
  1690. lpfnMergeProgress callback function
  1691. dwContext callback context
  1692. Returns:
  1693. Notes:
  1694. --*/
  1695. {
  1696. DWORD dwError, dwRet;
  1697. dwError = NO_ERROR;
  1698. ReintKdPrint(
  1699. MERGE,
  1700. ("++++++++PerformOneReint: %s (%08x) %d %d perform:\n",
  1701. lptzFullPath,
  1702. lpSI->hShadow,
  1703. iShadowStatus,
  1704. iFileStatus));
  1705. if (lpfnMergeProgress)
  1706. {
  1707. ULONG uStatus = lpSI->uStatus;
  1708. DWORD dwsav0, dwsav1;
  1709. // if there is an error in getting remote find32, then
  1710. // don't tell any conflicts to the callback, because we don't want to show any UI
  1711. if (dwErrorRemoteFind32 != NO_ERROR)
  1712. {
  1713. iFileStatus = SI_CHANGED;
  1714. uAction = RAIA_TOOUT;
  1715. }
  1716. // if this is a file, check whether access is allowed for this user
  1717. if (!(lpFind32Local->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  1718. {
  1719. BOOL fRet;
  1720. Assert(dwError == NO_ERROR);
  1721. Assert(ulPrincipalID != CSC_INVALID_PRINCIPAL_ID);
  1722. dwsav0 = lpFind32Local->dwReserved0;
  1723. dwsav1 = lpFind32Local->dwReserved1;
  1724. fRet = GetCSCAccessMaskForPrincipalEx(
  1725. ulPrincipalID,
  1726. lpSI->hDir,
  1727. lpSI->hShadow,
  1728. &uStatus,
  1729. &lpFind32Local->dwReserved0,
  1730. &lpFind32Local->dwReserved1);
  1731. //
  1732. // Adjust user and guest permissions based on share security, if
  1733. // we have such info.
  1734. //
  1735. if (pShareSecurityInfo != NULL) {
  1736. ULONG i;
  1737. ULONG GuestIdx = CSC_MAXIMUM_NUMBER_OF_CACHED_PRINCIPAL_IDS;
  1738. ULONG UserIdx = CSC_MAXIMUM_NUMBER_OF_CACHED_PRINCIPAL_IDS;
  1739. //
  1740. // Find the user's and guest's entries
  1741. //
  1742. for (i = 0; i < CSC_MAXIMUM_NUMBER_OF_CACHED_PRINCIPAL_IDS; i++) {
  1743. if (pShareSecurityInfo[i].ulPrincipalID == ulPrincipalID)
  1744. UserIdx = i;
  1745. if (pShareSecurityInfo[i].ulPrincipalID == CSC_GUEST_PRINCIPAL_ID)
  1746. GuestIdx = i;
  1747. }
  1748. //
  1749. // Only work with share perms if we found a guest perm in the list
  1750. //
  1751. if (GuestIdx < CSC_MAXIMUM_NUMBER_OF_CACHED_PRINCIPAL_IDS) {
  1752. if (UserIdx >= CSC_MAXIMUM_NUMBER_OF_CACHED_PRINCIPAL_IDS)
  1753. UserIdx = GuestIdx;
  1754. //
  1755. // Logical AND the share perms with the file perms - to prevent
  1756. // ACCESS_DENIED errors on files which a user has access to via
  1757. // file perms, but share perms deny such access.
  1758. //
  1759. lpFind32Local->dwReserved0 &= pShareSecurityInfo[UserIdx].ulPermissions;
  1760. lpFind32Local->dwReserved1 &= pShareSecurityInfo[GuestIdx].ulPermissions;
  1761. }
  1762. }
  1763. if (!fRet)
  1764. {
  1765. dwError = GetLastError();
  1766. ReintKdPrint(MERGE, ("Failed to get accessmask Error=%d \n", dwError));
  1767. lpFind32Local->dwReserved0 = dwsav0;
  1768. lpFind32Local->dwReserved1 = dwsav1;
  1769. goto bailout;
  1770. }
  1771. else
  1772. {
  1773. Assert((uStatus & ~FLAG_CSC_ACCESS_MASK) == lpSI->uStatus);
  1774. ReintKdPrint(MERGE, ("PerformOneReint: Status with mask 0x%x\n",uStatus));
  1775. }
  1776. }
  1777. try{
  1778. dwRet = (*lpfnMergeProgress)(
  1779. lptzFullPath,
  1780. uStatus,
  1781. lpSI->ulHintFlags,
  1782. lpSI->ulHintPri,
  1783. lpFind32Local,
  1784. CSCPROC_REASON_BEGIN,
  1785. (uAction == RAIA_MERGE),
  1786. (iFileStatus == SI_DELETED),
  1787. dwContext
  1788. );
  1789. }
  1790. except(EXCEPTION_EXECUTE_HANDLER)
  1791. {
  1792. dwRet = CSCPROC_RETURN_ABORT;
  1793. }
  1794. lpFind32Local->dwReserved0 = dwsav0;
  1795. lpFind32Local->dwReserved1 = dwsav1;
  1796. if (dwRet != CSCPROC_RETURN_CONTINUE)
  1797. {
  1798. // if the guy said abort, we want to quit with the correct error code
  1799. if (dwRet == CSCPROC_RETURN_ABORT)
  1800. {
  1801. dwError = ERROR_OPERATION_ABORTED;
  1802. goto bailout;
  1803. }
  1804. if (dwRet == CSCPROC_RETURN_FORCE_INWARD)
  1805. {
  1806. // the remote copy wins
  1807. uAction = RAIA_TOIN;
  1808. }
  1809. else if (dwRet == CSCPROC_RETURN_FORCE_OUTWARD)
  1810. {
  1811. // local copy wins
  1812. #if defined(BITCOPY)
  1813. ReintKdPrint(MERGE, ("CSCPROC_RETURN_FORCE_OUTWARD\n"));
  1814. uAction = RAIA_MERGE;
  1815. #else
  1816. uAction = RAIA_TOOUT;
  1817. #endif // defined(BITCOPY)
  1818. }
  1819. else
  1820. {
  1821. goto bailout;
  1822. }
  1823. }
  1824. else
  1825. {
  1826. // if we are asked to continue, we press on irrespective of whether there is
  1827. // a conflict or not
  1828. #if defined(BITCOPY)
  1829. ReintKdPrint(MERGE, ("CSCPROC_RETURN_CONTINUE\n"));
  1830. #endif // defined(BITCOPY)
  1831. uAction = RAIA_TOOUT;
  1832. }
  1833. // if there is an error in getting remote find32, then
  1834. // tell the real error code to the callback
  1835. if (dwErrorRemoteFind32 != NO_ERROR)
  1836. {
  1837. dwError = dwErrorRemoteFind32;
  1838. goto bailout;
  1839. }
  1840. }
  1841. switch(uAction){
  1842. case RAIA_MERGE:
  1843. case RAIA_TOOUT:
  1844. ReintKdPrint(MERGE, ((uAction==RAIA_TOOUT)?"RAIA_TOOUT\n":"RAIA_MERGE\n"));
  1845. if (lpFind32Local->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
  1846. dwError = DoCreateDir(
  1847. hShadowDB,
  1848. lpszDrive,
  1849. lptzFullPath,
  1850. lpCP,
  1851. lpSI,
  1852. lpFind32Local,
  1853. lpFind32Remote,
  1854. iShadowStatus,
  1855. iFileStatus,
  1856. uAction,
  1857. dwFileSystemFlags,
  1858. lpfnMergeProgress,
  1859. dwContext
  1860. );
  1861. }
  1862. else {
  1863. dwError = DoObjectEdit(
  1864. hShadowDB,
  1865. lpszDrive,
  1866. lptzFullPath,
  1867. lpCP,
  1868. lpSI,
  1869. lpFind32Local,
  1870. lpFind32Remote,
  1871. iShadowStatus,
  1872. iFileStatus,
  1873. uAction,
  1874. dwFileSystemFlags,
  1875. lpfnMergeProgress,
  1876. dwContext
  1877. );
  1878. ReintKdPrint(MERGE, ("DoObjectEdit returned 0x%x\n", dwError));
  1879. }
  1880. break;
  1881. case RAIA_TOIN:
  1882. ReintKdPrint(MERGE, ("RAIA_TOIN\n"));
  1883. if((!SetShadowInfo(hShadowDB, lpSI->hDir, lpSI->hShadow, NULL, (unsigned long)~(SHADOW_MODFLAGS), SHADOW_FLAGS_AND))
  1884. ||!CheckForStalenessAndRefresh(hShadowDB, lpszDrive, lpCP, lptzFullPath, lpSI))
  1885. {
  1886. dwError = GetLastError();
  1887. }
  1888. break;
  1889. case RAIA_SKIP:
  1890. ReintKdPrint(MERGE, ("RAIA_SKIP\n"));
  1891. break;
  1892. case RAIA_CONFLICT:
  1893. ReintKdPrint(MERGE, ("RAIA_CONFLICT\n"));
  1894. break;
  1895. case RAIA_SOMETHING:
  1896. ReintKdPrint(MERGE, ("RAIA_SOMETHING\n"));
  1897. break;
  1898. case RAIA_NOTHING:
  1899. ReintKdPrint(MERGE, ("RAIA_NOTHING\n"));
  1900. break;
  1901. case RAIA_ORPHAN:
  1902. ReintKdPrint(MERGE, ("RAIA_ORPHAN\n"));
  1903. break;
  1904. default:
  1905. ReintKdPrint(MERGE, ("BOGUS!!!!!!!!!!!! %d\n",uAction));
  1906. }
  1907. bailout:
  1908. if (lpfnMergeProgress)
  1909. {
  1910. try
  1911. {
  1912. dwRet = (*lpfnMergeProgress)(
  1913. lptzFullPath,
  1914. lpSI->uStatus,
  1915. lpSI->ulHintFlags,
  1916. lpSI->ulHintPri,
  1917. lpFind32Local,
  1918. CSCPROC_REASON_END,
  1919. (uAction == RAIA_MERGE),
  1920. dwError,
  1921. dwContext
  1922. );
  1923. ReintKdPrint(MERGE, ("Got %d from callback at CSCPROC_REASON_END\n", dwRet));
  1924. }
  1925. except(EXCEPTION_EXECUTE_HANDLER)
  1926. {
  1927. dwRet = CSCPROC_RETURN_ABORT;
  1928. }
  1929. if (dwRet == CSCPROC_RETURN_ABORT)
  1930. {
  1931. dwError = ERROR_OPERATION_ABORTED;
  1932. }
  1933. }
  1934. if (dwError == NO_ERROR) {
  1935. ReintKdPrint(MERGE, ("--------PerformOneReint exit TRUE\n"));
  1936. return TRUE;
  1937. }
  1938. ReintKdPrint(MERGE, ("--------PerformOneReint exit FALSE (0x%x)\n", dwError));
  1939. SetLastError(dwError);
  1940. return (FALSE);
  1941. }
  1942. /******************************* Conflict related operations ****************/
  1943. DWORD
  1944. PRIVATE
  1945. CheckFileConflict(
  1946. LPSHADOWINFO lpSI,
  1947. LPWIN32_FIND_DATA lpFind32Remote
  1948. )
  1949. {
  1950. unsigned long ulStatus = lpSI->uStatus;
  1951. if (!lpFind32Remote){
  1952. if (!(mShadowLocallyCreated(ulStatus)||mShadowDeleted(ulStatus))){
  1953. return (ERROR_DELETE_CONFLICT);
  1954. }
  1955. else{
  1956. return (NO_ERROR);
  1957. }
  1958. }
  1959. else {
  1960. // Create/Create conflict
  1961. if (mShadowLocallyCreated(ulStatus)){
  1962. return (ERROR_CREATE_CONFLICT);
  1963. }
  1964. if (lpFind32Remote->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
  1965. if (mShadowDeleted(ulStatus)){
  1966. return (NO_ERROR);
  1967. }
  1968. else{
  1969. return(ERROR_ATTRIBUTE_CONFLICT);
  1970. }
  1971. }
  1972. if(ChkUpdtStatus(INVALID_HANDLE_VALUE, lpSI->hDir, lpSI->hShadow, lpFind32Remote, &ulStatus) == 0){
  1973. return (GetLastError());
  1974. }
  1975. if (mShadowConflict(ulStatus)){
  1976. return (ERROR_UPDATE_CONFLICT);
  1977. }
  1978. }
  1979. return (NO_ERROR);
  1980. }
  1981. DWORD
  1982. PRIVATE
  1983. InbCreateDir(
  1984. _TCHAR * lpDir,
  1985. DWORD dwAttr
  1986. )
  1987. {
  1988. SECURITY_ATTRIBUTES sSA;
  1989. DWORD dwError = NO_ERROR, dwT;
  1990. sSA.nLength = sizeof(SECURITY_ATTRIBUTES);
  1991. sSA.lpSecurityDescriptor = NULL;
  1992. sSA.bInheritHandle = TRUE;
  1993. if ((dwT = GetFileAttributes(lpDir))==0xffffffff){
  1994. if (!CreateDirectory(lpDir, &sSA)){
  1995. dwError = GetLastError();
  1996. }
  1997. }
  1998. else
  1999. {
  2000. if (!(dwT & FILE_ATTRIBUTE_DIRECTORY))
  2001. {
  2002. dwError = ERROR_FILE_EXISTS; // there is a file by the same name
  2003. }
  2004. }
  2005. if (dwError == NO_ERROR)
  2006. {
  2007. if (dwAttr != 0xffffffff)
  2008. {
  2009. if(!SetFileAttributes(lpDir, dwAttr))
  2010. {
  2011. ReintKdPrint(MERGE, ("Benign error %x \n", GetLastError()));
  2012. }
  2013. }
  2014. }
  2015. return (dwError);
  2016. }
  2017. /*********************************** Misc routines **************************/
  2018. #if defined(BITCOPY)
  2019. int
  2020. PRIVATE
  2021. GetShadowByName(
  2022. HSHADOW hDir,
  2023. _TCHAR * lpName,
  2024. LPWIN32_FIND_DATA lpFind32,
  2025. unsigned long *lpuStatus
  2026. )
  2027. /*++
  2028. Routine Description:
  2029. Arguments:
  2030. Returns:
  2031. Notes:
  2032. --*/
  2033. {
  2034. HSHADOW hShadow;
  2035. memset(lpFind32, 0, sizeof(WIN32_FIND_DATA));
  2036. lstrcpyn(lpFind32->cFileName, lpName, sizeof(lpFind32->cFileName)-1);
  2037. return(GetShadow(INVALID_HANDLE_VALUE, hDir, &hShadow, lpFind32, lpuStatus));
  2038. }
  2039. #endif // defined(BITCOPY)
  2040. DWORD
  2041. DoSparseFill(
  2042. HANDLE hShadowDB,
  2043. _TCHAR * lpszFullPath,
  2044. _TCHAR * lptzDrive,
  2045. LPSHADOWINFO lpSI,
  2046. WIN32_FIND_DATA *lpFind32,
  2047. LPCOPYPARAMS lpCP,
  2048. BOOL fStalenessCheck,
  2049. ULONG ulPrincipalID,
  2050. LPCSCPROC lpfnProgress,
  2051. DWORD_PTR dwContext
  2052. )
  2053. /*++
  2054. Routine Description:
  2055. Arguments:
  2056. Returns:
  2057. Notes:
  2058. --*/
  2059. {
  2060. DWORD dwError = 0xffffffff, dwRet, dwTotal=0, dwTotalSleepTime = 0, cntRetries=0, cntMaxRetries=1;
  2061. BOOL fConnected = FALSE, fIsSlowLink, fDisabledShadowing = FALSE, fAmAgent;
  2062. int cbRead;
  2063. COPYCHUNKCONTEXT CopyChunkContext;
  2064. HANDLE hAnchor = INVALID_HANDLE_VALUE;
  2065. ULONG uStatus;
  2066. fAmAgent = (GetCurrentThreadId() == vdwCopyChunkThreadId);
  2067. Assert(GetCurrentThreadId() != vdwAgentThreadId);
  2068. memset(&CopyChunkContext, 0, sizeof(CopyChunkContext));
  2069. CopyChunkContext.handle = INVALID_HANDLE_VALUE;
  2070. if (!fAmAgent)
  2071. {
  2072. cntMaxRetries = MAX_SPARSE_FILL_RETRIES;
  2073. }
  2074. ReintKdPrint(FILL, ("cntMaxRetries = %d \r\n", cntMaxRetries));
  2075. if(!DoShadowMaintenance(hShadowDB, SHADOW_BEGIN_INODE_TRANSACTION))
  2076. {
  2077. return GetLastError();
  2078. }
  2079. // report the progress
  2080. if (lpfnProgress)
  2081. {
  2082. DWORD dwsav0, dwsav1;
  2083. BOOL fRet;
  2084. uStatus = lpSI->uStatus;
  2085. Assert(ulPrincipalID != CSC_INVALID_PRINCIPAL_ID);
  2086. dwError = ERROR_SUCCESS;
  2087. dwsav0 = lpFind32->dwReserved0;
  2088. dwsav1 = lpFind32->dwReserved1;
  2089. fRet = GetCSCAccessMaskForPrincipalEx(ulPrincipalID, lpSI->hDir, lpSI->hShadow, &uStatus, &lpFind32->dwReserved0, &lpFind32->dwReserved1);
  2090. if (!fRet)
  2091. {
  2092. dwError = GetLastError();
  2093. ReintKdPrint(BADERRORS, ("DoSparseFill Failed to get accessmask Error=%d\r\n", dwError));
  2094. lpFind32->dwReserved0 = dwsav0;
  2095. lpFind32->dwReserved1 = dwsav1;
  2096. goto done;
  2097. }
  2098. else
  2099. {
  2100. Assert((uStatus & ~FLAG_CSC_ACCESS_MASK) == lpSI->uStatus);
  2101. }
  2102. try{
  2103. dwRet = (*lpfnProgress)(
  2104. lpszFullPath,
  2105. uStatus,
  2106. lpSI->ulHintFlags,
  2107. lpSI->ulHintPri,
  2108. lpFind32,
  2109. CSCPROC_REASON_BEGIN,
  2110. 0,
  2111. 0,
  2112. dwContext
  2113. );
  2114. }
  2115. except(EXCEPTION_EXECUTE_HANDLER)
  2116. {
  2117. dwRet = CSCPROC_RETURN_ABORT;
  2118. }
  2119. lpFind32->dwReserved0 = dwsav0;
  2120. lpFind32->dwReserved1 = dwsav1;
  2121. if (dwRet != CSCPROC_RETURN_CONTINUE)
  2122. {
  2123. if (dwRet == CSCPROC_RETURN_ABORT)
  2124. {
  2125. dwError = ERROR_OPERATION_ABORTED;
  2126. }
  2127. else
  2128. {
  2129. dwError = ERROR_SUCCESS;
  2130. }
  2131. goto done;
  2132. }
  2133. }
  2134. if (fStalenessCheck)
  2135. {
  2136. ReintKdPrint(FILL, ("Doing staleness check %ls \r\n", lpszFullPath));
  2137. dwError = DoRefresh(hShadowDB, lpCP, lpszFullPath, lpSI, lptzDrive);
  2138. if (dwError != NO_ERROR)
  2139. {
  2140. ReintKdPrint(ALWAYS, ("Error = %x on refresh for %ls \r\n", dwError, lpszFullPath));
  2141. goto bailout;
  2142. }
  2143. if (!(lpSI->uStatus & SHADOW_SPARSE) && !(lpFind32->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  2144. {
  2145. HANDLE hFile;
  2146. if ( !lpfnProgress || // if this is not UI
  2147. (uStatus & FLAG_CSC_USER_ACCESS_MASK) || // or the user already has a mask
  2148. ((uStatus & FLAG_CSC_GUEST_ACCESS_MASK)== // or the guest has full permission
  2149. ((FLAG_CSC_READ_ACCESS|FLAG_CSC_WRITE_ACCESS)
  2150. <<FLAG_CSC_GUEST_ACCESS_SHIFT_COUNT)))
  2151. {
  2152. goto done;
  2153. }
  2154. // open the file to get the access rights for the user
  2155. hFile = CreateFile(lpszFullPath,
  2156. GENERIC_READ,
  2157. FILE_SHARE_READ,
  2158. NULL,
  2159. OPEN_EXISTING,
  2160. 0,
  2161. NULL);
  2162. if (hFile != INVALID_HANDLE_VALUE)
  2163. {
  2164. CloseHandle(hFile);
  2165. }
  2166. else
  2167. {
  2168. dwError = GetLastError();
  2169. goto bailout;
  2170. }
  2171. goto done;
  2172. }
  2173. if (!lpSI->hDir || !mShadowIsFile(lpSI->uStatus))
  2174. {
  2175. ReintKdPrint(FILL, ("Done staleness check for directory %ls, quitting \r\n", lpszFullPath));
  2176. goto done;
  2177. }
  2178. }
  2179. Assert(mShadowIsFile(lpSI->uStatus));
  2180. Assert((lpSI->uStatus & SHADOW_SPARSE));
  2181. fIsSlowLink = FALSE; // on NT we are always going aggressively
  2182. cbRead = (fIsSlowLink)?FILL_BUF_SIZE_SLOWLINK:FILL_BUF_SIZE_LAN;
  2183. for (cntRetries=0; cntRetries<cntMaxRetries; ++cntRetries)
  2184. {
  2185. memset(&CopyChunkContext, 0, sizeof(CopyChunkContext));
  2186. CopyChunkContext.handle = INVALID_HANDLE_VALUE;
  2187. if (fAmAgent)
  2188. {
  2189. CopyChunkContext.dwFlags |= COPYCHUNKCONTEXT_FLAG_IS_AGENT_OPEN;
  2190. }
  2191. if (!OpenFileWithCopyChunkIntent(hShadowDB, lpszFullPath,
  2192. &CopyChunkContext,
  2193. (fIsSlowLink)?FILL_BUF_SIZE_SLOWLINK
  2194. :FILL_BUF_SIZE_LAN
  2195. )) {
  2196. dwError = GetLastError();
  2197. if(dwError == ERROR_LOCK_VIOLATION)
  2198. {
  2199. if (cntMaxRetries > 1)
  2200. {
  2201. ReintKdPrint(FILL, ("LockViolation, Retrying Sparse filling %ls \r\n", lpszFullPath));
  2202. Sleep(1000);
  2203. continue;
  2204. }
  2205. }
  2206. ReintKdPrint(FILL, ("error %x, OpenCopyChunk failed %ls \r\n", dwError, lpszFullPath));
  2207. goto bailout;
  2208. }
  2209. do {
  2210. CopyChunkContext.ChunkSize = cbRead;
  2211. if (FAbortOperation())
  2212. {
  2213. dwError = ERROR_OPERATION_ABORTED;
  2214. goto done;
  2215. }
  2216. if((CopyChunk(hShadowDB, lpSI, &CopyChunkContext)) == 0){
  2217. // NB we break here deliberately in order to get into the outer loop
  2218. // where we will retry the operation
  2219. dwError = GetLastError();
  2220. ReintKdPrint(FILL, ("error %x, CopyChunk failed %ls \r\n", dwError, lpszFullPath));
  2221. break;
  2222. }
  2223. if (lpfnProgress)
  2224. {
  2225. dwRet = (*lpfnProgress)( lpszFullPath,
  2226. lpSI->uStatus,
  2227. lpSI->ulHintFlags,
  2228. lpSI->ulHintPri,
  2229. lpFind32,
  2230. CSCPROC_REASON_MORE_DATA,
  2231. (DWORD)(CopyChunkContext.LastAmountRead+
  2232. CopyChunkContext.TotalSizeBeforeThisRead), // low dword of bytes transferred
  2233. 0,
  2234. dwContext
  2235. );
  2236. if (dwRet != CSCPROC_RETURN_CONTINUE)
  2237. {
  2238. // once we start copying, any return code
  2239. // other than continue is abort
  2240. dwError = ERROR_OPERATION_ABORTED;
  2241. goto done;
  2242. }
  2243. }
  2244. // NB there seems to be a timing window here. The file could get out of ssync
  2245. // by the time we came here and it could have been marked sparse by then
  2246. if (!CopyChunkContext.LastAmountRead) {
  2247. SetShadowInfo(hShadowDB, lpSI->hDir, lpSI->hShadow, NULL, (unsigned long)~SHADOW_SPARSE, SHADOW_FLAGS_AND);
  2248. ReintKdPrint(FILL, ("Done Sparse filling %ls \r\n", lpszFullPath));
  2249. goto success;
  2250. }
  2251. }while (TRUE);
  2252. if (dwError == ERROR_GEN_FAILURE)
  2253. {
  2254. // this might be due to the fact that
  2255. // the guy we were piggybacking on went away
  2256. // Just try a few times
  2257. ReintKdPrint(FILL, ("Retrying Sparse filling %ls \r\n", lpszFullPath));
  2258. CloseFileWithCopyChunkIntent(hShadowDB, &CopyChunkContext);
  2259. CopyChunkContext.handle = INVALID_HANDLE_VALUE;
  2260. dwError = 0xffffffff;
  2261. continue;
  2262. }
  2263. else if (dwError != NO_ERROR)
  2264. {
  2265. ReintKdPrint(BADERRORS, ("Error %x while Sparse filling %ls \r\n", dwError, lpszFullPath));
  2266. goto bailout;
  2267. }
  2268. }
  2269. success:
  2270. dwError = NO_ERROR;
  2271. goto done;
  2272. bailout:
  2273. // if the net is disconnected then put the whole share in the skip queue
  2274. // else put the file in the queue
  2275. if (IsNetDisconnected(dwError))
  2276. {
  2277. #ifdef DEBUG
  2278. EnterSkipQueue(lpSI->hShare, 0, 0, lpszFullPath);
  2279. #else
  2280. EnterSkipQueue(lpSI->hShare, 0, 0);
  2281. #endif //DEBUG
  2282. }
  2283. else
  2284. {
  2285. #ifdef DEBUG
  2286. EnterSkipQueue(lpSI->hShare, lpSI->hDir, lpSI->hShadow, lpszFullPath);
  2287. #else
  2288. EnterSkipQueue(lpSI->hShare, lpSI->hDir, lpSI->hShadow);
  2289. #endif //DEBUG
  2290. }
  2291. ReportLastError();
  2292. done:
  2293. if (lpfnProgress)
  2294. {
  2295. dwRet = (*lpfnProgress)( lpszFullPath,
  2296. lpSI->uStatus,
  2297. lpSI->ulHintFlags,
  2298. lpSI->ulHintPri,
  2299. lpFind32,
  2300. CSCPROC_REASON_END,
  2301. (DWORD)(CopyChunkContext.LastAmountRead+
  2302. CopyChunkContext.TotalSizeBeforeThisRead), // low dword of bytes transferred
  2303. dwError, // errorcode
  2304. dwContext
  2305. );
  2306. if (dwRet == CSCPROC_RETURN_ABORT)
  2307. {
  2308. dwError = ERROR_OPERATION_ABORTED;
  2309. }
  2310. }
  2311. if (CopyChunkContext.handle != INVALID_HANDLE_VALUE){
  2312. CloseFileWithCopyChunkIntent(hShadowDB, &CopyChunkContext);
  2313. }
  2314. if (hAnchor != INVALID_HANDLE_VALUE)
  2315. {
  2316. CloseHandle(hAnchor);
  2317. }
  2318. DoShadowMaintenance(hShadowDB, SHADOW_END_INODE_TRANSACTION);
  2319. return (dwError);
  2320. }
  2321. BOOL
  2322. CheckForStalenessAndRefresh(
  2323. HANDLE hShadowDB,
  2324. _TCHAR *lptzDrive,
  2325. LPCOPYPARAMS lpCP,
  2326. _TCHAR *lpRemoteName,
  2327. LPSHADOWINFO lpSI
  2328. )
  2329. /*++
  2330. Routine Description:
  2331. Arguments:
  2332. Returns:
  2333. Notes:
  2334. --*/
  2335. {
  2336. BOOL fDone = FALSE, fDisabledShadowing=FALSE;
  2337. WIN32_FIND_DATA sFind32;
  2338. BOOL fExists = FALSE;
  2339. // Let us get the latest info
  2340. if (GetRemoteWin32Info(lptzDrive, lpCP, &sFind32, &fExists))
  2341. {
  2342. // If this is a file, update the file status
  2343. if (lpSI->hDir && mShadowIsFile(lpSI->uStatus))
  2344. {
  2345. if (!(lpSI->uStatus & SHADOW_STALE))
  2346. {
  2347. ReintKdPrint(FILL, ("Checking update status for a file %ls\r\n", lpRemoteName));
  2348. // compare the timestamp as obtained from the
  2349. // server with that on the database. If the two are the same
  2350. // the file in our database is still consistent with the one on the server
  2351. // Otherwise the call below will mark it as stale
  2352. if(ChkUpdtStatus( hShadowDB,
  2353. lpSI->hDir,
  2354. lpSI->hShadow,
  2355. &sFind32, &(lpSI->uStatus)) == 0){
  2356. ReintKdPrint(BADERRORS, ("ChkUpdt failed %X \r\n", lpSI->hShadow));
  2357. goto bailout;
  2358. }
  2359. }
  2360. if (lpSI->uStatus & SHADOW_STALE)
  2361. {
  2362. // if it changed from being a file, then mark it a orphan
  2363. // else truncate it's data and mark it sparse
  2364. if (IsFile(sFind32.dwFileAttributes))
  2365. {
  2366. ReintKdPrint(FILL, ("File %ls is stale, truncating\r\n", lpRemoteName));
  2367. if(SetShadowInfo(hShadowDB, lpSI->hDir, lpSI->hShadow, &sFind32, 0, SHADOW_FLAGS_OR|SHADOW_FLAGS_TRUNCATE_DATA))
  2368. {
  2369. lpSI->uStatus &= ~SHADOW_STALE;
  2370. lpSI->uStatus |= SHADOW_SPARSE;
  2371. fDone = TRUE;
  2372. }
  2373. }
  2374. else
  2375. {
  2376. ReintKdPrint(FILL, ("File %ls become directory, marking orphan\r\n", lpRemoteName));
  2377. if(SetShadowInfo(hShadowDB, lpSI->hDir, lpSI->hShadow, NULL, SHADOW_ORPHAN, SHADOW_FLAGS_OR))
  2378. {
  2379. lpSI->uStatus |= SHADOW_ORPHAN;
  2380. fDone = TRUE;
  2381. }
  2382. }
  2383. }
  2384. else
  2385. {
  2386. fDone = TRUE;
  2387. }
  2388. }
  2389. else
  2390. {
  2391. // NB, we do nothing if a directory changed to file
  2392. // we are letting the scavenging code remove the entries in due course.
  2393. // If one of the descendents of this directory are pinned, then they stay on
  2394. // in the database till the user actually cleans then up.
  2395. // Need a good startegy to warn the user about it.
  2396. if (!IsFile(sFind32.dwFileAttributes))
  2397. {
  2398. // this is a directory
  2399. // update it's win32 data so that things like attributes get updated
  2400. // We get here only during fullsync operations
  2401. if(SetShadowInfo(hShadowDB, lpSI->hDir, lpSI->hShadow, &sFind32, ~(SHADOW_STALE), SHADOW_FLAGS_AND|SHADOW_FLAGS_CHANGE_83NAME))
  2402. {
  2403. fDone = TRUE;
  2404. }
  2405. }
  2406. }
  2407. }
  2408. bailout:
  2409. if (fDisabledShadowing)
  2410. {
  2411. int iEnable;
  2412. iEnable = EnableShadowingForThisThread(hShadowDB);
  2413. Assert(iEnable);
  2414. }
  2415. if (!fDone)
  2416. {
  2417. ReportLastError();
  2418. }
  2419. return (fDone);
  2420. }
  2421. DWORD
  2422. DWConnectNetEx(
  2423. _TCHAR * lpSharePath,
  2424. _TCHAR * lpOutDrive,
  2425. BOOL fInteractive
  2426. )
  2427. /*++
  2428. Routine Description:
  2429. Arguments:
  2430. Returns:
  2431. Notes:
  2432. --*/
  2433. {
  2434. NETRESOURCE sNR;
  2435. DWORD dwError;
  2436. _TCHAR szErr[16], szNP[16];
  2437. if (lpOutDrive){
  2438. lpOutDrive[0]='E'; // Let use start searching from e:
  2439. lpOutDrive[1]=':';
  2440. lpOutDrive[2]=0;
  2441. }
  2442. do{
  2443. memset(&sNR, 0, sizeof(NETRESOURCE));
  2444. sNR.lpRemoteName = lpSharePath;
  2445. if (lpOutDrive){
  2446. if(lpOutDrive[0]=='Z') {
  2447. break;
  2448. }
  2449. sNR.lpLocalName = lpOutDrive;
  2450. }
  2451. sNR.dwType = RESOURCETYPE_DISK;
  2452. dwError = WNetAddConnection3(vhwndMain, &sNR, NULL, NULL, 0);
  2453. if (dwError==WN_SUCCESS){
  2454. break;
  2455. }
  2456. else if (lpOutDrive &&
  2457. ((dwError == WN_BAD_LOCALNAME)||
  2458. (dwError == WN_ALREADY_CONNECTED))){
  2459. ++lpOutDrive[0];
  2460. continue;
  2461. }
  2462. else{
  2463. if (dwError==WN_EXTENDED_ERROR){
  2464. WNetGetLastError(&dwError, szErr, sizeof(szErr), szNP, sizeof(szNP));
  2465. }
  2466. break;
  2467. }
  2468. }
  2469. while (TRUE);
  2470. if ((dwError == ERROR_SUCCESS) && !IsShareReallyConnected((LPCTSTR)lpSharePath))
  2471. {
  2472. WNetCancelConnection2((lpOutDrive)?lpOutDrive:lpSharePath, 0, FALSE);
  2473. SetLastError(dwError = ERROR_REM_NOT_LIST);
  2474. }
  2475. return (dwError);
  2476. }
  2477. /************************** Skip queue related operations *******************/
  2478. #ifdef DEBUG
  2479. VOID
  2480. EnterSkipQueue(
  2481. HSHARE hShare,
  2482. HSHADOW hDir,
  2483. HSHADOW hShadow,
  2484. _TCHAR * lpPath
  2485. )
  2486. #else
  2487. VOID
  2488. EnterSkipQueue(
  2489. HSHARE hShare,
  2490. HSHADOW hDir,
  2491. HSHADOW hShadow
  2492. )
  2493. #endif //DEBUG
  2494. /*++
  2495. Routine Description:
  2496. Arguments:
  2497. Returns:
  2498. Notes:
  2499. --*/
  2500. {
  2501. LPFAILINFO lpFI = NULL;
  2502. LPFAILINFO FAR * lplpFI;
  2503. if (!EnterAgentCrit()){
  2504. return;
  2505. }
  2506. if(lplpFI = LplpFindFailInfo(hShare, hDir, hShadow)){
  2507. lpFI = *lplpFI;
  2508. }
  2509. if (!lpFI){
  2510. if (lpFI = (LPFAILINFO)AllocMem(sizeof(FAILINFO))){
  2511. lpFI->hShare = hShare;
  2512. lpFI->hDir = hDir;
  2513. lpFI->hShadow = hShadow;
  2514. #ifdef DEBUG
  2515. lstrcpyn(lpFI->rgchPath, lpPath, MAX_SERVER_SHARE_NAME_FOR_CSC);
  2516. #endif //DEBUG
  2517. lpFI->cntFail = 1;
  2518. lpFI->cntMaxFail = (hShadow)?MAX_ATTEMPTS_SHADOW:MAX_ATTEMPTS_SHARE;
  2519. lpFI->lpnextFI = lpheadFI;
  2520. lpheadFI = lpFI;
  2521. }
  2522. }
  2523. if (lpFI){
  2524. if (lpFI->cntFail >= lpFI->cntMaxFail){
  2525. lpFI->dwFailTime = GetTickCount();
  2526. ReintKdPrint(SKIPQUEUE, ("EnterSkipQueue: Marking %ls for Skipping \r\n", lpPath));
  2527. } else{
  2528. // Increment the fail count
  2529. lpFI->cntFail++;
  2530. ReintKdPrint(SKIPQUEUE, ("EnterSkipQueue: Incementing failcount for %ls \r\n", lpPath));
  2531. }
  2532. }
  2533. LeaveAgentCrit();
  2534. }
  2535. BOOL
  2536. PRIVATE
  2537. FSkipObject(
  2538. HSHARE hShare,
  2539. HSHADOW hDir,
  2540. HSHADOW hShadow
  2541. )
  2542. /*++
  2543. Routine Description:
  2544. Arguments:
  2545. Returns:
  2546. Notes:
  2547. --*/
  2548. {
  2549. LPFAILINFO FAR *lplpFI;
  2550. if (!EnterAgentCrit()){
  2551. return 0;
  2552. }
  2553. if (lplpFI = LplpFindFailInfo(hShare, hDir, hShadow)){
  2554. if ((*lplpFI)->cntFail >= (*lplpFI)->cntMaxFail) {
  2555. LeaveAgentCrit();
  2556. return TRUE;
  2557. }
  2558. }
  2559. LeaveAgentCrit();
  2560. return FALSE;
  2561. }
  2562. int
  2563. PRIVATE
  2564. PurgeSkipQueue(
  2565. BOOL fAll,
  2566. HSHARE hShare,
  2567. HSHADOW hDir,
  2568. HSHADOW hShadow
  2569. )
  2570. /*++
  2571. Routine Description:
  2572. Arguments:
  2573. Returns:
  2574. Notes:
  2575. --*/
  2576. {
  2577. LPFAILINFO FAR *lplpFI = NULL, lpfiTemp;
  2578. DWORD dwCurTime = GetTickCount();
  2579. int cntUnmark=0;
  2580. if (!EnterAgentCrit()){
  2581. return 0;
  2582. }
  2583. for (lplpFI = &lpheadFI; *lplpFI; lplpFI = &((*lplpFI)->lpnextFI)){
  2584. if (fAll ||
  2585. ((dwCurTime - (*lplpFI)->dwFailTime) > WAIT_INTERVAL_SKIP_MS)){
  2586. if ((!hShare || (hShare==(*lplpFI)->hShare))
  2587. && (!hDir || (hDir==(*lplpFI)->hDir))
  2588. && (!hShadow || (hShadow==(*lplpFI)->hShadow)))
  2589. {
  2590. ReintKdPrint(SKIPQUEUE, ("PurgeSkipQueue: Purging Skip Queue Entry for %s \r\n"
  2591. ,(*lplpFI)->rgchPath));
  2592. lpfiTemp = *lplpFI;
  2593. *lplpFI = lpfiTemp->lpnextFI;
  2594. FreeMem(lpfiTemp);
  2595. ++cntUnmark;
  2596. if (!*lplpFI){
  2597. break;
  2598. }
  2599. }
  2600. }
  2601. }
  2602. LeaveAgentCrit();
  2603. return (cntUnmark);
  2604. }
  2605. LPFAILINFO FAR *
  2606. LplpFindFailInfo(
  2607. HSHARE hShare,
  2608. HSHADOW hDir,
  2609. HSHADOW hShadow
  2610. )
  2611. /*++
  2612. Routine Description:
  2613. Arguments:
  2614. Returns:
  2615. Notes:
  2616. --*/
  2617. {
  2618. LPFAILINFO FAR *lplpFI = NULL;
  2619. // look for the inode or the server entry
  2620. for (lplpFI = &lpheadFI; *lplpFI; lplpFI = &((*lplpFI)->lpnextFI)) {
  2621. if ((hShadow && (hShadow == (*lplpFI)->hShadow)) ||
  2622. (hShare && ((*lplpFI)->hShare == hShare))){
  2623. return (lplpFI);
  2624. }
  2625. }
  2626. return (NULL);
  2627. }
  2628. VOID
  2629. ReportLastError(
  2630. VOID
  2631. )
  2632. /*++
  2633. Routine Description:
  2634. Arguments:
  2635. Returns:
  2636. Notes:
  2637. --*/
  2638. {
  2639. DWORD dwError;
  2640. dwError = GetLastError();
  2641. ReintKdPrint(FILL, ("Error # %ld \r\n", dwError));
  2642. }
  2643. VOID
  2644. PRIVATE
  2645. ReportStats(
  2646. VOID
  2647. )
  2648. /*++
  2649. Routine Description:
  2650. Arguments:
  2651. Returns:
  2652. Notes:
  2653. --*/
  2654. {
  2655. ReintKdPrint(BADERRORS, ("dirty=%d stale=%d sparse=%d \r\n"
  2656. , vcntDirty
  2657. , vcntStale
  2658. , vcntSparse));
  2659. }
  2660. VOID
  2661. PRIVATE
  2662. CopyPQInfoToShadowInfo(
  2663. LPPQPARAMS lpPQ,
  2664. LPSHADOWINFO lpShadowInfo
  2665. )
  2666. /*++
  2667. Routine Description:
  2668. Arguments:
  2669. Returns:
  2670. Notes:
  2671. --*/
  2672. {
  2673. lpShadowInfo->hShare = lpPQ->hShare;
  2674. lpShadowInfo->hDir = lpPQ->hDir;
  2675. lpShadowInfo->hShadow = lpPQ->hShadow;
  2676. lpShadowInfo->uStatus = lpPQ->ulStatus; //Sic
  2677. }
  2678. int
  2679. PUBLIC
  2680. EnterAgentCrit(
  2681. VOID
  2682. )
  2683. /*++
  2684. Routine Description:
  2685. Arguments:
  2686. Returns:
  2687. Notes:
  2688. --*/
  2689. {
  2690. if (!vhMutex){
  2691. return 0;
  2692. }
  2693. WaitForSingleObject(vhMutex, INFINITE);
  2694. return 1;
  2695. }
  2696. VOID
  2697. PUBLIC
  2698. LeaveAgentCrit(
  2699. VOID
  2700. )
  2701. /*++
  2702. Routine Description:
  2703. Arguments:
  2704. Returns:
  2705. Notes:
  2706. --*/
  2707. {
  2708. ReleaseMutex(vhMutex);
  2709. }
  2710. BOOL
  2711. FGetConnectionList(
  2712. LPCONNECTINFO *lplpHead,
  2713. int *lpcntDiscon
  2714. )
  2715. /*++
  2716. Routine Description:
  2717. Arguments:
  2718. Returns:
  2719. Notes:
  2720. --*/
  2721. {
  2722. return (FGetConnectionListEx(lplpHead, NULL, FALSE, FALSE, lpcntDiscon));
  2723. }
  2724. BOOL
  2725. FGetConnectionListEx(
  2726. LPCONNECTINFO *lplpHead,
  2727. LPCTSTR lptzShareName,
  2728. BOOL fAllSharesOnServer,
  2729. BOOL fServerIsOffline,
  2730. int *lpcntDiscon
  2731. )
  2732. /*++
  2733. Routine Description:
  2734. This routine makes a list of shares that are connected and are in disconnected state.
  2735. If lptzShareName is not NULL it returns all the mapping of that share that are
  2736. in disconnected state.
  2737. This is the first of a trilogy of routines used while doing a merge. The other two are
  2738. DisconnectList and ReconnectList.
  2739. Arguments:
  2740. lplpHead head of the list is created here.
  2741. lptzShareName list of connections for this share, if NULL, list of all connected shares
  2742. lpcntDiscon # of shares in the list. Can be NULL.
  2743. Returns:
  2744. TRUE if there are some entries in the connection list
  2745. Notes:
  2746. List is allocated using LocalAlloc. It is upto the caller to free it.
  2747. --*/
  2748. {
  2749. HANDLE hEnum;
  2750. DWORD cbNum, cbSize, dwError, dwDummy, len=0;
  2751. LPCONNECTINFO lpCI;
  2752. WIN32_FIND_DATA sFind32;
  2753. ReintKdPrint(MERGE, ("Getting conection list\r\n"));
  2754. try
  2755. {
  2756. if (lpcntDiscon){
  2757. *lpcntDiscon = 0;
  2758. }
  2759. *lplpHead = NULL;
  2760. if (lptzShareName)
  2761. {
  2762. len = lstrlen(lptzShareName);
  2763. if (fAllSharesOnServer)
  2764. {
  2765. _TCHAR *lpT, chT;
  2766. len = 2;
  2767. for (lpT = (LPTSTR)lptzShareName+2;;)
  2768. {
  2769. chT = *lpT++;
  2770. Assert(chT);
  2771. if (chT == (_TCHAR)'\\')
  2772. {
  2773. break;
  2774. }
  2775. ++len;
  2776. }
  2777. ReintKdPrint(MERGE, ("Nuking shares %ls len %d \n", (LPTSTR)lptzShareName, len));
  2778. }
  2779. }
  2780. // enumerate all connected shares
  2781. if (WNetOpenEnum( RESOURCE_CONNECTED,
  2782. RESOURCETYPE_DISK, RESOURCEUSAGE_CONNECTABLE,
  2783. NULL, &hEnum) == NO_ERROR ){
  2784. do{
  2785. cbNum = 1;
  2786. cbSize = sizeof(dwDummy);
  2787. dwError = WNetEnumResource(hEnum, &cbNum, &dwDummy, &cbSize);
  2788. if (dwError==ERROR_MORE_DATA){
  2789. if (lpCI =
  2790. (LPCONNECTINFO)AllocMem(sizeof(CONNECTINFO)+cbSize)){
  2791. cbNum = 1;
  2792. dwError = WNetEnumResource(hEnum, &cbNum
  2793. , &(lpCI->rgFill[0])
  2794. , &cbSize);
  2795. if (!cbNum || (dwError!=NO_ERROR)){
  2796. FreeMem(lpCI);
  2797. break;
  2798. }
  2799. if(lptzShareName)
  2800. {
  2801. // do case insensitive prefix matching and ensure that
  2802. // the next character after the match is a path delimiter
  2803. if (!((CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
  2804. lptzShareName, len,
  2805. ((NETRESOURCE *)&(lpCI->rgFill[0]))->lpRemoteName,len)
  2806. == CSTR_EQUAL)&&
  2807. ((((NETRESOURCE *)&(lpCI->rgFill[0]))->lpRemoteName[len] == (_TCHAR)'\\')||
  2808. (((NETRESOURCE *)&(lpCI->rgFill[0]))->lpRemoteName[len] == (_TCHAR)0))))
  2809. {
  2810. FreeMem(lpCI);
  2811. continue;
  2812. }
  2813. ReintKdPrint(MERGE, ("Got %ls on %ls\r\n"
  2814. , (((NETRESOURCE *)&(lpCI->rgFill[0]))->lpLocalName)?((NETRESOURCE *)&(lpCI->rgFill[0]))->lpLocalName:L"Empty"
  2815. , ((NETRESOURCE *)&(lpCI->rgFill[0]))->lpRemoteName));
  2816. }
  2817. lpCI->lpnextCI = *lplpHead;
  2818. *lplpHead = lpCI;
  2819. if (!fServerIsOffline)
  2820. {
  2821. BOOL fRet;
  2822. SHADOWINFO sSI;
  2823. fRet = FindCreateShadowFromPath(((NETRESOURCE *)&(lpCI->rgFill[0]))->lpRemoteName,
  2824. FALSE, // Don't create, just look
  2825. &sFind32,
  2826. &sSI,
  2827. NULL
  2828. );
  2829. lpCI->uStatus = 0;
  2830. if (fRet && sSI.hShadow)
  2831. {
  2832. lpCI->uStatus = sSI.uStatus;
  2833. }
  2834. }
  2835. else
  2836. {
  2837. lpCI->uStatus |= SHARE_DISCONNECTED_OP;
  2838. }
  2839. if (lpcntDiscon && (lpCI->uStatus & SHARE_DISCONNECTED_OP)){
  2840. ++*lpcntDiscon;
  2841. }
  2842. }
  2843. else{
  2844. //PANIC
  2845. break;
  2846. }
  2847. }
  2848. else{
  2849. break;
  2850. }
  2851. }while (TRUE);
  2852. WNetCloseEnum(hEnum);
  2853. }
  2854. }
  2855. except(EXCEPTION_EXECUTE_HANDLER)
  2856. {
  2857. ReintKdPrint(BADERRORS, ("Took exception in FGetConnectionListEx list \n"));
  2858. }
  2859. return (*lplpHead != NULL);
  2860. }
  2861. int
  2862. DisconnectList(
  2863. LPCONNECTINFO *lplpHead,
  2864. LPFNREFRESHPROC lpfn,
  2865. DWORD dwCookie
  2866. )
  2867. /*++
  2868. Routine Description:
  2869. disconnects all drive mapped shares in a list accumulated using FGetConnectionList
  2870. Arguments:
  2871. Returns:
  2872. Notes:
  2873. --*/
  2874. {
  2875. BOOL fOk = TRUE;
  2876. DWORD dwError;
  2877. int icntDriveMapped=0;
  2878. LPCONNECTINFO lpTmp = *lplpHead;
  2879. ReintKdPrint(MERGE, ("In DisconnectList \n"));
  2880. try
  2881. {
  2882. for (;lpTmp;lpTmp = lpTmp->lpnextCI){
  2883. if (!(lpTmp->uStatus & SHARE_DISCONNECTED_OP))
  2884. {
  2885. continue;
  2886. }
  2887. if (((NETRESOURCE *)&(lpTmp->rgFill[0]))->lpLocalName){
  2888. ++icntDriveMapped;
  2889. ReintKdPrint(MERGE, ("Nuking %ls on %ls\r\n"
  2890. , ((NETRESOURCE *)&(lpTmp->rgFill[0]))->lpLocalName
  2891. , ((NETRESOURCE *)&(lpTmp->rgFill[0]))->lpRemoteName));
  2892. dwError = WNetCancelConnection2( ((NETRESOURCE *)&(lpTmp->rgFill[0]))->lpLocalName, 0, TRUE);
  2893. }
  2894. else{
  2895. ReintKdPrint(MERGE, ("Nuking %ls \r\n" , ((NETRESOURCE *)&(lpTmp->rgFill[0]))->lpRemoteName));
  2896. dwError = WNetCancelConnection2(
  2897. ((NETRESOURCE *)&(lpTmp->rgFill[0]))->lpRemoteName
  2898. , 0
  2899. , TRUE);
  2900. }
  2901. if (dwError != NO_ERROR){
  2902. ReintKdPrint(BADERRORS, ("Error=%ld \r\n", dwError));
  2903. fOk = FALSE;
  2904. }
  2905. }
  2906. }
  2907. except(EXCEPTION_EXECUTE_HANDLER)
  2908. {
  2909. ReintKdPrint(BADERRORS, ("Took exception in Disconnecte list \n"));
  2910. fOk = FALSE;
  2911. }
  2912. ReintKdPrint(MERGE, ("Out DisconnectList %x\n", (fOk?icntDriveMapped:-1)));
  2913. return (fOk?icntDriveMapped:-1);
  2914. }
  2915. int
  2916. CALLBACK
  2917. RefreshProc(
  2918. LPCONNECTINFO lpCI,
  2919. DWORD dwCookie // LOWORD 0==Silently, 1== Give messages
  2920. // HIWORD 0==Nuke UNC, 1==Nuke all if no ongoing open/finds
  2921. // 2==Maximum force for shadow 3==Nuke ALL
  2922. )
  2923. /*++
  2924. Routine Description:
  2925. Arguments:
  2926. Returns:
  2927. Notes:
  2928. --*/
  2929. {
  2930. WORD wVerbose = LOWORD(dwCookie), wForce = HIWORD(dwCookie);
  2931. int iRet = 0;
  2932. BOOL fDisconnectedOp=FALSE, fOpensFinds = FALSE;
  2933. fDisconnectedOp = (lpCI->uStatus & SHARE_DISCONNECTED_OP);
  2934. fOpensFinds = (lpCI->uStatus & (SHARE_FILES_OPEN|SHARE_FINDS_IN_PROGRESS));
  2935. switch (wForce){
  2936. case 0://shadow UNC connections with no opens/finds in progress
  2937. iRet = (fDisconnectedOp && !fOpensFinds && !((NETRESOURCE *)&(lpCI->rgFill[0]))->lpLocalName)?1:0;
  2938. break;
  2939. case 1://shadow connections (UNC+drivemapped) with no opens/finds in progress
  2940. iRet = (fDisconnectedOp && !fOpensFinds)?1:0;
  2941. break;
  2942. case 2://shadow connections with or without opens/finds
  2943. iRet = (fDisconnectedOp)?1:0;
  2944. break;
  2945. case 3://all connections
  2946. iRet = 1;
  2947. break;
  2948. }
  2949. if ((iRet==1) && wVerbose && fOpensFinds){
  2950. LoadString(vhinstCur, IDS_OPS_IN_PROGRESS, (LPTSTR)(vrgchBuff), 128 * sizeof(TCHAR));
  2951. LoadString(vhinstCur, IDS_SHADOW_AGENT, (LPTSTR)(vrgchBuff+128* sizeof(TCHAR)), 128* sizeof(TCHAR));
  2952. wsprintf((LPTSTR)(vrgchBuff+256), (LPTSTR)(vrgchBuff), ((NETRESOURCE *)&(lpCI->rgFill[0]))->lpRemoteName);
  2953. MessageBox(vhwndMain, (LPTSTR)(vrgchBuff+256* sizeof(TCHAR)), (LPTSTR)(vrgchBuff+128* sizeof(TCHAR)), MB_OK);
  2954. }
  2955. return (iRet);
  2956. }
  2957. //
  2958. // Reconnects a list of shares
  2959. // if you pass in a parent HWND then you will get UI
  2960. //
  2961. int
  2962. ReconnectList(
  2963. LPCONNECTINFO *lplpHead,
  2964. HWND hwndParent
  2965. )
  2966. /*++
  2967. Routine Description:
  2968. reconnects all the connections in disconnected state.
  2969. Arguments:
  2970. Returns:
  2971. Notes:
  2972. --*/
  2973. {
  2974. int iDone = 0;
  2975. DWORD dwError;
  2976. LPCONNECTINFO lpTmp = *lplpHead;
  2977. _TCHAR * lpSave;
  2978. HWND hwndUI=NULL;
  2979. try
  2980. {
  2981. for (;lpTmp;lpTmp = lpTmp->lpnextCI){
  2982. if (!(lpTmp->uStatus & SHARE_DISCONNECTED_OP))
  2983. {
  2984. continue;
  2985. }
  2986. if (((NETRESOURCE *)&(lpTmp->rgFill[0]))->lpLocalName){
  2987. ReintKdPrint(MERGE, ("Adding back %ls on %ls\r\n"
  2988. , ((NETRESOURCE *)&(lpTmp->rgFill[0]))->lpLocalName
  2989. , ((NETRESOURCE *)&(lpTmp->rgFill[0]))->lpRemoteName));
  2990. }
  2991. else{
  2992. ReintKdPrint(MERGE, ((LPSTR)vrgchBuff, "Adding back %ls\r\n" , ((NETRESOURCE *)&(lpTmp->rgFill[0]))->lpRemoteName));
  2993. }
  2994. lpSave = ((NETRESOURCE *)&(lpTmp->rgFill[0]))->lpProvider;
  2995. ((NETRESOURCE *)&(lpTmp->rgFill[0]))->lpProvider = NULL;
  2996. dwError = WNetAddConnection3(vhwndMain, (NETRESOURCE *)&(lpTmp->rgFill[0]), NULL, NULL, CONNECT_INTERACTIVE);
  2997. ((NETRESOURCE *)&(lpTmp->rgFill[0]))->lpProvider = lpSave;
  2998. if (dwError!=NO_ERROR){
  2999. ReintKdPrint(BADERRORS, ("Error=%ld \r\n", dwError));
  3000. iDone = -1;
  3001. }
  3002. else if (iDone >= 0){
  3003. ++iDone;
  3004. }
  3005. }
  3006. if( hwndUI ){
  3007. DestroyWindow(hwndUI);
  3008. }
  3009. }
  3010. except(EXCEPTION_EXECUTE_HANDLER)
  3011. {
  3012. ReintKdPrint(BADERRORS, ("Took exception in Reconnect list \n"));
  3013. iDone = 0;
  3014. }
  3015. return (iDone);
  3016. }
  3017. VOID
  3018. ClearConnectionList(
  3019. LPCONNECTINFO *lplpHead
  3020. )
  3021. /*++
  3022. Routine Description:
  3023. Arguments:
  3024. Returns:
  3025. Notes:
  3026. --*/
  3027. {
  3028. LPCONNECTINFO lpTmp = *lplpHead, lpSave;
  3029. for (;lpTmp;){
  3030. lpSave = lpTmp->lpnextCI;
  3031. FreeMem(lpTmp);
  3032. lpTmp = lpSave;
  3033. }
  3034. *lplpHead = NULL;
  3035. }
  3036. BOOL
  3037. PRIVATE
  3038. IsSlowLink(
  3039. _TCHAR * lpPath
  3040. )
  3041. /*++
  3042. Routine Description:
  3043. Arguments:
  3044. Returns:
  3045. Notes:
  3046. --*/
  3047. {
  3048. NETRESOURCE sNR;
  3049. NETCONNECTINFOSTRUCT sNCINFO;
  3050. int done = 0;
  3051. BOOL fRet = FALSE;
  3052. memset(&sNCINFO, 0, sizeof(NETCONNECTINFOSTRUCT));
  3053. sNCINFO.cbStructure = sizeof(NETCONNECTINFOSTRUCT);
  3054. memset(&sNR, 0, sizeof(NETRESOURCE));
  3055. sNR.lpRemoteName=lpPath;
  3056. if ((MultinetGetConnectionPerformance(&sNR, &sNCINFO)==WN_SUCCESS)
  3057. && (sNCINFO.dwSpeed < SLOWLINK_SPEED)){
  3058. fRet = TRUE;
  3059. }
  3060. return (fRet);
  3061. }
  3062. int RefreshConnectionsInternal(
  3063. int force,
  3064. BOOL verbose
  3065. )
  3066. {
  3067. return (RefreshConnectionsEx(force, verbose, NULL, 0));
  3068. }
  3069. int
  3070. BreakConnectionsInternal(
  3071. int force,
  3072. BOOL verbose
  3073. )
  3074. /*++
  3075. Routine Description:
  3076. Arguments:
  3077. Returns:
  3078. Notes:
  3079. --*/
  3080. {
  3081. LPCONNECTINFO lpHead = NULL;
  3082. if (FGetConnectionList(&lpHead, NULL)){
  3083. DisconnectList(&lpHead, RefreshProc, MAKELONG(verbose,force));
  3084. ClearConnectionList(&lpHead);
  3085. return (1);
  3086. }
  3087. return (0);
  3088. }
  3089. //
  3090. // This refreshes all the connections.
  3091. // Force -
  3092. // Verbose - causes annoying UI to be displayed
  3093. // lpfn -
  3094. // dwCookie - parameter for lpfn
  3095. //
  3096. int RefreshConnectionsEx(
  3097. int force,
  3098. BOOL verbose,
  3099. LPFNREFRESHEXPROC lpfn,
  3100. DWORD dwCookie)
  3101. {
  3102. int cntDriveMapped, iRet = -1;
  3103. LPCONNECTINFO lpHead = NULL;
  3104. if (FGetConnectionList(&lpHead, NULL)){
  3105. cntDriveMapped = DisconnectList(&lpHead, RefreshProc, MAKELONG(verbose,force));
  3106. if (cntDriveMapped < 0){
  3107. goto bailout;
  3108. }
  3109. if (lpfn){
  3110. (*lpfn)(cntDriveMapped, dwCookie);
  3111. }
  3112. if (cntDriveMapped > 0){
  3113. ReconnectList(&lpHead,verbose?vhwndMain:NULL);
  3114. }
  3115. ClearConnectionList(&lpHead);
  3116. iRet = 1;
  3117. }
  3118. else
  3119. {
  3120. iRet = 0;
  3121. }
  3122. bailout:
  3123. return iRet;
  3124. }
  3125. BOOL
  3126. FCheckAncestor(
  3127. node *lpnodeList,
  3128. LPCOPYPARAMS lpCP
  3129. )
  3130. {
  3131. node *lpItem;
  3132. BOOL fHaveAncestor = FALSE;
  3133. unsigned lenDest;
  3134. #ifdef DEBUG
  3135. unsigned lenSrc;
  3136. #endif
  3137. #ifdef DEBUG
  3138. lenSrc = lstrlen(lpCP->lpRemotePath);
  3139. #endif
  3140. for(lpItem = lpnodeList; lpItem; lpItem = lpItem->next)
  3141. {
  3142. // is it on the same share?
  3143. if (!lstrcmpi(lpItem->lpCP->lpSharePath, lpCP->lpSharePath))
  3144. {
  3145. // check upto the length of the ancestor. By definition he is supposed to be smaller
  3146. // than the src
  3147. lenDest = lstrlen(lpItem->lpCP->lpRemotePath);
  3148. Assert(lenDest <= lenSrc);
  3149. // NB, we do memcmp because, the strings will have the same case
  3150. // as they are obtained from the same source, ie, the CSC database.
  3151. // is it a child of any item in the list?
  3152. if (!memcmp(lpItem->lpCP->lpRemotePath, lpCP->lpRemotePath, lenDest * sizeof(_TCHAR)))
  3153. {
  3154. fHaveAncestor = TRUE;
  3155. break;
  3156. }
  3157. }
  3158. }
  3159. return (fHaveAncestor);
  3160. }
  3161. DWORD
  3162. PRIVATE
  3163. GetUniqueName(
  3164. _TCHAR * lpName,
  3165. _TCHAR * lpUniqueName
  3166. )
  3167. /*++
  3168. Routine Description:
  3169. Arguments:
  3170. Returns:
  3171. Notes:
  3172. --*/
  3173. {
  3174. int i=0, orglen;
  3175. DWORD dwError;
  3176. _TCHAR buff[10 * sizeof(_TCHAR)];
  3177. lstrcpy(lpUniqueName, lpName);
  3178. orglen = lstrlen(lpName);
  3179. if (orglen >= MAX_PATH-1){
  3180. lpUniqueName[MAX_PATH-5] = 0;
  3181. orglen = MAX_PATH-5;
  3182. }
  3183. for (i=0; i<100; ++i){
  3184. if (GetFileAttributes(lpUniqueName)==0xffffffff){
  3185. dwError = GetLastError();
  3186. if ((dwError==ERROR_FILE_NOT_FOUND)||
  3187. (dwError == ERROR_PATH_NOT_FOUND)){
  3188. break;
  3189. }
  3190. }
  3191. lpUniqueName[orglen] = 0;
  3192. wsprintf(buff, _TEXT("(%2d)"), i);
  3193. lstrcat(lpUniqueName, (LPTSTR)buff);
  3194. }
  3195. if (i < 100){
  3196. dwError = NO_ERROR;
  3197. }
  3198. else{
  3199. dwError = 0xffffffff;
  3200. }
  3201. return(dwError);
  3202. }
  3203. #ifdef MAYBE_USEFUL
  3204. /***************************************************************************
  3205. * reintegrate one server.
  3206. */
  3207. //
  3208. // Pass in the Share to merge on
  3209. // and the parent window.
  3210. //
  3211. BOOL
  3212. PUBLIC
  3213. ReintOneShare(
  3214. HSHARE hShare,
  3215. HWND hwndParent
  3216. )
  3217. /*++
  3218. Routine Description:
  3219. Arguments:
  3220. Returns:
  3221. Notes:
  3222. --*/
  3223. {
  3224. node *lpnodeInsertList=NULL; // merge file list.
  3225. PQPARAMS sPQP;
  3226. int state, iFileStatus, iShadowStatus;
  3227. BOOL fConnected=FALSE, fBeginReint=FALSE, fDone = FALSE;
  3228. BOOL fStamped = FALSE, fInsertInList = FALSE;
  3229. SHADOWINFO sSI;
  3230. LPCOPYPARAMS lpCP = NULL;
  3231. _TCHAR szDrive[3];
  3232. unsigned long ulStatus, uAction;
  3233. DWORD dwError;
  3234. WIN32_FIND_DATA sFind32Local, sFind32Remote;
  3235. WIN32_FIND_DATA *lpFind32Remote = NULL; // temporary variable
  3236. HANDLE hShadowDB;
  3237. BOOL fAmAgent=FALSE;
  3238. if ((hShadowDB = OpenShadowDatabaseIO()) ==INVALID_HANDLE_VALUE)
  3239. {
  3240. return FALSE;
  3241. }
  3242. fAmAgent = (GetCurrentThreadId() == vdwCopyChunkThreadId);
  3243. lpCP = LpAllocCopyParams();
  3244. if (!lpCP){
  3245. ReintKdPrint(BADERRORS, ("ReintOneShare():Allocation of copyparam buffer failed \r\n"));
  3246. goto bailout;
  3247. }
  3248. // Reint in multiple passes. Do directories first, files next
  3249. for (state=STATE_REINT_BEGIN;state<STATE_REINT_END;++state) {
  3250. if (FAbortOperation())
  3251. {
  3252. goto bailout;
  3253. }
  3254. dwError = NO_ERROR;
  3255. memset(&sPQP, 0, sizeof(PQPARAMS));
  3256. memset(&sSI, 0, sizeof(SHADOWINFO));
  3257. // Start looking through the queue
  3258. if(BeginPQEnum(hShadowDB, &sPQP) == 0) {
  3259. goto bailout;
  3260. }
  3261. // Start looking through the queue
  3262. do {
  3263. if (FAbortOperation())
  3264. {
  3265. goto bailout;
  3266. }
  3267. if(PrevPriShadow(hShadowDB, &sPQP) == 0){
  3268. break;
  3269. }
  3270. // end of this enumeration
  3271. if (!sPQP.hShadow){
  3272. break;
  3273. }
  3274. if ( mShadowOrphan(sPQP.ulStatus)||
  3275. mShadowSuspect(sPQP.ulStatus))
  3276. {
  3277. continue;
  3278. }
  3279. // keep going if this is a file and we are trying to reintegrate directories
  3280. // or if this entry isn't from the server we are dealing with.
  3281. if ((sPQP.hShare != hShare) ||
  3282. ((state != STATE_REINT_FILES) && mShadowIsFile(sPQP.ulStatus)) ||
  3283. ((state == STATE_REINT_FILES) && !mShadowIsFile(sPQP.ulStatus))){
  3284. continue;
  3285. }
  3286. if (mShadowNeedReint(sPQP.ulStatus)){
  3287. if (!fStamped){
  3288. StampReintLog();
  3289. fStamped = TRUE;
  3290. }
  3291. if (fAmAgent && FSkipObject(sPQP.hShare, 0, 0)){
  3292. continue;
  3293. }
  3294. if (!GetShadowInfo(hShadowDB, sPQP.hDir, sPQP.hShadow,
  3295. &sFind32Local, &ulStatus)){
  3296. ReintKdPrint(BADERRORS, ("ReintOneShare: GetShadowInfo failed\n"));
  3297. continue;
  3298. }
  3299. CopyPQInfoToShadowInfo(&sPQP, &sSI);
  3300. sSI.lpFind32 = &sFind32Local;
  3301. if(!GetUNCPath(hShadowDB, sPQP.hShare, sPQP.hDir, sPQP.hShadow, lpCP)){
  3302. ReintKdPrint(BADERRORS, ("ReintOneShare: GetUNCPath failed\n"));
  3303. continue;
  3304. }
  3305. if (!fConnected){
  3306. DWORD dwError2;
  3307. dwError2 = DWConnectNetEx(lpCP->lpSharePath, szDrive, TRUE);
  3308. if(dwError2 == WN_SUCCESS || dwError2 == WN_CONNECTED_OTHER_PASSWORD_DEFAULT)
  3309. {
  3310. fConnected = TRUE;
  3311. if (!BeginReint(hShadowDB, hShare)) {
  3312. goto bailout;
  3313. }
  3314. fBeginReint = TRUE;
  3315. }
  3316. else{
  3317. #ifdef DEBUG
  3318. EnterSkipQueue(sPQP.hShare, 0, 0, lpCP->lpSharePath);
  3319. #else
  3320. EnterSkipQueue(sPQP.hShare, 0, 0);
  3321. #endif //DEBUG
  3322. // try some other server for reintegration
  3323. goto bailout;
  3324. }
  3325. }
  3326. ReintKdPrint(BADERRORS, ("Merging local changes to <%s%s>\n", lpCP->lpSharePath, lpCP->lpRemotePath));
  3327. Assert((sPQP.hShare == hShare) && // this is the given server
  3328. (
  3329. ((state != STATE_REINT_FILES) && !mShadowIsFile(sPQP.ulStatus)) ||
  3330. ((state == STATE_REINT_FILES) && mShadowIsFile(sPQP.ulStatus))
  3331. )
  3332. );
  3333. fInsertInList = FALSE;
  3334. lpFind32Remote = NULL;
  3335. // if there is an insertion list, then check whether his ancestor
  3336. // didn't fail in reintegration
  3337. if (lpnodeInsertList)
  3338. {
  3339. // if there is an acestor then we should put this guy in the list
  3340. fInsertInList = FCheckAncestor(lpnodeInsertList, lpCP);
  3341. }
  3342. // if we are not supposed to put him in the list then try getting
  3343. // his win32 strucuture
  3344. if (!fInsertInList)
  3345. {
  3346. BOOL fExists;
  3347. GetRemoteWin32Info(NULL, lpCP, &sFind32Remote, &fExists);
  3348. // insert in list only if some error happened
  3349. if (fExists == -1)
  3350. {
  3351. fInsertInList = TRUE;
  3352. }
  3353. // passing remote find32 only if it succeeded
  3354. if (fExists == TRUE)
  3355. {
  3356. lpFind32Remote = &sFind32Remote;
  3357. }
  3358. }
  3359. // find out what needs to be done
  3360. // this one central place to infer all the stuff
  3361. InferReplicaReintStatus(
  3362. &sSI, // shadowinfo
  3363. &sFind32Local, // win32 info for the shadow
  3364. lpFind32Remote, // remote win32 info
  3365. &iShadowStatus,
  3366. &iFileStatus,
  3367. &uAction
  3368. );
  3369. // insert if it had an ancestor in the list or some merge needed to be done
  3370. fInsertInList = (fInsertInList || (uAction == RAIA_MERGE) || (uAction==RAIA_CONFLICT));
  3371. if (!fInsertInList)
  3372. {
  3373. ReintKdPrint(BADERRORS, ("Silently doing <%s%s>\n", lpCP->lpSharePath, lpCP->lpRemotePath));
  3374. fInsertInList = (PerformOneReint(
  3375. hShadowDB,
  3376. szDrive,
  3377. lpCP,
  3378. &sSI,
  3379. &sFind32Local,
  3380. lpFind32Remote,
  3381. iShadowStatus,
  3382. iFileStatus,
  3383. uAction
  3384. ) == FALSE);
  3385. }
  3386. if (fInsertInList)
  3387. {
  3388. if(!insertList( &lpnodeInsertList,
  3389. lpCP,
  3390. &sSI,
  3391. &sFind32Local,
  3392. lpFind32Remote,
  3393. iShadowStatus,
  3394. iFileStatus,
  3395. uAction
  3396. ))
  3397. {
  3398. ReintKdPrint(BADERRORS, ("ReintOneShare: insertlist failed in memory allocation \r\n"));
  3399. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  3400. fDone = FALSE;
  3401. goto bailout;
  3402. }
  3403. ReintKdPrint(BADERRORS, ("Inserted <%s%s> in list\n", lpCP->lpSharePath, lpCP->lpRemotePath));
  3404. }
  3405. }
  3406. } while (sPQP.uPos); // Priority queue enumeration
  3407. // Close the enumeration
  3408. EndPQEnum(hShadowDB, &sPQP);
  3409. } // reint pass 1 & 2
  3410. if (fBeginReint){
  3411. // we found something to merge
  3412. if (lpnodeInsertList)
  3413. {
  3414. ReintKdPrint(BADERRORS, ("Found reint list, doing UI \n"));
  3415. fDone = DoFilesListReint(hShadowDB, szDrive, hwndParent, lpnodeInsertList); // 1 if successful, -1 if error, 0 if cancelled
  3416. }
  3417. else
  3418. {
  3419. // all went well
  3420. fDone = TRUE;
  3421. }
  3422. }
  3423. if (fConnected){
  3424. DWDisconnectDriveMappedNet(szDrive, TRUE); // force a disconnect
  3425. fConnected = FALSE;
  3426. }
  3427. if (fDone==TRUE) {
  3428. SetShareStatus(hShadowDB, hShare, (unsigned long)(~SHARE_REINT), SHADOW_FLAGS_AND);
  3429. }
  3430. bailout:
  3431. if (fBeginReint){
  3432. EndReint(hShadowDB, hShare);
  3433. fBeginReint = FALSE;
  3434. }
  3435. CloseShadowDatabaseIO(hShadowDB);
  3436. if(lpnodeInsertList) {
  3437. killList(lpnodeInsertList);
  3438. lpnodeInsertList = NULL; //general paranoia
  3439. }
  3440. FreeCopyParams(lpCP);
  3441. if (fConnected) {
  3442. WNetCancelConnection2(szDrive, 0, FALSE);
  3443. }
  3444. // Remove the tray notification about merging
  3445. if( CheckDirtyShares()==0 ) {
  3446. Tray_Modify(vhwndMain,0,NULL);
  3447. }
  3448. return fDone;
  3449. }
  3450. /****************************************************************************
  3451. * Query the registry to see if we should make log copies
  3452. */
  3453. VOID GetLogCopyStatus(VOID)
  3454. {
  3455. HKEY hKey;
  3456. DWORD dwSize = MAX_NAME_LEN;
  3457. _TCHAR szDoCopy[MAX_NAME_LEN];
  3458. // get the user name.
  3459. if(RegOpenKey(HKEY_LOCAL_MACHINE, vszShadowReg, &hKey) != ERROR_SUCCESS) {
  3460. ReintKdPrint(BADERRORS, ("GetLogCopyStatus: RegOpenKey failed\n"));
  3461. return;
  3462. }
  3463. if(RegQueryValueEx(hKey, vszDoLogCopy, NULL, NULL, szDoCopy, &dwSize) != ERROR_SUCCESS) {
  3464. RegCloseKey(hKey);
  3465. ReintKdPrint(BADERRORS, ("GetLogCopyStatus: RegQueryValueEx failed\n"));
  3466. return;
  3467. }
  3468. if(mystrnicmp(szDoCopy, MY_SZ_TRUE, strlen(szDoCopy)))
  3469. vfLogCopying = FALSE;
  3470. else
  3471. vfLogCopying = TRUE;
  3472. RegCloseKey(hKey);
  3473. }
  3474. /****************************************************************************
  3475. * Make a connection to the logging server and copy the log over.
  3476. */
  3477. VOID CopyLogToShare(VOID)
  3478. {
  3479. HKEY hKeyShadow;
  3480. DWORD dwSize = MAX_NAME_LEN, dwRes;
  3481. _TCHAR szComputerName[MAX_NAME_LEN];
  3482. _TCHAR szLogDirPath[MAX_PATH], szLogPath[MAX_PATH];
  3483. WIN32_FIND_DATAA sFind32;
  3484. int iCurrFile=0;
  3485. NETRESOURCE sNR;
  3486. HANDLE hLog;
  3487. // check to see if we should copy the log over.
  3488. if(!vfLogCopying) {
  3489. return;
  3490. }
  3491. // get the user name.
  3492. if(RegOpenKey(HKEY_LOCAL_MACHINE, vszMachineName, &hKeyShadow) != ERROR_SUCCESS) {
  3493. ReintKdPrint(BADERRORS, ("RegOpenKey failed\n"));
  3494. }
  3495. if(RegQueryValueEx(hKeyShadow, vszComputerName, NULL, NULL, szComputerName, &dwSize) != ERROR_SUCCESS) {
  3496. RegCloseKey(hKeyShadow);
  3497. ReintKdPrint(BADERRORS, ("RegQueryValueEx failed\n"));
  3498. return;
  3499. }
  3500. RegCloseKey(hKeyShadow);
  3501. lstrcpy(szLogDirPath, vszLogUNCPath);
  3502. lstrcat(szLogDirPath, szComputerName);
  3503. sNR.lpRemoteName = vszLogShare;
  3504. sNR.lpLocalName = NULL;
  3505. sNR.lpProvider = NULL;
  3506. sNR.dwType = RESOURCETYPE_DISK;
  3507. dwRes = WNetAddConnection3(vhwndMain, &sNR, NULL, NULL, CONNECT_TEMPORARY);
  3508. if(dwRes != WN_SUCCESS) {
  3509. ReintKdPrint(BADERRORS, ("CopyLogToShare() AddConn3 failed (%d)\n", dwRes));
  3510. return;
  3511. }
  3512. // check to see if that dir lives on the server.
  3513. if(!GetWin32Info(szLogDirPath, &sFind32)) {
  3514. // if not, create it.
  3515. ReintKdPrint(BADERRORS, ("dir not found\n"));
  3516. if(!CreateDirectory(szLogDirPath, NULL)) {
  3517. ReintKdPrint(BADERRORS, ("Create dir failed, reason = %d\n", GetLastError()));
  3518. }
  3519. }
  3520. wsprintf(szLogPath, "%s\\status.log",szLogDirPath);
  3521. // copy file over.
  3522. ReintKdPrint(BADERRORS, ("we'll use <%s> next\n", szLogPath));
  3523. if((hLog = CreateFile(szLogPath
  3524. , GENERIC_READ|GENERIC_WRITE
  3525. , FILE_SHARE_READ|FILE_SHARE_WRITE
  3526. , NULL
  3527. , OPEN_ALWAYS
  3528. , 0
  3529. , NULL)) != INVALID_HANDLE_VALUE) {
  3530. ReintKdPrint(BADERRORS, ("file created\n"));
  3531. AppendToShareLog(hLog);
  3532. CloseHandle(hLog);
  3533. } else {
  3534. ReintKdPrint(BADERRORS, ("create failed, reason = %d\n", GetLastError()));
  3535. }
  3536. WNetCancelConnection2(vszLogShare, CONNECT_REFCOUNT, FALSE);
  3537. }
  3538. #define MAX_BUF_SIZE 1024
  3539. /****************************************************************************
  3540. * Copy the final stats from local log to the server version (hLog)
  3541. */
  3542. VOID AppendToShareLog(HANDLE hLog)
  3543. {
  3544. HANDLE hLocal=0;
  3545. DWORD dwBytesRead, dwBytesWritten, dwPos, x;
  3546. BOOL fDone=FALSE;
  3547. _TCHAR cBuffer[MAX_BUF_SIZE];
  3548. if((hLocal = CreateFile(vszLocalLogPath
  3549. , GENERIC_READ
  3550. , FILE_SHARE_READ
  3551. , NULL
  3552. , OPEN_EXISTING
  3553. , 0
  3554. , NULL)) != INVALID_HANDLE_VALUE) {
  3555. ReintKdPrint(BADERRORS, ("local log file opened (0x%x)\n", hLocal));
  3556. dwPos = SetFilePointer(hLog, 0, NULL, FILE_END);
  3557. if(dwPos == 0xFFFFFFFF) {
  3558. ReintKdPrint(BADERRORS, ("Failed seek on remote file, reason = %d\n", GetLastError()));
  3559. goto cleanup;
  3560. }
  3561. dwPos = SetFilePointer(hLocal, 0, NULL, FILE_END);
  3562. if(dwPos == 0xFFFFFFFF) {
  3563. ReintKdPrint(BADERRORS, ("Failed seek on local file, reason = %d\n", GetLastError()));
  3564. goto cleanup;
  3565. }
  3566. if((dwPos = SetFilePointer(hLocal, -MAX_BUF_SIZE, NULL, FILE_CURRENT)) == 0xFFFFFFFF)
  3567. goto cleanup;
  3568. // move backwards until we find the "!*" that I use as my start token.
  3569. while(!fDone) {
  3570. if(!ReadFile(hLocal, cBuffer, MAX_BUF_SIZE, &dwBytesRead, NULL) || !dwBytesRead) {
  3571. if(!dwBytesRead) {
  3572. ReintKdPrint(BADERRORS, ("local eof\n"));
  3573. } else {
  3574. ReintKdPrint(BADERRORS, ("R error: %d\n", GetLastError()));
  3575. }
  3576. goto cleanup;
  3577. }
  3578. for(x=0;x<dwBytesRead;x++) {
  3579. if(cBuffer[x] == '!' && cBuffer[x+1] == '*') {
  3580. fDone = TRUE;
  3581. dwPos += x;
  3582. break;
  3583. }
  3584. }
  3585. if(!fDone)
  3586. if((dwPos = SetFilePointer(hLocal, -2*MAX_BUF_SIZE, NULL, FILE_CURRENT)) == 0xFFFFFFFF) {
  3587. ReintKdPrint(BADERRORS, ("seeked all the way and failed, error=%d\n",GetLastError()));
  3588. goto cleanup;
  3589. }
  3590. }
  3591. // we have found the !*. Seek there and copy until end of file.
  3592. // tHACK. We should have a final delimiter (ie: *!)
  3593. if((dwPos = SetFilePointer(hLocal, dwPos, NULL, FILE_BEGIN)) == 0xFFFFFFFF)
  3594. goto cleanup;
  3595. for(;;) {
  3596. if(!ReadFile(hLocal, cBuffer, MAX_BUF_SIZE, &dwBytesRead, NULL)) {
  3597. ReintKdPrint(BADERRORS, ("R error: %d\n", GetLastError()));
  3598. break;
  3599. }
  3600. if(dwBytesRead == 0)
  3601. break;
  3602. if(!WriteFile(hLog, cBuffer, dwBytesRead, &dwBytesWritten, NULL)) {
  3603. ReintKdPrint(BADERRORS, ("W error: %d\n", GetLastError()));
  3604. break;
  3605. }
  3606. }
  3607. }
  3608. cleanup:
  3609. if(hLocal)
  3610. CloseHandle(hLocal);
  3611. if(!FlushFileBuffers(hLog)) {
  3612. ReintKdPrint(BADERRORS, ("FlushFileBuffers failed, reason = %d\n",GetLastError()));
  3613. }
  3614. }
  3615. DWORD
  3616. PRIVATE
  3617. MoveConflictingFile(
  3618. LPCOPYPARAMS lpCP
  3619. )
  3620. /*++
  3621. Routine Description:
  3622. Arguments:
  3623. Returns:
  3624. Notes:
  3625. --*/
  3626. {
  3627. DWORD dwError;
  3628. _TCHAR * lpLeaf;
  3629. lstrcpy(vrgchBuff, vszConflictDir);
  3630. lstrcat(vrgchBuff, vszSlash);
  3631. FormLocalNameFromRemoteName(vrgchBuff+strlen(vrgchBuff), lpCP->lpSharePath);
  3632. dwError = InbCreateDir(vrgchBuff, 0xffffffff);
  3633. if (dwError != NO_ERROR) {
  3634. dwError = ERROR_NO_CONFLICT_DIR;
  3635. goto bailout;
  3636. }
  3637. lpLeaf = GetLeafPtr(lpCP->lpRemotePath);
  3638. lstrcat(vrgchBuff, vszSlash);
  3639. lstrcat(vrgchBuff, lpLeaf);
  3640. GetUniqueName(vrgchBuff, vrgchBuff+512);
  3641. ReintKdPrint(BADERRORS, ("Shadow of %s!%s is saved as %s \r\n"
  3642. , lpCP->lpSharePath
  3643. , lpCP->lpRemotePath
  3644. , vrgchBuff+512));
  3645. if(!MoveFile(lpCP->lpLocalPath, vrgchBuff+512)){
  3646. dwError = GetLastError();
  3647. }
  3648. else{
  3649. wsprintf(vrwBuff, "Shadow of %s!%s is saved as %s \r\n"
  3650. , lpCP->lpSharePath
  3651. , lpCP->lpRemotePath
  3652. , vrgchBuff+512);
  3653. WriteLog(vrwBuff);
  3654. dwError = 0;
  3655. }
  3656. bailout:
  3657. return (dwError);
  3658. }
  3659. VOID
  3660. PRIVATE
  3661. FormLocalNameFromRemoteName(
  3662. _TCHAR * lpBuff,
  3663. _TCHAR * lpRemoteName
  3664. )
  3665. /*++
  3666. Routine Description:
  3667. Arguments:
  3668. Returns:
  3669. Notes:
  3670. --*/
  3671. {
  3672. int i;
  3673. lstrcpy(lpBuff, lpRemoteName);
  3674. for (i= strlen(lpRemoteName)-1; i>=0 ; --i){
  3675. if (lpBuff[i]=='\\') {
  3676. lpBuff[i] = '_';
  3677. }
  3678. }
  3679. }
  3680. int
  3681. PRIVATE
  3682. StampReintLog(
  3683. VOID
  3684. )
  3685. /*++
  3686. Routine Description:
  3687. Arguments:
  3688. Returns:
  3689. Notes:
  3690. --*/
  3691. {
  3692. SYSTEMTIME sST;
  3693. GetLocalTime(&sST);
  3694. wsprintf(vrgchBuff, vszTimeDateFormat, sST.wHour, sST.wMinute, sST.wSecond, sST.wMonth, sST.wDay, sST.wYear);
  3695. return (WriteLog(vrgchBuff));
  3696. }
  3697. int PRIVATE LogReintError(
  3698. DWORD dwError,
  3699. _TCHAR * lpSharePath,
  3700. _TCHAR * lpRemotePath
  3701. )
  3702. /*++
  3703. Routine Description:
  3704. Arguments:
  3705. Returns:
  3706. Notes:
  3707. --*/
  3708. {
  3709. int i;
  3710. for (i=0; i< sizeof(rgErrorTab)/sizeof(ERRMSG); ++i){
  3711. if (dwError == rgErrorTab[i].dwError){
  3712. LoadString(vhinstCur, rgErrorTab[i].uMessageID, vrgchBuff, 128);
  3713. wsprintf(vrgchBuff+128, "%s%s: %s \r\n"
  3714. , lpSharePath
  3715. , lpRemotePath
  3716. , vrgchBuff);
  3717. WriteLog(vrgchBuff+128);
  3718. return (1);
  3719. }
  3720. }
  3721. wsprintf(vrgchBuff, "%s%s: ", lpSharePath, lpRemotePath);
  3722. WriteLog(vrgchBuff);
  3723. if (FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM,
  3724. NULL, dwError,
  3725. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  3726. vrgchBuff, sizeof(vrgchBuff), NULL)){
  3727. WriteLog(vrgchBuff);
  3728. }
  3729. WriteLog(vrgchCRLF);
  3730. }
  3731. int
  3732. PRIVATE
  3733. WriteLog(
  3734. _TCHAR * lpStrLog
  3735. )
  3736. /*++
  3737. Routine Description:
  3738. Arguments:
  3739. Returns:
  3740. Notes:
  3741. --*/
  3742. {
  3743. HANDLE hfLog;
  3744. DWORD dwRetLen;
  3745. if((hfLog = CreateFile(vszLogFile
  3746. , GENERIC_READ|GENERIC_WRITE
  3747. , FILE_SHARE_READ|FILE_SHARE_WRITE
  3748. , NULL
  3749. , OPEN_ALWAYS
  3750. , 0
  3751. , NULL)) != INVALID_HANDLE_VALUE){
  3752. SetFilePointer(hfLog, 0, NULL, FILE_END);
  3753. WriteFile(hfLog, lpStrLog, strlen(lpStrLog), &dwRetLen, NULL);
  3754. CloseHandle(hfLog);
  3755. return (1);
  3756. }
  3757. return (0);
  3758. }
  3759. #endif //MAYBE_USEFUL
  3760. BOOL
  3761. GetWin32Info(
  3762. _TCHAR * lpFile,
  3763. LPWIN32_FIND_DATA lpFW32
  3764. )
  3765. /*++
  3766. Routine Description:
  3767. Arguments:
  3768. Returns:
  3769. Notes:
  3770. --*/
  3771. {
  3772. return GetWin32InfoForNT(lpFile, lpFW32);
  3773. }
  3774. DWORD
  3775. PRIVATE
  3776. DoObjectEdit(
  3777. HANDLE hShadowDB,
  3778. _TCHAR * lpDrive,
  3779. _TCHAR * lptzFullPath,
  3780. LPCOPYPARAMS lpCP,
  3781. LPSHADOWINFO lpSI,
  3782. LPWIN32_FIND_DATA lpFind32Local,
  3783. LPWIN32_FIND_DATA lpFind32Remote,
  3784. int iShadowStatus,
  3785. int iFileStatus,
  3786. int uAction,
  3787. DWORD dwFileSystemFlags,
  3788. LPCSCPROC lpfnMergeProgress,
  3789. DWORD_PTR dwContext
  3790. )
  3791. /*++
  3792. Routine Description:
  3793. This routine does the actual merge for files
  3794. Arguments:
  3795. hShadowDB Handle to the redir to call issue ioctl calls
  3796. lpDrive drivemapping to bypass CSC while making changes on the remote
  3797. lptzFullPath Fully qualified path
  3798. lpCP Copy parameters, contain share name, path relative to the share and the
  3799. the name in the local database
  3800. lpSI info such as pincount and pinflags
  3801. lpFind32Local win32 info for the local replica
  3802. lpFind32Remote win32 infor for the origianl, NULL if the original doesn't exist
  3803. iShadowStatus status of the local copy
  3804. iFileStatus status of the remote copy
  3805. uAction action to be performed
  3806. dwFileSystemFlags filesystem flags to do special things for NTFS
  3807. lpfnMergeProgress progress callback
  3808. dwContext callback context
  3809. Returns:
  3810. error code as defined in winerror.h
  3811. Notes:
  3812. --*/
  3813. {
  3814. HANDLE hfSrc = INVALID_HANDLE_VALUE, hfDst = INVALID_HANDLE_VALUE;
  3815. HANDLE hDst=0;
  3816. _TCHAR * lpT;
  3817. LONG lOffset=0;
  3818. DWORD dwError=ERROR_REINT_FAILED;
  3819. BOOL fRet, fFileExists, fOverWrite=FALSE, fForceAttribute = FALSE;
  3820. WIN32_FIND_DATA sFind32Remote;
  3821. DWORD dwTotal = 0, dwRet;
  3822. _TCHAR szSrcName[MAX_PATH+MAX_SERVER_SHARE_NAME_FOR_CSC+10];
  3823. _TCHAR szDstName[MAX_PATH+MAX_SERVER_SHARE_NAME_FOR_CSC+10];
  3824. _TCHAR *lprwBuff = NULL;
  3825. _TCHAR *lptzLocalPath = NULL;
  3826. _TCHAR *lptzLocalPathCscBmp = NULL;
  3827. LPCSC_BITMAP_U lpbitmap = NULL;
  3828. DWORD fileSize, fileSizeHigh;
  3829. int cscReintRet;
  3830. lprwBuff = LocalAlloc(LPTR, FILL_BUF_SIZE_LAN);
  3831. if (!lprwBuff)
  3832. {
  3833. return (ERROR_NOT_ENOUGH_MEMORY);
  3834. }
  3835. if (!(lptzLocalPath = GetTempFileForCSC(NULL)))
  3836. {
  3837. ReintKdPrint(BADERRORS, ("DoObjectEdit: failed to get temp file\r\n"));
  3838. goto bailout;
  3839. }
  3840. if (!CopyShadow(hShadowDB, lpSI->hDir, lpSI->hShadow, lptzLocalPath))
  3841. {
  3842. ReintKdPrint(BADERRORS, ("DoObjectEdit: failed to make local copy\r\n"));
  3843. goto bailout;
  3844. }
  3845. // for EFS files, we overwrite the original file, that way the encryption information
  3846. // will not be lost due to us doing a new create followed by a rename and delete
  3847. fOverWrite = ((lpFind32Local->dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) != 0);
  3848. if (!fOverWrite && lpFind32Remote)
  3849. {
  3850. fOverWrite = (((lpFind32Remote->dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) != 0)||
  3851. ((lpFind32Remote->dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) != 0));
  3852. }
  3853. // if this is the DFS root, always overwrite. This is to avoind sharing violation problems
  3854. // while merging
  3855. if (!fOverWrite && (dwFileSystemFlags == DFS_ROOT_FILE_SYSTEM_FLAGS))
  3856. {
  3857. fOverWrite = TRUE;
  3858. }
  3859. ReintKdPrint(MERGE, ("Overwrite=%d\r\n", fOverWrite));
  3860. lOffset=0;
  3861. // Create x:\foo\00010002 kind of temporary filename
  3862. lstrcpy(szDstName, lpDrive);
  3863. lstrcat(szDstName, lpCP->lpRemotePath);
  3864. lpT = GetLeafPtr(szDstName);
  3865. *lpT = 0; // remove the remote leaf
  3866. lpT = GetLeafPtr(lpCP->lpLocalPath);
  3867. // attach the local leaf
  3868. lstrcat(szDstName, lpT);
  3869. // Let us also create the real name x:\foo\bar
  3870. lstrcpy(szSrcName, lpDrive);
  3871. lstrcat(szSrcName, lpCP->lpRemotePath);
  3872. fFileExists = (lpFind32Remote != NULL);
  3873. if (!fFileExists)
  3874. {
  3875. fOverWrite = FALSE;
  3876. ReintKdPrint(MERGE, ("File doesn't exist, Overwrite=%d\r\n", fOverWrite));
  3877. }
  3878. if (mShadowDeleted(lpSI->uStatus)){
  3879. ReintKdPrint(MERGE, ("Deleting %ls \r\n", szSrcName));
  3880. if (lpFind32Remote)
  3881. {
  3882. if((lpFind32Remote->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  3883. {
  3884. ReintKdPrint(MERGE, ("DoObjectEdit:attribute conflict on %ls \r\n", szSrcName));
  3885. goto bailout;
  3886. }
  3887. if(!DeleteFile(szSrcName))
  3888. {
  3889. ReintKdPrint(BADERRORS, ("DoObjectEdit:delete failed %ls error=%d\r\n", szSrcName, GetLastError()));
  3890. goto bailout;
  3891. }
  3892. }
  3893. // if this operation fails we want to abort
  3894. // directory
  3895. if(!DeleteShadow(hShadowDB, lpSI->hDir, lpSI->hShadow))
  3896. {
  3897. dwError = GetLastError();
  3898. goto error;
  3899. }
  3900. else
  3901. {
  3902. dwError = 0;
  3903. goto bailout;
  3904. }
  3905. }
  3906. if (mShadowDirty(lpSI->uStatus)
  3907. || mShadowLocallyCreated(lpSI->uStatus)){
  3908. hfSrc = CreateFile( lptzLocalPath,
  3909. GENERIC_READ,
  3910. FILE_SHARE_READ,
  3911. NULL,
  3912. OPEN_EXISTING,
  3913. 0,
  3914. NULL);
  3915. if (hfSrc == INVALID_HANDLE_VALUE)
  3916. {
  3917. goto bailout;
  3918. }
  3919. if (lpFind32Remote && uAction != RAIA_MERGE) {
  3920. // Load the bitmap only when the remote file exists and
  3921. // that no conflict occurs. (if there's a conflict,
  3922. // uAction == RAIA_MERGE. See PerformOneReint()
  3923. lptzLocalPathCscBmp = (_TCHAR *)LocalAlloc(
  3924. LPTR,
  3925. (lstrlen(lptzLocalPath) +
  3926. CSC_BitmapStreamNameLen() + 1) * sizeof(_TCHAR));
  3927. lstrcpy(lptzLocalPathCscBmp, lptzLocalPath);
  3928. CSC_BitmapAppendStreamName(
  3929. lptzLocalPathCscBmp,
  3930. (lstrlen(lptzLocalPath) + CSC_BitmapStreamNameLen() + 1) * sizeof(_TCHAR));
  3931. ReintKdPrint(MERGE, ("TempFileBmp (WCHAR) %ws\r\n", lptzLocalPathCscBmp));
  3932. switch(CSC_BitmapRead(&lpbitmap, lptzLocalPathCscBmp)) {
  3933. // for return values of CSC_BitmapRead see csc_bmpu.c
  3934. case 0:
  3935. ReintKdPrint(BADERRORS, ("&lpbitmap is null, cannot happen\n"));
  3936. lpbitmap = NULL;
  3937. break;
  3938. case 1:
  3939. ReintKdPrint(MERGE, ("Read bitmap successful\n"));
  3940. // Overwrite the updated parts of the original file in the
  3941. // share
  3942. fOverWrite = TRUE;
  3943. CSC_BitmapOutput(lpbitmap); // this is NOTHING in free build
  3944. break;
  3945. case -2:
  3946. ReintKdPrint(
  3947. MERGE,
  3948. ("No Bitmap file %ws exists\n",
  3949. lptzLocalPathCscBmp));
  3950. lpbitmap = NULL;
  3951. break;
  3952. case -1:
  3953. ReintKdPrint(
  3954. MERGE,
  3955. ("Error in reading Bitmap file %ws\n",
  3956. lptzLocalPathCscBmp));
  3957. lpbitmap = NULL;
  3958. break;
  3959. default:
  3960. ReintKdPrint(MERGE, ("CSC_BitmapRead return code unknown\n"));
  3961. lpbitmap = NULL;
  3962. break;
  3963. }
  3964. }
  3965. // if the destination file has multiple streams
  3966. // we should overwrite it
  3967. if (mShadowDirty(lpSI->uStatus) &&
  3968. (dwFileSystemFlags & FS_PERSISTENT_ACLS)&& // indication of NTFS
  3969. (fFileExists)&&
  3970. !fOverWrite)
  3971. {
  3972. BOOL fStreams = FALSE;
  3973. // check if this has multiple streams
  3974. if(!HasMultipleStreams(szSrcName, &fStreams) || fStreams )
  3975. {
  3976. // if the call failed, we go conservative and assume there are multiple streams
  3977. ReintKdPrint(MERGE, ("Have multiple streams, overwriting\n"));
  3978. fOverWrite = TRUE;
  3979. }
  3980. }
  3981. if (!fOverWrite)
  3982. {
  3983. ReintKdPrint(MERGE, ("Creating temp \r\n"));
  3984. if ((dwFileSystemFlags & FS_PERSISTENT_ACLS)&&(fFileExists))
  3985. {
  3986. hfDst = CreateTmpFileWithSourceAcls(
  3987. szSrcName,
  3988. szDstName);
  3989. }
  3990. else
  3991. {
  3992. hfDst = CreateFile(szDstName,
  3993. GENERIC_WRITE,
  3994. 0,
  3995. NULL,
  3996. CREATE_ALWAYS,
  3997. 0,
  3998. NULL);
  3999. }
  4000. }
  4001. else
  4002. {
  4003. ReintKdPrint(MERGE, ("Overwriting existing file\r\n"));
  4004. Assert(lpFind32Remote);
  4005. if (lpFind32Remote->dwFileAttributes & FILE_ATTRIBUTE_READONLY)
  4006. {
  4007. ReintKdPrint(MERGE, ("Clearing Readonly attribute \r\n"));
  4008. if(!SetFileAttributes(szSrcName, (lpFind32Remote->dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))){
  4009. ReintKdPrint(MERGE, ("Failed to clear Readonly attribute, bailing\r\n"));
  4010. goto error;
  4011. }
  4012. fForceAttribute = TRUE;
  4013. }
  4014. // Want to open existing so can copy only those parts of
  4015. // file that needs to be updated
  4016. ReintKdPrint(MERGE, ("Opening %ws\n", szSrcName));
  4017. hfDst = CreateFile(
  4018. szSrcName,
  4019. GENERIC_WRITE,
  4020. 0,
  4021. NULL,
  4022. (lpbitmap == NULL) ? TRUNCATE_EXISTING : OPEN_EXISTING,
  4023. 0,
  4024. NULL);
  4025. if (hfDst == INVALID_HANDLE_VALUE) {
  4026. dwError = GetLastError();
  4027. ReintKdPrint(MERGE, ("open failed %d\n", dwError));
  4028. SetLastError(dwError);
  4029. goto error;
  4030. }
  4031. if (lpbitmap != NULL) {
  4032. // Resize the destination file
  4033. fileSizeHigh = 0;
  4034. fileSize = GetFileSize(hfSrc, &fileSizeHigh);
  4035. if (fileSize == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
  4036. ReintKdPrint(BADERRORS, ("Error getting source file size\n"));
  4037. goto error;
  4038. }
  4039. ReintKdPrint(MERGE, ("Source FileSize %u\n", fileSize));
  4040. if (SetFilePointer(
  4041. hfDst,
  4042. fileSize,
  4043. &fileSizeHigh,
  4044. FILE_BEGIN) == INVALID_SET_FILE_POINTER
  4045. &&
  4046. GetLastError() != NO_ERROR
  4047. ) {
  4048. ReintKdPrint(BADERRORS, ("Error setting destination file pointer\n"));
  4049. goto error;
  4050. }
  4051. if (!SetEndOfFile(hfDst)) {
  4052. ReintKdPrint(BADERRORS,
  4053. ("Error setting EOF info of destination file\n"));
  4054. goto error;
  4055. }
  4056. ReintKdPrint(MERGE, ("Resized Destination FileSize %u\n",
  4057. GetFileSize(hfDst, NULL)));
  4058. if (fileSizeHigh != 0 && lpbitmap) {
  4059. // file size cannot be represented by 32 bit (> 4Gb)
  4060. // do not use CSCBmp
  4061. CSC_BitmapDelete(&lpbitmap);
  4062. lpbitmap = NULL;
  4063. }
  4064. }
  4065. }
  4066. if (hfDst == INVALID_HANDLE_VALUE)
  4067. {
  4068. goto error;
  4069. }
  4070. // let us append
  4071. if((lOffset = SetFilePointer(hfDst, 0, NULL, FILE_END))==0xffffffff) {
  4072. goto error;
  4073. }
  4074. ReintKdPrint(MERGE, ("Copying back %ls to %ls%ls \r\n"
  4075. , lpCP->lpLocalPath
  4076. , lpCP->lpSharePath
  4077. , lpCP->lpRemotePath
  4078. ));
  4079. do {
  4080. unsigned cbRead;
  4081. if (lpbitmap) {
  4082. // Use CSC_BitmapReint Function
  4083. cscReintRet = CSC_BitmapReint(
  4084. lpbitmap,
  4085. hfSrc,
  4086. hfDst,
  4087. lprwBuff,
  4088. FILL_BUF_SIZE_LAN,
  4089. &cbRead);
  4090. if (cscReintRet == CSC_BITMAPReintCont) {
  4091. NOTHING;
  4092. } else if (cscReintRet == CSC_BITMAPReintDone) {
  4093. ReintKdPrint(
  4094. MERGE,
  4095. ("Done reint\n"));
  4096. break;
  4097. } else if (cscReintRet == CSC_BITMAPReintInvalid) {
  4098. ReintKdPrint(
  4099. BADERRORS,
  4100. ("Invalid param in calling CSC_BitmapReint\n"));
  4101. goto error;
  4102. } else if (cscReintRet == CSC_BITMAPReintError) {
  4103. ReintKdPrint(
  4104. BADERRORS,
  4105. ("Error in transferring data\n"));
  4106. goto error;
  4107. } else {
  4108. ReintKdPrint(
  4109. BADERRORS,
  4110. ("Unrecognized CSC_BitmapReint return code\n"));
  4111. goto error;
  4112. }
  4113. } else {
  4114. if (!ReadFile(hfSrc, lprwBuff, FILL_BUF_SIZE_LAN, &cbRead, NULL)) {
  4115. goto error;
  4116. }
  4117. // ReintKdPrint(BADERRORS, ("Read %d bytes \r\n", cbRead));
  4118. if (!cbRead) {
  4119. break;
  4120. }
  4121. if(!WriteFile(hfDst, (LPBYTE)lprwBuff, cbRead, &cbRead, NULL)){
  4122. goto error;
  4123. }
  4124. dwTotal += cbRead;
  4125. }
  4126. if (lpfnMergeProgress)
  4127. {
  4128. dwRet = (*lpfnMergeProgress)(
  4129. szSrcName,
  4130. lpSI->uStatus,
  4131. lpSI->ulHintFlags,
  4132. lpSI->ulHintPri,
  4133. lpFind32Local,
  4134. CSCPROC_REASON_MORE_DATA,
  4135. cbRead,
  4136. 0,
  4137. dwContext);
  4138. if (dwRet != CSCPROC_RETURN_CONTINUE)
  4139. {
  4140. SetLastError(ERROR_OPERATION_ABORTED);
  4141. goto bailout;
  4142. }
  4143. }
  4144. if (FAbortOperation())
  4145. {
  4146. SetLastError(ERROR_OPERATION_ABORTED);
  4147. goto error;
  4148. }
  4149. } while(TRUE);
  4150. CloseHandle(hfSrc);
  4151. hfSrc = 0;
  4152. CloseHandle(hfDst);
  4153. hfDst = 0;
  4154. // if we are not overwriting the original file, then we must make sure to cleanup
  4155. if (!fOverWrite)
  4156. {
  4157. // nuke the remote one if it exists
  4158. if (fFileExists){
  4159. if(!SetFileAttributes(szSrcName, FILE_ATTRIBUTE_NORMAL)
  4160. || !DeleteFile(szSrcName)){
  4161. goto error;
  4162. }
  4163. }
  4164. // Now rename the temp file to the real filename
  4165. if(!MoveFile(szDstName, szSrcName)){
  4166. ReintKdPrint(BADERRORS, ("Error #%ld Renaming %ls to %ls%ls\r\n"
  4167. , GetLastError()
  4168. , szSrcName
  4169. , lpCP->lpSharePath
  4170. , lpCP->lpRemotePath
  4171. ));
  4172. goto error;
  4173. }
  4174. ReintKdPrint(MERGE, ("Renamed %ls to %ls%ls\r\n"
  4175. , szDstName
  4176. , lpCP->lpSharePath
  4177. , lpCP->lpRemotePath));
  4178. }
  4179. }
  4180. if (fForceAttribute ||
  4181. mShadowAttribChange((lpSI->uStatus))||
  4182. mShadowTimeChange((lpSI->uStatus))){
  4183. if(!SetFileAttributes(szSrcName, FILE_ATTRIBUTE_NORMAL)) {
  4184. goto error;
  4185. }
  4186. if (mShadowTimeChange((lpSI->uStatus))){
  4187. if((hDst = CreateFile(szSrcName,
  4188. GENERIC_WRITE,
  4189. FILE_SHARE_READ,
  4190. NULL,
  4191. OPEN_EXISTING,
  4192. 0,
  4193. NULL
  4194. ))!=INVALID_HANDLE_VALUE){
  4195. fRet = SetFileTime( hDst, NULL,
  4196. NULL, &(lpFind32Local->ftLastWriteTime));
  4197. }
  4198. CloseHandle(hDst);
  4199. hDst = 0;
  4200. if (!fRet) {
  4201. goto error;
  4202. }
  4203. }
  4204. if(!SetFileAttributes(szSrcName, lpFind32Local->dwFileAttributes)){
  4205. goto error;
  4206. }
  4207. }
  4208. // Get the latest timestamps/attributes/LFN/SFN on the file we just copied back
  4209. if (!GetWin32Info(szSrcName, &sFind32Remote)) {
  4210. goto error;
  4211. }
  4212. lpSI->uStatus &= (unsigned long)(~(SHADOW_MODFLAGS));
  4213. if (!SetShadowInfo(hShadowDB, lpSI->hDir, lpSI->hShadow, &sFind32Remote, ~(SHADOW_MODFLAGS), SHADOW_FLAGS_AND|SHADOW_FLAGS_CHANGE_83NAME))
  4214. {
  4215. goto error;
  4216. }
  4217. else
  4218. {
  4219. dwError = NO_ERROR;
  4220. goto bailout;
  4221. }
  4222. error:
  4223. dwError = GetLastError();
  4224. ReportLastError();
  4225. #if 0
  4226. LogReintError( dwError,
  4227. lpCP->lpSharePath,
  4228. lpCP->lpRemotePath);
  4229. #endif
  4230. bailout:
  4231. if (hfSrc != INVALID_HANDLE_VALUE)
  4232. CloseHandle(hfSrc);
  4233. if (hfDst != INVALID_HANDLE_VALUE) {
  4234. CloseHandle(hfDst);
  4235. // if we failed,
  4236. if (dwError != ERROR_SUCCESS)
  4237. DeleteFile(szDstName);
  4238. }
  4239. if (lptzLocalPath) {
  4240. DeleteFile(lptzLocalPath);
  4241. LocalFree(lptzLocalPath);
  4242. }
  4243. if (lprwBuff)
  4244. LocalFree(lprwBuff);
  4245. if (lptzLocalPathCscBmp)
  4246. LocalFree(lptzLocalPathCscBmp);
  4247. if (lpbitmap)
  4248. CSC_BitmapDelete(&lpbitmap);
  4249. ReintKdPrint(MERGE, ("DoObjectEdit returning %d\n", dwError));
  4250. return (dwError);
  4251. }
  4252. DWORD
  4253. PRIVATE
  4254. DoCreateDir(
  4255. HANDLE hShadowDB,
  4256. _TCHAR * lpDrive,
  4257. _TCHAR * lptzFullPath,
  4258. LPCOPYPARAMS lpCP,
  4259. LPSHADOWINFO lpSI,
  4260. LPWIN32_FIND_DATA lpFind32Local,
  4261. LPWIN32_FIND_DATA lpFind32Remote,
  4262. int iShadowStatus,
  4263. int iFileStatus,
  4264. int uAction,
  4265. DWORD dwFileSystemFlags,
  4266. LPCSCPROC lpfnMergeProgress,
  4267. DWORD_PTR dwContext
  4268. )
  4269. /*++
  4270. Routine Description:
  4271. This routine does the actual merge for directories
  4272. Arguments:
  4273. hShadowDB Handle to the redir to call issue ioctl calls
  4274. lpDrive drivemapping to bypass CSC while making changes on the remote
  4275. lptzFullPath Fully qualified path
  4276. lpCP Copy parameters, contain share name, path relative to the share and the
  4277. the name in the local database
  4278. lpSI info such as pincount and pinflags
  4279. lpFind32Local win32 info for the local replica
  4280. lpFind32Remote win32 infor for the origianl, NULL if the original doesn't exist
  4281. iShadowStatus status of the local copy
  4282. iFileStatus status of the remote copy
  4283. uAction action to be performed
  4284. dwFileSystemFlags filesystem flags to do special things for NTFS
  4285. lpfnMergeProgress progress callback
  4286. dwContext callback context
  4287. Returns:
  4288. error code as defined in winerror.h
  4289. Notes:
  4290. --*/
  4291. {
  4292. DWORD dwError=ERROR_FILE_NOT_FOUND;
  4293. WIN32_FIND_DATA sFind32Remote;
  4294. BOOL fCreateDir = FALSE;
  4295. _TCHAR szSrcName[MAX_PATH+MAX_SERVER_SHARE_NAME_FOR_CSC+10];
  4296. _TCHAR *lprwBuff = NULL;
  4297. lprwBuff = LocalAlloc(LPTR, FILL_BUF_SIZE_LAN);
  4298. if (!lprwBuff)
  4299. {
  4300. return (ERROR_NOT_ENOUGH_MEMORY);
  4301. }
  4302. // Let us create the real name x:\foo\bar
  4303. lstrcpy(szSrcName, lpDrive);
  4304. lstrcat(szSrcName, lpCP->lpRemotePath);
  4305. if(lpFind32Remote &&
  4306. !(lpFind32Remote->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){
  4307. if (lpSI->uStatus & SHADOW_REUSED){
  4308. // we now know that a file by this name has been deleted
  4309. // and a directory has been created in it's place
  4310. // we try to delete the file before createing the directory
  4311. // NB, the other way is not possible because we don't allow directory deletes
  4312. // in disconnected mode
  4313. dwError = (!DeleteFile(szSrcName)) ? GetLastError(): NO_ERROR;
  4314. if ((dwError==NO_ERROR)||
  4315. (dwError==ERROR_FILE_NOT_FOUND)||
  4316. (dwError==ERROR_PATH_NOT_FOUND)){
  4317. lstrcpy(lprwBuff, szSrcName);
  4318. dwError = NO_ERROR;
  4319. }
  4320. }
  4321. if (dwError != NO_ERROR){
  4322. #if 0
  4323. LogReintError(ERROR_ATTRIBUTE_CONFLICT, lpCP->lpSharePath, lpCP->lpRemotePath);
  4324. #endif
  4325. dwError = GetUniqueName(szSrcName, lprwBuff);
  4326. }
  4327. if (dwError == NO_ERROR){
  4328. if ((dwError = InbCreateDir( lprwBuff,
  4329. (mShadowAttribChange(lpSI->uStatus)
  4330. ? lpFind32Local->dwFileAttributes
  4331. : 0xffffffff)
  4332. ))==NO_ERROR)
  4333. {
  4334. if(!GetWin32Info(lprwBuff, &sFind32Remote)){
  4335. dwError = GetLastError();
  4336. }
  4337. else{
  4338. #if 0
  4339. lpLeaf1 = GetLeafPtr(szSrcName);
  4340. lpLeaf2 = GetLeafPtr(lprwBuff);
  4341. wsprintf(lprwBuff+512
  4342. , "Directory Name changed from %s to %s on %s\r\n"
  4343. , lpLeaf1, lpLeaf2, lpCP->lpSharePath);
  4344. WriteLog(lprwBuff+512);
  4345. #endif
  4346. }
  4347. }
  4348. }
  4349. }
  4350. else{
  4351. if ((dwError = InbCreateDir(szSrcName,
  4352. (mShadowAttribChange(lpSI->uStatus)
  4353. ? lpFind32Local->dwFileAttributes
  4354. : 0xffffffff)
  4355. ))==NO_ERROR){
  4356. if (!GetWin32Info(szSrcName, &sFind32Remote)){
  4357. dwError = GetLastError();
  4358. }
  4359. }
  4360. }
  4361. if (dwError == NO_ERROR){
  4362. if(!SetShadowInfo(hShadowDB, lpSI->hDir, lpSI->hShadow, &sFind32Remote, (unsigned)(~SHADOW_MODFLAGS), SHADOW_FLAGS_AND))
  4363. {
  4364. dwError = GetLastError();
  4365. }
  4366. else
  4367. {
  4368. ReintKdPrint(MERGE, ("Created directory %s%s", lpCP->lpSharePath, lpCP->lpRemotePath));
  4369. }
  4370. }
  4371. else{
  4372. #if 0
  4373. wsprintf(lprwBuff, "Error merging %s%s\r\n"
  4374. , lpCP->lpSharePath
  4375. , lpCP->lpRemotePath);
  4376. WriteLog(lprwBuff);
  4377. #endif
  4378. }
  4379. if (lprwBuff)
  4380. {
  4381. LocalFree(lprwBuff);
  4382. }
  4383. return (dwError);
  4384. }
  4385. VOID
  4386. CleanupReintState(
  4387. VOID
  4388. )
  4389. {
  4390. if (vsRei.hShare)
  4391. {
  4392. ReintKdPrint(MERGE, ("CSCDLL.CleanupReintState: ending reint on hShare=%x\r\n", vsRei.hShare));
  4393. // EndReint(INVALID_HANDLE_VALUE, vsRei.hShare);
  4394. if (vsRei.tzDrive[0])
  4395. {
  4396. ReintKdPrint(MERGE, ("CSCDLL.CleanupReintState: unmapping merge drive\r\n"));
  4397. DWDisconnectDriveMappedNet(vsRei.tzDrive, TRUE);
  4398. vsRei.tzDrive[0] = 0;
  4399. }
  4400. vsRei.hShare = 0;
  4401. }
  4402. }
  4403. HANDLE
  4404. CreateTmpFileWithSourceAcls(
  4405. _TCHAR *lptzSrc,
  4406. _TCHAR *lptzDst
  4407. )
  4408. /*++
  4409. Routine Description:
  4410. This routine is used by DoObjectEdit while pushing back a file during merge.
  4411. It's job is to get the descritionary ACLs from the source file and use
  4412. them to create a temp file to which we are going to copy the data before renaming it to
  4413. the source
  4414. Arguments:
  4415. Returns:
  4416. file handle is successful, INVALID_HANDLE_VALUE if failed. In case of failure,
  4417. GetLastError() tells the specific error code.
  4418. Notes:
  4419. --*/
  4420. {
  4421. char buff[1];
  4422. BOOL fRet = FALSE;
  4423. SECURITY_ATTRIBUTES sSA;
  4424. DWORD dwSize = 0;
  4425. HANDLE hDst = INVALID_HANDLE_VALUE;
  4426. memset(&sSA, 0, sizeof(sSA));
  4427. sSA.lpSecurityDescriptor = buff;
  4428. dwSize = 0;
  4429. if(!GetFileSecurity(
  4430. lptzSrc,
  4431. DACL_SECURITY_INFORMATION,
  4432. sSA.lpSecurityDescriptor,
  4433. 0,
  4434. &dwSize))
  4435. {
  4436. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  4437. {
  4438. sSA.lpSecurityDescriptor = LocalAlloc(LPTR, dwSize);
  4439. if (sSA.lpSecurityDescriptor)
  4440. {
  4441. if(GetFileSecurity(
  4442. lptzSrc,
  4443. DACL_SECURITY_INFORMATION,
  4444. sSA.lpSecurityDescriptor,
  4445. dwSize,
  4446. &sSA.nLength))
  4447. {
  4448. sSA.nLength = sizeof(sSA);
  4449. fRet = TRUE;
  4450. }
  4451. else
  4452. {
  4453. dwSize = GetLastError();
  4454. LocalFree(sSA.lpSecurityDescriptor);
  4455. SetLastError(dwSize);
  4456. }
  4457. }
  4458. }
  4459. }
  4460. else
  4461. {
  4462. fRet = TRUE;
  4463. }
  4464. if (fRet)
  4465. {
  4466. hDst = CreateFile(lptzDst,
  4467. GENERIC_WRITE,
  4468. 0,
  4469. &sSA,
  4470. CREATE_ALWAYS,
  4471. 0,
  4472. NULL);
  4473. if (hDst == INVALID_HANDLE_VALUE)
  4474. {
  4475. dwSize = GetLastError();
  4476. }
  4477. if (sSA.lpSecurityDescriptor)
  4478. {
  4479. LocalFree(sSA.lpSecurityDescriptor);
  4480. }
  4481. if (hDst == INVALID_HANDLE_VALUE)
  4482. {
  4483. SetLastError(dwSize);
  4484. }
  4485. }
  4486. return hDst;
  4487. }
  4488. BOOL
  4489. HasMultipleStreams(
  4490. _TCHAR *lpExistingFileName,
  4491. BOOL *lpfTrueFalse
  4492. )
  4493. /*++
  4494. Routine Description:
  4495. This routine is used by DoObjectEdit while pushing back a file during merge.
  4496. It looks to see whether the destination file has multiple streams.
  4497. Arguments:
  4498. lpExistingFileName Name of an existing file
  4499. lpfTrueFalse output parameter, returns TRUE is the call succeedes and there are multiple streams
  4500. Returns:
  4501. returns TRUE if successful
  4502. Notes:
  4503. --*/
  4504. {
  4505. HANDLE SourceFile = INVALID_HANDLE_VALUE;
  4506. PFILE_STREAM_INFORMATION StreamInfoBase = NULL;
  4507. ULONG StreamInfoSize;
  4508. IO_STATUS_BLOCK IoStatus;
  4509. BOOL fRet = FALSE;
  4510. DWORD Status;
  4511. *lpfTrueFalse = FALSE;
  4512. SourceFile = CreateFile(
  4513. lpExistingFileName,
  4514. GENERIC_READ,
  4515. FILE_SHARE_READ | FILE_SHARE_WRITE,
  4516. NULL,
  4517. OPEN_EXISTING,
  4518. FILE_FLAG_SEQUENTIAL_SCAN,
  4519. NULL
  4520. );
  4521. if (SourceFile == INVALID_HANDLE_VALUE)
  4522. {
  4523. return FALSE;
  4524. }
  4525. //
  4526. // Obtain the full set of streams we have to copy. Since the Io subsystem does
  4527. // not provide us a way to find out how much space this information will take,
  4528. // we must iterate the call, doubling the buffer size upon each failure.
  4529. //
  4530. // If the underlying file system does not support stream enumeration, we end up
  4531. // with a NULL buffer. This is acceptable since we have at least a default
  4532. // data stream,
  4533. //
  4534. StreamInfoSize = 4096;
  4535. do {
  4536. StreamInfoBase = LocalAlloc(LPTR, StreamInfoSize );
  4537. if ( !StreamInfoBase ) {
  4538. SetLastError( STATUS_NO_MEMORY );
  4539. goto bailout;
  4540. }
  4541. Status = NtQueryInformationFile(
  4542. SourceFile,
  4543. &IoStatus,
  4544. (PVOID) StreamInfoBase,
  4545. StreamInfoSize,
  4546. FileStreamInformation
  4547. );
  4548. if (Status != STATUS_SUCCESS) {
  4549. //
  4550. // We failed the call. Free up the previous buffer and set up
  4551. // for another pass with a buffer twice as large
  4552. //
  4553. LocalFree(StreamInfoBase);
  4554. StreamInfoBase = NULL;
  4555. StreamInfoSize *= 2;
  4556. }
  4557. } while ( Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL );
  4558. if (Status == STATUS_SUCCESS)
  4559. {
  4560. fRet = TRUE;
  4561. if (StreamInfoBase)
  4562. {
  4563. if (StreamInfoBase->NextEntryOffset)
  4564. {
  4565. *lpfTrueFalse = TRUE;
  4566. }
  4567. }
  4568. }
  4569. bailout:
  4570. if (SourceFile != INVALID_HANDLE_VALUE)
  4571. {
  4572. CloseHandle(SourceFile);
  4573. }
  4574. if (StreamInfoBase)
  4575. {
  4576. LocalFree(StreamInfoBase);
  4577. }
  4578. return fRet;
  4579. }
  4580. #ifdef DEBUG
  4581. BOOL
  4582. CompareFilePrefixes(
  4583. _TCHAR *lptzRemotePath,
  4584. _TCHAR *lptzLocalPath,
  4585. SHADOWINFO *lpSI,
  4586. WIN32_FIND_DATA *lpFind32,
  4587. LPCSCPROC lpfnMergeProgress,
  4588. DWORD_PTR dwContext
  4589. )
  4590. {
  4591. HANDLE hfSrc = INVALID_HANDLE_VALUE, hfDst = INVALID_HANDLE_VALUE;
  4592. LPVOID lpvSrc = NULL, lpvDst = NULL;
  4593. unsigned cbSrcTotal = 0, cbDstTotal = 0;
  4594. DWORD dwError = NO_ERROR, dwRemoteSize;
  4595. if (lpfnMergeProgress)
  4596. {
  4597. (*lpfnMergeProgress)(lptzRemotePath, lpSI->uStatus, lpSI->ulHintFlags, lpSI->ulHintPri, lpFind32, CSCPROC_REASON_BEGIN, 0, 0, dwContext);
  4598. }
  4599. ReintKdPrint(ALWAYS, ("Comparing %ls with %ls \r\n", lptzLocalPath, lptzRemotePath));
  4600. lpvSrc = LocalAlloc(LPTR, FILL_BUF_SIZE_LAN);
  4601. if (!lpvSrc)
  4602. {
  4603. ReintKdPrint(BADERRORS, ("CompareFilesPrefix: Memory Allocation Error\r\n"));
  4604. goto bailout;
  4605. }
  4606. lpvDst = LocalAlloc(LPTR, FILL_BUF_SIZE_LAN);
  4607. if (!lpvDst)
  4608. {
  4609. ReintKdPrint(BADERRORS, ("CompareFilesPrefix: Memory Allocation Error\r\n"));
  4610. goto bailout;
  4611. }
  4612. hfSrc = CreateFile(lptzLocalPath,
  4613. GENERIC_READ,
  4614. FILE_SHARE_READ,
  4615. NULL,
  4616. OPEN_EXISTING,
  4617. 0,
  4618. NULL);
  4619. if (hfSrc == INVALID_HANDLE_VALUE)
  4620. {
  4621. ReintKdPrint(BADERRORS, ("Failed to open database file for Inode=%x\r\n", lpSI->hShadow));
  4622. goto bailout;
  4623. }
  4624. hfDst = CreateFile(lptzRemotePath,
  4625. GENERIC_READ,
  4626. FILE_SHARE_READ,
  4627. NULL,
  4628. OPEN_EXISTING,
  4629. 0,
  4630. NULL);
  4631. if (hfDst == INVALID_HANDLE_VALUE)
  4632. {
  4633. ReintKdPrint(BADERRORS, ("Failed to open remote file for Inode=%x\r\n", lpSI->hShadow));
  4634. goto error;
  4635. }
  4636. dwRemoteSize = GetFileSize(hfDst, NULL);
  4637. if (dwRemoteSize == 0xffffffff)
  4638. {
  4639. ReintKdPrint(BADERRORS, ("Failed to get size for remote file for Inode=%x\r\n", lpSI->hShadow));
  4640. goto error;
  4641. }
  4642. if (dwRemoteSize != lpFind32->nFileSizeLow)
  4643. {
  4644. ReintKdPrint(BADERRORS, ("mismatched local and remote sizes for Inode=%x\r\n", lpSI->hShadow));
  4645. SetLastError(ERROR_INVALID_DATA);
  4646. goto error;
  4647. }
  4648. do{
  4649. unsigned cbReadSrc, cbReadDst;
  4650. if (!ReadFile(hfSrc, lpvSrc, FILL_BUF_SIZE_LAN, &cbReadSrc, NULL)){
  4651. goto error;
  4652. }
  4653. if (!cbReadSrc) {
  4654. break;
  4655. }
  4656. cbSrcTotal += cbReadSrc;
  4657. if(!ReadFile(hfDst, (LPBYTE)lpvDst, cbReadSrc, &cbReadDst, NULL)){
  4658. goto error;
  4659. }
  4660. cbDstTotal += cbReadDst;
  4661. if (cbReadSrc > cbReadDst)
  4662. {
  4663. ReintKdPrint(ALWAYS, ("CompareFilesPrefix: RemoteFile sized is smaller than Local Size\r\n"));
  4664. SetLastError(ERROR_INVALID_DATA);
  4665. goto error;
  4666. }
  4667. if (memcmp(lpvSrc, lpvDst, cbReadSrc))
  4668. {
  4669. ReintKdPrint(ALWAYS, ("mismatched!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\r\n"));
  4670. SetLastError(ERROR_INVALID_DATA);
  4671. goto error;
  4672. }
  4673. } while(TRUE);
  4674. goto bailout;
  4675. error:
  4676. dwError = GetLastError();
  4677. ReintKdPrint(BADERRORS, ("Error=%d\r\n", dwError));
  4678. bailout:
  4679. if (hfSrc != INVALID_HANDLE_VALUE) {
  4680. CloseHandle(hfSrc);
  4681. }
  4682. if (hfDst != INVALID_HANDLE_VALUE) {
  4683. CloseHandle(hfDst);
  4684. }
  4685. if (lpvSrc)
  4686. {
  4687. FreeMem(lpvSrc);
  4688. }
  4689. if (lpvDst)
  4690. {
  4691. FreeMem(lpvDst);
  4692. }
  4693. if (lpfnMergeProgress)
  4694. {
  4695. (*lpfnMergeProgress)(lptzRemotePath, lpSI->uStatus, lpSI->ulHintFlags, lpSI->ulHintPri, lpFind32, CSCPROC_REASON_END, cbDstTotal, dwError, dwContext);
  4696. }
  4697. return TRUE;
  4698. }
  4699. int
  4700. CheckCSCDirCallback(
  4701. HANDLE hShadowDB,
  4702. LPSECURITYINFO pShareSecurityInfo,
  4703. LPTSTR lptzFullPath,
  4704. DWORD dwCallbackReason,
  4705. WIN32_FIND_DATA *lpFind32,
  4706. SHADOWINFO *lpSI,
  4707. LPREINT_INFO lpRei
  4708. )
  4709. {
  4710. int retCode = TOD_CONTINUE;
  4711. LPCOPYPARAMS lpCP = NULL;
  4712. BOOL fInsertInList = FALSE, fIsFile;
  4713. _TCHAR *lptzLocalPath = NULL;
  4714. _TCHAR szRemoteName[MAX_PATH+MAX_SERVER_SHARE_NAME_FOR_CSC+10];
  4715. if (dwCallbackReason != TOD_CALLBACK_REASON_NEXT_ITEM)
  4716. {
  4717. return retCode;
  4718. }
  4719. fIsFile = ((lpFind32->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0);
  4720. if (!fIsFile)
  4721. {
  4722. return retCode;
  4723. }
  4724. lpCP = LpAllocCopyParams();
  4725. if (!lpCP){
  4726. ReintKdPrint(BADERRORS, ("CheckCSCDirCallback: Allocation of copyparam buffer failed\n"));
  4727. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  4728. retCode = TOD_ABORT;
  4729. goto bailout;
  4730. }
  4731. if(!GetUNCPath(hShadowDB, lpSI->hShare, lpSI->hDir, lpSI->hShadow, lpCP)){
  4732. ReintKdPrint(BADERRORS, ("CheckCSCDirCallback: GetUNCPath failed\n"));
  4733. Assert(FALSE);
  4734. retCode = TOD_CONTINUE;
  4735. goto bailout;
  4736. }
  4737. Assert(lpRei);
  4738. if (!(lptzLocalPath = GetTempFileForCSC(NULL)))
  4739. {
  4740. ReintKdPrint(BADERRORS, ("CheckCSCDirCallback: failed to get temp file\r\n"));
  4741. goto bailout;
  4742. }
  4743. if (!CopyShadow(hShadowDB, lpSI->hDir, lpSI->hShadow, lptzLocalPath))
  4744. {
  4745. ReintKdPrint(BADERRORS, ("CheckCSCDirCallback: failed to make local copy\r\n"));
  4746. goto bailout;
  4747. }
  4748. // Let us create the real name x:\foo\bar
  4749. lstrcpy(szRemoteName, lpRei->tzDrive);
  4750. lstrcat(szRemoteName, lpCP->lpRemotePath);
  4751. CompareFilePrefixes(
  4752. szRemoteName,
  4753. lptzLocalPath,
  4754. lpSI,
  4755. lpFind32,
  4756. lpRei->lpfnMergeProgress,
  4757. lpRei->dwContext
  4758. );
  4759. bailout:
  4760. if (lptzLocalPath)
  4761. {
  4762. DeleteFile(lptzLocalPath);
  4763. LocalFree(lptzLocalPath);
  4764. }
  4765. if (lpCP) {
  4766. FreeCopyParams(lpCP);
  4767. }
  4768. return retCode;
  4769. }
  4770. BOOL
  4771. PUBLIC
  4772. CheckCSCShare(
  4773. _TCHAR *lptzShare,
  4774. LPCSCPROC lpfnMergeProgress,
  4775. DWORD dwContext
  4776. )
  4777. /*++
  4778. Routine Description:
  4779. Arguments:
  4780. Returns:
  4781. Notes:
  4782. --*/
  4783. {
  4784. BOOL fConnected=FALSE, fDone = FALSE;
  4785. BOOL fStamped = FALSE, fInsertInList = FALSE, fBeginReint = FALSE, fDisabledShadowing = FALSE;
  4786. HANDLE hShadowDB;
  4787. SHADOWINFO sSI;
  4788. int iRet;
  4789. DWORD dwError=NO_ERROR;
  4790. TCHAR tzFullPath[MAX_PATH+1];
  4791. WIN32_FIND_DATA sFind32;
  4792. REINT_INFO sRei;
  4793. if (!LpBreakPath(lptzShare, TRUE, &fDone) && !fDone)
  4794. {
  4795. SetLastError(ERROR_INVALID_PARAMETER);
  4796. return FALSE;
  4797. }
  4798. fDone = FALSE;
  4799. memset(&sRei, 0, sizeof(sRei));
  4800. sRei.lpfnMergeProgress = lpfnMergeProgress;
  4801. sRei.dwContext = dwContext;
  4802. memset(sRei.tzDrive, 0, sizeof(sRei.tzDrive));
  4803. if ((hShadowDB = OpenShadowDatabaseIO()) ==INVALID_HANDLE_VALUE)
  4804. {
  4805. ReintKdPrint(BADERRORS, ("CheckShare: failed to open database\r\n"));
  4806. goto bailout;
  4807. }
  4808. memset(&sFind32, 0, sizeof(sFind32));
  4809. lstrcpy(sFind32.cFileName, lptzShare);
  4810. if(!GetShadowEx(hShadowDB, 0, &sFind32, &sSI)||(!sSI.hShadow))
  4811. {
  4812. ReintKdPrint(BADERRORS, ("CheckShare: failed to get the share info\r\n"));
  4813. SetLastError(ERROR_INVALID_PARAMETER);
  4814. goto bailout;
  4815. }
  4816. lstrcpy(tzFullPath, lptzShare);
  4817. dwError = DWConnectNet(lptzShare, sRei.tzDrive, NULL, NULL, NULL, 0, NULL);
  4818. if ((dwError != WN_SUCCESS) && (dwError != WN_CONNECTED_OTHER_PASSWORD_DEFAULT))
  4819. {
  4820. ReintKdPrint(BADERRORS, ("CheckCSCOneShare: Error %d, couldn't connect to %s\r\n", dwError, lptzShare));
  4821. SetLastError(dwError);
  4822. goto bailout;
  4823. }
  4824. ReintKdPrint(MERGE, ("CSC.CheckShare: mapped drive letter %ls \r\n", sRei.tzDrive));
  4825. if (lpfnMergeProgress)
  4826. {
  4827. (*lpfnMergeProgress)(lptzShare, 0, 0, 0, NULL, CSCPROC_REASON_BEGIN, 0, 0, dwContext);
  4828. }
  4829. fConnected = TRUE;
  4830. iRet = TraverseOneDirectory(hShadowDB, NULL, 0, sSI.hShadow, tzFullPath, CheckCSCDirCallback, &sRei);
  4831. if (lpfnMergeProgress)
  4832. {
  4833. (*lpfnMergeProgress)(lptzShare, 0, 0, 0, NULL, CSCPROC_REASON_END, 0, 0, dwContext);
  4834. }
  4835. fDone = TRUE;
  4836. bailout:
  4837. CloseShadowDatabaseIO(hShadowDB);
  4838. if (fConnected) {
  4839. if(DWDisconnectDriveMappedNet(sRei.tzDrive, TRUE))
  4840. {
  4841. ReintKdPrint(BADERRORS, ("Failed disconnection of merge drive \r\n"));
  4842. }
  4843. else
  4844. {
  4845. ReintKdPrint(MERGE, ("Disconnected merge drive \r\n"));
  4846. }
  4847. }
  4848. return (fDone);
  4849. }
  4850. #endif