]> arthur.barton.de Git - netatalk.git/blobdiff - etc/cnid_dbd/cmd_dbd_scanvol.c
chmod wrapper for onnv145+ to preserve ACL
[netatalk.git] / etc / cnid_dbd / cmd_dbd_scanvol.c
index be0aaf9c44883b34457323088b6a5e2c63a23e40..45d67ae1bd5b2c5dcfc09ce618fa3f95fb768372 100644 (file)
@@ -1,6 +1,4 @@
 /*
-  $Id: cmd_dbd_scanvol.c,v 1.20 2010-02-15 13:58:38 franklahm Exp $
-
   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
 
   This program is free software; you can redistribute it and/or modify
@@ -35,6 +33,7 @@
 #include <atalk/volume.h>
 #include <atalk/ea.h>
 #include <atalk/util.h>
+#include <atalk/acl.h>
 
 #include "cmd_dbd.h"
 #include "dbif.h"
@@ -59,6 +58,10 @@ static char           *netatalk_dirs[] = {
     ".AppleDesktop",
     NULL
 };
+static char           *special_dirs[] = {
+    ".zfs",
+    NULL
+};
 static struct cnid_dbd_rqst rqst;
 static struct cnid_dbd_rply rply;
 static jmp_buf jmp;
@@ -271,6 +274,21 @@ static const char *check_netatalk_dirs(const char *name)
     return NULL;
 }
 
+/*
+  Check for special names
+  Returns pointer to name or NULL.
+*/
+static const char *check_special_dirs(const char *name)
+{
+    int c;
+
+    for (c=0; special_dirs[c]; c++) {
+        if ((strcmp(name, special_dirs[c])) == 0)
+            return special_dirs[c];
+    }
+    return NULL;
+}
+
 /*
   Check for .AppleDouble file, create if missing
 */
@@ -280,6 +298,9 @@ static int check_adfile(const char *fname, const struct stat *st)
     struct adouble ad;
     char *adname;
 
+    if (dbd_flags & DBD_FLAGS_CLEANUP)
+        return 0;
+
     if (S_ISREG(st->st_mode))
         adflags = 0;
     else
