2 * MOVE.C - move internal command.
7 * 14-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
10 * 18-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
12 * Preliminary version!!!
14 * 20-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
17 * 27-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
18 * Added help text ("/?").
19 * Added more error checks.
21 * 03-Feb-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
24 * 30-Apr-2005 (Magnus Olsen) <magnus@greatlord.com>)
25 * Remove all hardcode string to En.rc
27 * 24-Jun-2005 (Brandon Turner) <turnerb7@msu.edu>)
28 * Fixed bug to allow MS style wildcards + code clean up
35 #ifdef INCLUDE_CMD_MOVE
39 MOVE_NOTHING
= 0x001, /* /N */
40 MOVE_OVER_YES
= 0x002, /* /Y */
41 MOVE_OVER_NO
= 0x004, /* /-Y */
45 { /* Move status flags */
46 MOVE_SOURCE_IS_DIR
= 0x001,
47 MOVE_SOURCE_IS_FILE
= 0x002,
48 MOVE_DEST_IS_DIR
= 0x004,
49 MOVE_DEST_IS_FILE
= 0x008,
50 MOVE_SOURCE_HAS_WILD
= 0x010, /* source has wildcard */
51 MOVE_SRC_CURRENT_IS_DIR
= 0x020, /* source is file but at the current round we found a directory */
52 MOVE_DEST_EXISTS
= 0x040,
53 MOVE_PATHS_ON_DIF_VOL
= 0x080 /* source and destination paths are on different volume */
56 static INT
MoveOverwrite (LPTSTR fn
)
58 /*ask the user if they want to override*/
59 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
61 LoadString(CMD_ModuleHandle
, STRING_MOVE_HELP1
, szMsg
, RC_STRING_MAX_SIZE
);
62 ConOutPrintf(szMsg
,fn
);
63 res
= FilePromptYNA (_T(""));
67 void GetDirectory (LPTSTR wholepath
, LPTSTR directory
, BOOL CheckExisting
)
69 /* returns only directory part of path with backslash */
70 /* TODO: make code unc aware */
71 /* Is there a better alternative to this? */
73 if (CheckExisting
&& IsExistingDirectory(wholepath
))
75 _tcscpy(directory
, wholepath
);
77 else if ((last
= _tcsrchr(wholepath
,_T('\\'))) != NULL
)
79 _tcsncpy(directory
, wholepath
, last
- wholepath
+ 1);
80 directory
[last
- wholepath
+ 1] = 0;
84 GetRootPath(wholepath
,directory
, MAX_PATH
);
89 INT
cmd_move (LPTSTR cmd
, LPTSTR param
)
91 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
94 TCHAR szDestPath
[MAX_PATH
];
95 TCHAR szFullDestPath
[MAX_PATH
];
96 TCHAR szSrcDirPath
[MAX_PATH
];
97 TCHAR szSrcPath
[MAX_PATH
];
98 TCHAR szFullSrcPath
[MAX_PATH
];
101 WIN32_FIND_DATA findBuffer
;
104 /* used only when source and destination directories are on different volume*/
106 WIN32_FIND_DATA findDestBuffer
;
107 TCHAR szMoveDest
[MAX_PATH
];
108 TCHAR szMoveSrc
[MAX_PATH
];
109 LPTSTR pszDestDirPointer
;
110 LPTSTR pszSrcDirPointer
;
117 DWORD dwMoveFlags
= 0;
118 DWORD dwMoveStatusFlags
= 0;
121 if (!_tcsncmp (param
, _T("/?"), 2))
124 ConOutPuts (_T("Moves files and renames files and directories.\n\n"
125 "To move one or more files:\n"
126 "MOVE [/N][/Y|/-Y][drive:][path]filename1[,...] destination\n"
128 "To rename a directory:\n"
129 "MOVE [/N][/Y|/-Y][drive:][path]dirname1 dirname2\n"
131 " [drive:][path]filename1 Specifies the location and name of the file\n"
132 " or files you want to move.\n"
133 " /N Nothing. Don everthing but move files or direcories.\n"
138 ConOutResPaging(TRUE
,STRING_MOVE_HELP2
);
144 arg
= split (param
, &argc
, FALSE
);
148 for (i
= 0; i
< argc
; i
++)
150 if (*arg
[i
] == _T('/'))
152 if (_tcslen(arg
[i
]) >= 2)
154 switch (_totupper(arg
[i
][1]))
157 dwFlags
|= MOVE_NOTHING
;
161 dwFlags
|= MOVE_OVER_YES
;
165 dwFlags
|= MOVE_OVER_NO
;
175 /* there must be at least two pathspecs */
176 error_req_param_missing ();
180 /* check for wildcards in source and destination */
181 if (_tcschr (arg
[argc
- 1], _T('*')) != NULL
|| _tcschr (arg
[argc
- 1], _T('?')) != NULL
)
183 /* '*'/'?' in dest, this doesnt happen. give folder name instead*/
184 error_invalid_parameter_format(arg
[argc
- 1]);
187 if (_tcschr (arg
[argc
- 2], _T('*')) != NULL
|| _tcschr (arg
[argc
- 2], _T('?')) != NULL
)
189 dwMoveStatusFlags
|= MOVE_SOURCE_HAS_WILD
;
193 /* get destination */
194 GetFullPathName (arg
[argc
- 1], MAX_PATH
, szDestPath
, NULL
);
196 DebugPrintf (_T("Destination: %s\n"), szDestPath
);
199 /* get source folder */
200 GetDirectory(arg
[argc
- 2], szSrcDirPath
, 1);
201 GetFullPathName(szSrcDirPath
, MAX_PATH
, szSrcPath
, &pszFile
);
202 _tcscpy(szSrcDirPath
,szSrcPath
);
203 /* we need following check to see if source happens to be directly given directory
204 and if it is then rip off last directory part so that there won't be any clashes with codes after this point */
205 GetFullPathName(arg
[argc
- 2], MAX_PATH
, szSrcPath
, &pszFile
);
206 if (_tcscmp(szSrcDirPath
,szSrcPath
) == 0)
207 szSrcDirPath
[pszFile
- szSrcPath
] = _T('\0');
209 DebugPrintf (_T("Source Folder: %s\n"), szSrcDirPath
);
212 hFile
= FindFirstFile (arg
[argc
- 2], &findBuffer
);
213 if (hFile
== INVALID_HANDLE_VALUE
)
215 ErrorMessage (GetLastError (), arg
[argc
- 2]);
221 /* check for special cases "." and ".." and if found skip them */
224 (_tcscmp(findBuffer
.cFileName
,_T(".")) == 0 ||
225 _tcscmp(findBuffer
.cFileName
,_T("..")) == 0))
226 FoundFile
= FindNextFile (hFile
, &findBuffer
);
230 /* what? we don't have anything to move? */
231 error_file_not_found();
238 _tcscpy(szSrcPath
,szSrcDirPath
);
239 /*check to see if there is an ending slash, if not add one*/
240 if(szSrcPath
[_tcslen(szSrcPath
) - 1] != _T('\\'))
241 _tcscat (szSrcPath
, _T("\\"));
242 _tcscat(szSrcPath
,findBuffer
.cFileName
);
244 DebugPrintf (_T("Source Path: %s\n"), szSrcPath
);
246 /* check if there can be found files as files have first priority */
247 if (IsExistingFile(szSrcPath
)) dwMoveStatusFlags
|= MOVE_SOURCE_IS_FILE
;
248 else dwMoveStatusFlags
|= MOVE_SOURCE_IS_DIR
;
249 while(OnlyOneFile
&& FindNextFile(hFile
,&findBuffer
))
251 _tcscpy(szSrcPath
,szSrcDirPath
);
252 if(szSrcPath
[_tcslen(szSrcPath
) - 1] != _T('\\'))
253 _tcscat (szSrcPath
, _T("\\"));
254 _tcscat(szSrcPath
,findBuffer
.cFileName
);
255 if (IsExistingFile(szSrcPath
))
257 ConOutPrintf(_T(""));
258 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_FILE
) OnlyOneFile
= FALSE
;
260 { /* this has been done this way so that we don't disturb other settings if they have been set before this */
261 dwMoveStatusFlags
|= MOVE_SOURCE_IS_FILE
;
262 dwMoveStatusFlags
&= ~MOVE_SOURCE_IS_DIR
;
269 DebugPrintf(_T("Do we have only one file: %s\n"), OnlyOneFile
? _T("TRUE") : _T("FALSE"));
272 /* we have to start again to be sure we don't miss any files or folders*/
273 hFile
= FindFirstFile (arg
[argc
- 2], &findBuffer
);
274 if (hFile
== INVALID_HANDLE_VALUE
)
276 ErrorMessage (GetLastError (), arg
[argc
- 2]);
282 /* check for special cases "." and ".." and if found skip them */
285 (_tcscmp(findBuffer
.cFileName
,_T(".")) == 0 ||
286 _tcscmp(findBuffer
.cFileName
,_T("..")) == 0))
287 FoundFile
= FindNextFile (hFile
, &findBuffer
);
291 /* huh? somebody removed files and/or folders which were there */
292 error_file_not_found();
298 /* check if source and destination paths are on different volumes */
299 if (szSrcPath
[0] != szDestPath
[0])
300 dwMoveStatusFlags
|= MOVE_PATHS_ON_DIF_VOL
;
306 DebugPrintf (_T("Found file/directory: %s\n"), findBuffer
.cFileName
);
310 dwMoveStatusFlags
&= ~MOVE_DEST_IS_FILE
&
312 ~MOVE_SRC_CURRENT_IS_DIR
&
314 _tcscpy(szFullSrcPath
,szSrcDirPath
);
315 if(szFullSrcPath
[_tcslen(szFullSrcPath
) - 1] != _T('\\'))
316 _tcscat (szFullSrcPath
, _T("\\"));
317 _tcscat(szFullSrcPath
,findBuffer
.cFileName
);
318 _tcscpy(szSrcPath
, szFullSrcPath
);
320 if (IsExistingDirectory(szSrcPath
))
322 /* source is directory */
324 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_FILE
)
326 dwMoveStatusFlags
|= MOVE_SRC_CURRENT_IS_DIR
; /* source is file but at the current round we found a directory */
330 DebugPrintf (_T("Source is dir: %s\n"), szSrcPath
);
332 dwMoveFlags
= MOVEFILE_REPLACE_EXISTING
| MOVEFILE_WRITE_THROUGH
| MOVEFILE_COPY_ALLOWED
;
335 /* if source is file we don't need to do anything special */
337 if (IsExistingDirectory(szDestPath
))
339 /* destination is existing directory */
341 DebugPrintf (_T("Destination is directory: %s\n"), szDestPath
);
344 dwMoveStatusFlags
|= MOVE_DEST_IS_DIR
;
346 /*build the dest string(accounts for *)*/
347 _tcscpy (szFullDestPath
, szDestPath
);
348 /*check to see if there is an ending slash, if not add one*/
349 if(szFullDestPath
[_tcslen(szFullDestPath
) - 1] != _T('\\'))
350 _tcscat (szFullDestPath
, _T("\\"));
351 _tcscat (szFullDestPath
, findBuffer
.cFileName
);
353 if (IsExistingFile(szFullDestPath
) || IsExistingDirectory(szFullDestPath
))
354 dwMoveStatusFlags
|= MOVE_DEST_EXISTS
;
356 dwMoveFlags
|= MOVEFILE_REPLACE_EXISTING
| MOVEFILE_WRITE_THROUGH
| MOVEFILE_COPY_ALLOWED
;
359 if (IsExistingFile(szDestPath
))
361 /* destination is a file */
363 DebugPrintf (_T("Destination is file: %s\n"), szDestPath
);
366 dwMoveStatusFlags
|= MOVE_DEST_IS_FILE
| MOVE_DEST_EXISTS
;
367 _tcscpy (szFullDestPath
, szDestPath
);
369 dwMoveFlags
|= MOVEFILE_REPLACE_EXISTING
| MOVEFILE_WRITE_THROUGH
| MOVEFILE_COPY_ALLOWED
;
374 DebugPrintf(_T("Move Status Flags: 0x%X\n"),dwMoveStatusFlags
);
377 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_DIR
&&
378 dwMoveStatusFlags
& MOVE_DEST_IS_DIR
&&
379 dwMoveStatusFlags
& MOVE_SOURCE_HAS_WILD
)
381 /* We are not allowed to have existing source and destination dir when there is wildcard in source */
388 if (!(dwMoveStatusFlags
& (MOVE_DEST_IS_FILE
| MOVE_DEST_IS_DIR
)))
390 /* destination doesn't exist */
391 _tcscpy (szFullDestPath
, szDestPath
);
392 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_FILE
) dwMoveStatusFlags
|= MOVE_DEST_IS_FILE
;
393 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_DIR
) dwMoveStatusFlags
|= MOVE_DEST_IS_DIR
;
395 dwMoveFlags
|= MOVEFILE_REPLACE_EXISTING
| MOVEFILE_WRITE_THROUGH
| MOVEFILE_COPY_ALLOWED
;
398 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_FILE
&&
399 dwMoveStatusFlags
& MOVE_DEST_IS_FILE
&&
402 /*source has many files but there is only one destination file*/
403 error_invalid_parameter_format(arg
[argc
- 1]);
409 /*checks to make sure user wanted/wants the override*/
410 if((dwFlags
& MOVE_OVER_NO
) &&
411 (dwMoveStatusFlags
& MOVE_DEST_EXISTS
))
413 if(!(dwFlags
& MOVE_OVER_YES
) &&
414 (dwMoveStatusFlags
& MOVE_DEST_EXISTS
))
415 nOverwrite
= MoveOverwrite (szFullDestPath
);
416 if (nOverwrite
== PROMPT_NO
|| nOverwrite
== PROMPT_BREAK
)
418 if (nOverwrite
== PROMPT_ALL
)
419 dwFlags
|= MOVE_OVER_YES
;
422 ConOutPrintf (_T("%s => %s "), szSrcPath
, szFullDestPath
);
424 /* are we really supposed to do something */
425 if (dwFlags
& MOVE_NOTHING
)
429 if (!(dwMoveStatusFlags
& MOVE_SOURCE_IS_DIR
&&
430 dwMoveStatusFlags
& MOVE_PATHS_ON_DIF_VOL
))
431 /* we aren't moving source folder to different drive */
432 MoveStatus
= MoveFileEx (szSrcPath
, szFullDestPath
, dwMoveFlags
);
434 { /* we are moving source folder to different drive */
435 _tcscpy(szMoveDest
, szFullDestPath
);
436 _tcscpy(szMoveSrc
, szSrcPath
);
437 DeleteFile(szMoveDest
);
438 MoveStatus
= CreateDirectory(szMoveDest
, NULL
); /* we use default security settings */
441 _tcscat(szMoveDest
,_T("\\"));
442 _tcscat(szMoveSrc
,_T("\\"));
444 pszDestDirPointer
= szMoveDest
+ _tcslen(szMoveDest
);
445 pszSrcDirPointer
= szMoveSrc
+ _tcslen(szMoveSrc
);
446 _tcscpy(pszSrcDirPointer
,_T("*.*"));
447 hDestFile
= FindFirstFile(szMoveSrc
, &findDestBuffer
);
448 if (hDestFile
== INVALID_HANDLE_VALUE
)
452 BOOL FirstTime
= TRUE
;
460 FoundFile
= FindNextFile (hDestFile
, &findDestBuffer
);
463 { /* Nothing to do in this folder so we stop working on it */
464 FindClose(hDestFile
);
465 (pszSrcDirPointer
)--;
466 (pszDestDirPointer
)--;
467 _tcscpy(pszSrcDirPointer
,_T(""));
468 _tcscpy(pszDestDirPointer
,_T(""));
471 TCHAR szTempPath
[MAX_PATH
];
474 FoundFile
= TRUE
; /* we need to continue our seek for files */
476 RemoveDirectory(szMoveSrc
);
477 GetDirectory(szMoveSrc
,szTempPath
,0);
478 nDiff
= _tcslen(szMoveSrc
) - _tcslen(szTempPath
);
479 pszSrcDirPointer
= pszSrcDirPointer
- nDiff
;
480 _tcscpy(pszSrcDirPointer
,_T(""));
481 GetDirectory(szMoveDest
,szTempPath
,0);
482 nDiff
= _tcslen(szMoveDest
) - _tcslen(szTempPath
);
483 pszDestDirPointer
= pszDestDirPointer
- nDiff
;
484 _tcscpy(pszDestDirPointer
,_T(""));
485 if(szMoveSrc
[_tcslen(szMoveSrc
) - 1] != _T('\\'))
486 _tcscat (szMoveSrc
, _T("\\"));
487 if(szMoveDest
[_tcslen(szMoveDest
) - 1] != _T('\\'))
488 _tcscat (szMoveDest
, _T("\\"));
489 pszDestDirPointer
= szMoveDest
+ _tcslen(szMoveDest
);
490 pszSrcDirPointer
= szMoveSrc
+ _tcslen(szMoveSrc
);
491 _tcscpy(pszSrcDirPointer
,_T("*.*"));
492 hDestFile
= FindFirstFile(szMoveSrc
, &findDestBuffer
);
493 if (hDestFile
== INVALID_HANDLE_VALUE
)
499 MoveStatus
= TRUE
; /* we moved everything so lets tell user about it */
500 RemoveDirectory(szMoveSrc
);
505 /* if we find "." or ".." we'll skip them */
506 if (_tcscmp(findDestBuffer
.cFileName
,_T(".")) == 0 ||
507 _tcscmp(findDestBuffer
.cFileName
,_T("..")) == 0)
510 _tcscpy(pszSrcDirPointer
, findDestBuffer
.cFileName
);
511 _tcscpy(pszDestDirPointer
, findDestBuffer
.cFileName
);
512 if (IsExistingFile(szMoveSrc
))
514 FoundFile
= CopyFile(szMoveSrc
, szMoveDest
, FALSE
);
515 if (!FoundFile
) continue;
516 DeleteFile(szMoveSrc
);
520 FindClose(hDestFile
);
521 CreateDirectory(szMoveDest
, NULL
);
522 _tcscat(szMoveDest
,_T("\\"));
523 _tcscat(szMoveSrc
,_T("\\"));
525 pszDestDirPointer
= szMoveDest
+ _tcslen(szMoveDest
);
526 pszSrcDirPointer
= szMoveSrc
+ _tcslen(szMoveSrc
);
527 _tcscpy(pszSrcDirPointer
,_T("*.*"));
528 hDestFile
= FindFirstFile(szMoveSrc
, &findDestBuffer
);
529 if (hDestFile
== INVALID_HANDLE_VALUE
)
541 LoadString(CMD_ModuleHandle
, STRING_MOVE_ERROR1
, szMsg
, RC_STRING_MAX_SIZE
);
543 LoadString(CMD_ModuleHandle
, STRING_MOVE_ERROR2
, szMsg
, RC_STRING_MAX_SIZE
);
547 while ((!OnlyOneFile
|| dwMoveStatusFlags
& MOVE_SRC_CURRENT_IS_DIR
) &&
548 !(dwMoveStatusFlags
& MOVE_SOURCE_IS_DIR
) &&
549 FindNextFile (hFile
, &findBuffer
));
556 #endif /* INCLUDE_CMD_MOVE */