1 /* 2 * MOVE.C - move internal command. 3 * 4 * 5 * History: 6 * 7 * 14-Dec-1998 (Eric Kohl) 8 * Started. 9 * 10 * 18-Jan-1999 (Eric Kohl) 11 * Unicode safe! 12 * Preliminary version!!! 13 * 14 * 20-Jan-1999 (Eric Kohl) 15 * Redirection safe! 16 * 17 * 27-Jan-1999 (Eric Kohl) 18 * Added help text ("/?"). 19 * Added more error checks. 20 * 21 * 03-Feb-1999 (Eric Kohl) 22 * Added "/N" option. 23 * 24 * 30-Apr-2005 (Magnus Olsen <magnus@greatlord.com>) 25 * Remove all hardcoded strings in En.rc 26 * 27 * 24-Jun-2005 (Brandon Turner <turnerb7@msu.edu>) 28 * Fixed bug to allow MS style wildcards + code clean up 29 * added /y and /-y 30 */ 31 32 #include "precomp.h" 33 34 #ifdef INCLUDE_CMD_MOVE 35 36 enum 37 { 38 MOVE_NOTHING = 0x001, /* /N */ 39 MOVE_OVER_YES = 0x002, /* /Y */ 40 MOVE_OVER_NO = 0x004, /* /-Y */ 41 }; 42 43 enum 44 { 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 */ 54 }; 55 56 static INT MoveOverwrite (LPTSTR fn) 57 { 58 /* ask the user if they want to override */ 59 INT res; 60 ConOutResPrintf(STRING_MOVE_HELP1, fn); 61 res = FilePromptYNA (0); 62 return res; 63 } 64 65 void GetDirectory (LPTSTR wholepath, LPTSTR directory, BOOL CheckExisting) 66 { 67 /* returns only directory part of path with backslash */ 68 /* TODO: make code unc aware */ 69 /* Is there a better alternative to this? */ 70 LPTSTR last; 71 if (CheckExisting && IsExistingDirectory(wholepath)) 72 { 73 _tcscpy(directory, wholepath); 74 } 75 else if ((last = _tcsrchr(wholepath,_T('\\'))) != NULL) 76 { 77 _tcsncpy(directory, wholepath, last - wholepath + 1); 78 directory[last - wholepath + 1] = 0; 79 } 80 else 81 { 82 GetRootPath(wholepath,directory, MAX_PATH); 83 } 84 } 85 86 87 INT cmd_move (LPTSTR param) 88 { 89 LPTSTR *arg; 90 INT argc, i, nFiles; 91 LPTSTR pszDest; 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]; 97 DWORD dwFlags = 0; 98 INT nOverwrite = 0; 99 WIN32_FIND_DATA findBuffer; 100 HANDLE hFile; 101 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; 109 INT nDirLevel = 0; 110 111 LPTSTR pszFile; 112 BOOL OnlyOneFile; 113 BOOL FoundFile; 114 BOOL MoveStatus; 115 DWORD dwMoveFlags = 0; 116 DWORD dwMoveStatusFlags = 0; 117 118 if (!_tcsncmp (param, _T("/?"), 2)) 119 { 120 #if 0 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" 124 "\n" 125 "To rename a directory:\n" 126 "MOVE [/N][/Y|/-Y][drive:][path]dirname1 dirname2\n" 127 "\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" 131 " /Y\n" 132 " /-Y\n" 133 "...")); 134 #else 135 ConOutResPaging(TRUE,STRING_MOVE_HELP2); 136 #endif 137 return 0; 138 } 139 140 nErrorLevel = 0; 141 arg = splitspace(param, &argc); 142 143 /* read options */ 144 for (i = 0; i < argc; i++) 145 { 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; 152 else 153 break; 154 } 155 nFiles = argc - i; 156 157 if (nFiles < 1) 158 { 159 /* there must be at least one pathspec */ 160 error_req_param_missing(); 161 nErrorLevel = 1; 162 goto Quit; 163 } 164 165 if (nFiles > 2) 166 { 167 /* there are more than two pathspecs */ 168 error_too_many_parameters(param); 169 nErrorLevel = 1; 170 goto Quit; 171 } 172 173 /* If no destination is given, default to current directory */ 174 pszDest = (nFiles == 1) ? _T(".") : arg[i + 1]; 175 176 /* check for wildcards in source and destination */ 177 if (_tcschr(pszDest, _T('*')) != NULL || _tcschr(pszDest, _T('?')) != NULL) 178 { 179 /* '*'/'?' in dest, this doesnt happen. give folder name instead*/ 180 error_invalid_parameter_format(pszDest); 181 nErrorLevel = 1; 182 goto Quit; 183 } 184 if (_tcschr(arg[i], _T('*')) != NULL || _tcschr(arg[i], _T('?')) != NULL) 185 { 186 dwMoveStatusFlags |= MOVE_SOURCE_HAS_WILD; 187 } 188 189 /* get destination */ 190 GetFullPathName (pszDest, MAX_PATH, szDestPath, NULL); 191 TRACE ("Destination: %s\n", debugstr_aw(szDestPath)); 192 193 /* get source folder */ 194 GetFullPathName(arg[i], MAX_PATH, szSrcDirPath, &pszFile); 195 if (pszFile != NULL) 196 *pszFile = _T('\0'); 197 TRACE ("Source Folder: %s\n", debugstr_aw(szSrcDirPath)); 198 199 hFile = FindFirstFile (arg[i], &findBuffer); 200 if (hFile == INVALID_HANDLE_VALUE) 201 { 202 ErrorMessage(GetLastError(), arg[i]); 203 nErrorLevel = 1; 204 goto Quit; 205 } 206 207 /* check for special cases "." and ".." and if found skip them */ 208 FoundFile = TRUE; 209 while(FoundFile && 210 (_tcscmp(findBuffer.cFileName,_T(".")) == 0 || 211 _tcscmp(findBuffer.cFileName,_T("..")) == 0)) 212 FoundFile = FindNextFile (hFile, &findBuffer); 213 214 if (!FoundFile) 215 { 216 /* what? we don't have anything to move? */ 217 error_file_not_found(); 218 FindClose(hFile); 219 nErrorLevel = 1; 220 goto Quit; 221 } 222 223 OnlyOneFile = TRUE; 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; 227 else 228 dwMoveStatusFlags |= MOVE_SOURCE_IS_FILE; 229 while(OnlyOneFile && FindNextFile(hFile,&findBuffer)) 230 { 231 if (!(findBuffer.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) 232 { 233 ConOutPrintf(_T("")); 234 if (dwMoveStatusFlags & MOVE_SOURCE_IS_FILE) OnlyOneFile = FALSE; 235 else 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; 239 } 240 } 241 } 242 FindClose(hFile); 243 244 TRACE ("Do we have only one file: %s\n", OnlyOneFile ? "TRUE" : "FALSE"); 245 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) 249 { 250 ErrorMessage(GetLastError(), arg[i]); 251 nErrorLevel = 1; 252 goto Quit; 253 } 254 255 /* check for special cases "." and ".." and if found skip them */ 256 FoundFile = TRUE; 257 while(FoundFile && 258 (_tcscmp(findBuffer.cFileName,_T(".")) == 0 || 259 _tcscmp(findBuffer.cFileName,_T("..")) == 0)) 260 FoundFile = FindNextFile (hFile, &findBuffer); 261 262 if (!FoundFile) 263 { 264 /* huh? somebody removed files and/or folders which were there */ 265 error_file_not_found(); 266 FindClose(hFile); 267 nErrorLevel = 1; 268 goto Quit; 269 } 270 271 /* check if source and destination paths are on different volumes */ 272 if (szSrcDirPath[0] != szDestPath[0]) 273 dwMoveStatusFlags |= MOVE_PATHS_ON_DIF_VOL; 274 275 /* move it */ 276 do 277 { 278 TRACE ("Found file/directory: %s\n", debugstr_aw(findBuffer.cFileName)); 279 nOverwrite = 1; 280 dwMoveFlags = 0; 281 dwMoveStatusFlags &= ~MOVE_DEST_IS_FILE & 282 ~MOVE_DEST_IS_DIR & 283 ~MOVE_SRC_CURRENT_IS_DIR & 284 ~MOVE_DEST_EXISTS; 285 _tcscpy(szFullSrcPath,szSrcDirPath); 286 if (szFullSrcPath[_tcslen(szFullSrcPath) - 1] != _T('\\')) 287 _tcscat (szFullSrcPath, _T("\\")); 288 _tcscat(szFullSrcPath,findBuffer.cFileName); 289 _tcscpy(szSrcPath, szFullSrcPath); 290 291 if (IsExistingDirectory(szSrcPath)) 292 { 293 /* source is directory */ 294 if (dwMoveStatusFlags & MOVE_SOURCE_IS_FILE) 295 { 296 dwMoveStatusFlags |= MOVE_SRC_CURRENT_IS_DIR; /* source is file but at the current round we found a directory */ 297 continue; 298 } 299 TRACE ("Source is dir: %s\n", debugstr_aw(szSrcPath)); 300 dwMoveFlags = MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH | MOVEFILE_COPY_ALLOWED; 301 } 302 303 /* if source is file we don't need to do anything special */ 304 if (IsExistingDirectory(szDestPath)) 305 { 306 /* destination is existing directory */ 307 TRACE ("Destination is directory: %s\n", debugstr_aw(szDestPath)); 308 309 dwMoveStatusFlags |= MOVE_DEST_IS_DIR; 310 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); 317 318 if (IsExistingFile(szFullDestPath) || IsExistingDirectory(szFullDestPath)) 319 dwMoveStatusFlags |= MOVE_DEST_EXISTS; 320 321 dwMoveFlags |= MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH | MOVEFILE_COPY_ALLOWED; 322 } 323 if (IsExistingFile(szDestPath)) 324 { 325 /* destination is a file */ 326 TRACE ("Destination is file: %s\n", debugstr_aw(szDestPath)); 327 328 dwMoveStatusFlags |= MOVE_DEST_IS_FILE | MOVE_DEST_EXISTS; 329 _tcscpy (szFullDestPath, szDestPath); 330 331 dwMoveFlags |= MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH | MOVEFILE_COPY_ALLOWED; 332 } 333 334 TRACE ("Move Status Flags: 0x%X\n",dwMoveStatusFlags); 335 336 if (dwMoveStatusFlags & MOVE_SOURCE_IS_DIR && 337 dwMoveStatusFlags & MOVE_DEST_IS_DIR && 338 dwMoveStatusFlags & MOVE_SOURCE_HAS_WILD) 339 { 340 /* We are not allowed to have existing source and destination dir when there is wildcard in source */ 341 error_syntax(NULL); 342 FindClose(hFile); 343 nErrorLevel = 1; 344 goto Quit; 345 } 346 if (!(dwMoveStatusFlags & (MOVE_DEST_IS_FILE | MOVE_DEST_IS_DIR))) 347 { 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; 352 353 dwMoveFlags |= MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH | MOVEFILE_COPY_ALLOWED; 354 } 355 356 if (dwMoveStatusFlags & MOVE_SOURCE_IS_FILE && 357 dwMoveStatusFlags & MOVE_DEST_IS_FILE && 358 !OnlyOneFile) 359 { 360 /*source has many files but there is only one destination file*/ 361 error_invalid_parameter_format(pszDest); 362 FindClose(hFile); 363 nErrorLevel = 1; 364 goto Quit; 365 } 366 367 /*checks to make sure user wanted/wants the override*/ 368 if ((dwFlags & MOVE_OVER_NO) && 369 (dwMoveStatusFlags & MOVE_DEST_EXISTS)) 370 continue; 371 if (!(dwFlags & MOVE_OVER_YES) && 372 (dwMoveStatusFlags & MOVE_DEST_EXISTS)) 373 nOverwrite = MoveOverwrite (szFullDestPath); 374 if (nOverwrite == PROMPT_NO || nOverwrite == PROMPT_BREAK) 375 continue; 376 if (nOverwrite == PROMPT_ALL) 377 dwFlags |= MOVE_OVER_YES; 378 379 ConOutPrintf (_T("%s => %s "), szSrcPath, szFullDestPath); 380 381 /* are we really supposed to do something */ 382 if (dwFlags & MOVE_NOTHING) 383 continue; 384 385 /*move the file*/ 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); 390 else 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 */ 396 if (MoveStatus) 397 { 398 _tcscat(szMoveDest,_T("\\")); 399 _tcscat(szMoveSrc,_T("\\")); 400 nDirLevel = 0; 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) 406 MoveStatus = FALSE; 407 else 408 { 409 BOOL FirstTime = TRUE; 410 FoundFile = TRUE; 411 MoveStatus = FALSE; 412 while(FoundFile) 413 { 414 if (FirstTime) 415 FirstTime = FALSE; 416 else 417 FoundFile = FindNextFile (hDestFile, &findDestBuffer); 418 419 if (!FoundFile) 420 { 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("")); 427 if (nDirLevel > 0) 428 { 429 TCHAR szTempPath[MAX_PATH]; 430 INT_PTR nDiff; 431 432 FoundFile = TRUE; /* we need to continue our seek for files */ 433 nDirLevel--; 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) 452 continue; 453 FirstTime = TRUE; 454 } 455 else 456 { 457 MoveStatus = TRUE; /* we moved everything so lets tell user about it */ 458 RemoveDirectory(szMoveSrc); 459 } 460 continue; 461 } 462 463 /* if we find "." or ".." we'll skip them */ 464 if (_tcscmp(findDestBuffer.cFileName,_T(".")) == 0 || 465 _tcscmp(findDestBuffer.cFileName,_T("..")) == 0) 466 continue; 467 468 _tcscpy(pszSrcDirPointer, findDestBuffer.cFileName); 469 _tcscpy(pszDestDirPointer, findDestBuffer.cFileName); 470 if (IsExistingFile(szMoveSrc)) 471 { 472 FoundFile = CopyFile(szMoveSrc, szMoveDest, FALSE); 473 if (!FoundFile) continue; 474 DeleteFile(szMoveSrc); 475 } 476 else 477 { 478 FindClose(hDestFile); 479 CreateDirectory(szMoveDest, NULL); 480 _tcscat(szMoveDest,_T("\\")); 481 _tcscat(szMoveSrc,_T("\\")); 482 nDirLevel++; 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) 488 { 489 FoundFile = FALSE; 490 continue; 491 } 492 FirstTime = TRUE; 493 } 494 } 495 } 496 } 497 } 498 499 if (MoveStatus) 500 { 501 ConOutResPrintf(STRING_MOVE_ERROR1); 502 } 503 else 504 { 505 ConOutResPrintf(STRING_MOVE_ERROR2); 506 nErrorLevel = 1; 507 } 508 } 509 while ((!OnlyOneFile || dwMoveStatusFlags & MOVE_SRC_CURRENT_IS_DIR ) && 510 !(dwMoveStatusFlags & MOVE_SOURCE_IS_DIR) && 511 FindNextFile (hFile, &findBuffer)); 512 FindClose (hFile); 513 514 if(hDestFile && hDestFile != INVALID_HANDLE_VALUE) 515 FindClose(hDestFile); 516 517 Quit: 518 freep(arg); 519 return nErrorLevel; 520 } 521 522 #endif /* INCLUDE_CMD_MOVE */ 523