]> arthur.barton.de Git - netatalk.git/commitdiff
Autoconversion adouble v2 to ea
authorFrank Lahm <franklahm@googlemail.com>
Wed, 8 Feb 2012 19:02:43 +0000 (20:02 +0100)
committerFrank Lahm <franklahm@googlemail.com>
Wed, 8 Feb 2012 19:02:43 +0000 (20:02 +0100)
etc/afpd/enumerate.c
etc/afpd/file.c
etc/afpd/volume.c
include/atalk/adouble.h
include/atalk/volume.h
libatalk/adouble/ad_flush.c
libatalk/adouble/ad_open.c
libatalk/adouble/ad_write.c

index 4867640d8d63d9884cb148c2c7360722f80f2a6a..1a44aa7f6afb210d11aa98a957920f9b17cf8d63 100644 (file)
@@ -365,6 +365,10 @@ static int enumerate(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_,
 
         sd.sd_last += len + 1;
         s_path.m_name = NULL;
+
+        /* Convert adouble:v2 to adouble:ea on the fly */
+        (void)ad_convert(s_path.u_name, &s_path.st, vol);
+
         /*
          * If a fil/dir is not a dir, it's a file. This is slightly
          * inaccurate, since that means /dev/null is a file, /dev/printer
@@ -440,6 +444,15 @@ static int enumerate(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_,
 
     if ( actcnt == 0 ) {
         sd.sd_did = 0;         /* invalidate sd struct to force re-read */
+        /*
+         * in case were converting adouble stuff:
+         * after enumerating the whole dir we should have converted everything
+         * thus the .AppleDouble dir shouls be empty thus we can no try to
+         * delete it
+         */
+        if (vol->v_adouble == AD_VERSION_EA && ! (vol->v_flags & AFPVOL_NOV2TOEACONV))
+            (void)rmdir(".AppleDouble");
+
         return( AFPERR_NOOBJ );
     }
     sd.sd_sindex = sindex + actcnt;
index 1d619748b27f6fe7b5df4ebbeb69607e4c10e5d9..06ba8c19d5b99e17961dbdd856c1db5efe2018ba 100644 (file)
@@ -1336,104 +1336,6 @@ copy_exit:
     return( retvalue );
 }
 
-/* ----------------------- */
-static int copy_all(const int dfd, const void *buf,
-                               size_t buflen)
-{
-    ssize_t cc;
-
-#ifdef DEBUG
-    LOG(log_debug9, logtype_afpd, "begin copy_all:");
-#endif /* DEBUG */
-
-    while (buflen > 0) {
-        if ((cc = write(dfd, buf, buflen)) < 0) {
-            switch (errno) {
-            case EINTR:
-                continue;
-            default:
-                return -1;
-            }
-        }
-        buflen -= cc;
-    }
-
-#ifdef DEBUG
-    LOG(log_debug9, logtype_afpd, "end copy_all:");
-#endif /* DEBUG */
-
-    return 0;
-}
-
-/* -------------------------- 
- * copy only the fork data stream
-*/
-static int copy_fork(int eid, struct adouble *add, struct adouble *ads)
-{
-    ssize_t cc;
-    int     err = 0;
-    char    filebuf[8192];
-    int     sfd, dfd;
-
-    if (eid == ADEID_DFORK) {
-        sfd = ad_data_fileno(ads);
-        dfd = ad_data_fileno(add);
-    }
-    else {
-        sfd = ad_reso_fileno(ads);
-        dfd = ad_reso_fileno(add);
-    }        
-
-    if ((off_t)-1 == lseek(sfd, ad_getentryoff(ads, eid), SEEK_SET))
-       return -1;
-
-    if ((off_t)-1 == lseek(dfd, ad_getentryoff(add, eid), SEEK_SET))
-       return -1;
-       
-#if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
-    /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
-    off_t   offset = 0;
-    size_t  size;
-    struct stat         st;
-    #define BUF 128*1024*1024
-
-    if (fstat(sfd, &st) == 0) {
-        
-        while (1) {
-            if ( offset >= st.st_size) {
-               return 0;
-            }
-            size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
-            if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
-                switch (errno) {
-                case ENOSYS:
-                case EINVAL:  /* there's no guarantee that all fs support sendfile */
-                    goto no_sendfile;
-                default:
-                    return -1;
-                }
-            }
-        }
-    }
-    no_sendfile:
-    lseek(sfd, offset, SEEK_SET);
-#endif 
-
-    while (1) {
-        if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
-            if (errno == EINTR)
-                continue;
-            err = -1;
-            break;
-        }
-
-        if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
-            break;
-        }
-    }
-    return err;
-}
-
 /* ----------------------------------
  * if newname is NULL (from directory.c) we don't want to copy the resource fork.
  * because we are doing it elsewhere.
index b2586400d5fb544150ccdc8bc71014346520a95d..f596449962ef4c6d19516b7ba2c8862044121bfb 100644 (file)
@@ -435,6 +435,8 @@ static void volset(struct vol_option *options, struct vol_option *save,
                 options[VOLOPT_FLAGS].i_value |= AFPVOL_NONETIDS;
             else if (strcasecmp(p, "noacls") == 0)
                 options[VOLOPT_FLAGS].i_value &= ~AFPVOL_ACLS;
+            else if (strcasecmp(p, "nov2toeaconv") == 0)
+                options[VOLOPT_FLAGS].i_value |= AFPVOL_NOV2TOEACONV;
             p = strtok(NULL, ",");
         }
 
@@ -1598,6 +1600,9 @@ static int getvolparams( uint16_t bitmap, struct vol *vol, struct stat *st, char
      * For MacOS8.x support we need to create the
      * .Parent file here if it doesn't exist. */
 
