]> arthur.barton.de Git - netatalk.git/blobdiff - libatalk/adouble/ad_lock.c
Remove empty adoubel rfork and use UNIX name in struct adouble
[netatalk.git] / libatalk / adouble / ad_lock.c
index 6961930d4e3925babc3d8e4c26e0d78dd8506e9b..bdae8dc473ad11c99fef7913c11a5503dde1cb7f 100644 (file)
@@ -18,6 +18,9 @@
 
 #include <atalk/adouble.h>
 #include <atalk/logger.h>
+#include <atalk/compat.h>
+#include <atalk/errchk.h>
+#include <atalk/util.h>
 
 #include <stdio.h>
 #include <stdlib.h>
 
 #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;
 }