From cf4968a7b3609ed6450024a065f8c2b2226cd223 Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Wed, 1 Feb 2012 12:47:52 +0100 Subject: [PATCH 1/1] Various fixes for adouble:v2 --- etc/afpd/file.c | 34 ++-- etc/afpd/fork.c | 7 +- etc/afpd/fork.h | 1 + etc/afpd/ofork.c | 4 +- include/atalk/adouble.h | 8 +- libatalk/adouble/ad_flush.c | 5 + libatalk/adouble/ad_lock.c | 310 +++++++----------------------------- libatalk/adouble/ad_open.c | 142 +++++++++++------ libatalk/vfs/vfs.c | 9 +- 9 files changed, 182 insertions(+), 338 deletions(-) diff --git a/etc/afpd/file.c b/etc/afpd/file.c index bc9754f0..6d253d1e 100644 --- a/etc/afpd/file.c +++ b/etc/afpd/file.c @@ -609,6 +609,7 @@ int getfilparams(struct vol *vol, struct adouble ad, *adp; int opened = 0; int rc; + int flags; LOG(log_debug, logtype_afpd, "getfilparams(\"%s\")", path->u_name); @@ -617,7 +618,7 @@ int getfilparams(struct vol *vol, if (opened) { char *upath; - int flags = (bitmap & (1 << FILPBIT_ATTR)) ? ADFLAGS_CHECK_OF : 0; + flags = (bitmap & (1 << FILPBIT_ATTR)) ? ADFLAGS_CHECK_OF : 0; adp = of_ad(vol, path, &ad); upath = path->u_name; @@ -639,7 +640,7 @@ int getfilparams(struct vol *vol, } } rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp); - ad_close(adp, ADFLAGS_HF); + ad_close(adp, ADFLAGS_HF | flags); return( rc ); } @@ -1332,7 +1333,7 @@ int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, si setvoltime(obj, d_vol ); copy_exit: - ad_close( adp, ADFLAGS_DF |ADFLAGS_HF ); + ad_close( adp, ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_SETSHRMD); return( retvalue ); } @@ -1385,19 +1386,7 @@ static int copy_fork(int eid, struct adouble *add, struct adouble *ads) dfd = ad_reso_fileno(add); } - if (add->ad_version == AD_VERSION2) - soff = doff = ad_getentryoff(ads, eid); - else { - if (eid == ADEID_DFORK) - soff = doff = ad_getentryoff(ads, eid); - else { -#ifdef HAVE_EAFD - soff = doff = 0; -#else - soff = doff = ADEDOFF_RFORK_OSX; -#endif - } - } + soff = doff = ad_getentryoff(ads, eid); if ((off_t)-1 == lseek(sfd, soff, SEEK_SET)) return -1; @@ -1478,9 +1467,6 @@ int copyfile(const struct vol *s_vol, } adflags = ADFLAGS_DF | ADFLAGS_RF | ADFLAGS_NORF; - if (newname) { - adflags |= ADFLAGS_HF; - } if (ad_openat(adp, sfd, src, adflags | ADFLAGS_NOHF | ADFLAGS_RDONLY) < 0) { ret_err = errno; @@ -1509,13 +1495,15 @@ int copyfile(const struct vol *s_vol, return AFPERR_EXIST; } +#if 0 if (AD_RSRC_OPEN(adp)) err = copy_fork(ADEID_RFORK, &add, adp); - +#endif + if (err == 0) err = copy_fork(ADEID_DFORK, &add, adp); - if ((err == 0) && (ad_meta_fileno(adp) != -1)) + if (err == 0) err = d_vol->vfs->vfs_copyfile(d_vol, sfd, src, dst); if (err < 0) @@ -1614,7 +1602,7 @@ int deletefile(const struct vol *vol, int dirfd, char *file, int checkAttrib) */ if ( ad_metadataat(dirfd, file, ADFLAGS_CHECK_OF, &ad) == 0 ) { if ((err = check_attrib(&ad))) { - ad_close(&ad, ADFLAGS_HF); + ad_close(&ad, ADFLAGS_HF | ADFLAGS_CHECK_OF); return err; } meta = 1; @@ -1671,7 +1659,7 @@ int deletefile(const struct vol *vol, int dirfd, char *file, int checkAttrib) end: if (meta) - ad_close(&ad, ADFLAGS_HF); + ad_close(&ad, ADFLAGS_HF | ADFLAGS_CHECK_OF); if (adp) ad_close( &ad, adflags ); /* ad_close removes locks if any */ diff --git a/etc/afpd/fork.c b/etc/afpd/fork.c index 2d3a5ff5..7bd2128b 100644 --- a/etc/afpd/fork.c +++ b/etc/afpd/fork.c @@ -418,7 +418,7 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si } if ((ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof(int16_t), &buflen)) != AFP_OK) { - ad_close( ofork->of_ad, adflags ); + ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD); goto openfork_err; } @@ -433,7 +433,7 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */ ad_getattr(ofork->of_ad, &bshort); if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) { - ad_close( ofork->of_ad, adflags ); + ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD); of_dealloc( ofork ); ofrefnum = 0; memcpy(rbuf, &ofrefnum, sizeof(ofrefnum)); @@ -452,8 +452,9 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum); /* can we access the fork? */ if (ret < 0) { + ofork->of_flags |= AFPFORK_ERROR; ret = errno; - ad_close( ofork->of_ad, adflags ); + ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD); of_dealloc( ofork ); switch (ret) { case EAGAIN: /* return data anyway */ diff --git a/etc/afpd/fork.h b/etc/afpd/fork.h index 37605e4a..b8a6d3a9 100644 --- a/etc/afpd/fork.h +++ b/etc/afpd/fork.h @@ -46,6 +46,7 @@ struct ofork { #define AFPFORK_ACCWR (1<<5) #define AFPFORK_ACCMASK (AFPFORK_ACCRD | AFPFORK_ACCWR) #define AFPFORK_MODIFIED (1<<6) /* used in FCE for modified files */ +#define AFPFORK_ERROR (1<<7) /* used to indicate an error in opening the fork */ #ifdef AFS extern struct ofork *writtenfork; diff --git a/etc/afpd/ofork.c b/etc/afpd/ofork.c index 362097ae..5fc6a1d5 100644 --- a/etc/afpd/ofork.c +++ b/etc/afpd/ofork.c @@ -383,7 +383,7 @@ void of_dealloc( struct ofork *of) free( of->of_ad->ad_m_name ); free( of->of_ad); } else {/* someone's still using it. just free this user's locks */ - ad_unlock(of->of_ad, of->of_refnum); + ad_unlock(of->of_ad, of->of_refnum, of->of_flags & AFPFORK_ERROR ? 0 : 1); } free( of ); @@ -417,7 +417,7 @@ int of_closefork(struct ofork *ofork) } ret = 0; - if ( ad_close( ofork->of_ad, adflags ) < 0 ) { + if ( ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD) < 0 ) { ret = -1; } diff --git a/include/atalk/adouble.h b/include/atalk/adouble.h index a4a508bb..5601f439 100644 --- a/include/atalk/adouble.h +++ b/include/atalk/adouble.h @@ -358,7 +358,6 @@ struct adouble { #define ad_getentrylen(ad,eid) ((ad)->ad_eid[(eid)].ade_len) #define ad_setentrylen(ad,eid,len) ((ad)->ad_eid[(eid)].ade_len = (len)) -#define ad_getentryoff(ad,eid) ((ad)->ad_eid[(eid)].ade_off) #define ad_setentryoff(ad,eid,off) ((ad)->ad_eid[(eid)].ade_off = (off)) #define ad_entry(ad,eid) ((caddr_t)(ad)->ad_data + (ad)->ad_eid[(eid)].ade_off) @@ -379,11 +378,12 @@ extern int fsetrsrcea(struct adouble *ad, int fd, const char *eaname, const void /* ad_lock.c */ extern int ad_testlock (struct adouble *adp, int eid, off_t off); extern uint16_t ad_openforks(struct adouble *adp, uint16_t); -extern int ad_lock(struct adouble *, uint32_t eid, int type, off_t off, off_t len, int user); -extern void ad_unlock(struct adouble *, int user); -extern int ad_tmplock(struct adouble *, uint32_t eid, int type, off_t off, off_t len, int user); +extern int ad_lock(struct adouble *, uint32_t eid, int type, off_t off, off_t len, int fork); +extern void ad_unlock(struct adouble *, int fork, int unlckbrl); +extern int ad_tmplock(struct adouble *, uint32_t eid, int type, off_t off, off_t len, int fork); /* ad_open.c */ +extern off_t ad_getentryoff(const struct adouble *ad, int eid); extern const char *adflags2logstr(int adflags); extern int ad_setfuid (const uid_t ); extern uid_t ad_getfuid (void ); diff --git a/libatalk/adouble/ad_flush.c b/libatalk/adouble/ad_flush.c index 3331074b..dbf1576d 100644 --- a/libatalk/adouble/ad_flush.c +++ b/libatalk/adouble/ad_flush.c @@ -359,6 +359,11 @@ int ad_close(struct adouble *ad, int adflags) ad_meta_fileno(ad), ad->ad_mdp->adf_refcount, ad_reso_fileno(ad), ad->ad_rfp->adf_refcount); + if ((ad->ad_vers == AD_VERSION2) && (adflags & (ADFLAGS_SETSHRMD | ADFLAGS_CHECK_OF))) { + /* sharemode locks are stored in the data fork, adouble:v2 needs this extra handling */ + adflags |= ADFLAGS_DF; + } + if ((ad->ad_vers == AD_VERSION2) && (adflags & ADFLAGS_RF)) adflags |= ADFLAGS_HF; diff --git a/libatalk/adouble/ad_lock.c b/libatalk/adouble/ad_lock.c index 6932b33d..8d380817 100644 --- a/libatalk/adouble/ad_lock.c +++ b/libatalk/adouble/ad_lock.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -153,21 +154,21 @@ static void adf_freelock(struct ad_fd *ad, const int i) * i converted to using arrays of locks. everytime a lock * gets removed, we shift all of the locks down. */ -static void adf_unlock(struct ad_fd *ad, const int fork) +static void adf_unlock(struct adouble *ad, struct ad_fd *adf, const int fork, int unlckbrl) { - adf_lock_t *lock = ad->adf_lock; + adf_lock_t *lock = adf->adf_lock; int i; - for (i = 0; i < ad->adf_lockcount; i++) { - if (lock[i].lock.l_start < AD_FILELOCK_BASE + for (i = 0; i < adf->adf_lockcount; i++) { + if ((unlckbrl && lock[i].lock.l_start < AD_FILELOCK_BASE) || lock[i].user == fork) { /* we're really going to delete this lock. note: read locks are the only ones that allow refcounts > 1 */ - adf_freelock(ad, i); + adf_freelock(adf, i); /* we shifted things down, so we need to backtrack */ i--; /* unlikely but realloc may have change adf_lock */ - lock = ad->adf_lock; + lock = adf->adf_lock; } } } @@ -241,58 +242,6 @@ static int adf_findxlock(struct ad_fd *ad, * 2) if the header file doesn't exist, we stick the locks * in the locations specified by AD_FILELOCK_RD/WR. */ -#define LOCK_DATA_WR (0) -#define LOCK_DATA_RD (1) -#define LOCK_RSRC_WR (2) -#define LOCK_RSRC_RD (3) - -#define LOCK_RSRC_DRD (4) -#define LOCK_RSRC_DWR (5) -#define LOCK_DATA_DRD (6) -#define LOCK_DATA_DWR (7) - -#define LOCK_RSRC_NONE (8) -#define LOCK_DATA_NONE (9) - -/* -------------- - translate a data fork lock to an offset -*/ - -static off_t df2off(off_t off) -{ - off_t start = off; - if (off == AD_FILELOCK_OPEN_WR) - start = LOCK_DATA_WR; - else if (off == AD_FILELOCK_OPEN_RD) - start = LOCK_DATA_RD; - else if (off == AD_FILELOCK_DENY_RD) - start = LOCK_DATA_DRD; - else if (off == AD_FILELOCK_DENY_WR) - start = LOCK_DATA_DWR; - else if (off == AD_FILELOCK_OPEN_NONE) - start = LOCK_DATA_NONE; - return start; -} - -/* -------------- - translate a resource fork lock to an offset -*/ - -static off_t hf2off(off_t off) -{ - off_t start = off; - if (off == AD_FILELOCK_OPEN_WR) - start = LOCK_RSRC_WR; - else if (off == AD_FILELOCK_OPEN_RD) - start = LOCK_RSRC_RD; - else if (off == AD_FILELOCK_DENY_RD) - start = LOCK_RSRC_DRD; - else if (off == AD_FILELOCK_DENY_WR) - start = LOCK_RSRC_DWR; - else if (off == AD_FILELOCK_OPEN_NONE) - start = LOCK_RSRC_NONE; - return start; -} /* -------------- translate a resource fork lock to an offset @@ -358,130 +307,6 @@ static int testlock(const struct ad_fd *adf, off_t off, off_t len) return 1; } -static uint16_t ad_openforks_v2(struct adouble *ad, uint16_t attrbits) -{ - uint16_t ret = 0; - struct ad_fd *adf; - off_t off; - - if (!(attrbits & (ATTRBIT_DOPEN | ATTRBIT_ROPEN))) { - off_t len; - /* XXX know the locks layout: - AD_FILELOCK_OPEN_WR is first - and use it for merging requests - */ - if (ad_meta_fileno(ad) != -1) { - /* there's a resource fork test the four bytes for - * data RW/RD and fork RW/RD locks in one request - */ - adf = ad->ad_mdp; - off = LOCK_DATA_WR; - len = 4; - } - else { - /* no resource fork, only data RD/RW may exist */ - adf = &ad->ad_data_fork; - off = AD_FILELOCK_OPEN_WR; - len = 2; - } - if (!testlock(adf, off, len)) - return ret; - } - /* either there's a lock or we already know one - fork is open - */ - if (!(attrbits & ATTRBIT_DOPEN)) { - if (ad_meta_fileno(ad) != -1) { - adf = ad->ad_mdp; - off = LOCK_DATA_WR; - } - else { - adf = &ad->ad_data_fork; - off = AD_FILELOCK_OPEN_WR; - } - ret = testlock(adf, off, 2) > 0? ATTRBIT_DOPEN : 0; - } - - if (!(attrbits & ATTRBIT_ROPEN)) { - if (ad_meta_fileno(ad) != -1) { - adf = ad->ad_mdp; - off = LOCK_RSRC_WR; - ret |= testlock(adf, off, 2) > 0? ATTRBIT_ROPEN : 0; - } - } - - return ret; -} - -/* test for sharemode locks, adouble:ea stores them on the datafork */ -static uint16_t ad_openforks_ea(struct adouble *ad, uint16_t attrbits) -{ - uint16_t ret = 0; - struct ad_fd *adf; - off_t off; - off_t len; - - if (ad_data_fileno(ad) == -1) - return 0; - - if (!(attrbits & (ATTRBIT_DOPEN | ATTRBIT_ROPEN))) { - /* Test all 4 locks at once */ - off = AD_FILELOCK_OPEN_WR; - len = 4; - if (testlock(&ad->ad_data_fork, off, len) == 0) - return 0; - } - - /* either there's a lock or we already know one fork is open */ - - if (!(attrbits & ATTRBIT_DOPEN)) { - off = AD_FILELOCK_OPEN_WR; - ret = testlock(&ad->ad_data_fork, off, 2) > 0 ? ATTRBIT_DOPEN : 0; - } - - if (!(attrbits & ATTRBIT_ROPEN)) { - off = AD_FILELOCK_RSRC_OPEN_WR; - ret |= testlock(&ad->ad_data_fork, off, 2) > 0? ATTRBIT_ROPEN : 0; - } - - return ret; -} - -static int ad_testlock_v2(struct adouble *ad, int eid, const off_t off) -{ - struct ad_fd *adf; - off_t lock_offset; - - lock_offset = off; - if (eid == ADEID_DFORK) { - adf = &ad->ad_data_fork; - if (ad_meta_fileno(ad) != -1) { - adf = ad->ad_mdp; - lock_offset = df2off(off); - } - } else { /* rfork */ - if (ad_meta_fileno(ad) == -1) { - /* there's no resource fork. return no lock */ - return 0; - } - adf = ad->ad_mdp; - lock_offset = hf2off(off); - } - return testlock(adf, lock_offset, 1); -} - -static int ad_testlock_ea(struct adouble *ad, int eid, const off_t off) -{ - off_t lock_offset; - - if (eid == ADEID_DFORK) { - lock_offset = off; - } else { /* rfork */ - lock_offset = rf2off(off); - } - return testlock(&ad->ad_data_fork, lock_offset, 1); -} - #define LTYPE2STRBUFSIZ 128 static const char *locktypetostr(int type) { @@ -545,61 +370,21 @@ int ad_lock(struct adouble *ad, uint32_t eid, int locktype, off_t off, off_t len shmdstrfromoff(off), (intmax_t)len); - if ((locktype & ADLOCK_FILELOCK) && (len != 1)) { - /* safety check */ - ret = -1; - goto exit; - } + if ((locktype & ADLOCK_FILELOCK) && (len != 1)) + AFP_PANIC("lock API error"); - lock.l_start = off; type = locktype; if (eid == ADEID_DFORK) { adf = &ad->ad_data_fork; - if ((ad->ad_vers == AD_VERSION2) && (type & ADLOCK_FILELOCK)) { - if (ad_meta_fileno(ad) != -1) { /* META */ - adf = ad->ad_mdp; - lock.l_start = df2off(off); - } - } + lock.l_start = off; } else { /* rfork */ - switch (ad->ad_vers) { - case AD_VERSION2: - if (ad_meta_fileno(ad) == -1 || ad_reso_fileno(ad) == -1) { - /* there's no meta data. return a lock error - * otherwise if a second process is able to create it - * locks are a mess. */ - errno = EACCES; - ret= -1; - goto exit; - } - if (type & ADLOCK_FILELOCK) { - adf = ad->ad_mdp; /* either resource or meta data (set in ad_open) */ - lock.l_start = hf2off(off); - } else { - /* we really want the resource fork it's a byte lock */ - adf = &ad->ad_resource_fork; - lock.l_start += ad_getentryoff(ad, eid); - } - break; - - case AD_VERSION_EA: - if (type & ADLOCK_FILELOCK) { - adf = &ad->ad_data_fork; - lock.l_start = rf2off(off); - } else { - adf = ad->ad_rfp; -#if HAVE_EAFD - lock.l_start = off; -#else - lock.l_start= ADEDOFF_RFORK_OSX + off; -#endif - } - break; - - default: - ret = -1; - goto exit; + if (type & ADLOCK_FILELOCK) { + adf = &ad->ad_data_fork; + lock.l_start = rf2off(off); + } else { + adf = ad->ad_rfp; + lock.l_start = off + ad_getentryoff(ad, ADEID_RFORK); } } @@ -734,10 +519,10 @@ int ad_tmplock(struct adouble *ad, uint32_t eid, int locktype, off_t off, off_t lock.l_start = off; type = locktype; + if (eid == ADEID_DFORK) { adf = &ad->ad_data_fork; } else { - /* FIXME META */ adf = &ad->ad_resource_fork; if (adf->adf_fd == -1) { /* there's no resource fork. return success */ @@ -787,15 +572,16 @@ exit: } /* --------------------- */ -void ad_unlock(struct adouble *ad, const int fork) +void ad_unlock(struct adouble *ad, const int fork, int unlckbrl) { - LOG(log_debug, logtype_default, "ad_unlock(\"%s\"): BEGIN", ad->ad_m_name ? ad->ad_m_name : "???"); + LOG(log_debug, logtype_default, "ad_unlock(\"%s\", unlckbrl: %d): BEGIN", + ad->ad_m_name ? ad->ad_m_name : "???", unlckbrl); if (ad_data_fileno(ad) != -1) { - adf_unlock(&ad->ad_data_fork, fork); + adf_unlock(ad, &ad->ad_data_fork, fork, unlckbrl); } if (ad_reso_fileno(ad) != -1) { - adf_unlock(&ad->ad_resource_fork, fork); + adf_unlock(ad, &ad->ad_resource_fork, fork, unlckbrl); } LOG(log_debug, logtype_default, "ad_unlock(\"%s\"): END", ad->ad_m_name ? ad->ad_m_name : "???"); @@ -814,6 +600,7 @@ void ad_unlock(struct adouble *ad, const int fork) int ad_testlock(struct adouble *ad, int eid, const off_t off) { int ret = 0; + off_t lock_offset; LOG(log_debug, logtype_default, "ad_testlock(\"%s\", %s, off: %jd (%s): BEGIN", ad->ad_m_name ? ad->ad_m_name : "???", @@ -821,18 +608,14 @@ int ad_testlock(struct adouble *ad, int eid, const off_t off) (intmax_t)off, shmdstrfromoff(off)); - switch (ad->ad_vers) { - case AD_VERSION2: - ret = ad_testlock_v2(ad, eid, off); - break; - case AD_VERSION_EA: - ret = ad_testlock_ea(ad, eid, off); - break; - default: - ret = -1; - break; + if (eid == ADEID_DFORK) { + lock_offset = off; + } else { /* rfork */ + lock_offset = rf2off(off); } + ret = testlock(&ad->ad_data_fork, lock_offset, 1); + LOG(log_debug, logtype_default, "ad_testlock: END: %d", ret); return ret; } @@ -851,12 +634,33 @@ int ad_testlock(struct adouble *ad, int eid, const off_t off) */ uint16_t ad_openforks(struct adouble *ad, uint16_t attrbits) { - switch (ad->ad_vers) { - case AD_VERSION2: - return ad_openforks_v2(ad, attrbits); - case AD_VERSION_EA: - return ad_openforks_ea(ad, attrbits); - default: - return -1; + uint16_t ret = 0; + struct ad_fd *adf; + off_t off; + off_t len; + + if (ad_data_fileno(ad) == -1) + return 0; + + if (!(attrbits & (ATTRBIT_DOPEN | ATTRBIT_ROPEN))) { + /* Test all 4 locks at once */ + off = AD_FILELOCK_OPEN_WR; + len = 4; + if (testlock(&ad->ad_data_fork, off, len) == 0) + return 0; } + + /* either there's a lock or we already know one fork is open */ + + if (!(attrbits & ATTRBIT_DOPEN)) { + off = AD_FILELOCK_OPEN_WR; + ret = testlock(&ad->ad_data_fork, off, 2) > 0 ? ATTRBIT_DOPEN : 0; + } + + if (!(attrbits & ATTRBIT_ROPEN)) { + off = AD_FILELOCK_RSRC_OPEN_WR; + ret |= testlock(&ad->ad_data_fork, off, 2) > 0? ATTRBIT_ROPEN : 0; + } + + return ret; } diff --git a/libatalk/adouble/ad_open.c b/libatalk/adouble/ad_open.c index d9c364c6..4e6941c7 100644 --- a/libatalk/adouble/ad_open.c +++ b/libatalk/adouble/ad_open.c @@ -693,22 +693,28 @@ static int ad_error(struct adouble *ad, int adflags) if (adflags & ADFLAGS_NOHF) { /* 1 */ return 0; } - if (adflags & ADFLAGS_DF) { /* 2 */ + if (adflags & (ADFLAGS_DF | ADFLAGS_SETSHRMD | ADFLAGS_CHECK_OF)) { /* 2 */ ad_close( ad, ADFLAGS_DF ); err = errno; } return -1 ; } -/* Map ADFLAGS to open() flags */ -static int ad2openflags(int adflags) +/*! + * Map ADFLAGS to open() flags + * + * @param adfile (r) the file you really want to open: ADFLAGS_DF or ADFLAGS_HF + * @param adflags (r) flags from ad_open(..., adflags, ...) + * @returns mapped flags suitable for calling open() + */ +static int ad2openflags(int adfile, int adflags) { int oflags = 0; if (adflags & ADFLAGS_RDWR) oflags |= O_RDWR; if (adflags & ADFLAGS_RDONLY) { - if (adflags & ADFLAGS_SETSHRMD) + if ((adfile & ADFLAGS_DF) && (adflags & ADFLAGS_SETSHRMD)) oflags |= O_RDWR; else oflags |= O_RDONLY; @@ -725,14 +731,19 @@ static int ad2openflags(int adflags) static int ad_open_df(const char *path, int adflags, mode_t mode, struct adouble *ad) { + EC_INIT; struct stat st_dir; int oflags; mode_t admode; int st_invalid = -1; ssize_t lsz; - LOG(log_debug, logtype_default, "ad_open_df(\"%s\", %04o)", - fullpathname(path), mode); + LOG(log_debug, logtype_default, + "ad_open_df(\"%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 (ad_data_fileno(ad) != -1) { /* the file is already open, but we want write access: */ @@ -745,10 +756,10 @@ static int ad_open_df(const char *path, int adflags, mode_t mode, struct adouble /* it's not new anymore */ ad->ad_data_fork.adf_flags &= ~( O_TRUNC | O_CREAT ); ad->ad_data_fork.adf_refcount++; - return 0; + goto EC_CLEANUP; } - oflags = O_NOFOLLOW | ad2openflags(adflags); + oflags = O_NOFOLLOW | ad2openflags(ADFLAGS_DF, adflags); admode = mode; if ((adflags & ADFLAGS_CREATE)) { @@ -767,8 +778,7 @@ static int ad_open_df(const char *path, int adflags, mode_t mode, struct adouble if ((adflags & ADFLAGS_SETSHRMD) && (adflags & ADFLAGS_RDONLY)) { oflags &= ~O_RDWR; oflags |= O_RDONLY; - if ((ad->ad_data_fork.adf_fd = open(path, oflags, admode)) == -1) - return -1; + EC_NEG1( ad->ad_data_fork.adf_fd = open(path, oflags, admode) ); break; } return -1; @@ -776,13 +786,13 @@ static int ad_open_df(const char *path, int adflags, mode_t mode, struct adouble ad->ad_data_fork.adf_syml = malloc(MAXPATHLEN+1); if ((lsz = readlink(path, ad->ad_data_fork.adf_syml, MAXPATHLEN)) <= 0) { free(ad->ad_data_fork.adf_syml); - return -1; + EC_FAIL; } ad->ad_data_fork.adf_syml[lsz] = 0; ad->ad_data_fork.adf_fd = -2; /* -2 means its a symlink */ break; default: - return -1; + EC_FAIL; } } @@ -793,42 +803,56 @@ static int ad_open_df(const char *path, int adflags, mode_t mode, struct adouble adf_lock_init(&ad->ad_data_fork); ad->ad_data_fork.adf_refcount++; - return 0; +EC_CLEANUP: + LOG(log_debug, logtype_default, + "ad_open_df(\"%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; } -/* TODO: error handling */ static int ad_open_hf_v2(const char *path, int adflags, mode_t mode, struct adouble *ad) { + EC_INIT; struct stat st_dir; struct stat st_meta; struct stat *pst = NULL; const char *ad_p; - int oflags, nocreatflags; + int oflags, nocreatflags, opened = 0; mode_t admode; int st_invalid = -1; + LOG(log_debug, logtype_default, + "ad_open_hf_v2(\"%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 (ad_meta_fileno(ad) != -1) { /* the file is already open, but we want write access: */ if ((adflags & ADFLAGS_RDWR) && /* and it was already denied: */ (ad->ad_mdp->adf_flags & O_RDONLY)) { errno = EACCES; - return -1; + EC_FAIL; } ad_refresh(path, ad); /* it's not new anymore */ ad->ad_mdp->adf_flags &= ~( O_TRUNC | O_CREAT ); ad->ad_mdp->adf_refcount++; - return 0; + goto EC_CLEANUP; } ad_p = ad->ad_ops->ad_path(path, adflags); - oflags = O_NOFOLLOW | ad2openflags(adflags); + oflags = O_NOFOLLOW | ad2openflags(ADFLAGS_HF, adflags); nocreatflags = oflags & ~(O_CREAT | O_EXCL); - ad->ad_mdp->adf_fd = open(ad_p, nocreatflags); + ad_meta_fileno(ad) = open(ad_p, nocreatflags); - if (ad->ad_mdp->adf_fd != -1) { + if (ad_meta_fileno(ad) != -1) { ad->ad_mdp->adf_flags = nocreatflags; } else { switch (errno) { @@ -838,15 +862,14 @@ static int ad_open_hf_v2(const char *path, int adflags, mode_t mode, struct adou if ((adflags & ADFLAGS_RDONLY) && (adflags & ADFLAGS_SETSHRMD)) { nocreatflags &= ~O_RDWR; nocreatflags |= O_RDONLY; - if ((ad->ad_mdp->adf_fd = open(ad_p, nocreatflags)) == -1) - return -1; + EC_NEG1( ad_meta_fileno(ad) = open(ad_p, nocreatflags) ); ad->ad_mdp->adf_flags = nocreatflags; break; } - return -1; + EC_FAIL; case ENOENT: if (!(oflags & O_CREAT)) - return ad_error(ad, adflags); + EC_FAIL; /* * We're expecting to create a new adouble header file here */ @@ -859,9 +882,7 @@ static int ad_open_hf_v2(const char *path, int adflags, mode_t mode, struct adou admode = mode; admode = ad_hf_mode(admode); if (errno == ENOENT) { - if (ad->ad_ops->ad_mkrf( ad_p) < 0) { - return ad_error(ad, adflags); - } + EC_NEG1_LOG( ad->ad_ops->ad_mkrf(ad_p) ); admode = mode; st_invalid = ad_mode_st(ad_p, &admode, &st_dir); if ((ad->ad_options & ADVOL_UNIXPRIV)) @@ -870,20 +891,20 @@ static int ad_open_hf_v2(const char *path, int adflags, mode_t mode, struct adou } /* retry with O_CREAT */ - ad->ad_mdp->adf_fd = open(ad_p, oflags, admode); - if ( ad->ad_mdp->adf_fd < 0 ) - return ad_error(ad, adflags); - + EC_NEG1_LOG( ad_meta_fileno(ad) = open(ad_p, oflags, admode) ); ad->ad_mdp->adf_flags = oflags; /* just created, set owner if admin owner (root) */ if (!st_invalid) ad_chown(ad_p, &st_dir); break; default: - return -1; + EC_FAIL; } } + /* Now we've got a new opened fd, we need to check that in the error case */ + opened = 1; + if (!(ad->ad_mdp->adf_flags & O_CREAT)) { /* check for 0 length files, treat them as new. */ if (fstat(ad->ad_mdp->adf_fd, &st_meta) == 0) { @@ -900,26 +921,26 @@ static int ad_open_hf_v2(const char *path, int adflags, mode_t mode, struct adou if ((ad->ad_mdp->adf_flags & ( O_TRUNC | O_CREAT ))) { /* This is a new adouble header file, create it */ - if (new_ad_header(ad, path, pst, adflags) < 0) { - int err = errno; - /* the file is already deleted, perm, whatever, so return an error */ - ad_close(ad, adflags); - errno = err; - return -1; - } + EC_NEG1_LOG( new_ad_header(ad, path, pst, adflags) ); ad_flush(ad); } else { /* Read the adouble header in and parse it.*/ - if (ad->ad_ops->ad_header_read(path, ad, pst) < 0 - || ad->ad_ops->ad_header_upgrade(ad, ad_p) < 0) { - int err = errno; - ad_close(ad, adflags); - errno = err; - return -1; - } + EC_NEG1_LOG( ad->ad_ops->ad_header_read(path, ad, pst) ); } - return 0; +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; + } + LOG(log_debug, logtype_default, + "ad_open_hf_v2(\"%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_ea(const char *path, int adflags, int mode, struct adouble *ad) @@ -936,7 +957,7 @@ static int ad_open_hf_ea(const char *path, int adflags, int mode, struct adouble 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)); + oflags = O_NOFOLLOW | (ad2openflags(ADFLAGS_DF, adflags) & ~(O_CREAT | O_TRUNC)); if (ad_meta_fileno(ad) == -2) /* symlink */ @@ -1098,7 +1119,7 @@ static int ad_open_rf(const char *path, int adflags, int mode, struct adouble *a LOG(log_debug, logtype_default, "ad_open_rf(\"%s\"): BEGIN", fullpathname(path)); - oflags = O_NOFOLLOW | (ad2openflags(adflags) & ~O_CREAT); + oflags = O_NOFOLLOW | (ad2openflags(ADFLAGS_HF, adflags) & ~O_CREAT); if (ad_reso_fileno(ad) != -1) { /* the file is already open, but we want write access: */ @@ -1185,6 +1206,24 @@ EC_CLEANUP: * API functions ********************************************************************************* */ +off_t ad_getentryoff(const struct adouble *ad, int eid) +{ + if (ad->ad_vers == AD_VERSION2) + return ad->ad_eid[ADEID_RFORK].ade_off; + + if (eid == ADEID_DFORK) { + return 0; + } else if (eid == ADEID_RFORK) { +#ifdef HAVE_EAFD + return 0; +#else + return ADEDOFF_RFORK_OSX; +#endif + } else { + return ad->ad_eid[eid].ade_off; + } +} + const char *ad_path_ea( const char *path, int adflags _U_) { return path; @@ -1467,6 +1506,11 @@ int ad_open(struct adouble *ad, const char *path, int adflags, ...) /* Checking for open forks requires sharemode lock support (ie RDWR instead of RDONLY) */ adflags |= ADFLAGS_SETSHRMD; + if ((ad->ad_vers == AD_VERSION2) && (adflags & ADFLAGS_SETSHRMD)) { + /* sharemode locks are stored in the data fork, adouble:v2 needs this extra handling */ + adflags |= ADFLAGS_DF; + } + if ((ad->ad_vers == AD_VERSION2) && (adflags & ADFLAGS_RF)) { adflags |= ADFLAGS_HF; if (adflags & ADFLAGS_NORF) diff --git a/libatalk/vfs/vfs.c b/libatalk/vfs/vfs.c index 57d64ba1..2d150cc4 100644 --- a/libatalk/vfs/vfs.c +++ b/libatalk/vfs/vfs.c @@ -295,8 +295,6 @@ static int RF_renamefile_adouble(VFS_FUNC_ARGS_RENAMEFILE) static int RF_copyfile_adouble(VFS_FUNC_ARGS_COPYFILE) /* const struct vol *vol, int sfd, const char *src, const char *dst */ { - return 0; -#if 0 EC_INIT; bstring s = NULL, d = NULL; char *dup1 = NULL; @@ -341,7 +339,10 @@ static int RF_copyfile_adouble(VFS_FUNC_ARGS_COPYFILE) EC_ZERO(bcatcstr(d, name)); } - EC_ZERO(copy_file(sfd, cfrombstr(s), cfrombstr(d), 0666)); + /* ignore errors */ + if (copy_file(sfd, cfrombstr(s), cfrombstr(d), 0666) != 0) + if (errno != ENOENT) + EC_FAIL; EC_CLEANUP: bdestroy(s); @@ -352,7 +353,6 @@ EC_CLEANUP: if (dup4) free(dup4); EC_EXIT; -#endif } #ifdef HAVE_SOLARIS_ACLS @@ -580,6 +580,7 @@ static int RF_deletefile_ea(VFS_FUNC_ARGS_DELETEFILE) } static int RF_copyfile_ea(VFS_FUNC_ARGS_COPYFILE) { + /* the EA VFS module does this all for us */ return 0; #if 0 EC_INIT; -- 2.39.2