X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libatalk%2Fadouble%2Fad_lock.c;h=bdae8dc473ad11c99fef7913c11a5503dde1cb7f;hb=080aff015fa627cab032d6009ff3b27e7c2a46d6;hp=6961930d4e3925babc3d8e4c26e0d78dd8506e9b;hpb=5737d08e3c85485df6ad56d7be7423d6309e9b94;p=netatalk.git diff --git a/libatalk/adouble/ad_lock.c b/libatalk/adouble/ad_lock.c index 6961930d..bdae8dc4 100644 --- a/libatalk/adouble/ad_lock.c +++ b/libatalk/adouble/ad_lock.c @@ -18,6 +18,9 @@ #include #include +#include +#include +#include #include #include @@ -28,16 +31,57 @@ #include "ad_lock.h" +static const char *shmdstrfromoff(off_t off) +{ + switch (off) { + case AD_FILELOCK_OPEN_WR: + return "OPEN_WR_DATA"; + case AD_FILELOCK_OPEN_RD: + return "OPEN_RD_DATA"; + case AD_FILELOCK_RSRC_OPEN_WR: + return "OPEN_WR_RSRC"; + case AD_FILELOCK_RSRC_OPEN_RD: + return "OPEN_RD_RSRC"; + case AD_FILELOCK_DENY_WR: + return "DENY_WR_DATA"; + case AD_FILELOCK_DENY_RD: + return "DENY_RD_DATA"; + case AD_FILELOCK_RSRC_DENY_WR: + return "DENY_WR_RSRC"; + case AD_FILELOCK_RSRC_DENY_RD: + return "DENY_RD_RSRC"; + case AD_FILELOCK_OPEN_NONE: + return "OPEN_NONE_DATA"; + case AD_FILELOCK_RSRC_OPEN_NONE: + return "OPEN_NONE_RSRC"; + default: + return "-"; + } +} + /* ----------------------- */ static int set_lock(int fd, int cmd, struct flock *lock) { - if (fd == -2) { - /* We assign fd = -2 for symlinks -> do nothing */ - if (cmd == F_GETLK) - lock->l_type = F_UNLCK; - return 0; - } - return fcntl(fd, cmd, lock); + EC_INIT; + + LOG(log_debug, logtype_default, "set_lock(fd: %d, %s, %s, off: %jd (%s), len: %jd): BEGIN", + fd, cmd == F_SETLK ? "F_SETLK" : "F_GETLK", + lock->l_type == F_RDLCK ? "F_RDLCK" : lock->l_type == F_WRLCK ? "F_WRLCK" : "F_UNLCK", + (intmax_t)lock->l_start, + shmdstrfromoff(lock->l_start), + (intmax_t)lock->l_len); + + if (fd == -2) { + /* We assign fd = -2 for symlinks -> do nothing */ + if (cmd == F_GETLK) + lock->l_type = F_UNLCK; + return 0; + } + + EC_NEG1( fcntl(fd, cmd, lock) ); + +EC_CLEANUP: + EC_EXIT; } /* ----------------------- */ @@ -104,27 +148,28 @@ static void adf_freelock(struct ad_fd *ad, const int i) /* this needs to deal with the following cases: - * 1) fork is the only user of the lock - * 2) fork shares a read lock with another open fork + * 1) free all UNIX byterange lock from any fork + * 2) free all locks of the requested fork * * 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].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); - i--; /* we shifted things down, so we need to backtrack */ - /* unlikely but realloc may have change adf_lock */ - lock = ad->adf_lock; - } + 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(adf, i); + /* we shifted things down, so we need to backtrack */ + i--; + /* unlikely but realloc may have change adf_lock */ + lock = adf->adf_lock; + } } } @@ -197,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 @@ -314,124 +307,45 @@ 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) +#define LTYPE2STRBUFSIZ 128 +static const char *locktypetostr(int type) { - 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; -} - -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 (!(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; -} + int first = 1; + static char buf[LTYPE2STRBUFSIZ]; -static int ad_testlock_v2(struct adouble *ad, int eid, const off_t off) -{ - struct ad_fd *adf; - off_t lock_offset; + buf[0] = 0; - 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); + if (type == 0) { + strlcat(buf, "CLR", LTYPE2STRBUFSIZ); + first = 0; + return buf; } - 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); + if (type & ADLOCK_RD) { + if (!first) + strlcat(buf, "|", LTYPE2STRBUFSIZ); + strlcat(buf, "RD", LTYPE2STRBUFSIZ); + first = 0; + } + if (type & ADLOCK_WR) { + if (!first) + strlcat(buf, "|", LTYPE2STRBUFSIZ); + strlcat(buf, "WR", LTYPE2STRBUFSIZ); + first = 0; + } + if (type & ADLOCK_UPGRADE) { + if (!first) + strlcat(buf, "|", LTYPE2STRBUFSIZ); + strlcat(buf, "UPG", LTYPE2STRBUFSIZ); + first = 0; + } + if (type & ADLOCK_FILELOCK) { + if (!first) + strlcat(buf, "|", LTYPE2STRBUFSIZ); + strlcat(buf, "FILELOCK", LTYPE2STRBUFSIZ); + first = 0; } - return testlock(&ad->ad_data_fork, lock_offset, 1); + + return buf; } /****************************************************************************** @@ -446,53 +360,30 @@ int ad_lock(struct adouble *ad, uint32_t eid, int locktype, off_t off, off_t len int oldlock; int i; int type; + int ret = 0, fcntl_lock_err = 0; - if ((type & ADLOCK_FILELOCK) && (len != 1)) - /* safety check */ - return -1; + LOG(log_debug, logtype_default, "ad_lock(%s, %s, off: %jd (%s), len: %jd): BEGIN", + eid == ADEID_DFORK ? "data" : "reso", + locktypetostr(locktype), + (intmax_t)off, + shmdstrfromoff(off), + (intmax_t)len); + + 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 ((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; - return -1; - } - 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) { - lock.l_start = rf2off(off); - } else { - /* it's a byterange lock on the rsrcfork -> discard it */ - return 0; - } + if (type & ADLOCK_FILELOCK) { adf = &ad->ad_data_fork; - break; - - default: - return -1; + lock.l_start = rf2off(off); + } else { + adf = ad->ad_rfp; + lock.l_start = off + ad_getentryoff(ad, ADEID_RFORK); } } @@ -521,7 +412,8 @@ int ad_lock(struct adouble *ad, uint32_t eid, int locktype, off_t off, off_t len ((type & ADLOCK_WR) ? ADLOCK_RD : 0), lock.l_start, lock.l_len) > -1) { errno = EACCES; - return -1; + ret = -1; + goto exit; } /* look for any existing lock that we may have */ @@ -541,7 +433,8 @@ int ad_lock(struct adouble *ad, uint32_t eid, int locktype, off_t off, off_t len || (adflock->lock.l_len != lock.l_len) )) ) { errno = EINVAL; - return -1; + ret = -1; + goto exit; } @@ -549,17 +442,19 @@ int ad_lock(struct adouble *ad, uint32_t eid, int locktype, off_t off, off_t len /* clear the lock */ if (lock.l_type == F_UNLCK) { adf_freelock(adf, i); - return 0; + goto exit; } /* attempt to lock the file. */ - if (set_lock(adf->adf_fd, F_SETLK, &lock) < 0) - return -1; + if (set_lock(adf->adf_fd, F_SETLK, &lock) < 0) { + ret = -1; + goto exit; + } /* we upgraded this lock. */ if (adflock && (type & ADLOCK_UPGRADE)) { memcpy(&adflock->lock, &lock, sizeof(lock)); - return 0; + goto exit; } /* it wasn't an upgrade */ @@ -573,8 +468,10 @@ int ad_lock(struct adouble *ad, uint32_t eid, int locktype, off_t off, off_t len adf_lock_t *tmp = (adf_lock_t *) realloc(adf->adf_lock, sizeof(adf_lock_t)* (adf->adf_lockmax + ARRAY_BLOCK_SIZE)); - if (!tmp) - goto fcntl_lock_err; + if (!tmp) { + ret = fcntl_lock_err = -1; + goto exit; + } adf->adf_lock = tmp; adf->adf_lockmax += ARRAY_BLOCK_SIZE; } @@ -586,39 +483,49 @@ int ad_lock(struct adouble *ad, uint32_t eid, int locktype, off_t off, off_t len if (oldlock > -1) { adflock->refcount = (adf->adf_lock + oldlock)->refcount; } else if ((adflock->refcount = calloc(1, sizeof(int))) == NULL) { - goto fcntl_lock_err; + ret = fcntl_lock_err = 1; + goto exit; } (*adflock->refcount)++; adf->adf_lockcount++; - return 0; -fcntl_lock_err: - lock.l_type = F_UNLCK; - set_lock(adf->adf_fd, F_SETLK, &lock); - return -1; +exit: + if (ret != 0) { + if (fcntl_lock_err != 0) { + lock.l_type = F_UNLCK; + set_lock(adf->adf_fd, F_SETLK, &lock); + } + } + LOG(log_debug, logtype_default, "ad_lock: END: %d", ret); + return ret; } -/* ------------------------- -*/ -int ad_tmplock(struct adouble *ad, const uint32_t eid, const int locktype, - const off_t off, const off_t len, const int fork) +int ad_tmplock(struct adouble *ad, uint32_t eid, int locktype, off_t off, off_t len, int fork) { struct flock lock; struct ad_fd *adf; int err; int type; + LOG(log_debug, logtype_default, "ad_tmplock(%s, %s, off: %jd (%s), len: %jd): BEGIN", + eid == ADEID_DFORK ? "data" : "reso", + locktypetostr(locktype), + (intmax_t)off, + shmdstrfromoff(off), + (intmax_t)len); + 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 */ - return 0; + err = 0; + goto exit; } /* if ADLOCK_FILELOCK we want a lock from offset 0 * it's used when deleting a file: @@ -643,7 +550,8 @@ int ad_tmplock(struct adouble *ad, const uint32_t eid, const int locktype, ADLOCK_WR | ((type & ADLOCK_WR) ? ADLOCK_RD : 0), lock.l_start, lock.l_len) > -1) { errno = EACCES; - return -1; + err = -1; + goto exit; } /* okay, we might have ranges byte-locked. we need to make sure that @@ -656,18 +564,24 @@ int ad_tmplock(struct adouble *ad, const uint32_t eid, const int locktype, if (!err && (lock.l_type == F_UNLCK)) adf_relockrange(adf, adf->adf_fd, lock.l_start, len); +exit: + LOG(log_debug, logtype_default, "ad_tmplock: END: %d", err); return err; } /* --------------------- */ -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(unlckbrl: %d): BEGIN", 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: END"); } /*! @@ -682,14 +596,24 @@ void ad_unlock(struct adouble *ad, const int fork) */ int ad_testlock(struct adouble *ad, int eid, const off_t off) { - switch (ad->ad_vers) { - case AD_VERSION2: - return ad_testlock_v2(ad, eid, off); - case AD_VERSION_EA: - return ad_testlock_ea(ad, eid, off); - default: - return -1; + int ret = 0; + off_t lock_offset; + + LOG(log_debug, logtype_default, "ad_testlock(%s, off: %jd (%s): BEGIN", + eid == ADEID_DFORK ? "data" : "reso", + (intmax_t)off, + shmdstrfromoff(off)); + + 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; } /*! @@ -706,12 +630,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; }