Changes in uspace/app/bdsh/cmds/modules/cp/cp.c [1737bfb:2815505] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/bdsh/cmds/modules/cp/cp.c
r1737bfb r2815505 1 /* 2 * Copyright (c) 2008 Tim Post 1 /* Copyright (c) 2008, Tim Post <tinkertim@gmail.com> 3 2 * All rights reserved. 4 3 * 5 4 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * - Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * - Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * - The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. 9 * 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * Neither the name of the original program's authors nor the names of its 15 * contributors may be used to endorse or promote products derived from this 16 * software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 27 29 */ 28 30 … … 33 35 #include <str.h> 34 36 #include <fcntl.h> 35 #include <sys/stat.h>36 #include <dirent.h>37 37 #include "config.h" 38 38 #include "util.h" … … 57 57 }; 58 58 59 typedef enum {60 TYPE_NONE,61 TYPE_FILE,62 TYPE_DIR63 } dentry_type_t;64 65 static int64_t copy_file(const char *src, const char *dest,66 size_t blen, int vb);67 68 /** Get the type of a directory entry.69 *70 * @param path Path of the directory entry.71 *72 * @return TYPE_DIR if the dentry is a directory.73 * @return TYPE_FILE if the dentry is a file.74 * @return TYPE_NONE if the dentry does not exists.75 */76 static dentry_type_t get_type(const char *path)77 {78 struct stat s;79 80 int r = stat(path, &s);81 82 if (r)83 return TYPE_NONE;84 else if (s.is_directory)85 return TYPE_DIR;86 else if (s.is_file)87 return TYPE_FILE;88 89 return TYPE_NONE;90 }91 92 59 static int strtoint(const char *s1) 93 60 { … … 102 69 return (int) t1; 103 70 } 104 105 /** Get the last component of a path.106 *107 * e.g. /data/a ---> a108 *109 * @param path Pointer to the path.110 *111 * @return Pointer to the last component or to the path itself.112 */113 static char *get_last_path_component(char *path)114 {115 char *ptr;116 117 ptr = str_rchr(path, '/');118 if (!ptr)119 return path;120 else121 return ptr + 1;122 }123 124 /** Merge two paths together.125 *126 * e.g. (path1 = /data/dir, path2 = a/b) --> /data/dir/a/b127 *128 * @param path1 Path to which path2 will be appended.129 * @param path1_size Size of the path1 buffer.130 * @param path2 Path that will be appended to path1.131 */132 static void merge_paths(char *path1, size_t path1_size, char *path2)133 {134 const char *delim = "/";135 136 str_rtrim(path1, '/');137 str_append(path1, path1_size, delim);138 str_append(path1, path1_size, path2);139 }140 141 static int64_t do_copy(const char *src, const char *dest,142 size_t blen, int vb, int recursive, int force)143 {144 int r = -1;145 char dest_path[PATH_MAX];146 char src_path[PATH_MAX];147 DIR *dir = NULL;148 struct dirent *dp;149 150 dentry_type_t src_type = get_type(src);151 dentry_type_t dest_type = get_type(dest);152 153 const size_t src_len = str_size(src);154 155 if (src_type == TYPE_FILE) {156 char *src_fname;157 158 /* Initialize the src_path with the src argument */159 str_cpy(src_path, src_len + 1, src);160 str_rtrim(src_path, '/');161 162 /* Get the last component name from the src path */163 src_fname = get_last_path_component(src_path);164 165 /* Initialize dest_path with the dest argument */166 str_cpy(dest_path, PATH_MAX, dest);167 168 if (dest_type == TYPE_DIR) {169 /* e.g. cp file_name /data */170 /* e.g. cp file_name /data/ */171 172 /* dest is a directory,173 * append the src filename to it.174 */175 merge_paths(dest_path, PATH_MAX, src_fname);176 dest_type = get_type(dest_path);177 } else if (dest_type == TYPE_NONE) {178 if (dest_path[str_size(dest_path) - 1] == '/') {179 /* e.g. cp /textdemo /data/dirnotexists/ */180 181 printf("The dest directory %s does not exists",182 dest_path);183 goto exit;184 }185 }186 187 if (dest_type == TYPE_DIR) {188 printf("Cannot overwrite existing directory %s\n",189 dest_path);190 goto exit;191 } else if (dest_type == TYPE_FILE) {192 /* e.g. cp file_name existing_file */193 194 /* dest already exists, if force is set we will195 * try to remove it.196 */197 if (force) {198 if (unlink(dest_path)) {199 printf("Unable to remove %s\n",200 dest_path);201 goto exit;202 }203 } else {204 printf("file already exists: %s\n", dest_path);205 goto exit;206 }207 }208 209 /* call copy_file and exit */210 r = (copy_file(src, dest_path, blen, vb) < 0);211 212 } else if (src_type == TYPE_DIR) {213 /* e.g. cp -r /x/srcdir /y/destdir/ */214 215 if (!recursive) {216 printf("Cannot copy the %s directory without the "217 "-r option\n", src);218 goto exit;219 } else if (dest_type == TYPE_FILE) {220 printf("Cannot overwrite a file with a directory\n");221 goto exit;222 }223 224 char *src_dirname;225 226 /* Initialize src_path with the content of src */227 str_cpy(src_path, src_len + 1, src);228 str_rtrim(src_path, '/');229 230 src_dirname = get_last_path_component(src_path);231 232 str_cpy(dest_path, PATH_MAX, dest);233 234 switch (dest_type) {235 case TYPE_DIR:236 if (str_cmp(src_dirname, "..") &&237 str_cmp(src_dirname, ".")) {238 /* The last component of src_path is239 * not '.' or '..'240 */241 merge_paths(dest_path, PATH_MAX, src_dirname);242 243 if (mkdir(dest_path, 0) == -1) {244 printf("Unable to create "245 "dest directory %s\n", dest_path);246 goto exit;247 }248 }249 break;250 default:251 case TYPE_NONE:252 /* dest does not exists, this means the user wants253 * to specify the name of the destination directory254 *255 * e.g. cp -r /src /data/new_dir_src256 */257 if (mkdir(dest_path, 0)) {258 printf("Unable to create "259 "dest directory %s\n", dest_path);260 goto exit;261 }262 break;263 }264 265 dir = opendir(src);266 if (!dir) {267 /* Something strange is happening... */268 printf("Unable to open src %s directory\n", src);269 goto exit;270 }271 272 /* Copy every single directory entry of src into the273 * destination directory.274 */275 while ((dp = readdir(dir))) {276 struct stat src_s;277 struct stat dest_s;278 279 char src_dent[PATH_MAX];280 char dest_dent[PATH_MAX];281 282 str_cpy(src_dent, PATH_MAX, src);283 merge_paths(src_dent, PATH_MAX, dp->d_name);284 285 str_cpy(dest_dent, PATH_MAX, dest_path);286 merge_paths(dest_dent, PATH_MAX, dp->d_name);287 288 /* Check if we are copying a directory into itself */289 stat(src_dent, &src_s);290 stat(dest_path, &dest_s);291 292 if (dest_s.index == src_s.index &&293 dest_s.fs_handle == src_s.fs_handle) {294 printf("Cannot copy a directory "295 "into itself\n");296 goto exit;297 }298 299 if (vb)300 printf("copy %s %s\n", src_dent, dest_dent);301 302 /* Recursively call do_copy() */303 r = do_copy(src_dent, dest_dent, blen, vb, recursive,304 force);305 if (r)306 goto exit;307 308 }309 } else310 printf("Unable to open source file %s\n", src);311 312 exit:313 if (dir)314 closedir(dir);315 return r;316 }317 318 71 319 72 static int64_t copy_file(const char *src, const char *dest, 320 73 size_t blen, int vb) 321 74 { 322 int fd1, fd2, bytes ;323 off64_t total ;75 int fd1, fd2, bytes = 0; 76 off64_t total = 0; 324 77 int64_t copied = 0; 325 78 char *buff = NULL; … … 353 106 } 354 107 355 while ((bytes = read_all(fd1, buff, blen)) > 0) { 356 if ((bytes = write_all(fd2, buff, bytes)) < 0) 108 for (;;) { 109 ssize_t res; 110 size_t written = 0; 111 112 bytes = read(fd1, buff, blen); 113 if (bytes <= 0) 357 114 break; 358 115 copied += bytes; 116 res = bytes; 117 do { 118 /* 119 * Theoretically, it may not be enough to call write() 120 * only once. Also the previous read() may have 121 * returned less data than requested. 122 */ 123 bytes = write(fd2, buff + written, res); 124 if (bytes < 0) 125 goto err; 126 written += bytes; 127 res -= bytes; 128 } while (res > 0); 129 130 /* TODO: re-insert assert() once this is stand alone, 131 * removed as abort() exits the entire shell 132 */ 133 if (res != 0) { 134 printf("\n%zd more bytes than actually exist were copied\n", res); 135 goto err; 136 } 359 137 } 360 138 361 139 if (bytes < 0) { 140 err: 362 141 printf("\nError copying %s, (%d)\n", src, bytes); 363 142 copied = bytes; … … 376 155 static char helpfmt[] = 377 156 "Usage: %s [options] <source> <dest>\n" 378 "Options: \n"157 "Options: (* indicates not yet implemented)\n" 379 158 " -h, --help A short option summary\n" 380 159 " -v, --version Print version information and exit\n" 381 " -V, --verbose Be annoyingly noisy about what's being done\n" 382 " -f, --force Do not complain when <dest> exists\n" 383 " -r, --recursive Copy entire directories\n" 384 " -b, --buffer ## Set the read buffer size to ##\n"; 160 "* -V, --verbose Be annoyingly noisy about what's being done\n" 161 "* -f, --force Do not complain when <dest> exists\n" 162 "* -r, --recursive Copy entire directories\n" 163 " -b, --buffer ## Set the read buffer size to ##\n" 164 "Currently, %s is under development, some options may not work.\n"; 385 165 if (level == HELP_SHORT) { 386 166 printf("`%s' copies files and directories\n", cmdname); 387 167 } else { 388 168 help_cmd_cp(HELP_SHORT); 389 printf(helpfmt, cmdname );169 printf(helpfmt, cmdname, cmdname); 390 170 } 391 171 … … 396 176 { 397 177 unsigned int argc, verbose = 0; 398 int buffer = 0, recursive = 0; 399 int force = 0; 178 int buffer = 0; 400 179 int c, opt_ind; 401 180 int64_t ret; … … 416 195 break; 417 196 case 'f': 418 force = 1;419 197 break; 420 198 case 'r': 421 recursive = 1;422 199 break; 423 200 case 'b': … … 445 222 } 446 223 447 ret = do_copy(argv[optind], argv[optind + 1], buffer, verbose, 448 recursive, force); 449 450 if (ret == 0) 224 ret = copy_file(argv[optind], argv[optind + 1], buffer, verbose); 225 226 if (verbose) 227 printf("%" PRId64 " bytes copied\n", ret); 228 229 if (ret >= 0) 451 230 return CMD_SUCCESS; 452 231 else
Note:
See TracChangeset
for help on using the changeset viewer.