]> arthur.barton.de Git - netatalk.git/commitdiff
Convert afp_moveandrename and all called funcs to XXXat semantics if available after-renameat
authorfranklahm <franklahm>
Fri, 12 Mar 2010 15:16:48 +0000 (15:16 +0000)
committerfranklahm <franklahm>
Fri, 12 Mar 2010 15:16:48 +0000 (15:16 +0000)
17 files changed:
configure.in
etc/afpd/directory.c
etc/afpd/directory.h
etc/afpd/file.c
etc/afpd/file.h
etc/afpd/filedir.c
etc/afpd/fork.h
etc/afpd/ofork.c
include/atalk/adouble.h
include/atalk/ea.h
include/atalk/unix.h
include/atalk/vfs.h
libatalk/adouble/ad_open.c
libatalk/vfs/ea.c
libatalk/vfs/ea_sys.c
libatalk/vfs/unix.c
libatalk/vfs/vfs.c

index 1c107098d246ef6e5d13af149acacc9ad06916ca..7dfab7a106aebee15badef62efcc892735c3cb75 100644 (file)
@@ -1,4 +1,4 @@
-dnl $Id: configure.in,v 1.238 2010-02-10 14:05:36 franklahm Exp $
+dnl $Id: configure.in,v 1.239 2010-03-12 15:16:48 franklahm Exp $
 dnl configure.in for netatalk
 
 AC_INIT(etc/afpd/main.c)
