-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)
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
/*
- * $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.
*/
struct dir *curdir;
-int afp_errno;
+int afp_errno;
#define SENTINEL (&sentinel)
static struct dir sentinel = { SENTINEL, SENTINEL, NULL, /* left, right, back */
}
/* ------------------- */
-static int deletedir(char *dir)
+static int deletedir(int dirfd, char *dir)
{
char path[MAXPATHLEN + 1];
DIR *dp;
return AFPERR_PARAM;
/* already gone */
- if ((dp = opendir(dir)) == NULL)
+ if ((dp = opendirat(dirfd, dir)) == NULL)
return AFP_OK;
strcpy(path, 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);
/* 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;
/* 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 */
}
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;
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 {
}
/* 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);
}
return dir;
}
+#if 0
/* ------------------ */
static hash_val_t hash_fun_dir(const void *key)
{
}
return acc;
}
+#endif
#undef get16bits
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
* 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)
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 );
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 :
}
}
- 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
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);
/*
- * $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.
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);
/*
- * $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.
* 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 );
/* 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;
* 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 :
ad_flush( adp );
ad_close( adp, ADFLAGS_HF );
}
-#ifdef DEBUG
- LOG(log_debug9, logtype_afpd, "end renamefile:");
-#endif /* DEBUG */
return( AFP_OK );
}
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;
}
* 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;
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);
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;
}
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;
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);
}
}
}
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 */
*/
}
-#ifdef DEBUG
- LOG(log_debug9, logtype_afpd, "end copyfile:");
-#endif /* DEBUG */
-
done:
switch ( ret_err ) {
case 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) {
* 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;
/* 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;
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);
}
}
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;
}
}
/* 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);
* 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:
/*
- * $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.
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);
/*
- * $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.
/* -------------------------
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;
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) {
}
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;
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;
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 */
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 );
}
rc = AFPERR_NOOBJ;
}
else {
- rc = deletefile(vol, upath, 1);
+ rc = deletefile(vol, -1, upath, 1);
}
}
if ( rc == AFP_OK ) {
#ifdef DROPKLUDGE
int retvalue;
#endif /* DROPKLUDGE */
+ int sdir_fd = -1;
+
*rbuflen = 0;
ibuf += 2;
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--;
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
setvoltime(obj, vol );
}
+exit:
+#ifdef HAVE_RENAMEAT
+ if (sdir_fd != -1)
+ close(sdir_fd);
+#endif
+
return( rc );
}
/*
- * $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.
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 );
/*
- * $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.
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;
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
}
/* -------------------------- */
-struct ofork *
- of_findname(struct path *path)
+struct ofork *of_findname(struct path *path)
{
struct ofork *of;
struct file_key key;
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)
/*
- * $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.
*
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))
/*
- $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
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*/
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);
/*
- $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 */
#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
/*
- * $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.
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)
{
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;
+}
/*
- $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
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;
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
*
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;
{
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;
}
}
+ 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;
/* 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;
}
/* 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;
}
/* 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;
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;
}
/* 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;
/*
- $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
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) {
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;
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;
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++;
}
getout:
+ if (cwd != -1)
+ close(cwd);
+
free(value);
free(names);
/*
- * $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.
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;
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;
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;
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;
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;
}
#include <string.h>
#include <stdio.h>
+#include <stdlib.h>
#include <atalk/afp.h>
#include <atalk/adouble.h>
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" );
}
/* ----------------- */
/* ----------------- */
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));
}
/* ----------------- */
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.
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;
*/
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_)
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" );
}
/* ------------------- */
/* ------------------- */
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;
}
/* --------------------------- */
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 :
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;
{
/* 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));
}
/* ---------------- */
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;
/* vfs_setdirowner: */ RF_setdirowner_adouble,
/* vfs_deletefile: */ RF_deletefile_adouble,
/* vfs_renamefile: */ RF_renamefile_adouble,
+ /* vfs_copyfile: */ NULL,
NULL
};
/* vfs_setdirowner: */ RF_setdirowner_osx,
/* vfs_deletefile: */ RF_deletefile_adouble,
/* vfs_renamefile: */ RF_renamefile_osx,
+ /* vfs_copyfile: */ NULL,
NULL
};
/* vfs_setdirowner: */ RF_setdirowner_ads,
/* vfs_deletefile: */ RF_deletefile_ads,
/* vfs_renamefile: */ RF_renamefile_ads,
+ /* vfs_copyfile: */ NULL,
NULL
};