From 40ec781c1ddb2686c589e4184bc08fa266f28b40 Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Fri, 8 Mar 2013 18:29:13 +0100 Subject: [PATCH] File's ressource fork can't be read if metadata EA is missing Fixes bug #501. --- NEWS | 4 +++- etc/afpd/file.c | 28 ++++++++++++++++--------- include/atalk/adouble.h | 1 + libatalk/adouble/ad_open.c | 43 +++++++++++++++++++------------------- 4 files changed, 43 insertions(+), 33 deletions(-) diff --git a/NEWS b/NEWS index 8a628754..ba0c0cc7 100644 --- a/NEWS +++ b/NEWS @@ -25,7 +25,9 @@ Changes in 3.0.3 probes. * UPD: Reload groups when reloading volumes. FR #71. * FIX: Attempt to read read-only ._ rfork results in disconnect. - Fixes bugs #502. + Fixes bug #502. +* FIX: File's ressource fork can't be read if metadata EA is missing. + Fixes bug #501. Changes in 3.0.2 ================ diff --git a/etc/afpd/file.c b/etc/afpd/file.c index bd516087..be1fafe5 100644 --- a/etc/afpd/file.c +++ b/etc/afpd/file.c @@ -459,18 +459,23 @@ int getmetadata(const AFPObj *obj, data += sizeof( aint ); break; - case FILPBIT_RFLEN : - if ( adp ) { + case FILPBIT_RFLEN: { + off_t rlen; + if (adp) { if (adp->ad_rlen > 0xffffffff) aint = 0xffffffff; else aint = htonl( adp->ad_rlen); } else { - aint = 0; + rlen = ad_reso_size(path->u_name, 0, NULL); + if (rlen > 0xffffffff) + rlen = 0xffffffff; + aint = htonl(rlen); } memcpy(data, &aint, sizeof( aint )); data += sizeof( aint ); break; + } /* Current client needs ProDOS info block for this file. Use simple heuristic and let the Mac "type" string tell @@ -538,15 +543,18 @@ int getmetadata(const AFPObj *obj, data += sizeof( aint ); break; case FILPBIT_EXTRFLEN: - aint = 0; - if (adp) + if (adp) { aint = htonl(adp->ad_rlen >> 32); - memcpy(data, &aint, sizeof( aint )); - data += sizeof( aint ); - if (adp) + memcpy(data, &aint, sizeof( aint )); + data += sizeof( aint ); aint = htonl(adp->ad_rlen); - memcpy(data, &aint, sizeof( aint )); - data += sizeof( aint ); + memcpy(data, &aint, sizeof( aint )); + data += sizeof( aint ); + } else { + int64_t rlen = hton64(ad_reso_size(path->u_name, 0, NULL)); + memcpy(data, &rlen, sizeof(rlen)); + data += sizeof(rlen); + } break; case FILPBIT_UNIXPR : /* accessmode may change st_mode with ACLs */ diff --git a/include/atalk/adouble.h b/include/atalk/adouble.h index 6e76e51b..fd870876 100644 --- a/include/atalk/adouble.h +++ b/include/atalk/adouble.h @@ -409,6 +409,7 @@ extern int ad_metadata (const char *, int, struct adouble *); extern int ad_metadataat (int, const char *, int, struct adouble *); extern mode_t ad_hf_mode(mode_t mode); extern int ad_valid_header_osx(const char *path); +extern off_t ad_reso_size(const char *path, int adflags, struct adouble *ad); /* ad_conv.c */ extern int ad_convert(const char *path, const struct stat *sp, const struct vol *vol, const char **newpath); diff --git a/libatalk/adouble/ad_open.c b/libatalk/adouble/ad_open.c index ef971bb9..3b641d66 100644 --- a/libatalk/adouble/ad_open.c +++ b/libatalk/adouble/ad_open.c @@ -113,7 +113,7 @@ static int ad_mkrf_ea(const char *path); #endif static int ad_header_read_ea(const char *path, struct adouble *ad, const struct stat *hst); static int ad_header_upgrade_ea(struct adouble *ad, const char *name); -static int ad_reso_size(const char *path, int adflags, struct adouble *ad); +off_t ad_reso_size(const char *path, int adflags, struct adouble *ad); static int ad_mkrf_osx(const char *path); @@ -1105,7 +1105,7 @@ static int ad_open_hf_ea(const char *path, int adflags, int mode, struct adouble if (ad_meta_fileno(ad) != -1) ad->ad_mdp->adf_refcount++; - (void)ad_reso_size(path, adflags, ad); + ad->ad_rlen = ad_reso_size(path, adflags, ad); EC_CLEANUP: if (ret != 0 && opened && ad_meta_fileno(ad) != -1) { @@ -1128,7 +1128,6 @@ static int ad_open_hf(const char *path, int adflags, int mode, struct adouble *a int ret = 0; memset(ad->ad_eid, 0, sizeof( ad->ad_eid )); - ad->ad_rlen = 0; switch (ad->ad_vers) { case AD_VERSION2: @@ -1151,48 +1150,47 @@ static int ad_open_hf(const char *path, int adflags, int mode, struct adouble *a } /*! - * Get resofork length for adouble:ea + * Get resofork length for adouble:ea, parameter 'ad' may be NULL */ -static int ad_reso_size(const char *path, int adflags, struct adouble *ad) +off_t ad_reso_size(const char *path, int adflags, struct adouble *ad) { EC_INIT; struct stat st; + off_t rlen; - if (adflags & ADFLAGS_DIR) { - ad->ad_rlen = 0; - goto EC_CLEANUP; - } + if (adflags & ADFLAGS_DIR) + EC_FAIL; LOG(log_debug, logtype_ad, "ad_reso_size(\"%s\"): BEGIN", path); #ifdef HAVE_EAFD ssize_t easz; - if (ad_reso_fileno(ad) != -1) { + if (ad && 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( (ad->ad_rlen = sys_fgetxattr(ad_meta_fileno(ad), AD_EA_RESO, NULL, 0)) ); + rlen = st.st_size; + } else if (ad && ad_meta_fileno(ad) != -1) { + EC_NEG1( (rlen = sys_fgetxattr(ad_meta_fileno(ad), AD_EA_RESO, NULL, 0)) ); } else { - EC_NEG1( (ad->ad_rlen = sys_lgetxattr(path, AD_EA_RESO, NULL, 0)) ); + EC_NEG1( (rlen = sys_lgetxattr(path, AD_EA_RESO, NULL, 0)) ); } #else const char *rfpath; - EC_NULL_LOG( rfpath = ad->ad_ops->ad_path(path, adflags)); + EC_NULL_LOG( rfpath = ad_path_osx(path, adflags)); EC_ZERO( lstat(rfpath, &st)); if (st.st_size > ADEDOFF_RFORK_OSX) - ad->ad_rlen = st.st_size - ADEDOFF_RFORK_OSX; + rlen = st.st_size - ADEDOFF_RFORK_OSX; else - ad->ad_rlen = 0; + rlen = 0; #endif - LOG(log_debug, logtype_ad, "ad_reso_size(\"%s\"): size: %zd", path, ad->ad_rlen); + LOG(log_debug, logtype_ad, "ad_reso_size(\"%s\"): size: %zd", path, rlen); EC_CLEANUP: if (ret != 0) - ad->ad_rlen = 0; - EC_EXIT; + rlen = 0; + return rlen; } static int ad_open_rf_v2(const char *path, int adflags, int mode, struct adouble *ad) @@ -1241,7 +1239,7 @@ static int ad_open_rf_ea(const char *path, int adflags, int mode, struct adouble } ad->ad_rfp->adf_flags &= ~( O_TRUNC | O_CREAT ); ad->ad_rfp->adf_refcount++; - EC_NEG1_LOG( ad_reso_size(path, adflags, ad)); + EC_NEG1_LOG( ad->ad_rlen = ad_reso_size(path, adflags, ad)); goto EC_CLEANUP; } #ifdef HAVE_EAFD @@ -1312,7 +1310,7 @@ static int ad_open_rf_ea(const char *path, int adflags, int mode, struct adouble } #endif - (void)ad_reso_size(path, adflags, ad); + ad->ad_rlen = ad_reso_size(path, adflags, ad); EC_CLEANUP: if (ret != 0) { @@ -1586,6 +1584,7 @@ static void ad_init_func(struct adouble *ad) ad_reso_fileno(ad) = -1; ad_meta_fileno(ad) = -1; ad->ad_refcount = 1; + ad->ad_rlen = 0; return; } -- 2.39.2