]> arthur.barton.de Git - netatalk.git/blobdiff - libatalk/vfs/vfs.c
Merge from branch-2-1
[netatalk.git] / libatalk / vfs / vfs.c
index d3cca207ff89d44f681a7a69b518b9a6c6f6050e..3156afe33191433b0ac43cf7db77d1cb4d05e43e 100644 (file)
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 #include <string.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <libgen.h>
 
 #include <atalk/afp.h>    
 #include <atalk/adouble.h>
@@ -34,6 +39,9 @@
 #include <atalk/vfs.h>
 #include <atalk/directory.h>
 #include <atalk/unix.h>
+#include <atalk/errchk.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
 
 struct perm {
     uid_t uid;
@@ -148,7 +156,7 @@ static int RF_deletecurdir_adouble(VFS_FUNC_ARGS_DELETECURDIR)
        as well. */
     if ((err = for_each_adouble("deletecurdir", ".AppleDouble", deletecurdir_adouble_loop, NULL, 1, vol->v_umask))) 
         return err;
-    return netatalk_rmdir( ".AppleDouble" );
+    return netatalk_rmdir(-1, ".AppleDouble" );
 }
 
 /* ----------------- */
@@ -272,7 +280,7 @@ static int RF_setdirowner_adouble(VFS_FUNC_ARGS_SETDIROWNER)
 /* ----------------- */
 static int RF_deletefile_adouble(VFS_FUNC_ARGS_DELETEFILE)
 {
-       return netatalk_unlink(vol->ad_path(file, ADFLAGS_HF));
+       return netatalk_unlinkat(dirfd, vol->ad_path(file, ADFLAGS_HF));
 }
 
 /* ----------------- */
@@ -282,16 +290,16 @@ static int RF_renamefile_adouble(VFS_FUNC_ARGS_RENAMEFILE)
     int   err = 0;
 
     strcpy( adsrc, vol->ad_path(src, 0 ));
