X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=etc%2Fcnid_dbd%2Fcmd_dbd_scanvol.c;h=90293a48a0d1b8a25639d3f9fd32dff90103e4f1;hb=38e94665946a785acecab92ae88f15585ecd546e;hp=f4122d84ccf71af47d23531bfc4204e69191ec97;hpb=be96d276348da0a7e66eeec844b306e8a5fa8fac;p=netatalk.git diff --git a/etc/cnid_dbd/cmd_dbd_scanvol.c b/etc/cnid_dbd/cmd_dbd_scanvol.c index f4122d84..90293a48 100644 --- a/etc/cnid_dbd/cmd_dbd_scanvol.c +++ b/etc/cnid_dbd/cmd_dbd_scanvol.c @@ -157,85 +157,6 @@ static char *mtoupath(char *mpath) return( upath ); } -#if 0 -/* - Check if "name" is pointing to - a) an object inside the current volume (return 0) - b) an object outside the current volume (return 1) - Then stats the pointed to object and if it is a dir ors ADFLAGS_DIR to *adflags - Return -1 on any serious error. - */ -static int check_symlink(const char *name, int *adflags) -{ - int cwd; - ssize_t len; - char pathbuf[MAXPATHLEN + 1]; - char *sep; - struct stat st; - - if ((len = readlink(name, pathbuf, MAXPATHLEN)) == -1) { - dbd_log(LOGSTD, "Error reading link info for '%s/%s': %s", - cwdbuf, name, strerror(errno)); - return -1; - } - pathbuf[len] = 0; - - if ((stat(pathbuf, &st)) != 0) { - dbd_log(LOGSTD, "stat error '%s': %s", pathbuf, strerror(errno)); - } - - /* Remember cwd */ - if ((cwd = open(".", O_RDONLY)) < 0) { - dbd_log(LOGSTD, "error opening cwd '%s': %s", cwdbuf, strerror(errno)); - return -1; - } - - if (S_ISDIR(st.st_mode)) { - *adflags |= ADFLAGS_DIR; - } else { /* file */ - /* get basename from path */ - if ((sep = strrchr(pathbuf, '/')) == NULL) - /* just a file at the same level */ - return 0; - sep = 0; /* pathbuf now contains the directory*/ - } - - /* fchdir() to pathbuf so we can easily get its path with getcwd() */ - if ((chdir(pathbuf)) != 0) { - dbd_log(LOGSTD, "Cant chdir to '%s': %s", pathbuf, strerror(errno)); - return -1; - } - - if ((getcwd(pathbuf, MAXPATHLEN)) == NULL) { - dbd_log(LOGSTD, "Cant get symlink'ed dir '%s/%s': %s", cwdbuf, pathbuf, strerror(errno)); - if ((fchdir(cwd)) != 0) - /* We're foobared */ - longjmp(jmp, 1); /* this jumps back to cmd_dbd_scanvol() */ - return -1; - } - - if ((fchdir(cwd)) != 0) - /* We're foobared */ - longjmp(jmp, 1); /* this jumps back to cmd_dbd_scanvol() */ - - /* - We now have the symlink target dir as absoulte path in pathbuf - and can compare it with the currents volume path - */ - int i = 0; - while (myvolinfo->v_path[i]) { - if ((pathbuf[i] == 0) || (myvolinfo->v_path[i] != pathbuf[i])) { - dbd_log( LOGDEBUG, "extra-share symlink '%s/%s', following", cwdbuf, name); - return 1; - } - i++; - } - - dbd_log( LOGDEBUG, "intra-share symlink '%s/%s', not following", cwdbuf, name); - return 0; -} -#endif - /* Check for wrong encoding e.g. "." at the beginning is not CAP encoded (:2e) although volume is default !AFPVOL_USEDOTS. We do it by roundtripiping from volcharset to UTF8-MAC and back and then compare the result. @@ -298,13 +219,16 @@ static int check_adfile(const char *fname, const struct stat *st) struct adouble ad; const char *adname; + if (volume.v_adouble == AD_VERSION_EA) + return 0; + if (dbd_flags & DBD_FLAGS_CLEANUP) return 0; if (S_ISREG(st->st_mode)) adflags |= ADFLAGS_DIR; - adname = myvolinfo->ad_path(fname, adflags); + adname = volume.ad_path(fname, adflags); if ((ret = access( adname, F_OK)) != 0) { if (errno != ENOENT) { @@ -320,9 +244,9 @@ static int check_adfile(const char *fname, const struct stat *st) return -1; /* Create ad file */ - ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options); + ad_init(&ad, &volume); - if ((ret = ad_open(&ad, fname, adflags, O_CREAT | O_RDWR, 0666)) != 0) { + if ((ret = ad_open(&ad, fname, adflags | ADFLAGS_CREATE | ADFLAGS_RDWR, 0666)) != 0) { dbd_log( LOGSTD, "Error creating AppleDouble file '%s/%s': %s", cwdbuf, adname, strerror(errno)); @@ -332,7 +256,7 @@ static int check_adfile(const char *fname, const struct stat *st) /* Set name in ad-file */ ad_setname(&ad, utompath((char *)fname)); ad_flush(&ad); - ad_close_metadata(&ad); + ad_close(&ad, ADFLAGS_HF); chown(adname, st->st_uid, st->st_gid); /* FIXME: should we inherit mode too here ? */ @@ -340,12 +264,12 @@ static int check_adfile(const char *fname, const struct stat *st) chmod(adname, st->st_mode); #endif } else { - ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options); - if (ad_open(&ad, fname, adflags, O_RDONLY) != 0) { + ad_init(&ad, &volume); + if (ad_open(&ad, fname, adflags | ADFLAGS_RDONLY) != 0) { dbd_log( LOGSTD, "Error opening AppleDouble file for '%s/%s'", cwdbuf, fname); return -1; } - ad_close_metadata(&ad); + ad_close(&ad, ADFLAGS_HF); } return 0; } @@ -374,7 +298,7 @@ static void remove_eafiles(const char *name, struct ea *ea) if ((dp = opendir(".")) == NULL) { dbd_log(LOGSTD, "Couldn't open the directory '%s/%s': %s", cwdbuf, ADv2_DIRNAME, strerror(errno)); - return; + goto exit; } while ((ep = readdir(dp))) { @@ -388,9 +312,14 @@ static void remove_eafiles(const char *name, struct ea *ea) } /* if */ } /* while */ +exit: if (dp) closedir(dp); - + if ((chdir("..")) != 0) { + dbd_log(LOGSTD, "Couldn't chdir to '%s': %s", cwdbuf, strerror(errno)); + /* we can't proceed */ + longjmp(jmp, 1); /* this jumps back to cmd_dbd_scanvol() */ + } } /* @@ -460,6 +389,9 @@ static int check_addir(int volroot) if (dbd_flags & DBD_FLAGS_CLEANUP) return 0; + if (volume.v_adouble == AD_VERSION_EA) + return 0; + /* Check for ad-dir */ if ( (addir_ok = access(ADv2_DIRNAME, F_OK)) != 0) { if (errno != ENOENT) { @@ -470,10 +402,10 @@ static int check_addir(int volroot) } /* Check for ".Parent" */ - if ( (adpar_ok = access(myvolinfo->ad_path(".", ADFLAGS_DIR), F_OK)) != 0) { + if ( (adpar_ok = access(volume.ad_path(".", ADFLAGS_DIR), F_OK)) != 0) { if (errno != ENOENT) { dbd_log(LOGSTD, "Access error on '%s/%s': %s", - cwdbuf, myvolinfo->ad_path(".", ADFLAGS_DIR), strerror(errno)); + cwdbuf, volume.ad_path(".", ADFLAGS_DIR), strerror(errno)); return -1; } dbd_log(LOGSTD, "Missing .AppleDouble/.Parent for '%s'", cwdbuf); @@ -492,9 +424,9 @@ static int check_addir(int volroot) } /* Create ad dir and set name */ - ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options); + ad_init(&ad, &volume); - if (ad_open(&ad, ".", ADFLAGS_HF | ADFLAGS_DIR, O_CREAT | O_RDWR, 0777) != 0) { + if (ad_open(&ad, ".", ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_CREATE | ADFLAGS_RDWR, 0777) != 0) { dbd_log( LOGSTD, "Error creating AppleDouble dir in %s: %s", cwdbuf, strerror(errno)); return -1; } @@ -505,7 +437,7 @@ static int check_addir(int volroot) /* Update name in ad file */ ad_setname(&ad, mname); ad_flush(&ad); - ad_close_metadata(&ad); + ad_close(&ad, ADFLAGS_HF); /* Inherit owner/group from "." to ".AppleDouble" and ".Parent" */ if ((lstat(".", &st)) != 0) { @@ -513,7 +445,7 @@ static int check_addir(int volroot) return -1; } chown(ADv2_DIRNAME, st.st_uid, st.st_gid); - chown(myvolinfo->ad_path(".", ADFLAGS_DIR), st.st_uid, st.st_gid); + chown(volume.ad_path(".", ADFLAGS_DIR), st.st_uid, st.st_gid); } return 0; @@ -590,6 +522,9 @@ static int read_addir(void) struct dirent *ep; struct stat st; + if (volume.v_adouble == AD_VERSION_EA) + return 0; + if ((chdir(ADv2_DIRNAME)) != 0) { dbd_log(LOGSTD, "Couldn't chdir to '%s/%s': %s", cwdbuf, ADv2_DIRNAME, strerror(errno)); @@ -606,6 +541,7 @@ static int read_addir(void) /* Check if its "." or ".." */ if (DIR_DOT_OR_DOTDOT(ep->d_name)) continue; + /* Skip ".Parent" */ if (STRCMP(ep->d_name, ==, ".Parent")) continue; @@ -666,41 +602,59 @@ static int read_addir(void) /* Check CNID for a file/dir, both from db and from ad-file. For detailed specs see intro. + + @return Correct CNID of object or CNID_INVALID (ie 0) on error */ -static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfile_ok, int adflags) +static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfile_ok) { - int ret; + int ret, adflags = ADFLAGS_HF; cnid_t db_cnid, ad_cnid; struct adouble ad; - /* Get CNID from ad-file if volume is using AFPVOL_CACHE */ + adflags = ADFLAGS_HF | (S_ISDIR(st->st_mode) ? ADFLAGS_DIR : 0); + + /* Force checkout every X items */ + static int cnidcount = 0; + cnidcount++; + if (cnidcount > 10000) { + cnidcount = 0; + if (dbif_txn_checkpoint(dbd, 0, 0, 0) < 0) { + dbd_log(LOGSTD, "Error checkpointing!"); + return CNID_INVALID; + } + } + + /* Get CNID from ad-file */ ad_cnid = 0; - if ( (myvolinfo->v_flags & AFPVOL_CACHE) && ADFILE_OK) { - ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options); - if (ad_open(&ad, name, adflags, O_RDWR) != 0) { + if (ADFILE_OK) { + ad_init(&ad, &volume); + if (ad_open(&ad, name, adflags | ADFLAGS_RDWR) != 0) { if (dbd_flags & DBD_FLAGS_CLEANUP) - return 0; - - dbd_log( LOGSTD, "Error opening AppleDouble file for '%s/%s': %s", cwdbuf, name, strerror(errno)); - return 0; - } + return CNID_INVALID; - if (dbd_flags & DBD_FLAGS_FORCE) { - ad_cnid = ad_forcegetid(&ad); - /* This ensures the changed stamp is written */ - ad_setid( &ad, st->st_dev, st->st_ino, ad_cnid, did, stamp); - ad_flush(&ad); - } - else - ad_cnid = ad_getid(&ad, st->st_dev, st->st_ino, did, stamp); + if (volume.v_adouble != AD_VERSION_EA) { + dbd_log( LOGSTD, "Error opening AppleDouble file for '%s/%s': %s", cwdbuf, name, strerror(errno)); + return CNID_INVALID; + } + dbd_log( LOGDEBUG, "File without meta EA: \"%s/%s\"", cwdbuf, name); + adfile_ok = 1; + } else { - if (ad_cnid == 0) - dbd_log( LOGSTD, "Bad CNID in adouble file of '%s/%s'", cwdbuf, name); - else - dbd_log( LOGDEBUG, "CNID from .AppleDouble file for '%s/%s': %u", cwdbuf, name, ntohl(ad_cnid)); + if (dbd_flags & DBD_FLAGS_FORCE) { + ad_cnid = ad_forcegetid(&ad); + /* This ensures the changed stamp is written */ + ad_setid( &ad, st->st_dev, st->st_ino, ad_cnid, did, stamp); + ad_flush(&ad); + } else + ad_cnid = ad_getid(&ad, st->st_dev, st->st_ino, 0, stamp); - ad_close_metadata(&ad); + if (ad_cnid == 0) + dbd_log( LOGSTD, "Bad CNID in adouble file of '%s/%s'", cwdbuf, name); + else + dbd_log( LOGDEBUG, "CNID from .AppleDouble file for '%s/%s': %u", cwdbuf, name, ntohl(ad_cnid)); + ad_close(&ad, ADFLAGS_HF); + } } /* Get CNID from database */ @@ -719,7 +673,8 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi /* Query the database */ ret = dbd_lookup(dbd, &rqst, &rply, (dbd_flags & DBD_FLAGS_SCAN) ? 1 : 0); - dbif_txn_close(dbd, ret); + if (dbif_txn_close(dbd, ret) != 0) + return CNID_INVALID; if (rply.result == CNID_DBD_RES_OK) { db_cnid = rply.cnid; } else if (rply.result == CNID_DBD_RES_NOTFOUND) { @@ -736,21 +691,22 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi /* Everything is fine */ return db_cnid; } else if (ad_cnid && db_cnid && (ad_cnid != db_cnid)) { - /* Mismatch ? Delete both from db and re-add data from file */ + /* Mismatch, overwrite ad file with value from db */ dbd_log( LOGSTD, "CNID mismatch for '%s/%s', db: %u, ad-file: %u", cwdbuf, name, ntohl(db_cnid), ntohl(ad_cnid)); if ( ! (dbd_flags & DBD_FLAGS_SCAN)) { - rqst.cnid = db_cnid; - ret = dbd_delete(dbd, &rqst, &rply, DBIF_CNID); - dbif_txn_close(dbd, ret); - - rqst.cnid = ad_cnid; - ret = dbd_delete(dbd, &rqst, &rply, DBIF_CNID); - dbif_txn_close(dbd, ret); - - ret = dbd_rebuild_add(dbd, &rqst, &rply); - dbif_txn_close(dbd, ret); + dbd_log(LOGSTD, "Updating AppleDouble file for '%s/%s' with CNID: %u from database", + cwdbuf, name, ntohl(db_cnid)); + ad_init(&ad, &volume); + if (ad_open(&ad, name, adflags | ADFLAGS_HF | ADFLAGS_RDWR) != 0) { + dbd_log(LOGSTD, "Error opening AppleDouble file for '%s/%s': %s", + cwdbuf, name, strerror(errno)); + return CNID_INVALID; + } + ad_setid( &ad, st->st_dev, st->st_ino, db_cnid, did, stamp); + ad_flush(&ad); + ad_close(&ad, ADFLAGS_HF); } - return ad_cnid; + return db_cnid; } else if (ad_cnid && (db_cnid == 0)) { /* in ad-file but not in db */ if ( ! (dbd_flags & DBD_FLAGS_SCAN)) { @@ -760,27 +716,26 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi rqst.cnid = ad_cnid; ret = dbd_resolve(dbd, &rqst, &rply); - if (ret == CNID_DBD_RES_OK) { + if (rply.result == CNID_DBD_RES_OK) { /* Occupied! Choose another, update ad-file */ ret = dbd_add(dbd, &rqst, &rply, 1); - dbif_txn_close(dbd, ret); + if (dbif_txn_close(dbd, ret) != 0) + return CNID_INVALID; db_cnid = rply.cnid; dbd_log(LOGSTD, "New CNID for '%s/%s': %u", cwdbuf, name, ntohl(db_cnid)); - if ((myvolinfo->v_flags & AFPVOL_CACHE) - && ADFILE_OK - && ( ! (dbd_flags & DBD_FLAGS_SCAN))) { + if (ADFILE_OK && ( ! (dbd_flags & DBD_FLAGS_SCAN))) { dbd_log(LOGSTD, "Writing CNID data for '%s/%s' to AppleDouble file", cwdbuf, name, ntohl(db_cnid)); - ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options); - if (ad_open(&ad, name, adflags, O_RDWR) != 0) { + ad_init(&ad, &volume); + if (ad_open(&ad, name, adflags | ADFLAGS_RDWR) != 0) { dbd_log(LOGSTD, "Error opening AppleDouble file for '%s/%s': %s", cwdbuf, name, strerror(errno)); - return 0; + return CNID_INVALID; } ad_setid( &ad, st->st_dev, st->st_ino, db_cnid, did, stamp); ad_flush(&ad); - ad_close_metadata(&ad); + ad_close(&ad, ADFLAGS_HF); } return db_cnid; } @@ -789,7 +744,8 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi cwdbuf, name, ntohl(ad_cnid)); rqst.cnid = ad_cnid; ret = dbd_rebuild_add(dbd, &rqst, &rply); - dbif_txn_close(dbd, ret); + if (dbif_txn_close(dbd, ret) != 0) + return CNID_INVALID; } return ad_cnid; } else if ((db_cnid == 0) && (ad_cnid == 0)) { @@ -798,33 +754,32 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi if ( ! (dbd_flags & DBD_FLAGS_SCAN)) { /* add to db */ ret = dbd_add(dbd, &rqst, &rply, 1); - dbif_txn_close(dbd, ret); + if (dbif_txn_close(dbd, ret) != 0) + return CNID_INVALID; db_cnid = rply.cnid; dbd_log(LOGSTD, "New CNID for '%s/%s': %u", cwdbuf, name, ntohl(db_cnid)); } } if ((ad_cnid == 0) && db_cnid) { - /* in db but zeroID in ad-file, write it to ad-file if AFPVOL_CACHE */ - if ((myvolinfo->v_flags & AFPVOL_CACHE) && ADFILE_OK) { - if ( ! (dbd_flags & DBD_FLAGS_SCAN)) { - dbd_log(LOGSTD, "Writing CNID data for '%s/%s' to AppleDouble file", - cwdbuf, name, ntohl(db_cnid)); - ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options); - if (ad_open(&ad, name, adflags, O_RDWR) != 0) { - dbd_log(LOGSTD, "Error opening AppleDouble file for '%s/%s': %s", - cwdbuf, name, strerror(errno)); - return 0; - } - ad_setid( &ad, st->st_dev, st->st_ino, db_cnid, did, stamp); - ad_flush(&ad); - ad_close_metadata(&ad); + /* in db but zeroID in ad-file, write it to ad-file */ + if (ADFILE_OK && ! (dbd_flags & DBD_FLAGS_SCAN)) { + dbd_log(LOGSTD, "Writing CNID data for '%s/%s' to AppleDouble file", + cwdbuf, name, ntohl(db_cnid)); + ad_init(&ad, &volume); + if (ad_open(&ad, name, adflags | ADFLAGS_RDWR) != 0) { + dbd_log(LOGSTD, "Error opening AppleDouble file for '%s/%s': %s", + cwdbuf, name, strerror(errno)); + return CNID_INVALID; } + ad_setid( &ad, st->st_dev, st->st_ino, db_cnid, did, stamp); + ad_flush(&ad); + ad_close(&ad, ADFLAGS_HF); } return db_cnid; } - return 0; + return CNID_INVALID; } /* @@ -835,7 +790,7 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi */ static int dbd_readdir(int volroot, cnid_t did) { - int cwd, ret = 0, adflags, adfile_ok, addir_ok, encoding_ok; + int cwd, ret = 0, adfile_ok, addir_ok, encoding_ok; cnid_t cnid = 0; const char *name; DIR *dp; @@ -849,7 +804,7 @@ static int dbd_readdir(int volroot, cnid_t did) return -1; /* Check AppleDouble files in AppleDouble folder, but only if it exists or could be created */ - if (ADDIR_OK) + if (volume.v_adouble == AD_VERSION2 && ADDIR_OK) if ((read_addir()) != 0) if ( ! (dbd_flags & DBD_FLAGS_SCAN)) /* Fatal on rebuild run, continue if only scanning ! */ @@ -896,20 +851,10 @@ static int dbd_readdir(int volroot, cnid_t did) switch (st.st_mode & S_IFMT) { case S_IFREG: - adflags = 0; - break; case S_IFDIR: - adflags = ADFLAGS_DIR; break; case S_IFLNK: dbd_log(LOGDEBUG, "Ignoring symlink %s/%s", cwdbuf, ep->d_name); -#if 0 - ret = check_symlink(ep->d_name, &adflags); - if (ret == 1) - break; - if (ret == -1) - dbd_log(LOGSTD, "Error checking symlink %s/%s", cwdbuf, ep->d_name); -#endif continue; default: dbd_log(LOGSTD, "Bad filetype: %s/%s", cwdbuf, ep->d_name); @@ -921,6 +866,22 @@ static int dbd_readdir(int volroot, cnid_t did) continue; } + /************************************************************************** + Statistics + **************************************************************************/ + static unsigned long long statcount = 0; + static time_t t = 0; + + if (t == 0) + t = time(NULL); + + statcount++; + if ((statcount % 10000) == 0) { + if (dbd_flags & DBD_FLAGS_STATS) + dbd_log(LOGSTD, "Scanned: %10llu, time: %10llu s", + statcount, (unsigned long long)(time(NULL) - t)); + } + /************************************************************************** Tests **************************************************************************/ @@ -939,16 +900,27 @@ static int dbd_readdir(int volroot, cnid_t did) if ( ! nocniddb) { /* Check CNIDs */ - cnid = check_cnid(ep->d_name, did, &st, adfile_ok, adflags); + cnid = check_cnid(ep->d_name, did, &st, adfile_ok); /* Now add this object to our rebuild dbd */ - if (cnid) { + if (cnid && dbd_rebuild) { + static uint count = 0; rqst.cnid = rply.cnid; - dbd_rebuild_add(dbd_rebuild, &rqst, &rply); + ret = dbd_rebuild_add(dbd_rebuild, &rqst, &rply); + if (dbif_txn_close(dbd_rebuild, ret) != 0) + return -1; if (rply.result != CNID_DBD_RES_OK) { - dbd_log( LOGDEBUG, "Fatal error adding CNID: %u for '%s/%s' to in-memory rebuild-db", + dbd_log( LOGSTD, "Fatal error adding CNID: %u for '%s/%s' to in-memory rebuild-db", cnid, cwdbuf, ep->d_name); - longjmp(jmp, 1); /* this jumps back to cmd_dbd_scanvol() */ + return -1; + } + count++; + if (count == 10000) { + if (dbif_txn_checkpoint(dbd_rebuild, 0, 0, 0) < 0) { + dbd_log(LOGSTD, "Error checkpointing!"); + return -1; + } + count = 0; } } } @@ -980,7 +952,7 @@ static int dbd_readdir(int volroot, cnid_t did) close(cwd); *(strrchr(cwdbuf, '/')) = 0; if (ret < 0) - continue; + return -1; } } @@ -994,18 +966,14 @@ static int dbd_readdir(int volroot, cnid_t did) static int scanvol(struct volinfo *vi, dbd_flags_t flags) { - /* Dont scanvol on no-appledouble vols */ - if (vi->v_flags & AFPVOL_NOADOUBLE) { - dbd_log( LOGSTD, "Volume without AppleDouble support: skipping volume scanning."); - return 0; - } - /* Make this stuff accessible from all funcs easily */ myvolinfo = vi; dbd_flags = flags; - /* Init a fake struct vol with just enough so we can call ea_open and friends */ - volume.v_adouble = AD_VERSION2; + /* Init a fake struct vol so that we can call ad_init(.., &volume) and initvol_vfs(&volume) */ + volume.v_adouble = vi->v_adouble; + volume.v_ad_options = vi->v_flags; + volume.ad_path = vi->ad_path; volume.v_vfs_ea = myvolinfo->v_vfs_ea; initvol_vfs(&volume); @@ -1030,7 +998,7 @@ static int scanvol(struct volinfo *vi, dbd_flags_t flags) */ static void delete_orphaned_cnids(DBD *dbd, DBD *dbd_rebuild, dbd_flags_t flags) { - int ret, deleted = 0; + int ret = 0, deleted = 0; cnid_t dbd_cnid = 0, rebuild_cnid = 0; struct cnid_dbd_rqst rqst; struct cnid_dbd_rply rply; @@ -1051,7 +1019,7 @@ static void delete_orphaned_cnids(DBD *dbd, DBD *dbd_rebuild, dbd_flags_t flags) if (alarmed) longjmp(jmp, 1); /* this jumps back to cmd_dbd_scanvol() */ - if (deleted > 50) { + if (deleted > 1000) { deleted = 0; if (dbif_txn_checkpoint(dbd, 0, 0, 0) < 0) { dbd_log(LOGSTD, "Error checkpointing!"); @@ -1077,7 +1045,8 @@ static void delete_orphaned_cnids(DBD *dbd, DBD *dbd_rebuild, dbd_flags_t flags) goto cleanup; } - dbif_txn_close(dbd, ret); + if (dbif_txn_close(dbd, ret) != 0) + return; deleted++; } /* Check if we got a termination signal */ @@ -1100,19 +1069,21 @@ static void delete_orphaned_cnids(DBD *dbd, DBD *dbd_rebuild, dbd_flags_t flags) (void)dbif_txn_abort(dbd); goto cleanup; } - dbif_txn_close(dbd, ret); + if (dbif_txn_close(dbd, ret) != 0) + return; deleted++; } continue; } if (dbd_cnid > rebuild_cnid) { + dbif_idwalk(dbd, NULL, 1); /* Close cursor */ + dbif_idwalk(dbd_rebuild, NULL, 1); /* Close cursor */ + (void)dbif_txn_close(dbd, 2); + (void)dbif_txn_close(dbd_rebuild, 2); dbd_log(LOGSTD, "Ghost CNID: %u. This is fatal! Dumping rebuild db:\n", rebuild_cnid); dbif_dump(dbd_rebuild, 0); dbd_log(LOGSTD, "Send this dump and a `dbd -d ...` dump to the Netatalk Dev team!"); - dbif_txn_close(dbd, ret); - dbif_idwalk(dbd, NULL, 1); /* Close cursor */ - dbif_idwalk(dbd_rebuild, NULL, 1); /* Close cursor */ goto cleanup; } } /* while ((dbif_idwalk(dbd, &dbd_cnid, 0)) == 1) */ @@ -1123,6 +1094,16 @@ cleanup: return; } +static const char *get_tmpdb_path(void) +{ + pid_t pid = getpid(); + static char path[MAXPATHLEN]; + snprintf(path, MAXPATHLEN, "/tmp/tmpdb-dbd.%u", pid); + if (mkdir(path, 0755) != 0) + return NULL; + return path; +} + /* Main func called from cmd_dbd.c */ @@ -1130,9 +1111,13 @@ int cmd_dbd_scanvol(DBD *dbd_ref, struct volinfo *vi, dbd_flags_t flags) { int ret = 0; struct db_param db_param = { 0 }; + const char *tmpdb_path = NULL; /* Set cachesize for in-memory rebuild db */ - db_param.cachesize = 128 * 1024 * 1024; /* 128 MB */ + db_param.cachesize = 64 * 1024; /* 64 MB */ + db_param.maxlocks = DEFAULT_MAXLOCKS; + db_param.maxlockobjs = DEFAULT_MAXLOCKOBJS; + db_param.logfile_autoremove = 1; /* Make it accessible for all funcs */ dbd = dbd_ref; @@ -1143,38 +1128,76 @@ int cmd_dbd_scanvol(DBD *dbd_ref, struct volinfo *vi, dbd_flags_t flags) return -1; } - if (! nocniddb) { - /* Get volume stamp */ - dbd_getstamp(dbd, &rqst, &rply); - if (rply.result != CNID_DBD_RES_OK) - goto exit_cleanup; - memcpy(stamp, rply.name, CNID_DEV_LEN); - - /* open/create rebuild dbd, copy rootinfo key */ - if (NULL == (dbd_rebuild = dbif_init(NULL, NULL))) - return -1; - if (0 != (dbif_open(dbd_rebuild, &db_param, 0))) - return -1; - if (0 != (dbif_copy_rootinfokey(dbd, dbd_rebuild))) - goto exit_cleanup; + /* Get volume stamp */ + dbd_getstamp(dbd, &rqst, &rply); + if (rply.result != CNID_DBD_RES_OK) { + ret = -1; + goto exit; + } + memcpy(stamp, rply.name, CNID_DEV_LEN); + + /* temporary rebuild db, used with -re rebuild to delete unused CNIDs, not used with -f */ + if (! nocniddb && (flags & DBD_FLAGS_EXCL) && !(flags & DBD_FLAGS_FORCE)) { + tmpdb_path = get_tmpdb_path(); + if (NULL == (dbd_rebuild = dbif_init(tmpdb_path, "cnid2.db"))) { + ret = -1; + goto exit; + } + + if (dbif_env_open(dbd_rebuild, + &db_param, + DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN) < 0) { + dbd_log(LOGSTD, "error opening tmp database!"); + goto exit; + } + + if (0 != (dbif_open(dbd_rebuild, NULL, 0))) { + ret = -1; + goto exit; + } + + if (0 != (dbif_copy_rootinfokey(dbd, dbd_rebuild))) { + ret = -1; + goto exit; + } } - if (setjmp(jmp) != 0) - goto exit_cleanup; /* Got signal, jump from dbd_readdir */ + if (setjmp(jmp) != 0) { + ret = 0; /* Got signal, jump from dbd_readdir */ + goto exit; + } /* scanvol */ - if ( (scanvol(vi, flags)) != 0) - return -1; + if ( (scanvol(vi, flags)) != 0) { + ret = -1; + goto exit; + } +exit: if (! nocniddb) { - /* We can only do this in exclusive mode, otherwise we might delete CNIDs added from - other clients in between our pass 1 and 2 */ - if (flags & DBD_FLAGS_EXCL) + if (dbif_txn_close(dbd, ret == 0 ? 1 : 0) != 0) + ret = -1; + if (dbd_rebuild) + if (dbif_txn_close(dbd_rebuild, ret == 0 ? 1 : 0) != 0) + ret = -1; + if ((ret == 0) && dbd_rebuild && (flags & DBD_FLAGS_EXCL) && !(flags & DBD_FLAGS_FORCE)) + /* We can only do this in exclusive mode, otherwise we might delete CNIDs added from + other clients in between our pass 1 and 2 */ delete_orphaned_cnids(dbd, dbd_rebuild, flags); } -exit_cleanup: - if (! nocniddb) + if (dbd_rebuild) { + dbd_log(LOGDEBUG, "Closing tmp db"); dbif_close(dbd_rebuild); + + if (tmpdb_path) { + char cmd[8 + MAXPATHLEN]; + snprintf(cmd, 8 + MAXPATHLEN, "rm -f %s/*", tmpdb_path); + dbd_log( LOGDEBUG, "Removing temp database '%s'", tmpdb_path); + system(cmd); + snprintf(cmd, 8 + MAXPATHLEN, "rmdir %s", tmpdb_path); + system(cmd); + } + } return ret; }