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.

1889 lines
70 KiB

  1. #define trace
  2. /*
  3. *
  4. * client library for remote checksum server
  5. *
  6. * functions for connecting to the server pipe, and reading
  7. * and writing messages.
  8. *
  9. * !! DEBUG HINT: !!
  10. *
  11. * - ENABLE Trace_Stat and Trace_Fil about 30 lines below here
  12. * so that they generate file output.
  13. * F11 from Windiff will do the trick on a debug build version!
  14. *
  15. * expects Trace_Error() to be defined in the client program.
  16. */
  17. #include <windows.h>
  18. #include <lzexpand.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <gutils.h>
  22. #include <list.h>
  23. #include "..\server\sumserve.h"
  24. #include "..\windiff\windiff.h" // for TRACE_ERROR and Windiff_UI which it calls
  25. #include "ssclient.h"
  26. /* need to sort out header files !!! */
  27. void SetNames(LPSTR names); /* from Windiff !!! */
  28. void SetStatus(LPSTR cmd);
  29. ULONG ss_checksum_block(PSTR block, int size);
  30. DWORD WINAPI ReceiveFiles(LPVOID handle);
  31. #ifdef SOCKETS
  32. BOOL GetFile(SOCKET hpipe, PSTR localpath, PSSNEWRESP presp);
  33. #else
  34. BOOL GetFile(HANDLE hpipe, PSTR localpath, PSSNEWRESP presp);
  35. #endif
  36. HANDLE ConnectPipe(PSTR pipename);
  37. extern BOOL bTrace; /* in Windiff.c */
  38. int CountRetries = 5;
  39. /* SOCKETS / NAMED PIPES macros
  40. */
  41. #ifdef SOCKETS
  42. #define MAYBESOCKETTYPE SOCKET
  43. #define CLOSEHANDLE( handle ) closesocket( handle )
  44. #else
  45. #define MAYBESOCKETTYPE HANDLE
  46. #define CLOSEHANDLE( handle ) CloseHandle( handle )
  47. #endif
  48. /*--------------------------- DEBUG FUNCTIONS ----------------------------*/
  49. void Trace_Stat(LPSTR str)
  50. {
  51. if (bTrace) {
  52. Trace_File(str);
  53. Trace_File("\n");
  54. }
  55. Trace_Status(str);
  56. }/* Trace_Stat */
  57. void Trace_Fil(LPSTR str)
  58. {
  59. if (bTrace) {
  60. Trace_File(str);
  61. }
  62. } /* Trace_Fil */
  63. /*------------------------------------------------------------------------*/
  64. static char MainPipeName[400]; /* pipe name for requests to server */
  65. extern BOOL bAbort; /* abort flag from Windiff */
  66. /* set up pipename for main pipe */
  67. void InitPipeName(PSTR result, PSTR server, PSTR name)
  68. { sprintf(result, "\\\\%s\\pipe\\%s", server, name);
  69. } /* InitPipeName */
  70. /* ss_connect:
  71. * make a connection to the server.
  72. *
  73. * create the correct pipe name \\server\pipe\NPNAME,
  74. * connect to the pipe and set the pipe to message mode.
  75. *
  76. * return INVALID_HANDLE_VALUE if failure
  77. */
  78. HANDLE
  79. ss_connect(PSTR server)
  80. { char pipename[400];
  81. InitPipeName(pipename, server, NPNAME);
  82. return ConnectPipe(pipename);
  83. } /* ss_connect */
  84. VOID
  85. ss_setretries(int retries)
  86. {
  87. CountRetries = retries;
  88. }
  89. /* ss_connect:
  90. * make a connection to the pipe named.
  91. *
  92. * connect to the pipe and set the pipe to message mode.
  93. *
  94. * return INVALID_HANDLE_VALUE if failure
  95. */
  96. HANDLE ConnectPipe(PSTR pipename)
  97. {
  98. HANDLE hpipe;
  99. DWORD dwState;
  100. int i;
  101. BOOL haderror = FALSE;
  102. { char msg[400];
  103. wsprintf(msg, "ConnectPipe to %s\n", pipename);
  104. Trace_Fil(msg);
  105. }
  106. for (; ; ){ /* repeat if user asks */
  107. int MsgBoxId;
  108. /* repeat connect attempt up to 5 times without asking. */
  109. for (i= 0; i < CountRetries; i++) {
  110. if (bAbort) return INVALID_HANDLE_VALUE;
  111. /* connect to the named pipe */
  112. hpipe = CreateFile(pipename,
  113. GENERIC_READ|GENERIC_WRITE,
  114. FILE_SHARE_READ|FILE_SHARE_WRITE,
  115. NULL,
  116. OPEN_EXISTING,
  117. FILE_ATTRIBUTE_NORMAL,
  118. 0);
  119. if (hpipe != INVALID_HANDLE_VALUE) {
  120. /* switch the pipe to message mode */
  121. dwState = PIPE_WAIT | PIPE_READMODE_MESSAGE;
  122. SetNamedPipeHandleState(hpipe, &dwState, NULL, NULL);
  123. if (haderror) {
  124. Trace_Stat("connection ok");
  125. }
  126. { char msg[80];
  127. wsprintf(msg, "ConnectedPipe hpipe %x\n", HandleToUlong(hpipe));
  128. Trace_Fil(msg);
  129. }
  130. return(hpipe);
  131. }
  132. else {
  133. DWORD errorcode = GetLastError();
  134. char msg[400];
  135. wsprintf(msg, "Error %d on Create Pipe %s", errorcode, pipename);
  136. Trace_Stat(msg);
  137. }
  138. /* connect failed - wait one seconds before retrying */
  139. if (CountRetries > 1) {
  140. Sleep(1000);
  141. }
  142. /*
  143. * only report success with Trace_Stat if we also
  144. * reported an error (don't disturb the user
  145. * unnecessarily - he just see nothing unusual if all goes well
  146. */
  147. haderror = TRUE;
  148. Trace_Stat("Retrying pipe connection...");
  149. } /* retry 5 loop */
  150. if (CountRetries > 1) {
  151. windiff_UI(TRUE);
  152. MsgBoxId = MessageBox( hwndClient
  153. , "Pipe connection failed 5 times. Retry some more?"
  154. , "Windiff: Network connection error"
  155. , MB_RETRYCANCEL
  156. );
  157. windiff_UI(FALSE);
  158. if (MsgBoxId != IDRETRY)
  159. break;
  160. } else {
  161. break;
  162. }
  163. } /* ask loop */
  164. Trace_Fil("ConnectPipe failed");
  165. return(INVALID_HANDLE_VALUE);
  166. } /* ConnectPipe */
  167. /* build and send a request message to the server. Check for network
  168. * errors, and retry (unless the pipe is broken) up to 10 times.
  169. *
  170. * if write succeeds - return TRUE.
  171. * if failure - return FALSE to indicate connection is dropped.
  172. */
  173. BOOL
  174. ss_sendrequest(HANDLE hpipe, long lCode, PSTR szPath, int lenpath, DWORD dwFlags)
  175. {
  176. SSNEWREQ req;
  177. int size, count, errorcode;
  178. Trace_Fil("ss_sendrequest\n");
  179. req.lCode = -lCode; /* negative code for versions greater than 0 */
  180. req.lVersion = SS_VERSION;
  181. req.lRequest = LREQUEST;
  182. req.lFlags = dwFlags;
  183. if (szPath != NULL) {
  184. /* szPath may be more than one null-term string,
  185. * so copy the bytes rather than a strcpy().
  186. */
  187. for (size = 0; size < lenpath; size++) {
  188. req.szPath[size] = szPath[size];
  189. }
  190. } else {
  191. req.szPath[0] = '\0';
  192. }
  193. /* trace stuff */
  194. { char msg[80];
  195. wsprintf(msg, "Sending request: %d on pipe %x\n", req.lCode, HandleToUlong(hpipe));
  196. Trace_Fil(msg);
  197. }
  198. /* loop retrying the send until it goes ok */
  199. for (count = 0; count < CountRetries; count++) {
  200. if (bAbort) {
  201. CloseHandle(hpipe);
  202. return FALSE;
  203. }
  204. #ifdef trace
  205. { char msg[80];
  206. wsprintf(msg, "Actually sending on pipe %x... ", HandleToUlong(hpipe));
  207. Trace_Fil(msg);
  208. }
  209. #endif
  210. if (WriteFile(hpipe, &req, sizeof(req), (LPDWORD)(&size), NULL)) {
  211. #ifdef trace
  212. { char msg[80];
  213. wsprintf(msg, "Sent req %d OK, pipe %x\n", req.lCode, HandleToUlong(hpipe));
  214. Trace_Fil(msg);
  215. }
  216. #endif
  217. /* no error reported - was everything written?*/
  218. if (size != sizeof(req)) {
  219. /* write was NOT ok - report and retry */
  220. if (!TRACE_ERROR("pipe write size differs... Retry?", TRUE)) {
  221. return(FALSE);
  222. }
  223. continue;
  224. } else {
  225. /* all ok */
  226. char msg[80];
  227. wsprintf(msg, "Request %d sent on %x\n", req.lCode, HandleToUlong(hpipe));
  228. Trace_Fil(msg);
  229. return(TRUE);
  230. }
  231. }
  232. #ifdef trace
  233. { char msg[80];
  234. wsprintf(msg, "!!Bad send pipe %x\n", HandleToUlong(hpipe));
  235. Trace_Fil(msg);
  236. }
  237. #endif
  238. /* an error occurred */
  239. switch( (errorcode = (int)GetLastError())) {
  240. case ERROR_NO_DATA:
  241. case ERROR_BROKEN_PIPE:
  242. /* pipe connection lost - forget it */
  243. Trace_Stat("pipe broken on write");
  244. return(FALSE);
  245. default:
  246. { char msg[120];
  247. wsprintf(msg, "pipe write error %d on pipe %x. Retrying..."
  248. , errorcode, HandleToUlong(hpipe));
  249. Trace_Stat(msg);
  250. }
  251. Sleep(count*1000); /* total sleep possible is 45 sec */
  252. break; /* from switch, not loop */
  253. }
  254. }
  255. /* retry count reached - abandon this attempt */
  256. TRACE_ERROR("retry count reached on pipe write error.", FALSE);
  257. return(FALSE);
  258. } /* ss_sendrequest */
  259. /* read a message from a pipe, allowing for network errors
  260. *
  261. * if error occurs, retry up to 10 times unless error code
  262. * indicates that pipe is broken - in which case, give up.
  263. *
  264. * return size read if all ok, -1 to mean the connection is broken,
  265. * abort this client, 0 to mean other error.
  266. */
  267. int
  268. ss_getblock(HANDLE hpipe, PSTR block, int blocksize)
  269. {
  270. int count;
  271. int size;
  272. int errorcode;
  273. static BOOL PipeError = FALSE;
  274. char msg[200];
  275. wsprintf(msg, "ss_getblock. hpipe=%x\n", HandleToUlong(hpipe));
  276. Trace_Fil(msg);
  277. /* retry up to 10 times */
  278. for (count = 0; count < CountRetries; count++ ) {
  279. if (bAbort) {
  280. CloseHandle(hpipe);
  281. return -1;
  282. }
  283. #ifdef trace
  284. {
  285. wsprintf(msg, "Actual receive pipe %x...", HandleToUlong(hpipe));
  286. Trace_Fil(msg);
  287. }
  288. #endif
  289. if (ReadFile(hpipe, block, blocksize, (LPDWORD)(&size), NULL)) {
  290. #ifdef trace
  291. {
  292. wsprintf(msg, "Good receive pipe %x\n", HandleToUlong(hpipe));
  293. Trace_Fil(msg);
  294. }
  295. #endif
  296. /* check size of message */
  297. if (size == 0) {
  298. Trace_Fil("zero length message\r\n");
  299. continue;
  300. }
  301. /* everything ok */
  302. { SSNEWRESP * ssp;
  303. ssp = (PSSNEWRESP) block;
  304. wsprintf( msg, "ss_getblock got block OK pipe %x: %x %x %x %x %x\n"
  305. , HandleToUlong(hpipe)
  306. , ssp->lVersion, ssp->lResponse, ssp->lCode, ssp->ulSize
  307. , ssp->fileattribs
  308. );
  309. Trace_Fil ( msg );
  310. }
  311. if (PipeError) {
  312. PipeError = FALSE;
  313. SetStatus("Pipe recovered");
  314. }
  315. return size;
  316. }
  317. #ifdef trace
  318. {
  319. wsprintf(msg, "!!Bad receive pipe %x\n", HandleToUlong(hpipe));
  320. Trace_Fil(msg);
  321. }
  322. #endif
  323. /* error occurred - check code */
  324. switch((errorcode = (int)GetLastError())) {
  325. case ERROR_BROKEN_PIPE:
  326. /* connection broken. no point in retrying */
  327. {
  328. wsprintf( msg, "pipe %x broken on read.", HandleToUlong(hpipe));
  329. TRACE_ERROR(msg, FALSE);
  330. }
  331. return(-1);
  332. case ERROR_MORE_DATA:
  333. /* the message sent is larger than our buffer.
  334. * this is an internal error - report it and carry on
  335. */
  336. {
  337. SSNEWRESP * ssp;
  338. wsprintf( msg, "message too large on pipe %x blocksize=%d data="
  339. , HandleToUlong(hpipe), blocksize
  340. );
  341. Trace_Fil(msg);
  342. ssp = (PSSNEWRESP) block;
  343. wsprintf( msg, "%8x %8x %8x %8x %8x\n"
  344. , ssp->lVersion, ssp->lResponse, ssp->lCode, ssp->ulSize
  345. , ssp->fileattribs
  346. );
  347. Trace_Fil(msg);
  348. }
  349. /* Too low a level for message to user. Recoverable at higher level
  350. ** TRACE_ERROR("internal error- message too large", FALSE);
  351. */
  352. return -2;
  353. default:
  354. {
  355. wsprintf(msg, "read error %d on pipe %x", errorcode, HandleToUlong(hpipe));
  356. Trace_Stat(msg);
  357. }
  358. Sleep(count*1000);
  359. break;
  360. }
  361. }
  362. SetStatus("Pipe error");
  363. PipeError = TRUE;
  364. TRACE_ERROR("retry count reached on pipe read error.", FALSE);
  365. return 0;
  366. } /* ss_getblock */
  367. /*
  368. * read a standard response from the net, retrying if necessary. return
  369. * size if ok or <=0 if not. -1 means pipe broken.
  370. */
  371. int
  372. ss_getresponse(HANDLE hpipe, PSSNEWRESP presp)
  373. {
  374. Trace_Fil("ss_getresponse\n");
  375. return(ss_getblock(hpipe, (PSTR) presp, sizeof(SSNEWRESP)));
  376. } /* ss_getresponse */
  377. /*
  378. * terminate the connection to the server. send an END message and
  379. * close the pipe
  380. */
  381. void
  382. ss_terminate(HANDLE hpipe)
  383. {
  384. Trace_Fil("ss_terminate\n");
  385. ss_sendrequest(hpipe, SSREQ_END, NULL, 0,0);
  386. CloseHandle(hpipe);
  387. } /* ss_terminate */
  388. /* send a unc & password request. the password and the server strings
  389. * are both held in the buffer as two consecutive null-terminated strings
  390. */
  391. BOOL
  392. ss_sendunc(HANDLE hpipe, PSTR password, PSTR server)
  393. {
  394. char buffer[MAX_PATH] = {0};
  395. char * cp;
  396. int len;
  397. Trace_Fil("ss_sendunc\n");
  398. strncat(buffer, password, sizeof(buffer)-1);
  399. cp = &buffer[strlen(buffer) + 1];
  400. strcpy(cp,server);
  401. len = (int)((cp - buffer) + strlen(cp) + 1);
  402. return(ss_sendrequest(hpipe, SSREQ_UNC, buffer, len, 0));
  403. }
  404. /*
  405. * checksum a single file using the checksum server
  406. */
  407. BOOL
  408. ss_checksum_remote( HANDLE hpipe, PSTR path
  409. , ULONG * psum, FILETIME * pft, LONG * pSize, DWORD *pAttr )
  410. {
  411. SSNEWRESP resp;
  412. char msg[400];
  413. *psum = 0;
  414. if (!ss_sendrequest(hpipe, SSREQ_SCAN, path, strlen(path)+1, 0)) {
  415. return(FALSE);
  416. }
  417. if (0>=ss_getresponse(hpipe, &resp)) {
  418. return(FALSE);
  419. }
  420. if (resp.lResponse != LRESPONSE) {
  421. return(FALSE);
  422. }
  423. switch(resp.lCode) {
  424. case SSRESP_END:
  425. TRACE_ERROR("No remote files found", FALSE);
  426. return(FALSE);
  427. case SSRESP_ERROR:
  428. if (resp.ulSize!=0) {
  429. wsprintf( msg, "Checksum server could not read %s win32 code %d"
  430. , resp.szFile, resp.ulSize
  431. );
  432. }
  433. else
  434. wsprintf(msg, "Checksum server could not read %s", resp.szFile);
  435. TRACE_ERROR(msg, FALSE);
  436. return(FALSE);
  437. case SSRESP_CANTOPEN:
  438. wsprintf(msg, "Checksum server could not open %s", resp.szFile);
  439. TRACE_ERROR(msg, FALSE);
  440. return(FALSE);
  441. case SSRESP_FILE:
  442. *psum = resp.ulSum;
  443. *pSize = resp.ulSize;
  444. *pft = resp.ft_lastwrite;
  445. *pAttr = resp.fileattribs;
  446. /* read and discard any further packets until SSRESP_END */
  447. while(0<ss_getresponse(hpipe, &resp)) {
  448. if (resp.lCode == SSRESP_END) {
  449. break;
  450. }
  451. }
  452. return(TRUE);
  453. case SSRESP_DIR:
  454. wsprintf(msg, "Checksum server thinks %s is a directory", resp.szFile);
  455. TRACE_ERROR(msg, FALSE);
  456. return(FALSE);
  457. default:
  458. wsprintf(msg, "Bad code from checksum server:%d", resp.lCode);
  459. TRACE_ERROR(msg, FALSE);
  460. return(FALSE);
  461. }
  462. } /* ss_checksum_remote */
  463. /*****************************************************************************
  464. Bulk copying of files:
  465. Our caller should call ss_startcopy to set things up and then
  466. call ss_bulkcopy as many times as necessary to transmit the
  467. file names and then ss_endcopy to wait for the spawned threads
  468. to finish. It is also possible to copy a single file by
  469. ss_copy_reliable. For multiple files, bulkcopy should be
  470. much faster.
  471. Overall organisation, threads etc:
  472. There are multiple threads in the server. Read the writeup
  473. in ..\server\files.c if you want to understand those. Read
  474. that writeup ANYWAY to understand the link protocols (i.e.
  475. which messages are sent in which order between client and server).
  476. ss_startcopy kicks off a thread to do the actual receiving.
  477. It exits when it receives a SSRESP_END.
  478. Within this thread we do most of the processing synchronously. We
  479. rely on a file system that does lazy writing to disk to give
  480. us effectively a pipeline that gets the file written to disk
  481. in parallel with reading the pipe so that with luck we can always
  482. be waiting for the data to arrive through the pipe and never have
  483. the pipe waiting for us.
  484. The decompression of a file is a lengthy business, so we spawn threads
  485. to do that. We need to check the return codes of the decompression,
  486. so we get that via GetExitCodeThread. We put the hThreads that we
  487. create onto a LIST and periodically (after every file) run down this
  488. list trying to get exit codes. When we get a code other than STILL_ACTIVE
  489. we interpret it as good or bad, add to the counts of nGoodFiles or
  490. nBadFiles and delete it from the list. ss_endcopy will wait for all
  491. the decompression to finish by running down the list WAITing for the
  492. hThreads. Because we purge the list regularly it should never get
  493. very long. We are worried about the prospect of having 1000 dead
  494. threads lying around if we don't purge it.
  495. If a copy fails (i.e. the checksum on arrival after unpacking is different
  496. from that sent in the SSNEWRESP header for the file) then we call
  497. ss_copy_reliable to have it re-sent. If we just call that right away, it
  498. seems to cause confusion. As far as I can tell the attempt to open up
  499. a new pipe doesn't seem to work properly (the two processes interfere).
  500. The symptom is that we promptly get out of step on the data pipe (??!) with
  501. data packets arriving when we expected response packets.
  502. So we keep a list of things to be retried and retry them by serially doing
  503. a ss_copy_reliable for each one after the rest of the copying has finished.
  504. ****************************************************************************/
  505. /* The following are remembered across startcopy..bulkcopy..endcopy
  506. They correspond to the all-lower-case versions given as
  507. parameters to ss_copy_reliable
  508. Note that this is per-process storage, so multiple windiffs should be OK.
  509. */
  510. static char Server[MAX_PATH]; /* machine running sumserve */
  511. static char UNCName[MAX_PATH]; /* \\server\share for remote files */
  512. static char Password[MAX_PATH]; /* for remote share */
  513. static BOOL BulkCopy = FALSE; /* to prevent simple copy during bulk*/
  514. static int nGoodFiles = 0; /* number received OK */
  515. static int nBadFiles = 0; /* number received with errors */
  516. static int nFiles = 0; /* number requested */
  517. static HANDLE hThread = INVALID_HANDLE_VALUE; /* the receiving thread */
  518. static HANDLE hpipe = INVALID_HANDLE_VALUE; /* the main pipe to send names*/
  519. #ifdef SOCKETS
  520. static SOCKET hpData = (SOCKET)INVALID_HANDLE_VALUE; /* the data pipe to get files*/
  521. #else
  522. static HANDLE hpData = INVALID_HANDLE_VALUE; /* the data pipe to get files*/
  523. #endif
  524. static LIST Decomps = NULL; /* hThreads of decompressers */
  525. static LIST Retries = NULL; /* DECOMPARGS to retry */
  526. /* Thread arguments for the decompress thread */
  527. typedef struct{
  528. DWORD fileattribs;
  529. FILETIME ft_create;
  530. FILETIME ft_lastaccess;
  531. FILETIME ft_lastwrite;
  532. long lCode; /* success code from file xfer so far */
  533. ULONG ulSum; /* checksum for file */
  534. BOOL bSumValid; /* TRUE iff there was a checksum for file */
  535. char Temp[MAX_PATH]; /* temp path == source */
  536. char Real[MAX_PATH]; /* real path == target */
  537. char Remote[MAX_PATH]; /* remote path to allow retry */
  538. } DECOMPARGS;
  539. /* forward declarations */
  540. int Decompress(DECOMPARGS * da);
  541. void SpawnDecompress(PSTR TempPath, PSTR RealPath, PSSNEWRESP presp);
  542. void PurgeDecomps(LIST Decs);
  543. /* ss_startcopy
  544. Set things up for bulkcopy
  545. Because we expect to send a list of names off and get a list of
  546. files back, we need to keep track of the local names so that we can
  547. associate the file with the right name. This means either sending our
  548. local name across the link and back or else keeping a list of
  549. them here. The list could be long (typically 1000 for an NT build).
  550. MAX_PATH is 260 or 520 bytes if unicoded.
  551. and so long as this involves no extra line turnarounds, this might take
  552. as long as 520 /8K secs *2 (there and back) or about 130mSec.
  553. (We have seen 8K bytes/sec sustained over a period). Probably the
  554. true burst data rate is 32Kbytes/sec giving about 30msec.
  555. Either way this is only 30 secs to 2 mins per build overhead.
  556. Of course it's much shorter for normal paths, especially as we pack
  557. the data end to end (like a superstring but without the 00 at the end).
  558. So for the above reasons the local (client) name is transmitted with the
  559. file request and sent back with the file in a SSNEWRESP.
  560. */
  561. BOOL ss_startcopy(PSTR server, PSTR uncname, PSTR password)
  562. { int retry;
  563. SSNEWRESP resp; /* buffer for messages received */
  564. DWORD ThreadId; /* to keep CreateThread happy */
  565. #ifdef SOCKETS
  566. static BOOL SocketsInitialized = FALSE;
  567. #endif
  568. Trace_Fil("ss_startcopy\n");
  569. nFiles = 0; nGoodFiles = 0; nBadFiles = 0;
  570. /* don't need a crit sect here because this runs on the main thread */
  571. if (BulkCopy) return FALSE; /* already running! */
  572. BulkCopy = TRUE;
  573. if (server!=NULL) strcpy(Server, server); else Server[0] = '\0';
  574. if (uncname!=NULL) strcpy(UNCName, uncname); else UNCName[0] = '\0';
  575. if (password!=NULL) strcpy(Password, password); else Password[0] = '\0';
  576. { char msg[400];
  577. wsprintf(msg, "Server '%s' UNC '%s' pass '%s'\n", Server, UNCName, Password);
  578. Trace_Fil(msg);
  579. }
  580. /* create the list of decompressor hThreads */
  581. Decomps = List_Create();
  582. Retries = List_Create();
  583. for (retry = 0; retry < 10; retry++) {
  584. if (hpipe!=INVALID_HANDLE_VALUE) {
  585. Trace_Fil("ss_startcopy closing pipe for retry");
  586. CloseHandle(hpipe);
  587. hpipe = INVALID_HANDLE_VALUE;
  588. }
  589. if (bAbort) {
  590. CloseHandle(hpipe);
  591. hpipe = INVALID_HANDLE_VALUE;
  592. return FALSE;
  593. }
  594. /* connect to main pipe */
  595. { char pipename[400];
  596. InitPipeName(pipename, server, NPNAME);
  597. hpipe = ConnectPipe(pipename);
  598. }
  599. if (hpipe == INVALID_HANDLE_VALUE) {
  600. /* next retry in two seconds */
  601. Trace_Stat("connect failed - retrying");
  602. Sleep(1000);
  603. continue;
  604. }
  605. { char msg[80];
  606. wsprintf(msg, "ConnectedPipe to pipe number %x\n",HandleToUlong(hpipe));
  607. Trace_Fil(msg);
  608. }
  609. if ((uncname != NULL) && (password != NULL)) {
  610. /* send the password request */
  611. if (!ss_sendunc(hpipe, password, uncname)) {
  612. Trace_Fil("Server connection lost (1)\n");
  613. TRACE_ERROR("Server connection lost", FALSE);
  614. CloseHandle(hpipe);
  615. hpipe = INVALID_HANDLE_VALUE;
  616. continue;
  617. }
  618. /* wait for password response */
  619. if (0>=ss_getresponse(hpipe, &resp)) {
  620. Trace_Fil("Server connection lost (2)\n");
  621. TRACE_ERROR("Server connection lost", FALSE);
  622. continue;
  623. }
  624. if (resp.lResponse != LRESPONSE) {
  625. Trace_Fil("Password - bad response\n");
  626. TRACE_ERROR("Password - bad response", FALSE);
  627. return(FALSE);
  628. }
  629. if (resp.lCode != SSRESP_END) {
  630. Trace_Fil("Password attempt failed\n");
  631. TRACE_ERROR("Password attempt failed", FALSE);
  632. return(FALSE);
  633. }
  634. }
  635. break;
  636. } /* retry loop */
  637. if (hpipe == INVALID_HANDLE_VALUE) {
  638. return FALSE;
  639. }
  640. #ifdef SOCKETS
  641. if( !SocketsInitialized )
  642. {
  643. WSADATA WSAData;
  644. if( ( WSAStartup( MAKEWORD( 1, 1 ), &WSAData ) ) == 0 )
  645. {
  646. SocketsInitialized = TRUE;
  647. }
  648. else
  649. {
  650. TRACE_ERROR("WSAStartup failed", FALSE);
  651. }
  652. }
  653. #endif
  654. /* Tell server we want to send a file list */
  655. if(!ss_sendrequest( hpipe, SSREQ_FILES, NULL, 0, 0)){
  656. return FALSE;
  657. }
  658. /* expect a reply which names a data pipe */
  659. {
  660. if ( 0>=ss_getresponse(hpipe, &resp) ){
  661. Trace_Fil("Couldn't get data pipe name\n");
  662. TRACE_ERROR("Couldn't get data pipe name", FALSE);
  663. CloseHandle(hpipe);
  664. hpipe = INVALID_HANDLE_VALUE;
  665. return FALSE;
  666. }
  667. if ( resp.lResponse!=LRESPONSE){
  668. Trace_Fil("Bad RESPONSE when expecting data pipe name\n");
  669. TRACE_ERROR("Bad RESPONSE when expecting data pipe name", FALSE);
  670. CloseHandle(hpipe);
  671. hpipe = INVALID_HANDLE_VALUE;
  672. return FALSE;
  673. }
  674. if ( resp.lCode!=SSRESP_PIPENAME){
  675. char msg[80];
  676. TRACE_ERROR("Wrong response when expecting data pipe name", FALSE);
  677. wsprintf(msg
  678. ,"Wrong response (%d) when expecting data pipe name\n"
  679. , resp.lCode);
  680. Trace_Fil(msg);
  681. CloseHandle(hpipe);
  682. hpipe = INVALID_HANDLE_VALUE;
  683. return FALSE;
  684. }
  685. { char msg[400];
  686. wsprintf(msg, "data pipe name = '%s'\n", resp.szFile);
  687. Trace_Fil(msg);
  688. }
  689. #ifdef SOCKETS
  690. /* We put the TCP port in the high date time slot just for now:
  691. */
  692. if( SOCKET_ERROR == SocketConnect( server, (u_short)resp.ft_lastwrite.dwHighDateTime, &hpData ) )
  693. {
  694. Trace_Fil("Couldn't connect to socket\n");
  695. TRACE_ERROR("Couldn't connect to socket", FALSE);
  696. CLOSEHANDLE(hpData);
  697. hpData = (SOCKET)INVALID_HANDLE_VALUE;
  698. return FALSE;
  699. }
  700. #else
  701. if (resp.szFile[0]=='\\') {
  702. /* hack to fix bug. Replace "." by server name */
  703. char buff[70];
  704. PSTR temp;
  705. temp = strtok(resp.szFile,".");
  706. temp = strtok(NULL,".");
  707. strcpy(buff, temp);
  708. strcat(resp.szFile, server);
  709. strcat(resp.szFile, buff);
  710. wsprintf(buff, "fixed data pipe name = %s\n", resp.szFile);
  711. Trace_Fil(buff);
  712. }
  713. hpData = ConnectPipe(resp.szFile);
  714. if (hpData == INVALID_HANDLE_VALUE) {
  715. Trace_Fil("Couldn't connect to data pipe\n");
  716. TRACE_ERROR("Couldn't connect to data pipe", FALSE);
  717. CloseHandle(hpData);
  718. hpData = INVALID_HANDLE_VALUE;
  719. return FALSE;
  720. }
  721. #endif /* SOCKETS */
  722. }
  723. /* Start a thread to listen for the SSRESPs that will come through */
  724. Trace_Fil("Starting ReceiveFiles thread\n");
  725. hThread = CreateThread( NULL, 0, ReceiveFiles, (LPVOID)hpData, 0, &ThreadId);
  726. Trace_Fil("End of ss_startCopy\n");
  727. return TRUE;
  728. } /* ss_startcopy */
  729. /* Collect files from hpData.
  730. See ..\server\files.c for the protocol.
  731. */
  732. DWORD WINAPI ReceiveFiles(LPVOID handle)
  733. {
  734. LPSTR lname;
  735. BOOL Recovering = FALSE;
  736. SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_HIGHEST);
  737. #ifdef SOCKETS
  738. hpData = (SOCKET)handle;
  739. #else
  740. hpData = (HANDLE)handle;
  741. #endif
  742. { char msg[80];
  743. wsprintf(msg, "Receiving Files on pipe %x\n", PtrToLong(hpData));
  744. Trace_Fil(msg);
  745. }
  746. /* for each file... */
  747. for (; ; ) { /* loop getting files until we get END (or error) */
  748. SSNEWRESP Resp;
  749. char Guard = '\0'; /* to protect scanning for \0 in Resp */
  750. int BuffSize;
  751. #ifdef SOCKETS
  752. BuffSize = recv(hpData, (PSTR) &Resp, sizeof(Resp), 0);
  753. if (BuffSize==SOCKET_ERROR) {
  754. /* We're out of step - almost certainly got a data packet
  755. ** when we expected a response block
  756. ** Try to recover by reading until we DO get a resp.
  757. */
  758. if (Resp.lResponse==LRESPONSE) {
  759. CLOSEHANDLE(hpData); /* tough */
  760. hpData = (SOCKET)INVALID_HANDLE_VALUE;
  761. return (DWORD)(-1);
  762. }
  763. if (!Recovering){
  764. Recovering = TRUE;
  765. TRACE_ERROR("Network protocol error. OK to Resync? (else abort)", TRUE);
  766. }
  767. continue;
  768. }
  769. #else
  770. BuffSize = ss_getblock(hpData, (PSTR) &Resp, sizeof(Resp));
  771. if (BuffSize==-2) {
  772. /* We're out of step - almost certainly got a data packet
  773. ** when we expected a response block
  774. ** Try to recover by reading until we DO get a resp.
  775. */
  776. if (Resp.lResponse==LRESPONSE) {
  777. CloseHandle(hpData); /* tough */
  778. hpData = INVALID_HANDLE_VALUE;
  779. return (DWORD)(-1);
  780. }
  781. if (!Recovering){
  782. Recovering = TRUE;
  783. TRACE_ERROR("Network protocol error. OK to Resync? (else abort)", TRUE);
  784. }
  785. continue;
  786. }
  787. #endif /* SOCKETS */
  788. if (Recovering && Resp.lResponse!=LRESPONSE) continue;
  789. Recovering = FALSE;
  790. if (BuffSize<=0) {
  791. Trace_Fil("Couldn't read pipe to get file header.\n");
  792. CLOSEHANDLE(hpData); /* tough */
  793. hpData = (MAYBESOCKETTYPE)INVALID_HANDLE_VALUE;
  794. return BuffSize;
  795. }
  796. Trace_Fil("ReceiveFiles got resp\n");
  797. if (Resp.lResponse!=LRESPONSE) {
  798. Trace_Fil("Network protocol error. Not RESP block\n");
  799. TRACE_ERROR("Network protocol error. Not RESP block", FALSE);
  800. continue;
  801. }
  802. if (Resp.lVersion!=SS_VERSION) {
  803. Trace_Fil("Network protocol error. Bad VERSION\n");
  804. TRACE_ERROR("Network protocol error. Bad VERSION", FALSE);
  805. continue; /* maybe it will resync */
  806. }
  807. if (Resp.lCode==SSRESP_END)
  808. /* normal ending. */
  809. break;
  810. if ( Resp.lCode!=SSRESP_FILE
  811. && Resp.lCode!=SSRESP_NOTEMPPATH
  812. && Resp.lCode!=SSRESP_COMPRESSEXCEPT
  813. && Resp.lCode!=SSRESP_NOREADCOMP
  814. && Resp.lCode!=SSRESP_NOCOMPRESS
  815. && Resp.lCode!=SSRESP_COMPRESSFAIL
  816. ) {
  817. /// want a try finally here to protect the filename???!!!
  818. char msg[400];
  819. wsprintf( msg, "Error code received: %d file:%s"
  820. , Resp.lCode
  821. , (Resp.szFile ? Resp.szFile : "NULL") );
  822. Trace_Fil(msg);
  823. ++nBadFiles;
  824. if (!TRACE_ERROR(msg, TRUE)) {
  825. /* abort operation */
  826. bAbort = TRUE;
  827. CLOSEHANDLE(hpData); /* tough */
  828. hpData = (MAYBESOCKETTYPE)INVALID_HANDLE_VALUE;
  829. return (DWORD)-1;
  830. }
  831. continue;
  832. }
  833. /* Find the local name */
  834. lname = &(Resp.szFile[0]) + strlen(Resp.szFile) +1;
  835. /* memmove(Resp.szLocal, lname, strlen(lname)+1); */
  836. /* Assume Resp.(ulSize, ft, ulSum, bSumValid, szFile, szLocal
  837. are all valid */
  838. if (!GetFile( hpData, lname, &Resp))
  839. ++nBadFiles;
  840. /* If it's good it gets counted when decompressed */
  841. } /* files loop */
  842. return 0;
  843. } /* ReceiveFiles */
  844. /* Read the file from hpipe as a series of SSNEWPACKs.
  845. Write them into a temporary file. Stop writing when
  846. a short one comes in. Spawn a thread to decompress it into localpath.
  847. check existing decompress threads for status and count
  848. the number of good/bad files.
  849. */
  850. BOOL
  851. #ifdef SOCKETS
  852. GetFile(SOCKET hpipe, PSTR localpath, PSSNEWRESP presp)
  853. #else
  854. GetFile(HANDLE hpipe, PSTR localpath, PSSNEWRESP presp)
  855. #endif
  856. {
  857. HANDLE hfile;
  858. int sequence;
  859. ULONG size;
  860. SSNEWPACK packet;
  861. BOOL bOK = TRUE;
  862. BOOL bOKFile = TRUE; /* FALSE means output file nbg, but keep running along
  863. to stay in step with the pipe protocol
  864. */
  865. char szTempname[MAX_PATH];
  866. DWORD rc;
  867. { char msg[50+MAX_PATH];
  868. wsprintf(msg, "GetFile %s\n", localpath);
  869. Trace_Fil(msg);
  870. }
  871. /* create a temporary name */
  872. rc = GetTempPath(sizeof(szTempname), szTempname);
  873. if (rc==0) {
  874. char Msg[100];
  875. wsprintf(Msg, "GetTempPath failed, error code=%ld", GetLastError());
  876. TRACE_ERROR(Msg, FALSE);
  877. bOKFile = FALSE;
  878. }
  879. if (bOKFile){
  880. rc = GetTempFileName(szTempname, "ssb", 0, szTempname);
  881. if (rc==0) {
  882. char Msg[100];
  883. wsprintf(Msg, "GetTempFileName failed, error code=%ld", GetLastError());
  884. TRACE_ERROR(Msg, FALSE);
  885. return FALSE;
  886. }
  887. }
  888. if (bOKFile){
  889. /* try to create the temp file */
  890. hfile = CreateFile(szTempname,
  891. GENERIC_WRITE,
  892. 0,
  893. NULL,
  894. CREATE_ALWAYS,
  895. FILE_ATTRIBUTE_NORMAL,
  896. NULL);
  897. if (hfile == INVALID_HANDLE_VALUE) {
  898. char Msg[500];
  899. wsprintf(Msg, "GetFile: could not create temp file %s", szTempname);
  900. TRACE_ERROR(Msg, FALSE);
  901. bOKFile = FALSE;
  902. }
  903. }
  904. else hfile = INVALID_HANDLE_VALUE;
  905. for (sequence = 1; ; sequence++) {
  906. int SizeGotten;
  907. #ifdef SOCKETS
  908. SizeGotten = recv(hpipe, (PSTR) &packet, sizeof(packet), 0);
  909. #else
  910. SizeGotten = ss_getblock(hpipe, (PSTR) &packet, sizeof(packet));
  911. #endif
  912. if (SizeGotten<=0) {
  913. /* error - could be an Abort request */
  914. char msg[80];
  915. wsprintf( msg, "Network error. Size received=%d\n", SizeGotten);
  916. Trace_Fil(msg);
  917. bOK = FALSE;
  918. break;
  919. }
  920. if (packet.lPacket!=LPACKET) {
  921. { char msg[200];
  922. wsprintf( msg
  923. , "Network protocol error. Not PACKET: %x %x %x %x %x"
  924. , packet.lVersion
  925. , packet.lPacket
  926. , packet.lSequence
  927. , packet.ulSize
  928. , packet.ulSum
  929. );
  930. /* and maybe someone will recognise what on earth it is */
  931. Trace_Fil(msg);
  932. }
  933. TRACE_ERROR("Network protocol error. Not PACKET.", FALSE);
  934. bOK = FALSE;
  935. break;
  936. }
  937. if (sequence != packet.lSequence) {
  938. /* error or out of sequence */
  939. char msg[200];
  940. wsprintf( msg, "Packet out of sequence. Got %d expected %d\n"
  941. , packet.lSequence, sequence);
  942. Trace_Fil(msg);
  943. TRACE_ERROR("Packet sequence error.", FALSE);
  944. bOK = FALSE;
  945. break;
  946. }
  947. if (packet.ulSize ==0) {
  948. /*
  949. * this is really the last block (end of file).
  950. *
  951. * LATER
  952. * do SSATTRIBS on the end to support NTFS properly !!!
  953. */
  954. Trace_Fil("End of file marker (0 length)\n");
  955. break;
  956. }
  957. #if 1
  958. /* check the block checksums */
  959. if ( packet.ulSum != 0 ) {
  960. TRACE_ERROR("packet checksum error", FALSE);
  961. bOK = FALSE;
  962. break;
  963. }
  964. #else // Debug version. (Remember to enable server checksums too)
  965. // Also ensure that Trace_Fil is actually tracing.
  966. { ULONG PackSum;
  967. /* check the block checksums */
  968. if ( (PackSum = ss_checksum_block(packet.Data, packet.ulSize))
  969. != packet.ulSum
  970. ) {
  971. char msg[80];
  972. wsprintf( msg, "Packet checksum error was %x should be %x\n"
  973. , PackSum, packet.ulSum );
  974. Trace_Fil(msg);
  975. // but don't break;
  976. }
  977. }
  978. #endif
  979. if ( packet.ulSize==(ULONG)(-1) || packet.ulSize==(ULONG)(-2) ) {
  980. TRACE_ERROR("Error from server end", FALSE);
  981. bOK = FALSE;
  982. break;
  983. }
  984. if (bOKFile) {
  985. bOK = WriteFile(hfile, packet.Data, packet.ulSize, &size, NULL);
  986. { char msg[80];
  987. wsprintf( msg,"Writing block to disk - size= %d\n", size);
  988. Trace_Fil(msg);
  989. }
  990. if (!bOK || (size != packet.ulSize)) {
  991. TRACE_ERROR("File write error", FALSE);
  992. bOK = FALSE;
  993. break;
  994. }
  995. }
  996. else bOK = FALSE;
  997. if (packet.ulSize < PACKDATALENGTH)
  998. {
  999. /* this is the last block (end of file) */
  1000. Trace_Fil("End of file marker (short packet)\n");
  1001. break;
  1002. }
  1003. } /* for each block */
  1004. CloseHandle(hfile);
  1005. if (!bOK) {
  1006. DeleteFile(szTempname);
  1007. return FALSE;
  1008. }
  1009. SpawnDecompress(szTempname, localpath, presp);
  1010. PurgeDecomps(Decomps);
  1011. return bOK;
  1012. } /* GetFile */
  1013. /* Spawn a thread to decompress TempPath into RealPath on a new thread
  1014. Add the thread handle to the LIST Decomps.
  1015. If presp->lCode is one of SSRESP_NOTEMPPATH
  1016. SSRESP_COMPRESSEXCEPT
  1017. SSRESP_NOREADCOMP
  1018. SSRESP_NOCOMPRESS
  1019. Then the file should just be copied, not decompressed.
  1020. */
  1021. void SpawnDecompress(PSTR TempPath, PSTR RealPath, PSSNEWRESP presp)
  1022. {
  1023. DECOMPARGS * DecompArgs;
  1024. HANDLE L_hThread;
  1025. DWORD ThreadId;
  1026. { char msg[MAX_PATH+60];
  1027. wsprintf(msg, "Spawning decompress of %s", TempPath);
  1028. Trace_Fil(msg);
  1029. }
  1030. DecompArgs = (DECOMPARGS *)GlobalAlloc(GMEM_FIXED, sizeof(DECOMPARGS));
  1031. if (DecompArgs)
  1032. {
  1033. DecompArgs->fileattribs = presp->fileattribs;
  1034. DecompArgs->ft_create = presp->ft_create;
  1035. DecompArgs->ft_lastaccess = presp->ft_lastaccess;
  1036. DecompArgs->ft_lastwrite = presp->ft_lastwrite;
  1037. DecompArgs->ulSum = presp->ulSum;
  1038. DecompArgs->lCode = presp->lCode;
  1039. DecompArgs->bSumValid = presp->bSumValid;
  1040. strcpy(DecompArgs->Temp, TempPath);
  1041. strcpy(DecompArgs->Real, RealPath);
  1042. strcpy(DecompArgs->Remote, presp->szFile);
  1043. L_hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)Decompress, DecompArgs, 0, &ThreadId);
  1044. List_AddLast( Decomps, (LPVOID)&L_hThread, sizeof(L_hThread));
  1045. }
  1046. else
  1047. {
  1048. // shut up Prefix. no idea what is the right thing to do here,
  1049. // without spending a lot of time to understand how this whole
  1050. // add-on to windiff works. in some other product this would be
  1051. // worth investing time on. but not this add-on to windiff that
  1052. // most people don't even know exists, much less how to set up
  1053. // the server it needs to talk to.
  1054. }
  1055. } /* SpawnDecompress */
  1056. /* Decompress da->Temp into da->Real
  1057. Free the storage da->DECOMPARGS
  1058. Return 1 (TRUE) if it worked
  1059. Return 0 (FALSE) if it didn't work
  1060. This return code acts as the exit code for the thread.
  1061. */
  1062. int Decompress(DECOMPARGS * da)
  1063. {
  1064. OFSTRUCT os;
  1065. int fh1, fh2;
  1066. BOOL bOK = TRUE;
  1067. /* Decompress the file to the original name
  1068. If da->lCode is one of SSRESP_NOTEMPPATH
  1069. SSRESP_COMPRESSEXCEPT
  1070. SSRESP_NOREADCOMP
  1071. SSRESP_NOCOMPRESS
  1072. Then the file is just copied, not decompressed.
  1073. */
  1074. { char msg[2*MAX_PATH+50];
  1075. wsprintf( msg, "Decompressing %s => %s\n"
  1076. , da->Temp, da->Real);
  1077. Trace_Fil(msg);
  1078. wsprintf( msg, "%d done. Getting %s\n"
  1079. , nGoodFiles, da->Real);
  1080. SetNames(msg);
  1081. }
  1082. if ( da->lCode==SSRESP_NOTEMPPATH
  1083. || da->lCode==SSRESP_COMPRESSEXCEPT
  1084. || da->lCode==SSRESP_NOREADCOMP
  1085. || da->lCode==SSRESP_NOCOMPRESS
  1086. ) { /* Just copy, don't compress */
  1087. bOK = CopyFile(da->Temp, da->Real, FALSE);
  1088. if (bOK) Trace_Fil("Uncompressed file copied.\n");
  1089. else Trace_Fil("Uncompressed file failed final copy.\n");
  1090. } else {
  1091. fh1 = LZOpenFile(da->Temp, &os, OF_READ|OF_SHARE_DENY_WRITE);
  1092. if (fh1 == -1) {
  1093. char msg[500];
  1094. wsprintf( msg, "Packed temp file %s did not open for decompression into %s. Error code %d"
  1095. , da->Temp, da->Real, GetLastError()
  1096. );
  1097. TRACE_ERROR(msg, FALSE);
  1098. bOK = FALSE;
  1099. } else {
  1100. fh2 = LZOpenFile(da->Real, &os, OF_CREATE|OF_READWRITE|OF_SHARE_DENY_NONE);
  1101. if (fh2 == -1) {
  1102. char msg[MAX_PATH];
  1103. Trace_Fil("Could not create target file\n");
  1104. wsprintf(msg, "Could not create target file %s", da->Real);
  1105. if (!TRACE_ERROR(msg, TRUE)) {
  1106. /* user hit cancel - abort operation */
  1107. bAbort = TRUE;
  1108. }
  1109. bOK = FALSE;
  1110. LZClose(fh1);
  1111. } else {
  1112. long retcode;
  1113. retcode = LZCopy(fh1, fh2);
  1114. if (retcode<0){
  1115. bOK = FALSE;
  1116. }
  1117. LZClose(fh1);
  1118. LZClose(fh2);
  1119. }
  1120. }
  1121. }
  1122. /* May want to keep it for debugging...? */
  1123. #ifndef LAURIE
  1124. DeleteFile(da->Temp);
  1125. #endif //LAURIE
  1126. if (bOK) {
  1127. HANDLE hfile;
  1128. BOOL bChecked;
  1129. LONG err;
  1130. /*
  1131. * check the file's checksum (end-to-end check) and size and
  1132. * set file attributes and times according to the attribs
  1133. * struct we received. Remember to set file times BEFORE
  1134. * setting attributes in case the attributes include read-only!
  1135. */
  1136. bChecked = ( da->ulSum == checksum_file(da->Real, &err) );
  1137. if (err!=0) bChecked = FALSE;
  1138. if (!bChecked){
  1139. if (!bAbort){
  1140. char msg[200];
  1141. if (err>0) {
  1142. /* negative error codes are internal errors,
  1143. positive ones are meaningful to outsiders.
  1144. */
  1145. wsprintf( msg
  1146. , "error %ld, Will retry file %s."
  1147. , err
  1148. , da->Real
  1149. );
  1150. }
  1151. else {
  1152. #if defined(LAURIE)
  1153. wsprintf( msg
  1154. , "Checksum error %ld on file %s. Sum should be %8x, temp file %s"
  1155. , err
  1156. , da->Real
  1157. , da->ulSum
  1158. , da->Temp
  1159. );
  1160. TRACE_ERROR(msg, FALSE);
  1161. #endif
  1162. wsprintf( msg
  1163. , "Checksum error. Will retry file %s."
  1164. , da->Real
  1165. );
  1166. }
  1167. SetNames(msg);
  1168. List_AddLast(Retries, (LPVOID)da, (UINT)sizeof(DECOMPARGS));
  1169. return(FALSE); /* Hm - kind of a lie correct later */
  1170. }
  1171. else return FALSE;
  1172. }
  1173. hfile = CreateFile(da->Real, GENERIC_WRITE, 0, NULL,
  1174. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1175. if (!SetFileTime(hfile, &(da->ft_create),
  1176. &(da->ft_lastaccess),
  1177. &(da->ft_lastwrite)) ) {
  1178. TRACE_ERROR("could not set file times", FALSE);
  1179. }
  1180. CloseHandle(hfile);
  1181. if (!SetFileAttributes(da->Real, da->fileattribs)) {
  1182. TRACE_ERROR("could not set attributes", FALSE);
  1183. }
  1184. }
  1185. GlobalFree((HGLOBAL)da);
  1186. return bOK;
  1187. } /* Decompress */
  1188. /* safe strcmp of PTR against array, protecting against NULL PTR
  1189. b is an array and had better NOT be null
  1190. a NULL pointer is taken to match an empty arrray.
  1191. */
  1192. int safecmp(LPSTR a, LPSTR b)
  1193. { if (a==NULL)
  1194. return (b[0]!='\0'); /* returns 0 if ==, else 1 */
  1195. else return strcmp(a,b);
  1196. } /* safecmp */
  1197. /*
  1198. * request to copy a file. Sends the request on (static global) hpipe
  1199. *
  1200. * returns TRUE if it succeeded or FALSE if the connection was lost
  1201. * TRUE only means the REQUEST was sent.
  1202. */
  1203. BOOL
  1204. ss_bulkcopy(PSTR server, PSTR serverpath, PSTR clientpath, PSTR uncname,
  1205. PSTR password)
  1206. { char buffer[MAX_PATH*2] = {0};
  1207. LPSTR pstr;
  1208. ++nFiles;
  1209. Trace_Fil("ss_bulkcopy\n");
  1210. if (safecmp(server,Server)) {
  1211. char msg[400];
  1212. wsprintf( msg, "Protocol error. Server change was %s is %s"
  1213. , Server, (server?server:"NULL")
  1214. );
  1215. Trace_Fil(msg);
  1216. TRACE_ERROR("Protocol error. Server change", FALSE);
  1217. return FALSE;
  1218. }
  1219. if (safecmp(uncname,UNCName)) {
  1220. char msg[400];
  1221. wsprintf( msg, "Protocol error. UNCName change was %s is %s"
  1222. , UNCName, (uncname?uncname:"NULL")
  1223. );
  1224. Trace_Fil(msg);
  1225. TRACE_ERROR("Protocol error. UNCName change", FALSE);
  1226. return FALSE;
  1227. }
  1228. if (safecmp(password,Password)) {
  1229. char msg[400];
  1230. wsprintf( msg, "Protocol error. Password change was %s is %s"
  1231. , Password, (password?password:"NULL")
  1232. );
  1233. Trace_Fil(msg);
  1234. TRACE_ERROR("Protocol error. Password change", FALSE);
  1235. return FALSE;
  1236. }
  1237. /* pack local and remote paths into buffer */
  1238. _snprintf(buffer, sizeof(buffer)-1, "%s%c%s", serverpath, 0, clientpath);
  1239. return ss_sendrequest( hpipe
  1240. , SSREQ_NEXTFILE
  1241. , buffer
  1242. , strlen(serverpath)+strlen(clientpath)+2
  1243. , 0
  1244. );
  1245. } /* ss_bulkcopy */
  1246. /* Remove from the decompressers list those that have finished.
  1247. Don't hang about waiting. Leave the rest on the list
  1248. Updating nGoodFiles and/or nBadFiles for those that finished.
  1249. */
  1250. void PurgeDecomps(LIST Decs)
  1251. {
  1252. HANDLE * phThread, * Temp;
  1253. DWORD ExitCode;
  1254. phThread = List_First(Decs);
  1255. while (phThread!=NULL) {
  1256. if (GetExitCodeThread(*phThread, &ExitCode)) {
  1257. Temp = phThread;
  1258. phThread = List_Next((LPVOID)phThread);
  1259. if (ExitCode==1) {
  1260. ++nGoodFiles;
  1261. CloseHandle(*Temp);
  1262. Trace_Fil("Purged a good decomp\n");
  1263. List_Delete((LPVOID)Temp);
  1264. }
  1265. else if(ExitCode==0) {
  1266. ++nBadFiles;
  1267. CloseHandle(*Temp);
  1268. Trace_Fil("Purged a bad decomp\n");
  1269. List_Delete((LPVOID)Temp);
  1270. }
  1271. else /* still active? */ ;
  1272. }
  1273. } /* traverse */
  1274. } /* PurgeDecomps */
  1275. /* WAIT for each of the hThreads on Decomps and report its status by
  1276. updating nGoodFiles and/or nBadFiles
  1277. This thread must be run on the receive thread or else after
  1278. the receive thread has terminated (or else we need a critical section).
  1279. */
  1280. void WaitForDecomps(LIST Decs)
  1281. {
  1282. HANDLE * phThread;
  1283. DWORD ExitCode;
  1284. List_TRAVERSE(Decs, phThread) {
  1285. if (bAbort) return;
  1286. Trace_Fil("Waiting for a decomp...");
  1287. for (; ; ){
  1288. DWORD rc;
  1289. rc = WaitForSingleObject(*phThread, 5000);
  1290. if (rc==0) break; /* timeout complete */
  1291. if (bAbort) {
  1292. // This WILL leave a garbage thread and a temp file lying around!!!???
  1293. Trace_Fil("Aborting wait for decomp.");
  1294. return;
  1295. }
  1296. }
  1297. Trace_Fil(" Done waiting.\n");
  1298. GetExitCodeThread(*phThread, &ExitCode);
  1299. if (ExitCode==1)
  1300. ++nGoodFiles;
  1301. else
  1302. ++nBadFiles;
  1303. CloseHandle(*phThread);
  1304. } /* traverse */
  1305. Trace_Fil("All decompression finished.");
  1306. List_Destroy(&Decs);
  1307. } /* WaitForDecomps */
  1308. static void Retry(LIST Rets)
  1309. {
  1310. DECOMPARGS * da;
  1311. if (List_IsEmpty(Rets)) return;
  1312. List_TRAVERSE(Rets, da) {
  1313. if (ss_copy_reliable( Server, da->Remote, da->Real, UNCName, Password))
  1314. { /* correct the lie we told when Decompress returned FALSE */
  1315. ++nGoodFiles; --nBadFiles;
  1316. }
  1317. }
  1318. List_Destroy(&Rets);
  1319. SetNames("All errors recovered");
  1320. }/* Retry */
  1321. /* end of bulk copy. Tidy everything up */
  1322. int ss_endcopy(void)
  1323. {
  1324. Trace_Fil("ss_endcopy\n");
  1325. ss_sendrequest( hpipe, SSREQ_ENDFILES, "", 1, 0);
  1326. /* wait for receiving thread to complete (could be long) */
  1327. for (; ; ){
  1328. DWORD rc;
  1329. rc = WaitForSingleObject( hThread, 5000);
  1330. if (rc==0) break; /* thread complete */
  1331. if (bAbort) {
  1332. if (hpData != (MAYBESOCKETTYPE)INVALID_HANDLE_VALUE) {
  1333. CLOSEHANDLE(hpData);
  1334. hpData = (MAYBESOCKETTYPE)INVALID_HANDLE_VALUE;
  1335. }
  1336. break;
  1337. }
  1338. }
  1339. // don't close the connection until we've finished, otherwise
  1340. // someone might think it's ok to reboot the server
  1341. ss_sendrequest( hpipe, SSREQ_END, "", 1, 0);
  1342. CloseHandle(hpipe);
  1343. hpipe = INVALID_HANDLE_VALUE;
  1344. WaitForDecomps(Decomps);
  1345. Decomps = NULL;
  1346. SetNames(NULL);
  1347. Retry(Retries);
  1348. Retries = NULL;
  1349. BulkCopy = FALSE;
  1350. if (nBadFiles+nGoodFiles > nFiles) return -99999; /* !!? */
  1351. if (nBadFiles+nGoodFiles < nFiles) nBadFiles = nFiles-nGoodFiles;
  1352. if (nBadFiles>0)
  1353. return -nBadFiles;
  1354. else return nGoodFiles;
  1355. } /* ss_endcopy */
  1356. #if 0
  1357. /* A SSREQ_FILES has been sent and possibly one or more files,
  1358. but we have changed our minds. We try to send an Abort request.
  1359. */
  1360. int ss_abortcopy(void)
  1361. {
  1362. Trace_Fil("ss_abortcopy\n");
  1363. ss_sendrequest( hpipe, SSREQ_ABORT, "", 1);
  1364. { DWORD code;
  1365. TerminateThread(hThread, &code); /* storage leak */
  1366. hThread = INVALID_HANDLE_VALUE;
  1367. }
  1368. Server[0] = '\0';
  1369. CloseHandle(hpipe);
  1370. hpipe = INVALID_HANDLE_VALUE;
  1371. CLOSEHANDLE(hpData);
  1372. hpData = INVALID_HANDLE_VALUE;
  1373. if (Decomps!=NULL){
  1374. HANDLE * phThread;
  1375. List_TRAVERSE(Decomps, phThread){
  1376. DWORD code;
  1377. TerminateThread(*phThread, &code); /* storage leak */
  1378. }
  1379. }
  1380. Decomps = NULL;
  1381. BulkCopy = FALSE;
  1382. } /* ss_abortcopy */
  1383. #endif // 0
  1384. /*
  1385. * reliably copy a file (repeat (upto N times) until checksums match)
  1386. *
  1387. * returns TRUE if it succeeded or FALSE if the connection was lost
  1388. */
  1389. BOOL
  1390. ss_copy_reliable(PSTR server, PSTR remotepath, PSTR localpath, PSTR uncname,
  1391. PSTR password)
  1392. {
  1393. ULONG sum_local, sum_remote;
  1394. int retry;
  1395. SSNEWRESP resp;
  1396. HANDLE hpCopy = INVALID_HANDLE_VALUE; /* N.B. NOT the static global pipe! */
  1397. LONG err;
  1398. FILETIME ft;
  1399. LONG sz;
  1400. DWORD attr;
  1401. Trace_Fil("ss_copy_reliable\n");
  1402. // if (BulkCopy) {
  1403. // TRACE_ERROR("Cannot do simple copy as bulk copy is in progress", FALSE);
  1404. // return FALSE;
  1405. // }
  1406. for (retry = 0; retry < 10; retry++) {
  1407. if (bAbort) return FALSE; /* abort requested from WINDIFF */
  1408. if (hpCopy!=INVALID_HANDLE_VALUE) {
  1409. CloseHandle(hpCopy);
  1410. hpCopy = INVALID_HANDLE_VALUE;
  1411. }
  1412. { char pipename[400];
  1413. InitPipeName(pipename, server, NPNAME);
  1414. hpCopy = ConnectPipe(pipename);
  1415. }
  1416. if (hpCopy == INVALID_HANDLE_VALUE) {
  1417. /* next retry in two seconds */
  1418. Trace_Stat("connect failed - retrying");
  1419. Sleep(1000);
  1420. continue;
  1421. }
  1422. if ((uncname != NULL) && (uncname[0]!='\0')
  1423. && (password != NULL) && (password[0]!='\0')) {
  1424. /* send the password request */
  1425. if (!ss_sendunc(hpCopy, password, uncname)) {
  1426. TRACE_ERROR("Server connection lost", FALSE);
  1427. continue;
  1428. }
  1429. /* wait for password response */
  1430. if (0>=ss_getresponse(hpCopy, &resp)) {
  1431. TRACE_ERROR("Server connection lost", FALSE);
  1432. continue;
  1433. }
  1434. if (resp.lCode != SSRESP_END) {
  1435. TRACE_ERROR("Password attempt failed", FALSE);
  1436. return(FALSE);
  1437. }
  1438. }
  1439. /* try to copy the file */
  1440. ss_copy_file(hpCopy, remotepath, localpath);
  1441. /* whether or not he thinks he failed, we should look
  1442. * to see if the file is really there.
  1443. */
  1444. sum_local = checksum_file(localpath, &err);
  1445. if (err!=0) continue;
  1446. sum_remote = 0;
  1447. if (!ss_checksum_remote(hpCopy, remotepath, &sum_remote, &ft, &sz, &attr)) {
  1448. /* no remote checksum - better retry */
  1449. if (!TRACE_ERROR("remote checksum failed - retry?", TRUE)) {
  1450. CloseHandle(hpCopy);
  1451. return(FALSE);
  1452. }
  1453. continue;
  1454. }
  1455. if (sum_local == sum_remote) {
  1456. /* copy succeeded */
  1457. ss_terminate(hpCopy);
  1458. return(TRUE);
  1459. }
  1460. TRACE_ERROR("files different after apparently successful copy!!?", FALSE);
  1461. } /*retry loop */
  1462. /* too many retries */
  1463. CloseHandle(hpCopy);
  1464. return(FALSE);
  1465. } /* ss_copy_reliable */
  1466. /*
  1467. * copy one file using checksum server
  1468. *
  1469. * send a SSREQ_FILE for the file, and then loop reading
  1470. * blocks until we get an error (sequence count is wrong or -1),
  1471. * or the end of file (0-length block)
  1472. *
  1473. * File sent may be compressed. We write it to a temporary file, and
  1474. * then decompress it using LZCopy. This will work even if the
  1475. * file was sent uncompressed (eg because compress.exe could not be
  1476. * executed on the server).
  1477. */
  1478. BOOL
  1479. ss_copy_file(HANDLE hpipe, PSTR remotepath, PSTR localpath)
  1480. {
  1481. HANDLE hfile;
  1482. int sequence;
  1483. ULONG size;
  1484. SSPACKET packet;
  1485. BOOL bOK;
  1486. char szTempname[MAX_PATH];
  1487. OFSTRUCT os;
  1488. int fh1, fh2;
  1489. PSSATTRIBS attribs;
  1490. Trace_Fil("ss_copy_file\n");
  1491. /* create a temporary name */
  1492. *szTempname = 0;
  1493. GetTempPath(sizeof(szTempname), szTempname);
  1494. GetTempFileName(szTempname, "ssc", 0, szTempname);
  1495. /* try to create the temp file */
  1496. hfile = CreateFile(szTempname,
  1497. GENERIC_WRITE,
  1498. 0,
  1499. NULL,
  1500. CREATE_ALWAYS,
  1501. FILE_ATTRIBUTE_NORMAL,
  1502. NULL);
  1503. if (hfile == INVALID_HANDLE_VALUE) {
  1504. TRACE_ERROR("ss_copy: could not create temp file", FALSE);
  1505. return(FALSE);
  1506. }
  1507. if (!ss_sendrequest(hpipe, SSREQ_FILE, remotepath, strlen(remotepath)+1, 0)){
  1508. CloseHandle(hfile);
  1509. return(FALSE);
  1510. }
  1511. for (sequence = 0; ; sequence++) {
  1512. bOK = 0 <= ss_getblock(hpipe, (PSTR) &packet, sizeof(packet));
  1513. if (!bOK || (sequence != packet.lSequence)) {
  1514. /* error or out of sequence */
  1515. TRACE_ERROR("packet error", FALSE);
  1516. CloseHandle(hfile);
  1517. DeleteFile(szTempname);
  1518. return(FALSE);
  1519. }
  1520. if (packet.ulSize == 0) {
  1521. /*
  1522. * this is the last block (end of file).
  1523. *
  1524. * the data field for this block contains a
  1525. * SSATTRIBS struct that we can use to set the
  1526. * file times and attributes (after decompression).
  1527. */
  1528. attribs = (PSSATTRIBS) packet.Data;
  1529. break;
  1530. }
  1531. /* check the block checksums */
  1532. if ( packet.ulSum!=0 ) {
  1533. TRACE_ERROR("packet checksum error", FALSE);
  1534. CloseHandle(hfile);
  1535. DeleteFile(szTempname);
  1536. return(FALSE);
  1537. }
  1538. bOK = WriteFile(hfile, packet.Data, packet.ulSize, &size, NULL);
  1539. if (!bOK || (size != packet.ulSize)) {
  1540. CloseHandle(hfile);
  1541. DeleteFile(szTempname);
  1542. return(FALSE);
  1543. }
  1544. }
  1545. CloseHandle(hfile);
  1546. /* decompress the file to the original name */
  1547. fh1 = LZOpenFile(szTempname, &os, OF_READ|OF_SHARE_DENY_WRITE);
  1548. if (fh1 < 0) {
  1549. TRACE_ERROR("Failed to open file for decompression", FALSE);
  1550. } else {
  1551. fh2 = LZOpenFile(localpath, &os, OF_CREATE|OF_READWRITE|OF_SHARE_DENY_NONE);
  1552. if (fh2 < 0) {
  1553. char msg[MAX_PATH+40];
  1554. wsprintf(msg, "Could not create target file %s", localpath);
  1555. if (!TRACE_ERROR(msg, TRUE)) {
  1556. bAbort = TRUE;
  1557. }
  1558. return(FALSE);
  1559. } else {
  1560. LZCopy(fh1, fh2);
  1561. LZClose(fh1);
  1562. LZClose(fh2);
  1563. }
  1564. }
  1565. DeleteFile(szTempname);
  1566. /*
  1567. * now set file attributes and times according to the attribs
  1568. * struct we received. Remember to set file times BEFORE
  1569. * setting attributes in case the attributes include read-only!
  1570. */
  1571. hfile = CreateFile(localpath, GENERIC_WRITE, 0, NULL,
  1572. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1573. if (!SetFileTime(hfile, &attribs->ft_create,
  1574. &attribs->ft_lastaccess,
  1575. &attribs->ft_lastwrite) ) {
  1576. TRACE_ERROR("could not set file times", FALSE);
  1577. }
  1578. CloseHandle(hfile);
  1579. if (!SetFileAttributes(localpath, attribs->fileattribs)) {
  1580. TRACE_ERROR("could not set attributes", FALSE);
  1581. }
  1582. return(TRUE);
  1583. } /* ss_copy_file */
  1584. /* produce a checksum of a block of data.
  1585. *
  1586. * This algorithm is compute bound. It's probably overkill anyway and for
  1587. * version 1 is not used. It must match the one in server.
  1588. *
  1589. * Generate checksum by the formula
  1590. * checksum = SUM( rnd(i)*(1+byte[i]) )
  1591. * where byte[i] is the i-th byte in the file, counting from 1
  1592. * rnd(x) is a pseudo-random number generated from the seed x.
  1593. *
  1594. * Adding 1 to byte ensures that all null bytes contribute, rather than
  1595. * being ignored. Multiplying each such byte by a pseudo-random
  1596. * function of its position ensures that "anagrams" of each other come
  1597. * to different sums. The pseudorandom function chosen is successive
  1598. * powers of 1664525 modulo 2**32. 1664525 is a magic number taken
  1599. * from Donald Knuth's "The Art Of Computer Programming"
  1600. */
  1601. ULONG
  1602. ss_checksum_block(PSTR block, int size)
  1603. {
  1604. unsigned long lCheckSum = 0; /* grows into the checksum */
  1605. const unsigned long lSeed = 1664525; /* seed for random Knuth */
  1606. unsigned long lRand = 1; /* seed**n */
  1607. unsigned long lIndex = 1; /* byte number in block */
  1608. unsigned Byte; /* next byte to process in buffer */
  1609. unsigned length; /* unsigned copy of size */
  1610. Trace_Fil("ss_checksum_block\n");
  1611. length = size;
  1612. for (Byte = 0; Byte < length ;++Byte, ++lIndex) {
  1613. lRand = lRand*lSeed;
  1614. lCheckSum += lIndex*(1+block[Byte])*lRand;
  1615. }
  1616. return(lCheckSum);
  1617. }