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.

1191 lines
43 KiB

  1. /*++
  2. Copyright (c) 1988-1999 Microsoft Corporation
  3. Module Name:
  4. cfile.c
  5. Abstract:
  6. File manipulation support
  7. --*/
  8. #include "cmd.h"
  9. #define Wild(spec) ((spec)->flags & (CI_NAMEWILD))
  10. extern int LastRetCode ;
  11. extern jmp_buf CmdJBuf2 ;
  12. extern TCHAR Fmt19[], Fmt17[];
  13. extern TCHAR CurDrvDir[] ;
  14. extern TCHAR YesChar, NoChar ;
  15. extern TCHAR *SaveDir ;
  16. extern TCHAR PathChar, TmpBuf[], SwitChar;
  17. extern unsigned DosErr ;
  18. extern unsigned flgwd ; /* M021 */
  19. extern int LastRetCode ;
  20. extern BOOL CtrlCSeen;
  21. extern PTCHAR pszTitleCur;
  22. extern BOOLEAN fTitleChanged;
  23. //
  24. // Internal prototypes
  25. //
  26. PCPYINFOSetFsSetSaveDir() ;
  27. /*** ErrorDisplayAndJumnp - handle errors
  28. *
  29. * Purpose:
  30. * eRename and eMove error handler. Returns to routine via longjmp
  31. *
  32. * ErrorDisplayAndJump(unsigned int errmsg)
  33. *
  34. *
  35. * Args:
  36. * errmsg - the error message to print
  37. *
  38. */
  39. void ErrorDisplayAndJump( unsigned int errmsg )
  40. {
  41. PutStdErr( errmsg, NOARGS );
  42. RestoreSavedDirectory( );
  43. longjmp( CmdJBuf2, 1 ) ;
  44. }
  45. /*
  46. ** This routine returns the longest pathlength possible from the input path
  47. ** It assumes that the input path is a buffer that it can extend by a
  48. ** wildcard '\*' to search the file, if it is a directory.
  49. ** The input path must be fully qualified, eg: "c:\winnt\system32\kernel32.dll"
  50. **
  51. ** Input:
  52. ** pPath fully qualified Pathname
  53. ** pCch pointer to length of pathname
  54. ** Returns:
  55. ** TRUE succeeded, pCch contains length
  56. ** FALSE error occurred
  57. */
  58. BOOL
  59. GreatestLength(
  60. TCHAR *pPath,
  61. int *pCch
  62. )
  63. {
  64. WIN32_FIND_DATA fd;
  65. HANDLE hFind;
  66. DWORD err;
  67. int cch;
  68. int cchThis;
  69. DWORD attr;
  70. TCHAR *pLast;
  71. BOOL MoreFiles;
  72. /* assume a file, or empty directory */
  73. *pCch = cch = _tcslen(pPath) - 2; /* _tcslen(TEXT("C:")) */
  74. if ((attr=GetFileAttributes(pPath)) == 0xffffffff) {
  75. PutStdErr(GetLastError(), NOARGS);
  76. return FALSE;
  77. }
  78. if ( !(attr & FILE_ATTRIBUTE_DIRECTORY)) { /* if just a file... */
  79. return TRUE;
  80. }
  81. /* path is a directory, search it ... */
  82. pLast = pPath + _tcslen(pPath);
  83. if (*(pLast-1) == BSLASH) {
  84. *pLast = STAR;
  85. *(pLast+1) = NULLC;
  86. } else {
  87. *pLast = BSLASH;
  88. *(pLast+1) = STAR;
  89. *(pLast+2) = NULLC;
  90. }
  91. if ((hFind=FindFirstFile(pPath, &fd)) == INVALID_HANDLE_VALUE) {
  92. //
  93. // Check that failure was not due to some system error such
  94. // as an abort on access to floppy
  95. //
  96. err = GetLastError();
  97. FindClose(hFind);
  98. if (err != ERROR_FILE_NOT_FOUND && err != ERROR_NO_MORE_FILES) {
  99. PutStdErr(err, NOARGS);
  100. return FALSE;
  101. }
  102. return TRUE;
  103. }
  104. MoreFiles = TRUE;
  105. do {
  106. if (!_tcscmp(fd.cFileName, TEXT(".")))
  107. continue;
  108. if (!_tcscmp(fd.cFileName, TEXT("..")))
  109. continue;
  110. if (_tcslen( fd.cFileName ) == 0) {
  111. continue;
  112. }
  113. if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
  114. TCHAR path[MAX_PATH];
  115. _tcscpy(path, pPath);
  116. *(path+_tcslen(path)-1) = NULLC; /* zap asterisk */
  117. _tcscat(path, fd.cFileName);
  118. if (!GreatestLength(path, &cchThis))
  119. break;
  120. *pCch = max(*pCch, cch + cchThis);
  121. } else {
  122. *pCch = max(*pCch, (int) _tcslen(fd.cFileName));
  123. }
  124. } while ( MoreFiles = FindNextFile(hFind, &fd) );
  125. err = GetLastError();
  126. FindClose(hFind);
  127. if ( MoreFiles ) {
  128. return FALSE;
  129. } else if ( err != ERROR_NO_MORE_FILES ) {
  130. PutStdErr(err, NOARGS);
  131. return FALSE;
  132. }
  133. return TRUE;
  134. }
  135. void
  136. RestoreSavedDirectory( void )
  137. {
  138. if (SaveDir) {
  139. mystrcpy( CurDrvDir, SaveDir );
  140. SaveDir = NULL;
  141. }
  142. }
  143. BOOL
  144. GetPromptOkay(
  145. const TCHAR *arg,
  146. BOOL *promptokay
  147. )
  148. {
  149. BOOL Result;
  150. const TCHAR *p, *p1;
  151. Result = TRUE;
  152. if (arg != NULL) {
  153. p = arg;
  154. while (*p && *p <= SPACE)
  155. p += 1;
  156. p1 = p;
  157. while (*p1 && *p1 > SPACE)
  158. p1 += 1;
  159. if (!_tcsnicmp(p, TEXT("/Y"),(UINT)(p1-p)))
  160. *promptokay = FALSE;
  161. else
  162. if (!_tcsnicmp(p, TEXT("/-Y"),(UINT)(p1-p)))
  163. *promptokay = TRUE;
  164. else
  165. Result = FALSE;
  166. }
  167. return Result;
  168. }
  169. int eCopy(n)
  170. struct cmdnode *n ;
  171. {
  172. return(LastRetCode = copy(n->argptr)) ;
  173. }
  174. int eDelete(n)
  175. struct cmdnode *n ;
  176. {
  177. int DelWork() ;
  178. return(LastRetCode = DelWork(n->argptr));
  179. }
  180. /********************* START OF SPECIFICATION **************************/
  181. /* */
  182. /* SUBROUTINE NAME: eRename */
  183. /* */
  184. /* DESCRIPTIVE NAME: Rename Internal Command */
  185. /* */
  186. /* FUNCTION: Rename files and subdirectories. Wildcards only applies */
  187. /* to file names. */
  188. /* */
  189. /* NOTES: @@5* */
  190. /* */
  191. /* ENTRY POINT: eRename */
  192. /* LINKAGE: NEAR */
  193. /* */
  194. /* INPUT: */
  195. /* n - the parse tree node containing the rename command */
  196. /* */
  197. /* OUTPUT: None. */
  198. /* */
  199. /* EXIT-NORMAL: */
  200. /* Return SUCCESS to the caller. */
  201. /* */
  202. /* EXIT-ERROR: */
  203. /* Return FAILURE to the caller. */
  204. /* */
  205. /* EFFECTS: None. */
  206. /* */
  207. /* INTERNAL REFERENCES: */
  208. /* ROUTINES: */
  209. /* RenWork - Worker routine for rename. */
  210. /* */
  211. /* EXTERNAL REFERENCES: */
  212. /* ROUTINES: */
  213. /* None */
  214. /* */
  215. /********************** END OF SPECIFICATION **************************/
  216. int eRename(n)
  217. struct cmdnode *n ;
  218. {
  219. int RenWork(); /* @@ */
  220. return(LastRetCode = RenWork( n )); /* @@ */
  221. }
  222. /********************* START OF SPECIFICATION **************************/
  223. /* */
  224. /* SUBROUTINE NAME: RenWork */
  225. /* */
  226. /* DESCRIPTIVE NAME: Rename Internal Command Worker */
  227. /* */
  228. /* FUNCTION: Rename files and subdirectories. Wildcards only applies */
  229. /* to file names. */
  230. /* */
  231. /* NOTES: @@5* */
  232. /* */
  233. /* ENTRY POINT: RenWork */
  234. /* LINKAGE: NEAR */
  235. /* */
  236. /* INPUT: */
  237. /* n - The parse tree node containing the rename command */
  238. /* */
  239. /* OUTPUT: None. */
  240. /* */
  241. /* EXIT-NORMAL: */
  242. /* Return SUCCESS to the caller. */
  243. /* */
  244. /* EXIT-ERROR: */
  245. /* Return FAILURE to the caller. */
  246. /* */
  247. /* EFFECTS: None. */
  248. /* */
  249. /* INTERNAL REFERENCES: */
  250. /* ROUTINES: */
  251. /* ffirst - Find the first matching specified file. */
  252. /* fnext - Find the next matching specified file handle*/
  253. /* findclose - Close the file with the specified file handle, */
  254. /* hnFirst which is given by ffirst or fnext. */
  255. /* TokStr - Tokenize argument strings. */
  256. /* wildcard_rename - Obtain name based on wildcard specification.*/
  257. /* SetFsSetSaveDir - Save the current directory. */
  258. /* GetDir - Get the specified directory. */
  259. /* ChangeDir - Change to the specified directory. */
  260. /* PutStdErr - Displays an error message. */
  261. /* Wild - check if the arg contains wild card. */
  262. /* */
  263. /* EXTERNAL REFERENCES: */
  264. /* ROUTINES: */
  265. /* None */
  266. /* DOSMOVE - Rename file and directory names. */
  267. /* DOSCASEMAP - Change lower case character to upper case. */
  268. /* DOSFILEMODE - Get attribute of specified file. */
  269. /* */
  270. /********************** END OF SPECIFICATION **************************/
  271. int RenWork(n) /* @@ */
  272. struct cmdnode *n ;
  273. {
  274. TCHAR *arg1 ; /* Ptr to 1st arg */
  275. TCHAR *arg2 ; /* Ptr to 2nd arg */
  276. PCPYINFO a1info ; /* Holds arg1 fspec info */
  277. PCPYINFO SetFsSetSaveDir();
  278. TCHAR Source[MAX_PATH];
  279. TCHAR bufdst[MAX_PATH]; /* path of destination file*/
  280. TCHAR Replacement[MAX_PATH];
  281. int wlen; /* length of source path */
  282. int rc; /* return code */
  283. HANDLE hnFirst ; /* Findfirst handle */
  284. unsigned attr ;
  285. unsigned i; /* Temp Return Code */
  286. TCHAR *j ; /* Temp Ptr to dir name */
  287. unsigned wild_flag ; /* wildcard flag */
  288. TCHAR pcstr[3] ;
  289. unsigned retval = SUCCESS;
  290. DEBUG((FCGRP, RELVL, "RENAME: arptr = `%ws'", n->argptr)) ;
  291. if (setjmp(CmdJBuf2))
  292. return(FAILURE) ;
  293. /* There should be only two arguments */
  294. if (!*(arg1 = TokStr(n->argptr, NULL, TS_NOFLAGS)) ||
  295. !*(arg2 = arg1 + mystrlen(arg1) + 1) ||
  296. *(arg2 + mystrlen(arg2) +1)) { /* @@5g */
  297. ErrorDisplayAndJump( MSG_BAD_SYNTAX );
  298. }
  299. mystrcpy( arg1, StripQuotes(arg1) ); /* 509 */
  300. mystrcpy( arg2, StripQuotes(arg2) ); /* 509 */
  301. if ((a1info = SetFsSetSaveDir(arg1)) == (PCPYINFO)FAILURE) {
  302. ErrorDisplayAndJump( DosErr );
  303. }
  304. mystrcpy( Source, CurDrvDir );
  305. mystrcpy(bufdst,CurDrvDir); /* save path of dest */
  306. wlen = mystrlen( Source ); /* get len of src path */
  307. if ( (a1info->buf->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0 ) {
  308. mystrcpy(&Source[wlen],a1info->fnptr);
  309. } else {
  310. Source[--wlen] = NULLC ;
  311. bufdst[wlen] = NULLC ;
  312. }
  313. /* if not wild since */
  314. if (!Wild(a1info)) {
  315. a1info->buf->dwFileAttributes =
  316. GetFileAttributes( StripQuotes(Source) );
  317. if (a1info->buf->dwFileAttributes == -1 ) {
  318. ErrorDisplayAndJump( GetLastError( )) ;
  319. }
  320. }
  321. if (*(arg2+1) == COLON ||
  322. mystrchr(arg2,PathChar)) {
  323. ErrorDisplayAndJump( MSG_BAD_SYNTAX );
  324. }
  325. /**********************************************/
  326. /* M009 - Always specifiy drive, filename, */
  327. /* and extension. Note, it is */
  328. /* assumed that SaveDir always starts */
  329. /* with a drive letter */
  330. /**********************************************/
  331. Replacement[0] = CurDrvDir[0] ; /* @@5h */
  332. Replacement[1] = COLON ;
  333. /**********************************************/
  334. /* Set flag whether arg1 contains */
  335. /* wildcard or not. */
  336. /**********************************************/
  337. pcstr[0] = STAR ;
  338. pcstr[1] = QMARK ;
  339. pcstr[2] = NULLC ;
  340. wild_flag = ((mystrcspn(arg1,pcstr)) < mystrlen(arg1)) ;
  341. /**********************************************/
  342. /* Issue ffirst for a file name */
  343. /**********************************************/
  344. if ( !ffirst(Source, attr = FILE_ATTRIBUTE_ARCHIVE, a1info->buf, &hnFirst )) {
  345. /*********************************************/
  346. /* Issue ffirst for a directory name */
  347. /*********************************************/
  348. if (!ffirst(Source, attr = FILE_ATTRIBUTE_DIRECTORY, a1info->buf, &hnFirst )) {
  349. if (DosErr == ERROR_NO_MORE_FILES) {
  350. DosErr = ERROR_FILE_NOT_FOUND;
  351. }
  352. ErrorDisplayAndJump( DosErr );
  353. } else {
  354. if (wild_flag) {
  355. findclose( hnFirst );
  356. ErrorDisplayAndJump( MSG_BAD_SYNTAX );
  357. }
  358. }
  359. }
  360. Source[wlen] = NULLC; /* make filename = NULL */
  361. rc = 0 ; /* @@5 */
  362. do {
  363. if (CtrlCSeen) {
  364. findclose(hnFirst) ;
  365. RestoreSavedDirectory( );
  366. return(FAILURE);
  367. }
  368. /**********************************************/
  369. /* if the file attribute of Source is */
  370. /* directory then concatenate arg2 after the */
  371. /* last "\" character of bufdst */
  372. /**********************************************/
  373. if ( a1info->buf->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { /* @@5c*/
  374. j = mystrrchr(bufdst,PathChar) ; /* @@5 */
  375. if ( !j ) {
  376. ErrorDisplayAndJump( MSG_REN_INVAL_PATH_FILENAME );
  377. }
  378. *(++j) = NULLC;
  379. if ( (mystrlen(arg2) + 1 + mystrlen(bufdst)) > MAX_PATH ) {
  380. ErrorDisplayAndJump( MSG_REN_INVAL_PATH_FILENAME );
  381. }
  382. mystrcpy(j,arg2); /* @@5 */
  383. bufdst[mystrlen(bufdst)] = NULLC ; /* @@5 */
  384. } /* @@5 */
  385. else { /* @@5 */
  386. mystrcpy(&Source[wlen],a1info->buf->cFileName);
  387. wildcard_rename( Replacement, arg2, &Source[wlen], MAX_PATH );
  388. if ( (wlen + 1 + mystrlen( Replacement )) > MAX_PATH ) {
  389. ErrorDisplayAndJump( MSG_REN_INVAL_PATH_FILENAME );
  390. }
  391. mystrcpy(&bufdst[wlen],&Replacement[0]); /*@@4 @J1*/
  392. }
  393. /**********************************************/
  394. /* Rename a file or directory */
  395. /**********************************************/
  396. DEBUG((FCGRP, RELVL, "RENAME: src:`%ws', dst:`%ws'", Source, bufdst)) ;
  397. if ( !MoveFile( Source, bufdst ) ) {
  398. /**********************************************/
  399. /* rename fails */
  400. /**********************************************/
  401. i = GetLastError();
  402. if (i == ERROR_ALREADY_EXISTS) {
  403. i = MSG_DUP_FILENAME_OR_NOT_FD;
  404. }
  405. rc = i ; /* @@5 Save the error code*/
  406. PutStdErr(rc,NOARGS); /* @@5 Put our err message*/
  407. }
  408. } while (fnext(a1info->buf, attr, hnFirst ));
  409. /**********************************************/
  410. /* No more file is found */
  411. /**********************************************/
  412. findclose(hnFirst) ;
  413. RestoreSavedDirectory( );
  414. return( rc ? FAILURE : SUCCESS ); /* @@5 */
  415. }
  416. /********************* START OF SPECIFICATION **************************/
  417. /* */
  418. /* SUBROUTINE NAME: eMove */
  419. /* */
  420. /* DESCRIPTIVE NAME: Move Internal Command */
  421. /* */
  422. /* FUNCTION: Parse the parameter passed and */
  423. /* moves one or more files from directory to another */
  424. /* directory on the same drive. If you prefer you can give */
  425. /* the files different names. */
  426. /* */
  427. /* NOTES: ( New routine for Relaese 1.2 ) @@5* */
  428. /* */
  429. /* ENTRY POINT: eMove */
  430. /* LINKAGE: NEAR */
  431. /* */
  432. /* INPUT: */
  433. /* n - the parse tree node containing the copy command */
  434. /* */
  435. /* OUTPUT: None. */
  436. /* */
  437. /* EXIT-NORMAL: */
  438. /* Return SUCCESS to the caller. */
  439. /* */
  440. /* EXIT-ERROR: */
  441. /* Return FAILURE to caller. */
  442. /* */
  443. /* EFFECTS: None. */
  444. /* */
  445. /* INTERNAL REFERENCES: */
  446. /* ROUTINES: */
  447. /* MoveParse - parse move command parameter */
  448. /* Move - routine which actually call DosMove to move */
  449. /* file or directory. */
  450. /* */
  451. /* EXTERNAL REFERENCES: */
  452. /* ROUTINES: */
  453. /* None */
  454. /* */
  455. /********************** END OF SPECIFICATION **************************/
  456. int eMove(n)
  457. struct cmdnode *n ;
  458. {
  459. unsigned i;
  460. BOOL PromptOnOverwrite;
  461. TCHAR arg1[MAX_PATH] ; /* Ptr to 1st arg */
  462. TCHAR arg2[MAX_PATH] ; /* Ptr to 2nd arg */
  463. PCPYINFO a1info ; /* Holds arg1 fspec info */
  464. unsigned int is_dest_dir; /* generated by MoveParse(), used by Move() */
  465. DEBUG((FCGRP, RELVL, "RENAME: arptr = `%ws'", n->argptr)) ;
  466. if (setjmp(CmdJBuf2))
  467. return(LastRetCode = FAILURE) ;
  468. //
  469. // Get default prompt okay flag from COPYCMD variable. Allow
  470. // user to override with /Y or /-Y switch. Always assume /Y
  471. // if command executed from inside batch script or via CMD.EXE
  472. // command line switch (/C or /K)
  473. //
  474. if (SingleBatchInvocation || SingleCommandInvocation || CurrentBatchFile != 0)
  475. PromptOnOverwrite = FALSE; // Assume /Y
  476. else
  477. PromptOnOverwrite = TRUE; // Assume /-Y
  478. /* MoveParse parses the command line parameters to arg1 */
  479. /* and arg1. In addition, a1info holds the fspec */
  480. /* information for arg1. */
  481. /* Based on arg1 and arg2, Move moves file(s)/directory. */
  482. /* Move uses a1info to determine that arg1 contains */
  483. /* wildcard. */
  484. i = MoveParse( n,
  485. &PromptOnOverwrite,
  486. arg1,
  487. arg2,
  488. &a1info,
  489. &is_dest_dir,
  490. MAX_PATH,
  491. MAX_PATH
  492. );
  493. if (!i) {
  494. i = Move( arg1, arg2, PromptOnOverwrite, a1info, is_dest_dir ) ;
  495. }
  496. return(LastRetCode = i) ;
  497. }
  498. /********************* START OF SPECIFICATION **************************/
  499. /* */
  500. /* SUBROUTINE NAME: MoveParse */
  501. /* */
  502. /* DESCRIPTIVE NAME: Move Parser */
  503. /* */
  504. /* FUNCTION: Move Internal Function Parser */
  505. /* */
  506. /* NOTES: This parser breaks up the command line information */
  507. /* into two parameters. */
  508. /* ( New routine for Relaese 1.2 ) @@5* */
  509. /* */
  510. /* ENTRY POINT: MoveParse */
  511. /* LINKAGE: NEAR */
  512. /* */
  513. /* INPUT: */
  514. /* n - the parse tree node containing the move command */
  515. /* */
  516. /* OUTPUT: ptr1 - pointer to [drive:][path]filename to be moved from */
  517. /* ptr2 - pointer to [path]filename to be moved to */
  518. /* a1info - pointer to cpyinfo which has arg1 fspec info */
  519. /* is_dest_dir - flag used by Move() */
  520. /* */
  521. /* EXIT-NORMAL: */
  522. /* Return SUCCESS to the caller. */
  523. /* */
  524. /* EXIT-ERROR: */
  525. /* Return FAILURE to the caller. */
  526. /* */
  527. /* EFFECTS: None. */
  528. /* */
  529. /* INTERNAL REFERENCES: */
  530. /* ROUTINES: */
  531. /* TokStr - Tokenize argument strings. */
  532. /* FullPath - Figure out the full path for a file. */
  533. /* SetFsSetSaveDir - Save current directory. */
  534. /* */
  535. /* EXTERNAL REFERENCES: */
  536. /* ROUTINES: */
  537. /* DOSQFILEMODE - Get file mode of the specified file/dir. */
  538. /* */
  539. /********************** END OF SPECIFICATION **************************/
  540. int MoveParse(n, promptokay, source, target , a1info, is_dest_dir, sizpath1, sizpath2)
  541. struct cmdnode *n ;
  542. BOOL *promptokay ;
  543. TCHAR *source ; /* Ptr to source file(s)/directory name */
  544. TCHAR *target ; /* Ptr to target file(s)/directory name */
  545. PCPYINFO* a1info ; /* Holds arg1 fspec information */
  546. unsigned int *is_dest_dir; /* to pass to move */
  547. unsigned sizpath1; /* size of source buffer */
  548. unsigned sizpath2; /* size of target buffer */
  549. { PCPYINFO SetFsSetSaveDir() ;
  550. TCHAR *arg1 ; /* Ptr to 1st arg */
  551. TCHAR *arg2 ; /* Ptr to 2nd arg */
  552. TCHAR *p1;
  553. TCHAR *p2;
  554. TCHAR arg22[MAX_PATH] ; /* Ptr to modified 2nd arg */
  555. unsigned i;
  556. unsigned concat_flag ;
  557. unsigned att ;
  558. /*509*/unsigned arg1len, arg2len;
  559. //
  560. // Get default prompt okay flag from COPYCMD variable. Allow
  561. // user to override with first token after command.
  562. //
  563. GetPromptOkay(MyGetEnvVarPtr(TEXT("COPYCMD")), promptokay);
  564. arg1 = TokStr(n->argptr, NULL, TS_NOFLAGS);
  565. if (GetPromptOkay(arg1, promptokay))
  566. while (*arg1++)
  567. ;
  568. /* Get arg1. If fail to get arg1, display error message. */
  569. if (!*arg1) {
  570. ErrorDisplayAndJump( MSG_BAD_SYNTAX );
  571. }
  572. /*509*/
  573. else if ( (arg1len = mystrlen(arg1)) > MAX_PATH) {
  574. ErrorDisplayAndJump( MSG_REN_INVAL_PATH_FILENAME );
  575. }
  576. /*CurDrvDir = current directory or directory which is specified in arg1*/
  577. /*509*/mystrcpy( arg1, StripQuotes( arg1 ) );
  578. if (((*a1info) = SetFsSetSaveDir(arg1)) == (PCPYINFO)FAILURE) {
  579. ErrorDisplayAndJump( DosErr );
  580. }
  581. /* */
  582. /* Get arg2 out of arg1 */
  583. arg2 = arg1 + arg1len + 1;
  584. if ( !(*arg2) ) {
  585. arg22[0] = SaveDir[0]; /* get current drive */
  586. arg22[1] = COLON;
  587. arg22[2] = NULLC;
  588. } else if (*(arg2 + mystrlen(arg2) + 1)) { /* @@5g */
  589. ErrorDisplayAndJump( MSG_BAD_SYNTAX );
  590. }
  591. /*509*/
  592. else if ( (arg2len = mystrlen(arg2)) > MAX_PATH) {
  593. ErrorDisplayAndJump( MSG_REN_INVAL_PATH_FILENAME );
  594. } else {
  595. /* If arg2 conatins a drive name, display an error message. */
  596. /*509*/
  597. mystrcpy
  598. ( arg2, StripQuotes( arg2 ) );
  599. // UNC names fix
  600. if ( ( *(arg2+1) != COLON ) && ( ! ( ( *arg2 == BSLASH ) && ( *(arg2+1) == BSLASH ) ) ) ) {
  601. arg22[0] = SaveDir[0]; /* get drive we're using */
  602. arg22[1] = COLON;
  603. arg22[2] = NULLC;
  604. if ((mystrlen(arg22) + mystrlen(arg2)+1) > MAX_PATH) {
  605. ErrorDisplayAndJump( MSG_REN_INVAL_PATH_FILENAME );
  606. }
  607. mystrcat( arg22, arg2 ) ;
  608. } else
  609. {
  610. mystrcpy(arg22,arg2) ;
  611. }
  612. }
  613. /* source = complete path for arg1 */
  614. if ( i = FullPath(source, arg1,sizpath1) ) {
  615. ErrorDisplayAndJump( MSG_REN_INVAL_PATH_FILENAME );
  616. }
  617. //
  618. // If preserve file name portion from arg1 as FullPath will map *. to * which
  619. // is not what the user wants.
  620. //
  621. if (!((*a1info)->buf->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  622. p1 = mystrrchr(source,PathChar) ;
  623. if (p1 != NULL)
  624. p1 += 1;
  625. else
  626. p1 = source;
  627. p2 = mystrrchr((*a1info)->fnptr,PathChar) ;
  628. if (p2 == NULL)
  629. p2 = (*a1info)->fnptr;
  630. mystrcpy(p1, p2);
  631. }
  632. /* target = complete path for arg2 */
  633. if ( i = FullPath(target, arg22,sizpath2) ) {
  634. ErrorDisplayAndJump( MSG_REN_INVAL_PATH_FILENAME );
  635. }
  636. concat_flag = FALSE ;
  637. DosErr = NO_ERROR ;
  638. SetLastError(NO_ERROR);
  639. *is_dest_dir = 0;
  640. if (*lastc(target) == PathChar) { /* test for last non DBCS character path char @@5@J3 */
  641. concat_flag = TRUE ;
  642. target[mystrlen(target)-1] = NULLC ;
  643. };
  644. if ( (att = GetFileAttributes( target )) != -1 ) {
  645. if (att & FILE_ATTRIBUTE_DIRECTORY) { /* if target is a directory, copy the file */
  646. /* name from source. */
  647. *is_dest_dir = 1;
  648. concat_flag = TRUE ;
  649. };
  650. } else if ( (DosErr = GetLastError()) &&
  651. ( ( DosErr != ERROR_FILE_NOT_FOUND ) &&
  652. ( DosErr != ERROR_PATH_NOT_FOUND ) ) ) {
  653. ErrorDisplayAndJump( DosErr );
  654. };
  655. if (concat_flag) {
  656. arg1 = mystrrchr(source,PathChar);
  657. if ((mystrlen(arg1) + mystrlen(target) + 1) > MAX_PATH) {
  658. ErrorDisplayAndJump( MSG_REN_INVAL_PATH_FILENAME );
  659. }
  660. mystrcat( target, arg1 ) ;
  661. };
  662. return(SUCCESS) ;
  663. }
  664. BOOL
  665. MyMoveFile(
  666. TCHAR *src,
  667. TCHAR *dst,
  668. BOOL *promptokay,
  669. BOOL *file_moved
  670. )
  671. {
  672. DWORD dwFlags;
  673. dwFlags = MOVEFILE_COPY_ALLOWED;
  674. if (!*promptokay) {
  675. dwFlags |= MOVEFILE_REPLACE_EXISTING;
  676. }
  677. *file_moved = FALSE;
  678. if (!MoveFileEx(src, dst, dwFlags)) {
  679. if (GetLastError() == ERROR_ALREADY_EXISTS) {
  680. switch (PromptUser(dst, MSG_MOVE_COPY_OVERWRITE, MSG_NOYESALL_RESPONSE_DATA)) {
  681. case 0: // No
  682. return TRUE;
  683. break;
  684. case 2: // All
  685. *promptokay = FALSE;
  686. default: // Yes
  687. dwFlags |= MOVEFILE_REPLACE_EXISTING;
  688. return(*file_moved = MoveFileEx(src, dst, dwFlags));
  689. break;
  690. }
  691. }
  692. return FALSE;
  693. } else {
  694. *file_moved = TRUE;
  695. return TRUE;
  696. }
  697. }
  698. /********************* START OF SPECIFICATION **************************/
  699. /* */
  700. /* SUBROUTINE NAME: Move */
  701. /* */
  702. /* DESCRIPTIVE NAME: Move Process */
  703. /* */
  704. /* FUNCTION: Moves one or more files from directory to another */
  705. /* directory on the same drive. If you prefer you can give */
  706. /* the files different names. */
  707. /* */
  708. /* NOTES: ( New routine for Release 1.2 ) @@5* */
  709. /* */
  710. /* ENTRY POINT: eMove */
  711. /* LINKAGE: NEAR */
  712. /* */
  713. /* INPUT: ptr1 - pointer to [drive:][path]filename to be moved from */
  714. /* ptr2 - pointer to [path]filename to be moved to */
  715. /* a1info - pointer to cpyinfo which has arg1 fspec info */
  716. /* is_dest_dir - from MoveParse() */
  717. /* */
  718. /* OUTPUT: None. */
  719. /* */
  720. /* EXIT-NORMAL: */
  721. /* Return Success to the caller. */
  722. /* */
  723. /* EXIT-ERROR: */
  724. /* Return error code from DosMove API. */
  725. /* */
  726. /* EFFECTS: None. */
  727. /* */
  728. /* INTERNAL REFERENCES: */
  729. /* ROUTINES: */
  730. /* ChangeDir - Change back to the original directory. */
  731. /* ffirst - Find the first file which matches the specified */
  732. /* file name that may contain * or ?. */
  733. /* fnext - Find the next file which matches the specified */
  734. /* file name that may contain * or ?. */
  735. /* findclose - Close the file with the specified file handle, */
  736. /* hnFirst which is given by ffirst or fnext. */
  737. /* PutStdErr - Displays an error message. */
  738. /* PutStdOut - Displays a message. */
  739. /* Wild - check if the arg contains wild card. */
  740. /* */
  741. /* EXTERNAL REFERENCES: */
  742. /* ROUTINES: */
  743. /* DOSMOVE - move directories and files. */
  744. /* */
  745. /********************** END OF SPECIFICATION **************************/
  746. int
  747. Move( arg1, arg2, promptokay, a1info, is_dest_dir )
  748. TCHAR *arg1 ; /* Ptr to 1st arg */
  749. TCHAR *arg2 ; /* Ptr to 2nd arg */
  750. BOOL promptokay ;
  751. PCPYINFO a1info ; /* Holds arg1 fspec info */
  752. unsigned int is_dest_dir; /* flag if set--> dest. is a dir */
  753. {
  754. unsigned attr ;
  755. unsigned i, n;
  756. unsigned long number_of_files_moved ;
  757. TCHAR Source[MAX_PATH]; /* path of source file */
  758. TCHAR bufdst[MAX_PATH]; /* path of destination file*/
  759. HANDLE hnFirst ; /* Findfirst handle */
  760. TCHAR *j, *k,*l; /* Tmp Ptr */
  761. unsigned wild_flag ; /* wildcard flag */
  762. BOOL file_moved;
  763. unsigned save_error ; /* Saved error code */
  764. TCHAR pcstr[3] ;
  765. unsigned rc;
  766. int retc;
  767. int how_many_src=0; /* =f_RET_DIR if dir; =0 if none; = <number matching src files> else */
  768. char type_format_dest=0; /* decide on how to format dest */
  769. char fl_move_once=0; /* if =1 execute move once only */
  770. how_many_src = f_how_many (arg1, (ULONG) (attr=FILE_ATTRIBUTE_ARCHIVE) );
  771. /**********************************************/
  772. /* Set flag whether arg1 contains */
  773. /* wildcard or not. */
  774. /**********************************************/
  775. pcstr[0] = STAR ;
  776. pcstr[1] = QMARK ;
  777. pcstr[2] = NULLC ;
  778. wild_flag = ((mystrcspn(arg1,pcstr))
  779. < mystrlen(arg1)) ;
  780. // Decide on what to do depending on: <1.multiple/single src; 2.is dest dir ?>
  781. if (how_many_src == f_RET_DIR) {
  782. if (is_dest_dir) {
  783. if (!MyMoveFile(arg1, arg2, &promptokay, &file_moved) ) {
  784. i = GetLastError();
  785. if (i == ERROR_ALREADY_EXISTS) {
  786. i = MSG_DUP_FILENAME_OR_NOT_FD;
  787. }
  788. ErrorDisplayAndJump( i );
  789. } else {
  790. RestoreSavedDirectory( );
  791. return(SUCCESS) ;
  792. }
  793. } else {
  794. type_format_dest = 2;
  795. fl_move_once = 1;
  796. }
  797. }
  798. else if (how_many_src > 1 ) {
  799. if (is_dest_dir) {
  800. type_format_dest = 1;
  801. fl_move_once = 0;
  802. } else {
  803. ErrorDisplayAndJump( MSG_MOVE_MULTIPLE_FAIL );
  804. }
  805. }
  806. else { // single source or source doesn't exist
  807. if (is_dest_dir) {
  808. type_format_dest = 1;
  809. fl_move_once = 1;
  810. } else {
  811. type_format_dest = 2;
  812. fl_move_once = 1;
  813. }
  814. }
  815. /**********************************************/
  816. /* Issue ffirst for a file name */
  817. /**********************************************/
  818. /*M006*/ if (!ffirst(arg1, attr = FILE_ATTRIBUTE_ARCHIVE, a1info->buf, &hnFirst )) {
  819. /**********************************************/
  820. /* Issue ffirst for a directory name */
  821. /**********************************************/
  822. rc = ffirst(arg1, attr = FILE_ATTRIBUTE_DIRECTORY, a1info->buf, &hnFirst ) ;
  823. if ( !rc) {
  824. /**********************************************/
  825. /* No file or directory which arg1 */
  826. /* specifies found */
  827. /**********************************************/
  828. if (!rc && DosErr == ERROR_NO_MORE_FILES) { /* @@5e */
  829. rc = ERROR_FILE_NOT_FOUND;
  830. } else if (wild_flag) {
  831. rc = MSG_DUP_FILENAME_OR_NOT_FD;
  832. } else {
  833. rc = DosErr;
  834. }
  835. ErrorDisplayAndJump( rc );
  836. }
  837. }
  838. number_of_files_moved = 0 ; /* Reset the counter to zero */
  839. save_error = NO_ERROR ; /* Reset error code to zero */
  840. mystrcpy(Source,arg1) ;
  841. j = mystrrchr(Source,PathChar) ;
  842. ++j; /* get to filename area */
  843. do {
  844. if (CtrlCSeen) {
  845. findclose(hnFirst) ;
  846. RestoreSavedDirectory( );
  847. return(FAILURE);
  848. }
  849. /**********************************************/
  850. /* build bufdst */
  851. /**********************************************/
  852. mystrcpy(j,a1info->buf->cFileName) ;
  853. mystrcpy(bufdst,arg2);
  854. if (type_format_dest == 1 ) {
  855. l = mystrrchr(bufdst,PathChar);
  856. ++l;
  857. mystrcpy(l,a1info->buf->cFileName) ;
  858. if ((mystrlen(bufdst) ) > MAX_PATH) {
  859. ErrorDisplayAndJump( MSG_REN_INVAL_PATH_FILENAME ) ;
  860. }
  861. }
  862. /**********************************************/
  863. /* check to see if filename is legal */
  864. /**********************************************/
  865. {
  866. TCHAR TempBuffer[MAX_PATH];
  867. DWORD Length;
  868. Length = GetFullPathName( bufdst, MAX_PATH, TempBuffer, NULL );
  869. if (Length == 0 || Length >= MAX_PATH) {
  870. goto badness;
  871. }
  872. n = _tcslen( TempBuffer );
  873. Length = GetFullPathName( Source, MAX_PATH, TempBuffer, NULL );
  874. if (Length == 0 || Length >= MAX_PATH) {
  875. goto badness;
  876. }
  877. if (!GreatestLength( TempBuffer, &i))
  878. continue;
  879. i -= _tcslen( TempBuffer );
  880. }
  881. if (n + i > MAX_PATH) {
  882. i = ERROR_FILENAME_EXCED_RANGE;
  883. goto badness2;
  884. }
  885. /**********************************************/
  886. /* Move a file or directory */
  887. /**********************************************/
  888. if (!MyMoveFile(Source, bufdst, &promptokay, &file_moved)) {
  889. /**********************************************/
  890. /* Move fails */
  891. /**********************************************/
  892. badness:
  893. i = GetLastError();
  894. badness2:
  895. if (i == ERROR_ALREADY_EXISTS) {
  896. i = MSG_DUP_FILENAME_OR_NOT_FD;
  897. }
  898. save_error = i ; /* Save the error code */
  899. PutStdErr(i, NOARGS); /* Put out an error message */
  900. i = mystrlen(bufdst) ;
  901. if ( bufdst[--i] == DOT ) { /* @@5a */
  902. bufdst[i] = 0 ; /* @@5a */
  903. } /* @@5a */
  904. /* @@5a */
  905. /*509*/if (!_tcsicmp(Source,bufdst)) { /* @@5a */
  906. break ; /* @@5a */
  907. } /* @@5a */
  908. } else
  909. if (file_moved) {
  910. number_of_files_moved += 1;
  911. if ( wild_flag ) { /* If wild card is used */
  912. cmd_printf(Fmt17,Source); /* display the file name*/
  913. }
  914. }
  915. if (fl_move_once)
  916. break;
  917. } while (fnext(a1info->buf, attr, hnFirst ));
  918. /**********************************************/
  919. /* No more files to be found */
  920. /**********************************************/
  921. findclose(hnFirst) ;
  922. RestoreSavedDirectory( );
  923. /**********************************************/
  924. /* Display the total number of file(s) moved */
  925. /**********************************************/
  926. if ( (a1info->buf->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 ) {
  927. PutStdOut(MSG_FILES_MOVED, ONEARG,
  928. argstr1(TEXT("%9d"), (unsigned long)number_of_files_moved)) ;
  929. }
  930. return(save_error == NO_ERROR ? SUCCESS : FAILURE) ;
  931. }
  932. int
  933. eTitle (
  934. IN struct cmdnode *pcmdnode
  935. ) {
  936. LPTSTR NewTitle;
  937. if (!pszTitleCur) {
  938. pszTitleCur = HeapAlloc(GetProcessHeap(), 0, MAX_PATH*sizeof(TCHAR) + 2*sizeof(TCHAR));
  939. if (pszTitleCur == NULL) {
  940. PutStdErr(ERROR_NOT_ENOUGH_MEMORY, NOARGS);
  941. return( FAILURE );
  942. }
  943. }
  944. if (mystrlen(pcmdnode->argptr) >= MAX_PATH) {
  945. PutStdErr(ERROR_NOT_ENOUGH_MEMORY, NOARGS);
  946. return( FAILURE );
  947. }
  948. NewTitle = EatWS(pcmdnode->argptr, NULL);
  949. if (NewTitle && *NewTitle) {
  950. mystrcpy(pszTitleCur,NewTitle);
  951. }
  952. SetConsoleTitle(pszTitleCur);
  953. //
  954. // This insures that ResetConTitle does not undo what
  955. // we have just done
  956. //
  957. fTitleChanged = FALSE;
  958. return( SUCCESS );
  959. }
  960. /*** eStart - Entry point for Start routine
  961. *
  962. * Purpose:
  963. * to call Start and pass it a pointer to the command line
  964. * arguments
  965. *
  966. * Args:
  967. * a pointer to the command node structure
  968. *
  969. */
  970. int eStart( n ) /* @@ */
  971. struct cmdnode *n; /* @@ */
  972. { /* @@ */
  973. DBG_UNREFERENCED_PARAMETER( n );
  974. return( Start(n->argptr) );
  975. } /* @@ */