2 * $Id: file.c,v 1.92.2.2.2.11 2004-02-06 13:39:51 bfernhomberg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
16 #endif /* HAVE_UNISTD_H */
21 #else /* STDC_HEADERS */
25 #endif /* HAVE_STRCHR */
26 char *strchr (), *strrchr ();
28 #define memcpy(d,s,n) bcopy ((s), (d), (n))
29 #define memmove(d,s,n) bcopy ((s), (d), (n))
30 #endif /* ! HAVE_MEMCPY */
31 #endif /* STDC_HEADERS */
36 #endif /* HAVE_FCNTL_H */
41 #include <atalk/logger.h>
42 #include <sys/types.h>
44 #include <sys/param.h>
47 #include <netatalk/endian.h>
48 #include <atalk/adouble.h>
49 #include <atalk/afp.h>
50 #include <atalk/util.h>
51 #include <atalk/cnid.h>
52 #include "directory.h"
61 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
62 * field bytes subfield bytes
65 * ioFlFndrInfo 16 -> type 4 type field
66 * creator 4 creator field
67 * flags 2 finder flags:
69 * location 4 location in window
70 * folder 2 window that contains file
72 * ioFlXFndrInfo 16 -> iconID 2 icon id
74 * script 1 script system
76 * commentID 2 comment id
77 * putawayID 4 home directory id
80 const u_char ufinderi[] = {
81 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
82 0, 0, 0, 0, 0, 0, 0, 0,
83 0, 0, 0, 0, 0, 0, 0, 0,
84 0, 0, 0, 0, 0, 0, 0, 0
87 /* FIXME mpath : unix or mac name ? (for now it's mac name ) */
88 void *get_finderinfo(const char *mpath, struct adouble *adp, void *data)
93 if (adp && (ad_finder = ad_entry(adp, ADEID_FINDERI))) {
94 memcpy(data, ad_finder, 32);
97 memcpy(data, ufinderi, 32);
100 if ((!adp || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 ))
101 && (em = getextmap( mpath ))
103 memcpy(data, em->em_type, sizeof( em->em_type ));
104 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
109 /* ---------------------
111 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8)
116 aint = strlen( name );
120 if (utf8_encoding()) {
121 /* but name is an utf8 mac name */
124 /* global static variable... */
126 if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
135 if (aint > MACFILELEN)
142 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
145 utf8 = vol->v_mac?htonl(vol->v_mac->kTextEncoding):0; /* htonl(utf8) */
146 memcpy(data, &utf8, sizeof(utf8));
147 data += sizeof(utf8);
150 memcpy(data, &temp, sizeof(temp));
151 data += sizeof(temp);
154 memcpy( data, src, aint );
164 * FIXME: PDINFO is UTF8 and doesn't need adp
166 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
167 (1 << FILPBIT_CDATE) |\
168 (1 << FILPBIT_MDATE) |\
169 (1 << FILPBIT_BDATE) |\
170 (1 << FILPBIT_FINFO) |\
171 (1 << FILPBIT_RFLEN) |\
172 (1 << FILPBIT_EXTRFLEN) |\
173 (1 << FILPBIT_PDINFO)))
175 /* -------------------------- */
176 u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st,
177 const cnid_t did, const char *upath, const int len)
181 #if AD_VERSION > AD_VERSION1
185 char stamp[ADEDLEN_PRIVSYN];
186 /* look in AD v2 header
187 * note inode and device are opaques and not in network order
189 if (adp && sizeof(dev_t) == ad_getentrylen(adp, ADEID_PRIVDEV)) {
190 memcpy(&dev, ad_entry(adp, ADEID_PRIVDEV), sizeof(dev_t));
191 if ( sizeof(ino_t) == ad_getentrylen(adp,ADEID_PRIVINO)) {
192 memcpy(&ino, ad_entry(adp, ADEID_PRIVINO), sizeof(ino_t));
193 if (sizeof(stamp) == ad_getentrylen(adp,ADEID_PRIVSYN)) {
194 memcpy(stamp, ad_entry(adp, ADEID_PRIVSYN), sizeof(stamp));
195 if (sizeof(cnid_t) == ad_getentrylen(adp, ADEID_DID)) {
196 memcpy(&a_did, ad_entry(adp, ADEID_DID), sizeof(cnid_t));
198 if ( ((vol->v_flags & AFPVOL_NODEV) || dev == st->st_dev)
199 && ino == st->st_ino && a_did == did &&
200 !memcmp(vol->v_stamp, stamp, sizeof(stamp)) &&
201 (sizeof(cnid_t) == ad_getentrylen(adp, ADEID_PRIVID)) )
203 memcpy(&aint, ad_entry(adp, ADEID_PRIVID), sizeof(aint));
211 if (vol->v_cdb != NULL) {
212 aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
213 /* Throw errors if cnid_add fails. */
214 if (aint == CNID_INVALID) {
216 case CNID_ERR_CLOSE: /* the db is closed */
219 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
220 afp_errno = AFPERR_PARAM;
223 afp_errno = AFPERR_PARAM;
226 afp_errno = AFPERR_MISC;
230 #if AD_VERSION > AD_VERSION1
231 else if (adp && sizeof(dev_t) == ADEDLEN_PRIVDEV && sizeof(ino_t) == ADEDLEN_PRIVINO) {
232 /* update the ressource fork
233 * for a folder adp is always null
235 ad_setid(adp,(vol->v_flags & AFPVOL_NODEV)?0:st->st_dev, st->st_ino, aint, did, vol->v_stamp);
236 ad_flush(adp, ADFLAGS_HF);
243 /* -------------------------- */
244 int getmetadata(struct vol *vol,
246 struct path *path, struct dir *dir,
247 char *buf, int *buflen, struct adouble *adp, int attrbits )
249 char *data, *l_nameoff = NULL, *upath;
250 char *utf_nameoff = NULL;
255 u_char achar, fdType[4];
261 LOG(log_info, logtype_afpd, "begin getmetadata:");
264 upath = path->u_name;
269 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
270 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
271 || (bitmap & (1 << FILPBIT_FNUM))) {
273 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
277 path->m_name = utompath(vol, upath, id, utf8_encoding());
280 while ( bitmap != 0 ) {
281 while (( bitmap & 1 ) == 0 ) {
289 ad_getattr(adp, &ashort);
290 } else if (*upath == '.') {
291 ashort = htons(ATTRBIT_INVISIBLE);
295 /* FIXME do we want a visual clue if the file is read only
298 accessmode( ".", &ma, dir , NULL);
299 if ((ma.ma_user & AR_UWRITE)) {
300 accessmode( upath, &ma, dir , st);
301 if (!(ma.ma_user & AR_UWRITE)) {
302 attrbits |= ATTRBIT_NOWRITE;
307 ashort = htons(ntohs(ashort) | attrbits);
308 memcpy(data, &ashort, sizeof( ashort ));
309 data += sizeof( ashort );
313 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
314 data += sizeof( u_int32_t );
318 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
319 aint = AD_DATE_FROM_UNIX(st->st_mtime);
320 memcpy(data, &aint, sizeof( aint ));
321 data += sizeof( aint );
325 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
326 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
327 aint = AD_DATE_FROM_UNIX(st->st_mtime);
330 aint = AD_DATE_FROM_UNIX(st->st_mtime);
332 memcpy(data, &aint, sizeof( int ));
333 data += sizeof( int );
337 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
338 aint = AD_DATE_START;
339 memcpy(data, &aint, sizeof( int ));
340 data += sizeof( int );
344 get_finderinfo(path->m_name, adp, (char *)data);
346 if (*upath == '.') { /* make it invisible */
347 ashort = htons(FINDERINFO_INVISIBLE);
348 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
356 data += sizeof( u_int16_t );
360 memset(data, 0, sizeof(u_int16_t));
361 data += sizeof( u_int16_t );
365 memcpy(data, &id, sizeof( id ));
366 data += sizeof( id );
370 if (st->st_size > 0xffffffff)
373 aint = htonl( st->st_size );
374 memcpy(data, &aint, sizeof( aint ));
375 data += sizeof( aint );
380 if (adp->ad_rlen > 0xffffffff)
383 aint = htonl( adp->ad_rlen);
387 memcpy(data, &aint, sizeof( aint ));
388 data += sizeof( aint );
391 /* Current client needs ProDOS info block for this file.
392 Use simple heuristic and let the Mac "type" string tell
393 us what the PD file code should be. Everything gets a
394 subtype of 0x0000 unless the original value was hashed
395 to "pXYZ" when we created it. See IA, Ver 2.
396 <shirsch@adelphia.net> */
397 case FILPBIT_PDINFO :
398 if (afp_version >= 30) { /* UTF8 name */
399 utf8 = kTextEncodingUTF8;
401 data += sizeof( u_int16_t );
403 memcpy(data, &aint, sizeof( aint ));
404 data += sizeof( aint );
408 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
410 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
414 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
418 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
422 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
426 else if ( fdType[0] == 'p' ) {
428 ashort = (fdType[2] * 256) + fdType[3];
442 memcpy(data, &ashort, sizeof( ashort ));
443 data += sizeof( ashort );
444 memset(data, 0, sizeof( ashort ));
445 data += sizeof( ashort );
448 case FILPBIT_EXTDFLEN:
449 aint = htonl(st->st_size >> 32);
450 memcpy(data, &aint, sizeof( aint ));
451 data += sizeof( aint );
452 aint = htonl(st->st_size);
453 memcpy(data, &aint, sizeof( aint ));
454 data += sizeof( aint );
456 case FILPBIT_EXTRFLEN:
459 aint = htonl(adp->ad_rlen >> 32);
460 memcpy(data, &aint, sizeof( aint ));
461 data += sizeof( aint );
463 aint = htonl(adp->ad_rlen);
464 memcpy(data, &aint, sizeof( aint ));
465 data += sizeof( aint );
467 case FILPBIT_UNIXPR :
468 aint = htonl(st->st_uid);
469 memcpy( data, &aint, sizeof( aint ));
470 data += sizeof( aint );
471 aint = htonl(st->st_gid);
472 memcpy( data, &aint, sizeof( aint ));
473 data += sizeof( aint );
475 aint = htonl(st->st_mode);
476 memcpy( data, &aint, sizeof( aint ));
477 data += sizeof( aint );
479 accessmode( upath, &ma, dir , st);
481 *data++ = ma.ma_user;
482 *data++ = ma.ma_world;
483 *data++ = ma.ma_group;
484 *data++ = ma.ma_owner;
488 return( AFPERR_BITMAP );
494 ashort = htons( data - buf );
495 memcpy(l_nameoff, &ashort, sizeof( ashort ));
496 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
499 ashort = htons( data - buf );
500 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
501 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
503 *buflen = data - buf;
507 /* ----------------------- */
508 int getfilparams(struct vol *vol,
510 struct path *path, struct dir *dir,
511 char *buf, int *buflen )
513 struct adouble ad, *adp;
516 u_int16_t attrbits = 0;
521 LOG(log_info, logtype_default, "begin getfilparams:");
524 opened = PARAM_NEED_ADP(bitmap);
527 upath = path->u_name;
528 if ((of = of_findname(path))) {
530 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
531 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
533 ad_init(&ad, vol->v_adouble);
537 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
542 we need to check if the file is open by another process.
543 it's slow so we only do it if we have to:
544 - bitmap is requested.
545 - we don't already have the answer!
547 if ((bitmap & (1 << FILPBIT_ATTR))) {
548 if (!(attrbits & ATTRBIT_ROPEN)) {
550 if (!(attrbits & ATTRBIT_DOPEN)) {
555 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
557 ad_close( adp, ADFLAGS_HF );
560 LOG(log_info, logtype_afpd, "end getfilparams:");
566 /* ----------------------------- */
567 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
570 int ibuflen, *rbuflen;
572 struct adouble ad, *adp;
575 struct ofork *of = NULL;
577 int creatf, did, openf, retvalue = AFP_OK;
583 LOG(log_info, logtype_afpd, "begin afp_createfile:");
588 creatf = (unsigned char) *ibuf++;
590 memcpy(&vid, ibuf, sizeof( vid ));
591 ibuf += sizeof( vid );
593 if (NULL == ( vol = getvolbyvid( vid )) ) {
594 return( AFPERR_PARAM );
597 if (vol->v_flags & AFPVOL_RO)
600 memcpy(&did, ibuf, sizeof( did));
601 ibuf += sizeof( did );
603 if (NULL == ( dir = dirlookup( vol, did )) ) {
607 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
608 return get_afp_errno(AFPERR_PARAM);
611 if ( *s_path->m_name == '\0' ) {
612 return( AFPERR_BADTYPE );
615 upath = s_path->u_name;
616 if (0 != (ret = check_name(vol, upath)))
619 /* if upath is deleted we already in trouble anyway */
620 if ((of = of_findname(s_path))) {
623 ad_init(&ad, vol->v_adouble);
627 /* on a hard create, fail if file exists and is open */
630 openf = O_RDWR|O_CREAT|O_TRUNC;
632 /* on a soft create, if the file is open then ad_open won't fail
633 because open syscall is not called
638 openf = O_RDWR|O_CREAT|O_EXCL;
641 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
642 openf, 0666, adp) < 0 ) {
646 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
647 return ( AFPERR_NOOBJ );
649 return( AFPERR_EXIST );
651 return( AFPERR_ACCESS );
653 return( AFPERR_PARAM );
656 if ( ad_hfileno( adp ) == -1 ) {
657 /* on noadouble volumes, just creating the data fork is ok */
658 if (vol_noadouble(vol)) {
659 ad_close( adp, ADFLAGS_DF );
660 goto createfile_done;
662 /* FIXME with hard create on an existing file, we already
663 * corrupted the data file.
665 netatalk_unlink( upath );
666 ad_close( adp, ADFLAGS_DF );
667 return AFPERR_ACCESS;
670 path = s_path->m_name;
671 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
672 memcpy(ad_entry( adp, ADEID_NAME ), path,
673 ad_getentrylen( adp, ADEID_NAME ));
674 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
675 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
681 if (vol->v_flags & AFPVOL_DROPBOX) {
682 retvalue = matchfile2dirperms(upath, vol, did);
684 #endif /* DROPKLUDGE */
686 setvoltime(obj, vol );
689 LOG(log_info, logtype_afpd, "end afp_createfile");
695 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
698 int ibuflen, *rbuflen;
704 u_int16_t vid, bitmap;
707 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
713 memcpy(&vid, ibuf, sizeof( vid ));
714 ibuf += sizeof( vid );
715 if (NULL == ( vol = getvolbyvid( vid )) ) {
716 return( AFPERR_PARAM );
719 if (vol->v_flags & AFPVOL_RO)
722 memcpy(&did, ibuf, sizeof( did ));
723 ibuf += sizeof( did );
724 if (NULL == ( dir = dirlookup( vol, did )) ) {
725 return afp_errno; /* was AFPERR_NOOBJ */
728 memcpy(&bitmap, ibuf, sizeof( bitmap ));
729 bitmap = ntohs( bitmap );
730 ibuf += sizeof( bitmap );
732 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
733 return get_afp_errno(AFPERR_PARAM);
736 if (path_isadir(s_path)) {
737 return( AFPERR_BADTYPE ); /* it's a directory */
740 if ( s_path->st_errno != 0 ) {
741 return( AFPERR_NOOBJ );
744 if ((u_long)ibuf & 1 ) {
748 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
749 setvoltime(obj, vol );
753 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
760 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
763 extern struct path Cur_Path;
765 int setfilparams(struct vol *vol,
766 struct path *path, u_int16_t bitmap, char *buf )
768 struct adouble ad, *adp;
771 int bit = 0, isad = 1, err = AFP_OK;
773 u_char achar, *fdType, xyy[4];
774 u_int16_t ashort, bshort;
778 int change_mdate = 0;
779 int change_parent_mdate = 0;
785 LOG(log_info, logtype_afpd, "begin setfilparams:");
788 upath = path->u_name;
789 if ((of = of_findname(path))) {
792 ad_init(&ad, vol->v_adouble);
796 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
797 return AFPERR_ACCESS;
800 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
801 O_RDWR|O_CREAT, 0666, adp) < 0) {
802 /* for some things, we don't need an adouble header */
803 if (bitmap & ~(1<<FILPBIT_MDATE)) {
804 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
807 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
808 ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
809 memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
810 ad_getentrylen( adp, ADEID_NAME ));
813 while ( bitmap != 0 ) {
814 while (( bitmap & 1 ) == 0 ) {
822 memcpy(&ashort, buf, sizeof( ashort ));
823 ad_getattr(adp, &bshort);
824 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
825 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
829 if ((ashort & htons(ATTRBIT_INVISIBLE)))
830 change_parent_mdate = 1;
831 ad_setattr(adp, bshort);
832 buf += sizeof( ashort );
837 memcpy(&aint, buf, sizeof(aint));
838 ad_setdate(adp, AD_DATE_CREATE, aint);
839 buf += sizeof( aint );
843 memcpy(&newdate, buf, sizeof( newdate ));
844 buf += sizeof( newdate );
849 memcpy(&aint, buf, sizeof(aint));
850 ad_setdate(adp, AD_DATE_BACKUP, aint);
851 buf += sizeof( aint );
857 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
859 ((em = getextmap( path->m_name )) &&
860 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
861 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
862 || ((em = getdefextmap()) &&
863 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
864 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
866 memcpy(buf, ufinderi, 8 );
869 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
873 case FILPBIT_UNIXPR :
874 /* Skip the UIG/GID, no way to set them from OSX clients */
875 buf += sizeof( aint );
876 buf += sizeof( aint );
879 change_parent_mdate = 1;
880 memcpy( &aint, buf, sizeof( aint ));
881 buf += sizeof( aint );
884 setfilemode(path, aint);
886 /* Client needs to set the ProDOS file info for this file.
887 Use a defined string for TEXT to support crlf
888 translations and convert all else into pXYY per Inside
889 Appletalk. Always set the creator as "pdos". Changes
890 from original by Marsha Jackson. */
891 case FILPBIT_PDINFO :
892 if (afp_version < 30) { /* else it's UTF8 name */
895 /* Keep special case to support crlf translations */
896 if ((unsigned int) achar == 0x04) {
897 fdType = (u_char *)"TEXT";
900 xyy[0] = ( u_char ) 'p';
906 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
907 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
913 goto setfilparam_done;
921 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
922 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
926 ad_setdate(adp, AD_DATE_MODIFY, newdate);
927 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
932 ad_flush( adp, ADFLAGS_HF );
933 ad_close( adp, ADFLAGS_HF );
937 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
938 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
939 bitmap = 1<<FILPBIT_MDATE;
940 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
944 LOG(log_info, logtype_afpd, "end setfilparams:");
950 * renamefile and copyfile take the old and new unix pathnames
951 * and the new mac name.
953 * src the source path
954 * dst the dest filename in current dir
955 * newname the dest mac name
956 * adp adouble struct of src file, if open, or & zeroed one
959 int renamefile(src, dst, newname, noadouble, adp )
960 char *src, *dst, *newname;
964 char adsrc[ MAXPATHLEN + 1];
969 LOG(log_info, logtype_afpd, "begin renamefile:");
972 if ( unix_rename( src, dst ) < 0 ) {
975 return( AFPERR_NOOBJ );
978 return( AFPERR_ACCESS );
981 case EXDEV : /* Cross device move -- try copy */
982 /* NOTE: with open file it's an error because after the copy we will
983 * get two files, it's fixable for our process (eg reopen the new file, get the
984 * locks, and so on. But it doesn't solve the case with a second process
986 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
987 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
988 return AFPERR_OLOCK; /* little lie */
990 if (AFP_OK != ( rc = copyfile(src, dst, newname, noadouble )) ) {
991 /* on error copyfile delete dest */
994 return deletefile(NULL, src, 0);
996 return( AFPERR_PARAM );
1000 strcpy( adsrc, ad_path( src, 0 ));
1002 if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
1007 if (errno == ENOENT) {
1010 if (stat(adsrc, &st)) /* source has no ressource fork, */
1013 /* We are here because :
1014 * -there's no dest folder.
1015 * -there's no .AppleDouble in the dest folder.
1016 * if we use the struct adouble passed in parameter it will not
1017 * create .AppleDouble if the file is already opened, so we
1018 * use a diff one, it's not a pb,ie it's not the same file, yet.
1020 ad_init(&ad, AD_VERSION); /* FIXME */
1021 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
1022 ad_close(&ad, ADFLAGS_HF);
1023 if (!unix_rename( adsrc, ad_path( dst, 0 )) )
1028 else { /* it's something else, bail out */
1032 /* try to undo the data fork rename,
1033 * we know we are on the same device
1036 unix_rename( dst, src );
1037 /* return the first error */
1040 return AFPERR_NOOBJ;
1043 return AFPERR_ACCESS ;
1045 return AFPERR_VLOCK;
1047 return AFPERR_PARAM ;
1052 /* don't care if we can't open the newly renamed ressource fork
1054 if ( !ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1055 len = strlen( newname );
1056 ad_setentrylen( adp, ADEID_NAME, len );
1057 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
1058 ad_flush( adp, ADFLAGS_HF );
1059 ad_close( adp, ADFLAGS_HF );
1062 LOG(log_info, logtype_afpd, "end renamefile:");
1068 int copy_path_name(char *newname, char *ibuf)
1075 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1081 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1082 strncpy( newname, ibuf, plen );
1083 newname[ plen ] = '\0';
1084 if (strlen(newname) != plen) {
1085 /* there's \0 in newname, e.g. it's a pathname not
1093 memcpy(&hint, ibuf, sizeof(hint));
1094 ibuf += sizeof(hint);
1096 memcpy(&len16, ibuf, sizeof(len16));
1097 ibuf += sizeof(len16);
1098 plen = ntohs(len16);
1101 if (plen > AFPOBJ_TMPSIZ) {
1104 strncpy( newname, ibuf, plen );
1105 newname[ plen ] = '\0';
1106 if (strlen(newname) != plen) {
1115 /* -----------------------------------
1117 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1120 int ibuflen, *rbuflen;
1124 char *newname, *p, *upath;
1125 struct path *s_path;
1126 u_int32_t sdid, ddid;
1127 int err, retvalue = AFP_OK;
1128 u_int16_t svid, dvid;
1131 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1137 memcpy(&svid, ibuf, sizeof( svid ));
1138 ibuf += sizeof( svid );
1139 if (NULL == ( vol = getvolbyvid( svid )) ) {
1140 return( AFPERR_PARAM );
1143 memcpy(&sdid, ibuf, sizeof( sdid ));
1144 ibuf += sizeof( sdid );
1145 if (NULL == ( dir = dirlookup( vol, sdid )) ) {
1149 memcpy(&dvid, ibuf, sizeof( dvid ));
1150 ibuf += sizeof( dvid );
1151 memcpy(&ddid, ibuf, sizeof( ddid ));
1152 ibuf += sizeof( ddid );
1154 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1155 return get_afp_errno(AFPERR_PARAM);
1157 if ( path_isadir(s_path) ) {
1158 return( AFPERR_BADTYPE );
1161 /* don't allow copies when the file is open.
1162 * XXX: the spec only calls for read/deny write access.
1163 * however, copyfile doesn't have any of that info,
1164 * and locks need to stay coherent. as a result,
1165 * we just balk if the file is opened already. */
1167 newname = obj->newtmp;
1168 strcpy( newname, s_path->m_name );
1170 if (of_findname(s_path))
1171 return AFPERR_DENYCONF;
1173 p = ctoupath( vol, curdir, newname );
1175 return AFPERR_PARAM;
1179 /* FIXME svid != dvid && dvid's user can't read svid */
1181 if (NULL == ( vol = getvolbyvid( dvid )) ) {
1182 return( AFPERR_PARAM );
1185 if (vol->v_flags & AFPVOL_RO)
1186 return AFPERR_VLOCK;
1188 if (NULL == ( dir = dirlookup( vol, ddid )) ) {
1192 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1193 return get_afp_errno(AFPERR_NOOBJ);
1195 if ( *s_path->m_name != '\0' ) {
1197 return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1199 path_error(s_path, AFPERR_PARAM);
1202 /* one of the handful of places that knows about the path type */
1203 if (copy_path_name(newname, ibuf) < 0) {
1204 return( AFPERR_PARAM );
1206 /* newname is always only a filename so curdir *is* its
1209 if (NULL == (upath = mtoupath(vol, newname, curdir->d_did, utf8_encoding()))) {
1210 return( AFPERR_PARAM );
1212 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1218 if (vol->v_flags & AFPVOL_DROPBOX) {
1219 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1221 #endif /* DROPKLUDGE */
1223 setvoltime(obj, vol );
1226 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1233 static __inline__ int copy_all(const int dfd, const void *buf,
1239 LOG(log_info, logtype_afpd, "begin copy_all:");
1242 while (buflen > 0) {
1243 if ((cc = write(dfd, buf, buflen)) < 0) {
1250 return AFPERR_DFULL;
1252 return AFPERR_VLOCK;
1254 return AFPERR_PARAM;
1261 LOG(log_info, logtype_afpd, "end copy_all:");
1267 /* -------------------------- */
1268 static int copy_fd(int dfd, int sfd)
1274 #ifdef SENDFILE_FLAVOR_LINUX
1278 #define BUF 128*1024*1024
1280 if (fstat(sfd, &st) == 0) {
1283 if ( offset >= st.st_size) {
1286 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1287 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1290 case EINVAL: /* there's no guarantee that all fs support sendfile */
1295 return AFPERR_DFULL;
1297 return AFPERR_VLOCK;
1299 return AFPERR_PARAM;
1305 lseek(sfd, offset, SEEK_SET);
1309 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1316 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1322 /* ----------------------------------
1323 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1324 * because we are doing it elsewhere.
1326 int copyfile(src, dst, newname, noadouble )
1327 char *src, *dst, *newname;
1328 const int noadouble;
1330 struct adouble ads, add;
1331 int len, err = AFP_OK;
1336 LOG(log_info, logtype_afpd, "begin copyfile:");
1339 ad_init(&ads, 0); /* OK */
1340 ad_init(&add, 0); /* FIXME */
1341 adflags = ADFLAGS_DF;
1343 adflags |= ADFLAGS_HF;
1346 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1349 return( AFPERR_NOOBJ );
1351 return( AFPERR_ACCESS );
1353 return( AFPERR_PARAM );
1356 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1357 ad_close( &ads, adflags );
1358 if (EEXIST != (err = errno)) {
1359 deletefile(NULL, dst, 0);
1363 return AFPERR_EXIST;
1365 return( AFPERR_NOOBJ );
1367 return( AFPERR_ACCESS );
1369 return AFPERR_VLOCK;
1371 return( AFPERR_PARAM );
1374 if (ad_hfileno(&ads) == -1 || AFP_OK == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1375 /* copy the data fork */
1376 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1379 /* Now, reopen destination file */
1381 if (ad_close( &add, adflags ) <0) {
1382 deletefile(NULL, dst, 0);
1383 return AFPERR_PARAM; /* FIXME */
1386 if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
1387 ad_close( &ads, adflags );
1388 deletefile(NULL, dst, 0);
1391 return( AFPERR_NOOBJ );
1393 return( AFPERR_ACCESS );
1395 return AFPERR_VLOCK;
1397 return( AFPERR_PARAM );
1403 len = strlen( newname );
1404 ad_setentrylen( &add, ADEID_NAME, len );
1405 memcpy(ad_entry( &add, ADEID_NAME ), newname, len );
1408 ad_close( &ads, adflags );
1409 ad_flush( &add, adflags );
1410 if (ad_close( &add, adflags ) <0) {
1413 if (err != AFP_OK) {
1414 deletefile(NULL, dst, 0);
1417 return( AFPERR_NOOBJ );
1419 return( AFPERR_ACCESS );
1421 return( AFPERR_PARAM );
1425 /* set dest modification date to src date */
1426 if (!stat(src, &st)) {
1429 ut.actime = ut.modtime = st.st_mtime;
1434 LOG(log_info, logtype_afpd, "end copyfile:");
1441 /* -----------------------------------
1442 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1443 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1445 when deletefile is called we don't have lock on it, file is closed (for us)
1446 untrue if called by renamefile
1448 ad_open always try to open file RDWR first and ad_lock takes care of
1449 WRITE lock on read only file.
1451 int deletefile( vol, file, checkAttrib )
1457 int adflags, err = AFP_OK;
1460 LOG(log_info, logtype_afpd, "begin deletefile:");
1463 /* try to open both forks at once */
1464 adflags = ADFLAGS_DF|ADFLAGS_HF;
1466 ad_init(&ad, 0); /* OK */
1467 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1470 if (adflags == ADFLAGS_DF)
1471 return AFPERR_NOOBJ;
1473 /* that failed. now try to open just the data fork */
1474 adflags = ADFLAGS_DF;
1478 return AFPERR_ACCESS;
1480 return AFPERR_VLOCK;
1482 return( AFPERR_PARAM );
1485 break; /* from the while */
1488 * Does kFPDeleteInhibitBit (bit 8) set?
1490 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1493 ad_getattr(&ad, &bshort);
1494 if ((bshort & htons(ATTRBIT_NODELETE))) {
1495 ad_close( &ad, adflags );
1496 return(AFPERR_OLOCK);
1500 if ((adflags & ADFLAGS_HF) ) {
1501 /* FIXME we have a pb here because we want to know if a file is open
1502 * there's a 'priority inversion' if you can't open the ressource fork RW
1503 * you can delete it if it's open because you can't get a write lock.
1505 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1508 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1510 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1511 ad_close( &ad, adflags );
1512 return( AFPERR_BUSY );
1516 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1519 else if (!(err = netatalk_unlink( ad_path( file, ADFLAGS_HF)) ) &&
1520 !(err = netatalk_unlink( file )) ) {
1522 if (vol && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1524 cnid_delete(vol->v_cdb, id);
1528 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1531 LOG(log_info, logtype_afpd, "end deletefile:");
1537 /* ------------------------------------ */
1538 /* return a file id */
1539 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1542 int ibuflen, *rbuflen;
1551 struct path *s_path;
1554 LOG(log_info, logtype_afpd, "begin afp_createid:");
1561 memcpy(&vid, ibuf, sizeof(vid));
1562 ibuf += sizeof(vid);
1564 if (NULL == ( vol = getvolbyvid( vid )) ) {
1565 return( AFPERR_PARAM);
1568 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1572 if (vol->v_flags & AFPVOL_RO)
1573 return AFPERR_VLOCK;
1575 memcpy(&did, ibuf, sizeof( did ));
1576 ibuf += sizeof(did);
1578 if (NULL == ( dir = dirlookup( vol, did )) ) {
1579 return afp_errno; /* was AFPERR_PARAM */
1582 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1583 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1586 if ( path_isadir(s_path) ) {
1587 return( AFPERR_BADTYPE );
1590 upath = s_path->u_name;
1591 switch (s_path->st_errno) {
1593 break; /* success */
1596 return AFPERR_ACCESS;
1598 return AFPERR_NOOBJ;
1600 return AFPERR_PARAM;
1603 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1604 memcpy(rbuf, &id, sizeof(id));
1605 *rbuflen = sizeof(id);
1606 return AFPERR_EXISTID;
1609 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1610 memcpy(rbuf, &id, sizeof(id));
1611 *rbuflen = sizeof(id);
1616 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1622 reenumerate_id(const struct vol *vol, char *name, cnid_t did)
1632 if (vol->v_cdb != NULL) {
1635 if (NULL == ( dp = opendir( name)) ) {
1639 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
1640 if (NULL == check_dirent(vol, de->d_name))
1643 if ( stat(de->d_name, &st)<0 )
1646 /* update or add to cnid */
1647 aint = cnid_add(vol->v_cdb, &st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1649 #if AD_VERSION > AD_VERSION1
1650 if (aint != CNID_INVALID && !S_ISDIR(st.st_mode)) {
1651 ad_init(&ad, 0); /* OK */
1652 if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, &ad ) < 0 ) {
1656 ad_setid(&ad,(vol->v_flags & AFPVOL_NODEV)?0:st.st_dev, st.st_ino, aint, did, vol->v_stamp);
1657 ad_flush(&ad, ADFLAGS_HF);
1658 ad_close(&ad, ADFLAGS_HF);
1661 #endif /* AD_VERSION > AD_VERSION1 */
1670 /* ------------------------------
1671 resolve a file id */
1672 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1675 int ibuflen, *rbuflen;
1681 int err, buflen, retry=0;
1683 u_int16_t vid, bitmap;
1685 static char buffer[12 + MAXPATHLEN + 1];
1686 int len = 12 + MAXPATHLEN + 1;
1689 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1695 memcpy(&vid, ibuf, sizeof(vid));
1696 ibuf += sizeof(vid);
1698 if (NULL == ( vol = getvolbyvid( vid )) ) {
1699 return( AFPERR_PARAM);
1702 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1706 memcpy(&id, ibuf, sizeof( id ));
1711 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1712 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1715 if (NULL == ( dir = dirlookup( vol, id )) ) {
1716 return AFPERR_NOID; /* idem AFPERR_PARAM */
1718 path.u_name = upath;
1719 if (movecwd(vol, dir) < 0) {
1723 return AFPERR_ACCESS;
1727 return AFPERR_PARAM;
1731 if ( of_stat(&path) < 0 ) {
1732 if ( errno == ENOENT && !retry) {
1733 /* cnid db is out of sync, reenumerate the directory and updated ids */
1734 reenumerate_id(vol, ".", id);
1742 return AFPERR_ACCESS;
1746 return AFPERR_PARAM;
1750 /* directories are bad */
1751 if (S_ISDIR(path.st.st_mode))
1752 return AFPERR_BADTYPE;
1754 memcpy(&bitmap, ibuf, sizeof(bitmap));
1755 bitmap = ntohs( bitmap );
1756 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1759 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1760 rbuf + sizeof(bitmap), &buflen))) {
1763 *rbuflen = buflen + sizeof(bitmap);
1764 memcpy(rbuf, ibuf, sizeof(bitmap));
1767 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1773 /* ------------------------------ */
1774 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1777 int ibuflen, *rbuflen;
1787 static char buffer[12 + MAXPATHLEN + 1];
1788 int len = 12 + MAXPATHLEN + 1;
1791 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1797 memcpy(&vid, ibuf, sizeof(vid));
1798 ibuf += sizeof(vid);
1800 if (NULL == ( vol = getvolbyvid( vid )) ) {
1801 return( AFPERR_PARAM);
1804 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1808 if (vol->v_flags & AFPVOL_RO)
1809 return AFPERR_VLOCK;
1811 memcpy(&id, ibuf, sizeof( id ));
1815 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1819 if (NULL == ( dir = dirlookup( vol, id )) ) {
1820 return( AFPERR_PARAM );
1824 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1828 return AFPERR_ACCESS;
1830 /* still try to delete the id */
1834 return AFPERR_PARAM;
1837 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1838 return AFPERR_BADTYPE;
1840 if (cnid_delete(vol->v_cdb, fileid)) {
1843 return AFPERR_VLOCK;
1846 return AFPERR_ACCESS;
1848 return AFPERR_PARAM;
1853 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1859 #define APPLETEMP ".AppleTempXXXXXX"
1861 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1864 int ibuflen, *rbuflen;
1866 struct stat srcst, destst;
1868 struct dir *dir, *sdir;
1869 char *spath, temp[17], *p;
1870 char *supath, *upath;
1875 struct adouble *adsp;
1876 struct adouble *addp;
1886 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1892 memcpy(&vid, ibuf, sizeof(vid));
1893 ibuf += sizeof(vid);
1895 if (NULL == ( vol = getvolbyvid( vid )) ) {
1896 return( AFPERR_PARAM);
1899 if (vol->v_flags & AFPVOL_RO)
1900 return AFPERR_VLOCK;
1902 /* source and destination dids */
1903 memcpy(&sid, ibuf, sizeof(sid));
1904 ibuf += sizeof(sid);
1905 memcpy(&did, ibuf, sizeof(did));
1906 ibuf += sizeof(did);
1909 if (NULL == (dir = dirlookup( vol, sid )) ) {
1910 return afp_errno; /* was AFPERR_PARAM */
1913 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1914 return get_afp_errno(AFPERR_NOOBJ);
1917 if ( path_isadir(path) ) {
1918 return( AFPERR_BADTYPE ); /* it's a dir */
1921 upath = path->u_name;
1922 switch (path->st_errno) {
1929 return AFPERR_ACCESS;
1931 return AFPERR_PARAM;
1933 ad_init(&ads, vol->v_adouble);
1935 if ((s_of = of_findname(path))) {
1936 /* reuse struct adouble so it won't break locks */
1939 memcpy(&srcst, &path->st, sizeof(struct stat));
1940 /* save some stuff */
1942 spath = obj->oldtmp;
1943 supath = obj->newtmp;
1944 strcpy(spath, path->m_name);
1945 strcpy(supath, upath); /* this is for the cnid changing */
1946 p = absupath( vol, sdir, upath);
1948 /* pathname too long */
1949 return AFPERR_PARAM ;
1952 /* look for the source cnid. if it doesn't exist, don't worry about
1954 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
1956 if (NULL == ( dir = dirlookup( vol, did )) ) {
1957 return afp_errno; /* was AFPERR_PARAM */
1960 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1961 return get_afp_errno(AFPERR_NOOBJ);
1964 if ( path_isadir(path) ) {
1965 return( AFPERR_BADTYPE );
1968 /* FPExchangeFiles is the only call that can return the SameObj
1970 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1971 return AFPERR_SAMEOBJ;
1973 switch (path->st_errno) {
1980 return AFPERR_ACCESS;
1982 return AFPERR_PARAM;
1984 ad_init(&add, vol->v_adouble);
1986 if ((d_of = of_findname( path))) {
1987 /* reuse struct adouble so it won't break locks */
1990 memcpy(&destst, &path->st, sizeof(struct stat));
1992 /* they are not on the same device and at least one is open
1994 crossdev = (srcst.st_dev != destst.st_dev);
1995 if ((d_of || s_of) && crossdev)
1998 upath = path->u_name;
1999 /* look for destination id. */
2000 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2002 /* construct a temp name.
2003 * NOTE: the temp file will be in the dest file's directory. it
2004 * will also be inaccessible from AFP. */
2005 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2009 /* now, quickly rename the file. we error if we can't. */
2010 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
2011 goto err_exchangefile;
2012 of_rename(vol, s_of, sdir, spath, curdir, temp);
2014 /* rename destination to source */
2015 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
2016 goto err_src_to_tmp;
2017 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2019 /* rename temp to destination */
2020 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
2021 goto err_dest_to_src;
2022 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2024 /* id's need switching. src -> dest and dest -> src.
2025 * we need to re-stat() if it was a cross device copy.
2028 cnid_delete(vol->v_cdb, sid);
2031 cnid_delete(vol->v_cdb, did);
2033 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2034 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2036 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2037 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2042 err = AFPERR_ACCESS;
2047 goto err_temp_to_dest;
2051 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2057 /* all this stuff is so that we can unwind a failed operation
2060 /* rename dest to temp */
2061 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
2062 of_rename(vol, s_of, curdir, upath, curdir, temp);
2065 /* rename source back to dest */
2066 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
2067 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2070 /* rename temp back to source */
2071 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
2072 of_rename(vol, s_of, curdir, temp, sdir, spath);