@@ -388,8 +409,7 @@ static int check_eafiles(const char *fname)
     if ((ret = ea_open(&volume, fname, EA_RDWR, &ea)) != 0) {
         if (errno == ENOENT)
             return 0;
-        dbd_log(LOGSTD, "Error calling ea_open for file: %s/%s, removing EA files",
-                cwdbuf, fname);
+        dbd_log(LOGSTD, "Error calling ea_open for file: %s/%s, removing EA files", cwdbuf, fname);
         if ( ! (dbd_flags & DBD_FLAGS_SCAN))
             remove_eafiles(fname, &ea);
         return -1;
@@ -439,6 +459,9 @@ static int check_addir(int volroot)
     struct adouble ad;
     char *mname = NULL;
 
+    if (dbd_flags & DBD_FLAGS_CLEANUP)
+        return 0;
+
     /* Check for ad-dir */
     if ( (addir_ok = access(ADv2_DIRNAME, F_OK)) != 0) {
         if (errno != ENOENT) {
@@ -657,6 +680,10 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi
     if ( (volinfo->v_flags & AFPVOL_CACHE) && ADFILE_OK) {
         ad_init(&ad, volinfo->v_adouble, volinfo->v_ad_options);
         if (ad_open_metadata( name, adflags, O_RDWR, &ad) != 0) {
+            
+            if (dbd_flags & DBD_FLAGS_CLEANUP)
+                return 0;
+
             dbd_log( LOGSTD, "Error opening AppleDouble file for '%s/%s': %s", cwdbuf, name, strerror(errno));
             return 0;
         }
@@ -671,7 +698,7 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi
             ad_cnid = ad_getid(&ad, st->st_dev, st->st_ino, did, stamp);
 
         if (ad_cnid == 0)
-            dbd_log( LOGSTD, "Incorrect CNID data in .AppleDouble data for '%s/%s' (bad stamp?)", cwdbuf, name);
+            dbd_log( LOGSTD, "Bad CNID in adouble file of '%s/%s'", cwdbuf, name);
         else
             dbd_log( LOGDEBUG, "CNID from .AppleDouble file for '%s/%s': %u", cwdbuf, name, ntohl(ad_cnid));
 
@@ -729,10 +756,40 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi
     } else if (ad_cnid && (db_cnid == 0)) {
         /* in ad-file but not in db */
         if ( ! (dbd_flags & DBD_FLAGS_SCAN)) {
-            dbd_log( LOGDEBUG, "CNID rebuild add for '%s/%s', adding with CNID from ad-file: %u", cwdbuf, name, ntohl(ad_cnid));
+            /* Ensure the cnid from the ad-file is not already occupied by another file */
+            dbd_log(LOGDEBUG, "Checking whether CNID %u from ad-file is occupied",
+                    ntohl(ad_cnid));
+
+            rqst.cnid = ad_cnid;
+            ret = dbd_resolve(dbd, &rqst, &rply);
+            if (ret == CNID_DBD_RES_OK) {
+                /* Occupied! Choose another, update ad-file */
+                ret = dbd_add(dbd, &rqst, &rply, 1);
+                dbif_txn_close(dbd, ret);
+                db_cnid = rply.cnid;
+                dbd_log(LOGSTD, "New CNID for '%s/%s': %u", cwdbuf, name, ntohl(db_cnid));
+
+                if ((volinfo->v_flags & AFPVOL_CACHE)
+                    && ADFILE_OK
+                    && ( ! (dbd_flags & DBD_FLAGS_SCAN))) {
+                    dbd_log(LOGSTD, "Writing CNID data for '%s/%s' to AppleDouble file",
+                            cwdbuf, name, ntohl(db_cnid));
+                    ad_init(&ad, volinfo->v_adouble, volinfo->v_ad_options);
+                    if (ad_open_metadata( name, adflags, O_RDWR, &ad) != 0) {
+                        dbd_log(LOGSTD, "Error opening AppleDouble file for '%s/%s': %s",
+                                cwdbuf, name, strerror(errno));
+                        return 0;
+                    }
+                    ad_setid( &ad, st->st_dev, st->st_ino, db_cnid, did, stamp);
+                    ad_flush(&ad);
+                    ad_close_metadata(&ad);
+                }
+                return db_cnid;
+            }
+
+            dbd_log(LOGDEBUG, "CNID rebuild add '%s/%s' with CNID from ad-file %u",
+                    cwdbuf, name, ntohl(ad_cnid));
             rqst.cnid = ad_cnid;
-            ret = dbd_delete(dbd, &rqst, &rply, DBIF_CNID);
-            dbif_txn_close(dbd, ret);
             ret = dbd_rebuild_add(dbd, &rqst, &rply);
             dbif_txn_close(dbd, ret);
         }
@@ -745,7 +802,7 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi
             ret = dbd_add(dbd, &rqst, &rply, 1);
             dbif_txn_close(dbd, ret);
             db_cnid = rply.cnid;
-            dbd_log( LOGSTD, "New CNID for '%s/%s': %u", cwdbuf, name, ntohl(db_cnid));
+            dbd_log(LOGSTD, "New CNID for '%s/%s': %u", cwdbuf, name, ntohl(db_cnid));
         }
     }
 
@@ -753,10 +810,12 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi
         /* in db but zeroID in ad-file, write it to ad-file if AFPVOL_CACHE */
         if ((volinfo->v_flags & AFPVOL_CACHE) && ADFILE_OK) {
             if ( ! (dbd_flags & DBD_FLAGS_SCAN)) {
-                dbd_log( LOGSTD, "Writing CNID data for '%s/%s' to AppleDouble file", cwdbuf, name, ntohl(db_cnid));
+                dbd_log(LOGSTD, "Writing CNID data for '%s/%s' to AppleDouble file",
+                        cwdbuf, name, ntohl(db_cnid));
                 ad_init(&ad, volinfo->v_adouble, volinfo->v_ad_options);
                 if (ad_open_metadata( name, adflags, O_RDWR, &ad) != 0) {
-                    dbd_log( LOGSTD, "Error opening AppleDouble file for '%s/%s': %s", cwdbuf, name, strerror(errno));
+                    dbd_log(LOGSTD, "Error opening AppleDouble file for '%s/%s': %s",
+                            cwdbuf, name, strerror(errno));
                     return 0;
                 }
                 ad_setid( &ad, st->st_dev, st->st_ino, db_cnid, did, stamp);
@@ -819,12 +878,21 @@ static int dbd_readdir(int volroot, cnid_t did)
             continue;
         }
 
+        /* Check for special folders in volume root e.g. ".zfs" */
+        if (volroot) {
+            if ((name = check_special_dirs(ep->d_name)) != NULL) {
+                dbd_log(LOGSTD, "Ignoring special dir \"%s\"", name);
+                continue;
+            }
+        }
+
         /* Skip .AppleDouble dir in this loop */
         if (STRCMP(ep->d_name, == , ADv2_DIRNAME))
             continue;
 
         if ((ret = lstat(ep->d_name, &st)) < 0) {
-            dbd_log( LOGSTD, "Lost file while reading dir '%s/%s', probably removed: %s", cwdbuf, ep->d_name, strerror(errno));
+            dbd_log( LOGSTD, "Lost file while reading dir '%s/%s', probably removed: %s",
+                     cwdbuf, ep->d_name, strerror(errno));
             continue;
         }
         
@@ -981,6 +1049,9 @@ static void delete_orphaned_cnids(DBD *dbd, DBD *dbd_rebuild, dbd_flags_t flags)
 
     /* Start main loop through dbd: get CNID from dbd */
     while ((dbif_idwalk(dbd, &dbd_cnid, 0)) == 1) {
+        /* Check if we got a termination signal */
+        if (alarmed)
+            longjmp(jmp, 1); /* this jumps back to cmd_dbd_scanvol() */
 
         if (deleted > 50) {
             deleted = 0;
@@ -1006,6 +1077,9 @@ static void delete_orphaned_cnids(DBD *dbd, DBD *dbd_rebuild, dbd_flags_t flags)
                         dbif_txn_close(dbd, ret);
                         deleted++;
                     }
+                    /* Check if we got a termination signal */
+                    if (alarmed)
+                        longjmp(jmp, 1); /* this jumps back to cmd_dbd_scanvol() */
                 }
                 return;
             } else