2 * $Id: file.c,v 1.92.2.2.2.17 2004-03-04 23:57:20 bfernhomberg 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
180 if (adp && sizeof(dev_t) == ad_getentrylen(adp, ADEID_PRIVDEV)) {
181 memcpy(&dev, ad_entry(adp, ADEID_PRIVDEV), sizeof(dev_t));
182 if ( sizeof(ino_t) == ad_getentrylen(adp,ADEID_PRIVINO)) {
183 memcpy(&ino, ad_entry(adp, ADEID_PRIVINO), sizeof(ino_t));
184 if (sizeof(stamp) == ad_getentrylen(adp,ADEID_PRIVSYN)) {
185 memcpy(stamp, ad_entry(adp, ADEID_PRIVSYN), sizeof(stamp));
186 if (sizeof(cnid_t) == ad_getentrylen(adp, ADEID_DID)) {
187 memcpy(&a_did, ad_entry(adp, ADEID_DID), sizeof(cnid_t));
189 if ( ((vol->v_flags & AFPVOL_NODEV) || dev == st->st_dev)
190 && ino == st->st_ino && a_did == did &&
191 !memcmp(vol->v_stamp, stamp, sizeof(stamp)) &&
192 (sizeof(cnid_t) == ad_getentrylen(adp, ADEID_PRIVID)) )
194 memcpy(&aint, ad_entry(adp, ADEID_PRIVID), sizeof(aint));
202 if (vol->v_cdb != NULL) {
203 aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
204 /* Throw errors if cnid_add fails. */
205 if (aint == CNID_INVALID) {
207 case CNID_ERR_CLOSE: /* the db is closed */
210 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
211 afp_errno = AFPERR_PARAM;
214 afp_errno = AFPERR_PARAM;
217 afp_errno = AFPERR_MISC;
221 #if AD_VERSION > AD_VERSION1
222 else if (adp && sizeof(dev_t) == ADEDLEN_PRIVDEV && sizeof(ino_t) == ADEDLEN_PRIVINO) {
223 /* update the ressource fork
224 * for a folder adp is always null
226 ad_setid(adp,(vol->v_flags & AFPVOL_NODEV)?0:st->st_dev, st->st_ino, aint, did, vol->v_stamp);
227 ad_flush(adp, ADFLAGS_HF);
234 /* -------------------------- */
235 int getmetadata(struct vol *vol,
237 struct path *path, struct dir *dir,
238 char *buf, int *buflen, struct adouble *adp, int attrbits )
240 char *data, *l_nameoff = NULL, *upath;
241 char *utf_nameoff = NULL;
246 u_char achar, fdType[4];
252 LOG(log_info, logtype_afpd, "begin getmetadata:");
255 upath = path->u_name;
260 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
261 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
262 || (bitmap & (1 << FILPBIT_FNUM))) {
264 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
268 path->m_name = utompath(vol, upath, id, utf8_encoding());
271 while ( bitmap != 0 ) {
272 while (( bitmap & 1 ) == 0 ) {
280 ad_getattr(adp, &ashort);
281 } else if (*upath == '.') {
282 ashort = htons(ATTRBIT_INVISIBLE);
286 /* FIXME do we want a visual clue if the file is read only
289 accessmode( ".", &ma, dir , NULL);
290 if ((ma.ma_user & AR_UWRITE)) {
291 accessmode( upath, &ma, dir , st);
292 if (!(ma.ma_user & AR_UWRITE)) {
293 attrbits |= ATTRBIT_NOWRITE;
298 ashort = htons(ntohs(ashort) | attrbits);
299 memcpy(data, &ashort, sizeof( ashort ));
300 data += sizeof( ashort );
304 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
305 data += sizeof( u_int32_t );
309 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
310 aint = AD_DATE_FROM_UNIX(st->st_mtime);
311 memcpy(data, &aint, sizeof( aint ));
312 data += sizeof( aint );
316 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
317 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
318 aint = AD_DATE_FROM_UNIX(st->st_mtime);
321 aint = AD_DATE_FROM_UNIX(st->st_mtime);
323 memcpy(data, &aint, sizeof( int ));
324 data += sizeof( int );
328 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
329 aint = AD_DATE_START;
330 memcpy(data, &aint, sizeof( int ));
331 data += sizeof( int );
335 get_finderinfo(path->m_name, adp, (char *)data);
337 if (*upath == '.') { /* make it invisible */
338 ashort = htons(FINDERINFO_INVISIBLE);
339 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
347 data += sizeof( u_int16_t );
351 memset(data, 0, sizeof(u_int16_t));
352 data += sizeof( u_int16_t );
356 memcpy(data, &id, sizeof( id ));
357 data += sizeof( id );
361 if (st->st_size > 0xffffffff)
364 aint = htonl( st->st_size );
365 memcpy(data, &aint, sizeof( aint ));
366 data += sizeof( aint );
371 if (adp->ad_rlen > 0xffffffff)
374 aint = htonl( adp->ad_rlen);
378 memcpy(data, &aint, sizeof( aint ));
379 data += sizeof( aint );
382 /* Current client needs ProDOS info block for this file.
383 Use simple heuristic and let the Mac "type" string tell
384 us what the PD file code should be. Everything gets a
385 subtype of 0x0000 unless the original value was hashed
386 to "pXYZ" when we created it. See IA, Ver 2.
387 <shirsch@adelphia.net> */
388 case FILPBIT_PDINFO :
389 if (afp_version >= 30) { /* UTF8 name */
390 utf8 = kTextEncodingUTF8;
392 data += sizeof( u_int16_t );
394 memcpy(data, &aint, sizeof( aint ));
395 data += sizeof( aint );
399 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
401 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
405 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
409 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
413 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
417 else if ( fdType[0] == 'p' ) {
419 ashort = (fdType[2] * 256) + fdType[3];
433 memcpy(data, &ashort, sizeof( ashort ));
434 data += sizeof( ashort );
435 memset(data, 0, sizeof( ashort ));
436 data += sizeof( ashort );
439 case FILPBIT_EXTDFLEN:
440 aint = htonl(st->st_size >> 32);
441 memcpy(data, &aint, sizeof( aint ));
442 data += sizeof( aint );
443 aint = htonl(st->st_size);
444 memcpy(data, &aint, sizeof( aint ));
445 data += sizeof( aint );
447 case FILPBIT_EXTRFLEN:
450 aint = htonl(adp->ad_rlen >> 32);
451 memcpy(data, &aint, sizeof( aint ));
452 data += sizeof( aint );
454 aint = htonl(adp->ad_rlen);
455 memcpy(data, &aint, sizeof( aint ));
456 data += sizeof( aint );
458 case FILPBIT_UNIXPR :
459 aint = htonl(st->st_uid);
460 memcpy( data, &aint, sizeof( aint ));
461 data += sizeof( aint );
462 aint = htonl(st->st_gid);
463 memcpy( data, &aint, sizeof( aint ));
464 data += sizeof( aint );
466 aint = htonl(st->st_mode);
467 memcpy( data, &aint, sizeof( aint ));
468 data += sizeof( aint );
470 accessmode( upath, &ma, dir , st);
472 *data++ = ma.ma_user;
473 *data++ = ma.ma_world;
474 *data++ = ma.ma_group;
475 *data++ = ma.ma_owner;
479 return( AFPERR_BITMAP );
485 ashort = htons( data - buf );
486 memcpy(l_nameoff, &ashort, sizeof( ashort ));
487 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
490 ashort = htons( data - buf );
491 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
492 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
494 *buflen = data - buf;
498 /* ----------------------- */
499 int getfilparams(struct vol *vol,
501 struct path *path, struct dir *dir,
502 char *buf, int *buflen )
504 struct adouble ad, *adp;
507 u_int16_t attrbits = 0;
512 LOG(log_info, logtype_default, "begin getfilparams:");
515 opened = PARAM_NEED_ADP(bitmap);
518 upath = path->u_name;
519 if ((of = of_findname(path))) {
521 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
522 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
524 ad_init(&ad, vol->v_adouble);
528 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
533 we need to check if the file is open by another process.
534 it's slow so we only do it if we have to:
535 - bitmap is requested.
536 - we don't already have the answer!
538 if ((bitmap & (1 << FILPBIT_ATTR))) {
539 if (!(attrbits & ATTRBIT_ROPEN)) {
540 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_ROPEN : 0;
541 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_ROPEN : 0;
543 if (!(attrbits & ATTRBIT_DOPEN)) {
544 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_DOPEN : 0;
545 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_DOPEN : 0;
550 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
552 ad_close( adp, ADFLAGS_HF );
555 LOG(log_info, logtype_afpd, "end getfilparams:");
561 /* ----------------------------- */
562 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
565 int ibuflen, *rbuflen;
567 struct adouble ad, *adp;
570 struct ofork *of = NULL;
572 int creatf, did, openf, retvalue = AFP_OK;
578 LOG(log_info, logtype_afpd, "begin afp_createfile:");
583 creatf = (unsigned char) *ibuf++;
585 memcpy(&vid, ibuf, sizeof( vid ));
586 ibuf += sizeof( vid );
588 if (NULL == ( vol = getvolbyvid( vid )) ) {
589 return( AFPERR_PARAM );
592 if (vol->v_flags & AFPVOL_RO)
595 memcpy(&did, ibuf, sizeof( did));
596 ibuf += sizeof( did );
598 if (NULL == ( dir = dirlookup( vol, did )) ) {
602 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
603 return get_afp_errno(AFPERR_PARAM);
606 if ( *s_path->m_name == '\0' ) {
607 return( AFPERR_BADTYPE );
610 upath = s_path->u_name;
611 if (0 != (ret = check_name(vol, upath)))
614 /* if upath is deleted we already in trouble anyway */
615 if ((of = of_findname(s_path))) {
618 ad_init(&ad, vol->v_adouble);
622 /* on a hard create, fail if file exists and is open */
625 openf = O_RDWR|O_CREAT|O_TRUNC;
627 /* on a soft create, if the file is open then ad_open won't fail
628 because open syscall is not called
633 openf = O_RDWR|O_CREAT|O_EXCL;
636 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
637 openf, 0666, adp) < 0 ) {
641 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
642 return ( AFPERR_NOOBJ );
644 return( AFPERR_EXIST );
646 return( AFPERR_ACCESS );
648 return( AFPERR_PARAM );
651 if ( ad_hfileno( adp ) == -1 ) {
652 /* on noadouble volumes, just creating the data fork is ok */
653 if (vol_noadouble(vol)) {
654 ad_close( adp, ADFLAGS_DF );
655 goto createfile_done;
657 /* FIXME with hard create on an existing file, we already
658 * corrupted the data file.
660 netatalk_unlink( upath );
661 ad_close( adp, ADFLAGS_DF );
662 return AFPERR_ACCESS;
665 path = s_path->m_name;
666 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
667 memcpy(ad_entry( adp, ADEID_NAME ), path,
668 ad_getentrylen( adp, ADEID_NAME ));
669 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
670 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
676 if (vol->v_flags & AFPVOL_DROPBOX) {
677 retvalue = matchfile2dirperms(upath, vol, did);
679 #endif /* DROPKLUDGE */
681 setvoltime(obj, vol );
684 LOG(log_info, logtype_afpd, "end afp_createfile");
690 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
693 int ibuflen, *rbuflen;
699 u_int16_t vid, bitmap;
702 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
708 memcpy(&vid, ibuf, sizeof( vid ));
709 ibuf += sizeof( vid );
710 if (NULL == ( vol = getvolbyvid( vid )) ) {
711 return( AFPERR_PARAM );
714 if (vol->v_flags & AFPVOL_RO)
717 memcpy(&did, ibuf, sizeof( did ));
718 ibuf += sizeof( did );
719 if (NULL == ( dir = dirlookup( vol, did )) ) {
720 return afp_errno; /* was AFPERR_NOOBJ */
723 memcpy(&bitmap, ibuf, sizeof( bitmap ));
724 bitmap = ntohs( bitmap );
725 ibuf += sizeof( bitmap );
727 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
728 return get_afp_errno(AFPERR_PARAM);
731 if (path_isadir(s_path)) {
732 return( AFPERR_BADTYPE ); /* it's a directory */
735 if ( s_path->st_errno != 0 ) {
736 return( AFPERR_NOOBJ );
739 if ((u_long)ibuf & 1 ) {
743 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
744 setvoltime(obj, vol );
748 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
755 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
758 extern struct path Cur_Path;
760 int setfilparams(struct vol *vol,
761 struct path *path, u_int16_t bitmap, char *buf )
763 struct adouble ad, *adp;
766 int bit = 0, isad = 1, err = AFP_OK;
768 u_char achar, *fdType, xyy[4];
769 u_int16_t ashort, bshort;
773 int change_mdate = 0;
774 int change_parent_mdate = 0;
780 LOG(log_info, logtype_afpd, "begin setfilparams:");
783 upath = path->u_name;
784 if ((of = of_findname(path))) {
787 ad_init(&ad, vol->v_adouble);
791 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
792 return AFPERR_ACCESS;
795 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
796 O_RDWR|O_CREAT, 0666, adp) < 0) {
797 /* for some things, we don't need an adouble header */
798 if (bitmap & ~(1<<FILPBIT_MDATE)) {
799 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
802 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
803 ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
804 memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
805 ad_getentrylen( adp, ADEID_NAME ));
808 while ( bitmap != 0 ) {
809 while (( bitmap & 1 ) == 0 ) {
817 memcpy(&ashort, buf, sizeof( ashort ));
818 ad_getattr(adp, &bshort);
819 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
820 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
824 if ((ashort & htons(ATTRBIT_INVISIBLE)))
825 change_parent_mdate = 1;
826 ad_setattr(adp, bshort);
827 buf += sizeof( ashort );
832 memcpy(&aint, buf, sizeof(aint));
833 ad_setdate(adp, AD_DATE_CREATE, aint);
834 buf += sizeof( aint );
838 memcpy(&newdate, buf, sizeof( newdate ));
839 buf += sizeof( newdate );
844 memcpy(&aint, buf, sizeof(aint));
845 ad_setdate(adp, AD_DATE_BACKUP, aint);
846 buf += sizeof( aint );
852 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
854 ((em = getextmap( path->m_name )) &&
855 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
856 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
857 || ((em = getdefextmap()) &&
858 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
859 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
861 memcpy(buf, ufinderi, 8 );
864 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
868 case FILPBIT_UNIXPR :
869 /* Skip the UIG/GID, no way to set them from OSX clients */
870 buf += sizeof( aint );
871 buf += sizeof( aint );
874 change_parent_mdate = 1;
875 memcpy( &aint, buf, sizeof( aint ));
876 buf += sizeof( aint );
879 setfilemode(path, aint);
881 /* Client needs to set the ProDOS file info for this file.
882 Use a defined string for TEXT to support crlf
883 translations and convert all else into pXYY per Inside
884 Appletalk. Always set the creator as "pdos". Changes
885 from original by Marsha Jackson. */
886 case FILPBIT_PDINFO :
887 if (afp_version < 30) { /* else it's UTF8 name */
890 /* Keep special case to support crlf translations */
891 if ((unsigned int) achar == 0x04) {
892 fdType = (u_char *)"TEXT";
895 xyy[0] = ( u_char ) 'p';
901 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
902 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
908 goto setfilparam_done;
916 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
917 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
921 ad_setdate(adp, AD_DATE_MODIFY, newdate);
922 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
927 ad_flush( adp, ADFLAGS_HF );
928 ad_close( adp, ADFLAGS_HF );
932 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
933 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
934 bitmap = 1<<FILPBIT_MDATE;
935 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
939 LOG(log_info, logtype_afpd, "end setfilparams:");
945 * renamefile and copyfile take the old and new unix pathnames
946 * and the new mac name.
948 * src the source path
949 * dst the dest filename in current dir
950 * newname the dest mac name
951 * adp adouble struct of src file, if open, or & zeroed one
954 int renamefile(src, dst, newname, noadouble, adp )
955 char *src, *dst, *newname;
959 char adsrc[ MAXPATHLEN + 1];
964 LOG(log_info, logtype_afpd, "begin renamefile:");
967 if ( unix_rename( src, dst ) < 0 ) {
970 return( AFPERR_NOOBJ );
973 return( AFPERR_ACCESS );
976 case EXDEV : /* Cross device move -- try copy */
977 /* NOTE: with open file it's an error because after the copy we will
978 * get two files, it's fixable for our process (eg reopen the new file, get the
979 * locks, and so on. But it doesn't solve the case with a second process
981 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
982 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
983 return AFPERR_OLOCK; /* little lie */
985 if (AFP_OK != ( rc = copyfile(src, dst, newname, noadouble )) ) {
986 /* on error copyfile delete dest */
989 return deletefile(NULL, src, 0);
991 return( AFPERR_PARAM );
995 strcpy( adsrc, ad_path( src, 0 ));
997 if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
1002 if (errno == ENOENT) {
1005 if (stat(adsrc, &st)) /* source has no ressource fork, */
1008 /* We are here because :
1009 * -there's no dest folder.
1010 * -there's no .AppleDouble in the dest folder.
1011 * if we use the struct adouble passed in parameter it will not
1012 * create .AppleDouble if the file is already opened, so we
1013 * use a diff one, it's not a pb,ie it's not the same file, yet.
1015 ad_init(&ad, AD_VERSION); /* FIXME */
1016 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
1017 ad_close(&ad, ADFLAGS_HF);
1018 if (!unix_rename( adsrc, ad_path( dst, 0 )) )
1023 else { /* it's something else, bail out */
1027 /* try to undo the data fork rename,
1028 * we know we are on the same device
1031 unix_rename( dst, src );
1032 /* return the first error */
1035 return AFPERR_NOOBJ;
1038 return AFPERR_ACCESS ;
1040 return AFPERR_VLOCK;
1042 return AFPERR_PARAM ;
1047 /* don't care if we can't open the newly renamed ressource fork
1049 if ( !ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1050 len = strlen( newname );
1051 ad_setentrylen( adp, ADEID_NAME, len );
1052 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
1053 ad_flush( adp, ADFLAGS_HF );
1054 ad_close( adp, ADFLAGS_HF );
1057 LOG(log_info, logtype_afpd, "end renamefile:");
1063 int copy_path_name(char *newname, char *ibuf)
1070 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1076 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1077 strncpy( newname, ibuf, plen );
1078 newname[ plen ] = '\0';
1079 if (strlen(newname) != plen) {
1080 /* there's \0 in newname, e.g. it's a pathname not
1088 memcpy(&hint, ibuf, sizeof(hint));
1089 ibuf += sizeof(hint);
1091 memcpy(&len16, ibuf, sizeof(len16));
1092 ibuf += sizeof(len16);
1093 plen = ntohs(len16);
1096 if (plen > AFPOBJ_TMPSIZ) {
1099 strncpy( newname, ibuf, plen );
1100 newname[ plen ] = '\0';
1101 if (strlen(newname) != plen) {
1110 /* -----------------------------------
1112 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1115 int ibuflen, *rbuflen;
1119 char *newname, *p, *upath;
1120 struct path *s_path;
1121 u_int32_t sdid, ddid;
1122 int err, retvalue = AFP_OK;
1123 u_int16_t svid, dvid;
1126 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1132 memcpy(&svid, ibuf, sizeof( svid ));
1133 ibuf += sizeof( svid );
1134 if (NULL == ( vol = getvolbyvid( svid )) ) {
1135 return( AFPERR_PARAM );
1138 memcpy(&sdid, ibuf, sizeof( sdid ));
1139 ibuf += sizeof( sdid );
1140 if (NULL == ( dir = dirlookup( vol, sdid )) ) {
1144 memcpy(&dvid, ibuf, sizeof( dvid ));
1145 ibuf += sizeof( dvid );
1146 memcpy(&ddid, ibuf, sizeof( ddid ));
1147 ibuf += sizeof( ddid );
1149 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1150 return get_afp_errno(AFPERR_PARAM);
1152 if ( path_isadir(s_path) ) {
1153 return( AFPERR_BADTYPE );
1156 /* don't allow copies when the file is open.
1157 * XXX: the spec only calls for read/deny write access.
1158 * however, copyfile doesn't have any of that info,
1159 * and locks need to stay coherent. as a result,
1160 * we just balk if the file is opened already. */
1162 newname = obj->newtmp;
1163 strcpy( newname, s_path->m_name );
1165 if (of_findname(s_path))
1166 return AFPERR_DENYCONF;
1168 p = ctoupath( vol, curdir, newname );
1170 return AFPERR_PARAM;
1174 /* FIXME svid != dvid && dvid's user can't read svid */
1176 if (NULL == ( vol = getvolbyvid( dvid )) ) {
1177 return( AFPERR_PARAM );
1180 if (vol->v_flags & AFPVOL_RO)
1181 return AFPERR_VLOCK;
1183 if (NULL == ( dir = dirlookup( vol, ddid )) ) {
1187 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1188 return get_afp_errno(AFPERR_NOOBJ);
1190 if ( *s_path->m_name != '\0' ) {
1192 return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1194 path_error(s_path, AFPERR_PARAM);
1197 /* one of the handful of places that knows about the path type */
1198 if (copy_path_name(newname, ibuf) < 0) {
1199 return( AFPERR_PARAM );
1201 /* newname is always only a filename so curdir *is* its
1204 if (NULL == (upath = mtoupath(vol, newname, curdir->d_did, utf8_encoding()))) {
1205 return( AFPERR_PARAM );
1207 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1213 if (vol->v_flags & AFPVOL_DROPBOX) {
1214 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1216 #endif /* DROPKLUDGE */
1218 setvoltime(obj, vol );
1221 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1228 static __inline__ int copy_all(const int dfd, const void *buf,
1234 LOG(log_info, logtype_afpd, "begin copy_all:");
1237 while (buflen > 0) {
1238 if ((cc = write(dfd, buf, buflen)) < 0) {
1245 return AFPERR_DFULL;
1247 return AFPERR_VLOCK;
1249 return AFPERR_PARAM;
1256 LOG(log_info, logtype_afpd, "end copy_all:");
1262 /* -------------------------- */
1263 static int copy_fd(int dfd, int sfd)
1269 #ifdef SENDFILE_FLAVOR_LINUX
1273 #define BUF 128*1024*1024
1275 if (fstat(sfd, &st) == 0) {
1278 if ( offset >= st.st_size) {
1281 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1282 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1285 case EINVAL: /* there's no guarantee that all fs support sendfile */
1290 return AFPERR_DFULL;
1292 return AFPERR_VLOCK;
1294 return AFPERR_PARAM;
1300 lseek(sfd, offset, SEEK_SET);
1304 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1311 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1317 /* ----------------------------------
1318 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1319 * because we are doing it elsewhere.
1321 int copyfile(src, dst, newname, noadouble )
1322 char *src, *dst, *newname;
1323 const int noadouble;
1325 struct adouble ads, add;
1326 int len, err = AFP_OK;
1331 LOG(log_info, logtype_afpd, "begin copyfile:");
1334 ad_init(&ads, 0); /* OK */
1335 ad_init(&add, 0); /* FIXME */
1336 adflags = ADFLAGS_DF;
1338 adflags |= ADFLAGS_HF;
1341 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1344 return( AFPERR_NOOBJ );
1346 return( AFPERR_ACCESS );
1348 return( AFPERR_PARAM );
1351 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1352 ad_close( &ads, adflags );
1353 if (EEXIST != (err = errno)) {
1354 deletefile(NULL, dst, 0);
1358 return AFPERR_EXIST;
1360 return( AFPERR_NOOBJ );
1362 return( AFPERR_ACCESS );
1364 return AFPERR_VLOCK;
1366 return( AFPERR_PARAM );
1369 if (ad_hfileno(&ads) == -1 || AFP_OK == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1370 /* copy the data fork */
1371 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1374 /* Now, reopen destination file */
1376 if (ad_close( &add, adflags ) <0) {
1377 deletefile(NULL, dst, 0);
1378 return AFPERR_PARAM; /* FIXME */
1381 if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
1382 ad_close( &ads, adflags );
1383 deletefile(NULL, dst, 0);
1386 return( AFPERR_NOOBJ );
1388 return( AFPERR_ACCESS );
1390 return AFPERR_VLOCK;
1392 return( AFPERR_PARAM );
1398 len = strlen( newname );
1399 ad_setentrylen( &add, ADEID_NAME, len );
1400 memcpy(ad_entry( &add, ADEID_NAME ), newname, len );
1403 ad_close( &ads, adflags );
1404 ad_flush( &add, adflags );
1405 if (ad_close( &add, adflags ) <0) {
1408 if (err != AFP_OK) {
1409 deletefile(NULL, dst, 0);
1412 return( AFPERR_NOOBJ );
1414 return( AFPERR_ACCESS );
1416 return( AFPERR_PARAM );
1420 /* set dest modification date to src date */
1421 if (!stat(src, &st)) {
1424 ut.actime = ut.modtime = st.st_mtime;
1429 LOG(log_info, logtype_afpd, "end copyfile:");
1436 /* -----------------------------------
1437 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1438 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1440 when deletefile is called we don't have lock on it, file is closed (for us)
1441 untrue if called by renamefile
1443 ad_open always try to open file RDWR first and ad_lock takes care of
1444 WRITE lock on read only file.
1446 int deletefile( vol, file, checkAttrib )
1452 int adflags, err = AFP_OK;
1455 LOG(log_info, logtype_afpd, "begin deletefile:");
1458 /* try to open both forks at once */
1459 adflags = ADFLAGS_DF|ADFLAGS_HF;
1461 ad_init(&ad, 0); /* OK */
1462 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1465 if (adflags == ADFLAGS_DF)
1466 return AFPERR_NOOBJ;
1468 /* that failed. now try to open just the data fork */
1469 adflags = ADFLAGS_DF;
1473 return AFPERR_ACCESS;
1475 return AFPERR_VLOCK;
1477 return( AFPERR_PARAM );
1480 break; /* from the while */
1483 * Does kFPDeleteInhibitBit (bit 8) set?
1485 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1488 ad_getattr(&ad, &bshort);
1489 if ((bshort & htons(ATTRBIT_NODELETE))) {
1490 ad_close( &ad, adflags );
1491 return(AFPERR_OLOCK);
1495 if ((adflags & ADFLAGS_HF) ) {
1496 /* FIXME we have a pb here because we want to know if a file is open
1497 * there's a 'priority inversion' if you can't open the ressource fork RW
1498 * you can delete it if it's open because you can't get a write lock.
1500 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1503 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1505 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1506 ad_close( &ad, adflags );
1507 return( AFPERR_BUSY );
1511 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1514 else if (!(err = netatalk_unlink( ad_path( file, ADFLAGS_HF)) ) &&
1515 !(err = netatalk_unlink( file )) ) {
1517 if (vol && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1519 cnid_delete(vol->v_cdb, id);
1523 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1526 LOG(log_info, logtype_afpd, "end deletefile:");
1532 /* ------------------------------------ */
1533 /* return a file id */
1534 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1537 int ibuflen, *rbuflen;
1546 struct path *s_path;
1549 LOG(log_info, logtype_afpd, "begin afp_createid:");
1556 memcpy(&vid, ibuf, sizeof(vid));
1557 ibuf += sizeof(vid);
1559 if (NULL == ( vol = getvolbyvid( vid )) ) {
1560 return( AFPERR_PARAM);
1563 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1567 if (vol->v_flags & AFPVOL_RO)
1568 return AFPERR_VLOCK;
1570 memcpy(&did, ibuf, sizeof( did ));
1571 ibuf += sizeof(did);
1573 if (NULL == ( dir = dirlookup( vol, did )) ) {
1574 return afp_errno; /* was AFPERR_PARAM */
1577 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1578 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1581 if ( path_isadir(s_path) ) {
1582 return( AFPERR_BADTYPE );
1585 upath = s_path->u_name;
1586 switch (s_path->st_errno) {
1588 break; /* success */
1591 return AFPERR_ACCESS;
1593 return AFPERR_NOOBJ;
1595 return AFPERR_PARAM;
1598 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1599 memcpy(rbuf, &id, sizeof(id));
1600 *rbuflen = sizeof(id);
1601 return AFPERR_EXISTID;
1604 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1605 memcpy(rbuf, &id, sizeof(id));
1606 *rbuflen = sizeof(id);
1611 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1617 reenumerate_id(const struct vol *vol, char *name, cnid_t did)
1627 if (vol->v_cdb == NULL) {
1630 if (NULL == ( dp = opendir( name)) ) {
1634 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
1635 if (NULL == check_dirent(vol, de->d_name))
1638 if ( stat(de->d_name, &st)<0 )
1641 /* update or add to cnid */
1642 aint = cnid_add(vol->v_cdb, &st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1644 #if AD_VERSION > AD_VERSION1
1645 if (aint != CNID_INVALID && !S_ISDIR(st.st_mode)) {
1646 ad_init(&ad, 0); /* OK */
1647 if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, &ad ) < 0 ) {
1651 ad_setid(&ad,(vol->v_flags & AFPVOL_NODEV)?0:st.st_dev, st.st_ino, aint, did, vol->v_stamp);
1652 ad_flush(&ad, ADFLAGS_HF);
1653 ad_close(&ad, ADFLAGS_HF);
1656 #endif /* AD_VERSION > AD_VERSION1 */
1665 /* ------------------------------
1666 resolve a file id */
1667 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1670 int ibuflen, *rbuflen;
1676 int err, buflen, retry=0;
1678 u_int16_t vid, bitmap;
1680 static char buffer[12 + MAXPATHLEN + 1];
1681 int len = 12 + MAXPATHLEN + 1;
1684 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1690 memcpy(&vid, ibuf, sizeof(vid));
1691 ibuf += sizeof(vid);
1693 if (NULL == ( vol = getvolbyvid( vid )) ) {
1694 return( AFPERR_PARAM);
1697 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1701 memcpy(&id, ibuf, sizeof( id ));
1706 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1707 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1710 if (NULL == ( dir = dirlookup( vol, id )) ) {
1711 return AFPERR_NOID; /* idem AFPERR_PARAM */
1713 path.u_name = upath;
1714 if (movecwd(vol, dir) < 0) {
1718 return AFPERR_ACCESS;
1722 return AFPERR_PARAM;
1726 if ( of_stat(&path) < 0 ) {
1727 if ( errno == ENOENT && !retry) {
1728 /* cnid db is out of sync, reenumerate the directory and updated ids */
1729 reenumerate_id(vol, ".", id);
1737 return AFPERR_ACCESS;
1741 return AFPERR_PARAM;
1745 /* directories are bad */
1746 if (S_ISDIR(path.st.st_mode))
1747 return AFPERR_BADTYPE;
1749 memcpy(&bitmap, ibuf, sizeof(bitmap));
1750 bitmap = ntohs( bitmap );
1751 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1754 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1755 rbuf + sizeof(bitmap), &buflen))) {
1758 *rbuflen = buflen + sizeof(bitmap);
1759 memcpy(rbuf, ibuf, sizeof(bitmap));
1762 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1768 /* ------------------------------ */
1769 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1772 int ibuflen, *rbuflen;
1782 static char buffer[12 + MAXPATHLEN + 1];
1783 int len = 12 + MAXPATHLEN + 1;
1786 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1792 memcpy(&vid, ibuf, sizeof(vid));
1793 ibuf += sizeof(vid);
1795 if (NULL == ( vol = getvolbyvid( vid )) ) {
1796 return( AFPERR_PARAM);
1799 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1803 if (vol->v_flags & AFPVOL_RO)
1804 return AFPERR_VLOCK;
1806 memcpy(&id, ibuf, sizeof( id ));
1810 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1814 if (NULL == ( dir = dirlookup( vol, id )) ) {
1815 return( AFPERR_PARAM );
1819 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1823 return AFPERR_ACCESS;
1825 /* still try to delete the id */
1829 return AFPERR_PARAM;
1832 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1833 return AFPERR_BADTYPE;
1835 if (cnid_delete(vol->v_cdb, fileid)) {
1838 return AFPERR_VLOCK;
1841 return AFPERR_ACCESS;
1843 return AFPERR_PARAM;
1848 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1854 #define APPLETEMP ".AppleTempXXXXXX"
1856 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1859 int ibuflen, *rbuflen;
1861 struct stat srcst, destst;
1863 struct dir *dir, *sdir;
1864 char *spath, temp[17], *p;
1865 char *supath, *upath;
1870 struct adouble *adsp;
1871 struct adouble *addp;
1881 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1887 memcpy(&vid, ibuf, sizeof(vid));
1888 ibuf += sizeof(vid);
1890 if (NULL == ( vol = getvolbyvid( vid )) ) {
1891 return( AFPERR_PARAM);
1894 if (vol->v_flags & AFPVOL_RO)
1895 return AFPERR_VLOCK;
1897 /* source and destination dids */
1898 memcpy(&sid, ibuf, sizeof(sid));
1899 ibuf += sizeof(sid);
1900 memcpy(&did, ibuf, sizeof(did));
1901 ibuf += sizeof(did);
1904 if (NULL == (dir = dirlookup( vol, sid )) ) {
1905 return afp_errno; /* was AFPERR_PARAM */
1908 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1909 return get_afp_errno(AFPERR_NOOBJ);
1912 if ( path_isadir(path) ) {
1913 return( AFPERR_BADTYPE ); /* it's a dir */
1916 upath = path->u_name;
1917 switch (path->st_errno) {
1924 return AFPERR_ACCESS;
1926 return AFPERR_PARAM;
1928 ad_init(&ads, vol->v_adouble);
1930 if ((s_of = of_findname(path))) {
1931 /* reuse struct adouble so it won't break locks */
1934 memcpy(&srcst, &path->st, sizeof(struct stat));
1935 /* save some stuff */
1937 spath = obj->oldtmp;
1938 supath = obj->newtmp;
1939 strcpy(spath, path->m_name);
1940 strcpy(supath, upath); /* this is for the cnid changing */
1941 p = absupath( vol, sdir, upath);
1943 /* pathname too long */
1944 return AFPERR_PARAM ;
1947 /* look for the source cnid. if it doesn't exist, don't worry about
1949 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
1951 if (NULL == ( dir = dirlookup( vol, did )) ) {
1952 return afp_errno; /* was AFPERR_PARAM */
1955 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1956 return get_afp_errno(AFPERR_NOOBJ);
1959 if ( path_isadir(path) ) {
1960 return( AFPERR_BADTYPE );
1963 /* FPExchangeFiles is the only call that can return the SameObj
1965 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1966 return AFPERR_SAMEOBJ;
1968 switch (path->st_errno) {
1975 return AFPERR_ACCESS;
1977 return AFPERR_PARAM;
1979 ad_init(&add, vol->v_adouble);
1981 if ((d_of = of_findname( path))) {
1982 /* reuse struct adouble so it won't break locks */
1985 memcpy(&destst, &path->st, sizeof(struct stat));
1987 /* they are not on the same device and at least one is open
1989 crossdev = (srcst.st_dev != destst.st_dev);
1990 if ((d_of || s_of) && crossdev)
1993 upath = path->u_name;
1994 /* look for destination id. */
1995 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
1997 /* construct a temp name.
1998 * NOTE: the temp file will be in the dest file's directory. it
1999 * will also be inaccessible from AFP. */
2000 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2004 /* now, quickly rename the file. we error if we can't. */
2005 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
2006 goto err_exchangefile;
2007 of_rename(vol, s_of, sdir, spath, curdir, temp);
2009 /* rename destination to source */
2010 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
2011 goto err_src_to_tmp;
2012 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2014 /* rename temp to destination */
2015 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
2016 goto err_dest_to_src;
2017 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2019 /* id's need switching. src -> dest and dest -> src.
2020 * we need to re-stat() if it was a cross device copy.
2023 cnid_delete(vol->v_cdb, sid);
2026 cnid_delete(vol->v_cdb, did);
2028 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2029 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2031 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2032 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2037 err = AFPERR_ACCESS;
2042 goto err_temp_to_dest;
2046 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2052 /* all this stuff is so that we can unwind a failed operation
2055 /* rename dest to temp */
2056 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
2057 of_rename(vol, s_of, curdir, upath, curdir, temp);
2060 /* rename source back to dest */
2061 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
2062 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2065 /* rename temp back to source */
2066 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
2067 of_rename(vol, s_of, curdir, temp, sdir, spath);