1/* 2 Copyright (c) 2009 Frank Lahm <franklahm@gmail.com> 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 2 of the License, or 7 (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13*/ 14 15#ifdef HAVE_CONFIG_H 16#include "config.h" 17#endif /* HAVE_CONFIG_H */ 18 19#include <unistd.h> 20#include <stdlib.h> 21#include <sys/types.h> 22#include <sys/stat.h> 23#include <dirent.h> 24#include <fcntl.h> 25#include <string.h> 26#include <errno.h> 27#include <setjmp.h> 28 29#include <atalk/adouble.h> 30#include <atalk/unicode.h> 31#include <atalk/volinfo.h> 32#include <atalk/cnid_dbd_private.h> 33#include <atalk/volume.h> 34#include <atalk/ea.h> 35#include <atalk/util.h> 36#include <atalk/acl.h> 37 38#include "cmd_dbd.h" 39#include "dbif.h" 40#include "db_param.h" 41#include "dbd.h" 42 43/* Some defines to ease code parsing */ 44#define ADDIR_OK (addir_ok == 0) 45#define ADFILE_OK (adfile_ok == 0) 46 47 48static struct volinfo *myvolinfo; 49static char cwdbuf[MAXPATHLEN+1]; 50static DBD *dbd; 51static DBD *dbd_rebuild; 52static dbd_flags_t dbd_flags; 53static char stamp[CNID_DEV_LEN]; 54static char *netatalk_dirs[] = { 55 ".AppleDB", 56 ".AppleDesktop", 57 NULL 58}; 59static char *special_dirs[] = { 60 ".zfs", 61 NULL 62}; 63static struct cnid_dbd_rqst rqst; 64static struct cnid_dbd_rply rply; 65static jmp_buf jmp; 66static struct vol volume; /* fake it for ea_open */ 67static char pname[MAXPATHLEN] = "../"; 68 69/* 70 Taken form afpd/desktop.c 71*/ 72static char *utompath(char *upath) 73{ 74 static char mpath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */ 75 char *m, *u; 76 uint16_t flags = CONV_IGNORE | CONV_UNESCAPEHEX; 77 size_t outlen; 78 79 if (!upath) 80 return NULL; 81 82 m = mpath; 83 u = upath; 84 outlen = strlen(upath); 85 86 if ((myvolinfo->v_casefold & AFPVOL_UTOMUPPER)) 87 flags |= CONV_TOUPPER; 88 else if ((myvolinfo->v_casefold & AFPVOL_UTOMLOWER)) 89 flags |= CONV_TOLOWER; 90 91 if ((myvolinfo->v_flags & AFPVOL_EILSEQ)) { 92 flags |= CONV__EILSEQ; 93 } 94 95 /* convert charsets */ 96 if ((size_t)-1 == ( outlen = convert_charset(myvolinfo->v_volcharset, 97 CH_UTF8_MAC, 98 myvolinfo->v_maccharset, 99 u, outlen, mpath, MAXPATHLEN, &flags)) ) { 100 dbd_log( LOGSTD, "Conversion from %s to %s for %s failed.", 101 myvolinfo->v_volcodepage, myvolinfo->v_maccodepage, u); 102 return NULL; 103 } 104 105 return(m); 106} 107 108/* 109 Taken form afpd/desktop.c 110*/ 111static char *mtoupath(char *mpath) 112{ 113 static char upath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */ 114 char *m, *u; 115 size_t inplen; 116 size_t outlen; 117 u_int16_t flags = 0; 118 119 if (!mpath) 120 return NULL; 121 122 if ( *mpath == '\0' ) { 123 return( "." ); 124 } 125 126 /* set conversion flags */ 127 if (!(myvolinfo->v_flags & AFPVOL_NOHEX)) 128 flags |= CONV_ESCAPEHEX; 129 if (!(myvolinfo->v_flags & AFPVOL_USEDOTS)) 130 flags |= CONV_ESCAPEDOTS; 131 132 if ((myvolinfo->v_casefold & AFPVOL_MTOUUPPER)) 133 flags |= CONV_TOUPPER; 134 else if ((myvolinfo->v_casefold & AFPVOL_MTOULOWER)) 135 flags |= CONV_TOLOWER; 136 137 if ((myvolinfo->v_flags & AFPVOL_EILSEQ)) { 138 flags |= CONV__EILSEQ; 139 } 140 141 m = mpath; 142 u = upath; 143 144 inplen = strlen(m); 145 outlen = MAXPATHLEN; 146 147 if ((size_t)-1 == (outlen = convert_charset(CH_UTF8_MAC, 148 myvolinfo->v_volcharset, 149 myvolinfo->v_maccharset, 150 m, inplen, u, outlen, &flags)) ) { 151 dbd_log( LOGSTD, "conversion from UTF8-MAC to %s for %s failed.", 152 myvolinfo->v_volcodepage, mpath); 153 return NULL; 154 } 155 156 return( upath ); 157} 158 159#if 0 160/* 161 Check if "name" is pointing to 162 a) an object inside the current volume (return 0) 163 b) an object outside the current volume (return 1) 164 Then stats the pointed to object and if it is a dir ors ADFLAGS_DIR to *adflags 165 Return -1 on any serious error. 166 */ 167static int check_symlink(const char *name, int *adflags) 168{ 169 int cwd; 170 ssize_t len; 171 char pathbuf[MAXPATHLEN + 1]; 172 char *sep; 173 struct stat st; 174 175 if ((len = readlink(name, pathbuf, MAXPATHLEN)) == -1) { 176 dbd_log(LOGSTD, "Error reading link info for '%s/%s': %s", 177 cwdbuf, name, strerror(errno)); 178 return -1; 179 } 180 pathbuf[len] = 0; 181 182 if ((stat(pathbuf, &st)) != 0) { 183 dbd_log(LOGSTD, "stat error '%s': %s", pathbuf, strerror(errno)); 184 } 185 186 /* Remember cwd */ 187 if ((cwd = open(".", O_RDONLY)) < 0) { 188 dbd_log(LOGSTD, "error opening cwd '%s': %s", cwdbuf, strerror(errno)); 189 return -1; 190 } 191 192 if (S_ISDIR(st.st_mode)) { 193 *adflags |= ADFLAGS_DIR; 194 } else { /* file */ 195 /* get basename from path */ 196 if ((sep = strrchr(pathbuf, '/')) == NULL) 197 /* just a file at the same level */ 198 return 0; 199 sep = 0; /* pathbuf now contains the directory*/ 200 } 201 202 /* fchdir() to pathbuf so we can easily get its path with getcwd() */ 203 if ((chdir(pathbuf)) != 0) { 204 dbd_log(LOGSTD, "Cant chdir to '%s': %s", pathbuf, strerror(errno)); 205 return -1; 206 } 207 208 if ((getcwd(pathbuf, MAXPATHLEN)) == NULL) { 209 dbd_log(LOGSTD, "Cant get symlink'ed dir '%s/%s': %s", cwdbuf, pathbuf, strerror(errno)); 210 if ((fchdir(cwd)) != 0) 211 /* We're foobared */ 212 longjmp(jmp, 1); /* this jumps back to cmd_dbd_scanvol() */ 213 return -1; 214 } 215 216 if ((fchdir(cwd)) != 0) 217 /* We're foobared */ 218 longjmp(jmp, 1); /* this jumps back to cmd_dbd_scanvol() */ 219 220 /* 221 We now have the symlink target dir as absoulte path in pathbuf 222 and can compare it with the currents volume path 223 */ 224 int i = 0; 225 while (myvolinfo->v_path[i]) { 226 if ((pathbuf[i] == 0) || (myvolinfo->v_path[i] != pathbuf[i])) { 227 dbd_log( LOGDEBUG, "extra-share symlink '%s/%s', following", cwdbuf, name); 228 return 1; 229 } 230 i++; 231 } 232 233 dbd_log( LOGDEBUG, "intra-share symlink '%s/%s', not following", cwdbuf, name); 234 return 0; 235} 236#endif 237 238/* 239 Check for wrong encoding e.g. "." at the beginning is not CAP encoded (:2e) although volume is default !AFPVOL_USEDOTS. 240 We do it by roundtripiping from volcharset to UTF8-MAC and back and then compare the result. 241*/ 242static int check_name_encoding(char *uname) 243{ 244 char *roundtripped; 245 246 roundtripped = mtoupath(utompath(uname)); 247 if (!roundtripped) { 248 dbd_log( LOGSTD, "Error checking encoding for '%s/%s'", cwdbuf, uname); 249 return -1; 250 } 251 252 if ( STRCMP(uname, !=, roundtripped)) { 253 dbd_log( LOGSTD, "Bad encoding for '%s/%s'", cwdbuf, uname); 254 return -1; 255 } 256 257 return 0; 258} 259 260/* 261 Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" 262 Returns pointer to name or NULL. 263*/ 264static const char *check_netatalk_dirs(const char *name) 265{ 266 int c; 267 268 for (c=0; netatalk_dirs[c]; c++) { 269 if ((strcmp(name, netatalk_dirs[c])) == 0) 270 return netatalk_dirs[c]; 271 } 272 return NULL; 273} 274 275/* 276 Check for special names 277 Returns pointer to name or NULL. 278*/ 279static const char *check_special_dirs(const char *name) 280{ 281 int c; 282 283 for (c=0; special_dirs[c]; c++) { 284 if ((strcmp(name, special_dirs[c])) == 0) 285 return special_dirs[c]; 286 } 287 return NULL; 288} 289 290/* 291 Check for .AppleDouble file, create if missing 292*/ 293static int check_adfile(const char *fname, const struct stat *st) 294{ 295 int ret, adflags; 296 struct adouble ad; 297 char *adname; 298 299 if (dbd_flags & DBD_FLAGS_CLEANUP) 300 return 0; 301 302 if (S_ISREG(st->st_mode)) 303 adflags = 0; 304 else 305 adflags = ADFLAGS_DIR; 306 307 adname = myvolinfo->ad_path(fname, adflags); 308 309 if ((ret = access( adname, F_OK)) != 0) { 310 if (errno != ENOENT) { 311 dbd_log(LOGSTD, "Access error for ad-file '%s/%s': %s", 312 cwdbuf, adname, strerror(errno)); 313 return -1; 314 } 315 /* Missing. Log and create it */ 316 dbd_log(LOGSTD, "Missing AppleDouble file '%s/%s'", cwdbuf, adname); 317 318 if (dbd_flags & DBD_FLAGS_SCAN) 319 /* Scan only requested, dont change anything */ 320 return -1; 321 322 /* Create ad file */ 323 ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options); 324 325 if ((ret = ad_open_metadata( fname, adflags, O_CREAT, &ad)) != 0) { 326 dbd_log( LOGSTD, "Error creating AppleDouble file '%s/%s': %s", 327 cwdbuf, adname, strerror(errno)); 328 329 return -1; 330 } 331 332 /* Set name in ad-file */ 333 ad_setname(&ad, utompath((char *)fname)); 334 ad_flush(&ad); 335 ad_close_metadata(&ad); 336 337 chown(adname, st->st_uid, st->st_gid); 338 /* FIXME: should we inherit mode too here ? */ 339#if 0 340 chmod(adname, st->st_mode); 341#endif 342 } else { 343 ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options); 344 if (ad_open_metadata( fname, adflags, O_RDONLY, &ad) != 0) { 345 dbd_log( LOGSTD, "Error opening AppleDouble file for '%s/%s'", cwdbuf, fname); 346 return -1; 347 } 348 ad_close_metadata(&ad); 349 } 350 return 0; 351} 352 353/* 354 Remove all files with file::EA* from adouble dir 355*/ 356static void remove_eafiles(const char *name, struct ea *ea) 357{ 358 DIR *dp = NULL; 359 struct dirent *ep; 360 char eaname[MAXPATHLEN]; 361 362 strlcpy(eaname, name, sizeof(eaname)); 363 if (strlcat(eaname, "::EA", sizeof(eaname)) >= sizeof(eaname)) { 364 dbd_log(LOGSTD, "name too long: '%s/%s/%s'", cwdbuf, ADv2_DIRNAME, name); 365 return; 366 } 367 368 if ((chdir(ADv2_DIRNAME)) != 0) { 369 dbd_log(LOGSTD, "Couldn't chdir to '%s/%s': %s", 370 cwdbuf, ADv2_DIRNAME, strerror(errno)); 371 return; 372 } 373 374 if ((dp = opendir(".")) == NULL) { 375 dbd_log(LOGSTD, "Couldn't open the directory '%s/%s': %s", 376 cwdbuf, ADv2_DIRNAME, strerror(errno)); 377 goto exit; 378 } 379 380 while ((ep = readdir(dp))) { 381 if (strstr(ep->d_name, eaname) != NULL) { 382 dbd_log(LOGSTD, "Removing EA file: '%s/%s/%s'", 383 cwdbuf, ADv2_DIRNAME, ep->d_name); 384 if ((unlink(ep->d_name)) != 0) { 385 dbd_log(LOGSTD, "Error unlinking EA file '%s/%s/%s': %s", 386 cwdbuf, ADv2_DIRNAME, ep->d_name, strerror(errno)); 387 } 388 } /* if */ 389 } /* while */ 390 391exit: 392 if (dp) 393 closedir(dp); 394 if ((chdir("..")) != 0) { 395 dbd_log(LOGSTD, "Couldn't chdir to '%s': %s", cwdbuf, strerror(errno)); 396 /* we can't proceed */ 397 longjmp(jmp, 1); /* this jumps back to cmd_dbd_scanvol() */ 398 } 399} 400 401/* 402 Check Extended Attributes files 403*/ 404static int check_eafiles(const char *fname) 405{ 406 unsigned int count = 0; 407 int ret = 0, remove; 408 struct ea ea; 409 struct stat st; 410 char *eaname; 411 412 if ((ret = ea_open(&volume, fname, EA_RDWR, &ea)) != 0) { 413 if (errno == ENOENT) 414 return 0; 415 dbd_log(LOGSTD, "Error calling ea_open for file: %s/%s, removing EA files", cwdbuf, fname); 416 if ( ! (dbd_flags & DBD_FLAGS_SCAN)) 417 remove_eafiles(fname, &ea); 418 return -1; 419 } 420 421 /* Check all EAs */ 422 while (count < ea.ea_count) { 423 dbd_log(LOGDEBUG, "EA: %s", (*ea.ea_entries)[count].ea_name); 424 remove = 0; 425 426 eaname = ea_path(&ea, (*ea.ea_entries)[count].ea_name, 0); 427 428 if (lstat(eaname, &st) != 0) { 429 if (errno == ENOENT) 430 dbd_log(LOGSTD, "Missing EA: %s/%s", cwdbuf, eaname); 431 else 432 dbd_log(LOGSTD, "Bogus EA: %s/%s", cwdbuf, eaname); 433 remove = 1; 434 } else if (st.st_size != (*ea.ea_entries)[count].ea_size) { 435 dbd_log(LOGSTD, "Bogus EA: %s/%s, removing it...", cwdbuf, eaname); 436 remove = 1; 437 if ((unlink(eaname)) != 0) 438 dbd_log(LOGSTD, "Error removing EA file '%s/%s': %s", 439 cwdbuf, eaname, strerror(errno)); 440 } 441 442 if (remove) { 443 /* Be CAREFUL here! This should do what ea_delentry does. ea_close relies on it !*/ 444 free((*ea.ea_entries)[count].ea_name); 445 (*ea.ea_entries)[count].ea_name = NULL; 446 } 447 448 count++; 449 } /* while */ 450 451 ea_close(&ea); 452 return ret; 453} 454 455/* 456 Check for .AppleDouble folder and .Parent, create if missing 457*/ 458static int check_addir(int volroot) 459{ 460 int addir_ok, adpar_ok; 461 struct stat st; 462 struct adouble ad; 463 char *mname = NULL; 464 465 if (dbd_flags & DBD_FLAGS_CLEANUP) 466 return 0; 467 468 /* Check for ad-dir */ 469 if ( (addir_ok = access(ADv2_DIRNAME, F_OK)) != 0) { 470 if (errno != ENOENT) { 471 dbd_log(LOGSTD, "Access error in directory %s: %s", cwdbuf, strerror(errno)); 472 return -1; 473 } 474 dbd_log(LOGSTD, "Missing %s for '%s'", ADv2_DIRNAME, cwdbuf); 475 } 476 477 /* Check for ".Parent" */ 478 if ( (adpar_ok = access(myvolinfo->ad_path(".", ADFLAGS_DIR), F_OK)) != 0) { 479 if (errno != ENOENT) { 480 dbd_log(LOGSTD, "Access error on '%s/%s': %s", 481 cwdbuf, myvolinfo->ad_path(".", ADFLAGS_DIR), strerror(errno)); 482 return -1; 483 } 484 dbd_log(LOGSTD, "Missing .AppleDouble/.Parent for '%s'", cwdbuf); 485 } 486 487 /* Is one missing ? */ 488 if ((addir_ok != 0) || (adpar_ok != 0)) { 489 /* Yes, but are we only scanning ? */ 490 if (dbd_flags & DBD_FLAGS_SCAN) { 491 /* Yes: missing .Parent is not a problem, but missing ad-dir 492 causes later checking of ad-files to fail. So we have to return appropiately */ 493 if (addir_ok != 0) 494 return -1; 495 else /* (adpar_ok != 0) */ 496 return 0; 497 } 498 499 /* Create ad dir and set name */ 500 ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options); 501 502 if (ad_open_metadata( ".", ADFLAGS_DIR, O_CREAT, &ad) != 0) { 503 dbd_log( LOGSTD, "Error creating AppleDouble dir in %s: %s", cwdbuf, strerror(errno)); 504 return -1; 505 } 506 507 /* Get basename of cwd from cwdbuf */ 508 mname = utompath(strrchr(cwdbuf, '/') + 1); 509 510 /* Update name in ad file */ 511 ad_setname(&ad, mname); 512 ad_flush(&ad); 513 ad_close_metadata(&ad); 514 515 /* Inherit owner/group from "." to ".AppleDouble" and ".Parent" */ 516 if ((lstat(".", &st)) != 0) { 517 dbd_log( LOGSTD, "Couldnt stat %s: %s", cwdbuf, strerror(errno)); 518 return -1; 519 } 520 chown(ADv2_DIRNAME, st.st_uid, st.st_gid); 521 chown(myvolinfo->ad_path(".", ADFLAGS_DIR), st.st_uid, st.st_gid); 522 } 523 524 return 0; 525} 526 527/* 528 Check if file cotains "::EA" and if it does check if its correspondig data fork exists. 529 Returns: 530 0 = name is not an EA file 531 1 = name is an EA file and no problem was found 532 -1 = name is an EA file and data fork is gone 533 */ 534static int check_eafile_in_adouble(const char *name) 535{ 536 int ret = 0; 537 char *namep, *namedup = NULL; 538 539 /* Check if this is an AFPVOL_EA_AD vol */ 540 if (myvolinfo->v_vfs_ea == AFPVOL_EA_AD) { 541 /* Does the filename contain "::EA" ? */ 542 namedup = strdup(name); 543 if ((namep = strstr(namedup, "::EA")) == NULL) { 544 ret = 0; 545 goto ea_check_done; 546 } else { 547 /* File contains "::EA" so it's an EA file. Check for data file */ 548 549 /* Get string before "::EA" from EA filename */ 550 namep[0] = 0; 551 strlcpy(pname + 3, namedup, sizeof(pname)); /* Prepends "../" */ 552 553 if ((access( pname, F_OK)) == 0) { 554 ret = 1; 555 goto ea_check_done; 556 } else { 557 ret = -1; 558 if (errno != ENOENT) { 559 dbd_log(LOGSTD, "Access error for file '%s/%s': %s", 560 cwdbuf, name, strerror(errno)); 561 goto ea_check_done; 562 } 563 564 /* Orphaned EA file*/ 565 dbd_log(LOGSTD, "Orphaned Extended Attribute file '%s/%s/%s'", 566 cwdbuf, ADv2_DIRNAME, name); 567 568 if (dbd_flags & DBD_FLAGS_SCAN) 569 /* Scan only requested, dont change anything */ 570 goto ea_check_done; 571 572 if ((unlink(name)) != 0) { 573 dbd_log(LOGSTD, "Error unlinking orphaned Extended Attribute file '%s/%s/%s'", 574 cwdbuf, ADv2_DIRNAME, name); 575 } 576 } /* if (access) */ 577 } /* if strstr */ 578 } /* if AFPVOL_EA_AD */ 579 580ea_check_done: 581 if (namedup) 582 free(namedup); 583 584 return ret; 585} 586 587/* 588 Check files and dirs inside .AppleDouble folder: 589 - remove orphaned files 590 - bail on dirs 591*/ 592static int read_addir(void) 593{ 594 DIR *dp; 595 struct dirent *ep; 596 struct stat st; 597 598 if ((chdir(ADv2_DIRNAME)) != 0) { 599 dbd_log(LOGSTD, "Couldn't chdir to '%s/%s': %s", 600 cwdbuf, ADv2_DIRNAME, strerror(errno)); 601 return -1; 602 } 603 604 if ((dp = opendir(".")) == NULL) { 605 dbd_log(LOGSTD, "Couldn't open the directory '%s/%s': %s", 606 cwdbuf, ADv2_DIRNAME, strerror(errno)); 607 return -1; 608 } 609 610 while ((ep = readdir(dp))) { 611 /* Check if its "." or ".." */ 612 if (DIR_DOT_OR_DOTDOT(ep->d_name)) 613 continue; 614 /* Skip ".Parent" */ 615 if (STRCMP(ep->d_name, ==, ".Parent")) 616 continue; 617 618 if ((lstat(ep->d_name, &st)) < 0) { 619 dbd_log( LOGSTD, "Lost file or dir while enumeratin dir '%s/%s/%s', probably removed: %s", 620 cwdbuf, ADv2_DIRNAME, ep->d_name, strerror(errno)); 621 continue; 622 } 623 624 /* Check for dirs */ 625 if (S_ISDIR(st.st_mode)) { 626 dbd_log( LOGSTD, "Unexpected directory '%s' in AppleDouble dir '%s/%s'", 627 ep->d_name, cwdbuf, ADv2_DIRNAME); 628 continue; 629 } 630 631 /* Check if for orphaned and corrupt Extended Attributes file */ 632 if (check_eafile_in_adouble(ep->d_name) != 0) 633 continue; 634 635 /* Check for data file */ 636 strcpy(pname + 3, ep->d_name); 637 if ((access( pname, F_OK)) != 0) { 638 if (errno != ENOENT) { 639 dbd_log(LOGSTD, "Access error for file '%s/%s': %s", 640 cwdbuf, pname, strerror(errno)); 641 continue; 642 } 643 /* Orphaned ad-file*/ 644 dbd_log(LOGSTD, "Orphaned AppleDoube file '%s/%s/%s'", 645 cwdbuf, ADv2_DIRNAME, ep->d_name); 646 647 if (dbd_flags & DBD_FLAGS_SCAN) 648 /* Scan only requested, dont change anything */ 649 continue;; 650 651 if ((unlink(ep->d_name)) != 0) { 652 dbd_log(LOGSTD, "Error unlinking orphaned AppleDoube file '%s/%s/%s'", 653 cwdbuf, ADv2_DIRNAME, ep->d_name); 654 655 } 656 } 657 } 658 659 if ((chdir("..")) != 0) { 660 dbd_log(LOGSTD, "Couldn't chdir back to '%s' from AppleDouble dir: %s", 661 cwdbuf, strerror(errno)); 662 /* This really is EOT! */ 663 longjmp(jmp, 1); /* this jumps back to cmd_dbd_scanvol() */ 664 } 665 666 closedir(dp); 667 668 return 0; 669} 670 671/* 672 Check CNID for a file/dir, both from db and from ad-file. 673 For detailed specs see intro. 674 675 @return Correct CNID of object or CNID_INVALID (ie 0) on error 676*/ 677static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfile_ok, int adflags) 678{ 679 int ret; 680 cnid_t db_cnid, ad_cnid; 681 struct adouble ad; 682 683 /* Force checkout every X items */ 684 static int cnidcount = 0; 685 cnidcount++; 686 if (cnidcount > 10000) { 687 cnidcount = 0; 688 if (dbif_txn_checkpoint(dbd, 0, 0, 0) < 0) { 689 dbd_log(LOGSTD, "Error checkpointing!"); 690 return CNID_INVALID; 691 } 692 } 693 694 /* Get CNID from ad-file if volume is using AFPVOL_CACHE */ 695 ad_cnid = 0; 696 if ( (myvolinfo->v_flags & AFPVOL_CACHE) && ADFILE_OK) { 697 ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options); 698 if (ad_open_metadata( name, adflags, O_RDWR, &ad) != 0) { 699 700 if (dbd_flags & DBD_FLAGS_CLEANUP) 701 return CNID_INVALID; 702 703 dbd_log( LOGSTD, "Error opening AppleDouble file for '%s/%s': %s", cwdbuf, name, strerror(errno)); 704 return CNID_INVALID; 705 } 706 707 if (dbd_flags & DBD_FLAGS_FORCE) { 708 ad_cnid = ad_forcegetid(&ad); 709 /* This ensures the changed stamp is written */ 710 ad_setid( &ad, st->st_dev, st->st_ino, ad_cnid, did, stamp); 711 ad_flush(&ad); 712 } 713 else 714 ad_cnid = ad_getid(&ad, st->st_dev, st->st_ino, 0, stamp); 715 716 if (ad_cnid == 0) 717 dbd_log( LOGSTD, "Bad CNID in adouble file of '%s/%s'", cwdbuf, name); 718 else 719 dbd_log( LOGDEBUG, "CNID from .AppleDouble file for '%s/%s': %u", cwdbuf, name, ntohl(ad_cnid)); 720 721 ad_close_metadata(&ad); 722 } 723 724 /* Get CNID from database */ 725 726 /* Prepare request data */ 727 memset(&rqst, 0, sizeof(struct cnid_dbd_rqst)); 728 memset(&rply, 0, sizeof(struct cnid_dbd_rply)); 729 rqst.did = did; 730 rqst.cnid = ad_cnid; 731 if ( ! (myvolinfo->v_flags & AFPVOL_NODEV)) 732 rqst.dev = st->st_dev; 733 rqst.ino = st->st_ino; 734 rqst.type = S_ISDIR(st->st_mode)?1:0; 735 rqst.name = (char *)name; 736 rqst.namelen = strlen(name); 737 738 /* Query the database */ 739 ret = dbd_lookup(dbd, &rqst, &rply, (dbd_flags & DBD_FLAGS_SCAN) ? 1 : 0); 740 if (dbif_txn_close(dbd, ret) != 0) 741 return CNID_INVALID; 742 if (rply.result == CNID_DBD_RES_OK) { 743 db_cnid = rply.cnid; 744 } else if (rply.result == CNID_DBD_RES_NOTFOUND) { 745 if ( ! (dbd_flags & DBD_FLAGS_FORCE)) 746 dbd_log( LOGSTD, "No CNID for '%s/%s' in database", cwdbuf, name); 747 db_cnid = 0; 748 } else { 749 dbd_log( LOGSTD, "Fatal error resolving '%s/%s'", cwdbuf, name); 750 db_cnid = 0; 751 } 752 753 /* Compare results from both CNID searches */ 754 if (ad_cnid && db_cnid && (ad_cnid == db_cnid)) { 755 /* Everything is fine */ 756 return db_cnid; 757 } else if (ad_cnid && db_cnid && (ad_cnid != db_cnid)) { 758 /* Mismatch, overwrite ad file with value from db */ 759 dbd_log( LOGSTD, "CNID mismatch for '%s/%s', db: %u, ad-file: %u", cwdbuf, name, ntohl(db_cnid), ntohl(ad_cnid)); 760 if ( ! (dbd_flags & DBD_FLAGS_SCAN)) { 761 dbd_log(LOGSTD, "Updating AppleDouble file for '%s/%s' with CNID: %u from database", 762 cwdbuf, name, ntohl(db_cnid)); 763 ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options); 764 if (ad_open_metadata( name, adflags, O_RDWR, &ad) != 0) { 765 dbd_log(LOGSTD, "Error opening AppleDouble file for '%s/%s': %s", 766 cwdbuf, name, strerror(errno)); 767 return CNID_INVALID; 768 } 769 ad_setid( &ad, st->st_dev, st->st_ino, db_cnid, did, stamp); 770 ad_flush(&ad); 771 ad_close_metadata(&ad); 772 } 773 return db_cnid; 774 } else if (ad_cnid && (db_cnid == 0)) { 775 /* in ad-file but not in db */ 776 if ( ! (dbd_flags & DBD_FLAGS_SCAN)) { 777 /* Ensure the cnid from the ad-file is not already occupied by another file */ 778 dbd_log(LOGDEBUG, "Checking whether CNID %u from ad-file is occupied", 779 ntohl(ad_cnid)); 780 781 rqst.cnid = ad_cnid; 782 ret = dbd_resolve(dbd, &rqst, &rply); 783 if (rply.result == CNID_DBD_RES_OK) { 784 /* Occupied! Choose another, update ad-file */ 785 ret = dbd_add(dbd, &rqst, &rply, 1); 786 if (dbif_txn_close(dbd, ret) != 0) 787 return CNID_INVALID; 788 db_cnid = rply.cnid; 789 dbd_log(LOGSTD, "New CNID for '%s/%s': %u", cwdbuf, name, ntohl(db_cnid)); 790 791 if ((myvolinfo->v_flags & AFPVOL_CACHE) 792 && ADFILE_OK 793 && ( ! (dbd_flags & DBD_FLAGS_SCAN))) { 794 dbd_log(LOGSTD, "Writing CNID data for '%s/%s' to AppleDouble file", 795 cwdbuf, name, ntohl(db_cnid)); 796 ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options); 797 if (ad_open_metadata( name, adflags, O_RDWR, &ad) != 0) { 798 dbd_log(LOGSTD, "Error opening AppleDouble file for '%s/%s': %s", 799 cwdbuf, name, strerror(errno)); 800 return CNID_INVALID; 801 } 802 ad_setid( &ad, st->st_dev, st->st_ino, db_cnid, did, stamp); 803 ad_flush(&ad); 804 ad_close_metadata(&ad); 805 } 806 return db_cnid; 807 } 808 809 dbd_log(LOGDEBUG, "CNID rebuild add '%s/%s' with CNID from ad-file %u", 810 cwdbuf, name, ntohl(ad_cnid)); 811 rqst.cnid = ad_cnid; 812 ret = dbd_rebuild_add(dbd, &rqst, &rply); 813 if (dbif_txn_close(dbd, ret) != 0) 814 return CNID_INVALID; 815 } 816 return ad_cnid; 817 } else if ((db_cnid == 0) && (ad_cnid == 0)) { 818 /* No CNID at all, we clearly have to allocate a fresh one... */ 819 /* Note: the next test will use this new CNID too! */ 820 if ( ! (dbd_flags & DBD_FLAGS_SCAN)) { 821 /* add to db */ 822 ret = dbd_add(dbd, &rqst, &rply, 1); 823 if (dbif_txn_close(dbd, ret) != 0) 824 return CNID_INVALID; 825 db_cnid = rply.cnid; 826 dbd_log(LOGSTD, "New CNID for '%s/%s': %u", cwdbuf, name, ntohl(db_cnid)); 827 } 828 } 829 830 if ((ad_cnid == 0) && db_cnid) { 831 /* in db but zeroID in ad-file, write it to ad-file if AFPVOL_CACHE */ 832 if ((myvolinfo->v_flags & AFPVOL_CACHE) && ADFILE_OK) { 833 if ( ! (dbd_flags & DBD_FLAGS_SCAN)) { 834 dbd_log(LOGSTD, "Writing CNID data for '%s/%s' to AppleDouble file", 835 cwdbuf, name, ntohl(db_cnid)); 836 ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options); 837 if (ad_open_metadata( name, adflags, O_RDWR, &ad) != 0) { 838 dbd_log(LOGSTD, "Error opening AppleDouble file for '%s/%s': %s", 839 cwdbuf, name, strerror(errno)); 840 return CNID_INVALID; 841 } 842 ad_setid( &ad, st->st_dev, st->st_ino, db_cnid, did, stamp); 843 ad_flush(&ad); 844 ad_close_metadata(&ad); 845 } 846 } 847 return db_cnid; 848 } 849 850 return CNID_INVALID; 851} 852 853/* 854 This is called recursively for all dirs. 855 volroot=1 means we're in the volume root dir, 0 means we aren't. 856 We use this when checking for netatalk private folders like .AppleDB. 857 did is our parents CNID. 858*/ 859static int dbd_readdir(int volroot, cnid_t did) 860{ 861 int cwd, ret = 0, adflags, adfile_ok, addir_ok, encoding_ok; 862 cnid_t cnid = 0; 863 const char *name; 864 DIR *dp; 865 struct dirent *ep; 866 static struct stat st; /* Save some stack space */ 867 868 /* Check again for .AppleDouble folder, check_adfile also checks/creates it */ 869 if ((addir_ok = check_addir(volroot)) != 0) 870 if ( ! (dbd_flags & DBD_FLAGS_SCAN)) 871 /* Fatal on rebuild run, continue if only scanning ! */ 872 return -1; 873 874 /* Check AppleDouble files in AppleDouble folder, but only if it exists or could be created */ 875 if (ADDIR_OK) 876 if ((read_addir()) != 0) 877 if ( ! (dbd_flags & DBD_FLAGS_SCAN)) 878 /* Fatal on rebuild run, continue if only scanning ! */ 879 return -1; 880 881 if ((dp = opendir (".")) == NULL) { 882 dbd_log(LOGSTD, "Couldn't open the directory: %s",strerror(errno)); 883 return -1; 884 } 885 886 while ((ep = readdir (dp))) { 887 /* Check if we got a termination signal */ 888 if (alarmed) 889 longjmp(jmp, 1); /* this jumps back to cmd_dbd_scanvol() */ 890 891 /* Check if its "." or ".." */ 892 if (DIR_DOT_OR_DOTDOT(ep->d_name)) 893 continue; 894 895 /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */ 896 if ((name = check_netatalk_dirs(ep->d_name)) != NULL) { 897 if (! volroot) 898 dbd_log(LOGSTD, "Nested %s in %s", name, cwdbuf); 899 continue; 900 } 901 902 /* Check for special folders in volume root e.g. ".zfs" */ 903 if (volroot) { 904 if ((name = check_special_dirs(ep->d_name)) != NULL) { 905 dbd_log(LOGSTD, "Ignoring special dir \"%s\"", name); 906 continue; 907 } 908 } 909 910 /* Skip .AppleDouble dir in this loop */ 911 if (STRCMP(ep->d_name, == , ADv2_DIRNAME)) 912 continue; 913 914 if ((ret = lstat(ep->d_name, &st)) < 0) { 915 dbd_log( LOGSTD, "Lost file while reading dir '%s/%s', probably removed: %s", 916 cwdbuf, ep->d_name, strerror(errno)); 917 continue; 918 } 919 920 switch (st.st_mode & S_IFMT) { 921 case S_IFREG: 922 adflags = 0; 923 break; 924 case S_IFDIR: 925 adflags = ADFLAGS_DIR; 926 break; 927 case S_IFLNK: 928 dbd_log(LOGDEBUG, "Ignoring symlink %s/%s", cwdbuf, ep->d_name); 929#if 0 930 ret = check_symlink(ep->d_name, &adflags); 931 if (ret == 1) 932 break; 933 if (ret == -1) 934 dbd_log(LOGSTD, "Error checking symlink %s/%s", cwdbuf, ep->d_name); 935#endif 936 continue; 937 default: 938 dbd_log(LOGSTD, "Bad filetype: %s/%s", cwdbuf, ep->d_name); 939 if ( ! (dbd_flags & DBD_FLAGS_SCAN)) { 940 if ((unlink(ep->d_name)) != 0) { 941 dbd_log(LOGSTD, "Error removing: %s/%s: %s", cwdbuf, ep->d_name, strerror(errno)); 942 } 943 } 944 continue; 945 } 946 947 /************************************************************************** 948 Statistics 949 **************************************************************************/ 950 static unsigned long long statcount = 0; 951 static time_t t = 0; 952 953 if (t == 0) 954 t = time(NULL); 955 956 statcount++; 957 if ((statcount % 10000) == 0) { 958 if (dbd_flags & DBD_FLAGS_STATS) 959 dbd_log(LOGSTD, "Scanned: %10llu, time: %10llu s", 960 statcount, (unsigned long long)(time(NULL) - t)); 961 } 962 963 /************************************************************************** 964 Tests 965 **************************************************************************/ 966 967 /* Check encoding */ 968 if ( -1 == (encoding_ok = check_name_encoding(ep->d_name)) ) { 969 /* If its a file: skipp all other tests now ! */ 970 /* For dirs we could try to get a CNID for it and recurse, but currently I prefer not to */ 971 continue; 972 } 973 974 /* Check for appledouble file, create if missing, but only if we have addir */ 975 adfile_ok = -1; 976 if (ADDIR_OK) 977 adfile_ok = check_adfile(ep->d_name, &st); 978 979 if ( ! nocniddb) { 980 /* Check CNIDs */ 981 cnid = check_cnid(ep->d_name, did, &st, adfile_ok, adflags); 982 983 /* Now add this object to our rebuild dbd */ 984 if (cnid && dbd_rebuild) { 985 static uint count = 0; 986 rqst.cnid = rply.cnid; 987 ret = dbd_rebuild_add(dbd_rebuild, &rqst, &rply); 988 if (dbif_txn_close(dbd_rebuild, ret) != 0) 989 return -1; 990 if (rply.result != CNID_DBD_RES_OK) { 991 dbd_log( LOGSTD, "Fatal error adding CNID: %u for '%s/%s' to in-memory rebuild-db", 992 cnid, cwdbuf, ep->d_name); 993 return -1; 994 } 995 count++; 996 if (count == 10000) { 997 if (dbif_txn_checkpoint(dbd_rebuild, 0, 0, 0) < 0) { 998 dbd_log(LOGSTD, "Error checkpointing!"); 999 return -1; 1000 } 1001 count = 0; 1002 } 1003 } 1004 } 1005 1006 /* Check EA files */ 1007 if (myvolinfo->v_vfs_ea == AFPVOL_EA_AD) 1008 check_eafiles(ep->d_name); 1009 1010 /************************************************************************** 1011 Recursion 1012 **************************************************************************/ 1013 if (S_ISDIR(st.st_mode) && (cnid || nocniddb)) { /* If we have no cnid for it we cant recur */ 1014 strcat(cwdbuf, "/"); 1015 strcat(cwdbuf, ep->d_name); 1016 dbd_log( LOGDEBUG, "Entering directory: %s", cwdbuf); 1017 if (-1 == (cwd = open(".", O_RDONLY))) { 1018 dbd_log( LOGSTD, "Cant open directory '%s': %s", cwdbuf, strerror(errno)); 1019 continue; 1020 } 1021 if (0 != chdir(ep->d_name)) { 1022 dbd_log( LOGSTD, "Cant chdir to directory '%s': %s", cwdbuf, strerror(errno)); 1023 close(cwd); 1024 continue; 1025 } 1026 1027 ret = dbd_readdir(0, cnid); 1028 1029 fchdir(cwd); 1030 close(cwd); 1031 *(strrchr(cwdbuf, '/')) = 0; 1032 if (ret < 0) 1033 return -1; 1034 } 1035 } 1036 1037 /* 1038 Use results of previous checks 1039 */ 1040 1041 closedir(dp); 1042 return ret; 1043} 1044 1045static int scanvol(struct volinfo *vi, dbd_flags_t flags) 1046{ 1047 /* Dont scanvol on no-appledouble vols */ 1048 if (vi->v_flags & AFPVOL_NOADOUBLE) { 1049 dbd_log( LOGSTD, "Volume without AppleDouble support: skipping volume scanning."); 1050 return 0; 1051 } 1052 1053 /* Make this stuff accessible from all funcs easily */ 1054 myvolinfo = vi; 1055 dbd_flags = flags; 1056 1057 /* Init a fake struct vol with just enough so we can call ea_open and friends */ 1058 volume.v_adouble = AD_VERSION2; 1059 volume.v_vfs_ea = myvolinfo->v_vfs_ea; 1060 initvol_vfs(&volume); 1061 1062 /* Run with umask 0 */ 1063 umask(0); 1064 1065 /* Remove trailing slash from volume, chdir to vol */ 1066 if (myvolinfo->v_path[strlen(myvolinfo->v_path) - 1] == '/') 1067 myvolinfo->v_path[strlen(myvolinfo->v_path) - 1] = 0; 1068 strcpy(cwdbuf, myvolinfo->v_path); 1069 chdir(myvolinfo->v_path); 1070 1071 /* Start recursion */ 1072 if (dbd_readdir(1, htonl(2)) < 0) /* 2 = volumeroot CNID */ 1073 return -1; 1074 1075 return 0; 1076} 1077 1078/* 1079 Remove all CNIDs from dbd that are not in dbd_rebuild 1080*/ 1081static void delete_orphaned_cnids(DBD *dbd, DBD *dbd_rebuild, dbd_flags_t flags) 1082{ 1083 int ret = 0, deleted = 0; 1084 cnid_t dbd_cnid = 0, rebuild_cnid = 0; 1085 struct cnid_dbd_rqst rqst; 1086 struct cnid_dbd_rply rply; 1087 1088 /* jump over rootinfo key */ 1089 if ( dbif_idwalk(dbd, &dbd_cnid, 0) != 1) 1090 return; 1091 if ( dbif_idwalk(dbd_rebuild, &rebuild_cnid, 0) != 1) 1092 return; 1093 1094 /* Get first id from dbd_rebuild */ 1095 if ((dbif_idwalk(dbd_rebuild, &rebuild_cnid, 0)) == -1) 1096 return; 1097 1098 /* Start main loop through dbd: get CNID from dbd */ 1099 while ((dbif_idwalk(dbd, &dbd_cnid, 0)) == 1) { 1100 /* Check if we got a termination signal */ 1101 if (alarmed) 1102 longjmp(jmp, 1); /* this jumps back to cmd_dbd_scanvol() */ 1103 1104 if (deleted > 1000) { 1105 deleted = 0; 1106 if (dbif_txn_checkpoint(dbd, 0, 0, 0) < 0) { 1107 dbd_log(LOGSTD, "Error checkpointing!"); 1108 goto cleanup; 1109 } 1110 } 1111 1112 /* This should be the normal case: CNID is in both dbs */ 1113 if (dbd_cnid == rebuild_cnid) { 1114 /* Get next CNID from rebuild db */ 1115 if ((ret = dbif_idwalk(dbd_rebuild, &rebuild_cnid, 0)) == -1) { 1116 /* Some error */ 1117 goto cleanup; 1118 } else if (ret == 0) { 1119 /* end of rebuild_cnid, delete all remaining CNIDs from dbd */ 1120 while ((dbif_idwalk(dbd, &dbd_cnid, 0)) == 1) { 1121 dbd_log(LOGSTD, "Orphaned CNID in database: %u", dbd_cnid); 1122 if ( ! (dbd_flags & DBD_FLAGS_SCAN)) { 1123 rqst.cnid = htonl(dbd_cnid); 1124 if ((ret = dbd_delete(dbd, &rqst, &rply, DBIF_CNID)) == -1) { 1125 dbd_log(LOGSTD, "Error deleting CNID %u", dbd_cnid); 1126 (void)dbif_txn_abort(dbd); 1127 goto cleanup; 1128 } 1129 1130 if (dbif_txn_close(dbd, ret) != 0) 1131 return; 1132 deleted++; 1133 } 1134 /* Check if we got a termination signal */ 1135 if (alarmed) 1136 longjmp(jmp, 1); /* this jumps back to cmd_dbd_scanvol() */ 1137 } 1138 return; 1139 } else 1140 /* Normal case (ret=1): continue while loop */ 1141 continue; 1142 } 1143 1144 if (dbd_cnid < rebuild_cnid) { 1145 /* CNID is orphaned -> delete */ 1146 dbd_log(LOGSTD, "One orphaned CNID in database: %u.", dbd_cnid); 1147 if ( ! (dbd_flags & DBD_FLAGS_SCAN)) { 1148 rqst.cnid = htonl(dbd_cnid); 1149 if ((ret = dbd_delete(dbd, &rqst, &rply, DBIF_CNID)) == -1) { 1150 dbd_log(LOGSTD, "Error deleting CNID %u", dbd_cnid); 1151 (void)dbif_txn_abort(dbd); 1152 goto cleanup; 1153 } 1154 if (dbif_txn_close(dbd, ret) != 0) 1155 return; 1156 deleted++; 1157 } 1158 continue; 1159 } 1160 1161 if (dbd_cnid > rebuild_cnid) { 1162 dbif_idwalk(dbd, NULL, 1); /* Close cursor */ 1163 dbif_idwalk(dbd_rebuild, NULL, 1); /* Close cursor */ 1164 (void)dbif_txn_close(dbd, 2); 1165 (void)dbif_txn_close(dbd_rebuild, 2); 1166 dbd_log(LOGSTD, "Ghost CNID: %u. This is fatal! Dumping rebuild db:\n", rebuild_cnid); 1167 dbif_dump(dbd_rebuild, 0); 1168 dbd_log(LOGSTD, "Send this dump and a `dbd -d ...` dump to the Netatalk Dev team!"); 1169 goto cleanup; 1170 } 1171 } /* while ((dbif_idwalk(dbd, &dbd_cnid, 0)) == 1) */ 1172 1173cleanup: 1174 dbif_idwalk(dbd, NULL, 1); /* Close cursor */ 1175 dbif_idwalk(dbd_rebuild, NULL, 1); /* Close cursor */ 1176 return; 1177} 1178 1179static const char *get_tmpdb_path(void) 1180{ 1181 pid_t pid = getpid(); 1182 static char path[MAXPATHLEN]; 1183 snprintf(path, MAXPATHLEN, "/tmp/tmpdb-dbd.%u", pid); 1184 if (mkdir(path, 0755) != 0) 1185 return NULL; 1186 return path; 1187} 1188 1189/* 1190 Main func called from cmd_dbd.c 1191*/ 1192int cmd_dbd_scanvol(DBD *dbd_ref, struct volinfo *vi, dbd_flags_t flags) 1193{ 1194 int ret = 0; 1195 struct db_param db_param = { 0 }; 1196 const char *tmpdb_path = NULL; 1197 1198 /* Set cachesize for in-memory rebuild db */ 1199 db_param.cachesize = 64 * 1024; /* 64 MB */ 1200 db_param.maxlocks = DEFAULT_MAXLOCKS; 1201 db_param.maxlockobjs = DEFAULT_MAXLOCKOBJS; 1202 db_param.logfile_autoremove = 1; 1203 1204 /* Make it accessible for all funcs */ 1205 dbd = dbd_ref; 1206 1207 /* We only support unicode volumes ! */ 1208 if ( vi->v_volcharset != CH_UTF8) { 1209 dbd_log( LOGSTD, "Not a Unicode volume: %s, %u != %u", vi->v_volcodepage, vi->v_volcharset, CH_UTF8); 1210 return -1; 1211 } 1212 1213 /* Get volume stamp */ 1214 dbd_getstamp(dbd, &rqst, &rply); 1215 if (rply.result != CNID_DBD_RES_OK) { 1216 ret = -1; 1217 goto exit; 1218 } 1219 memcpy(stamp, rply.name, CNID_DEV_LEN); 1220 1221 /* temporary rebuild db, used with -re rebuild to delete unused CNIDs, not used with -f */ 1222 if (! nocniddb && (flags & DBD_FLAGS_EXCL) && !(flags & DBD_FLAGS_FORCE)) { 1223 tmpdb_path = get_tmpdb_path(); 1224 if (NULL == (dbd_rebuild = dbif_init(tmpdb_path, "cnid2.db"))) { 1225 ret = -1; 1226 goto exit; 1227 } 1228 1229 if (dbif_env_open(dbd_rebuild, 1230 &db_param, 1231 DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN) < 0) { 1232 dbd_log(LOGSTD, "error opening tmp database!"); 1233 goto exit; 1234 } 1235 1236 if (0 != (dbif_open(dbd_rebuild, NULL, 0))) { 1237 ret = -1; 1238 goto exit; 1239 } 1240 1241 if (0 != (dbif_copy_rootinfokey(dbd, dbd_rebuild))) { 1242 ret = -1; 1243 goto exit; 1244 } 1245 } 1246 1247 if (setjmp(jmp) != 0) { 1248 ret = 0; /* Got signal, jump from dbd_readdir */ 1249 goto exit; 1250 } 1251 1252 /* scanvol */ 1253 if ( (scanvol(vi, flags)) != 0) { 1254 ret = -1; 1255 goto exit; 1256 } 1257 1258exit: 1259 if (! nocniddb) { 1260 if (dbif_txn_close(dbd, ret == 0 ? 1 : 0) != 0) 1261 ret = -1; 1262 if (dbd_rebuild) 1263 if (dbif_txn_close(dbd_rebuild, ret == 0 ? 1 : 0) != 0) 1264 ret = -1; 1265 if ((ret == 0) && dbd_rebuild && (flags & DBD_FLAGS_EXCL) && !(flags & DBD_FLAGS_FORCE)) 1266 /* We can only do this in exclusive mode, otherwise we might delete CNIDs added from 1267 other clients in between our pass 1 and 2 */ 1268 delete_orphaned_cnids(dbd, dbd_rebuild, flags); 1269 } 1270 1271 if (dbd_rebuild) { 1272 dbd_log(LOGDEBUG, "Closing tmp db"); 1273 dbif_close(dbd_rebuild); 1274 1275 if (tmpdb_path) { 1276 char cmd[8 + MAXPATHLEN]; 1277 snprintf(cmd, 8 + MAXPATHLEN, "rm -f %s/*", tmpdb_path); 1278 dbd_log( LOGDEBUG, "Removing temp database '%s'", tmpdb_path); 1279 system(cmd); 1280 snprintf(cmd, 8 + MAXPATHLEN, "rmdir %s", tmpdb_path); 1281 system(cmd); 1282 } 1283 } 1284 return ret; 1285} 1286