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.

1334 lines
32 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. main.c
  5. Abstract:
  6. <TODO: fill in abstract>
  7. Author:
  8. TODO: <full name> (<alias>) <date>
  9. Revision History:
  10. <full name> (<alias>) <date> <comments>
  11. --*/
  12. #include "pch.h"
  13. #define MAX_BRANCHES 16
  14. HANDLE g_hHeap;
  15. HINSTANCE g_hInst;
  16. BOOL g_Commit;
  17. BOOL WINAPI MigUtil_Entry (HINSTANCE, DWORD, PVOID);
  18. BOOL
  19. pCallEntryPoints (
  20. DWORD Reason
  21. )
  22. {
  23. switch (Reason) {
  24. case DLL_PROCESS_ATTACH:
  25. UtInitialize (NULL);
  26. break;
  27. case DLL_PROCESS_DETACH:
  28. UtTerminate ();
  29. break;
  30. }
  31. return TRUE;
  32. }
  33. BOOL
  34. Init (
  35. VOID
  36. )
  37. {
  38. g_hHeap = GetProcessHeap();
  39. g_hInst = GetModuleHandle (NULL);
  40. return pCallEntryPoints (DLL_PROCESS_ATTACH);
  41. }
  42. VOID
  43. Terminate (
  44. VOID
  45. )
  46. {
  47. pCallEntryPoints (DLL_PROCESS_DETACH);
  48. }
  49. VOID
  50. HelpAndExit (
  51. VOID
  52. )
  53. {
  54. //
  55. // This routine is called whenever command line args are wrong
  56. //
  57. fprintf (
  58. stderr,
  59. "\nDescription:\n\n"
  60. " SDPB.EXE executes sd branch and sd client for a specific branch.\n"
  61. " It maps in the branch into view, or removes the branch from view if\n"
  62. " the -d argument is specified.\n\n"
  63. " This utility assumes a specific format of the branch layout:\n\n"
  64. " //depot/private/{branch}/{project}/{path}\n\n"
  65. " {branch} specifies the private branch, and the last path member must\n"
  66. " match the <branchname> arg.\n\n"
  67. " Examples: (assume <branchname> is \"foo\")\n"
  68. " //depot/private/foo/root\n"
  69. " //depot/private/foo/bar\n"
  70. " //depot/private/cat/foo/bar\n\n"
  71. " {project} specifies the depot, such as root or base\n\n"
  72. " {path} specifies the rest of the path\n\n"
  73. " The local path is computed by %%_NTBINDIR%%\\{project}\\{path}, unless\n"
  74. " {project} == \"root\" (%%_NTBINDIR%%\\{path} is used for root).\n\n"
  75. " The -p switch overrides local path computation.\n\n"
  76. " Example: (a private branch of winnt32)\n\n"
  77. " //depot/private/migration/base/ntsetup/winnt32\n\n"
  78. " NOTE: SDPB.EXE changes have no affect until sd sync is executed.\n\n"
  79. "Command Line Syntax:\n\n"
  80. " sdpb <branchname(s)> [-p:<local_proj_root>] [-d] [-o] [-c]\n"
  81. "\nArguments: (order-insensitive)\n\n"
  82. " <branchname> specifies the Source Depot branch name to map in. A max of\n"
  83. " 16 branches can be specified.\n\n"
  84. " -p:<local_proj_root> specifies an alternative local subdirectory to\n"
  85. " use as the path base. If specified, //depot/private/{branch}/{project}\n"
  86. " is replaced by <local_proj_root>.\n\n"
  87. " -d enables delete mode, to remove a branch from the client view\n\n"
  88. " -o outputs various interesting data about the branch views (no changes)\n\n"
  89. " -c commits changes to sd client\n"
  90. );
  91. exit (1);
  92. }
  93. BOOL
  94. pGetNextLine (
  95. IN PCSTR Start,
  96. IN PCSTR Eof,
  97. OUT PCSTR *PrintableStart,
  98. OUT PCSTR *End,
  99. OUT PCSTR *NextLine
  100. )
  101. {
  102. PCSTR pos;
  103. pos = Start;
  104. *End = NULL;
  105. while (pos < Eof) {
  106. if (pos[0] != ' ' && pos[0] != '\t') {
  107. break;
  108. }
  109. pos++;
  110. }
  111. *PrintableStart = pos;
  112. while (pos < Eof) {
  113. if (pos[0] == '\r' || pos[0] == '\n') {
  114. break;
  115. }
  116. pos++;
  117. }
  118. *End = pos;
  119. if (pos < Eof && pos[0] == '\r') {
  120. pos++;
  121. }
  122. if (pos < Eof && pos[0] == '\n') {
  123. pos++;
  124. }
  125. *NextLine = pos;
  126. return Start != *NextLine;
  127. }
  128. PCSTR
  129. pFindNextCharAB (
  130. IN PCSTR Start,
  131. IN PCSTR End,
  132. IN CHAR FindChar
  133. )
  134. {
  135. if (!Start) {
  136. return NULL;
  137. }
  138. while (Start < End) {
  139. if (*Start == FindChar) {
  140. return Start;
  141. }
  142. Start++;
  143. }
  144. return NULL;
  145. }
  146. BOOL
  147. pParseViewLines (
  148. IN OUT PCSTR *FilePos,
  149. IN PCSTR Eof,
  150. IN OUT PGROWLIST LeftSide, OPTIONAL
  151. IN OUT PGROWLIST RightSide OPTIONAL
  152. )
  153. {
  154. UINT count = 0;
  155. PCSTR pos;
  156. PCSTR nextPos;
  157. PSTR midString;
  158. PCSTR rightSideStart;
  159. PCSTR rightSideEnd;
  160. PSTR p;
  161. PCSTR lineStart;
  162. PCSTR lineEnd;
  163. PCSTR leftSideStart;
  164. PCSTR leftSideEnd;
  165. PCSTR dash;
  166. BOOL b;
  167. pos = *FilePos;
  168. while (pGetNextLine (pos, Eof, &lineStart, &lineEnd, &nextPos)) {
  169. if (pos == lineStart) {
  170. break;
  171. }
  172. //
  173. // Extract the left side string
  174. //
  175. leftSideStart = pFindNextCharAB (lineStart, lineEnd, '/');
  176. if (!leftSideStart || (leftSideStart + 1 >= lineEnd) || leftSideStart[1] != '/') {
  177. break;
  178. }
  179. leftSideEnd = leftSideStart + 2;
  180. dash = pFindNextCharAB (lineStart, lineEnd, '-');
  181. if (dash == leftSideStart - 1) {
  182. leftSideStart = dash;
  183. }
  184. for (;;) {
  185. leftSideEnd = pFindNextCharAB (leftSideEnd, lineEnd, '/');
  186. if (!leftSideEnd || (leftSideEnd + 1 >= lineEnd)) {
  187. leftSideEnd = NULL;
  188. break;
  189. }
  190. if (leftSideEnd[1] == '/') {
  191. leftSideEnd--;
  192. break;
  193. }
  194. leftSideEnd++;
  195. }
  196. if (!leftSideEnd) {
  197. break;
  198. }
  199. rightSideStart = pFindNextCharAB (leftSideEnd, lineEnd, '/');
  200. if (!rightSideStart || (rightSideStart + 1 >= lineEnd) || rightSideStart[1] != '/') {
  201. break;
  202. }
  203. while (leftSideEnd > leftSideStart) {
  204. leftSideEnd--;
  205. if (!isspace (*leftSideEnd)) {
  206. leftSideEnd++;
  207. break;
  208. }
  209. }
  210. if (leftSideEnd == leftSideStart) {
  211. break;
  212. }
  213. //
  214. // Extract the right side string
  215. //
  216. rightSideEnd = lineEnd;
  217. while (rightSideEnd > rightSideStart) {
  218. rightSideEnd--;
  219. if (!isspace (*rightSideEnd)) {
  220. rightSideEnd++;
  221. break;
  222. }
  223. }
  224. if (rightSideEnd == rightSideStart) {
  225. break;
  226. }
  227. if (LeftSide) {
  228. if (!GlAppendStringAB (LeftSide, leftSideStart, leftSideEnd)) {
  229. break;
  230. }
  231. }
  232. if (RightSide) {
  233. if (!GlAppendStringAB (RightSide, rightSideStart, rightSideEnd)) {
  234. break;
  235. }
  236. }
  237. count++;
  238. pos = nextPos;
  239. }
  240. *FilePos = pos;
  241. return count > 0;
  242. }
  243. VOID
  244. pDumpOutput (
  245. IN PCSTR SdClientOutput,
  246. IN PCSTR Eof
  247. )
  248. {
  249. PCSTR lineStart;
  250. PCSTR lineEnd;
  251. PCSTR pos;
  252. PSTR dup;
  253. PCSTR root;
  254. BOOL viewFound = FALSE;
  255. pos = SdClientOutput;
  256. while (pGetNextLine (pos, Eof, &lineStart, &lineEnd, &pos)) {
  257. if (lineEnd == lineStart) {
  258. printf ("\n");
  259. continue;
  260. }
  261. dup = AllocText (lineEnd - lineStart);
  262. StringCopyAB (dup, lineStart, lineEnd);
  263. _tprintf ("%s\n", dup);
  264. FreeText (dup);
  265. }
  266. }
  267. BOOL
  268. pParseClientMapping (
  269. IN PCSTR SdClientOutput,
  270. IN PCSTR Eof,
  271. OUT PSTR Client,
  272. OUT PSTR RootPath,
  273. IN OUT PGROWLIST LeftSide, OPTIONAL
  274. IN OUT PGROWLIST RightSide OPTIONAL
  275. )
  276. {
  277. PCSTR lineStart;
  278. PCSTR lineEnd;
  279. PCSTR pos;
  280. PSTR dup;
  281. PCSTR data;
  282. BOOL viewFound = FALSE;
  283. //
  284. // Find Client:, Root: or View:
  285. //
  286. pos = SdClientOutput;
  287. *RootPath = 0;
  288. while (pGetNextLine (pos, Eof, &lineStart, &lineEnd, &pos)) {
  289. if (lineStart == lineEnd) {
  290. continue;
  291. }
  292. if (*lineStart == '#') {
  293. continue;
  294. }
  295. dup = AllocText (lineEnd - lineStart);
  296. StringCopyAB (dup, lineStart, lineEnd);
  297. if (StringIPrefix (dup, "Client:")) {
  298. data = dup + 7;
  299. while (isspace (*data)) {
  300. data++;
  301. }
  302. StringCopy (Client, data);
  303. } else if (StringIPrefix (dup, "Root:")) {
  304. data = dup + 5;
  305. while (isspace (*data)) {
  306. data++;
  307. }
  308. StringCopy (RootPath, data);
  309. } else if (StringIPrefix (dup, "View:")) {
  310. if (!(*RootPath)) {
  311. break;
  312. }
  313. viewFound = pParseViewLines (&pos, Eof, LeftSide, RightSide);
  314. }
  315. FreeText (dup);
  316. dup = NULL;
  317. }
  318. FreeText (dup);
  319. return *RootPath && viewFound;
  320. }
  321. BOOL
  322. pParseBranchMapping (
  323. IN PCSTR SdClientOutput,
  324. IN PCSTR Eof,
  325. IN OUT PGROWLIST LeftSide, OPTIONAL
  326. IN OUT PGROWLIST RightSide OPTIONAL
  327. )
  328. {
  329. PCSTR lineStart;
  330. PCSTR lineEnd;
  331. PCSTR pos;
  332. PSTR dup;
  333. PCSTR root;
  334. BOOL viewFound = FALSE;
  335. //
  336. // Find View:
  337. //
  338. pos = SdClientOutput;
  339. while (pGetNextLine (pos, Eof, &lineStart, &lineEnd, &pos)) {
  340. if (lineStart == lineEnd) {
  341. continue;
  342. }
  343. if (*lineStart == '#') {
  344. continue;
  345. }
  346. dup = AllocText (lineEnd - lineStart);
  347. StringCopyAB (dup, lineStart, lineEnd);
  348. if (StringIPrefix (dup, "View:")) {
  349. viewFound = pParseViewLines (&pos, Eof, LeftSide, RightSide);
  350. }
  351. FreeText (dup);
  352. dup = NULL;
  353. }
  354. FreeText (dup);
  355. return viewFound;
  356. }
  357. BOOL
  358. pVerifyBranch (
  359. IN PCSTR BranchName,
  360. IN PGROWLIST BranchStorage,
  361. OUT PGROWLIST BranchProject, OPTIONAL
  362. OUT PGROWLIST BranchPath, OPTIONAL
  363. IN PCSTR LocalRoot, OPTIONAL
  364. IN PCSTR ClientViewRoot OPTIONAL
  365. )
  366. {
  367. UINT u;
  368. UINT count;
  369. BOOL result = TRUE;
  370. PCSTR projectStart;
  371. PCSTR projectEnd;
  372. UINT branchNameTchars;
  373. PCSTR localPathBase = NULL;
  374. PCSTR p;
  375. PSTR localSubPath = NULL;
  376. PCSTR restOfPath = NULL;
  377. PSTR q;
  378. PCSTR fullSubPath = NULL;
  379. if (LocalRoot) {
  380. p = LocalRoot + TcharCountA (ClientViewRoot);
  381. if (*p == '\\') {
  382. p++;
  383. }
  384. localSubPath = DuplicatePathString (p, 0);
  385. q = localSubPath;
  386. while (*q) {
  387. if (*q == '\\') {
  388. *q = '/';
  389. }
  390. q++;
  391. }
  392. }
  393. branchNameTchars = TcharCountA (BranchName);
  394. count = GlGetSize (BranchStorage);
  395. for (u = 0 ; u < count ; u++) {
  396. projectStart = GlGetString (BranchStorage, u);
  397. if (!projectStart || !StringIPrefix (projectStart, "//depot/private/")) {
  398. result = FALSE;
  399. break;
  400. }
  401. projectStart += sizeof ("//depot/private/") - 1; // minus one for nul
  402. while (*projectStart) {
  403. if (StringIPrefix (projectStart, BranchName)) {
  404. if (projectStart[branchNameTchars] == '/') {
  405. //
  406. // Recall syntax is:
  407. //
  408. // //depot/private/[subdir/]{branch}/{project}/{path}
  409. //
  410. // If -p switch is specified, we don't have {project}.
  411. //
  412. //
  413. // We just found {branch}, locate start and end ptrs of {project},
  414. // leave them equal if there is no {project}. projectEnd must
  415. // point to /{path}.
  416. //
  417. projectStart += branchNameTchars;
  418. projectEnd = projectStart;
  419. if (!LocalRoot) {
  420. projectStart++;
  421. projectEnd = strchr (projectStart, '/');
  422. if (!projectEnd) {
  423. //
  424. // Assumption failure -- break now
  425. //
  426. projectStart = NULL;
  427. break;
  428. }
  429. }
  430. //
  431. // prepare the base path from -p switch
  432. //
  433. if (localSubPath) {
  434. localPathBase = localSubPath;
  435. } else {
  436. localPathBase = "";
  437. }
  438. //
  439. // After projectEnd comes optional {path}, find {path}
  440. //
  441. restOfPath = projectEnd;
  442. if (*restOfPath && !(*localPathBase)) {
  443. restOfPath++;
  444. }
  445. // done
  446. break;
  447. }
  448. }
  449. //
  450. // {project} not found yet, keep searching
  451. //
  452. projectStart = strchr (projectStart, '/');
  453. if (projectStart) {
  454. projectStart++;
  455. } else {
  456. break;
  457. }
  458. }
  459. if (!projectStart || !restOfPath || !localPathBase) {
  460. result = FALSE;
  461. fprintf (
  462. stderr,
  463. "\nThe branch spec below does not fit assumptions. See help (/? switch).\n\n%s\n\n",
  464. GlGetString (BranchStorage, u)
  465. );
  466. break;
  467. }
  468. fullSubPath = JoinText (localPathBase, restOfPath);
  469. if (!fullSubPath) {
  470. result = FALSE;
  471. break;
  472. }
  473. localPathBase = NULL;
  474. restOfPath = NULL;
  475. if (BranchProject) {
  476. if (!GlAppendStringAB (BranchProject, projectStart, projectEnd)) {
  477. result = FALSE;
  478. break;
  479. }
  480. }
  481. if (BranchPath) {
  482. if (!GlAppendString (BranchPath, fullSubPath)) {
  483. result = FALSE;
  484. break;
  485. }
  486. }
  487. FreeText (fullSubPath);
  488. fullSubPath = NULL;
  489. }
  490. FreeText (fullSubPath);
  491. FreePathString (localSubPath);
  492. return result;
  493. }
  494. BOOL
  495. pLaunchSd (
  496. IN PSTR CmdLine,
  497. IN HANDLE TempInput,
  498. IN HANDLE TempOutput,
  499. IN PCSTR Msg,
  500. OUT HANDLE *Mapping,
  501. OUT PCSTR *FileContent,
  502. OUT PCSTR *Eof
  503. )
  504. {
  505. STARTUPINFO si;
  506. PROCESS_INFORMATION pi;
  507. LONG rc;
  508. if (TempInput != INVALID_HANDLE_VALUE) {
  509. SetFilePointer (TempInput, 0, NULL, FILE_BEGIN);
  510. }
  511. if (TempOutput != INVALID_HANDLE_VALUE) {
  512. SetFilePointer (TempOutput, 0, NULL, FILE_BEGIN);
  513. SetEndOfFile (TempOutput);
  514. }
  515. ZeroMemory (&si, sizeof (si));
  516. si.dwFlags = STARTF_USESTDHANDLES;
  517. if (TempInput == INVALID_HANDLE_VALUE) {
  518. si.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
  519. } else {
  520. if (!DuplicateHandle (
  521. GetCurrentProcess(),
  522. TempInput,
  523. GetCurrentProcess(),
  524. &si.hStdInput,
  525. 0,
  526. TRUE,
  527. DUPLICATE_SAME_ACCESS
  528. )) {
  529. printf ("Can't dup temp input file handle\n");
  530. return FALSE;
  531. }
  532. }
  533. if (!DuplicateHandle (
  534. GetCurrentProcess(),
  535. TempOutput,
  536. GetCurrentProcess(),
  537. &si.hStdOutput,
  538. 0,
  539. TRUE,
  540. DUPLICATE_SAME_ACCESS
  541. )) {
  542. printf ("Can't dup temp output file handle\n");
  543. return FALSE;
  544. }
  545. si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
  546. if (!CreateProcess (
  547. NULL,
  548. CmdLine,
  549. NULL,
  550. NULL,
  551. TRUE,
  552. 0,
  553. NULL,
  554. NULL,
  555. &si,
  556. &pi
  557. )) {
  558. printf ("Can't launch sd describe\n");
  559. CloseHandle (si.hStdOutput);
  560. return FALSE;
  561. }
  562. printf ("%s", Msg);
  563. rc = WaitForSingleObject (pi.hProcess, INFINITE);
  564. printf ("\n");
  565. CloseHandle (pi.hProcess);
  566. CloseHandle (pi.hThread);
  567. CloseHandle (si.hStdOutput);
  568. if (rc != WAIT_OBJECT_0) {
  569. return FALSE;
  570. }
  571. if (!GetFileSize (TempOutput, NULL)) {
  572. return FALSE;
  573. }
  574. *Mapping = CreateFileMapping (TempOutput, NULL, PAGE_READONLY, 0, 0, NULL);
  575. if (!(*Mapping)) {
  576. printf ("Can't map temp file into memory\n");
  577. return FALSE;
  578. }
  579. *FileContent = (PCSTR) MapViewOfFile (*Mapping, FILE_MAP_READ, 0, 0, 0);
  580. if (!*FileContent) {
  581. printf ("Can't map temp file data into memory\n");
  582. CloseHandle (*Mapping);
  583. return FALSE;
  584. }
  585. *Eof = *FileContent + GetFileSize (TempOutput, NULL);
  586. return TRUE;
  587. }
  588. PCSTR
  589. pSkipMachineName (
  590. IN PCSTR LocalView
  591. )
  592. {
  593. if (LocalView[0] == '-' && LocalView[1] == '/' && LocalView[2] == '/') {
  594. return strchr (LocalView + 3, '/');
  595. }
  596. if (LocalView[0] == '/' && LocalView[1] == '/') {
  597. return strchr (LocalView + 2, '/');
  598. }
  599. return NULL;
  600. }
  601. BOOL
  602. pIsBranchInView (
  603. IN PCSTR ViewInLocalPath,
  604. IN PGROWLIST StoredSpec,
  605. OUT UINT *Index OPTIONAL
  606. )
  607. {
  608. UINT subPathTchars;
  609. UINT u;
  610. UINT count;
  611. PCSTR localSpecPath;
  612. PCSTR p1;
  613. PCSTR p2;
  614. p2 = pSkipMachineName (ViewInLocalPath);
  615. if (!p2) {
  616. return FALSE;
  617. }
  618. subPathTchars = TcharCount (p2);
  619. count = GlGetSize (StoredSpec);
  620. for (u = 0 ; u < count ; u++) {
  621. p1 = pSkipMachineName (GlGetString (StoredSpec, u));
  622. if (!p1) {
  623. continue;
  624. }
  625. if (StringIPrefix (p1, p2)) {
  626. if (p1[subPathTchars] == 0 || p1[subPathTchars] == '/') {
  627. if (Index) {
  628. *Index = u;
  629. }
  630. return TRUE;
  631. }
  632. }
  633. }
  634. return FALSE;
  635. }
  636. VOID
  637. pDumpBranchStatus (
  638. IN PGROWLIST BranchParent,
  639. IN PGROWLIST BranchStorage,
  640. IN PGROWLIST BranchProject,
  641. IN PGROWLIST BranchPath,
  642. IN PGROWLIST StoredSpec,
  643. IN PGROWLIST LocalSpec,
  644. IN PCSTR LocalRoot,
  645. IN PCSTR NtBinDir,
  646. IN PCSTR Root,
  647. IN PCSTR ComputerName
  648. )
  649. {
  650. UINT count;
  651. UINT u;
  652. UINT rootTchars;
  653. PCSTR p;
  654. PCSTR localBase;
  655. PSTR q;
  656. PCSTR baseOfPath;
  657. PCSTR fullPath;
  658. CHAR fullSpec[MAX_PATH * 2];
  659. BOOL outOfView = FALSE;
  660. count = GlGetSize (BranchParent);
  661. if (count != GlGetSize (BranchStorage)) {
  662. exit (1);
  663. }
  664. for (u = 0 ; u < count ; u++) {
  665. wsprintf (fullSpec, "//%s/%s", ComputerName, GlGetString (BranchPath, u));
  666. if (!pIsBranchInView (GlGetString (BranchStorage, u), StoredSpec, NULL)) {
  667. outOfView = TRUE;
  668. break;
  669. }
  670. }
  671. if (outOfView) {
  672. printf ("All Branch View Mappings:\n");
  673. } else {
  674. printf ("Branch View Mappings: (all are in client view)\n");
  675. }
  676. for (u = 0 ; u < count ; u++) {
  677. _tprintf (
  678. " %s //%s/%s\n",
  679. GlGetString (BranchStorage, u),
  680. ComputerName,
  681. GlGetString (BranchPath, u)
  682. );
  683. }
  684. if (outOfView) {
  685. printf ("\nOut-of-View Mapping:\n");
  686. for (u = 0 ; u < count ; u++) {
  687. wsprintf (fullSpec, "//%s/%s", ComputerName, GlGetString (BranchPath, u));
  688. if (!pIsBranchInView (GlGetString (BranchStorage, u), StoredSpec, NULL)) {
  689. _tprintf (
  690. " %s %s\n",
  691. GlGetString (BranchStorage, u),
  692. fullSpec
  693. );
  694. }
  695. }
  696. }
  697. rootTchars = TcharCount (Root);
  698. printf ("\nLocal View: (%s)\n", Root);
  699. for (u = 0 ; u < count ; u++) {
  700. p = GlGetString (BranchProject, u);
  701. if (!LocalRoot) {
  702. if (!p || StringIMatch (p, "root")) {
  703. baseOfPath = DuplicatePathString (NtBinDir, 0);
  704. } else {
  705. baseOfPath = JoinPaths (NtBinDir, p);
  706. }
  707. } else {
  708. baseOfPath = DuplicatePathString (LocalRoot, 0);
  709. }
  710. if (!baseOfPath) {
  711. exit (1);
  712. }
  713. fullPath = JoinPaths (baseOfPath, GlGetString (BranchPath, u));
  714. if (!fullPath) {
  715. exit (1);
  716. }
  717. FreePathString (baseOfPath);
  718. q = (PSTR) fullPath;
  719. while (*q) {
  720. if (*q == '/') {
  721. *q = '\\';
  722. }
  723. q++;
  724. }
  725. if (StringIPrefix (fullPath, Root) && (fullPath[rootTchars] == 0 || fullPath[rootTchars] == '\\')) {
  726. printf (" %s\n", fullPath);
  727. }
  728. FreePathString (fullPath);
  729. }
  730. printf ("\n");
  731. }
  732. BOOL
  733. pAddAllMappings (
  734. IN PGROWLIST BranchStorage,
  735. IN PGROWLIST BranchPath,
  736. IN OUT PGROWLIST StoredSpec,
  737. IN OUT PGROWLIST LocalSpec,
  738. IN PCSTR ComputerName
  739. )
  740. {
  741. UINT u;
  742. UINT count;
  743. CHAR fullSpec[MAX_PATH * 2];
  744. BOOL heading = TRUE;
  745. count = GlGetSize (BranchPath);
  746. for (u = 0 ; u < count ; u++) {
  747. wsprintf (fullSpec, "//%s/%s", ComputerName, GlGetString (BranchPath, u));
  748. if (!pIsBranchInView (GlGetString (BranchStorage, u), StoredSpec, NULL)) {
  749. if (heading) {
  750. heading = FALSE;
  751. printf ("Add to client view:\n");
  752. }
  753. printf (" %s %s\n", GlGetString (BranchStorage, u), fullSpec);
  754. GlAppendString (StoredSpec, GlGetString (BranchStorage, u));
  755. GlAppendString (LocalSpec, fullSpec);
  756. }
  757. }
  758. return heading == FALSE;
  759. }
  760. BOOL
  761. pDeleteAllMappings (
  762. IN PGROWLIST BranchStorage,
  763. IN PGROWLIST BranchPath,
  764. IN OUT PGROWLIST StoredSpec,
  765. IN OUT PGROWLIST LocalSpec,
  766. IN PCSTR ComputerName
  767. )
  768. {
  769. UINT u;
  770. UINT count;
  771. CHAR fullSpec[MAX_PATH * 2];
  772. BOOL heading = TRUE;
  773. BOOL restart;
  774. UINT delIndex;
  775. do {
  776. restart = FALSE;
  777. count = GlGetSize (BranchPath);
  778. for (u = 0 ; u < count ; u++) {
  779. wsprintf (fullSpec, "//%s/%s", ComputerName, GlGetString (BranchPath, u));
  780. if (pIsBranchInView (GlGetString (BranchStorage, u), StoredSpec, &delIndex)) {
  781. if (heading) {
  782. heading = FALSE;
  783. printf ("Remove from client view:\n");
  784. }
  785. printf (" %s %s\n", GlGetString (BranchStorage, u), fullSpec);
  786. GlDeleteItem (StoredSpec, delIndex);
  787. GlDeleteItem (LocalSpec, delIndex);
  788. restart = TRUE;
  789. break;
  790. }
  791. }
  792. } while (restart);
  793. return heading == FALSE;
  794. }
  795. BOOL
  796. pDumpClientView (
  797. IN HANDLE Output,
  798. IN PGROWLIST StoredSpec,
  799. IN PGROWLIST LocalSpec,
  800. IN PCSTR Client,
  801. IN PCSTR Root
  802. )
  803. {
  804. UINT u;
  805. UINT count;
  806. CHAR buffer[1024];
  807. wsprintf (buffer, "Client: %s\n\n", Client);
  808. if (!WriteFileString (Output, buffer)) {
  809. return FALSE;
  810. }
  811. wsprintf (buffer, "Root: %s\n\n", Root);
  812. if (!WriteFileString (Output, buffer)) {
  813. return FALSE;
  814. }
  815. wsprintf (buffer, "View:\n");
  816. if (!WriteFileString (Output, buffer)) {
  817. return FALSE;
  818. }
  819. count = GlGetSize (StoredSpec);
  820. for (u = 0 ; u < count ; u++) {
  821. wsprintf (buffer, " %s %s\n", GlGetString (StoredSpec, u), GlGetString (LocalSpec, u));
  822. if (!WriteFileString (Output, buffer)) {
  823. return FALSE;
  824. }
  825. }
  826. return TRUE;
  827. }
  828. INT
  829. __cdecl
  830. _tmain (
  831. INT argc,
  832. PCTSTR argv[]
  833. )
  834. {
  835. INT i;
  836. PCSTR branchName[MAX_BRANCHES];
  837. UINT branches = 0;
  838. UINT u;
  839. UINT count;
  840. PCSTR localRoot = NULL;
  841. CHAR fullRoot[MAX_PATH];
  842. BOOL dumpStatus = FALSE;
  843. BOOL deleteMode = FALSE;
  844. PSTR dontCare;
  845. DWORD rc;
  846. //
  847. // TODO: Parse command line here
  848. //
  849. for (i = 1 ; i < argc ; i++) {
  850. if (argv[i][0] == TEXT('/') || argv[i][0] == TEXT('-')) {
  851. switch (tolower (argv[i][1])) {
  852. case 'o':
  853. if (dumpStatus) {
  854. HelpAndExit();
  855. }
  856. dumpStatus = TRUE;
  857. break;
  858. case 'd':
  859. if (deleteMode) {
  860. HelpAndExit();
  861. }
  862. deleteMode = TRUE;
  863. break;
  864. case 'p':
  865. if (localRoot) {
  866. HelpAndExit();
  867. }
  868. if (argv[i][2] == ':') {
  869. localRoot = &(argv[i][3]);
  870. } else {
  871. i++;
  872. if (i == argc) {
  873. HelpAndExit();
  874. }
  875. localRoot = argv[i];
  876. }
  877. rc = GetFullPathName (localRoot, ARRAYSIZE(fullRoot), fullRoot, &dontCare);
  878. if (rc == 0 || rc >= ARRAYSIZE(fullRoot)) {
  879. fprintf (stderr, "Can't get full path of %s\n", localRoot);
  880. exit (1);
  881. }
  882. localRoot = fullRoot;
  883. break;
  884. case 'c':
  885. if (g_Commit) {
  886. HelpAndExit();
  887. }
  888. g_Commit = TRUE;
  889. break;
  890. default:
  891. HelpAndExit();
  892. }
  893. } else {
  894. //
  895. // Parse other args that don't require / or -
  896. //
  897. if (branches == MAX_BRANCHES) {
  898. HelpAndExit();
  899. }
  900. branchName[branches++] = argv[i];
  901. }
  902. }
  903. if (!branches) {
  904. HelpAndExit();
  905. }
  906. //
  907. // Begin processing
  908. //
  909. if (!Init()) {
  910. return 0;
  911. }
  912. //
  913. // TODO: Do work here
  914. //
  915. {
  916. TCHAR cmd[MAX_PATH];
  917. HANDLE tempInput;
  918. HANDLE tempOut;
  919. HANDLE mapping;
  920. PCSTR fileData;
  921. PCSTR endOfFile;
  922. CHAR root[MAX_PATH];
  923. CHAR client[MAX_PATH];
  924. GROWLIST parentBranch = INIT_GROWLIST;
  925. GROWLIST branchStorage = INIT_GROWLIST;
  926. GROWLIST branchProject = INIT_GROWLIST;
  927. GROWLIST branchPath = INIT_GROWLIST;
  928. GROWLIST storedSpec = INIT_GROWLIST;
  929. GROWLIST localSpec = INIT_GROWLIST;
  930. PCTSTR ntBinDir;
  931. BOOL changed = FALSE;
  932. UINT currentBranch;
  933. ntBinDir = getenv ("_NTBINDIR");
  934. if (!ntBinDir && !localRoot) {
  935. fprintf (stderr, "%%_NTBINDIR%% required to be set\n");
  936. exit (1);
  937. }
  938. tempInput = BfGetTempFile (); // handle & file cleans up with process termination
  939. if (!tempInput) {
  940. printf ("Can't create temp input file\n");
  941. exit (1);
  942. }
  943. tempOut = BfGetTempFile (); // handle & file cleans up with process termination
  944. if (!tempOut) {
  945. printf ("Can't create temp output file\n");
  946. exit (1);
  947. }
  948. for (currentBranch = 0 ; currentBranch < branches ; currentBranch++) {
  949. printf ("Branch: %s\n\n", branchName[currentBranch]);
  950. wsprintf (cmd, TEXT("sd branch -o %s"), branchName[currentBranch]);
  951. if (!pLaunchSd (
  952. cmd,
  953. INVALID_HANDLE_VALUE,
  954. tempOut,
  955. "Getting branch mapping...",
  956. &mapping,
  957. &fileData,
  958. &endOfFile
  959. )) {
  960. exit (1);
  961. }
  962. if (!pParseBranchMapping (fileData, endOfFile, &parentBranch, &branchStorage)) {
  963. exit (1);
  964. }
  965. if (!pLaunchSd (
  966. TEXT("sd client -o"),
  967. INVALID_HANDLE_VALUE,
  968. tempOut,
  969. "Getting client mapping...",
  970. &mapping,
  971. &fileData,
  972. &endOfFile
  973. )) {
  974. exit (1);
  975. }
  976. if (!pParseClientMapping (fileData, endOfFile, client, root, &storedSpec, &localSpec)) {
  977. exit (1);
  978. }
  979. if (localRoot) {
  980. if (!StringIPrefix (localRoot, root)) {
  981. fprintf (stderr, "Local root %s must be in client root of %s\n", localRoot, root);
  982. exit (1);
  983. }
  984. }
  985. if (!pVerifyBranch (branchName[currentBranch], &branchStorage, &branchProject, &branchPath, localRoot, root)) {
  986. exit (1);
  987. }
  988. printf ("\n\n");
  989. if (dumpStatus) {
  990. pDumpBranchStatus (
  991. &parentBranch,
  992. &branchStorage,
  993. &branchProject,
  994. &branchPath,
  995. &storedSpec,
  996. &localSpec,
  997. localRoot,
  998. ntBinDir,
  999. root,
  1000. client
  1001. );
  1002. } else if (deleteMode) {
  1003. changed = pDeleteAllMappings (
  1004. &branchStorage,
  1005. &branchPath,
  1006. &storedSpec,
  1007. &localSpec,
  1008. client
  1009. );
  1010. } else {
  1011. changed = pAddAllMappings (
  1012. &branchStorage,
  1013. &branchPath,
  1014. &storedSpec,
  1015. &localSpec,
  1016. client
  1017. );
  1018. }
  1019. if (changed) {
  1020. if (!g_Commit) {
  1021. printf ("\nChanges not committed -- specify -c to commit\n");
  1022. } else {
  1023. SetFilePointer (tempInput, 0, NULL, FILE_BEGIN);
  1024. if (!pDumpClientView (tempInput, &storedSpec, &localSpec, client, root)) {
  1025. fprintf (stderr, "Error writing to temp file\n");
  1026. exit (1);
  1027. }
  1028. printf ("\n");
  1029. if (!pLaunchSd (
  1030. TEXT("sd client -i"),
  1031. tempInput,
  1032. tempOut,
  1033. "Setting client mapping...",
  1034. &mapping,
  1035. &fileData,
  1036. &endOfFile
  1037. )) {
  1038. exit (1);
  1039. }
  1040. printf ("\nChanges committed. Run sd sync to update your enlistment.\n\n");
  1041. }
  1042. } else {
  1043. printf ("No changes made.\n\n");
  1044. }
  1045. GlFree (&parentBranch);
  1046. GlFree (&branchStorage);
  1047. GlFree (&branchProject);
  1048. GlFree (&branchPath);
  1049. GlFree (&storedSpec);
  1050. GlFree (&localSpec);
  1051. }
  1052. }
  1053. //
  1054. // End of processing
  1055. //
  1056. Terminate();
  1057. return 0;
  1058. }