]> arthur.barton.de Git - netatalk.git/blobdiff - libatalk/vfs/vfs.c
Merge branch 'develop' into nohex
[netatalk.git] / libatalk / vfs / vfs.c
index b33138bc26ab22efe1fbd4d795b9a1b467f18c3c..8495d8c22fba19dd88789b82c6822bfb4a4fb3d6 100644 (file)
@@ -89,26 +89,21 @@ for_each_adouble(const char *from, const char *name, rf_loop fn, void *data, int
     return ret;
 }
 
-/*******************************************************************************
- * classic adouble format 
- *******************************************************************************/
-
 static int netatalk_name(const char *name)
 {
-    return strcasecmp(name,".AppleDouble") &&
-        strcasecmp(name,".AppleDB") &&
-        strcasecmp(name,".AppleDesktop");
+    return strcmp(name,".AppleDB") && strcmp(name,".AppleDesktop");        
 }
 
+/*******************************************************************************
+ * classic adouble format 
+ *******************************************************************************/
+
 static int validupath_adouble(VFS_FUNC_ARGS_VALIDUPATH)
 {
     if (name[0] != '.')
         return 1;
     
-    if (!(vol->v_flags & AFPVOL_USEDOTS))
-        return 0;
-        
-    return netatalk_name(name) && strcasecmp(name,".Parent");
+    return netatalk_name(name) && strcmp(name,".AppleDouble") && strcasecmp(name,".Parent");
 }                                           
 
 /* ----------------- */
@@ -140,7 +135,7 @@ static int deletecurdir_adouble_loop(struct dirent *de, char *name, void *data _
     /* bail if the file exists in the current directory.
      * note: this will not fail with dangling symlinks */
     
-    if (stat(de->d_name, &st) == 0)
+    if (lstat(de->d_name, &st) == 0)
         return AFPERR_DIRNEMPT;
 
     if ((err = netatalk_unlink(name)))
@@ -178,7 +173,7 @@ static int RF_setdirunixmode_adouble(VFS_FUNC_ARGS_SETDIRUNIXMODE)
     int  dropbox = vol->v_flags;
 
     if (dir_rx_set(mode)) {
-        if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox, vol->v_umask) < 0 ) 
+        if (chmod_acl(ad_dir(adouble), (DIRBITS | mode) & ~vol->v_umask) < 0 ) 
             return -1;
     }
 
@@ -186,7 +181,7 @@ static int RF_setdirunixmode_adouble(VFS_FUNC_ARGS_SETDIRUNIXMODE)
         return -1;
 
     if (!dir_rx_set(mode)) {
-        if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox, vol->v_umask) < 0 ) 
+        if (chmod_acl(ad_dir(adouble), (DIRBITS | mode) & ~vol->v_umask) < 0 ) 
             return  -1 ;
     }
     return 0;
@@ -219,61 +214,25 @@ static int RF_setdirmode_adouble(VFS_FUNC_ARGS_SETDIRMODE)
     const char  *adouble_p = ad_dir(adouble);
 
     if (dir_rx_set(mode)) {
-        if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox, vol->v_umask) < 0) 
+        if (chmod_acl(ad_dir(adouble), (DIRBITS | mode) & ~vol->v_umask) < 0) 
             return -1;
     }
 
-    if (for_each_adouble("setdirmode", adouble_p, setdirmode_adouble_loop, &hf_mode, vol_noadouble(vol), vol->v_umask))
+    if (for_each_adouble("setdirmode", adouble_p, setdirmode_adouble_loop, &hf_mode, 0, vol->v_umask))
         return -1;
 
     if (!dir_rx_set(mode)) {
-        if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox, vol->v_umask) < 0) 
+        if (chmod_acl(ad_dir(adouble), (DIRBITS | mode) & ~vol->v_umask) < 0) 
             return  -1 ;
     }
     return 0;
 }
 
