Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/bdsh/cmds/modules/cp/cp.c

    r1737bfb r6348376  
    3333#include <str.h>
    3434#include <fcntl.h>
    35 #include <sys/stat.h>
    36 #include <dirent.h>
    3735#include "config.h"
    3836#include "util.h"
     
    5755};
    5856
    59 typedef enum {
    60         TYPE_NONE,
    61         TYPE_FILE,
    62         TYPE_DIR
    63 } 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 
    9257static int strtoint(const char *s1)
    9358{
     
    10267        return (int) t1;
    10368}
    104 
    105 /** Get the last component of a path.
    106  *
    107  * e.g. /data/a  ---> a
    108  *
    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         else
    121                 return ptr + 1;
    122 }
    123 
    124 /** Merge two paths together.
    125  *
    126  * e.g. (path1 = /data/dir, path2 = a/b) --> /data/dir/a/b
    127  *
    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 will
    195                          * 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 is
    239                                  * 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 wants
    253                          * to specify the name of the destination directory
    254                          *
    255                          * e.g. cp -r /src /data/new_dir_src
    256                          */
    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 the
    273                  * 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         } else
    310                 printf("Unable to open source file %s\n", src);
    311 
    312 exit:
    313         if (dir)
    314                 closedir(dir);
    315         return r;
    316 }
    317 
    31869
    31970static int64_t copy_file(const char *src, const char *dest,
     
    376127        static char helpfmt[] =
    377128            "Usage:  %s [options] <source> <dest>\n"
    378             "Options:\n"
     129            "Options: (* indicates not yet implemented)\n"
    379130            "  -h, --help       A short option summary\n"
    380131            "  -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";
     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";
    385137        if (level == HELP_SHORT) {
    386138                printf("`%s' copies files and directories\n", cmdname);
    387139        } else {
    388140                help_cmd_cp(HELP_SHORT);
    389                 printf(helpfmt, cmdname);
     141                printf(helpfmt, cmdname, cmdname);
    390142        }
    391143
     
    396148{
    397149        unsigned int argc, verbose = 0;
    398         int buffer = 0, recursive = 0;
    399         int force = 0;
     150        int buffer = 0;
    400151        int c, opt_ind;
    401152        int64_t ret;
     
    416167                        break;
    417168                case 'f':
    418                         force = 1;
    419169                        break;
    420170                case 'r':
    421                         recursive = 1;
    422171                        break;
    423172                case 'b':
     
    445194        }
    446195
    447         ret = do_copy(argv[optind], argv[optind + 1], buffer, verbose,
    448             recursive, force);
    449 
    450         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)
    451202                return CMD_SUCCESS;
    452203        else
Note: See TracChangeset for help on using the changeset viewer.