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 hardcoded strings in 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 */
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 */
60 ConOutResPrintf(STRING_MOVE_HELP1
, fn
);
61 res
= FilePromptYNA (0);
65 void GetDirectory (LPTSTR wholepath
, LPTSTR directory
, BOOL CheckExisting
)
67 /* returns only directory part of path with backslash */
68 /* TODO: make code unc aware */
69 /* Is there a better alternative to this? */
71 if (CheckExisting
&& IsExistingDirectory(wholepath
))
73 _tcscpy(directory
, wholepath
);
75 else if ((last
= _tcsrchr(wholepath
,_T('\\'))) != NULL
)
77 _tcsncpy(directory
, wholepath
, last
- wholepath
+ 1);
78 directory
[last
- wholepath
+ 1] = 0;
82 GetRootPath(wholepath
,directory
, MAX_PATH
);
87 INT
cmd_move (LPTSTR param
)
92 TCHAR szDestPath
[MAX_PATH
];
93 TCHAR szFullDestPath
[MAX_PATH
];
94 TCHAR szSrcDirPath
[MAX_PATH
];
95 TCHAR szSrcPath
[MAX_PATH
];
96 TCHAR szFullSrcPath
[MAX_PATH
];
99 WIN32_FIND_DATA findBuffer
;
102 /* used only when source and destination directories are on different volume */
103 HANDLE hDestFile
= NULL
;
104 WIN32_FIND_DATA findDestBuffer
;
105 TCHAR szMoveDest
[MAX_PATH
];
106 TCHAR szMoveSrc
[MAX_PATH
];
107 LPTSTR pszDestDirPointer
;
108 LPTSTR pszSrcDirPointer
;
115 DWORD dwMoveFlags
= 0;
116 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 directories.\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
;
189 /* get destination */
190 GetFullPathName (pszDest
, MAX_PATH
, szDestPath
, NULL
);
191 TRACE ("Destination: %s\n", debugstr_aw(szDestPath
));
193 /* get source folder */
194 GetFullPathName(arg
[i
], MAX_PATH
, szSrcDirPath
, &pszFile
);
197 TRACE ("Source Folder: %s\n", debugstr_aw(szSrcDirPath
));
199 hFile
= FindFirstFile (arg
[i
], &findBuffer
);
200 if (hFile
== INVALID_HANDLE_VALUE
)
202 ErrorMessage (GetLastError (), arg
[i
]);
207 /* check for special cases "." and ".." and if found skip them */
210 (_tcscmp(findBuffer
.cFileName
,_T(".")) == 0 ||
211 _tcscmp(findBuffer
.cFileName
,_T("..")) == 0))
212 FoundFile
= FindNextFile (hFile
, &findBuffer
);
216 /* what? we don't have anything to move? */
217 error_file_not_found();
224 /* check if there can be found files as files have first priority */
225 if (findBuffer
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
226 dwMoveStatusFlags
|= MOVE_SOURCE_IS_DIR
;
228 dwMoveStatusFlags
|= MOVE_SOURCE_IS_FILE
;
229 while(OnlyOneFile
&& FindNextFile(hFile
,&findBuffer
))
231 if (!(findBuffer
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
233 ConOutPrintf(_T(""));
234 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_FILE
) OnlyOneFile
= FALSE
;
236 { /* this has been done this way so that we don't disturb other settings if they have been set before this */
237 dwMoveStatusFlags
|= MOVE_SOURCE_IS_FILE
;
238 dwMoveStatusFlags
&= ~MOVE_SOURCE_IS_DIR
;
244 TRACE ("Do we have only one file: %s\n", OnlyOneFile
? "TRUE" : "FALSE");
246 /* we have to start again to be sure we don't miss any files or folders*/
247 hFile
= FindFirstFile (arg
[i
], &findBuffer
);
248 if (hFile
== INVALID_HANDLE_VALUE
)
250 ErrorMessage (GetLastError (), arg
[i
]);
255 /* check for special cases "." and ".." and if found skip them */
258 (_tcscmp(findBuffer
.cFileName
,_T(".")) == 0 ||
259 _tcscmp(findBuffer
.cFileName
,_T("..")) == 0))
260 FoundFile
= FindNextFile (hFile
, &findBuffer
);
264 /* huh? somebody removed files and/or folders which were there */
265 error_file_not_found();
271 /* check if source and destination paths are on different volumes */
272 if (szSrcDirPath
[0] != szDestPath
[0])
273 dwMoveStatusFlags
|= MOVE_PATHS_ON_DIF_VOL
;
278 TRACE ("Found file/directory: %s\n", debugstr_aw(findBuffer
.cFileName
));
281 dwMoveStatusFlags
&= ~MOVE_DEST_IS_FILE
&
283 ~MOVE_SRC_CURRENT_IS_DIR
&
285 _tcscpy(szFullSrcPath
,szSrcDirPath
);
286 if (szFullSrcPath
[_tcslen(szFullSrcPath
) - 1] != _T('\\'))
287 _tcscat (szFullSrcPath
, _T("\\"));
288 _tcscat(szFullSrcPath
,findBuffer
.cFileName
);
289 _tcscpy(szSrcPath
, szFullSrcPath
);
291 if (IsExistingDirectory(szSrcPath
))
293 /* source is directory */
294 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_FILE
)
296 dwMoveStatusFlags
|= MOVE_SRC_CURRENT_IS_DIR
; /* source is file but at the current round we found a directory */
299 TRACE ("Source is dir: %s\n", debugstr_aw(szSrcPath
));
300 dwMoveFlags
= MOVEFILE_REPLACE_EXISTING
| MOVEFILE_WRITE_THROUGH
| MOVEFILE_COPY_ALLOWED
;
303 /* if source is file we don't need to do anything special */
304 if (IsExistingDirectory(szDestPath
))
306 /* destination is existing directory */
307 TRACE ("Destination is directory: %s\n", debugstr_aw(szDestPath
));
309 dwMoveStatusFlags
|= MOVE_DEST_IS_DIR
;
311 /*build the dest string(accounts for *)*/
312 _tcscpy (szFullDestPath
, szDestPath
);
313 /*check to see if there is an ending slash, if not add one*/
314 if (szFullDestPath
[_tcslen(szFullDestPath
) - 1] != _T('\\'))
315 _tcscat (szFullDestPath
, _T("\\"));
316 _tcscat (szFullDestPath
, findBuffer
.cFileName
);
318 if (IsExistingFile(szFullDestPath
) || IsExistingDirectory(szFullDestPath
))
319 dwMoveStatusFlags
|= MOVE_DEST_EXISTS
;
321 dwMoveFlags
|= MOVEFILE_REPLACE_EXISTING
| MOVEFILE_WRITE_THROUGH
| MOVEFILE_COPY_ALLOWED
;
323 if (IsExistingFile(szDestPath
))
325 /* destination is a file */
326 TRACE ("Destination is file: %s\n", debugstr_aw(szDestPath
));
328 dwMoveStatusFlags
|= MOVE_DEST_IS_FILE
| MOVE_DEST_EXISTS
;
329 _tcscpy (szFullDestPath
, szDestPath
);
331 dwMoveFlags
|= MOVEFILE_REPLACE_EXISTING
| MOVEFILE_WRITE_THROUGH
| MOVEFILE_COPY_ALLOWED
;
334 TRACE ("Move Status Flags: 0x%X\n",dwMoveStatusFlags
);
336 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_DIR
&&
337 dwMoveStatusFlags
& MOVE_DEST_IS_DIR
&&
338 dwMoveStatusFlags
& MOVE_SOURCE_HAS_WILD
)
340 /* We are not allowed to have existing source and destination dir when there is wildcard in source */
346 if (!(dwMoveStatusFlags
& (MOVE_DEST_IS_FILE
| MOVE_DEST_IS_DIR
)))
348 /* destination doesn't exist */
349 _tcscpy (szFullDestPath
, szDestPath
);
350 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_FILE
) dwMoveStatusFlags
|= MOVE_DEST_IS_FILE
;
351 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_DIR
) dwMoveStatusFlags
|= MOVE_DEST_IS_DIR
;
353 dwMoveFlags
|= MOVEFILE_REPLACE_EXISTING
| MOVEFILE_WRITE_THROUGH
| MOVEFILE_COPY_ALLOWED
;
356 if (dwMoveStatusFlags
& MOVE_SOURCE_IS_FILE
&&
357 dwMoveStatusFlags
& MOVE_DEST_IS_FILE
&&
360 /*source has many files but there is only one destination file*/
361 error_invalid_parameter_format(pszDest
);
367 /*checks to make sure user wanted/wants the override*/
368 if ((dwFlags
& MOVE_OVER_NO
) &&
369 (dwMoveStatusFlags
& MOVE_DEST_EXISTS
))
371 if (!(dwFlags
& MOVE_OVER_YES
) &&
372 (dwMoveStatusFlags
& MOVE_DEST_EXISTS
))
373 nOverwrite
= MoveOverwrite (szFullDestPath
);
374 if (nOverwrite
== PROMPT_NO
|| nOverwrite
== PROMPT_BREAK
)
376 if (nOverwrite
== PROMPT_ALL
)
377 dwFlags
|= MOVE_OVER_YES
;
379 ConOutPrintf (_T("%s => %s "), szSrcPath
, szFullDestPath
);
381 /* are we really supposed to do something */
382 if (dwFlags
& MOVE_NOTHING
)
386 if (!(dwMoveStatusFlags
& MOVE_SOURCE_IS_DIR
&&
387 dwMoveStatusFlags
& MOVE_PATHS_ON_DIF_VOL
))
388 /* we aren't moving source folder to different drive */
389 MoveStatus
= MoveFileEx (szSrcPath
, szFullDestPath
, dwMoveFlags
);
391 { /* we are moving source folder to different drive */
392 _tcscpy(szMoveDest
, szFullDestPath
);
393 _tcscpy(szMoveSrc
, szSrcPath
);
394 DeleteFile(szMoveDest
);
395 MoveStatus
= CreateDirectory(szMoveDest
, NULL
); /* we use default security settings */
398 _tcscat(szMoveDest
,_T("\\"));
399 _tcscat(szMoveSrc
,_T("\\"));
401 pszDestDirPointer
= szMoveDest
+ _tcslen(szMoveDest
);
402 pszSrcDirPointer
= szMoveSrc
+ _tcslen(szMoveSrc
);
403 _tcscpy(pszSrcDirPointer
,_T("*.*"));
404 hDestFile
= FindFirstFile(szMoveSrc
, &findDestBuffer
);
405 if (hDestFile
== INVALID_HANDLE_VALUE
)
409 BOOL FirstTime
= TRUE
;
417 FoundFile
= FindNextFile (hDestFile
, &findDestBuffer
);
421 /* Nothing to do in this folder so we stop working on it */
422 FindClose(hDestFile
);
423 (pszSrcDirPointer
)--;
424 (pszDestDirPointer
)--;
425 _tcscpy(pszSrcDirPointer
,_T(""));
426 _tcscpy(pszDestDirPointer
,_T(""));
429 TCHAR szTempPath
[MAX_PATH
];
432 FoundFile
= TRUE
; /* we need to continue our seek for files */
434 RemoveDirectory(szMoveSrc
);
435 GetDirectory(szMoveSrc
,szTempPath
,0);
436 nDiff
= _tcslen(szMoveSrc
) - _tcslen(szTempPath
);
437 pszSrcDirPointer
= pszSrcDirPointer
- nDiff
;
438 _tcscpy(pszSrcDirPointer
,_T(""));
439 GetDirectory(szMoveDest
,szTempPath
,0);
440 nDiff
= _tcslen(szMoveDest
) - _tcslen(szTempPath
);
441 pszDestDirPointer
= pszDestDirPointer
- nDiff
;
442 _tcscpy(pszDestDirPointer
,_T(""));
443 if (szMoveSrc
[_tcslen(szMoveSrc
) - 1] != _T('\\'))
444 _tcscat (szMoveSrc
, _T("\\"));
445 if (szMoveDest
[_tcslen(szMoveDest
) - 1] != _T('\\'))
446 _tcscat (szMoveDest
, _T("\\"));
447 pszDestDirPointer
= szMoveDest
+ _tcslen(szMoveDest
);
448 pszSrcDirPointer
= szMoveSrc
+ _tcslen(szMoveSrc
);
449 _tcscpy(pszSrcDirPointer
,_T("*.*"));
450 hDestFile
= FindFirstFile(szMoveSrc
, &findDestBuffer
);
451 if (hDestFile
== INVALID_HANDLE_VALUE
)
457 MoveStatus
= TRUE
; /* we moved everything so lets tell user about it */
458 RemoveDirectory(szMoveSrc
);
463 /* if we find "." or ".." we'll skip them */
464 if (_tcscmp(findDestBuffer
.cFileName
,_T(".")) == 0 ||
465 _tcscmp(findDestBuffer
.cFileName
,_T("..")) == 0)
468 _tcscpy(pszSrcDirPointer
, findDestBuffer
.cFileName
);
469 _tcscpy(pszDestDirPointer
, findDestBuffer
.cFileName
);
470 if (IsExistingFile(szMoveSrc
))
472 FoundFile
= CopyFile(szMoveSrc
, szMoveDest
, FALSE
);
473 if (!FoundFile
) continue;
474 DeleteFile(szMoveSrc
);
478 FindClose(hDestFile
);
479 CreateDirectory(szMoveDest
, NULL
);
480 _tcscat(szMoveDest
,_T("\\"));
481 _tcscat(szMoveSrc
,_T("\\"));
483 pszDestDirPointer
= szMoveDest
+ _tcslen(szMoveDest
);
484 pszSrcDirPointer
= szMoveSrc
+ _tcslen(szMoveSrc
);
485 _tcscpy(pszSrcDirPointer
,_T("*.*"));
486 hDestFile
= FindFirstFile(szMoveSrc
, &findDestBuffer
);
487 if (hDestFile
== INVALID_HANDLE_VALUE
)
499 ConOutResPrintf(STRING_MOVE_ERROR1
);
501 ConOutResPrintf(STRING_MOVE_ERROR2
);
503 while ((!OnlyOneFile
|| dwMoveStatusFlags
& MOVE_SRC_CURRENT_IS_DIR
) &&
504 !(dwMoveStatusFlags
& MOVE_SOURCE_IS_DIR
) &&
505 FindNextFile (hFile
, &findBuffer
));
508 if(hDestFile
&& hDestFile
!= INVALID_HANDLE_VALUE
)
509 FindClose(hDestFile
);
515 #endif /* INCLUDE_CMD_MOVE */