-/* ----------------- */
-static int setdirowner_adouble_loop(struct dirent *de _U_, char *name, void *data, int flag _U_, mode_t v_umask _U_)
-{
-    struct perm   *owner  = data;
-
-    if ( chown( name, owner->uid, owner->gid ) < 0 && errno != EPERM ) {
-         LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
-                owner->uid, owner->gid, fullpathname(name), strerror(errno) );
-         /* return ( -1 ); Sometimes this is okay */
-    }
-    return 0;
-}
-
 static int RF_setdirowner_adouble(VFS_FUNC_ARGS_SETDIROWNER)
 {
-    int           noadouble = vol_noadouble(vol);
-    char          *adouble_p;
-    struct stat   st;
-    struct perm   owner;
-    
-    owner.uid = uid;
-    owner.gid = gid;
-
-    adouble_p = ad_dir(vol->ad_path(name, ADFLAGS_DIR ));
-
-    if (for_each_adouble("setdirowner", adouble_p, setdirowner_adouble_loop, &owner, noadouble, vol->v_umask)) 
-        return -1;
-
-    /*
-     * We cheat: we know that chown doesn't do anything.
-     */
-    if ( stat( ".AppleDouble", &st ) < 0) {
-        if (errno == ENOENT && noadouble)
-            return 0;
-        LOG(log_error, logtype_afpd, "setdirowner: stat %s: %s", fullpathname(".AppleDouble"), strerror(errno) );
-        return -1;
-    }
-    if ( gid && gid != st.st_gid && chown( ".AppleDouble", uid, gid ) < 0 && errno != EPERM ) {
+    if (lchown(".AppleDouble", uid, gid) < 0 && errno != EPERM ) {
         LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
-            uid, gid,fullpathname(".AppleDouble"), strerror(errno) );
-        /* return ( -1 ); Sometimes this is okay */
+            uid, gid,fullpathname(".AppleDouble"), strerror(errno));
     }
     return 0;
 }
@@ -308,8 +267,8 @@ static int RF_renamefile_adouble(VFS_FUNC_ARGS_RENAMEFILE)
              * create .AppleDouble if the file is already opened, so we
              * use a diff one, it's not a pb,ie it's not the same file, yet.
              */
-            ad_init(&ad, vol->v_adouble, vol->v_ad_options); 
-            if (ad_open(&ad, dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666) == 0) {
+            ad_init(&ad, vol); 
+            if (ad_open(&ad, dst, ADFLAGS_HF | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) == 0) {
                ad_close(&ad, ADFLAGS_HF);
                if (!unix_rename(dirfd, adsrc, -1, vol->ad_path(dst, 0 )) ) 
                    err = 0;
@@ -375,7 +334,10 @@ static int RF_copyfile_adouble(VFS_FUNC_ARGS_COPYFILE)
         EC_ZERO(bcatcstr(d, name));
     }
 
-    EC_ZERO(copy_file(sfd, cfrombstr(s), cfrombstr(d), 0666));
+    /* ignore errors */
+    if (copy_file(sfd, cfrombstr(s), cfrombstr(d), 0666) != 0)
+        if (errno != ENOENT)
+            EC_FAIL;
 
 EC_CLEANUP:
     bdestroy(s);
@@ -499,39 +461,22 @@ EC_CLEANUP:
  ************************************************************************/
 static int validupath_ea(VFS_FUNC_ARGS_VALIDUPATH)
 {
-    return 1;
-}             
+    if (name[0] != '.')
+        return 1;
+    
+#ifndef HAVE_EAFD
+    if (name[1] == '_')
+        return ad_valid_header_osx(name);
+#endif
+    return netatalk_name(name);
+}
 
 /* ----------------- */
 static int RF_chown_ea(VFS_FUNC_ARGS_CHOWN)
 {
-    mode_t file_mode = ad_hf_mode(mode);
-    mode_t dir_mode = file_mode;
-    struct set_mode param;
-
-    if ((dir_mode & (S_IRUSR | S_IWUSR )))
-        dir_mode |= S_IXUSR;
-    if ((dir_mode & (S_IRGRP | S_IWGRP )))
-        dir_mode |= S_IXGRP;
-    if ((dir_mode & (S_IROTH | S_IWOTH )))
-        dir_mode |= S_IXOTH;
-
-       /* change folder */
-       dir_mode |= DIRBITS;
-    if (dir_rx_set(dir_mode)) {
-        if (chmod_acl( name,  dir_mode ) < 0)
-            return -1;
-    }
-    param.st = st;
-    param.mode = file_mode;
-    if (for_each_adouble("setfilmode_ads", name, ads_setfilmode_loop, &param, 0, v_umask) < 0)
-        return -1;
-
-    if (!dir_rx_set(dir_mode)) {
-        if (chmod_acl( name,  dir_mode ) < 0)
-            return -1;
-    }
-
+#ifndef HAVE_EAFD
+    return chown(vol->ad_path(path, ADFLAGS_HF ), uid, gid);
+#endif
     return 0;
 }
 