-    if (unix_rename( adsrc, vol->ad_path(dst, 0 )) < 0) {
+    if (unix_rename(dirfd, adsrc, -1, vol->ad_path(dst, 0 )) < 0) {
         struct stat st;
 
         err = errno;
         if (errno == ENOENT) {
                struct adouble    ad;
 
-            if (stat(adsrc, &st)) /* source has no ressource fork, */
+            if (lstatat(dirfd, adsrc, &st)) /* source has no ressource fork, */
                 return 0;
-            
+
             /* We are here  because :
              * -there's no dest folder. 
              * -there's no .AppleDouble in the dest folder.
@@ -302,7 +310,7 @@ static int RF_renamefile_adouble(VFS_FUNC_ARGS_RENAMEFILE)
             ad_init(&ad, vol->v_adouble, vol->v_ad_options); 
             if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
                ad_close(&ad, ADFLAGS_HF);
-               if (!unix_rename( adsrc, vol->ad_path(dst, 0 )) ) 
+               if (!unix_rename(dirfd, adsrc, -1, vol->ad_path(dst, 0 )) ) 
                    err = 0;
                 else 
                    err = errno;
@@ -319,7 +327,67 @@ static int RF_renamefile_adouble(VFS_FUNC_ARGS_RENAMEFILE)
        return 0;
 }
 
-#ifdef HAVE_NFSv4_ACLS
+static int RF_copyfile_adouble(VFS_FUNC_ARGS_COPYFILE)
+/* const struct vol *vol, int sfd, const char *src, const char *dst */
+{
+    EC_INIT;
+    bstring s = NULL, d = NULL;
+    char *dup1 = NULL;
+    char *dup2 = NULL;
+    char *dup3 = NULL;
+    char *dup4 = NULL;
+    const char *name = NULL;
+    const char *dir = NULL;
+
+    struct stat st;
+    EC_ZERO(stat(dst, &st));
+
+    if (S_ISDIR(st.st_mode)) {
+        /* build src path to AppleDouble file*/
+        EC_NULL(s = bfromcstr(src));
+        EC_ZERO(bcatcstr(s, "/.AppleDouble/.Parent"));
+
+        /* build dst path to AppleDouble file*/
+        EC_NULL(d = bfromcstr(dst));
+        EC_ZERO(bcatcstr(d, "/.AppleDouble/.Parent"));
+    } else {
+        /* get basename */
+
+        /* build src path to AppleDouble file*/
+        EC_NULL(dup1 = strdup(src));
+        EC_NULL(name = basename(strdup(dup1)));
+
+        EC_NULL(dup2 = strdup(src));
+        EC_NULL(dir = dirname(dup2));
+        EC_NULL(s = bfromcstr(dir));
+        EC_ZERO(bcatcstr(s, "/.AppleDouble/"));
+        EC_ZERO(bcatcstr(s, name));
+
+        /* build dst path to AppleDouble file*/
+        EC_NULL(dup4 = strdup(dst));
+        EC_NULL(name = basename(strdup(dup4)));
+
+        EC_NULL(dup3 = strdup(dst));
+        EC_NULL(dir = dirname(dup3));
+        EC_NULL(d = bfromcstr(dir));
+        EC_ZERO(bcatcstr(d, "/.AppleDouble/"));
+        EC_ZERO(bcatcstr(d, name));
+    }
+
+    EC_ZERO(copy_file(sfd, cfrombstr(s), cfrombstr(d), 0666));
+
+EC_CLEANUP:
+    bdestroy(s);
+    bdestroy(d);
+    if (dup1) free(dup1);
+    if (dup2) free(dup2);
+    if (dup3) free(dup3);
+    if (dup4) free(dup4);
+
+    EC_EXIT;
+}
+
+#ifdef HAVE_SOLARIS_ACLS
 static int RF_solaris_acl(VFS_FUNC_ARGS_ACL)
 {
     static char buf[ MAXPATHLEN + 1];
@@ -336,11 +404,11 @@ static int RF_solaris_acl(VFS_FUNC_ARGS_ACL)
        if ((acl(buf, cmd, count, aces)) != 0)
            return -1;
        /* now set ACL on ressource fork */
-       if ((acl(vol->vfs->ad_path(path, ADFLAGS_DIR), cmd, count, aces)) != 0)
+       if ((acl(vol->ad_path(path, ADFLAGS_DIR), cmd, count, aces)) != 0)
            return -1;
     } else
        /* set ACL on ressource fork */
-       if ((acl(vol->vfs->ad_path(path, ADFLAGS_HF), cmd, count, aces)) != 0)
+       if ((acl(vol->ad_path(path, ADFLAGS_HF), cmd, count, aces)) != 0)
            return -1;
 
     return 0;
@@ -357,20 +425,74 @@ static int RF_solaris_remove_acl(VFS_FUNC_ARGS_REMOVE_ACL)
        if (len < 0 || len >=  MAXPATHLEN)
            return AFPERR_MISC;
        /* remove ACL from .AppleDouble/.Parent first */
-       if ((ret = remove_acl(vol->vfs->ad_path(path, ADFLAGS_DIR))) != AFP_OK)
+       if ((ret = remove_acl_vfs(vol->ad_path(path, ADFLAGS_DIR))) != AFP_OK)
            return ret;
        /* now remove from .AppleDouble dir */
-       if ((ret = remove_acl(buf)) != AFP_OK)
+       if ((ret = remove_acl_vfs(buf)) != AFP_OK)
            return ret;
     } else
        /* remove ACL from ressource fork */
-       if ((ret = remove_acl(vol->vfs->ad_path(path, ADFLAGS_HF))) != AFP_OK)
+       if ((ret = remove_acl_vfs(vol->ad_path(path, ADFLAGS_HF))) != AFP_OK)
            return ret;
 
     return AFP_OK;
 }
 #endif
 
+#ifdef HAVE_POSIX_ACLS
+static int RF_posix_acl(VFS_FUNC_ARGS_ACL)
+{
+    EC_INIT;
+    static char buf[ MAXPATHLEN + 1];
+    struct stat st;
+    int len;
+
+    if (S_ISDIR(st.st_mode)) {
+        len = snprintf(buf, MAXPATHLEN, "%s/.AppleDouble",path);
+        if (len < 0 || len >=  MAXPATHLEN)
+            EC_FAIL;
+        /* set acl on .AppleDouble dir first */
+        EC_ZERO_LOG(acl_set_file(buf, type, acl));
+
+        if (type == ACL_TYPE_ACCESS)
+            /* set ACL on ressource fork (".Parent") too */
+            EC_ZERO_LOG(acl_set_file(vol->ad_path(path, ADFLAGS_DIR), type, acl));
+    } else {
+        /* set ACL on ressource fork */
+        EC_ZERO_LOG(acl_set_file(vol->ad_path(path, ADFLAGS_HF), type, acl));
+    }
+    
+EC_CLEANUP:
+    if (ret != 0)
+        return AFPERR_MISC;
+    return AFP_OK;
+}
+
+static int RF_posix_remove_acl(VFS_FUNC_ARGS_REMOVE_ACL)
+{
+    EC_INIT;
+    static char buf[ MAXPATHLEN + 1];
+    int len;
+
+    if (dir) {
+        len = snprintf(buf, MAXPATHLEN, "%s/.AppleDouble",path);
+        if (len < 0 || len >=  MAXPATHLEN)
+            return AFPERR_MISC;
+        /* remove ACL from .AppleDouble/.Parent first */
+        EC_ZERO_LOG_ERR(remove_acl_vfs(vol->ad_path(path, ADFLAGS_DIR)), AFPERR_MISC);
+
+        /* now remove from .AppleDouble dir */
+        EC_ZERO_LOG_ERR(remove_acl_vfs(buf), AFPERR_MISC);
+    } else {
+        /* remove ACL from ressource fork */
+        EC_ZERO_LOG_ERR(remove_acl_vfs(vol->ad_path(path, ADFLAGS_HF)), AFPERR_MISC);
+    }
+
+EC_CLEANUP:
+    EC_EXIT;
+}
+#endif
+
 /*********************************************************************************
  * sfm adouble format
  *********************************************************************************/
@@ -426,7 +548,7 @@ static int ads_delete_rf(char *name)
     */
     if ((err = for_each_adouble("deletecurdir", name, deletecurdir_ads1_loop, NULL, 1, 0))) 
         return err;
-    return netatalk_rmdir(name);
+    return netatalk_rmdir(-1, name);
 }
 
 static int deletecurdir_ads_loop(struct dirent *de, char *name, void *data _U_, int flag _U_, mode_t v_umask _U_)
