Changes in uspace/app/bdsh/cmds/modules/cp/cp.c [e367f5b8:6348376] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/bdsh/cmds/modules/cp/cp.c
re367f5b8 r6348376 30 30 #include <stdlib.h> 31 31 #include <unistd.h> 32 #include <io/console.h>33 #include <io/keycode.h>34 32 #include <getopt.h> 35 33 #include <str.h> 36 34 #include <fcntl.h> 37 #include <sys/stat.h>38 #include <dirent.h>39 35 #include "config.h" 40 36 #include "util.h" … … 48 44 49 45 static const char *cmdname = "cp"; 50 static console_ctrl_t *con;51 46 52 47 static struct option const long_options[] = { 53 48 { "buffer", required_argument, 0, 'b' }, 54 49 { "force", no_argument, 0, 'f' }, 55 { "interactive", no_argument, 0, 'i'},56 50 { "recursive", no_argument, 0, 'r' }, 57 51 { "help", no_argument, 0, 'h' }, … … 61 55 }; 62 56 63 typedef enum {64 TYPE_NONE,65 TYPE_FILE,66 TYPE_DIR67 } dentry_type_t;68 69 static int64_t copy_file(const char *src, const char *dest,70 size_t blen, int vb);71 72 /** Get the type of a directory entry.73 *74 * @param path Path of the directory entry.75 *76 * @return TYPE_DIR if the dentry is a directory.77 * @return TYPE_FILE if the dentry is a file.78 * @return TYPE_NONE if the dentry does not exists.79 */80 static dentry_type_t get_type(const char *path)81 {82 struct stat s;83 84 int r = stat(path, &s);85 86 if (r)87 return TYPE_NONE;88 else if (s.is_directory)89 return TYPE_DIR;90 else if (s.is_file)91 return TYPE_FILE;92 93 return TYPE_NONE;94 }95 96 57 static int strtoint(const char *s1) 97 58 { … … 105 66 106 67 return (int) t1; 107 }108 109 /** Get the last component of a path.110 *111 * e.g. /data/a ---> a112 *113 * @param path Pointer to the path.114 *115 * @return Pointer to the last component or to the path itself.116 */117 static char *get_last_path_component(char *path)118 {119 char *ptr;120 121 ptr = str_rchr(path, '/');122 if (!ptr)123 return path;124 else125 return ptr + 1;126 }127 128 /** Merge two paths together.129 *130 * e.g. (path1 = /data/dir, path2 = a/b) --> /data/dir/a/b131 *132 * @param path1 Path to which path2 will be appended.133 * @param path1_size Size of the path1 buffer.134 * @param path2 Path that will be appended to path1.135 */136 static void merge_paths(char *path1, size_t path1_size, char *path2)137 {138 const char *delim = "/";139 140 str_rtrim(path1, '/');141 str_append(path1, path1_size, delim);142 str_append(path1, path1_size, path2);143 }144 145 static bool get_user_decision(bool bdefault, const char *message, ...)146 {147 va_list args;148 149 va_start(args, message);150 vprintf(message, args);151 va_end(args);152 153 while (true) {154 kbd_event_t ev;155 console_flush(con);156 console_get_kbd_event(con, &ev);157 if ((ev.type != KEY_PRESS)158 || (ev.mods & (KM_CTRL | KM_ALT)) != 0) {159 continue;160 }161 162 switch(ev.key) {163 case KC_Y:164 printf("y\n");165 return true;166 case KC_N:167 printf("n\n");168 return false;169 case KC_ENTER:170 printf("%c\n", bdefault ? 'Y' : 'N');171 return bdefault;172 default:173 break;174 }175 }176 }177 178 static int64_t do_copy(const char *src, const char *dest,179 size_t blen, int vb, int recursive, int force, int interactive)180 {181 int r = -1;182 char dest_path[PATH_MAX];183 char src_path[PATH_MAX];184 DIR *dir = NULL;185 struct dirent *dp;186 187 dentry_type_t src_type = get_type(src);188 dentry_type_t dest_type = get_type(dest);189 190 const size_t src_len = str_size(src);191 192 if (src_type == TYPE_FILE) {193 char *src_fname;194 195 /* Initialize the src_path with the src argument */196 str_cpy(src_path, src_len + 1, src);197 str_rtrim(src_path, '/');198 199 /* Get the last component name from the src path */200 src_fname = get_last_path_component(src_path);201 202 /* Initialize dest_path with the dest argument */203 str_cpy(dest_path, PATH_MAX, dest);204 205 if (dest_type == TYPE_DIR) {206 /* e.g. cp file_name /data */207 /* e.g. cp file_name /data/ */208 209 /* dest is a directory,210 * append the src filename to it.211 */212 merge_paths(dest_path, PATH_MAX, src_fname);213 dest_type = get_type(dest_path);214 } else if (dest_type == TYPE_NONE) {215 if (dest_path[str_size(dest_path) - 1] == '/') {216 /* e.g. cp /textdemo /data/dirnotexists/ */217 218 printf("The dest directory %s does not exists",219 dest_path);220 goto exit;221 }222 }223 224 if (dest_type == TYPE_DIR) {225 printf("Cannot overwrite existing directory %s\n",226 dest_path);227 goto exit;228 } else if (dest_type == TYPE_FILE) {229 /* e.g. cp file_name existing_file */230 231 /* dest already exists,232 * if force is set we will try to remove it.233 * if interactive is set user input is required.234 */235 if (force && !interactive) {236 if (unlink(dest_path)) {237 printf("Unable to remove %s\n",238 dest_path);239 goto exit;240 }241 } else if (!force && interactive) {242 bool overwrite = get_user_decision(false,243 "File already exists: %s. Overwrite? [y/N]: ",244 dest_path);245 if (overwrite) {246 printf("Overwriting file: %s\n", dest_path);247 if (unlink(dest_path)) {248 printf("Unable to remove %s\n", dest_path);249 goto exit;250 }251 } else {252 printf("Not overwriting file: %s\n", dest_path);253 r = 0;254 goto exit;255 }256 } else {257 printf("File already exists: %s\n", dest_path);258 goto exit;259 }260 }261 262 /* call copy_file and exit */263 r = (copy_file(src, dest_path, blen, vb) < 0);264 265 } else if (src_type == TYPE_DIR) {266 /* e.g. cp -r /x/srcdir /y/destdir/ */267 268 if (!recursive) {269 printf("Cannot copy the %s directory without the "270 "-r option\n", src);271 goto exit;272 } else if (dest_type == TYPE_FILE) {273 printf("Cannot overwrite a file with a directory\n");274 goto exit;275 }276 277 char *src_dirname;278 279 /* Initialize src_path with the content of src */280 str_cpy(src_path, src_len + 1, src);281 str_rtrim(src_path, '/');282 283 src_dirname = get_last_path_component(src_path);284 285 str_cpy(dest_path, PATH_MAX, dest);286 287 switch (dest_type) {288 case TYPE_DIR:289 if (str_cmp(src_dirname, "..") &&290 str_cmp(src_dirname, ".")) {291 /* The last component of src_path is292 * not '.' or '..'293 */294 merge_paths(dest_path, PATH_MAX, src_dirname);295 296 if (mkdir(dest_path, 0) == -1) {297 printf("Unable to create "298 "dest directory %s\n", dest_path);299 goto exit;300 }301 }302 break;303 default:304 case TYPE_NONE:305 /* dest does not exists, this means the user wants306 * to specify the name of the destination directory307 *308 * e.g. cp -r /src /data/new_dir_src309 */310 if (mkdir(dest_path, 0)) {311 printf("Unable to create "312 "dest directory %s\n", dest_path);313 goto exit;314 }315 break;316 }317 318 dir = opendir(src);319 if (!dir) {320 /* Something strange is happening... */321 printf("Unable to open src %s directory\n", src);322 goto exit;323 }324 325 /* Copy every single directory entry of src into the326 * destination directory.327 */328 while ((dp = readdir(dir))) {329 struct stat src_s;330 struct stat dest_s;331 332 char src_dent[PATH_MAX];333 char dest_dent[PATH_MAX];334 335 str_cpy(src_dent, PATH_MAX, src);336 merge_paths(src_dent, PATH_MAX, dp->d_name);337 338 str_cpy(dest_dent, PATH_MAX, dest_path);339 merge_paths(dest_dent, PATH_MAX, dp->d_name);340 341 /* Check if we are copying a directory into itself */342 stat(src_dent, &src_s);343 stat(dest_path, &dest_s);344 345 if (dest_s.index == src_s.index &&346 dest_s.fs_handle == src_s.fs_handle) {347 printf("Cannot copy a directory "348 "into itself\n");349 goto exit;350 }351 352 if (vb)353 printf("copy %s %s\n", src_dent, dest_dent);354 355 /* Recursively call do_copy() */356 r = do_copy(src_dent, dest_dent, blen, vb, recursive,357 force, interactive);358 if (r)359 goto exit;360 361 }362 } else363 printf("Unable to open source file %s\n", src);364 365 exit:366 if (dir)367 closedir(dir);368 return r;369 68 } 370 69 … … 428 127 static char helpfmt[] = 429 128 "Usage: %s [options] <source> <dest>\n" 430 "Options: \n"129 "Options: (* indicates not yet implemented)\n" 431 130 " -h, --help A short option summary\n" 432 131 " -v, --version Print version information and exit\n" 433 " 434 " -f, --force Do not complain when <dest> exists (overrides a previous -i)\n"435 " -i, --interactive Ask what to do when <dest> exists (overrides a previous -f)\n"436 " - r, --recursive Copy entire directories\n"437 " -b, --buffer ## Set the read buffer size to ##\n";132 "* -V, --verbose Be annoyingly noisy about what's being done\n" 133 "* -f, --force Do not complain when <dest> exists\n" 134 "* -r, --recursive Copy entire directories\n" 135 " -b, --buffer ## Set the read buffer size to ##\n" 136 "Currently, %s is under development, some options may not work.\n"; 438 137 if (level == HELP_SHORT) { 439 138 printf("`%s' copies files and directories\n", cmdname); 440 139 } else { 441 140 help_cmd_cp(HELP_SHORT); 442 printf(helpfmt, cmdname );141 printf(helpfmt, cmdname, cmdname); 443 142 } 444 143 … … 449 148 { 450 149 unsigned int argc, verbose = 0; 451 int buffer = 0, recursive = 0; 452 int force = 0, interactive = 0; 150 int buffer = 0; 453 151 int c, opt_ind; 454 152 int64_t ret; 455 153 456 con = console_init(stdin, stdout);457 154 argc = cli_count_args(argv); 458 155 459 156 for (c = 0, optind = 0, opt_ind = 0; c != -1;) { 460 c = getopt_long(argc, argv, "hvVf irb:", long_options, &opt_ind);157 c = getopt_long(argc, argv, "hvVfrb:", long_options, &opt_ind); 461 158 switch (c) { 462 159 case 'h': … … 470 167 break; 471 168 case 'f': 472 interactive = 0;473 force = 1;474 break;475 case 'i':476 force = 0;477 interactive = 1;478 169 break; 479 170 case 'r': 480 recursive = 1;481 171 break; 482 172 case 'b': … … 485 175 "(should be a number greater than zero)\n", 486 176 cmdname); 487 console_done(con);488 177 return CMD_FAILURE; 489 178 } … … 502 191 printf("%s: invalid number of arguments. Try %s --help\n", 503 192 cmdname, cmdname); 504 console_done(con);505 193 return CMD_FAILURE; 506 194 } 507 195 508 ret = do_copy(argv[optind], argv[optind + 1], buffer, verbose,509 recursive, force, interactive); 510 511 console_done(con);512 513 if (ret == 0)196 ret = copy_file(argv[optind], argv[optind + 1], buffer, verbose); 197 198 if (verbose) 199 printf("%" PRId64 " bytes copied\n", ret); 200 201 if (ret >= 0) 514 202 return CMD_SUCCESS; 515 203 else
Note:
See TracChangeset
for help on using the changeset viewer.