]> arthur.barton.de Git - netatalk.git/commitdiff
Merge branch 'sendfile' into develop
authorFrank Lahm <franklahm@googlemail.com>
Sun, 29 Apr 2012 12:30:45 +0000 (14:30 +0200)
committerFrank Lahm <franklahm@googlemail.com>
Sun, 29 Apr 2012 12:30:45 +0000 (14:30 +0200)
13 files changed:
etc/afpd/desktop.c
etc/afpd/fork.c
include/atalk/adouble.h
include/atalk/dsi.h
include/atalk/globals.h
libatalk/adouble/ad_flush.c
libatalk/adouble/ad_lock.c
libatalk/adouble/ad_open.c
libatalk/adouble/ad_write.c
libatalk/dsi/dsi_read.c
libatalk/dsi/dsi_stream.c
libatalk/util/netatalk_conf.c
macros/netatalk.m4

index 6019150360f4d8a56a6bff4ce1108e1eabab3e4e..873cc0b1848b7fb8bad88c8db565e7eff79429f6 100644 (file)
@@ -485,15 +485,17 @@ int afp_geticon(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t
             return AFPERR_PARAM;
         }
 
+#ifndef WITH_SENDFILE
         if ((buflen = dsi_readinit(dsi, rbuf, buflen, rc, AFP_OK)) < 0)
             goto geticon_exit;