@@ -541,95 +486,154 @@ static int RF_renamedir_ea(VFS_FUNC_ARGS_RENAMEDIR)
     return 0;
 }
 
+/* Returns 1 if the entry is NOT an ._ file */
+static int deletecurdir_ea_osx_chkifempty_loop(struct dirent *de, char *name, void *data _U_, int flag _U_, mode_t v_umask _U_)
+{
+    if (de->d_name[0] != '.' || de->d_name[0] == '_')
+        return 1;
+
+    return 0;
+}
+
+static int deletecurdir_ea_osx_loop(struct dirent *de, char *name, void *data _U_, int flag _U_, mode_t v_umask _U_)
+{
+    int ret;
+    
+    if ((ret = netatalk_unlink(name)) != 0)
+        return ret;
+
+    return 0;
+}
+
 /* ---------------- */
 static int RF_deletecurdir_ea(VFS_FUNC_ARGS_DELETECURDIR)
 {
+#ifndef HAVE_EAFD
+    int err;
+    /* delete stray ._AppleDouble files */
+
+    /* first check if there's really no other file besides files starting with ._ */
+    if ((err = for_each_adouble("deletecurdir_ea_osx", ".",
+                                deletecurdir_ea_osx_chkifempty_loop,
+                                NULL, 0, 0)) != 0) {
+        if (err == 1)
+            return AFPERR_DIRNEMPT;
+        return AFPERR_MISC;
+    }
+
+    /* Now delete orphaned ._ files */
+    if ((err = for_each_adouble("deletecurdir_ea_osx", ".",
+                                deletecurdir_ea_osx_loop,
+                                NULL, 0, 0)) != 0)
+        return err;
+
+#endif
     return 0;
 }
 
 /* ---------------- */
 static int RF_setdirunixmode_ea(VFS_FUNC_ARGS_SETDIRUNIXMODE)
 {
+#ifndef HAVE_EAFD
+#endif
     return 0;
 }
 
 static int RF_setfilmode_ea(VFS_FUNC_ARGS_SETFILEMODE)
 {
+#ifndef HAVE_EAFD
+    return adouble_setfilmode(vol->ad_path(name, ADFLAGS_HF ), mode, st, vol->v_umask);
+#endif
     return 0;
 }
 
 /* ---------------- */
 static int RF_setdirmode_ea(VFS_FUNC_ARGS_SETDIRMODE)
 {
+#ifndef HAVE_EAFD
+#endif
     return 0;
 }
 
 /* ---------------- */
 static int RF_setdirowner_ea(VFS_FUNC_ARGS_SETDIROWNER)
 {
+#ifndef HAVE_EAFD
+#endif
        return 0;
 }
 
 static int RF_deletefile_ea(VFS_FUNC_ARGS_DELETEFILE)
 {
+#ifndef HAVE_EAFD
+       return netatalk_unlinkat(dirfd, vol->ad_path(file, ADFLAGS_HF));
+#endif
     return 0;
 }
 static int RF_copyfile_ea(VFS_FUNC_ARGS_COPYFILE)
 {
+#ifdef HAVE_EAFD
+    /* the EA VFS module does this all for us */
     return 0;
-}
-
-/* ---------------- */
-static int RF_renamefile_ea(VFS_FUNC_ARGS_RENAMEFILE)
-{
-    return 0;
-}
-
-#if 0
-/*************************************************************************
- * osx adouble format 
- ************************************************************************/
-static int validupath_osx(VFS_FUNC_ARGS_VALIDUPATH)
-{
-    return strncmp(name,"._", 2) && (
-      (vol->v_flags & AFPVOL_USEDOTS) ? netatalk_name(name): name[0] != '.');
-}             
-
-/* ---------------- */
-static int RF_renamedir_osx(VFS_FUNC_ARGS_RENAMEDIR)
-{
-    /* We simply move the corresponding ad file as well */
-    char   tempbuf[258]="._";
-    return unix_rename(dirfd, vol->ad_path(oldpath,0), -1, strcat(tempbuf,newpath));
-}
-
-/* ---------------- */
-static int RF_deletecurdir_osx(VFS_FUNC_ARGS_DELETECURDIR)
-{
-    return netatalk_unlink( vol->ad_path(".",0) );
-}
+#endif
 
