]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/volume.c
Merge master
[netatalk.git] / etc / afpd / volume.c
index 23bd2c16444d62e68ed614fd60b1e1191f4e8ff7..1b442093239c31fc8dc190a65625b591868d0fca 100644 (file)
@@ -19,6 +19,8 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#include <inttypes.h>
+#include <time.h>
 
 #include <atalk/dsi.h>
 #include <atalk/adouble.h>
 #include <atalk/ea.h>
 #include <atalk/bstrlib.h>
 #include <atalk/bstradd.h>
+#include <atalk/ftw.h>
+#include <atalk/globals.h>
+#include <atalk/fce_api.h>
 
 #ifdef CNID_DB
 #include <atalk/cnid.h>
 #endif /* CNID_DB*/
 
-#include "globals.h"
 #include "directory.h"
 #include "file.h"
 #include "volume.h"
@@ -52,17 +56,6 @@ extern int afprun(int root, char *cmd, int *outfd);
 #define MIN(a, b) ((a) < (b) ? (a) : (b))
 #endif /* ! MIN */
 
-#ifndef NO_LARGE_VOL_SUPPORT
-#if BYTE_ORDER == BIG_ENDIAN
-#define hton64(x)       (x)
-#define ntoh64(x)       (x)
-#else /* BYTE_ORDER == BIG_ENDIAN */
-#define hton64(x)       ((u_int64_t) (htonl(((x) >> 32) & 0xffffffffLL)) | \
-                         (u_int64_t) ((htonl(x) & 0xffffffffLL) << 32))
-#define ntoh64(x)       (hton64(x))
-#endif /* BYTE_ORDER == BIG_ENDIAN */
-#endif /* ! NO_LARGE_VOL_SUPPORT */
-
 #ifndef UUID_PRINTABLE_STRING_LENGTH
 #define UUID_PRINTABLE_STRING_LENGTH 37
 #endif
@@ -451,11 +444,8 @@ static void volset(struct vol_option *options, struct vol_option *save,
                 options[VOLOPT_FLAGS].i_value |= AFPVOL_TM;
             else if (strcasecmp(p, "searchdb") == 0)
                 options[VOLOPT_FLAGS].i_value |= AFPVOL_SEARCHDB;
-/* Found this in branch dir-rewrite, maybe we want to use it sometimes */
-#if 0
-            else if (strcasecmp(p, "cdrom") == 0)
-                options[VOLOPT_FLAGS].i_value |= AFPVOL_CDROM | AFPVOL_RO;
-#endif
+            else if (strcasecmp(p, "nonetids") == 0)
+                options[VOLOPT_FLAGS].i_value |= AFPVOL_NONETIDS;
             p = strtok(NULL, ",");
         }
 
@@ -1133,12 +1123,22 @@ static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int us
         p1->mtime = st.st_mtime;
     }
 
-    if ((read_lock(fd, 0, SEEK_SET, 0)) != 0) {
-        LOG(log_error, logtype_afpd, "readvolfile: can't lock volume file \"%s\"", path);
-        if ( fclose( fp ) != 0 ) {
-            LOG(log_error, logtype_afpd, "readvolfile: fclose: %s", strerror(errno) );
+    /* try putting a read lock on the volume file twice, sleep 1 second if first attempt fails */
+    int retries = 2;
+    while (1) {
+        if ((read_lock(fd, 0, SEEK_SET, 0)) != 0) {
+            retries--;
+            if (!retries) {
+                LOG(log_error, logtype_afpd, "readvolfile: can't lock volume file \"%s\"", path);
+                if ( fclose( fp ) != 0 ) {
+                    LOG(log_error, logtype_afpd, "readvolfile: fclose: %s", strerror(errno) );
+                }
+                return -1;
+            }
+            sleep(1);
+            continue;
         }
-        return -1;
+        break;
     }
 
     memset(save_options, 0, sizeof(save_options));
@@ -1344,12 +1344,72 @@ static void volume_unlink(struct vol *volume)
     }
 }
 
