2 Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
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.
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.
17 #endif /* HAVE_CONFIG_H */
21 #include <sys/types.h>
29 #include <atalk/adouble.h>
30 #include <atalk/unicode.h>
31 #include <atalk/netatalk_conf.h>
32 //#include <atalk/cnid_dbd_private.h>
33 #include <atalk/volume.h>
35 #include <atalk/util.h>
36 #include <atalk/acl.h>
37 #include <atalk/compat.h>
38 #include <atalk/cnid.h>
45 /* Some defines to ease code parsing */
46 #define ADDIR_OK (addir_ok == 0)
47 #define ADFILE_OK (adfile_ok == 0)
50 static struct vol *myvol;
51 static char cwdbuf[MAXPATHLEN+1];
52 static struct vol *vol;
53 static DBD *dbd_rebuild;
54 static dbd_flags_t dbd_flags;
55 static char stamp[CNID_DEV_LEN];
56 static char *netatalk_dirs[] = {
61 static char *special_dirs[] = {
65 static struct cnid_dbd_rqst rqst;
66 static struct cnid_dbd_rply rply;
68 static char pname[MAXPATHLEN] = "../";
69 static char cnidResBuf[12 + MAXPATHLEN + 1];
72 Taken form afpd/desktop.c
74 static char *utompath(char *upath)
76 static char mpath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
78 uint16_t flags = CONV_IGNORE | CONV_UNESCAPEHEX;
86 outlen = strlen(upath);
88 if ((myvol->v_casefold & AFPVOL_UTOMUPPER))
89 flags |= CONV_TOUPPER;
90 else if ((myvol->v_casefold & AFPVOL_UTOMLOWER))
91 flags |= CONV_TOLOWER;
93 if ((myvol->v_flags & AFPVOL_EILSEQ)) {
94 flags |= CONV__EILSEQ;
97 /* convert charsets */
98 if ((size_t)-1 == ( outlen = convert_charset(myvol->v_volcharset,
101 u, outlen, mpath, MAXPATHLEN, &flags)) ) {
102 dbd_log( LOGSTD, "Conversion from %s to %s for %s failed.",
103 myvol->v_volcodepage, myvol->v_maccodepage, u);
111 Taken form afpd/desktop.c
113 static char *mtoupath(char *mpath)
115 static char upath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
124 if ( *mpath == '\0' ) {
128 /* set conversion flags */
129 if ((myvol->v_casefold & AFPVOL_MTOUUPPER))
130 flags |= CONV_TOUPPER;
131 else if ((myvol->v_casefold & AFPVOL_MTOULOWER))
132 flags |= CONV_TOLOWER;
134 if ((myvol->v_flags & AFPVOL_EILSEQ)) {
135 flags |= CONV__EILSEQ;
144 if ((size_t)-1 == (outlen = convert_charset(CH_UTF8_MAC,
147 m, inplen, u, outlen, &flags)) ) {
148 dbd_log( LOGSTD, "conversion from UTF8-MAC to %s for %s failed.",
149 myvol->v_volcodepage, mpath);
157 Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop"
158 Returns pointer to name or NULL.
160 static const char *check_netatalk_dirs(const char *name)
164 for (c=0; netatalk_dirs[c]; c++) {
165 if ((strcmp(name, netatalk_dirs[c])) == 0)
166 return netatalk_dirs[c];
172 Check for special names
173 Returns pointer to name or NULL.
175 static const char *check_special_dirs(const char *name)
179 for (c=0; special_dirs[c]; c++) {
180 if ((strcmp(name, special_dirs[c])) == 0)
181 return special_dirs[c];
187 * We unCAPed a name, update CNID db
189 static int update_cnid(cnid_t did, const struct stat *sp, const char *oldname, const char *newname)
194 /* Query the database */
195 if ((id = cnid_lookup(vol->v_cdb, sp, did, (char *)oldname, strlen(oldname))) == CNID_INVALID)
196 /* not in db, no need to update */
199 /* Update the database */
200 if (cnid_update(vol->v_cdb, id, sp, did, (char *)newname, strlen(newname)) < 0)
207 Check for .AppleDouble file, create if missing
209 static int check_adfile(const char *fname, const struct stat *st, const char **newname)
212 int adflags = ADFLAGS_HF;
218 if (myvol->v_adouble == AD_VERSION_EA) {
219 if (!(dbd_flags & DBD_FLAGS_V2TOEA))
221 if (ad_convert(fname, st, myvol, newname) != 0) {
226 dbd_log(LOGSTD, "Conversion error for \"%s/%s\": %s", cwdbuf, fname, strerror(errno));
233 if (S_ISDIR(st->st_mode))
234 adflags |= ADFLAGS_DIR;
236 adname = myvol->ad_path(fname, adflags);
238 if ((ret = access( adname, F_OK)) != 0) {
239 if (errno != ENOENT) {
240 dbd_log(LOGSTD, "Access error for ad-file '%s/%s': %s",
241 cwdbuf, adname, strerror(errno));
244 /* Missing. Log and create it */
245 dbd_log(LOGSTD, "Missing AppleDouble file '%s/%s'", cwdbuf, adname);
247 if (dbd_flags & DBD_FLAGS_SCAN)
248 /* Scan only requested, dont change anything */
254 if ((ret = ad_open(&ad, fname, adflags | ADFLAGS_CREATE | ADFLAGS_RDWR, 0666)) != 0) {
255 dbd_log( LOGSTD, "Error creating AppleDouble file '%s/%s': %s",
256 cwdbuf, adname, strerror(errno));
261 /* Set name in ad-file */
262 ad_setname(&ad, utompath((char *)fname));
264 ad_close(&ad, ADFLAGS_HF);
266 chown(adname, st->st_uid, st->st_gid);
267 /* FIXME: should we inherit mode too here ? */
269 chmod(adname, st->st_mode);
273 if (ad_open(&ad, fname, adflags | ADFLAGS_RDONLY) != 0) {
274 dbd_log( LOGSTD, "Error opening AppleDouble file for '%s/%s'", cwdbuf, fname);
277 ad_close(&ad, ADFLAGS_HF);
283 Remove all files with file::EA* from adouble dir
285 static void remove_eafiles(const char *name, struct ea *ea)
289 char eaname[MAXPATHLEN];
291 strlcpy(eaname, name, sizeof(eaname));
292 if (strlcat(eaname, "::EA", sizeof(eaname)) >= sizeof(eaname)) {
293 dbd_log(LOGSTD, "name too long: '%s/%s/%s'", cwdbuf, ADv2_DIRNAME, name);
297 if ((chdir(ADv2_DIRNAME)) != 0) {
298 dbd_log(LOGSTD, "Couldn't chdir to '%s/%s': %s",
299 cwdbuf, ADv2_DIRNAME, strerror(errno));
303 if ((dp = opendir(".")) == NULL) {
304 dbd_log(LOGSTD, "Couldn't open the directory '%s/%s': %s",
305 cwdbuf, ADv2_DIRNAME, strerror(errno));
309 while ((ep = readdir(dp))) {
310 if (strstr(ep->d_name, eaname) != NULL) {
311 dbd_log(LOGSTD, "Removing EA file: '%s/%s/%s'",
312 cwdbuf, ADv2_DIRNAME, ep->d_name);
313 if ((unlink(ep->d_name)) != 0) {
314 dbd_log(LOGSTD, "Error unlinking EA file '%s/%s/%s': %s",
315 cwdbuf, ADv2_DIRNAME, ep->d_name, strerror(errno));
323 if ((chdir("..")) != 0) {
324 dbd_log(LOGSTD, "Couldn't chdir to '%s': %s", cwdbuf, strerror(errno));
325 /* we can't proceed */
326 longjmp(jmp, 1); /* this jumps back to cmd_dbd_scanvol() */
331 Check Extended Attributes files
333 static int check_eafiles(const char *fname)
335 unsigned int count = 0;
341 if ((ret = ea_open(myvol, fname, EA_RDWR, &ea)) != 0) {
344 dbd_log(LOGSTD, "Error calling ea_open for file: %s/%s, removing EA files", cwdbuf, fname);
345 if ( ! (dbd_flags & DBD_FLAGS_SCAN))
346 remove_eafiles(fname, &ea);
351 while (count < ea.ea_count) {
352 dbd_log(LOGDEBUG, "EA: %s", (*ea.ea_entries)[count].ea_name);
355 eaname = ea_path(&ea, (*ea.ea_entries)[count].ea_name, 0);
357 if (lstat(eaname, &st) != 0) {
359 dbd_log(LOGSTD, "Missing EA: %s/%s", cwdbuf, eaname);
361 dbd_log(LOGSTD, "Bogus EA: %s/%s", cwdbuf, eaname);
363 } else if (st.st_size != (*ea.ea_entries)[count].ea_size) {
364 dbd_log(LOGSTD, "Bogus EA: %s/%s, removing it...", cwdbuf, eaname);
366 if ((unlink(eaname)) != 0)
367 dbd_log(LOGSTD, "Error removing EA file '%s/%s': %s",
368 cwdbuf, eaname, strerror(errno));
372 /* Be CAREFUL here! This should do what ea_delentry does. ea_close relies on it !*/
373 free((*ea.ea_entries)[count].ea_name);
374 (*ea.ea_entries)[count].ea_name = NULL;
385 Check for .AppleDouble folder and .Parent, create if missing
387 static int check_addir(int volroot)
389 int addir_ok, adpar_ok;
394 if (myvol->v_adouble == AD_VERSION_EA)
397 /* Check for ad-dir */
398 if ( (addir_ok = access(ADv2_DIRNAME, F_OK)) != 0) {
399 if (errno != ENOENT) {
400 dbd_log(LOGSTD, "Access error in directory %s: %s", cwdbuf, strerror(errno));
403 dbd_log(LOGSTD, "Missing %s for '%s'", ADv2_DIRNAME, cwdbuf);
406 /* Check for ".Parent" */
407 if ( (adpar_ok = access(myvol->ad_path(".", ADFLAGS_DIR), F_OK)) != 0) {
408 if (errno != ENOENT) {
409 dbd_log(LOGSTD, "Access error on '%s/%s': %s",
410 cwdbuf, myvol->ad_path(".", ADFLAGS_DIR), strerror(errno));
413 dbd_log(LOGSTD, "Missing .AppleDouble/.Parent for '%s'", cwdbuf);
416 /* Is one missing ? */
417 if ((addir_ok != 0) || (adpar_ok != 0)) {
418 /* Yes, but are we only scanning ? */
419 if (dbd_flags & DBD_FLAGS_SCAN) {
420 /* Yes: missing .Parent is not a problem, but missing ad-dir
421 causes later checking of ad-files to fail. So we have to return appropiately */
424 else /* (adpar_ok != 0) */
428 /* Create ad dir and set name */
431 if (ad_open(&ad, ".", ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_CREATE | ADFLAGS_RDWR, 0777) != 0) {
432 dbd_log( LOGSTD, "Error creating AppleDouble dir in %s: %s", cwdbuf, strerror(errno));
436 /* Get basename of cwd from cwdbuf */
437 mname = utompath(strrchr(cwdbuf, '/') + 1);
439 /* Update name in ad file */
440 ad_setname(&ad, mname);
442 ad_close(&ad, ADFLAGS_HF);
444 /* Inherit owner/group from "." to ".AppleDouble" and ".Parent" */
445 if ((lstat(".", &st)) != 0) {
446 dbd_log( LOGSTD, "Couldnt stat %s: %s", cwdbuf, strerror(errno));
449 chown(ADv2_DIRNAME, st.st_uid, st.st_gid);
450 chown(myvol->ad_path(".", ADFLAGS_DIR), st.st_uid, st.st_gid);
457 Check if file cotains "::EA" and if it does check if its correspondig data fork exists.
459 0 = name is not an EA file
460 1 = name is an EA file and no problem was found
461 -1 = name is an EA file and data fork is gone
463 static int check_eafile_in_adouble(const char *name)
466 char *namep, *namedup = NULL;
468 /* Check if this is an AFPVOL_EA_AD vol */
469 if (myvol->v_vfs_ea == AFPVOL_EA_AD) {
470 /* Does the filename contain "::EA" ? */
471 namedup = strdup(name);
472 if ((namep = strstr(namedup, "::EA")) == NULL) {
476 /* File contains "::EA" so it's an EA file. Check for data file */
478 /* Get string before "::EA" from EA filename */
480 strlcpy(pname + 3, namedup, sizeof(pname)); /* Prepends "../" */
482 if ((access( pname, F_OK)) == 0) {
487 if (errno != ENOENT) {
488 dbd_log(LOGSTD, "Access error for file '%s/%s': %s",
489 cwdbuf, name, strerror(errno));
493 /* Orphaned EA file*/
494 dbd_log(LOGSTD, "Orphaned Extended Attribute file '%s/%s/%s'",
495 cwdbuf, ADv2_DIRNAME, name);
497 if (dbd_flags & DBD_FLAGS_SCAN)
498 /* Scan only requested, dont change anything */
501 if ((unlink(name)) != 0) {
502 dbd_log(LOGSTD, "Error unlinking orphaned Extended Attribute file '%s/%s/%s'",
503 cwdbuf, ADv2_DIRNAME, name);
507 } /* if AFPVOL_EA_AD */
517 Check files and dirs inside .AppleDouble folder:
518 - remove orphaned files
521 static int read_addir(void)
527 if ((chdir(ADv2_DIRNAME)) != 0) {
528 if (myvol->v_adouble == AD_VERSION_EA) {
531 dbd_log(LOGSTD, "Couldn't chdir to '%s/%s': %s",
532 cwdbuf, ADv2_DIRNAME, strerror(errno));
536 if ((dp = opendir(".")) == NULL) {
537 dbd_log(LOGSTD, "Couldn't open the directory '%s/%s': %s",
538 cwdbuf, ADv2_DIRNAME, strerror(errno));
542 while ((ep = readdir(dp))) {
543 /* Check if its "." or ".." */
544 if (DIR_DOT_OR_DOTDOT(ep->d_name))
548 if (STRCMP(ep->d_name, ==, ".Parent"))
551 if ((lstat(ep->d_name, &st)) < 0) {
552 dbd_log( LOGSTD, "Lost file or dir while enumeratin dir '%s/%s/%s', probably removed: %s",
553 cwdbuf, ADv2_DIRNAME, ep->d_name, strerror(errno));
558 if (S_ISDIR(st.st_mode)) {
559 dbd_log( LOGSTD, "Unexpected directory '%s' in AppleDouble dir '%s/%s'",
560 ep->d_name, cwdbuf, ADv2_DIRNAME);
564 /* Check if for orphaned and corrupt Extended Attributes file */
565 if (check_eafile_in_adouble(ep->d_name) != 0)
568 /* Check for data file */
569 strcpy(pname + 3, ep->d_name);
570 if ((access( pname, F_OK)) != 0) {
571 if (errno != ENOENT) {
572 dbd_log(LOGSTD, "Access error for file '%s/%s': %s",
573 cwdbuf, pname, strerror(errno));
576 /* Orphaned ad-file*/
577 dbd_log(LOGSTD, "Orphaned AppleDoube file '%s/%s/%s'",
578 cwdbuf, ADv2_DIRNAME, ep->d_name);
580 if (dbd_flags & DBD_FLAGS_SCAN)
581 /* Scan only requested, dont change anything */
584 if ((unlink(ep->d_name)) != 0) {
585 dbd_log(LOGSTD, "Error unlinking orphaned AppleDoube file '%s/%s/%s'",
586 cwdbuf, ADv2_DIRNAME, ep->d_name);
592 if ((chdir("..")) != 0) {
593 dbd_log(LOGSTD, "Couldn't chdir back to '%s' from AppleDouble dir: %s",
594 cwdbuf, strerror(errno));
595 /* This really is EOT! */
596 longjmp(jmp, 1); /* this jumps back to cmd_dbd_scanvol() */
605 Check CNID for a file/dir, both from db and from ad-file.
606 For detailed specs see intro.
608 @return Correct CNID of object or CNID_INVALID (ie 0) on error
610 static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfile_ok)
612 int ret, adflags = ADFLAGS_HF;
613 cnid_t db_cnid, ad_cnid, tmpid;
616 adflags = ADFLAGS_HF | (S_ISDIR(st->st_mode) ? ADFLAGS_DIR : 0);
618 /* Get CNID from ad-file */
619 ad_cnid = CNID_INVALID;
622 if (ad_open(&ad, name, adflags | ADFLAGS_RDWR) != 0) {
624 if (myvol->v_adouble != AD_VERSION_EA) {
625 dbd_log( LOGSTD, "Error opening AppleDouble file for '%s/%s': %s", cwdbuf, name, strerror(errno));
628 dbd_log( LOGDEBUG, "File without meta EA: \"%s/%s\"", cwdbuf, name);
631 ad_cnid = ad_getid(&ad, st->st_dev, st->st_ino, 0, stamp);
632 if (ad_cnid == CNID_INVALID)
633 dbd_log( LOGSTD, "Bad CNID in adouble file of '%s/%s'", cwdbuf, name);
635 dbd_log( LOGDEBUG, "CNID from .AppleDouble file for '%s/%s': %u", cwdbuf, name, ntohl(ad_cnid));
636 ad_close(&ad, ADFLAGS_HF);
640 /* Get CNID from database */
641 if ((db_cnid = cnid_add(vol->v_cdb, st, did, (char *)name, strlen(name), ad_cnid)) == CNID_INVALID)
644 /* Compare CNID from db and adouble file */
645 if (ad_cnid != db_cnid && adfile_ok == 0) {
646 /* Mismatch, overwrite ad file with value from db */
647 dbd_log(LOGSTD, "CNID mismatch for '%s/%s', CNID db: %u, ad-file: %u",
648 cwdbuf, name, ntohl(db_cnid), ntohl(ad_cnid));
650 if (ad_open(&ad, name, adflags | ADFLAGS_HF | ADFLAGS_RDWR) != 0) {
651 dbd_log(LOGSTD, "Error opening AppleDouble file for '%s/%s': %s",
652 cwdbuf, name, strerror(errno));
655 ad_setid( &ad, st->st_dev, st->st_ino, db_cnid, did, stamp);
657 ad_close(&ad, ADFLAGS_HF);
664 This is called recursively for all dirs.
665 volroot=1 means we're in the volume root dir, 0 means we aren't.
666 We use this when checking for netatalk private folders like .AppleDB.
667 did is our parents CNID.
669 static int dbd_readdir(int volroot, cnid_t did)
671 int cwd, ret = 0, adfile_ok, addir_ok, encoding_ok;
676 static struct stat st; /* Save some stack space */
678 /* Check again for .AppleDouble folder, check_adfile also checks/creates it */
679 if ((addir_ok = check_addir(volroot)) != 0)
680 if ( ! (dbd_flags & DBD_FLAGS_SCAN))
681 /* Fatal on rebuild run, continue if only scanning ! */
684 /* Check AppleDouble files in AppleDouble folder, but only if it exists or could be created */
686 if ((read_addir()) != 0)
687 if ( ! (dbd_flags & DBD_FLAGS_SCAN))
688 /* Fatal on rebuild run, continue if only scanning ! */
691 if ((dp = opendir (".")) == NULL) {
692 dbd_log(LOGSTD, "Couldn't open the directory: %s",strerror(errno));
696 while ((ep = readdir (dp))) {
697 /* Check if we got a termination signal */
699 longjmp(jmp, 1); /* this jumps back to cmd_dbd_scanvol() */
701 /* Check if its "." or ".." */
702 if (DIR_DOT_OR_DOTDOT(ep->d_name))
705 /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
706 if ((name = check_netatalk_dirs(ep->d_name)) != NULL) {
708 dbd_log(LOGSTD, "Nested %s in %s", name, cwdbuf);
712 /* Check for special folders in volume root e.g. ".zfs" */
714 if ((name = check_special_dirs(ep->d_name)) != NULL) {
715 dbd_log(LOGSTD, "Ignoring special dir \"%s\"", name);
720 /* Skip .AppleDouble dir in this loop */
721 if (STRCMP(ep->d_name, == , ADv2_DIRNAME))
724 if (!myvol->vfs->vfs_validupath(myvol, ep->d_name)) {
725 dbd_log(LOGDEBUG, "Ignoring \"%s\"", ep->d_name);
729 if ((ret = lstat(ep->d_name, &st)) < 0) {
730 dbd_log( LOGSTD, "Lost file while reading dir '%s/%s', probably removed: %s",
731 cwdbuf, ep->d_name, strerror(errno));
735 switch (st.st_mode & S_IFMT) {
740 dbd_log(LOGDEBUG, "Ignoring symlink %s/%s", cwdbuf, ep->d_name);
743 dbd_log(LOGSTD, "Bad filetype: %s/%s", cwdbuf, ep->d_name);
744 if ( ! (dbd_flags & DBD_FLAGS_SCAN)) {
745 if ((unlink(ep->d_name)) != 0) {
746 dbd_log(LOGSTD, "Error removing: %s/%s: %s", cwdbuf, ep->d_name, strerror(errno));
752 /**************************************************************************
754 **************************************************************************/
755 static unsigned long long statcount = 0;
762 if ((statcount % 10000) == 0) {
763 if (dbd_flags & DBD_FLAGS_STATS)
764 dbd_log(LOGSTD, "Scanned: %10llu, time: %10llu s",
765 statcount, (unsigned long long)(time(NULL) - t));
768 /**************************************************************************
770 **************************************************************************/
772 /* Check for appledouble file, create if missing, but only if we have addir */
773 const char *name = NULL;
776 adfile_ok = check_adfile(ep->d_name, &st, &name);
781 update_cnid(did, &st, ep->d_name, name);
785 cnid = check_cnid(name, did, &st, adfile_ok);
787 /* Now add this object to our rebuild dbd */
788 if (cnid && dbd_rebuild) {
789 static uint count = 0;
790 rqst.cnid = rply.cnid;
791 ret = dbd_rebuild_add(dbd_rebuild, &rqst, &rply);
792 if (dbif_txn_close(dbd_rebuild, ret) != 0)
794 if (rply.result != CNID_DBD_RES_OK) {
795 dbd_log( LOGSTD, "Fatal error adding CNID: %u for '%s/%s' to in-memory rebuild-db",
800 if (count == 10000) {
801 if (dbif_txn_checkpoint(dbd_rebuild, 0, 0, 0) < 0) {
802 dbd_log(LOGSTD, "Error checkpointing!");
810 if (myvol->v_vfs_ea == AFPVOL_EA_AD)
813 /**************************************************************************
815 **************************************************************************/
816 if (S_ISDIR(st.st_mode) && cnid) { /* If we have no cnid for it we cant enter recursion */
818 strcat(cwdbuf, name);
819 dbd_log( LOGDEBUG, "Entering directory: %s", cwdbuf);
820 if (-1 == (cwd = open(".", O_RDONLY))) {
821 dbd_log( LOGSTD, "Cant open directory '%s': %s", cwdbuf, strerror(errno));
824 if (0 != chdir(name)) {
825 dbd_log( LOGSTD, "Cant chdir to directory '%s': %s", cwdbuf, strerror(errno));
830 ret = dbd_readdir(0, cnid);
834 *(strrchr(cwdbuf, '/')) = 0;
841 Use results of previous checks
843 if ((myvol->v_adouble == AD_VERSION_EA) && (dbd_flags & DBD_FLAGS_V2TOEA)) {
844 if (rmdir(ADv2_DIRNAME) != 0) {
849 dbd_log(LOGSTD, "Error removing adouble dir \"%s/%s\": %s", cwdbuf, ADv2_DIRNAME, strerror(errno));
858 static int scanvol(struct vol *vol, dbd_flags_t flags)
862 /* Make this stuff accessible from all funcs easily */
866 /* Run with umask 0 */
869 strcpy(cwdbuf, myvol->v_path);
870 chdir(myvol->v_path);
872 if ((myvol->v_adouble == AD_VERSION_EA) && (dbd_flags & DBD_FLAGS_V2TOEA)) {
873 if (lstat(".", &st) != 0)
875 if (ad_convert(".", &st, vol, NULL) != 0) {
880 dbd_log(LOGSTD, "Conversion error for \"%s\": %s", myvol->v_path, strerror(errno));
886 /* Start recursion */
887 if (dbd_readdir(1, htonl(2)) < 0) /* 2 = volumeroot CNID */
894 Main func called from cmd_dbd.c
896 int cmd_dbd_scanvol(struct vol *vol_in, dbd_flags_t flags)
900 /* Make vol accessible for all funcs */
903 /* We only support unicode volumes ! */
904 if (vol->v_volcharset != CH_UTF8) {
905 dbd_log(LOGSTD, "Not a Unicode volume: %s, %u != %u", vol->v_volcodepage, vol->v_volcharset, CH_UTF8);
910 * Get CNID database stamp, cnid_getstamp() passes the buffer,
911 * then cnid_resolve() actually gets the value from the db
913 cnid_getstamp(vol->v_cdb, stamp, sizeof(stamp));
915 if (setjmp(jmp) != 0) {
916 ret = 0; /* Got signal, jump from dbd_readdir */
921 if ((scanvol(vol, flags)) != 0) {