1/* vi: set sw=4 ts=4: */ 2/* 3 * Mini mv implementation for busybox 4 * 5 * 6 * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 */ 23 24#include <sys/types.h> 25#include <sys/stat.h> 26#include <unistd.h> 27#include <dirent.h> 28#include <errno.h> 29#include <stdlib.h> 30 31#include "busybox.h" 32 33static int flags; 34 35static int manual_rename(const char *source, const char *dest) 36{ 37 struct stat source_stat; 38 struct stat dest_stat; 39 int source_exists = 1; 40 int dest_exists = 1; 41 42 if (stat(source, &source_stat) < 0) { 43 if (errno != ENOENT) { 44 perror_msg("unable to stat `%s'", source); 45 return -1; 46 } 47 source_exists = 0; 48 } 49 50 if (stat(dest, &dest_stat) < 0) { 51 if (errno != ENOENT) { 52 perror_msg("unable to stat `%s'", dest); 53 return -1; 54 } 55 dest_exists = 0; 56 } 57 58 if (dest_exists) { 59 if (S_ISDIR(dest_stat.st_mode) && 60 (!source_exists || !S_ISDIR(source_stat.st_mode))) { 61 error_msg("cannot overwrite directory with non-directory"); 62 return -1; 63 } 64 65 if (!S_ISDIR(dest_stat.st_mode) && source_exists && 66 S_ISDIR(source_stat.st_mode)) { 67 error_msg("cannot overwrite non-directory with directory"); 68 return -1; 69 } 70 71 if (unlink(dest) < 0) { 72 perror_msg("cannot remove `%s'", dest); 73 return -1; 74 } 75 } 76 77 if (copy_file(source, dest, FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS | 78 FILEUTILS_PRESERVE_SYMLINKS) < 0) 79 return -1; 80 81 if (remove_file(source, FILEUTILS_RECUR | FILEUTILS_FORCE) < 0) 82 return -1; 83 84 return 0; 85} 86 87static int move_file(const char *source, const char *dest) 88{ 89 struct stat dest_stat; 90 int dest_exists = 1; 91 92 if (stat(dest, &dest_stat) < 0) { 93 if (errno != ENOENT) { 94 perror_msg("unable to stat `%s'", dest); 95 return -1; 96 } 97 dest_exists = 0; 98 } 99 100 if (dest_exists && !(flags & FILEUTILS_FORCE) && 101 ((access(dest, W_OK) < 0 && isatty(0)) || 102 (flags & FILEUTILS_INTERACTIVE))) { 103 fprintf(stderr, "mv: overwrite `%s'? ", dest); 104 if (!ask_confirmation()) 105 return 0; 106 } 107 108 if (rename(source, dest) < 0) { 109 if (errno == EXDEV) 110 return manual_rename(source, dest); 111 112 perror_msg("unable to rename `%s'", source); 113 return -1; 114 } 115 116 return 0; 117} 118 119extern int mv_main(int argc, char **argv) 120{ 121 int status = 0; 122 int opt; 123 int i; 124 125 while ((opt = getopt(argc, argv, "fi")) != -1) 126 switch (opt) { 127 case 'f': 128 flags &= ~FILEUTILS_INTERACTIVE; 129 flags |= FILEUTILS_FORCE; 130 break; 131 case 'i': 132 flags &= ~FILEUTILS_FORCE; 133 flags |= FILEUTILS_INTERACTIVE; 134 break; 135 default: 136 show_usage(); 137 } 138 139 if (optind + 2 > argc) 140 show_usage(); 141 142 if (optind + 2 == argc) { 143 struct stat dest_stat; 144 int dest_exists = 1; 145 146 if (stat(argv[optind + 1], &dest_stat) < 0) { 147 if (errno != ENOENT) 148 perror_msg_and_die("unable to stat `%s'", argv[optind + 1]); 149 dest_exists = 0; 150 } 151 152 if (!dest_exists || !S_ISDIR(dest_stat.st_mode)) { 153 if (move_file(argv[optind], argv[optind + 1]) < 0) 154 status = 1; 155 return status; 156 } 157 } 158 159 for (i = optind; i < argc - 1; i++) { 160 char *dest = concat_path_file(argv[argc - 1], 161 get_last_path_component(argv[i])); 162 if (move_file(argv[i], dest) < 0) 163 status = 1; 164 free(dest); 165 } 166 167 return status; 168} 169