2 * $Id: file.c,v 1.92.2.2.2.20 2004-03-11 16:16:40 didg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
18 #else /* STDC_HEADERS */
22 #endif /* HAVE_STRCHR */
23 char *strchr (), *strrchr ();
26 #define memcpy(d,s,n) bcopy ((s), (d), (n))
27 #define memmove(d,s,n) bcopy ((s), (d), (n))
28 #endif /* ! HAVE_MEMCPY */
29 #endif /* STDC_HEADERS */
31 #include <atalk/adouble.h>
36 #include <atalk/logger.h>
37 #include <sys/param.h>
40 #include <atalk/afp.h>
41 #include <atalk/util.h>
42 #include <atalk/cnid.h>
43 #include "directory.h"
52 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
53 * field bytes subfield bytes
56 * ioFlFndrInfo 16 -> type 4 type field
57 * creator 4 creator field
58 * flags 2 finder flags:
60 * location 4 location in window
61 * folder 2 window that contains file
63 * ioFlXFndrInfo 16 -> iconID 2 icon id
65 * script 1 script system
67 * commentID 2 comment id
68 * putawayID 4 home directory id
71 const u_char ufinderi[] = {
72 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
73 0, 0, 0, 0, 0, 0, 0, 0,
74 0, 0, 0, 0, 0, 0, 0, 0,
75 0, 0, 0, 0, 0, 0, 0, 0
78 /* FIXME mpath : unix or mac name ? (for now it's mac name ) */
79 void *get_finderinfo(const char *mpath, struct adouble *adp, void *data)
84 if (adp && (ad_finder = ad_entry(adp, ADEID_FINDERI))) {
85 memcpy(data, ad_finder, 32);
88 memcpy(data, ufinderi, 32);
91 if ((!adp || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 ))
92 && (em = getextmap( mpath ))
94 memcpy(data, em->em_type, sizeof( em->em_type ));
95 memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator));
100 /* ---------------------
102 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8)
107 aint = strlen( name );
111 if (utf8_encoding()) {
112 /* but name is an utf8 mac name */
115 /* global static variable... */
117 if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
126 if (aint > MACFILELEN)
133 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
136 utf8 = vol->v_mac?htonl(vol->v_mac->kTextEncoding):0; /* htonl(utf8) */
137 memcpy(data, &utf8, sizeof(utf8));
138 data += sizeof(utf8);
141 memcpy(data, &temp, sizeof(temp));
142 data += sizeof(temp);
145 memcpy( data, src, aint );
155 * FIXME: PDINFO is UTF8 and doesn't need adp
157 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
158 (1 << FILPBIT_CDATE) |\
159 (1 << FILPBIT_MDATE) |\
160 (1 << FILPBIT_BDATE) |\
161 (1 << FILPBIT_FINFO) |\
162 (1 << FILPBIT_RFLEN) |\
163 (1 << FILPBIT_EXTRFLEN) |\
164 (1 << FILPBIT_PDINFO)))
166 /* -------------------------- */
167 u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st,
168 const cnid_t did, const char *upath, const int len)
172 #if AD_VERSION > AD_VERSION1
176 char stamp[ADEDLEN_PRIVSYN];
177 /* look in AD v2 header
178 * note inode and device are opaques and not in network order
181 && sizeof(dev_t) == ad_getentrylen(adp, ADEID_PRIVDEV)
182 && sizeof(ino_t) == ad_getentrylen(adp,ADEID_PRIVINO)
183 && sizeof(stamp) == ad_getentrylen(adp,ADEID_PRIVSYN)
184 && sizeof(cnid_t) == ad_getentrylen(adp, ADEID_DID)
185 && sizeof(cnid_t) == ad_getentrylen(adp, ADEID_PRIVID)
188 memcpy(&dev, ad_entry(adp, ADEID_PRIVDEV), sizeof(dev_t));
189 memcpy(&ino, ad_entry(adp, ADEID_PRIVINO), sizeof(ino_t));
190 memcpy(stamp, ad_entry(adp, ADEID_PRIVSYN), sizeof(stamp));
191 memcpy(&a_did, ad_entry(adp, ADEID_DID), sizeof(cnid_t));
193 if ( ( (vol->v_flags & AFPVOL_NODEV) || dev == st->st_dev)
194 && ino == st->st_ino && a_did == did
195 && !memcmp(vol->v_stamp, stamp, sizeof(stamp))) {
196 memcpy(&aint, ad_entry(adp, ADEID_PRIVID), sizeof(aint));
201 if (vol->v_cdb != NULL) {
202 aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
203 /* Throw errors if cnid_add fails. */
204 if (aint == CNID_INVALID) {
206 case CNID_ERR_CLOSE: /* the db is closed */
209 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
210 afp_errno = AFPERR_PARAM;
213 afp_errno = AFPERR_PARAM;
216 afp_errno = AFPERR_MISC;
220 #if AD_VERSION > AD_VERSION1
221 else if (adp && sizeof(dev_t) == ADEDLEN_PRIVDEV && sizeof(ino_t) == ADEDLEN_PRIVINO) {
222 /* update the ressource fork
223 * for a folder adp is always null
225 ad_setid(adp,(vol->v_flags & AFPVOL_NODEV)?0:st->st_dev, st->st_ino, aint, did, vol->v_stamp);
226 ad_flush(adp, ADFLAGS_HF);
233 /* -------------------------- */
234 int getmetadata(struct vol *vol,
236 struct path *path, struct dir *dir,
237 char *buf, int *buflen, struct adouble *adp, int attrbits )
239 char *data, *l_nameoff = NULL, *upath;
240 char *utf_nameoff = NULL;
245 u_char achar, fdType[4];
251 LOG(log_info, logtype_afpd, "begin getmetadata:");
254 upath = path->u_name;
259 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
260 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
261 || (bitmap & (1 << FILPBIT_FNUM))) {
263 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
267 path->m_name = utompath(vol, upath, id, utf8_encoding());
270 while ( bitmap != 0 ) {
271 while (( bitmap & 1 ) == 0 ) {
279 ad_getattr(adp, &ashort);
280 } else if (*upath == '.') {
281 ashort = htons(ATTRBIT_INVISIBLE);
285 /* FIXME do we want a visual clue if the file is read only
288 accessmode( ".", &ma, dir , NULL);
289 if ((ma.ma_user & AR_UWRITE)) {
290 accessmode( upath, &ma, dir , st);
291 if (!(ma.ma_user & AR_UWRITE)) {
292 attrbits |= ATTRBIT_NOWRITE;
297 ashort = htons(ntohs(ashort) | attrbits);
298 memcpy(data, &ashort, sizeof( ashort ));
299 data += sizeof( ashort );
303 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
304 data += sizeof( u_int32_t );
308 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
309 aint = AD_DATE_FROM_UNIX(st->st_mtime);
310 memcpy(data, &aint, sizeof( aint ));
311 data += sizeof( aint );
315 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
316 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
317 aint = AD_DATE_FROM_UNIX(st->st_mtime);
320 aint = AD_DATE_FROM_UNIX(st->st_mtime);
322 memcpy(data, &aint, sizeof( int ));
323 data += sizeof( int );
327 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
328 aint = AD_DATE_START;
329 memcpy(data, &aint, sizeof( int ));
330 data += sizeof( int );
334 get_finderinfo(path->m_name, adp, (char *)data);
336 if (*upath == '.') { /* make it invisible */
337 ashort = htons(FINDERINFO_INVISIBLE);
338 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
346 data += sizeof( u_int16_t );
350 memset(data, 0, sizeof(u_int16_t));
351 data += sizeof( u_int16_t );
355 memcpy(data, &id, sizeof( id ));
356 data += sizeof( id );
360 if (st->st_size > 0xffffffff)
363 aint = htonl( st->st_size );
364 memcpy(data, &aint, sizeof( aint ));
365 data += sizeof( aint );
370 if (adp->ad_rlen > 0xffffffff)
373 aint = htonl( adp->ad_rlen);
377 memcpy(data, &aint, sizeof( aint ));
378 data += sizeof( aint );
381 /* Current client needs ProDOS info block for this file.
382 Use simple heuristic and let the Mac "type" string tell
383 us what the PD file code should be. Everything gets a
384 subtype of 0x0000 unless the original value was hashed
385 to "pXYZ" when we created it. See IA, Ver 2.
386 <shirsch@adelphia.net> */
387 case FILPBIT_PDINFO :
388 if (afp_version >= 30) { /* UTF8 name */
389 utf8 = kTextEncodingUTF8;
391 data += sizeof( u_int16_t );
393 memcpy(data, &aint, sizeof( aint ));
394 data += sizeof( aint );
398 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
400 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
404 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
408 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
412 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
416 else if ( fdType[0] == 'p' ) {
418 ashort = (fdType[2] * 256) + fdType[3];
432 memcpy(data, &ashort, sizeof( ashort ));
433 data += sizeof( ashort );
434 memset(data, 0, sizeof( ashort ));
435 data += sizeof( ashort );
438 case FILPBIT_EXTDFLEN:
439 aint = htonl(st->st_size >> 32);
440 memcpy(data, &aint, sizeof( aint ));
441 data += sizeof( aint );
442 aint = htonl(st->st_size);
443 memcpy(data, &aint, sizeof( aint ));
444 data += sizeof( aint );
446 case FILPBIT_EXTRFLEN:
449 aint = htonl(adp->ad_rlen >> 32);
450 memcpy(data, &aint, sizeof( aint ));
451 data += sizeof( aint );
453 aint = htonl(adp->ad_rlen);
454 memcpy(data, &aint, sizeof( aint ));
455 data += sizeof( aint );
457 case FILPBIT_UNIXPR :
458 aint = htonl(st->st_uid);
459 memcpy( data, &aint, sizeof( aint ));
460 data += sizeof( aint );
461 aint = htonl(st->st_gid);
462 memcpy( data, &aint, sizeof( aint ));
463 data += sizeof( aint );
465 aint = htonl(st->st_mode);
466 memcpy( data, &aint, sizeof( aint ));
467 data += sizeof( aint );
469 accessmode( upath, &ma, dir , st);
471 *data++ = ma.ma_user;
472 *data++ = ma.ma_world;
473 *data++ = ma.ma_group;
474 *data++ = ma.ma_owner;
478 return( AFPERR_BITMAP );
484 ashort = htons( data - buf );
485 memcpy(l_nameoff, &ashort, sizeof( ashort ));
486 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
489 ashort = htons( data - buf );
490 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
491 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
493 *buflen = data - buf;
497 /* ----------------------- */
498 int getfilparams(struct vol *vol,
500 struct path *path, struct dir *dir,
501 char *buf, int *buflen )
503 struct adouble ad, *adp;
506 u_int16_t attrbits = 0;
511 LOG(log_info, logtype_default, "begin getfilparams:");
514 opened = PARAM_NEED_ADP(bitmap);
517 upath = path->u_name;
518 if ((of = of_findname(path))) {
520 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
521 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
523 ad_init(&ad, vol->v_adouble);
527 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
532 we need to check if the file is open by another process.
533 it's slow so we only do it if we have to:
534 - bitmap is requested.
535 - we don't already have the answer!
537 if ((bitmap & (1 << FILPBIT_ATTR))) {
538 if (!(attrbits & ATTRBIT_ROPEN)) {
539 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_ROPEN : 0;
540 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_ROPEN : 0;
542 if (!(attrbits & ATTRBIT_DOPEN)) {
543 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_DOPEN : 0;
544 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_DOPEN : 0;
549 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
551 ad_close( adp, ADFLAGS_HF );
554 LOG(log_info, logtype_afpd, "end getfilparams:");
560 /* ----------------------------- */
561 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
564 int ibuflen, *rbuflen;
566 struct adouble ad, *adp;
569 struct ofork *of = NULL;
571 int creatf, did, openf, retvalue = AFP_OK;
577 LOG(log_info, logtype_afpd, "begin afp_createfile:");
582 creatf = (unsigned char) *ibuf++;
584 memcpy(&vid, ibuf, sizeof( vid ));
585 ibuf += sizeof( vid );
587 if (NULL == ( vol = getvolbyvid( vid )) ) {
588 return( AFPERR_PARAM );
591 if (vol->v_flags & AFPVOL_RO)
594 memcpy(&did, ibuf, sizeof( did));
595 ibuf += sizeof( did );
597 if (NULL == ( dir = dirlookup( vol, did )) ) {
601 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
602 return get_afp_errno(AFPERR_PARAM);
605 if ( *s_path->m_name == '\0' ) {
606 return( AFPERR_BADTYPE );
609 upath = s_path->u_name;
610 if (0 != (ret = check_name(vol, upath)))
613 /* if upath is deleted we already in trouble anyway */
614 if ((of = of_findname(s_path))) {
617 ad_init(&ad, vol->v_adouble);
621 /* on a hard create, fail if file exists and is open */
624 openf = O_RDWR|O_CREAT|O_TRUNC;
626 /* on a soft create, if the file is open then ad_open won't fail
627 because open syscall is not called
632 openf = O_RDWR|O_CREAT|O_EXCL;
635 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
636 openf, 0666, adp) < 0 ) {
640 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
641 return ( AFPERR_NOOBJ );
643 return( AFPERR_EXIST );
645 return( AFPERR_ACCESS );
647 return( AFPERR_PARAM );
650 if ( ad_hfileno( adp ) == -1 ) {
651 /* on noadouble volumes, just creating the data fork is ok */
652 if (vol_noadouble(vol)) {
653 ad_close( adp, ADFLAGS_DF );
654 goto createfile_done;
656 /* FIXME with hard create on an existing file, we already
657 * corrupted the data file.
659 netatalk_unlink( upath );
660 ad_close( adp, ADFLAGS_DF );
661 return AFPERR_ACCESS;
664 path = s_path->m_name;
665 ad_setname(adp, path);
666 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
667 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
673 if (vol->v_flags & AFPVOL_DROPBOX) {
674 retvalue = matchfile2dirperms(upath, vol, did);
676 #endif /* DROPKLUDGE */
678 setvoltime(obj, vol );
681 LOG(log_info, logtype_afpd, "end afp_createfile");
687 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
690 int ibuflen, *rbuflen;
696 u_int16_t vid, bitmap;
699 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
705 memcpy(&vid, ibuf, sizeof( vid ));
706 ibuf += sizeof( vid );
707 if (NULL == ( vol = getvolbyvid( vid )) ) {
708 return( AFPERR_PARAM );
711 if (vol->v_flags & AFPVOL_RO)
714 memcpy(&did, ibuf, sizeof( did ));
715 ibuf += sizeof( did );
716 if (NULL == ( dir = dirlookup( vol, did )) ) {
717 return afp_errno; /* was AFPERR_NOOBJ */
720 memcpy(&bitmap, ibuf, sizeof( bitmap ));
721 bitmap = ntohs( bitmap );
722 ibuf += sizeof( bitmap );
724 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
725 return get_afp_errno(AFPERR_PARAM);
728 if (path_isadir(s_path)) {
729 return( AFPERR_BADTYPE ); /* it's a directory */
732 if ( s_path->st_errno != 0 ) {
733 return( AFPERR_NOOBJ );
736 if ((u_long)ibuf & 1 ) {
740 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
741 setvoltime(obj, vol );
745 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
752 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
755 extern struct path Cur_Path;
757 int setfilparams(struct vol *vol,
758 struct path *path, u_int16_t bitmap, char *buf )
760 struct adouble ad, *adp;
763 int bit = 0, isad = 1, err = AFP_OK;
765 u_char achar, *fdType, xyy[4];
766 u_int16_t ashort, bshort;
770 int change_mdate = 0;
771 int change_parent_mdate = 0;
777 LOG(log_info, logtype_afpd, "begin setfilparams:");
780 upath = path->u_name;
781 if ((of = of_findname(path))) {
784 ad_init(&ad, vol->v_adouble);
788 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
789 return AFPERR_ACCESS;
792 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
793 O_RDWR|O_CREAT, 0666, adp) < 0) {
794 /* for some things, we don't need an adouble header */
795 if (bitmap & ~(1<<FILPBIT_MDATE)) {
796 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
799 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
800 ad_setname(adp, path->m_name);
803 while ( bitmap != 0 ) {
804 while (( bitmap & 1 ) == 0 ) {
812 memcpy(&ashort, buf, sizeof( ashort ));
813 ad_getattr(adp, &bshort);
814 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
815 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
819 if ((ashort & htons(ATTRBIT_INVISIBLE)))
820 change_parent_mdate = 1;
821 ad_setattr(adp, bshort);
822 buf += sizeof( ashort );
827 memcpy(&aint, buf, sizeof(aint));
828 ad_setdate(adp, AD_DATE_CREATE, aint);
829 buf += sizeof( aint );
833 memcpy(&newdate, buf, sizeof( newdate ));
834 buf += sizeof( newdate );
839 memcpy(&aint, buf, sizeof(aint));
840 ad_setdate(adp, AD_DATE_BACKUP, aint);
841 buf += sizeof( aint );
847 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
849 ((em = getextmap( path->m_name )) &&
850 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
851 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
852 || ((em = getdefextmap()) &&
853 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
854 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
856 memcpy(buf, ufinderi, 8 );
859 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
863 case FILPBIT_UNIXPR :
864 /* Skip the UIG/GID, no way to set them from OSX clients */
865 buf += sizeof( aint );
866 buf += sizeof( aint );
869 change_parent_mdate = 1;
870 memcpy( &aint, buf, sizeof( aint ));
871 buf += sizeof( aint );
874 setfilunixmode(vol, path, aint);
876 /* Client needs to set the ProDOS file info for this file.
877 Use a defined string for TEXT to support crlf
878 translations and convert all else into pXYY per Inside
879 Appletalk. Always set the creator as "pdos". Changes
880 from original by Marsha Jackson. */
881 case FILPBIT_PDINFO :
882 if (afp_version < 30) { /* else it's UTF8 name */
885 /* Keep special case to support crlf translations */
886 if ((unsigned int) achar == 0x04) {
887 fdType = (u_char *)"TEXT";
890 xyy[0] = ( u_char ) 'p';
896 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
897 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
903 goto setfilparam_done;
911 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
912 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
916 ad_setdate(adp, AD_DATE_MODIFY, newdate);
917 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
922 ad_flush( adp, ADFLAGS_HF );
923 ad_close( adp, ADFLAGS_HF );
927 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
928 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
929 bitmap = 1<<FILPBIT_MDATE;
930 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
934 LOG(log_info, logtype_afpd, "end setfilparams:");
940 * renamefile and copyfile take the old and new unix pathnames
941 * and the new mac name.
943 * src the source path
944 * dst the dest filename in current dir
945 * newname the dest mac name
946 * adp adouble struct of src file, if open, or & zeroed one
949 int renamefile(vol, src, dst, newname, adp )
950 const struct vol *vol;
951 char *src, *dst, *newname;
954 char adsrc[ MAXPATHLEN + 1];
958 LOG(log_info, logtype_afpd, "begin renamefile:");
961 if ( unix_rename( src, dst ) < 0 ) {
964 return( AFPERR_NOOBJ );
967 return( AFPERR_ACCESS );
970 case EXDEV : /* Cross device move -- try copy */
971 /* NOTE: with open file it's an error because after the copy we will
972 * get two files, it's fixable for our process (eg reopen the new file, get the
973 * locks, and so on. But it doesn't solve the case with a second process
975 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
976 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
977 return AFPERR_OLOCK; /* little lie */
979 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname )) ) {
980 /* on error copyfile delete dest */
983 return deletefile(vol, src, 0);
985 return( AFPERR_PARAM );
989 strcpy( adsrc, vol->ad_path( src, 0 ));
991 if (unix_rename( adsrc, vol->ad_path( dst, 0 )) < 0 ) {
996 if (errno == ENOENT) {
999 if (stat(adsrc, &st)) /* source has no ressource fork, */
1002 /* We are here because :
1003 * -there's no dest folder.
1004 * -there's no .AppleDouble in the dest folder.
1005 * if we use the struct adouble passed in parameter it will not
1006 * create .AppleDouble if the file is already opened, so we
1007 * use a diff one, it's not a pb,ie it's not the same file, yet.
1009 ad_init(&ad, vol->v_adouble);
1010 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
1011 ad_close(&ad, ADFLAGS_HF);
1012 if (!unix_rename( adsrc, vol->ad_path( dst, 0 )) )
1017 else { /* it's something else, bail out */
1021 /* try to undo the data fork rename,
1022 * we know we are on the same device
1025 unix_rename( dst, src );
1026 /* return the first error */
1029 return AFPERR_NOOBJ;
1032 return AFPERR_ACCESS ;
1034 return AFPERR_VLOCK;
1036 return AFPERR_PARAM ;
1041 /* don't care if we can't open the newly renamed ressource fork
1043 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1044 ad_setname(adp, newname);
1045 ad_flush( adp, ADFLAGS_HF );
1046 ad_close( adp, ADFLAGS_HF );
1049 LOG(log_info, logtype_afpd, "end renamefile:");
1055 int copy_path_name(char *newname, char *ibuf)
1062 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1068 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1069 strncpy( newname, ibuf, plen );
1070 newname[ plen ] = '\0';
1071 if (strlen(newname) != plen) {
1072 /* there's \0 in newname, e.g. it's a pathname not
1080 memcpy(&hint, ibuf, sizeof(hint));
1081 ibuf += sizeof(hint);
1083 memcpy(&len16, ibuf, sizeof(len16));
1084 ibuf += sizeof(len16);
1085 plen = ntohs(len16);
1088 if (plen > AFPOBJ_TMPSIZ) {
1091 strncpy( newname, ibuf, plen );
1092 newname[ plen ] = '\0';
1093 if (strlen(newname) != plen) {
1102 /* -----------------------------------
1104 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1107 int ibuflen, *rbuflen;
1109 struct vol *s_vol, *d_vol;
1111 char *newname, *p, *upath;
1112 struct path *s_path;
1113 u_int32_t sdid, ddid;
1114 int err, retvalue = AFP_OK;
1115 u_int16_t svid, dvid;
1118 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1124 memcpy(&svid, ibuf, sizeof( svid ));
1125 ibuf += sizeof( svid );
1126 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1127 return( AFPERR_PARAM );
1130 memcpy(&sdid, ibuf, sizeof( sdid ));
1131 ibuf += sizeof( sdid );
1132 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1136 memcpy(&dvid, ibuf, sizeof( dvid ));
1137 ibuf += sizeof( dvid );
1138 memcpy(&ddid, ibuf, sizeof( ddid ));
1139 ibuf += sizeof( ddid );
1141 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1142 return get_afp_errno(AFPERR_PARAM);
1144 if ( path_isadir(s_path) ) {
1145 return( AFPERR_BADTYPE );
1148 /* don't allow copies when the file is open.
1149 * XXX: the spec only calls for read/deny write access.
1150 * however, copyfile doesn't have any of that info,
1151 * and locks need to stay coherent. as a result,
1152 * we just balk if the file is opened already. */
1154 newname = obj->newtmp;
1155 strcpy( newname, s_path->m_name );
1157 if (of_findname(s_path))
1158 return AFPERR_DENYCONF;
1160 p = ctoupath( s_vol, curdir, newname );
1162 return AFPERR_PARAM;
1166 /* FIXME svid != dvid && dvid's user can't read svid */
1168 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1169 return( AFPERR_PARAM );
1172 if (d_vol->v_flags & AFPVOL_RO)
1173 return AFPERR_VLOCK;
1175 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1179 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1180 return get_afp_errno(AFPERR_NOOBJ);
1182 if ( *s_path->m_name != '\0' ) {
1184 return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1186 path_error(s_path, AFPERR_PARAM);
1189 /* one of the handful of places that knows about the path type */
1190 if (copy_path_name(newname, ibuf) < 0) {
1191 return( AFPERR_PARAM );
1193 /* newname is always only a filename so curdir *is* its
1196 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1197 return( AFPERR_PARAM );
1199 if ( (err = copyfile(s_vol, d_vol, p, upath , newname)) < 0 ) {
1205 if (vol->v_flags & AFPVOL_DROPBOX) {
1206 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1208 #endif /* DROPKLUDGE */
1210 setvoltime(obj, d_vol );
1213 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1219 /* ----------------------- */
1220 static __inline__ int copy_all(const int dfd, const void *buf,
1226 LOG(log_info, logtype_afpd, "begin copy_all:");
1229 while (buflen > 0) {
1230 if ((cc = write(dfd, buf, buflen)) < 0) {
1242 LOG(log_info, logtype_afpd, "end copy_all:");
1248 /* -------------------------- */
1249 static int copy_fd(int dfd, int sfd)
1255 #ifdef SENDFILE_FLAVOR_LINUX
1259 #define BUF 128*1024*1024
1261 if (fstat(sfd, &st) == 0) {
1264 if ( offset >= st.st_size) {
1267 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1268 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1271 case EINVAL: /* there's no guarantee that all fs support sendfile */
1280 lseek(sfd, offset, SEEK_SET);
1284 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1291 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1298 /* ----------------------------------
1299 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1300 * because we are doing it elsewhere.
1302 int copyfile(s_vol, d_vol, src, dst, newname )
1303 const struct vol *s_vol, *d_vol;
1304 char *src, *dst, *newname;
1306 struct adouble ads, add;
1310 int noadouble = vol_noadouble(d_vol);
1314 LOG(log_info, logtype_afpd, "begin copyfile:");
1317 ad_init(&ads, s_vol->v_adouble);
1318 ad_init(&add, d_vol->v_adouble);
1319 adflags = ADFLAGS_DF;
1321 adflags |= ADFLAGS_HF;
1324 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1329 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1331 ad_close( &ads, adflags );
1332 if (EEXIST != ret_err) {
1333 deletefile(d_vol, dst, 0);
1336 return AFPERR_EXIST;
1338 if (ad_hfileno(&ads) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1339 /* copy the data fork */
1340 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1343 /* Now, reopen destination file */
1347 ad_close( &ads, adflags );
1349 if (ad_close( &add, adflags ) <0) {
1350 deletefile(d_vol, dst, 0);
1355 ad_init(&add, d_vol->v_adouble);
1356 if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
1361 if (!ret_err && newname) {
1362 ad_setname(&add, newname);
1365 ad_flush( &add, adflags );
1366 if (ad_close( &add, adflags ) <0) {
1370 deletefile(d_vol, dst, 0);
1373 /* set dest modification date to src date */
1374 if (!stat(src, &st)) {
1377 ut.actime = ut.modtime = st.st_mtime;
1382 LOG(log_info, logtype_afpd, "end copyfile:");
1386 switch ( ret_err ) {
1392 return AFPERR_DFULL;
1394 return AFPERR_NOOBJ;
1396 return AFPERR_ACCESS;
1398 return AFPERR_VLOCK;
1400 return AFPERR_PARAM;
1404 /* -----------------------------------
1405 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1406 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1408 when deletefile is called we don't have lock on it, file is closed (for us)
1409 untrue if called by renamefile
1411 ad_open always try to open file RDWR first and ad_lock takes care of
1412 WRITE lock on read only file.
1414 int deletefile( vol, file, checkAttrib )
1415 const struct vol *vol;
1420 int adflags, err = AFP_OK;
1423 LOG(log_info, logtype_afpd, "begin deletefile:");
1426 /* try to open both forks at once */
1427 adflags = ADFLAGS_DF|ADFLAGS_HF;
1429 ad_init(&ad, vol->v_adouble); /* OK */
1430 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1433 if (adflags == ADFLAGS_DF)
1434 return AFPERR_NOOBJ;
1436 /* that failed. now try to open just the data fork */
1437 adflags = ADFLAGS_DF;
1441 return AFPERR_ACCESS;
1443 return AFPERR_VLOCK;
1445 return( AFPERR_PARAM );
1448 break; /* from the while */
1451 * Does kFPDeleteInhibitBit (bit 8) set?
1453 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1456 ad_getattr(&ad, &bshort);
1457 if ((bshort & htons(ATTRBIT_NODELETE))) {
1458 ad_close( &ad, adflags );
1459 return(AFPERR_OLOCK);
1463 if ((adflags & ADFLAGS_HF) ) {
1464 /* FIXME we have a pb here because we want to know if a file is open
1465 * there's a 'priority inversion' if you can't open the ressource fork RW
1466 * you can delete it if it's open because you can't get a write lock.
1468 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1471 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1473 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1474 ad_close( &ad, adflags );
1475 return( AFPERR_BUSY );
1479 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1482 else if (!(err = netatalk_unlink( vol->ad_path( file, ADFLAGS_HF)) ) &&
1483 !(err = netatalk_unlink( file )) ) {
1485 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1487 cnid_delete(vol->v_cdb, id);
1491 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1494 LOG(log_info, logtype_afpd, "end deletefile:");
1500 /* ------------------------------------ */
1501 /* return a file id */
1502 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1505 int ibuflen, *rbuflen;
1514 struct path *s_path;
1517 LOG(log_info, logtype_afpd, "begin afp_createid:");
1524 memcpy(&vid, ibuf, sizeof(vid));
1525 ibuf += sizeof(vid);
1527 if (NULL == ( vol = getvolbyvid( vid )) ) {
1528 return( AFPERR_PARAM);
1531 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1535 if (vol->v_flags & AFPVOL_RO)
1536 return AFPERR_VLOCK;
1538 memcpy(&did, ibuf, sizeof( did ));
1539 ibuf += sizeof(did);
1541 if (NULL == ( dir = dirlookup( vol, did )) ) {
1542 return afp_errno; /* was AFPERR_PARAM */
1545 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1546 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1549 if ( path_isadir(s_path) ) {
1550 return( AFPERR_BADTYPE );
1553 upath = s_path->u_name;
1554 switch (s_path->st_errno) {
1556 break; /* success */
1559 return AFPERR_ACCESS;
1561 return AFPERR_NOOBJ;
1563 return AFPERR_PARAM;
1566 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1567 memcpy(rbuf, &id, sizeof(id));
1568 *rbuflen = sizeof(id);
1569 return AFPERR_EXISTID;
1572 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1573 memcpy(rbuf, &id, sizeof(id));
1574 *rbuflen = sizeof(id);
1579 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1585 reenumerate_id(const struct vol *vol, char *name, cnid_t did)
1595 if (vol->v_cdb == NULL) {
1598 if (NULL == ( dp = opendir( name)) ) {
1602 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
1603 if (NULL == check_dirent(vol, de->d_name))
1606 if ( stat(de->d_name, &st)<0 )
1609 /* update or add to cnid */
1610 aint = cnid_add(vol->v_cdb, &st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1612 #if AD_VERSION > AD_VERSION1
1613 if (aint != CNID_INVALID && !S_ISDIR(st.st_mode)) {
1614 ad_init(&ad, 0); /* OK */
1615 if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, &ad ) < 0 ) {
1619 ad_setid(&ad,(vol->v_flags & AFPVOL_NODEV)?0:st.st_dev, st.st_ino, aint, did, vol->v_stamp);
1620 ad_flush(&ad, ADFLAGS_HF);
1621 ad_close(&ad, ADFLAGS_HF);
1624 #endif /* AD_VERSION > AD_VERSION1 */
1633 /* ------------------------------
1634 resolve a file id */
1635 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1638 int ibuflen, *rbuflen;
1644 int err, buflen, retry=0;
1646 u_int16_t vid, bitmap;
1648 static char buffer[12 + MAXPATHLEN + 1];
1649 int len = 12 + MAXPATHLEN + 1;
1652 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1658 memcpy(&vid, ibuf, sizeof(vid));
1659 ibuf += sizeof(vid);
1661 if (NULL == ( vol = getvolbyvid( vid )) ) {
1662 return( AFPERR_PARAM);
1665 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1669 memcpy(&id, ibuf, sizeof( id ));
1674 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1675 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1678 if (NULL == ( dir = dirlookup( vol, id )) ) {
1679 return AFPERR_NOID; /* idem AFPERR_PARAM */
1681 path.u_name = upath;
1682 if (movecwd(vol, dir) < 0) {
1686 return AFPERR_ACCESS;
1690 return AFPERR_PARAM;
1694 if ( of_stat(&path) < 0 ) {
1695 if ( errno == ENOENT && !retry) {
1696 /* cnid db is out of sync, reenumerate the directory and updated ids */
1697 reenumerate_id(vol, ".", id);
1705 return AFPERR_ACCESS;
1709 return AFPERR_PARAM;
1713 /* directories are bad */
1714 if (S_ISDIR(path.st.st_mode))
1715 return AFPERR_BADTYPE;
1717 memcpy(&bitmap, ibuf, sizeof(bitmap));
1718 bitmap = ntohs( bitmap );
1719 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1722 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1723 rbuf + sizeof(bitmap), &buflen))) {
1726 *rbuflen = buflen + sizeof(bitmap);
1727 memcpy(rbuf, ibuf, sizeof(bitmap));
1730 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1736 /* ------------------------------ */
1737 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1740 int ibuflen, *rbuflen;
1750 static char buffer[12 + MAXPATHLEN + 1];
1751 int len = 12 + MAXPATHLEN + 1;
1754 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1760 memcpy(&vid, ibuf, sizeof(vid));
1761 ibuf += sizeof(vid);
1763 if (NULL == ( vol = getvolbyvid( vid )) ) {
1764 return( AFPERR_PARAM);
1767 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1771 if (vol->v_flags & AFPVOL_RO)
1772 return AFPERR_VLOCK;
1774 memcpy(&id, ibuf, sizeof( id ));
1778 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1782 if (NULL == ( dir = dirlookup( vol, id )) ) {
1783 return( AFPERR_PARAM );
1787 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1791 return AFPERR_ACCESS;
1793 /* still try to delete the id */
1797 return AFPERR_PARAM;
1800 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1801 return AFPERR_BADTYPE;
1803 if (cnid_delete(vol->v_cdb, fileid)) {
1806 return AFPERR_VLOCK;
1809 return AFPERR_ACCESS;
1811 return AFPERR_PARAM;
1816 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1822 #define APPLETEMP ".AppleTempXXXXXX"
1824 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1827 int ibuflen, *rbuflen;
1829 struct stat srcst, destst;
1831 struct dir *dir, *sdir;
1832 char *spath, temp[17], *p;
1833 char *supath, *upath;
1838 struct adouble *adsp;
1839 struct adouble *addp;
1849 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1855 memcpy(&vid, ibuf, sizeof(vid));
1856 ibuf += sizeof(vid);
1858 if (NULL == ( vol = getvolbyvid( vid )) ) {
1859 return( AFPERR_PARAM);
1862 if (vol->v_flags & AFPVOL_RO)
1863 return AFPERR_VLOCK;
1865 /* source and destination dids */
1866 memcpy(&sid, ibuf, sizeof(sid));
1867 ibuf += sizeof(sid);
1868 memcpy(&did, ibuf, sizeof(did));
1869 ibuf += sizeof(did);
1872 if (NULL == (dir = dirlookup( vol, sid )) ) {
1873 return afp_errno; /* was AFPERR_PARAM */
1876 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1877 return get_afp_errno(AFPERR_NOOBJ);
1880 if ( path_isadir(path) ) {
1881 return( AFPERR_BADTYPE ); /* it's a dir */
1884 upath = path->u_name;
1885 switch (path->st_errno) {
1892 return AFPERR_ACCESS;
1894 return AFPERR_PARAM;
1896 ad_init(&ads, vol->v_adouble);
1898 if ((s_of = of_findname(path))) {
1899 /* reuse struct adouble so it won't break locks */
1902 memcpy(&srcst, &path->st, sizeof(struct stat));
1903 /* save some stuff */
1905 spath = obj->oldtmp;
1906 supath = obj->newtmp;
1907 strcpy(spath, path->m_name);
1908 strcpy(supath, upath); /* this is for the cnid changing */
1909 p = absupath( vol, sdir, upath);
1911 /* pathname too long */
1912 return AFPERR_PARAM ;
1915 /* look for the source cnid. if it doesn't exist, don't worry about
1917 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
1919 if (NULL == ( dir = dirlookup( vol, did )) ) {
1920 return afp_errno; /* was AFPERR_PARAM */
1923 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1924 return get_afp_errno(AFPERR_NOOBJ);
1927 if ( path_isadir(path) ) {
1928 return( AFPERR_BADTYPE );
1931 /* FPExchangeFiles is the only call that can return the SameObj
1933 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1934 return AFPERR_SAMEOBJ;
1936 switch (path->st_errno) {
1943 return AFPERR_ACCESS;
1945 return AFPERR_PARAM;
1947 ad_init(&add, vol->v_adouble);
1949 if ((d_of = of_findname( path))) {
1950 /* reuse struct adouble so it won't break locks */
1953 memcpy(&destst, &path->st, sizeof(struct stat));
1955 /* they are not on the same device and at least one is open
1957 crossdev = (srcst.st_dev != destst.st_dev);
1958 if ((d_of || s_of) && crossdev)
1961 upath = path->u_name;
1962 /* look for destination id. */
1963 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
1965 /* construct a temp name.
1966 * NOTE: the temp file will be in the dest file's directory. it
1967 * will also be inaccessible from AFP. */
1968 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1972 /* now, quickly rename the file. we error if we can't. */
1973 if ((err = renamefile(vol, p, temp, temp, adsp)) < 0)
1974 goto err_exchangefile;
1975 of_rename(vol, s_of, sdir, spath, curdir, temp);
1977 /* rename destination to source */
1978 if ((err = renamefile(vol, upath, p, spath, addp)) < 0)
1979 goto err_src_to_tmp;
1980 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1982 /* rename temp to destination */
1983 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) < 0)
1984 goto err_dest_to_src;
1985 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1987 /* id's need switching. src -> dest and dest -> src.
1988 * we need to re-stat() if it was a cross device copy.
1991 cnid_delete(vol->v_cdb, sid);
1994 cnid_delete(vol->v_cdb, did);
1996 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
1997 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
1999 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2000 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2005 err = AFPERR_ACCESS;
2010 goto err_temp_to_dest;
2014 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2020 /* all this stuff is so that we can unwind a failed operation
2023 /* rename dest to temp */
2024 renamefile(vol, upath, temp, temp, adsp);
2025 of_rename(vol, s_of, curdir, upath, curdir, temp);
2028 /* rename source back to dest */
2029 renamefile(vol, p, upath, path->m_name, addp);
2030 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2033 /* rename temp back to source */
2034 renamefile(vol, temp, p, spath, adsp);
2035 of_rename(vol, s_of, curdir, temp, sdir, spath);