+    /* Convert adouble:v2 to adouble:ea on the fly */
+    (void)ad_convert(vol->v_path, st, vol);
+
     ad_init(&ad, vol);
     if (ad_open(&ad, vol->v_path, ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) != 0 ) {
         isad = 0;
index 6cdbef72c9ec1b05a470c6a84bf3c2fb08668b7d..c130a5e985209f6f2988fbaff2838249b6a3b3b4 100644 (file)
@@ -186,7 +186,7 @@ struct adouble_fops {
     const char *(*ad_path)(const char *, int);
     int  (*ad_mkrf)(const char *);
     int  (*ad_rebuild_header)(struct adouble *);
-    int  (*ad_header_read)(const char *, struct adouble *, struct stat *);
+    int  (*ad_header_read)(const char *, struct adouble *, const struct stat *);
     int  (*ad_header_upgrade)(struct adouble *, const char *);
 };
 
@@ -402,31 +402,8 @@ extern int ad_refresh     (const char *path, struct adouble *);
 extern int ad_stat        (const char *, struct stat *);
 extern int ad_metadata    (const char *, int, struct adouble *);
 extern int ad_metadataat  (int, const char *, int, struct adouble *);
-
-/* build a resource fork mode from the data fork mode:
- * remove X mode and extend header to RW if R or W (W if R for locking),
- */
-static inline mode_t ad_hf_mode (mode_t mode)
-{
-    mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH);
-    /* fnctl lock need write access */
-    if ((mode & S_IRUSR))
-        mode |= S_IWUSR;
-    if ((mode & S_IRGRP))
-        mode |= S_IWGRP;
-    if ((mode & S_IROTH))
-        mode |= S_IWOTH;
-
-    /* if write mode set add read mode */
-    if ((mode & S_IWUSR))
-        mode |= S_IRUSR;
-    if ((mode & S_IWGRP))
-        mode |= S_IRGRP;
-    if ((mode & S_IWOTH))
-        mode |= S_IROTH;
-
-    return mode;
-}
+extern mode_t ad_hf_mode(mode_t mode);
+extern int ad_convert(const char *path, const struct stat *sp, const struct vol *vol);
 
 /* ad_read.c/ad_write.c */
 extern int     sys_ftruncate(int fd, off_t length);
@@ -437,6 +414,7 @@ extern ssize_t adf_pread(struct ad_fd *, void *, size_t, off_t);
 extern ssize_t adf_pwrite(struct ad_fd *, const void *, size_t, off_t);
 extern int     ad_dtruncate(struct adouble *, off_t);
 extern int     ad_rtruncate(struct adouble *, off_t);
+extern int     copy_fork(int eid, struct adouble *add, struct adouble *ads);
 
 /* ad_size.c */
 extern off_t ad_size (const struct adouble *, uint32_t );
