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.

2929 lines
92 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. TCHAR buffer1[2*MAX_PATH]; /* Increased buffer size @WM1 */
  52. /* PTM 1412 */
  53. extern BOOL CtrlCSeen;
  54. int same_fcpy(int, TCHAR *, TCHAR *);
  55. int scan_bytes(CHAR*,unsigned int *,int);
  56. int ZScanA(BOOL flag, PCHAR buf, PULONG buflen, PULONG skip);
  57. CRTHANDLE open_for_append(PTCHAR, PCPYINFO source, PCHAR, ULONG);
  58. void source_eq_dest(PCPYINFO,CRTHANDLE *,int ,CHAR *,unsigned ,HANDLE);
  59. int read_bytes(CRTHANDLE ,PCHAR, ULONG, PULONG, PCPYINFO source, CRTHANDLE, PTCHAR);
  60. VOID write_bytes(CRTHANDLE, PCHAR, ULONG, PTCHAR, CRTHANDLE);
  61. /*** copy - Copy one or more files
  62. *
  63. * Purpose:
  64. * This is the main routine for the copy command.
  65. *
  66. * int copy(TCHAR *args)
  67. *
  68. * Args:
  69. * args = The raw arguments from the command line.
  70. *
  71. * Returns:
  72. * SUCCESS if able to perform the copy
  73. * FAILURE if not
  74. *
  75. */
  76. int
  77. copy(TCHAR *args)
  78. {
  79. PCPYINFO source; /* list of source specs */
  80. PCPYINFO dest;
  81. /*@@J*/int rcp = SUCCESS;
  82. /*@@4*/int rc = SUCCESS;
  83. VerifyCurrent = GetSetVerMode(GSVM_GET);
  84. if (setjmp(CmdJBuf2)) /* in case of error */
  85. return(FAILURE);
  86. GetDir(CurDrvDir, GD_DEFAULT); /* @@5c */
  87. DEBUG((FCGRP,COLVL,"COPY: Entered."));
  88. first_file = TRUE; /* flag-first file? @@5@J1 */
  89. first_fflag= TRUE; /* flag-first file? @@5@J3 */
  90. number_of_files_copied = 0; /* initialize global vars */
  91. copy_mode = COPY;
  92. cpyfirst = TRUE; /* @@5b reset flag for COPY DOSQFILEMODE indicator */
  93. cpydflag = FALSE; /* @@5b reset flag for COPY dirflag not found */
  94. cpydest = FALSE; /* @@5b reset flag for not disp bad dev msg twice */
  95. cdevfail = FALSE; /* @@5b reset flag for not disp extra dev msg in copy */
  96. //
  97. // Mark level of find first handle. If an copy_error
  98. // is called this will allow only copies find handles to be
  99. // closed. For statement processing will have handles open
  100. // and these should not be closed
  101. FFhndlCopy = FFhndlsaved;
  102. source = NewCpyInfo();
  103. dest = NewCpyInfo();
  104. parse_args(args, source, dest); /* do parsing @@5d */
  105. DEBUG((FCGRP,COLVL,"COPY: Args parsed, copy_mode = %d.",copy_mode));
  106. if (copy_mode == COMBINE) {
  107. DEBUG((FCGRP,COLVL,"COPY: Going to do combined copy."));
  108. do_combine_copy(source, dest); /* @@5d */
  109. } else {
  110. DEBUG((FCGRP,COLVL,"COPY: Going to do normal copy."));
  111. rc = do_normal_copy(source, dest); /* @@4 @@5d */
  112. } ;
  113. PutStdOut(MSG_FILES_COPIED, ONEARG, argstr1(TEXT("%9d"), (unsigned long)number_of_files_copied)) ; /* M016 */
  114. VerifyCurrent = GetSetVerMode(GSVM_GET);
  115. return( rc ); /* @@4 */
  116. }
  117. /*** get_full_name - Init struct with full name
  118. *
  119. * Purpose:
  120. * Given a cpyinfo structure that has just been filled in by
  121. * findfirst or findnext, put the full name of the file that
  122. * was found in struct->curfspec.
  123. *
  124. * int get_full_name(struct copyinfo *src, TCHAR *srcbuf)
  125. *
  126. * Args:
  127. * src = The copy information structure
  128. * srcbuf = buffer to have curfspec point to
  129. *
  130. * Returns:
  131. * Returns SUCCESS normally
  132. *
  133. * Notes:
  134. * *** W A R N I N G ! ***
  135. * THIS ROUTINE WILL CAUSE AN ABORT IF MEMORY CANNOT BE ALLOCATED
  136. * THIS ROUTINE MUST NOT BE CALLED DURING A SIGNAL
  137. * CRITICAL SECTION OR DURING RECOVERY FROM AN ABORT
  138. */
  139. int get_full_name(src, srcbuf)
  140. PCPYINFO src;
  141. TCHAR *srcbuf;
  142. {
  143. int retval = SUCCESS; /* - return value boolean */
  144. unsigned plen,flen,diff; /* - length of path & file name */
  145. DEBUG((FCGRP,COLVL,"GetFullName: Entered fspec = TEXT('%ws')",src->fspec));
  146. src->curfspec = srcbuf;
  147. plen = mystrlen(src->fspec);
  148. flen = mystrlen(src->buf->cFileName);
  149. if (src->pathend) {
  150. diff = (UINT)(src->pathend - src->fspec) + 1;
  151. if ((plen+1 > MAX_PATH) ||
  152. (diff + flen + 1 > MAX_PATH)) {
  153. retval = FAILURE;
  154. } else {
  155. mystrcpy(src->curfspec,src->fspec);
  156. *(src->curfspec + diff) = NULLC;
  157. mystrcat(src->curfspec,src->buf->cFileName);
  158. }
  159. } else {
  160. mystrcpy(src->curfspec,src->buf->cFileName);
  161. }
  162. DEBUG((FCGRP,COLVL,"GetFullName: Exiting full name = TEXT('%ws')",src->curfspec));
  163. return( retval );
  164. }
  165. #ifndef WIN95_CMD
  166. /*** CopyProgressRtn
  167. *
  168. * Purpose:
  169. * This is a callback routine for CopyFileEx(). This
  170. * function is called once per chunk of data during a
  171. * restartable file copy.
  172. *
  173. * Args:
  174. * See winbase.h
  175. *
  176. * Returns:
  177. * See winbase.h
  178. *
  179. */
  180. DWORD WINAPI
  181. CopyProgressRtn(
  182. LARGE_INTEGER TotalFileSize,
  183. LARGE_INTEGER TotalBytesTransferred,
  184. LARGE_INTEGER StreamSize,
  185. LARGE_INTEGER StreamBytesTransferred,
  186. DWORD dwStreamNumber,
  187. DWORD dwCallbackReason,
  188. HANDLE hSourceFile,
  189. HANDLE hDestinationFile,
  190. BOOL ReallyRestartable
  191. )
  192. {
  193. LARGE_INTEGER percent;
  194. if (TotalFileSize.QuadPart != 0) {
  195. percent.QuadPart = (TotalBytesTransferred.QuadPart * 100) / TotalFileSize.QuadPart;
  196. } else {
  197. percent.QuadPart = 100;
  198. }
  199. PutStdOut( MSG_PROGRESS, ONEARG, argstr1(TEXT("%3d"), (unsigned long)percent.LowPart) );
  200. if (CtrlCSeen) {
  201. PutStdOut( MSG_PROGRESS, ONEARG, argstr1(TEXT("%3d"), (unsigned long)percent.LowPart) );
  202. printf( "\n" );
  203. if (ReallyRestartable) {
  204. return PROGRESS_STOP;
  205. } else {
  206. return PROGRESS_CANCEL;
  207. }
  208. } else {
  209. return PROGRESS_CONTINUE;
  210. }
  211. }
  212. #endif
  213. /*** do_normal_copy - Does actual copying for normal copy
  214. *
  215. * Purpose:
  216. * On entry, source points to the empty header of a list of
  217. * source filespecs, and dest points an empty struct that
  218. * points to the zero or one destination filespec given.
  219. * This procedure does the actual copying.
  220. *
  221. * int do_normal_copy(struct copyinfo *source, struct copyinfo *dest)
  222. *
  223. * Args:
  224. * source = The source copy information structure
  225. * dest = The destination copy information structure
  226. *
  227. * Returns:
  228. * FAILURE if not able to perform the copy
  229. *
  230. */
  231. int
  232. do_normal_copy(
  233. PCPYINFO source,
  234. PCPYINFO dest)
  235. {
  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. dwAttrib &= ~FILE_ATTRIBUTE_READONLY;
  774. SetFileAttributes(curr_dest, dwAttrib);
  775. // need to get a handle to verify write.
  776. if (VerifyCurrent) {
  777. destptr = Copen2((TCHAR *)curr_dest,
  778. (unsigned int)O_WRONLY,
  779. FALSE);
  780. if (destptr == BADHANDLE) {
  781. // printf( "do_normal_copy: Unable to open file for verification %d\n", DosErr);
  782. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  783. goto l_out;
  784. }
  785. if ( FileIsDevice(destptr) ) {
  786. // printf( "do_normal_copy: Somehow this is now a device for verification?\n" );
  787. Cclose(destptr);
  788. destptr=BADHANDLE;
  789. goto l_out;
  790. }
  791. if (!FlushFileBuffers ( CRTTONT(destptr) ) ) {
  792. // printf( "do_normal_copy: Unable to flush buffers verification %d\n", GetLastError( ));
  793. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  794. Cclose(destptr);
  795. destptr=BADHANDLE;
  796. goto l_out;
  797. }
  798. Cclose(destptr);
  799. destptr=BADHANDLE;
  800. // read the Src and Dest files back to memory and compare.
  801. destptr = Copen_Copy2(curr_dest, (ULONG)O_RDONLY);
  802. if (destptr == BADHANDLE) {
  803. // printf( "do_normal_copy: Unable to open file for verification 2 %d\n", DosErr);
  804. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  805. goto l_out;
  806. }
  807. if ( FileIsDevice(destptr) ) {
  808. // printf( "do_normal_copy: Somehow this is now a device for verification 2?\n" );
  809. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  810. Cclose(destptr);
  811. destptr=BADHANDLE;
  812. goto l_out;
  813. }
  814. SetFilePointer( CRTTONT(srcptr), 0, NULL, FILE_BEGIN);
  815. SetFilePointer( CRTTONT(destptr), 0, NULL, FILE_BEGIN);
  816. dwSrcFileSize = GetFileSize( CRTTONT(srcptr), &dwSrcFileSizeHigh);
  817. dwDestFileSize = GetFileSize( CRTTONT(destptr), &dwDestFileSizeHigh);
  818. if ( (dwSrcFileSize != dwDestFileSize) || (dwSrcFileSizeHigh != dwDestFileSizeHigh ) ) {
  819. // printf( "do_normal_copy: Files are different sizes %x:%08x %x:%08x\n", dwSrcFileSizeHigh, dwSrcFileSize, dwDestFileSizeHigh, dwDestFileSize );
  820. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  821. Cclose(destptr);
  822. destptr=BADHANDLE;
  823. goto l_out;
  824. }
  825. fEof = 0;
  826. while (!fEof) {
  827. if (!ReadFile( CRTTONT(srcptr), buf_seg, buf_len, &bytes_read,NULL ) ) {
  828. // printf( "do_normal_copy: Failure to read source block - %d\n", GetLastError( ));
  829. Cclose(destptr);
  830. destptr=BADHANDLE;
  831. goto l_out;
  832. }
  833. if ( bytes_read == 0 ) {
  834. // printf( "do_normal_copy: Unexpectedly read 0 bytes from source\n" );
  835. Cclose(destptr);
  836. destptr=BADHANDLE;
  837. goto l_out;
  838. }
  839. if (!ReadFile( CRTTONT(destptr), buf_seg_dest, bytes_read, &bytes_read_dest,NULL) ) {
  840. // printf( "do_normal_copy: Failure to read dest block - %d\n", GetLastError( ) );
  841. Cclose(destptr);
  842. destptr=BADHANDLE;
  843. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  844. goto l_out;
  845. }
  846. if (bytes_read_dest != bytes_read ) {
  847. // printf( "do_normal_copy: Unexpectedly read fewer bytes\n" );
  848. Cclose(destptr);
  849. destptr=BADHANDLE;
  850. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  851. goto l_out;
  852. }
  853. if (buf_len != bytes_read)
  854. fEof = 1;
  855. if ( memcmp (buf_seg, buf_seg_dest, bytes_read) != 0 ) {
  856. // printf( "do_normal_copy: Data is different at offset %x\n", memcmp (buf_seg, buf_seg_dest, bytes_read) );
  857. Cclose(destptr);
  858. destptr=BADHANDLE;
  859. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  860. goto l_out;
  861. }
  862. }
  863. Cclose(destptr);
  864. destptr=BADHANDLE;
  865. }
  866. l_out: ;
  867. // check file timestamp in FUTURE to handle wildcard.
  868. }
  869. } else {
  870. //
  871. // open the destination
  872. //
  873. if (destptr == BADHANDLE) {
  874. destptr = Copen2((TCHAR *)curr_dest,
  875. (unsigned int)O_WRONLY,
  876. FALSE);
  877. if (destptr == BADHANDLE) {
  878. Cclose(srcptr) ;
  879. if (cdevfail == FALSE) {
  880. PrtErr(DosErr);
  881. }
  882. if ( copy_mode != CONCAT ) {
  883. rc = FAILURE;
  884. first_fflag = TRUE;
  885. continue;
  886. }
  887. findclose(hnFirst);
  888. copy_error(0,CE_PCOUNT) ;
  889. }
  890. }
  891. //
  892. // Handle appending of unicode text files with byte order marks.
  893. // Do this except on the first file and only when appending
  894. // ascii files.
  895. //
  896. if (!first_file
  897. && copy_mode == CONCAT
  898. && (source->flags & CI_ASCII) != 0
  899. && (source->flags & CI_UNICODE) != 0) {
  900. bytes_read -= sizeof( WORD );
  901. memmove( buf_seg, buf_seg + sizeof( WORD ), bytes_read );
  902. }
  903. if ((source->flags & CI_UNICODE) != 0) {
  904. if (dest->next != NULL) {
  905. dest->next->flags |= CI_UNICODE;
  906. } else {
  907. dest->flags |= CI_UNICODE;
  908. }
  909. }
  910. //
  911. // If eof and bytesread > 0 then write the data.
  912. // If fail then exit through write_bytes
  913. //
  914. if (Heof && ((int)bytes_read > 0)) {
  915. write_bytes(destptr,buf_seg,bytes_read,curr_dest,srcptr);
  916. if (VerifyCurrent && !FileIsDevice(destptr) ) {
  917. if ( DoVerify(&destptr, curr_dest, bytes_read, buf_seg, buf_seg_dest) == FAILURE ) {
  918. findclose(hnFirst);
  919. copy_error(0,CE_PCOUNT) ;
  920. }
  921. }
  922. } else {
  923. //
  924. // Loop through writing and reading bytes
  925. // If fail then exit through write_bytes
  926. //
  927. while (!Heof && (rcode == TRUE)) {
  928. write_bytes(destptr,buf_seg,bytes_read,curr_dest,srcptr);
  929. if (VerifyCurrent && !FileIsDevice(destptr) ) {
  930. if ( DoVerify(&destptr, curr_dest, bytes_read, buf_seg, buf_seg_dest) == FAILURE ) {
  931. findclose(hnFirst);
  932. copy_error(0,CE_PCOUNT) ;
  933. }
  934. }
  935. rcode = read_bytes(srcptr,
  936. buf_seg,
  937. buf_len,
  938. (PULONG)&bytes_read,
  939. source,
  940. destptr,
  941. curr_dest);
  942. DEBUG((FCGRP,COLVL,"In rd/wt loop 1, Heof = %d",Heof));
  943. }
  944. if (Heof && ((int)bytes_read > 0) && (rcode == TRUE)) {
  945. write_bytes(destptr,buf_seg,bytes_read,curr_dest,srcptr);
  946. if (VerifyCurrent && !FileIsDevice(destptr) ) {
  947. if ( DoVerify(&destptr, curr_dest, bytes_read, buf_seg, buf_seg_dest) == FAILURE ) {
  948. findclose(hnFirst);
  949. copy_error(0,CE_PCOUNT) ;
  950. }
  951. }
  952. }
  953. }
  954. }
  955. //
  956. // Clear when src closed
  957. //
  958. Heof = FALSE ;
  959. DEBUG((FCGRP,COLVL,"Closing, Heof reset to %d",Heof));
  960. //
  961. // update file data in dir
  962. //
  963. src_dateTime = source->buf->ftLastWriteTime ;
  964. Cclose(srcptr);
  965. //
  966. // keep dest open if concat since it will be used again
  967. //
  968. if (copy_mode != CONCAT) {
  969. if (CtrlCSeen) {
  970. Cclose(destptr);
  971. DeleteFile(curr_dest);
  972. rc = FAILURE;
  973. } else {
  974. close_dest(source,dest,curr_dest,destptr,&src_dateTime);
  975. }
  976. //
  977. // reset EA xfer flag from src
  978. //
  979. first_fflag = TRUE;
  980. }
  981. first_file = FALSE;
  982. } while (fnext( (PWIN32_FIND_DATA)source->buf, (unsigned int)FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_ARCHIVE,hnFirst));
  983. findclose(hnFirst) ;
  984. }
  985. //
  986. // Remember that dest was left open for concat
  987. //
  988. if (copy_mode == CONCAT && destptr != BADHANDLE) {
  989. close_dest(source,dest,curr_dest,destptr,NULL);
  990. }
  991. return( rc );
  992. }
  993. /*** source_eq_dest - Handles cases where source and dest files are same
  994. *
  995. * Purpose:
  996. * While copying, we ran across a source and destination that
  997. * were the same. In concatenation or touch mode this is
  998. * acceptable, otherwise it isn't. If we are concatenating
  999. * and this is the first file, we can just open it for appending
  1000. * as the destination. We save ourselves the copy and are ready
  1001. * to append the other files to it. If this isn't the first
  1002. * file, * we have already messed up the contents of the source
  1003. * from previous concatenations, so we report that but keep
  1004. * going. If we are doing a touch, go ahead and do it and
  1005. * increment the file counter.
  1006. *
  1007. * int source_eq_dest(PCPYINFO source,int *destptr,int *first_file,
  1008. * TCHAR *buf_seg, unsigned buf_len)
  1009. *
  1010. * Args:
  1011. * source = Source copy information structure
  1012. * destptr = Destination file handle
  1013. * first_file = First file flag
  1014. * buf_seg = Copy buffer
  1015. * buf_len = Buffer length
  1016. *
  1017. * Returns:
  1018. * Nothing. Terminates through copy_error if unable to continue
  1019. *
  1020. */
  1021. void
  1022. source_eq_dest(source, destptr, first_file, buf_seg, buf_len, hnFirst)
  1023. PCPYINFO source;
  1024. CRTHANDLE *destptr; /* dest file handle */
  1025. int first_file;
  1026. CHAR *buf_seg ;
  1027. unsigned buf_len;
  1028. HANDLE hnFirst; /* ffirst/fnext handle @@5@J15 */
  1029. {
  1030. CRTHANDLE fh ; /* file handle for touch */
  1031. FILETIME FileTime;
  1032. DEBUG((FCGRP,COLVL,"SourceEqDest: Entered."));
  1033. if (copy_mode == CONCAT) { /* it's ok in concat mode */
  1034. if (!first_file) { /* dest was wiped if not 1st file */
  1035. /* M016 */
  1036. PutStdOut(MSG_CONT_LOST_BEF_COPY, NOARGS);
  1037. } else { /* must open so later files append */
  1038. *destptr = open_for_append(
  1039. source->curfspec,
  1040. source,
  1041. buf_seg,
  1042. (unsigned int)buf_len
  1043. );
  1044. }
  1045. } else {
  1046. if (copy_mode == TOUCH) { /* just touch - no copy */
  1047. DEBUG((FCGRP,COLVL,"touching file"));
  1048. fh = Copen2( /* open file for destination file */
  1049. (TCHAR *)source->curfspec, /* explicit cast */
  1050. (unsigned int)O_RDWR, /* make explicit cast */
  1051. TRUE);
  1052. if (fh == BADHANDLE) {
  1053. findclose(hnFirst);
  1054. PrtErr(ERROR_OPEN_FAILED) ; /* M019 */
  1055. copy_error(0,CE_PCOUNT) ; /* M019 */
  1056. }
  1057. ConverttmToFILETIME( NULL, &FileTime );
  1058. SetFileTime( CRTTONT(fh),
  1059. NULL,
  1060. NULL,
  1061. &FileTime
  1062. );
  1063. Cclose(fh);
  1064. number_of_files_copied++;
  1065. } else {
  1066. findclose(hnFirst); /* close ffirst/fnext handle for dup file name @@5@J15 */
  1067. copy_error(MSG_CANNOT_COPIED_ONTO_SELF,CE_PCOUNT); /* M016 */
  1068. }
  1069. }
  1070. }
  1071. /*** do_combine_copy - Handle combining copy commands
  1072. *
  1073. *
  1074. * Purpose:
  1075. * This handles commands like "copy *.tmp+*.foo *.out". The
  1076. * idea is to look through the source specs until one matches
  1077. * a file. Generally this will be the first one. Then, for
  1078. * each match for the first spec, cycle through the remaining
  1079. * source specs, seeing if they have a corresponding match. If
  1080. * so, append it to the file matched by the first spec.
  1081. *
  1082. * int do_combine_copy(PCPYINFO source, PCPYINFO dest)
  1083. *
  1084. * Args:
  1085. * source = The source copy information structure
  1086. * dest = The destination copy information structure
  1087. *
  1088. * Returns:
  1089. * SUCCESS if able to perform the copy
  1090. * FAILURE if not
  1091. *
  1092. * Notes:
  1093. * As an example, suppose the files a.tmp, b.tmp, c.tmp, and
  1094. * b.foo were in the current directory. The example mentioned
  1095. * above would: copy a.tmp to a.out, append b.tmp and b.foo
  1096. * into b.out, and copy c.tmp to c.out. The default mode when
  1097. * doing this type of copy is ascii, so all the .out files would
  1098. * have a ^Z appended to them.
  1099. *
  1100. */
  1101. do_combine_copy(source, dest)
  1102. PCPYINFO source;
  1103. PCPYINFO dest;
  1104. {
  1105. TCHAR curr_dest[MAX_PATH]; /* buffer for src names */
  1106. TCHAR source_buff[MAX_PATH]; /* @@4 */
  1107. TCHAR other_source[MAX_PATH]; /* same */
  1108. PCPYINFO other_source_spec = source; /* ptr to source */
  1109. CRTHANDLE srcptr,destptr; /* file pointers */
  1110. unsigned buf_len, /* for GetBigBuf() */
  1111. buf_len_dest,
  1112. bytes_read; /* for data copying funcs */
  1113. CHAR *buf_seg ;
  1114. CHAR *buf_seg_dest;
  1115. HANDLE hnFirst ;
  1116. unsigned rcode = TRUE; /* ret code from read @@J */
  1117. unsigned wrc;
  1118. int dest_att=0;
  1119. DEBUG((FCGRP,COLVL,"DoCombineCopy: Entered."));
  1120. buf_seg = (CHAR*)GetBigBuf(MAXCOPYBUFSIZE, MINCOPYBUFSIZE, (unsigned int *)&buf_len, 0); /* allocate large buffer */
  1121. if (!buf_seg) {
  1122. return(FAILURE) ;
  1123. }
  1124. if (VerifyCurrent) {
  1125. buf_seg_dest = (CHAR*)GetBigBuf(buf_len, MINCOPYBUFSIZE, (unsigned int *)&buf_len_dest, 1); /* allocate large buffer */
  1126. if (!buf_seg_dest) {
  1127. return(FAILURE) ;
  1128. }
  1129. buf_len = min(buf_len, buf_len_dest);
  1130. }
  1131. /* find the first spec with any matching files */
  1132. source = source->next; /* point to first source */
  1133. while (!exists(source->fspec)) {
  1134. DEBUG((FCGRP,COLVL,"exists() reports file %ws non-existant",source->fspec));
  1135. if (!(source = source->next)) { /* no match, try next spec */
  1136. return(SUCCESS); /* no match for any source */
  1137. }
  1138. }
  1139. DEBUG((FCGRP,COLVL,"Preparing to do ffirst on %ws",source->fspec));
  1140. ffirst( /* get DOSFINDFIRST2 level 2 @@5@J1 */
  1141. (TCHAR *)source->fspec, /* make explicit cast @@5@J1 */
  1142. (unsigned int)FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_ARCHIVE,
  1143. (PWIN32_FIND_DATA)source->buf, /* make explicit cast @@5@J1 */
  1144. &hnFirst);
  1145. /* cycle through files, trying to match with other source specs */
  1146. do {
  1147. source->flags &= ~(CI_UNICODE | CI_NOT_UNICODE);
  1148. rcode = TRUE;
  1149. if (source->flags & CI_NOTSET) { /* set default copy mode */
  1150. source->flags = (source->flags & ~CI_NOTSET) | CI_ASCII;
  1151. }
  1152. if (CtrlCSeen) {
  1153. findclose(hnFirst) ;
  1154. return(FAILURE);
  1155. }
  1156. if (get_full_name(source, source_buff) == FAILURE) { /* @@4 */
  1157. findclose(hnFirst);
  1158. return(FAILURE) ; /* get matching file name */
  1159. }
  1160. cmd_printf(Fmt17,source->curfspec); /* and print it */
  1161. if (get_dest_name(source,dest,curr_dest,MAX_PATH,FALSE) == FAILURE) {
  1162. findclose(hnFirst);
  1163. return(FAILURE); /* get full name of src */
  1164. }
  1165. //
  1166. // If user said no to overwrite, then skip this file.
  1167. //
  1168. if (curr_dest[0] == NULLC)
  1169. continue;
  1170. if (same_file(source->curfspec,curr_dest)) { /* append */
  1171. destptr = open_for_append(
  1172. source->curfspec,
  1173. source,
  1174. buf_seg,
  1175. (unsigned int)buf_len);
  1176. } else {
  1177. DEBUG((FCGRP,COLVL,"open %ws for reading",source->curfspec));
  1178. DEBUG((FCGRP,COLVL,"open %ws for writing",curr_dest));
  1179. srcptr = Copen_Copy2( /* open a source file */
  1180. (TCHAR *)source->curfspec, /* using this file name */
  1181. (unsigned int)O_RDONLY); /* for read-only */
  1182. if (srcptr == BADHANDLE) { /* if open failed then */
  1183. /* then */
  1184. findclose(hnFirst);
  1185. PrtErr(ERROR_OPEN_FAILED); /* display error */
  1186. copy_error(0,CE_PCOUNT);
  1187. }
  1188. if (FileIsDevice(srcptr)) {
  1189. buf_len = MINCOPYBUFSIZE;
  1190. }
  1191. /* @@J */rcode = read_bytes( srcptr,buf_seg, /* read first src data */
  1192. /* @@J */ buf_len,
  1193. (PULONG)&bytes_read, /* to see if src bad */
  1194. /* @@J */ source,
  1195. destptr,
  1196. curr_dest); /* if bad do not open */
  1197. /* @@J */
  1198. if (DosErr )
  1199. /* @@J */
  1200. {
  1201. /* dest file. */
  1202. findclose(hnFirst);
  1203. /* M011 @@J */Cclose(srcptr) ; /* close soure file */
  1204. /* @@J */PrtErr(ERROR_OPEN_FAILED) ; /* display error message */
  1205. /* @@J */copy_error(0,CE_PCOUNT) ; /* catch all copy terminate */
  1206. /* @@J */
  1207. } /* routine and display # files*/
  1208. /* @@J */
  1209. else /* copied trailer info */
  1210. /* @@J */
  1211. {
  1212. dest_att = GetFileAttributes(curr_dest);
  1213. if ( ! (dest_att & FILE_ATTRIBUTE_HIDDEN) )
  1214. destptr = Copen_Copy3((TCHAR *)curr_dest);
  1215. else
  1216. /* @@5 @J1*/ destptr = Copen2( /* open destination file */
  1217. (TCHAR *)curr_dest, /* filename */
  1218. (unsigned int)O_WRONLY,
  1219. FALSE);
  1220. /* M011@@J */
  1221. if (destptr == BADHANDLE) /* if open failed @@5@J1*/
  1222. /* @@J */
  1223. {
  1224. /* then */
  1225. findclose(hnFirst);
  1226. /* M011 @@J */Cclose(srcptr) ; /* Close src on dst open err */
  1227. /* @@J */PrtErr(ERROR_OPEN_FAILED) ;
  1228. /* @@J */copy_error(0,CE_PCOUNT) ;
  1229. /* @@J */
  1230. }
  1231. }
  1232. /* @@J */ if (Heof && ((int)bytes_read > 0 )) /* if eof but bytes read */
  1233. /* @@J */
  1234. {
  1235. /* then write data and */
  1236. /* @@J */ /* if fail then will exit */
  1237. /* @@J */
  1238. write_bytes(destptr,buf_seg,bytes_read,curr_dest,srcptr);
  1239. if (VerifyCurrent && !FileIsDevice(destptr) ) {
  1240. if ( DoVerify(&destptr, curr_dest, bytes_read, buf_seg, buf_seg_dest) == FAILURE ) {
  1241. findclose(hnFirst);
  1242. Cclose(srcptr);
  1243. Cclose(destptr);
  1244. copy_error(0,CE_PCOUNT) ;
  1245. }
  1246. }
  1247. /* @@J */
  1248. }
  1249. /* @@J */ /* */
  1250. /* @@J */while (!Heof && (rcode == TRUE)) /* while not at EOF or bad rc */
  1251. /* @@J */
  1252. {
  1253. /* perform copy loop */
  1254. /* @@J */ /* if fail then will exit */
  1255. /* @@J */
  1256. write_bytes(destptr,buf_seg,bytes_read,curr_dest,srcptr);
  1257. /* @@J */ /* */
  1258. if (VerifyCurrent && !FileIsDevice(destptr) ) {
  1259. if ( DoVerify(&destptr, curr_dest, bytes_read, buf_seg, buf_seg_dest) == FAILURE ) {
  1260. findclose(hnFirst);
  1261. Cclose(srcptr);
  1262. Cclose(destptr);
  1263. copy_error(0,CE_PCOUNT) ;
  1264. }
  1265. }
  1266. /* @@J */rcode = read_bytes(srcptr,buf_seg, /* read next src data */
  1267. /* @@J */ buf_len,(PULONG)&bytes_read,
  1268. /* @@J */ source,destptr,curr_dest);
  1269. /* @@J */
  1270. /* @@J */DEBUG((FCGRP,COLVL,"Closing, Heof reset to %d",Heof));
  1271. /* @@J */
  1272. /* @@J */
  1273. };
  1274. Heof = FALSE ; /* Clear when src closed */
  1275. Cclose(srcptr); /* M011 */
  1276. }
  1277. first_file = FALSE; /* set first file processed @@5@J1 */
  1278. /* The source is handled, now cycle through the other wildcards that
  1279. * were entered and see if they match a file that should be appended.
  1280. * If the file they match is the same as the destination, report
  1281. * contents lost and keep going. Ex: "copy *.a+b*.b b.*" where a.b
  1282. * and b.b exist. b*.b matches b.b but the target file is b.b and
  1283. * its contents were already destroyed when a.b was copied into it.
  1284. */
  1285. other_source_spec = source;
  1286. while (other_source_spec = other_source_spec->next) {
  1287. if (other_source_spec->flags & CI_NOTSET) {
  1288. other_source_spec->flags &= ~CI_NOTSET;
  1289. other_source_spec->flags |= CI_ASCII;
  1290. }
  1291. wrc = wildcard_rename( /* rename filename for wild */
  1292. (TCHAR *)other_source, /* result filename */
  1293. (TCHAR *)other_source_spec->fspec, /* dest input filename */
  1294. (TCHAR *)source->curfspec, /* source input filename */
  1295. (unsigned)MAX_PATH); /* size of result filename area */
  1296. if (wrc) {
  1297. PutStdOut(wrc,NOARGS);
  1298. } else {
  1299. cmd_printf(Fmt17,other_source); /* print filename */
  1300. }
  1301. if (exists(other_source)) {
  1302. if (same_file(other_source,curr_dest)) {
  1303. /* M016 */
  1304. PutStdOut(MSG_CONT_LOST_BEF_COPY,NOARGS);
  1305. } else { /* append to curr_dest */
  1306. DEBUG((FCGRP,COLVL,
  1307. "open %s for reading",
  1308. other_source));
  1309. /* @@5 @J1 */
  1310. srcptr = Copen_Copy2( /* open a source file @@5@J1*/
  1311. (TCHAR *)other_source,/* using this file name @@5@J1*/
  1312. (unsigned int)O_RDONLY); /* for read-only @@5@J1*/
  1313. /* @@5@J1*/
  1314. if (srcptr == BADHANDLE) { /* if open failed then */
  1315. /* then */
  1316. findclose(hnFirst);
  1317. Cclose(destptr); /* close destination file */
  1318. PrtErr(ERROR_OPEN_FAILED) ; /* M019 */
  1319. copy_error(0,CE_PCOUNT) ; /* M019 */
  1320. }
  1321. if (FileIsDevice( srcptr )) {
  1322. buf_len = MINCOPYBUFSIZE;
  1323. }
  1324. while (!Heof && read_bytes(srcptr,
  1325. buf_seg,
  1326. buf_len,
  1327. (PULONG)&bytes_read,
  1328. other_source_spec,
  1329. destptr,curr_dest)) {
  1330. write_bytes(destptr,
  1331. buf_seg,
  1332. bytes_read,
  1333. curr_dest,
  1334. srcptr);
  1335. if (VerifyCurrent && !FileIsDevice(destptr) ) {
  1336. if ( DoVerify(&destptr, curr_dest, bytes_read, buf_seg, buf_seg_dest) == FAILURE ) {
  1337. findclose(hnFirst);
  1338. Cclose(srcptr);
  1339. Cclose(destptr);
  1340. copy_error(0,CE_PCOUNT) ;
  1341. }
  1342. }
  1343. DEBUG((FCGRP,COLVL,
  1344. "In rd/wt loop 3, Heof = %d",
  1345. Heof));
  1346. } ;
  1347. Heof = FALSE ; /* M017 - Clear it */
  1348. DEBUG((FCGRP,COLVL,"Closing, Heof reset to %d",Heof));
  1349. Cclose(srcptr); /* M011 */
  1350. }
  1351. }
  1352. }
  1353. close_dest(source,dest,curr_dest,destptr,NULL);
  1354. /*@@5@J3*/first_fflag = TRUE;
  1355. } while (fnext ((PWIN32_FIND_DATA)source->buf,
  1356. (unsigned int)FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_ARCHIVE, hnFirst));
  1357. findclose(hnFirst) ;
  1358. return( SUCCESS );
  1359. }
  1360. /*** NewCpyInfo - Init the cpyinfo struct
  1361. *
  1362. * Purpose:
  1363. * Allocate space for a cpyinfo struct and fill it in with null values.
  1364. *
  1365. * CPYINFO NewCpyInfo()
  1366. *
  1367. * Args:
  1368. * None
  1369. *
  1370. * Returns:
  1371. * Pointer to cpyinfo struct if allocated,
  1372. * ABORT's if not.
  1373. *
  1374. * Notes:
  1375. * *** W A R N I N G ! ***
  1376. * THIS ROUTINE WILL CAUSE AN ABORT IF MEMORY CANNOT BE ALLOCATED
  1377. * THIS ROUTINE MUST NOT BE CALLED DURING A SIGNAL
  1378. * CRITICAL SECTION OR DURING RECOVERY FROM AN ABORT
  1379. */
  1380. PCPYINFO
  1381. NewCpyInfo( VOID )
  1382. {
  1383. PCPYINFO temp;
  1384. DEBUG((FCGRP,COLVL,"InitStruct: Entered."));
  1385. temp = (PCPYINFO) gmkstr(sizeof(CPYINFO)); /*WARNING*/
  1386. temp->fspec = NULL;
  1387. temp->flags = 0;
  1388. temp->next = NULL;
  1389. return(temp);
  1390. }
  1391. /*** close_dest - Handle close operation on destination file
  1392. *
  1393. * Purpose:
  1394. * o Append a control-Z to the destination if the copy mode for it
  1395. * is ascii. If a destination wasn't specified, the dest spec
  1396. * points to the empty header, the next field is NULL, and the
  1397. * parser put the copy mode into the empty header's flags field.
  1398. * If the dest was specified, then the mode is in the struct
  1399. * pointed to by the header.
  1400. *
  1401. * o Set all the appropriate attributes. Read-only and system
  1402. * don't stay, but the rest do. Also, set the time and date if
  1403. * neither source nor target is a device and src_date is valid.
  1404. * The caller tell us it isn't valid by setting it to -1.
  1405. *
  1406. * o Close the destination file.
  1407. *
  1408. * o Update the number of files copied.
  1409. *
  1410. * int close_dest(PCPYINFO source,PCPYINFO dest,
  1411. * TCHAR *curr_dest,int destptr,LPFIMETIME src_dateTime)
  1412. *
  1413. * Args:
  1414. * source = Source copy information structure
  1415. * dest = Source copy information structure
  1416. * curr_dest = Filename of current destination
  1417. * destptr = Handle of current destination
  1418. * src_dateTime = Date and time of source file
  1419. *
  1420. * Returns:
  1421. * Nothing
  1422. *
  1423. */
  1424. void
  1425. close_dest(
  1426. PCPYINFO source,
  1427. PCPYINFO dest,
  1428. TCHAR *curr_dest,
  1429. CRTHANDLE destptr,
  1430. LPFILETIME src_dateTime
  1431. )
  1432. {
  1433. TCHAR contz = CTRLZ;
  1434. DWORD bytes_writ ;
  1435. PCPYINFO RealDest = dest->next != NULL ? dest->next : dest;
  1436. DBG_UNREFERENCED_PARAMETER( curr_dest );
  1437. /* Append a ^Z if the destination was in ascii mode. Don't check if
  1438. * the write was successful as it is a waste of time anyway.
  1439. */
  1440. DEBUG((FCGRP,COLVL,"CloseDest: Entered."));
  1441. if (DestinationNeedsCtrlZ( RealDest ) && !FileIsDevice( destptr )) {
  1442. WriteFile( CRTTONT( destptr ), &contz, 1, &bytes_writ, NULL);
  1443. }
  1444. /* if source and dest aren't devices, we aren't touching, and the
  1445. * src_date is valid, set time and date
  1446. *
  1447. * THE REMAINING DATE AND TIME VALUES MUST BE ZERO UNTIL
  1448. * THEY ARE FULLY IMPLIMENTED OR WILL CAUSE ERROR
  1449. */
  1450. if (source && !(source->flags & CI_ISDEVICE) && !FileIsDevice(destptr) &&
  1451. (copy_mode != CONCAT) && (src_dateTime != NULL) && (copy_mode != TOUCH)) {
  1452. SetFileTime( CRTTONT(destptr),
  1453. NULL,
  1454. NULL,
  1455. src_dateTime
  1456. );
  1457. }
  1458. Cclose(destptr); /* M011 */
  1459. number_of_files_copied++;
  1460. }
  1461. /*** get_dest_name - Create destination filename
  1462. *
  1463. * Purpose:
  1464. * Given the source file and the destination filespec,
  1465. * come up with a destination name.
  1466. *
  1467. * int get_dest_name(PCPYINFO source, PCPYINFO dest_spec,
  1468. * TCHAR *dest_name)
  1469. *
  1470. * Args:
  1471. * source = Source copy information structure
  1472. * dest_spec = Destination copy information structure
  1473. * dest_name = Buffer to place the destination name in
  1474. *
  1475. * Returns:
  1476. * Nothing
  1477. *
  1478. */
  1479. int
  1480. get_dest_name(
  1481. PCPYINFO source,
  1482. PCPYINFO dest,
  1483. TCHAR *dest_name,
  1484. unsigned sizbufr,
  1485. BOOL checkmeta
  1486. )
  1487. {
  1488. TCHAR *i ;
  1489. TCHAR *x, *y;
  1490. TCHAR c;
  1491. int retval = SUCCESS;
  1492. unsigned rcode = NO_ERROR;
  1493. PCPYINFO dest_spec;
  1494. TCHAR FullName[MAX_PATH];
  1495. DEBUG((FCGRP,COLVL,"GetDestName: Entered."));
  1496. dest_spec = dest->next;
  1497. if (dest_spec == NULL) {
  1498. mystrcpy(dest_name,CurDrvDir);
  1499. i= 0;
  1500. y= dest_name + mystrlen(dest_name);
  1501. for (x=dest_name; x < y; ++x) {
  1502. c=*x;
  1503. if (*x == PathChar) {
  1504. i = x;
  1505. }
  1506. }
  1507. if ((i == NULLC) || (i < y-1)) {
  1508. *y = PathChar;
  1509. *(y+1) = NULLC;
  1510. }
  1511. if (!(source->flags & CI_SHORTNAME) ||
  1512. (mystrlen(source->buf->cAlternateFileName) == 0)) {
  1513. if ((mystrlen(dest_name) + 1 +
  1514. mystrlen(source->buf->cFileName))
  1515. > MAX_PATH) {
  1516. retval = FAILURE;
  1517. } else {
  1518. mystrcat(dest_name,source->buf->cFileName);
  1519. }
  1520. } else {
  1521. if ((mystrlen(source->buf->cAlternateFileName) == 0) ||
  1522. (mystrlen(dest_name) + 1 +
  1523. mystrlen(source->buf->cAlternateFileName))
  1524. > MAX_PATH) {
  1525. retval = FAILURE;
  1526. } else {
  1527. mystrcat(dest_name,source->buf->cAlternateFileName);
  1528. }
  1529. }
  1530. } else {
  1531. if (*(lastc(dest_spec->fspec)) == COLON) {
  1532. if (!(source->flags & CI_SHORTNAME)||
  1533. (mystrlen(source->buf->cAlternateFileName) == 0)) {
  1534. if ((mystrlen(dest_spec->fspec) + 1 +
  1535. mystrlen(source->buf->cFileName))
  1536. > MAX_PATH) {
  1537. retval = FAILURE;
  1538. } else {
  1539. mystrcpy(dest_name,dest_spec->fspec);
  1540. mystrcat(dest_name,source->buf->cFileName);
  1541. }
  1542. } else {
  1543. if ((mystrlen(source->buf->cAlternateFileName) == 0) ||
  1544. (mystrlen(dest_spec->fspec) + 1 +
  1545. mystrlen(source->buf->cAlternateFileName))
  1546. > MAX_PATH) {
  1547. retval = FAILURE;
  1548. } else {
  1549. mystrcpy(dest_name,dest_spec->fspec);
  1550. mystrcat(dest_name,source->buf->cAlternateFileName);
  1551. }
  1552. }
  1553. } else {
  1554. // this code does short name substitution when copying from
  1555. // an NTFS volume to a FAT volume.
  1556. if (checkmeta &&
  1557. (*(lastc(dest_spec->fspec)) == STAR) &&
  1558. (*(penulc(dest_spec->fspec)) == BSLASH)) {
  1559. TCHAR *LastComponent;
  1560. LastComponent = mystrrchr(source->curfspec,'\\');
  1561. if (LastComponent) {
  1562. // skip the \.
  1563. LastComponent++;
  1564. } else {
  1565. if (source->curfspec[1] == COLON) {
  1566. LastComponent = &source->curfspec[2];
  1567. } else {
  1568. LastComponent = source->curfspec;
  1569. }
  1570. }
  1571. if ((source->flags & CI_SHORTNAME) &&
  1572. (mystrlen(source->buf->cAlternateFileName) != 0) ) {
  1573. mystrcpy(LastComponent,source->buf->cAlternateFileName);
  1574. }
  1575. }
  1576. rcode = wildcard_rename(
  1577. (TCHAR *)dest_name,
  1578. (TCHAR *)dest_spec->fspec,
  1579. (TCHAR *)source->curfspec,
  1580. (unsigned)sizbufr);
  1581. if (rcode) {
  1582. PrtErr(rcode);
  1583. retval = FAILURE;
  1584. }
  1585. if (GetFullPathName( dest_name, MAX_PATH, FullName, NULL) > MAX_PATH) {
  1586. PrtErr( ERROR_BUFFER_OVERFLOW );
  1587. retval = FAILURE;
  1588. }
  1589. }
  1590. }
  1591. if (checkmeta &&
  1592. ((dest_spec != NULL && (dest_spec->flags & CI_PROMPTUSER) != 0) ||
  1593. (dest->flags & CI_PROMPTUSER) != 0)) {
  1594. HANDLE Handle = CreateFile( dest_name,
  1595. GENERIC_READ,
  1596. FILE_SHARE_READ,
  1597. NULL,
  1598. OPEN_EXISTING,
  1599. FILE_ATTRIBUTE_NORMAL,
  1600. 0 );
  1601. BOOL IsFile = FALSE;
  1602. if (Handle != INVALID_HANDLE_VALUE) {
  1603. IsFile = (GetFileType( Handle ) & ~FILE_TYPE_REMOTE) == FILE_TYPE_DISK;
  1604. CloseHandle( Handle );
  1605. }
  1606. if (IsFile) {
  1607. switch (PromptUser(dest_name, MSG_MOVE_COPY_OVERWRITE, MSG_NOYESALL_RESPONSE_DATA)) {
  1608. case 0: // No
  1609. dest_name[0] = NULLC;
  1610. break;
  1611. case 2: // All
  1612. if (dest_spec != NULL)
  1613. dest_spec->flags &= ~CI_PROMPTUSER;
  1614. else
  1615. dest->flags &= ~CI_PROMPTUSER;
  1616. default: // Yes
  1617. break;
  1618. }
  1619. }
  1620. }
  1621. return(retval);
  1622. }
  1623. /*** wildcard_rename - Obtain name from wildcard spec
  1624. *
  1625. * Purpose:
  1626. * This function converts the filenames into a nice clean form
  1627. * with get_clean_filename. Then it extracts the correct
  1628. * filename using the wildcard renaming rules. Basically,
  1629. * you have a template with wildcards in it, and a source
  1630. * filename. Any time there is a letter in the template, it
  1631. * gets used. Where the template has a wildcard, use the
  1632. * letter from the source filename.
  1633. *
  1634. * int wildcard_rename(TCHAR *buffer, TCHAR *dest, TCHAR *source)
  1635. *
  1636. * Args:
  1637. * OutputBuffer = The buffer to put the name in
  1638. * dest = The destination filespec
  1639. * source = The source filename
  1640. *
  1641. * Returns:
  1642. * Nothing
  1643. *
  1644. * Notes:
  1645. * As an example, *.out + foo.bar = foo.out. A more extreme
  1646. * example is: filename.ext + a?b??c*foo.?a* = aibencme.eat.
  1647. * The foo, because it comes after the '*', is ignored. The
  1648. * dot causes the template's letters to be significant again.
  1649. *
  1650. */
  1651. unsigned
  1652. wildcard_rename(
  1653. TCHAR *OutputBuffer,
  1654. const TCHAR *dest,
  1655. const TCHAR *source,
  1656. ULONG sizbufr
  1657. )
  1658. {
  1659. TCHAR dest_buffer[MAX_PATH];
  1660. unsigned wrc = 0;
  1661. const TCHAR *temp1, *temp2;
  1662. DEBUG((FCGRP,COLVL,"WildcardRename: Entered."));
  1663. //
  1664. // Find the filename component. The filename is the first
  1665. // character after the last \ or, if none, after the first : or,
  1666. // if none, the first character.
  1667. //
  1668. temp1 = mystrrchr( source, PathChar );
  1669. if (temp1 == NULLC) {
  1670. if (source[0] != TEXT( '\0' ) && source[1] == COLON) {
  1671. temp1 = source + 2;
  1672. } else {
  1673. temp1 = source;
  1674. }
  1675. } else {
  1676. temp1++;
  1677. }
  1678. //
  1679. // Find the filename component. The filename is the first
  1680. // character after the last \ or, if none, after the first : or,
  1681. // if none, the first character.
  1682. //
  1683. temp2 = mystrrchr(dest,PathChar);
  1684. if (temp2 == NULLC) {
  1685. temp2 = mystrchr(dest, COLON);
  1686. if (temp2 && (temp2 - dest == 1)) {
  1687. ++temp2;
  1688. } else {
  1689. temp2 = dest;
  1690. }
  1691. } else {
  1692. ++temp2;
  1693. }
  1694. wrc = WinEditName( temp1,
  1695. temp2,
  1696. dest_buffer,
  1697. sizbufr );
  1698. if (wrc) {
  1699. *OutputBuffer = NULLC;
  1700. }
  1701. /*temp fix */
  1702. else if (temp2 != dest) {
  1703. if (mystrlen(dest) > MAX_PATH ) {
  1704. wrc = ERROR_BUFFER_OVERFLOW;
  1705. return(wrc);
  1706. }
  1707. mystrcpy( OutputBuffer, dest );
  1708. *(OutputBuffer + (temp2-dest)) = NULLC;
  1709. if ( mystrlen( OutputBuffer )+mystrlen(dest_buffer)+1 > MAX_PATH ) {
  1710. wrc = ERROR_BUFFER_OVERFLOW;
  1711. } else {
  1712. mystrcat( OutputBuffer, dest_buffer );
  1713. }
  1714. } else {
  1715. mystrcpy( OutputBuffer, dest_buffer );
  1716. }
  1717. return(wrc);
  1718. }
  1719. /*** scan_bytes - Scan bytes from file for Control-Z
  1720. *
  1721. * Purpose:
  1722. * This just calls ZScanA. It is called with a
  1723. * and some variables needed by ZScanA routine.
  1724. * Since we are reading in ASCII mode,
  1725. * we need to truncate after a ^Z is read. ZScanA does this,
  1726. * changing bytes_read to the new length if it finds one.
  1727. *
  1728. * int scan_bytes(int srcptr,unsigned int *buf_seg,unsigned buf_len,
  1729. * unsigned *bytes_read,int mode,
  1730. * int dstptr, TCHAR *dest_name );
  1731. *
  1732. * Args:
  1733. * buf_seg = Buffer address
  1734. * bytes_read = Location to put bytes read
  1735. * mode = Read mode
  1736. * dstptr = Handle of file to write
  1737. *
  1738. * Returns:
  1739. * TRUE if read successful
  1740. * FALSE if not
  1741. *
  1742. */
  1743. scan_bytes(buf_seg,bytes_read,mode) /* @@6 */
  1744. CHAR *buf_seg ; /* @@6 */
  1745. unsigned int *bytes_read ; /* @@6 */ /* @@5@J16 */
  1746. int mode; /* @@6 */
  1747. { /* @@6 */
  1748. unsigned rdsav; /* storage for ZScanA */ /* @@6 */
  1749. int skip_first_byte = 0; /* storage for ZScanA */ /* @@6 */
  1750. /*************************************************************************/
  1751. /* if we are copying source in ascii mode, strip bytes after ^Z */
  1752. /* M017 - ^Z was not terminating input because although input was */
  1753. /* truncated, the caller had no idea that EOF had occurred and would */
  1754. /* read again. This is especially true with devices. */
  1755. /*************************************************************************/
  1756. /* @@6 */if (TruncateOnCtrlZ( mode )) {
  1757. /* @@6 */
  1758. rdsav = *bytes_read;
  1759. if (rdsav == 0) { /* if len = 0 @@5@J16 */
  1760. Heof = TRUE ;
  1761. } /* Tell caller @@5@J16 */
  1762. else { /* else @@5@J16 */
  1763. /* scan @@5@J16 */
  1764. /* @@6 */
  1765. ZScanA(TRUE, buf_seg, (PULONG)bytes_read, (PULONG)&skip_first_byte); /* @@5@J16 */
  1766. /* @@6 */if (rdsav != *bytes_read)
  1767. /* @@6 */
  1768. {
  1769. /* @@6 */
  1770. Heof = TRUE ; /* Tell caller */
  1771. /* @@6 */
  1772. /* @@6 */DEBUG((FCGRP,COLVL,
  1773. /* @@6 */ "ReadBytes: Ascii mode, Found ^Z, Heof set to %d.",
  1774. /* @@6 */ Heof));
  1775. /* @@6 */
  1776. }
  1777. } /* @@5@J16 */
  1778. /* @@6 */
  1779. }
  1780. return(TRUE);
  1781. }
  1782. /*** read_bytes - Read bytes from file
  1783. *
  1784. * Purpose:
  1785. * This just calls FarRead and ZScanA. It is called with a
  1786. * file handle to read from, and some variables needed by those
  1787. * two routines. FarRead gets as many bytes into the previously
  1788. * allocated buffer as it can. If we are reading in ASCII mode,
  1789. * we need to truncate after a ^Z is read. ZScanA does this,
  1790. * changing bytes_read to the new length if it finds one.
  1791. *
  1792. * int read_bytes(int srcptr,TCHAR *buf_seg,unsigned buf_len, @@5@J16
  1793. * unsigned int *bytes_read,int mode,
  1794. * int dstptr, TCHAR *dest_name );
  1795. *
  1796. * Args:
  1797. * srcptr = Handle of file to read
  1798. * buf_seg = Buffer address
  1799. * buf_len = Buffer length
  1800. * bytes_read = Location to put bytes read
  1801. * source = copy source state
  1802. * dstptr = Handle of file to write
  1803. * dest_name = file name of destination file
  1804. *
  1805. * Returns:
  1806. * TRUE if read successful
  1807. * FALSE if not
  1808. *
  1809. */
  1810. int
  1811. read_bytes(srcptr,buf_seg,buf_len,bytes_read,source,dstptr,dest_name)
  1812. CRTHANDLE srcptr;
  1813. PCHAR buf_seg ;
  1814. ULONG buf_len ;
  1815. PULONG bytes_read ; /* @@5@J16 */
  1816. PCPYINFO source;
  1817. CRTHANDLE dstptr;
  1818. PTCHAR dest_name;
  1819. {
  1820. unsigned rdsav ;
  1821. int skip_first_byte = 0; /* storage for ZScanA */
  1822. DEBUG((FCGRP,COLVL,"ReadBytes: Entered."));
  1823. Heof = FALSE ; /* Clear flag */
  1824. DEBUG((FCGRP,COLVL,"ReadBytes: Heof reset to %d.",Heof));
  1825. if (!ReadFile( CRTTONT(srcptr), buf_seg, buf_len, bytes_read, NULL) ||
  1826. (*bytes_read == 0 && GetLastError() == ERROR_OPERATION_ABORTED) // ctrl-c
  1827. ) {
  1828. DosErr=GetLastError();
  1829. Cclose(srcptr);
  1830. if (!FileIsDevice(dstptr)) {
  1831. Cclose(dstptr);
  1832. DeleteFile(dest_name );
  1833. } else {
  1834. Cclose(dstptr);
  1835. }
  1836. copy_error( DosErr, CE_PCOUNT );
  1837. }
  1838. if (*bytes_read == 0) {
  1839. DosErr = 0;
  1840. return(FALSE); /* M006 */
  1841. }
  1842. //
  1843. // Determine the contents of the buffer if we don't already
  1844. // know the sort of data inside it
  1845. //
  1846. if ((source->flags & (CI_UNICODE | CI_NOT_UNICODE)) == 0) {
  1847. if (*bytes_read >= sizeof( WORD ) && *(PWORD)buf_seg == BYTE_ORDER_MARK) {
  1848. source->flags |= CI_UNICODE;
  1849. } else {
  1850. source->flags |= CI_NOT_UNICODE;
  1851. }
  1852. }
  1853. //
  1854. // Ascii, non-unicode copies are terminated at the first ^Z. If a read
  1855. // succeeded but we truncated, indicate that we might be at EOF.
  1856. // Devices are not guaranteed to fill the buffer
  1857. //
  1858. if (TruncateOnCtrlZ( source->flags )) {
  1859. rdsav = *bytes_read ;
  1860. ZScanA(TRUE, buf_seg, bytes_read, (PULONG)&skip_first_byte); /* @@5@J16 */
  1861. if (rdsav != *bytes_read) {
  1862. Heof = TRUE ; /* Tell caller */
  1863. DEBUG((FCGRP,COLVL,
  1864. "ReadBytes: Ascii mode, Found ^Z, Heof set to %d.",
  1865. Heof));
  1866. };
  1867. };
  1868. return(TRUE);
  1869. }
  1870. /*** write_bytes - Write bytes to destination file.
  1871. *
  1872. * Purpose:
  1873. * Writes buffer of information to destination file using
  1874. * FarWrite.
  1875. *
  1876. * int write_bytes(int destptr,CHAR *buf_seg,
  1877. * unsigned bytes_read,TCHAR *dest_name, unsigned srcptr)
  1878. *
  1879. * Args:
  1880. * destptr = Handle of destination file
  1881. * buf_seg = Buffer to write
  1882. * bytes_read = Bytes previously read into buffer
  1883. * dest_name = Destination filename
  1884. * srcptr = source file handle
  1885. *
  1886. * Returns:
  1887. * Nothing if successful write
  1888. * Transfers to copy_error if not
  1889. *
  1890. * Notes:
  1891. * M020 - Added srcptr handle to args so that source could be closed
  1892. * if write error occurred.
  1893. *
  1894. */
  1895. void
  1896. write_bytes(destptr,buf_seg,bytes_read,dest_name,srcptr)
  1897. CRTHANDLE destptr ;
  1898. PCHAR buf_seg ;
  1899. ULONG bytes_read ;
  1900. PTCHAR dest_name ;
  1901. CRTHANDLE srcptr ;
  1902. {
  1903. DWORD bytes_writ ;
  1904. unsigned msg = 0 ;
  1905. DEBUG((FCGRP,COLVL,"WriteBytes: Entered."));
  1906. if (!WriteFile( CRTTONT(destptr), buf_seg, bytes_read, &bytes_writ, NULL ) ||
  1907. bytes_read != bytes_writ ||
  1908. CtrlCSeen ) {
  1909. DosErr=GetLastError();
  1910. Cclose(srcptr) ;
  1911. Cclose(destptr);
  1912. if (FileIsDevice( destptr )) {
  1913. msg = ERROR_WRITE_FAULT;
  1914. } else {
  1915. DeleteFile( dest_name );
  1916. }
  1917. Heof = FALSE;
  1918. if (!DosErr) {
  1919. DosErr = ERROR_DISK_FULL ;
  1920. }
  1921. if (CtrlCSeen) {
  1922. msg = 0;
  1923. } else {
  1924. if (!msg) {
  1925. PrtErr(DosErr);
  1926. }
  1927. }
  1928. copy_error(msg,CE_PCOUNT);
  1929. }
  1930. }
  1931. /*** same_fcpy - Detects case where source equals destination
  1932. *
  1933. * Purpose: (M015)
  1934. * The user might type something like "copy foo .\foo". To recognize
  1935. * that these are the same, copy translates the names into root-based
  1936. * pathnames. There is no internal DOS5 function to do this so we
  1937. * have partially simulated the old DOS3 functionality in the FullPath
  1938. * function in CTOOLS1. Note that this does not translate net names
  1939. * or ASSIGN/JOIN/SUBST type filespecs. It is called on both names
  1940. * returning FAILURE (1) if they are malformed and SUCCESS (0) if not.
  1941. * If there is a successful return, the two new strings are strcmp'd.
  1942. *
  1943. * int same_fcpy(int fres, TCHAR *first, TCHAR *second)
  1944. *
  1945. * Args:
  1946. * fsame = The source FullPath return code
  1947. * buffer1= The source buffer from FullPath
  1948. * second = The destination filename
  1949. *
  1950. * Returns:
  1951. * TRUE if names match
  1952. * FALSE if not
  1953. *
  1954. */
  1955. same_fcpy(fres,buffer1,second)
  1956. int fres;
  1957. TCHAR *buffer1;
  1958. TCHAR *second;
  1959. {
  1960. /*Increased buffer size @WM1 */
  1961. TCHAR buffer2[2*MAX_PATH] ; /* PTM 1412 */
  1962. DEBUG((FCGRP,COLVL,"SameFile: Entered."));
  1963. if (fres || FullPath(buffer2,second,MAX_PATH*2)) /* M015 */
  1964. return(FALSE) ;
  1965. DEBUG((FCGRP,COLVL,"SameFile: name1 after FullPath = %ws",buffer1));
  1966. DEBUG((FCGRP,COLVL,"SameFile: name2 after FullPath = %ws",buffer2));
  1967. /*509*/
  1968. return(_tcsicmp(buffer1,buffer2) == 0);
  1969. }
  1970. /*** same_file - Detects case where source equals destination
  1971. *
  1972. * Purpose: (M015)
  1973. * The user might type something like "copy foo .\foo". To recognize
  1974. * that these are the same, copy translates the names into root-based
  1975. * pathnames. There is no internal DOS5 function to do this so we
  1976. * have partially simulated the old DOS3 functionality in the FullPath
  1977. * function in CTOOLS1. Note that this does not translate net names
  1978. * or ASSIGN/JOIN/SUBST type filespecs. It is called on both names
  1979. * returning FAILURE (1) if they are malformed and SUCCESS (0) if not.
  1980. * If there is a successful return, the two new strings are strcmp'd.
  1981. *
  1982. * int same_file(TCHAR *first, TCHAR *second)
  1983. *
  1984. * Args:
  1985. * first = The source filename
  1986. * second = The destination filename
  1987. *
  1988. * Returns:
  1989. * TRUE if names match
  1990. * FALSE if not
  1991. *
  1992. */
  1993. same_file(first,second)
  1994. TCHAR *first,*second;
  1995. {
  1996. TCHAR buffer1[2*MAX_PATH], /* Increased buffer size @WM1 */
  1997. buffer2[2*MAX_PATH] ; /* PTM 1412 */
  1998. DEBUG((FCGRP,COLVL,"SameFile: Entered."));
  1999. if (FullPath(buffer1,first,MAX_PATH*2) || FullPath(buffer2,second,MAX_PATH*2)) /* M015 */
  2000. return(FALSE) ;
  2001. DEBUG((FCGRP,COLVL,"SameFile: name1 after FullPath = %ws",buffer1));
  2002. DEBUG((FCGRP,COLVL,"SameFile: name2 after FullPath = %ws",buffer2));
  2003. return(_tcsicmp(buffer1,buffer2) == 0);
  2004. }
  2005. /*** copy_error - Main error routine
  2006. *
  2007. * Purpose:
  2008. * Accepts a message number and a flag which determines whether
  2009. * it should print the number of files copied before the error.
  2010. * Resets the verify mode and longjmp's out.
  2011. *
  2012. * int copy_error(unsigned int messagenum, int flag)
  2013. *
  2014. * Args:
  2015. * messagenum = The message number for the message retriever
  2016. * flag = Print files copied message flag
  2017. *
  2018. * Returns:
  2019. * Does not return
  2020. *
  2021. */
  2022. void copy_error(messagenum,flag)
  2023. unsigned int messagenum;
  2024. int flag;
  2025. {
  2026. DEBUG((FCGRP,COLVL,"CopyError: Entered."));
  2027. if (messagenum) /* M019 */
  2028. PutStdOut(messagenum, NOARGS);
  2029. if (flag == CE_PCOUNT)
  2030. PutStdOut(MSG_FILES_COPIED, ONEARG, argstr1(TEXT("%9d"), (unsigned long)number_of_files_copied)) ;
  2031. VerifyCurrent = GetSetVerMode(GSVM_GET);
  2032. while (FFhndlCopy < FFhndlsaved) {
  2033. // while (FFhndlsaved) { /* findclose will dec this @@1 */
  2034. findclose(FFhandles[FFhndlsaved - 1]); /* @@1 */
  2035. } /* @@1 */
  2036. longjmp(CmdJBuf2,1);
  2037. }
  2038. /*** DestinationNeedsCtrlZ - Test type of copy in progress
  2039. *
  2040. * Purpose:
  2041. * Given a struct, check if the copy was in ascii mode by
  2042. * looking at its flags. If it was, either the CI_ASCII flag
  2043. * was set or the user didn't specify and the operation was
  2044. * concat or combine, which default to ascii mode.
  2045. *
  2046. * Args:
  2047. * dest = The destination copy information structure.
  2048. *
  2049. * Returns:
  2050. * TRUE for ^Z termination needed,
  2051. * FALSE otherwise.
  2052. *
  2053. */
  2054. BOOL
  2055. DestinationNeedsCtrlZ( dest )
  2056. PCPYINFO dest;
  2057. {
  2058. DEBUG((FCGRP,COLVL,"CopyWasAscii: Entered."));
  2059. //
  2060. // We append a ^Z only if:
  2061. // This isn't a unicode copy
  2062. // and
  2063. // (explicit ^Z addition requested
  2064. // or
  2065. // (no flags were set
  2066. // and
  2067. // the copy mode was concat or combine)
  2068. //
  2069. return (dest->flags & CI_UNICODE) == 0
  2070. && ((dest->flags & CI_ASCII) != 0
  2071. || ((dest->flags & CI_NOTSET) != 0
  2072. && (copy_mode == CONCAT || copy_mode == COMBINE)));
  2073. }
  2074. /*** open_for_append - Open and seek to end (or ^Z)
  2075. *
  2076. * Purpose:
  2077. * Open a file for writing, and seek the pointer to the
  2078. * end of it. If we are copying in ascii mode, seek to
  2079. * the first ^Z found. If not, seek to the physical end.
  2080. *
  2081. * int open_for_append(TCHAR *filename,int flags,
  2082. * TCHAR *buf_seg,unsigned buf_len)
  2083. *
  2084. * Args:
  2085. * filename = ASCII filename
  2086. * source = copy info source
  2087. * buf_seg = Read buffer
  2088. * buf_len = Buffer length
  2089. *
  2090. * Returns:
  2091. * Handle of open file if successful
  2092. * Error out if not
  2093. *
  2094. */
  2095. CRTHANDLE
  2096. open_for_append(
  2097. PTCHAR filename,
  2098. PCPYINFO source,
  2099. PCHAR buf_seg,
  2100. ULONG buf_len)
  2101. {
  2102. ULONG bytesread ;
  2103. CRTHANDLE ptr;
  2104. int foundz = FALSE ;
  2105. unsigned brcopy ;
  2106. ULONG skip_first_byte = 0; /* storage for ZScanA */
  2107. DEBUG((FCGRP,COLVL,"OpenForAppend: Entered."));
  2108. ptr = Copen2( /* open file for destination file */
  2109. filename, /* make explicit cast */
  2110. (unsigned int)O_RDWR, /* make explicit cast */
  2111. FALSE);
  2112. if (ptr == BADHANDLE) { /* M011 */
  2113. PrtErr(ERROR_OPEN_FAILED) ; /* M019 */
  2114. copy_error(0,CE_PCOUNT) ; /* M019 */
  2115. }
  2116. do {
  2117. if (ReadFile( CRTTONT(ptr), buf_seg, buf_len, &bytesread, NULL)) {
  2118. brcopy = bytesread ;
  2119. //
  2120. // Determine the contents of the buffer if we don't already
  2121. // know the sort of data inside it
  2122. //
  2123. if ((source->flags & (CI_UNICODE | CI_NOT_UNICODE)) == 0) {
  2124. if (bytesread > sizeof( WORD ) && *(PWORD)buf_seg == BYTE_ORDER_MARK) {
  2125. source->flags |= CI_UNICODE;
  2126. } else {
  2127. source->flags |= CI_NOT_UNICODE;
  2128. }
  2129. }
  2130. if (brcopy != 0) {
  2131. foundz = ZScanA( TruncateOnCtrlZ( source->flags ),
  2132. buf_seg,
  2133. &bytesread,
  2134. &skip_first_byte
  2135. ) ;
  2136. }
  2137. } else {
  2138. DosErr = GetLastError();
  2139. Cclose(ptr);
  2140. PutStdErr(DosErr,NOARGS) ;
  2141. copy_error(0,CE_PCOUNT) ; /* end copy at this point */
  2142. }
  2143. } while (bytesread == buf_len) ;
  2144. if (foundz == 0) {
  2145. SetFilePointer(CRTTONT(ptr), -(long)(brcopy-bytesread), NULL, FILE_CURRENT) ;
  2146. }
  2147. return(ptr) ;
  2148. }
  2149. DWORD
  2150. WinEditName(
  2151. const TCHAR *pSrc,
  2152. const TCHAR *pEd,
  2153. TCHAR *pRes,
  2154. const unsigned ResBufLen
  2155. )
  2156. /*++
  2157. Routine Description:
  2158. This routine takes a source filename, an editing pattern, and produces
  2159. an output name suitable for rename or copy. It relies on the semantics
  2160. of ? and * matching. There are a whole raft of user-model issues here
  2161. especially when doing things like:
  2162. rename *.foo.bar *
  2163. Does the user intend that the destination * match precisely what the
  2164. source * matches? This is a huge RATHOLE.
  2165. Arguments:
  2166. pSrc
  2167. Input filename as produced by find-first/next
  2168. pEd
  2169. Editing string, containing *, ? and other characters
  2170. pRes
  2171. Output buffer where edited string is placed
  2172. ResBufLen
  2173. Length of output buffer
  2174. Return Value:
  2175. Status code
  2176. --*/
  2177. {
  2178. DWORD ResLen;
  2179. TCHAR delimit;
  2180. TCHAR *pTmp;
  2181. //
  2182. // Walk forward through the editing string processing the
  2183. // editing chars:
  2184. //
  2185. // : and /\ are not allowed
  2186. // * matches the current point in the source string
  2187. // through either the end of string or through the
  2188. // LAST character that may follow the *: *A will
  2189. // match up to (but not including) the last A.
  2190. // ? matches the next character UNLESS it's a dot in
  2191. // which case, it's ignored.
  2192. // . matches any number of dots, including zero.
  2193. //
  2194. // all other characters match
  2195. ResLen = 0;
  2196. while (*pEd) {
  2197. if (ResLen < ResBufLen) {
  2198. switch (*pEd) {
  2199. case COLON:
  2200. case BSLASH:
  2201. return(ERROR_INVALID_NAME);
  2202. case STAR:
  2203. delimit = *(pEd+1);
  2204. if (!(pTmp = _tcsrchr(pSrc, delimit))) {
  2205. pTmp = _tcsrchr(pSrc, NULLC);
  2206. }
  2207. while ((ResLen < ResBufLen) && pSrc < pTmp) {
  2208. if (ResLen < ResBufLen) {
  2209. *(pRes++) = *(pSrc++);
  2210. ResLen++;
  2211. } else
  2212. return(ERROR_BUFFER_OVERFLOW);
  2213. }
  2214. break;
  2215. case QMARK:
  2216. if ((*pSrc != DOT) && (*pSrc != NULLC)) {
  2217. if (ResLen < ResBufLen) {
  2218. *(pRes++) = *(pSrc++);
  2219. ResLen++;
  2220. } else
  2221. return(ERROR_BUFFER_OVERFLOW);
  2222. }
  2223. break;
  2224. case DOT:
  2225. while ((*pSrc != DOT) && (*pSrc != NULLC)) {
  2226. pSrc++;
  2227. }
  2228. *(pRes++) = DOT; /* from EditMask, even if src doesn't */
  2229. /* have one, so always put one. */
  2230. ResLen++;
  2231. if (*pSrc) /* point one past '.' */
  2232. pSrc++;
  2233. break;
  2234. default:
  2235. if ((*pSrc != DOT) && (*pSrc != NULLC)) {
  2236. pSrc++;
  2237. }
  2238. if (ResLen < ResBufLen) {
  2239. *(pRes++) = *pEd;
  2240. ResLen++;
  2241. } else
  2242. return(ERROR_BUFFER_OVERFLOW);
  2243. break;
  2244. }
  2245. pEd++;
  2246. } else {
  2247. return(ERROR_BUFFER_OVERFLOW);
  2248. }
  2249. }
  2250. if ((ResLen) < ResBufLen) {
  2251. *pRes = NULLC;
  2252. return(NO_ERROR);
  2253. } else
  2254. return(ERROR_BUFFER_OVERFLOW);
  2255. }
  2256. /*** MyWriteFile - write ansi/unicode to file
  2257. *
  2258. * Purpose:
  2259. * Write buffer in requested mode (ansi/unicode) to destination.
  2260. *
  2261. * Args:
  2262. * Same as WriteFileW
  2263. *
  2264. * Returns:
  2265. * return value from WriteFileW
  2266. *
  2267. */
  2268. BOOL
  2269. MyWriteFile(
  2270. CRTHANDLE fh,
  2271. CONST VOID *rgb,
  2272. DWORD cb,
  2273. LPDWORD lpcb
  2274. )
  2275. {
  2276. DWORD cbTotal = cb;
  2277. HANDLE dh = CRTTONT(fh);
  2278. DWORD cbT;
  2279. #ifdef UNICODE
  2280. if (fOutputUnicode)
  2281. #endif // UNICODE
  2282. return WriteFile(dh, rgb, cb, lpcb, NULL);
  2283. #ifdef UNICODE
  2284. else {
  2285. TCHAR *rgw = (TCHAR*)rgb;
  2286. #ifdef FE_SB
  2287. // If dbcs string include, Unicode string len != MultiByte string len.
  2288. // MSKK NT RAID :#10855 by V-HIDEKK
  2289. while (cb > LBUFLEN) {
  2290. // - 1 for NULLC
  2291. cbT = WideCharToMultiByte(CurrentCP, 0, (LPWSTR)rgw, LBUFLEN/(sizeof(TCHAR)),
  2292. (LPSTR)AnsiBuf, LBUFLEN, NULL, NULL);
  2293. rgw += LBUFLEN/(sizeof(TCHAR));
  2294. cb -= LBUFLEN;
  2295. #else
  2296. while (cb > LBUFLEN*sizeof(TCHAR)) {
  2297. // - 1 for NULLC
  2298. cbT = WideCharToMultiByte(CurrentCP, 0, (LPWSTR)rgw, LBUFLEN,
  2299. (LPSTR)AnsiBuf, LBUFLEN, NULL, NULL);
  2300. rgw += LBUFLEN;
  2301. cb -= LBUFLEN*sizeof(TCHAR);
  2302. #endif
  2303. if (!WriteFile(dh, AnsiBuf, cbT, lpcb, NULL) || *lpcb != cbT)
  2304. return FALSE;
  2305. }
  2306. if (cb != 0) {
  2307. // - 1 for NULLC
  2308. cb = WideCharToMultiByte(CurrentCP, 0, (LPWSTR)rgw, -1,
  2309. (LPSTR)AnsiBuf, LBUFLEN, NULL, NULL) - 1;
  2310. if (!WriteFile(dh, AnsiBuf, cb, lpcb, NULL) || *lpcb != cb)
  2311. return FALSE;
  2312. }
  2313. *lpcb = cbTotal;
  2314. return TRUE;
  2315. }
  2316. #endif // UNICODE
  2317. }
  2318. int DoVerify(
  2319. CRTHANDLE *pdestptr,
  2320. TCHAR *curr_dest,
  2321. ULONG bytes_read,
  2322. CHAR *buf_seg,
  2323. CHAR *buf_seg_dest
  2324. )
  2325. {
  2326. ULONG bytes_read_dest;
  2327. FlushFileBuffers ( CRTTONT(*pdestptr) );
  2328. Cclose(*pdestptr);
  2329. *pdestptr = Copen_Copy2(curr_dest, (ULONG)O_RDONLY);
  2330. if (*pdestptr == BADHANDLE) {
  2331. // printf( "DoVerify: unable to open dest - %d\n", DosErr );
  2332. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  2333. return(FAILURE);
  2334. }
  2335. SetFilePointer( CRTTONT(*pdestptr), - (LONG) bytes_read, NULL, FILE_END);
  2336. if (!ReadFile( CRTTONT(*pdestptr), buf_seg_dest, bytes_read, &bytes_read_dest, NULL) ) {
  2337. // printf( "DoVerify: unable to read dest - %d\n", GetLastError( ) );
  2338. Cclose(*pdestptr);
  2339. *pdestptr=BADHANDLE;
  2340. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  2341. return(FAILURE);
  2342. }
  2343. if (bytes_read_dest != bytes_read ) {
  2344. // printf( "DoVerify: Read different numbers of bytes\n" );
  2345. Cclose(*pdestptr);
  2346. *pdestptr=BADHANDLE;
  2347. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  2348. return(FAILURE);
  2349. }
  2350. if ( memcmp (buf_seg, buf_seg_dest, bytes_read) != 0 ) {
  2351. // printf( "DoVerify: buffers differ at offset %x\n", memcmp (buf_seg, buf_seg_dest, bytes_read) );
  2352. Cclose(*pdestptr);
  2353. *pdestptr=BADHANDLE;
  2354. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  2355. return(FAILURE);
  2356. }
  2357. // last buffers compared OK, resuming writing.
  2358. Cclose(*pdestptr);
  2359. *pdestptr = Copen2((TCHAR *)curr_dest,
  2360. (unsigned int)O_WRONLY,
  2361. FALSE);
  2362. if (*pdestptr == BADHANDLE) {
  2363. // printf( "DoVerify: Unable to open dest 2 - %d\n", DosErr );
  2364. PutStdErr(MSG_VERIFY_FAIL, ONEARG, curr_dest);
  2365. return(FAILURE);
  2366. }
  2367. SetFilePointer( CRTTONT(*pdestptr), 0, NULL, FILE_END);
  2368. return(SUCCESS);
  2369. }