@@ -138,6 +138,7 @@ AC_CHECK_FUNCS(getcwd gethostname gettimeofday getusershell mkdir rmdir select s
 AC_CHECK_FUNCS(backtrace_symbols setlocale nl_langinfo)
 AC_CHECK_FUNCS(waitpid getcwd strdup strndup strnlen strtoul strerror chown fchown chmod fchmod chroot link mknod mknod64)
 AC_CHECK_FUNCS(strlcpy strlcat setlinebuf gethostid dirfd)
+AC_CHECK_FUNC(renameat, AC_DEFINE([_ATFILE_SOURCE], 1, AT file source)) 
 AC_CHECK_MEMBERS(struct tm.tm_gmtoff,,, [#include <time.h>])
 AC_CACHE_SAVE
 
index 14edeeb424843ef290bb65a9abb5c6ae108d652d..6480ca7f65c83158d770194d2a5f7a3bdea973bb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: directory.c,v 1.139 2010-03-02 18:07:13 didg Exp $
+ * $Id: directory.c,v 1.140 2010-03-12 15:16:49 franklahm Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -98,7 +98,7 @@ extern void addir_inherit_acl(const struct vol *vol);
  */
 
 struct dir  *curdir;
-int             afp_errno;
+int         afp_errno;
 
 #define SENTINEL (&sentinel)
 static struct dir sentinel = { SENTINEL, SENTINEL, NULL, /* left, right, back */
@@ -787,7 +787,7 @@ static int netatalk_mkdir(const char *name)
 }
 
 /* ------------------- */
-static int deletedir(char *dir)
+static int deletedir(int dirfd, char *dir)
 {
     char path[MAXPATHLEN + 1];
     DIR *dp;
@@ -801,7 +801,7 @@ static int deletedir(char *dir)
         return AFPERR_PARAM;
 
     /* already gone */
-    if ((dp = opendir(dir)) == NULL)
+    if ((dp = opendirat(dirfd, dir)) == NULL)
         return AFP_OK;
 
     strcpy(path, dir);
@@ -818,13 +818,13 @@ static int deletedir(char *dir)
             break;
         }
         strcpy(path + len, de->d_name);
-        if (lstat(path, &st)) {
+        if (lstatat(dirfd, path, &st)) {
             continue;
         }
         if (S_ISDIR(st.st_mode)) {
-            err = deletedir(path);
+            err = deletedir(dirfd, path);
         } else {
-            err = netatalk_unlink(path);
+            err = netatalk_unlinkat(dirfd, path);
         }
     }
     closedir(dp);
@@ -832,13 +832,13 @@ static int deletedir(char *dir)
     /* okay. the directory is empty. delete it. note: we already got rid
        of .AppleDouble.  */
     if (err == AFP_OK) {
-        err = netatalk_rmdir(dir);
+        err = netatalk_rmdir(dirfd, dir);
     }
     return err;
 }
 
 /* do a recursive copy. */
-static int copydir(const struct vol *vol, char *src, char *dst)
+static int copydir(const struct vol *vol, int dirfd, char *src, char *dst)
 {
     char spath[MAXPATHLEN + 1], dpath[MAXPATHLEN + 1];
     DIR *dp;
@@ -852,7 +852,7 @@ static int copydir(const struct vol *vol, char *src, char *dst)
     /* doesn't exist or the path is too long. */
     if (((slen = strlen(src)) > sizeof(spath) - 2) ||
         ((dlen = strlen(dst)) > sizeof(dpath) - 2) ||
-        ((dp = opendir(src)) == NULL))
+        ((dp = opendirat(dirfd, src)) == NULL))
         return AFPERR_PARAM;
 
     /* try to create the destination directory */
@@ -884,7 +884,7 @@ static int copydir(const struct vol *vol, char *src, char *dst)
         }
         strcpy(spath + slen, de->d_name);
 
-        if (lstat(spath, &st) == 0) {
+        if (lstatat(dirfd, spath, &st) == 0) {
             if (strlen(de->d_name) > drem) {
                 err = AFPERR_PARAM;
                 break;
@@ -892,9 +892,9 @@ static int copydir(const struct vol *vol, char *src, char *dst)
             strcpy(dpath + dlen, de->d_name);
 
             if (S_ISDIR(st.st_mode)) {
-                if (AFP_OK != (err = copydir(vol, spath, dpath)))
+                if (AFP_OK != (err = copydir(vol, dirfd, spath, dpath)))
                     goto copydir_done;
-            } else if (AFP_OK != (err = copyfile(vol, vol, spath, dpath, NULL, NULL))) {
+            } else if (AFP_OK != (err = copyfile(vol, vol, dirfd, spath, dpath, NULL, NULL))) {
                 goto copydir_done;
 
             } else {
@@ -906,7 +906,7 @@ static int copydir(const struct vol *vol, char *src, char *dst)
     }
 
     /* keep the same time stamp. */
-    if (lstat(src, &st) == 0) {
+    if (lstatat(dirfd, src, &st) == 0) {
         ut.actime = ut.modtime = st.st_mtime;
         utime(dst, &ut);
     }
@@ -1122,6 +1122,7 @@ struct dir *dirnew(const char *m_name, const char *u_name)
     return dir;
 }
 
+#if 0
 /* ------------------ */
 static hash_val_t hash_fun_dir(const void *key)
 {
@@ -1147,6 +1148,7 @@ static hash_val_t hash_fun_dir(const void *key)
     }
     return acc;
 }
+#endif
 
 #undef get16bits
 #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__)    \
@@ -2532,9 +2534,12 @@ createdir_done:
  * dst       new unix filename (not a pathname)
  * newname   new mac name
  * newparent curdir
- *
+ * dirfd     -1 means ignore dirfd (or use AT_FDCWD), otherwise src is relative to dirfd
  */
-int renamedir(const struct vol *vol, char *src, char *dst,
+int renamedir(const struct vol *vol,
+              int dirfd,
+              char *src,
+              char *dst,
               struct dir *dir,
               struct dir *newparent,
               char *newname)
@@ -2545,7 +2550,7 @@ int renamedir(const struct vol *vol, char *src, char *dst,
     int         len, err;
 
     /* existence check moved to afp_moveandrename */
-    if ( unix_rename( src, dst ) < 0 ) {
+    if ( unix_rename(dirfd, src, -1, dst ) < 0 ) {
         switch ( errno ) {
         case ENOENT :
             return( AFPERR_NOOBJ );
@@ -2559,11 +2564,11 @@ int renamedir(const struct vol *vol, char *src, char *dst,
         case EXDEV:
             /* this needs to copy and delete. bleah. that means we have
              * to deal with entire directory hierarchies. */
-            if ((err = copydir(vol, src, dst)) < 0) {
-                deletedir(dst);
+            if ((err = copydir(vol, dirfd, src, dst)) < 0) {
+                deletedir(-1, dst);
                 return err;
             }
-            if ((err = deletedir(src)) < 0)
+            if ((err = deletedir(dirfd, src)) < 0)
                 return err;
             break;
         default :
@@ -2571,7 +2576,7 @@ int renamedir(const struct vol *vol, char *src, char *dst,
         }
     }
 
-    vol->vfs->vfs_renamedir(vol, src, dst);
+    vol->vfs->vfs_renamedir(vol, dirfd, src, dst);
 
     len = strlen( newname );
     /* rename() succeeded so we need to update our tree even if we can't open
@@ -2690,7 +2695,7 @@ int deletecurdir(struct vol *vol)
         goto delete_done;
     }
 
-    err = netatalk_rmdir_all_errors(fdir->d_u_name);
+    err = netatalk_rmdir_all_errors(-1, fdir->d_u_name);
     if ( err ==  AFP_OK || err == AFPERR_NOOBJ) {
         dirchildremove(curdir, fdir);
         cnid_delete(vol->v_cdb, fdir->d_did);
index 0a699a2a8e7d8accbe8c8f26b6a44fcf2ae4148c..5334be5d5610817c7e117f2efd3390c4420f2aff 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: directory.h,v 1.33 2009-11-13 00:27:35 didg Exp $
+ * $Id: directory.h,v 1.34 2010-03-12 15:16:49 franklahm Exp $
  *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
@@ -132,8 +132,8 @@ extern void             utommode (struct stat *, struct maccess *);
 extern int getdirparams (const struct vol *, u_int16_t, struct path *,
                                  struct dir *, char *, size_t *);
 extern int setdirparams (struct vol *, struct path *, u_int16_t, char *);
-extern int renamedir (const struct vol *, char *, char *, struct dir *,
-                              struct dir *, char *);
+extern int renamedir(const struct vol *, int, char *, char *, struct dir *,
+                     struct dir *, char *);
 extern int path_error (struct path *, int error);
 
 extern void setdiroffcnt (struct dir *dir, struct stat *st,  u_int32_t count);
index 94b4f91ab055a687cb6d870deb1825b258c3675c..aa692842ed4a5c8d919080336292528d33dbcbd2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: file.c,v 1.140 2010-03-02 12:45:31 didg Exp $
+ * $Id: file.c,v 1.141 2010-03-12 15:16:49 franklahm Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -1003,21 +1003,19 @@ setfilparam_done:
  * renamefile and copyfile take the old and new unix pathnames
  * and the new mac name.
  *
+ * sdir_fd     source dir fd to which src path is relative (for openat et al semantics)
+ *             passing -1 means this is not used, src path is a full path
  * src         the source path 
  * dst         the dest filename in current dir
  * newname     the dest mac name
  * adp         adouble struct of src file, if open, or & zeroed one
  *
  */
-int renamefile(const struct vol *vol, char *src, char *dst, char *newname, struct adouble *adp)
+int renamefile(const struct vol *vol, int sdir_fd, char *src, char *dst, char *newname, struct adouble *adp)
 {
     int                rc;
 
-#ifdef DEBUG
-    LOG(log_debug9, logtype_afpd, "begin renamefile:");
-#endif /* DEBUG */
-
-    if ( unix_rename( src, dst ) < 0 ) {
+    if ( unix_rename( sdir_fd, src, -1, dst ) < 0 ) {
         switch ( errno ) {
         case ENOENT :
             return( AFPERR_NOOBJ );
@@ -1035,17 +1033,17 @@ int renamefile(const struct vol *vol, char *src, char *dst, char *newname, struc
                /* FIXME  warning in syslog so admin'd know there's a conflict ?*/
                return AFPERR_OLOCK; /* little lie */
            }
-            if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
+            if (AFP_OK != ( rc = copyfile(vol, vol, sdir_fd, src, dst, newname, NULL )) ) {
                 /* on error copyfile delete dest */
                 return( rc );
             }
-            return deletefile(vol, src, 0);
+            return deletefile(vol, sdir_fd, src, 0);
         default :
             return( AFPERR_PARAM );
         }
     }
 
-    if (vol->vfs->vfs_renamefile(vol, src, dst) < 0 ) {
+    if (vol->vfs->vfs_renamefile(vol, sdir_fd, src, dst) < 0 ) {
         int err;
         
         err = errno;        
@@ -1053,7 +1051,7 @@ int renamefile(const struct vol *vol, char *src, char *dst, char *newname, struc
         * we know we are on the same device 
        */
        if (err) {
-           unix_rename( dst, src ); 
+        unix_rename(-1, dst, sdir_fd, src ); 
            /* return the first error */
            switch ( err) {
             case ENOENT :
@@ -1076,9 +1074,6 @@ int renamefile(const struct vol *vol, char *src, char *dst, char *newname, struc
         ad_flush( adp );
         ad_close( adp, ADFLAGS_HF );
     }
-#ifdef DEBUG
-    LOG(log_debug9, logtype_afpd, "end renamefile:");
-#endif /* DEBUG */
 
     return( AFP_OK );
 }
@@ -1263,7 +1258,7 @@ int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, si
         goto copy_exit;
     }
 
-    if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
+    if ( (err = copyfile(s_vol, d_vol, -1, p, upath , newname, adp)) < 0 ) {
         retvalue = err;
         goto copy_exit;
     }
@@ -1385,8 +1380,13 @@ static int copy_fork(int eid, struct adouble *add, struct adouble *ads)
  * because we are doing it elsewhere.
  * currently if newname is NULL then adp is NULL. 
  */
-int copyfile(const struct vol *s_vol, const struct vol*d_vol, 
-    char *src, char *dst, char *newname, struct adouble *adp)
+int copyfile(const struct vol *s_vol,
+             const struct vol *d_vol, 
+             int sfd,
+             char *src,
+             char *dst,
+             char *newname,
+             struct adouble *adp)
 {
     struct adouble     ads, add;
     int                        err = 0;
@@ -1395,9 +1395,8 @@ int copyfile(const struct vol *s_vol, const struct vol*d_vol,
     int                 stat_result;
     struct stat         st;
     
-#ifdef DEBUG
-    LOG(log_debug9, logtype_afpd, "begin copyfile:");
-#endif /* DEBUG */
+    LOG(log_debug, logtype_afpd, "copyfile(sfd:%d,s:'%s',d:'%s',n:'%s')",
+        sfd, src, dst, newname);
 
     if (adp == NULL) {
         ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options); 
@@ -1409,7 +1408,7 @@ int copyfile(const struct vol *s_vol, const struct vol*d_vol,
         adflags |= ADFLAGS_HF;
     }
 
-    if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
+    if (ad_openat(sfd, src, adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
         ret_err = errno;
         goto done;
     }
@@ -1431,7 +1430,7 @@ int copyfile(const struct vol *s_vol, const struct vol*d_vol,
         ret_err = errno;
         ad_close( adp, adflags );
         if (EEXIST != ret_err) {
-            deletefile(d_vol, dst, 0);
+            deletefile(d_vol, -1, dst, 0);
             goto done;
         }
         return AFPERR_EXIST;
@@ -1443,7 +1442,7 @@ int copyfile(const struct vol *s_vol, const struct vol*d_vol,
     if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){
         /* copy the data fork */
         if ((err = copy_fork(ADEID_DFORK, &add, adp)) == 0) {
-            err = d_vol->vfs->vfs_copyfile(d_vol, src, dst);
+            err = d_vol->vfs->vfs_copyfile(d_vol, sfd, src, dst);
         }
     }
 
@@ -1464,7 +1463,7 @@ int copyfile(const struct vol *s_vol, const struct vol*d_vol,
     } 
 
     if (ret_err) {
-        deletefile(d_vol, dst, 0);
+        deletefile(d_vol, -1, dst, 0);
     }
     else if (stat_result == 0) {
         /* set dest modification date to src date */
@@ -1477,10 +1476,6 @@ int copyfile(const struct vol *s_vol, const struct vol*d_vol,
        */
     }
 
-#ifdef DEBUG
-    LOG(log_debug9, logtype_afpd, "end copyfile:");
-#endif /* DEBUG */
-
 done:
     switch ( ret_err ) {
     case 0:
@@ -1527,17 +1522,17 @@ u_int16_t   bshort = 0;
        }
        return 0;
 }
-
-int deletefile(const struct vol *vol, char *file, int checkAttrib)
+/* 
+ * dirfd can be used for unlinkat semantics
+ */
+int deletefile(const struct vol *vol, int dirfd, char *file, int checkAttrib)
 {
     struct adouble     ad;
     struct adouble      *adp = NULL;
     int                        adflags, err = AFP_OK;
     int                        meta = 0;
 
-#ifdef DEBUG
-    LOG(log_debug9, logtype_afpd, "begin deletefile:");
-#endif /* DEBUG */
+    LOG(log_debug, logtype_afpd, "deletefile('%s')", file);
 
     ad_init(&ad, vol->v_adouble, vol->v_ad_options);
     if (checkAttrib) {
@@ -1546,7 +1541,7 @@ int deletefile(const struct vol *vol, char *file, int checkAttrib)
          * moreover sometimes deletefile is called with a no existent file and 
          * ad_open would create a 0 byte resource fork
         */
-        if ( ad_metadata( file, ADFLAGS_OPENFORKS, &ad) == 0 ) {
+        if ( ad_metadataat(dirfd, file, ADFLAGS_OPENFORKS, &ad) == 0 ) {
             if ((err = check_attrib(&ad))) {
                ad_close_metadata(&ad);
                return err;
@@ -1557,7 +1552,7 @@ int deletefile(const struct vol *vol, char *file, int checkAttrib)
  
     /* try to open both forks at once */
     adflags = ADFLAGS_DF;
-    if ( ad_open( file, adflags |ADFLAGS_HF|ADFLAGS_NOHF, O_RDONLY, 0, &ad ) < 0 ) {
+    if ( ad_openat(dirfd, file, adflags |ADFLAGS_HF|ADFLAGS_NOHF, O_RDONLY, 0, &ad ) < 0 ) {
         switch (errno) {
         case ENOENT:
             err = AFPERR_NOOBJ;
@@ -1595,11 +1590,9 @@ int deletefile(const struct vol *vol, char *file, int checkAttrib)
 
     if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
         err = AFPERR_BUSY;
-    }
-    else if (!(err = vol->vfs->vfs_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
+    } else if (!(err = vol->vfs->vfs_deletefile(vol, dirfd, file)) && !(err = netatalk_unlinkat(dirfd, file )) ) {
         cnid_t id;
-        if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file)))) 
-        {
+        if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file)))) {
             cnid_delete(vol->v_cdb, id);
         }
     }
@@ -1611,11 +1604,6 @@ end:
     if (adp)
         ad_close( &ad, adflags );  /* ad_close removes locks if any */
 
-
-#ifdef DEBUG
-    LOG(log_debug9, logtype_afpd, "end deletefile:");
-#endif /* DEBUG */
-
     return err;
 }
 
@@ -2144,17 +2132,17 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U
     }
 
     /* now, quickly rename the file. we error if we can't. */
-    if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
+    if ((err = renamefile(vol, -1, p, temp, temp, adsp)) != AFP_OK)
         goto err_exchangefile;
     of_rename(vol, s_of, sdir, spath, curdir, temp);
 
     /* rename destination to source */
-    if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
+    if ((err = renamefile(vol, -1, upath, p, spath, addp)) != AFP_OK)
         goto err_src_to_tmp;
     of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
 
     /* rename temp to destination */
-    if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
+    if ((err = renamefile(vol, -1, temp, upath, path->m_name, adsp)) != AFP_OK)
         goto err_dest_to_src;
     of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
 
@@ -2239,17 +2227,17 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U
      * properly. */
 err_temp_to_dest:
     /* rename dest to temp */
-    renamefile(vol, upath, temp, temp, adsp);
+    renamefile(vol, -1, upath, temp, temp, adsp);
     of_rename(vol, s_of, curdir, upath, curdir, temp);
 
 err_dest_to_src:
     /* rename source back to dest */
-    renamefile(vol, p, upath, path->m_name, addp);
+    renamefile(vol, -1, p, upath, path->m_name, addp);
     of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
 
 err_src_to_tmp:
     /* rename temp back to source */
-    renamefile(vol, temp, p, spath, adsp);
+    renamefile(vol, -1, temp, p, spath, adsp);
     of_rename(vol, s_of, curdir, temp, sdir, spath);
 
 err_exchangefile:
index 9d3ca116177d0145d17cc189b1fb61e77605404f..6cf4ae22f8184d15319dddb26d6d25b75bf5c832 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: file.h,v 1.25 2010-02-10 14:05:37 franklahm Exp $
+ * $Id: file.h,v 1.26 2010-03-12 15:16:49 franklahm Exp $
  *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
@@ -115,9 +115,9 @@ extern int getfilparams (struct vol *, u_int16_t, struct path *,
                                  struct dir *, char *buf, size_t *);
 
 extern int setfilparams (struct vol *, struct path *, u_int16_t, char *);
-extern int renamefile   (const struct vol *, char *, char *, char *, struct adouble *);
-extern int copyfile     (const struct vol *, const struct vol *, char *, char *, char *, struct adouble *);
-extern int deletefile   (const struct vol *, char *, int);
+extern int renamefile   (const struct vol *, int, char *, char *, char *, struct adouble *);
+extern int copyfile     (const struct vol *, const struct vol *, int, char *, char *, char *, struct adouble *);
+extern int deletefile   (const struct vol *, int, char *, int);
 
 extern int getmetadata  (struct vol *vol, u_int16_t bitmap, struct path *path, 
                          struct dir *dir, char *buf, size_t *buflen, struct adouble *adp);
index 203622f45c7dac1005fc29612af88a3b145df6fb..3e5cb2f5ee8048597a75d0552c971f7c769821f9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: filedir.c,v 1.72 2010-02-19 10:51:59 franklahm Exp $
+ * $Id: filedir.c,v 1.73 2010-03-12 15:16:49 franklahm Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -313,10 +313,14 @@ int check_name(const struct vol *vol, char *name)
 
 /* ------------------------- 
     move and rename sdir:oldname to curdir:newname in volume vol
-   
     special care is needed for lock   
 */
-static int moveandrename(const struct vol *vol, struct dir *sdir, char *oldname, char *newname, int isdir)
+static int moveandrename(const struct vol *vol,
+                         struct dir *sdir,
+                         int sdir_fd,
+                         char *oldname,
+                         char *newname,
+                         int isdir)
 {
     char            *p;
     char            *upath;
@@ -326,31 +330,38 @@ static int moveandrename(const struct vol *vol, struct dir *sdir, char *oldname,
     struct adouble     ad;
     struct adouble     *adp;
     struct ofork       *opened = NULL;
-    struct path         path;
-    cnid_t      id;
+    struct path     path;
+    cnid_t          id;
+    int             cwd_fd;
 
     ad_init(&ad, vol->v_adouble, vol->v_ad_options);
     adp = &ad;
     adflags = 0;
-    
+
     if (!isdir) {
-        p = mtoupath(vol, oldname, sdir->d_did, utf8_encoding());
-        if (!p) { 
+        if ((p = mtoupath(vol, oldname, sdir->d_did, utf8_encoding())) == NULL)
             return AFPERR_PARAM; /* can't convert */
-        }
+
+#ifndef HAVE_RENAMEAT
+        /* Need full path */
         id = cnid_get(vol->v_cdb, sdir->d_did, p, strlen(p));
         p = ctoupath( vol, sdir, oldname );
-        if (!p) { 
+        if (!p)
             return AFPERR_PARAM; /* pathname too long */
-        }
+#endif /* HAVE_RENAMEAT */
+
         path.st_valid = 0;
         path.u_name = p;
-        if ((opened = of_findname(&path))) {
+#ifdef HAVE_RENAMEAT
+        opened = of_findnameat(sdir_fd, &path);
+#else
+        opened = of_findname(&path);
+#endif /* HAVE_RENAMEAT */
+        if (opened) {
             /* reuse struct adouble so it won't break locks */
             adp = opened->of_ad;
         }
-    }
-    else {
+    } else {
         id = sdir->d_did; /* we already have the CNID */
         p = ctoupath( vol, sdir->d_parent, oldname );
         if (!p) {
@@ -358,12 +369,23 @@ static int moveandrename(const struct vol *vol, struct dir *sdir, char *oldname,
         }
         adflags = ADFLAGS_DIR;
     }
+
+
     /*
-     * p now points to the full pathname of the source fs object.
-     * 
-     * we are in the dest folder so we need to use p for ad_open
-    */
-    
+     * p now points to either
+     *   a) full pathname of the source fs object (if renameat is not available)
+     *   b) the oldname (renameat is available)
+     * we are in the dest folder so we need to use 
+     *   a) p for ad_open
+     *   b) fchdir sdir_fd before eg ad_open or use *at functions where appropiate
+     */
+
+    if (sdir_fd != -1) {
+        if ((cwd_fd = open(".", O_RDONLY)) == -1)
+            return AFPERR_MISC;
+        if (fchdir(sdir_fd) != 0)
+            return AFPERR_MISC;
+    }
     if (!ad_metadata(p, adflags, adp)) {
         u_int16_t bshort;
 
@@ -372,6 +394,12 @@ static int moveandrename(const struct vol *vol, struct dir *sdir, char *oldname,
         if ((bshort & htons(ATTRBIT_NORENAME))) 
             return(AFPERR_OLOCK);
     }
+    if (sdir_fd != -1) {
+        if (fchdir(cwd_fd) != 0) {
+            LOG(log_error, logtype_afpd, "moveandrename: %s", strerror(errno) );
+            return AFPERR_MISC;
+        }
+    }
 
     if (NULL == (upath = mtoupath(vol, newname, curdir->d_did, utf8_encoding()))){ 
         return AFPERR_PARAM;
@@ -403,12 +431,12 @@ static int moveandrename(const struct vol *vol, struct dir *sdir, char *oldname,
         if (of_findname(&path)) {
             rc = AFPERR_EXIST; /* was AFPERR_BUSY; */
         } else {
-            rc = renamefile(vol, p, upath, newname, adp );
+            rc = renamefile(vol, sdir_fd, p, upath, newname, adp );
             if (rc == AFP_OK)
                 of_rename(vol, opened, sdir, oldname, curdir, newname);
         }
     } else {
-        rc = renamedir(vol, p, upath, sdir, curdir, newname);
+        rc = renamedir(vol, sdir_fd, p, upath, sdir, curdir, newname);
     }
     if ( rc == AFP_OK && id ) {
         /* renaming may have moved the file/dir across a filesystem */
@@ -489,8 +517,7 @@ int afp_rename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size
         return AFP_OK; /* newname == oldname same dir */
     }
     
-    rc = moveandrename(vol, sdir, oldname, newname, isdir);
-
+    rc = moveandrename(vol, sdir, -1, oldname, newname, isdir);
     if ( rc == AFP_OK ) {
         setvoltime(obj, vol );
     }
@@ -549,7 +576,7 @@ int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size
             rc = AFPERR_NOOBJ;
         }
         else {
-            rc = deletefile(vol, upath, 1);
+            rc = deletefile(vol, -1, upath, 1);
         }
     }
     if ( rc == AFP_OK ) {
@@ -623,6 +650,8 @@ int afp_moveandrename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U
 #ifdef DROPKLUDGE
     int                retvalue;
 #endif /* DROPKLUDGE */
+    int     sdir_fd = -1;
+
 
     *rbuflen = 0;
     ibuf += 2;
@@ -659,40 +688,51 @@ int afp_moveandrename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U
     if ( *path->m_name != '\0' ) {
         if (isdir) {
             sdir = path->d_dir;
-       }
+        }
         strcpy(oldname, path->m_name); /* an extra copy for of_rename */
     } else {
         strcpy(oldname, sdir->d_m_name);
     }
 
+#ifdef HAVE_RENAMEAT
+    if ((sdir_fd = open(".", O_RDONLY)) == -1)
+        return AFPERR_MISC;
+#endif
+
     /* get the destination directory */
     if (NULL == ( ddir = dirlookup( vol, did )) ) {
-        return afp_errno; /*  was AFPERR_PARAM */
+        rc = afp_errno; /*  was AFPERR_PARAM */
+        goto exit;
     }
     if (NULL == ( path = cname( vol, ddir, &ibuf ))) {
-        return( AFPERR_NOOBJ );
+        rc = AFPERR_NOOBJ;
+        goto exit;
     }
     pdid = curdir->d_did;
     if ( *path->m_name != '\0' ) {
-        return path_error(path, AFPERR_NOOBJ);
+        rc = path_error(path, AFPERR_NOOBJ);
+        goto exit;
     }
 
     /* one more place where we know about path type */
     if ((plen = copy_path_name(vol, newname, ibuf)) < 0) {
-        return( AFPERR_PARAM );
+        rc = AFPERR_PARAM;
+        goto exit;
     }
 
     if (!plen) {
         strcpy(newname, oldname);
     }
 
-    rc = moveandrename(vol, sdir, oldname, newname, isdir);
+    /* This does the work */
+    rc = moveandrename(vol, sdir, sdir_fd, oldname, newname, isdir);
 
     if ( rc == AFP_OK ) {
         char *upath = mtoupath(vol, newname, pdid, utf8_encoding());
         
         if (NULL == upath) {
-            return AFPERR_PARAM;
+            rc = AFPERR_PARAM;
+            goto exit;
         }
         curdir->offcnt++;
         sdir->offcnt--;
@@ -700,7 +740,8 @@ int afp_moveandrename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U
         if (vol->v_flags & AFPVOL_DROPBOX) {
             /* FIXME did is not always the source id */
             if ((retvalue=matchfile2dirperms (upath, vol, did)) != AFP_OK) {
-                return retvalue;
+                rc = retvalue;
+                goto exit;
             }
         }
         else
@@ -715,6 +756,12 @@ int afp_moveandrename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U
         setvoltime(obj, vol );
     }
 
+exit:
+#ifdef HAVE_RENAMEAT
+    if (sdir_fd != -1)
+        close(sdir_fd);
+#endif
+
     return( rc );
 }
 
index 36576b39c8d9f60cac14c27c93a24c9953662e9b..5a42afc71dc202492c3ca875876b913a5f944a86 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: fork.h,v 1.17 2009-11-13 00:27:35 didg Exp $
+ * $Id: fork.h,v 1.18 2010-03-12 15:16:49 franklahm Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -75,6 +75,13 @@ extern int          of_statdir   (struct vol *vol, struct path *);
 extern int          of_closefork (struct ofork *ofork);
 extern void         of_closevol  (const struct vol *vol);
 extern struct adouble *of_ad     (const struct vol *, struct path *, struct adouble *);
+
+#ifdef HAVE_RENAMEAT
+extern struct ofork *of_findnameat(int dirfd, struct path *path);
+extern int of_fstatat(int dirfd, struct path *path);
+#endif  /* HAVE_RENAMEAT */
+
+
 /* in fork.c */
 extern int          flushfork    (struct ofork *);
 extern int          getforkmode  (struct adouble *, int , int );
index d9c4f31e8e5b0d2685b740a9cddf0dc6a8303fa7..49c014ccef9befec7be7f15068e5c7039e757139 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ofork.c,v 1.31 2010-02-10 14:05:37 franklahm Exp $
+ * $Id: ofork.c,v 1.32 2010-03-12 15:16:49 franklahm Exp $
  *
  * Copyright (c) 1996 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -101,11 +101,10 @@ int of_flush(const struct vol *vol)
     return( 0 );
 }
 
-int of_rename(
-    const struct vol *vol,
-    struct ofork *s_of,
-    struct dir *olddir, const char *oldpath _U_,
-    struct dir *newdir, const char *newpath)
+int of_rename(const struct vol *vol,
+              struct ofork *s_of,
+              struct dir *olddir, const char *oldpath _U_,
+              struct dir *newdir, const char *newpath)
 {
     struct ofork *of, *next, *d_ofork;
     int done = 0;
@@ -290,6 +289,21 @@ int ret;
    return ret;
 }
 
+#ifdef HAVE_RENAMEAT
+int of_fstatat(int dirfd, struct path *path)
+{
+    int ret;
+
+    path->st_errno = 0;
+    path->st_valid = 1;
+
+    if ((ret = fstatat(dirfd, path->u_name, &path->st, AT_SYMLINK_NOFOLLOW)) < 0)
+       path->st_errno = errno;
+
+   return ret;
+}
+#endif /* HAVE_RENAMEAT */
+
 /* -------------------------- 
    stat the current directory.
    stat(".") works even if "." is deleted thus
@@ -325,8 +339,7 @@ int ret;
 }
 
 /* -------------------------- */
-struct ofork *
-            of_findname(struct path *path)
+struct ofork *of_findname(struct path *path)
 {
     struct ofork *of;
     struct file_key key;
@@ -350,6 +363,41 @@ struct ofork *
     return NULL;
 }
 
+/*!
+ * @brief Search for open fork by dirfd/name
+ *
+ * Function call of_fstatat with dirfd and path and uses dev and ino
+ * to search the open fork table.
+ *
+ * @param dirfd     (r) directory fd
+ * @param path      (rw) pointer to struct path
+ */
+#ifdef HAVE_RENAMEAT
+struct ofork *of_findnameat(int dirfd, struct path *path)
+{
+    struct ofork *of;
+    struct file_key key;
+    
+    if ( ! path->st_valid) {
+        of_fstatat(dirfd, path);
+    }
+       
+    if (path->st_errno)
+        return NULL;
+
+    key.dev = path->st.st_dev;
+    key.inode = path->st.st_ino;
+
+    for (of = ofork_table[hashfn(&key)]; of; of = of->next) {
+        if (key.dev == of->key.dev && key.inode == of->key.inode ) {
+            return of;
+        }
+    }
+
+    return NULL;
+}
+#endif
+
 void of_dealloc( struct ofork *of)
 {
     if (!oforks)
index fbf53a1c34ce2c78b6d858fbe20ae8ddacada4cb..aaf21227954e45068f97404d4ede1d41c55ccca5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: adouble.h,v 1.53 2010-02-10 14:05:37 franklahm Exp $
+ * $Id: adouble.h,v 1.54 2010-03-12 15:16:49 franklahm Exp $
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
  *
@@ -474,9 +474,11 @@ extern int ad_mode        (const char *, int);
 extern int ad_mkdir       (const char *, int);
 extern void ad_init       (struct adouble *, int, int );
 extern int ad_open        (const char *, int, int, int, struct adouble *);
+extern int ad_openat      (int dirfd, const char *, int, int, int, struct adouble *);
 extern int ad_refresh     (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 *);
 
 #define ad_open_metadata(name, flags, mode, adp)\
    ad_open(name, ADFLAGS_MD|(flags), O_RDWR |(mode), 0666, (adp))
index 48432ef6e9aa88391ad0a6b88acafa04f60fcaad..00d987de77b27bd37fcc69d3949e65416af386b9 100644 (file)
@@ -1,5 +1,5 @@
 /*
-   $Id: ea.h,v 1.10 2009-12-10 17:40:25 franklahm Exp $
+   $Id: ea.h,v 1.11 2010-03-12 15:16:49 franklahm Exp $
    Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
 
    This program is free software; you can redistribute it and/or modify
@@ -99,6 +99,7 @@ struct ea_entry {
 struct ea {
     uint32_t             ea_inited;       /* needed for interfacing ea_open w. ea_close */
     const struct vol     *vol;            /* vol handle, ea_close needs it */
+    int                  dirfd;           /* for *at (cf openat) semantics, -1 means ignore */
     char                 *filename;       /* name of file, needed by ea_close too */
     unsigned int         ea_count;        /* number of EAs in ea_entries array */
     struct ea_entry      (*ea_entries)[]; /* malloced and realloced as needed by ea_count*/
@@ -154,6 +155,11 @@ extern int ea_open(const struct vol * restrict vol,
                    const char * restrict uname,
                    eaflags_t eaflags,
                    struct ea * restrict ea);
+extern int ea_openat(const struct vol * restrict vol,
+                     int dirfd,
+                     const char * restrict uname,
+                     eaflags_t eaflags,
+                     struct ea * restrict ea);
 extern int ea_close(struct ea * restrict ea);
 extern char *ea_path(const struct ea * restrict ea, const char * restrict eaname, int macname);
 
index 697d2a7f4cb4f40123df295c8e9b8dda6ae03ba9..06e3f49391dd7feea4e0998b805e9dcbfb4e9406 100644 (file)
@@ -1,5 +1,5 @@
 /*
-   $Id: unix.h,v 1.2 2010-01-26 08:14:09 didg Exp $
+   $Id: unix.h,v 1.3 2010-03-12 15:16:49 franklahm Exp $
    Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
 
    This program is free software; you can redistribute it and/or modify
 #endif
 
 #include <sys/types.h>
+#include <dirent.h>
 
 /* vfs/unix.c */
 extern int netatalk_unlink(const char *name);
+extern int netatalk_unlinkat(int dirfd, const char *name);
 extern char *fullpathname(const char *);
+extern int statat(int dirfd, const char *path, struct stat *st);
+extern int lstatat(int dirfd, const char *path, struct stat *st);
+extern DIR *opendirat(int dirfd, const char *path);
 
 /* rmdir ENOENT not an error */
-extern int netatalk_rmdir(const char *name);
-
-extern int netatalk_rmdir_all_errors(const char *name);
+extern int netatalk_rmdir(int dirfd, const char *name);
+extern int netatalk_rmdir_all_errors(int dirfd, const char *name);
 
 extern int setfilmode(const char *, mode_t, struct stat *, mode_t);
 extern int dir_rx_set(mode_t mode);
 extern int stickydirmode(const char *name, const mode_t mode, const int dropbox, const mode_t v_umask);
-extern int unix_rename(const char *oldpath, const char *newpath);
-extern int copy_file(const char *src, const char *dst, mode_t mode);
-
+extern int unix_rename(int sfd, const char *oldpath, int dfd, const char *newpath);
+extern int copy_file(int sfd, const char *src, const char *dst, mode_t mode);
 #endif  /* ATALK_UNIX_H */
index a252909d884623ab5e556dc0f95fc6a01bc8c2fc..de1c008ce22d2f1b50e82d752cab64d195896fdf 100644 (file)
@@ -34,8 +34,8 @@
 #define VFS_FUNC_ARGS_CHOWN const struct vol *vol, const char *path, uid_t uid, gid_t gid
 #define VFS_FUNC_VARS_CHOWN vol, path, uid, gid
 
-#define VFS_FUNC_ARGS_RENAMEDIR const struct vol *vol, const char *oldpath, const char *newpath
-#define VFS_FUNC_VARS_RENAMEDIR vol, oldpath, newpath
+#define VFS_FUNC_ARGS_RENAMEDIR const struct vol *vol, int dirfd, const char *oldpath, const char *newpath
+#define VFS_FUNC_VARS_RENAMEDIR vol, dirfd, oldpath, newpath
 
 #define VFS_FUNC_ARGS_DELETECURDIR const struct vol *vol
 #define VFS_FUNC_VARS_DELETECURDIR vol
 #define VFS_FUNC_ARGS_SETDIROWNER const struct vol *vol, const char *name, uid_t uid, gid_t gid
 #define VFS_FUNC_VARS_SETDIROWNER vol, name, uid, gid
 
-#define VFS_FUNC_ARGS_DELETEFILE const struct vol *vol, const char *file
-#define VFS_FUNC_VARS_DELETEFILE vol, file
+#define VFS_FUNC_ARGS_DELETEFILE const struct vol *vol, int dirfd, const char *file
+#define VFS_FUNC_VARS_DELETEFILE vol, dirfd, file
 
-#define VFS_FUNC_ARGS_RENAMEFILE const struct vol *vol, const char *src, const char *dst
-#define VFS_FUNC_VARS_RENAMEFILE vol, src, dst
+#define VFS_FUNC_ARGS_RENAMEFILE const struct vol *vol, int dirfd, const char *src, const char *dst
+#define VFS_FUNC_VARS_RENAMEFILE vol, dirfd, src, dst
 
-#define VFS_FUNC_ARGS_COPYFILE const struct vol *vol, const char *src, const char *dst
-#define VFS_FUNC_VARS_COPYFILE vol, src, dst
+#define VFS_FUNC_ARGS_COPYFILE const struct vol *vol, int sfd, const char *src, const char *dst
+#define VFS_FUNC_VARS_COPYFILE vol, sfd, src, dst
 
 #define VFS_FUNC_ARGS_ACL const struct vol *vol, const char *path, int cmd, int count, void *aces
 #define VFS_FUNC_VARS_ACL vol, path, cmd, count, aces
index 6e9dc85c33eb1f7e74db2c041d6aa17ddc02d416..b4e7c3a58cad0c8d92d547bc635a8ed92ce86db5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ad_open.c,v 1.71 2010-03-07 18:27:59 didg Exp $
+ * $Id: ad_open.c,v 1.72 2010-03-12 15:16:49 franklahm Exp $
  *
  * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu)
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
@@ -1586,6 +1586,41 @@ int ad_metadata(const char *name, int flags, struct adouble *adp)
     return ret;
 }
 
+/*
+ * @brief openat like wrapper for ad_metadata
+ */
+int ad_metadataat(int dirfd, const char *name, int flags, struct adouble *adp)
+{
+    int ret = 0;
+    int cwdfd = -1;
+
+    if (dirfd != -1) {
+        if ((cwdfd = open(".", O_RDONLY) == -1) || (fchdir(dirfd) != 0)) {
+            ret = -1;
+            goto exit;
+        }
+    }
+
+    if (ad_metadata(name, flags, adp) < 0) {
+        ret = -1;
+        goto exit;
+    }
+
+    if (dirfd != -1) {
+        if (fchdir(cwdfd) != 0) {
+            LOG(log_error, logtype_afpd, "ad_openat: cant chdir back, exiting");
+            exit(EXITERR_SYS);
+        }
+    }
+
+exit:
+    if (cwdfd != -1)
+        close(cwdfd);
+
+    return ret;
+
+}
+
 /* ----------------------------------- */
 static int new_rfork(const char *path, struct adouble *ad, int adflags)
 {
@@ -1665,3 +1700,39 @@ int ad_refresh(struct adouble *ad)
 
     return ad->ad_ops->ad_header_read(ad, NULL);
 }
+
+int ad_openat(int dirfd,  /* dir fd openat like */
+              const char *path,
+              int adflags,
+              int oflags,
+              int mode,
+              struct adouble  *ad)
+{
+    int ret = 0;
+    int cwdfd = -1;
+
+    if (dirfd != -1) {
+        if ((cwdfd = open(".", O_RDONLY) == -1) || (fchdir(dirfd) != 0)) {
+            ret = -1;
+            goto exit;
+        }
+    }
+
+    if (ad_open(path, adflags, oflags, mode, ad) < 0) {
+        ret = -1;
+        goto exit;
+    }
+
+    if (dirfd != -1) {
+        if (fchdir(cwdfd) != 0) {
+            LOG(log_error, logtype_afpd, "ad_openat: cant chdir back, exiting");
+            exit(EXITERR_SYS);
+        }
+    }
+
+exit:
+    if (cwdfd != -1)
+        close(cwdfd);
+
+    return ret;
+}
index 70d281068f766c4ae437eebd161fe418138e09ea..f8e85acf0fe656707df16e9ec1d47334305646f2 100644 (file)
@@ -1,5 +1,5 @@
 /*
-  $Id: ea.c,v 1.19 2010-02-10 14:05:37 franklahm Exp $
+  $Id: ea.c,v 1.20 2010-03-12 15:16:49 franklahm Exp $
   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
 
   This program is free software; you can redistribute it and/or modify
@@ -661,6 +661,8 @@ int ea_open(const struct vol * restrict vol,
 
     ea->vol = vol;              /* ea_close needs it */
     ea->ea_flags = eaflags;
+    ea->dirfd = -1;             /* no *at (cf openat) semantics by default */
+
     /* Dont care for errors, eg when removing the file is already gone */
     if (!stat(uname, &st) && S_ISDIR(st.st_mode))
         ea->ea_flags |=  EA_DIR;
@@ -786,6 +788,68 @@ exit:
     return ret;
 }
 
+/*
+ * Function: ea_openat
+ *
+ * Purpose: openat like wrapper for ea_open, takes a additional file descriptor
+ *
+ * Arguments:
+ *
+ *    vol         (r) current volume
+ *    sfd         (r) openat like file descriptor
+ *    uname       (r) filename for which we have to open a header
+ *    flags       (r) EA_CREATE: create if it doesn't exist (without it won't be created)
+ *                    EA_RDONLY: open read only
+ *                    EA_RDWR: open read/write
+ *                    Eiterh EA_RDONLY or EA_RDWR MUST be requested
+ *    ea          (w) pointer to a struct ea that we fill
+ *
+ * Returns: 0 on success
+ *         -1 on misc error with errno = EFAULT
+ *         -2 if no EA header exists with errno = ENOENT
+ *
+ * Effects:
+ *
+ * opens header file and stores fd in ea->ea_fd. Size of file is put into ea->ea_size.
+ * number of EAs is stored in ea->ea_count. flags are remembered in ea->ea_flags.
+ * file is either read or write locked depending on the open flags.
+ * When you're done with struct ea you must call ea_close on it.
+ */
+int ea_openat(const struct vol * restrict vol,
+              int dirfd,
+              const char * restrict uname,
+              eaflags_t eaflags,
+              struct ea * restrict ea)
+{
+    int ret = 0;
+    int cwdfd = -1;
+
+    if (dirfd != -1) {
+        if (((cwdfd = open(".", O_RDONLY)) == -1) || (fchdir(dirfd) != 0)) {
+            ret = -1;
+            goto exit;
+        }
+    }
+
+    ret = ea_open(vol, uname, eaflags, ea);
+    ea->dirfd = dirfd;
+
+    if (dirfd != -1) {
+        if (fchdir(cwdfd) != 0) {
+            LOG(log_error, logtype_afpd, "ea_openat: cant chdir back, exiting");
+            exit(EXITERR_SYS);
+        }
+    }
+
+
+exit:
+    if (cwdfd != -1)
+        close(cwdfd);
+
+    return ret;
+
+}
+
 /*
  * Function: ea_close
  *
@@ -825,8 +889,8 @@ int ea_close(struct ea * restrict ea)
             if (ea->ea_count == 0) {
                 /* Check if EA header exists and remove it */
                 eaname = ea_path(ea, NULL, 0);
-                if ((stat(eaname, &st)) == 0) {
-                    if ((unlink(eaname)) != 0) {
+                if ((lstatat(ea->dirfd, eaname, &st)) == 0) {
+                    if ((netatalk_unlinkat(ea->dirfd, eaname)) != 0) {
                         LOG(log_error, logtype_afpd, "ea_close('%s'): unlink: %s",
                             eaname, strerror(errno));
                         ret = -1;
@@ -1244,12 +1308,13 @@ int ea_deletefile(VFS_FUNC_ARGS_DELETEFILE)
 {
     unsigned int count = 0;
     int ret = AFP_OK;
+    int cwd = -1;
     struct ea ea;
 
     LOG(log_debug, logtype_afpd, "ea_deletefile('%s')", file);
 
     /* Open EA stuff */
-    if ((ea_open(vol, file, EA_RDWR, &ea)) != 0) {
+    if ((ea_openat(vol, dirfd, file, EA_RDWR, &ea)) != 0) {
         if (errno == ENOENT)
             /* no EA files, nothing to do */
             return AFP_OK;
@@ -1259,6 +1324,13 @@ int ea_deletefile(VFS_FUNC_ARGS_DELETEFILE)
         }
     }
 
+    if (dirfd != -1) {
+        if (((cwd = open(".", O_RDONLY)) == -1) || (fchdir(dirfd) != 0)) {
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+    }
+
     while (count < ea.ea_count) {
         if ((delete_ea_file(&ea, (*ea.ea_entries)[count].ea_name)) != 0) {
             ret = AFPERR_MISC;
@@ -1272,9 +1344,18 @@ int ea_deletefile(VFS_FUNC_ARGS_DELETEFILE)
     /* ea_close removes the EA header file for us because all names are NULL */
     if ((ea_close(&ea)) != 0) {
         LOG(log_error, logtype_afpd, "ea_deletefile('%s'): error closing ea handle", file);
-        return AFPERR_MISC;
+        ret = AFPERR_MISC;
     }
 
+    if (dirfd != -1 && fchdir(cwd) != 0) {
+        LOG(log_error, logtype_afpd, "ea_deletefile: cant chdir back. exit!");
+        exit(EXITERR_SYS);
+    }
+
+exit:
+    if (cwd != -1)
+        close(cwd);
+
     return ret;
 }
 
@@ -1294,7 +1375,7 @@ int ea_renamefile(VFS_FUNC_ARGS_RENAMEFILE)
             
 
     /* Open EA stuff */
-    if ((ea_open(vol, src, EA_RDWR, &srcea)) != 0) {
+    if ((ea_openat(vol, dirfd, src, EA_RDWR, &srcea)) != 0) {
         if (errno == ENOENT)
             /* no EA files, nothing to do */
             return AFP_OK;
@@ -1359,7 +1440,7 @@ int ea_renamefile(VFS_FUNC_ARGS_RENAMEFILE)
         }
 
         /* Now rename the EA */
-        if ((rename( srceapath, eapath)) < 0) {
+        if ((unix_rename(dirfd, srceapath, -1, eapath)) < 0) {
             LOG(log_error, logtype_afpd, "ea_renamefile('%s/%s'): moving EA '%s' to '%s'",
                 src, dst, srceapath, eapath);
             ret = AFPERR_MISC;
@@ -1391,7 +1472,7 @@ int ea_copyfile(VFS_FUNC_ARGS_COPYFILE)
     LOG(log_debug, logtype_afpd, "ea_copyfile('%s'/'%s')", src, dst);
 
     /* Open EA stuff */
-    if ((ea_open(vol, src, EA_RDWR, &srcea)) != 0) {
+    if ((ea_openat(vol, sfd, src, EA_RDWR, &srcea)) != 0) {
         if (errno == ENOENT)
             /* no EA files, nothing to do */
             return AFP_OK;
@@ -1447,7 +1528,7 @@ int ea_copyfile(VFS_FUNC_ARGS_COPYFILE)
         }
 
         /* Now copy the EA */
-        if ((copy_file( srceapath, eapath, (0666 & ~vol->v_umask))) < 0) {
+        if ((copy_file(sfd, srceapath, eapath, (0666 & ~vol->v_umask))) < 0) {
             LOG(log_error, logtype_afpd, "ea_copyfile('%s/%s'): copying EA '%s' to '%s'",
                 src, dst, srceapath, eapath);
             ret = AFPERR_MISC;
index 02a407cfacce957b2bcfbe5e7497d59bcdfc89cd..079458562933ced7a034a56cb05d03792eb9ef4a 100644 (file)
@@ -1,5 +1,5 @@
 /*
-  $Id: ea_sys.c,v 1.5 2010-01-23 14:54:43 franklahm Exp $
+  $Id: ea_sys.c,v 1.6 2010-03-12 15:16:49 franklahm Exp $
   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
 
   This program is free software; you can redistribute it and/or modify
@@ -380,16 +380,37 @@ int sys_remove_ea(VFS_FUNC_ARGS_EA_REMOVE)
     return AFP_OK;
 }
 
-/* --------------------- 
-   copy EA 
-*/
+/*
+ * @brief Copy EAs
+ *
+ * @note Supports *at semantics, therfor switches back and forth between sfd and cwd
+ */
 int sys_ea_copyfile(VFS_FUNC_ARGS_COPYFILE)
 {
        int ret = 0;
+    int cwd = -1;
        ssize_t size;
        char *names = NULL, *end_names, *name, *value = NULL;
        unsigned int setxattr_ENOTSUP = 0;
 
+    if (sfd != -1) {
+        if ((cwd = open(".", O_RDONLY)) == -1) {
+            LOG(log_error, logtype_afpd, "sys_ea_copyfile: cant open cwd: %s",
+                strerror(errno));
+            ret = -1;
+            goto getout;
+        }
+    }
+
+    if (sfd != -1) {
+        if (fchdir(sfd) == -1) {
+            LOG(log_error, logtype_afpd, "sys_ea_copyfile: cant chdir to sfd: %s",
+                strerror(errno));
+            ret = -1;
+            goto getout;
+        }
+    }
+
        size = sys_listxattr(src, NULL, 0);
        if (size < 0) {
                if (errno != ENOSYS && errno != ENOTSUP) {
@@ -411,6 +432,15 @@ int sys_ea_copyfile(VFS_FUNC_ARGS_COPYFILE)
                end_names = names + size;
        }
 
+    if (sfd != -1) {
+        if (fchdir(cwd) == -1) {
+            LOG(log_error, logtype_afpd, "sys_ea_copyfile: cant chdir to cwd: %s",
+                strerror(errno));
+            ret = -1;
+            goto getout;
+        }
+    }
+
        for (name = names; name != end_names; name = strchr(name, '\0') + 1) {
                void *old_value;
 
@@ -418,6 +448,15 @@ int sys_ea_copyfile(VFS_FUNC_ARGS_COPYFILE)
                if (!*name)
                        continue;
 
+        if (sfd != -1) {
+            if (fchdir(sfd) == -1) {
+                LOG(log_error, logtype_afpd, "sys_ea_copyfile: cant chdir to sfd: %s",
+                    strerror(errno));
+                ret = -1;
+                goto getout;
+            }
+        }
+
                size = sys_getxattr (src, name, NULL, 0);
                if (size < 0) {
                        ret = -1;
@@ -433,6 +472,16 @@ int sys_ea_copyfile(VFS_FUNC_ARGS_COPYFILE)
                        ret = -1;
                        continue;
                }
+
+        if (sfd != -1) {
+            if (fchdir(cwd) == -1) {
+                LOG(log_error, logtype_afpd, "sys_ea_copyfile: cant chdir to cwd: %s",
+                    strerror(errno));
+                ret = -1;
+                goto getout;
+            }
+        }
+
                if (sys_setxattr(dst, name, value, size, 0) != 0) {
                        if (errno == ENOTSUP)
                                setxattr_ENOTSUP++;
@@ -453,6 +502,9 @@ int sys_ea_copyfile(VFS_FUNC_ARGS_COPYFILE)
        }
 
 getout:
+    if (cwd != -1)
+        close(cwd);
+        
        free(value);
        free(names);
 
index 991d04a01a8f6b4c99ced2c7bb8a9cb9ff89e7e6..d0ea31282351be18c23cec8bd7d9f407c00120fd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: unix.c,v 1.9 2010-02-10 14:05:37 franklahm Exp $
+ * $Id: unix.c,v 1.10 2010-03-12 15:16:49 franklahm Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -99,12 +99,24 @@ int setfilmode(const char * name, mode_t mode, struct stat *st, mode_t v_umask)
     return 0;
 }
 
-/* -------------------
-   system rmdir with afp error code.
-*/
-int netatalk_rmdir_all_errors(const char *name)
+/*
+ * @brief system rmdir with afp error code.
+ *
+ * Supports *at semantics (cf openat) if HAVE_RENAMEAT. Pass dirfd=-1 to ignore this.
+ */
+int netatalk_rmdir_all_errors(int dirfd, const char *name)
 {
-    if (rmdir(name) < 0) {
+    int err;
+
+#ifdef HAVE_RENAMEAT
+    if (dirfd == -1)
+        dirfd = ATFD_CWD;
+    err = unlinkat(dirfd, name, AT_REMOVEDIR);
+#else
+    err = rmdir(name);
+#endif
+
+    if (err < 0) {
         switch ( errno ) {
         case ENOENT :
             return AFPERR_NOOBJ;
@@ -122,13 +134,14 @@ int netatalk_rmdir_all_errors(const char *name)
     return AFP_OK;
 }
 
-/* -------------------
-   system rmdir with afp error code.
-   ENOENT is not an error.
-*/
-int netatalk_rmdir(const char *name)
+/*
+ * @brief System rmdir with afp error code, but ENOENT is not an error.
+ *
+ * Supports *at semantics (cf openat) if HAVE_RENAMEAT. Pass dirfd=-1 to ignore this.
+ */
+int netatalk_rmdir(int dirfd, const char *name)
 {
-    int ret = netatalk_rmdir_all_errors(name);
+    int ret = netatalk_rmdir_all_errors(dirfd, name);
     if (ret == AFPERR_NOOBJ)
         return AFP_OK;
     return ret;
@@ -170,7 +183,15 @@ char *fullpathname(const char *name)
     return wd;
 }
 
-int copy_file(const char *src, const char *dst, mode_t mode)
+
+/**************************************************************************
+ * *at semnatics support functions (like openat, renameat standard funcs)
+ **************************************************************************/
+
+/* 
+ * Supports *at semantics if HAVE_RENAMEAT, pass dirfd=-1 to ignore this
+ */
+int copy_file(int dirfd, const char *src, const char *dst, mode_t mode)
 {
     int    ret = 0;
     int    sfd = -1;
@@ -179,7 +200,14 @@ int copy_file(const char *src, const char *dst, mode_t mode)
     size_t  buflen;
     char   filebuf[8192];
 
-    if ((sfd = open(src, O_RDONLY)) < 0) {
+#ifdef HAVE_RENAMEAT
+    if (dirfd == -1)
+        dirfd = ATFD_CWD;
+    sfd = openat(dirfd, src, O_RDONLY);
+#else
+    sfd = open(src, O_RDONLY);
+#endif
+    if (sfd < 0) {
         LOG(log_error, logtype_afpd, "copy_file('%s'/'%s'): open '%s' error: %s",
             src, dst, src, strerror(errno));
         return -1;
@@ -235,44 +263,142 @@ exit:
     return ret;
 }
 
-/* This is equivalent of unix rename(). */
-int unix_rename(const char *oldpath, const char *newpath)
+/* 
+ * at wrapper for netatalk_unlink
+ */
+int netatalk_unlinkat(int dirfd, const char *name)
 {
-#if 0
-    char pd_name[PATH_MAX+1];
-    int i;
-    struct stat pd_stat;
-    uid_t uid;
+#ifdef HAVE_RENAMEAT
+    if (dirfd == -1)
+        dirfd = AT_FDCWD;
+
+    if (unlinkat(dirfd, name, 0) < 0) {
+        switch (errno) {
+        case ENOENT :
+            break;
+        case EROFS:
+            return AFPERR_VLOCK;
+        case EPERM:
+        case EACCES :
+            return AFPERR_ACCESS;
+        default :
+            return AFPERR_PARAM;
+        }
+    }
+    return AFP_OK;
+#else
+    return netatalk_unlink(name);
 #endif
 
+    /* DEADC0DE */
+    return 0;
+}
+
+/*
+ * @brief This is equivalent of unix rename()
+ *
+ * unix_rename mulitplexes rename and renameat. If we dont HAVE_RENAMEAT, sfd and dfd
+ * are ignored.
+ *
+ * @param sfd        (r) if we HAVE_RENAMEAT, -1 gives AT_FDCWD
+ * @param oldpath    (r) guess what
+ * @param dfd        (r) same as sfd
+ * @param newpath    (r) guess what
+ */
+int unix_rename(int sfd, const char *oldpath, int dfd, const char *newpath)
+{
+#ifdef HAVE_RENAMEAT
+    if (sfd == -1)
+        sfd = AT_FDCWD;
+    if (dfd == -1)
+        dfd = AT_FDCWD;
+
+    if (renameat(sfd, oldpath, dfd, newpath) < 0)
+        return -1;        
+#else
     if (rename(oldpath, newpath) < 0)
         return -1;
-#if 0
-    for (i = 0; i <= PATH_MAX && newpath[i] != '\0'; i++)
-        pd_name[i] = newpath[i];
-    pd_name[i] = '\0';
+#endif  /* HAVE_RENAMEAT */
 
-    while (i > 0 && pd_name[i] != '/') i--;
-    if (pd_name[i] == '/') i++;
+    return 0;
+}
 
-    pd_name[i++] = '.'; pd_name[i++] = '\0';
+/* 
+ * @brief stat/fsstatat multiplexer
+ *
+ * statat mulitplexes stat and fstatat. If we dont HAVE_RENAMEAT, dirfd is ignored.
+ *
+ * @param dirfd   (r) Only used if HAVE_RENAMEAT, ignored else, -1 gives AT_FDCWD
+ * @param path    (r) pathname
+ * @param st      (rw) pointer to struct stat
+ */
+int statat(int dirfd, const char *path, struct stat *st)
+{
+#ifdef HAVE_RENAMEAT
+    if (dirfd == -1)
+        dirfd = AT_FDCWD;
+    return (fstatat(dirfd, path, st, 0));
+#else
+    return (stat(path, st));
+#endif            
+
+    /* DEADC0DE */
+    return -1;
+}
 
-    if (stat(pd_name, &pd_stat) < 0) {
-        LOG(log_error, logtype_afpd, "stat() of parent dir failed: pd_name = %s, uid = %d: %s",
-            pd_name, geteuid(), strerror(errno));
-        return 0;
+/* 
+ * @brief lstat/fsstatat multiplexer
+ *
+ * lstatat mulitplexes lstat and fstatat. If we dont HAVE_RENAMEAT, dirfd is ignored.
+ *
+ * @param dirfd   (r) Only used if HAVE_RENAMEAT, ignored else, -1 gives AT_FDCWD
+ * @param path    (r) pathname
+ * @param st      (rw) pointer to struct stat
+ */
+int lstatat(int dirfd, const char *path, struct stat *st)
+{
+#ifdef HAVE_RENAMEAT
+    if (dirfd == -1)
+        dirfd = AT_FDCWD;
+    return (fstatat(dirfd, path, st, AT_SYMLINK_NOFOLLOW));
+#else
+    return (lstat(path, st));
+#endif            
+
+    /* DEADC0DE */
+    return -1;
+}
+
+/* 
+ * @brief opendir wrapper for *at semantics support
+ *
+ * opendirat chdirs to dirfd if dirfd != -1 before calling opendir on path.
+ *
+ * @param dirfd   (r) if != -1, chdir(dirfd) before opendir(path)
+ * @param path    (r) pathname
+ */
+DIR *opendirat(int dirfd, const char *path)
+{
+    DIR *ret;
+    int cwd = -1;
+
+    if (dirfd != -1) {
+        if (((cwd = open(".", O_RDONLY)) == -1) || (fchdir(dirfd) != 0)) {
+            ret = NULL;
+            goto exit;
+        }
     }
 
-    /* So we have SGID bit set... */
-    if ((S_ISGID & pd_stat.st_mode) != 0) {
-        uid = geteuid();
-        if (seteuid(0) < 0)
-            LOG(log_error, logtype_afpd, "seteuid() failed: %s", strerror(errno));
-        if (recursive_chown(newpath, uid, pd_stat.st_gid) < 0)
-            LOG(log_error, logtype_afpd, "chown() of parent dir failed: newpath=%s, uid=%d: %s",
-                pd_name, geteuid(), strerror(errno));
-        seteuid(uid);
+    ret = opendir(path);
+
+    if (dirfd != -1 && fchdir(cwd) != 0) {
+        LOG(log_error, logtype_afpd, "opendirat: cant chdir back. exit!");
+        exit(EXITERR_SYS);
     }
-#endif
-    return 0;
+
+exit:
+    if (cwd != -1)
+        close(cwd);
+
+    return ret;
 }
index b43cfebe01c82746a341b5d6e13ad7f8a0285c9e..dadedc5bbee20c21ac384b0ee7d19f435656c069 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <string.h>
 #include <stdio.h>
+#include <stdlib.h>
 
 #include <atalk/afp.h>    
 #include <atalk/adouble.h>
@@ -148,7 +149,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 +273,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 +283,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 +303,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;
@@ -426,7 +427,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 +446,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 +660,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;
+        }
+    }
 
-    return ads_delete_rf(ad_p);
+    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 ret;
 }
 
 /* --------------------------- */
@@ -670,14 +694,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 +716,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 +748,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 +783,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;
@@ -868,6 +892,7 @@ static struct vfs_ops netatalk_adouble = {
     /* vfs_setdirowner:   */ RF_setdirowner_adouble,
     /* vfs_deletefile:    */ RF_deletefile_adouble,
     /* vfs_renamefile:    */ RF_renamefile_adouble,
+    /* vfs_copyfile:      */ NULL,
     NULL
 };
 
@@ -882,6 +907,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 +923,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
 };