X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=etc%2Fcnid_dbd%2Fcmd_dbd_scanvol.c;h=dcbd4c74779161acb4be4f3b3feda12bc6bec771;hb=b668f73bf257e8a088f901e5212e000039273ea2;hp=90293a48a0d1b8a25639d3f9fd32dff90103e4f1;hpb=38e94665946a785acecab92ae88f15585ecd546e;p=netatalk.git diff --git a/etc/cnid_dbd/cmd_dbd_scanvol.c b/etc/cnid_dbd/cmd_dbd_scanvol.c index 90293a48..dcbd4c74 100644 --- a/etc/cnid_dbd/cmd_dbd_scanvol.c +++ b/etc/cnid_dbd/cmd_dbd_scanvol.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include #include @@ -46,7 +46,7 @@ #define ADFILE_OK (adfile_ok == 0) -static struct volinfo *myvolinfo; +static struct vol *myvol; static char cwdbuf[MAXPATHLEN+1]; static DBD *dbd; static DBD *dbd_rebuild; @@ -64,7 +64,6 @@ static char *special_dirs[] = { static struct cnid_dbd_rqst rqst; static struct cnid_dbd_rply rply; static jmp_buf jmp; -static struct vol volume; /* fake it for ea_open */ static char pname[MAXPATHLEN] = "../"; /* @@ -84,22 +83,22 @@ static char *utompath(char *upath) u = upath; outlen = strlen(upath); - if ((myvolinfo->v_casefold & AFPVOL_UTOMUPPER)) + if ((myvol->v_casefold & AFPVOL_UTOMUPPER)) flags |= CONV_TOUPPER; - else if ((myvolinfo->v_casefold & AFPVOL_UTOMLOWER)) + else if ((myvol->v_casefold & AFPVOL_UTOMLOWER)) flags |= CONV_TOLOWER; - if ((myvolinfo->v_flags & AFPVOL_EILSEQ)) { + if ((myvol->v_flags & AFPVOL_EILSEQ)) { flags |= CONV__EILSEQ; } /* convert charsets */ - if ((size_t)-1 == ( outlen = convert_charset(myvolinfo->v_volcharset, + if ((size_t)-1 == ( outlen = convert_charset(myvol->v_volcharset, CH_UTF8_MAC, - myvolinfo->v_maccharset, + myvol->v_maccharset, u, outlen, mpath, MAXPATHLEN, &flags)) ) { dbd_log( LOGSTD, "Conversion from %s to %s for %s failed.", - myvolinfo->v_volcodepage, myvolinfo->v_maccodepage, u); + myvol->v_volcodepage, myvol->v_maccodepage, u); return NULL; } @@ -125,17 +124,12 @@ static char *mtoupath(char *mpath) } /* set conversion flags */ - if (!(myvolinfo->v_flags & AFPVOL_NOHEX)) - flags |= CONV_ESCAPEHEX; - if (!(myvolinfo->v_flags & AFPVOL_USEDOTS)) - flags |= CONV_ESCAPEDOTS; - - if ((myvolinfo->v_casefold & AFPVOL_MTOUUPPER)) + if ((myvol->v_casefold & AFPVOL_MTOUUPPER)) flags |= CONV_TOUPPER; - else if ((myvolinfo->v_casefold & AFPVOL_MTOULOWER)) + else if ((myvol->v_casefold & AFPVOL_MTOULOWER)) flags |= CONV_TOLOWER; - if ((myvolinfo->v_flags & AFPVOL_EILSEQ)) { + if ((myvol->v_flags & AFPVOL_EILSEQ)) { flags |= CONV__EILSEQ; } @@ -146,39 +140,17 @@ static char *mtoupath(char *mpath) outlen = MAXPATHLEN; if ((size_t)-1 == (outlen = convert_charset(CH_UTF8_MAC, - myvolinfo->v_volcharset, - myvolinfo->v_maccharset, + myvol->v_volcharset, + myvol->v_maccharset, m, inplen, u, outlen, &flags)) ) { dbd_log( LOGSTD, "conversion from UTF8-MAC to %s for %s failed.", - myvolinfo->v_volcodepage, mpath); + myvol->v_volcodepage, mpath); return NULL; } return( upath ); } -/* - 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. -*/ -static int check_name_encoding(char *uname) -{ - char *roundtripped; - - roundtripped = mtoupath(utompath(uname)); - if (!roundtripped) { - dbd_log( LOGSTD, "Error checking encoding for '%s/%s'", cwdbuf, uname); - return -1; - } - - if ( STRCMP(uname, !=, roundtripped)) { - dbd_log( LOGSTD, "Bad encoding for '%s/%s'", cwdbuf, uname); - return -1; - } - - return 0; -} - /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" Returns pointer to name or NULL. @@ -209,26 +181,90 @@ static const char *check_special_dirs(const char *name) return NULL; } +/* + * We unCAPed a name, update CNID db + */ +static int update_cnid(cnid_t did, const struct stat *sp, const char *oldname, const char *newname) +{ + int ret; + cnid_t id; + + /* Prepare request data */ + memset(&rqst, 0, sizeof(struct cnid_dbd_rqst)); + memset(&rply, 0, sizeof(struct cnid_dbd_rply)); + rqst.did = did; + rqst.cnid = 0; + if ( ! (myvol->v_flags & AFPVOL_NODEV)) + rqst.dev = sp->st_dev; + rqst.ino = sp->st_ino; + rqst.type = S_ISDIR(sp->st_mode) ? 1 : 0; + rqst.name = (char *)oldname; + rqst.namelen = strlen(oldname); + + /* Query the database */ + ret = dbd_lookup(dbd, &rqst, &rply, (dbd_flags & DBD_FLAGS_SCAN) ? 1 : 0); + if (dbif_txn_close(dbd, ret) != 0) + return -1; + if (rply.result != CNID_DBD_RES_OK) + return 0; + id = rply.cnid; + + /* Prepare request data */ + memset(&rqst, 0, sizeof(struct cnid_dbd_rqst)); + memset(&rply, 0, sizeof(struct cnid_dbd_rply)); + rqst.did = did; + rqst.cnid = id; + if ( ! (myvol->v_flags & AFPVOL_NODEV)) + rqst.dev = sp->st_dev; + rqst.ino = sp->st_ino; + rqst.type = S_ISDIR(sp->st_mode) ? 1 : 0; + rqst.name = (char *)newname; + rqst.namelen = strlen(newname); + + /* Update the database */ + ret = dbd_update(dbd, &rqst, &rply); + if (dbif_txn_close(dbd, ret) != 0) + return -1; + if (rply.result != CNID_DBD_RES_OK) + return -1; + + return 0; +} + /* Check for .AppleDouble file, create if missing */ -static int check_adfile(const char *fname, const struct stat *st) +static int check_adfile(const char *fname, const struct stat *st, const char **newname) { int ret; int adflags = ADFLAGS_HF; struct adouble ad; const char *adname; - if (volume.v_adouble == AD_VERSION_EA) - return 0; + *newname = NULL; + if (myvol->v_adouble == AD_VERSION_EA) { + if (!(dbd_flags & DBD_FLAGS_V2TOEA)) + return 0; + if (ad_convert(fname, st, myvol, newname) != 0) { + switch (errno) { + case ENOENT: + break; + default: + dbd_log(LOGSTD, "Conversion error for \"%s/%s\": %s", cwdbuf, fname, strerror(errno)); + break; + } + } + return 0; + } + if (dbd_flags & DBD_FLAGS_CLEANUP) return 0; - if (S_ISREG(st->st_mode)) + if (S_ISDIR(st->st_mode)) adflags |= ADFLAGS_DIR; - adname = volume.ad_path(fname, adflags); + adname = myvol->ad_path(fname, adflags); if ((ret = access( adname, F_OK)) != 0) { if (errno != ENOENT) { @@ -244,7 +280,7 @@ static int check_adfile(const char *fname, const struct stat *st) return -1; /* Create ad file */ - ad_init(&ad, &volume); + ad_init(&ad, myvol); if ((ret = ad_open(&ad, fname, adflags | ADFLAGS_CREATE | ADFLAGS_RDWR, 0666)) != 0) { dbd_log( LOGSTD, "Error creating AppleDouble file '%s/%s': %s", @@ -264,7 +300,7 @@ static int check_adfile(const char *fname, const struct stat *st) chmod(adname, st->st_mode); #endif } else { - ad_init(&ad, &volume); + ad_init(&ad, myvol); if (ad_open(&ad, fname, adflags | ADFLAGS_RDONLY) != 0) { dbd_log( LOGSTD, "Error opening AppleDouble file for '%s/%s'", cwdbuf, fname); return -1; @@ -333,7 +369,7 @@ static int check_eafiles(const char *fname) struct stat st; char *eaname; - if ((ret = ea_open(&volume, fname, EA_RDWR, &ea)) != 0) { + if ((ret = ea_open(myvol, fname, EA_RDWR, &ea)) != 0) { if (errno == ENOENT) return 0; dbd_log(LOGSTD, "Error calling ea_open for file: %s/%s, removing EA files", cwdbuf, fname); @@ -389,7 +425,7 @@ static int check_addir(int volroot) if (dbd_flags & DBD_FLAGS_CLEANUP) return 0; - if (volume.v_adouble == AD_VERSION_EA) + if (myvol->v_adouble == AD_VERSION_EA) return 0; /* Check for ad-dir */ @@ -402,10 +438,10 @@ static int check_addir(int volroot) } /* Check for ".Parent" */ - if ( (adpar_ok = access(volume.ad_path(".", ADFLAGS_DIR), F_OK)) != 0) { + if ( (adpar_ok = access(myvol->ad_path(".", ADFLAGS_DIR), F_OK)) != 0) { if (errno != ENOENT) { dbd_log(LOGSTD, "Access error on '%s/%s': %s", - cwdbuf, volume.ad_path(".", ADFLAGS_DIR), strerror(errno)); + cwdbuf, myvol->ad_path(".", ADFLAGS_DIR), strerror(errno)); return -1; } dbd_log(LOGSTD, "Missing .AppleDouble/.Parent for '%s'", cwdbuf); @@ -424,7 +460,7 @@ static int check_addir(int volroot) } /* Create ad dir and set name */ - ad_init(&ad, &volume); + ad_init(&ad, myvol); 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)); @@ -445,7 +481,7 @@ static int check_addir(int volroot) return -1; } chown(ADv2_DIRNAME, st.st_uid, st.st_gid); - chown(volume.ad_path(".", ADFLAGS_DIR), st.st_uid, st.st_gid); + chown(myvol->ad_path(".", ADFLAGS_DIR), st.st_uid, st.st_gid); } return 0; @@ -464,7 +500,7 @@ static int check_eafile_in_adouble(const char *name) char *namep, *namedup = NULL; /* Check if this is an AFPVOL_EA_AD vol */ - if (myvolinfo->v_vfs_ea == AFPVOL_EA_AD) { + if (myvol->v_vfs_ea == AFPVOL_EA_AD) { /* Does the filename contain "::EA" ? */ namedup = strdup(name); if ((namep = strstr(namedup, "::EA")) == NULL) { @@ -522,10 +558,10 @@ 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) { + if (myvol->v_adouble == AD_VERSION_EA) { + return 0; + } dbd_log(LOGSTD, "Couldn't chdir to '%s/%s': %s", cwdbuf, ADv2_DIRNAME, strerror(errno)); return -1; @@ -627,13 +663,13 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi /* Get CNID from ad-file */ ad_cnid = 0; if (ADFILE_OK) { - ad_init(&ad, &volume); + ad_init(&ad, myvol); if (ad_open(&ad, name, adflags | ADFLAGS_RDWR) != 0) { if (dbd_flags & DBD_FLAGS_CLEANUP) return CNID_INVALID; - if (volume.v_adouble != AD_VERSION_EA) { + if (myvol->v_adouble != AD_VERSION_EA) { dbd_log( LOGSTD, "Error opening AppleDouble file for '%s/%s': %s", cwdbuf, name, strerror(errno)); return CNID_INVALID; } @@ -664,7 +700,7 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi memset(&rply, 0, sizeof(struct cnid_dbd_rply)); rqst.did = did; rqst.cnid = ad_cnid; - if ( ! (myvolinfo->v_flags & AFPVOL_NODEV)) + if ( ! (myvol->v_flags & AFPVOL_NODEV)) rqst.dev = st->st_dev; rqst.ino = st->st_ino; rqst.type = S_ISDIR(st->st_mode)?1:0; @@ -696,7 +732,7 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi if ( ! (dbd_flags & DBD_FLAGS_SCAN)) { dbd_log(LOGSTD, "Updating AppleDouble file for '%s/%s' with CNID: %u from database", cwdbuf, name, ntohl(db_cnid)); - ad_init(&ad, &volume); + ad_init(&ad, myvol); 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)); @@ -727,7 +763,7 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi 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); + ad_init(&ad, myvol); if (ad_open(&ad, name, adflags | ADFLAGS_RDWR) != 0) { dbd_log(LOGSTD, "Error opening AppleDouble file for '%s/%s': %s", cwdbuf, name, strerror(errno)); @@ -766,7 +802,7 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi 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); + ad_init(&ad, myvol); if (ad_open(&ad, name, adflags | ADFLAGS_RDWR) != 0) { dbd_log(LOGSTD, "Error opening AppleDouble file for '%s/%s': %s", cwdbuf, name, strerror(errno)); @@ -804,7 +840,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 (volume.v_adouble == AD_VERSION2 && ADDIR_OK) + if (ADDIR_OK) if ((read_addir()) != 0) if ( ! (dbd_flags & DBD_FLAGS_SCAN)) /* Fatal on rebuild run, continue if only scanning ! */ @@ -843,6 +879,11 @@ static int dbd_readdir(int volroot, cnid_t did) if (STRCMP(ep->d_name, == , ADv2_DIRNAME)) continue; + if (!myvol->vfs->vfs_validupath(myvol, ep->d_name)) { + dbd_log(LOGDEBUG, "Ignoring \"%s\"", ep->d_name); + continue; + } + if ((ret = lstat(ep->d_name, &st)) < 0) { dbd_log( LOGSTD, "Lost file while reading dir '%s/%s', probably removed: %s", cwdbuf, ep->d_name, strerror(errno)); @@ -886,21 +927,21 @@ static int dbd_readdir(int volroot, cnid_t did) Tests **************************************************************************/ - /* Check encoding */ - if ( -1 == (encoding_ok = check_name_encoding(ep->d_name)) ) { - /* If its a file: skipp all other tests now ! */ - /* For dirs we could try to get a CNID for it and recurse, but currently I prefer not to */ - continue; - } - /* Check for appledouble file, create if missing, but only if we have addir */ + const char *name = NULL; adfile_ok = -1; if (ADDIR_OK) - adfile_ok = check_adfile(ep->d_name, &st); + adfile_ok = check_adfile(ep->d_name, &st, &name); + + if (name == NULL) { + name = ep->d_name; + } else { + update_cnid(did, &st, ep->d_name, name); + } if ( ! nocniddb) { /* Check CNIDs */ - cnid = check_cnid(ep->d_name, did, &st, adfile_ok); + cnid = check_cnid(name, did, &st, adfile_ok); /* Now add this object to our rebuild dbd */ if (cnid && dbd_rebuild) { @@ -911,7 +952,7 @@ static int dbd_readdir(int volroot, cnid_t did) return -1; if (rply.result != CNID_DBD_RES_OK) { dbd_log( LOGSTD, "Fatal error adding CNID: %u for '%s/%s' to in-memory rebuild-db", - cnid, cwdbuf, ep->d_name); + cnid, cwdbuf, name); return -1; } count++; @@ -926,21 +967,21 @@ static int dbd_readdir(int volroot, cnid_t did) } /* Check EA files */ - if (myvolinfo->v_vfs_ea == AFPVOL_EA_AD) - check_eafiles(ep->d_name); + if (myvol->v_vfs_ea == AFPVOL_EA_AD) + check_eafiles(name); /************************************************************************** Recursion **************************************************************************/ if (S_ISDIR(st.st_mode) && (cnid || nocniddb)) { /* If we have no cnid for it we cant recur */ strcat(cwdbuf, "/"); - strcat(cwdbuf, ep->d_name); + strcat(cwdbuf, name); dbd_log( LOGDEBUG, "Entering directory: %s", cwdbuf); if (-1 == (cwd = open(".", O_RDONLY))) { dbd_log( LOGSTD, "Cant open directory '%s': %s", cwdbuf, strerror(errno)); continue; } - if (0 != chdir(ep->d_name)) { + if (0 != chdir(name)) { dbd_log( LOGSTD, "Cant chdir to directory '%s': %s", cwdbuf, strerror(errno)); close(cwd); continue; @@ -959,32 +1000,48 @@ static int dbd_readdir(int volroot, cnid_t did) /* Use results of previous checks */ - + if ((myvol->v_adouble == AD_VERSION_EA) && (dbd_flags & DBD_FLAGS_V2TOEA)) { + if (rmdir(ADv2_DIRNAME) != 0) { + switch (errno) { + case ENOENT: + break; + default: + dbd_log(LOGSTD, "Error removing adouble dir \"%s/%s\": %s", cwdbuf, ADv2_DIRNAME, strerror(errno)); + break; + } + } + } closedir(dp); return ret; } -static int scanvol(struct volinfo *vi, dbd_flags_t flags) +static int scanvol(struct vol *vol, dbd_flags_t flags) { + struct stat st; + /* Make this stuff accessible from all funcs easily */ - myvolinfo = vi; + myvol = vol; dbd_flags = flags; - /* 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); - /* Run with umask 0 */ umask(0); - /* Remove trailing slash from volume, chdir to vol */ - if (myvolinfo->v_path[strlen(myvolinfo->v_path) - 1] == '/') - myvolinfo->v_path[strlen(myvolinfo->v_path) - 1] = 0; - strcpy(cwdbuf, myvolinfo->v_path); - chdir(myvolinfo->v_path); + strcpy(cwdbuf, myvol->v_path); + chdir(myvol->v_path); + + if ((myvol->v_adouble == AD_VERSION_EA) && (dbd_flags & DBD_FLAGS_V2TOEA)) { + if (lstat(".", &st) != 0) + return -1; + if (ad_convert(".", &st, vol, NULL) != 0) { + switch (errno) { + case ENOENT: + break; + default: + dbd_log(LOGSTD, "Conversion error for \"%s\": %s", myvol->v_path, strerror(errno)); + break; + } + } + } /* Start recursion */ if (dbd_readdir(1, htonl(2)) < 0) /* 2 = volumeroot CNID */ @@ -1107,7 +1164,7 @@ static const char *get_tmpdb_path(void) /* Main func called from cmd_dbd.c */ -int cmd_dbd_scanvol(DBD *dbd_ref, struct volinfo *vi, dbd_flags_t flags) +int cmd_dbd_scanvol(DBD *dbd_ref, struct vol *vol, dbd_flags_t flags) { int ret = 0; struct db_param db_param = { 0 }; @@ -1123,8 +1180,8 @@ int cmd_dbd_scanvol(DBD *dbd_ref, struct volinfo *vi, dbd_flags_t flags) dbd = dbd_ref; /* We only support unicode volumes ! */ - if ( vi->v_volcharset != CH_UTF8) { - dbd_log( LOGSTD, "Not a Unicode volume: %s, %u != %u", vi->v_volcodepage, vi->v_volcharset, CH_UTF8); + if (vol->v_volcharset != CH_UTF8) { + dbd_log( LOGSTD, "Not a Unicode volume: %s, %u != %u", vol->v_volcodepage, vol->v_volcharset, CH_UTF8); return -1; } @@ -1168,7 +1225,7 @@ int cmd_dbd_scanvol(DBD *dbd_ref, struct volinfo *vi, dbd_flags_t flags) } /* scanvol */ - if ( (scanvol(vi, flags)) != 0) { + if ((scanvol(vol, flags)) != 0) { ret = -1; goto exit; }