2 * $Id: file.c,v 1.92.2.2.2.19 2004-03-11 12:47:59 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 if (ad_getentryoff(adp, ADEID_NAME)) {
666 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
667 memcpy(ad_entry( adp, ADEID_NAME ), path, 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_getentryoff(adp, ADEID_NAME) && (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 setfilunixmode(vol, 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(vol, src, dst, newname, adp )
955 const struct vol *vol;
956 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(vol, vol, src, dst, newname )) ) {
986 /* on error copyfile delete dest */
989 return deletefile(vol, src, 0);
991 return( AFPERR_PARAM );
995 strcpy( adsrc, vol->ad_path( src, 0 ));
997 if (unix_rename( adsrc, vol->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, vol->v_adouble);
1016 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
1017 ad_close(&ad, ADFLAGS_HF);
1018 if (!unix_rename( adsrc, vol->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 if (ad_getentryoff(adp, ADEID_NAME) ) {
1051 len = strlen( newname );
1052 ad_setentrylen( adp, ADEID_NAME, len );
1053 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
1055 ad_flush( adp, ADFLAGS_HF );
1056 ad_close( adp, ADFLAGS_HF );
1059 LOG(log_info, logtype_afpd, "end renamefile:");
1065 int copy_path_name(char *newname, char *ibuf)
1072 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1078 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1079 strncpy( newname, ibuf, plen );
1080 newname[ plen ] = '\0';
1081 if (strlen(newname) != plen) {
1082 /* there's \0 in newname, e.g. it's a pathname not
1090 memcpy(&hint, ibuf, sizeof(hint));
1091 ibuf += sizeof(hint);
1093 memcpy(&len16, ibuf, sizeof(len16));
1094 ibuf += sizeof(len16);
1095 plen = ntohs(len16);
1098 if (plen > AFPOBJ_TMPSIZ) {
1101 strncpy( newname, ibuf, plen );
1102 newname[ plen ] = '\0';
1103 if (strlen(newname) != plen) {
1112 /* -----------------------------------
1114 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1117 int ibuflen, *rbuflen;
1119 struct vol *s_vol, *d_vol;
1121 char *newname, *p, *upath;
1122 struct path *s_path;
1123 u_int32_t sdid, ddid;
1124 int err, retvalue = AFP_OK;
1125 u_int16_t svid, dvid;
1128 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1134 memcpy(&svid, ibuf, sizeof( svid ));
1135 ibuf += sizeof( svid );
1136 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1137 return( AFPERR_PARAM );
1140 memcpy(&sdid, ibuf, sizeof( sdid ));
1141 ibuf += sizeof( sdid );
1142 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1146 memcpy(&dvid, ibuf, sizeof( dvid ));
1147 ibuf += sizeof( dvid );
1148 memcpy(&ddid, ibuf, sizeof( ddid ));
1149 ibuf += sizeof( ddid );
1151 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1152 return get_afp_errno(AFPERR_PARAM);
1154 if ( path_isadir(s_path) ) {
1155 return( AFPERR_BADTYPE );
1158 /* don't allow copies when the file is open.
1159 * XXX: the spec only calls for read/deny write access.
1160 * however, copyfile doesn't have any of that info,
1161 * and locks need to stay coherent. as a result,
1162 * we just balk if the file is opened already. */
1164 newname = obj->newtmp;
1165 strcpy( newname, s_path->m_name );
1167 if (of_findname(s_path))
1168 return AFPERR_DENYCONF;
1170 p = ctoupath( s_vol, curdir, newname );
1172 return AFPERR_PARAM;
1176 /* FIXME svid != dvid && dvid's user can't read svid */
1178 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1179 return( AFPERR_PARAM );
1182 if (d_vol->v_flags & AFPVOL_RO)
1183 return AFPERR_VLOCK;
1185 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1189 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1190 return get_afp_errno(AFPERR_NOOBJ);
1192 if ( *s_path->m_name != '\0' ) {
1194 return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1196 path_error(s_path, AFPERR_PARAM);
1199 /* one of the handful of places that knows about the path type */
1200 if (copy_path_name(newname, ibuf) < 0) {
1201 return( AFPERR_PARAM );
1203 /* newname is always only a filename so curdir *is* its
1206 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1207 return( AFPERR_PARAM );
1209 if ( (err = copyfile(s_vol, d_vol, p, upath , newname)) < 0 ) {
1215 if (vol->v_flags & AFPVOL_DROPBOX) {
1216 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1218 #endif /* DROPKLUDGE */
1220 setvoltime(obj, d_vol );
1223 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1229 /* ----------------------- */
1230 static __inline__ int copy_all(const int dfd, const void *buf,
1236 LOG(log_info, logtype_afpd, "begin copy_all:");
1239 while (buflen > 0) {
1240 if ((cc = write(dfd, buf, buflen)) < 0) {
1252 LOG(log_info, logtype_afpd, "end copy_all:");
1258 /* -------------------------- */
1259 static int copy_fd(int dfd, int sfd)
1265 #ifdef SENDFILE_FLAVOR_LINUX
1269 #define BUF 128*1024*1024
1271 if (fstat(sfd, &st) == 0) {
1274 if ( offset >= st.st_size) {
1277 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1278 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1281 case EINVAL: /* there's no guarantee that all fs support sendfile */
1290 lseek(sfd, offset, SEEK_SET);
1294 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1301 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1308 /* ----------------------------------
1309 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1310 * because we are doing it elsewhere.
1312 int copyfile(s_vol, d_vol, src, dst, newname )
1313 const struct vol *s_vol, *d_vol;
1314 char *src, *dst, *newname;
1316 struct adouble ads, add;
1320 int noadouble = vol_noadouble(d_vol);
1324 LOG(log_info, logtype_afpd, "begin copyfile:");
1327 ad_init(&ads, s_vol->v_adouble);
1328 ad_init(&add, d_vol->v_adouble);
1329 adflags = ADFLAGS_DF;
1331 adflags |= ADFLAGS_HF;
1334 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1339 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1341 ad_close( &ads, adflags );
1342 if (EEXIST != ret_err) {
1343 deletefile(d_vol, dst, 0);
1346 return AFPERR_EXIST;
1348 if (ad_hfileno(&ads) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1349 /* copy the data fork */
1350 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1353 /* Now, reopen destination file */
1357 ad_close( &ads, adflags );
1359 if (ad_close( &add, adflags ) <0) {
1360 deletefile(d_vol, dst, 0);
1365 ad_init(&add, d_vol->v_adouble);
1366 if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
1371 if (!ret_err && newname && ad_getentryoff(&add, ADEID_NAME)) {
1372 len = strlen( newname );
1373 ad_setentrylen( &add, ADEID_NAME, len );
1374 memcpy(ad_entry( &add, ADEID_NAME ), newname, len );
1377 ad_flush( &add, adflags );
1378 if (ad_close( &add, adflags ) <0) {
1382 deletefile(d_vol, dst, 0);
1385 /* set dest modification date to src date */
1386 if (!stat(src, &st)) {
1389 ut.actime = ut.modtime = st.st_mtime;
1394 LOG(log_info, logtype_afpd, "end copyfile:");
1398 switch ( ret_err ) {
1404 return AFPERR_DFULL;
1406 return AFPERR_NOOBJ;
1408 return AFPERR_ACCESS;
1410 return AFPERR_VLOCK;
1412 return AFPERR_PARAM;
1416 /* -----------------------------------
1417 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1418 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1420 when deletefile is called we don't have lock on it, file is closed (for us)
1421 untrue if called by renamefile
1423 ad_open always try to open file RDWR first and ad_lock takes care of
1424 WRITE lock on read only file.
1426 int deletefile( vol, file, checkAttrib )
1427 const struct vol *vol;
1432 int adflags, err = AFP_OK;
1435 LOG(log_info, logtype_afpd, "begin deletefile:");
1438 /* try to open both forks at once */
1439 adflags = ADFLAGS_DF|ADFLAGS_HF;
1441 ad_init(&ad, vol->v_adouble); /* OK */
1442 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1445 if (adflags == ADFLAGS_DF)
1446 return AFPERR_NOOBJ;
1448 /* that failed. now try to open just the data fork */
1449 adflags = ADFLAGS_DF;
1453 return AFPERR_ACCESS;
1455 return AFPERR_VLOCK;
1457 return( AFPERR_PARAM );
1460 break; /* from the while */
1463 * Does kFPDeleteInhibitBit (bit 8) set?
1465 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1468 ad_getattr(&ad, &bshort);
1469 if ((bshort & htons(ATTRBIT_NODELETE))) {
1470 ad_close( &ad, adflags );
1471 return(AFPERR_OLOCK);
1475 if ((adflags & ADFLAGS_HF) ) {
1476 /* FIXME we have a pb here because we want to know if a file is open
1477 * there's a 'priority inversion' if you can't open the ressource fork RW
1478 * you can delete it if it's open because you can't get a write lock.
1480 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1483 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1485 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1486 ad_close( &ad, adflags );
1487 return( AFPERR_BUSY );
1491 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1494 else if (!(err = netatalk_unlink( vol->ad_path( file, ADFLAGS_HF)) ) &&
1495 !(err = netatalk_unlink( file )) ) {
1497 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1499 cnid_delete(vol->v_cdb, id);
1503 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1506 LOG(log_info, logtype_afpd, "end deletefile:");
1512 /* ------------------------------------ */
1513 /* return a file id */
1514 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1517 int ibuflen, *rbuflen;
1526 struct path *s_path;
1529 LOG(log_info, logtype_afpd, "begin afp_createid:");
1536 memcpy(&vid, ibuf, sizeof(vid));
1537 ibuf += sizeof(vid);
1539 if (NULL == ( vol = getvolbyvid( vid )) ) {
1540 return( AFPERR_PARAM);
1543 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1547 if (vol->v_flags & AFPVOL_RO)
1548 return AFPERR_VLOCK;
1550 memcpy(&did, ibuf, sizeof( did ));
1551 ibuf += sizeof(did);
1553 if (NULL == ( dir = dirlookup( vol, did )) ) {
1554 return afp_errno; /* was AFPERR_PARAM */
1557 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1558 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1561 if ( path_isadir(s_path) ) {
1562 return( AFPERR_BADTYPE );
1565 upath = s_path->u_name;
1566 switch (s_path->st_errno) {
1568 break; /* success */
1571 return AFPERR_ACCESS;
1573 return AFPERR_NOOBJ;
1575 return AFPERR_PARAM;
1578 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1579 memcpy(rbuf, &id, sizeof(id));
1580 *rbuflen = sizeof(id);
1581 return AFPERR_EXISTID;
1584 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1585 memcpy(rbuf, &id, sizeof(id));
1586 *rbuflen = sizeof(id);
1591 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1597 reenumerate_id(const struct vol *vol, char *name, cnid_t did)
1607 if (vol->v_cdb == NULL) {
1610 if (NULL == ( dp = opendir( name)) ) {
1614 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
1615 if (NULL == check_dirent(vol, de->d_name))
1618 if ( stat(de->d_name, &st)<0 )
1621 /* update or add to cnid */
1622 aint = cnid_add(vol->v_cdb, &st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1624 #if AD_VERSION > AD_VERSION1
1625 if (aint != CNID_INVALID && !S_ISDIR(st.st_mode)) {
1626 ad_init(&ad, 0); /* OK */
1627 if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, &ad ) < 0 ) {
1631 ad_setid(&ad,(vol->v_flags & AFPVOL_NODEV)?0:st.st_dev, st.st_ino, aint, did, vol->v_stamp);
1632 ad_flush(&ad, ADFLAGS_HF);
1633 ad_close(&ad, ADFLAGS_HF);
1636 #endif /* AD_VERSION > AD_VERSION1 */
1645 /* ------------------------------
1646 resolve a file id */
1647 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1650 int ibuflen, *rbuflen;
1656 int err, buflen, retry=0;
1658 u_int16_t vid, bitmap;
1660 static char buffer[12 + MAXPATHLEN + 1];
1661 int len = 12 + MAXPATHLEN + 1;
1664 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1670 memcpy(&vid, ibuf, sizeof(vid));
1671 ibuf += sizeof(vid);
1673 if (NULL == ( vol = getvolbyvid( vid )) ) {
1674 return( AFPERR_PARAM);
1677 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1681 memcpy(&id, ibuf, sizeof( id ));
1686 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1687 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1690 if (NULL == ( dir = dirlookup( vol, id )) ) {
1691 return AFPERR_NOID; /* idem AFPERR_PARAM */
1693 path.u_name = upath;
1694 if (movecwd(vol, dir) < 0) {
1698 return AFPERR_ACCESS;
1702 return AFPERR_PARAM;
1706 if ( of_stat(&path) < 0 ) {
1707 if ( errno == ENOENT && !retry) {
1708 /* cnid db is out of sync, reenumerate the directory and updated ids */
1709 reenumerate_id(vol, ".", id);
1717 return AFPERR_ACCESS;
1721 return AFPERR_PARAM;
1725 /* directories are bad */
1726 if (S_ISDIR(path.st.st_mode))
1727 return AFPERR_BADTYPE;
1729 memcpy(&bitmap, ibuf, sizeof(bitmap));
1730 bitmap = ntohs( bitmap );
1731 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1734 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1735 rbuf + sizeof(bitmap), &buflen))) {
1738 *rbuflen = buflen + sizeof(bitmap);
1739 memcpy(rbuf, ibuf, sizeof(bitmap));
1742 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1748 /* ------------------------------ */
1749 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1752 int ibuflen, *rbuflen;
1762 static char buffer[12 + MAXPATHLEN + 1];
1763 int len = 12 + MAXPATHLEN + 1;
1766 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1772 memcpy(&vid, ibuf, sizeof(vid));
1773 ibuf += sizeof(vid);
1775 if (NULL == ( vol = getvolbyvid( vid )) ) {
1776 return( AFPERR_PARAM);
1779 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1783 if (vol->v_flags & AFPVOL_RO)
1784 return AFPERR_VLOCK;
1786 memcpy(&id, ibuf, sizeof( id ));
1790 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1794 if (NULL == ( dir = dirlookup( vol, id )) ) {
1795 return( AFPERR_PARAM );
1799 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1803 return AFPERR_ACCESS;
1805 /* still try to delete the id */
1809 return AFPERR_PARAM;
1812 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1813 return AFPERR_BADTYPE;
1815 if (cnid_delete(vol->v_cdb, fileid)) {
1818 return AFPERR_VLOCK;
1821 return AFPERR_ACCESS;
1823 return AFPERR_PARAM;
1828 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1834 #define APPLETEMP ".AppleTempXXXXXX"
1836 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1839 int ibuflen, *rbuflen;
1841 struct stat srcst, destst;
1843 struct dir *dir, *sdir;
1844 char *spath, temp[17], *p;
1845 char *supath, *upath;
1850 struct adouble *adsp;
1851 struct adouble *addp;
1861 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1867 memcpy(&vid, ibuf, sizeof(vid));
1868 ibuf += sizeof(vid);
1870 if (NULL == ( vol = getvolbyvid( vid )) ) {
1871 return( AFPERR_PARAM);
1874 if (vol->v_flags & AFPVOL_RO)
1875 return AFPERR_VLOCK;
1877 /* source and destination dids */
1878 memcpy(&sid, ibuf, sizeof(sid));
1879 ibuf += sizeof(sid);
1880 memcpy(&did, ibuf, sizeof(did));
1881 ibuf += sizeof(did);
1884 if (NULL == (dir = dirlookup( vol, sid )) ) {
1885 return afp_errno; /* was AFPERR_PARAM */
1888 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1889 return get_afp_errno(AFPERR_NOOBJ);
1892 if ( path_isadir(path) ) {
1893 return( AFPERR_BADTYPE ); /* it's a dir */
1896 upath = path->u_name;
1897 switch (path->st_errno) {
1904 return AFPERR_ACCESS;
1906 return AFPERR_PARAM;
1908 ad_init(&ads, vol->v_adouble);
1910 if ((s_of = of_findname(path))) {
1911 /* reuse struct adouble so it won't break locks */
1914 memcpy(&srcst, &path->st, sizeof(struct stat));
1915 /* save some stuff */
1917 spath = obj->oldtmp;
1918 supath = obj->newtmp;
1919 strcpy(spath, path->m_name);
1920 strcpy(supath, upath); /* this is for the cnid changing */
1921 p = absupath( vol, sdir, upath);
1923 /* pathname too long */
1924 return AFPERR_PARAM ;
1927 /* look for the source cnid. if it doesn't exist, don't worry about
1929 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
1931 if (NULL == ( dir = dirlookup( vol, did )) ) {
1932 return afp_errno; /* was AFPERR_PARAM */
1935 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1936 return get_afp_errno(AFPERR_NOOBJ);
1939 if ( path_isadir(path) ) {
1940 return( AFPERR_BADTYPE );
1943 /* FPExchangeFiles is the only call that can return the SameObj
1945 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1946 return AFPERR_SAMEOBJ;
1948 switch (path->st_errno) {
1955 return AFPERR_ACCESS;
1957 return AFPERR_PARAM;
1959 ad_init(&add, vol->v_adouble);
1961 if ((d_of = of_findname( path))) {
1962 /* reuse struct adouble so it won't break locks */
1965 memcpy(&destst, &path->st, sizeof(struct stat));
1967 /* they are not on the same device and at least one is open
1969 crossdev = (srcst.st_dev != destst.st_dev);
1970 if ((d_of || s_of) && crossdev)
1973 upath = path->u_name;
1974 /* look for destination id. */
1975 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
1977 /* construct a temp name.
1978 * NOTE: the temp file will be in the dest file's directory. it
1979 * will also be inaccessible from AFP. */
1980 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1984 /* now, quickly rename the file. we error if we can't. */
1985 if ((err = renamefile(vol, p, temp, temp, adsp)) < 0)
1986 goto err_exchangefile;
1987 of_rename(vol, s_of, sdir, spath, curdir, temp);
1989 /* rename destination to source */
1990 if ((err = renamefile(vol, upath, p, spath, addp)) < 0)
1991 goto err_src_to_tmp;
1992 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1994 /* rename temp to destination */
1995 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) < 0)
1996 goto err_dest_to_src;
1997 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1999 /* id's need switching. src -> dest and dest -> src.
2000 * we need to re-stat() if it was a cross device copy.
2003 cnid_delete(vol->v_cdb, sid);
2006 cnid_delete(vol->v_cdb, did);
2008 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2009 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2011 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2012 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2017 err = AFPERR_ACCESS;
2022 goto err_temp_to_dest;
2026 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2032 /* all this stuff is so that we can unwind a failed operation
2035 /* rename dest to temp */
2036 renamefile(vol, upath, temp, temp, adsp);
2037 of_rename(vol, s_of, curdir, upath, curdir, temp);
2040 /* rename source back to dest */
2041 renamefile(vol, p, upath, path->m_name, addp);
2042 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2045 /* rename temp back to source */
2046 renamefile(vol, temp, p, spath, adsp);
2047 of_rename(vol, s_of, curdir, temp, sdir, spath);