@@ -445,11 +567,12 @@ static int deletecurdir_ads_loop(struct dirent *de, char *name, void *data _U_,
 static int RF_deletecurdir_ads(VFS_FUNC_ARGS_DELETECURDIR)
 {
     int err;
-    
+
     /* delete stray .AppleDouble files. this happens to get .Parent files as well. */
     if ((err = for_each_adouble("deletecurdir", ".AppleDouble", deletecurdir_ads_loop, NULL, 1, 0))) 
         return err;
-    return netatalk_rmdir( ".AppleDouble" );
+
+    return netatalk_rmdir(-1, ".AppleDouble" );
 }
 
 /* ------------------- */
@@ -658,9 +781,31 @@ static int RF_setdirowner_ads(VFS_FUNC_ARGS_SETDIROWNER)
 /* ------------------- */
 static int RF_deletefile_ads(VFS_FUNC_ARGS_DELETEFILE)
 {
-    char *ad_p = ad_dir(vol->ad_path(file, ADFLAGS_HF ));
+    int ret = 0;
+    int cwd = -1;
+    char *ad_p;
+
+    ad_p = ad_dir(vol->ad_path(file, ADFLAGS_HF ));
+
+    if (dirfd != -1) {
+        if (((cwd = open(".", O_RDONLY)) == -1) || (fchdir(dirfd) != 0)) {
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+    }
+
+    ret = ads_delete_rf(ad_p);
+
+    if (dirfd != -1 && fchdir(cwd) != 0) {
+        LOG(log_error, logtype_afpd, "RF_deletefile_ads: cant chdir back. exit!");
+        exit(EXITERR_SYS);
+    }
+
+exit:
+    if (cwd != -1)
+        close(cwd);
 
-    return ads_delete_rf(ad_p);
+    return ret;
 }
 
 /* --------------------------- */
@@ -670,14 +815,14 @@ static int RF_renamefile_ads(VFS_FUNC_ARGS_RENAMEFILE)
     int   err = 0;
 
     strcpy( adsrc, ad_dir(vol->ad_path(src, 0 )));
-    if (unix_rename( adsrc, ad_dir(vol->ad_path(dst, 0 ))) < 0) {
+    if (unix_rename(dirfd, adsrc, -1, ad_dir(vol->ad_path(dst, 0 ))) < 0) {
         struct stat st;
 
         err = errno;
         if (errno == ENOENT) {
                struct adouble    ad;
 
-            if (stat(adsrc, &st)) /* source has no ressource fork, */
+            if (lstatat(dirfd, adsrc, &st)) /* source has no ressource fork, */
                 return 0;
             
             /* We are here  because :
@@ -692,8 +837,8 @@ static int RF_renamefile_ads(VFS_FUNC_ARGS_RENAMEFILE)
                ad_close(&ad, ADFLAGS_HF);
 
                /* We must delete it */
-               RF_deletefile_ads(vol, dst );
-               if (!unix_rename( adsrc, ad_dir(vol->ad_path(dst, 0 ))) ) 
+               RF_deletefile_ads(vol, -1, dst );
+               if (!unix_rename(dirfd, adsrc, -1, ad_dir(vol->ad_path(dst, 0 ))) ) 
                    err = 0;
                 else 
                    err = errno;
@@ -724,7 +869,7 @@ static int RF_renamedir_osx(VFS_FUNC_ARGS_RENAMEDIR)
 {
     /* We simply move the corresponding ad file as well */
     char   tempbuf[258]="._";
-    return rename(vol->ad_path(oldpath,0),strcat(tempbuf,newpath));
+    return unix_rename(dirfd, vol->ad_path(oldpath,0), -1, strcat(tempbuf,newpath));
 }
 
 /* ---------------- */
@@ -759,11 +904,11 @@ static int RF_renamefile_osx(VFS_FUNC_ARGS_RENAMEFILE)
 
     strcpy( adsrc, vol->ad_path(src, 0 ));
 
-    if (unix_rename( adsrc, vol->ad_path(dst, 0 )) < 0) {
+    if (unix_rename(dirfd, adsrc, -1, vol->ad_path(dst, 0 )) < 0) {
         struct stat st;
 
         err = errno;
-        if (errno == ENOENT && stat(adsrc, &st)) /* source has no ressource fork, */
+        if (errno == ENOENT && lstatat(dirfd, adsrc, &st)) /* source has no ressource fork, */
             return 0;
         errno = err;
         return -1;
@@ -815,8 +960,10 @@ VFS_MFUNC(setdirowner, VFS_FUNC_ARGS_SETDIROWNER, VFS_FUNC_VARS_SETDIROWNER)
 VFS_MFUNC(deletefile, VFS_FUNC_ARGS_DELETEFILE, VFS_FUNC_VARS_DELETEFILE)
 VFS_MFUNC(renamefile, VFS_FUNC_ARGS_RENAMEFILE, VFS_FUNC_VARS_RENAMEFILE)
 VFS_MFUNC(copyfile, VFS_FUNC_ARGS_COPYFILE, VFS_FUNC_VARS_COPYFILE)
+#ifdef HAVE_ACLS
 VFS_MFUNC(acl, VFS_FUNC_ARGS_ACL, VFS_FUNC_VARS_ACL)
 VFS_MFUNC(remove_acl, VFS_FUNC_ARGS_REMOVE_ACL, VFS_FUNC_VARS_REMOVE_ACL)
+#endif
 VFS_MFUNC(ea_getsize, VFS_FUNC_ARGS_EA_GETSIZE, VFS_FUNC_VARS_EA_GETSIZE)
 VFS_MFUNC(ea_getcontent, VFS_FUNC_ARGS_EA_GETCONTENT, VFS_FUNC_VARS_EA_GETCONTENT)
 VFS_MFUNC(ea_list, VFS_FUNC_ARGS_EA_LIST, VFS_FUNC_VARS_EA_LIST)
@@ -844,8 +991,10 @@ static struct vfs_ops vfs_master_funcs = {
     vfs_deletefile,
     vfs_renamefile,
     vfs_copyfile,
+#ifdef HAVE_ACLS
     vfs_acl,
     vfs_remove_acl,
+#endif
     vfs_ea_getsize,
     vfs_ea_getcontent,
     vfs_ea_list,
@@ -868,6 +1017,7 @@ static struct vfs_ops netatalk_adouble = {
     /* vfs_setdirowner:   */ RF_setdirowner_adouble,
     /* vfs_deletefile:    */ RF_deletefile_adouble,
     /* vfs_renamefile:    */ RF_renamefile_adouble,
+    /* vfs_copyfile:      */ RF_copyfile_adouble,
     NULL
 };
 
@@ -882,6 +1032,7 @@ static struct vfs_ops netatalk_adouble_osx = {
     /* vfs_setdirowner:   */ RF_setdirowner_osx,
     /* vfs_deletefile:    */ RF_deletefile_adouble,
     /* vfs_renamefile:    */ RF_renamefile_osx,
+    /* vfs_copyfile:      */ NULL,
     NULL
 };
 
@@ -897,6 +1048,7 @@ static struct vfs_ops netatalk_adouble_sfm = {
     /* vfs_setdirowner:   */ RF_setdirowner_ads,
     /* vfs_deletefile:    */ RF_deletefile_ads,
     /* vfs_renamefile:    */ RF_renamefile_ads,
+    /* vfs_copyfile:      */ NULL,
     NULL
 };
 
@@ -916,8 +1068,10 @@ static struct vfs_ops netatalk_ea_adouble = {
     /* vfs_deletefile:    */ ea_deletefile,
     /* vfs_renamefile:    */ ea_renamefile,
     /* vfs_copyfile       */ ea_copyfile,
+#ifdef HAVE_ACLS
     /* vfs_acl:           */ NULL,
     /* vfs_remove_acl     */ NULL,
+#endif
     /* vfs_getsize        */ get_easize,
     /* vfs_getcontent     */ get_eacontent,
     /* vfs_list           */ list_eas,
@@ -925,7 +1079,7 @@ static struct vfs_ops netatalk_ea_adouble = {
     /* vfs_remove         */ remove_ea
 };
 
-static struct vfs_ops netatalk_ea_solaris = {
+static struct vfs_ops netatalk_ea_sys = {
     /* validupath:        */ NULL,
     /* rf_chown:          */ NULL,
     /* rf_renamedir:      */ NULL,
@@ -936,21 +1090,23 @@ static struct vfs_ops netatalk_ea_solaris = {
     /* rf_setdirowner:    */ NULL,
     /* rf_deletefile:     */ NULL,
     /* rf_renamefile:     */ NULL,
-    /* vfs_copyfile:      */ NULL,
+    /* vfs_copyfile:      */ sys_ea_copyfile,
+#ifdef HAVE_ACLS
     /* rf_acl:            */ NULL,
     /* rf_remove_acl      */ NULL,
-    /* ea_getsize         */ sol_get_easize,
-    /* ea_getcontent      */ sol_get_eacontent,
-    /* ea_list            */ sol_list_eas,
-    /* ea_set             */ sol_set_ea,
-    /* ea_remove          */ sol_remove_ea
+#endif
+    /* ea_getsize         */ sys_get_easize,
+    /* ea_getcontent      */ sys_get_eacontent,
+    /* ea_list            */ sys_list_eas,
+    /* ea_set             */ sys_set_ea,
+    /* ea_remove          */ sys_remove_ea
 };
 
 /* 
  * Tertiary VFS modules for ACLs
  */
 
-#ifdef HAVE_NFSv4_ACLS
+#ifdef HAVE_SOLARIS_ACLS
 static struct vfs_ops netatalk_solaris_acl_adouble = {
     /* validupath:        */ NULL,
     /* rf_chown:          */ NULL,
@@ -964,7 +1120,26 @@ static struct vfs_ops netatalk_solaris_acl_adouble = {
     /* rf_renamefile:     */ NULL,
     /* vfs_copyfile       */ NULL,
     /* rf_acl:            */ RF_solaris_acl,
-    /* rf_remove_acl      */ RF_remove_acl,
+    /* rf_remove_acl      */ RF_solaris_remove_acl,
+    NULL
+};
+#endif
+
+#ifdef HAVE_POSIX_ACLS
+static struct vfs_ops netatalk_posix_acl_adouble = {
+    /* validupath:        */ NULL,
+    /* rf_chown:          */ NULL,
+    /* rf_renamedir:      */ NULL,
+    /* rf_deletecurdir:   */ NULL,
+    /* rf_setfilmode:     */ NULL,
+    /* rf_setdirmode:     */ NULL,
+    /* rf_setdirunixmode: */ NULL,
+    /* rf_setdirowner:    */ NULL,
+    /* rf_deletefile:     */ NULL,
+    /* rf_renamefile:     */ NULL,
+    /* vfs_copyfile       */ NULL,
+    /* rf_acl:            */ RF_posix_acl,
+    /* rf_remove_acl      */ RF_posix_remove_acl,
     NULL
 };
 #endif
@@ -989,18 +1164,22 @@ void initvol_vfs(struct vol *vol)
     }
 
     /* Extended Attributes */
-    if (vol->v_vfs_ea == AFPVOL_EA_SOLARIS) {
-
-        LOG(log_debug, logtype_afpd, "initvol_vfs: Enabling EA support with native EAs.");
-        vol->vfs_modules[1] = &netatalk_ea_solaris;
-    } else {
-        /* default: AFPVOL_EA_AD */
-        LOG(log_debug, logtype_afpd, "initvol_vfs: Enabling EA support with adouble files.");
+    if (vol->v_vfs_ea == AFPVOL_EA_SYS) {
+        LOG(log_debug, logtype_afpd, "initvol_vfs: enabling EA support with native EAs");
+        vol->vfs_modules[1] = &netatalk_ea_sys;
+    } else if (vol->v_vfs_ea == AFPVOL_EA_AD) {
+        LOG(log_debug, logtype_afpd, "initvol_vfs: enabling EA support with adouble files");
         vol->vfs_modules[1] = &netatalk_ea_adouble;
+    } else {
+        LOG(log_debug, logtype_afpd, "initvol_vfs: volume without EA support");
     }
 
     /* ACLs */
-#ifdef HAVE_NFSv4_ACLS
+#ifdef HAVE_SOLARIS_ACLS
     vol->vfs_modules[2] = &netatalk_solaris_acl_adouble;
 #endif
+#ifdef HAVE_POSIX_ACLS
+    vol->vfs_modules[2] = &netatalk_posix_acl_adouble;
+#endif
+
 }