+#endif
 
         *rbuflen = buflen;
         /* do to the streaming nature, we have to exit if we encounter
          * a problem. much confusion results otherwise. */
         while (*rbuflen > 0) {
 #ifdef WITH_SENDFILE
-            if (dsi_stream_read_file(dsi, si.sdt_fd, offset, dsi->datasize) < 0) {
+            if (dsi_stream_read_file(dsi, si.sdt_fd, offset, dsi->datasize, AFP_OK) < 0) {
                 switch (errno) {
                 case ENOSYS:
                 case EINVAL:  /* there's no guarantee that all fs support sendfile */
index 96ac39363ad09930ca6b19255f69cda8e7ace4b8..3e557ad6b6c436ed9b196ee0ff1888b88489ead0 100644 (file)
@@ -165,7 +165,7 @@ static int fork_setmode(const AFPObj *obj, struct adouble *adp, int eid, int acc
 
         int fd = (eid == ADEID_DFORK) ? ad_data_fileno(adp) : ad_reso_fileno(adp);
 
-        if (fd != -1 && fd != -2 && fcntl(fd, F_SHARE, &shmd) != 0) {
+        if (fd != -1 && fd != AD_SYMLINK && fcntl(fd, F_SHARE, &shmd) != 0) {
             LOG(log_debug, logtype_afpd, "fork_setmode: fcntl: %s", strerror(errno));
             errno = EACCES;
             return -1;
@@ -739,10 +739,18 @@ int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t
 
 #undef UNLOCKBIT
 
-static ssize_t read_file(struct ofork *ofork, int eid,
-                         off_t offset, u_char nlmask,
-                         u_char nlchar, char *rbuf,
-                         size_t *rbuflen)
+/*!
+ * Read *rbuflen bytes from fork at offset
+ *
+ * @param ofork    (r)  fork handle
+ * @param eid      (r)  data fork or ressource fork entry id
+ * @param offset   (r)  offset
+ * @param rbuf     (r)  data buffer
+ * @param rbuflen  (rw) in: number of bytes to read, out: bytes read
+ *
+ * @return         AFP status code
+ */
+static int read_file(const struct ofork *ofork, int eid, off_t offset, char *rbuf, size_t *rbuflen)
 {
     ssize_t cc;
     int eof = 0;
@@ -754,53 +762,23 @@ static ssize_t read_file(struct ofork *ofork, int eid,
         *rbuflen = 0;
         return( AFPERR_PARAM );
     }
-    if ( (size_t)cc < *rbuflen ) {
-        eof = 1;
-    }
-
-    /*
-     * Do Newline check.
-     */
-    if ( nlmask != 0 ) {
-        for ( p = rbuf, q = p + cc; p < q; ) {
-            if (( *p++ & nlmask ) == nlchar ) {
-                break;
-            }
-        }
-        if ( p != q ) {
-            cc = p - rbuf;
-            eof = 0;
-        }
-    }
-
     *rbuflen = cc;
-    if ( eof ) {
-        return( AFPERR_EOF );
-    }
+
+    if ((size_t)cc < *rbuflen)
+        return AFPERR_EOF;
     return AFP_OK;
 }
 
-/* -----------------------------
- * with ddp, afp_read can return fewer bytes than in reqcount
- * so return EOF only if read actually past end of file not
- * if offset +reqcount > size of file
- * e.g.:
- * getfork size ==> 10430
- * read fork offset 0 size 10752 ????  ==> 4264 bytes (without EOF)
- * read fork offset 4264 size 6128 ==> 4264 (without EOF)
- * read fork offset 9248 size 1508 ==> 1182 (EOF)
- * 10752 is a bug in Mac 7.5.x finder
- *
- * with dsi, should we check that reqcount < server quantum?
- */
 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
 {
-    struct ofork    *ofork;
-    off_t       offset, saveoff, reqcount, savereqcount;
-    ssize_t     cc, err;
-    int         eid;
-    uint16_t       ofrefnum;
-    u_char      nlmask, nlchar;
+    DSI          *dsi = obj->dsi;
+    struct ofork *ofork;
+    off_t        offset, saveoff, reqcount, savereqcount, size;
+    ssize_t      cc, err;
+    int          eid;
+    uint16_t     ofrefnum;
+
+    /* we break the AFP spec here by not supporting nlmask and nlchar anymore */
 
     ibuf += 2;
     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
@@ -816,27 +794,6 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si
         err = AFPERR_ACCESS;
         goto afp_read_err;
     }
-    offset   = get_off_t(&ibuf, is64);
-    reqcount = get_off_t(&ibuf, is64);
-
-    LOG(log_debug, logtype_afpd,
-        "afp_read(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)", offset, reqcount,
-        (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
-
-    if (is64) {
-        nlmask = nlchar = 0;
-    }
-    else {
-        nlmask = *ibuf++;
-        nlchar = *ibuf++;
-    }
-    /* if we wanted to be picky, we could add in the following
-     * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
-     */
-    if (reqcount < 0 || offset < 0) {
-        err = AFPERR_PARAM;
-        goto afp_read_err;
-    }
 
     if ( ofork->of_flags & AFPFORK_DATA) {
         eid = ADEID_DFORK;
@@ -847,103 +804,115 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si
         goto afp_read_err;
     }
 
+    offset   = get_off_t(&ibuf, is64);
+    reqcount = get_off_t(&ibuf, is64);
+
     /* zero request count */
     err = AFP_OK;
     if (!reqcount) {
         goto afp_read_err;
     }
 
-    LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd)",
-        of_name(ofork), (intmax_t)offset, (intmax_t)reqcount);
+    /* reqcount isn't always truthful. we need to deal with that. */
+    size = ad_size(ofork->of_ad, eid);
+
+    LOG(log_debug, logtype_afpd,
+        "afp_read(off: %" PRIu64 ", len: %" PRIu64 ", fork: %s, size: %" PRIu64 ")",
+        offset, reqcount, (ofork->of_flags & AFPFORK_DATA) ? "d" : "r", size);
+
+    if (offset > size) {
+        err = AFPERR_EOF;
+        goto afp_read_err;
+    }
+
+    /* subtract off the offset */
+    if (reqcount + offset > size) {
+        reqcount = size - offset;
+        err = AFPERR_EOF;
+    }
 
     savereqcount = reqcount;
     saveoff = offset;
-    if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
-        err = AFPERR_LOCK;
+
+    LOG(log_debug, logtype_afpd,
+        "afp_read(off: %" PRIu64 ", len: %" PRIu64 ", fork: %s)",
+        offset, reqcount, (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
+
+    if (reqcount < 0 || offset < 0) {
+        err = AFPERR_PARAM;
         goto afp_read_err;
     }
 
+    LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd)",
+        of_name(ofork), (intmax_t)offset, (intmax_t)reqcount);
+
+    if (obj->options.flags & OPTION_AFP_READ_LOCK) {
+        if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, offset, reqcount, ofork->of_refnum) < 0) {
+            err = AFPERR_LOCK;
+            goto afp_read_err;
+        }
+    }
+
+#ifdef WITH_SENDFILE
+    if (!(eid == ADEID_DFORK && ad_data_fileno(ofork->of_ad) == AD_SYMLINK) &&
+        !(obj->options.flags & OPTION_NOSENDFILE)) {
+        int fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
+        if (dsi_stream_read_file(dsi, fd, offset, reqcount, err) < 0) {
+            LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s",
+                of_name(ofork), strerror(errno));
+            goto afp_read_exit;
+        }
+        dsi_readdone(dsi);
+        goto afp_read_done;
+    }
+#endif
+
     *rbuflen = MIN(reqcount, *rbuflen);
-    LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): reading %jd bytes from file",
-        of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
 
-    err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen);
+    err = read_file(ofork, eid, offset, rbuf, rbuflen);
     if (err < 0)
         goto afp_read_done;
-    LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file",
+
+    LOG(log_debug, logtype_afpd,
+        "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file",
         of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
 
-    /* dsi can stream requests. we can only do this if we're not checking
-     * for an end-of-line character. oh well. */
-    if ((*rbuflen < reqcount) && !nlmask) {
-        DSI    *dsi = obj->dsi;
-        off_t  size;
+    offset += *rbuflen;
 
-        /* reqcount isn't always truthful. we need to deal with that. */
-        size = ad_size(ofork->of_ad, eid);
+    /*
+     * dsi_readinit() returns size of next read buffer. by this point,
+     * we know that we're sending some data. if we fail, something
+     * horrible happened.
+     */
+    if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
+        goto afp_read_exit;
+    *rbuflen = cc;
 
-        /* subtract off the offset */
-        size -= offset;
-        if (reqcount > size) {
-            reqcount = size;
-            err = AFPERR_EOF;
-        }
+    while (*rbuflen > 0) {
+        cc = read_file(ofork, eid, offset, rbuf, rbuflen);
+        if (cc < 0)
+            goto afp_read_exit;
 
         offset += *rbuflen;
-
-        /* dsi_readinit() returns size of next read buffer. by this point,
-         * we know that we're sending some data. if we fail, something
-         * horrible happened. */
-        if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
+        /* dsi_read() also returns buffer size of next allocation */
+        cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
+        if (cc < 0)
             goto afp_read_exit;
         *rbuflen = cc;
-        /* due to the nature of afp packets, we have to exit if we get
-           an error. we can't do this with translation on. */
-#ifdef WITH_SENDFILE
-        if (!(obj->options.flags & OPTION_NOSENDFILE)) {
-            int fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
-            if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) { 
-               switch (errno) {
-                case EINVAL:
-                case ENOSYS:
-                    goto afp_read_loop;
-                default:
-                    LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
-                    goto afp_read_exit;
-                }
-            }
-
-            dsi_readdone(dsi);
-            goto afp_read_done;
-        }
-    afp_read_loop:
-#endif
-
-        /* fill up our buffer. */
-        while (*rbuflen > 0) {
-            cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen);
-            if (cc < 0)
-                goto afp_read_exit;
-
-            offset += *rbuflen;
-            /* dsi_read() also returns buffer size of next allocation */
-            cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
-            if (cc < 0)
-                goto afp_read_exit;
-            *rbuflen = cc;
-        }
-        dsi_readdone(dsi);
-        goto afp_read_done;
-
-    afp_read_exit:
-        LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
-        dsi_readdone(dsi);
-        ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
-        obj->exit(EXITERR_CLNT);
     }
+    dsi_readdone(dsi);
+    goto afp_read_done;
+
+afp_read_exit:
+    LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
+    dsi_readdone(dsi);
+   if (obj->options.flags & OPTION_AFP_READ_LOCK)
+       ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount, ofork->of_refnum);
+    obj->exit(EXITERR_CLNT);
 
 afp_read_done:
-    ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
+    if (obj->options.flags & OPTION_AFP_READ_LOCK)
+        ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount, ofork->of_refnum);
     return err;
 
 afp_read_err:
