1 #include "compat.h" 2 #include "backuppcd.h" 3 #include "backuppcd-common.h" 4 #include "net.h" 5 6 typedef enum { 7 BPC_CDT_END, 8 BPC_CDT_UINT8, 9 BPC_CDT_UINT16, 10 BPC_CDT_UINT32, 11 BPC_CDT_UINT64, 12 BPC_CDT_BYTEARRAY, 13 BPC_CDT_STRING, 14 BPC_CDT_STRING_PTR, 15 } backuppc_clntdt_t; 16 17 #ifndef MSG_WAITALL 18 #define MSG_WAITALL 0 19 #endif 20 21 #ifndef BPC_MAXPATH_LEN 22 #define BPC_MAXPATH_LEN 4096 23 #endif 24 25 /* 26 * Example BackupPCd client with USTAR output. 27 */ 28 29 int backuppcd_client(const char *host, const int port, const char *username, const char *password, const char *root); 30 31 int main(int argc, char **argv) { 32 char *host, *rootpath, *username, *password; 33 int port; 34 int cmd_ret = -1; 35 36 if (argc < 3) { 37 fprintf(stderr, "Usage: backuppcd-tar -xOf hostname:/path [... ignored...]\n"); 38 return(EXIT_FAILURE); 39 } 40 41 password = getenv("PASSWD"); 42 43 if (!password) { 44 fprintf(stderr, "Must supply password in the environment variable \"PASSWD\"\n"); 45 return(EXIT_FAILURE); 46 } 47 48 host = strdup(argv[2]); 49 rootpath = strchr(host, ':'); 50 if (rootpath) { 51 *rootpath = '\0'; 52 rootpath++; 53 } else { 54 rootpath = "/"; 55 } 56 57 port = 874; 58 username = "backuppc-tar"; 59 60 cmd_ret = backuppcd_client(host, port, username, password, rootpath); 61 62 if (cmd_ret < 0) { 63 return(EXIT_FAILURE); 64 } 65 66 return(EXIT_SUCCESS); 67 } 68 69 70 int backuppcd_client_read(const int sockid, ...) { 71 backuppc_clntdt_t typeid; 72 va_list ap; 73 uint8_t *u8v; 74 uint16_t *u16v; 75 uint32_t *u32v; 76 uint64_t *u64v; 77 char *cpv, **cppv; 78 void *vpv = NULL, *vpv_s; 79 size_t vpv_len; 80 ssize_t read_ret; 81 82 va_start(ap, sockid); 83 while (1) { 84 typeid = va_arg(ap, backuppc_clntdt_t); 85 86 if (typeid == BPC_CDT_END) { 87 break; 88 } 89 90 switch (typeid) { 91 case BPC_CDT_UINT8: 92 u8v = va_arg(ap, uint8_t *); 93 vpv_len = sizeof(*u8v); 94 vpv = u8v; 95 break; 96 case BPC_CDT_UINT16: 97 u16v = va_arg(ap, uint16_t *); 98 vpv_len = sizeof(*u16v); 99 vpv = u16v; 100 break; 101 case BPC_CDT_UINT32: 102 u32v = va_arg(ap, uint32_t *); 103 vpv_len = sizeof(*u32v); 104 vpv = u32v; 105 break; 106 case BPC_CDT_UINT64: 107 u64v = va_arg(ap, uint64_t *); 108 vpv_len = sizeof(*u64v); 109 vpv = u64v; 110 break; 111 case BPC_CDT_BYTEARRAY: 112 vpv_len = va_arg(ap, size_t); 113 vpv = va_arg(ap, void *); 114 break; 115 case BPC_CDT_STRING: 116 vpv_len = va_arg(ap, size_t); 117 vpv_len--; 118 cpv = va_arg(ap, char *); 119 cpv[vpv_len] = '\0'; 120 vpv = cpv; 121 break; 122 case BPC_CDT_STRING_PTR: 123 vpv_len = va_arg(ap, size_t); 124 cppv = va_arg(ap, char **); 125 if (*cppv == NULL) { 126 cpv = *cppv = malloc(vpv_len + 1); 127 cpv[vpv_len] = '\0'; 128 } else { 129 cpv = *cppv; 130 } 131 vpv = cpv; 132 break; 133 default: 134 return(0); 135 } 136 137 vpv_s = vpv; 138 while (vpv_len) { 139 read_ret = recv(sockid, vpv, vpv_len, MSG_WAITALL); 140 141 if (read_ret <= 0) { 142 return(0); 143 } 144 145 vpv_len -= read_ret; 146 vpv += read_ret; 147 } 148 vpv = vpv_s; 149 150 switch (typeid) { 151 case BPC_CDT_UINT16: 152 u16v = vpv; 153 *u16v = ntohs(*u16v); 154 break; 155 case BPC_CDT_UINT32: 156 u32v = vpv; 157 *u32v = ntohl(*u32v); 158 break; 159 case BPC_CDT_UINT64: 160 u64v = vpv; 161 *u64v = ntohll(*u64v); 162 break; 163 default: 164 break; 165 } 166 } 167 va_end(ap); 168 169 return(1); 170 } 171 172 int backuppcd_client_write(const int sockid, ...) { 173 backuppc_clntdt_t typeid; 174 va_list ap; 175 uint8_t u8v; 176 uint16_t u16v; 177 uint32_t u32v; 178 uint64_t u64v; 179 void *vpv; 180 char *cpv; 181 size_t vpv_len; 182 ssize_t write_ret; 183 184 va_start(ap, sockid); 185 while (1) { 186 typeid = va_arg(ap, backuppc_clntdt_t); 187 188 if (typeid == BPC_CDT_END) { 189 break; 190 } 191 192 switch (typeid) { 193 case BPC_CDT_UINT8: 194 u8v = va_arg(ap, int); 195 vpv_len = sizeof(u8v); 196 vpv = &u8v; 197 break; 198 case BPC_CDT_UINT16: 199 u16v = va_arg(ap, int); 200 u16v = htons(u16v); 201 vpv_len = sizeof(u16v); 202 vpv = &u16v; 203 break; 204 case BPC_CDT_UINT32: 205 u32v = va_arg(ap, uint32_t); 206 u32v = htonl(u32v); 207 vpv_len = sizeof(u32v); 208 vpv = &u32v; 209 break; 210 case BPC_CDT_UINT64: 211 u64v = va_arg(ap, uint64_t); 212 u64v = htonll(u64v); 213 vpv_len = sizeof(u64v); 214 vpv = &u64v; 215 break; 216 case BPC_CDT_BYTEARRAY: 217 vpv_len = va_arg(ap, size_t); 218 vpv = va_arg(ap, void *); 219 break; 220 case BPC_CDT_STRING: 221 cpv = va_arg(ap, char *); 222 vpv_len = strlen(cpv); 223 vpv = cpv; 224 break; 225 case BPC_CDT_STRING_PTR: 226 default: 227 return(0); 228 } 229 230 while (vpv_len) { 231 write_ret = send(sockid, vpv, vpv_len, 0); 232 233 if (write_ret < 0) { 234 return(0); 235 } 236 237 vpv_len -= write_ret; 238 vpv += write_ret; 239 } 240 } 241 va_end(ap); 242 243 return(1); 244 } 245 246 247 248 int backuppcd_client_auth(const int sockid, const char *username, const char *password) { 249 uint8_t cmd_reply; 250 uint8_t status; 251 252 if (!backuppcd_client_write(sockid, 253 BPC_CDT_UINT8, (uint8_t) BPC_CMD_AUTH, 254 BPC_CDT_UINT16, (uint16_t) strlen(username), 255 BPC_CDT_UINT16, (uint16_t) strlen(password), 256 BPC_CDT_STRING, username, 257 BPC_CDT_STRING, password, 258 BPC_CDT_END)) { 259 return(0); 260 } 261 262 if (!backuppcd_client_read(sockid, 263 BPC_CDT_UINT8, (uint8_t *) &cmd_reply, 264 BPC_CDT_UINT8, (uint8_t *) &status, 265 BPC_CDT_END)) { 266 return(0); 267 } 268 269 if (cmd_reply != BPC_CMD_AUTH_REPLY) { 270 return(0); 271 } 272 273 if (status != BPC_STATUS_OKAY) { 274 return(0); 275 } 276 277 return(1); 278 } 279 280 int backuppcd_client_target(const int sockid, const char *rootpath, const int opt_verbosity, const int opt_totals) { 281 backuppc_cmd_t sendcmd; 282 unsigned char pathbuf[8192], *outpathbuf = NULL, tarbuf[512], *shortname, *dirname; 283 unsigned char *buf = NULL; 284 uint32_t attr_sect_len, blocksize, pathnamelen, blocknum = 0; 285 uint64_t filesize, byteswritten = 0; 286 uint32_t bufsize = 0; 287 uint32_t attr_uid, attr_gid, attr_ctime, attr_mtime, attr_devmajor, attr_devminor; 288 uint32_t attrlen; 289 uint32_t tar_checksum; 290 uint32_t tarblocks = 0; 291 uint16_t attrid; 292 uint16_t attr_mode; 293 uint8_t filetype, cmd; 294 ssize_t write_ret; 295 size_t writelen, bytes_to_copy; 296 time_t totaltime, starttime; 297 mode_t modeval; 298 char *attr_linkdest, *attr_username, *attr_groupname, *attr_hrdlinkdest; 299 char type_string[][7] = {"dir", "file", "syml", "sock", "fifo", "blk", "chr", "hrdl"}; 300 int tar_type; 301 int i, x, skipfile; 302 303 starttime = time(NULL); 304 305 sendcmd = BPC_CMD_GET; 306 307 if (!backuppcd_client_write(sockid, 308 BPC_CDT_UINT8, (uint8_t) sendcmd, 309 BPC_CDT_UINT8, (uint8_t) BPC_OPT_RECURSIVE, 310 BPC_CDT_UINT32, (uint32_t) 0, /* exclude section length */ 311 BPC_CDT_UINT32, (uint32_t) 0, /* include section length */ 312 BPC_CDT_UINT32, (uint32_t) strlen(rootpath), 313 BPC_CDT_STRING, (char *) rootpath, 314 /* Exclude section is 0 bytes (XXX) */ 315 /* Include section is 0 bytes (XXX) */ 316 BPC_CDT_END)) { 317 CHECKPOINT; 318 return(0); 319 } 320 321 if (!backuppcd_client_read(sockid, 322 BPC_CDT_UINT8, (uint8_t *) &cmd, 323 BPC_CDT_END)) { 324 CHECKPOINT; 325 return(0); 326 } 327 328 /* 329 * If the server sends us a reply for something other than what we 330 * asked for, something went wrong, abort. 331 */ 332 if (cmd != (sendcmd | 0x80)) { 333 CHECKPOINT; 334 return(0); 335 } 336 337 /* 338 * Process every file entry in the reply. 339 */ 340 while (1) { 341 if (!backuppcd_client_read(sockid, 342 BPC_CDT_UINT8, (uint8_t *) &filetype, 343 BPC_CDT_END)) { 344 CHECKPOINT; 345 return(0); 346 } 347 348 for (i = 0; i < sizeof(tarbuf); i++) { 349 tarbuf[i] = 0; 350 } 351 352 if (filetype == 0xff) { 353 break; 354 } 355 356 if (!backuppcd_client_read(sockid, 357 BPC_CDT_UINT32, (uint32_t *) &attr_sect_len, 358 BPC_CDT_UINT64, (uint64_t *) &filesize, 359 BPC_CDT_UINT32, (uint32_t *) &blocksize, 360 BPC_CDT_UINT32, (uint32_t *) &pathnamelen, 361 BPC_CDT_END)) { 362 CHECKPOINT; 363 return(0); 364 } 365 366 367 if (pathnamelen >= sizeof(pathbuf)) { 368 SPOTVAR_I(pathnamelen); 369 CHECKPOINT; 370 return(0); 371 } 372 373 if (!backuppcd_client_read(sockid, 374 BPC_CDT_STRING, (size_t) (pathnamelen + 1), &pathbuf, 375 BPC_CDT_END)) { 376 CHECKPOINT; 377 return(0); 378 } 379 380 attr_uid = 0; 381 attr_gid = 0; 382 attr_mode = 0; 383 attr_ctime = 0; 384 attr_mtime = 0; 385 attr_devmajor = 0; 386 attr_devminor = 0; 387 attr_username = NULL; 388 attr_groupname = NULL; 389 attr_linkdest = NULL; 390 attr_hrdlinkdest = NULL; 391 392 /* 393 * Read the sent attributes. 394 * Currently this does not handle all attributes and any 395 * attribute that is not handled is not properly sunk, instead 396 * the data remains in the buffer to be mis-processed later. 397 * Fix this (XXX) 398 */ 399 if (attr_sect_len != 0) { 400 while (1) { 401 if (!backuppcd_client_read(sockid, 402 BPC_CDT_UINT16, (uint16_t *) &attrid, 403 BPC_CDT_END)) { 404 CHECKPOINT; 405 return(0); 406 } 407 408 if (attrid == 0xffff) { 409 break; 410 } 411 412 if (!backuppcd_client_read(sockid, 413 BPC_CDT_UINT32, (uint32_t *) &attrlen, 414 BPC_CDT_END)) { 415 CHECKPOINT; 416 return(0); 417 } 418 419 switch ((backuppc_attrid_t) attrid) { 420 case BPC_ATTRID_NOP: 421 if (attrlen != 0) { 422 CHECKPOINT; 423 return(0); 424 } 425 break; 426 case BPC_ATTRID_MTIME: 427 if (!backuppcd_client_read(sockid, 428 BPC_CDT_UINT32, (uint32_t *) &attr_mtime, 429 BPC_CDT_END)) { 430 CHECKPOINT; 431 return(0); 432 } 433 break; 434 case BPC_ATTRID_CTIME: 435 if (!backuppcd_client_read(sockid, 436 BPC_CDT_UINT32, (uint32_t *) &attr_ctime, 437 BPC_CDT_END)) { 438 CHECKPOINT; 439 return(0); 440 } 441 break; 442 case BPC_ATTRID_UID: 443 if (!backuppcd_client_read(sockid, 444 BPC_CDT_UINT32, (uint32_t *) &attr_uid, 445 BPC_CDT_END)) { 446 CHECKPOINT; 447 return(0); 448 } 449 break; 450 case BPC_ATTRID_GID: 451 if (!backuppcd_client_read(sockid, 452 BPC_CDT_UINT32, (uint32_t *) &attr_gid, 453 BPC_CDT_END)) { 454 CHECKPOINT; 455 return(0); 456 } 457 break; 458 case BPC_ATTRID_ACL: 459 if (!backuppcd_client_read(sockid, 460 BPC_CDT_UINT16, (uint16_t *) &attr_mode, 461 BPC_CDT_END)) { 462 CHECKPOINT; 463 return(0); 464 } 465 466 break; 467 case BPC_ATTRID_USER: 468 if (attrlen > BPC_MAXPATH_LEN) { 469 CHECKPOINT; 470 return(0); 471 } 472 473 if (attr_username) { 474 free(attr_username); 475 } 476 477 attr_username = NULL; 478 479 if (!backuppcd_client_read(sockid, 480 BPC_CDT_STRING_PTR, (size_t) attrlen, (char **) &attr_username, 481 BPC_CDT_END)) { 482 CHECKPOINT; 483 return(0); 484 } 485 break; 486 case BPC_ATTRID_GROUP: 487 if (attrlen > BPC_MAXPATH_LEN) { 488 CHECKPOINT; 489 return(0); 490 } 491 492 if (attr_groupname) { 493 free(attr_groupname); 494 } 495 496 attr_groupname = NULL; 497 498 if (!backuppcd_client_read(sockid, 499 BPC_CDT_STRING_PTR, (size_t) attrlen, (char **) &attr_groupname, 500 BPC_CDT_END)) { 501 CHECKPOINT; 502 return(0); 503 } 504 break; 505 case BPC_ATTRID_SYMLINKDEST: 506 if (attrlen > BPC_MAXPATH_LEN) { 507 CHECKPOINT; 508 return(0); 509 } 510 511 if (attr_linkdest) { 512 free(attr_linkdest); 513 } 514 515 attr_linkdest = NULL; 516 517 if (!backuppcd_client_read(sockid, 518 BPC_CDT_STRING_PTR, (size_t) attrlen, (char **) &attr_linkdest, 519 BPC_CDT_END)) { 520 CHECKPOINT; 521 return(0); 522 } 523 break; 524 case BPC_ATTRID_HRDLINKDEST: 525 if (attrlen > BPC_MAXPATH_LEN) { 526 CHECKPOINT; 527 return(0); 528 } 529 530 if (attr_hrdlinkdest) { 531 free(attr_hrdlinkdest); 532 } 533 534 attr_hrdlinkdest = NULL; 535 536 if (!backuppcd_client_read(sockid, 537 BPC_CDT_STRING_PTR, (size_t) attrlen, (char **) &attr_hrdlinkdest, 538 BPC_CDT_END)) { 539 CHECKPOINT; 540 return(0); 541 } 542 break; 543 } 544 } 545 } 546 547 /* 548 * Split the filename into 2 parts, the directory name and 549 * the file name. USTAR allows us to fit longer file names 550 * if we do this. 551 */ 552 shortname = strrchr(pathbuf, '/'); 553 if (shortname) { 554 *shortname = '\0'; 555 shortname++; 556 dirname = pathbuf; 557 } else { 558 shortname = pathbuf; 559 dirname = ""; 560 } 561 562 /* 563 * Do not attempt to fill the USTAR header with data that will 564 * not fit. If an overflow condition is found, mark the file 565 * to be skipped and print a warning. 566 */ 567 skipfile = 0; 568 if (strlen(shortname) >= 100 || strlen(dirname) >= 155) { 569 fprintf(stderr, "Skipping %s/%s, pathname too long.\n", dirname, shortname); 570 skipfile = 1; 571 } 572 if (filesize >= 0x200000000LLU) { 573 fprintf(stderr, "Skipping %s/%s, file too large.\n", dirname, shortname); 574 skipfile = 1; 575 } 576 577 /* 578 * Determine the POSIX "mode" value from the ACL attrs. 579 */ 580 modeval = 0; 581 if (attr_mode) { 582 if ((attr_mode & BPC_ACL_XUSR) == BPC_ACL_XUSR) { 583 modeval |= S_IXUSR; 584 } 585 if ((attr_mode & BPC_ACL_WUSR) == BPC_ACL_WUSR) { 586 modeval |= S_IWUSR; 587 } 588 if ((attr_mode & BPC_ACL_RUSR) == BPC_ACL_RUSR) { 589 modeval |= S_IRUSR; 590 } 591 #ifndef _USE_WIN32_ 592 if ((attr_mode & BPC_ACL_XGRP) == BPC_ACL_XGRP) { 593 modeval |= S_IXGRP; 594 } 595 if ((attr_mode & BPC_ACL_WGRP) == BPC_ACL_WGRP) { 596 modeval |= S_IWGRP; 597 } 598 if ((attr_mode & BPC_ACL_RGRP) == BPC_ACL_RGRP) { 599 modeval |= S_IRGRP; 600 } 601 if ((attr_mode & BPC_ACL_XOTH) == BPC_ACL_XOTH) { 602 modeval |= S_IXOTH; 603 } 604 if ((attr_mode & BPC_ACL_WOTH) == BPC_ACL_WOTH) { 605 modeval |= S_IWOTH; 606 } 607 if ((attr_mode & BPC_ACL_ROTH) == BPC_ACL_ROTH) { 608 modeval |= S_IROTH; 609 } 610 if ((attr_mode & BPC_ACL_STCK) == BPC_ACL_STCK) { 611 modeval |= S_ISVTX; 612 } 613 if ((attr_mode & BPC_ACL_SGID) == BPC_ACL_SGID) { 614 modeval |= S_ISGID; 615 } 616 if ((attr_mode & BPC_ACL_SUID) == BPC_ACL_SUID) { 617 modeval |= S_ISUID; 618 } 619 #endif 620 } 621 622 /* 623 * Determine the USTAR "type" flag from the file type, and 624 * continue adding bits to the POSIX "mode" value. 625 */ 626 tar_type = 0; 627 if (filetype == BPC_FILE_REG) { 628 modeval |= S_IFREG; 629 tar_type = 0; 630 } 631 #ifndef _USE_WIN32_ 632 if (filetype == BPC_FILE_SYMLINK) { 633 modeval |= S_IFLNK; 634 tar_type = 1; 635 } 636 if (filetype == BPC_FILE_SOCKET) { 637 modeval |= S_IFSOCK; 638 tar_type = 2; /* ??? */ 639 } 640 #endif 641 if (filetype == BPC_FILE_DIR) { 642 modeval |= S_IFDIR; 643 tar_type = 5; 644 } 645 if (filetype == BPC_FILE_BDEV) { 646 modeval |= S_IFBLK; 647 tar_type = 4; 648 } 649 if (filetype == BPC_FILE_CDEV) { 650 modeval |= S_IFCHR; 651 tar_type = 3; 652 } 653 if (filetype == BPC_FILE_FIFO) { 654 modeval |= S_IFIFO; 655 tar_type = 6; 656 } 657 658 /* 659 * Only send a header for this file if we intend to send the 660 * data for it. 661 */ 662 if (!skipfile) { 663 /* 664 * Generate the USTAR header in the buffer. 665 */ 666 memcpy(tarbuf, shortname, strlen(shortname)); 667 sprintf(tarbuf + 100, "%07o", modeval); 668 sprintf(tarbuf + 108, "%07o", attr_uid); 669 sprintf(tarbuf + 116, "%07o", attr_gid); 670 sprintf(tarbuf + 124, "%011o", (unsigned int) filesize); 671 sprintf(tarbuf + 136, "%011o", attr_mtime); 672 sprintf(tarbuf + 148, " "); 673 sprintf(tarbuf + 156, "%i", tar_type); 674 if (filetype == BPC_FILE_SYMLINK) { 675 sprintf(tarbuf + 157, attr_linkdest); 676 } 677 sprintf(tarbuf + 257, "ustar"); 678 sprintf(tarbuf + 263, " "); 679 if (attr_username) { 680 sprintf(tarbuf + 265, "%s", attr_username); 681 } 682 if (attr_groupname) { 683 sprintf(tarbuf + 297, "%s", attr_groupname); 684 } 685 if (attr_devmajor) { 686 sprintf(tarbuf + 329, "%07o", attr_devmajor); 687 } 688 if (attr_devminor) { 689 sprintf(tarbuf + 337, "%07o", attr_devminor); 690 } 691 sprintf(tarbuf + 345, "%s", dirname); 692 693 /* Calculate checksum. */ 694 tar_checksum = 0; 695 for (i = 0; i < sizeof(tarbuf); i++) { 696 tar_checksum += tarbuf[i]; 697 } 698 sprintf(tarbuf + 148, "%06o", tar_checksum); 699 700 write_ret = write(STDOUT_FILENO, tarbuf, sizeof(tarbuf)); 701 if (write_ret != sizeof(tarbuf)) { 702 CHECKPOINT; 703 return(0); 704 } 705 706 /* 707 * Calculate the number of blocks this file will need 708 * including the 1-block header. 709 */ 710 tarblocks += 1 + ((filesize + sizeof(tarbuf) - 1) / sizeof(tarbuf)); 711 } 712 713 switch (opt_verbosity) { 714 case 0: 715 break; 716 case 1: 717 fprintf(stderr, ".%s/%s\n", dirname, shortname); 718 break; 719 case 2: 720 fprintf(stderr, "[%4s] %04o %6lu %6lu %10llu %12lu %s/%s", 721 type_string[filetype], 722 (unsigned int) attr_mode, 723 (unsigned long) attr_uid, 724 (unsigned long) attr_gid, 725 (unsigned long long) filesize, 726 (unsigned long) attr_mtime, 727 dirname, 728 shortname); 729 if (filetype == BPC_FILE_SYMLINK) { 730 fprintf(stderr, " -> %s", attr_linkdest); 731 } 732 fprintf(stderr, "\n"); 733 break; 734 } 735 736 outpathbuf = pathbuf + 1; 737 738 byteswritten = 0; 739 740 /* 741 * Ensure the buffer is large enough to hold all the data. 742 * If the buffer starts changing a lot between files, we 743 * should make this grow-only. It's fine for now. 744 */ 745 if (bufsize != blocksize) { 746 if (buf) { 747 free(buf); 748 } 749 750 bufsize = blocksize; 751 752 buf = malloc(bufsize); 753 754 if (!buf) { 755 CHECKPOINT; 756 return(0); 757 } 758 } 759 760 /* 761 * Read the file data from the server. We must do this even 762 * if we are not planning on sending it in USTAR format. 763 * The data comes in "blocksize" sized blocks and may be 764 * larger than the actual file. 765 */ 766 while (1) { 767 if (!backuppcd_client_read(sockid, 768 BPC_CDT_UINT32, (uint32_t *) &blocknum, 769 BPC_CDT_END)) { 770 CHECKPOINT; 771 return(0); 772 } 773 774 if (blocknum == 0xffffffff) { 775 break; 776 } 777 778 if (!backuppcd_client_read(sockid, 779 BPC_CDT_BYTEARRAY, (size_t) blocksize, (void *) buf, 780 BPC_CDT_END)) { 781 782 CHECKPOINT; 783 return(0); 784 } 785 786 /* 787 * Determine the amount of data in this block that we 788 * should write. Currently this fails to deal with 789 * sparse files and assumes that an entire file is 790 * with all blocks in order. This will need to change. 791 * (XXX) 792 */ 793 if ((byteswritten + blocksize) > filesize) { 794 if (filesize > byteswritten) { 795 writelen = filesize - byteswritten; 796 } else { 797 writelen = 0; 798 } 799 } else { 800 writelen = blocksize; 801 } 802 803 if (!skipfile) { 804 /* 805 * Send the file data if there is any. 806 */ 807 if (writelen > 0) { 808 x = 0; 809 while (x < writelen) { 810 write_ret = write(STDOUT_FILENO, buf + x, writelen - x); 811 812 if (write_ret <= 0) { 813 CHECKPOINT; 814 return(0); 815 } 816 817 x += write_ret; 818 } 819 } 820 } 821 822 byteswritten += blocksize; 823 } 824 825 if (!skipfile) { 826 /* 827 * Round the file to 512-byte blocks. 828 */ 829 bytes_to_copy = sizeof(tarbuf) - (filesize % sizeof(tarbuf)); 830 if (bytes_to_copy != sizeof(tarbuf)) { 831 for (i = 0; i < bytes_to_copy; i++) { 832 tarbuf[i] = 0; 833 } 834 write_ret = write(STDOUT_FILENO, tarbuf, bytes_to_copy); 835 if (write_ret != bytes_to_copy) { 836 CHECKPOINT; 837 return(0); 838 } 839 } 840 } 841 842 /* Clean up any allocated memory, if needed. */ 843 if (attr_linkdest) { 844 free(attr_linkdest); 845 } 846 if (attr_username) { 847 free(attr_username); 848 } 849 if (attr_groupname) { 850 free(attr_groupname); 851 } 852 if (attr_hrdlinkdest) { 853 free(attr_hrdlinkdest); 854 } 855 } 856 857 /* 858 * USTAR end of archive is two empty blocks. 859 */ 860 write(STDOUT_FILENO, tarbuf, sizeof(tarbuf)); 861 write(STDOUT_FILENO, tarbuf, sizeof(tarbuf)); 862 tarblocks += 2; 863 864 if (opt_totals) { 865 totaltime = time(NULL) - starttime; 866 if (totaltime == 0) { 867 totaltime = 1; 868 } 869 870 fprintf(stderr, "Total bytes written: %lu (%luKiB, %fKiB/s)\n", (unsigned long) (tarblocks * sizeof(tarbuf)), (unsigned long) (tarblocks * sizeof(tarbuf) / 1024), (((double) tarblocks * sizeof(tarbuf)) / 1024.0) / ((double) totaltime)); 871 } 872 873 CHECKPOINT; 874 return(1); 875 } 876 877 int backuppcd_client(const char *host, const int port, const char *username, const char *password, const char *rootpath) { 878 int sockid; 879 880 sockid = net_connect_tcp(host, port); 881 882 if (sockid < 0) { 883 return(-1); 884 } 885 886 if (!backuppcd_client_auth(sockid, username, password)) { 887 return(-1); 888 } 889 890 if (!backuppcd_client_target(sockid, rootpath, 1, 1)) { 891 return(-1); 892 } 893 894 return(0); 895 } |