2 * $Id: file.c,v 1.122 2009-11-26 11:09:08 franklahm 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 */
33 #include <sys/param.h>
35 #include <atalk/adouble.h>
36 #include <atalk/vfs.h>
37 #include <atalk/logger.h>
38 #include <atalk/afp.h>
39 #include <atalk/util.h>
40 #include <atalk/cnid.h>
41 #include <atalk/unix.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[ADEDLEN_FINDERI] = {
72 0, 0, 0, 0, 0, 0, 0, 0,
73 1, 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 static const u_char old_ufinderi[] = {
79 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X'
82 /* ----------------------
84 static int default_type(void *finder)
86 if (!memcmp(finder, ufinderi, 8) || !memcmp(finder, old_ufinderi, 8))
91 /* FIXME path : unix or mac name ? (for now it's unix name ) */
92 void *get_finderinfo(const struct vol *vol, const char *upath, struct adouble *adp, void *data)
95 void *ad_finder = NULL;
99 ad_finder = ad_entry(adp, ADEID_FINDERI);
102 memcpy(data, ad_finder, ADEDLEN_FINDERI);
104 if (default_type(ad_finder))
108 memcpy(data, ufinderi, ADEDLEN_FINDERI);
110 if (vol_inv_dots(vol) && *upath == '.') { /* make it invisible */
113 ashort = htons(FINDERINFO_INVISIBLE);
114 memcpy((char *)data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
117 /** Only enter if no appledouble information and no finder information found. */
118 if (chk_ext && (em = getextmap( upath ))) {
119 memcpy(data, em->em_type, sizeof( em->em_type ));
120 memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator));
125 /* ---------------------
127 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8)
132 aint = strlen( name );
136 if (utf8_encoding()) {
137 /* but name is an utf8 mac name */
140 /* global static variable... */
142 if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
151 if (aint > MACFILELEN)
158 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
161 utf8 = vol->v_kTextEncoding;
162 memcpy(data, &utf8, sizeof(utf8));
163 data += sizeof(utf8);
166 memcpy(data, &temp, sizeof(temp));
167 data += sizeof(temp);
170 memcpy( data, src, aint );
180 * FIXME: PDINFO is UTF8 and doesn't need adp
182 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
183 (1 << FILPBIT_CDATE) |\
184 (1 << FILPBIT_MDATE) |\
185 (1 << FILPBIT_BDATE) |\
186 (1 << FILPBIT_FINFO) |\
187 (1 << FILPBIT_RFLEN) |\
188 (1 << FILPBIT_EXTRFLEN) |\
189 (1 << FILPBIT_PDINFO) |\
190 (1 << FILPBIT_UNIXPR)))
192 /* -------------------------- */
193 u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st,
194 const cnid_t did, char *upath, const int len)
199 #if AD_VERSION > AD_VERSION1
200 if ((aint = ad_getid(adp, st->st_dev, st->st_ino, did, vol->v_stamp))) {
206 if (vol->v_cdb != NULL) {
207 aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
208 /* Throw errors if cnid_add fails. */
209 if (aint == CNID_INVALID) {
211 case CNID_ERR_CLOSE: /* the db is closed */
214 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
215 afp_errno = AFPERR_PARAM;
218 afp_errno = AFPERR_PARAM;
221 afp_errno = AFPERR_MISC;
225 #if AD_VERSION > AD_VERSION1
227 /* update the ressource fork
228 * for a folder adp is always null
230 if (ad_setid(adp, st->st_dev, st->st_ino, aint, did, vol->v_stamp)) {
239 /* -------------------------- */
240 int getmetadata(struct vol *vol,
242 struct path *path, struct dir *dir,
243 char *buf, size_t *buflen, struct adouble *adp)
245 char *data, *l_nameoff = NULL, *upath;
246 char *utf_nameoff = NULL;
251 u_char achar, fdType[4];
257 LOG(log_debug9, logtype_afpd, "begin getmetadata:");
260 upath = path->u_name;
265 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
266 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
267 || (bitmap & (1 << FILPBIT_FNUM))) {
269 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
275 path->m_name = utompath(vol, upath, id, utf8_encoding());
278 while ( bitmap != 0 ) {
279 while (( bitmap & 1 ) == 0 ) {
287 ad_getattr(adp, &ashort);
288 } else if (vol_inv_dots(vol) && *upath == '.') {
289 ashort = htons(ATTRBIT_INVISIBLE);
293 /* FIXME do we want a visual clue if the file is read only
296 accessmode( ".", &ma, dir , NULL);
297 if ((ma.ma_user & AR_UWRITE)) {
298 accessmode( upath, &ma, dir , st);
299 if (!(ma.ma_user & AR_UWRITE)) {
300 ashort |= htons(ATTRBIT_NOWRITE);
304 memcpy(data, &ashort, sizeof( ashort ));
305 data += sizeof( ashort );
309 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
310 data += sizeof( u_int32_t );
314 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
315 aint = AD_DATE_FROM_UNIX(st->st_mtime);
316 memcpy(data, &aint, sizeof( aint ));
317 data += sizeof( aint );
321 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
322 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
323 aint = AD_DATE_FROM_UNIX(st->st_mtime);
326 aint = AD_DATE_FROM_UNIX(st->st_mtime);
328 memcpy(data, &aint, sizeof( int ));
329 data += sizeof( int );
333 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
334 aint = AD_DATE_START;
335 memcpy(data, &aint, sizeof( int ));
336 data += sizeof( int );
340 get_finderinfo(vol, upath, adp, (char *)data);
341 data += ADEDLEN_FINDERI;
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 /* accessmode may change st_mode with ACLs */
459 accessmode( upath, &ma, dir , st);
461 aint = htonl(st->st_uid);
462 memcpy( data, &aint, sizeof( aint ));
463 data += sizeof( aint );
464 aint = htonl(st->st_gid);
465 memcpy( data, &aint, sizeof( aint ));
466 data += sizeof( aint );
469 type == slnk indicates an OSX style symlink,
470 we have to add S_IFLNK to the mode, otherwise
471 10.3 clients freak out. */
475 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
476 if ( memcmp( fdType, "slnk", 4 ) == 0 ) {
482 memcpy( data, &aint, sizeof( aint ));
483 data += sizeof( aint );
485 *data++ = ma.ma_user;
486 *data++ = ma.ma_world;
487 *data++ = ma.ma_group;
488 *data++ = ma.ma_owner;
492 return( AFPERR_BITMAP );
498 ashort = htons( data - buf );
499 memcpy(l_nameoff, &ashort, sizeof( ashort ));
500 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
503 ashort = htons( data - buf );
504 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
505 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
507 *buflen = data - buf;
511 /* ----------------------- */
512 int getfilparams(struct vol *vol,
514 struct path *path, struct dir *dir,
515 char *buf, size_t *buflen )
517 struct adouble ad, *adp;
522 LOG(log_debug9, logtype_default, "begin getfilparams:");
525 opened = PARAM_NEED_ADP(bitmap);
530 int flags = (bitmap & (1 << FILPBIT_ATTR))?ADFLAGS_OPENFORKS:0;
532 adp = of_ad(vol, path, &ad);
533 upath = path->u_name;
535 if ( ad_metadata( upath, flags, adp) < 0 ) {
538 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
539 upath, strerror(errno));
540 return AFPERR_ACCESS;
542 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
551 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp);
553 ad_close_metadata( adp);
556 LOG(log_debug9, logtype_afpd, "end getfilparams:");
562 /* ----------------------------- */
563 int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
565 struct adouble ad, *adp;
568 struct ofork *of = NULL;
570 int creatf, did, openf, retvalue = AFP_OK;
576 creatf = (unsigned char) *ibuf++;
578 memcpy(&vid, ibuf, sizeof( vid ));
579 ibuf += sizeof( vid );
581 if (NULL == ( vol = getvolbyvid( vid )) ) {
582 return( AFPERR_PARAM );
585 if (vol->v_flags & AFPVOL_RO)
588 memcpy(&did, ibuf, sizeof( did));
589 ibuf += sizeof( did );
591 if (NULL == ( dir = dirlookup( vol, did )) ) {
595 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
596 return get_afp_errno(AFPERR_PARAM);
599 if ( *s_path->m_name == '\0' ) {
600 return( AFPERR_BADTYPE );
603 upath = s_path->u_name;
605 /* if upath is deleted we already in trouble anyway */
606 if ((of = of_findname(s_path))) {
609 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
613 /* on a hard create, fail if file exists and is open */
616 openf = O_RDWR|O_CREAT|O_TRUNC;
618 /* on a soft create, if the file is open then ad_open won't fail
619 because open syscall is not called
624 openf = O_RDWR|O_CREAT|O_EXCL;
627 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF|ADFLAGS_CREATE,
628 openf, 0666, adp) < 0 ) {
632 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
633 return ( AFPERR_NOOBJ );
635 return( AFPERR_EXIST );
637 return( AFPERR_ACCESS );
640 return( AFPERR_DFULL );
642 return( AFPERR_PARAM );
645 if ( ad_reso_fileno( adp ) == -1 ) { /* Hard META / HF */
646 /* on noadouble volumes, just creating the data fork is ok */
647 if (vol_noadouble(vol)) {
648 ad_close( adp, ADFLAGS_DF );
649 goto createfile_done;
651 /* FIXME with hard create on an existing file, we already
652 * corrupted the data file.
654 netatalk_unlink( upath );
655 ad_close( adp, ADFLAGS_DF );
656 return AFPERR_ACCESS;
659 path = s_path->m_name;
660 ad_setname(adp, path);
662 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
668 if (vol->v_flags & AFPVOL_DROPBOX) {
669 retvalue = matchfile2dirperms(upath, vol, did);
671 #endif /* DROPKLUDGE */
673 setvoltime(obj, vol );
678 int afp_setfilparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
684 u_int16_t vid, bitmap;
689 memcpy(&vid, ibuf, sizeof( vid ));
690 ibuf += sizeof( vid );
691 if (NULL == ( vol = getvolbyvid( vid )) ) {
692 return( AFPERR_PARAM );
695 if (vol->v_flags & AFPVOL_RO)
698 memcpy(&did, ibuf, sizeof( did ));
699 ibuf += sizeof( did );
700 if (NULL == ( dir = dirlookup( vol, did )) ) {
701 return afp_errno; /* was AFPERR_NOOBJ */
704 memcpy(&bitmap, ibuf, sizeof( bitmap ));
705 bitmap = ntohs( bitmap );
706 ibuf += sizeof( bitmap );
708 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
709 return get_afp_errno(AFPERR_PARAM);
712 if (path_isadir(s_path)) {
713 return( AFPERR_BADTYPE ); /* it's a directory */
716 if ( s_path->st_errno != 0 ) {
717 return( AFPERR_NOOBJ );
720 if ((u_long)ibuf & 1 ) {
724 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
725 setvoltime(obj, vol );
732 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
735 extern struct path Cur_Path;
737 int setfilparams(struct vol *vol,
738 struct path *path, u_int16_t f_bitmap, char *buf )
740 struct adouble ad, *adp;
742 int bit, isad = 1, err = AFP_OK;
744 u_char achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
745 u_int16_t ashort, bshort;
748 u_int16_t upriv_bit = 0;
752 int change_mdate = 0;
753 int change_parent_mdate = 0;
758 u_int16_t bitmap = f_bitmap;
759 u_int32_t cdate,bdate;
760 u_char finder_buf[32];
763 LOG(log_debug9, logtype_afpd, "begin setfilparams:");
766 adp = of_ad(vol, path, &ad);
767 upath = path->u_name;
769 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
770 return AFPERR_ACCESS;
773 /* with unix priv maybe we have to change adouble file priv first */
775 while ( bitmap != 0 ) {
776 while (( bitmap & 1 ) == 0 ) {
783 memcpy(&ashort, buf, sizeof( ashort ));
784 buf += sizeof( ashort );
788 memcpy(&cdate, buf, sizeof(cdate));
789 buf += sizeof( cdate );
792 memcpy(&newdate, buf, sizeof( newdate ));
793 buf += sizeof( newdate );
797 memcpy(&bdate, buf, sizeof( bdate));
798 buf += sizeof( bdate );
802 memcpy(finder_buf, buf, 32 );
805 case FILPBIT_UNIXPR :
806 if (!vol_unix_priv(vol)) {
807 /* this volume doesn't use unix priv */
813 change_parent_mdate = 1;
815 memcpy( &aint, buf, sizeof( aint ));
816 f_uid = ntohl (aint);
817 buf += sizeof( aint );
818 memcpy( &aint, buf, sizeof( aint ));
819 f_gid = ntohl (aint);
820 buf += sizeof( aint );
821 setfilowner(vol, f_uid, f_gid, path);
823 memcpy( &upriv, buf, sizeof( upriv ));
824 buf += sizeof( upriv );
825 upriv = ntohl (upriv);
826 if ((upriv & S_IWUSR)) {
827 setfilunixmode(vol, path, upriv);
834 case FILPBIT_PDINFO :
835 if (afp_version < 30) { /* else it's UTF8 name */
838 /* Keep special case to support crlf translations */
839 if ((unsigned int) achar == 0x04) {
840 fdType = (u_char *)"TEXT";
843 xyy[0] = ( u_char ) 'p';
854 /* break while loop */
863 /* second try with adouble open
865 if ( ad_open_metadata( upath, vol_noadouble(vol), O_CREAT, adp) < 0) {
866 LOG(log_debug, logtype_afpd, "setfilparams: ad_open_metadata error");
868 * For some things, we don't need an adouble header:
869 * - change of modification date
870 * - UNIX privs (Bug-ID #2863424)
872 if ( (f_bitmap & ~(1<<FILPBIT_MDATE | 1<<FILPBIT_UNIXPR))) {
873 LOG(log_debug, logtype_afpd, "setfilparams: need adouble access");
874 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
876 LOG(log_debug, logtype_afpd, "setfilparams: no adouble perms, but only FILPBIT_MDATE and/or FILPBIT_UNIXPR");
878 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
879 ad_setname(adp, path->m_name);
884 while ( bitmap != 0 ) {
885 while (( bitmap & 1 ) == 0 ) {
892 ad_getattr(adp, &bshort);
893 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
894 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
895 change_parent_mdate = 1;
896 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
897 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
901 ad_setattr(adp, bshort);
904 ad_setdate(adp, AD_DATE_CREATE, cdate);
909 ad_setdate(adp, AD_DATE_BACKUP, bdate);
912 if (default_type( ad_entry( adp, ADEID_FINDERI ))
914 ((em = getextmap( path->m_name )) &&
915 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
916 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
917 || ((em = getdefextmap()) &&
918 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
919 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
921 memcpy(finder_buf, ufinderi, 8 );
923 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
925 case FILPBIT_UNIXPR :
927 setfilunixmode(vol, path, upriv);
930 case FILPBIT_PDINFO :
931 if (afp_version < 30) { /* else it's UTF8 name */
932 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
933 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
939 goto setfilparam_done;
946 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
947 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
951 ad_setdate(adp, AD_DATE_MODIFY, newdate);
952 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
958 ad_close_metadata( adp);
962 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
963 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
964 bitmap = 1<<FILPBIT_MDATE;
965 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
969 LOG(log_debug9, logtype_afpd, "end setfilparams:");
975 * renamefile and copyfile take the old and new unix pathnames
976 * and the new mac name.
978 * src the source path
979 * dst the dest filename in current dir
980 * newname the dest mac name
981 * adp adouble struct of src file, if open, or & zeroed one
984 int renamefile(const struct vol *vol, char *src, char *dst, char *newname, struct adouble *adp)
989 LOG(log_debug9, logtype_afpd, "begin renamefile:");
992 if ( unix_rename( src, dst ) < 0 ) {
995 return( AFPERR_NOOBJ );
998 return( AFPERR_ACCESS );
1000 return AFPERR_VLOCK;
1001 case EXDEV : /* Cross device move -- try copy */
1002 /* NOTE: with open file it's an error because after the copy we will
1003 * get two files, it's fixable for our process (eg reopen the new file, get the
1004 * locks, and so on. But it doesn't solve the case with a second process
1006 if (adp->ad_open_forks) {
1007 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1008 return AFPERR_OLOCK; /* little lie */
1010 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1011 /* on error copyfile delete dest */
1014 return deletefile(vol, src, 0);
1016 return( AFPERR_PARAM );
1020 if (vol->vfs->vfs_renamefile(vol, src, dst) < 0 ) {
1024 /* try to undo the data fork rename,
1025 * we know we are on the same device
1028 unix_rename( dst, src );
1029 /* return the first error */
1032 return AFPERR_NOOBJ;
1035 return AFPERR_ACCESS ;
1037 return AFPERR_VLOCK;
1039 return AFPERR_PARAM ;
1044 /* don't care if we can't open the newly renamed ressource fork
1046 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1047 ad_setname(adp, newname);
1049 ad_close( adp, ADFLAGS_HF );
1052 LOG(log_debug9, logtype_afpd, "end renamefile:");
1059 convert a Mac long name to an utf8 name,
1061 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1065 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1071 /* ---------------- */
1072 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1079 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1085 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1086 if (afp_version >= 30) {
1087 /* convert it to UTF8
1089 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1)
1093 strncpy( newname, ibuf, plen );
1094 newname[ plen ] = '\0';
1096 if (strlen(newname) != plen) {
1097 /* there's \0 in newname, e.g. it's a pathname not
1105 memcpy(&hint, ibuf, sizeof(hint));
1106 ibuf += sizeof(hint);
1108 memcpy(&len16, ibuf, sizeof(len16));
1109 ibuf += sizeof(len16);
1110 plen = ntohs(len16);
1113 if (plen > AFPOBJ_TMPSIZ) {
1116 strncpy( newname, ibuf, plen );
1117 newname[ plen ] = '\0';
1118 if (strlen(newname) != plen) {
1127 /* -----------------------------------
1129 int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1131 struct vol *s_vol, *d_vol;
1133 char *newname, *p, *upath;
1134 struct path *s_path;
1135 u_int32_t sdid, ddid;
1136 int err, retvalue = AFP_OK;
1137 u_int16_t svid, dvid;
1139 struct adouble ad, *adp;
1145 memcpy(&svid, ibuf, sizeof( svid ));
1146 ibuf += sizeof( svid );
1147 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1148 return( AFPERR_PARAM );
1151 memcpy(&sdid, ibuf, sizeof( sdid ));
1152 ibuf += sizeof( sdid );
1153 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1157 memcpy(&dvid, ibuf, sizeof( dvid ));
1158 ibuf += sizeof( dvid );
1159 memcpy(&ddid, ibuf, sizeof( ddid ));
1160 ibuf += sizeof( ddid );
1162 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1163 return get_afp_errno(AFPERR_PARAM);
1165 if ( path_isadir(s_path) ) {
1166 return( AFPERR_BADTYPE );
1169 /* don't allow copies when the file is open.
1170 * XXX: the spec only calls for read/deny write access.
1171 * however, copyfile doesn't have any of that info,
1172 * and locks need to stay coherent. as a result,
1173 * we just balk if the file is opened already. */
1175 adp = of_ad(s_vol, s_path, &ad);
1177 if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1178 return AFPERR_DENYCONF;
1180 denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
1181 getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1182 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1184 return AFPERR_DENYCONF;
1187 newname = obj->newtmp;
1188 strcpy( newname, s_path->m_name );
1190 p = ctoupath( s_vol, curdir, newname );
1192 return AFPERR_PARAM;
1196 /* FIXME svid != dvid && dvid's user can't read svid */
1198 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1199 return( AFPERR_PARAM );
1202 if (d_vol->v_flags & AFPVOL_RO)
1203 return AFPERR_VLOCK;
1205 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1209 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1210 return get_afp_errno(AFPERR_NOOBJ);
1212 if ( *s_path->m_name != '\0' ) {
1213 path_error(s_path, AFPERR_PARAM);
1216 /* one of the handful of places that knows about the path type */
1217 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1218 return( AFPERR_PARAM );
1220 /* newname is always only a filename so curdir *is* its
1223 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1224 return( AFPERR_PARAM );
1226 if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1232 if (vol->v_flags & AFPVOL_DROPBOX) {
1233 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1235 #endif /* DROPKLUDGE */
1237 setvoltime(obj, d_vol );
1242 /* ----------------------- */
1243 static int copy_all(const int dfd, const void *buf,
1249 LOG(log_debug9, logtype_afpd, "begin copy_all:");
1252 while (buflen > 0) {
1253 if ((cc = write(dfd, buf, buflen)) < 0) {
1265 LOG(log_debug9, logtype_afpd, "end copy_all:");
1271 /* --------------------------
1272 * copy only the fork data stream
1274 static int copy_fork(int eid, struct adouble *add, struct adouble *ads)
1281 if (eid == ADEID_DFORK) {
1282 sfd = ad_data_fileno(ads);
1283 dfd = ad_data_fileno(add);
1286 sfd = ad_reso_fileno(ads);
1287 dfd = ad_reso_fileno(add);
1290 if ((off_t)-1 == lseek(sfd, ad_getentryoff(ads, eid), SEEK_SET))
1293 if ((off_t)-1 == lseek(dfd, ad_getentryoff(add, eid), SEEK_SET))
1296 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1297 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1301 #define BUF 128*1024*1024
1303 if (fstat(sfd, &st) == 0) {
1306 if ( offset >= st.st_size) {
1309 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1310 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1313 case EINVAL: /* there's no guarantee that all fs support sendfile */
1322 lseek(sfd, offset, SEEK_SET);
1326 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1333 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1340 /* ----------------------------------
1341 * if newname is NULL (from directory.c) we don't want to copy the resource fork.
1342 * because we are doing it elsewhere.
1343 * currently if newname is NULL then adp is NULL.
1345 int copyfile(const struct vol *s_vol, const struct vol*d_vol,
1346 char *src, char *dst, char *newname, struct adouble *adp)
1348 struct adouble ads, add;
1356 LOG(log_debug9, logtype_afpd, "begin copyfile:");
1360 ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options);
1363 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1364 adflags = ADFLAGS_DF;
1366 adflags |= ADFLAGS_HF;
1369 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1374 if (ad_meta_fileno(adp) == -1 && ad_reso_fileno(adp) == -1) { /* META / HF */
1375 /* no resource fork, don't create one for dst file */
1376 adflags &= ~ADFLAGS_HF;
1379 stat_result = fstat(ad_data_fileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */
1381 if (stat_result < 0) {
1382 /* unlikely but if fstat fails, the default file mode will be 0666. */
1383 st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
1386 if (ad_open(dst , adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
1388 ad_close( adp, adflags );
1389 if (EEXIST != ret_err) {
1390 deletefile(d_vol, dst, 0);
1393 return AFPERR_EXIST;
1397 * XXX if the source and the dest don't use the same resource type it's broken
1399 if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){
1400 /* copy the data fork */
1401 if ((err = copy_fork(ADEID_DFORK, &add, adp)) == 0) {
1402 err = d_vol->vfs->vfs_copyfile(d_vol, src, dst);
1410 if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
1411 /* set the new name in the resource fork */
1412 ad_copy_header(&add, adp);
1413 ad_setname(&add, newname);
1416 ad_close( adp, adflags );
1418 if (ad_close( &add, adflags ) <0) {
1423 deletefile(d_vol, dst, 0);
1425 else if (stat_result == 0) {
1426 /* set dest modification date to src date */
1429 ut.actime = ut.modtime = st.st_mtime;
1431 /* FIXME netatalk doesn't use resource fork file date
1432 * but maybe we should set its modtime too.
1437 LOG(log_debug9, logtype_afpd, "end copyfile:");
1441 switch ( ret_err ) {
1447 return AFPERR_DFULL;
1449 return AFPERR_NOOBJ;
1451 return AFPERR_ACCESS;
1453 return AFPERR_VLOCK;
1455 return AFPERR_PARAM;
1459 /* -----------------------------------
1460 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1461 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1463 when deletefile is called we don't have lock on it, file is closed (for us)
1464 untrue if called by renamefile
1466 ad_open always try to open file RDWR first and ad_lock takes care of
1467 WRITE lock on read only file.
1470 static int check_attrib(struct adouble *adp)
1472 u_int16_t bshort = 0;
1474 ad_getattr(adp, &bshort);
1476 * Does kFPDeleteInhibitBit (bit 8) set?
1478 if ((bshort & htons(ATTRBIT_NODELETE))) {
1479 return AFPERR_OLOCK;
1481 if ((bshort & htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN))) {
1487 int deletefile(const struct vol *vol, char *file, int checkAttrib)
1490 struct adouble *adp = &ad;
1491 int adflags, err = AFP_OK;
1494 LOG(log_debug9, logtype_afpd, "begin deletefile:");
1497 /* try to open both forks at once */
1498 adflags = ADFLAGS_DF|ADFLAGS_HF;
1500 /* was EACCESS error try to get only metadata */
1501 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1502 if ( ad_metadata( file , ADFLAGS_OPENFORKS, &ad) == 0 ) {
1503 ad_close( &ad, adflags );
1504 if ((err = check_attrib(&ad))) {
1511 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1512 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1515 if (adflags == ADFLAGS_DF)
1516 return AFPERR_NOOBJ;
1518 /* that failed. now try to open just the data fork */
1519 adflags = ADFLAGS_DF;
1523 adp = NULL; /* maybe it's a file with no write mode for us */
1524 break; /* was return AFPERR_ACCESS;*/
1526 return AFPERR_VLOCK;
1528 return( AFPERR_PARAM );
1531 break; /* from the while */
1534 if (adp && (adflags & ADFLAGS_HF) ) {
1535 /* FIXME we have a pb here because we want to know if a file is open
1536 * there's a 'priority inversion' if you can't open the ressource fork RW
1537 * you can delete it if it's open because you can't get a write lock.
1539 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1542 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1544 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1545 ad_close( &ad, adflags );
1546 return( AFPERR_BUSY );
1550 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1553 else if (!(err = vol->vfs->vfs_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
1555 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1557 cnid_delete(vol->v_cdb, id);
1561 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1564 LOG(log_debug9, logtype_afpd, "end deletefile:");
1570 /* ------------------------------------ */
1571 /* return a file id */
1572 int afp_createid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1581 struct path *s_path;
1587 memcpy(&vid, ibuf, sizeof(vid));
1588 ibuf += sizeof(vid);
1590 if (NULL == ( vol = getvolbyvid( vid )) ) {
1591 return( AFPERR_PARAM);
1594 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1598 if (vol->v_flags & AFPVOL_RO)
1599 return AFPERR_VLOCK;
1601 memcpy(&did, ibuf, sizeof( did ));
1602 ibuf += sizeof(did);
1604 if (NULL == ( dir = dirlookup( vol, did )) ) {
1605 return afp_errno; /* was AFPERR_PARAM */
1608 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1609 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1612 if ( path_isadir(s_path) ) {
1613 return( AFPERR_BADTYPE );
1616 upath = s_path->u_name;
1617 switch (s_path->st_errno) {
1619 break; /* success */
1622 return AFPERR_ACCESS;
1624 return AFPERR_NOOBJ;
1626 return AFPERR_PARAM;
1629 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1630 memcpy(rbuf, &id, sizeof(id));
1631 *rbuflen = sizeof(id);
1632 return AFPERR_EXISTID;
1635 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1636 memcpy(rbuf, &id, sizeof(id));
1637 *rbuflen = sizeof(id);
1644 /* ------------------------------- */
1650 static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
1653 struct reenum *param = data;
1654 struct vol *vol = param->vol;
1655 cnid_t did = param->did;
1658 if ( stat(de->d_name, &path.st)<0 )
1661 /* update or add to cnid */
1662 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1664 #if AD_VERSION > AD_VERSION1
1665 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1666 struct adouble ad, *adp;
1670 path.u_name = de->d_name;
1672 adp = of_ad(vol, &path, &ad);
1674 if ( ad_open_metadata( de->d_name, 0, 0, adp ) < 0 ) {
1677 if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1680 ad_close_metadata(adp);
1682 #endif /* AD_VERSION > AD_VERSION1 */
1687 /* --------------------
1688 * Ok the db is out of synch with the dir.
1689 * but if it's a deleted file we don't want to do it again and again.
1692 reenumerate_id(struct vol *vol, char *name, struct dir *dir)
1698 if (vol->v_cdb == NULL) {
1702 /* FIXME use of_statdir ? */
1703 if (stat(name, &st)) {
1707 if (dirreenumerate(dir, &st)) {
1708 /* we already did it once and the dir haven't been modified */
1713 data.did = dir->d_did;
1714 if ((ret = for_each_dirent(vol, name, reenumerate_loop, (void *)&data)) >= 0) {
1715 setdiroffcnt(curdir, &st, ret);
1716 dir->d_flags |= DIRF_CNID;
1722 /* ------------------------------
1723 resolve a file id */
1724 int afp_resolveid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1733 u_int16_t vid, bitmap;
1735 static char buffer[12 + MAXPATHLEN + 1];
1736 int len = 12 + MAXPATHLEN + 1;
1741 memcpy(&vid, ibuf, sizeof(vid));
1742 ibuf += sizeof(vid);
1744 if (NULL == ( vol = getvolbyvid( vid )) ) {
1745 return( AFPERR_PARAM);
1748 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1752 memcpy(&id, ibuf, sizeof( id ));
1757 /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
1761 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1762 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1765 if (NULL == ( dir = dirlookup( vol, id )) ) {
1766 return AFPERR_NOID; /* idem AFPERR_PARAM */
1768 if (movecwd(vol, dir) < 0) {
1772 return AFPERR_ACCESS;
1776 return AFPERR_PARAM;
1780 memset(&path, 0, sizeof(path));
1781 path.u_name = upath;
1782 if ( of_stat(&path) < 0 ) {
1784 /* with nfs and our working directory is deleted */
1785 if (errno == ESTALE) {
1789 if ( errno == ENOENT && !retry) {
1790 /* cnid db is out of sync, reenumerate the directory and update ids */
1791 reenumerate_id(vol, ".", dir);
1799 return AFPERR_ACCESS;
1803 return AFPERR_PARAM;
1807 /* directories are bad */
1808 if (S_ISDIR(path.st.st_mode)) {
1809 /* OS9 and OSX don't return the same error code */
1810 return (afp_version >=30)?AFPERR_NOID:AFPERR_BADTYPE;
1813 memcpy(&bitmap, ibuf, sizeof(bitmap));
1814 bitmap = ntohs( bitmap );
1815 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1819 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1820 rbuf + sizeof(bitmap), &buflen))) {
1823 *rbuflen = buflen + sizeof(bitmap);
1824 memcpy(rbuf, ibuf, sizeof(bitmap));
1829 /* ------------------------------ */
1830 int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1840 static char buffer[12 + MAXPATHLEN + 1];
1841 int len = 12 + MAXPATHLEN + 1;
1846 memcpy(&vid, ibuf, sizeof(vid));
1847 ibuf += sizeof(vid);
1849 if (NULL == ( vol = getvolbyvid( vid )) ) {
1850 return( AFPERR_PARAM);
1853 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1857 if (vol->v_flags & AFPVOL_RO)
1858 return AFPERR_VLOCK;
1860 memcpy(&id, ibuf, sizeof( id ));
1864 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1868 if (NULL == ( dir = dirlookup( vol, id )) ) {
1869 return( AFPERR_PARAM );
1873 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1877 return AFPERR_ACCESS;
1882 /* still try to delete the id */
1886 return AFPERR_PARAM;
1889 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1890 return AFPERR_BADTYPE;
1892 if (cnid_delete(vol->v_cdb, fileid)) {
1895 return AFPERR_VLOCK;
1898 return AFPERR_ACCESS;
1900 return AFPERR_PARAM;
1907 /* ------------------------------ */
1908 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1912 if (path->st_errno) {
1913 switch (path->st_errno) {
1915 afp_errno = AFPERR_NOID;
1919 afp_errno = AFPERR_ACCESS;
1922 afp_errno = AFPERR_PARAM;
1927 /* we use file_access both for legacy Mac perm and
1928 * for unix privilege, rename will take care of folder perms
1930 if (file_access(path, OPENACC_WR ) < 0) {
1931 afp_errno = AFPERR_ACCESS;
1935 if ((*of = of_findname(path))) {
1936 /* reuse struct adouble so it won't break locks */
1940 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
1942 if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
1944 * The user must have the Read & Write privilege for both files in order to use this command.
1946 ad_close(adp, ADFLAGS_HF);
1947 afp_errno = AFPERR_ACCESS;
1954 #define APPLETEMP ".AppleTempXXXXXX"
1956 int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1958 struct stat srcst, destst;
1960 struct dir *dir, *sdir;
1961 char *spath, temp[17], *p;
1962 char *supath, *upath;
1967 struct adouble *adsp = NULL;
1968 struct adouble *addp = NULL;
1969 struct ofork *s_of = NULL;
1970 struct ofork *d_of = NULL;
1983 memcpy(&vid, ibuf, sizeof(vid));
1984 ibuf += sizeof(vid);
1986 if (NULL == ( vol = getvolbyvid( vid )) ) {
1987 return( AFPERR_PARAM);
1990 if ((vol->v_flags & AFPVOL_RO))
1991 return AFPERR_VLOCK;
1993 /* source and destination dids */
1994 memcpy(&sid, ibuf, sizeof(sid));
1995 ibuf += sizeof(sid);
1996 memcpy(&did, ibuf, sizeof(did));
1997 ibuf += sizeof(did);
2000 if (NULL == (dir = dirlookup( vol, sid )) ) {
2001 return afp_errno; /* was AFPERR_PARAM */
2004 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2005 return get_afp_errno(AFPERR_NOOBJ);
2008 if ( path_isadir(path) ) {
2009 return AFPERR_BADTYPE; /* it's a dir */
2012 /* save some stuff */
2015 spath = obj->oldtmp;
2016 supath = obj->newtmp;
2017 strcpy(spath, path->m_name);
2018 strcpy(supath, path->u_name); /* this is for the cnid changing */
2019 p = absupath( vol, sdir, supath);
2021 /* pathname too long */
2022 return AFPERR_PARAM ;
2025 ad_init(&ads, vol->v_adouble, vol->v_ad_options);
2026 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2030 /* ***** from here we may have resource fork open **** */
2032 /* look for the source cnid. if it doesn't exist, don't worry about
2034 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2036 if (NULL == ( dir = dirlookup( vol, did )) ) {
2037 err = afp_errno; /* was AFPERR_PARAM */
2038 goto err_exchangefile;
2041 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2042 err = get_afp_errno(AFPERR_NOOBJ);
2043 goto err_exchangefile;
2046 if ( path_isadir(path) ) {
2047 err = AFPERR_BADTYPE;
2048 goto err_exchangefile;
2051 /* FPExchangeFiles is the only call that can return the SameObj
2053 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2054 err = AFPERR_SAMEOBJ;
2055 goto err_exchangefile;
2058 ad_init(&add, vol->v_adouble, vol->v_ad_options);
2059 if (!(addp = find_adouble( path, &d_of, &add))) {
2061 goto err_exchangefile;
2065 /* they are not on the same device and at least one is open
2066 * FIXME broken for for crossdev and adouble v2
2069 crossdev = (srcst.st_dev != destst.st_dev);
2070 if (/* (d_of || s_of) && */ crossdev) {
2072 goto err_exchangefile;
2075 /* look for destination id. */
2076 upath = path->u_name;
2077 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2079 /* construct a temp name.
2080 * NOTE: the temp file will be in the dest file's directory. it
2081 * will also be inaccessible from AFP. */
2082 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2083 if (!mktemp(temp)) {
2085 goto err_exchangefile;
2089 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2090 ad_close(adsp, ADFLAGS_HF);
2091 ad_close(addp, ADFLAGS_HF);
2094 /* now, quickly rename the file. we error if we can't. */
2095 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2096 goto err_exchangefile;
2097 of_rename(vol, s_of, sdir, spath, curdir, temp);
2099 /* rename destination to source */
2100 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2101 goto err_src_to_tmp;
2102 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2104 /* rename temp to destination */
2105 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2106 goto err_dest_to_src;
2107 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2109 /* id's need switching. src -> dest and dest -> src.
2110 * we need to re-stat() if it was a cross device copy.
2113 cnid_delete(vol->v_cdb, sid);
2116 cnid_delete(vol->v_cdb, did);
2118 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2119 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2121 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2122 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2127 err = AFPERR_ACCESS;
2132 goto err_temp_to_dest;
2135 /* here we need to reopen if crossdev */
2136 if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2141 if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2146 /* change perms, src gets dest perm and vice versa */
2151 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2152 err = AFP_OK; /* ignore error */
2153 goto err_temp_to_dest;
2157 * we need to exchange ACL entries as well
2159 /* exchange_acls(vol, p, upath); */
2164 path->m_name = NULL;
2165 path->u_name = upath;
2167 setfilunixmode(vol, path, destst.st_mode);
2168 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2175 setfilunixmode(vol, path, srcst.st_mode);
2176 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2178 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2179 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2184 goto err_exchangefile;
2186 /* all this stuff is so that we can unwind a failed operation
2189 /* rename dest to temp */
2190 renamefile(vol, upath, temp, temp, adsp);
2191 of_rename(vol, s_of, curdir, upath, curdir, temp);
2194 /* rename source back to dest */
2195 renamefile(vol, p, upath, path->m_name, addp);
2196 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2199 /* rename temp back to source */
2200 renamefile(vol, temp, p, spath, adsp);
2201 of_rename(vol, s_of, curdir, temp, sdir, spath);
2204 if ( !s_of && adsp && ad_meta_fileno(adsp) != -1 ) { /* META */
2205 ad_close(adsp, ADFLAGS_HF);
2207 if ( !d_of && addp && ad_meta_fileno(addp) != -1 ) {/* META */
2208 ad_close(addp, ADFLAGS_HF);