Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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