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 param
)
91 TCHAR szDestPath
[MAX_PATH
];
92 TCHAR szFullDestPath
[MAX_PATH
];
93 TCHAR szSrcDirPath
[MAX_PATH
];
94 TCHAR szSrcPath
[MAX_PATH
];
95 TCHAR szFullSrcPath
[MAX_PATH
];
98 WIN32_FIND_DATA findBuffer
;
101 /* used only when source and destination directories are on different volume*/
103 WIN32_FIND_DATA findDestBuffer
;
104 TCHAR szMoveDest
[MAX_PATH
];
105 TCHAR szMoveSrc
[MAX_PATH
];
106 LPTSTR pszDestDirPointer
;
107 LPTSTR pszSrcDirPointer
;
114 DWORD dwMoveFlags
= 0;
115 DWORD dwMoveStatusFlags
= 0;
118 if (!_tcsncmp (param
, _T("/?"), 2))
121 ConOutPuts (_T("Moves files and renames files and directories.\n\n"
122 "To move one or more files:\n"
123 "MOVE [/N][/Y|/-Y][drive:][path]filename1[,...] destination\n"
125 "To rename a directory:\n"
126 "MOVE [/N][/Y|/-Y][drive:][path]dirname1 dirname2\n"
128 " [drive:][path]filename1 Specifies the location and name of the file\n"
129 " or files you want to move.\n"
130 " /N Nothing. Don everthing but move files or direcories.\n"
135 ConOutResPaging(TRUE
,STRING_MOVE_HELP2
);
141 arg
= splitspace(param
, &argc
);
144 for (i
= 0; i
< argc
; i
++)
146 if (!_tcsicmp(arg
[i
], _T("/N")))
147 dwFlags
|= MOVE_NOTHING
;
148 else if (!_tcsicmp(arg
[i
], _T("/Y")))
149 dwFlags
|= MOVE_OVER_YES
;
150 else if (!_tcsicmp(arg
[i
], _T("/-Y")))
151 dwFlags
|= MOVE_OVER_NO
;
159 /* there must be at least one pathspec */
160 error_req_param_missing();
167 /* there are more than two pathspecs */
168 error_too_many_parameters(param
);
173 /* If no destination is given, default to current directory */
174 pszDest
= (nFiles
== 1) ? _T(".") : arg
[i
+ 1];
176 /* check for wildcards in source and destination */
177 if (_tcschr(pszDest
, _T('*')) != NULL
|| _tcschr(pszDest
, _T('?')) != NULL
)
179 /* '*'/'?' in dest, this doesnt happen. give folder name instead*/
180 error_invalid_parameter_format(pszDest
);
184 if (_tcschr(arg
[i
], _T('*')) != NULL
|| _tcschr(arg
[i
], _T('?')) != NULL
)
186 dwMoveStatusFlags
|= MOVE_SOURCE_HAS_WILD
;
190 /* get destination */
191 GetFullPathName (pszDest
, MAX_PATH
, szDestPath
, NULL
);
192 TRACE ("Destination: %s\n", debugstr_aw(szDestPath
));
194 /* get source folder */
195 GetFullPathName(arg
[i
], MAX_PATH
, szSrcDirPath
, &pszFile
);
198 TRACE ("Source Folder: %s\n", debugstr_aw(szSrcDirPath
));
200 hFile
= FindFirstFile (arg
[i
], &findBuffer
);
201 if (hFile
== INVALID_HANDLE_VALUE
)
203 ErrorMessage (GetLastError (), arg
[i
]);
209 /* check for special cases "." and ".." and if found skip them */
212 (_tcscmp(findBuffer
.cFileName
,_T(".")) == 0 ||
213 _tcscmp(findBuffer
.cFileName
,_T("..")) == 0))
214 FoundFile
= FindNextFile (hFile
, &findBuffer
);
218 /* what? we don't have anything to move? */
219 error_file_not_found();
226 /* check if there can be found files as files have first priority */
227 if (findBuffer
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
228 dwMoveStatusFlags
|= MOVE_SOURCE_IS_DIR
;
230 dwMoveStatusFlags
|= MOVE_SOURCE_IS_FILE
;
231 while(OnlyOneFile
&& FindNextFile(hFile
,&findBuffer
))
233 if (!(findBuffer
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
235 ConOutPrintf(_T(""));
236 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_FILE
) OnlyOneFile
= FALSE
;
238 { /* this has been done this way so that we don't disturb other settings if they have been set before this */
239 dwMoveStatusFlags
|= MOVE_SOURCE_IS_FILE
;
240 dwMoveStatusFlags
&= ~MOVE_SOURCE_IS_DIR
;
246 TRACE ("Do we have only one file: %s\n", OnlyOneFile
? "TRUE" : "FALSE");
248 /* we have to start again to be sure we don't miss any files or folders*/
249 hFile
= FindFirstFile (arg
[i
], &findBuffer
);
250 if (hFile
== INVALID_HANDLE_VALUE
)
252 ErrorMessage (GetLastError (), arg
[i
]);
258 /* check for special cases "." and ".." and if found skip them */
261 (_tcscmp(findBuffer
.cFileName
,_T(".")) == 0 ||
262 _tcscmp(findBuffer
.cFileName
,_T("..")) == 0))
263 FoundFile
= FindNextFile (hFile
, &findBuffer
);
267 /* huh? somebody removed files and/or folders which were there */
268 error_file_not_found();
274 /* check if source and destination paths are on different volumes */
275 if (szSrcDirPath
[0] != szDestPath
[0])
276 dwMoveStatusFlags
|= MOVE_PATHS_ON_DIF_VOL
;
281 TRACE ("Found file/directory: %s\n", debugstr_aw(findBuffer
.cFileName
));
284 dwMoveStatusFlags
&= ~MOVE_DEST_IS_FILE
&
286 ~MOVE_SRC_CURRENT_IS_DIR
&
288 _tcscpy(szFullSrcPath
,szSrcDirPath
);
289 if(szFullSrcPath
[_tcslen(szFullSrcPath
) - 1] != _T('\\'))
290 _tcscat (szFullSrcPath
, _T("\\"));
291 _tcscat(szFullSrcPath
,findBuffer
.cFileName
);
292 _tcscpy(szSrcPath
, szFullSrcPath
);
294 if (IsExistingDirectory(szSrcPath
))
296 /* source is directory */
298 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_FILE
)
300 dwMoveStatusFlags
|= MOVE_SRC_CURRENT_IS_DIR
; /* source is file but at the current round we found a directory */
303 TRACE ("Source is dir: %s\n", debugstr_aw(szSrcPath
));
304 dwMoveFlags
= MOVEFILE_REPLACE_EXISTING
| MOVEFILE_WRITE_THROUGH
| MOVEFILE_COPY_ALLOWED
;
307 /* if source is file we don't need to do anything special */
309 if (IsExistingDirectory(szDestPath
))
311 /* destination is existing directory */
312 TRACE ("Destination is directory: %s\n", debugstr_aw(szDestPath
));
314 dwMoveStatusFlags
|= MOVE_DEST_IS_DIR
;
316 /*build the dest string(accounts for *)*/
317 _tcscpy (szFullDestPath
, szDestPath
);
318 /*check to see if there is an ending slash, if not add one*/
319 if(szFullDestPath
[_tcslen(szFullDestPath
) - 1] != _T('\\'))
320 _tcscat (szFullDestPath
, _T("\\"));
321 _tcscat (szFullDestPath
, findBuffer
.cFileName
);
323 if (IsExistingFile(szFullDestPath
) || IsExistingDirectory(szFullDestPath
))
324 dwMoveStatusFlags
|= MOVE_DEST_EXISTS
;
326 dwMoveFlags
|= MOVEFILE_REPLACE_EXISTING
| MOVEFILE_WRITE_THROUGH
| MOVEFILE_COPY_ALLOWED
;
329 if (IsExistingFile(szDestPath
))
331 /* destination is a file */
332 TRACE ("Destination is file: %s\n", debugstr_aw(szDestPath
));
334 dwMoveStatusFlags
|= MOVE_DEST_IS_FILE
| MOVE_DEST_EXISTS
;
335 _tcscpy (szFullDestPath
, szDestPath
);
337 dwMoveFlags
|= MOVEFILE_REPLACE_EXISTING
| MOVEFILE_WRITE_THROUGH
| MOVEFILE_COPY_ALLOWED
;
341 TRACE ("Move Status Flags: 0x%X\n",dwMoveStatusFlags
);
343 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_DIR
&&
344 dwMoveStatusFlags
& MOVE_DEST_IS_DIR
&&
345 dwMoveStatusFlags
& MOVE_SOURCE_HAS_WILD
)
347 /* We are not allowed to have existing source and destination dir when there is wildcard in source */
354 if (!(dwMoveStatusFlags
& (MOVE_DEST_IS_FILE
| MOVE_DEST_IS_DIR
)))
356 /* destination doesn't exist */
357 _tcscpy (szFullDestPath
, szDestPath
);
358 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_FILE
) dwMoveStatusFlags
|= MOVE_DEST_IS_FILE
;
359 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_DIR
) dwMoveStatusFlags
|= MOVE_DEST_IS_DIR
;
361 dwMoveFlags
|= MOVEFILE_REPLACE_EXISTING
| MOVEFILE_WRITE_THROUGH
| MOVEFILE_COPY_ALLOWED
;
364 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_FILE
&&
365 dwMoveStatusFlags
& MOVE_DEST_IS_FILE
&&
368 /*source has many files but there is only one destination file*/
369 error_invalid_parameter_format(pszDest
);
375 /*checks to make sure user wanted/wants the override*/
376 if((dwFlags
& MOVE_OVER_NO
) &&
377 (dwMoveStatusFlags
& MOVE_DEST_EXISTS
))
379 if(!(dwFlags
& MOVE_OVER_YES
) &&
380 (dwMoveStatusFlags
& MOVE_DEST_EXISTS
))
381 nOverwrite
= MoveOverwrite (szFullDestPath
);
382 if (nOverwrite
== PROMPT_NO
|| nOverwrite
== PROMPT_BREAK
)
384 if (nOverwrite
== PROMPT_ALL
)
385 dwFlags
|= MOVE_OVER_YES
;
388 ConOutPrintf (_T("%s => %s "), szSrcPath
, szFullDestPath
);
390 /* are we really supposed to do something */
391 if (dwFlags
& MOVE_NOTHING
)
395 if (!(dwMoveStatusFlags
& MOVE_SOURCE_IS_DIR
&&
396 dwMoveStatusFlags
& MOVE_PATHS_ON_DIF_VOL
))
397 /* we aren't moving source folder to different drive */
398 MoveStatus
= MoveFileEx (szSrcPath
, szFullDestPath
, dwMoveFlags
);
400 { /* we are moving source folder to different drive */
401 _tcscpy(szMoveDest
, szFullDestPath
);
402 _tcscpy(szMoveSrc
, szSrcPath
);
403 DeleteFile(szMoveDest
);
404 MoveStatus
= CreateDirectory(szMoveDest
, NULL
); /* we use default security settings */
407 _tcscat(szMoveDest
,_T("\\"));
408 _tcscat(szMoveSrc
,_T("\\"));
410 pszDestDirPointer
= szMoveDest
+ _tcslen(szMoveDest
);
411 pszSrcDirPointer
= szMoveSrc
+ _tcslen(szMoveSrc
);
412 _tcscpy(pszSrcDirPointer
,_T("*.*"));
413 hDestFile
= FindFirstFile(szMoveSrc
, &findDestBuffer
);
414 if (hDestFile
== INVALID_HANDLE_VALUE
)
418 BOOL FirstTime
= TRUE
;
426 FoundFile
= FindNextFile (hDestFile
, &findDestBuffer
);
429 { /* Nothing to do in this folder so we stop working on it */
430 FindClose(hDestFile
);
431 (pszSrcDirPointer
)--;
432 (pszDestDirPointer
)--;
433 _tcscpy(pszSrcDirPointer
,_T(""));
434 _tcscpy(pszDestDirPointer
,_T(""));
437 TCHAR szTempPath
[MAX_PATH
];
440 FoundFile
= TRUE
; /* we need to continue our seek for files */
442 RemoveDirectory(szMoveSrc
);
443 GetDirectory(szMoveSrc
,szTempPath
,0);
444 nDiff
= _tcslen(szMoveSrc
) - _tcslen(szTempPath
);
445 pszSrcDirPointer
= pszSrcDirPointer
- nDiff
;
446 _tcscpy(pszSrcDirPointer
,_T(""));
447 GetDirectory(szMoveDest
,szTempPath
,0);
448 nDiff
= _tcslen(szMoveDest
) - _tcslen(szTempPath
);
449 pszDestDirPointer
= pszDestDirPointer
- nDiff
;
450 _tcscpy(pszDestDirPointer
,_T(""));
451 if(szMoveSrc
[_tcslen(szMoveSrc
) - 1] != _T('\\'))
452 _tcscat (szMoveSrc
, _T("\\"));
453 if(szMoveDest
[_tcslen(szMoveDest
) - 1] != _T('\\'))
454 _tcscat (szMoveDest
, _T("\\"));
455 pszDestDirPointer
= szMoveDest
+ _tcslen(szMoveDest
);
456 pszSrcDirPointer
= szMoveSrc
+ _tcslen(szMoveSrc
);
457 _tcscpy(pszSrcDirPointer
,_T("*.*"));
458 hDestFile
= FindFirstFile(szMoveSrc
, &findDestBuffer
);
459 if (hDestFile
== INVALID_HANDLE_VALUE
)
465 MoveStatus
= TRUE
; /* we moved everything so lets tell user about it */
466 RemoveDirectory(szMoveSrc
);
471 /* if we find "." or ".." we'll skip them */
472 if (_tcscmp(findDestBuffer
.cFileName
,_T(".")) == 0 ||
473 _tcscmp(findDestBuffer
.cFileName
,_T("..")) == 0)
476 _tcscpy(pszSrcDirPointer
, findDestBuffer
.cFileName
);
477 _tcscpy(pszDestDirPointer
, findDestBuffer
.cFileName
);
478 if (IsExistingFile(szMoveSrc
))
480 FoundFile
= CopyFile(szMoveSrc
, szMoveDest
, FALSE
);
481 if (!FoundFile
) continue;
482 DeleteFile(szMoveSrc
);
486 FindClose(hDestFile
);
487 CreateDirectory(szMoveDest
, NULL
);
488 _tcscat(szMoveDest
,_T("\\"));
489 _tcscat(szMoveSrc
,_T("\\"));
491 pszDestDirPointer
= szMoveDest
+ _tcslen(szMoveDest
);
492 pszSrcDirPointer
= szMoveSrc
+ _tcslen(szMoveSrc
);
493 _tcscpy(pszSrcDirPointer
,_T("*.*"));
494 hDestFile
= FindFirstFile(szMoveSrc
, &findDestBuffer
);
495 if (hDestFile
== INVALID_HANDLE_VALUE
)
507 ConOutResPrintf(STRING_MOVE_ERROR1
);
509 ConOutResPrintf(STRING_MOVE_ERROR2
);
511 while ((!OnlyOneFile
|| dwMoveStatusFlags
& MOVE_SRC_CURRENT_IS_DIR
) &&
512 !(dwMoveStatusFlags
& MOVE_SOURCE_IS_DIR
) &&
513 FindNextFile (hFile
, &findBuffer
));
520 #endif /* INCLUDE_CMD_MOVE */