index 53676ce8c43f3ad15c20075ebaab6fbcac05d8b5..42b8a170180f5c3bb74b855544cb41c8466b097e 100644 (file)
@@ -95,15 +95,16 @@ struct vol {
 
 /* flags  for AFS and quota 0xxx0 */
 #define AFPVOL_GVSMASK  (7<<2)
-#define AFPVOL_NONE (0<<2)
+#define AFPVOL_NONE     (0<<2)
 #define AFPVOL_AFSGVS   (1<<2)
-#define AFPVOL_USTATFS  (2<<2)
-#define AFPVOL_UQUOTA   (4<<2)
+#define AFPVOL_USTATFS  (1<<3)
+#define AFPVOL_UQUOTA   (1<<4)
 
 /*
   Flags that alter volume behaviour.
   Keep in sync with libatalk/util/volinfo.c
 */
+#define AFPVOL_NOV2TOEACONV (1 << 5) /* no adouble:v2 to adouble:ea conversion */
 #define AFPVOL_RO        (1 << 8)   /* read-only volume */
 #define AFPVOL_NOHEX     (1 << 10)  /* don't do :hex translation */
 #define AFPVOL_USEDOTS   (1 << 11)  /* use real dots */
index 89a37a7e9fcf55f9e9820f1d9cee8bc52e2c313e..c8ff4ef4bdd13b8972a912a77b45e8a893046b40 100644 (file)
@@ -183,25 +183,24 @@ int ad_copy_header(struct adouble *add, struct adouble *ads)
     uint32_t       len;
 
     for ( eid = 0; eid < ADEID_MAX; eid++ ) {
-        if ( ads->ad_eid[ eid ].ade_off == 0 ) {
+        if ( ads->ad_eid[ eid ].ade_off == 0 || add->ad_eid[ eid ].ade_off == 0 )
             continue;
-        }
-
-        if ( add->ad_eid[ eid ].ade_off == 0 ) {
-            continue;
-        }
 
         len = ads->ad_eid[ eid ].ade_len;
-        if (!len) {
+        if (!len || len != add->ad_eid[ eid ].ade_len)
             continue;
-        }
 
-        if (eid != ADEID_COMMENT && add->ad_eid[ eid ].ade_len != len ) {
+        switch (eid) {
+        case ADEID_COMMENT:
+        case ADEID_PRIVDEV:
+        case ADEID_PRIVINO:
+        case ADEID_PRIVSYN:
+        case ADEID_PRIVID:
             continue;
+        default:
+            ad_setentrylen( add, eid, len );
+            memcpy( ad_entry( add, eid ), ad_entry( ads, eid ), len );
         }
-
-        ad_setentrylen( add, eid, len );
-        memcpy( ad_entry( add, eid ), ad_entry( ads, eid ), len );
     }
     add->ad_rlen = ads->ad_rlen;
     return 0;
index b83d384d4570213521e1e7e7a4f81ac498beb23a..adbdbe1ebe35e5673cf90ae87bf49b09f0d65b3d 100644 (file)
@@ -45,6 +45,7 @@
 #include <atalk/logger.h>
 #include <atalk/adouble.h>
 #include <atalk/util.h>
+#include <atalk/unix.h>
 #include <atalk/ea.h>
 #include <atalk/bstrlib.h>
 #include <atalk/bstradd.h>
@@ -104,11 +105,11 @@ static uid_t default_uid = -1;
 
 /* Forward declarations */
 static int ad_mkrf(const char *path);
-static int ad_header_read(const char *path, struct adouble *ad, struct stat *hst);
+static int ad_header_read(const char *path, struct adouble *ad, const struct stat *hst);
 static int ad_header_upgrade(struct adouble *ad, const char *name);
 
 static int ad_mkrf_ea(const char *path);
-static int ad_header_read_ea(const char *path, struct adouble *ad, struct stat *hst);
+static int ad_header_read_ea(const char *path, struct adouble *ad, const struct stat *hst);
 static int ad_header_upgrade_ea(struct adouble *ad, const char *name);
 static int ad_reso_size(const char *path, int adflags, struct adouble *ad);
 static int ad_mkrf_osx(const char *path);
@@ -434,7 +435,7 @@ static void parse_entries(struct adouble *ad, char *buf, uint16_t nentries)
  * NOTE: we're assuming that the resource fork is kept at the end of
  *       the file. also, mmapping won't work for the hfs fs until it
  *       understands how to mmap header files. */
-static int ad_header_read(const char *path _U_, struct adouble *ad, struct stat *hst)
+static int ad_header_read(const char *path _U_, struct adouble *ad, const struct stat *hst)
 {
     char                *buf = ad->ad_data;
     uint16_t            nentries;
@@ -510,7 +511,7 @@ static int ad_header_read(const char *path _U_, struct adouble *ad, struct stat
 }
 
 /* Read an ._ file, only uses the resofork, finderinfo is taken from EA */
-static int ad_header_read_osx(const char *path _U_, struct adouble *ad, struct stat *hst)
+static int ad_header_read_osx(const char *path _U_, struct adouble *ad, const struct stat *hst)
 {
     EC_INIT;
     struct adouble      adosx;
@@ -579,7 +580,7 @@ EC_CLEANUP:
     EC_EXIT;
 }
 
-static int ad_header_read_ea(const char *path, struct adouble *ad, struct stat *hst _U_)
+static int ad_header_read_ea(const char *path, struct adouble *ad, const struct stat *hst _U_)
 {
     uint16_t nentries;
     int      len;
@@ -778,24 +779,68 @@ static int ad2openflags(const struct adouble *ad, int adfile, int adflags)
     return oflags;
 }
 
-static int ad_conv_v22ea(const char *path, int adflags, const struct adouble *adea)
+static int ad_conv_v22ea_hf(const char *path, const struct stat *sp, const struct vol *vol)
 {
     EC_INIT;
     struct adouble adv2;
-    const char *adp;
+    struct adouble adea;
+    const char *adpath;
+    int adflags;
 
-    LOG(log_note, logtype_default,"ad_conv_v22ea(\"%s\"): BEGIN", fullpathname(path));
+    LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): BEGIN", fullpathname(path));
 
-    ad_init_old(&adv2, AD_VERSION2, adea->ad_options);
-    EC_NULL( adp = adv2.ad_ops->ad_path(path, adflags) );
+    ad_init(&adea, vol);
+    ad_init_old(&adv2, AD_VERSION2, adea.ad_options);
+    adflags = S_ISDIR(sp->st_mode) ? ADFLAGS_DIR : 0;
 
-    LOG(log_note, logtype_default,"ad_conv_v22ea(\"%s\"): adouble:v2 path: \"%s\"",
-        fullpathname(path), fullpathname(adp));
+    /* Open and lock adouble:v2 file */
+    EC_ZERO( ad_open(&adv2, path, adflags | ADFLAGS_HF | ADFLAGS_RDWR) );
+    EC_NEG1_LOG( ad_tmplock(&adv2, ADEID_RFORK, ADLOCK_WR | ADLOCK_FILELOCK, 0, 0, 0) );
+    EC_NEG1_LOG( adv2.ad_ops->ad_header_read(path, &adv2, sp) );
+
+    /* Create a adouble:ea meta EA */
+    EC_ZERO_LOG( ad_open(&adea, path, adflags | ADFLAGS_HF | ADFLAGS_RDWR | ADFLAGS_CREATE) );
+    EC_ZERO_LOG( ad_copy_header(&adea, &adv2) );
+    ad_flush(&adea);
 
 EC_CLEANUP:
+    EC_ZERO_LOG( ad_close(&adv2, ADFLAGS_HF | ADFLAGS_SETSHRMD) );
+    EC_ZERO_LOG( ad_close(&adea, ADFLAGS_HF | ADFLAGS_SETSHRMD) );
     EC_EXIT;
 }
 
+static int ad_conv_v22ea_rf(const char *path, const struct stat *sp, const struct vol *vol)
+{
+    EC_INIT;
+    struct adouble adv2;
+    struct adouble adea;
+
+    LOG(log_debug, logtype_default,"ad_conv_v22ea_rf(\"%s\"): BEGIN", fullpathname(path));
+
+    if (S_ISDIR(sp->st_mode))
+        return 0;
+
+    ad_init(&adea, vol);
+    ad_init_old(&adv2, AD_VERSION2, adea.ad_options);
+
+    /* Open and lock adouble:v2 file */
+    EC_ZERO( ad_open(&adv2, path, ADFLAGS_HF | ADFLAGS_RF | ADFLAGS_RDWR) );
+    if (adv2.ad_rlen > 0) {
+        EC_NEG1_LOG( ad_tmplock(&adv2, ADEID_RFORK, ADLOCK_WR | ADLOCK_FILELOCK, 0, 0, 0) );
+
+        /* Create a adouble:ea resource fork */
+        EC_ZERO_LOG( ad_open(&adea, path, ADFLAGS_HF | ADFLAGS_RF | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) );
+
+        EC_ZERO_LOG( copy_fork(ADEID_RFORK, &adea, &adv2) );
+        adea.ad_rlen = adv2.ad_rlen;
+        ad_flush(&adea);
+    }
+
+EC_CLEANUP:
+    EC_ZERO_LOG( ad_close(&adv2, ADFLAGS_HF | ADFLAGS_RF) );
+    EC_ZERO_LOG( ad_close(&adea, ADFLAGS_HF | ADFLAGS_RF) );
+    EC_EXIT;
+}
 
 static int ad_open_df(const char *path, int adflags, mode_t mode, struct adouble *ad)
 {
@@ -1810,3 +1855,52 @@ EC_CLEANUP:
 
     return ret;
 }
+
+int ad_convert(const char *path, const struct stat *sp, const struct vol *vol)
+{
+    EC_INIT;
+    const char *adpath;
+    int adflags = S_ISDIR(sp->st_mode) ? ADFLAGS_DIR : 0;
+
+    if (!(vol->v_adouble == AD_VERSION_EA) || (vol->v_flags & AFPVOL_NOV2TOEACONV))
+        goto EC_CLEANUP;
+
+    EC_ZERO( ad_conv_v22ea_hf(path, sp, vol) );
+    EC_ZERO( ad_conv_v22ea_rf(path, sp, vol) );
+
+    EC_NULL( adpath = ad_path(path, adflags) );
+    LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): deleting adouble:v2 file: \"%s\"",
+        path, fullpathname(adpath));
+
+    become_root();
+    EC_ZERO_LOG( unlink(adpath) );
+    unbecome_root();
+
+EC_CLEANUP:
+    EC_EXIT;
+}
+
+/* build a resource fork mode from the data fork mode:
+ * remove X mode and extend header to RW if R or W (W if R for locking),
+ */
+mode_t ad_hf_mode(mode_t mode)
+{
+    mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH);
+    /* fnctl lock need write access */
+    if ((mode & S_IRUSR))
+        mode |= S_IWUSR;
+    if ((mode & S_IRGRP))
+        mode |= S_IWGRP;
+    if ((mode & S_IROTH))
+        mode |= S_IWOTH;
+
+    /* if write mode set add read mode */
+    if ((mode & S_IWUSR))
+        mode |= S_IRUSR;
+    if ((mode & S_IWGRP))
+        mode |= S_IRGRP;
+    if ((mode & S_IWOTH))
+        mode |= S_IROTH;
+
+    return mode;
+}
index 1ca938900a168afee36db9fd6bb2e7f112b4c47b..a142ef00fa47ac954beb6765e164085298b1123d 100644 (file)
@@ -182,3 +182,93 @@ int ad_dtruncate(struct adouble *ad, const off_t size)
 
     return 0;
 }