+static off_t getused_size; /* result of getused() */
+
+/*!
+  nftw callback for getused()
+ */
+static int getused_stat(const char *path,
+                        const struct stat *statp,
+                        int tflag,
+                        struct FTW *ftw)
+{
+    off_t low, high;
+
+    if (tflag == FTW_F || tflag == FTW_D) {
+        getused_size += statp->st_blocks * 512;
+    }
+
+    return 0;
+}
+
+#define GETUSED_CACHETIME 5
+/*!
+ * Calculate used size of a volume with nftw
+ *
+ * The result is cached, we're try to avoid frequently calling nftw()
+ *
+ * 1) Call nftw an refresh if:
+ * 1a) - we're called the first time 
+ * 1b) - volume modification date is not yet set and the last time we've been called is
+ *       longer then 30 sec ago
+ * 1c) - the last volume modification is less then 30 sec old
+ *
+ * @param vol     (rw) volume to calculate
+ */
+static int getused(struct vol *vol)
+{
+    static time_t vol_mtime = 0;
+    int ret = 0;
+    time_t now = time(NULL);
+
+    if (!vol_mtime
+        || (!vol->v_mtime && ((vol_mtime + GETUSED_CACHETIME) < now))
+        || (vol->v_mtime && ((vol_mtime + GETUSED_CACHETIME) < vol->v_mtime))
+        ) {
+        vol_mtime = now;
+        getused_size = 0;
+        vol->v_written = 0;
+        ret = nftw(vol->v_path, getused_stat, NULL, 20, FTW_PHYS); /* 2 */
+        LOG(log_debug, logtype_afpd, "volparams: from nftw: %" PRIu64 " bytes",
+            getused_size);
+    } else {
+        getused_size += vol->v_written;
+        vol->v_written = 0;
+        LOG(log_debug, logtype_afpd, "volparams: cached used: %" PRIu64 " bytes",
+            getused_size);
+    }
+
+    return ret;
+}
+
 static int getvolspace(struct vol *vol,
                        u_int32_t *bfree, u_int32_t *btotal,
                        VolSpace *xbfree, VolSpace *xbtotal, u_int32_t *bsize)
 {
     int         spaceflag, rc;
     u_int32_t   maxsize;
+    VolSpace    used;
 #ifndef NO_QUOTA_SUPPORT
     VolSpace    qfree, qtotal;
 #endif
@@ -1388,45 +1448,14 @@ static int getvolspace(struct vol *vol,
 
 getvolspace_done:
     if (vol->v_limitsize) {
-        bstring cmdstr;
-        if ((cmdstr = bformat("du -sh \"%s\" 2> /dev/null | cut -f1", vol->v_path)) == NULL)
+        if (getused(vol) != 0)
             return AFPERR_MISC;
-
-        FILE *cmd = popen(cfrombstr(cmdstr), "r");
-        bdestroy(cmdstr);
-        if (cmd == NULL)
-            return AFPERR_MISC;
-
-        char buf[100];
-        fgets(buf, 100, cmd);
-
-        if (pclose(cmd) == -1)
-            return AFPERR_MISC;
-
-        size_t multi = 0;
-        if (buf[strlen(buf) - 2] == 'G' || buf[strlen(buf) - 2] == 'g')
-            /* GB */
-            multi = 1024 * 1024 * 1024;
-        else if (buf[strlen(buf) - 2] == 'M' || buf[strlen(buf) - 2] == 'm')
-            /* MB */
-            multi = 1024 * 1024;
-        else if (buf[strlen(buf) - 2] == 'K' || buf[strlen(buf) - 2] == 'k')
-            /* MB */
-            multi = 1024;
-
-        char *p;
-        if (p = strchr(buf, ','))
-            /* ignore fraction */
-            *p = 0;
-        else
-            /* remove G|M|K char */
-            buf[strlen(buf) - 2] = 0;
-        /* now buf contains only digits */
-        long long used = atoll(buf) * multi;
-        LOG(log_debug, logtype_afpd, "volparams: used on volume: %llu bytes", used);
+        LOG(log_debug, logtype_afpd, "volparams: used on volume: %" PRIu64 " bytes",
+            getused_size);
+        vol->v_tm_used = getused_size;
 
         *xbtotal = min(*xbtotal, (vol->v_limitsize * 1024 * 1024));
-        *xbfree = min(*xbfree, *xbtotal < used ? 0 : *xbtotal - used);
+        *xbfree = min(*xbfree, *xbtotal < getused_size ? 0 : *xbtotal - getused_size);
     }
 
     *bfree = min( *xbfree, maxsize);
@@ -1434,6 +1463,22 @@ getvolspace_done:
     return( AFP_OK );
 }
 
+#define FCE_TM_DELTA 10  /* send notification every 10 seconds */
+void vol_fce_tm_event(void)
+{
+    static time_t last;
+    time_t now = time(NULL);
+    struct vol  *vol = Volumes;
+
+    if ((last + FCE_TM_DELTA) < now) {
+        last = now;
+        for ( ; vol; vol = vol->v_next ) {
+            if (vol->v_flags & AFPVOL_TM)
+                (void)fce_register_tm_size(vol->v_path, vol->v_tm_used + vol->v_written);
+        }
+    }
+}
+
 /* -----------------------
  * set volume creation date
  * avoid duplicate, well at least it tries
@@ -1544,7 +1589,8 @@ static int getvolparams( u_int16_t bitmap, struct vol *vol, struct stat *st, cha
                         ashort |= VOLPBIT_ATTR_UNIXPRIV;
                     if (vol->v_flags & AFPVOL_TM)
                         ashort |= VOLPBIT_ATTR_TM;
-
+                    if (vol->v_flags & AFPVOL_NONETIDS)
+                        ashort |= VOLPBIT_ATTR_NONETIDS;
                     if (afp_version >= 32) {
                         if (vol->v_vfs_ea)
                             ashort |= VOLPBIT_ATTR_EXT_ATTRS;
@@ -2389,12 +2435,6 @@ void setvoltime(AFPObj *obj, struct vol *vol)
 {
     struct timeval  tv;
 
-    /* just looking at vol->v_mtime is broken seriously since updates
-     * from other users afpd processes never are seen.
-     * This is not the most elegant solution (a shared memory between
-     * the afpd processes would come closer)
-     * [RS] */
-
     if ( gettimeofday( &tv, NULL ) < 0 ) {
         LOG(log_error, logtype_afpd, "setvoltime(%s): gettimeofday: %s", vol->v_path, strerror(errno) );
         return;