/*
- * $Id: file.c,v 1.92.2.2.2.12 2004-02-07 19:46:08 didg Exp $
+ * $Id: file.c,v 1.92.2.2.2.31.2.10 2005-02-10 01:23:12 didg Exp $
*
* Copyright (c) 1990,1993 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
#include <stdio.h>
#include <stdlib.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
/* STDC check */
#if STDC_HEADERS
#define strrchr index
#endif /* HAVE_STRCHR */
char *strchr (), *strrchr ();
+
#ifndef HAVE_MEMCPY
#define memcpy(d,s,n) bcopy ((s), (d), (n))
#define memmove(d,s,n) bcopy ((s), (d), (n))
#endif /* ! HAVE_MEMCPY */
#endif /* STDC_HEADERS */
+#include <atalk/adouble.h>
#include <utime.h>
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif /* HAVE_FCNTL_H */
#include <dirent.h>
-#include <sys/mman.h>
#include <errno.h>
#include <atalk/logger.h>
-#include <sys/types.h>
-#include <sys/time.h>
#include <sys/param.h>
-#include <sys/stat.h>
-#include <netatalk/endian.h>
-#include <atalk/adouble.h>
+
#include <atalk/afp.h>
#include <atalk/util.h>
#include <atalk/cnid.h>
*/
const u_char ufinderi[] = {
- 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
void *get_finderinfo(const char *mpath, struct adouble *adp, void *data)
{
struct extmap *em;
- void *ad_finder;
+ void *ad_finder = NULL;
+ int chk_ext = 0;
+
+ if (adp)
+ ad_finder = ad_entry(adp, ADEID_FINDERI);
- if (adp && (ad_finder = ad_entry(adp, ADEID_FINDERI))) {
+ if ((ad_finder != NULL)) {
memcpy(data, ad_finder, 32);
+ /* default type ? */
+ if (!memcmp(ad_finder, ufinderi, 8))
+ chk_ext = 1;
}
else {
memcpy(data, ufinderi, 32);
+ chk_ext = 1;
}
-
- if ((!adp || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 ))
- && (em = getextmap( mpath ))
- ) {
+ /** Only enter if no appledouble information and no finder information found. */
+ if (chk_ext && (em = getextmap( mpath ))) {
memcpy(data, em->em_type, sizeof( em->em_type ));
memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator));
}
/* -------------------------- */
u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st,
- const cnid_t did, const char *upath, const int len)
+ const cnid_t did, char *upath, const int len)
{
u_int32_t aint = 0;
#if AD_VERSION > AD_VERSION1
-dev_t dev;
-ino_t ino;
-cnid_t a_did;
-char stamp[ADEDLEN_PRIVSYN];
- /* look in AD v2 header
- * note inode and device are opaques and not in network order
- */
- if (adp && sizeof(dev_t) == ad_getentrylen(adp, ADEID_PRIVDEV)) {
- memcpy(&dev, ad_entry(adp, ADEID_PRIVDEV), sizeof(dev_t));
- if ( sizeof(ino_t) == ad_getentrylen(adp,ADEID_PRIVINO)) {
- memcpy(&ino, ad_entry(adp, ADEID_PRIVINO), sizeof(ino_t));
- if (sizeof(stamp) == ad_getentrylen(adp,ADEID_PRIVSYN)) {
- memcpy(stamp, ad_entry(adp, ADEID_PRIVSYN), sizeof(stamp));
- if (sizeof(cnid_t) == ad_getentrylen(adp, ADEID_DID)) {
- memcpy(&a_did, ad_entry(adp, ADEID_DID), sizeof(cnid_t));
-
- if ( ((vol->v_flags & AFPVOL_NODEV) || dev == st->st_dev)
- && ino == st->st_ino && a_did == did &&
- !memcmp(vol->v_stamp, stamp, sizeof(stamp)) &&
- (sizeof(cnid_t) == ad_getentrylen(adp, ADEID_PRIVID)) )
- {
- memcpy(&aint, ad_entry(adp, ADEID_PRIVID), sizeof(aint));
- return aint;
- }
- }
- }
- }
+
+ if ((aint = ad_getid(adp, st->st_dev, st->st_ino, did, vol->v_stamp))) {
+ return aint;
}
#endif
+
if (vol->v_cdb != NULL) {
aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
/* Throw errors if cnid_add fails. */
}
}
#if AD_VERSION > AD_VERSION1
- else if (adp && sizeof(dev_t) == ADEDLEN_PRIVDEV && sizeof(ino_t) == ADEDLEN_PRIVINO) {
+ else if (adp ) {
/* update the ressource fork
* for a folder adp is always null
*/
- ad_setid(adp,(vol->v_flags & AFPVOL_NODEV)?0:st->st_dev, st->st_ino, aint, did, vol->v_stamp);
- ad_flush(adp, ADFLAGS_HF);
+ if (ad_setid(adp, st->st_dev, st->st_ino, aint, did, vol->v_stamp)) {
+ ad_flush(adp, ADFLAGS_HF);
+ }
}
#endif
}
memcpy(data, &aint, sizeof( aint ));
data += sizeof( aint );
break;
- case FILPBIT_UNIXPR :
+ case FILPBIT_UNIXPR :
+ /* accessmode may change st_mode with ACLs */
+ accessmode( upath, &ma, dir , st);
+
aint = htonl(st->st_uid);
memcpy( data, &aint, sizeof( aint ));
data += sizeof( aint );
memcpy( data, &aint, sizeof( aint ));
data += sizeof( aint );
- accessmode( upath, &ma, dir , st);
-
*data++ = ma.ma_user;
*data++ = ma.ma_world;
*data++ = ma.ma_group;
*data++ = ma.ma_owner;
break;
-
+
default :
return( AFPERR_BITMAP );
}
attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
} else {
- ad_init(&ad, vol->v_adouble);
+ ad_init(&ad, vol->v_adouble, vol->v_ad_options);
adp = &ad;
}
- if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
- adp = NULL;
+ if ( ad_metadata( upath, 0, adp) < 0 ) {
+ switch (errno) {
+ case EACCES:
+ LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
+ upath, strerror(errno));
+ return AFPERR_ACCESS;
+ case EIO:
+ LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
+ /* fall through */
+ case ENOENT:
+ default:
+ adp = NULL;
+ break;
+ }
}
- else {
+ if (adp) {
/* FIXME
we need to check if the file is open by another process.
it's slow so we only do it if we have to:
*/
if ((bitmap & (1 << FILPBIT_ATTR))) {
if (!(attrbits & ATTRBIT_ROPEN)) {
+ attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_ROPEN : 0;
+ attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_ROPEN : 0;
}
if (!(attrbits & ATTRBIT_DOPEN)) {
+ attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_DOPEN : 0;
+ attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_DOPEN : 0;
}
}
}
if ((of = of_findname(s_path))) {
adp = of->of_ad;
} else {
- ad_init(&ad, vol->v_adouble);
+ ad_init(&ad, vol->v_adouble, vol->v_ad_options);
adp = &ad;
}
if ( creatf) {
}
path = s_path->m_name;
- ad_setentrylen( adp, ADEID_NAME, strlen( path ));
- memcpy(ad_entry( adp, ADEID_NAME ), path,
- ad_getentrylen( adp, ADEID_NAME ));
+ ad_setname(adp, path);
ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
/*
* cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
- *
+ *
*/
extern struct path Cur_Path;
int setfilparams(struct vol *vol,
- struct path *path, u_int16_t bitmap, char *buf )
+ struct path *path, u_int16_t f_bitmap, char *buf )
{
struct adouble ad, *adp;
- struct ofork *of;
struct extmap *em;
- int bit = 0, isad = 1, err = AFP_OK;
+ int bit, isad = 1, err = AFP_OK;
char *upath;
- u_char achar, *fdType, xyy[4];
+ u_char achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
u_int16_t ashort, bshort;
u_int32_t aint;
+ u_int32_t upriv;
+ u_int16_t upriv_bit = 0;
+
struct utimbuf ut;
int change_mdate = 0;
int change_parent_mdate = 0;
int newdate = 0;
struct timeval tv;
-
+ uid_t f_uid;
+ gid_t f_gid;
+ u_int16_t bitmap = f_bitmap;
+ u_int32_t cdate,bdate;
+ u_char finder_buf[32];
#ifdef DEBUG
LOG(log_info, logtype_afpd, "begin setfilparams:");
#endif /* DEBUG */
upath = path->u_name;
- if ((of = of_findname(path))) {
- adp = of->of_ad;
- } else {
- ad_init(&ad, vol->v_adouble);
- adp = &ad;
- }
+ adp = of_ad(vol, path, &ad);
+
if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
return AFPERR_ACCESS;
}
- if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
- O_RDWR|O_CREAT, 0666, adp) < 0) {
- /* for some things, we don't need an adouble header */
- if (bitmap & ~(1<<FILPBIT_MDATE)) {
- return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
- }
- isad = 0;
- } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
- ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
- memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
- ad_getentrylen( adp, ADEID_NAME ));
- }
-
+ /* with unix priv maybe we have to change adouble file priv first */
+ bit = 0;
while ( bitmap != 0 ) {
while (( bitmap & 1 ) == 0 ) {
bitmap = bitmap>>1;
bit++;
}
-
switch( bit ) {
case FILPBIT_ATTR :
change_mdate = 1;
memcpy(&ashort, buf, sizeof( ashort ));
- ad_getattr(adp, &bshort);
- if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
- bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
- } else {
- bshort &= ~ashort;
- }
- if ((ashort & htons(ATTRBIT_INVISIBLE)))
- change_parent_mdate = 1;
- ad_setattr(adp, bshort);
buf += sizeof( ashort );
break;
-
case FILPBIT_CDATE :
change_mdate = 1;
- memcpy(&aint, buf, sizeof(aint));
- ad_setdate(adp, AD_DATE_CREATE, aint);
- buf += sizeof( aint );
+ memcpy(&cdate, buf, sizeof(cdate));
+ buf += sizeof( cdate );
break;
-
case FILPBIT_MDATE :
memcpy(&newdate, buf, sizeof( newdate ));
buf += sizeof( newdate );
break;
-
case FILPBIT_BDATE :
change_mdate = 1;
- memcpy(&aint, buf, sizeof(aint));
- ad_setdate(adp, AD_DATE_BACKUP, aint);
- buf += sizeof( aint );
+ memcpy(&bdate, buf, sizeof( bdate));
+ buf += sizeof( bdate );
break;
-
case FILPBIT_FINFO :
change_mdate = 1;
-
- if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
- && (
- ((em = getextmap( path->m_name )) &&
- !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
- !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
- || ((em = getdefextmap()) &&
- !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
- !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
- )) {
- memcpy(buf, ufinderi, 8 );
- }
-
- memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
+ memcpy(finder_buf, buf, 32 );
buf += 32;
break;
-
case FILPBIT_UNIXPR :
- /* Skip the UIG/GID, no way to set them from OSX clients */
- buf += sizeof( aint );
- buf += sizeof( aint );
-
+ if (!vol_unix_priv(vol)) {
+ /* this volume doesn't use unix priv */
+ err = AFPERR_BITMAP;
+ bitmap = 0;
+ break;
+ }
change_mdate = 1;
change_parent_mdate = 1;
+
+ memcpy( &aint, buf, sizeof( aint ));
+ f_uid = ntohl (aint);
+ buf += sizeof( aint );
memcpy( &aint, buf, sizeof( aint ));
+ f_gid = ntohl (aint);
buf += sizeof( aint );
- aint = ntohl (aint);
+ setfilowner(vol, f_uid, f_gid, path);
- setfilemode(path, aint);
+ memcpy( &upriv, buf, sizeof( upriv ));
+ buf += sizeof( upriv );
+ upriv = ntohl (upriv);
+ if ((upriv & S_IWUSR)) {
+ setfilunixmode(vol, path, upriv);
+ }
+ else {
+ /* do it later */
+ upriv_bit = 1;
+ }
break;
- /* Client needs to set the ProDOS file info for this file.
- Use a defined string for TEXT to support crlf
- translations and convert all else into pXYY per Inside
- Appletalk. Always set the creator as "pdos". Changes
- from original by Marsha Jackson. */
case FILPBIT_PDINFO :
if (afp_version < 30) { /* else it's UTF8 name */
achar = *buf;
xyy[2] = *buf++;
fdType = xyy;
}
+ break;
+ }
+ /* fallthrough */
+ default :
+ err = AFPERR_BITMAP;
+ /* break while loop */
+ bitmap = 0;
+ break;
+ }
+
+ bitmap = bitmap>>1;
+ bit++;
+ }
+
+ /* second try with adouble open
+ */
+ if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
+ O_RDWR|O_CREAT, 0666, adp) < 0) {
+ /* for some things, we don't need an adouble header */
+ if (f_bitmap & ~(1<<FILPBIT_MDATE)) {
+ return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
+ }
+ isad = 0;
+ } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
+ ad_setname(adp, path->m_name);
+ }
+
+ bit = 0;
+ bitmap = f_bitmap;
+ while ( bitmap != 0 ) {
+ while (( bitmap & 1 ) == 0 ) {
+ bitmap = bitmap>>1;
+ bit++;
+ }
+
+ switch( bit ) {
+ case FILPBIT_ATTR :
+ ad_getattr(adp, &bshort);
+ if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
+ (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
+ change_parent_mdate = 1;
+ if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
+ bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
+ } else {
+ bshort &= ~ashort;
+ }
+ ad_setattr(adp, bshort);
+ break;
+ case FILPBIT_CDATE :
+ ad_setdate(adp, AD_DATE_CREATE, cdate);
+ break;
+ case FILPBIT_MDATE :
+ break;
+ case FILPBIT_BDATE :
+ ad_setdate(adp, AD_DATE_BACKUP, bdate);
+ break;
+ case FILPBIT_FINFO :
+ if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
+ && (
+ ((em = getextmap( path->m_name )) &&
+ !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
+ !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
+ || ((em = getdefextmap()) &&
+ !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
+ !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
+ )) {
+ memcpy(finder_buf, ufinderi, 8 );
+ }
+ memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
+ break;
+ case FILPBIT_UNIXPR :
+ if (upriv_bit) {
+ setfilunixmode(vol, path, upriv);
+ }
+ break;
+ case FILPBIT_PDINFO :
+ if (afp_version < 30) { /* else it's UTF8 name */
memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
break;
err = AFPERR_BITMAP;
goto setfilparam_done;
}
-
bitmap = bitmap>>1;
bit++;
}
* adp adouble struct of src file, if open, or & zeroed one
*
*/
-int renamefile(src, dst, newname, noadouble, adp )
+int renamefile(vol, src, dst, newname, adp )
+const struct vol *vol;
char *src, *dst, *newname;
-const int noadouble;
struct adouble *adp;
{
char adsrc[ MAXPATHLEN + 1];
- int len;
int rc;
#ifdef DEBUG
/* FIXME warning in syslog so admin'd know there's a conflict ?*/
return AFPERR_OLOCK; /* little lie */
}
- if (AFP_OK != ( rc = copyfile(src, dst, newname, noadouble )) ) {
+ if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
/* on error copyfile delete dest */
return( rc );
}
- return deletefile(NULL, src, 0);
+ return deletefile(vol, src, 0);
default :
return( AFPERR_PARAM );
}
}
- strcpy( adsrc, ad_path( src, 0 ));
+ strcpy( adsrc, vol->ad_path( src, 0 ));
- if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
+ if (unix_rename( adsrc, vol->ad_path( dst, 0 )) < 0 ) {
struct stat st;
int err;
* create .AppleDouble if the file is already opened, so we
* use a diff one, it's not a pb,ie it's not the same file, yet.
*/
- ad_init(&ad, AD_VERSION); /* FIXME */
+ 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, ad_path( dst, 0 )) )
+ if (!unix_rename( adsrc, vol->ad_path( dst, 0 )) )
err = 0;
else
err = errno;
/* don't care if we can't open the newly renamed ressource fork
*/
- if ( !ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
- len = strlen( newname );
- ad_setentrylen( adp, ADEID_NAME, len );
- memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
+ if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
+ ad_setname(adp, newname);
ad_flush( adp, ADFLAGS_HF );
ad_close( adp, ADFLAGS_HF );
}
return( AFP_OK );
}
-int copy_path_name(char *newname, char *ibuf)
+/* ----------------
+ convert a Mac long name to an utf8 name,
+*/
+size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
+{
+size_t outlen;
+
+ if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
+ return -1;
+ }
+ return outlen;
+}
+
+/* ---------------- */
+int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
{
char type = *ibuf;
size_t plen = 0;
switch (type) {
case 2:
if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
- strncpy( newname, ibuf, plen );
- newname[ plen ] = '\0';
+ if (afp_version >= 30) {
+ /* convert it to UTF8
+ */
+ if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == -1)
+ return -1;
+ }
+ else {
+ strncpy( newname, ibuf, plen );
+ newname[ plen ] = '\0';
+ }
if (strlen(newname) != plen) {
/* there's \0 in newname, e.g. it's a pathname not
* only a filename.
char *ibuf, *rbuf;
int ibuflen, *rbuflen;
{
- struct vol *vol;
+ struct vol *s_vol, *d_vol;
struct dir *dir;
char *newname, *p, *upath;
struct path *s_path;
int err, retvalue = AFP_OK;
u_int16_t svid, dvid;
+ struct adouble ad, *adp;
+ int denyreadset;
+
#ifdef DEBUG
LOG(log_info, logtype_afpd, "begin afp_copyfile:");
#endif /* DEBUG */
memcpy(&svid, ibuf, sizeof( svid ));
ibuf += sizeof( svid );
- if (NULL == ( vol = getvolbyvid( svid )) ) {
+ if (NULL == ( s_vol = getvolbyvid( svid )) ) {
return( AFPERR_PARAM );
}
memcpy(&sdid, ibuf, sizeof( sdid ));
ibuf += sizeof( sdid );
- if (NULL == ( dir = dirlookup( vol, sdid )) ) {
+ if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
return afp_errno;
}
memcpy(&ddid, ibuf, sizeof( ddid ));
ibuf += sizeof( ddid );
- if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
+ if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
return get_afp_errno(AFPERR_PARAM);
}
if ( path_isadir(s_path) ) {
* and locks need to stay coherent. as a result,
* we just balk if the file is opened already. */
- newname = obj->newtmp;
- strcpy( newname, s_path->m_name );
+ adp = of_ad(s_vol, s_path, &ad);
- if (of_findname(s_path))
+ if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
return AFPERR_DENYCONF;
+ }
+ denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
+ getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
+ ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
+ if (denyreadset) {
+ return AFPERR_DENYCONF;
+ }
- p = ctoupath( vol, curdir, newname );
+ newname = obj->newtmp;
+ strcpy( newname, s_path->m_name );
+
+ p = ctoupath( s_vol, curdir, newname );
if (!p) {
return AFPERR_PARAM;
#ifdef FORCE_UIDGID
/* FIXME svid != dvid && dvid's user can't read svid */
#endif
- if (NULL == ( vol = getvolbyvid( dvid )) ) {
+ if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
return( AFPERR_PARAM );
}
- if (vol->v_flags & AFPVOL_RO)
+ if (d_vol->v_flags & AFPVOL_RO)
return AFPERR_VLOCK;
- if (NULL == ( dir = dirlookup( vol, ddid )) ) {
+ if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
return afp_errno;
}
- if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
+ if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
return get_afp_errno(AFPERR_NOOBJ);
}
if ( *s_path->m_name != '\0' ) {
-#if 0
- return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
-#endif
path_error(s_path, AFPERR_PARAM);
}
/* one of the handful of places that knows about the path type */
- if (copy_path_name(newname, ibuf) < 0) {
+ if (copy_path_name(d_vol, newname, ibuf) < 0) {
return( AFPERR_PARAM );
}
/* newname is always only a filename so curdir *is* its
* parent folder
*/
- if (NULL == (upath = mtoupath(vol, newname, curdir->d_did, utf8_encoding()))) {
+ if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
return( AFPERR_PARAM );
}
- if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
+ if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
return err;
}
curdir->offcnt++;
}
#endif /* DROPKLUDGE */
- setvoltime(obj, vol );
+ setvoltime(obj, d_vol );
#ifdef DEBUG
LOG(log_info, logtype_afpd, "end afp_copyfile:");
return( retvalue );
}
-
+/* ----------------------- */
static __inline__ int copy_all(const int dfd, const void *buf,
size_t buflen)
{
switch (errno) {
case EINTR:
continue;
- case EDQUOT:
- case EFBIG:
- case ENOSPC:
- return AFPERR_DFULL;
- case EROFS:
- return AFPERR_VLOCK;
default:
- return AFPERR_PARAM;
+ return -1;
}
}
buflen -= cc;
LOG(log_info, logtype_afpd, "end copy_all:");
#endif /* DEBUG */
- return AFP_OK;
+ return 0;
}
/* -------------------------- */
static int copy_fd(int dfd, int sfd)
{
ssize_t cc;
- int err = AFP_OK;
+ int err = 0;
char filebuf[8192];
-#ifdef SENDFILE_FLAVOR_LINUX
+#if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
+ /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
off_t offset = 0;
size_t size;
struct stat st;
while (1) {
if ( offset >= st.st_size) {
- return AFP_OK;
+ return 0;
}
size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
case ENOSYS:
case EINVAL: /* there's no guarantee that all fs support sendfile */
goto no_sendfile;
- case EDQUOT:
- case EFBIG:
- case ENOSPC:
- return AFPERR_DFULL;
- case EROFS:
- return AFPERR_VLOCK;
default:
- return AFPERR_PARAM;
+ return -1;
}
}
}
if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
if (errno == EINTR)
continue;
- err = AFPERR_PARAM;
+ err = -1;
break;
}
- if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
+ if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
break;
+ }
}
return err;
}
* if newname is NULL (from directory.c) we don't want to copy ressource fork.
* because we are doing it elsewhere.
*/
-int copyfile(src, dst, newname, noadouble )
+int copyfile(s_vol, d_vol, src, dst, newname, adp )
+const struct vol *s_vol, *d_vol;
char *src, *dst, *newname;
-const int noadouble;
+struct adouble *adp;
{
struct adouble ads, add;
- int len, err = AFP_OK;
+ int err = 0;
+ int ret_err = 0;
int adflags;
+ int noadouble = vol_noadouble(d_vol);
struct stat st;
#ifdef DEBUG
LOG(log_info, logtype_afpd, "begin copyfile:");
#endif /* DEBUG */
- ad_init(&ads, 0); /* OK */
- ad_init(&add, 0); /* FIXME */
+ if (adp == NULL) {
+ ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options);
+ adp = &ads;
+ }
+ ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
adflags = ADFLAGS_DF;
if (newname) {
adflags |= ADFLAGS_HF;
}
- if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
- switch ( errno ) {
- case ENOENT :
- return( AFPERR_NOOBJ );
- case EACCES :
- return( AFPERR_ACCESS );
- default :
- return( AFPERR_PARAM );
- }
+ if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
+ ret_err = errno;
+ goto done;
}
+
+ if (ad_hfileno(adp) == -1) {
+ /* no resource fork, don't create one for dst file */
+ adflags &= ~ADFLAGS_HF;
+ }
+
if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
- ad_close( &ads, adflags );
- if (EEXIST != (err = errno)) {
- deletefile(NULL, dst, 0);
- }
- switch ( err ) {
- case EEXIST :
- return AFPERR_EXIST;
- case ENOENT :
- return( AFPERR_NOOBJ );
- case EACCES :
- return( AFPERR_ACCESS );
- case EROFS:
- return AFPERR_VLOCK;
- default :
- return( AFPERR_PARAM );
+ ret_err = errno;
+ ad_close( adp, adflags );
+ if (EEXIST != ret_err) {
+ deletefile(d_vol, dst, 0);
+ goto done;
}
+ return AFPERR_EXIST;
}
- if (ad_hfileno(&ads) == -1 || AFP_OK == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
+ if (ad_hfileno(adp) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(adp)))){
/* copy the data fork */
- err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
+ err = copy_fd(ad_dfileno(&add), ad_dfileno(adp));
}
/* Now, reopen destination file */
- err = AFP_OK;
+ if (err < 0) {
+ ret_err = errno;
+ }
+ ad_close( adp, adflags );
+
if (ad_close( &add, adflags ) <0) {
- deletefile(NULL, dst, 0);
- return AFPERR_PARAM; /* FIXME */
- } else {
- ad_init(&add, 0);
+ deletefile(d_vol, dst, 0);
+ ret_err = errno;
+ goto done;
+ }
+ else {
+ ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
- ad_close( &ads, adflags );
- deletefile(NULL, dst, 0);
- switch ( err ) {
- case ENOENT :
- return( AFPERR_NOOBJ );
- case EACCES :
- return( AFPERR_ACCESS );
- case EROFS:
- return AFPERR_VLOCK;
- default :
- return( AFPERR_PARAM );
- }
+ ret_err = errno;
}
}
- if (newname) {
- len = strlen( newname );
- ad_setentrylen( &add, ADEID_NAME, len );
- memcpy(ad_entry( &add, ADEID_NAME ), newname, len );
+ if (!ret_err && newname) {
+ ad_setname(&add, newname);
}
- ad_close( &ads, adflags );
ad_flush( &add, adflags );
if (ad_close( &add, adflags ) <0) {
- err = errno;
+ ret_err = errno;
}
- if (err != AFP_OK) {
- deletefile(NULL, dst, 0);
- switch ( err ) {
- case ENOENT :
- return( AFPERR_NOOBJ );
- case EACCES :
- return( AFPERR_ACCESS );
- default :
- return( AFPERR_PARAM );
- }
+ if (ret_err) {
+ deletefile(d_vol, dst, 0);
}
-
- /* set dest modification date to src date */
- if (!stat(src, &st)) {
+ else if (!stat(src, &st)) {
+ /* set dest modification date to src date */
struct utimbuf ut;
ut.actime = ut.modtime = st.st_mtime;
utime(dst, &ut);
+ /* FIXME netatalk doesn't use resource fork file date
+ * but maybe we should set its modtime too.
+ */
}
#ifdef DEBUG
LOG(log_info, logtype_afpd, "end copyfile:");
#endif /* DEBUG */
- return( AFP_OK );
+done:
+ switch ( ret_err ) {
+ case 0:
+ return AFP_OK;
+ case EDQUOT:
+ case EFBIG:
+ case ENOSPC:
+ return AFPERR_DFULL;
+ case ENOENT:
+ return AFPERR_NOOBJ;
+ case EACCES:
+ return AFPERR_ACCESS;
+ case EROFS:
+ return AFPERR_VLOCK;
+ }
+ return AFPERR_PARAM;
}
WRITE lock on read only file.
*/
int deletefile( vol, file, checkAttrib )
-struct vol *vol;
+const struct vol *vol;
char *file;
int checkAttrib;
{
struct adouble ad;
+ struct adouble *adp = &ad;
int adflags, err = AFP_OK;
#ifdef DEBUG
/* try to open both forks at once */
adflags = ADFLAGS_DF|ADFLAGS_HF;
+ ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
while(1) {
- ad_init(&ad, 0); /* OK */
if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
switch (errno) {
case ENOENT:
continue;
case EACCES:
- return AFPERR_ACCESS;
+ adp = NULL; /* maybe it's a file we no rw mode for us */
+ break; /* was return AFPERR_ACCESS;*/
case EROFS:
return AFPERR_VLOCK;
default:
/*
* Does kFPDeleteInhibitBit (bit 8) set?
*/
- if (checkAttrib && (adflags & ADFLAGS_HF)) {
+ if (checkAttrib) {
u_int16_t bshort;
+
+ if (adp && (adflags & ADFLAGS_HF)) {
- ad_getattr(&ad, &bshort);
- if ((bshort & htons(ATTRBIT_NODELETE))) {
- ad_close( &ad, adflags );
- return(AFPERR_OLOCK);
+ ad_getattr(&ad, &bshort);
+ if ((bshort & htons(ATTRBIT_NODELETE))) {
+ ad_close( &ad, adflags );
+ return(AFPERR_OLOCK);
+ }
+ }
+ else if (!adp) {
+ /* was EACCESS error try to get only metadata */
+ ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
+ if ( ad_metadata( file , 0, &ad) == 0 ) {
+ ad_getattr(&ad, &bshort);
+ ad_close( &ad, ADFLAGS_HF );
+ if ((bshort & htons(ATTRBIT_NODELETE))) {
+ return AFPERR_OLOCK;
+ }
+ }
}
}
- if ((adflags & ADFLAGS_HF) ) {
+ if (adp && (adflags & ADFLAGS_HF) ) {
/* FIXME we have a pb here because we want to know if a file is open
* there's a 'priority inversion' if you can't open the ressource fork RW
* you can delete it if it's open because you can't get a write lock.
}
}
- if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
+ if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
err = AFPERR_BUSY;
}
- else if (!(err = netatalk_unlink( ad_path( file, ADFLAGS_HF)) ) &&
+ else if (!(err = netatalk_unlink( vol->ad_path( file, ADFLAGS_HF)) ) &&
!(err = netatalk_unlink( file )) ) {
cnid_t id;
- if (vol && (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);
}
}
- ad_close( &ad, adflags ); /* ad_close removes locks if any */
+ if (adp)
+ ad_close( &ad, adflags ); /* ad_close removes locks if any */
#ifdef DEBUG
LOG(log_info, logtype_afpd, "end deletefile:");
DIR *dp;
struct dirent *de;
int ret;
- struct stat st;
cnid_t aint;
- struct adouble ad;
-
-
- if (vol->v_cdb != NULL) {
+ struct path path;
+
+ memset(&path, 0, sizeof(path));
+ if (vol->v_cdb == NULL) {
return -1;
}
if (NULL == ( dp = opendir( name)) ) {
if (NULL == check_dirent(vol, de->d_name))
continue;
- if ( stat(de->d_name, &st)<0 )
+ if ( stat(de->d_name, &path.st)<0 )
continue;
/* update or add to cnid */
- aint = cnid_add(vol->v_cdb, &st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
+ aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
#if AD_VERSION > AD_VERSION1
- if (aint != CNID_INVALID && !S_ISDIR(st.st_mode)) {
- ad_init(&ad, 0); /* OK */
- if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, &ad ) < 0 ) {
+ if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
+ struct adouble ad, *adp;
+
+ path.st_errno = 0;
+ path.st_valid = 1;
+ path.u_name = de->d_name;
+
+ adp = of_ad(vol, &path, &ad);
+
+ if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, adp ) < 0 ) {
continue;
}
- else {
- ad_setid(&ad,(vol->v_flags & AFPVOL_NODEV)?0:st.st_dev, st.st_ino, aint, did, vol->v_stamp);
- ad_flush(&ad, ADFLAGS_HF);
- ad_close(&ad, ADFLAGS_HF);
- }
+ if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
+ ad_flush(adp, ADFLAGS_HF);
+ }
+ ad_close(adp, ADFLAGS_HF);
}
#endif /* AD_VERSION > AD_VERSION1 */
}
if ( of_stat(&path) < 0 ) {
+#ifdef ESTALE
+ /* with nfs and our working directory is deleted */
+ if (errno == ESTALE) {
+ errno = ENOENT;
+ }
+#endif
if ( errno == ENOENT && !retry) {
/* cnid db is out of sync, reenumerate the directory and updated ids */
reenumerate_id(vol, ".", id);
case EACCES:
case EPERM:
return AFPERR_ACCESS;
+#ifdef ESTALE
+ case ESTALE:
+#endif
case ENOENT:
/* still try to delete the id */
err = AFPERR_NOOBJ;
return err;
}
+/* ------------------------------ */
+static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
+{
+ int ret;
+
+ if (path->st_errno) {
+ switch (path->st_errno) {
+ case ENOENT:
+ afp_errno = AFPERR_NOID;
+ break;
+ case EPERM:
+ case EACCES:
+ afp_errno = AFPERR_ACCESS;
+ break;
+ default:
+ afp_errno = AFPERR_PARAM;
+ break;
+ }
+ return NULL;
+ }
+ /* we use file_access both for legacy Mac perm and
+ * for unix privilege, rename will take care of folder perms
+ */
+ if (file_access(path, OPENACC_WR ) < 0) {
+ afp_errno = AFPERR_ACCESS;
+ return NULL;
+ }
+
+ if ((*of = of_findname(path))) {
+ /* reuse struct adouble so it won't break locks */
+ adp = (*of)->of_ad;
+ }
+ else {
+ ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
+ if ( !ret && ad_hfileno(adp) != -1 && !(adp->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) {
+ /* from AFP spec.
+ * The user must have the Read & Write privilege for both files in order to use this command.
+ */
+ ad_close(adp, ADFLAGS_HF);
+ afp_errno = AFPERR_ACCESS;
+ return NULL;
+ }
+ }
+ return adp;
+}
+
#define APPLETEMP ".AppleTempXXXXXX"
int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
int err;
struct adouble ads;
struct adouble add;
- struct adouble *adsp;
- struct adouble *addp;
- struct ofork *s_of;
- struct ofork *d_of;
+ struct adouble *adsp = NULL;
+ struct adouble *addp = NULL;
+ struct ofork *s_of = NULL;
+ struct ofork *d_of = NULL;
int crossdev;
int slen, dlen;
u_int32_t sid, did;
u_int16_t vid;
+ uid_t uid;
+ gid_t gid;
+
#ifdef DEBUG
LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
#endif /* DEBUG */
return( AFPERR_PARAM);
}
- if (vol->v_flags & AFPVOL_RO)
+ if ((vol->v_flags & AFPVOL_RO))
return AFPERR_VLOCK;
/* source and destination dids */
}
if ( path_isadir(path) ) {
- return( AFPERR_BADTYPE ); /* it's a dir */
+ return AFPERR_BADTYPE; /* it's a dir */
}
- upath = path->u_name;
- switch (path->st_errno) {
- case 0:
- break;
- case ENOENT:
- return AFPERR_NOID;
- case EPERM:
- case EACCES:
- return AFPERR_ACCESS;
- default:
- return AFPERR_PARAM;
- }
- ad_init(&ads, vol->v_adouble);
- adsp = &ads;
- if ((s_of = of_findname(path))) {
- /* reuse struct adouble so it won't break locks */
- adsp = s_of->of_ad;
- }
- memcpy(&srcst, &path->st, sizeof(struct stat));
/* save some stuff */
+ srcst = path->st;
sdir = curdir;
spath = obj->oldtmp;
supath = obj->newtmp;
strcpy(spath, path->m_name);
- strcpy(supath, upath); /* this is for the cnid changing */
- p = absupath( vol, sdir, upath);
+ strcpy(supath, path->u_name); /* this is for the cnid changing */
+ p = absupath( vol, sdir, supath);
if (!p) {
/* pathname too long */
return AFPERR_PARAM ;
}
+
+ ad_init(&ads, vol->v_adouble, vol->v_ad_options);
+ if (!(adsp = find_adouble( path, &s_of, &ads))) {
+ return afp_errno;
+ }
+ /* ***** from here we may have resource fork open **** */
+
/* look for the source cnid. if it doesn't exist, don't worry about
* it. */
sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
if (NULL == ( dir = dirlookup( vol, did )) ) {
- return afp_errno; /* was AFPERR_PARAM */
+ err = afp_errno; /* was AFPERR_PARAM */
+ goto err_exchangefile;
}
if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
- return get_afp_errno(AFPERR_NOOBJ);
+ err = get_afp_errno(AFPERR_NOOBJ);
+ goto err_exchangefile;
}
if ( path_isadir(path) ) {
- return( AFPERR_BADTYPE );
+ err = AFPERR_BADTYPE;
+ goto err_exchangefile;
}
/* FPExchangeFiles is the only call that can return the SameObj
* error */
- if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
- return AFPERR_SAMEOBJ;
-
- switch (path->st_errno) {
- case 0:
- break;
- case ENOENT:
- return AFPERR_NOID;
- case EPERM:
- case EACCES:
- return AFPERR_ACCESS;
- default:
- return AFPERR_PARAM;
+ if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
+ err = AFPERR_SAMEOBJ;
+ goto err_exchangefile;
}
- ad_init(&add, vol->v_adouble);
- addp = &add;
- if ((d_of = of_findname( path))) {
- /* reuse struct adouble so it won't break locks */
- addp = d_of->of_ad;
+
+ ad_init(&add, vol->v_adouble, vol->v_ad_options);
+ if (!(addp = find_adouble( path, &d_of, &add))) {
+ err = afp_errno;
+ goto err_exchangefile;
}
- memcpy(&destst, &path->st, sizeof(struct stat));
+ destst = path->st;
/* they are not on the same device and at least one is open
+ * FIXME broken for for crossdev and adouble v2
+ * return an error
*/
crossdev = (srcst.st_dev != destst.st_dev);
- if ((d_of || s_of) && crossdev)
- return AFPERR_MISC;
-
- upath = path->u_name;
+ if (/* (d_of || s_of) && */ crossdev) {
+ err = AFPERR_MISC;
+ goto err_exchangefile;
+ }
+
/* look for destination id. */
+ upath = path->u_name;
did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
/* construct a temp name.
* NOTE: the temp file will be in the dest file's directory. it
* will also be inaccessible from AFP. */
memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
- if (!mktemp(temp))
- return AFPERR_MISC;
+ if (!mktemp(temp)) {
+ err = AFPERR_MISC;
+ goto err_exchangefile;
+ }
+
+ if (crossdev) {
+ /* FIXME we need to close fork for copy, both s_of and d_of are null */
+ ad_close(adsp, ADFLAGS_HF);
+ ad_close(addp, ADFLAGS_HF);
+ }
/* now, quickly rename the file. we error if we can't. */
- if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
+ if ((err = renamefile(vol, 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(upath, p, spath, vol_noadouble(vol), addp)) < 0)
+ if ((err = renamefile(vol, 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(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
+ if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
goto err_dest_to_src;
of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
}
goto err_temp_to_dest;
}
+
+ /* here we need to reopen if crossdev */
+ if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
+ {
+ ad_flush( addp, ADFLAGS_HF );
+ }
+
+ if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
+ {
+ ad_flush( adsp, ADFLAGS_HF );
+ }
+
+ /* change perms, src gets dest perm and vice versa */
+
+ uid = geteuid();
+ gid = getegid();
+ if (seteuid(0)) {
+ LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
+ err = AFP_OK; /* ignore error */
+ goto err_temp_to_dest;
+ }
+
+ /*
+ * we need to exchange ACL entries as well
+ */
+ /* exchange_acls(vol, p, upath); */
+
+ path->st = srcst;
+ path->st_valid = 1;
+ path->st_errno = 0;
+ path->m_name = NULL;
+ path->u_name = upath;
+
+ setfilunixmode(vol, path, destst.st_mode);
+ setfilowner(vol, destst.st_uid, destst.st_gid, path);
+
+ path->st = destst;
+ path->st_valid = 1;
+ path->st_errno = 0;
+ path->u_name = p;
+
+ setfilunixmode(vol, path, srcst.st_mode);
+ setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
+
+ if ( setegid(gid) < 0 || seteuid(uid) < 0) {
+ LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
+ exit(EXITERR_SYS);
+ }
#ifdef DEBUG
LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
#endif /* DEBUG */
- return AFP_OK;
-
+ err = AFP_OK;
+ goto err_exchangefile;
/* all this stuff is so that we can unwind a failed operation
* properly. */
err_temp_to_dest:
/* rename dest to temp */
- renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
+ renamefile(vol, upath, temp, temp, adsp);
of_rename(vol, s_of, curdir, upath, curdir, temp);
err_dest_to_src:
/* rename source back to dest */
- renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
+ renamefile(vol, 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(temp, p, spath, vol_noadouble(vol), adsp);
+ renamefile(vol, temp, p, spath, adsp);
of_rename(vol, s_of, curdir, temp, sdir, spath);
err_exchangefile:
+ if ( !s_of && adsp && ad_hfileno(adsp) != -1 ) {
+ ad_close(adsp, ADFLAGS_HF);
+ }
+ if ( !d_of && addp && ad_hfileno(addp) != -1 ) {
+ ad_close(addp, ADFLAGS_HF);
+ }
+
return err;
}