X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=blobdiff_plain;f=etc%2Fafpd%2Ffile.c;h=323642f9ce92f305e7b9b905fdf102c726119656;hp=175e6d93fe4dc24281a70733acd5b6f510be0654;hb=465246e257d9aff9855e3e35d8fd5983db932b45;hpb=83db9cc5df13d2e3b03897e3a39a3826c40c7e61 diff --git a/etc/afpd/file.c b/etc/afpd/file.c index 175e6d93..323642f9 100644 --- a/etc/afpd/file.c +++ b/etc/afpd/file.c @@ -1,6 +1,4 @@ /* - * $Id: file.c,v 1.138 2010-02-18 02:02:30 didg Exp $ - * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. */ @@ -39,14 +37,15 @@ char *strchr (), *strrchr (); #include #include #include +#include #include "directory.h" +#include "dircache.h" #include "desktop.h" #include "volume.h" #include "fork.h" #include "file.h" #include "filedir.h" -#include "globals.h" #include "unix.h" /* the format for the finderinfo fields (from IM: Toolbox Essentials): @@ -166,8 +165,8 @@ char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t else { u_int16_t temp; - if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/ - aint = 255; + if (aint > UTF8FILELEN_EARLY) /* FIXME safeguard, anyway if no ascii char it's game over*/ + aint = UTF8FILELEN_EARLY; utf8 = vol->v_kTextEncoding; memcpy(data, &utf8, sizeof(utf8)); @@ -201,19 +200,39 @@ char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t (1 << FILPBIT_FNUM) |\ (1 << FILPBIT_UNIXPR))) -/* -------------------------- */ -u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st, - const cnid_t did, char *upath, const int len) +/*! + * @brief Get CNID for did/upath args both from database and adouble file + * + * 1. Get the objects CNID as stored in its adouble file + * 2. Get the objects CNID from the database + * 3. If there's a problem with a "dbd" database, fallback to "tdb" in memory + * 4. In case 2 and 3 differ, store 3 in the adouble file + * + * @param vol (rw) volume + * @param adp (rw) adouble struct of object upath, might be NULL + * @param st (r) stat of upath, must NOT be NULL + * @param did (r) parent CNID of upath + * @param upath (r) name of object + * @param len (r) strlen of upath + */ +uint32_t get_id(struct vol *vol, + struct adouble *adp, + const struct stat *st, + const cnid_t did, + const char *upath, + const int len) { + static int first = 1; /* mark if this func is called the first time */ u_int32_t adcnid; u_int32_t dbcnid = CNID_INVALID; +restart: if (vol->v_cdb != NULL) { /* prime aint with what we think is the cnid, set did to zero for catching moved files */ - adcnid = ad_getid(adp, st->st_dev, st->st_ino, 0, vol->v_stamp); + adcnid = ad_getid(adp, st->st_dev, st->st_ino, 0, vol->v_stamp); /* (1) */ - dbcnid = cnid_add(vol->v_cdb, st, did, upath, len, adcnid); + dbcnid = cnid_add(vol->v_cdb, st, did, upath, len, adcnid); /* (2) */ /* Throw errors if cnid_add fails. */ if (dbcnid == CNID_INVALID) { switch (errno) { @@ -222,23 +241,61 @@ u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st, case CNID_ERR_PARAM: LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add"); afp_errno = AFPERR_PARAM; - return CNID_INVALID; + goto exit; case CNID_ERR_PATH: afp_errno = AFPERR_PARAM; - return CNID_INVALID; + goto exit; default: + /* Close CNID backend if "dbd" and switch to temp in-memory "tdb" */ + /* we have to do it here for "dbd" because it uses "lazy opening" */ + /* In order to not end in a loop somehow with goto restart below */ + /* */ + if (first && (strcmp(vol->v_cnidscheme, "dbd") == 0)) { /* (3) */ + cnid_close(vol->v_cdb); + free(vol->v_cnidscheme); + vol->v_cnidscheme = strdup("tdb"); + + int flags = CNID_FLAG_MEMORY; + if ((vol->v_flags & AFPVOL_NODEV)) { + flags |= CNID_FLAG_NODEV; + } + LOG(log_error, logtype_afpd, "Reopen volume %s using in memory temporary CNID DB.", + vol->v_path); + vol->v_cdb = cnid_open(vol->v_path, vol->v_umask, "tdb", flags, NULL, NULL); + if (vol->v_cdb) { + /* deactivate cnid caching/storing in AppleDouble files and set ro mode*/ + vol->v_flags &= ~AFPVOL_CACHE; + vol->v_flags |= AFPVOL_RO; +#ifdef SERVERTEXT + /* kill ourself with SIGUSR2 aka msg pending */ + setmessage("Something wrong with the volume's CNID DB, using temporary CNID DB instead." + "Check server messages for details. Switching to read-only mode."); + kill(getpid(), SIGUSR2); +#endif + goto restart; /* not try again with the temp CNID db */ + } else { +#ifdef SERVERTEXT + setmessage("Something wrong with the volume's CNID DB, using temporary CNID DB failed too!" + "Check server messages for details, can't recover from this state!"); +#endif + } + } afp_errno = AFPERR_MISC; - return CNID_INVALID; + goto exit; } } - else if (adp && (adcnid != dbcnid)) { + else if (adp && (adcnid != dbcnid)) { /* 4 */ /* Update the ressource fork. For a folder adp is always null */ - LOG(log_debug, logtype_afpd, "get_id: calling ad_setid. adcnid: %u, dbcnid: %u", htonl(adcnid), htonl(dbcnid)); + LOG(log_debug, logtype_afpd, "get_id(%s/%s): calling ad_setid(old: %u, new: %u)", + getcwdpath(), upath, htonl(adcnid), htonl(dbcnid)); if (ad_setid(adp, st->st_dev, st->st_ino, dbcnid, did, vol->v_stamp)) { ad_flush(adp); } } } + +exit: + first = 0; return dbcnid; } @@ -259,24 +316,61 @@ int getmetadata(struct vol *vol, struct stat *st; struct maccess ma; -#ifdef DEBUG - LOG(log_debug9, logtype_afpd, "begin getmetadata:"); -#endif /* DEBUG */ + LOG(log_debug, logtype_afpd, "getmetadata(\"%s\")", path->u_name); upath = path->u_name; st = &path->st; - data = buf; if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <m_name) || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */ || (bitmap & (1 << FILPBIT_FNUM))) { - if (!path->id) - id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath)); - else + if (!path->id) { + bstring fullpath; + struct dir *cachedfile; + int len = strlen(upath); + if ((cachedfile = dircache_search_by_name(vol, dir, upath, len)) != NULL) + id = cachedfile->d_did; + else { + id = get_id(vol, adp, st, dir->d_did, upath, len); + + /* Add it to the cache */ + LOG(log_debug, logtype_afpd, "getmetadata: caching: did:%u, \"%s\", cnid:%u", + ntohl(dir->d_did), upath, ntohl(id)); + + /* Get macname from unixname first */ + if (path->m_name == NULL) { + if ((path->m_name = utompath(vol, upath, id, utf8_encoding())) == NULL) { + LOG(log_error, logtype_afpd, "getmetadata: utompath error"); + return AFPERR_MISC; + } + } + + /* Build fullpath */ + if (((fullpath = bstrcpy(dir->d_fullpath)) == NULL) + || (bconchar(fullpath, '/') != BSTR_OK) + || (bcatcstr(fullpath, upath)) != BSTR_OK) { + LOG(log_error, logtype_afpd, "getmetadata: fullpath: %s", strerror(errno)); + return AFPERR_MISC; + } + + if ((cachedfile = dir_new(path->m_name, upath, vol, dir->d_did, id, fullpath, st)) == NULL) { + LOG(log_error, logtype_afpd, "getmetadata: error from dir_new"); + return AFPERR_MISC; + } + + if ((dircache_add(vol, cachedfile)) != 0) { + LOG(log_error, logtype_afpd, "getmetadata: fatal dircache error"); + return AFPERR_MISC; + } + } + } else { id = path->id; + } + if (id == CNID_INVALID) return afp_errno; + if (!path->m_name) { path->m_name = utompath(vol, upath, id, utf8_encoding()); } @@ -309,11 +403,15 @@ int getmetadata(struct vol *vol, #endif memcpy(data, &ashort, sizeof( ashort )); data += sizeof( ashort ); + LOG(log_debug, logtype_afpd, "metadata('%s'): AFP Attributes: %04x", + path->u_name, ntohs(ashort)); break; case FILPBIT_PDID : memcpy(data, &dir->d_did, sizeof( u_int32_t )); data += sizeof( u_int32_t ); + LOG(log_debug, logtype_afpd, "metadata('%s'): Parent DID: %u", + path->u_name, ntohl(dir->d_did)); break; case FILPBIT_CDATE : @@ -360,6 +458,8 @@ int getmetadata(struct vol *vol, case FILPBIT_FNUM : memcpy(data, &id, sizeof( id )); data += sizeof( id ); + LOG(log_debug, logtype_afpd, "metadata('%s'): CNID: %u", + path->u_name, ntohl(id)); break; case FILPBIT_DFLEN : @@ -524,9 +624,7 @@ int getfilparams(struct vol *vol, int opened = 0; int rc; -#ifdef DEBUG - LOG(log_debug9, logtype_default, "begin getfilparams:"); -#endif /* DEBUG */ + LOG(log_debug, logtype_afpd, "getfilparams(\"%s\")", path->u_name); opened = PARAM_NEED_ADP(bitmap); adp = NULL; @@ -558,9 +656,6 @@ int getfilparams(struct vol *vol, if ( adp ) { ad_close_metadata( adp); } -#ifdef DEBUG - LOG(log_debug9, logtype_afpd, "end getfilparams:"); -#endif /* DEBUG */ return( rc ); } @@ -664,11 +759,22 @@ int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, path = s_path->m_name; ad_setname(adp, path); + + struct stat st; + if (lstat(upath, &st) != 0) { + LOG(log_error, logtype_afpd, "afp_createfile(\"%s\"): stat: %s", + upath, strerror(errno)); + ad_close( adp, ADFLAGS_DF|ADFLAGS_HF); + return AFPERR_MISC; + } + + (void)get_id(vol, adp, &st, dir->d_did, upath, strlen(upath)); + ad_flush( adp); ad_close( adp, ADFLAGS_DF|ADFLAGS_HF ); createfile_done: - curdir->offcnt++; + curdir->d_offcnt++; #ifdef DROPKLUDGE if (vol->v_flags & AFPVOL_DROPBOX) { @@ -1003,21 +1109,22 @@ setfilparam_done: * renamefile and copyfile take the old and new unix pathnames * and the new mac name. * + * sdir_fd source dir fd to which src path is relative (for openat et al semantics) + * passing -1 means this is not used, src path is a full path * src the source path * dst the dest filename in current dir * newname the dest mac name * adp adouble struct of src file, if open, or & zeroed one * */ -int renamefile(const struct vol *vol, char *src, char *dst, char *newname, struct adouble *adp) +int renamefile(const struct vol *vol, int sdir_fd, char *src, char *dst, char *newname, struct adouble *adp) { int rc; -#ifdef DEBUG - LOG(log_debug9, logtype_afpd, "begin renamefile:"); -#endif /* DEBUG */ + LOG(log_debug, logtype_afpd, + "renamefile: src[%d, \"%s\"] -> dst[\"%s\"]", sdir_fd, src, dst); - if ( unix_rename( src, dst ) < 0 ) { + if ( unix_rename( sdir_fd, src, -1, dst ) < 0 ) { switch ( errno ) { case ENOENT : return( AFPERR_NOOBJ ); @@ -1035,17 +1142,17 @@ int renamefile(const struct vol *vol, char *src, char *dst, char *newname, struc /* FIXME warning in syslog so admin'd know there's a conflict ?*/ return AFPERR_OLOCK; /* little lie */ } - if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) { + if (AFP_OK != ( rc = copyfile(vol, vol, sdir_fd, src, dst, newname, NULL )) ) { /* on error copyfile delete dest */ return( rc ); } - return deletefile(vol, src, 0); + return deletefile(vol, sdir_fd, src, 0); default : return( AFPERR_PARAM ); } } - if (vol->vfs->vfs_renamefile(vol, src, dst) < 0 ) { + if (vol->vfs->vfs_renamefile(vol, sdir_fd, src, dst) < 0 ) { int err; err = errno; @@ -1053,7 +1160,7 @@ int renamefile(const struct vol *vol, char *src, char *dst, char *newname, struc * we know we are on the same device */ if (err) { - unix_rename( dst, src ); + unix_rename(-1, dst, sdir_fd, src ); /* return the first error */ switch ( err) { case ENOENT : @@ -1076,9 +1183,6 @@ int renamefile(const struct vol *vol, char *src, char *dst, char *newname, struc ad_flush( adp ); ad_close( adp, ADFLAGS_HF ); } -#ifdef DEBUG - LOG(log_debug9, logtype_afpd, "end renamefile:"); -#endif /* DEBUG */ return( AFP_OK ); } @@ -1246,7 +1350,7 @@ int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, si } if ( *s_path->m_name != '\0' ) { - retvalue = path_error(s_path, AFPERR_PARAM); + retvalue =path_error(s_path, AFPERR_NOOBJ); goto copy_exit; } @@ -1263,11 +1367,11 @@ int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, si goto copy_exit; } - if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) { + if ( (err = copyfile(s_vol, d_vol, -1, p, upath , newname, adp)) < 0 ) { retvalue = err; goto copy_exit; } - curdir->offcnt++; + curdir->d_offcnt++; #ifdef DROPKLUDGE if (vol->v_flags & AFPVOL_DROPBOX) { @@ -1385,8 +1489,13 @@ static int copy_fork(int eid, struct adouble *add, struct adouble *ads) * because we are doing it elsewhere. * currently if newname is NULL then adp is NULL. */ -int copyfile(const struct vol *s_vol, const struct vol*d_vol, - char *src, char *dst, char *newname, struct adouble *adp) +int copyfile(const struct vol *s_vol, + const struct vol *d_vol, + int sfd, + char *src, + char *dst, + char *newname, + struct adouble *adp) { struct adouble ads, add; int err = 0; @@ -1395,9 +1504,8 @@ int copyfile(const struct vol *s_vol, const struct vol*d_vol, int stat_result; struct stat st; -#ifdef DEBUG - LOG(log_debug9, logtype_afpd, "begin copyfile:"); -#endif /* DEBUG */ + LOG(log_debug, logtype_afpd, "copyfile(sfd:%d,s:'%s',d:'%s',n:'%s')", + sfd, src, dst, newname); if (adp == NULL) { ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options); @@ -1409,7 +1517,7 @@ int copyfile(const struct vol *s_vol, const struct vol*d_vol, adflags |= ADFLAGS_HF; } - if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) { + if (ad_openat(sfd, src, adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) { ret_err = errno; goto done; } @@ -1431,7 +1539,7 @@ int copyfile(const struct vol *s_vol, const struct vol*d_vol, ret_err = errno; ad_close( adp, adflags ); if (EEXIST != ret_err) { - deletefile(d_vol, dst, 0); + deletefile(d_vol, -1, dst, 0); goto done; } return AFPERR_EXIST; @@ -1443,7 +1551,7 @@ int copyfile(const struct vol *s_vol, const struct vol*d_vol, if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){ /* copy the data fork */ if ((err = copy_fork(ADEID_DFORK, &add, adp)) == 0) { - err = d_vol->vfs->vfs_copyfile(d_vol, src, dst); + err = d_vol->vfs->vfs_copyfile(d_vol, sfd, src, dst); } } @@ -1464,7 +1572,7 @@ int copyfile(const struct vol *s_vol, const struct vol*d_vol, } if (ret_err) { - deletefile(d_vol, dst, 0); + deletefile(d_vol, -1, dst, 0); } else if (stat_result == 0) { /* set dest modification date to src date */ @@ -1477,10 +1585,6 @@ int copyfile(const struct vol *s_vol, const struct vol*d_vol, */ } -#ifdef DEBUG - LOG(log_debug9, logtype_afpd, "end copyfile:"); -#endif /* DEBUG */ - done: switch ( ret_err ) { case 0: @@ -1527,59 +1631,57 @@ u_int16_t bshort = 0; } return 0; } - -int deletefile(const struct vol *vol, char *file, int checkAttrib) +/* + * dirfd can be used for unlinkat semantics + */ +int deletefile(const struct vol *vol, int dirfd, char *file, int checkAttrib) { struct adouble ad; - struct adouble *adp = &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); - /* try to open both forks at once */ - adflags = ADFLAGS_DF|ADFLAGS_HF; + ad_init(&ad, vol->v_adouble, vol->v_ad_options); if (checkAttrib) { /* was EACCESS error try to get only metadata */ - ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* we never want to create a resource fork here, we are going to delete it * 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 ) { - ad_close( &ad, adflags ); + if ( ad_metadataat(dirfd, file, ADFLAGS_OPENFORKS, &ad) == 0 ) { if ((err = check_attrib(&ad))) { + ad_close_metadata(&ad); return err; } + meta = 1; } } - while(1) { - ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */ - if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) { - switch (errno) { - case ENOENT: - if (adflags == ADFLAGS_DF) - return AFPERR_NOOBJ; - - /* that failed. now try to open just the data fork */ - adflags = ADFLAGS_DF; - continue; - - case EACCES: - adp = NULL; /* maybe it's a file with no write mode for us */ - break; /* was return AFPERR_ACCESS;*/ - case EROFS: - return AFPERR_VLOCK; - default: - return( AFPERR_PARAM ); - } + /* try to open both forks at once */ + adflags = ADFLAGS_DF; + if ( ad_openat(dirfd, file, adflags |ADFLAGS_HF|ADFLAGS_NOHF, O_RDONLY, 0, &ad ) < 0 ) { + switch (errno) { + case ENOENT: + err = AFPERR_NOOBJ; + goto end; + case EACCES: /* maybe it's a file with no write mode for us */ + break; /* was return AFPERR_ACCESS;*/ + case EROFS: + err = AFPERR_VLOCK; + goto end; + default: + err = AFPERR_PARAM; + goto end; } - break; /* from the while */ + } + else { + adp = &ad; } - if (adp && (adflags & ADFLAGS_HF) ) { + if ( adp && ad_reso_fileno( adp ) != -1 ) { /* there's a resource fork */ + 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. @@ -1590,28 +1692,27 @@ int deletefile(const struct vol *vol, char *file, int checkAttrib) * FIXME it doesn't work for RFORK open read only and fork open without deny mode */ if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) { - ad_close( &ad, adflags ); - return( AFPERR_BUSY ); + err = AFPERR_BUSY; + goto end; } } 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); } } + +end: + if (meta) + ad_close_metadata(&ad); + 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; } @@ -1754,7 +1855,7 @@ reenumerate_id(struct vol *vol, char *name, struct dir *dir) if (dirreenumerate(dir, &st)) { /* we already did it once and the dir haven't been modified */ - return dir->offcnt; + return dir->d_offcnt; } data.vol = vol; @@ -1914,6 +2015,10 @@ int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_ } if (NULL == ( dir = dirlookup( vol, id )) ) { + if (afp_errno == AFPERR_NOOBJ) { + err = AFPERR_NOOBJ; + goto delete; + } return( AFPERR_PARAM ); } @@ -1937,6 +2042,7 @@ int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_ else if (S_ISDIR(st.st_mode)) /* directories are bad */ return AFPERR_BADTYPE; +delete: if (cnid_delete(vol->v_cdb, fileid)) { switch (errno) { case EROFS: @@ -2140,29 +2246,28 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U } /* now, quickly rename the file. we error if we can't. */ - if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK) + if ((err = renamefile(vol, -1, p, temp, temp, adsp)) != AFP_OK) goto err_exchangefile; of_rename(vol, s_of, sdir, spath, curdir, temp); /* rename destination to source */ - if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK) + if ((err = renamefile(vol, -1, upath, p, spath, addp)) != AFP_OK) goto err_src_to_tmp; of_rename(vol, d_of, curdir, path->m_name, sdir, spath); /* rename temp to destination */ - if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK) + if ((err = renamefile(vol, -1, temp, upath, path->m_name, adsp)) != AFP_OK) goto err_dest_to_src; of_rename(vol, s_of, curdir, temp, curdir, path->m_name); /* id's need switching. src -> dest and dest -> src. * we need to re-stat() if it was a cross device copy. */ - if (sid) { - cnid_delete(vol->v_cdb, sid); - } - if (did) { - cnid_delete(vol->v_cdb, did); - } + if (sid) + cnid_delete(vol->v_cdb, sid); + if (did) + cnid_delete(vol->v_cdb, did); + if ((did && ( (crossdev && lstat( upath, &srcst) < 0) || cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0)) || @@ -2235,17 +2340,17 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U * properly. */ err_temp_to_dest: /* rename dest to temp */ - renamefile(vol, upath, temp, temp, adsp); + renamefile(vol, -1, upath, temp, temp, adsp); of_rename(vol, s_of, curdir, upath, curdir, temp); err_dest_to_src: /* rename source back to dest */ - renamefile(vol, p, upath, path->m_name, addp); + renamefile(vol, -1, p, upath, path->m_name, addp); of_rename(vol, d_of, sdir, spath, curdir, path->m_name); err_src_to_tmp: /* rename temp back to source */ - renamefile(vol, temp, p, spath, adsp); + renamefile(vol, -1, temp, p, spath, adsp); of_rename(vol, s_of, curdir, temp, sdir, spath); err_exchangefile: @@ -2256,5 +2361,11 @@ err_exchangefile: ad_close(addp, ADFLAGS_HF); } + struct dir *cached; + if ((cached = dircache_search_by_did(vol, sid)) != NULL) + (void)dir_remove(vol, cached); + if ((cached = dircache_search_by_did(vol, did)) != NULL) + (void)dir_remove(vol, cached); + return err; }