+
+/* ----------------------- */
+static int copy_all(const int dfd, const void *buf,
+                               size_t buflen)
+{
+    ssize_t cc;
+
+    while (buflen > 0) {
+        if ((cc = write(dfd, buf, buflen)) < 0) {
+            switch (errno) {
+            case EINTR:
+                continue;
+            default:
+                return -1;
+            }
+        }
+        buflen -= cc;
+    }
+
+    return 0;
+}
+
+/* -------------------------- 
+ * copy only the fork data stream
+*/
+int copy_fork(int eid, struct adouble *add, struct adouble *ads)
+{
+    ssize_t cc;
+    int     err = 0;
+    char    filebuf[8192];
+    int     sfd, dfd;
+
+    if (eid == ADEID_DFORK) {
+        sfd = ad_data_fileno(ads);
+        dfd = ad_data_fileno(add);
+    }
+    else {
+        sfd = ad_reso_fileno(ads);
+        dfd = ad_reso_fileno(add);
+    }        
+
+    if ((off_t)-1 == lseek(sfd, ad_getentryoff(ads, eid), SEEK_SET))
+       return -1;
+
+    if ((off_t)-1 == lseek(dfd, ad_getentryoff(add, eid), SEEK_SET))
+       return -1;
+       
+#if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
+    /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
+    off_t   offset = 0;
+    size_t  size;
+    struct stat         st;
+    #define BUF 128*1024*1024
+
+    if (fstat(sfd, &st) == 0) {
+        
+        while (1) {
+            if ( offset >= st.st_size) {
+               return 0;
+            }
+            size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
+            if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
+                switch (errno) {
+                case ENOSYS:
+                case EINVAL:  /* there's no guarantee that all fs support sendfile */
+                    goto no_sendfile;
+                default:
+                    return -1;
+                }
+            }
+        }
+    }
+    no_sendfile:
+    lseek(sfd, offset, SEEK_SET);
+#endif 
+
+    while (1) {
+        if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
+            if (errno == EINTR)
+                continue;
+            err = -1;
+            break;
+        }
+
+        if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
+            break;
+        }
+    }
+    return err;
+}