From 8e8430ea012c57e2285b04e3b2567b75d7d1a38f Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Thu, 23 Aug 2012 10:06:04 +0200 Subject: [PATCH] Restructure fork opening, fix adouble refcounting Fixes Bug ID 3559783 The bug is caused by passing ADFLAGS_NOHF to ad_open() when opening a files data fork. For files without metadata then ad_open() doesn't return an error for the ADFLAGS_HF request to open the metadata. As a result of the successfull ad_open return AFPFORK_META is set in the fork struct, which implies the meta is open. Later afp_close looked at that flag and added ADFLAGS_HF to ad_close flags, resulting in a refcount decement of 2 although the ad_open only incremented by 1. Eg opening such a file twice, then closing once, close the fork. Later operations on the other still open fork fail. afp_openfork opens the fork and metadata in one call to ad_open which lead to an insane if/else and error checking code path. I've seperated this in two distincs calls to ad_open(): the first opens the fork (data or ressource), the second opens the metadata. This gives a cleaner code path but it required a subtle modifications to the way we refcount and flag forks as open inside ad_open: currently we use the fd and it's recount but these do not differente between open data and metadata in the case of adouble:ea as both use the data fork handle, fd and it's refcount. Now we add real refcounting for the forks different from the recount on the file fd by adding three refcounting variables to struct.adouble and change the AD_XXX_OPEN macros to use these. Added test-suite testcases 3, 4 and 7. --- etc/afpd/fork.c | 194 +++++++++++++++--------------------- include/atalk/adouble.h | 15 ++- libatalk/adouble/ad_flush.c | 60 ++++++----- libatalk/adouble/ad_open.c | 104 ++++++++++--------- 4 files changed, 184 insertions(+), 189 deletions(-) diff --git a/etc/afpd/fork.c b/etc/afpd/fork.c index 8f5a2e67..cd1580fa 100644 --- a/etc/afpd/fork.c +++ b/etc/afpd/fork.c @@ -301,8 +301,11 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si LOG(log_error, logtype_afpd, "afp_openfork(%s): %s", s_path->m_name, strerror(errno)); return AFPERR_PARAM; } - /* FIXME should we check it first ? */ + upath = s_path->u_name; + path = s_path->m_name; + st = &s_path->st; + if (!vol_unix_priv(vol)) { if (check_access(obj, vol, upath, access ) < 0) { return AFPERR_ACCESS; @@ -313,124 +316,97 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si } } - st = &s_path->st; - /* XXX: this probably isn't the best way to do this. the already - open bits should really be set if the fork is opened by any - program, not just this one. however, that's problematic to do - if we can't write lock files somewhere. opened is also passed to - ad_open so that we can keep file locks together. - FIXME: add the fork we are opening? - */ if ((opened = of_findname(s_path))) { adsame = opened->of_ad; } - if ( fork == OPENFORK_DATA ) { + adflags = ADFLAGS_SETSHRMD; + + if (fork == OPENFORK_DATA) { eid = ADEID_DFORK; - adflags = ADFLAGS_DF | ADFLAGS_HF | ADFLAGS_NOHF; + adflags |= ADFLAGS_DF; } else { eid = ADEID_RFORK; - adflags = ADFLAGS_RF | ADFLAGS_HF | ADFLAGS_NOHF; + adflags |= ADFLAGS_RF; if (!(access & OPENACC_WR)) adflags |= ADFLAGS_NORF; } - path = s_path->m_name; - if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid, - adsame, st)) == NULL ) { - return( AFPERR_NFILE ); + if (access & OPENACC_WR) { + adflags |= ADFLAGS_RDWR; + if (fork != OPENFORK_DATA) + /* + * We only try to create the resource + * fork if the user wants to open it for write acess. + */ + adflags |= ADFLAGS_CREATE; + } else { + adflags |= ADFLAGS_RDONLY; } + if ((ofork = of_alloc(vol, curdir, path, &ofrefnum, eid, adsame, st)) == NULL) + return AFPERR_NFILE; + LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\", %s, %s)", fullpathname(s_path->u_name), (fork == OPENFORK_DATA) ? "data" : "reso", !(access & OPENACC_WR) ? "O_RDONLY" : "O_RDWR"); ret = AFPERR_NOOBJ; - if (access & OPENACC_WR) { - /* try opening in read-write mode */ - if (ad_open(ofork->of_ad, upath, - adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) { - switch ( errno ) { - case EROFS: - ret = AFPERR_VLOCK; - case EACCES: - goto openfork_err; - case ENOENT: - if (fork == OPENFORK_DATA) { - /* try to open only the data fork */ - if (ad_open(ofork->of_ad, upath, - ADFLAGS_DF | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) { - goto openfork_err; - } - adflags = ADFLAGS_DF; - } else { - /* here's the deal. we only try to create the resource - * fork if the user wants to open it for write acess. */ - if (ad_open(ofork->of_ad, upath, - adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD | ADFLAGS_CREATE, 0666) < 0) - goto openfork_err; - ofork->of_flags |= AFPFORK_META; - } - break; - case EMFILE : - case ENFILE : - ret = AFPERR_NFILE; - goto openfork_err; - case EISDIR : - ret = AFPERR_BADTYPE; - goto openfork_err; - default: - LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) ); - ret = AFPERR_PARAM; - goto openfork_err; - } - } - else { - /* the ressource fork is open too */ - ofork->of_flags |= AFPFORK_META; + + /* First ad_open(), opens data or ressource fork */ + if (ad_open(ofork->of_ad, upath, adflags, 0666) < 0) { + switch (errno) { + case EROFS: + ret = AFPERR_VLOCK; + case EACCES: + goto openfork_err; + case ENOENT: + goto openfork_err; + case EMFILE : + case ENFILE : + ret = AFPERR_NFILE; + goto openfork_err; + case EISDIR : + ret = AFPERR_BADTYPE; + goto openfork_err; + default: + LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) ); + ret = AFPERR_PARAM; + goto openfork_err; } + } + + /* + * Create metadata if we open rw, otherwise only open existing metadata + */ + if (access & OPENACC_WR) { + adflags = ADFLAGS_HF | ADFLAGS_RDWR | ADFLAGS_CREATE; } else { - /* try opening in read-only mode */ - ret = AFPERR_NOOBJ; - if (ad_open(ofork->of_ad, upath, adflags | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) { - switch ( errno ) { - case EROFS: - ret = AFPERR_VLOCK; - goto openfork_err; - case EACCES: - goto openfork_err; - case ENOENT: - /* see if client asked for a read only data fork */ - if (fork == OPENFORK_DATA) { - if (ad_open(ofork->of_ad, upath, ADFLAGS_DF | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) { - goto openfork_err; - } - adflags = ADFLAGS_DF; - } - /* else we don't set AFPFORK_META because there's no ressource fork file - * We need to check AFPFORK_META in afp_closefork(). eg fork open read-only - * then create in open read-write. - * FIXME , it doesn't play well with byte locking example: - * ressource fork open read only - * locking set on it (no effect, there's no file!) - * ressource fork open read write now - */ - break; - case EMFILE : - case ENFILE : - ret = AFPERR_NFILE; - goto openfork_err; - case EISDIR : - ret = AFPERR_BADTYPE; - goto openfork_err; - default: - LOG(log_error, logtype_afpd, "afp_openfork(\"%s\"): %s", - fullpathname(s_path->m_name), strerror(errno) ); - goto openfork_err; - } - } else { - ofork->of_flags |= AFPFORK_META; + adflags = ADFLAGS_HF | ADFLAGS_RDONLY; + } + + if (ad_open(ofork->of_ad, upath, adflags, 0666) == 0) { + ofork->of_flags |= AFPFORK_META; + } else { + switch (errno) { + case EACCES: + case ENOENT: + /* no metadata? We don't care! */ + break; + case EROFS: + ret = AFPERR_VLOCK; + case EMFILE : + case ENFILE : + ret = AFPERR_NFILE; + goto openfork_err; + case EISDIR : + ret = AFPERR_BADTYPE; + goto openfork_err; + default: + LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) ); + ret = AFPERR_PARAM; + goto openfork_err; } } @@ -500,6 +476,9 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si if ((access & OPENACC_RD)) ofork->of_flags |= AFPFORK_ACCRD; + LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\"): fork: %" PRIu16, + fullpathname(s_path->m_name), ofork->of_refnum); + memcpy(rbuf, &ofrefnum, sizeof(ofrefnum)); return( AFP_OK ); @@ -818,8 +797,8 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si size = ad_size(ofork->of_ad, eid); LOG(log_debug, logtype_afpd, - "afp_read(off: %" PRIu64 ", len: %" PRIu64 ", fork: %s, size: %" PRIu64 ")", - offset, reqcount, (ofork->of_flags & AFPFORK_DATA) ? "d" : "r", size); + "afp_read(fork: %" PRIu16 " [%s], off: %" PRIu64 ", len: %" PRIu64 ", size: %" PRIu64 ")", + ofork->of_refnum, (ofork->of_flags & AFPFORK_DATA) ? "data" : "reso", offset, reqcount, size); if (offset > size) { err = AFPERR_EOF; @@ -835,18 +814,11 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si savereqcount = reqcount; saveoff = offset; - LOG(log_debug, logtype_afpd, - "afp_read(off: %" PRIu64 ", len: %" PRIu64 ", fork: %s)", - offset, reqcount, (ofork->of_flags & AFPFORK_DATA) ? "d" : "r"); - if (reqcount < 0 || offset < 0) { err = AFPERR_PARAM; goto afp_read_err; } - LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd)", - of_name(ofork), (intmax_t)offset, (intmax_t)reqcount); - if (obj->options.flags & OPTION_AFP_READ_LOCK) { if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, offset, reqcount, ofork->of_refnum) < 0) { err = AFPERR_LOCK; @@ -1063,8 +1035,8 @@ int afp_closefork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, s return( AFPERR_PARAM ); } - LOG(log_debug, logtype_afpd, "afp_closefork(fork: %s)", - (ofork->of_flags & AFPFORK_DATA) ? "d" : "r"); + LOG(log_debug, logtype_afpd, "afp_closefork(fork: %" PRIu16 " [%s])", + ofork->of_refnum, (ofork->of_flags & AFPFORK_DATA) ? "data" : "rsrc"); if (of_closefork(obj, ofork) < 0 ) { LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) ); @@ -1137,8 +1109,8 @@ static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, s goto afp_write_err; } - LOG(log_debug, logtype_afpd, "afp_write(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)", - offset, reqcount, (ofork->of_flags & AFPFORK_DATA) ? "d" : "r"); + LOG(log_debug, logtype_afpd, "afp_write(fork: %" PRIu16 " [%s], off: %" PRIu64 ", size: %" PRIu64 ")", + ofork->of_refnum, (ofork->of_flags & AFPFORK_DATA) ? "data" : "reso", offset, reqcount); if ((ofork->of_flags & AFPFORK_ACCWR) == 0) { err = AFPERR_ACCESS; diff --git a/include/atalk/adouble.h b/include/atalk/adouble.h index a551d162..384486ea 100644 --- a/include/atalk/adouble.h +++ b/include/atalk/adouble.h @@ -49,7 +49,6 @@ /* version info */ #define AD_VERSION2 0x00020000 -#define AD_VERSION2_OSX 0x00020001 #define AD_VERSION_EA 0x00020002 /* default */ @@ -201,9 +200,6 @@ struct adouble { struct ad_fd ad_data_fork; /* the data fork */ - struct ad_fd ad_metadata_fork; /* adouble:v2 -> unused * - * adouble:ea -> fd unused, only flags used */ - struct ad_fd ad_resource_fork; /* adouble:v2 -> the adouble file * * adouble:ea -> the EA fd */ @@ -211,13 +207,16 @@ struct adouble { * adouble:ea -> ad_resource_fork */ struct ad_fd *ad_mdp; /* adouble:v2 -> ad_resource_fork * - * adouble:ea -> ad_metadata_fork */ + * adouble:ea -> ad_data_fork */ int ad_vers; /* Our adouble version info (AD_VERSION*) */ int ad_adflags; /* ad_open flags adflags like ADFLAGS_DIR */ uint32_t ad_inited; int ad_options; int ad_refcount; /* multiple forks may open one adouble */ + int ad_data_refcount; + int ad_meta_refcount; + int ad_reso_refcount; off_t ad_rlen; /* ressource fork len with AFP 3.0 * * the header parameter size is too small. */ char *ad_name; /* name in server encoding (usually UTF8) */ @@ -352,9 +351,9 @@ struct adouble { #define ad_meta_fileno(ad) ((ad)->ad_mdp->adf_fd) /* -1: not open, AD_SYMLINK (-2): it's a symlink */ -#define AD_DATA_OPEN(ad) ((ad)->ad_data_fork.adf_fd >= 0) -#define AD_META_OPEN(ad) ((ad)->ad_mdp->adf_fd >= 0) -#define AD_RSRC_OPEN(ad) ((ad)->ad_rfp->adf_fd >= 0) +#define AD_DATA_OPEN(ad) (((ad)->ad_data_refcount) && (ad_data_fileno(ad) >= 0)) +#define AD_META_OPEN(ad) (((ad)->ad_meta_refcount) && (ad_meta_fileno(ad) >= 0)) +#define AD_RSRC_OPEN(ad) (((ad)->ad_reso_refcount) && (ad_reso_fileno(ad) >= 0)) #define ad_getversion(ad) ((ad)->ad_version) diff --git a/libatalk/adouble/ad_flush.c b/libatalk/adouble/ad_flush.c index eaf904ca..a637b27f 100644 --- a/libatalk/adouble/ad_flush.c +++ b/libatalk/adouble/ad_flush.c @@ -392,9 +392,12 @@ int ad_close(struct adouble *ad, int adflags) if (ad == NULL) return err; + LOG(log_debug, logtype_default, - "ad_close(%s): BEGIN [dfd: %d (ref: %d), mfd: %d (ref: %d), rfd: %d (ref: %d)]", + "ad_close(%s): BEGIN: {d: %d, m: %d, r: %d} " + "[dfd: %d (ref: %d), mfd: %d (ref: %d), rfd: %d (ref: %d)]", adflags2logstr(adflags), + ad->ad_data_refcount, ad->ad_meta_refcount, ad->ad_reso_refcount, 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); @@ -407,37 +410,48 @@ int ad_close(struct adouble *ad, int adflags) if ((ad->ad_vers == AD_VERSION2) && (adflags & ADFLAGS_RF)) adflags |= ADFLAGS_HF; - if ((adflags & ADFLAGS_DF) - && (ad_data_fileno(ad) >= 0 || ad_data_fileno(ad) == AD_SYMLINK) - && --ad->ad_data_fork.adf_refcount == 0) { - if (ad_data_closefd(ad) < 0) - err = -1; - adf_lock_free(&ad->ad_data_fork); + if ((adflags & ADFLAGS_DF) && (ad_data_fileno(ad) >= 0 || ad_data_fileno(ad) == AD_SYMLINK)) { + if (ad->ad_data_refcount) + ad->ad_data_refcount--; + if (--ad->ad_data_fork.adf_refcount == 0) { + if (ad_data_closefd(ad) < 0) + err = -1; + adf_lock_free(&ad->ad_data_fork); + } } - if ((adflags & ADFLAGS_HF) - && (ad_meta_fileno(ad) != -1) && !(--ad->ad_mdp->adf_refcount)) { - if (close( ad_meta_fileno(ad)) < 0) - err = -1; - ad_meta_fileno(ad) = -1; - if (ad->ad_vers == AD_VERSION2) - adf_lock_free(ad->ad_mdp); + if ((adflags & ADFLAGS_HF) && (ad_meta_fileno(ad) != -1)) { + if (ad->ad_meta_refcount) + ad->ad_meta_refcount--; + if (!(--ad->ad_mdp->adf_refcount)) { + if (close( ad_meta_fileno(ad)) < 0) + err = -1; + ad_meta_fileno(ad) = -1; + if (ad->ad_vers == AD_VERSION2) + adf_lock_free(ad->ad_mdp); + } } - if ((adflags & ADFLAGS_RF) && (ad->ad_vers == AD_VERSION_EA)) { - if ((ad_reso_fileno(ad) != -1) - && !(--ad->ad_rfp->adf_refcount)) { - if (close(ad->ad_rfp->adf_fd) < 0) - err = -1; - ad->ad_rlen = 0; - ad_reso_fileno(ad) = -1; - adf_lock_free(ad->ad_rfp); + if (adflags & ADFLAGS_RF) { + if (ad->ad_reso_refcount) + ad->ad_reso_refcount--; + if (ad->ad_vers == AD_VERSION_EA) { + if ((ad_reso_fileno(ad) != -1) + && !(--ad->ad_rfp->adf_refcount)) { + if (close(ad->ad_rfp->adf_fd) < 0) + err = -1; + ad->ad_rlen = 0; + ad_reso_fileno(ad) = -1; + adf_lock_free(ad->ad_rfp); + } } } LOG(log_debug, logtype_default, - "ad_close(%s): END: %d [dfd: %d (ref: %d), mfd: %d (ref: %d), rfd: %d (ref: %d)]", + "ad_close(%s): END: %d {d: %d, m: %d, r: %d} " + "[dfd: %d (ref: %d), mfd: %d (ref: %d), rfd: %d (ref: %d)]", adflags2logstr(adflags), err, + ad->ad_data_refcount, ad->ad_meta_refcount, ad->ad_reso_refcount, 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); diff --git a/libatalk/adouble/ad_open.c b/libatalk/adouble/ad_open.c index 98ec4c7f..70fba7d2 100644 --- a/libatalk/adouble/ad_open.c +++ b/libatalk/adouble/ad_open.c @@ -166,13 +166,6 @@ static const struct entry entry_order_ea[ADEID_NUM_EA + 1] = { {0, 0, 0} }; -/* fallback for EAs */ -static const struct entry entry_order_osx[ADEID_NUM_OSX +1] = { - {ADEID_FINDERI, ADEDOFF_FINDERI_OSX, ADEDLEN_FINDERI}, - {ADEID_RFORK, ADEDOFF_RFORK_OSX, ADEDLEN_INIT}, - {0, 0, 0} -}; - #define ADFLAGS2LOGSTRBUFSIZ 128 const char *adflags2logstr(int adflags) { @@ -325,10 +318,9 @@ static int new_ad_header(struct adouble *ad, const char *path, struct stat *stp, LOG(log_debug, logtype_default, "new_ad_header(\"%s\")", path); - if (stp == NULL) { - stp = &st; - if (lstat(path, &st) != 0) - return -1; + if (ad->ad_magic == AD_MAGIC) { + LOG(log_debug, logtype_default, "new_ad_header(\"%s\"): already initialized", path); + return 0; } ad->ad_magic = AD_MAGIC; @@ -343,11 +335,8 @@ static int new_ad_header(struct adouble *ad, const char *path, struct stat *stp, eid = entry_order2; else if (ad->ad_vers == AD_VERSION_EA) eid = entry_order_ea; - else if (ad->ad_vers == AD_VERSION2_OSX) - eid = entry_order_osx; - else { + else return -1; - } while (eid->id) { ad->ad_eid[eid->id].ade_off = eid->offset; @@ -356,34 +345,39 @@ static int new_ad_header(struct adouble *ad, const char *path, struct stat *stp, } /* put something sane in the directory finderinfo */ - if (ad->ad_vers != AD_VERSION2_OSX) { - if ((adflags & ADFLAGS_DIR)) { - /* set default view */ - ashort = htons(FINDERINFO_CLOSEDVIEW); - memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRVIEWOFF, &ashort, sizeof(ashort)); - } else { - /* set default creator/type fields */ - memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRTYPEOFF,"\0\0\0\0", 4); - memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRCREATOFF,"\0\0\0\0", 4); - } + if (stp == NULL) { + stp = &st; + if (lstat(path, &st) != 0) + return -1; + } - /* make things invisible */ - 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); - memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort)); - } + if ((adflags & ADFLAGS_DIR)) { + /* set default view */ + ashort = htons(FINDERINFO_CLOSEDVIEW); + memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRVIEWOFF, &ashort, sizeof(ashort)); + } else { + /* set default creator/type fields */ + memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRTYPEOFF,"\0\0\0\0", 4); + memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRCREATOFF,"\0\0\0\0", 4); + } - /* put something sane in the date fields */ - ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, stp->st_mtime); - ad_setdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, stp->st_mtime); - ad_setdate(ad, AD_DATE_ACCESS | AD_DATE_UNIX, stp->st_mtime); - ad_setdate(ad, AD_DATE_BACKUP, AD_DATE_START); + /* make things invisible */ + 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); + memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort)); } + + /* put something sane in the date fields */ + ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, stp->st_mtime); + ad_setdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, stp->st_mtime); + ad_setdate(ad, AD_DATE_ACCESS | AD_DATE_UNIX, stp->st_mtime); + ad_setdate(ad, AD_DATE_BACKUP, AD_DATE_START); + return 0; } @@ -1042,8 +1036,7 @@ static int ad_open_hf_ea(const char *path, int adflags, int mode, struct adouble oflags = O_NOFOLLOW | (ad2openflags(ad, ADFLAGS_DF, adflags) & ~(O_CREAT | O_TRUNC)); if (ad_meta_fileno(ad) == AD_SYMLINK) - /* symlink */ - EC_EXIT; + goto EC_CLEANUP; if (ad_meta_fileno(ad) != -1) { /* the file is already open, but we want write access: */ @@ -1256,6 +1249,7 @@ static int ad_open_rf_ea(const char *path, int adflags, int mode, struct adouble /* 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, path, NULL, adflags) ); LOG(log_debug, logtype_default, "ad_open_rf(\"%s\"): created adouble rfork, flushing: \"%s\"", path, rfpath); ad_flush(ad); @@ -1610,8 +1604,10 @@ int ad_open(struct adouble *ad, const char *path, int adflags, ...) mode_t mode = 0; LOG(log_debug, logtype_default, - "ad_open(\"%s\", %s): BEGIN [dfd: %d (ref: %d), mfd: %d (ref: %d), rfd: %d (ref: %d)]", + "ad_open(\"%s\", %s): BEGIN {d: %d, m: %d, r: %d}" + "[dfd: %d (ref: %d), mfd: %d (ref: %d), rfd: %d (ref: %d)]", fullpathname(path), adflags2logstr(adflags), + ad->ad_data_refcount, ad->ad_meta_refcount, ad->ad_reso_refcount, 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); @@ -1646,15 +1642,27 @@ int ad_open(struct adouble *ad, const char *path, int adflags, ...) va_end(args); if (adflags & ADFLAGS_DF) { - EC_ZERO( ad_open_df(path, adflags, mode, ad) ); + ad->ad_data_refcount++; + if (ad_open_df(path, adflags, mode, ad) != 0) { + ad->ad_data_refcount--; + EC_FAIL; + } } if (adflags & ADFLAGS_HF) { - EC_ZERO( ad_open_hf(path, adflags, mode, ad) ); + ad->ad_meta_refcount++; + if (ad_open_hf(path, adflags, mode, ad) != 0) { + ad->ad_meta_refcount--; + EC_FAIL; + } } if (adflags & ADFLAGS_RF) { - EC_ZERO( ad_open_rf(path, adflags, mode, ad) ); + ad->ad_reso_refcount++; + if (ad_open_rf(path, adflags, mode, ad) != 0) { + ad->ad_reso_refcount--; + EC_FAIL; + } } if (adflags & ADFLAGS_CHECK_OF) { @@ -1663,8 +1671,10 @@ int ad_open(struct adouble *ad, const char *path, int adflags, ...) EC_CLEANUP: LOG(log_debug, logtype_default, - "ad_open(\"%s\"): END: %d [dfd: %d (ref: %d), mfd: %d (ref: %d), rfd: %d (ref: %d)]", + "ad_open(\"%s\"): END: %d {d: %d, m: %d, r: %d}" + "[dfd: %d (ref: %d), mfd: %d (ref: %d), rfd: %d (ref: %d)]", fullpathname(path), ret, + ad->ad_data_refcount, ad->ad_meta_refcount, ad->ad_reso_refcount, 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); -- 2.39.2