5762839 [rkeene@sledge /home/rkeene/devel/backuppcd/all/backuppcd-200601171056]$ cat -n libbackuppcd.c
   1 #include "compat.h"
   2 #include "backuppcd.h"
   3 #include "backuppcd-common.h"
   4 #include "libbackuppcd.h"
   5 #include "sha1.h"
   6 #include "net.h"
   7 
   8 #define BPC_CMD_GET_DATA (BPC_CMD_GET | 0x100)
   9 #define BPC_MAX_RDIFF_BLOCKSIZE 8192
  10 
  11 /*
  12  * This structure contains all the variables that are needed to keep track of
  13  * the state of a transfer (GET).
  14  */
  15 struct bpc_transfer {
  16     uint64_t filesize;
  17     int64_t idealblocknum;
  18     uint32_t currblocknum;
  19     uint32_t blocksize;
  20     uint32_t blockoffset;
  21 };
  22 
  23 /*
  24  * This structure is used as a handle for a connection to a BackupPC server.
  25  */
  26 struct bpc_conn {
  27     struct bpc_fileinfo dent;
  28     struct bpc_transfer tinfo;
  29     backuppc_cmd_t state;
  30     int fd;
  31 };
  32 
  33 /*
  34  * These values are used by _bpc_client_read() and _bpc_client_write() to
  35  * determine the type of variable to read or write.
  36  */
  37 typedef enum {
  38         BPC_CDT_END,
  39         BPC_CDT_UINT8,
  40         BPC_CDT_UINT16,
  41         BPC_CDT_UINT32,
  42         BPC_CDT_UINT64,
  43         BPC_CDT_BYTEARRAY,
  44         BPC_CDT_STRING,
  45         BPC_CDT_STRING_PTR,
  46     BPC_CDT_SINK,
  47 } bpc_clntdt_t;
  48 
  49 #ifndef MSG_WAITALL
  50 #define MSG_WAITALL 0
  51 #endif
  52 
  53 #ifndef BPC_MAXPATH_LEN
  54 #define BPC_MAXPATH_LEN 4096
  55 #endif                                                                                                                  
	                 
  56 
  57 /*
  58  * SYNOPSIS (internal):
  59  *   static int _bpc_client_read(
  60  *                               const int sockid,
  61  *                               ...
  62  *                              );
  63  *
  64  * ARGUMENTS:
  65  *   const int sockid             Socket descriptor to read from
  66  *   ...                          List of parameters with the appropriate type
  67  *                                and terminated by a BPC_CDT_END
  68  *
  69  * RETURN VALUE:
  70  *   This function returns 0 on failure, 1 on success.
  71  *
  72  * NOTES:
  73  *   This function reads a variable number of parameters in various formats
  74  *   from a socket descriptor and stores them in the pointer given.  To
  75  *   specify a value, use the appropriate value from `bpc_clntdt_t' followed
  76  *   by a pointer to the memory location to store the actual value (in most
  77  *   cases) or the size of the memory location and the start of the memory
  78  *   location (for BYTEARRAY, STRING, STRING_PTR).
  79  *
  80  *   If the pointer at the pointed to location is NULL and the data type is
  81  *   STRING_PTR (size) bytes will be allocated and (size-1) bytes read.
  82  *   You are responsible for deallocating allocated memory using free().
  83  *
  84  *   This is an internal function and not part of the LibBackupPCd API and
  85  *   therefore subject to change or removal.
  86  *
  87  * EXAMPLES:
  88  *   uint8_t val_u8;
  89  *   char *val_str = NULL;
  90  *
  91  *   // Read a uint8_t into val_u8
  92  *   if (!_bpc_client_read(sockid, BPC_CDT_UINT8, &val_u8, BPC_CDT_END)) {
  93  *         return(-1);
  94  *   }
  95  *
  96  *   // Read 4 bytes and a NIL termination char into newly allocated memory
  97  *   if (!_bpc_client_read(sockid, BPC_CDT_STRING_PTR, (size_t) 5, &val_str, BPC_CDT_END)) {
  98  *         return(-1);
  99  *   }
 100  *
 101  *   if (val_str) {
 102  *         free(val_str);
 103  *   }
 104  *
 105  */
 106 static int _bpc_client_read(const int sockid, ...) {
 107     bpc_clntdt_t typeid;
 108     char tmpbuf[1024];
 109     va_list ap;
 110     uint8_t *u8v;
 111     uint16_t *u16v;
 112     uint32_t *u32v;
 113     uint64_t *u64v;
 114     char *cpv, **cppv;
 115     void *vpv = NULL, *vpv_s;
 116     size_t vpv_len, bytes_to_copy;
 117     ssize_t read_ret;
 118 
 119     va_start(ap, sockid);
 120     while (1) {
 121         typeid = va_arg(ap, bpc_clntdt_t);
 122 
 123         if (typeid == BPC_CDT_END) {
 124             break;
 125         }
 126 
 127         switch (typeid) {
 128             case BPC_CDT_UINT8:
 129                 u8v = va_arg(ap, uint8_t *);
 130                 vpv_len = sizeof(*u8v);
 131                 vpv = u8v;
 132                 break;
 133             case BPC_CDT_UINT16:
 134                 u16v = va_arg(ap, uint16_t *);
 135                 vpv_len = sizeof(*u16v);
 136                 vpv = u16v;
 137                 break;
 138             case BPC_CDT_UINT32:
 139                 u32v = va_arg(ap, uint32_t *);
 140                 vpv_len = sizeof(*u32v);
 141                 vpv = u32v;
 142                 break;
 143             case BPC_CDT_UINT64:
 144                 u64v = va_arg(ap, uint64_t *);
 145                 vpv_len = sizeof(*u64v);
 146                 vpv = u64v;
 147                 break;
 148             case BPC_CDT_BYTEARRAY:
 149                 vpv_len = va_arg(ap, size_t);
 150                 vpv = va_arg(ap, void *);
 151                 break;
 152             case BPC_CDT_STRING:
 153                 vpv_len = va_arg(ap, size_t);
 154                 vpv_len--;
 155                 cpv = va_arg(ap, char *);
 156                 cpv[vpv_len] = '\0';
 157                 vpv = cpv;
 158                 break;
 159             case BPC_CDT_STRING_PTR:
 160                 vpv_len = va_arg(ap, size_t);
 161                 cppv = va_arg(ap, char **);
 162                 if (*cppv == NULL) {
 163                     cpv = *cppv = malloc(vpv_len + 1);
 164                     cpv[vpv_len] = '\0';
 165                 } else {
 166                     cpv = *cppv;
 167                 }
 168                 vpv = cpv;
 169                 break;
 170             case BPC_CDT_SINK:
 171                 vpv_len = va_arg(ap, size_t);
 172                 vpv = NULL;
 173                 break;
 174             case BPC_CDT_END:
 175                 return(0);
 176                 break;
 177             default:
 178                 return(0);
 179         }
 180 
 181         vpv_s = vpv;
 182         while (vpv_len) {
 183             if (vpv) {
 184                 read_ret = recv(sockid, vpv, vpv_len, MSG_WAITALL);
 185             } else {
 186                 /*
 187                  * If we have been given no place to put the
 188                  * data, we just read it to a buffer and
 189                  * ignore it (aka, sink it).
 190                  */
 191                 bytes_to_copy = sizeof(tmpbuf);
 192                 if (vpv_len < bytes_to_copy) {
 193                     bytes_to_copy = vpv_len;
 194                 }
 195                 read_ret = recv(sockid, tmpbuf, bytes_to_copy, MSG_WAITALL);
 196             }
 197 
 198             if (read_ret <= 0) {
 199                 return(0);
 200             }
 201 
 202             vpv_len -= read_ret;
 203 
 204             if (vpv) {
 205                 vpv += read_ret;
 206             }
 207         }
 208         vpv = vpv_s;
 209 
 210         switch (typeid) {
 211             case BPC_CDT_UINT16:
 212                 u16v = vpv;
 213                 *u16v = ntohs(*u16v);
 214                 break;
 215             case BPC_CDT_UINT32:
 216                 u32v = vpv;
 217                 *u32v = ntohl(*u32v);
 218                 break;
 219             case BPC_CDT_UINT64:
 220                 u64v = vpv;
 221                 *u64v = ntohll(*u64v);
 222                 break;
 223             default:
 224                 break;
 225         }
 226     }
 227     va_end(ap);
 228 
 229     return(1);
 230 }
 231 
 232 /*
 233  * SYNOPSIS (internal):
 234  *   static int _bpc_client_write(
 235  *                                const int sockid,
 236  *                                ...
 237  *                               );
 238  *
 239  * ARGUMENTS:
 240  *   const int sockid             Socket descriptor to write to
 241  *   ...                          List of parameters with the appropriate type
 242  *                                and terminated by a BPC_CDT_END
 243  *
 244  * RETURN VALUE:
 245  *   This function returns 0 on failure, 1 on success.
 246  *
 247  * NOTES:
 248  *   This function writes a variable number of parameters in various formats
 249  *   to a socket descriptor.  To specify a value, use the appropriate value
 250  *   from `bpc_clntdt_t' followed by a value of the appropriate type (in most
 251  *   cases), or the size of the data to write followed by the appropriate
 252  *   value (for BYTEARRAY, STRING, STRING_PTR)
 253  *
 254  *   This is an internal function and not part of the LibBackupPCd API and
 255  *   therefore subject to change or removal.
 256  *
 257  * EXAMPLES:
 258  *   uint8_t val_u8 = 3;
 259  *   char *val_str = "Joe";
 260  *
 261  *   // Write 3 in a uint8_t format to the socket
 262  *   if (!_bpc_client_write(sockid, BPC_CDT_UINT8, val_u8, BPC_CDT_END)) {
 263  *         return(-1);
 264  *   }
 265  *
 266  *   // Write 3 bytes from a string to the socket
 267  *   if (!_bpc_client_write(sockid, BPC_CDT_STRING, (size_t) 3, val_str, BPC_CDT_END)) {
 268  *         return(-1);
 269  *   }
 270  *
 271  */
 272 static int _bpc_client_write(const int sockid, ...) {
 273     bpc_clntdt_t typeid;
 274     va_list ap;
 275     uint8_t u8v;
 276     uint16_t u16v;
 277     uint32_t u32v;
 278     uint64_t u64v;
 279     void *vpv;
 280     char *cpv;
 281     size_t vpv_len;
 282     ssize_t write_ret;
 283 
 284     va_start(ap, sockid);
 285     while (1) {
 286         typeid = va_arg(ap, bpc_clntdt_t);
 287 
 288         if (typeid == BPC_CDT_END) {
 289             break;
 290         }
 291 
 292         switch (typeid) {
 293             case BPC_CDT_UINT8:
 294                 u8v = va_arg(ap, int);
 295                 vpv_len = sizeof(u8v);
 296                 vpv = &u8v;
 297                 break;
 298             case BPC_CDT_UINT16:
 299                 u16v = va_arg(ap, int);
 300                 u16v = htons(u16v);
 301                 vpv_len = sizeof(u16v);
 302                 vpv = &u16v;
 303                 break;
 304             case BPC_CDT_UINT32:
 305                 u32v = va_arg(ap, uint32_t);
 306                 u32v = htonl(u32v);
 307                 vpv_len = sizeof(u32v);
 308                 vpv = &u32v;
 309                 break;
 310             case BPC_CDT_UINT64:
 311                 u64v = va_arg(ap, uint64_t);
 312                 u64v = htonll(u64v);
 313                 vpv_len = sizeof(u64v);
 314                 vpv = &u64v;
 315                 break;
 316             case BPC_CDT_BYTEARRAY:
 317                 vpv_len = va_arg(ap, size_t);
 318                 vpv = va_arg(ap, void *);
 319                 break;
 320             case BPC_CDT_STRING:
 321                 cpv = va_arg(ap, char *);
 322                 vpv_len = strlen(cpv);
 323                 vpv = cpv;
 324                 break;
 325             case BPC_CDT_SINK:
 326             case BPC_CDT_STRING_PTR:
 327             case BPC_CDT_END:
 328                 return(0);
 329             default:
 330                 return(0);
 331         }
 332 
 333         while (vpv_len) {
 334             write_ret = send(sockid, vpv, vpv_len, 0);
 335 
 336             if (write_ret < 0) {
 337                 return(0);
 338             }
 339 
 340             vpv_len -= write_ret;
 341             vpv += write_ret;
 342         }
 343     }
 344     va_end(ap);
 345 
 346     return(1);
 347 }
 348 
 349 /*
 350  * SYNOPSIS:
 351  *   int bpc_auth(
 352  *                BPC_CONN *handle,
 353  *                const char *username,
 354  *                const char *password
 355  *               );
 356  *
 357  * ARGUMENTS:
 358  *   BPC_CONN *handle             Connection handle
 359  *   const char *username         Username to authenticate with
 360  *   const char *password         Password to authenticate with
 361  *
 362  * RETURN VALUE:
 363  *   This function returns 0 on failure, 1 on success.
 364  *
 365  * NOTES:
 366  *   This function authenticates with the server specified by the handle.
 367  *
 368  * EXAMPLES:
 369  *
 370  *   // Authenticate with the user "user" and password "pass"
 371  *   if (!bpc_auth(bpc_handle, "user", "pass")) {
 372  *         return(-1);
 373  *   }
 374  */
 375 int bpc_auth(BPC_CONN *handle, const char *username, const char *password) {
 376     uint8_t cmd_reply;
 377     uint8_t status;
 378     int sockid;
 379 
 380     if (!handle || !username || !password) {
 381         CHECKPOINT;
 382         return(0);
 383     }
 384 
 385     if (handle->state != BPC_CMD_NONE) {
 386         CHECKPOINT;
 387         return(0);
 388     }
 389 
 390     sockid = handle->fd;
 391 
 392     if (!_bpc_client_write(sockid,
 393                           BPC_CDT_UINT8, (uint8_t) BPC_CMD_AUTH,
 394                           BPC_CDT_UINT16, (uint16_t) strlen(username),
 395                           BPC_CDT_UINT16, (uint16_t) strlen(password),
 396                           BPC_CDT_STRING, username,
 397                           BPC_CDT_STRING, password,
 398                           BPC_CDT_END)) {
 399         CHECKPOINT;
 400         return(0);
 401     }
 402 
 403     if (!_bpc_client_read(sockid,
 404                          BPC_CDT_UINT8, (uint8_t *) &cmd_reply,
 405                          BPC_CDT_UINT8, (uint8_t *) &status,
 406                          BPC_CDT_END)) {
 407         CHECKPOINT;
 408         return(0);
 409     }
 410 
 411     if (cmd_reply != BPC_CMD_AUTH_REPLY) {
 412         CHECKPOINT;
 413         return(0);
 414     }
 415 
 416     if (status != BPC_STATUS_OKAY) {
 417         CHECKPOINT;
 418         return(0);
 419     }
 420 
 421     CHECKPOINT;
 422     return(1);
 423 }
 424 
 425 /*
 426  * SYNOPSIS (internal):
 427  *   static int _bpc_listget_open(
 428  *                                BPC_CONN *handle,
 429  *                                backuppc_cmd_t sendcmd,
 430  *                                const char *rootpath,
 431  *                                const int recursive,
 432  *                                backuppc_hashid_t hashalgo,
 433  *                                const char *exclpat,
 434  *                                const char *inclpat
 435  *                               );
 436  *
 437  * ARGUMENTS:
 438  *   BPC_CONN *handle             Connection handle
 439  *   backuppc_cmd_t sendcmd       Command to send (BPC_CMD_LIST or BPC_CMD_GET)
 440  *   const char *rootpath         Root path to start the GET or LIST from
 441  *   const int recursive          Boolean option to specify whether or not to
 442  *                                recurse into directories
 443  *   backuppc_hashid_t hashalgo   OR'd list of hash algorithms to ask the
 444  *                                server to compute for each file
 445  *   const char *exclpat          <<NOT USED:XXX>>
 446  *   const char *inclpat          <<NOT USED:XXX>>
 447  *
 448  * RETURN VALUE:
 449  *   This function returns 0 on failure, 1 on success.
 450  *
 451  * NOTES:
 452  *   This function initiates a LIST or GET command (depending on the value of
 453  *   the `sendcmd' parameter) and updates the internal state to indicate that
 454  *   it is in the middle of such a command.
 455  *
 456  *   You should then call _bpc_list() to get either the LIST results or the
 457  *   header of a GET result.
 458  *
 459  *   This is an internal function and not part of the LibBackupPCd API and
 460  *   therefore subject to change or removal.
 461  *
 462  * EXAMPLES:
 463  *
 464  *   // List every node under the root directory non-recursively with no
 465  *   // hashing performed on files.
 466  *   if (!_bpc_listget_open(bpc_handle, BPC_CMD_LIST, "/", 0, BPC_HASH_NONE, NULL, NULL)) {
 467  *         return(-1);
 468  *   }
 469  *
 470  */
 471 static int _bpc_listget_open(BPC_CONN *handle, backuppc_cmd_t sendcmd, const char *rootpath, const int recursive,
	backuppc_hashid_t hashalgo, const char *exclpat, const char *inclpat) {
 472     uint8_t cmd, cmd_options = 0;
 473     int sockid;
 474 
 475     sockid = handle->fd;
 476 
 477     if (sendcmd != BPC_CMD_LIST && sendcmd != BPC_CMD_GET) {
 478         CHECKPOINT;
 479         return(0);
 480     }
 481 
 482     /*
 483      * Handle NULL patterns as blank ones.
 484      */
 485     if (!exclpat) {
 486         exclpat = "";
 487     }
 488     if (!inclpat) {
 489         inclpat = "";
 490     }
 491 
 492     if (recursive) {
 493         cmd_options |= BPC_OPT_RECURSIVE;
 494     }
 495 
 496     switch (hashalgo) {
 497         case BPC_HASH_NONE:
 498             break;
 499         case BPC_HASH_MD4:
 500             cmd_options |= BPC_OPT_MD4;
 501             break;
 502         case BPC_HASH_MD5:
 503             cmd_options |= BPC_OPT_MD5;
 504             break;
 505         case BPC_HASH_SHA1:
 506             cmd_options |= BPC_OPT_SHA1;
 507             break;
 508         case BPC_HASH_BPC:
 509             cmd_options |= BPC_OPT_BPCHASH;
 510             break;
 511     }
 512 
 513     if (!_bpc_client_write(sockid,
 514                           BPC_CDT_UINT8, (uint8_t) sendcmd,
 515                           BPC_CDT_UINT8, (uint8_t) cmd_options,
 516                           BPC_CDT_UINT32, (uint32_t) strlen(exclpat),
 517                           BPC_CDT_UINT32, (uint32_t) strlen(inclpat),
 518                           BPC_CDT_UINT32, (uint32_t) strlen(rootpath),
 519                           BPC_CDT_STRING, (char *) rootpath,
 520                           BPC_CDT_STRING, (char *) exclpat,
 521                           BPC_CDT_STRING, (char *) inclpat,
 522                           BPC_CDT_END)) {
 523         CHECKPOINT;
 524         return(0);
 525     }
 526 
 527     if (!_bpc_client_read(sockid,
 528                          BPC_CDT_UINT8, (uint8_t *) &cmd,
 529                          BPC_CDT_END)) {
 530         CHECKPOINT;
 531         return(0);
 532     }
 533 
 534     /*
 535      * If the server sends us a reply for something other than what we
 536      * asked for, something went wrong, abort.
 537      */
 538     if (cmd != (sendcmd | 0x80)) {
 539         CHECKPOINT;
 540         return(0);
 541     }
 542 
 543     handle->state = sendcmd;
 544 
 545     handle->dent.owner_group[0] = '\0';
 546     handle->dent.owner_user[0] = '\0';
 547     handle->dent.linkdest[0] = '\0';
 548     handle->dent.name[0] = '\0';
 549 
 550     memset(&handle->dent.hash_md4, 0, sizeof(handle->dent.hash_md4));
 551     memset(&handle->dent.hash_md5, 0, sizeof(handle->dent.hash_md5));
 552     memset(&handle->dent.hash_sha1, 0, sizeof(handle->dent.hash_sha1));
 553     memset(&handle->dent.hash_bpc, 0, sizeof(handle->dent.hash_bpc));
 554 
 555     CHECKPOINT;
 556     return(1);
 557 }
 558 
 559 /*
 560  * SYNOPSIS (internal):
 561  *   static int _bpc_listget_close(
 562  *                                 BPC_CONN *handle
 563  *                                );
 564  *
 565  * ARGUMENTS:
 566  *   BPC_CONN *handle             Connection handle
 567  *
 568  * RETURN VALUE:
 569  *   This function returns 0 on failure, 1 on success.
 570  *
 571  * NOTES:
 572  *   This function sets the state of a handle back to NONE after a LIST or GET
 573  *   request has finished.
 574  *
 575  *   This is an internal function and not part of the LibBackupPCd API and
 576  *   therefore subject to change or removal.
 577  *
 578  * EXAMPLES:
 579  *
 580  *   // Terminate an existing LIST or GET command
 581  *   if (!_bpc_listget_close(bpc_handle)) {
 582  *         return(-1);
 583  *   }
 584  *
 585  */
 586 static int _bpc_listget_close(BPC_CONN *handle) {
 587 
 588     handle->state = BPC_CMD_NONE;
 589 
 590     CHECKPOINT;
 591     return(1);
 592 }
 593 
 594 /*
 595  * SYNOPSIS (internal):
 596  *   static struct bpc_fileinfo *_bpc_list(
 597  *                                         BPC_CONN *handle,
 598  *                                         backuppc_cmd_t cmd
 599  *                                        );
 600  *
 601  * ARGUMENTS:
 602  *   BPC_CONN *handle             Connection handle
 603  *   backuppc_cmd_t cmd           Command to process results from (LIST or GET)
 604  *
 605  * RETURN VALUE:
 606  *   This function returns a pointer to a (struct bpc_fileinfo) object.  The
 607  *   contents of this objects may be overwritten with subsequent calls to
 608  *   _bpc_list() for the same handle.  NULL is returned on error or when no
 609  *   more objects exist in the stream.
 610  *
 611  * NOTES:
 612  *   This function gets the contents of a LIST_REPLY or GET_REPLY from the
 613  *   handle and sets them in the (struct bpc_fileinfo) value that it
 614  *   returns.  If it is processing a GET_REPLY it also initializes the
 615  *   values in the (struct bpc_transfer) members.
 616  *
 617  *   This is an internal function and not part of the LibBackupPCd API and
 618  *   therefore subject to change or removal.
 619  *
 620  * EXAMPLES:
 621  *
 622  *   // Get an item from an open LIST command
 623  *   struct bpc_fileinfo *fileinfo;
 624  *
 625  *   fileinfo = _bpc_list(bpc_handle, BPC_CMD_LIST);
 626  *
 627  *   if (!fileinfo) {
 628  *         return(-1);
 629  *   }
 630  *
 631  */
 632 static struct bpc_fileinfo *_bpc_list(BPC_CONN *handle, backuppc_cmd_t cmd) {
 633     struct bpc_fileinfo *ret;
 634     struct bpc_transfer *tinfo;
 635     int sockid;
 636 
 637     uint64_t filesize;
 638     uint32_t attr_sect_len, blocksize, pathnamelen;
 639     uint32_t attr_uid, attr_gid, attr_ctime, attr_mtime, attr_devmajor, attr_devminor;
 640     uint32_t attrlen;
 641     uint16_t attrid;
 642     uint16_t attr_mode;
 643     uint8_t filetype;
 644     mode_t modeval;
 645 
 646     ret = &handle->dent;
 647     tinfo = &handle->tinfo;
 648 
 649     sockid = handle->fd;
 650 
 651     if (!_bpc_client_read(sockid,
 652                           BPC_CDT_UINT8, (uint8_t *) &filetype,
 653                           BPC_CDT_END)) {
 654         CHECKPOINT;
 655         return(NULL);
 656     }
 657 
 658     if (filetype == 0xff) {
 659         _bpc_listget_close(handle);
 660         CHECKPOINT;
 661         return(NULL);
 662     }
 663 
 664     if (!_bpc_client_read(sockid,
 665                           BPC_CDT_UINT32, (uint32_t *) &attr_sect_len,
 666                           BPC_CDT_UINT64, (uint64_t *) &filesize,
 667                           BPC_CDT_UINT32, (uint32_t *) &blocksize,
 668                           BPC_CDT_UINT32, (uint32_t *) &pathnamelen,
 669                           BPC_CDT_END)) {
 670         CHECKPOINT;
 671         return(NULL);
 672     }
 673 
 674     if (pathnamelen >= sizeof(ret->name)) {
 675         SPOTVAR_I(pathnamelen);
 676         CHECKPOINT;
 677         return(NULL);
 678     }
 679 
 680     if (!_bpc_client_read(sockid,
 681                           BPC_CDT_STRING, (size_t) (pathnamelen + 1), &ret->name,
 682                           BPC_CDT_END)) {
 683         CHECKPOINT;
 684         return(NULL);
 685     }
 686 
 687     attr_uid = 0;
 688     attr_gid = 0;
 689     attr_mode = 0;
 690     attr_ctime = 0;
 691     attr_mtime = 0;
 692     attr_devmajor = 0;
 693     attr_devminor = 0;
 694 
 695     memset(ret->hash_md4, '\0', sizeof(ret->hash_md4));
 696     memset(ret->hash_md5, '\0', sizeof(ret->hash_md5));
 697     memset(ret->hash_bpc, '\0', sizeof(ret->hash_bpc));
 698     memset(ret->hash_sha1, '\0', sizeof(ret->hash_sha1));
 699 
 700     /*
 701      * Read the sent attributes.
 702      */
 703     if (attr_sect_len != 0) {
 704         while (1) {
 705             if (!_bpc_client_read(sockid,
 706                                   BPC_CDT_UINT16, (uint16_t *) &attrid,
 707                                   BPC_CDT_END)) {
 708                 CHECKPOINT;
 709                 return(NULL);
 710             }
 711 
 712             if (attrid == 0xffff) {
 713                 break;
 714             }
 715 
 716             if (!_bpc_client_read(sockid,
 717                                   BPC_CDT_UINT32, (uint32_t *) &attrlen,
 718                                   BPC_CDT_END)) {
 719                 CHECKPOINT;
 720                 return(NULL);
 721             }
 722 
 723             switch ((backuppc_attrid_t) attrid) {
 724                 case BPC_ATTRID_NOP:
 725                     if (attrlen != 0) {
 726                         CHECKPOINT;
 727                         return(NULL);
 728                     }
 729                     break;
 730                 case BPC_ATTRID_MTIME:
 731                     if (!_bpc_client_read(sockid,
 732                                           BPC_CDT_UINT32, (uint32_t *) &attr_mtime,
 733                                           BPC_CDT_END)) {
 734                         CHECKPOINT;
 735                         return(NULL);
 736                     }
 737                     break;
 738                 case BPC_ATTRID_CTIME:
 739                     if (!_bpc_client_read(sockid,
 740                                           BPC_CDT_UINT32, (uint32_t *) &attr_ctime,
 741                                           BPC_CDT_END)) {
 742                         CHECKPOINT;
 743                         return(NULL);
 744                     }
 745                     break;
 746                 case BPC_ATTRID_UID:
 747                     if (!_bpc_client_read(sockid,
 748                                           BPC_CDT_UINT32, (uint32_t *) &attr_uid,
 749                                           BPC_CDT_END)) {
 750                         CHECKPOINT;
 751                         return(NULL);
 752                     }
 753                     break;
 754                 case BPC_ATTRID_GID:
 755                     if (!_bpc_client_read(sockid,
 756                                           BPC_CDT_UINT32, (uint32_t *) &attr_gid,
 757                                           BPC_CDT_END)) {
 758                         CHECKPOINT;
 759                         return(NULL);
 760                     }
 761                     break;
 762                 case BPC_ATTRID_ACL:
 763                     if (!_bpc_client_read(sockid,
 764                                           BPC_CDT_UINT16, (uint16_t *) &attr_mode,
 765                                           BPC_CDT_END)) {
 766                         CHECKPOINT;
 767                         return(NULL);
 768                     }
 769 
 770                     break;
 771                 case BPC_ATTRID_USER:
 772                     if (attrlen >= sizeof(ret->owner_user)) {
 773                         CHECKPOINT;
 774                         return(NULL);
 775                     }
 776 
 777                     if (!_bpc_client_read(sockid,
 778                                           BPC_CDT_STRING, (size_t) attrlen + 1, (char *) &ret->owner_user,
 779                                           BPC_CDT_END)) {
 780                         CHECKPOINT;
 781                         return(NULL);
 782                     }
 783                     break;
 784                 case BPC_ATTRID_GROUP:
 785                     if (attrlen >= sizeof(ret->owner_group)) {
 786                         CHECKPOINT;
 787                         return(NULL);
 788                     }
 789 
 790                     if (!_bpc_client_read(sockid,
 791                                           BPC_CDT_STRING, (size_t) attrlen + 1, (char *) &ret->owner_group,
 792                                           BPC_CDT_END)) {
 793                         CHECKPOINT;
 794                         return(NULL);
 795                     }
 796                     break;
 797                 case BPC_ATTRID_SYMLINKDEST:
 798                     if (attrlen >= sizeof(ret->linkdest)) {
 799                         CHECKPOINT;
 800                         return(NULL);
 801                     }
 802 
 803                     if (!_bpc_client_read(sockid,
 804                                           BPC_CDT_STRING, (size_t) attrlen + 1, (char *) &ret->linkdest,
 805                                           BPC_CDT_END)) {
 806                         CHECKPOINT;
 807                         return(NULL);
 808                     }
 809                     break;
 810                 case BPC_ATTRID_HRDLINKDEST:
 811                     if (attrlen >= sizeof(ret->linkdest)) {
 812                         CHECKPOINT;
 813                         return(NULL);
 814                     }
 815 
 816                     if (!_bpc_client_read(sockid,
 817                                           BPC_CDT_STRING, (size_t) attrlen + 1, (char *) &ret->linkdest,
 818                                           BPC_CDT_END)) {
 819                         CHECKPOINT;
 820                         return(NULL);
 821                     }
 822                     break;
 823                 case BPC_ATTRID_MD4:
 824                     if (attrlen != sizeof(ret->hash_md4)) {
 825                         CHECKPOINT;
 826                         return(NULL);
 827                     }
 828 
 829                     if (!_bpc_client_read(sockid,
 830                                           BPC_CDT_BYTEARRAY, (size_t) sizeof(ret->hash_md4), (void *) &ret->hash_md4,
 831                                           BPC_CDT_END)) {
 832                         CHECKPOINT;
 833                         return(NULL);
 834                     }
 835                     break;
 836                 case BPC_ATTRID_MD5:
 837                     if (attrlen != sizeof(ret->hash_md5)) {
 838                         CHECKPOINT;
 839                         return(NULL);
 840                     }
 841 
 842                     if (!_bpc_client_read(sockid,
 843                                           BPC_CDT_BYTEARRAY, (size_t) sizeof(ret->hash_md5), (void *) &ret->hash_md5,
 844                                           BPC_CDT_END)) {
 845                         CHECKPOINT;
 846                         return(NULL);
 847                     }
 848                     break;
 849                 case BPC_ATTRID_SHA1:
 850                     if (attrlen != sizeof(ret->hash_sha1)) {
 851                         CHECKPOINT;
 852                         return(NULL);
 853                     }
 854 
 855                     if (!_bpc_client_read(sockid,
 856                                           BPC_CDT_BYTEARRAY, (size_t) sizeof(ret->hash_sha1), (void *) &ret->hash_sha1,
 857                                           BPC_CDT_END)) {
 858                         CHECKPOINT;
 859                         return(NULL);
 860                     }
 861                     break;
 862                 case BPC_ATTRID_BPCHASH:
 863                     if (attrlen != sizeof(ret->hash_bpc)) {
 864                         CHECKPOINT;
 865                         return(NULL);
 866                     }
 867 
 868                     if (!_bpc_client_read(sockid,
 869                                           BPC_CDT_BYTEARRAY, (size_t) sizeof(ret->hash_bpc), (void *) &ret->hash_bpc,
 870                                           BPC_CDT_END)) {
 871                         CHECKPOINT;
 872                         return(NULL);
 873                     }
 874                     break;
 875 #ifndef DEBUG
 876                 default:
 877                     if (!_bpc_client_read(sockid,
 878                                           BPC_CDT_SINK, (size_t) attrlen,
 879                                           BPC_CDT_END)) {
 880                         CHECKPOINT;
 881                         return(NULL);
 882                     }
 883                     break;
 884 #endif
 885             }
 886         }
 887     }
 888 
 889     /*
 890      * Determine the POSIX "mode" value from the ACL attrs.
 891      */
 892     modeval = 0;
 893     if (attr_mode) {
 894         if ((attr_mode & BPC_ACL_XUSR) == BPC_ACL_XUSR) {
 895             modeval |= S_IXUSR;
 896         }
 897         if ((attr_mode & BPC_ACL_WUSR) == BPC_ACL_WUSR) {
 898             modeval |= S_IWUSR;
 899         }
 900         if ((attr_mode & BPC_ACL_RUSR) == BPC_ACL_RUSR) {
 901             modeval |= S_IRUSR;
 902         }
 903 #ifndef _USE_WIN32_
 904         if ((attr_mode & BPC_ACL_XGRP) == BPC_ACL_XGRP) {
 905             modeval |= S_IXGRP;
 906         }
 907         if ((attr_mode & BPC_ACL_WGRP) == BPC_ACL_WGRP) {
 908             modeval |= S_IWGRP;
 909         }
 910         if ((attr_mode & BPC_ACL_RGRP) == BPC_ACL_RGRP) {
 911             modeval |= S_IRGRP;
 912         }
 913         if ((attr_mode & BPC_ACL_XOTH) == BPC_ACL_XOTH) {
 914             modeval |= S_IXOTH;
 915         }
 916         if ((attr_mode & BPC_ACL_WOTH) == BPC_ACL_WOTH) {
 917             modeval |= S_IWOTH;
 918         }
 919         if ((attr_mode & BPC_ACL_ROTH) == BPC_ACL_ROTH) {
 920             modeval |= S_IROTH;
 921         }
 922         if ((attr_mode & BPC_ACL_STCK) == BPC_ACL_STCK) {
 923             modeval |= S_ISVTX;
 924         }
 925         if ((attr_mode & BPC_ACL_SGID) == BPC_ACL_SGID) {
 926             modeval |= S_ISGID;
 927         }
 928         if ((attr_mode & BPC_ACL_SUID) == BPC_ACL_SUID) {
 929             modeval |= S_ISUID;
 930         }
 931 #endif
 932     }
 933 
 934 #if 0
 935     if (filetype == BPC_FILE_REG) {
 936         modeval |= S_IFREG;
 937     }
 938 #ifndef _USE_WIN32_
 939     if (filetype == BPC_FILE_SYMLINK) {
 940         modeval |= S_IFLNK;
 941     }
 942     if (filetype == BPC_FILE_SOCKET) {
 943         modeval |= S_IFSOCK;
 944     }
 945 #endif
 946     if (filetype == BPC_FILE_DIR) {
 947         modeval |= S_IFDIR;
 948     }
 949     if (filetype == BPC_FILE_BDEV) {
 950         modeval |= S_IFBLK;
 951     }
 952     if (filetype == BPC_FILE_CDEV) {
 953         modeval |= S_IFCHR;
 954     }
 955     if (filetype == BPC_FILE_FIFO) {
 956         modeval |= S_IFIFO;
 957     }
 958 #endif
 959 
 960     ret->mode = modeval;
 961     ret->type = filetype;
 962     ret->size = filesize;
 963     ret->uid = attr_uid;
 964     ret->gid = attr_gid;
 965     ret->mtime = attr_mtime;
 966     ret->ctime = attr_ctime;
 967 
 968     if (cmd == BPC_CMD_GET) {
 969         tinfo->blocksize = blocksize;
 970         tinfo->idealblocknum = -1;
 971         tinfo->currblocknum = 0;
 972         tinfo->filesize = filesize;
 973         tinfo->blockoffset = 0;
 974     }
 975 
 976     return(ret);
 977 }
 978 
 979 /*
 980  * SYNOPSIS:
 981  *   int bpc_list_open(
 982  *                     BPC_CONN *handle,
 983  *                     const char *rootpath,
 984  *                     const int recursive,
 985  *                     backuppc_hashid_t hashalgo,
 986  *                     const char *exclpat,
 987  *                     const char *inclpat
 988  *                    );
 989  *
 990  * ARGUMENTS:
 991  *   BPC_CONN *handle             Connection handle
 992  *   const char *rootpath         Root path to start the GET or LIST from
 993  *   const int recursive          Boolean option to specify whether or not to
 994  *                                recurse into directories
 995  *   backuppc_hashid_t hashalgo   OR'd list of hash algorithms to ask the
 996  *                                server to compute for each file
 997  *   const char *exclpat          <<NOT USED:XXX>>
 998  *   const char *inclpat          <<NOT USED:XXX>>
 999  *
1000  * RETURN VALUE:
1001  *   This function returns 0 on failure, 1 on success.
1002  *
1003  * NOTES:
1004  *   This function initiates a LIST command (by calling _bpc_listget_open()).
1005  *   You must not be in the middle of any other command at the time.
1006  *
1007  *   You should then call bpc_list() to get the LIST results.
1008  *
1009  * EXAMPLES:
1010  *
1011  *   // List every node under the root directory non-recursively with no
1012  *   // hashing performed on files.
1013  *   if (!bpc_list_open(bpc_handle, "/", 0, BPC_HASH_NONE, NULL, NULL)) {
1014  *         return(-1);
1015  *   }
1016  *
1017  */
1018 int bpc_list_open(BPC_CONN *handle, const char *rootpath, const int recursive, backuppc_hashid_t hashalgo, const char
	*exclpat, const char *inclpat) {
1019     if (!handle) {
1020         return(0);
1021     }
1022 
1023     if (handle->state != BPC_CMD_NONE) {
1024         return(0);
1025     }
1026 
1027     return(_bpc_listget_open(handle, BPC_CMD_LIST, rootpath, recursive, hashalgo, exclpat, inclpat));
1028 }
1029 
1030 /*
1031  * SYNOPSIS:
1032  *   int bpc_list_close(
1033  *                      BPC_CONN *handle
1034  *                     );
1035  *
1036  * ARGUMENTS:
1037  *   BPC_CONN *handle             Connection handle
1038  *
1039  * RETURN VALUE:
1040  *   This function returns 0 on failure, 1 on success.
1041  *
1042  * NOTES:
1043  *   This function verifies that a previous operation completed
1044  *   sucessfully and that we are now not in the middle of any command.
1045  *
1046  * EXAMPLES:
1047  *
1048  *   // Verify that the previous LIST command is complete
1049  *   if (!bpc_list_close(bpc_handle)) {
1050  *         return(-1);
1051  *   }
1052  *
1053  */
1054 int bpc_list_close(BPC_CONN *handle) {
1055     if (!handle) {
1056         return(0);
1057     }
1058 
1059     if (handle->state != BPC_CMD_NONE) {
1060         return(0);
1061     }
1062 
1063     return(1);
1064 }
1065 
1066 /*
1067  * SYNOPSIS:
1068  *   struct bpc_fileinfo *bpc_list(
1069  *                                 BPC_CONN *handle,
1070  *                                );
1071  *
1072  * ARGUMENTS:
1073  *   BPC_CONN *handle             Connection handle
1074  *
1075  * RETURN VALUE:
1076  *   This function returns a pointer to a (struct bpc_fileinfo) object.  The
1077  *   contents of this objects may be overwritten with subsequent calls to
1078  *   bpc_list() for the same handle.  NULL is returned on error or when no
1079  *   more objects exist in the stream.
1080  *
1081  * NOTES:
1082  *   This function gets the contents of a LIST_REPLY from the handle and sets
1083  *   them in the (struct bpc_fileinfo) value that it returns.
1084  *
1085  * EXAMPLES:
1086  *
1087  *   // Get an item from an open LIST command
1088  *   struct bpc_fileinfo *fileinfo;
1089  *
1090  *   fileinfo = bpc_list(bpc_handle);
1091  *
1092  *   if (!fileinfo) {
1093  *         return(-1);
1094  *   }
1095  *
1096  */
1097 struct bpc_fileinfo *bpc_list(BPC_CONN *handle) {
1098     if (!handle) {
1099         return(NULL);
1100     }
1101 
1102     if (handle->state != BPC_CMD_LIST) {
1103         return(NULL);
1104     }
1105 
1106     return(_bpc_list(handle, BPC_CMD_LIST));
1107 }
1108 
1109 /*
1110  * SYNOPSIS:
1111  *   int bpc_get_open(
1112  *                    BPC_CONN *handle,
1113  *                    const char *rootpath,
1114  *                    const int recursive,
1115  *                    backuppc_hashid_t hashalgo,
1116  *                    const char *exclpat,
1117  *                    const char *inclpat
1118  *                   );
1119  *
1120  * ARGUMENTS:
1121  *   BPC_CONN *handle             Connection handle
1122  *   const char *rootpath         Root path to start the GET or LIST from
1123  *   const int recursive          Boolean option to specify whether or not to
1124  *                                recurse into directories
1125  *   backuppc_hashid_t hashalgo   OR'd list of hash algorithms to ask the
1126  *                                server to compute for each file
1127  *   const char *exclpat          <<NOT USED:XXX>>
1128  *   const char *inclpat          <<NOT USED:XXX>>
1129  *
1130  * RETURN VALUE:
1131  *   This function returns 0 on failure, 1 on success.
1132  *
1133  * NOTES:
1134  *   This function initiates a GET command and updates the internal state to
1135  *   indicate that it is in the middle of such a command.
1136  *
1137  *   You should then call bpc_get_head() to get the header of the GET result.
1138  *
1139  * EXAMPLES:
1140  *
1141  *   // Get every node under "/" non-recursively and do not perform any
1142  *   // hashing on the files.
1143  *   if (!bpc_get_open(bpc_handle, "/", 0, BPC_HASH_NONE, NULL, NULL)) {
1144  *         return(-1);
1145  *   }
1146  *
1147  */
1148 int bpc_get_open(BPC_CONN *handle, const char *rootpath, const int recursive, backuppc_hashid_t hashalgo, const char
	*exclpat, const char *inclpat) {
1149     int retval;
1150 
1151     if (!handle) {
1152         CHECKPOINT;
1153         return(0);
1154     }
1155 
1156     if (handle->state != BPC_CMD_NONE) {
1157         CHECKPOINT;
1158         return(0);
1159     }
1160 
1161     retval = _bpc_listget_open(handle, BPC_CMD_GET, rootpath, recursive, hashalgo, exclpat, inclpat);
1162 
1163     if (retval == 0) {
1164         CHECKPOINT;
1165         return(0);
1166     }
1167 
1168     CHECKPOINT;
1169     return(retval);
1170 }
1171 
1172 /*
1173  * SYNOPSIS:
1174  *   int bpc_get_close(
1175  *                     BPC_CONN *handle
1176  *                    );
1177  *
1178  * ARGUMENTS:
1179  *   BPC_CONN *handle             Connection handle
1180  *
1181  * RETURN VALUE:
1182  *   This function returns 0 on failure, 1 on success.
1183  *
1184  * NOTES:
1185  *   This function verifies that a previous operation completed
1186  *   sucessfully and that we are now not in the middle of any command.
1187  *
1188  * EXAMPLES:
1189  *
1190  *   // Verify that we have terminated a previously existing GET command
1191  *   if (!bpc_get_close(bpc_handle)) {
1192  *         return(-1);
1193  *   }
1194  *
1195  */
1196 int bpc_get_close(BPC_CONN *handle) {
1197     if (!handle) {
1198         return(0);
1199     }
1200 
1201     if (handle->state != BPC_CMD_NONE) {
1202         return(0);
1203     }
1204 
1205     return(1);
1206 }
1207 
1208 /*
1209  * SYNOPSIS (internal):
1210  *   struct bpc_fileinfo *bpc_get_head(
1211  *                                     BPC_CONN *handle,
1212  *                                    );
1213  *
1214  * ARGUMENTS:
1215  *   BPC_CONN *handle             Connection handle
1216  *
1217  * RETURN VALUE:
1218  *   This function returns a pointer to a (struct bpc_fileinfo) object.  The
1219  *   contents of this objects may be overwritten with subsequent calls to
1220  *   bpc_get_head() for the same handle.  NULL is returned on error or when no
1221  *   more objects exist in the stream.
1222  *
1223  * NOTES:
1224  *   This function gets the header of a GET_REPLY from the handle and sets
1225  *   them in the (struct bpc_fileinfo) value that it returns.
1226  *
1227  *   You should then call bpc_get() if the header indicates that this
1228  *   represents this is a regular file.
1229  *
1230  * EXAMPLES:
1231  *
1232  *   // Get an item from an open LIST command
1233  *   struct bpc_fileinfo *fileinfo;
1234  *
1235  *   fileinfo = bpc_get_head(bpc_handle);
1236  *
1237  *   if (!fileinfo) {
1238  *         return(-1);
1239  *   }
1240  *
1241  */
1242 struct bpc_fileinfo *bpc_get_head(BPC_CONN *handle) {
1243     uint32_t blocknum;
1244     struct bpc_fileinfo *ret;
1245 
1246     if (!handle) {
1247         CHECKPOINT;
1248         return(NULL);
1249     }
1250 
1251     if (handle->state != BPC_CMD_GET) {
1252         CHECKPOINT;
1253         return(NULL);
1254     }
1255 
1256     /*
1257      * The "GET" operation is the same as the "LIST" operation, except
1258      * data will follow if the type is BPC_FILE_REG.
1259      */
1260     ret = _bpc_list(handle, BPC_CMD_GET);
1261 
1262     if (!ret) {
1263         CHECKPOINT;
1264         return(NULL);
1265     }
1266 
1267     if (ret->type != BPC_FILE_REG) {
1268         if (!_bpc_client_read(handle->fd,
1269                               BPC_CDT_UINT32, &blocknum,
1270                               BPC_CDT_END)) {
1271             CHECKPOINT;
1272             return(NULL);
1273         }
1274 
1275         if (blocknum != 0xffffffff) {
1276             CHECKPOINT;
1277             return(NULL);
1278         }
1279 
1280         CHECKPOINT;
1281         return(ret);
1282     }
1283 
1284     handle->state = BPC_CMD_GET_DATA;
1285 
1286     return(ret);
1287 }
1288 
1289 /*
1290  * SYNOPSIS:
1291  *   ssize_t bpc_get(
1292  *                   BPC_CONN *handle,
1293  *                   char *buf,
1294  *                   size_t count
1295  *                  );
1296  *
1297  * ARGUMENTS:
1298  *   BPC_CONN *handle             Connection handle
1299  *   void *buf                    Pointer to a buffer to return data into
1300  *   size_t count                 Size of buffer
1301  *
1302  * RETURN VALUE:
1303  *   This function returns the number of bytes written to the memory pointed to
1304  *   by `buf' on success.  On error -1 is returned.
1305  *
1306  * NOTES:
1307  *
1308  * EXAMPLES:
1309  *
1310  *   // Get an item from an open LIST command
1311  *   ssize_t ret;
1312  *   char buf[20];
1313  *
1314  *   ret = bpc_get(bpc_handle, buf, sizeof(buf));
1315  *
1316  *   if (ret < 0) {
1317  *         return(-1);
1318  *   }
1319  *
1320  */
1321 ssize_t bpc_get(BPC_CONN *handle, void *buf, size_t count) {
1322     struct bpc_transfer *tinfo;
1323     ssize_t recv_ret;
1324     uint32_t bytes_left;
1325     uint32_t sinkbytes = 0;
1326     int sockid;
1327 
1328     if (!handle) {
1329         CHECKPOINT;
1330         return(-1);
1331     }
1332 
1333     if (handle->state != BPC_CMD_GET_DATA) {
1334         CHECKPOINT;
1335         return(-1);
1336     }
1337 
1338     sockid = handle->fd;
1339 
1340     tinfo = &handle->tinfo;
1341 
1342     if (tinfo->blockoffset == 0) {
1343         if (tinfo->currblocknum == tinfo->idealblocknum || tinfo->idealblocknum == -1) {
1344             if (!_bpc_client_read(sockid,
1345                                   BPC_CDT_UINT32, &tinfo->currblocknum,
1346                                   BPC_CDT_END)) {
1347                 CHECKPOINT;
1348                 return(-1);
1349             }
1350 
1351             if (tinfo->currblocknum == 0xffffffff) {
1352                 handle->state = BPC_CMD_GET;
1353                 CHECKPOINT;
1354                 return(0);
1355             }
1356         }
1357 
1358         if (tinfo->currblocknum == 0) {
1359             tinfo->idealblocknum = 0;
1360         } else {
1361             tinfo->idealblocknum++;
1362         }
1363     }
1364 
1365     bytes_left = tinfo->blocksize - tinfo->blockoffset;
1366 
1367     if (count > bytes_left) {
1368         count = bytes_left;
1369     }
1370 
1371     if ((tinfo->idealblocknum * tinfo->blocksize + tinfo->blockoffset) > tinfo->filesize) {
1372         count = 0;
1373         sinkbytes = tinfo->blocksize - tinfo->blockoffset;
1374     } else {
1375         if ((tinfo->idealblocknum * tinfo->blocksize + tinfo->blockoffset + count) > tinfo->filesize) {
1376             count = tinfo->filesize - (tinfo->idealblocknum * tinfo->blocksize + tinfo->blockoffset);
1377             sinkbytes = tinfo->blocksize - count;
1378         }
1379     }
1380 
1381     if (tinfo->currblocknum != tinfo->idealblocknum) {
1382         memset(buf, '\0', count);
1383         recv_ret = count;
1384     } else {
1385         recv_ret = recv(sockid, buf, count, MSG_WAITALL);
1386 
1387         if (sinkbytes) {
1388             if (!_bpc_client_read(sockid,
1389                                   BPC_CDT_SINK, (ssize_t) sinkbytes,
1390                                   BPC_CDT_END)) {
1391                 CHECKPOINT;
1392                 return(-1);
1393             }
1394         }
1395     }
1396 
1397     if (recv_ret < 0) {
1398         CHECKPOINT;
1399         return(-1);
1400     }
1401 
1402     tinfo->blockoffset += recv_ret + sinkbytes;
1403 
1404     if (tinfo->blockoffset == tinfo->blocksize) {
1405         tinfo->blockoffset = 0;
1406     }
1407 
1408     CHECKPOINT;
1409     return(recv_ret);
1410 }
1411 
1412 int bpc_copy(BPC_CONN *handle, bpc_mode_t mode, int fd) {
1413     char buf[32768];
1414     ssize_t read_ret, write_ret;
1415     int write_fail_count = 0;
1416     int retval = 1;
1417 
1418     while (1) {
1419         read_ret = bpc_get(handle, buf, sizeof(buf));
1420 
1421         if (read_ret == 0) {
1422             break;
1423         }
1424 
1425         if (read_ret < 0) {
1426             retval = 0;
1427             break;
1428         }
1429 
1430         while (read_ret) {
1431             switch (mode) {
1432                 case BPC_MODE_WRITE:
1433                     write_ret = write(fd, buf, read_ret);
1434                     break;
1435                 case BPC_MODE_SEND:
1436                     write_ret = send(fd, buf, read_ret, 0);
1437                     break;
1438                 default:
1439                     write_ret = -1;
1440             }
1441             
1442 
1443             if (write_ret < 0) {
1444                 retval = 0;
1445                 break;
1446             }
1447 
1448             if (write_ret == 0) {
1449                 write_fail_count++;
1450             } else {
1451                 write_fail_count = 0;
1452             }
1453 
1454             if (write_fail_count >= 10) {
1455                 retval = 0;
1456                 break;
1457             }
1458 
1459             read_ret -= write_ret;
1460         }
1461     }
1462 
1463     CHECKPOINT;
1464     return(retval);
1465 }
1466 
1467 int bpc_rdiffget(BPC_CONN *handle, const char *remote_src, const char *dest) {
1468     backuppc_hashid_t hashalgo = BPC_HASH_MD4;
1469     struct stat stbuf;
1470     uint64_t filesize;
1471     uint32_t blocksize;
1472     uint32_t num_hash_ents, hash_ent, hash_ent_size, hash_list_size;
1473     ssize_t read_ret;
1474     char buf[BPC_MAX_RDIFF_BLOCKSIZE];
1475     void *hash_handle;
1476     int stat_ret;
1477     int sockid;
1478     int fd;
1479 
1480     if (!handle) {
1481         return(0);
1482     }
1483 
1484     sockid = handle->fd;
1485 
1486     stat_ret = stat(dest, &stbuf);
1487     if (stat_ret < 0) {
1488         filesize = 0xffffffffffffffffLLU;
1489         blocksize = 0;
1490         num_hash_ents = 0;
1491     } else {
1492         filesize = stbuf.st_size;
1493 
1494         /*
1495          * Determine the block size:
1496          *  0 bytes to 20 MBytes:  2 KBytes
1497          *  20 MBytes to 1 GByte:  4 KBytes
1498          *  1 GByte to Infinity:   8 KBytes
1499          */
1500         if (filesize < (20 * 1024 * 1024)) {
1501             blocksize = 2048;
1502         } else if (filesize < (1024 * 1024 * 1024)) {
1503             blocksize = 4096;
1504         } else {
1505             blocksize = BPC_MAX_RDIFF_BLOCKSIZE;
1506         }
1507 
1508         if (blocksize > BPC_MAX_RDIFF_BLOCKSIZE) {
1509             blocksize = BPC_MAX_RDIFF_BLOCKSIZE;
1510         }
1511 
1512         num_hash_ents = (filesize + blocksize - 1) / blocksize;
1513     }
1514 
1515     switch (hashalgo) {
1516         case BPC_HASH_NONE:
1517             break;
1518         case BPC_HASH_MD5:
1519             hash_ent_size = (128 / 8);
1520             hash_handle = NULL;
1521             break;
1522         case BPC_HASH_MD4:
1523             hash_ent_size = (128 / 8);
1524             hash_handle = NULL;
1525             break;
1526         case BPC_HASH_SHA1:
1527             hash_ent_size = (160 / 8);
1528             hash_handle = malloc(sizeof(SHA1_CTX));
1529             break;
1530         case BPC_HASH_BPC:
1531             hash_ent_size = (128 / 8);
1532             hash_handle = NULL;
1533             break;
1534     }
1535 
1536     hash_list_size = num_hash_ents * hash_ent_size;
1537 
1538     if (!_bpc_client_write(sockid,
1539                            BPC_CDT_UINT8, (uint8_t) BPC_CMD_RDGET,
1540                            BPC_CDT_UINT64, (uint64_t) filesize,
1541                            BPC_CDT_UINT32, (uint32_t) blocksize, 
1542                            BPC_CDT_UINT8, (uint8_t) hashalgo,
1543                            BPC_CDT_UINT32, (uint32_t) hash_list_size, 
1544                            BPC_CDT_UINT32, (uint32_t) strlen(remote_src),
1545                            BPC_CDT_STRING, (char *) remote_src,
1546                            BPC_CDT_END)) {
1547         return(0);
1548     }
1549 
1550     fd = open(dest, O_RDONLY);
1551 
1552     if (fd < 0) {
1553         return(0);
1554     }
1555 
1556     for (hash_ent = 0; hash_ent < num_hash_ents; hash_ent++) {
1557         read_ret = read(fd, buf, blocksize);
1558         if (read_ret < 0) {
1559             read_ret = 0;
1560         }
1561 
1562         if (read_ret == 0) {
1563             CHECKPOINT;
1564         }
1565 
1566         switch (hashalgo) {
1567             case BPC_HASH_NONE:
1568                 break;
1569             case BPC_HASH_SHA1:
1570                 SHA1Init(hash_handle);
1571                 SHA1Update(hash_handle, buf, read_ret);
1572 //              SHA1Final(digest[20], hash_handle);
1573                 break;
1574             case BPC_HASH_MD5:
1575             case BPC_HASH_MD4:
1576             case BPC_HASH_BPC:
1577                 break;
1578         }
1579     }
1580 
1581     close(fd);
1582 
1583     if (hash_handle) {
1584         free(hash_handle);
1585     }
1586 
1587     return(1);
1588 }
1589 
1590 int bpc_copyfile(BPC_CONN *handle, struct bpc_fileinfo *src, const char *dest, int preserve) {
1591     int fd;
1592     int retval = 0;
1593     int sys_ret;
1594 
1595     switch (src->type) {
1596         case BPC_FILE_DIR:
1597             backuppc_mkdir(dest);
1598             retval = 1;
1599             break;
1600         case BPC_FILE_SYMLINK:
1601 #ifdef HAVE_SYMLINK
1602             sys_ret = symlink(src->linkdest, dest);
1603             if (sys_ret == 0) {
1604                 retval = 1;
1605             }
1606 #endif
1607             break;
1608         case BPC_FILE_HRDLINK:
1609             sys_ret = link(src->linkdest, dest);
1610             if (sys_ret == 0) {
1611                 retval = 1;
1612             }
1613             break;
1614         case BPC_FILE_CDEV:
1615         case BPC_FILE_BDEV:
1616         case BPC_FILE_SOCKET:
1617         case BPC_FILE_FIFO:
1618         case BPC_FILE_UNKNOWN:
1619             CHECKPOINT;
1620             return(0); 
1621         case BPC_FILE_REG:
1622             /*
1623              * Regular files are handled seperately
1624              */
1625             break;
1626     }
1627 
1628     if (src->type != BPC_FILE_REG) {
1629         if (retval && preserve) {
1630             chmod(dest, src->mode);
1631 #ifdef HAVE_LCHOWN
1632             lchown(dest, src->uid, src->gid);
1633 #else
1634             chown(dest, src->uid, src->gid);
1635 #endif
1636 #ifdef HAVE_UTIME
1637 //          utime(...)
1638 #endif
1639         }
1640         CHECKPOINT;
1641         return(retval);
1642     }
1643 
1644 
1645     /*
1646      * Handle the regular files using either RDIFF or GET.
1647      */
1648     if (access(dest, F_OK) == 0 && 0 /* XXX: RGET NOT IMPLEMENTED */) {
1649         /*
1650          * Do RDIFF 
1651          */
1652     } else {
1653         /*
1654          * Copy the entire file.
1655          */
1656         fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600);
1657 
1658         if (bpc_copy(handle, BPC_MODE_WRITE, fd)) {
1659             retval = 1;
1660         }
1661 
1662         close(fd);
1663     }
1664     if (preserve) {
1665         chmod(dest, src->mode);
1666         chown(dest, src->uid, src->gid);
1667 #ifdef HAVE_UTIME
1668 //      utime(...)
1669 #endif
1670     }
1671 
1672     CHECKPOINT;
1673     return(retval);
1674 }
1675 
1676 /*
1677  * SYNOPSIS:
1678  *   BPC_CONN *bpc_connect(
1679  *                         const char *host,
1680  *                         const int port,
1681  *                         const char *username,
1682  *                         const char *password
1683  *                        );
1684  *
1685  * ARGUMENTS:
1686  *   const char *host             BackupPCd host to connect to
1687  *   const int port               Port to connect to host on (default if == 0)
1688  *   const char *username         (optional) Username to authenticate with
1689  *   const char *password         (optional) Password to authenticate with
1690  *
1691  * RETURN VALUE:
1692  *   This function returns NULL on failure, a pointer to a (BPC_CONN) on success.
1693  *
1694  * NOTES:
1695  *
1696  * EXAMPLES:
1697  *
1698  */
1699 BPC_CONN *bpc_connect(const char *host, const int port, const char *username, const char *password) {
1700     BPC_CONN *ret;
1701     int sockid;
1702     int real_port;
1703 
1704     if (port == 0) {
1705         real_port = BPC_TCP_PORT;
1706     } else {
1707         real_port = port;
1708     }
1709 
1710     sockid = net_connect_tcp(host, real_port);
1711 
1712     if (sockid < 0) {
1713         CHECKPOINT;
1714         return(NULL);
1715     }
1716 
1717     ret = malloc(sizeof(*ret));
1718 
1719     if (!ret) {
1720         close(sockid);
1721 
1722         CHECKPOINT;
1723         return(NULL);
1724     }
1725 
1726     ret->fd = sockid;
1727     ret->state = BPC_CMD_NONE;
1728 
1729     if (username && password) {
1730         if (!bpc_auth(ret, username, password)) {
1731             close(ret->fd);
1732             free(ret);
1733 
1734             CHECKPOINT;
1735             return(NULL);
1736         }
1737     }
1738 
1739     CHECKPOINT;
1740     return(ret);
1741 }
1742 
1743 /*
1744  * SYNOPSIS:
1745  *   int bpc_disconnect(
1746  *                      BPC_CONN *handle
1747  *                     );
1748  *
1749  * ARGUMENTS:
1750  *   BPC_CONN *handle             Connection handle
1751  *
1752  * RETURN VALUE:
1753  *   This function returns -1 on failure, 0 on success.
1754  *
1755  * NOTES:
1756  *
1757  * EXAMPLES:
1758  *
1759  */
1760 int bpc_disconnect(BPC_CONN *handle) {
1761     int close_ret;
1762 
1763     if (!handle) {
1764         CHECKPOINT;
1765         return(-1);
1766     }
1767 
1768     if (handle->fd < 0) {
1769         CHECKPOINT;
1770         return(0);
1771     }
1772 
1773     close_ret = net_close(handle->fd);
1774 
1775     if (close_ret < 0) {
1776         CHECKPOINT;
1777         return(close_ret);
1778     }
1779 
1780     free(handle);
1781 
1782     CHECKPOINT;
1783     return(0);
1784 }
5762840 [rkeene@sledge /home/rkeene/devel/backuppcd/all/backuppcd-200601171056]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2006-01-17 16:11:01