Rev 3448 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3448 | Rev 3674 | ||
---|---|---|---|
Line 28... | Line 28... | ||
28 | * POSSIBILITY OF SUCH DAMAGE. |
28 | * POSSIBILITY OF SUCH DAMAGE. |
29 | */ |
29 | */ |
30 | 30 | ||
31 | #include <stdio.h> |
31 | #include <stdio.h> |
32 | #include <stdlib.h> |
32 | #include <stdlib.h> |
- | 33 | #include <unistd.h> |
|
- | 34 | #include <getopt.h> |
|
- | 35 | #include <string.h> |
|
- | 36 | #include <fcntl.h> |
|
- | 37 | #include <assert.h> |
|
33 | #include "config.h" |
38 | #include "config.h" |
34 | #include "util.h" |
39 | #include "util.h" |
35 | #include "errors.h" |
40 | #include "errors.h" |
36 | #include "entry.h" |
41 | #include "entry.h" |
37 | #include "cp.h" |
42 | #include "cp.h" |
38 | #include "cmds.h" |
43 | #include "cmds.h" |
39 | 44 | ||
- | 45 | #define CP_VERSION "0.0.1" |
|
- | 46 | #define CP_DEFAULT_BUFLEN 1024 |
|
- | 47 | ||
40 | static char *cmdname = "cp"; |
48 | static const char *cmdname = "cp"; |
- | 49 | ||
- | 50 | static struct option const long_options[] = { |
|
- | 51 | { "buffer", required_argument, 0, 'b' }, |
|
- | 52 | { "force", no_argument, 0, 'f' }, |
|
- | 53 | { "recursive", no_argument, 0, 'r' }, |
|
- | 54 | { "help", no_argument, 0, 'h' }, |
|
- | 55 | { "version", no_argument, 0, 'v' }, |
|
- | 56 | { "verbose", no_argument, 0, 'V' }, |
|
- | 57 | { 0, 0, 0, 0 } |
|
- | 58 | }; |
|
- | 59 | ||
- | 60 | static int strtoint(const char *s1) |
|
- | 61 | { |
|
- | 62 | long t1; |
|
- | 63 | ||
- | 64 | if (-1 == (t1 = strtol(s1, (char **) NULL, 10))) |
|
- | 65 | return -1; |
|
- | 66 | ||
- | 67 | if (t1 <= 0) |
|
- | 68 | return -1; |
|
- | 69 | ||
- | 70 | return (int) t1; |
|
- | 71 | } |
|
- | 72 | ||
- | 73 | static int64_t copy_file(const char *src, const char *dest, size_t blen, int vb) |
|
- | 74 | { |
|
- | 75 | int fd1, fd2, bytes = 0; |
|
- | 76 | off_t total = 0; |
|
- | 77 | int64_t copied = 0; |
|
- | 78 | char *buff = NULL; |
|
- | 79 | ||
- | 80 | if (vb) |
|
- | 81 | printf("Copying %s to %s\n", src, dest); |
|
- | 82 | ||
- | 83 | if (-1 == (fd1 = open(src, O_RDONLY))) { |
|
- | 84 | printf("Unable to open source file %s\n", src); |
|
- | 85 | return -1; |
|
- | 86 | } |
|
- | 87 | ||
- | 88 | if (-1 == (fd2 = open(dest, O_CREAT))) { |
|
- | 89 | printf("Unable to open destination file %s\n", dest); |
|
- | 90 | close(fd1); |
|
- | 91 | return -1; |
|
- | 92 | } |
|
- | 93 | ||
- | 94 | total = lseek(fd1, 0, SEEK_END); |
|
- | 95 | ||
- | 96 | if (vb) |
|
- | 97 | printf("%d bytes to copy\n", total); |
|
- | 98 | ||
- | 99 | lseek(fd1, 0, SEEK_SET); |
|
- | 100 | ||
- | 101 | if (NULL == (buff = (char *) malloc(blen))) { |
|
- | 102 | printf("Unable to allocate enough memory to read %s\n", |
|
- | 103 | src); |
|
- | 104 | copied = -1; |
|
- | 105 | goto out; |
|
- | 106 | } |
|
- | 107 | ||
- | 108 | for (;;) { |
|
- | 109 | ssize_t res; |
|
- | 110 | ||
- | 111 | bytes = read(fd1, buff, blen); |
|
- | 112 | if (bytes <= 0) |
|
- | 113 | break; |
|
- | 114 | copied += bytes; |
|
- | 115 | res = bytes; |
|
- | 116 | do { |
|
- | 117 | /* |
|
- | 118 | * Theoretically, it may not be enough to call write() |
|
- | 119 | * only once. Also the previous read() may have |
|
- | 120 | * returned less data than requested. |
|
- | 121 | */ |
|
- | 122 | bytes = write(fd2, buff, res); |
|
- | 123 | if (bytes < 0) |
|
- | 124 | goto err; |
|
- | 125 | res -= bytes; |
|
- | 126 | } while (res > 0); |
|
- | 127 | assert(res == 0); |
|
- | 128 | } |
|
- | 129 | ||
- | 130 | if (bytes < 0) { |
|
- | 131 | err: |
|
- | 132 | printf("Error copying %s, (%d)\n", src, bytes); |
|
- | 133 | copied = bytes; |
|
- | 134 | } |
|
- | 135 | ||
- | 136 | out: |
|
- | 137 | close(fd1); |
|
- | 138 | close(fd2); |
|
- | 139 | if (buff) |
|
- | 140 | free(buff); |
|
- | 141 | return copied; |
|
- | 142 | } |
|
41 | 143 | ||
42 | /* Dispays help for cp in various levels */ |
- | |
43 | void help_cmd_cp(unsigned int level) |
144 | void help_cmd_cp(unsigned int level) |
44 | { |
145 | { |
- | 146 | static char helpfmt[] = |
|
- | 147 | "Usage: %s [options] <source> <dest>\n" |
|
- | 148 | "Options: (* indicates not yet implemented)\n" |
|
- | 149 | " -h, --help A short option summary\n" |
|
- | 150 | " -v, --version Print version information and exit\n" |
|
- | 151 | "* -V, --verbose Be annoyingly noisy about what's being done\n" |
|
- | 152 | "* -f, --force Do not complain when <dest> exists\n" |
|
- | 153 | "* -r, --recursive Copy entire directories\n" |
|
- | 154 | " -b, --buffer ## Set the read buffer size to ##\n" |
|
- | 155 | "Currently, %s is under development, some options may not work.\n"; |
|
- | 156 | if (level == HELP_SHORT) { |
|
45 | printf("This is the %s help for '%s'.\n", |
157 | printf("`%s' copies files and directories\n", cmdname); |
- | 158 | } else { |
|
- | 159 | help_cmd_cp(HELP_SHORT); |
|
46 | level ? EXT_HELP : SHORT_HELP, cmdname); |
160 | printf(helpfmt, cmdname, cmdname); |
- | 161 | } |
|
- | 162 | ||
47 | return; |
163 | return; |
48 | } |
164 | } |
49 | 165 | ||
50 | /* Main entry point for cp, accepts an array of arguments */ |
- | |
51 | int cmd_cp(char **argv) |
166 | int cmd_cp(char **argv) |
52 | { |
167 | { |
- | 168 | unsigned int argc, buffer = 0, verbose = 0; |
|
- | 169 | int c, opt_ind; |
|
53 | unsigned int argc; |
170 | int64_t ret; |
- | 171 | ||
- | 172 | argc = cli_count_args(argv); |
|
- | 173 | ||
- | 174 | for (c = 0, optind = 0, opt_ind = 0; c != -1;) { |
|
- | 175 | c = getopt_long(argc, argv, "hvVfrb:", long_options, &opt_ind); |
|
54 | unsigned int i; |
176 | switch (c) { |
- | 177 | case 'h': |
|
- | 178 | help_cmd_cp(1); |
|
- | 179 | return CMD_SUCCESS; |
|
- | 180 | case 'v': |
|
- | 181 | printf("%d\n", CP_VERSION); |
|
- | 182 | return CMD_SUCCESS; |
|
- | 183 | case 'V': |
|
- | 184 | verbose = 1; |
|
- | 185 | break; |
|
- | 186 | case 'f': |
|
- | 187 | break; |
|
- | 188 | case 'r': |
|
- | 189 | break; |
|
- | 190 | case 'b': |
|
- | 191 | if (-1 == (buffer = strtoint(optarg))) { |
|
- | 192 | printf("%s: Invalid buffer specification, " |
|
- | 193 | "(should be a number greater than zero)\n", |
|
- | 194 | cmdname); |
|
- | 195 | return CMD_FAILURE; |
|
- | 196 | } |
|
- | 197 | if (verbose) |
|
- | 198 | printf("Buffer = %d\n", buffer); |
|
- | 199 | break; |
|
- | 200 | } |
|
- | 201 | } |
|
55 | 202 | ||
56 | /* Count the arguments */ |
203 | if (buffer == 0) |
57 | for (argc = 0; argv[argc] != NULL; argc ++); |
204 | buffer = CP_DEFAULT_BUFLEN; |
58 | 205 | ||
59 | printf("%s %s\n", TEST_ANNOUNCE, cmdname); |
206 | argc -= optind; |
60 | printf("%d arguments passed to %s", argc - 1, cmdname); |
- | |
61 | 207 | ||
62 | if (argc < 2) { |
208 | if (argc != 2) { |
- | 209 | printf("%s: invalid number of arguments. Try %s --help\n", |
|
63 | printf("\n"); |
210 | cmdname, cmdname); |
64 | return CMD_SUCCESS; |
211 | return CMD_FAILURE; |
65 | } |
212 | } |
66 | 213 | ||
67 | printf(":\n"); |
214 | ret = copy_file(argv[optind], argv[optind + 1], buffer, verbose); |
- | 215 | ||
68 | for (i = 1; i < argc; i++) |
216 | if (verbose) |
69 | printf("[%d] -> %s\n", i, argv[i]); |
217 | printf("%d bytes copied\n", ret); |
70 | 218 | ||
- | 219 | if (ret >= 0) |
|
71 | return CMD_SUCCESS; |
220 | return CMD_SUCCESS; |
- | 221 | else |
|
- | 222 | return CMD_FAILURE; |
|
72 | } |
223 | } |
73 | 224 |