2 * $Id: file.c,v 1.125 2009-11-27 15:45:40 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)
198 if (vol->v_cdb != NULL) {
199 aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
200 /* Throw errors if cnid_add fails. */
201 if (aint == CNID_INVALID) {
203 case CNID_ERR_CLOSE: /* the db is closed */
206 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
207 afp_errno = AFPERR_PARAM;
210 afp_errno = AFPERR_PARAM;
213 afp_errno = AFPERR_MISC;
218 /* update the ressource fork
219 * for a folder adp is always null
221 if (ad_setid(adp, st->st_dev, st->st_ino, aint, did, vol->v_stamp)) {
229 /* -------------------------- */
230 int getmetadata(struct vol *vol,
232 struct path *path, struct dir *dir,
233 char *buf, size_t *buflen, struct adouble *adp)
235 char *data, *l_nameoff = NULL, *upath;
236 char *utf_nameoff = NULL;
241 u_char achar, fdType[4];
247 LOG(log_debug9, logtype_afpd, "begin getmetadata:");
250 upath = path->u_name;
255 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
256 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
257 || (bitmap & (1 << FILPBIT_FNUM))) {
259 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
265 path->m_name = utompath(vol, upath, id, utf8_encoding());
268 while ( bitmap != 0 ) {
269 while (( bitmap & 1 ) == 0 ) {
277 ad_getattr(adp, &ashort);
278 } else if (vol_inv_dots(vol) && *upath == '.') {
279 ashort = htons(ATTRBIT_INVISIBLE);
283 /* FIXME do we want a visual clue if the file is read only
286 accessmode( ".", &ma, dir , NULL);
287 if ((ma.ma_user & AR_UWRITE)) {
288 accessmode( upath, &ma, dir , st);
289 if (!(ma.ma_user & AR_UWRITE)) {
290 ashort |= htons(ATTRBIT_NOWRITE);
294 memcpy(data, &ashort, sizeof( ashort ));
295 data += sizeof( ashort );
299 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
300 data += sizeof( u_int32_t );
304 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
305 aint = AD_DATE_FROM_UNIX(st->st_mtime);
306 memcpy(data, &aint, sizeof( aint ));
307 data += sizeof( aint );
311 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
312 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
313 aint = AD_DATE_FROM_UNIX(st->st_mtime);
316 aint = AD_DATE_FROM_UNIX(st->st_mtime);
318 memcpy(data, &aint, sizeof( int ));
319 data += sizeof( int );
323 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
324 aint = AD_DATE_START;
325 memcpy(data, &aint, sizeof( int ));
326 data += sizeof( int );
330 get_finderinfo(vol, upath, adp, (char *)data);
331 data += ADEDLEN_FINDERI;
336 data += sizeof( u_int16_t );
340 memset(data, 0, sizeof(u_int16_t));
341 data += sizeof( u_int16_t );
345 memcpy(data, &id, sizeof( id ));
346 data += sizeof( id );
350 if (st->st_size > 0xffffffff)
353 aint = htonl( st->st_size );
354 memcpy(data, &aint, sizeof( aint ));
355 data += sizeof( aint );
360 if (adp->ad_rlen > 0xffffffff)
363 aint = htonl( adp->ad_rlen);
367 memcpy(data, &aint, sizeof( aint ));
368 data += sizeof( aint );
371 /* Current client needs ProDOS info block for this file.
372 Use simple heuristic and let the Mac "type" string tell
373 us what the PD file code should be. Everything gets a
374 subtype of 0x0000 unless the original value was hashed
375 to "pXYZ" when we created it. See IA, Ver 2.
376 <shirsch@adelphia.net> */
377 case FILPBIT_PDINFO :
378 if (afp_version >= 30) { /* UTF8 name */
379 utf8 = kTextEncodingUTF8;
381 data += sizeof( u_int16_t );
383 memcpy(data, &aint, sizeof( aint ));
384 data += sizeof( aint );
388 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
390 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
394 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
398 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
402 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
406 else if ( fdType[0] == 'p' ) {
408 ashort = (fdType[2] * 256) + fdType[3];
422 memcpy(data, &ashort, sizeof( ashort ));
423 data += sizeof( ashort );
424 memset(data, 0, sizeof( ashort ));
425 data += sizeof( ashort );
428 case FILPBIT_EXTDFLEN:
429 aint = htonl(st->st_size >> 32);
430 memcpy(data, &aint, sizeof( aint ));
431 data += sizeof( aint );
432 aint = htonl(st->st_size);
433 memcpy(data, &aint, sizeof( aint ));
434 data += sizeof( aint );
436 case FILPBIT_EXTRFLEN:
439 aint = htonl(adp->ad_rlen >> 32);
440 memcpy(data, &aint, sizeof( aint ));
441 data += sizeof( aint );
443 aint = htonl(adp->ad_rlen);
444 memcpy(data, &aint, sizeof( aint ));
445 data += sizeof( aint );
447 case FILPBIT_UNIXPR :
448 /* accessmode may change st_mode with ACLs */
449 accessmode( upath, &ma, dir , st);
451 aint = htonl(st->st_uid);
452 memcpy( data, &aint, sizeof( aint ));
453 data += sizeof( aint );
454 aint = htonl(st->st_gid);
455 memcpy( data, &aint, sizeof( aint ));
456 data += sizeof( aint );
459 type == slnk indicates an OSX style symlink,
460 we have to add S_IFLNK to the mode, otherwise
461 10.3 clients freak out. */
465 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
466 if ( memcmp( fdType, "slnk", 4 ) == 0 ) {
472 memcpy( data, &aint, sizeof( aint ));
473 data += sizeof( aint );
475 *data++ = ma.ma_user;
476 *data++ = ma.ma_world;
477 *data++ = ma.ma_group;
478 *data++ = ma.ma_owner;
482 return( AFPERR_BITMAP );
488 ashort = htons( data - buf );
489 memcpy(l_nameoff, &ashort, sizeof( ashort ));
490 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
493 ashort = htons( data - buf );
494 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
495 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
497 *buflen = data - buf;
501 /* ----------------------- */
502 int getfilparams(struct vol *vol,
504 struct path *path, struct dir *dir,
505 char *buf, size_t *buflen )
507 struct adouble ad, *adp;
512 LOG(log_debug9, logtype_default, "begin getfilparams:");
515 opened = PARAM_NEED_ADP(bitmap);
520 int flags = (bitmap & (1 << FILPBIT_ATTR))?ADFLAGS_OPENFORKS:0;
522 adp = of_ad(vol, path, &ad);
523 upath = path->u_name;
525 if ( ad_metadata( upath, vol_noadouble(vol) | flags, adp) < 0 ) {
528 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
529 upath, strerror(errno));
530 return AFPERR_ACCESS;
532 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
541 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp);
543 ad_close_metadata( adp);
546 LOG(log_debug9, logtype_afpd, "end getfilparams:");
552 /* ----------------------------- */
553 int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
555 struct adouble ad, *adp;
558 struct ofork *of = NULL;
560 int creatf, did, openf, retvalue = AFP_OK;
566 creatf = (unsigned char) *ibuf++;
568 memcpy(&vid, ibuf, sizeof( vid ));
569 ibuf += sizeof( vid );
571 if (NULL == ( vol = getvolbyvid( vid )) ) {
572 return( AFPERR_PARAM );
575 if (vol->v_flags & AFPVOL_RO)
578 memcpy(&did, ibuf, sizeof( did));
579 ibuf += sizeof( did );
581 if (NULL == ( dir = dirlookup( vol, did )) ) {
585 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
586 return get_afp_errno(AFPERR_PARAM);
589 if ( *s_path->m_name == '\0' ) {
590 return( AFPERR_BADTYPE );
593 upath = s_path->u_name;
595 /* if upath is deleted we already in trouble anyway */
596 if ((of = of_findname(s_path))) {
599 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
603 /* on a hard create, fail if file exists and is open */
606 openf = O_RDWR|O_CREAT|O_TRUNC;
608 /* on a soft create, if the file is open then ad_open won't fail
609 because open syscall is not called
614 openf = O_RDWR|O_CREAT|O_EXCL;
617 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF|ADFLAGS_CREATE,
618 openf, 0666, adp) < 0 ) {
622 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
623 return ( AFPERR_NOOBJ );
625 return( AFPERR_EXIST );
627 return( AFPERR_ACCESS );
630 return( AFPERR_DFULL );
632 return( AFPERR_PARAM );
635 if ( ad_reso_fileno( adp ) == -1 ) { /* Hard META / HF */
636 /* on noadouble volumes, just creating the data fork is ok */
637 if (vol_noadouble(vol)) {
638 ad_close( adp, ADFLAGS_DF );
639 goto createfile_done;
641 /* FIXME with hard create on an existing file, we already
642 * corrupted the data file.
644 netatalk_unlink( upath );
645 ad_close( adp, ADFLAGS_DF );
646 return AFPERR_ACCESS;
649 path = s_path->m_name;
650 ad_setname(adp, path);
652 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
658 if (vol->v_flags & AFPVOL_DROPBOX) {
659 retvalue = matchfile2dirperms(upath, vol, did);
661 #endif /* DROPKLUDGE */
663 setvoltime(obj, vol );
668 int afp_setfilparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
674 u_int16_t vid, bitmap;
679 memcpy(&vid, ibuf, sizeof( vid ));
680 ibuf += sizeof( vid );
681 if (NULL == ( vol = getvolbyvid( vid )) ) {
682 return( AFPERR_PARAM );
685 if (vol->v_flags & AFPVOL_RO)
688 memcpy(&did, ibuf, sizeof( did ));
689 ibuf += sizeof( did );
690 if (NULL == ( dir = dirlookup( vol, did )) ) {
691 return afp_errno; /* was AFPERR_NOOBJ */
694 memcpy(&bitmap, ibuf, sizeof( bitmap ));
695 bitmap = ntohs( bitmap );
696 ibuf += sizeof( bitmap );
698 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
699 return get_afp_errno(AFPERR_PARAM);
702 if (path_isadir(s_path)) {
703 return( AFPERR_BADTYPE ); /* it's a directory */
706 if ( s_path->st_errno != 0 ) {
707 return( AFPERR_NOOBJ );
710 if ((u_long)ibuf & 1 ) {
714 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
715 setvoltime(obj, vol );
722 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
725 extern struct path Cur_Path;
727 int setfilparams(struct vol *vol,
728 struct path *path, u_int16_t f_bitmap, char *buf )
730 struct adouble ad, *adp;
732 int bit, isad = 1, err = AFP_OK;
734 u_char achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
735 u_int16_t ashort, bshort;
738 u_int16_t upriv_bit = 0;
742 int change_mdate = 0;
743 int change_parent_mdate = 0;
748 u_int16_t bitmap = f_bitmap;
749 u_int32_t cdate,bdate;
750 u_char finder_buf[32];
753 LOG(log_debug9, logtype_afpd, "begin setfilparams:");
756 adp = of_ad(vol, path, &ad);
757 upath = path->u_name;
759 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
760 return AFPERR_ACCESS;
763 /* with unix priv maybe we have to change adouble file priv first */
765 while ( bitmap != 0 ) {
766 while (( bitmap & 1 ) == 0 ) {
773 memcpy(&ashort, buf, sizeof( ashort ));
774 buf += sizeof( ashort );
778 memcpy(&cdate, buf, sizeof(cdate));
779 buf += sizeof( cdate );
782 memcpy(&newdate, buf, sizeof( newdate ));
783 buf += sizeof( newdate );
787 memcpy(&bdate, buf, sizeof( bdate));
788 buf += sizeof( bdate );
792 memcpy(finder_buf, buf, 32 );
795 case FILPBIT_UNIXPR :
796 if (!vol_unix_priv(vol)) {
797 /* this volume doesn't use unix priv */
803 change_parent_mdate = 1;
805 memcpy( &aint, buf, sizeof( aint ));
806 f_uid = ntohl (aint);
807 buf += sizeof( aint );
808 memcpy( &aint, buf, sizeof( aint ));
809 f_gid = ntohl (aint);
810 buf += sizeof( aint );
811 setfilowner(vol, f_uid, f_gid, path);
813 memcpy( &upriv, buf, sizeof( upriv ));
814 buf += sizeof( upriv );
815 upriv = ntohl (upriv);
816 if ((upriv & S_IWUSR)) {
817 setfilunixmode(vol, path, upriv);
824 case FILPBIT_PDINFO :
825 if (afp_version < 30) { /* else it's UTF8 name */
828 /* Keep special case to support crlf translations */
829 if ((unsigned int) achar == 0x04) {
830 fdType = (u_char *)"TEXT";
833 xyy[0] = ( u_char ) 'p';
844 /* break while loop */
853 /* second try with adouble open
855 if ( ad_open_metadata( upath, vol_noadouble(vol), O_CREAT, adp) < 0) {
856 LOG(log_debug, logtype_afpd, "setfilparams: ad_open_metadata error");
858 * For some things, we don't need an adouble header:
859 * - change of modification date
860 * - UNIX privs (Bug-ID #2863424)
862 if ( (f_bitmap & ~(1<<FILPBIT_MDATE | 1<<FILPBIT_UNIXPR))) {
863 LOG(log_debug, logtype_afpd, "setfilparams: need adouble access");
864 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
866 LOG(log_debug, logtype_afpd, "setfilparams: no adouble perms, but only FILPBIT_MDATE and/or FILPBIT_UNIXPR");
868 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
869 ad_setname(adp, path->m_name);
874 while ( bitmap != 0 ) {
875 while (( bitmap & 1 ) == 0 ) {
882 ad_getattr(adp, &bshort);
883 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
884 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
885 change_parent_mdate = 1;
886 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
887 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
891 ad_setattr(adp, bshort);
894 ad_setdate(adp, AD_DATE_CREATE, cdate);
899 ad_setdate(adp, AD_DATE_BACKUP, bdate);
902 if (default_type( ad_entry( adp, ADEID_FINDERI ))
904 ((em = getextmap( path->m_name )) &&
905 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
906 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
907 || ((em = getdefextmap()) &&
908 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
909 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
911 memcpy(finder_buf, ufinderi, 8 );
913 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
915 case FILPBIT_UNIXPR :
917 setfilunixmode(vol, path, upriv);
920 case FILPBIT_PDINFO :
921 if (afp_version < 30) { /* else it's UTF8 name */
922 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
923 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
929 goto setfilparam_done;
936 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
937 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
941 ad_setdate(adp, AD_DATE_MODIFY, newdate);
942 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
948 ad_close_metadata( adp);
952 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
953 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
954 bitmap = 1<<FILPBIT_MDATE;
955 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
959 LOG(log_debug9, logtype_afpd, "end setfilparams:");
965 * renamefile and copyfile take the old and new unix pathnames
966 * and the new mac name.
968 * src the source path
969 * dst the dest filename in current dir
970 * newname the dest mac name
971 * adp adouble struct of src file, if open, or & zeroed one
974 int renamefile(const struct vol *vol, char *src, char *dst, char *newname, struct adouble *adp)
979 LOG(log_debug9, logtype_afpd, "begin renamefile:");
982 if ( unix_rename( src, dst ) < 0 ) {
985 return( AFPERR_NOOBJ );
988 return( AFPERR_ACCESS );
991 case EXDEV : /* Cross device move -- try copy */
992 /* NOTE: with open file it's an error because after the copy we will
993 * get two files, it's fixable for our process (eg reopen the new file, get the
994 * locks, and so on. But it doesn't solve the case with a second process
996 if (adp->ad_open_forks) {
997 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
998 return AFPERR_OLOCK; /* little lie */
1000 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1001 /* on error copyfile delete dest */
1004 return deletefile(vol, src, 0);
1006 return( AFPERR_PARAM );
1010 if (vol->vfs->vfs_renamefile(vol, src, dst) < 0 ) {
1014 /* try to undo the data fork rename,
1015 * we know we are on the same device
1018 unix_rename( dst, src );
1019 /* return the first error */
1022 return AFPERR_NOOBJ;
1025 return AFPERR_ACCESS ;
1027 return AFPERR_VLOCK;
1029 return AFPERR_PARAM ;
1034 /* don't care if we can't open the newly renamed ressource fork
1036 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1037 ad_setname(adp, newname);
1039 ad_close( adp, ADFLAGS_HF );
1042 LOG(log_debug9, logtype_afpd, "end renamefile:");
1049 convert a Mac long name to an utf8 name,
1051 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1055 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1061 /* ---------------- */
1062 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1069 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1075 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1076 if (afp_version >= 30) {
1077 /* convert it to UTF8
1079 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1)
1083 strncpy( newname, ibuf, plen );
1084 newname[ plen ] = '\0';
1086 if (strlen(newname) != plen) {
1087 /* there's \0 in newname, e.g. it's a pathname not
1095 memcpy(&hint, ibuf, sizeof(hint));
1096 ibuf += sizeof(hint);
1098 memcpy(&len16, ibuf, sizeof(len16));
1099 ibuf += sizeof(len16);
1100 plen = ntohs(len16);
1103 if (plen > AFPOBJ_TMPSIZ) {
1106 strncpy( newname, ibuf, plen );
1107 newname[ plen ] = '\0';
1108 if (strlen(newname) != plen) {
1117 /* -----------------------------------
1119 int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1121 struct vol *s_vol, *d_vol;
1123 char *newname, *p, *upath;
1124 struct path *s_path;
1125 u_int32_t sdid, ddid;
1126 int err, retvalue = AFP_OK;
1127 u_int16_t svid, dvid;
1129 struct adouble ad, *adp;
1135 memcpy(&svid, ibuf, sizeof( svid ));
1136 ibuf += sizeof( svid );
1137 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1138 return( AFPERR_PARAM );
1141 memcpy(&sdid, ibuf, sizeof( sdid ));
1142 ibuf += sizeof( sdid );
1143 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1147 memcpy(&dvid, ibuf, sizeof( dvid ));
1148 ibuf += sizeof( dvid );
1149 memcpy(&ddid, ibuf, sizeof( ddid ));
1150 ibuf += sizeof( ddid );
1152 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1153 return get_afp_errno(AFPERR_PARAM);
1155 if ( path_isadir(s_path) ) {
1156 return( AFPERR_BADTYPE );
1159 /* don't allow copies when the file is open.
1160 * XXX: the spec only calls for read/deny write access.
1161 * however, copyfile doesn't have any of that info,
1162 * and locks need to stay coherent. as a result,
1163 * we just balk if the file is opened already. */
1165 adp = of_ad(s_vol, s_path, &ad);
1167 if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1168 return AFPERR_DENYCONF;
1170 denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
1171 getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1172 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1174 return AFPERR_DENYCONF;
1177 newname = obj->newtmp;
1178 strcpy( newname, s_path->m_name );
1180 p = ctoupath( s_vol, curdir, newname );
1182 return AFPERR_PARAM;
1186 /* FIXME svid != dvid && dvid's user can't read svid */
1188 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1189 return( AFPERR_PARAM );
1192 if (d_vol->v_flags & AFPVOL_RO)
1193 return AFPERR_VLOCK;
1195 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1199 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1200 return get_afp_errno(AFPERR_NOOBJ);
1202 if ( *s_path->m_name != '\0' ) {
1203 path_error(s_path, AFPERR_PARAM);
1206 /* one of the handful of places that knows about the path type */
1207 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1208 return( AFPERR_PARAM );
1210 /* newname is always only a filename so curdir *is* its
1213 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1214 return( AFPERR_PARAM );
1216 if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1222 if (vol->v_flags & AFPVOL_DROPBOX) {
1223 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1225 #endif /* DROPKLUDGE */
1227 setvoltime(obj, d_vol );
1232 /* ----------------------- */
1233 static int copy_all(const int dfd, const void *buf,
1239 LOG(log_debug9, logtype_afpd, "begin copy_all:");
1242 while (buflen > 0) {
1243 if ((cc = write(dfd, buf, buflen)) < 0) {
1255 LOG(log_debug9, logtype_afpd, "end copy_all:");
1261 /* --------------------------
1262 * copy only the fork data stream
1264 static int copy_fork(int eid, struct adouble *add, struct adouble *ads)
1271 if (eid == ADEID_DFORK) {
1272 sfd = ad_data_fileno(ads);
1273 dfd = ad_data_fileno(add);
1276 sfd = ad_reso_fileno(ads);
1277 dfd = ad_reso_fileno(add);
1280 if ((off_t)-1 == lseek(sfd, ad_getentryoff(ads, eid), SEEK_SET))
1283 if ((off_t)-1 == lseek(dfd, ad_getentryoff(add, eid), SEEK_SET))
1286 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1287 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1291 #define BUF 128*1024*1024
1293 if (fstat(sfd, &st) == 0) {
1296 if ( offset >= st.st_size) {
1299 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1300 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1303 case EINVAL: /* there's no guarantee that all fs support sendfile */
1312 lseek(sfd, offset, SEEK_SET);
1316 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1323 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1330 /* ----------------------------------
1331 * if newname is NULL (from directory.c) we don't want to copy the resource fork.
1332 * because we are doing it elsewhere.
1333 * currently if newname is NULL then adp is NULL.
1335 int copyfile(const struct vol *s_vol, const struct vol*d_vol,
1336 char *src, char *dst, char *newname, struct adouble *adp)
1338 struct adouble ads, add;
1346 LOG(log_debug9, logtype_afpd, "begin copyfile:");
1350 ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options);
1353 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1354 adflags = ADFLAGS_DF;
1356 adflags |= ADFLAGS_HF;
1359 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1364 if (ad_meta_fileno(adp) == -1 && ad_reso_fileno(adp) == -1) { /* META / HF */
1365 /* no resource fork, don't create one for dst file */
1366 adflags &= ~ADFLAGS_HF;
1369 stat_result = fstat(ad_data_fileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */
1371 if (stat_result < 0) {
1372 /* unlikely but if fstat fails, the default file mode will be 0666. */
1373 st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
1376 if (ad_open(dst , adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
1378 ad_close( adp, adflags );
1379 if (EEXIST != ret_err) {
1380 deletefile(d_vol, dst, 0);
1383 return AFPERR_EXIST;
1387 * XXX if the source and the dest don't use the same resource type it's broken
1389 if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){
1390 /* copy the data fork */
1391 if ((err = copy_fork(ADEID_DFORK, &add, adp)) == 0) {
1392 err = d_vol->vfs->vfs_copyfile(d_vol, src, dst);
1400 if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
1401 /* set the new name in the resource fork */
1402 ad_copy_header(&add, adp);
1403 ad_setname(&add, newname);
1406 ad_close( adp, adflags );
1408 if (ad_close( &add, adflags ) <0) {
1413 deletefile(d_vol, dst, 0);
1415 else if (stat_result == 0) {
1416 /* set dest modification date to src date */
1419 ut.actime = ut.modtime = st.st_mtime;
1421 /* FIXME netatalk doesn't use resource fork file date
1422 * but maybe we should set its modtime too.
1427 LOG(log_debug9, logtype_afpd, "end copyfile:");
1431 switch ( ret_err ) {
1437 return AFPERR_DFULL;
1439 return AFPERR_NOOBJ;
1441 return AFPERR_ACCESS;
1443 return AFPERR_VLOCK;
1445 return AFPERR_PARAM;
1449 /* -----------------------------------
1450 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1451 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1453 when deletefile is called we don't have lock on it, file is closed (for us)
1454 untrue if called by renamefile
1456 ad_open always try to open file RDWR first and ad_lock takes care of
1457 WRITE lock on read only file.
1460 static int check_attrib(struct adouble *adp)
1462 u_int16_t bshort = 0;
1464 ad_getattr(adp, &bshort);
1466 * Does kFPDeleteInhibitBit (bit 8) set?
1468 if ((bshort & htons(ATTRBIT_NODELETE))) {
1469 return AFPERR_OLOCK;
1471 if ((bshort & htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN))) {
1477 int deletefile(const struct vol *vol, char *file, int checkAttrib)
1480 struct adouble *adp = &ad;
1481 int adflags, err = AFP_OK;
1484 LOG(log_debug9, logtype_afpd, "begin deletefile:");
1487 /* try to open both forks at once */
1488 adflags = ADFLAGS_DF|ADFLAGS_HF;
1490 /* was EACCESS error try to get only metadata */
1491 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1492 /* we never want to create a resource fork here, we are going to delete it
1493 * moreover sometimes deletefile is called with a no existent file and
1494 * ad_open would create a 0 byte resource fork
1496 if ( ad_metadata( file , ADFLAGS_NOADOUBLE | ADFLAGS_OPENFORKS, &ad) == 0 ) {
1497 ad_close( &ad, adflags );
1498 if ((err = check_attrib(&ad))) {
1505 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1506 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1509 if (adflags == ADFLAGS_DF)
1510 return AFPERR_NOOBJ;
1512 /* that failed. now try to open just the data fork */
1513 adflags = ADFLAGS_DF;
1517 adp = NULL; /* maybe it's a file with no write mode for us */
1518 break; /* was return AFPERR_ACCESS;*/
1520 return AFPERR_VLOCK;
1522 return( AFPERR_PARAM );
1525 break; /* from the while */
1528 if (adp && (adflags & ADFLAGS_HF) ) {
1529 /* FIXME we have a pb here because we want to know if a file is open
1530 * there's a 'priority inversion' if you can't open the ressource fork RW
1531 * you can delete it if it's open because you can't get a write lock.
1533 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1536 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1538 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1539 ad_close( &ad, adflags );
1540 return( AFPERR_BUSY );
1544 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1547 else if (!(err = vol->vfs->vfs_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
1549 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1551 cnid_delete(vol->v_cdb, id);
1555 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1558 LOG(log_debug9, logtype_afpd, "end deletefile:");
1564 /* ------------------------------------ */
1565 /* return a file id */
1566 int afp_createid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1575 struct path *s_path;
1581 memcpy(&vid, ibuf, sizeof(vid));
1582 ibuf += sizeof(vid);
1584 if (NULL == ( vol = getvolbyvid( vid )) ) {
1585 return( AFPERR_PARAM);
1588 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1592 if (vol->v_flags & AFPVOL_RO)
1593 return AFPERR_VLOCK;
1595 memcpy(&did, ibuf, sizeof( did ));
1596 ibuf += sizeof(did);
1598 if (NULL == ( dir = dirlookup( vol, did )) ) {
1599 return afp_errno; /* was AFPERR_PARAM */
1602 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1603 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1606 if ( path_isadir(s_path) ) {
1607 return( AFPERR_BADTYPE );
1610 upath = s_path->u_name;
1611 switch (s_path->st_errno) {
1613 break; /* success */
1616 return AFPERR_ACCESS;
1618 return AFPERR_NOOBJ;
1620 return AFPERR_PARAM;
1623 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1624 memcpy(rbuf, &id, sizeof(id));
1625 *rbuflen = sizeof(id);
1626 return AFPERR_EXISTID;
1629 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1630 memcpy(rbuf, &id, sizeof(id));
1631 *rbuflen = sizeof(id);
1638 /* ------------------------------- */
1644 static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
1647 struct reenum *param = data;
1648 struct vol *vol = param->vol;
1649 cnid_t did = param->did;
1652 if ( stat(de->d_name, &path.st)<0 )
1655 /* update or add to cnid */
1656 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1658 #if AD_VERSION > AD_VERSION1
1659 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1660 struct adouble ad, *adp;
1664 path.u_name = de->d_name;
1666 adp = of_ad(vol, &path, &ad);
1668 if ( ad_open_metadata( de->d_name, 0, 0, adp ) < 0 ) {
1671 if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1674 ad_close_metadata(adp);
1676 #endif /* AD_VERSION > AD_VERSION1 */
1681 /* --------------------
1682 * Ok the db is out of synch with the dir.
1683 * but if it's a deleted file we don't want to do it again and again.
1686 reenumerate_id(struct vol *vol, char *name, struct dir *dir)
1692 if (vol->v_cdb == NULL) {
1696 /* FIXME use of_statdir ? */
1697 if (stat(name, &st)) {
1701 if (dirreenumerate(dir, &st)) {
1702 /* we already did it once and the dir haven't been modified */
1707 data.did = dir->d_did;
1708 if ((ret = for_each_dirent(vol, name, reenumerate_loop, (void *)&data)) >= 0) {
1709 setdiroffcnt(curdir, &st, ret);
1710 dir->d_flags |= DIRF_CNID;
1716 /* ------------------------------
1717 resolve a file id */
1718 int afp_resolveid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1727 u_int16_t vid, bitmap;
1729 static char buffer[12 + MAXPATHLEN + 1];
1730 int len = 12 + MAXPATHLEN + 1;
1735 memcpy(&vid, ibuf, sizeof(vid));
1736 ibuf += sizeof(vid);
1738 if (NULL == ( vol = getvolbyvid( vid )) ) {
1739 return( AFPERR_PARAM);
1742 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1746 memcpy(&id, ibuf, sizeof( id ));
1751 /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
1755 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1756 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1759 if (NULL == ( dir = dirlookup( vol, id )) ) {
1760 return AFPERR_NOID; /* idem AFPERR_PARAM */
1762 if (movecwd(vol, dir) < 0) {
1766 return AFPERR_ACCESS;
1770 return AFPERR_PARAM;
1774 memset(&path, 0, sizeof(path));
1775 path.u_name = upath;
1776 if ( of_stat(&path) < 0 ) {
1778 /* with nfs and our working directory is deleted */
1779 if (errno == ESTALE) {
1783 if ( errno == ENOENT && !retry) {
1784 /* cnid db is out of sync, reenumerate the directory and update ids */
1785 reenumerate_id(vol, ".", dir);
1793 return AFPERR_ACCESS;
1797 return AFPERR_PARAM;
1801 /* directories are bad */
1802 if (S_ISDIR(path.st.st_mode)) {
1803 /* OS9 and OSX don't return the same error code */
1804 return (afp_version >=30)?AFPERR_NOID:AFPERR_BADTYPE;
1807 memcpy(&bitmap, ibuf, sizeof(bitmap));
1808 bitmap = ntohs( bitmap );
1809 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1813 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1814 rbuf + sizeof(bitmap), &buflen))) {
1817 *rbuflen = buflen + sizeof(bitmap);
1818 memcpy(rbuf, ibuf, sizeof(bitmap));
1823 /* ------------------------------ */
1824 int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1834 static char buffer[12 + MAXPATHLEN + 1];
1835 int len = 12 + MAXPATHLEN + 1;
1840 memcpy(&vid, ibuf, sizeof(vid));
1841 ibuf += sizeof(vid);
1843 if (NULL == ( vol = getvolbyvid( vid )) ) {
1844 return( AFPERR_PARAM);
1847 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1851 if (vol->v_flags & AFPVOL_RO)
1852 return AFPERR_VLOCK;
1854 memcpy(&id, ibuf, sizeof( id ));
1858 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1862 if (NULL == ( dir = dirlookup( vol, id )) ) {
1863 return( AFPERR_PARAM );
1867 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1871 return AFPERR_ACCESS;
1876 /* still try to delete the id */
1880 return AFPERR_PARAM;
1883 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1884 return AFPERR_BADTYPE;
1886 if (cnid_delete(vol->v_cdb, fileid)) {
1889 return AFPERR_VLOCK;
1892 return AFPERR_ACCESS;
1894 return AFPERR_PARAM;
1901 /* ------------------------------ */
1902 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1906 if (path->st_errno) {
1907 switch (path->st_errno) {
1909 afp_errno = AFPERR_NOID;
1913 afp_errno = AFPERR_ACCESS;
1916 afp_errno = AFPERR_PARAM;
1921 /* we use file_access both for legacy Mac perm and
1922 * for unix privilege, rename will take care of folder perms
1924 if (file_access(path, OPENACC_WR ) < 0) {
1925 afp_errno = AFPERR_ACCESS;
1929 if ((*of = of_findname(path))) {
1930 /* reuse struct adouble so it won't break locks */
1934 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
1936 if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
1938 * The user must have the Read & Write privilege for both files in order to use this command.
1940 ad_close(adp, ADFLAGS_HF);
1941 afp_errno = AFPERR_ACCESS;
1948 #define APPLETEMP ".AppleTempXXXXXX"
1950 int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1952 struct stat srcst, destst;
1954 struct dir *dir, *sdir;
1955 char *spath, temp[17], *p;
1956 char *supath, *upath;
1961 struct adouble *adsp = NULL;
1962 struct adouble *addp = NULL;
1963 struct ofork *s_of = NULL;
1964 struct ofork *d_of = NULL;
1977 memcpy(&vid, ibuf, sizeof(vid));
1978 ibuf += sizeof(vid);
1980 if (NULL == ( vol = getvolbyvid( vid )) ) {
1981 return( AFPERR_PARAM);
1984 if ((vol->v_flags & AFPVOL_RO))
1985 return AFPERR_VLOCK;
1987 /* source and destination dids */
1988 memcpy(&sid, ibuf, sizeof(sid));
1989 ibuf += sizeof(sid);
1990 memcpy(&did, ibuf, sizeof(did));
1991 ibuf += sizeof(did);
1994 if (NULL == (dir = dirlookup( vol, sid )) ) {
1995 return afp_errno; /* was AFPERR_PARAM */
1998 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1999 return get_afp_errno(AFPERR_NOOBJ);
2002 if ( path_isadir(path) ) {
2003 return AFPERR_BADTYPE; /* it's a dir */
2006 /* save some stuff */
2009 spath = obj->oldtmp;
2010 supath = obj->newtmp;
2011 strcpy(spath, path->m_name);
2012 strcpy(supath, path->u_name); /* this is for the cnid changing */
2013 p = absupath( vol, sdir, supath);
2015 /* pathname too long */
2016 return AFPERR_PARAM ;
2019 ad_init(&ads, vol->v_adouble, vol->v_ad_options);
2020 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2024 /* ***** from here we may have resource fork open **** */
2026 /* look for the source cnid. if it doesn't exist, don't worry about
2028 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2030 if (NULL == ( dir = dirlookup( vol, did )) ) {
2031 err = afp_errno; /* was AFPERR_PARAM */
2032 goto err_exchangefile;
2035 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2036 err = get_afp_errno(AFPERR_NOOBJ);
2037 goto err_exchangefile;
2040 if ( path_isadir(path) ) {
2041 err = AFPERR_BADTYPE;
2042 goto err_exchangefile;
2045 /* FPExchangeFiles is the only call that can return the SameObj
2047 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2048 err = AFPERR_SAMEOBJ;
2049 goto err_exchangefile;
2052 ad_init(&add, vol->v_adouble, vol->v_ad_options);
2053 if (!(addp = find_adouble( path, &d_of, &add))) {
2055 goto err_exchangefile;
2059 /* they are not on the same device and at least one is open
2060 * FIXME broken for for crossdev and adouble v2
2063 crossdev = (srcst.st_dev != destst.st_dev);
2064 if (/* (d_of || s_of) && */ crossdev) {
2066 goto err_exchangefile;
2069 /* look for destination id. */
2070 upath = path->u_name;
2071 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2073 /* construct a temp name.
2074 * NOTE: the temp file will be in the dest file's directory. it
2075 * will also be inaccessible from AFP. */
2076 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2077 if (!mktemp(temp)) {
2079 goto err_exchangefile;
2083 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2084 ad_close(adsp, ADFLAGS_HF);
2085 ad_close(addp, ADFLAGS_HF);
2088 /* now, quickly rename the file. we error if we can't. */
2089 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2090 goto err_exchangefile;
2091 of_rename(vol, s_of, sdir, spath, curdir, temp);
2093 /* rename destination to source */
2094 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2095 goto err_src_to_tmp;
2096 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2098 /* rename temp to destination */
2099 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2100 goto err_dest_to_src;
2101 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2103 /* id's need switching. src -> dest and dest -> src.
2104 * we need to re-stat() if it was a cross device copy.
2107 cnid_delete(vol->v_cdb, sid);
2110 cnid_delete(vol->v_cdb, did);
2112 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2113 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2115 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2116 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2121 err = AFPERR_ACCESS;
2126 goto err_temp_to_dest;
2129 /* here we need to reopen if crossdev */
2130 if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2135 if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2140 /* change perms, src gets dest perm and vice versa */
2145 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2146 err = AFP_OK; /* ignore error */
2147 goto err_temp_to_dest;
2151 * we need to exchange ACL entries as well
2153 /* exchange_acls(vol, p, upath); */
2158 path->m_name = NULL;
2159 path->u_name = upath;
2161 setfilunixmode(vol, path, destst.st_mode);
2162 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2169 setfilunixmode(vol, path, srcst.st_mode);
2170 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2172 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2173 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2178 goto err_exchangefile;
2180 /* all this stuff is so that we can unwind a failed operation
2183 /* rename dest to temp */
2184 renamefile(vol, upath, temp, temp, adsp);
2185 of_rename(vol, s_of, curdir, upath, curdir, temp);
2188 /* rename source back to dest */
2189 renamefile(vol, p, upath, path->m_name, addp);
2190 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2193 /* rename temp back to source */
2194 renamefile(vol, temp, p, spath, adsp);
2195 of_rename(vol, s_of, curdir, temp, sdir, spath);
2198 if ( !s_of && adsp && ad_meta_fileno(adsp) != -1 ) { /* META */
2199 ad_close(adsp, ADFLAGS_HF);
2201 if ( !d_of && addp && ad_meta_fileno(addp) != -1 ) {/* META */
2202 ad_close(addp, ADFLAGS_HF);