index f95279d7aa7779ada385ea7642799aad682b832e..44409ee2b184d197712a759547269d09c75ea065 100644 (file)
 #define ADEDOFF_FINDERI_OSX  (AD_HEADER_LEN + ADEID_NUM_OSX*AD_ENTRY_LEN)
 #define ADEDOFF_RFORK_OSX    (ADEDOFF_FINDERI_OSX + ADEDLEN_FINDERI)
 
+/* special fd value used to indicate an open fork file is a (not open) symlink */
+#define AD_SYMLINK -2
+
 typedef uint32_t cnid_t;
 
 struct ad_entry {
@@ -169,7 +172,7 @@ typedef struct adf_lock_t {
 } adf_lock_t;
 
 struct ad_fd {
-    int          adf_fd;        /* -1: invalid, -2: symlink */
+    int          adf_fd;        /* -1: invalid, AD_SYMLINK: symlink */
     char         *adf_syml;
     int          adf_flags;
     adf_lock_t   *adf_lock;
@@ -348,7 +351,7 @@ struct adouble {
 #define ad_reso_fileno(ad)  ((ad)->ad_rfp->adf_fd)
 #define ad_meta_fileno(ad)  ((ad)->ad_mdp->adf_fd)
 
-/* -1 means not open, -2 is a symlink */
+/* -1: not open, AD_SYMLINK (-2): it's a symlink */
 #define AD_DATA_OPEN(ad) ((ad)->ad_data_fork.adf_fd >= 0)
 #define AD_META_OPEN(ad) ((ad)->ad_mdp->adf_fd >= 0)
 #define AD_RSRC_OPEN(ad) ((ad)->ad_rfp->adf_fd >= 0)
index 5af4cac570457f5228ff36bf1729781e98e81df3..60afc18659f5140b59b36433dfc41105993efce0 100644 (file)
@@ -174,6 +174,8 @@ extern void dsi_getstatus (DSI *);
 extern void dsi_close (DSI *);
 
 #define DSI_NOWAIT 1
+#define DSI_MSG_MORE 2
+
 /* low-level stream commands -- in dsi_stream.c */
 extern ssize_t dsi_stream_write (DSI *, void *, const size_t, const int mode);
 extern size_t dsi_stream_read (DSI *, void *, const size_t);
@@ -182,7 +184,7 @@ extern int dsi_stream_receive (DSI *);
 extern int dsi_disconnect(DSI *dsi);
 
 #ifdef WITH_SENDFILE
-extern ssize_t dsi_stream_read_file(DSI *, int, off_t off, const size_t len);
+extern ssize_t dsi_stream_read_file(DSI *, int, off_t off, const size_t len, const int err);
 #endif
 
 /* client writes -- dsi_write.c */
index e25efdbd12fd585cb66e3de7e38f6e6e47e194f1..124c398865500dac322c971d9ae7f7234093c426 100644 (file)
@@ -39,6 +39,7 @@
 #define OPTION_SERVERNOTIF   (1 << 2)
 #define OPTION_NOSENDFILE    (1 << 3)
 #define OPTION_CUSTOMICON    (1 << 4)
+#define OPTION_AFP_READ_LOCK (1 << 5) /* whether to do AFP spec conforming read locks (default: no) */
 #define OPTION_ANNOUNCESSH   (1 << 6)
 #define OPTION_UUID          (1 << 7)
 #define OPTION_ACL2MACCESS   (1 << 8)
index 86a624e069cd4f7d557be7c545a7da4ef5ecd24b..eaf904cac77ab597d57e89ee0699a68d8788db01 100644 (file)
@@ -371,7 +371,7 @@ static int ad_data_closefd(struct adouble *ad)
 {
     int ret = 0;
 
-    if (ad_data_fileno(ad) == -2) {
+    if (ad_data_fileno(ad) == AD_SYMLINK) {
         free(ad->ad_data_fork.adf_syml);
         ad->ad_data_fork.adf_syml = NULL;
     } else {
@@ -408,7 +408,7 @@ int ad_close(struct adouble *ad, int adflags)
         adflags |= ADFLAGS_HF;
 
     if ((adflags & ADFLAGS_DF)
-        && (ad_data_fileno(ad) >= 0 || ad_data_fileno(ad) == -2) /* -2 means symlink */
+        && (ad_data_fileno(ad) >= 0 || ad_data_fileno(ad) == AD_SYMLINK)
         && --ad->ad_data_fork.adf_refcount == 0) {
         if (ad_data_closefd(ad) < 0)
             err = -1;
index bdae8dc473ad11c99fef7913c11a5503dde1cb7f..92f0ab89224501331c5a010dd323196ced0258b3 100644 (file)
@@ -71,8 +71,7 @@ static int set_lock(int fd, int cmd,  struct flock *lock)
         shmdstrfromoff(lock->l_start),
         (intmax_t)lock->l_len);
 
-    if (fd == -2) {
-        /* We assign fd = -2 for symlinks -> do nothing */
+    if (fd == AD_SYMLINK) {
         if (cmd == F_GETLK)
             lock->l_type = F_UNLCK;
         return 0;
index 79016b5feac43e1d6fed2110e2d5e320610470e9..bde46e57d7c2f42eb411f43ed38d9e3b03b4d211 100644 (file)
@@ -869,7 +869,7 @@ static int ad_open_df(const char *path, int adflags, mode_t mode, struct adouble
                 EC_FAIL;
             }
             ad->ad_data_fork.adf_syml[lsz] = 0;
-            ad->ad_data_fork.adf_fd = -2; /* -2 means its a symlink */
+            ad->ad_data_fork.adf_fd = AD_SYMLINK;
             break;
         default:
             EC_FAIL;
@@ -1041,7 +1041,7 @@ static int ad_open_hf_ea(const char *path, int adflags, int mode, struct adouble
 
     oflags = O_NOFOLLOW | (ad2openflags(ad, ADFLAGS_DF, adflags) & ~(O_CREAT | O_TRUNC));
 
-    if (ad_meta_fileno(ad) == -2)
+    if (ad_meta_fileno(ad) == AD_SYMLINK)
         /* symlink */
         EC_EXIT;
 
index 08554a274ae6f48d1ac940d826a5d1306d91b7f5..bfed9b400f27f8fd577310bc4052a76e2e6a5017 100644 (file)
@@ -55,8 +55,7 @@ ssize_t ad_write(struct adouble *ad, uint32_t eid, off_t off, int end, const cha
     size_t roundup;
     off_t    r_off;
 
-    if (ad_data_fileno(ad) == -2) {
-        /* It's a symlink */
+    if (ad_data_fileno(ad) == AD_SYMLINK) {
         errno = EACCES;
         return -1;
     }
index 75dfe9579d1c0923c3818a0b42255386f3e5fdd7..a0cbd872c2851a7ef2ba14021a52138f4a03d7ad 100644 (file)
@@ -23,8 +23,7 @@
  * it will send off the header plus whatever is in its command
  * buffer. it returns the amount of stuff still to be read
  * (constrained by the buffer size). */
-ssize_t dsi_readinit(DSI *dsi, void *buf, const size_t buflen,
-                     const size_t size, const int err)
+ssize_t dsi_readinit(DSI *dsi, void *buf, const size_t buflen, const size_t size, const int err)
 {
     LOG(log_maxdebug, logtype_dsi, "dsi_readinit: sending %zd bytes from buffer, total size: %zd",
         buflen, size);
index 6cda43453f52e0e85c5375b58dad6051b99da13e..97eb8ad717e96b17c493df472a2254be318a0c15 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 1998 Adrian Sun (asun@zoology.washington.edu)
+ * Copyright (c) 2010,2011,2012 Frank Lahm <franklahm@googlemail.com>
  * All rights reserved. See COPYRIGHT.
  *
  * this file provides the following functions:
 
 #include <stdio.h>
 #include <stdlib.h>
-
-#ifdef HAVE_UNISTD_H
 #include <unistd.h>
-#endif
-
 #include <string.h>
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/uio.h>
 
+#ifdef HAVE_SENDFILEV
+#include <sys/sendfile.h>
+#endif
+
 #include <atalk/logger.h>
 #include <atalk/dsi.h>
 #include <atalk/util.h>
 
-#define min(a,b)  ((a) < (b) ? (a) : (b))
-
 #ifndef MSG_MORE
 #define MSG_MORE 0x8000
 #endif
 #define MSG_DONTWAIT 0x40
 #endif
 
+/* Pack a DSI header in wire format */
+static void dsi_header_pack_reply(const DSI *dsi, char *buf)
+{
+    buf[0] = dsi->header.dsi_flags;
+    buf[1] = dsi->header.dsi_command;
+    memcpy(buf + 2, &dsi->header.dsi_requestID, sizeof(dsi->header.dsi_requestID));           
+    memcpy(buf + 4, &dsi->header.dsi_code, sizeof(dsi->header.dsi_code));
+    memcpy(buf + 8, &dsi->header.dsi_len, sizeof(dsi->header.dsi_len));
+    memcpy(buf + 12, &dsi->header.dsi_reserved, sizeof(dsi->header.dsi_reserved));
+}
+
 /*
  * afpd is sleeping too much while trying to send something.
  * May be there's no reader or the reader is also sleeping in write,
@@ -140,7 +150,7 @@ static size_t from_buf(DSI *dsi, uint8_t *buf, size_t count)
     nbe = dsi->eof - dsi->start;
 
     if (nbe > 0) {
-        nbe = min((size_t)nbe, count);
+        nbe = MIN((size_t)nbe, count);
         memcpy(buf, dsi->start, nbe);
         dsi->start += nbe;
 
@@ -200,7 +210,7 @@ static size_t dsi_buffered_stream_read(DSI *dsi, uint8_t *data, const size_t len
   }
 
   /* fill the buffer with 8192 bytes or until buffer is full */
-  buflen = min(8192, dsi->end - dsi->eof);
+  buflen = MIN(8192, dsi->end - dsi->eof);
   if (buflen > 0) {
       ssize_t ret;
       ret = read(dsi->socket, dsi->eof, buflen);
@@ -263,7 +273,7 @@ ssize_t dsi_stream_write(DSI *dsi, void *data, const size_t length, int mode)
 {
   size_t written;
   ssize_t len;
-  unsigned int flags = 0;
+  unsigned int flags;
 
   dsi->in_write++;
   written = 0;
@@ -273,6 +283,11 @@ ssize_t dsi_stream_write(DSI *dsi, void *data, const size_t length, int mode)
   if (dsi->flags & DSI_DISCONNECTED)
       return -1;
 
+  if (mode & DSI_MSG_MORE)
+      flags = MSG_MORE;
+  else
+      flags = 0;
+
   while (written < length) {
       len = send(dsi->socket, (uint8_t *) data + written, length - written, flags);
       if (len >= 0) {
@@ -314,72 +329,116 @@ exit:
   return written;
 }
 
-
 /* ---------------------------------
 */
 #ifdef WITH_SENDFILE
-ssize_t dsi_stream_read_file(DSI *dsi, int fromfd, off_t offset, const size_t length)
+ssize_t dsi_stream_read_file(DSI *dsi, const int fromfd, off_t offset, const size_t length, const int err)
 {
-  int ret = 0;
-  size_t written;
-  ssize_t len;
-  off_t pos = offset;
+    int ret = 0;
+    size_t written = 0;
+    size_t total = length;
+    ssize_t len;
+    off_t pos = offset;
+    char block[DSI_BLOCKSIZ];
+#ifdef HAVE_SENDFILEV
+    int sfvcnt;
+    struct sendfilevec vec[2];
+    ssize_t nwritten;
+#endif
 
-  LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file(send %zd bytes): START", length);
+    LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file(off: %jd, len: %zu)", (intmax_t)offset, length);
 
-  if (dsi->flags & DSI_DISCONNECTED)
-      return -1;
+    if (dsi->flags & DSI_DISCONNECTED)
+        return -1;
 
-  dsi->in_write++;
-  written = 0;
+    dsi->in_write++;
+
+    dsi->flags |= DSI_NOREPLY;
+    dsi->header.dsi_flags = DSIFL_REPLY;
+    dsi->header.dsi_len = htonl(length);
+    dsi->header.dsi_code = htonl(err);
+    dsi_header_pack_reply(dsi, block);
+
+#ifdef HAVE_SENDFILEV
+    total += DSI_BLOCKSIZ;
+    sfvcnt = 2;
+    vec[0].sfv_fd = SFV_FD_SELF;
+    vec[0].sfv_flag = 0;
+    vec[0].sfv_off = block;
+    vec[0].sfv_len = DSI_BLOCKSIZ;
+    vec[1].sfv_fd = fromfd;
+    vec[1].sfv_flag = 0;
+    vec[1].sfv_off = offset;
+    vec[1].sfv_len = length;
+#else
+    dsi_stream_write(dsi, block, sizeof(block), DSI_MSG_MORE);
+#endif
 
-  while (written < length) {
-    len = sys_sendfile(dsi->socket, fromfd, &pos, length - written);
-        
-    if (len < 0) {
-      if (errno == EINTR)
-          continue;
-      if (errno == EINVAL || errno == ENOSYS) {
-          ret = -1;
-          goto exit;
-      }          
-      if (errno == EAGAIN || errno == EWOULDBLOCK) {
-#if defined(SOLARIS) || defined(FREEBSD)
-          if (pos > offset) {
-              /* we actually have sent sth., adjust counters and keep trying */
-              len = pos - offset;
-              written += len;
-              offset = pos;
-          }
+    while (written < total) {
+#ifdef HAVE_SENDFILEV
+        nwritten = 0;
+        len = sendfilev(dsi->socket, vec, sfvcnt, &nwritten);
+#else
+        len = sys_sendfile(dsi->socket, fromfd, &pos, total - written);
 #endif
-          if (dsi_peek(dsi)) {
-              /* can't go back to blocking mode, exit, the next read
-                 will return with an error and afpd will die.
-              */
-              break;
-          }
-          continue;
-      }
-      LOG(log_error, logtype_dsi, "dsi_stream_read_file: %s", strerror(errno));
-      break;
-    }
-    else if (!len) {
-        /* afpd is going to exit */
-          ret = -1;
-          goto exit;
-    }
-    else 
-        written += len;
-  }
+        if (len < 0) {
+            switch (errno) {
+            case EINTR:
+            case EAGAIN:
+                len = 0;
+#ifdef HAVE_SENDFILEV
+                len = (size_t)nwritten;
+#else
+#if defined(SOLARIS) || defined(FREEBSD)
+                if (pos > offset) {
+                    /* we actually have sent sth., adjust counters and keep trying */
+                    len = pos - offset;
+                    offset = pos;
+                }
+#endif /* defined(SOLARIS) || defined(FREEBSD) */
+#endif /* HAVE_SENDFILEV */
 
-  dsi->write_count += written;
+                if (dsi_peek(dsi)) {
+                    ret = -1;
+                    goto exit;
+                }
+                break;
+            default:
+                LOG(log_error, logtype_dsi, "dsi_stream_read_file: %s", strerror(errno));
+                ret = -1;
+                goto exit;
+            }
+        } else if (len == 0) {
+            /* afpd is going to exit */
+            ret = -1;
+            goto exit;
+        }
+#ifdef HAVE_SENDFILEV
+        if (sfvcnt == 2 && len >= vec[0].sfv_len) {
+            vec[1].sfv_off += len - vec[0].sfv_len;
+            vec[1].sfv_len -= len - vec[0].sfv_len;
+
+            vec[0] = vec[1];
+            sfvcnt = 1;
+        } else {
+            vec[0].sfv_off += len;
+            vec[0].sfv_len -= len;
+        }
+#endif  /* HAVE_SENDFILEV */
+        LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file: wrote: %zd", len);
+        written += len;
+    }
+#ifdef HAVE_SENDFILEV
+    written -= DSI_BLOCKSIZ;
+#endif
+    dsi->write_count += written;
 
 exit:
-  dsi->in_write--;
-  LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file: sent: %zd", written);
-  if (ret != 0)
-      return -1;
-  return written;
+    dsi->in_write--;
+    LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file: written: %zd", written);
+    if (ret != 0)
+        return -1;
+    return written;
 }
 #endif
 
@@ -447,14 +506,7 @@ int dsi_stream_send(DSI *dsi, void *buf, size_t length)
   if (dsi->flags & DSI_DISCONNECTED)
       return 0;
 
-  block[0] = dsi->header.dsi_flags;
-  block[1] = dsi->header.dsi_command;
-  memcpy(block + 2, &dsi->header.dsi_requestID, 
-        sizeof(dsi->header.dsi_requestID));
-  memcpy(block + 4, &dsi->header.dsi_code, sizeof(dsi->header.dsi_code));
-  memcpy(block + 8, &dsi->header.dsi_len, sizeof(dsi->header.dsi_len));
-  memcpy(block + 12, &dsi->header.dsi_reserved,
-        sizeof(dsi->header.dsi_reserved));
+  dsi_header_pack_reply(dsi, block);
 
   if (!length) { /* just write the header */
       LOG(log_maxdebug, logtype_dsi, "dsi_stream_send(%u bytes): DSI header, no data", sizeof(block));
@@ -542,7 +594,7 @@ int dsi_stream_receive(DSI *dsi)
   dsi->clientID = ntohs(dsi->header.dsi_requestID);
   
   /* make sure we don't over-write our buffers. */
-  dsi->cmdlen = min(ntohl(dsi->header.dsi_len), DSI_CMDSIZ);
+  dsi->cmdlen = MIN(ntohl(dsi->header.dsi_len), DSI_CMDSIZ);
   if (dsi_stream_read(dsi, dsi->commands, dsi->cmdlen) != dsi->cmdlen) 
     return 0;
 
index cd2246ed54bf5156f08589f2921dfcbae7581941..39a725c2905e2b5bd82087248c0f413f30ef448e 100644 (file)
@@ -1448,6 +1448,8 @@ int afp_config_parse(AFPObj *AFPObj, char *processname)
         options->flags |= OPTION_NOSENDFILE;
     if (iniparser_getboolean(config, INISEC_GLOBAL, "solaris share reservations", 1))
         options->flags |= OPTION_SHARE_RESERV;
+    if (iniparser_getboolean(config, INISEC_GLOBAL, "afp read locks", 0))
+        options->flags |= OPTION_AFP_READ_LOCK;
     if (!iniparser_getboolean(config, INISEC_GLOBAL, "save password", 1))
         options->passwdbits |= PASSWD_NOSAVE;
     if (iniparser_getboolean(config, INISEC_GLOBAL, "set password", 0))
index e3bc4e8473c79545532b88f7c27ee0d5ab70cd24..6ae3fab2b0d51ac2a6191652376333e40c817c2f 100644 (file)
@@ -931,6 +931,7 @@ if test x"$netatalk_cv_search_sendfile" = x"yes"; then
         AC_DEFINE(SENDFILE_FLAVOR_SOLARIS, 1, [Solaris sendfile()])
         AC_SEARCH_LIBS(sendfile, sendfile)
         AC_CHECK_FUNC([sendfile], [netatalk_cv_HAVE_SENDFILE=yes])
+        AC_CHECK_FUNCS([sendfilev])
         ;;
 
     *freebsd*)