X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libatalk%2Fadouble%2Fad_open.c;h=72250de8034caca1cacf9422870e0ad2ee0f87a6;hb=61e09782a5bec443fbc26a7c311a9801860a0866;hp=d3a4c6b3ace9e8a246a1b43e0e7591af28bbb0a4;hpb=18b886e36518cc7c8d570857131e1c8bdc116952;p=netatalk.git diff --git a/libatalk/adouble/ad_open.c b/libatalk/adouble/ad_open.c index d3a4c6b3..72250de8 100644 --- a/libatalk/adouble/ad_open.c +++ b/libatalk/adouble/ad_open.c @@ -82,10 +82,11 @@ #define ADEDOFF_RFORK_V2 (ADEDOFF_PRIVID + ADEDLEN_PRIVID) /* ad:ea */ -#define ADEDOFF_FINDERI_EA (AD_HEADER_LEN + ADEID_NUM_EA * AD_ENTRY_LEN) -#define ADEDOFF_COMMENT_EA (ADEDOFF_FINDERI_EA + ADEDLEN_FINDERI) +#define ADEDOFF_FINDERI_EA (AD_HEADER_LEN + ADEID_NUM_EA * AD_ENTRY_LEN) +#define ADEDOFF_COMMENT_EA (ADEDOFF_FINDERI_EA + ADEDLEN_FINDERI) #define ADEDOFF_FILEDATESI_EA (ADEDOFF_COMMENT_EA + ADEDLEN_COMMENT) -#define ADEDOFF_AFPFILEI_EA (ADEDOFF_FILEDATESI_EA + ADEDLEN_FILEDATESI) +#define ADEDOFF_AFPFILEI_EA (ADEDOFF_FILEDATESI_EA + ADEDLEN_FILEDATESI) +#define ADEDOFF_PRIVID_EA (ADEDOFF_AFPFILEI_EA + ADEDLEN_AFPFILEI) /* this is to prevent changing timezones from causing problems with localtime volumes. the screw-up is 30 years. we use a delta of 5 years */ @@ -106,9 +107,7 @@ static int ad_header_upgrade(struct adouble *ad, const char *name); static int ad_mkrf_ea(const char *path); static int ad_header_read_ea(const char *path, struct adouble *ad, struct stat *hst); static int ad_header_upgrade_ea(struct adouble *ad, const char *name); - - -static const char *ad_path_osx(const char *path, int adflags); +static int ad_reso_size(const char *path, int adflags, struct adouble *ad); static int ad_mkrf_osx(const char *path); @@ -164,7 +163,7 @@ static const struct entry entry_order_ea[ADEID_NUM_EA + 1] = { {ADEID_COMMENT, ADEDOFF_COMMENT_EA, ADEDLEN_INIT}, {ADEID_FILEDATESI, ADEDOFF_FILEDATESI_EA, ADEDLEN_FILEDATESI}, {ADEID_AFPFILEI, ADEDOFF_AFPFILEI_EA, ADEDLEN_AFPFILEI}, - {ADEID_PRIVID, ADEDOFF_PRIVID, ADEDLEN_INIT}, + {ADEID_PRIVID, ADEDOFF_PRIVID_EA, ADEDLEN_INIT}, {0, 0, 0} }; @@ -193,6 +192,12 @@ const char *adflags2logstr(int adflags) strlcat(buf, "RF", ADFLAGS2LOGSTRBUFSIZ); first = 0; } + if (adflags & ADFLAGS_NORF) { + if (!first) + strlcat(buf, "|", ADFLAGS2LOGSTRBUFSIZ); + strlcat(buf, "NORF", ADFLAGS2LOGSTRBUFSIZ); + first = 0; + } if (adflags & ADFLAGS_HF) { if (!first) strlcat(buf, "|", ADFLAGS2LOGSTRBUFSIZ); @@ -217,6 +222,12 @@ const char *adflags2logstr(int adflags) strlcat(buf, "OF", ADFLAGS2LOGSTRBUFSIZ); first = 0; } + if (adflags & ADFLAGS_SETSHRMD) { + if (!first) + strlcat(buf, "|", ADFLAGS2LOGSTRBUFSIZ); + strlcat(buf, "SHRMD", ADFLAGS2LOGSTRBUFSIZ); + first = 0; + } if (adflags & ADFLAGS_RDWR) { if (!first) strlcat(buf, "|", ADFLAGS2LOGSTRBUFSIZ); @@ -288,7 +299,6 @@ static int new_ad_header(struct adouble *ad, const char *path, struct stat *stp, ad->ad_version = AD_VERSION; } - memset(ad->ad_data, 0, sizeof(ad->ad_data)); if (ad->ad_vers == AD_VERSION2) @@ -320,7 +330,10 @@ static int new_ad_header(struct adouble *ad, const char *path, struct stat *stp, } /* make things invisible */ - if ((ad->ad_options & ADVOL_INVDOTS) && (*path == '.')) { + if ((ad->ad_options & ADVOL_INVDOTS) + && (*path == '.') + && !((adflags & ADFLAGS_DIR) && (path[1] == 0)) + ) { ashort = htons(ATTRBIT_INVISIBLE); ad_setattr(ad, ashort); ashort = htons(FINDERINFO_INVISIBLE); @@ -528,18 +541,11 @@ static int ad_header_read_ea(const char *path, struct adouble *ad, struct stat * ssize_t header_len; char *buf = ad->ad_data; - /* read the header */ - if ((ad_meta_fileno(ad) == -1) - && (ad->ad_adflags & ADFLAGS_RDWR)) { - LOG(log_error, logtype_default, "ad_header_read_ea: need filedescriptor for rw access"); - return -1; - } - if (ad_meta_fileno(ad) != -1) header_len = sys_fgetxattr(ad_meta_fileno(ad), AD_EA_META, ad->ad_data, AD_DATASZ_EA); else header_len = sys_lgetxattr(path, AD_EA_META, ad->ad_data, AD_DATASZ_EA); - if (header_len < 1) { + if (header_len < 1) { LOG(log_debug, logtype_default, "ad_header_read_ea: %s", strerror(errno)); return -1; } @@ -685,7 +691,6 @@ static int ad_error(struct adouble *ad, int adflags) { int err = errno; if (adflags & ADFLAGS_NOHF) { /* 1 */ - ad->ad_adflags &= ~ADFLAGS_HF; return 0; } if (adflags & ADFLAGS_DF) { /* 2 */ @@ -853,7 +858,7 @@ static int ad_open_hf_v2(const char *path, int adflags, mode_t mode, struct adou if ((ad->ad_options & ADVOL_UNIXPRIV)) admode = mode; admode = ad_hf_mode(admode); - if ((errno == ENOENT) && (ad->ad_vers != AD_VERSION2_OSX)) { + if (errno == ENOENT) { if (ad->ad_ops->ad_mkrf( ad_p) < 0) { return ad_error(ad, adflags); } @@ -917,87 +922,97 @@ static int ad_open_hf_v2(const char *path, int adflags, mode_t mode, struct adou return 0; } -/* TODO: error handling */ static int ad_open_hf_ea(const char *path, int adflags, int mode, struct adouble *ad) { + EC_INIT; ssize_t rforklen; int oflags; + int opened = 0; - LOG(log_debug, logtype_default, "ad_open_hf_ea(\"%s\", %s, %04o)", - path, adflags2logstr(adflags), mode); + LOG(log_debug, logtype_default, + "ad_open_hf_ea(\"%s\", %s): BEGIN [dfd: %d (ref: %d), mfd: %d (ref: %d), rfd: %d (ref: %d)]", + fullpathname(path), adflags2logstr(adflags), + ad_data_fileno(ad), ad->ad_data_fork.adf_refcount, + ad_meta_fileno(ad), ad->ad_mdp->adf_refcount, + ad_reso_fileno(ad), ad->ad_rfp->adf_refcount); oflags = O_NOFOLLOW | (ad2openflags(adflags) & ~(O_CREAT | O_TRUNC)); + if (ad_meta_fileno(ad) == -2) + /* symlink */ + EC_EXIT; + if (ad_meta_fileno(ad) != -1) { /* the file is already open, but we want write access: */ - if ((adflags & ADFLAGS_RDWR) && + if ((oflags & O_RDWR) && /* and it was already denied: */ (ad->ad_mdp->adf_flags & O_RDONLY)) { LOG(log_error, logtype_default, "ad_open_hf_ea(%s): rw request for ro file: %s", fullpathname(path), strerror(errno)); errno = EACCES; - return -1; + EC_FAIL; } /* it's not new anymore */ ad->ad_mdp->adf_flags &= ~( O_TRUNC | O_CREAT ); - ad->ad_mdp->adf_refcount++; } else { - if (adflags & ADFLAGS_RDWR) { + if (oflags & O_RDWR) { /* Fo a RDONLY adouble we just use sys_lgetxattr instead if sys_fgetxattr */ - LOG(log_debug, logtype_default, "ad_open_hf_ea(\"%s\"): opening for base file for meta adouble EA", path); - if ((ad_meta_fileno(ad) = open(path, oflags)) == -1) - goto error; + if (adflags & ADFLAGS_DIR) + /* For directories we open the directory RDONYL so we can later fchdir() */ + oflags = (oflags & ~O_RDWR) | O_RDONLY; + LOG(log_debug, logtype_default, "ad_open_hf_ea(\"%s\"): opening base file for meta adouble EA", path); + EC_NEG1_LOG(ad_meta_fileno(ad) = open(path, oflags)); + opened = 1; ad->ad_mdp->adf_flags = oflags; } - ad->ad_mdp->adf_refcount = 1; } /* Read the adouble header in and parse it.*/ if (ad->ad_ops->ad_header_read(path, ad, NULL) != 0) { - LOG(log_error, logtype_default, "ad_open_hf_ea: no EA adouble"); - - if (!(adflags & ADFLAGS_CREATE)) - goto error; + if (!(adflags & ADFLAGS_CREATE)) { + LOG(log_error, logtype_default, "ad_open_hf_ea(\"%s\"): can't read metadata EA", path); + errno = ENOENT; + EC_FAIL; + } LOG(log_debug, logtype_default, "ad_open_hf_ea(\"%s\"): creating metadata EA", path); /* It doesnt exist, EPERM or another error */ if (!(errno == ENOATTR || errno == ENOENT)) { LOG(log_error, logtype_default, "ad_open_hf_ea: unexpected: %s", strerror(errno)); - goto error; + EC_FAIL; } /* Create one */ - if (new_ad_header(ad, path, NULL, adflags) < 0) { - LOG(log_error, logtype_default, "ad_open_hf_ea: can't create new header: %s", - fullpathname(path)); - goto error; - } + EC_NEG1_LOG(new_ad_header(ad, path, NULL, adflags)); ad->ad_mdp->adf_flags |= O_CREAT; /* mark as just created */ ad_flush(ad); LOG(log_debug, logtype_default, "ad_open_hf_ea(\"%s\"): created metadata EA", path); } - /* TODO: ad_rlen calculation */ - ad->ad_rlen = 0; - - return 0; + ad->ad_mdp->adf_refcount++; + (void)ad_reso_size(path, adflags, ad); -error: - if (ad_meta_fileno(ad) != -1) { +EC_CLEANUP: + if (ret != 0 && opened && ad_meta_fileno(ad) != -1) { close(ad_meta_fileno(ad)); ad_meta_fileno(ad) = -1; ad->ad_mdp->adf_refcount = 0; } - return ad_error(ad, adflags); + LOG(log_debug, logtype_default, + "ad_open_hf_ea(\"%s\", %s): END: %d [dfd: %d (ref: %d), mfd: %d (ref: %d), rfd: %d (ref: %d)]", + fullpathname(path), adflags2logstr(adflags), ret, + ad_data_fileno(ad), ad->ad_data_fork.adf_refcount, + ad_meta_fileno(ad), ad->ad_mdp->adf_refcount, + ad_reso_fileno(ad), ad->ad_rfp->adf_refcount); + + EC_EXIT; } static int ad_open_hf(const char *path, int adflags, int mode, struct adouble *ad) { int ret = 0; - LOG(log_debug, logtype_default, "ad_open_hf(\"%s\", %04o)", path, mode); - memset(ad->ad_eid, 0, sizeof( ad->ad_eid )); ad->ad_rlen = 0; @@ -1013,12 +1028,52 @@ static int ad_open_hf(const char *path, int adflags, int mode, struct adouble *a break; } - if (ret != 0) { - return ad_error(ad, adflags); - } + if (ret != 0) + ret = ad_error(ad, adflags); + return ret; } +/*! + * Get resofork length for adouble:ea + */ +static int ad_reso_size(const char *path, int adflags, struct adouble *ad) +{ + EC_INIT; + struct stat st; + + LOG(log_debug, logtype_default, "ad_reso_size(\"%s\")", path); + +#ifdef HAVE_EAFD + ssize_t easz; + + if (ad_reso_fileno(ad) != -1) { + EC_NEG1( fstat(ad_reso_fileno(ad), &st) ); + ad->ad_rlen = st.st_size; + } else if (ad_meta_fileno(ad) != -1) { + EC_NEG1( easz = sys_fgetxattr(ad_meta_fileno(ad), AD_EA_RESO, NULL, 0) ); + ad->ad_rlen = easz; + } else { + EC_FAIL; + } + +#else + const char *rfpath; + EC_NULL_LOG( rfpath = ad->ad_ops->ad_path(path, adflags)); + EC_ZERO( lstat(rfpath, &st)); + if (st.st_size > ADEDOFF_RFORK_OSX) + ad->ad_rlen = st.st_size - ADEDOFF_RFORK_OSX; + else + ad->ad_rlen = 0; +#endif + + LOG(log_debug, logtype_default, "ad_reso_size(\"%s\"): size: %zd", path, ad->ad_rlen); + +EC_CLEANUP: + if (ret != 0) + ad->ad_rlen = 0; + EC_EXIT; +} /*! * Open ressource fork @@ -1030,6 +1085,7 @@ static int ad_open_rf(const char *path, int adflags, int mode, struct adouble *a { EC_INIT; int oflags; + int opened = 0; int closeflags = adflags & (ADFLAGS_DF | ADFLAGS_HF); ssize_t rlen; #ifndef HAVE_EAFD @@ -1040,28 +1096,34 @@ static int ad_open_rf(const char *path, int adflags, int mode, struct adouble *a if (ad->ad_vers != AD_VERSION_EA) return 0; - LOG(log_debug, logtype_default, "ad_open_rf(\"%s\", %04o)", path, mode); + LOG(log_debug, logtype_default, "ad_open_rf(\"%s\"): BEGIN", fullpathname(path)); oflags = O_NOFOLLOW | (ad2openflags(adflags) & ~O_CREAT); if (ad_reso_fileno(ad) != -1) { /* the file is already open, but we want write access: */ - if ((adflags & ADFLAGS_RDWR) + if ((oflags & O_RDWR) /* and it was already denied: */ && (ad->ad_rfp->adf_flags & O_RDONLY)) { errno = EACCES; - return -1; + EC_FAIL; } ad->ad_rfp->adf_flags &= ~( O_TRUNC | O_CREAT ); ad->ad_rfp->adf_refcount++; - return 0; + EC_NEG1_LOG( ad_reso_size(path, adflags, ad)); + goto EC_CLEANUP; } #ifdef HAVE_EAFD - if ((ad_reso_fileno(ad) = sys_getxattrfd(path, oflags)) == -1) { - if (!(adflags & ADFLAGS_CREATE)) + if (ad_meta_fileno(ad) == -1) + EC_FAIL; + if ((ad_reso_fileno(ad) = sys_getxattrfd(ad_meta_fileno(ad), AD_EA_RESO, oflags)) == -1) { + if (!(adflags & ADFLAGS_CREATE)) { + errno = ENOENT; EC_FAIL; + } oflags |= O_CREAT; - EC_NEG1_LOG( ad_reso_fileno(ad) = sys_getxattrfd(path, oflags, 0666) ); + EC_NEG1_LOG( ad_reso_fileno(ad) = sys_getxattrfd(ad_meta_fileno(ad), + AD_EA_RESO, oflags, 0666) ); } #else EC_NULL_LOG( rfpath = ad->ad_ops->ad_path(path, adflags) ); @@ -1074,7 +1136,7 @@ static int ad_open_rf(const char *path, int adflags, int mode, struct adouble *a path, rfpath); } #endif - + opened = 1; ad->ad_rfp->adf_refcount = 1; ad->ad_rfp->adf_flags = oflags; @@ -1084,7 +1146,6 @@ static int ad_open_rf(const char *path, int adflags, int mode, struct adouble *a /* This is a new adouble header file, create it */ LOG(log_debug, logtype_default, "ad_open_rf(\"%s\"): created adouble rfork, initializing: \"%s\"", path, rfpath); -// EC_NEG1_LOG( new_ad_header(ad, rfpath, &st, adflags) ); LOG(log_debug, logtype_default, "ad_open_rf(\"%s\"): created adouble rfork, flushing: \"%s\"", path, rfpath); ad_flush(ad); @@ -1096,20 +1157,26 @@ static int ad_open_rf(const char *path, int adflags, int mode, struct adouble *a } #endif + (void)ad_reso_size(path, adflags, ad); + EC_CLEANUP: if (ret != 0) { - if (ad_reso_fileno(ad) != -1) { + if (opened && (ad_reso_fileno(ad) != -1)) { close(ad_reso_fileno(ad)); ad_reso_fileno(ad) = -1; ad->ad_rfp->adf_refcount = 0; } - int err = errno; - (void)ad_close(ad, closeflags); - errno = err; + if (adflags & ADFLAGS_NORF) { + ret = 0; + } else { + int err = errno; + (void)ad_close(ad, closeflags); + errno = err; + } ad->ad_rlen = 0; } - LOG(log_debug, logtype_default, "ad_open_rf(\"%s\"): END", path); + LOG(log_debug, logtype_default, "ad_open_rf(\"%s\"): END: %d", fullpathname(path), ret); EC_EXIT; } @@ -1359,7 +1426,8 @@ void ad_init(struct adouble *ad, const struct vol * restrict vol) * ADFLAGS_DF: open data fork * ADFLAGS_RF: open ressource fork * ADFLAGS_HF: open header (metadata) file - * ADFLAGS_NOHF: it's not an error if header file couldn't be created + * ADFLAGS_NOHF: it's not an error if header file couldn't be opened + * ADFLAGS_NORF: it's not an error if reso fork couldn't be opened * ADFLAGS_DIR: if path is a directory you MUST or ADFLAGS_DIR to adflags * * Access mode for the forks: @@ -1388,16 +1456,22 @@ int ad_open(struct adouble *ad, const char *path, int adflags, ...) va_list args; mode_t mode = 0; - LOG(log_debug, logtype_default, "ad_open(\"%s\", %s)", - fullpathname(path), adflags2logstr(adflags)); + LOG(log_debug, logtype_default, + "ad_open(\"%s\", %s): BEGIN [dfd: %d (ref: %d), mfd: %d (ref: %d), rfd: %d (ref: %d)]", + fullpathname(path), adflags2logstr(adflags), + ad_data_fileno(ad), ad->ad_data_fork.adf_refcount, + ad_meta_fileno(ad), ad->ad_mdp->adf_refcount, + ad_reso_fileno(ad), ad->ad_rfp->adf_refcount); if (adflags & ADFLAGS_CHECK_OF) /* Checking for open forks requires sharemode lock support (ie RDWR instead of RDONLY) */ adflags |= ADFLAGS_SETSHRMD; - if ((ad->ad_vers == AD_VERSION_EA) && (adflags & ADFLAGS_SETSHRMD)) - /* adouble:ea sets sharemode locks on the datafork */ - adflags |= ADFLAGS_DF; + if ((ad->ad_vers == AD_VERSION2) && (adflags & ADFLAGS_RF)) { + adflags |= ADFLAGS_HF; + if (adflags & ADFLAGS_NORF) + adflags |= ADFLAGS_NOHF; + } if (ad->ad_inited != AD_INITED) { ad->ad_adflags = adflags; @@ -1415,17 +1489,14 @@ int ad_open(struct adouble *ad, const char *path, int adflags, ...) if (adflags & ADFLAGS_DF) { EC_ZERO( ad_open_df(path, adflags, mode, ad) ); - ad->ad_adflags |= ADFLAGS_DF; } if (adflags & ADFLAGS_HF) { EC_ZERO( ad_open_hf(path, adflags, mode, ad) ); - ad->ad_adflags |= ADFLAGS_HF; } if (adflags & ADFLAGS_RF) { EC_ZERO( ad_open_rf(path, adflags, mode, ad) ); - ad->ad_adflags |= ADFLAGS_RF; } if (adflags & ADFLAGS_CHECK_OF) { @@ -1433,7 +1504,14 @@ int ad_open(struct adouble *ad, const char *path, int adflags, ...) } EC_CLEANUP: - return ret; + LOG(log_debug, logtype_default, + "ad_open(\"%s\"): END: %d [dfd: %d (ref: %d), mfd: %d (ref: %d), rfd: %d (ref: %d)]", + fullpathname(path), ret, + ad_data_fileno(ad), ad->ad_data_fork.adf_refcount, + ad_meta_fileno(ad), ad->ad_mdp->adf_refcount, + ad_reso_fileno(ad), ad->ad_rfp->adf_refcount); + + EC_EXIT; } /*! @@ -1496,6 +1574,7 @@ int ad_metadataat(int dirfd, const char *name, int flags, struct adouble *adp) } if (dirfd != -1) { + if (fchdir(cwdfd) != 0) { LOG(log_error, logtype_afpd, "ad_openat: cant chdir back, exiting"); exit(EXITERR_SYS); @@ -1529,10 +1608,10 @@ int ad_refresh(const char *path, struct adouble *ad) if (AD_RSRC_OPEN(ad)) { if (ad_reso_fileno(ad) == -1) return -1; - ssize_t len; - if ((len = fstat(ad_reso_fileno(ad))) == -1) + struct stat st; + if (fstat(ad_reso_fileno(ad), &st) == -1) return -1; - ad->ad_rlen = len; + ad->ad_rlen = st.st_size; } #else if (AD_META_OPEN(ad)) {