X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libatalk%2Fadouble%2Fad_lock.c;h=8222500b0c46135cda15a7eacd22b7aa4ad78340;hb=22ce5ab8206909a9972ee1b95cdd65c3ae403ae6;hp=22ceef504c9a2fc20fe453e8459ccd282076929d;hpb=6749df4c02d3d97fcf7078110c329e389d924863;p=netatalk.git diff --git a/libatalk/adouble/ad_lock.c b/libatalk/adouble/ad_lock.c index 22ceef50..8222500b 100644 --- a/libatalk/adouble/ad_lock.c +++ b/libatalk/adouble/ad_lock.c @@ -1,5 +1,5 @@ /* - * $Id: ad_lock.c,v 1.6 2002-11-14 17:15:22 srittau Exp $ + * $Id: ad_lock.c,v 1.11 2003-02-16 12:35:05 didg Exp $ * * Copyright (c) 1998,1999 Adrian Sun (asun@zoology.washington.edu) * All Rights Reserved. See COPYRIGHT for more information. @@ -40,15 +40,27 @@ ((type) == ADLOCK_WR ? LOCK_EX : \ ((type) == ADLOCK_CLR ? LOCK_UN : -1))) -#define XLATE_FCNTL_LOCK(type) ((type) == ADLOCK_RD ? F_RDLCK : \ -((type) == ADLOCK_WR ? F_WRLCK : \ - ((type) == ADLOCK_CLR ? F_UNLCK : -1))) - -#define OVERLAP(a,alen,b,blen) ((!(alen) && (a) <= (b)) || \ - (!(blen) && (b) <= (a)) || \ - ((((a) + (alen)) > (b)) && \ - (((b) + (blen)) > (a)))) +/* ----------------------- */ +static int XLATE_FCNTL_LOCK(int type) +{ + switch(type) { + case ADLOCK_RD: + return F_RDLCK; + case ADLOCK_WR: + return F_WRLCK; + case ADLOCK_CLR: + return F_UNLCK; + } + return -1; +} +/* ----------------------- */ +static int OVERLAP(off_t a, off_t alen, off_t b, off_t blen) +{ + return (!alen && a <= b) || + (!blen && b <= a) || + ( (a + alen > b) && (b + blen > a) ); +} /* allocation for lock regions. we allocate aggressively and shrink * only in large chunks. */ @@ -62,8 +74,10 @@ static __inline__ void adf_freelock(struct ad_fd *ad, const int i) if (--(*lock->refcount) < 1) { free(lock->refcount); - lock->lock.l_type = F_UNLCK; - fcntl(ad->adf_fd, F_SETLK, &lock->lock); /* unlock */ + if (!ad->adf_excl) { + lock->lock.l_type = F_UNLCK; + fcntl(ad->adf_fd, F_SETLK, &lock->lock); /* unlock */ + } } ad->adf_lockcount--; @@ -116,12 +130,12 @@ static __inline__ void adf_unlock(struct ad_fd *ad, int fd, const int user) /* relock any byte lock that overlaps off/len. unlock everything * else. */ static __inline__ void adf_relockrange(struct ad_fd *ad, int fd, - const off_t off, const size_t len) + const off_t off, const off_t len) { adf_lock_t *lock = ad->adf_lock; int i; - for (i = 0; i < ad->adf_lockcount; i++) { + 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); } @@ -132,7 +146,7 @@ static __inline__ void adf_relockrange(struct ad_fd *ad, int fd, static __inline__ int adf_findlock(struct ad_fd *ad, const int user, const int type, const off_t off, - const size_t len) + const off_t len) { adf_lock_t *lock = ad->adf_lock; int i; @@ -154,7 +168,7 @@ static __inline__ int adf_findlock(struct ad_fd *ad, static __inline__ int adf_findxlock(struct ad_fd *ad, const int user, const int type, const off_t off, - const size_t len) + const off_t len) { adf_lock_t *lock = ad->adf_lock; int i; @@ -198,7 +212,7 @@ static __inline__ int adf_findxlock(struct ad_fd *ad, translate a data fork lock to an offset */ -static int df2off(int off) +static off_t df2off(int off) { int start = off; if (off == AD_FILELOCK_OPEN_WR) @@ -218,7 +232,7 @@ int start = off; translate a resource fork lock to an offset */ -static int hf2off(int off) +static off_t hf2off(int off) { int start = off; if (off == AD_FILELOCK_OPEN_WR) @@ -234,20 +248,24 @@ int start = off; return start; } -int ad_fcntl_lock(struct adouble *ad, const u_int32_t eid, const int type, - const off_t off, const size_t len, const int user) +/* ------------------ */ +int ad_fcntl_lock(struct adouble *ad, const u_int32_t eid, const int locktype, + const off_t off, const off_t len, const int user) { struct flock lock; struct ad_fd *adf; - adf_lock_t *adflock, *oldlock; + adf_lock_t *adflock; + int oldlock; int i; - + int type; + lock.l_start = off; + type = locktype; if (eid == ADEID_DFORK) { adf = &ad->ad_df; if ((type & ADLOCK_FILELOCK)) { if (ad_hfileno(ad) != -1) { - lock.l_start = df2off(off); + lock.l_start = df2off(off); adf = &ad->ad_hf; } } @@ -258,8 +276,22 @@ int ad_fcntl_lock(struct adouble *ad, const u_int32_t eid, const int type, else lock.l_start += ad_getentryoff(ad, eid); } - + /* NOTE: we can't write lock a read-only file. on those, we just + * make sure that we have a read lock set. that way, we at least prevent + * someone else from really setting a deny read/write on the file. + */ + if (!(adf->adf_flags & O_RDWR) && (type & ADLOCK_WR)) { + type = (type & ~ADLOCK_WR) | ADLOCK_RD; + } + lock.l_type = XLATE_FCNTL_LOCK(type & ADLOCK_MASK); + lock.l_whence = SEEK_SET; + lock.l_len = len; + + /* byte_lock(len=-1) lock whole file */ + if (len == BYTELOCK_MAX) { + lock.l_len -= lock.l_start; /* otherwise EOVERFLOW error */ + } /* see if it's locked by another user. * NOTE: this guarantees that any existing locks must be at most @@ -267,13 +299,13 @@ int ad_fcntl_lock(struct adouble *ad, const u_int32_t eid, const int type, * guaranteed to be ORable. */ if (adf_findxlock(adf, user, ADLOCK_WR | ((type & ADLOCK_WR) ? ADLOCK_RD : 0), - lock.l_start, len) > -1) { + lock.l_start, lock.l_len) > -1) { errno = EACCES; return -1; } /* look for any existing lock that we may have */ - i = adf_findlock(adf, user, ADLOCK_RD | ADLOCK_WR, lock.l_start, len); + i = adf_findlock(adf, user, ADLOCK_RD | ADLOCK_WR, lock.l_start, lock.l_len); adflock = (i < 0) ? NULL : adf->adf_lock + i; /* here's what we check for: @@ -283,13 +315,11 @@ int ad_fcntl_lock(struct adouble *ad, const u_int32_t eid, const int type, if ((!adflock && (lock.l_type == F_UNLCK)) || (adflock && !(type & ADLOCK_UPGRADE) && ((lock.l_type != F_UNLCK) || (adflock->lock.l_start != lock.l_start) || - (adflock->lock.l_len != len)))) { + (adflock->lock.l_len != lock.l_len)))) { errno = EINVAL; return -1; } - lock.l_whence = SEEK_SET; - lock.l_len = len; /* now, update our list of locks */ /* clear the lock */ @@ -299,7 +329,7 @@ int ad_fcntl_lock(struct adouble *ad, const u_int32_t eid, const int type, } /* attempt to lock the file. */ - if (fcntl(adf->adf_fd, F_SETLK, &lock) < 0) + if (!adf->adf_excl && fcntl(adf->adf_fd, F_SETLK, &lock) < 0) return -1; /* we upgraded this lock. */ @@ -309,10 +339,9 @@ int ad_fcntl_lock(struct adouble *ad, const u_int32_t eid, const int type, } /* it wasn't an upgrade */ - oldlock = NULL; - if ((lock.l_type = F_RDLCK) && - ((i = adf_findxlock(adf, user, ADLOCK_RD, lock.l_start, len)) > -1)) { - oldlock = adf->adf_lock + i; + oldlock = -1; + if (lock.l_type == F_RDLCK) { + oldlock = adf_findxlock(adf, user, ADLOCK_RD, lock.l_start, lock.l_len); } /* no more space. this will also happen if lockmax == lockcount == 0 */ @@ -330,9 +359,9 @@ int ad_fcntl_lock(struct adouble *ad, const u_int32_t eid, const int type, /* fill in fields */ memcpy(&adflock->lock, &lock, sizeof(lock)); adflock->user = user; - if (oldlock) - adflock->refcount = oldlock->refcount; - else if ((adflock->refcount = calloc(1, sizeof(int))) == NULL) { + if (oldlock > -1) { + adflock->refcount = (adf->adf_lock + oldlock)->refcount; + } else if ((adflock->refcount = calloc(1, sizeof(int))) == NULL) { goto fcntl_lock_err; } @@ -342,7 +371,7 @@ int ad_fcntl_lock(struct adouble *ad, const u_int32_t eid, const int type, fcntl_lock_err: lock.l_type = F_UNLCK; - fcntl(adf->adf_fd, F_SETLK, &lock); + if (!adf->adf_excl) fcntl(adf->adf_fd, F_SETLK, &lock); return -1; } @@ -384,7 +413,7 @@ int ad_testlock(struct adouble *ad, int eid, const off_t off) /* Does another process have a lock? FIXME F_GETLK ? */ - lock.l_type = (ad_getoflags(ad, eid) & O_RDWR) ?F_WRLCK : F_RDLCK; + lock.l_type = (adf->adf_flags & O_RDWR) ?F_WRLCK : F_RDLCK; if (fcntl(adf->adf_fd, F_SETLK, &lock) < 0) { return (errno == EACCES || errno == EAGAIN)?1:-1; @@ -396,17 +425,16 @@ int ad_testlock(struct adouble *ad, int eid, const off_t off) /* ------------------------- */ -/* with temp locks, we don't need to distinguish within the same - * process as everything is single-threaded. in addition, if - * multi-threading gets added, it will only be in a few areas. */ -int ad_fcntl_tmplock(struct adouble *ad, const u_int32_t eid, const int type, - const off_t off, const size_t len) +int ad_fcntl_tmplock(struct adouble *ad, const u_int32_t eid, const int locktype, + const off_t off, const off_t len, const int user) { struct flock lock; struct ad_fd *adf; int err; + int type; lock.l_start = off; + type = locktype; if (eid == ADEID_DFORK) { adf = &ad->ad_df; } else { @@ -420,24 +448,68 @@ int ad_fcntl_tmplock(struct adouble *ad, const u_int32_t eid, const int type, if (!(type & ADLOCK_FILELOCK)) lock.l_start += ad_getentryoff(ad, eid); } + + if (!(adf->adf_flags & O_RDWR) && (type & ADLOCK_WR)) { + type = (type & ~ADLOCK_WR) | ADLOCK_RD; + } + lock.l_type = XLATE_FCNTL_LOCK(type & ADLOCK_MASK); lock.l_whence = SEEK_SET; lock.l_len = len; + /* see if it's locked by another user. */ + if (user && adf_findxlock(adf, user, ADLOCK_WR | + ((type & ADLOCK_WR) ? ADLOCK_RD : 0), + lock.l_start, lock.l_len) > -1) { + errno = EACCES; + return -1; + } + /* okay, we might have ranges byte-locked. we need to make sure that * we restore the appropriate ranges once we're done. so, we check * for overlap on an unlock and relock. * XXX: in the future, all the byte locks will be sorted and contiguous. * we just want to upgrade all the locks and then downgrade them * here. */ - err = fcntl(adf->adf_fd, F_SETLK, &lock); + if (!adf->adf_excl) { + err = fcntl(adf->adf_fd, F_SETLK, &lock); + } + else { + err = 0; + } if (!err && (lock.l_type == F_UNLCK)) adf_relockrange(adf, adf->adf_fd, lock.l_start, len); return err; } +/* ------------------------- + the fork is opened in Read Write, Deny Read, Deny Write mode + lock the whole file once +*/ +int ad_excl_lock(struct adouble *ad, const u_int32_t eid) +{ + struct ad_fd *adf; + struct flock lock; + int err; + + if (eid == ADEID_DFORK) { + adf = &ad->ad_df; + } else { + adf = &ad->ad_hf; + } + lock.l_start = 0; + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + + err = fcntl(adf->adf_fd, F_SETLK, &lock); + if (!err) + adf->adf_excl = 1; + return err; +} +/* --------------------- */ void ad_fcntl_unlock(struct adouble *ad, const int user) { if (ad->ad_df.adf_fd != -1) {