1 1.6 christos /* $NetBSD: utoppya.c,v 1.6 2015/06/16 22:54:11 christos Exp $ */ 2 1.1 scw 3 1.1 scw /*- 4 1.1 scw * Copyright (c) 2006 The NetBSD Foundation, Inc. 5 1.1 scw * All rights reserved. 6 1.1 scw * 7 1.1 scw * This code is derived from software contributed to The NetBSD Foundation 8 1.1 scw * by Steve C. Woodford. 9 1.1 scw * 10 1.1 scw * Redistribution and use in source and binary forms, with or without 11 1.1 scw * modification, are permitted provided that the following conditions 12 1.1 scw * are met: 13 1.1 scw * 1. Redistributions of source code must retain the above copyright 14 1.1 scw * notice, this list of conditions and the following disclaimer. 15 1.1 scw * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 scw * notice, this list of conditions and the following disclaimer in the 17 1.1 scw * documentation and/or other materials provided with the distribution. 18 1.1 scw * 19 1.1 scw * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 scw * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 scw * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 scw * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 scw * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 scw * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 scw * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 scw * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 scw * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 scw * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 scw * POSSIBILITY OF SUCH DAMAGE. 30 1.1 scw */ 31 1.1 scw 32 1.1 scw #include <sys/types.h> 33 1.1 scw #include <sys/stat.h> 34 1.1 scw #include <sys/ioctl.h> 35 1.1 scw 36 1.1 scw #include <err.h> 37 1.1 scw #include <errno.h> 38 1.1 scw #include <fcntl.h> 39 1.1 scw #include <libgen.h> 40 1.1 scw #include <sysexits.h> 41 1.1 scw #include <stdio.h> 42 1.1 scw #include <stdlib.h> 43 1.1 scw #include <strings.h> 44 1.1 scw #include <unistd.h> 45 1.1 scw #include <time.h> 46 1.2 martin #include <inttypes.h> 47 1.1 scw 48 1.1 scw #include <dev/usb/utoppy.h> 49 1.1 scw 50 1.1 scw #define GLOBAL 51 1.1 scw #include "progressbar.h" 52 1.1 scw 53 1.1 scw #define _PATH_DEV_UTOPPY "/dev/utoppy0" 54 1.1 scw 55 1.1 scw /* 56 1.1 scw * This looks weird for a reason. The toppy protocol allows for data to be 57 1.1 scw * transferred in 65535-byte chunks only. Anything more than this has to be 58 1.1 scw * split within the driver. The following value leaves enough space for the 59 1.1 scw * packet header plus some alignmnent slop. 60 1.1 scw */ 61 1.1 scw #define TOPPY_IO_SIZE 0xffec 62 1.1 scw 63 1.1 scw static int toppy_fd; 64 1.1 scw 65 1.1 scw static void cmd_df(int, char **); 66 1.1 scw static void cmd_ls(int, char **); 67 1.1 scw static void cmd_rm(int, char **); 68 1.1 scw static void cmd_mkdir(int, char **); 69 1.1 scw static void cmd_rename(int, char **); 70 1.1 scw static void cmd_get(int, char **); 71 1.1 scw static void cmd_put(int, char **); 72 1.1 scw 73 1.5 joerg static const struct toppy_command { 74 1.1 scw const char *tc_cmd; 75 1.1 scw void (*tc_handler)(int, char **); 76 1.1 scw } toppy_commands[] = { 77 1.1 scw {"df", cmd_df}, 78 1.1 scw {"ls", cmd_ls}, 79 1.1 scw {"get", cmd_get}, 80 1.1 scw {"mkdir", cmd_mkdir}, 81 1.1 scw {"put", cmd_put}, 82 1.1 scw {"rename", cmd_rename}, 83 1.1 scw {"rm", cmd_rm}, 84 1.1 scw {NULL, NULL} 85 1.1 scw }; 86 1.1 scw 87 1.5 joerg __dead static void 88 1.1 scw usage(void) 89 1.1 scw { 90 1.1 scw 91 1.1 scw fprintf(stderr, "usage: %s [-f <path>] <cmd> ...\n", 92 1.1 scw getprogname()); 93 1.1 scw 94 1.1 scw exit(EX_USAGE); 95 1.1 scw } 96 1.1 scw 97 1.1 scw int 98 1.1 scw main(int argc, char *argv[]) 99 1.1 scw { 100 1.5 joerg const struct toppy_command *tc; 101 1.1 scw const char *devpath; 102 1.1 scw int ch; 103 1.1 scw 104 1.1 scw setprogname(argv[0]); 105 1.1 scw devpath = _PATH_DEV_UTOPPY; 106 1.1 scw 107 1.1 scw while ((ch = getopt(argc, argv, "f:")) != -1) { 108 1.1 scw switch (ch) { 109 1.1 scw case 'f': 110 1.1 scw devpath = optarg; 111 1.1 scw break; 112 1.1 scw 113 1.1 scw default: 114 1.1 scw usage(); 115 1.1 scw } 116 1.1 scw } 117 1.1 scw argc -= optind; 118 1.1 scw argv += optind; 119 1.1 scw 120 1.1 scw if (argc == 0) 121 1.1 scw usage(); 122 1.1 scw 123 1.1 scw for (tc = toppy_commands; tc->tc_cmd != NULL; tc++) 124 1.1 scw if (strcasecmp(argv[0], tc->tc_cmd) == 0) 125 1.1 scw break; 126 1.1 scw 127 1.1 scw if (tc->tc_cmd == NULL) 128 1.1 scw errx(EX_USAGE, "'%s' is not a valid command", argv[0]); 129 1.1 scw 130 1.1 scw if ((toppy_fd = open(devpath, O_RDWR)) < 0) 131 1.1 scw err(EX_OSERR, "open(%s)", devpath); 132 1.1 scw 133 1.1 scw (*tc->tc_handler)(argc, argv); 134 1.1 scw 135 1.1 scw close(toppy_fd); 136 1.1 scw 137 1.1 scw return (0); 138 1.1 scw } 139 1.1 scw 140 1.1 scw static int 141 1.1 scw find_toppy_dirent(const char *path, struct utoppy_dirent *udp) 142 1.1 scw { 143 1.1 scw struct utoppy_dirent ud; 144 1.1 scw char *d, *b, dir[FILENAME_MAX]; 145 1.1 scw ssize_t l; 146 1.1 scw 147 1.1 scw strncpy(dir, path, sizeof(dir)); 148 1.1 scw b = basename(dir); 149 1.1 scw d = dirname(dir); 150 1.1 scw if (strcmp(b, "/") == 0 || strcmp(b, ".") == 0 || strcmp(d, ".") == 0) 151 1.1 scw errx(EX_USAGE, "'%s' is not a valid Toppy pathname", path); 152 1.1 scw 153 1.1 scw if (ioctl(toppy_fd, UTOPPYIOREADDIR, &d) < 0) 154 1.1 scw err(EX_OSERR, "ioctl(UTOPPYIOREADDIR, %s)", d); 155 1.1 scw 156 1.1 scw if (udp == NULL) 157 1.1 scw udp = &ud; 158 1.1 scw 159 1.1 scw while ((l = read(toppy_fd, udp, sizeof(*udp))) == sizeof(*udp)) { 160 1.1 scw if (strcmp(b, udp->ud_path) == 0) 161 1.1 scw break; 162 1.1 scw } 163 1.1 scw 164 1.1 scw if (l < 0) 165 1.1 scw err(EX_OSERR, "read(TOPPYDIR, %s)", d); 166 1.1 scw 167 1.1 scw if (l == 0) 168 1.1 scw return (0); 169 1.1 scw 170 1.1 scw while (read(toppy_fd, &ud, sizeof(ud)) > 0) 171 1.1 scw ; 172 1.1 scw 173 1.1 scw return (1); 174 1.1 scw } 175 1.1 scw 176 1.1 scw static void 177 1.1 scw cmd_df(int argc, char **argv) 178 1.1 scw { 179 1.1 scw struct utoppy_stats us; 180 1.1 scw 181 1.1 scw if (ioctl(toppy_fd, UTOPPYIOSTATS, &us) < 0) 182 1.1 scw err(EX_OSERR, "ioctl(UTOPPYIOSTATS)"); 183 1.1 scw 184 1.2 martin printf("Hard Disk Size: %" PRId64 " MB\n", us.us_hdd_size / (1024 * 1024)); 185 1.2 martin printf("Hard Disk Free: %" PRId64 " MB\n", us.us_hdd_free / (1024 * 1024)); 186 1.1 scw } 187 1.1 scw 188 1.1 scw static void 189 1.1 scw cmd_ls(int argc, char **argv) 190 1.1 scw { 191 1.1 scw struct utoppy_dirent ud; 192 1.1 scw struct tm *tm; 193 1.1 scw char *dir, *ext, dirbuf[2], ex, ft, tmbuf[32]; 194 1.1 scw ssize_t l; 195 1.1 scw 196 1.1 scw if (argc == 1) { 197 1.1 scw dirbuf[0] = '/'; 198 1.1 scw dirbuf[1] = '\0'; 199 1.1 scw dir = dirbuf; 200 1.1 scw } else 201 1.1 scw if (argc == 2) 202 1.1 scw dir = argv[1]; 203 1.1 scw else 204 1.1 scw errx(EX_USAGE, "usage: ls [toppy-pathname]"); 205 1.1 scw 206 1.1 scw if (ioctl(toppy_fd, UTOPPYIOREADDIR, &dir) < 0) 207 1.1 scw err(EX_OSERR, "ioctl(UTOPPYIOREADDIR, %s)", dir); 208 1.1 scw 209 1.1 scw while ((l = read(toppy_fd, &ud, sizeof(ud))) == sizeof(ud)) { 210 1.1 scw switch (ud.ud_type) { 211 1.1 scw default: 212 1.1 scw ft = '?'; 213 1.1 scw break; 214 1.1 scw 215 1.1 scw case UTOPPY_DIRENT_DIRECTORY: 216 1.1 scw ft = 'd'; 217 1.1 scw break; 218 1.1 scw 219 1.1 scw case UTOPPY_DIRENT_FILE: 220 1.1 scw ft = '-'; 221 1.1 scw break; 222 1.1 scw } 223 1.1 scw 224 1.1 scw if ((ext = strrchr(ud.ud_path, '.')) != NULL && 225 1.1 scw strcasecmp(ext, ".tap") == 0) 226 1.1 scw ex = 'x'; 227 1.1 scw else 228 1.1 scw ex = '-'; 229 1.1 scw 230 1.1 scw tm = localtime(&ud.ud_mtime); 231 1.1 scw strftime(tmbuf, sizeof(tmbuf), "%b %e %G %R", tm); 232 1.1 scw 233 1.2 martin printf("%crw%c %11lld %s %s\n", ft, ex, (long long)ud.ud_size, 234 1.2 martin tmbuf, ud.ud_path); 235 1.1 scw } 236 1.1 scw 237 1.1 scw if (l < 0) 238 1.1 scw err(EX_OSERR, "read(utoppy_dirent)"); 239 1.1 scw } 240 1.1 scw 241 1.1 scw static void 242 1.1 scw cmd_rm(int argc, char **argv) 243 1.1 scw { 244 1.1 scw char *path; 245 1.1 scw 246 1.1 scw if (argc != 2) 247 1.1 scw errx(EX_USAGE, "usage: rm <toppy-pathname>"); 248 1.1 scw 249 1.1 scw path = argv[1]; 250 1.1 scw 251 1.1 scw if (ioctl(toppy_fd, UTOPPYIODELETE, &path) < 0) 252 1.1 scw err(EX_OSERR, "ioctl(UTOPPYIODELETE, %s)", path); 253 1.1 scw } 254 1.1 scw 255 1.1 scw static void 256 1.1 scw cmd_mkdir(int argc, char **argv) 257 1.1 scw { 258 1.1 scw char *path; 259 1.1 scw 260 1.1 scw if (argc != 2) 261 1.1 scw errx(EX_USAGE, "usage: mkdir <toppy-pathname>"); 262 1.1 scw 263 1.1 scw path = argv[1]; 264 1.1 scw 265 1.1 scw if (find_toppy_dirent(path, NULL)) 266 1.1 scw errx(EX_DATAERR, "'%s' already exists", path); 267 1.1 scw 268 1.1 scw if (ioctl(toppy_fd, UTOPPYIOMKDIR, &path) < 0) 269 1.1 scw err(EX_OSERR, "ioctl(UTOPPYIOMKDIR, %s)", path); 270 1.1 scw } 271 1.1 scw 272 1.1 scw static void 273 1.1 scw cmd_rename(int argc, char **argv) 274 1.1 scw { 275 1.1 scw struct utoppy_dirent ud; 276 1.1 scw struct utoppy_rename ur; 277 1.1 scw char *oldpath, *newpath, *o, *n; 278 1.1 scw 279 1.1 scw if (argc != 3) 280 1.1 scw errx(EX_USAGE, "usage: rename <from> <to>"); 281 1.1 scw 282 1.1 scw o = oldpath = argv[1]; 283 1.1 scw n = newpath = argv[2]; 284 1.1 scw 285 1.1 scw for (o = oldpath; *o != '\0'; o++) 286 1.1 scw if (*o == '\\') 287 1.1 scw *o = '/'; 288 1.1 scw for (n = newpath; *n != '\0'; n++) 289 1.1 scw if (*n == '\\') 290 1.1 scw *n = '/'; 291 1.1 scw 292 1.1 scw for (o = oldpath; *o && *o == '\\'; o++) 293 1.1 scw ; 294 1.1 scw for (n = newpath; *n && *n == '\\'; n++) 295 1.1 scw ; 296 1.1 scw 297 1.1 scw if (strcmp(n, o) == 0) 298 1.6 christos errx(EX_DATAERR, "'%s' and '%s' refer to the same file", 299 1.1 scw oldpath, newpath); 300 1.1 scw 301 1.1 scw if (find_toppy_dirent(oldpath, &ud) == 0) 302 1.1 scw errx(EX_DATAERR, "'%s' does not exist on the Toppy", oldpath); 303 1.1 scw 304 1.1 scw if (ud.ud_type != UTOPPY_DIRENT_FILE) 305 1.1 scw errx(EX_DATAERR, "%s: not a regular file", oldpath); 306 1.1 scw 307 1.1 scw if (find_toppy_dirent(newpath, &ud)) 308 1.1 scw errx(EX_DATAERR, "'%s' already exists", newpath); 309 1.1 scw 310 1.1 scw ur.ur_old_path = o; 311 1.1 scw ur.ur_new_path = n; 312 1.1 scw 313 1.1 scw if (ioctl(toppy_fd, UTOPPYIORENAME, &ur) < 0) 314 1.1 scw err(EX_OSERR, "ioctl(UTOPPYIORENAME, %s, %s)", oldpath, 315 1.1 scw newpath); 316 1.1 scw } 317 1.1 scw 318 1.1 scw 319 1.1 scw static void 320 1.1 scw init_progress(FILE *to, char *f, off_t fsize, off_t restart) 321 1.1 scw { 322 1.1 scw struct ttysize ts; 323 1.1 scw 324 1.1 scw if (ioctl(fileno(to), TIOCGSIZE, &ts) == -1) 325 1.1 scw ttywidth = 80; 326 1.1 scw else 327 1.1 scw ttywidth = ts.ts_cols; 328 1.1 scw 329 1.1 scw ttyout = to; 330 1.1 scw progress = 1; 331 1.1 scw bytes = 0; 332 1.1 scw filesize = fsize; 333 1.1 scw restart_point = restart; 334 1.1 scw prefix = f; 335 1.1 scw } 336 1.1 scw 337 1.1 scw static void 338 1.1 scw cmd_get(int argc, char **argv) 339 1.1 scw { 340 1.1 scw struct utoppy_readfile ur; 341 1.1 scw struct utoppy_dirent ud; 342 1.1 scw struct stat st; 343 1.1 scw char *dst, dstbuf[FILENAME_MAX]; 344 1.1 scw uint8_t *buf; 345 1.1 scw ssize_t l; 346 1.1 scw size_t rv; 347 1.1 scw int ch, turbo_mode = 0, reget = 0, progbar = 0; 348 1.1 scw FILE *ofp, *to; 349 1.1 scw 350 1.1 scw optind = 1; 351 1.1 scw optreset = 1; 352 1.1 scw 353 1.1 scw while ((ch = getopt(argc, argv, "prt")) != -1) { 354 1.1 scw switch (ch) { 355 1.1 scw case 'p': 356 1.1 scw progbar = 1; 357 1.1 scw break; 358 1.1 scw case 'r': 359 1.1 scw reget = 1; 360 1.1 scw break; 361 1.1 scw case 't': 362 1.1 scw turbo_mode = 1; 363 1.1 scw break; 364 1.1 scw default: 365 1.1 scw get_usage: 366 1.1 scw errx(EX_USAGE, "usage: get [-prt] <toppy-pathname> " 367 1.1 scw "[file | directory]"); 368 1.1 scw } 369 1.1 scw } 370 1.1 scw argc -= optind; 371 1.1 scw argv += optind; 372 1.1 scw 373 1.1 scw if (argc == 1) 374 1.1 scw dst = basename(argv[0]); 375 1.1 scw else 376 1.1 scw if (argc == 2) { 377 1.1 scw dst = argv[1]; 378 1.1 scw if (stat(dst, &st) == 0 && S_ISDIR(st.st_mode)) { 379 1.1 scw snprintf(dstbuf, sizeof(dstbuf), "%s/%s", dst, 380 1.1 scw basename(argv[0])); 381 1.1 scw dst = dstbuf; 382 1.1 scw } 383 1.1 scw } else 384 1.1 scw goto get_usage; 385 1.1 scw 386 1.1 scw ur.ur_path = argv[0]; 387 1.1 scw ur.ur_offset = 0; 388 1.1 scw 389 1.1 scw if ((buf = malloc(TOPPY_IO_SIZE)) == NULL) 390 1.1 scw err(EX_OSERR, "malloc(TOPPY_IO_SIZE)"); 391 1.1 scw 392 1.1 scw if (strcmp(dst, "-") == 0) { 393 1.1 scw ofp = stdout; 394 1.1 scw to = stderr; 395 1.1 scw if (reget) 396 1.1 scw warnx("Ignoring -r option in combination with stdout"); 397 1.1 scw } else { 398 1.1 scw to = stdout; 399 1.1 scw 400 1.1 scw if (reget) { 401 1.1 scw if (stat(dst, &st) < 0) { 402 1.1 scw if (errno != ENOENT) 403 1.1 scw err(EX_OSERR, "stat(%s)", dst); 404 1.1 scw } else 405 1.1 scw if (!S_ISREG(st.st_mode)) 406 1.1 scw errx(EX_DATAERR, "-r only works with regular " 407 1.1 scw "files"); 408 1.1 scw else 409 1.1 scw ur.ur_offset = st.st_size; 410 1.1 scw } 411 1.1 scw 412 1.1 scw if ((ofp = fopen(dst, reget ? "a" : "w")) == NULL) 413 1.1 scw err(EX_OSERR, "fopen(%s)", dst); 414 1.1 scw } 415 1.1 scw 416 1.1 scw if (progbar) { 417 1.1 scw if (find_toppy_dirent(ur.ur_path, &ud) == 0) 418 1.1 scw ud.ud_size = 0; 419 1.1 scw init_progress(to, dst, ud.ud_size, ur.ur_offset); 420 1.1 scw } 421 1.1 scw 422 1.1 scw if (ioctl(toppy_fd, UTOPPYIOTURBO, &turbo_mode) < 0) 423 1.1 scw err(EX_OSERR, "ioctl(UTOPPYIOTURBO, %d)", turbo_mode); 424 1.1 scw 425 1.1 scw if (ioctl(toppy_fd, UTOPPYIOREADFILE, &ur) < 0) 426 1.1 scw err(EX_OSERR, "ioctl(UTOPPYIOREADFILE, %s)", ur.ur_path); 427 1.1 scw 428 1.1 scw if (progbar) 429 1.1 scw progressmeter(-1); 430 1.1 scw 431 1.1 scw for (;;) { 432 1.1 scw while ((l = read(toppy_fd, buf, TOPPY_IO_SIZE)) < 0 && 433 1.1 scw errno == EINTR) 434 1.1 scw ; 435 1.1 scw 436 1.1 scw if (l <= 0) 437 1.1 scw break; 438 1.1 scw 439 1.1 scw rv = fwrite(buf, 1, l, ofp); 440 1.1 scw 441 1.4 lukem if (rv != (size_t)l) { 442 1.1 scw if (ofp != stdout) 443 1.1 scw fclose(ofp); 444 1.1 scw progressmeter(1); 445 1.1 scw err(EX_OSERR, "fwrite(%s)", dst); 446 1.1 scw } 447 1.1 scw bytes += l; 448 1.1 scw } 449 1.1 scw 450 1.1 scw if (progbar) 451 1.1 scw progressmeter(1); 452 1.1 scw 453 1.1 scw if (ofp != stdout) 454 1.1 scw fclose(ofp); 455 1.1 scw 456 1.1 scw if (l < 0) 457 1.1 scw err(EX_OSERR, "read(TOPPY: ur.ur_path)"); 458 1.1 scw 459 1.1 scw free(buf); 460 1.1 scw } 461 1.1 scw 462 1.1 scw static void 463 1.1 scw cmd_put(int argc, char **argv) 464 1.1 scw { 465 1.1 scw struct utoppy_writefile uw; 466 1.1 scw struct utoppy_dirent ud; 467 1.1 scw struct stat st; 468 1.1 scw char dstbuf[FILENAME_MAX]; 469 1.1 scw char *src; 470 1.1 scw void *buf; 471 1.1 scw ssize_t rv; 472 1.1 scw size_t l; 473 1.1 scw int ch, turbo_mode = 0, reput = 0, progbar = 0; 474 1.1 scw FILE *ifp; 475 1.1 scw 476 1.1 scw optind = 1; 477 1.1 scw optreset = 1; 478 1.1 scw 479 1.1 scw while ((ch = getopt(argc, argv, "prt")) != -1) { 480 1.1 scw switch (ch) { 481 1.1 scw case 'p': 482 1.1 scw progbar = 1; 483 1.1 scw break; 484 1.1 scw case 'r': 485 1.1 scw reput = 1; 486 1.1 scw break; 487 1.1 scw case 't': 488 1.1 scw turbo_mode = 1; 489 1.1 scw break; 490 1.1 scw default: 491 1.1 scw put_usage: 492 1.1 scw errx(EX_USAGE, "usage: put [-prt] <local-pathname> " 493 1.1 scw "<toppy-pathname>"); 494 1.1 scw } 495 1.1 scw } 496 1.1 scw argc -= optind; 497 1.1 scw argv += optind; 498 1.1 scw 499 1.1 scw if (argc != 2) 500 1.1 scw goto put_usage; 501 1.1 scw 502 1.1 scw src = argv[0]; 503 1.1 scw uw.uw_path = argv[1]; 504 1.1 scw 505 1.1 scw if (stat(src, &st) < 0) 506 1.1 scw err(EX_OSERR, "%s", src); 507 1.1 scw 508 1.1 scw if (!S_ISREG(st.st_mode)) 509 1.1 scw errx(EX_DATAERR, "'%s' is not a regular file", src); 510 1.1 scw 511 1.1 scw uw.uw_size = st.st_size; 512 1.1 scw uw.uw_mtime = st.st_mtime; 513 1.1 scw uw.uw_offset = 0; 514 1.1 scw 515 1.1 scw if (find_toppy_dirent(uw.uw_path, &ud)) { 516 1.1 scw if (ud.ud_type == UTOPPY_DIRENT_DIRECTORY) { 517 1.1 scw snprintf(dstbuf, sizeof(dstbuf), "%s/%s", uw.uw_path, 518 1.1 scw basename(src)); 519 1.1 scw uw.uw_path = dstbuf; 520 1.1 scw } else 521 1.1 scw if (ud.ud_type != UTOPPY_DIRENT_FILE) 522 1.1 scw errx(EX_DATAERR, "'%s' is not a regular file.", 523 1.1 scw uw.uw_path); 524 1.1 scw else 525 1.1 scw if (reput) { 526 1.1 scw if (ud.ud_size > uw.uw_size) 527 1.1 scw errx(EX_DATAERR, "'%s' is already larger than " 528 1.1 scw "'%s'", uw.uw_path, src); 529 1.1 scw 530 1.1 scw uw.uw_size -= ud.ud_size; 531 1.1 scw uw.uw_offset = ud.ud_size; 532 1.1 scw } 533 1.1 scw } 534 1.1 scw 535 1.1 scw if ((buf = malloc(TOPPY_IO_SIZE)) == NULL) 536 1.1 scw err(EX_OSERR, "malloc(TOPPY_IO_SIZE)"); 537 1.1 scw 538 1.1 scw if ((ifp = fopen(src, "r")) == NULL) 539 1.1 scw err(EX_OSERR, "fopen(%s)", src); 540 1.1 scw 541 1.1 scw if (ioctl(toppy_fd, UTOPPYIOTURBO, &turbo_mode) < 0) 542 1.1 scw err(EX_OSERR, "ioctl(UTOPPYIOTURBO, %d)", turbo_mode); 543 1.1 scw 544 1.1 scw if (ioctl(toppy_fd, UTOPPYIOWRITEFILE, &uw) < 0) 545 1.1 scw err(EX_OSERR, "ioctl(UTOPPYIOWRITEFILE, %s)", uw.uw_path); 546 1.1 scw 547 1.1 scw if (progbar) 548 1.1 scw init_progress(stdout, src, st.st_size, uw.uw_offset); 549 1.1 scw 550 1.1 scw if (progbar) 551 1.1 scw progressmeter(-1); 552 1.1 scw 553 1.1 scw while ((l = fread(buf, 1, TOPPY_IO_SIZE, ifp)) > 0) { 554 1.1 scw rv = write(toppy_fd, buf, l); 555 1.4 lukem if ((size_t)rv != l) { 556 1.1 scw fclose(ifp); 557 1.1 scw if (progbar) 558 1.1 scw progressmeter(1); 559 1.1 scw err(EX_OSERR, "write(TOPPY: %s)", uw.uw_path); 560 1.1 scw } 561 1.1 scw bytes += l; 562 1.1 scw } 563 1.1 scw 564 1.1 scw if (progbar) 565 1.1 scw progressmeter(1); 566 1.1 scw 567 1.1 scw if (ferror(ifp)) 568 1.1 scw err(EX_OSERR, "fread(%s)", src); 569 1.1 scw 570 1.1 scw fclose(ifp); 571 1.1 scw free(buf); 572 1.1 scw } 573