-/* ---------------- */
-static int RF_setdirunixmode_osx(VFS_FUNC_ARGS_SETDIRUNIXMODE)
-{
-    return adouble_setfilmode(vol->ad_path(name, ADFLAGS_DIR ), mode, st, vol->v_umask);
-}
+    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;
 
-/* ---------------- */
-static int RF_setdirmode_osx(VFS_FUNC_ARGS_SETDIRMODE)
-{
-    return 0;
-}
+    /* get basename */
+
+    /* build src path to ._ 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, "/._"));
+    EC_ZERO(bcatcstr(s, name));
+
+    /* build dst path to ._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, "/._"));
+    EC_ZERO(bcatcstr(d, name));
+
+    if (copy_file(sfd, cfrombstr(s), cfrombstr(d), 0666) != 0) {
+        switch (errno) {
+        case ENOENT:
+            break;
+        default:
+            LOG(log_error, logtype_afpd, "[VFS] copyfile(\"%s\" -> \"%s\"): %s",
+                cfrombstr(s), cfrombstr(d), strerror(errno));
+            EC_FAIL;
+                    
+        }
+    }
 
-/* ---------------- */
-static int RF_setdirowner_osx(VFS_FUNC_ARGS_SETDIROWNER)
-{
-       return 0;
+EC_CLEANUP:
+    bdestroy(s);
+    bdestroy(d);
+    free(dup1);
+    free(dup2);
+    free(dup3);
+    free(dup4);
+    EC_EXIT;
 }
 
 /* ---------------- */
-static int RF_renamefile_osx(VFS_FUNC_ARGS_RENAMEFILE)
+static int RF_renamefile_ea(VFS_FUNC_ARGS_RENAMEFILE)
 {
+#ifndef HAVE_EAFD
     char  adsrc[ MAXPATHLEN + 1];
     int   err = 0;
 
@@ -645,8 +649,9 @@ static int RF_renamefile_osx(VFS_FUNC_ARGS_RENAMEFILE)
         return -1;
     }
     return 0;
-}
 #endif
+    return 0;
+}
 
 /********************************************************************************************
  * VFS chaining
@@ -871,7 +876,11 @@ void initvol_vfs(struct vol *vol)
         vol->ad_path = ad_path;
     } else {
         vol->vfs_modules[0] = &netatalk_adouble_ea;
+#ifdef HAVE_EAFD
         vol->ad_path = ad_path_ea;
+#else
+        vol->ad_path = ad_path_osx;
+#endif
     }
 
     /* Extended Attributes */