Ignore:
File:
1 edited

Legend:

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

    re367f5b8 r6348376  
    3030#include <stdlib.h>
    3131#include <unistd.h>
    32 #include <io/console.h>
    33 #include <io/keycode.h>
    3432#include <getopt.h>
    3533#include <str.h>
    3634#include <fcntl.h>
    37 #include <sys/stat.h>
    38 #include <dirent.h>
    3935#include "config.h"
    4036#include "util.h"
     
    4844
    4945static const char *cmdname = "cp";
    50 static console_ctrl_t *con;
    5146
    5247static struct option const long_options[] = {
    5348        { "buffer", required_argument, 0, 'b' },
    5449        { "force", no_argument, 0, 'f' },
    55         { "interactive", no_argument, 0, 'i'},
    5650        { "recursive", no_argument, 0, 'r' },
    5751        { "help", no_argument, 0, 'h' },
     
    6155};
    6256
    63 typedef enum {
    64         TYPE_NONE,
    65         TYPE_FILE,
    66         TYPE_DIR
    67 } 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 
    9657static int strtoint(const char *s1)
    9758{
     
    10566
    10667        return (int) t1;
    107 }
    108 
    109 /** Get the last component of a path.
    110  *
    111  * e.g. /data/a  ---> a
    112  *
    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         else
    125                 return ptr + 1;
    126 }
    127 
    128 /** Merge two paths together.
    129  *
    130  * e.g. (path1 = /data/dir, path2 = a/b) --> /data/dir/a/b
    131  *
    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 is
    292                                  * 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 wants
    306                          * to specify the name of the destination directory
    307                          *
    308                          * e.g. cp -r /src /data/new_dir_src
    309                          */
    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 the
    326                  * 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         } else
    363                 printf("Unable to open source file %s\n", src);
    364 
    365 exit:
    366         if (dir)
    367                 closedir(dir);
    368         return r;
    36968}
    37069
     
    428127        static char helpfmt[] =
    429128            "Usage:  %s [options] <source> <dest>\n"
    430             "Options:\n"
     129            "Options: (* indicates not yet implemented)\n"
    431130            "  -h, --help       A short option summary\n"
    432131            "  -v, --version    Print version information and exit\n"
    433             "  -V, --verbose    Be annoyingly noisy about what's being done\n"
    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";
    438137        if (level == HELP_SHORT) {
    439138                printf("`%s' copies files and directories\n", cmdname);
    440139        } else {
    441140                help_cmd_cp(HELP_SHORT);
    442                 printf(helpfmt, cmdname);
     141                printf(helpfmt, cmdname, cmdname);
    443142        }
    444143
     
    449148{
    450149        unsigned int argc, verbose = 0;
    451         int buffer = 0, recursive = 0;
    452         int force = 0, interactive = 0;
     150        int buffer = 0;
    453151        int c, opt_ind;
    454152        int64_t ret;
    455153
    456         con = console_init(stdin, stdout);
    457154        argc = cli_count_args(argv);
    458155
    459156        for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
    460                 c = getopt_long(argc, argv, "hvVfirb:", long_options, &opt_ind);
     157                c = getopt_long(argc, argv, "hvVfrb:", long_options, &opt_ind);
    461158                switch (c) {
    462159                case 'h':
     
    470167                        break;
    471168                case 'f':
    472                         interactive = 0;
    473                         force = 1;
    474                         break;
    475                 case 'i':
    476                         force = 0;
    477                         interactive = 1;
    478169                        break;
    479170                case 'r':
    480                         recursive = 1;
    481171                        break;
    482172                case 'b':
     
    485175                                    "(should be a number greater than zero)\n",
    486176                                    cmdname);
    487                                 console_done(con);
    488177                                return CMD_FAILURE;
    489178                        }
     
    502191                printf("%s: invalid number of arguments. Try %s --help\n",
    503192                    cmdname, cmdname);
    504                 console_done(con);
    505193                return CMD_FAILURE;
    506194        }
    507195
    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)
    514202                return CMD_SUCCESS;
    515203        else
Note: See TracChangeset for help on using the changeset viewer.