X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libatalk%2Fadouble%2Fad_lock.c;h=d5b58f8c954bd52ea1be7d5e90e4c84ccedab5b3;hb=296eb8dfd48fb30bbc4b2371c3e1dabefe9d833d;hp=df529493f7d59140a8bcf3191c5611bec93c79c2;hpb=51ed4be5afb6cdb829a6a4f94edbfc90dc542cac;p=netatalk.git diff --git a/libatalk/adouble/ad_lock.c b/libatalk/adouble/ad_lock.c index df529493..d5b58f8c 100644 --- a/libatalk/adouble/ad_lock.c +++ b/libatalk/adouble/ad_lock.c @@ -1,5 +1,5 @@ /* - * $Id: ad_lock.c,v 1.16 2009-10-21 10:49:36 didg Exp $ + * $Id: ad_lock.c,v 1.20 2010-03-30 12:55:26 franklahm Exp $ * * Copyright (c) 1998,1999 Adrian Sun (asun@zoology.washington.edu) * All Rights Reserved. See COPYRIGHT for more information. @@ -39,6 +39,18 @@ #define fcntl(a, b, c ) (0) #endif +/* ----------------------- */ +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); +} + /* ----------------------- */ static int XLATE_FCNTL_LOCK(int type) { @@ -75,7 +87,7 @@ static void adf_freelock(struct ad_fd *ad, const int i) free(lock->refcount); if (!ad->adf_excl) { lock->lock.l_type = F_UNLCK; - fcntl(ad->adf_fd, F_SETLK, &lock->lock); /* unlock */ + set_lock(ad->adf_fd, F_SETLK, &lock->lock); /* unlock */ } } @@ -117,12 +129,15 @@ static void adf_unlock(struct ad_fd *ad, const int fork) 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; + } } } @@ -136,7 +151,7 @@ static void adf_relockrange(struct ad_fd *ad, int fd, if (!ad->adf_excl) for (i = 0; i < ad->adf_lockcount; i++) { if (OVERLAP(off, len, lock[i].lock.l_start, lock[i].lock.l_len)) - fcntl(fd, F_SETLK, &lock[i].lock); + set_lock(fd, F_SETLK, &lock[i].lock); } } @@ -194,10 +209,10 @@ 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_RSRC_RD (0) -#define LOCK_RSRC_WR (1) -#define LOCK_DATA_RD (2) -#define LOCK_DATA_WR (3) +#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) @@ -340,7 +355,7 @@ int ad_fcntl_lock(struct adouble *ad, const u_int32_t eid, const int locktype, } /* attempt to lock the file. */ - if (!adf->adf_excl && fcntl(adf->adf_fd, F_SETLK, &lock) < 0) + if (!adf->adf_excl && set_lock(adf->adf_fd, F_SETLK, &lock) < 0) return -1; /* we upgraded this lock. */ @@ -382,7 +397,7 @@ int ad_fcntl_lock(struct adouble *ad, const u_int32_t eid, const int locktype, fcntl_lock_err: lock.l_type = F_UNLCK; - if (!adf->adf_excl) fcntl(adf->adf_fd, F_SETLK, &lock); + if (!adf->adf_excl) set_lock(adf->adf_fd, F_SETLK, &lock); return -1; } @@ -394,43 +409,28 @@ fcntl_lock_err: error ==> -1 */ -int ad_testlock(struct adouble *ad, int eid, const off_t off) +static int testlock(struct ad_fd *adf, off_t off, off_t len) { struct flock lock; - struct ad_fd *adf; adf_lock_t *plock; int i; lock.l_start = off; - if (eid == ADEID_DFORK) { - adf = &ad->ad_data_fork; - if ((ad_meta_fileno(ad) != -1)) { - adf = ad->ad_md; - lock.l_start = df2off(off); - } - } - else { /* rfork */ - if ((ad_meta_fileno(ad) == -1)) { - /* there's no resource fork. return no lock */ - return 0; - } - adf = ad->ad_md; - lock.l_start = hf2off(off); - } plock = adf->adf_lock; - /* Do we have a lock? */ lock.l_whence = SEEK_SET; - lock.l_len = 1; + lock.l_len = len; + + /* Do we have a lock? */ for (i = 0; i < adf->adf_lockcount; i++) { if (OVERLAP(lock.l_start, 1, plock[i].lock.l_start, plock[i].lock.l_len)) return 1; /* */ } /* Does another process have a lock? */ - lock.l_type = (adf->adf_flags & O_RDWR) ?F_WRLCK : F_RDLCK; + lock.l_type = (adf->adf_flags & O_RDWR) ?F_WRLCK : F_RDLCK; - if (fcntl(adf->adf_fd, F_GETLK, &lock) < 0) { + if (set_lock(adf->adf_fd, F_GETLK, &lock) < 0) { /* is that kind of error possible ?*/ return (errno == EACCES || errno == EAGAIN)?1:-1; } @@ -441,6 +441,92 @@ int ad_testlock(struct adouble *ad, int eid, const off_t off) return 1; } +/* --------------- */ +int ad_testlock(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_md; + 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_md; + lock_offset = hf2off(off); + } + return testlock(adf, lock_offset, 1); +} + +/* ------------------------- + return if a file is open by another process. + Optimized for the common case: + - there's no locks held by another process (clients) + - or we already know the answer and don't need to test. +*/ +u_int16_t ad_openforks(struct adouble *ad, u_int16_t attrbits) +{ + u_int16_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_md; + 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_md; + 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_md; + off = LOCK_RSRC_WR; + ret |= testlock(adf, off, 2) > 0? ATTRBIT_ROPEN : 0; + } + } + + return ret; +} + /* ------------------------- */ int ad_fcntl_tmplock(struct adouble *ad, const u_int32_t eid, const int locktype, @@ -495,7 +581,7 @@ int ad_fcntl_tmplock(struct adouble *ad, const u_int32_t eid, const int locktype * we just want to upgrade all the locks and then downgrade them * here. */ if (!adf->adf_excl) { - err = fcntl(adf->adf_fd, F_SETLK, &lock); + err = set_lock(adf->adf_fd, F_SETLK, &lock); } else { err = 0; @@ -528,7 +614,7 @@ int ad_excl_lock(struct adouble *ad, const u_int32_t eid) lock.l_start = ad_getentryoff(ad, eid); } - err = fcntl(adf->adf_fd, F_SETLK, &lock); + err = set_lock(adf->adf_fd, F_SETLK, &lock); if (!err) adf->adf_excl = 1; return err;