1/* 2 * Copyright (C) Joerg Lenneis 2003 3 * Copyright (C) Frank Lahm 2010 4 * All Rights Reserved. See COPYING. 5 */ 6 7#ifdef HAVE_CONFIG_H 8#include "config.h" 9#endif /* HAVE_CONFIG_H */ 10 11#ifdef CNID_BACKEND_DBD 12 13#include <stdlib.h> 14#ifdef HAVE_SYS_STAT_H 15#include <sys/stat.h> 16#endif /* HAVE_SYS_STAT_H */ 17#ifdef HAVE_SYS_UIO_H 18#include <sys/uio.h> 19#endif /* HAVE_SYS_UIO_H */ 20#ifdef HAVE_STRINGS_H 21#include <strings.h> 22#endif 23#include <sys/time.h> 24#include <sys/un.h> 25#include <sys/socket.h> 26#include <sys/param.h> 27#include <errno.h> 28#include <netinet/in.h> 29#include <net/if.h> 30#include <netinet/tcp.h> 31#include <netinet/in.h> 32#include <arpa/inet.h> 33#include <errno.h> 34#include <netdb.h> 35#include <time.h> 36 37#include <netatalk/endian.h> 38#include <atalk/logger.h> 39#include <atalk/adouble.h> 40#include <atalk/cnid.h> 41#include <atalk/cnid_dbd_private.h> 42#include <atalk/util.h> 43 44#include "cnid_dbd.h" 45 46#ifndef SOL_TCP 47#define SOL_TCP IPPROTO_TCP 48#endif /* ! SOL_TCP */ 49 50/* Wait MAX_DELAY seconds before a request to the CNID server times out */ 51#define MAX_DELAY 20 52#define ONE_DELAY 5 53 54static void RQST_RESET(struct cnid_dbd_rqst *r) 55{ 56 memset(r, 0, sizeof(struct cnid_dbd_rqst )); 57} 58 59static void delay(int sec) 60{ 61 struct timeval tv; 62 63 tv.tv_usec = 0; 64 tv.tv_sec = sec; 65 select(0, NULL, NULL, NULL, &tv); 66} 67 68#ifndef AI_NUMERICSERV 69#define AI_NUMERICSERV 0 70#endif 71 72static int tsock_getfd(const char *host, const char *port) 73{ 74 int sock = -1; 75 int attr; 76 int err; 77 struct addrinfo hints, *servinfo, *p; 78 int optval; 79 socklen_t optlen = sizeof(optval); 80 81 /* Prepare hint for getaddrinfo */ 82 memset(&hints, 0, sizeof hints); 83 hints.ai_family = AF_UNSPEC; 84 hints.ai_socktype = SOCK_STREAM; 85 hints.ai_flags = AI_NUMERICSERV; 86 87 if ((err = getaddrinfo(host, port, &hints, &servinfo)) != 0) { 88 LOG(log_error, logtype_default, "tsock_getfd: getaddrinfo: CNID server %s:%s : %s\n", 89 host, port, gai_strerror(err)); 90 return -1; 91 } 92 93 /* loop through all the results and bind to the first we can */ 94 for (p = servinfo; p != NULL; p = p->ai_next) { 95 if ((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { 96 LOG(log_info, logtype_default, "tsock_getfd: socket CNID server %s:: %s", 97 host, strerror(errno)); 98 continue; 99 } 100 101 attr = 1; 102 if (setsockopt(sock, SOL_TCP, TCP_NODELAY, &attr, sizeof(attr)) == -1) { 103 LOG(log_error, logtype_cnid, "getfd: set TCP_NODELAY CNID server %s: %s", 104 host, strerror(errno)); 105 close(sock); 106 sock = -1; 107 return -1; 108 } 109 110 if (setnonblock(sock, 1) != 0) { 111 LOG(log_error, logtype_cnid, "getfd: setnonblock: %s", strerror(errno)); 112 close(sock); 113 sock = -1; 114 return -1; 115 } 116 117 if (connect(sock, p->ai_addr, p->ai_addrlen) == -1) { 118 if (errno == EINPROGRESS) { 119 struct timeval tv; 120 tv.tv_usec = 0; 121 tv.tv_sec = 5; /* give it five seconds ... */ 122 fd_set wfds; 123 FD_ZERO(&wfds); 124 FD_SET(sock, &wfds); 125 126 if ((err = select(sock + 1, NULL, &wfds, NULL, &tv)) == 0) { 127 /* timeout */ 128 LOG(log_error, logtype_cnid, "getfd: select timed out for CNID server %s", 129 host); 130 close(sock); 131 sock = -1; 132 continue; 133 } 134 if (err == -1) { 135 /* select failed */ 136 LOG(log_error, logtype_cnid, "getfd: select failed for CNID server %s", 137 host); 138 close(sock); 139 sock = -1; 140 continue; 141 } 142 143 if ( ! FD_ISSET(sock, &wfds)) { 144 /* give up */ 145 LOG(log_error, logtype_cnid, "getfd: socket not ready connecting to %s", 146 host); 147 close(sock); 148 sock = -1; 149 continue; 150 } 151 152 if ((err = getsockopt(sock, SOL_SOCKET, SO_ERROR, &optval, &optlen)) != 0 || optval != 0) { 153 if (err != 0) { 154 /* somethings very wrong */ 155 LOG(log_error, logtype_cnid, "getfd: getsockopt error with CNID server %s: %s", 156 host, strerror(errno)); 157 } else { 158 errno = optval; 159 LOG(log_error, logtype_cnid, "getfd: getsockopt says: %s", 160 strerror(errno)); 161 } 162 close(sock); 163 sock = -1; 164 continue; 165 } 166 } else { 167 LOG(log_error, logtype_cnid, "getfd: connect CNID server %s: %s", 168 host, strerror(errno)); 169 close(sock); 170 sock = -1; 171 continue; 172 } 173 } 174 175 /* We've got a socket */ 176 break; 177 } 178 179 freeaddrinfo(servinfo); 180 181 if (p == NULL) { 182 errno = optval; 183 LOG(log_error, logtype_cnid, "tsock_getfd: no suitable network config from CNID server (%s:%s): %s", 184 host, port, strerror(errno)); 185 return -1; 186 } 187 188 return(sock); 189} 190 191/*! 192 * Write "towrite" bytes using writev on non-blocking fd 193 * 194 * Every short write is considered an error, transmit can handle that. 195 * 196 * @param fd (r) socket fd which must be non-blocking 197 * @param iov (r) iovec for writev 198 * @param towrite (r) number of bytes in all iovec elements 199 * @param vecs (r) number of iovecs in array 200 * 201 * @returns "towrite" bytes written or -1 on error 202 */ 203static int write_vec(int fd, struct iovec *iov, ssize_t towrite, int vecs) 204{ 205 ssize_t len; 206 int slept = 0; 207 int sleepsecs; 208 209 while (1) { 210 if (((len = writev(fd, iov, vecs)) == -1 && errno == EINTR)) 211 continue; 212 213 if ((! slept) && len == -1 && errno == EAGAIN) { 214 sleepsecs = 2; 215 while ((sleepsecs = sleep(sleepsecs))); 216 slept = 1; 217 continue; 218 } 219 220 if (len == towrite) /* wrote everything out */ 221 break; 222 223 if (len == -1) 224 LOG(log_error, logtype_cnid, "write_vec: %s", strerror(errno)); 225 else 226 LOG(log_error, logtype_cnid, "write_vec: short write: %d", len); 227 return len; 228 } 229 230 LOG(log_maxdebug, logtype_cnid, "write_vec: wrote %d bytes", len); 231 232 return len; 233} 234 235/* --------------------- */ 236static int init_tsock(CNID_private *db) 237{ 238 int fd; 239 int len; 240 struct iovec iov[2]; 241 242 LOG(log_debug, logtype_cnid, "init_tsock: BEGIN. Opening volume '%s', CNID Server: %s/%s", 243 db->db_dir, db->cnidserver, db->cnidport); 244 245 if ((fd = tsock_getfd(db->cnidserver, db->cnidport)) < 0) 246 return -1; 247 248 len = strlen(db->db_dir); 249 250 iov[0].iov_base = &len; 251 iov[0].iov_len = sizeof(int); 252 253 iov[1].iov_base = db->db_dir; 254 iov[1].iov_len = len; 255 256 if (write_vec(fd, iov, len + sizeof(int), 2) != len + sizeof(int)) { 257 LOG(log_error, logtype_cnid, "init_tsock: Error/short write: %s", strerror(errno)); 258 close(fd); 259 return -1; 260 } 261 262 LOG(log_debug, logtype_cnid, "init_tsock: ok"); 263 264 return fd; 265} 266 267/* --------------------- */ 268static int send_packet(CNID_private *db, struct cnid_dbd_rqst *rqst) 269{ 270 struct iovec iov[2]; 271 size_t towrite; 272 int vecs; 273 274 iov[0].iov_base = rqst; 275 iov[0].iov_len = sizeof(struct cnid_dbd_rqst); 276 towrite = sizeof(struct cnid_dbd_rqst); 277 vecs = 1; 278 279 if (rqst->namelen) { 280 iov[1].iov_base = rqst->name; 281 iov[1].iov_len = rqst->namelen; 282 towrite += rqst->namelen; 283 vecs++; 284 } 285 286 if (write_vec(db->fd, iov, towrite, vecs) != towrite) { 287 LOG(log_warning, logtype_cnid, "send_packet: Error writev rqst (db_dir %s): %s", 288 db->db_dir, strerror(errno)); 289 return -1; 290 } 291 292 LOG(log_maxdebug, logtype_cnid, "send_packet: {done}"); 293 return 0; 294} 295 296/* ------------------- */ 297static void dbd_initstamp(struct cnid_dbd_rqst *rqst) 298{ 299 RQST_RESET(rqst); 300 rqst->op = CNID_DBD_OP_GETSTAMP; 301} 302 303/* ------------------- */ 304static int dbd_reply_stamp(struct cnid_dbd_rply *rply) 305{ 306 switch (rply->result) { 307 case CNID_DBD_RES_OK: 308 break; 309 case CNID_DBD_RES_NOTFOUND: 310 return -1; 311 case CNID_DBD_RES_ERR_DB: 312 default: 313 errno = CNID_ERR_DB; 314 return -1; 315 } 316 return 0; 317} 318 319/* --------------------- 320 * send a request and get reply 321 * assume send is non blocking 322 * if no answer after sometime (at least MAX_DELAY secondes) return an error 323 */ 324static int dbd_rpc(CNID_private *db, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply) 325{ 326 ssize_t ret; 327 char *nametmp; 328 size_t len; 329 330 if (send_packet(db, rqst) < 0) { 331 return -1; 332 } 333 len = rply->namelen; 334 nametmp = rply->name; 335 336 ret = readt(db->fd, rply, sizeof(struct cnid_dbd_rply), 0, ONE_DELAY); 337 338 if (ret != sizeof(struct cnid_dbd_rply)) { 339 LOG(log_debug, logtype_cnid, "dbd_rpc: Error reading header from fd (db_dir %s): %s", 340 db->db_dir, ret == -1 ? strerror(errno) : "closed"); 341 rply->name = nametmp; 342 return -1; 343 } 344 rply->name = nametmp; 345 if (rply->namelen && rply->namelen > len) { 346 LOG(log_error, logtype_cnid, 347 "dbd_rpc: Error reading name (db_dir %s): %s name too long: %d. only wanted %d, garbage?", 348 db->db_dir, rply->name, rply->namelen, len); 349 return -1; 350 } 351 if (rply->namelen && (ret = readt(db->fd, rply->name, rply->namelen, 0, ONE_DELAY)) != (ssize_t)rply->namelen) { 352 LOG(log_error, logtype_cnid, "dbd_rpc: Error reading name from fd (db_dir %s): %s", 353 db->db_dir, ret == -1?strerror(errno):"closed"); 354 return -1; 355 } 356 357 LOG(log_maxdebug, logtype_cnid, "dbd_rpc: {done}"); 358 359 return 0; 360} 361 362/* -------------------- */ 363static int transmit(CNID_private *db, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply) 364{ 365 time_t orig, t; 366 int clean = 1; /* no errors so far - to prevent sleep on first try */ 367 368 if (db->changed) { 369 /* volume and db don't have the same timestamp 370 */ 371 return -1; 372 } 373 while (1) { 374 if (db->fd == -1) { 375 struct cnid_dbd_rqst rqst_stamp; 376 struct cnid_dbd_rply rply_stamp; 377 char stamp[ADEDLEN_PRIVSYN]; 378 379 LOG(log_maxdebug, logtype_cnid, "transmit: connecting to cnid_dbd ..."); 380 if ((db->fd = init_tsock(db)) < 0) { 381 goto transmit_fail; 382 } 383 dbd_initstamp(&rqst_stamp); 384 memset(stamp, 0, ADEDLEN_PRIVSYN); 385 rply_stamp.name = stamp; 386 rply_stamp.namelen = ADEDLEN_PRIVSYN; 387 388 if (dbd_rpc(db, &rqst_stamp, &rply_stamp) < 0) 389 goto transmit_fail; 390 if (dbd_reply_stamp(&rply_stamp ) < 0) 391 goto transmit_fail; 392 393 if (db->notfirst) { 394 LOG(log_debug7, logtype_cnid, "transmit: reconnected to cnid_dbd, comparing database stamps..."); 395 if (memcmp(stamp, db->stamp, ADEDLEN_PRIVSYN)) { 396 LOG(log_error, logtype_cnid, "transmit: ... not the same db!"); 397 db->changed = 1; 398 return -1; 399 } 400 LOG(log_debug7, logtype_cnid, "transmit: ... OK."); 401 } else { /* db->notfirst == 0 */ 402 db->notfirst = 1; 403 if (db->client_stamp) 404 memcpy(db->client_stamp, stamp, ADEDLEN_PRIVSYN); 405 memcpy(db->stamp, stamp, ADEDLEN_PRIVSYN); 406 } 407 LOG(log_debug, logtype_cnid, "transmit: attached to '%s', stamp: '%08lx'.", 408 db->db_dir, *(uint64_t *)stamp); 409 } 410 if (!dbd_rpc(db, rqst, rply)) { 411 LOG(log_maxdebug, logtype_cnid, "transmit: {done}"); 412 return 0; 413 } 414 transmit_fail: 415 if (db->fd != -1) { 416 close(db->fd); 417 db->fd = -1; /* FD not valid... will need to reconnect */ 418 } 419 420 if (errno == ECONNREFUSED) { /* errno carefully injected in tsock_getfd */ 421 /* give up */ 422 LOG(log_error, logtype_cnid, "transmit: connection refused (db_dir %s)", db->db_dir); 423 return -1; 424 } 425 426 if (!clean) { /* don't sleep if just got disconnected by cnid server */ 427 time(&t); 428 if (t - orig > MAX_DELAY) { 429 LOG(log_error, logtype_cnid, "transmit: Request to dbd daemon (db_dir %s) timed out.", db->db_dir); 430 return -1; 431 } 432 /* sleep a little before retry */ 433 delay(1); 434 } else { 435 clean = 0; /* false... next time sleep */ 436 time(&orig); 437 } 438 } 439 return -1; 440} 441 442/* ---------------------- */ 443static struct _cnid_db *cnid_dbd_new(const char *volpath) 444{ 445 struct _cnid_db *cdb; 446 447 if ((cdb = (struct _cnid_db *)calloc(1, sizeof(struct _cnid_db))) == NULL) 448 return NULL; 449 450 if ((cdb->volpath = strdup(volpath)) == NULL) { 451 free(cdb); 452 return NULL; 453 } 454 455 cdb->flags = CNID_FLAG_PERSISTENT | CNID_FLAG_LAZY_INIT; 456 457 cdb->cnid_add = cnid_dbd_add; 458 cdb->cnid_delete = cnid_dbd_delete; 459 cdb->cnid_get = cnid_dbd_get; 460 cdb->cnid_lookup = cnid_dbd_lookup; 461 cdb->cnid_find = cnid_dbd_find; 462 cdb->cnid_nextid = NULL; 463 cdb->cnid_resolve = cnid_dbd_resolve; 464 cdb->cnid_getstamp = cnid_dbd_getstamp; 465 cdb->cnid_update = cnid_dbd_update; 466 cdb->cnid_rebuild_add = cnid_dbd_rebuild_add; 467 cdb->cnid_close = cnid_dbd_close; 468 469 return cdb; 470} 471 472/* ---------------------- */ 473struct _cnid_db *cnid_dbd_open(struct cnid_open_args *args) 474{ 475 CNID_private *db = NULL; 476 struct _cnid_db *cdb = NULL; 477 478 if (!args->dir) { 479 return NULL; 480 } 481 482 if ((cdb = cnid_dbd_new(args->dir)) == NULL) { 483 LOG(log_error, logtype_cnid, "cnid_open: Unable to allocate memory for database"); 484 return NULL; 485 } 486 487 if ((db = (CNID_private *)calloc(1, sizeof(CNID_private))) == NULL) { 488 LOG(log_error, logtype_cnid, "cnid_open: Unable to allocate memory for database"); 489 goto cnid_dbd_open_fail; 490 } 491 492 cdb->_private = db; 493 494 /* We keep a copy of the directory in the db structure so that we can 495 transparently reconnect later. */ 496 strcpy(db->db_dir, args->dir); 497 db->magic = CNID_DB_MAGIC; 498 db->fd = -1; 499 db->cnidserver = strdup(args->cnidserver); 500 db->cnidport = strdup(args->cnidport); 501 502 LOG(log_debug, logtype_cnid, "cnid_dbd_open: Finished initializing cnid dbd module for volume '%s'", db->db_dir); 503 504 return cdb; 505 506cnid_dbd_open_fail: 507 if (cdb != NULL) { 508 if (cdb->volpath != NULL) { 509 free(cdb->volpath); 510 } 511 free(cdb); 512 } 513 if (db != NULL) 514 free(db); 515 516 return NULL; 517} 518 519/* ---------------------- */ 520void cnid_dbd_close(struct _cnid_db *cdb) 521{ 522 CNID_private *db; 523 524 if (!cdb) { 525 LOG(log_error, logtype_cnid, "cnid_close called with NULL argument !"); 526 return; 527 } 528 529 if ((db = cdb->_private) != NULL) { 530 LOG(log_debug, logtype_cnid, "closing database connection for volume '%s'", db->db_dir); 531 532 if (db->fd >= 0) 533 close(db->fd); 534 free(db); 535 } 536 537 free(cdb->volpath); 538 free(cdb); 539 540 return; 541} 542 543/* ---------------------- */ 544cnid_t cnid_dbd_add(struct _cnid_db *cdb, const struct stat *st, 545 const cnid_t did, char *name, const size_t len, 546 cnid_t hint) 547{ 548 CNID_private *db; 549 struct cnid_dbd_rqst rqst; 550 struct cnid_dbd_rply rply; 551 cnid_t id; 552 553 if (!cdb || !(db = cdb->_private) || !st || !name) { 554 LOG(log_error, logtype_cnid, "cnid_add: Parameter error"); 555 errno = CNID_ERR_PARAM; 556 return CNID_INVALID; 557 } 558 559 if (len > MAXPATHLEN) { 560 LOG(log_error, logtype_cnid, "cnid_add: Path name is too long"); 561 errno = CNID_ERR_PATH; 562 return CNID_INVALID; 563 } 564 565 RQST_RESET(&rqst); 566 rqst.op = CNID_DBD_OP_ADD; 567 568 if (!(cdb->flags & CNID_FLAG_NODEV)) { 569 rqst.dev = st->st_dev; 570 } 571 572 rqst.ino = st->st_ino; 573 rqst.type = S_ISDIR(st->st_mode)?1:0; 574 rqst.cnid = hint; 575 rqst.did = did; 576 rqst.name = name; 577 rqst.namelen = len; 578 579 LOG(log_debug, logtype_cnid, "cnid_dbd_add: CNID: %u, name: '%s', inode: 0x%llx, type: %d (0=file, 1=dir)", 580 ntohl(did), name, (long long)st->st_ino, rqst.type); 581 582 rply.namelen = 0; 583 if (transmit(db, &rqst, &rply) < 0) { 584 errno = CNID_ERR_DB; 585 return CNID_INVALID; 586 } 587 588 switch(rply.result) { 589 case CNID_DBD_RES_OK: 590 id = rply.cnid; 591 LOG(log_debug, logtype_cnid, "cnid_dbd_add: got CNID: %u", ntohl(id)); 592 break; 593 case CNID_DBD_RES_ERR_MAX: 594 errno = CNID_ERR_MAX; 595 id = CNID_INVALID; 596 break; 597 case CNID_DBD_RES_ERR_DB: 598 case CNID_DBD_RES_ERR_DUPLCNID: 599 errno = CNID_ERR_DB; 600 id = CNID_INVALID; 601 break; 602 default: 603 abort(); 604 } 605 606 return id; 607} 608 609/* ---------------------- */ 610cnid_t cnid_dbd_get(struct _cnid_db *cdb, const cnid_t did, char *name, const size_t len) 611{ 612 CNID_private *db; 613 struct cnid_dbd_rqst rqst; 614 struct cnid_dbd_rply rply; 615 cnid_t id; 616 617 if (!cdb || !(db = cdb->_private) || !name) { 618 LOG(log_error, logtype_cnid, "cnid_dbd_get: Parameter error"); 619 errno = CNID_ERR_PARAM; 620 return CNID_INVALID; 621 } 622 623 if (len > MAXPATHLEN) { 624 LOG(log_error, logtype_cnid, "cnid_dbd_get: Path name is too long"); 625 errno = CNID_ERR_PATH; 626 return CNID_INVALID; 627 } 628 629 LOG(log_debug, logtype_cnid, "cnid_dbd_get: DID: %u, name: '%s'", ntohl(did), name); 630 631 RQST_RESET(&rqst); 632 rqst.op = CNID_DBD_OP_GET; 633 rqst.did = did; 634 rqst.name = name; 635 rqst.namelen = len; 636 637 rply.namelen = 0; 638 if (transmit(db, &rqst, &rply) < 0) { 639 errno = CNID_ERR_DB; 640 return CNID_INVALID; 641 } 642 643 switch(rply.result) { 644 case CNID_DBD_RES_OK: 645 id = rply.cnid; 646 LOG(log_debug, logtype_cnid, "cnid_dbd_get: got CNID: %u", ntohl(id)); 647 break; 648 case CNID_DBD_RES_NOTFOUND: 649 id = CNID_INVALID; 650 break; 651 case CNID_DBD_RES_ERR_DB: 652 id = CNID_INVALID; 653 errno = CNID_ERR_DB; 654 break; 655 default: 656 abort(); 657 } 658 659 return id; 660} 661 662/* ---------------------- */ 663char *cnid_dbd_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, size_t len) 664{ 665 CNID_private *db; 666 struct cnid_dbd_rqst rqst; 667 struct cnid_dbd_rply rply; 668 char *name; 669 670 if (!cdb || !(db = cdb->_private) || !id || !(*id)) { 671 LOG(log_error, logtype_cnid, "cnid_resolve: Parameter error"); 672 errno = CNID_ERR_PARAM; 673 return NULL; 674 } 675 676 LOG(log_debug, logtype_cnid, "cnid_dbd_resolve: resolving CNID: %u", ntohl(*id)); 677 678 /* TODO: We should maybe also check len. At the moment we rely on the caller 679 to provide a buffer that is large enough for MAXPATHLEN plus 680 CNID_HEADER_LEN plus 1 byte, which is large enough for the maximum that 681 can come from the database. */ 682 683 RQST_RESET(&rqst); 684 rqst.op = CNID_DBD_OP_RESOLVE; 685 rqst.cnid = *id; 686 687 /* Pass buffer to transmit so it can stuff the reply data there */ 688 rply.name = (char *)buffer; 689 rply.namelen = len; 690 691 if (transmit(db, &rqst, &rply) < 0) { 692 errno = CNID_ERR_DB; 693 *id = CNID_INVALID; 694 return NULL; 695 } 696 697 switch (rply.result) { 698 case CNID_DBD_RES_OK: 699 *id = rply.did; 700 name = rply.name + CNID_NAME_OFS; 701 LOG(log_debug, logtype_cnid, "cnid_dbd_resolve: resolved did: %u, name: '%s'", ntohl(*id), name); 702 break; 703 case CNID_DBD_RES_NOTFOUND: 704 *id = CNID_INVALID; 705 name = NULL; 706 break; 707 case CNID_DBD_RES_ERR_DB: 708 errno = CNID_ERR_DB; 709 *id = CNID_INVALID; 710 name = NULL; 711 break; 712 default: 713 abort(); 714 } 715 716 return name; 717} 718 719/* ---------------------- */ 720int cnid_dbd_getstamp(struct _cnid_db *cdb, void *buffer, const size_t len) 721{ 722 CNID_private *db; 723 724 if (!cdb || !(db = cdb->_private) || len != ADEDLEN_PRIVSYN) { 725 LOG(log_error, logtype_cnid, "cnid_getstamp: Parameter error"); 726 errno = CNID_ERR_PARAM; 727 return -1; 728 } 729 db->client_stamp = buffer; 730 db->stamp_size = len; 731 memset(buffer,0, len); 732 return 0; 733} 734 735/* ---------------------- */ 736cnid_t cnid_dbd_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did, 737 char *name, const size_t len) 738{ 739 CNID_private *db; 740 struct cnid_dbd_rqst rqst; 741 struct cnid_dbd_rply rply; 742 cnid_t id; 743 744 if (!cdb || !(db = cdb->_private) || !st || !name) { 745 LOG(log_error, logtype_cnid, "cnid_lookup: Parameter error"); 746 errno = CNID_ERR_PARAM; 747 return CNID_INVALID; 748 } 749 750 if (len > MAXPATHLEN) { 751 LOG(log_error, logtype_cnid, "cnid_lookup: Path name is too long"); 752 errno = CNID_ERR_PATH; 753 return CNID_INVALID; 754 } 755 756 RQST_RESET(&rqst); 757 rqst.op = CNID_DBD_OP_LOOKUP; 758 759 if (!(cdb->flags & CNID_FLAG_NODEV)) { 760 rqst.dev = st->st_dev; 761 } 762 763 rqst.ino = st->st_ino; 764 rqst.type = S_ISDIR(st->st_mode)?1:0; 765 rqst.did = did; 766 rqst.name = name; 767 rqst.namelen = len; 768 769 LOG(log_debug, logtype_cnid, "cnid_dbd_lookup: CNID: %u, name: '%s', inode: 0x%llx, type: %d (0=file, 1=dir)", 770 ntohl(did), name, (long long)st->st_ino, rqst.type); 771 772 rply.namelen = 0; 773 if (transmit(db, &rqst, &rply) < 0) { 774 errno = CNID_ERR_DB; 775 return CNID_INVALID; 776 } 777 778 switch (rply.result) { 779 case CNID_DBD_RES_OK: 780 id = rply.cnid; 781 LOG(log_debug, logtype_cnid, "cnid_dbd_lookup: got CNID: %u", ntohl(id)); 782 break; 783 case CNID_DBD_RES_NOTFOUND: 784 id = CNID_INVALID; 785 break; 786 case CNID_DBD_RES_ERR_DB: 787 errno = CNID_ERR_DB; 788 id = CNID_INVALID; 789 break; 790 default: 791 abort(); 792 } 793 794 return id; 795} 796 797/* ---------------------- */ 798int cnid_dbd_find(struct _cnid_db *cdb, char *name, size_t namelen, void *buffer, size_t buflen) 799{ 800 CNID_private *db; 801 struct cnid_dbd_rqst rqst; 802 struct cnid_dbd_rply rply; 803 int count; 804 805 if (!cdb || !(db = cdb->_private) || !name) { 806 LOG(log_error, logtype_cnid, "cnid_find: Parameter error"); 807 errno = CNID_ERR_PARAM; 808 return CNID_INVALID; 809 } 810 811 if (namelen > MAXPATHLEN) { 812 LOG(log_error, logtype_cnid, "cnid_find: Path name is too long"); 813 errno = CNID_ERR_PATH; 814 return CNID_INVALID; 815 } 816 817 LOG(log_debug, logtype_cnid, "cnid_find(\"%s\")", name); 818 819 RQST_RESET(&rqst); 820 rqst.op = CNID_DBD_OP_SEARCH; 821 822 rqst.name = name; 823 rqst.namelen = namelen; 824 825 rply.name = buffer; 826 rply.namelen = buflen; 827 828 if (transmit(db, &rqst, &rply) < 0) { 829 errno = CNID_ERR_DB; 830 return CNID_INVALID; 831 } 832 833 switch (rply.result) { 834 case CNID_DBD_RES_OK: 835 count = rply.namelen / sizeof(cnid_t); 836 LOG(log_debug, logtype_cnid, "cnid_find: got %d matches", count); 837 break; 838 case CNID_DBD_RES_NOTFOUND: 839 count = 0; 840 break; 841 case CNID_DBD_RES_ERR_DB: 842 errno = CNID_ERR_DB; 843 count = -1; 844 break; 845 default: 846 abort(); 847 } 848 849 return count; 850} 851 852/* ---------------------- */ 853int cnid_dbd_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st, 854 const cnid_t did, char *name, const size_t len) 855{ 856 CNID_private *db; 857 struct cnid_dbd_rqst rqst; 858 struct cnid_dbd_rply rply; 859 860 if (!cdb || !(db = cdb->_private) || !id || !st || !name) { 861 LOG(log_error, logtype_cnid, "cnid_update: Parameter error"); 862 errno = CNID_ERR_PARAM; 863 return -1; 864 } 865 866 if (len > MAXPATHLEN) { 867 LOG(log_error, logtype_cnid, "cnid_update: Path name is too long"); 868 errno = CNID_ERR_PATH; 869 return -1; 870 } 871 872 RQST_RESET(&rqst); 873 rqst.op = CNID_DBD_OP_UPDATE; 874 rqst.cnid = id; 875 if (!(cdb->flags & CNID_FLAG_NODEV)) { 876 rqst.dev = st->st_dev; 877 } 878 rqst.ino = st->st_ino; 879 rqst.type = S_ISDIR(st->st_mode)?1:0; 880 rqst.did = did; 881 rqst.name = name; 882 rqst.namelen = len; 883 884 LOG(log_debug, logtype_cnid, "cnid_dbd_update: CNID: %u, name: '%s', inode: 0x%llx, type: %d (0=file, 1=dir)", 885 ntohl(id), name, (long long)st->st_ino, rqst.type); 886 887 rply.namelen = 0; 888 if (transmit(db, &rqst, &rply) < 0) { 889 errno = CNID_ERR_DB; 890 return -1; 891 } 892 893 switch (rply.result) { 894 case CNID_DBD_RES_OK: 895 LOG(log_debug, logtype_cnid, "cnid_dbd_update: updated"); 896 case CNID_DBD_RES_NOTFOUND: 897 return 0; 898 case CNID_DBD_RES_ERR_DB: 899 errno = CNID_ERR_DB; 900 return -1; 901 default: 902 abort(); 903 } 904} 905 906/* ---------------------- */ 907cnid_t cnid_dbd_rebuild_add(struct _cnid_db *cdb, const struct stat *st, 908 const cnid_t did, char *name, const size_t len, 909 cnid_t hint) 910{ 911 CNID_private *db; 912 struct cnid_dbd_rqst rqst; 913 struct cnid_dbd_rply rply; 914 cnid_t id; 915 916 if (!cdb || !(db = cdb->_private) || !st || !name || hint == CNID_INVALID) { 917 LOG(log_error, logtype_cnid, "cnid_rebuild_add: Parameter error"); 918 errno = CNID_ERR_PARAM; 919 return CNID_INVALID; 920 } 921 922 if (len > MAXPATHLEN) { 923 LOG(log_error, logtype_cnid, "cnid_rebuild_add: Path name is too long"); 924 errno = CNID_ERR_PATH; 925 return CNID_INVALID; 926 } 927 928 RQST_RESET(&rqst); 929 rqst.op = CNID_DBD_OP_REBUILD_ADD; 930 931 if (!(cdb->flags & CNID_FLAG_NODEV)) { 932 rqst.dev = st->st_dev; 933 } 934 935 rqst.ino = st->st_ino; 936 rqst.type = S_ISDIR(st->st_mode)?1:0; 937 rqst.did = did; 938 rqst.name = name; 939 rqst.namelen = len; 940 rqst.cnid = hint; 941 942 LOG(log_debug, logtype_cnid, "cnid_dbd_rebuild_add: CNID: %u, name: '%s', inode: 0x%llx, type: %d (0=file, 1=dir), hint: %u", 943 ntohl(did), name, (long long)st->st_ino, rqst.type, hint); 944 945 if (transmit(db, &rqst, &rply) < 0) { 946 errno = CNID_ERR_DB; 947 return CNID_INVALID; 948 } 949 950 switch(rply.result) { 951 case CNID_DBD_RES_OK: 952 id = rply.cnid; 953 LOG(log_debug, logtype_cnid, "cnid_dbd_rebuild_add: got CNID: %u", ntohl(id)); 954 break; 955 case CNID_DBD_RES_ERR_MAX: 956 errno = CNID_ERR_MAX; 957 id = CNID_INVALID; 958 break; 959 case CNID_DBD_RES_ERR_DB: 960 case CNID_DBD_RES_ERR_DUPLCNID: 961 errno = CNID_ERR_DB; 962 id = CNID_INVALID; 963 break; 964 default: 965 abort(); 966 } 967 return id; 968} 969 970/* ---------------------- */ 971int cnid_dbd_delete(struct _cnid_db *cdb, const cnid_t id) 972{ 973 CNID_private *db; 974 struct cnid_dbd_rqst rqst; 975 struct cnid_dbd_rply rply; 976 977 if (!cdb || !(db = cdb->_private) || !id) { 978 LOG(log_error, logtype_cnid, "cnid_delete: Parameter error"); 979 errno = CNID_ERR_PARAM; 980 return -1; 981 } 982 983 LOG(log_debug, logtype_cnid, "cnid_dbd_delete: delete CNID: %u", ntohl(id)); 984 985 RQST_RESET(&rqst); 986 rqst.op = CNID_DBD_OP_DELETE; 987 rqst.cnid = id; 988 989 rply.namelen = 0; 990 if (transmit(db, &rqst, &rply) < 0) { 991 errno = CNID_ERR_DB; 992 return -1; 993 } 994 995 switch (rply.result) { 996 case CNID_DBD_RES_OK: 997 LOG(log_debug, logtype_cnid, "cnid_dbd_delete: deleted CNID: %u", ntohl(id)); 998 case CNID_DBD_RES_NOTFOUND: 999 return 0; 1000 case CNID_DBD_RES_ERR_DB: 1001 errno = CNID_ERR_DB; 1002 return -1; 1003 default: 1004 abort(); 1005 } 1006} 1007 1008 1009struct _cnid_module cnid_dbd_module = { 1010 "dbd", 1011 {NULL, NULL}, 1012 cnid_dbd_open, 1013 0 1014}; 1015 1016#endif /* CNID_DBD */ 1017 1018