From ff117107526219d5ce89d5ff683eddd414e40293 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 4 Dec 2012 16:08:27 +0100 Subject: [PATCH] Dont copy our metadata EA in copyfile() Apparently Apple is now relying more on the AFP copyfile function for file copies where source and destination are on the same vol. The copying is done by our copyfile() function. It calls into our VFS stack where in the end _all_ extended attributes of the file, including our metadata EA, will be copied from source to dest. This resulted in an incorrect metadata EA on the destination file, eg the CNID was still the one of the source file. Obviously the metadata EA of the destination file must be created such that all relevant fields are properly assigned. Fixes bug #452. --- NEWS | 2 ++ etc/afpd/directory.c | 10 ++++----- etc/afpd/directory.h | 2 +- etc/afpd/enumerate.c | 2 +- etc/afpd/file.c | 52 +++++++++++++++++++++++++++++-------------- etc/afpd/file.h | 4 ++-- etc/afpd/filedir.c | 4 ++-- libatalk/vfs/ea_sys.c | 3 +++ 8 files changed, 51 insertions(+), 28 deletions(-) diff --git a/NEWS b/NEWS index c9b6a6a6..9c5472cc 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,8 @@ Changes in 3.0.2 Fixes bug #472. * FIX: Remove length limitation of options like "valid users". Fixes bug #473. +* FIX: Dont copy our metadata EA in copyfile(). + Fixes bug #452. * REM: Remove TimeMachine volume used size FCE event. Changes in 3.0.1 diff --git a/etc/afpd/directory.c b/etc/afpd/directory.c index 8b36c99b..854b6941 100644 --- a/etc/afpd/directory.c +++ b/etc/afpd/directory.c @@ -185,7 +185,7 @@ static int deletedir(int dirfd, char *dir) } /* do a recursive copy. */ -static int copydir(const struct vol *vol, int dirfd, char *src, char *dst) +static int copydir(struct vol *vol, struct dir *ddir, int dirfd, char *src, char *dst) { char spath[MAXPATHLEN + 1], dpath[MAXPATHLEN + 1]; DIR *dp; @@ -239,9 +239,9 @@ static int copydir(const struct vol *vol, int dirfd, char *src, char *dst) strcpy(dpath + dlen, de->d_name); if (S_ISDIR(st.st_mode)) { - if (AFP_OK != (err = copydir(vol, dirfd, spath, dpath))) + if (AFP_OK != (err = copydir(vol, ddir, dirfd, spath, dpath))) goto copydir_done; - } else if (AFP_OK != (err = copyfile(vol, vol, dirfd, spath, dpath, NULL, NULL))) { + } else if (AFP_OK != (err = copyfile(vol, vol, ddir, dirfd, spath, dpath, NULL, NULL))) { goto copydir_done; } else { @@ -2213,7 +2213,7 @@ createdir_done: * newparent curdir * dirfd -1 means ignore dirfd (or use AT_FDCWD), otherwise src is relative to dirfd */ -int renamedir(const struct vol *vol, +int renamedir(struct vol *vol, int dirfd, char *src, char *dst, @@ -2239,7 +2239,7 @@ int renamedir(const struct vol *vol, case EXDEV: /* this needs to copy and delete. bleah. that means we have * to deal with entire directory hierarchies. */ - if ((err = copydir(vol, dirfd, src, dst)) < 0) { + if ((err = copydir(vol, newparent, dirfd, src, dst)) < 0) { deletedir(-1, dst); return err; } diff --git a/etc/afpd/directory.h b/etc/afpd/directory.h index 7f3e8c56..eb89c606 100644 --- a/etc/afpd/directory.h +++ b/etc/afpd/directory.h @@ -115,7 +115,7 @@ extern int getdirparams (const AFPObj *obj, const struct vol *, uint16_t struct dir *, char *, size_t *); extern int setdirparams(struct vol *, struct path *, uint16_t, char *); -extern int renamedir(const struct vol *, int, char *, char *, struct dir *, +extern int renamedir(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, uint32_t count); diff --git a/etc/afpd/enumerate.c b/etc/afpd/enumerate.c index d469928c..c3b3acb4 100644 --- a/etc/afpd/enumerate.c +++ b/etc/afpd/enumerate.c @@ -370,7 +370,7 @@ static int enumerate(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, if (convname) { s_path.id = cnid_lookup(vol->v_cdb, &s_path.st, curdir->d_did, sd.sd_last, strlen(sd.sd_last)); if (s_path.id != CNID_INVALID) { - if (cnid_update(vol->v_cdb, s_path.id, &s_path.st, curdir->d_did, convname, strlen(convname)) != 0) + if (cnid_update(vol->v_cdb, s_path.id, &s_path.st, curdir->d_did, (char *)convname, strlen(convname)) != 0) LOG(log_error, logtype_afpd, "enumerate: error updating CNID of \"%s\"", fullpathname(convname)); } } diff --git a/etc/afpd/file.c b/etc/afpd/file.c index c4c55fb8..bc336a4e 100644 --- a/etc/afpd/file.c +++ b/etc/afpd/file.c @@ -1085,7 +1085,7 @@ setfilparam_done: * adp adouble struct of src file, if open, or & zeroed one * */ -int renamefile(const struct vol *vol, int sdir_fd, char *src, char *dst, char *newname, struct adouble *adp) +int renamefile(struct vol *vol, struct dir *ddir, int sdir_fd, char *src, char *dst, char *newname, struct adouble *adp) { int rc; @@ -1110,7 +1110,7 @@ int renamefile(const struct vol *vol, int sdir_fd, char *src, char *dst, char *n /* FIXME warning in syslog so admin'd know there's a conflict ?*/ return AFPERR_OLOCK; /* little lie */ } - if (AFP_OK != ( rc = copyfile(vol, vol, sdir_fd, src, dst, newname, NULL )) ) { + if (AFP_OK != ( rc = copyfile(vol, vol, ddir, sdir_fd, src, dst, newname, NULL )) ) { /* on error copyfile delete dest */ return( rc ); } @@ -1344,7 +1344,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, -1, p, upath , newname, adp)) < 0 ) { + if ( (err = copyfile(s_vol, d_vol, curdir, -1, p, upath , newname, adp)) < 0 ) { retvalue = err; goto copy_exit; } @@ -1362,8 +1362,9 @@ 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, +int copyfile(struct vol *s_vol, + struct vol *d_vol, + struct dir *d_dir, int sfd, char *src, char *dst, @@ -1385,13 +1386,17 @@ int copyfile(const struct vol *s_vol, adp = &ads; } - adflags = ADFLAGS_DF | ADFLAGS_RF | ADFLAGS_NORF; + adflags = ADFLAGS_DF | ADFLAGS_HF | ADFLAGS_NOHF | ADFLAGS_RF | ADFLAGS_NORF; if (ad_openat(adp, sfd, src, adflags | ADFLAGS_RDONLY) < 0) { ret_err = errno; goto done; } + if (!AD_META_OPEN(adp)) + /* no resource fork, don't create one for dst file */ + adflags &= ~ADFLAGS_HF; + if (!AD_RSRC_OPEN(adp)) /* no resource fork, don't create one for dst file */ adflags &= ~ADFLAGS_RF; @@ -1424,12 +1429,25 @@ int copyfile(const struct vol *s_vol, if (err < 0) ret_err = errno; - if (!ret_err && newname && (adflags & ADFLAGS_HF)) { - /* set the new name in the resource fork */ - ad_copy_header(&add, adp); - ad_setname(&add, newname); - ad_flush( &add ); + if (AD_META_OPEN(&add)) { + if (AD_META_OPEN(adp)) + ad_copy_header(&add, adp); + ad_setname(&add, dst); + cnid_t id; + struct stat stdest; + if (fstat(ad_meta_fileno(&add), &stdest) != 0) { + ret_err = errno; + goto error; + } + if ((id = get_id(d_vol, &add, &stdest, d_dir->d_did, dst, strlen(dst))) == CNID_INVALID) { + ret_err = EINVAL; + goto error; + } + (void)ad_setid(&add, stdest.st_dev, stdest.st_ino, id, d_dir->d_did, d_vol->v_stamp); + ad_flush(&add); } + +error: ad_close( adp, adflags ); if (ad_close( &add, adflags ) <0) { @@ -2090,17 +2108,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, -1, p, temp, temp, adsp)) != AFP_OK) + if ((err = renamefile(vol, curdir, -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, -1, upath, p, spath, addp)) != AFP_OK) + if ((err = renamefile(vol, curdir, -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, -1, temp, upath, path->m_name, adsp)) != AFP_OK) + if ((err = renamefile(vol, curdir, -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); @@ -2175,17 +2193,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, -1, upath, temp, temp, adsp); + renamefile(vol, curdir, -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, -1, p, upath, path->m_name, addp); + renamefile(vol, curdir, -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, -1, temp, p, spath, adsp); + renamefile(vol, curdir, -1, temp, p, spath, adsp); of_rename(vol, s_of, curdir, temp, sdir, spath); err_exchangefile: diff --git a/etc/afpd/file.h b/etc/afpd/file.h index ec811596..1d0ff45e 100644 --- a/etc/afpd/file.h +++ b/etc/afpd/file.h @@ -105,8 +105,8 @@ extern struct extmap *getdefextmap (void); extern int getfilparams (const AFPObj *obj, struct vol *, uint16_t, struct path *, struct dir *, char *buf, size_t *, int); extern int setfilparams (const AFPObj *obj, struct vol *, struct path *, uint16_t, char *); -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 renamefile (struct vol *, struct dir *, int, char *, char *, char *, struct adouble *); +extern int copyfile (struct vol *, struct vol *, struct dir *, int, char *, char *, char *, struct adouble *); extern int deletefile (const struct vol *, int, char *, int); extern int getmetadata (const AFPObj *obj, struct vol *vol, uint16_t bitmap, struct path *path, diff --git a/etc/afpd/filedir.c b/etc/afpd/filedir.c index 83f7f1aa..9a897d1b 100644 --- a/etc/afpd/filedir.c +++ b/etc/afpd/filedir.c @@ -218,7 +218,7 @@ 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, +static int moveandrename(struct vol *vol, struct dir *sdir, int sdir_fd, char *oldname, @@ -349,7 +349,7 @@ static int moveandrename(const struct vol *vol, if (of_findname(&path)) { rc = AFPERR_EXIST; /* was AFPERR_BUSY; */ } else { - rc = renamefile(vol, sdir_fd, oldunixname, upath, newname, adp ); + rc = renamefile(vol, curdir, sdir_fd, oldunixname, upath, newname, adp ); if (rc == AFP_OK) of_rename(vol, opened, sdir, oldname, curdir, newname); } diff --git a/libatalk/vfs/ea_sys.c b/libatalk/vfs/ea_sys.c index a30e6d96..374248bc 100644 --- a/libatalk/vfs/ea_sys.c +++ b/libatalk/vfs/ea_sys.c @@ -439,6 +439,9 @@ int sys_ea_copyfile(VFS_FUNC_ARGS_COPYFILE) if (!*name) continue; + if (STRCMP(name, ==, AD_EA_META)) + continue; + if (sfd != -1) { if (fchdir(sfd) == -1) { LOG(log_error, logtype_afpd, "sys_ea_copyfile: cant chdir to sfd: %s", -- 2.39.2