2 * MOVE.C - move internal command.
7 * 14-Dec-1998 (Eric Kohl)
10 * 18-Jan-1999 (Eric Kohl)
12 * Preliminary version!!!
14 * 20-Jan-1999 (Eric Kohl)
17 * 27-Jan-1999 (Eric Kohl)
18 * Added help text ("/?").
19 * Added more error checks.
21 * 03-Feb-1999 (Eric Kohl)
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
34 #ifdef INCLUDE_CMD_MOVE
38 MOVE_NOTHING
= 0x001, /* /N */
39 MOVE_OVER_YES
= 0x002, /* /Y */
40 MOVE_OVER_NO
= 0x004, /* /-Y */
44 { /* Move status flags */
45 MOVE_SOURCE_IS_DIR
= 0x001,
46 MOVE_SOURCE_IS_FILE
= 0x002,
47 MOVE_DEST_IS_DIR
= 0x004,
48 MOVE_DEST_IS_FILE
= 0x008,
49 MOVE_SOURCE_HAS_WILD
= 0x010, /* source has wildcard */
50 MOVE_SRC_CURRENT_IS_DIR
= 0x020, /* source is file but at the current round we found a directory */
51 MOVE_DEST_EXISTS
= 0x040,
52 MOVE_PATHS_ON_DIF_VOL
= 0x080 /* source and destination paths are on different volume */
55 static INT
MoveOverwrite (LPTSTR fn
)
57 /*ask the user if they want to override*/
59 ConOutResPrintf(STRING_MOVE_HELP1
, fn
);
60 res
= FilePromptYNA (0);
64 void GetDirectory (LPTSTR wholepath
, LPTSTR directory
, BOOL CheckExisting
)
66 /* returns only directory part of path with backslash */
67 /* TODO: make code unc aware */
68 /* Is there a better alternative to this? */
70 if (CheckExisting
&& IsExistingDirectory(wholepath
))
72 _tcscpy(directory
, wholepath
);
74 else if ((last
= _tcsrchr(wholepath
,_T('\\'))) != NULL
)
76 _tcsncpy(directory
, wholepath
, last
- wholepath
+ 1);
77 directory
[last
- wholepath
+ 1] = 0;
81 GetRootPath(wholepath
,directory
, MAX_PATH
);
86 INT
cmd_move (LPTSTR cmd
, LPTSTR param
)
90 TCHAR szDestPath
[MAX_PATH
];
91 TCHAR szFullDestPath
[MAX_PATH
];
92 TCHAR szSrcDirPath
[MAX_PATH
];
93 TCHAR szSrcPath
[MAX_PATH
];
94 TCHAR szFullSrcPath
[MAX_PATH
];
97 WIN32_FIND_DATA findBuffer
;
100 /* used only when source and destination directories are on different volume*/
102 WIN32_FIND_DATA findDestBuffer
;
103 TCHAR szMoveDest
[MAX_PATH
];
104 TCHAR szMoveSrc
[MAX_PATH
];
105 LPTSTR pszDestDirPointer
;
106 LPTSTR pszSrcDirPointer
;
113 DWORD dwMoveFlags
= 0;
114 DWORD dwMoveStatusFlags
= 0;
117 if (!_tcsncmp (param
, _T("/?"), 2))
120 ConOutPuts (_T("Moves files and renames files and directories.\n\n"
121 "To move one or more files:\n"
122 "MOVE [/N][/Y|/-Y][drive:][path]filename1[,...] destination\n"
124 "To rename a directory:\n"
125 "MOVE [/N][/Y|/-Y][drive:][path]dirname1 dirname2\n"
127 " [drive:][path]filename1 Specifies the location and name of the file\n"
128 " or files you want to move.\n"
129 " /N Nothing. Don everthing but move files or direcories.\n"
134 ConOutResPaging(TRUE
,STRING_MOVE_HELP2
);
140 arg
= split (param
, &argc
, FALSE
);
144 for (i
= 0; i
< argc
; i
++)
146 if (*arg
[i
] == _T('/'))
148 if (_tcslen(arg
[i
]) >= 2)
150 switch (_totupper(arg
[i
][1]))
153 dwFlags
|= MOVE_NOTHING
;
157 dwFlags
|= MOVE_OVER_YES
;
161 dwFlags
|= MOVE_OVER_NO
;
171 /* there must be at least two pathspecs */
172 error_req_param_missing ();
176 /* check for wildcards in source and destination */
177 if (_tcschr (arg
[argc
- 1], _T('*')) != NULL
|| _tcschr (arg
[argc
- 1], _T('?')) != NULL
)
179 /* '*'/'?' in dest, this doesnt happen. give folder name instead*/
180 error_invalid_parameter_format(arg
[argc
- 1]);
183 if (_tcschr (arg
[argc
- 2], _T('*')) != NULL
|| _tcschr (arg
[argc
- 2], _T('?')) != NULL
)
185 dwMoveStatusFlags
|= MOVE_SOURCE_HAS_WILD
;
189 /* get destination */
190 GetFullPathName (arg
[argc
- 1], MAX_PATH
, szDestPath
, NULL
);
191 TRACE ("Destination: %s\n", debugstr_aw(szDestPath
));
193 /* get source folder */
194 GetDirectory(arg
[argc
- 2], szSrcDirPath
, 1);
195 GetFullPathName(szSrcDirPath
, MAX_PATH
, szSrcPath
, &pszFile
);
196 _tcscpy(szSrcDirPath
,szSrcPath
);
197 /* we need following check to see if source happens to be directly given directory
198 and if it is then rip off last directory part so that there won't be any clashes with codes after this point */
199 GetFullPathName(arg
[argc
- 2], MAX_PATH
, szSrcPath
, &pszFile
);
200 if (_tcscmp(szSrcDirPath
,szSrcPath
) == 0)
201 szSrcDirPath
[pszFile
- szSrcPath
] = _T('\0');
202 TRACE ("Source Folder: %s\n", debugstr_aw(szSrcDirPath
));
204 hFile
= FindFirstFile (arg
[argc
- 2], &findBuffer
);
205 if (hFile
== INVALID_HANDLE_VALUE
)
207 ErrorMessage (GetLastError (), arg
[argc
- 2]);
213 /* check for special cases "." and ".." and if found skip them */
216 (_tcscmp(findBuffer
.cFileName
,_T(".")) == 0 ||
217 _tcscmp(findBuffer
.cFileName
,_T("..")) == 0))
218 FoundFile
= FindNextFile (hFile
, &findBuffer
);
222 /* what? we don't have anything to move? */
223 error_file_not_found();
230 _tcscpy(szSrcPath
,szSrcDirPath
);
231 /*check to see if there is an ending slash, if not add one*/
232 if(szSrcPath
[_tcslen(szSrcPath
) - 1] != _T('\\'))
233 _tcscat (szSrcPath
, _T("\\"));
234 _tcscat(szSrcPath
,findBuffer
.cFileName
);
235 TRACE ("Source Path: %s\n", debugstr_aw(szSrcPath
));
236 /* check if there can be found files as files have first priority */
237 if (IsExistingFile(szSrcPath
)) dwMoveStatusFlags
|= MOVE_SOURCE_IS_FILE
;
238 else dwMoveStatusFlags
|= MOVE_SOURCE_IS_DIR
;
239 while(OnlyOneFile
&& FindNextFile(hFile
,&findBuffer
))
241 _tcscpy(szSrcPath
,szSrcDirPath
);
242 if(szSrcPath
[_tcslen(szSrcPath
) - 1] != _T('\\'))
243 _tcscat (szSrcPath
, _T("\\"));
244 _tcscat(szSrcPath
,findBuffer
.cFileName
);
245 if (IsExistingFile(szSrcPath
))
247 ConOutPrintf(_T(""));
248 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_FILE
) OnlyOneFile
= FALSE
;
250 { /* this has been done this way so that we don't disturb other settings if they have been set before this */
251 dwMoveStatusFlags
|= MOVE_SOURCE_IS_FILE
;
252 dwMoveStatusFlags
&= ~MOVE_SOURCE_IS_DIR
;
258 TRACE ("Do we have only one file: %s\n", OnlyOneFile
? "TRUE" : "FALSE");
260 /* we have to start again to be sure we don't miss any files or folders*/
261 hFile
= FindFirstFile (arg
[argc
- 2], &findBuffer
);
262 if (hFile
== INVALID_HANDLE_VALUE
)
264 ErrorMessage (GetLastError (), arg
[argc
- 2]);
270 /* check for special cases "." and ".." and if found skip them */
273 (_tcscmp(findBuffer
.cFileName
,_T(".")) == 0 ||
274 _tcscmp(findBuffer
.cFileName
,_T("..")) == 0))
275 FoundFile
= FindNextFile (hFile
, &findBuffer
);
279 /* huh? somebody removed files and/or folders which were there */
280 error_file_not_found();
286 /* check if source and destination paths are on different volumes */
287 if (szSrcPath
[0] != szDestPath
[0])
288 dwMoveStatusFlags
|= MOVE_PATHS_ON_DIF_VOL
;
293 TRACE ("Found file/directory: %s\n", debugstr_aw(findBuffer
.cFileName
));
296 dwMoveStatusFlags
&= ~MOVE_DEST_IS_FILE
&
298 ~MOVE_SRC_CURRENT_IS_DIR
&
300 _tcscpy(szFullSrcPath
,szSrcDirPath
);
301 if(szFullSrcPath
[_tcslen(szFullSrcPath
) - 1] != _T('\\'))
302 _tcscat (szFullSrcPath
, _T("\\"));
303 _tcscat(szFullSrcPath
,findBuffer
.cFileName
);
304 _tcscpy(szSrcPath
, szFullSrcPath
);
306 if (IsExistingDirectory(szSrcPath
))
308 /* source is directory */
310 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_FILE
)
312 dwMoveStatusFlags
|= MOVE_SRC_CURRENT_IS_DIR
; /* source is file but at the current round we found a directory */
315 TRACE ("Source is dir: %s\n", debugstr_aw(szSrcPath
));
316 dwMoveFlags
= MOVEFILE_REPLACE_EXISTING
| MOVEFILE_WRITE_THROUGH
| MOVEFILE_COPY_ALLOWED
;
319 /* if source is file we don't need to do anything special */
321 if (IsExistingDirectory(szDestPath
))
323 /* destination is existing directory */
324 TRACE ("Destination is directory: %s\n", debugstr_aw(szDestPath
));
326 dwMoveStatusFlags
|= MOVE_DEST_IS_DIR
;
328 /*build the dest string(accounts for *)*/
329 _tcscpy (szFullDestPath
, szDestPath
);
330 /*check to see if there is an ending slash, if not add one*/
331 if(szFullDestPath
[_tcslen(szFullDestPath
) - 1] != _T('\\'))
332 _tcscat (szFullDestPath
, _T("\\"));
333 _tcscat (szFullDestPath
, findBuffer
.cFileName
);
335 if (IsExistingFile(szFullDestPath
) || IsExistingDirectory(szFullDestPath
))
336 dwMoveStatusFlags
|= MOVE_DEST_EXISTS
;
338 dwMoveFlags
|= MOVEFILE_REPLACE_EXISTING
| MOVEFILE_WRITE_THROUGH
| MOVEFILE_COPY_ALLOWED
;
341 if (IsExistingFile(szDestPath
))
343 /* destination is a file */
344 TRACE ("Destination is file: %s\n", debugstr_aw(szDestPath
));
346 dwMoveStatusFlags
|= MOVE_DEST_IS_FILE
| MOVE_DEST_EXISTS
;
347 _tcscpy (szFullDestPath
, szDestPath
);
349 dwMoveFlags
|= MOVEFILE_REPLACE_EXISTING
| MOVEFILE_WRITE_THROUGH
| MOVEFILE_COPY_ALLOWED
;
353 TRACE ("Move Status Flags: 0x%X\n",dwMoveStatusFlags
);
355 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_DIR
&&
356 dwMoveStatusFlags
& MOVE_DEST_IS_DIR
&&
357 dwMoveStatusFlags
& MOVE_SOURCE_HAS_WILD
)
359 /* We are not allowed to have existing source and destination dir when there is wildcard in source */
366 if (!(dwMoveStatusFlags
& (MOVE_DEST_IS_FILE
| MOVE_DEST_IS_DIR
)))
368 /* destination doesn't exist */
369 _tcscpy (szFullDestPath
, szDestPath
);
370 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_FILE
) dwMoveStatusFlags
|= MOVE_DEST_IS_FILE
;
371 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_DIR
) dwMoveStatusFlags
|= MOVE_DEST_IS_DIR
;
373 dwMoveFlags
|= MOVEFILE_REPLACE_EXISTING
| MOVEFILE_WRITE_THROUGH
| MOVEFILE_COPY_ALLOWED
;
376 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_FILE
&&
377 dwMoveStatusFlags
& MOVE_DEST_IS_FILE
&&
380 /*source has many files but there is only one destination file*/
381 error_invalid_parameter_format(arg
[argc
- 1]);
387 /*checks to make sure user wanted/wants the override*/
388 if((dwFlags
& MOVE_OVER_NO
) &&
389 (dwMoveStatusFlags
& MOVE_DEST_EXISTS
))
391 if(!(dwFlags
& MOVE_OVER_YES
) &&
392 (dwMoveStatusFlags
& MOVE_DEST_EXISTS
))
393 nOverwrite
= MoveOverwrite (szFullDestPath
);
394 if (nOverwrite
== PROMPT_NO
|| nOverwrite
== PROMPT_BREAK
)
396 if (nOverwrite
== PROMPT_ALL
)
397 dwFlags
|= MOVE_OVER_YES
;
400 ConOutPrintf (_T("%s => %s "), szSrcPath
, szFullDestPath
);
402 /* are we really supposed to do something */
403 if (dwFlags
& MOVE_NOTHING
)
407 if (!(dwMoveStatusFlags
& MOVE_SOURCE_IS_DIR
&&
408 dwMoveStatusFlags
& MOVE_PATHS_ON_DIF_VOL
))
409 /* we aren't moving source folder to different drive */
410 MoveStatus
= MoveFileEx (szSrcPath
, szFullDestPath
, dwMoveFlags
);
412 { /* we are moving source folder to different drive */
413 _tcscpy(szMoveDest
, szFullDestPath
);
414 _tcscpy(szMoveSrc
, szSrcPath
);
415 DeleteFile(szMoveDest
);
416 MoveStatus
= CreateDirectory(szMoveDest
, NULL
); /* we use default security settings */
419 _tcscat(szMoveDest
,_T("\\"));
420 _tcscat(szMoveSrc
,_T("\\"));
422 pszDestDirPointer
= szMoveDest
+ _tcslen(szMoveDest
);
423 pszSrcDirPointer
= szMoveSrc
+ _tcslen(szMoveSrc
);
424 _tcscpy(pszSrcDirPointer
,_T("*.*"));
425 hDestFile
= FindFirstFile(szMoveSrc
, &findDestBuffer
);
426 if (hDestFile
== INVALID_HANDLE_VALUE
)
430 BOOL FirstTime
= TRUE
;
438 FoundFile
= FindNextFile (hDestFile
, &findDestBuffer
);
441 { /* Nothing to do in this folder so we stop working on it */
442 FindClose(hDestFile
);
443 (pszSrcDirPointer
)--;
444 (pszDestDirPointer
)--;
445 _tcscpy(pszSrcDirPointer
,_T(""));
446 _tcscpy(pszDestDirPointer
,_T(""));
449 TCHAR szTempPath
[MAX_PATH
];
452 FoundFile
= TRUE
; /* we need to continue our seek for files */
454 RemoveDirectory(szMoveSrc
);
455 GetDirectory(szMoveSrc
,szTempPath
,0);
456 nDiff
= _tcslen(szMoveSrc
) - _tcslen(szTempPath
);
457 pszSrcDirPointer
= pszSrcDirPointer
- nDiff
;
458 _tcscpy(pszSrcDirPointer
,_T(""));
459 GetDirectory(szMoveDest
,szTempPath
,0);
460 nDiff
= _tcslen(szMoveDest
) - _tcslen(szTempPath
);
461 pszDestDirPointer
= pszDestDirPointer
- nDiff
;
462 _tcscpy(pszDestDirPointer
,_T(""));
463 if(szMoveSrc
[_tcslen(szMoveSrc
) - 1] != _T('\\'))
464 _tcscat (szMoveSrc
, _T("\\"));
465 if(szMoveDest
[_tcslen(szMoveDest
) - 1] != _T('\\'))
466 _tcscat (szMoveDest
, _T("\\"));
467 pszDestDirPointer
= szMoveDest
+ _tcslen(szMoveDest
);
468 pszSrcDirPointer
= szMoveSrc
+ _tcslen(szMoveSrc
);
469 _tcscpy(pszSrcDirPointer
,_T("*.*"));
470 hDestFile
= FindFirstFile(szMoveSrc
, &findDestBuffer
);
471 if (hDestFile
== INVALID_HANDLE_VALUE
)
477 MoveStatus
= TRUE
; /* we moved everything so lets tell user about it */
478 RemoveDirectory(szMoveSrc
);
483 /* if we find "." or ".." we'll skip them */
484 if (_tcscmp(findDestBuffer
.cFileName
,_T(".")) == 0 ||
485 _tcscmp(findDestBuffer
.cFileName
,_T("..")) == 0)
488 _tcscpy(pszSrcDirPointer
, findDestBuffer
.cFileName
);
489 _tcscpy(pszDestDirPointer
, findDestBuffer
.cFileName
);
490 if (IsExistingFile(szMoveSrc
))
492 FoundFile
= CopyFile(szMoveSrc
, szMoveDest
, FALSE
);
493 if (!FoundFile
) continue;
494 DeleteFile(szMoveSrc
);
498 FindClose(hDestFile
);
499 CreateDirectory(szMoveDest
, NULL
);
500 _tcscat(szMoveDest
,_T("\\"));
501 _tcscat(szMoveSrc
,_T("\\"));
503 pszDestDirPointer
= szMoveDest
+ _tcslen(szMoveDest
);
504 pszSrcDirPointer
= szMoveSrc
+ _tcslen(szMoveSrc
);
505 _tcscpy(pszSrcDirPointer
,_T("*.*"));
506 hDestFile
= FindFirstFile(szMoveSrc
, &findDestBuffer
);
507 if (hDestFile
== INVALID_HANDLE_VALUE
)
519 ConOutResPrintf(STRING_MOVE_ERROR1
);
521 ConOutResPrintf(STRING_MOVE_ERROR2
);
523 while ((!OnlyOneFile
|| dwMoveStatusFlags
& MOVE_SRC_CURRENT_IS_DIR
) &&
524 !(dwMoveStatusFlags
& MOVE_SOURCE_IS_DIR
) &&
525 FindNextFile (hFile
, &findBuffer
));
532 #endif /* INCLUDE_CMD_MOVE */