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.

2933 lines
95 KiB

  1. /*++
  2. Copyright (c) 1988-1999 Microsoft Corporation
  3. Module Name:
  4. cpwork.c
  5. Abstract:
  6. Copy command internal workers
  7. --*/
  8. #include "cmd.h"
  9. /* useful macro */
  10. #define Wild(spec) (((spec)->flags & CI_NAMEWILD) != 0)
  11. #define TruncateOnCtrlZ(flags) (((flags) & (CI_ASCII | CI_NOT_UNICODE)) == (CI_ASCII | CI_NOT_UNICODE))
  12. /*
  13. * The following two constants determine the minimum and maximum
  14. * sizes (in bytes) for temporary buffers allocated by TYPE or COPY
  15. */
  16. #define MINCOPYBUFSIZE 128
  17. #define MAXCOPYBUFSIZE (65536-512)
  18. DWORD
  19. WinEditName(
  20. const TCHAR *pSrc,
  21. const TCHAR *pEd,
  22. TCHAR *pRes,
  23. const unsigned ResBufLen
  24. );
  25. int DoVerify(
  26. CRTHANDLE *pdestptr,
  27. TCHAR *curr_dest,
  28. ULONG bytes_read,
  29. CHAR *buf_seg,
  30. CHAR *buf_seg_dest
  31. );
  32. /* Global Vars */
  33. int copy_mode;
  34. int number_of_files_copied;
  35. /* Global Vars from command */
  36. extern jmp_buf CmdJBuf2; /* used to return on error */
  37. extern UINT CurrentCP;
  38. extern CHAR AnsiBuf[];
  39. extern TCHAR CurDrvDir[];
  40. extern TCHAR SwitChar, PathChar ; /* M007 */
  41. extern TCHAR Fmt11[], Fmt17[];
  42. extern unsigned DosErr ;
  43. extern TCHAR VolSrch[] ; /* M009 */
  44. extern PHANDLE FFhandles; /* @@1 */
  45. extern unsigned FFhndlsaved; /* @@1 */
  46. unsigned FFhndlCopy;
  47. BOOL VerifyCurrent;
  48. int first_file; /* flag first file process @@5@J1 */
  49. int first_fflag; /* flag first file process @@5@J3 */
  50. unsigned Heof = FALSE ; /* M017 - EOF flag */
  51. /* PTM 1412 */
  52. extern BOOL CtrlCSeen;
  53. int same_fcpy(int, TCHAR *, TCHAR *);
  54. int scan_bytes(CHAR*,unsigned int *,int);
  55. int ZScanA(BOOL flag, PCHAR buf, PULONG buflen, PULONG skip);
  56. CRTHANDLE open_for_append(PTCHAR, PCPYINFO source, PCHAR, ULONG);
  57. void source_eq_dest(PCPYINFO,CRTHANDLE *,int ,CHAR *,unsigned ,HANDLE);
  58. int read_bytes(CRTHANDLE ,PCHAR, ULONG, PULONG, PCPYINFO source, CRTHANDLE, PTCHAR);
  59. VOID write_bytes(CRTHANDLE, PCHAR, ULONG, PTCHAR, CRTHANDLE);
  60. /*** copy - Copy one or more files
  61. *
  62. * Purpose:
  63. * This is the main routine for the copy command.
  64. *
  65. * int copy(TCHAR *args)
  66. *
  67. * Args:
  68. * args = The raw arguments from the command line.
  69. *
  70. * Returns:
  71. * SUCCESS if able to perform the copy
  72. * FAILURE if not
  73. *
  74. */
  75. int
  76. copy(TCHAR *args)
  77. {
  78. PCPYINFO source; /* list of source specs */
  79. PCPYINFO dest;
  80. /*@@J*/int rcp = SUCCESS;
  81. /*@@4*/int rc = SUCCESS;
  82. VerifyCurrent = GetSetVerMode(GSVM_GET);
  83. if (setjmp(CmdJBuf2)) /* in case of error */
  84. return(FAILURE);
  85. GetDir(CurDrvDir, GD_DEFAULT); /* @@5c */
  86. DEBUG((FCGRP,COLVL,"COPY: Entered."));
  87. first_file = TRUE; /* flag-first file? @@5@J1 */
  88. first_fflag= TRUE; /* flag-first file? @@5@J3 */
  89. number_of_files_copied = 0; /* initialize global vars */
  90. copy_mode = COPY;
  91. cpyfirst = TRUE; /* @@5b reset flag for COPY DOSQFILEMODE indicator */
  92. cpydflag = FALSE; /* @@5b reset flag for COPY dirflag not found */
  93. cpydest = FALSE; /* @@5b reset flag for not disp bad dev msg twice */
  94. cdevfail = FALSE; /* @@5b reset flag for not disp extra dev msg in copy */
  95. //
  96. // Mark level of find first handle. If an copy_error
  97. // is called this will allow only copies find handles to be
  98. // closed. For statement processing will have handles open
  99. // and these should not be closed
  100. FFhndlCopy = FFhndlsaved;
  101. source = NewCpyInfo();
  102. dest = NewCpyInfo();
  103. parse_args(args, source, dest); /* do parsing @@5d */
  104. DEBUG((FCGRP,COLVL,"COPY: Args parsed, copy_mode = %d.",copy_mode));
  105. if (copy_mode == COMBINE) {
  106. DEBUG((FCGRP,COLVL,"COPY: Going to do combined copy."));
  107. do_combine_copy(source, dest); /* @@5d */
  108. } else {
  109. DEBUG((FCGRP,COLVL,"COPY: Going to do normal copy."));
  110. rc = do_normal_copy(source, dest); /* @@4 @@5d */
  111. } ;
  112. PutStdOut(MSG_FILES_COPIED, ONEARG, argstr1(TEXT("%9d"), (unsigned long)number_of_files_copied)) ; /* M016 */
  113. VerifyCurrent = GetSetVerMode(GSVM_GET);
  114. return( rc ); /* @@4 */
  115. }
  116. /*** get_full_name - Init struct with full name
  117. *
  118. * Purpose:
  119. * Given a cpyinfo structure that has just been filled in by
  120. * findfirst or findnext, put the full name of the file that
  121. * was found in struct->curfspec.
  122. *
  123. * int get_full_name(struct copyinfo *src, TCHAR *srcbuf)
  124. *
  125. * Args:
  126. * src = The copy information structure
  127. * srcbuf = buffer to have curfspec point to
  128. *
  129. * Returns:
  130. * Returns SUCCESS normally
  131. *
  132. * Notes:
  133. * *** W A R N I N G ! ***
  134. * THIS ROUTINE WILL CAUSE AN ABORT IF MEMORY CANNOT BE ALLOCATED
  135. * THIS ROUTINE MUST NOT BE CALLED DURING A SIGNAL
  136. * CRITICAL SECTION OR DURING RECOVERY FROM AN ABORT
  137. */
  138. int get_full_name(src, srcbuf)
  139. PCPYINFO src;
  140. TCHAR *srcbuf;
  141. {
  142. int retval = SUCCESS; /* - return value boolean */
  143. unsigned plen,flen,diff; /* - length of path & file name */
  144. DEBUG((FCGRP,COLVL,"GetFullName: Entered fspec = TEXT('%ws')",src->fspec));
  145. src->curfspec = srcbuf;
  146. plen = mystrlen(src->fspec);
  147. flen = mystrlen(src->buf->cFileName);
  148. if (src->pathend) {
  149. diff = (UINT)(src->pathend - src->fspec) + 1;
  150. if ((plen+1 > MAX_PATH) ||
  151. (diff + flen + 1 > MAX_PATH)) {
  152. retval = FAILURE;
  153. } else {
  154. mystrcpy(src->curfspec,src->fspec);
  155. *(src->curfspec + diff) = NULLC;
  156. mystrcat(src->curfspec,src->buf->cFileName);
  157. }
  158. } else {
  159. mystrcpy(src->curfspec,src->buf->cFileName);
  160. }
  161. DEBUG((FCGRP,COLVL,"GetFullName: Exiting full name = TEXT('%ws')",src->curfspec));
  162. return( retval );
  163. }
  164. #ifndef WIN95_CMD
  165. /*** CopyProgressRtn
  166. *
  167. * Purpose:
  168. * This is a callback routine for CopyFileEx(). This
  169. * function is called once per chunk of data during a
  170. * restartable file copy.
  171. *
  172. * Args:
  173. * See winbase.h
  174. *
  175. * Returns:
  176. * See winbase.h
  177. *
  178. */
  179. DWORD WINAPI
  180. CopyProgressRtn(
  181. LARGE_INTEGER TotalFileSize,
  182. LARGE_INTEGER TotalBytesTransferred,
  183. LARGE_INTEGER StreamSize,
  184. LARGE_INTEGER StreamBytesTransferred,
  185. DWORD dwStreamNumber,
  186. DWORD dwCallbackReason,
  187. HANDLE hSourceFile,
  188. HANDLE hDestinationFile,
  189. BOOL ReallyRestartable
  190. )
  191. {
  192. LARGE_INTEGER percent;
  193. if (TotalFileSize.QuadPart != 0) {
  194. percent.QuadPart = (TotalBytesTransferred.QuadPart * 100) / TotalFileSize.QuadPart;
  195. } else {
  196. percent.QuadPart = 100;
  197. }
  198. PutStdOut( MSG_PROGRESS, ONEARG, argstr1(TEXT("%3d"), (unsigned long)percent.LowPart) );
  199. if (CtrlCSeen) {
  200. PutStdOut( MSG_PROGRESS, ONEARG, argstr1(TEXT("%3d"), (unsigned long)percent.LowPart) );
  201. printf( "\n" );
  202. if (ReallyRestartable) {
  203. return PROGRESS_STOP;
  204. } else {
  205. return PROGRESS_CANCEL;
  206. }
  207. } else {
  208. return PROGRESS_CONTINUE;
  209. }
  210. }
  211. #endif
  212. /*** do_normal_copy - Does actual copying for normal copy
  213. *
  214. * Purpose:
  215. * On entry, source points to the empty header of a list of
  216. * source filespecs, and dest points an empty struct that
  217. * points to the zero or one destination filespec given.
  218. * This procedure does the actual copying.
  219. *
  220. * int do_normal_copy(struct copyinfo *source, struct copyinfo *dest)
  221. *
  222. * Args:
  223. * source = The source copy information structure
  224. * dest = The destination copy information structure
  225. *
  226. * Returns:
  227. * FAILURE if not able to perform the copy
  228. *
  229. */
  230. int
  231. do_normal_copy(
  232. PCPYINFO source,
  233. PCPYINFO dest)
  234. {
  235. TCHAR buffer1[2*MAX_PATH];
  236. TCHAR curr_dest[MAX_PATH];
  237. TCHAR save_dest[MAX_PATH] = TEXT(" ");
  238. TCHAR source_buff[MAX_PATH];
  239. CRTHANDLE srcptr, destptr=BADHANDLE;
  240. FILETIME src_dateTime;
  241. ULONG buf_len, original_buflen;
  242. ULONG buf_len_dest;
  243. ULONG bytes_read;
  244. ULONG bytes_read_dest;
  245. CHAR * buf_seg ;
  246. CHAR * buf_seg_dest;
  247. HANDLE hnFirst ;
  248. unsigned rc = SUCCESS;
  249. unsigned rcode = TRUE;
  250. BOOL OpenWorked;
  251. BOOL DestIsDevice;
  252. BOOL Rslt;
  253. #ifndef WIN95_CMD
  254. BOOL ReallyRestartable;
  255. #endif
  256. int fsames;
  257. int skip_first_byte = 0;
  258. int multfile = FALSE;
  259. int save_flags = 0;
  260. int first_dest = TRUE;
  261. int dest_dirflag;
  262. int save_cmode;
  263. int dest_att;
  264. BOOL DecryptFlags =
  265. #if !defined( WIN95_CMD )
  266. ( ((dest->next == 0 ? dest->flags : dest->next->flags) & CI_ALLOWDECRYPT) != 0)
  267. ? COPY_FILE_ALLOW_DECRYPTED_DESTINATION :
  268. #endif // !defined( WIN95_CMD )
  269. FALSE;
  270. BOOL fFixList2Copy = 0; // fix "copy *.* foo" for FAT where foo does not exist.
  271. // work-around a problem with FindFirstFile/FindNextFile on FAT.
  272. BOOL fEof;
  273. DWORD dwSrcFileSize,
  274. dwSrcFileSizeHigh,
  275. dwDestFileSize,
  276. dwDestFileSizeHigh;
  277. dest_att = 0;
  278. save_cmode = 0;
  279. dest_dirflag = FALSE;
  280. //
  281. // Allocate a large buffer to hold read on copy.
  282. //
  283. buf_seg = (CHAR*)GetBigBuf(MAXCOPYBUFSIZE, MINCOPYBUFSIZE, (unsigned int *)&original_buflen, 0); /* allocate large buffer */
  284. if (!buf_seg) {
  285. return(FAILURE) ;
  286. }
  287. if (VerifyCurrent) {
  288. buf_seg_dest = (CHAR*)GetBigBuf(original_buflen, MINCOPYBUFSIZE, (unsigned int *)&buf_len_dest, 1); /* allocate large buffer */
  289. if (!buf_seg_dest) {
  290. return(FAILURE) ;
  291. }
  292. }
  293. //
  294. // Cycle through source files coping each to destination
  295. // This list along with parsing of file names occured in copy
  296. // paring code.
  297. //
  298. while (source = source->next) {
  299. //
  300. // Look for Read-Only (FILE_ATTRIBUTE_READONLY) and Archive (FILE_ATTRIBUTE_ARCHIVE) files in addition
  301. // to directories.
  302. //
  303. if (!ffirst(StripQuotes( source->fspec ),
  304. (unsigned int)FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_ARCHIVE,
  305. (PWIN32_FIND_DATA)source->buf,
  306. &hnFirst)) {
  307. DEBUG((FCGRP,COLVL,"DoNormalCopy: FFirst reports file %ws not found",source->fspec));
  308. //
  309. // Could not find file. Check if not concatinating files together
  310. // or this is the first file
  311. //
  312. if (copy_mode != CONCAT || first_file) {
  313. cmd_printf(Fmt11,source->fspec);
  314. cmd_printf(CrLf);
  315. PrtErr(DosErr) ;
  316. findclose(hnFirst);
  317. copy_error(0,CE_PCOUNT);
  318. } else {
  319. //
  320. // It is OK to fail for CONCAT. If it was the first file
  321. // a concat could have gone through the above loop and
  322. // printed out an error message
  323. //
  324. continue;
  325. }
  326. }
  327. DEBUG((FCGRP,COLVL,"DoNormalCopy: FFirst found file %ws",source->fspec));
  328. //
  329. // In case source is a wild card cycle through each file found
  330. //
  331. do {
  332. if (CtrlCSeen) {
  333. findclose(hnFirst) ;
  334. if (destptr != BADHANDLE)
  335. Cclose(destptr);
  336. return(FAILURE);
  337. }
  338. //
  339. // Put file name that was broken into pieces back together.
  340. //
  341. if (get_full_name(source, source_buff) == FAILURE) {
  342. findclose(hnFirst) ;
  343. return(FAILURE);
  344. }
  345. //
  346. // work-around a problem with FindFirstFile/FindNextFile on FAT
  347. // where just created dest. file is enumerated as one of the source files.
  348. //
  349. if ( (!first_file) && (copy_mode == CONCAT) ) {
  350. if ( same_file( save_dest, source->curfspec) ) {
  351. continue;
  352. }
  353. }
  354. //
  355. // if there are sources files from wildcards or '+' operators
  356. // used for concating files print out each one copied.
  357. //
  358. if (Wild(source) || (copy_mode == CONCAT)) {
  359. cmd_printf(Fmt17,source->curfspec);
  360. }
  361. //
  362. // If the dest. has not been opened, which will be the case
  363. // when not concat'ing files or this is the first file copied
  364. // then get then dest. name to open. get_dest_name will use
  365. // the source and dest. pattern (wild cards etc.) to form this
  366. // name
  367. //
  368. if ((copy_mode != CONCAT) || first_file) {
  369. if (get_dest_name(source,dest,curr_dest,MAX_PATH,FALSE) == FAILURE) {
  370. findclose(hnFirst) ;
  371. return(FAILURE);
  372. }
  373. if ( copy_mode == CONCAT ) {
  374. mystrcpy(save_dest, curr_dest);
  375. }
  376. //
  377. // If user said no to overwrite, then skip this file.
  378. //
  379. if (curr_dest[0] == NULLC)
  380. continue;
  381. }
  382. //
  383. // Now that the source and dest. have been determined, open
  384. // the source file
  385. //
  386. DEBUG((FCGRP,COLVL,"Attempt open of %ws",source->curfspec));
  387. srcptr = Copen_Copy2(source->curfspec, (ULONG)O_RDONLY);
  388. if (srcptr == BADHANDLE) {
  389. //
  390. // Print the error if failed to open
  391. //
  392. PrtErr(DosErr);
  393. //
  394. // If it is a CONCAT and do not have a destination
  395. // and the source and destination are the same then
  396. // go no futhur otherwise not FAILURE and continue
  397. // cycling through source names.
  398. //
  399. if ( (copy_mode == CONCAT) &&
  400. (destptr == BADHANDLE) &&
  401. (same_file(curr_dest,source->curfspec) )) {
  402. findclose(hnFirst);
  403. copy_error(0,CE_PCOUNT);
  404. }
  405. rc = FAILURE;
  406. continue;
  407. }
  408. //
  409. // Set Device flag, needed below for perfoming DOSQHANDTYPE
  410. //
  411. //
  412. // FileIsDevice will return TRUE if we opened NUL
  413. // above, and we don't want that.
  414. //
  415. if (FileIsDevice(srcptr)) {
  416. buf_len = MINCOPYBUFSIZE;
  417. source->flags |= CI_ISDEVICE;
  418. } else {
  419. if (VerifyCurrent)
  420. buf_len = min (original_buflen, buf_len_dest);
  421. else
  422. buf_len = original_buflen;
  423. buf_len_dest = buf_len;
  424. }
  425. //
  426. // set default mode
  427. //
  428. if (source->flags & CI_NOTSET) {
  429. source->flags &= ~CI_NOTSET;
  430. if (source->flags & CI_ISDEVICE) {
  431. //
  432. // Always run ASCII mode for a device
  433. //
  434. source->flags |= CI_ASCII;
  435. } else {
  436. //
  437. // Assume binary if just a file
  438. //
  439. source->flags |= CI_BINARY;
  440. }
  441. //
  442. // If this is the first file and it's not wild cards but
  443. // it is CONCAT mode then default to ASCII. This will
  444. // cause binaries files to get truncated on a CONCAT.
  445. //
  446. if (!fEnableExtensions &&
  447. first_file && !(Wild(source)) && (copy_mode == CONCAT)) {
  448. source->flags &= ~CI_BINARY;
  449. source->flags |= CI_ASCII;
  450. }
  451. } else {
  452. //
  453. // If they have been already set let them ride for
  454. // all file copies
  455. //
  456. save_flags = source->flags;
  457. }
  458. //
  459. // rcode is used to track read/write error. rc is used for
  460. // general track general FAILURES
  461. //
  462. rcode = TRUE;
  463. //
  464. // Prepare to handle the case where dest=source by
  465. // first getting the full source path name
  466. //
  467. fsames = FullPath(buffer1,source->curfspec,MAX_PATH*2);
  468. //
  469. // Let's start some copying
  470. //
  471. DEBUG((FCGRP,COLVL,"open %ws for writing",curr_dest));
  472. //
  473. // Read a buffer to check if source is bad. If source OK then
  474. // continue.
  475. //
  476. rcode = read_bytes(srcptr,
  477. buf_seg,
  478. 512,
  479. &bytes_read,
  480. source,
  481. destptr,
  482. StripQuotes( curr_dest ) );
  483. if (DosErr ) {
  484. Cclose(srcptr) ;
  485. PrtErr(ERROR_OPEN_FAILED) ;
  486. //
  487. // If not in CONCAT mode then read on source will fail copy
  488. // We want to continue in concat mode, gathering everything
  489. // together
  490. //
  491. if ( copy_mode != CONCAT ) {
  492. rc = FAILURE;
  493. continue;
  494. }
  495. findclose(hnFirst);
  496. copy_error(0,CE_PCOUNT) ;
  497. } else {
  498. //
  499. // If not combining files or the first file in a combine
  500. // check if source and dest. are the same.
  501. //
  502. if ((copy_mode != CONCAT) || (first_file)) {
  503. if (same_fcpy(fsames,buffer1,curr_dest) && !(source->flags & CI_ISDEVICE)) {
  504. Cclose(srcptr);
  505. //
  506. // If this is nither CONCAT or TOUCH mode then, this
  507. // call will not return but go to copy error code.
  508. //
  509. source_eq_dest(source,
  510. &destptr,
  511. first_file,
  512. buf_seg,
  513. buf_len,
  514. hnFirst
  515. );
  516. if (first_file) {
  517. if (copy_mode == CONCAT) {
  518. source->flags &= ~CI_BINARY;
  519. if (save_flags == 0) {
  520. source->flags |= CI_ASCII;
  521. } else {
  522. source->flags |= save_flags;
  523. }
  524. }
  525. multfile = TRUE;
  526. }
  527. //
  528. // In ASCII case can for a Ctrl-Z, used for file
  529. // termination.
  530. //
  531. scan_bytes(buf_seg,(unsigned int *)&bytes_read,source->flags);
  532. first_file = FALSE;
  533. continue;
  534. }
  535. cpydflag = TRUE;
  536. if (dest->next != NULL && first_file) {
  537. //
  538. // do not disp bad dev msg twice
  539. //
  540. cpydest = TRUE;
  541. DosErr = 0;
  542. ScanFSpec(dest->next);
  543. //
  544. // Do not fail if it was justa file name found.
  545. // or copy *.c foo would not work. Likewise do not
  546. // fail on just an invalid name, this would be
  547. // returned for a wild card on dest.
  548. //
  549. //
  550. if (DosErr == ERROR_NOT_READY || DosErr == ERROR_NO_MEDIA_IN_DRIVE) {
  551. PutStdOut(DosErr, NOARGS);
  552. Cclose(srcptr);
  553. findclose(hnFirst) ;
  554. return( FAILURE );
  555. }
  556. }
  557. //
  558. // this is called twice so that in the case where we're copying
  559. // to a directory, the file name gets appended to the directory
  560. // if it's not there.
  561. //
  562. if (get_dest_name(source,dest,curr_dest,MAX_PATH,TRUE) == FAILURE) {
  563. //
  564. // don't need to read it
  565. Cclose(srcptr);
  566. findclose(hnFirst) ;
  567. return(FAILURE);
  568. }
  569. //
  570. // If user said no to overwrite, then skip this file.
  571. //
  572. if (curr_dest[0] == NULLC) {
  573. Cclose(srcptr);
  574. continue;
  575. }
  576. if (same_fcpy(fsames,buffer1,curr_dest) && !(source->flags & CI_ISDEVICE)) {
  577. Cclose(srcptr);
  578. // set copy_mode so we don't delete the file in the case where
  579. // we're copying the files in a directory to the same directory.
  580. if (first_file && (dest->next != NULL && Wild(dest->next)) &&
  581. (!source->next)) {
  582. copy_mode = COPY;
  583. }
  584. //
  585. // If this is nither CONCAT or TOUCH mode then, this
  586. // call will not return but go to copy error code.
  587. //
  588. source_eq_dest(source,
  589. &destptr,
  590. first_file,
  591. buf_seg,
  592. buf_len,
  593. hnFirst
  594. );
  595. }
  596. //
  597. // save_flags == 0 only if copy modes have not been set
  598. //
  599. dest_att = GetFileAttributes(curr_dest);
  600. if (save_flags == 0) {
  601. if (first_dest) {
  602. //
  603. // Determine if copying to a directory. The assumption
  604. // that target is not a directory
  605. //
  606. dest_dirflag = FALSE;
  607. if (dest_att != -1) {
  608. if (dest_att & FILE_ATTRIBUTE_DIRECTORY) {
  609. dest_dirflag = TRUE;
  610. }
  611. }
  612. first_dest = FALSE;
  613. }
  614. source->flags &= ~CI_NOTSET;
  615. if (!fEnableExtensions &&
  616. Wild(source) && (copy_mode == CONCAT)) {
  617. save_cmode = CONCAT;
  618. if (dest_dirflag == FALSE) {
  619. if (dest->next == NULL || !(Wild(dest->next))) {
  620. source->flags |= CI_ASCII;
  621. } else {
  622. source->flags |= CI_BINARY;
  623. }
  624. }
  625. } else {
  626. if ((dest_dirflag) && (save_cmode == CONCAT)) {
  627. source->flags |= CI_BINARY;
  628. }
  629. }
  630. }
  631. if (first_file && (dest->next != NULL && Wild(dest->next)) &&
  632. (!source->next)) {
  633. copy_mode = COPY;
  634. }
  635. if (first_file) {
  636. if (copy_mode == CONCAT) {
  637. if (save_flags == 0) {
  638. source->flags &= ~CI_BINARY;
  639. source->flags |= CI_ASCII;
  640. } else {
  641. source->flags = save_flags;
  642. }
  643. }
  644. }
  645. // see if destination exists. open it with write only
  646. // access, no create.
  647. if (dest_att & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
  648. DosErr=ERROR_ACCESS_DENIED;
  649. destptr = BADHANDLE;
  650. if (copy_mode == CONCAT)
  651. fFixList2Copy = 1;
  652. } else {
  653. if (!(source->flags & CI_RESTARTABLE)) {
  654. destptr = Copen_Copy3((TCHAR *)curr_dest);
  655. }
  656. }
  657. DestIsDevice=FALSE;
  658. if (destptr != BADHANDLE) {
  659. OpenWorked = TRUE;
  660. if (FileIsDevice(destptr)) {
  661. DestIsDevice=TRUE;
  662. if (save_flags == 0) {
  663. source->flags &= ~CI_BINARY;
  664. source->flags |= CI_ASCII ;
  665. }
  666. }
  667. } else {
  668. OpenWorked = FALSE;
  669. }
  670. } // if on (copy_mode != CONCAT) || (first_file))
  671. } // else from no DosErr on File Read of current source
  672. if (multfile == TRUE) {
  673. if (copy_mode == CONCAT) {
  674. source->flags &= ~CI_BINARY;
  675. if (save_flags == 0) {
  676. source->flags |= CI_ASCII;
  677. } else {
  678. source->flags |= save_flags;
  679. }
  680. }
  681. }
  682. if (!Wild(source) && (copy_mode == CONCAT)) {
  683. if (save_flags == 0) {
  684. source->flags &= ~CI_BINARY;
  685. source->flags |= CI_ASCII;
  686. }
  687. }
  688. if (Wild(source) && (copy_mode == CONCAT) && (dest_dirflag == FALSE)) {
  689. if (save_flags == 0) {
  690. source->flags &= ~CI_BINARY;
  691. source->flags |= CI_ASCII;
  692. }
  693. }
  694. scan_bytes(buf_seg,(unsigned int *)&bytes_read,source->flags);
  695. if ((copy_mode != CONCAT) && (source->flags & CI_BINARY)) {
  696. if (destptr != BADHANDLE) {
  697. Cclose(destptr);
  698. destptr=BADHANDLE;
  699. }
  700. #ifndef WIN95_CMD
  701. if (source->flags & CI_RESTARTABLE) {
  702. if ( (!FileIsRemote( source->curfspec )) &&
  703. (!FileIsRemote( curr_dest )) ) {
  704. ReallyRestartable = FALSE;
  705. } else {
  706. ReallyRestartable = TRUE;
  707. }
  708. Rslt = (*lpCopyFileExW)(
  709. source->curfspec,
  710. curr_dest,
  711. (LPPROGRESS_ROUTINE) CopyProgressRtn,
  712. (LPVOID)IntToPtr(ReallyRestartable),
  713. NULL,
  714. COPY_FILE_RESTARTABLE | DecryptFlags
  715. );
  716. } else {
  717. if (lpCopyFileExW == NULL) {
  718. #endif // WIN95_CMD
  719. Rslt = CopyFile(
  720. source->curfspec,
  721. curr_dest,
  722. DecryptFlags
  723. );
  724. #ifndef WIN95_CMD
  725. } else {
  726. Rslt = (*lpCopyFileExW)(
  727. source->curfspec,
  728. curr_dest,
  729. NULL,
  730. NULL,
  731. &CtrlCSeen,
  732. DecryptFlags
  733. );
  734. }
  735. }
  736. #endif // WIN95_CMD
  737. if (!Rslt) {
  738. unsigned int msg = 0;
  739. DosErr=GetLastError();
  740. Cclose(srcptr) ;
  741. if (DestIsDevice) {
  742. msg = ERROR_WRITE_FAULT;
  743. }/* else if (DosErr != ERROR_NO_MEDIA_IN_DRIVE &&
  744. DosErr != ERROR_ACCESS_DENIED) {
  745. DeleteFile( curr_dest );
  746. } */
  747. Heof = FALSE;
  748. if (!DosErr) {
  749. DosErr = ERROR_DISK_FULL ;
  750. }
  751. if (CtrlCSeen) {
  752. msg = 0;
  753. } else {
  754. if (!msg) {
  755. PrtErr(DosErr);
  756. }
  757. }
  758. if (!OpenWorked) {
  759. // copy failed because target was RO or hidden
  760. rc = FAILURE;
  761. first_fflag = TRUE;
  762. continue;
  763. }
  764. copy_error(msg,CE_PCOUNT);
  765. } else
  766. if (!DestIsDevice) {
  767. //
  768. // CopyFile preserves Read-Only. For DOS compat. need
  769. // to remove.
  770. //
  771. DWORD dwAttrib;
  772. dwAttrib = GetFileAttributes(curr_dest);
  773. if (dwAttrib == 0xFFFFFFFF
  774. || !SetFileAttributes(curr_dest, dwAttrib & ~FILE_ATTRIBUTE_READONLY)) {
  775. // PutStdErr( GetLastError( ), NOARGS );
  776. // PutStdErr( MSG_UNABLE_TO_RESET_READ_ONLY_ATTRIBUTE, ONEARG, curr_dest );
  777. }
  778. // need to get a handle to verify write.
  779. if (VerifyCurrent) {
  780. destptr = Copen2((TCHAR *)curr_dest,
  781. (unsigned int)O_WRONLY,
  782. FALSE);
  783. if (destptr == BADHANDLE) {
  784. // printf( "do_normal_copy: Unable to open file for verification %d\n", DosErr);
  785. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  786. goto l_out;
  787. }
  788. if ( FileIsDevice(destptr) ) {
  789. // printf( "do_normal_copy: Somehow this is now a device for verification?\n" );
  790. Cclose(destptr);
  791. destptr=BADHANDLE;
  792. goto l_out;
  793. }
  794. if (!FlushFileBuffers ( CRTTONT(destptr) ) ) {
  795. // printf( "do_normal_copy: Unable to flush buffers verification %d\n", GetLastError( ));
  796. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  797. Cclose(destptr);
  798. destptr=BADHANDLE;
  799. goto l_out;
  800. }
  801. Cclose(destptr);
  802. destptr=BADHANDLE;
  803. // read the Src and Dest files back to memory and compare.
  804. destptr = Copen_Copy2(curr_dest, (ULONG)O_RDONLY);
  805. if (destptr == BADHANDLE) {
  806. // printf( "do_normal_copy: Unable to open file for verification 2 %d\n", DosErr);
  807. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  808. goto l_out;
  809. }
  810. if ( FileIsDevice(destptr) ) {
  811. // printf( "do_normal_copy: Somehow this is now a device for verification 2?\n" );
  812. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  813. Cclose(destptr);
  814. destptr=BADHANDLE;
  815. goto l_out;
  816. }
  817. SetFilePointer( CRTTONT(srcptr), 0, NULL, FILE_BEGIN);
  818. SetFilePointer( CRTTONT(destptr), 0, NULL, FILE_BEGIN);
  819. dwSrcFileSize = GetFileSize( CRTTONT(srcptr), &dwSrcFileSizeHigh);
  820. dwDestFileSize = GetFileSize( CRTTONT(destptr), &dwDestFileSizeHigh);
  821. if ( (dwSrcFileSize != dwDestFileSize) || (dwSrcFileSizeHigh != dwDestFileSizeHigh ) ) {
  822. // printf( "do_normal_copy: Files are different sizes %x:%08x %x:%08x\n", dwSrcFileSizeHigh, dwSrcFileSize, dwDestFileSizeHigh, dwDestFileSize );
  823. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  824. Cclose(destptr);
  825. destptr=BADHANDLE;
  826. goto l_out;
  827. }
  828. fEof = 0;
  829. while (!fEof) {
  830. if (!ReadFile( CRTTONT(srcptr), buf_seg, buf_len, &bytes_read,NULL ) ) {
  831. // printf( "do_normal_copy: Failure to read source block - %d\n", GetLastError( ));
  832. Cclose(destptr);
  833. destptr=BADHANDLE;
  834. goto l_out;
  835. }
  836. if ( bytes_read == 0 ) {
  837. // printf( "do_normal_copy: Unexpectedly read 0 bytes from source\n" );
  838. Cclose(destptr);
  839. destptr=BADHANDLE;
  840. goto l_out;
  841. }
  842. if (!ReadFile( CRTTONT(destptr), buf_seg_dest, bytes_read, &bytes_read_dest,NULL) ) {
  843. // printf( "do_normal_copy: Failure to read dest block - %d\n", GetLastError( ) );
  844. Cclose(destptr);
  845. destptr=BADHANDLE;
  846. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  847. goto l_out;
  848. }
  849. if (bytes_read_dest != bytes_read ) {
  850. // printf( "do_normal_copy: Unexpectedly read fewer bytes\n" );
  851. Cclose(destptr);
  852. destptr=BADHANDLE;
  853. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  854. goto l_out;
  855. }
  856. if (buf_len != bytes_read)
  857. fEof = 1;
  858. if ( memcmp (buf_seg, buf_seg_dest, bytes_read) != 0 ) {
  859. // printf( "do_normal_copy: Data is different at offset %x\n", memcmp (buf_seg, buf_seg_dest, bytes_read) );
  860. Cclose(destptr);
  861. destptr=BADHANDLE;
  862. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  863. goto l_out;
  864. }
  865. }
  866. Cclose(destptr);
  867. destptr=BADHANDLE;
  868. }
  869. l_out: ;
  870. // check file timestamp in FUTURE to handle wildcard.
  871. }
  872. } else {
  873. //
  874. // open the destination
  875. //
  876. if (destptr == BADHANDLE) {
  877. destptr = Copen2((TCHAR *)curr_dest,
  878. (unsigned int)O_WRONLY,
  879. FALSE);
  880. if (destptr == BADHANDLE) {
  881. Cclose(srcptr) ;
  882. if (cdevfail == FALSE) {
  883. PrtErr(DosErr);
  884. }
  885. if ( copy_mode != CONCAT ) {
  886. rc = FAILURE;
  887. first_fflag = TRUE;
  888. continue;
  889. }
  890. findclose(hnFirst);
  891. copy_error(0,CE_PCOUNT) ;
  892. }
  893. }
  894. //
  895. // Handle appending of unicode text files with byte order marks.
  896. // Do this except on the first file and only when appending
  897. // ascii files.
  898. //
  899. if (!first_file
  900. && copy_mode == CONCAT
  901. && (source->flags & CI_ASCII) != 0
  902. && (source->flags & CI_UNICODE) != 0) {
  903. bytes_read -= sizeof( WORD );
  904. memmove( buf_seg, buf_seg + sizeof( WORD ), bytes_read );
  905. }
  906. if ((source->flags & CI_UNICODE) != 0) {
  907. if (dest->next != NULL) {
  908. dest->next->flags |= CI_UNICODE;
  909. } else {
  910. dest->flags |= CI_UNICODE;
  911. }
  912. }
  913. //
  914. // If eof and bytesread > 0 then write the data.
  915. // If fail then exit through write_bytes
  916. //
  917. if (Heof && ((int)bytes_read > 0)) {
  918. write_bytes(destptr,buf_seg,bytes_read,curr_dest,srcptr);
  919. if (VerifyCurrent && !FileIsDevice(destptr) ) {
  920. if ( DoVerify(&destptr, curr_dest, bytes_read, buf_seg, buf_seg_dest) == FAILURE ) {
  921. findclose(hnFirst);
  922. copy_error(0,CE_PCOUNT) ;
  923. }
  924. }
  925. } else {
  926. //
  927. // Loop through writing and reading bytes
  928. // If fail then exit through write_bytes
  929. //
  930. while (!Heof && (rcode == TRUE)) {
  931. write_bytes(destptr,buf_seg,bytes_read,curr_dest,srcptr);
  932. if (VerifyCurrent && !FileIsDevice(destptr) ) {
  933. if ( DoVerify(&destptr, curr_dest, bytes_read, buf_seg, buf_seg_dest) == FAILURE ) {
  934. findclose(hnFirst);
  935. copy_error(0,CE_PCOUNT) ;
  936. }
  937. }
  938. rcode = read_bytes(srcptr,
  939. buf_seg,
  940. buf_len,
  941. (PULONG)&bytes_read,
  942. source,
  943. destptr,
  944. curr_dest);
  945. DEBUG((FCGRP,COLVL,"In rd/wt loop 1, Heof = %d",Heof));
  946. }
  947. if (Heof && ((int)bytes_read > 0) && (rcode == TRUE)) {
  948. write_bytes(destptr,buf_seg,bytes_read,curr_dest,srcptr);
  949. if (VerifyCurrent && !FileIsDevice(destptr) ) {
  950. if ( DoVerify(&destptr, curr_dest, bytes_read, buf_seg, buf_seg_dest) == FAILURE ) {
  951. findclose(hnFirst);
  952. copy_error(0,CE_PCOUNT) ;
  953. }
  954. }
  955. }
  956. }
  957. }
  958. //
  959. // Clear when src closed
  960. //
  961. Heof = FALSE ;
  962. DEBUG((FCGRP,COLVL,"Closing, Heof reset to %d",Heof));
  963. //
  964. // update file data in dir
  965. //
  966. src_dateTime = source->buf->ftLastWriteTime ;
  967. Cclose(srcptr);
  968. //
  969. // keep dest open if concat since it will be used again
  970. //
  971. if (copy_mode != CONCAT) {
  972. if (CtrlCSeen) {
  973. Cclose(destptr);
  974. DeleteFile(curr_dest);
  975. rc = FAILURE;
  976. } else {
  977. close_dest(source,dest,curr_dest,destptr,&src_dateTime);
  978. }
  979. //
  980. // reset EA xfer flag from src
  981. //
  982. first_fflag = TRUE;
  983. }
  984. first_file = FALSE;
  985. } while (fnext( (PWIN32_FIND_DATA)source->buf, (unsigned int)FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_ARCHIVE,hnFirst));
  986. findclose(hnFirst) ;
  987. }
  988. //
  989. // Remember that dest was left open for concat
  990. //
  991. if (copy_mode == CONCAT && destptr != BADHANDLE) {
  992. close_dest(source,dest,curr_dest,destptr,NULL);
  993. }
  994. return( rc );
  995. }
  996. /*** source_eq_dest - Handles cases where source and dest files are same
  997. *
  998. * Purpose:
  999. * While copying, we ran across a source and destination that
  1000. * were the same. In concatenation or touch mode this is
  1001. * acceptable, otherwise it isn't. If we are concatenating
  1002. * and this is the first file, we can just open it for appending
  1003. * as the destination. We save ourselves the copy and are ready
  1004. * to append the other files to it. If this isn't the first
  1005. * file, * we have already messed up the contents of the source
  1006. * from previous concatenations, so we report that but keep
  1007. * going. If we are doing a touch, go ahead and do it and
  1008. * increment the file counter.
  1009. *
  1010. * int source_eq_dest(PCPYINFO source,int *destptr,int *first_file,
  1011. * TCHAR *buf_seg, unsigned buf_len)
  1012. *
  1013. * Args:
  1014. * source = Source copy information structure
  1015. * destptr = Destination file handle
  1016. * first_file = First file flag
  1017. * buf_seg = Copy buffer
  1018. * buf_len = Buffer length
  1019. *
  1020. * Returns:
  1021. * Nothing. Terminates through copy_error if unable to continue
  1022. *
  1023. */
  1024. void
  1025. source_eq_dest(source, destptr, first_file, buf_seg, buf_len, hnFirst)
  1026. PCPYINFO source;
  1027. CRTHANDLE *destptr; /* dest file handle */
  1028. int first_file;
  1029. CHAR *buf_seg ;
  1030. unsigned buf_len;
  1031. HANDLE hnFirst; /* ffirst/fnext handle @@5@J15 */
  1032. {
  1033. CRTHANDLE fh ; /* file handle for touch */
  1034. FILETIME FileTime;
  1035. DEBUG((FCGRP,COLVL,"SourceEqDest: Entered."));
  1036. if (copy_mode == CONCAT) { /* it's ok in concat mode */
  1037. if (!first_file) { /* dest was wiped if not 1st file */
  1038. /* M016 */
  1039. PutStdOut(MSG_CONT_LOST_BEF_COPY, NOARGS);
  1040. } else { /* must open so later files append */
  1041. *destptr = open_for_append(
  1042. source->curfspec,
  1043. source,
  1044. buf_seg,
  1045. (unsigned int)buf_len
  1046. );
  1047. }
  1048. } else {
  1049. if (copy_mode == TOUCH) { /* just touch - no copy */
  1050. DEBUG((FCGRP,COLVL,"touching file"));
  1051. fh = Copen2( /* open file for destination file */
  1052. (TCHAR *)source->curfspec, /* explicit cast */
  1053. (unsigned int)O_RDWR, /* make explicit cast */
  1054. TRUE);
  1055. if (fh == BADHANDLE) {
  1056. findclose(hnFirst);
  1057. PrtErr(ERROR_OPEN_FAILED) ; /* M019 */
  1058. copy_error(0,CE_PCOUNT) ; /* M019 */
  1059. }
  1060. ConverttmToFILETIME( NULL, &FileTime );
  1061. SetFileTime( CRTTONT(fh),
  1062. NULL,
  1063. NULL,
  1064. &FileTime
  1065. );
  1066. Cclose(fh);
  1067. number_of_files_copied++;
  1068. } else {
  1069. findclose(hnFirst); /* close ffirst/fnext handle for dup file name @@5@J15 */
  1070. copy_error(MSG_CANNOT_COPIED_ONTO_SELF,CE_PCOUNT); /* M016 */
  1071. }
  1072. }
  1073. }
  1074. /*** do_combine_copy - Handle combining copy commands
  1075. *
  1076. *
  1077. * Purpose:
  1078. * This handles commands like "copy *.tmp+*.foo *.out". The
  1079. * idea is to look through the source specs until one matches
  1080. * a file. Generally this will be the first one. Then, for
  1081. * each match for the first spec, cycle through the remaining
  1082. * source specs, seeing if they have a corresponding match. If
  1083. * so, append it to the file matched by the first spec.
  1084. *
  1085. * int do_combine_copy(PCPYINFO source, PCPYINFO dest)
  1086. *
  1087. * Args:
  1088. * source = The source copy information structure
  1089. * dest = The destination copy information structure
  1090. *
  1091. * Returns:
  1092. * SUCCESS if able to perform the copy
  1093. * FAILURE if not
  1094. *
  1095. * Notes:
  1096. * As an example, suppose the files a.tmp, b.tmp, c.tmp, and
  1097. * b.foo were in the current directory. The example mentioned
  1098. * above would: copy a.tmp to a.out, append b.tmp and b.foo
  1099. * into b.out, and copy c.tmp to c.out. The default mode when
  1100. * doing this type of copy is ascii, so all the .out files would
  1101. * have a ^Z appended to them.
  1102. *
  1103. */
  1104. do_combine_copy(source, dest)
  1105. PCPYINFO source;
  1106. PCPYINFO dest;
  1107. {
  1108. TCHAR curr_dest[MAX_PATH]; /* buffer for src names */
  1109. TCHAR source_buff[MAX_PATH]; /* @@4 */
  1110. TCHAR other_source[MAX_PATH]; /* same */
  1111. PCPYINFO other_source_spec = source; /* ptr to source */
  1112. CRTHANDLE srcptr,destptr; /* file pointers */
  1113. unsigned buf_len, /* for GetBigBuf() */
  1114. buf_len_dest,
  1115. bytes_read; /* for data copying funcs */
  1116. CHAR *buf_seg ;
  1117. CHAR *buf_seg_dest;
  1118. HANDLE hnFirst ;
  1119. unsigned rcode = TRUE; /* ret code from read @@J */
  1120. unsigned wrc;
  1121. int dest_att=0;
  1122. DEBUG((FCGRP,COLVL,"DoCombineCopy: Entered."));
  1123. buf_seg = (CHAR*)GetBigBuf(MAXCOPYBUFSIZE, MINCOPYBUFSIZE, (unsigned int *)&buf_len, 0); /* allocate large buffer */
  1124. if (!buf_seg) {
  1125. return(FAILURE) ;
  1126. }
  1127. if (VerifyCurrent) {
  1128. buf_seg_dest = (CHAR*)GetBigBuf(buf_len, MINCOPYBUFSIZE, (unsigned int *)&buf_len_dest, 1); /* allocate large buffer */
  1129. if (!buf_seg_dest) {
  1130. return(FAILURE) ;
  1131. }
  1132. buf_len = min(buf_len, buf_len_dest);
  1133. }
  1134. /* find the first spec with any matching files */
  1135. source = source->next; /* point to first source */
  1136. while (!exists(source->fspec)) {
  1137. DEBUG((FCGRP,COLVL,"exists() reports file %ws non-existant",source->fspec));
  1138. if (!(source = source->next)) { /* no match, try next spec */
  1139. return(SUCCESS); /* no match for any source */
  1140. }
  1141. }
  1142. DEBUG((FCGRP,COLVL,"Preparing to do ffirst on %ws",source->fspec));
  1143. ffirst( /* get DOSFINDFIRST2 level 2 @@5@J1 */
  1144. (TCHAR *)source->fspec, /* make explicit cast @@5@J1 */
  1145. (unsigned int)FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_ARCHIVE,
  1146. (PWIN32_FIND_DATA)source->buf, /* make explicit cast @@5@J1 */
  1147. &hnFirst);
  1148. /* cycle through files, trying to match with other source specs */
  1149. do {
  1150. source->flags &= ~(CI_UNICODE | CI_NOT_UNICODE);
  1151. rcode = TRUE;
  1152. if (source->flags & CI_NOTSET) { /* set default copy mode */
  1153. source->flags = (source->flags & ~CI_NOTSET) | CI_ASCII;
  1154. }
  1155. if (CtrlCSeen) {
  1156. findclose(hnFirst) ;
  1157. return(FAILURE);
  1158. }
  1159. if (get_full_name(source, source_buff) == FAILURE) { /* @@4 */
  1160. findclose(hnFirst);
  1161. return(FAILURE) ; /* get matching file name */
  1162. }
  1163. cmd_printf(Fmt17,source->curfspec); /* and print it */
  1164. if (get_dest_name(source,dest,curr_dest,MAX_PATH,FALSE) == FAILURE) {
  1165. findclose(hnFirst);
  1166. return(FAILURE); /* get full name of src */
  1167. }
  1168. //
  1169. // If user said no to overwrite, then skip this file.
  1170. //
  1171. if (curr_dest[0] == NULLC)
  1172. continue;
  1173. if (same_file(source->curfspec,curr_dest)) { /* append */
  1174. destptr = open_for_append(
  1175. source->curfspec,
  1176. source,
  1177. buf_seg,
  1178. (unsigned int)buf_len);
  1179. } else {
  1180. DEBUG((FCGRP,COLVL,"open %ws for reading",source->curfspec));
  1181. DEBUG((FCGRP,COLVL,"open %ws for writing",curr_dest));
  1182. srcptr = Copen_Copy2( /* open a source file */
  1183. (TCHAR *)source->curfspec, /* using this file name */
  1184. (unsigned int)O_RDONLY); /* for read-only */
  1185. if (srcptr == BADHANDLE) { /* if open failed then */
  1186. /* then */
  1187. findclose(hnFirst);
  1188. PrtErr(ERROR_OPEN_FAILED); /* display error */
  1189. copy_error(0,CE_PCOUNT);
  1190. }
  1191. if (FileIsDevice(srcptr)) {
  1192. buf_len = MINCOPYBUFSIZE;
  1193. }
  1194. /* @@J */rcode = read_bytes( srcptr,buf_seg, /* read first src data */
  1195. /* @@J */ buf_len,
  1196. (PULONG)&bytes_read, /* to see if src bad */
  1197. /* @@J */ source,
  1198. destptr,
  1199. curr_dest); /* if bad do not open */
  1200. /* @@J */
  1201. if (DosErr )
  1202. /* @@J */
  1203. {
  1204. /* dest file. */
  1205. findclose(hnFirst);
  1206. /* M011 @@J */Cclose(srcptr) ; /* close soure file */
  1207. /* @@J */PrtErr(ERROR_OPEN_FAILED) ; /* display error message */
  1208. /* @@J */copy_error(0,CE_PCOUNT) ; /* catch all copy terminate */
  1209. /* @@J */
  1210. } /* routine and display # files*/
  1211. /* @@J */
  1212. else /* copied trailer info */
  1213. /* @@J */
  1214. {
  1215. dest_att = GetFileAttributes(curr_dest);
  1216. if ( ! (dest_att & FILE_ATTRIBUTE_HIDDEN) )
  1217. destptr = Copen_Copy3((TCHAR *)curr_dest);
  1218. else
  1219. /* @@5 @J1*/ destptr = Copen2( /* open destination file */
  1220. (TCHAR *)curr_dest, /* filename */
  1221. (unsigned int)O_WRONLY,
  1222. FALSE);
  1223. /* M011@@J */
  1224. if (destptr == BADHANDLE) /* if open failed @@5@J1*/
  1225. /* @@J */
  1226. {
  1227. /* then */
  1228. findclose(hnFirst);
  1229. /* M011 @@J */Cclose(srcptr) ; /* Close src on dst open err */
  1230. /* @@J */PrtErr(ERROR_OPEN_FAILED) ;
  1231. /* @@J */copy_error(0,CE_PCOUNT) ;
  1232. /* @@J */
  1233. }
  1234. }
  1235. /* @@J */ if (Heof && ((int)bytes_read > 0 )) /* if eof but bytes read */
  1236. /* @@J */
  1237. {
  1238. /* then write data and */
  1239. /* @@J */ /* if fail then will exit */
  1240. /* @@J */
  1241. write_bytes(destptr,buf_seg,bytes_read,curr_dest,srcptr);
  1242. if (VerifyCurrent && !FileIsDevice(destptr) ) {
  1243. if ( DoVerify(&destptr, curr_dest, bytes_read, buf_seg, buf_seg_dest) == FAILURE ) {
  1244. findclose(hnFirst);
  1245. Cclose(srcptr);
  1246. Cclose(destptr);
  1247. copy_error(0,CE_PCOUNT) ;
  1248. }
  1249. }
  1250. /* @@J */
  1251. }
  1252. /* @@J */ /* */
  1253. /* @@J */while (!Heof && (rcode == TRUE)) /* while not at EOF or bad rc */
  1254. /* @@J */
  1255. {
  1256. /* perform copy loop */
  1257. /* @@J */ /* if fail then will exit */
  1258. /* @@J */
  1259. write_bytes(destptr,buf_seg,bytes_read,curr_dest,srcptr);
  1260. /* @@J */ /* */
  1261. if (VerifyCurrent && !FileIsDevice(destptr) ) {
  1262. if ( DoVerify(&destptr, curr_dest, bytes_read, buf_seg, buf_seg_dest) == FAILURE ) {
  1263. findclose(hnFirst);
  1264. Cclose(srcptr);
  1265. Cclose(destptr);
  1266. copy_error(0,CE_PCOUNT) ;
  1267. }
  1268. }
  1269. /* @@J */rcode = read_bytes(srcptr,buf_seg, /* read next src data */
  1270. /* @@J */ buf_len,(PULONG)&bytes_read,
  1271. /* @@J */ source,destptr,curr_dest);
  1272. /* @@J */
  1273. /* @@J */DEBUG((FCGRP,COLVL,"Closing, Heof reset to %d",Heof));
  1274. /* @@J */
  1275. /* @@J */
  1276. };
  1277. Heof = FALSE ; /* Clear when src closed */
  1278. Cclose(srcptr); /* M011 */
  1279. }
  1280. first_file = FALSE; /* set first file processed @@5@J1 */
  1281. /* The source is handled, now cycle through the other wildcards that
  1282. * were entered and see if they match a file that should be appended.
  1283. * If the file they match is the same as the destination, report
  1284. * contents lost and keep going. Ex: "copy *.a+b*.b b.*" where a.b
  1285. * and b.b exist. b*.b matches b.b but the target file is b.b and
  1286. * its contents were already destroyed when a.b was copied into it.
  1287. */
  1288. other_source_spec = source;
  1289. while (other_source_spec = other_source_spec->next) {
  1290. if (other_source_spec->flags & CI_NOTSET) {
  1291. other_source_spec->flags &= ~CI_NOTSET;
  1292. other_source_spec->flags |= CI_ASCII;
  1293. }
  1294. wrc = wildcard_rename( /* rename filename for wild */
  1295. (TCHAR *)other_source, /* result filename */
  1296. (TCHAR *)other_source_spec->fspec, /* dest input filename */
  1297. (TCHAR *)source->curfspec, /* source input filename */
  1298. (unsigned)MAX_PATH); /* size of result filename area */
  1299. if (wrc) {
  1300. PutStdOut(wrc,NOARGS);
  1301. } else {
  1302. cmd_printf(Fmt17,other_source); /* print filename */
  1303. }
  1304. if (exists(other_source)) {
  1305. if (same_file(other_source,curr_dest)) {
  1306. /* M016 */
  1307. PutStdOut(MSG_CONT_LOST_BEF_COPY,NOARGS);
  1308. } else { /* append to curr_dest */
  1309. DEBUG((FCGRP,COLVL,
  1310. "open %s for reading",
  1311. other_source));
  1312. /* @@5 @J1 */
  1313. srcptr = Copen_Copy2( /* open a source file @@5@J1*/
  1314. (TCHAR *)other_source,/* using this file name @@5@J1*/
  1315. (unsigned int)O_RDONLY); /* for read-only @@5@J1*/
  1316. /* @@5@J1*/
  1317. if (srcptr == BADHANDLE) { /* if open failed then */
  1318. /* then */
  1319. findclose(hnFirst);
  1320. Cclose(destptr); /* close destination file */
  1321. PrtErr(ERROR_OPEN_FAILED) ; /* M019 */
  1322. copy_error(0,CE_PCOUNT) ; /* M019 */
  1323. }
  1324. if (FileIsDevice( srcptr )) {
  1325. buf_len = MINCOPYBUFSIZE;
  1326. }
  1327. while (!Heof && read_bytes(srcptr,
  1328. buf_seg,
  1329. buf_len,
  1330. (PULONG)&bytes_read,
  1331. other_source_spec,
  1332. destptr,curr_dest)) {
  1333. write_bytes(destptr,
  1334. buf_seg,
  1335. bytes_read,
  1336. curr_dest,
  1337. srcptr);
  1338. if (VerifyCurrent && !FileIsDevice(destptr) ) {
  1339. if ( DoVerify(&destptr, curr_dest, bytes_read, buf_seg, buf_seg_dest) == FAILURE ) {
  1340. findclose(hnFirst);
  1341. Cclose(srcptr);
  1342. Cclose(destptr);
  1343. copy_error(0,CE_PCOUNT) ;
  1344. }
  1345. }
  1346. DEBUG((FCGRP,COLVL,
  1347. "In rd/wt loop 3, Heof = %d",
  1348. Heof));
  1349. } ;
  1350. Heof = FALSE ; /* M017 - Clear it */
  1351. DEBUG((FCGRP,COLVL,"Closing, Heof reset to %d",Heof));
  1352. Cclose(srcptr); /* M011 */
  1353. }
  1354. }
  1355. }
  1356. close_dest(source,dest,curr_dest,destptr,NULL);
  1357. /*@@5@J3*/first_fflag = TRUE;
  1358. } while (fnext ((PWIN32_FIND_DATA)source->buf,
  1359. (unsigned int)FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_ARCHIVE, hnFirst));
  1360. findclose(hnFirst) ;
  1361. return( SUCCESS );
  1362. }
  1363. /*** NewCpyInfo - Init the cpyinfo struct
  1364. *
  1365. * Purpose:
  1366. * Allocate space for a cpyinfo struct and fill it in with null values.
  1367. *
  1368. * CPYINFO NewCpyInfo()
  1369. *
  1370. * Args:
  1371. * None
  1372. *
  1373. * Returns:
  1374. * Pointer to cpyinfo struct if allocated,
  1375. * ABORT's if not.
  1376. *
  1377. * Notes:
  1378. * *** W A R N I N G ! ***
  1379. * THIS ROUTINE WILL CAUSE AN ABORT IF MEMORY CANNOT BE ALLOCATED
  1380. * THIS ROUTINE MUST NOT BE CALLED DURING A SIGNAL
  1381. * CRITICAL SECTION OR DURING RECOVERY FROM AN ABORT
  1382. */
  1383. PCPYINFO
  1384. NewCpyInfo( VOID )
  1385. {
  1386. PCPYINFO temp;
  1387. DEBUG((FCGRP,COLVL,"InitStruct: Entered."));
  1388. temp = (PCPYINFO) gmkstr(sizeof(CPYINFO)); /*WARNING*/
  1389. temp->fspec = NULL;
  1390. temp->flags = 0;
  1391. temp->next = NULL;
  1392. return(temp);
  1393. }
  1394. /*** close_dest - Handle close operation on destination file
  1395. *
  1396. * Purpose:
  1397. * o Append a control-Z to the destination if the copy mode for it
  1398. * is ascii. If a destination wasn't specified, the dest spec
  1399. * points to the empty header, the next field is NULL, and the
  1400. * parser put the copy mode into the empty header's flags field.
  1401. * If the dest was specified, then the mode is in the struct
  1402. * pointed to by the header.
  1403. *
  1404. * o Set all the appropriate attributes. Read-only and system
  1405. * don't stay, but the rest do. Also, set the time and date if
  1406. * neither source nor target is a device and src_date is valid.
  1407. * The caller tell us it isn't valid by setting it to -1.
  1408. *
  1409. * o Close the destination file.
  1410. *
  1411. * o Update the number of files copied.
  1412. *
  1413. * int close_dest(PCPYINFO source,PCPYINFO dest,
  1414. * TCHAR *curr_dest,int destptr,LPFIMETIME src_dateTime)
  1415. *
  1416. * Args:
  1417. * source = Source copy information structure
  1418. * dest = Source copy information structure
  1419. * curr_dest = Filename of current destination
  1420. * destptr = Handle of current destination
  1421. * src_dateTime = Date and time of source file
  1422. *
  1423. * Returns:
  1424. * Nothing
  1425. *
  1426. */
  1427. void
  1428. close_dest(
  1429. PCPYINFO source,
  1430. PCPYINFO dest,
  1431. TCHAR *curr_dest,
  1432. CRTHANDLE destptr,
  1433. LPFILETIME src_dateTime
  1434. )
  1435. {
  1436. TCHAR contz = CTRLZ;
  1437. DWORD bytes_writ ;
  1438. PCPYINFO RealDest = dest->next != NULL ? dest->next : dest;
  1439. DBG_UNREFERENCED_PARAMETER( curr_dest );
  1440. /* Append a ^Z if the destination was in ascii mode. Don't check if
  1441. * the write was successful as it is a waste of time anyway.
  1442. */
  1443. DEBUG((FCGRP,COLVL,"CloseDest: Entered."));
  1444. if (DestinationNeedsCtrlZ( RealDest ) && !FileIsDevice( destptr )) {
  1445. WriteFile( CRTTONT( destptr ), &contz, 1, &bytes_writ, NULL);
  1446. }
  1447. /* if source and dest aren't devices, we aren't touching, and the
  1448. * src_date is valid, set time and date
  1449. *
  1450. * THE REMAINING DATE AND TIME VALUES MUST BE ZERO UNTIL
  1451. * THEY ARE FULLY IMPLIMENTED OR WILL CAUSE ERROR
  1452. */
  1453. if (source && !(source->flags & CI_ISDEVICE) && !FileIsDevice(destptr) &&
  1454. (copy_mode != CONCAT) && (src_dateTime != NULL) && (copy_mode != TOUCH)) {
  1455. SetFileTime( CRTTONT(destptr),
  1456. NULL,
  1457. NULL,
  1458. src_dateTime
  1459. );
  1460. }
  1461. Cclose(destptr); /* M011 */
  1462. number_of_files_copied++;
  1463. }
  1464. /*** get_dest_name - Create destination filename
  1465. *
  1466. * Purpose:
  1467. * Given the source file and the destination filespec,
  1468. * come up with a destination name.
  1469. *
  1470. * int get_dest_name(PCPYINFO source, PCPYINFO dest_spec,
  1471. * TCHAR *dest_name)
  1472. *
  1473. * Args:
  1474. * source = Source copy information structure
  1475. * dest_spec = Destination copy information structure
  1476. * dest_name = Buffer to place the destination name in
  1477. *
  1478. * Returns:
  1479. * Nothing
  1480. *
  1481. */
  1482. int
  1483. get_dest_name(
  1484. PCPYINFO source,
  1485. PCPYINFO dest,
  1486. TCHAR *dest_name,
  1487. unsigned sizbufr,
  1488. BOOL checkmeta
  1489. )
  1490. {
  1491. TCHAR *i ;
  1492. TCHAR *x, *y;
  1493. TCHAR c;
  1494. int retval = SUCCESS;
  1495. unsigned rcode = NO_ERROR;
  1496. PCPYINFO dest_spec;
  1497. TCHAR FullName[MAX_PATH];
  1498. DEBUG((FCGRP,COLVL,"GetDestName: Entered."));
  1499. dest_spec = dest->next;
  1500. if (dest_spec == NULL) {
  1501. mystrcpy(dest_name,CurDrvDir);
  1502. i= 0;
  1503. y= dest_name + mystrlen(dest_name);
  1504. for (x=dest_name; x < y; ++x) {
  1505. c=*x;
  1506. if (*x == PathChar) {
  1507. i = x;
  1508. }
  1509. }
  1510. if ((i == NULLC) || (i < y-1)) {
  1511. *y = PathChar;
  1512. *(y+1) = NULLC;
  1513. }
  1514. if (!(source->flags & CI_SHORTNAME) ||
  1515. (mystrlen(source->buf->cAlternateFileName) == 0)) {
  1516. if ((mystrlen(dest_name) + 1 +
  1517. mystrlen(source->buf->cFileName))
  1518. > MAX_PATH) {
  1519. retval = FAILURE;
  1520. } else {
  1521. mystrcat(dest_name,source->buf->cFileName);
  1522. }
  1523. } else {
  1524. if ((mystrlen(source->buf->cAlternateFileName) == 0) ||
  1525. (mystrlen(dest_name) + 1 +
  1526. mystrlen(source->buf->cAlternateFileName))
  1527. > MAX_PATH) {
  1528. retval = FAILURE;
  1529. } else {
  1530. mystrcat(dest_name,source->buf->cAlternateFileName);
  1531. }
  1532. }
  1533. } else {
  1534. if (*(lastc(dest_spec->fspec)) == COLON) {
  1535. if (!(source->flags & CI_SHORTNAME)||
  1536. (mystrlen(source->buf->cAlternateFileName) == 0)) {
  1537. if ((mystrlen(dest_spec->fspec) + 1 +
  1538. mystrlen(source->buf->cFileName))
  1539. > MAX_PATH) {
  1540. retval = FAILURE;
  1541. } else {
  1542. mystrcpy(dest_name,dest_spec->fspec);
  1543. mystrcat(dest_name,source->buf->cFileName);
  1544. }
  1545. } else {
  1546. if ((mystrlen(source->buf->cAlternateFileName) == 0) ||
  1547. (mystrlen(dest_spec->fspec) + 1 +
  1548. mystrlen(source->buf->cAlternateFileName))
  1549. > MAX_PATH) {
  1550. retval = FAILURE;
  1551. } else {
  1552. mystrcpy(dest_name,dest_spec->fspec);
  1553. mystrcat(dest_name,source->buf->cAlternateFileName);
  1554. }
  1555. }
  1556. } else {
  1557. // this code does short name substitution when copying from
  1558. // an NTFS volume to a FAT volume.
  1559. if (checkmeta &&
  1560. (*(lastc(dest_spec->fspec)) == STAR) &&
  1561. (*(penulc(dest_spec->fspec)) == BSLASH)) {
  1562. TCHAR *LastComponent;
  1563. LastComponent = mystrrchr(source->curfspec,'\\');
  1564. if (LastComponent) {
  1565. // skip the \.
  1566. LastComponent++;
  1567. } else {
  1568. if (source->curfspec[1] == COLON) {
  1569. LastComponent = &source->curfspec[2];
  1570. } else {
  1571. LastComponent = source->curfspec;
  1572. }
  1573. }
  1574. if ((source->flags & CI_SHORTNAME) &&
  1575. (mystrlen(source->buf->cAlternateFileName) != 0) ) {
  1576. mystrcpy(LastComponent,source->buf->cAlternateFileName);
  1577. }
  1578. }
  1579. rcode = wildcard_rename(
  1580. (TCHAR *)dest_name,
  1581. (TCHAR *)dest_spec->fspec,
  1582. (TCHAR *)source->curfspec,
  1583. (unsigned)sizbufr);
  1584. if (rcode) {
  1585. PrtErr(rcode);
  1586. retval = FAILURE;
  1587. }
  1588. if (GetFullPathName( dest_name, MAX_PATH, FullName, NULL) > MAX_PATH) {
  1589. PrtErr( ERROR_BUFFER_OVERFLOW );
  1590. retval = FAILURE;
  1591. }
  1592. }
  1593. }
  1594. if (checkmeta &&
  1595. ((dest_spec != NULL && (dest_spec->flags & CI_PROMPTUSER) != 0) ||
  1596. (dest->flags & CI_PROMPTUSER) != 0)) {
  1597. HANDLE Handle = CreateFile( dest_name,
  1598. GENERIC_READ,
  1599. FILE_SHARE_READ,
  1600. NULL,
  1601. OPEN_EXISTING,
  1602. FILE_ATTRIBUTE_NORMAL,
  1603. 0 );
  1604. BOOL IsFile = FALSE;
  1605. if (Handle != INVALID_HANDLE_VALUE) {
  1606. IsFile = (GetFileType( Handle ) & ~FILE_TYPE_REMOTE) == FILE_TYPE_DISK;
  1607. CloseHandle( Handle );
  1608. }
  1609. if (IsFile) {
  1610. switch (PromptUser(dest_name, MSG_MOVE_COPY_OVERWRITE, MSG_NOYESALL_RESPONSE_DATA)) {
  1611. case 0: // No
  1612. dest_name[0] = NULLC;
  1613. break;
  1614. case 2: // All
  1615. if (dest_spec != NULL)
  1616. dest_spec->flags &= ~CI_PROMPTUSER;
  1617. else
  1618. dest->flags &= ~CI_PROMPTUSER;
  1619. default: // Yes
  1620. break;
  1621. }
  1622. }
  1623. }
  1624. return(retval);
  1625. }
  1626. /*** wildcard_rename - Obtain name from wildcard spec
  1627. *
  1628. * Purpose:
  1629. * This function converts the filenames into a nice clean form
  1630. * with get_clean_filename. Then it extracts the correct
  1631. * filename using the wildcard renaming rules. Basically,
  1632. * you have a template with wildcards in it, and a source
  1633. * filename. Any time there is a letter in the template, it
  1634. * gets used. Where the template has a wildcard, use the
  1635. * letter from the source filename.
  1636. *
  1637. * int wildcard_rename(TCHAR *buffer, TCHAR *dest, TCHAR *source)
  1638. *
  1639. * Args:
  1640. * OutputBuffer = The buffer to put the name in
  1641. * dest = The destination filespec
  1642. * source = The source filename
  1643. *
  1644. * Returns:
  1645. * Nothing
  1646. *
  1647. * Notes:
  1648. * As an example, *.out + foo.bar = foo.out. A more extreme
  1649. * example is: filename.ext + a?b??c*foo.?a* = aibencme.eat.
  1650. * The foo, because it comes after the '*', is ignored. The
  1651. * dot causes the template's letters to be significant again.
  1652. *
  1653. */
  1654. unsigned
  1655. wildcard_rename(
  1656. TCHAR *OutputBuffer,
  1657. const TCHAR *dest,
  1658. const TCHAR *source,
  1659. ULONG sizbufr
  1660. )
  1661. {
  1662. TCHAR dest_buffer[MAX_PATH];
  1663. unsigned wrc = 0;
  1664. const TCHAR *temp1, *temp2;
  1665. DEBUG((FCGRP,COLVL,"WildcardRename: Entered."));
  1666. //
  1667. // Find the filename component. The filename is the first
  1668. // character after the last \ or, if none, after the first : or,
  1669. // if none, the first character.
  1670. //
  1671. temp1 = mystrrchr( source, PathChar );
  1672. if (temp1 == NULLC) {
  1673. if (source[0] != TEXT( '\0' ) && source[1] == COLON) {
  1674. temp1 = source + 2;
  1675. } else {
  1676. temp1 = source;
  1677. }
  1678. } else {
  1679. temp1++;
  1680. }
  1681. //
  1682. // Find the filename component. The filename is the first
  1683. // character after the last \ or, if none, after the first : or,
  1684. // if none, the first character.
  1685. //
  1686. temp2 = mystrrchr(dest,PathChar);
  1687. if (temp2 == NULLC) {
  1688. temp2 = mystrchr(dest, COLON);
  1689. if (temp2 && (temp2 - dest == 1)) {
  1690. ++temp2;
  1691. } else {
  1692. temp2 = dest;
  1693. }
  1694. } else {
  1695. ++temp2;
  1696. }
  1697. wrc = WinEditName( temp1,
  1698. temp2,
  1699. dest_buffer,
  1700. sizbufr );
  1701. if (wrc) {
  1702. *OutputBuffer = NULLC;
  1703. }
  1704. /*temp fix */
  1705. else if (temp2 != dest) {
  1706. if (mystrlen(dest) > MAX_PATH ) {
  1707. wrc = ERROR_BUFFER_OVERFLOW;
  1708. return(wrc);
  1709. }
  1710. mystrcpy( OutputBuffer, dest );
  1711. *(OutputBuffer + (temp2-dest)) = NULLC;
  1712. if ( mystrlen( OutputBuffer )+mystrlen(dest_buffer)+1 > MAX_PATH ) {
  1713. wrc = ERROR_BUFFER_OVERFLOW;
  1714. } else {
  1715. mystrcat( OutputBuffer, dest_buffer );
  1716. }
  1717. } else {
  1718. mystrcpy( OutputBuffer, dest_buffer );
  1719. }
  1720. return(wrc);
  1721. }
  1722. /*** scan_bytes - Scan bytes from file for Control-Z
  1723. *
  1724. * Purpose:
  1725. * This just calls ZScanA. It is called with a
  1726. * and some variables needed by ZScanA routine.
  1727. * Since we are reading in ASCII mode,
  1728. * we need to truncate after a ^Z is read. ZScanA does this,
  1729. * changing bytes_read to the new length if it finds one.
  1730. *
  1731. * int scan_bytes(int srcptr,unsigned int *buf_seg,unsigned buf_len,
  1732. * unsigned *bytes_read,int mode,
  1733. * int dstptr, TCHAR *dest_name );
  1734. *
  1735. * Args:
  1736. * buf_seg = Buffer address
  1737. * bytes_read = Location to put bytes read
  1738. * mode = Read mode
  1739. * dstptr = Handle of file to write
  1740. *
  1741. * Returns:
  1742. * TRUE if read successful
  1743. * FALSE if not
  1744. *
  1745. */
  1746. scan_bytes(buf_seg,bytes_read,mode) /* @@6 */
  1747. CHAR *buf_seg ; /* @@6 */
  1748. unsigned int *bytes_read ; /* @@6 */ /* @@5@J16 */
  1749. int mode; /* @@6 */
  1750. { /* @@6 */
  1751. unsigned rdsav; /* storage for ZScanA */ /* @@6 */
  1752. int skip_first_byte = 0; /* storage for ZScanA */ /* @@6 */
  1753. /*************************************************************************/
  1754. /* if we are copying source in ascii mode, strip bytes after ^Z */
  1755. /* M017 - ^Z was not terminating input because although input was */
  1756. /* truncated, the caller had no idea that EOF had occurred and would */
  1757. /* read again. This is especially true with devices. */
  1758. /*************************************************************************/
  1759. /* @@6 */if (TruncateOnCtrlZ( mode )) {
  1760. /* @@6 */
  1761. rdsav = *bytes_read;
  1762. if (rdsav == 0) { /* if len = 0 @@5@J16 */
  1763. Heof = TRUE ;
  1764. } /* Tell caller @@5@J16 */
  1765. else { /* else @@5@J16 */
  1766. /* scan @@5@J16 */
  1767. /* @@6 */
  1768. ZScanA(TRUE, buf_seg, (PULONG)bytes_read, (PULONG)&skip_first_byte); /* @@5@J16 */
  1769. /* @@6 */if (rdsav != *bytes_read)
  1770. /* @@6 */
  1771. {
  1772. /* @@6 */
  1773. Heof = TRUE ; /* Tell caller */
  1774. /* @@6 */
  1775. /* @@6 */DEBUG((FCGRP,COLVL,
  1776. /* @@6 */ "ReadBytes: Ascii mode, Found ^Z, Heof set to %d.",
  1777. /* @@6 */ Heof));
  1778. /* @@6 */
  1779. }
  1780. } /* @@5@J16 */
  1781. /* @@6 */
  1782. }
  1783. return(TRUE);
  1784. }
  1785. /*** read_bytes - Read bytes from file
  1786. *
  1787. * Purpose:
  1788. * This just calls FarRead and ZScanA. It is called with a
  1789. * file handle to read from, and some variables needed by those
  1790. * two routines. FarRead gets as many bytes into the previously
  1791. * allocated buffer as it can. If we are reading in ASCII mode,
  1792. * we need to truncate after a ^Z is read. ZScanA does this,
  1793. * changing bytes_read to the new length if it finds one.
  1794. *
  1795. * int read_bytes(int srcptr,TCHAR *buf_seg,unsigned buf_len, @@5@J16
  1796. * unsigned int *bytes_read,int mode,
  1797. * int dstptr, TCHAR *dest_name );
  1798. *
  1799. * Args:
  1800. * srcptr = Handle of file to read
  1801. * buf_seg = Buffer address
  1802. * buf_len = Buffer length
  1803. * bytes_read = Location to put bytes read
  1804. * source = copy source state
  1805. * dstptr = Handle of file to write
  1806. * dest_name = file name of destination file
  1807. *
  1808. * Returns:
  1809. * TRUE if read successful
  1810. * FALSE if not
  1811. *
  1812. */
  1813. int
  1814. read_bytes(srcptr,buf_seg,buf_len,bytes_read,source,dstptr,dest_name)
  1815. CRTHANDLE srcptr;
  1816. PCHAR buf_seg ;
  1817. ULONG buf_len ;
  1818. PULONG bytes_read ; /* @@5@J16 */
  1819. PCPYINFO source;
  1820. CRTHANDLE dstptr;
  1821. PTCHAR dest_name;
  1822. {
  1823. unsigned rdsav ;
  1824. int skip_first_byte = 0; /* storage for ZScanA */
  1825. DEBUG((FCGRP,COLVL,"ReadBytes: Entered."));
  1826. Heof = FALSE ; /* Clear flag */
  1827. DEBUG((FCGRP,COLVL,"ReadBytes: Heof reset to %d.",Heof));
  1828. if (!ReadFile( CRTTONT(srcptr), buf_seg, buf_len, bytes_read, NULL) ||
  1829. (*bytes_read == 0 && GetLastError() == ERROR_OPERATION_ABORTED) // ctrl-c
  1830. ) {
  1831. DosErr=GetLastError();
  1832. Cclose(srcptr);
  1833. if (!FileIsDevice(dstptr)) {
  1834. Cclose(dstptr);
  1835. DeleteFile(dest_name );
  1836. } else {
  1837. Cclose(dstptr);
  1838. }
  1839. copy_error( DosErr, CE_PCOUNT );
  1840. }
  1841. if (*bytes_read == 0) {
  1842. DosErr = 0;
  1843. return(FALSE); /* M006 */
  1844. }
  1845. //
  1846. // Determine the contents of the buffer if we don't already
  1847. // know the sort of data inside it
  1848. //
  1849. if ((source->flags & (CI_UNICODE | CI_NOT_UNICODE)) == 0) {
  1850. if (*bytes_read >= sizeof( WORD ) && *(PWORD)buf_seg == BYTE_ORDER_MARK) {
  1851. source->flags |= CI_UNICODE;
  1852. } else {
  1853. source->flags |= CI_NOT_UNICODE;
  1854. }
  1855. }
  1856. //
  1857. // Ascii, non-unicode copies are terminated at the first ^Z. If a read
  1858. // succeeded but we truncated, indicate that we might be at EOF.
  1859. // Devices are not guaranteed to fill the buffer
  1860. //
  1861. if (TruncateOnCtrlZ( source->flags )) {
  1862. rdsav = *bytes_read ;
  1863. ZScanA(TRUE, buf_seg, bytes_read, (PULONG)&skip_first_byte); /* @@5@J16 */
  1864. if (rdsav != *bytes_read) {
  1865. Heof = TRUE ; /* Tell caller */
  1866. DEBUG((FCGRP,COLVL,
  1867. "ReadBytes: Ascii mode, Found ^Z, Heof set to %d.",
  1868. Heof));
  1869. };
  1870. };
  1871. return(TRUE);
  1872. }
  1873. /*** write_bytes - Write bytes to destination file.
  1874. *
  1875. * Purpose:
  1876. * Writes buffer of information to destination file using
  1877. * FarWrite.
  1878. *
  1879. * int write_bytes(int destptr,CHAR *buf_seg,
  1880. * unsigned bytes_read,TCHAR *dest_name, unsigned srcptr)
  1881. *
  1882. * Args:
  1883. * destptr = Handle of destination file
  1884. * buf_seg = Buffer to write
  1885. * bytes_read = Bytes previously read into buffer
  1886. * dest_name = Destination filename
  1887. * srcptr = source file handle
  1888. *
  1889. * Returns:
  1890. * Nothing if successful write
  1891. * Transfers to copy_error if not
  1892. *
  1893. * Notes:
  1894. * M020 - Added srcptr handle to args so that source could be closed
  1895. * if write error occurred.
  1896. *
  1897. */
  1898. void
  1899. write_bytes(destptr,buf_seg,bytes_read,dest_name,srcptr)
  1900. CRTHANDLE destptr ;
  1901. PCHAR buf_seg ;
  1902. ULONG bytes_read ;
  1903. PTCHAR dest_name ;
  1904. CRTHANDLE srcptr ;
  1905. {
  1906. DWORD bytes_writ ;
  1907. unsigned msg = 0 ;
  1908. DEBUG((FCGRP,COLVL,"WriteBytes: Entered."));
  1909. if (!WriteFile( CRTTONT(destptr), buf_seg, bytes_read, &bytes_writ, NULL ) ||
  1910. bytes_read != bytes_writ ||
  1911. CtrlCSeen ) {
  1912. DosErr=GetLastError();
  1913. Cclose(srcptr) ;
  1914. Cclose(destptr);
  1915. if (FileIsDevice( destptr )) {
  1916. msg = ERROR_WRITE_FAULT;
  1917. } else {
  1918. DeleteFile( dest_name );
  1919. }
  1920. Heof = FALSE;
  1921. if (!DosErr) {
  1922. DosErr = ERROR_DISK_FULL ;
  1923. }
  1924. if (CtrlCSeen) {
  1925. msg = 0;
  1926. } else {
  1927. if (!msg) {
  1928. PrtErr(DosErr);
  1929. }
  1930. }
  1931. copy_error(msg,CE_PCOUNT);
  1932. }
  1933. }
  1934. /*** same_fcpy - Detects case where source equals destination
  1935. *
  1936. * Purpose: (M015)
  1937. * The user might type something like "copy foo .\foo". To recognize
  1938. * that these are the same, copy translates the names into root-based
  1939. * pathnames. There is no internal DOS5 function to do this so we
  1940. * have partially simulated the old DOS3 functionality in the FullPath
  1941. * function in CTOOLS1. Note that this does not translate net names
  1942. * or ASSIGN/JOIN/SUBST type filespecs. It is called on both names
  1943. * returning FAILURE (1) if they are malformed and SUCCESS (0) if not.
  1944. * If there is a successful return, the two new strings are strcmp'd.
  1945. *
  1946. * int same_fcpy(int fres, TCHAR *first, TCHAR *second)
  1947. *
  1948. * Args:
  1949. * fsame = The source FullPath return code
  1950. * buffer= The source buffer from FullPath
  1951. * second = The destination filename
  1952. *
  1953. * Returns:
  1954. * TRUE if names match
  1955. * FALSE if not
  1956. *
  1957. */
  1958. same_fcpy(fres,buffer,second)
  1959. int fres;
  1960. TCHAR *buffer;
  1961. TCHAR *second;
  1962. {
  1963. /*Increased buffer size @WM1 */
  1964. TCHAR buffer2[2*MAX_PATH] ; /* PTM 1412 */
  1965. DEBUG((FCGRP,COLVL,"SameFile: Entered."));
  1966. if (fres || FullPath(buffer2,second,MAX_PATH*2)) /* M015 */
  1967. return(FALSE) ;
  1968. DEBUG((FCGRP,COLVL,"SameFile: name1 after FullPath = %ws",buffer));
  1969. DEBUG((FCGRP,COLVL,"SameFile: name2 after FullPath = %ws",buffer2));
  1970. /*509*/
  1971. return(_tcsicmp(buffer,buffer2) == 0);
  1972. }
  1973. /*** same_file - Detects case where source equals destination
  1974. *
  1975. * Purpose: (M015)
  1976. * The user might type something like "copy foo .\foo". To recognize
  1977. * that these are the same, copy translates the names into root-based
  1978. * pathnames. There is no internal DOS5 function to do this so we
  1979. * have partially simulated the old DOS3 functionality in the FullPath
  1980. * function in CTOOLS1. Note that this does not translate net names
  1981. * or ASSIGN/JOIN/SUBST type filespecs. It is called on both names
  1982. * returning FAILURE (1) if they are malformed and SUCCESS (0) if not.
  1983. * If there is a successful return, the two new strings are strcmp'd.
  1984. *
  1985. * int same_file(TCHAR *first, TCHAR *second)
  1986. *
  1987. * Args:
  1988. * first = The source filename
  1989. * second = The destination filename
  1990. *
  1991. * Returns:
  1992. * TRUE if names match
  1993. * FALSE if not
  1994. *
  1995. */
  1996. same_file(first,second)
  1997. TCHAR *first,*second;
  1998. {
  1999. TCHAR buffer[2*MAX_PATH];
  2000. TCHAR buffer2[2*MAX_PATH];
  2001. DEBUG((FCGRP,COLVL,"SameFile: Entered."));
  2002. if (FullPath( buffer, first, sizeof( buffer ) / sizeof( TCHAR ))
  2003. || FullPath( buffer2, second, sizeof( buffer2 ) / sizeof( TCHAR )))
  2004. return(FALSE) ;
  2005. DEBUG((FCGRP,COLVL,"SameFile: name1 after FullPath = %ws",buffer));
  2006. DEBUG((FCGRP,COLVL,"SameFile: name2 after FullPath = %ws",buffer2));
  2007. return _tcsicmp( buffer, buffer2 ) == 0;
  2008. }
  2009. /*** copy_error - Main error routine
  2010. *
  2011. * Purpose:
  2012. * Accepts a message number and a flag which determines whether
  2013. * it should print the number of files copied before the error.
  2014. * Resets the verify mode and longjmp's out.
  2015. *
  2016. * int copy_error(unsigned int messagenum, int flag)
  2017. *
  2018. * Args:
  2019. * messagenum = The message number for the message retriever
  2020. * flag = Print files copied message flag
  2021. *
  2022. * Returns:
  2023. * Does not return
  2024. *
  2025. */
  2026. void copy_error(messagenum,flag)
  2027. unsigned int messagenum;
  2028. int flag;
  2029. {
  2030. DEBUG((FCGRP,COLVL,"CopyError: Entered."));
  2031. if (messagenum) /* M019 */
  2032. PutStdOut(messagenum, NOARGS);
  2033. if (flag == CE_PCOUNT)
  2034. PutStdOut(MSG_FILES_COPIED, ONEARG, argstr1(TEXT("%9d"), (unsigned long)number_of_files_copied)) ;
  2035. VerifyCurrent = GetSetVerMode(GSVM_GET);
  2036. while (FFhndlCopy < FFhndlsaved) {
  2037. // while (FFhndlsaved) { /* findclose will dec this @@1 */
  2038. findclose(FFhandles[FFhndlsaved - 1]); /* @@1 */
  2039. } /* @@1 */
  2040. longjmp(CmdJBuf2,1);
  2041. }
  2042. /*** DestinationNeedsCtrlZ - Test type of copy in progress
  2043. *
  2044. * Purpose:
  2045. * Given a struct, check if the copy was in ascii mode by
  2046. * looking at its flags. If it was, either the CI_ASCII flag
  2047. * was set or the user didn't specify and the operation was
  2048. * concat or combine, which default to ascii mode.
  2049. *
  2050. * Args:
  2051. * dest = The destination copy information structure.
  2052. *
  2053. * Returns:
  2054. * TRUE for ^Z termination needed,
  2055. * FALSE otherwise.
  2056. *
  2057. */
  2058. BOOL
  2059. DestinationNeedsCtrlZ( dest )
  2060. PCPYINFO dest;
  2061. {
  2062. DEBUG((FCGRP,COLVL,"CopyWasAscii: Entered."));
  2063. //
  2064. // We append a ^Z only if:
  2065. // This isn't a unicode copy
  2066. // and
  2067. // (explicit ^Z addition requested
  2068. // or
  2069. // (no flags were set
  2070. // and
  2071. // the copy mode was concat or combine)
  2072. //
  2073. return (dest->flags & CI_UNICODE) == 0
  2074. && ((dest->flags & CI_ASCII) != 0
  2075. || ((dest->flags & CI_NOTSET) != 0
  2076. && (copy_mode == CONCAT || copy_mode == COMBINE)));
  2077. }
  2078. /*** open_for_append - Open and seek to end (or ^Z)
  2079. *
  2080. * Purpose:
  2081. * Open a file for writing, and seek the pointer to the
  2082. * end of it. If we are copying in ascii mode, seek to
  2083. * the first ^Z found. If not, seek to the physical end.
  2084. *
  2085. * int open_for_append(TCHAR *filename,int flags,
  2086. * TCHAR *buf_seg,unsigned buf_len)
  2087. *
  2088. * Args:
  2089. * filename = ASCII filename
  2090. * source = copy info source
  2091. * buf_seg = Read buffer
  2092. * buf_len = Buffer length
  2093. *
  2094. * Returns:
  2095. * Handle of open file if successful
  2096. * Error out if not
  2097. *
  2098. */
  2099. CRTHANDLE
  2100. open_for_append(
  2101. PTCHAR filename,
  2102. PCPYINFO source,
  2103. PCHAR buf_seg,
  2104. ULONG buf_len)
  2105. {
  2106. ULONG bytesread ;
  2107. CRTHANDLE ptr;
  2108. int foundz = FALSE ;
  2109. unsigned brcopy ;
  2110. ULONG skip_first_byte = 0; /* storage for ZScanA */
  2111. DEBUG((FCGRP,COLVL,"OpenForAppend: Entered."));
  2112. ptr = Copen2( /* open file for destination file */
  2113. filename, /* make explicit cast */
  2114. (unsigned int)O_RDWR, /* make explicit cast */
  2115. FALSE);
  2116. if (ptr == BADHANDLE) { /* M011 */
  2117. PrtErr(ERROR_OPEN_FAILED) ; /* M019 */
  2118. copy_error(0,CE_PCOUNT) ; /* M019 */
  2119. }
  2120. do {
  2121. if (ReadFile( CRTTONT(ptr), buf_seg, buf_len, &bytesread, NULL)) {
  2122. brcopy = bytesread ;
  2123. //
  2124. // Determine the contents of the buffer if we don't already
  2125. // know the sort of data inside it
  2126. //
  2127. if ((source->flags & (CI_UNICODE | CI_NOT_UNICODE)) == 0) {
  2128. if (bytesread > sizeof( WORD ) && *(PWORD)buf_seg == BYTE_ORDER_MARK) {
  2129. source->flags |= CI_UNICODE;
  2130. } else {
  2131. source->flags |= CI_NOT_UNICODE;
  2132. }
  2133. }
  2134. if (brcopy != 0) {
  2135. foundz = ZScanA( TruncateOnCtrlZ( source->flags ),
  2136. buf_seg,
  2137. &bytesread,
  2138. &skip_first_byte
  2139. ) ;
  2140. }
  2141. } else {
  2142. DosErr = GetLastError();
  2143. Cclose(ptr);
  2144. PutStdErr(DosErr,NOARGS) ;
  2145. copy_error(0,CE_PCOUNT) ; /* end copy at this point */
  2146. }
  2147. } while (bytesread == buf_len) ;
  2148. if (foundz == 0) {
  2149. SetFilePointer(CRTTONT(ptr), -(long)(brcopy-bytesread), NULL, FILE_CURRENT) ;
  2150. }
  2151. return(ptr) ;
  2152. }
  2153. DWORD
  2154. WinEditName(
  2155. const TCHAR *pSrc,
  2156. const TCHAR *pEd,
  2157. TCHAR *pRes,
  2158. const unsigned ResBufLen
  2159. )
  2160. /*++
  2161. Routine Description:
  2162. This routine takes a source filename, an editing pattern, and produces
  2163. an output name suitable for rename or copy. It relies on the semantics
  2164. of ? and * matching. There are a whole raft of user-model issues here
  2165. especially when doing things like:
  2166. rename *.foo.bar *
  2167. Does the user intend that the destination * match precisely what the
  2168. source * matches? This is a huge RATHOLE.
  2169. Arguments:
  2170. pSrc
  2171. Input filename as produced by find-first/next
  2172. pEd
  2173. Editing string, containing *, ? and other characters
  2174. pRes
  2175. Output buffer where edited string is placed
  2176. ResBufLen
  2177. Length of output buffer
  2178. Return Value:
  2179. Status code
  2180. --*/
  2181. {
  2182. DWORD ResLen;
  2183. TCHAR delimit;
  2184. TCHAR *pTmp;
  2185. //
  2186. // Walk forward through the editing string processing the
  2187. // editing chars:
  2188. //
  2189. // : and /\ are not allowed
  2190. // * matches the current point in the source string
  2191. // through either the end of string or through the
  2192. // LAST character that may follow the *: *A will
  2193. // match up to (but not including) the last A.
  2194. // ? matches the next character UNLESS it's a dot in
  2195. // which case, it's ignored.
  2196. // . matches any number of dots, including zero.
  2197. //
  2198. // all other characters match
  2199. ResLen = 0;
  2200. while (*pEd) {
  2201. if (ResLen < ResBufLen) {
  2202. switch (*pEd) {
  2203. case COLON:
  2204. case BSLASH:
  2205. return(ERROR_INVALID_NAME);
  2206. case STAR:
  2207. delimit = *(pEd+1);
  2208. if (!(pTmp = _tcsrchr(pSrc, delimit))) {
  2209. pTmp = _tcsrchr(pSrc, NULLC);
  2210. }
  2211. while ((ResLen < ResBufLen) && pSrc < pTmp) {
  2212. if (ResLen < ResBufLen) {
  2213. *(pRes++) = *(pSrc++);
  2214. ResLen++;
  2215. } else
  2216. return(ERROR_BUFFER_OVERFLOW);
  2217. }
  2218. break;
  2219. case QMARK:
  2220. if ((*pSrc != DOT) && (*pSrc != NULLC)) {
  2221. if (ResLen < ResBufLen) {
  2222. *(pRes++) = *(pSrc++);
  2223. ResLen++;
  2224. } else
  2225. return(ERROR_BUFFER_OVERFLOW);
  2226. }
  2227. break;
  2228. case DOT:
  2229. while ((*pSrc != DOT) && (*pSrc != NULLC)) {
  2230. pSrc++;
  2231. }
  2232. *(pRes++) = DOT; /* from EditMask, even if src doesn't */
  2233. /* have one, so always put one. */
  2234. ResLen++;
  2235. if (*pSrc) /* point one past '.' */
  2236. pSrc++;
  2237. break;
  2238. default:
  2239. if ((*pSrc != DOT) && (*pSrc != NULLC)) {
  2240. pSrc++;
  2241. }
  2242. if (ResLen < ResBufLen) {
  2243. *(pRes++) = *pEd;
  2244. ResLen++;
  2245. } else
  2246. return(ERROR_BUFFER_OVERFLOW);
  2247. break;
  2248. }
  2249. pEd++;
  2250. } else {
  2251. return(ERROR_BUFFER_OVERFLOW);
  2252. }
  2253. }
  2254. if ((ResLen) < ResBufLen) {
  2255. *pRes = NULLC;
  2256. return(NO_ERROR);
  2257. } else
  2258. return(ERROR_BUFFER_OVERFLOW);
  2259. }
  2260. /*** MyWriteFile - write ansi/unicode to file
  2261. *
  2262. * Purpose:
  2263. * Write buffer in requested mode (ansi/unicode) to destination.
  2264. *
  2265. * Args:
  2266. * Same as WriteFileW
  2267. *
  2268. * Returns:
  2269. * return value from WriteFileW
  2270. *
  2271. */
  2272. BOOL
  2273. MyWriteFile(
  2274. CRTHANDLE fh,
  2275. CONST VOID *rgb,
  2276. DWORD cb,
  2277. LPDWORD lpcb
  2278. )
  2279. {
  2280. DWORD cbTotal = cb;
  2281. HANDLE dh = CRTTONT(fh);
  2282. DWORD cbT;
  2283. #ifdef UNICODE
  2284. if (fOutputUnicode)
  2285. #endif // UNICODE
  2286. return WriteFile(dh, rgb, cb, lpcb, NULL);
  2287. #ifdef UNICODE
  2288. else {
  2289. TCHAR *rgw = (TCHAR*)rgb;
  2290. #ifdef FE_SB
  2291. // If dbcs string include, Unicode string len != MultiByte string len.
  2292. // MSKK NT RAID :#10855 by V-HIDEKK
  2293. while (cb > LBUFLEN) {
  2294. // - 1 for NULLC
  2295. cbT = WideCharToMultiByte(CurrentCP, 0, (LPWSTR)rgw, LBUFLEN/(sizeof(TCHAR)),
  2296. (LPSTR)AnsiBuf, LBUFLEN, NULL, NULL);
  2297. rgw += LBUFLEN/(sizeof(TCHAR));
  2298. cb -= LBUFLEN;
  2299. #else
  2300. while (cb > LBUFLEN*sizeof(TCHAR)) {
  2301. // - 1 for NULLC
  2302. cbT = WideCharToMultiByte(CurrentCP, 0, (LPWSTR)rgw, LBUFLEN,
  2303. (LPSTR)AnsiBuf, LBUFLEN, NULL, NULL);
  2304. rgw += LBUFLEN;
  2305. cb -= LBUFLEN*sizeof(TCHAR);
  2306. #endif
  2307. if (!WriteFile(dh, AnsiBuf, cbT, lpcb, NULL) || *lpcb != cbT)
  2308. return FALSE;
  2309. }
  2310. if (cb != 0) {
  2311. // - 1 for NULLC
  2312. cb = WideCharToMultiByte(CurrentCP, 0, (LPWSTR)rgw, -1,
  2313. (LPSTR)AnsiBuf, LBUFLEN, NULL, NULL) - 1;
  2314. if (!WriteFile(dh, AnsiBuf, cb, lpcb, NULL) || *lpcb != cb)
  2315. return FALSE;
  2316. }
  2317. *lpcb = cbTotal;
  2318. return TRUE;
  2319. }
  2320. #endif // UNICODE
  2321. }
  2322. int DoVerify(
  2323. CRTHANDLE *pdestptr,
  2324. TCHAR *curr_dest,
  2325. ULONG bytes_read,
  2326. CHAR *buf_seg,
  2327. CHAR *buf_seg_dest
  2328. )
  2329. {
  2330. ULONG bytes_read_dest;
  2331. FlushFileBuffers ( CRTTONT(*pdestptr) );
  2332. Cclose(*pdestptr);
  2333. *pdestptr = Copen_Copy2(curr_dest, (ULONG)O_RDONLY);
  2334. if (*pdestptr == BADHANDLE) {
  2335. // printf( "DoVerify: unable to open dest - %d\n", DosErr );
  2336. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  2337. return(FAILURE);
  2338. }
  2339. SetFilePointer( CRTTONT(*pdestptr), - (LONG) bytes_read, NULL, FILE_END);
  2340. if (!ReadFile( CRTTONT(*pdestptr), buf_seg_dest, bytes_read, &bytes_read_dest, NULL) ) {
  2341. // printf( "DoVerify: unable to read dest - %d\n", GetLastError( ) );
  2342. Cclose(*pdestptr);
  2343. *pdestptr=BADHANDLE;
  2344. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  2345. return(FAILURE);
  2346. }
  2347. if (bytes_read_dest != bytes_read ) {
  2348. // printf( "DoVerify: Read different numbers of bytes\n" );
  2349. Cclose(*pdestptr);
  2350. *pdestptr=BADHANDLE;
  2351. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  2352. return(FAILURE);
  2353. }
  2354. if ( memcmp (buf_seg, buf_seg_dest, bytes_read) != 0 ) {
  2355. // printf( "DoVerify: buffers differ at offset %x\n", memcmp (buf_seg, buf_seg_dest, bytes_read) );
  2356. Cclose(*pdestptr);
  2357. *pdestptr=BADHANDLE;
  2358. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  2359. return(FAILURE);
  2360. }
  2361. // last buffers compared OK, resuming writing.
  2362. Cclose(*pdestptr);
  2363. *pdestptr = Copen2((TCHAR *)curr_dest,
  2364. (unsigned int)O_WRONLY,
  2365. FALSE);
  2366. if (*pdestptr == BADHANDLE) {
  2367. // printf( "DoVerify: Unable to open dest 2 - %d\n", DosErr );
  2368. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  2369. return(FAILURE);
  2370. }
  2371. SetFilePointer( CRTTONT(*pdestptr), 0, NULL, FILE_END);
  2372. return(SUCCESS);
  2373. }