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