2 * $Id: file.c,v 1.118 2009-10-29 13:17:28 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 */
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_mac?htonl(vol->v_mac->kTextEncoding):0; /* htonl(utf8) */
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 AD_VERSION > AD_VERSION1
200 if ((aint = ad_getid(adp, st->st_dev, st->st_ino, did, vol->v_stamp))) {
205 if (vol->v_cdb != NULL) {
206 aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
207 /* Throw errors if cnid_add fails. */
208 if (aint == CNID_INVALID) {
210 case CNID_ERR_CLOSE: /* the db is closed */
213 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
214 afp_errno = AFPERR_PARAM;
217 afp_errno = AFPERR_PARAM;
220 afp_errno = AFPERR_MISC;
224 #if AD_VERSION > AD_VERSION1
226 /* update the ressource fork
227 * for a folder adp is always null
229 if (ad_setid(adp, st->st_dev, st->st_ino, aint, did, vol->v_stamp)) {
238 /* -------------------------- */
239 int getmetadata(struct vol *vol,
241 struct path *path, struct dir *dir,
242 char *buf, size_t *buflen, struct adouble *adp)
244 char *data, *l_nameoff = NULL, *upath;
245 char *utf_nameoff = NULL;
250 u_char achar, fdType[4];
256 LOG(log_debug, logtype_afpd, "begin getmetadata:");
259 upath = path->u_name;
264 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
265 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
266 || (bitmap & (1 << FILPBIT_FNUM))) {
268 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
274 path->m_name = utompath(vol, upath, id, utf8_encoding());
277 while ( bitmap != 0 ) {
278 while (( bitmap & 1 ) == 0 ) {
286 ad_getattr(adp, &ashort);
287 } else if (vol_inv_dots(vol) && *upath == '.') {
288 ashort = htons(ATTRBIT_INVISIBLE);
292 /* FIXME do we want a visual clue if the file is read only
295 accessmode( ".", &ma, dir , NULL);
296 if ((ma.ma_user & AR_UWRITE)) {
297 accessmode( upath, &ma, dir , st);
298 if (!(ma.ma_user & AR_UWRITE)) {
299 ashort |= htons(ATTRBIT_NOWRITE);
303 memcpy(data, &ashort, sizeof( ashort ));
304 data += sizeof( ashort );
308 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
309 data += sizeof( u_int32_t );
313 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
314 aint = AD_DATE_FROM_UNIX(st->st_mtime);
315 memcpy(data, &aint, sizeof( aint ));
316 data += sizeof( aint );
320 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
321 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
322 aint = AD_DATE_FROM_UNIX(st->st_mtime);
325 aint = AD_DATE_FROM_UNIX(st->st_mtime);
327 memcpy(data, &aint, sizeof( int ));
328 data += sizeof( int );
332 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
333 aint = AD_DATE_START;
334 memcpy(data, &aint, sizeof( int ));
335 data += sizeof( int );
339 get_finderinfo(vol, upath, adp, (char *)data);
340 data += ADEDLEN_FINDERI;
345 data += sizeof( u_int16_t );
349 memset(data, 0, sizeof(u_int16_t));
350 data += sizeof( u_int16_t );
354 memcpy(data, &id, sizeof( id ));
355 data += sizeof( id );
359 if (st->st_size > 0xffffffff)
362 aint = htonl( st->st_size );
363 memcpy(data, &aint, sizeof( aint ));
364 data += sizeof( aint );
369 if (adp->ad_rlen > 0xffffffff)
372 aint = htonl( adp->ad_rlen);
376 memcpy(data, &aint, sizeof( aint ));
377 data += sizeof( aint );
380 /* Current client needs ProDOS info block for this file.
381 Use simple heuristic and let the Mac "type" string tell
382 us what the PD file code should be. Everything gets a
383 subtype of 0x0000 unless the original value was hashed
384 to "pXYZ" when we created it. See IA, Ver 2.
385 <shirsch@adelphia.net> */
386 case FILPBIT_PDINFO :
387 if (afp_version >= 30) { /* UTF8 name */
388 utf8 = kTextEncodingUTF8;
390 data += sizeof( u_int16_t );
392 memcpy(data, &aint, sizeof( aint ));
393 data += sizeof( aint );
397 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
399 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
403 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
407 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
411 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
415 else if ( fdType[0] == 'p' ) {
417 ashort = (fdType[2] * 256) + fdType[3];
431 memcpy(data, &ashort, sizeof( ashort ));
432 data += sizeof( ashort );
433 memset(data, 0, sizeof( ashort ));
434 data += sizeof( ashort );
437 case FILPBIT_EXTDFLEN:
438 aint = htonl(st->st_size >> 32);
439 memcpy(data, &aint, sizeof( aint ));
440 data += sizeof( aint );
441 aint = htonl(st->st_size);
442 memcpy(data, &aint, sizeof( aint ));
443 data += sizeof( aint );
445 case FILPBIT_EXTRFLEN:
448 aint = htonl(adp->ad_rlen >> 32);
449 memcpy(data, &aint, sizeof( aint ));
450 data += sizeof( aint );
452 aint = htonl(adp->ad_rlen);
453 memcpy(data, &aint, sizeof( aint ));
454 data += sizeof( aint );
456 case FILPBIT_UNIXPR :
457 /* accessmode may change st_mode with ACLs */
458 accessmode( upath, &ma, dir , st);
460 aint = htonl(st->st_uid);
461 memcpy( data, &aint, sizeof( aint ));
462 data += sizeof( aint );
463 aint = htonl(st->st_gid);
464 memcpy( data, &aint, sizeof( aint ));
465 data += sizeof( aint );
468 type == slnk indicates an OSX style symlink,
469 we have to add S_IFLNK to the mode, otherwise
470 10.3 clients freak out. */
474 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
475 if ( memcmp( fdType, "slnk", 4 ) == 0 ) {
481 memcpy( data, &aint, sizeof( aint ));
482 data += sizeof( aint );
484 *data++ = ma.ma_user;
485 *data++ = ma.ma_world;
486 *data++ = ma.ma_group;
487 *data++ = ma.ma_owner;
491 return( AFPERR_BITMAP );
497 ashort = htons( data - buf );
498 memcpy(l_nameoff, &ashort, sizeof( ashort ));
499 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
502 ashort = htons( data - buf );
503 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
504 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
506 *buflen = data - buf;
510 /* ----------------------- */
511 int getfilparams(struct vol *vol,
513 struct path *path, struct dir *dir,
514 char *buf, size_t *buflen )
516 struct adouble ad, *adp;
523 LOG(log_debug, logtype_default, "begin getfilparams:");
526 opened = PARAM_NEED_ADP(bitmap);
530 int flags = (bitmap & (1 << FILPBIT_ATTR))?ADFLAGS_OPENFORKS:0;
531 upath = path->u_name;
532 if ((of = of_findname(path))) {
535 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
539 if ( ad_metadata( upath, flags, adp) < 0 ) {
542 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
543 upath, strerror(errno));
544 return AFPERR_ACCESS;
546 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
555 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp);
557 ad_close_metadata( adp);
560 LOG(log_debug, logtype_afpd, "end getfilparams:");
566 /* ----------------------------- */
567 int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
569 struct adouble ad, *adp;
572 struct ofork *of = NULL;
574 int creatf, did, openf, retvalue = AFP_OK;
580 creatf = (unsigned char) *ibuf++;
582 memcpy(&vid, ibuf, sizeof( vid ));
583 ibuf += sizeof( vid );
585 if (NULL == ( vol = getvolbyvid( vid )) ) {
586 return( AFPERR_PARAM );
589 if (vol->v_flags & AFPVOL_RO)
592 memcpy(&did, ibuf, sizeof( did));
593 ibuf += sizeof( did );
595 if (NULL == ( dir = dirlookup( vol, did )) ) {
599 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
600 return get_afp_errno(AFPERR_PARAM);
603 if ( *s_path->m_name == '\0' ) {
604 return( AFPERR_BADTYPE );
607 upath = s_path->u_name;
609 /* if upath is deleted we already in trouble anyway */
610 if ((of = of_findname(s_path))) {
613 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
617 /* on a hard create, fail if file exists and is open */
620 openf = O_RDWR|O_CREAT|O_TRUNC;
622 /* on a soft create, if the file is open then ad_open won't fail
623 because open syscall is not called
628 openf = O_RDWR|O_CREAT|O_EXCL;
631 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF|ADFLAGS_CREATE,
632 openf, 0666, adp) < 0 ) {
636 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
637 return ( AFPERR_NOOBJ );
639 return( AFPERR_EXIST );
641 return( AFPERR_ACCESS );
644 return( AFPERR_DFULL );
646 return( AFPERR_PARAM );
649 if ( ad_reso_fileno( adp ) == -1 ) { /* Hard META / HF */
650 /* on noadouble volumes, just creating the data fork is ok */
651 if (vol_noadouble(vol)) {
652 ad_close( adp, ADFLAGS_DF );
653 goto createfile_done;
655 /* FIXME with hard create on an existing file, we already
656 * corrupted the data file.
658 netatalk_unlink( upath );
659 ad_close( adp, ADFLAGS_DF );
660 return AFPERR_ACCESS;
663 path = s_path->m_name;
664 ad_setname(adp, path);
666 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
672 if (vol->v_flags & AFPVOL_DROPBOX) {
673 retvalue = matchfile2dirperms(upath, vol, did);
675 #endif /* DROPKLUDGE */
677 setvoltime(obj, vol );
682 int afp_setfilparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
688 u_int16_t vid, bitmap;
693 memcpy(&vid, ibuf, sizeof( vid ));
694 ibuf += sizeof( vid );
695 if (NULL == ( vol = getvolbyvid( vid )) ) {
696 return( AFPERR_PARAM );
699 if (vol->v_flags & AFPVOL_RO)
702 memcpy(&did, ibuf, sizeof( did ));
703 ibuf += sizeof( did );
704 if (NULL == ( dir = dirlookup( vol, did )) ) {
705 return afp_errno; /* was AFPERR_NOOBJ */
708 memcpy(&bitmap, ibuf, sizeof( bitmap ));
709 bitmap = ntohs( bitmap );
710 ibuf += sizeof( bitmap );
712 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
713 return get_afp_errno(AFPERR_PARAM);
716 if (path_isadir(s_path)) {
717 return( AFPERR_BADTYPE ); /* it's a directory */
720 if ( s_path->st_errno != 0 ) {
721 return( AFPERR_NOOBJ );
724 if ((u_long)ibuf & 1 ) {
728 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
729 setvoltime(obj, vol );
736 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
739 extern struct path Cur_Path;
741 int setfilparams(struct vol *vol,
742 struct path *path, u_int16_t f_bitmap, char *buf )
744 struct adouble ad, *adp;
746 int bit, isad = 1, err = AFP_OK;
748 u_char achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
749 u_int16_t ashort, bshort;
752 u_int16_t upriv_bit = 0;
756 int change_mdate = 0;
757 int change_parent_mdate = 0;
762 u_int16_t bitmap = f_bitmap;
763 u_int32_t cdate,bdate;
764 u_char finder_buf[32];
767 LOG(log_debug, logtype_afpd, "begin setfilparams:");
770 upath = path->u_name;
771 adp = of_ad(vol, path, &ad);
774 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
775 return AFPERR_ACCESS;
778 /* with unix priv maybe we have to change adouble file priv first */
780 while ( bitmap != 0 ) {
781 while (( bitmap & 1 ) == 0 ) {
788 memcpy(&ashort, buf, sizeof( ashort ));
789 buf += sizeof( ashort );
793 memcpy(&cdate, buf, sizeof(cdate));
794 buf += sizeof( cdate );
797 memcpy(&newdate, buf, sizeof( newdate ));
798 buf += sizeof( newdate );
802 memcpy(&bdate, buf, sizeof( bdate));
803 buf += sizeof( bdate );
807 memcpy(finder_buf, buf, 32 );
810 case FILPBIT_UNIXPR :
811 if (!vol_unix_priv(vol)) {
812 /* this volume doesn't use unix priv */
818 change_parent_mdate = 1;
820 memcpy( &aint, buf, sizeof( aint ));
821 f_uid = ntohl (aint);
822 buf += sizeof( aint );
823 memcpy( &aint, buf, sizeof( aint ));
824 f_gid = ntohl (aint);
825 buf += sizeof( aint );
826 setfilowner(vol, f_uid, f_gid, path);
828 memcpy( &upriv, buf, sizeof( upriv ));
829 buf += sizeof( upriv );
830 upriv = ntohl (upriv);
831 if ((upriv & S_IWUSR)) {
832 setfilunixmode(vol, path, upriv);
839 case FILPBIT_PDINFO :
840 if (afp_version < 30) { /* else it's UTF8 name */
843 /* Keep special case to support crlf translations */
844 if ((unsigned int) achar == 0x04) {
845 fdType = (u_char *)"TEXT";
848 xyy[0] = ( u_char ) 'p';
859 /* break while loop */
868 /* second try with adouble open
870 if ( ad_open_metadata( upath, vol_noadouble(vol), O_CREAT, adp) < 0) {
871 LOG(log_debug, logtype_afpd, "setfilparams: ad_open_metadata error");
873 * For some things, we don't need an adouble header:
874 * - change of modification date
875 * - UNIX privs (Bug-ID #2863424)
877 if ( (f_bitmap & ~(1<<FILPBIT_MDATE | 1<<FILPBIT_UNIXPR))) {
878 LOG(log_debug, logtype_afpd, "setfilparams: need adouble access");
879 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
881 LOG(log_debug, logtype_afpd, "setfilparams: no adouble perms, but only FILPBIT_MDATE and/or FILPBIT_UNIXPR");
883 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
884 ad_setname(adp, path->m_name);
889 while ( bitmap != 0 ) {
890 while (( bitmap & 1 ) == 0 ) {
897 ad_getattr(adp, &bshort);
898 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
899 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
900 change_parent_mdate = 1;
901 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
902 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
906 ad_setattr(adp, bshort);
909 ad_setdate(adp, AD_DATE_CREATE, cdate);
914 ad_setdate(adp, AD_DATE_BACKUP, bdate);
917 if (default_type( ad_entry( adp, ADEID_FINDERI ))
919 ((em = getextmap( path->m_name )) &&
920 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
921 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
922 || ((em = getdefextmap()) &&
923 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
924 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
926 memcpy(finder_buf, ufinderi, 8 );
928 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
930 case FILPBIT_UNIXPR :
932 setfilunixmode(vol, path, upriv);
935 case FILPBIT_PDINFO :
936 if (afp_version < 30) { /* else it's UTF8 name */
937 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
938 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
944 goto setfilparam_done;
951 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
952 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
956 ad_setdate(adp, AD_DATE_MODIFY, newdate);
957 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
963 ad_close_metadata( adp);
967 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
968 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
969 bitmap = 1<<FILPBIT_MDATE;
970 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
974 LOG(log_debug, logtype_afpd, "end setfilparams:");
980 * renamefile and copyfile take the old and new unix pathnames
981 * and the new mac name.
983 * src the source path
984 * dst the dest filename in current dir
985 * newname the dest mac name
986 * adp adouble struct of src file, if open, or & zeroed one
989 int renamefile(const struct vol *vol, char *src, char *dst, char *newname, struct adouble *adp)
994 LOG(log_debug, logtype_afpd, "begin renamefile:");
997 if ( unix_rename( src, dst ) < 0 ) {
1000 return( AFPERR_NOOBJ );
1003 return( AFPERR_ACCESS );
1005 return AFPERR_VLOCK;
1006 case EXDEV : /* Cross device move -- try copy */
1007 /* NOTE: with open file it's an error because after the copy we will
1008 * get two files, it's fixable for our process (eg reopen the new file, get the
1009 * locks, and so on. But it doesn't solve the case with a second process
1011 if (adp->ad_open_forks) {
1012 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1013 return AFPERR_OLOCK; /* little lie */
1015 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1016 /* on error copyfile delete dest */
1019 return deletefile(vol, src, 0);
1021 return( AFPERR_PARAM );
1025 if (vol->vfs->vfs_renamefile(vol, src, dst) < 0 ) {
1029 /* try to undo the data fork rename,
1030 * we know we are on the same device
1033 unix_rename( dst, src );
1034 /* return the first error */
1037 return AFPERR_NOOBJ;
1040 return AFPERR_ACCESS ;
1042 return AFPERR_VLOCK;
1044 return AFPERR_PARAM ;
1049 /* don't care if we can't open the newly renamed ressource fork
1051 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1052 ad_setname(adp, newname);
1054 ad_close( adp, ADFLAGS_HF );
1057 LOG(log_debug, logtype_afpd, "end renamefile:");
1064 convert a Mac long name to an utf8 name,
1066 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1070 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1076 /* ---------------- */
1077 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1084 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1090 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1091 if (afp_version >= 30) {
1092 /* convert it to UTF8
1094 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1)
1098 strncpy( newname, ibuf, plen );
1099 newname[ plen ] = '\0';
1101 if (strlen(newname) != plen) {
1102 /* there's \0 in newname, e.g. it's a pathname not
1110 memcpy(&hint, ibuf, sizeof(hint));
1111 ibuf += sizeof(hint);
1113 memcpy(&len16, ibuf, sizeof(len16));
1114 ibuf += sizeof(len16);
1115 plen = ntohs(len16);
1118 if (plen > AFPOBJ_TMPSIZ) {
1121 strncpy( newname, ibuf, plen );
1122 newname[ plen ] = '\0';
1123 if (strlen(newname) != plen) {
1132 /* -----------------------------------
1134 int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1136 struct vol *s_vol, *d_vol;
1138 char *newname, *p, *upath;
1139 struct path *s_path;
1140 u_int32_t sdid, ddid;
1141 int err, retvalue = AFP_OK;
1142 u_int16_t svid, dvid;
1144 struct adouble ad, *adp;
1150 memcpy(&svid, ibuf, sizeof( svid ));
1151 ibuf += sizeof( svid );
1152 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1153 return( AFPERR_PARAM );
1156 memcpy(&sdid, ibuf, sizeof( sdid ));
1157 ibuf += sizeof( sdid );
1158 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1162 memcpy(&dvid, ibuf, sizeof( dvid ));
1163 ibuf += sizeof( dvid );
1164 memcpy(&ddid, ibuf, sizeof( ddid ));
1165 ibuf += sizeof( ddid );
1167 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1168 return get_afp_errno(AFPERR_PARAM);
1170 if ( path_isadir(s_path) ) {
1171 return( AFPERR_BADTYPE );
1174 /* don't allow copies when the file is open.
1175 * XXX: the spec only calls for read/deny write access.
1176 * however, copyfile doesn't have any of that info,
1177 * and locks need to stay coherent. as a result,
1178 * we just balk if the file is opened already. */
1180 adp = of_ad(s_vol, s_path, &ad);
1182 if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1183 return AFPERR_DENYCONF;
1185 denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
1186 getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1187 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1189 return AFPERR_DENYCONF;
1192 newname = obj->newtmp;
1193 strcpy( newname, s_path->m_name );
1195 p = ctoupath( s_vol, curdir, newname );
1197 return AFPERR_PARAM;
1201 /* FIXME svid != dvid && dvid's user can't read svid */
1203 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1204 return( AFPERR_PARAM );
1207 if (d_vol->v_flags & AFPVOL_RO)
1208 return AFPERR_VLOCK;
1210 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1214 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1215 return get_afp_errno(AFPERR_NOOBJ);
1217 if ( *s_path->m_name != '\0' ) {
1218 path_error(s_path, AFPERR_PARAM);
1221 /* one of the handful of places that knows about the path type */
1222 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1223 return( AFPERR_PARAM );
1225 /* newname is always only a filename so curdir *is* its
1228 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1229 return( AFPERR_PARAM );
1231 if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1237 if (vol->v_flags & AFPVOL_DROPBOX) {
1238 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1240 #endif /* DROPKLUDGE */
1242 setvoltime(obj, d_vol );
1247 /* ----------------------- */
1248 static int copy_all(const int dfd, const void *buf,
1254 LOG(log_debug, logtype_afpd, "begin copy_all:");
1257 while (buflen > 0) {
1258 if ((cc = write(dfd, buf, buflen)) < 0) {
1270 LOG(log_debug, logtype_afpd, "end copy_all:");
1276 /* --------------------------
1277 * copy only the fork data stream
1279 static int copy_fork(int eid, struct adouble *add, struct adouble *ads)
1286 if (eid == ADEID_DFORK) {
1287 sfd = ad_data_fileno(ads);
1288 dfd = ad_data_fileno(add);
1291 sfd = ad_reso_fileno(ads);
1292 dfd = ad_reso_fileno(add);
1295 if ((off_t)-1 == lseek(sfd, ad_getentryoff(ads, eid), SEEK_SET))
1298 if ((off_t)-1 == lseek(dfd, ad_getentryoff(add, eid), SEEK_SET))
1301 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1302 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1306 #define BUF 128*1024*1024
1308 if (fstat(sfd, &st) == 0) {
1311 if ( offset >= st.st_size) {
1314 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1315 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1318 case EINVAL: /* there's no guarantee that all fs support sendfile */
1327 lseek(sfd, offset, SEEK_SET);
1331 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1338 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1345 /* ----------------------------------
1346 * if newname is NULL (from directory.c) we don't want to copy the resource fork.
1347 * because we are doing it elsewhere.
1348 * currently if newname is NULL then adp is NULL.
1350 int copyfile(const struct vol *s_vol, const struct vol*d_vol,
1351 char *src, char *dst, char *newname, struct adouble *adp)
1353 struct adouble ads, add;
1361 LOG(log_debug, logtype_afpd, "begin copyfile:");
1365 ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options);
1368 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1369 adflags = ADFLAGS_DF;
1371 adflags |= ADFLAGS_HF;
1374 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1379 if (ad_meta_fileno(adp) == -1 && ad_reso_fileno(adp) == -1) { /* META / HF */
1380 /* no resource fork, don't create one for dst file */
1381 adflags &= ~ADFLAGS_HF;
1384 stat_result = fstat(ad_data_fileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */
1386 if (stat_result < 0) {
1387 /* unlikely but if fstat fails, the default file mode will be 0666. */
1388 st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
1391 if (ad_open(dst , adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
1393 ad_close( adp, adflags );
1394 if (EEXIST != ret_err) {
1395 deletefile(d_vol, dst, 0);
1398 return AFPERR_EXIST;
1402 * XXX if the source and the dest don't use the same resource type it's broken
1404 if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){
1405 /* copy the data fork */
1406 if ((err = copy_fork(ADEID_DFORK, &add, adp)) == 0) {
1407 err = d_vol->vfs->vfs_copyfile(d_vol, src, dst);
1415 if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
1416 /* set the new name in the resource fork */
1417 ad_copy_header(&add, adp);
1418 ad_setname(&add, newname);
1421 ad_close( adp, adflags );
1423 if (ad_close( &add, adflags ) <0) {
1428 deletefile(d_vol, dst, 0);
1430 else if (stat_result == 0) {
1431 /* set dest modification date to src date */
1434 ut.actime = ut.modtime = st.st_mtime;
1436 /* FIXME netatalk doesn't use resource fork file date
1437 * but maybe we should set its modtime too.
1442 LOG(log_debug, logtype_afpd, "end copyfile:");
1446 switch ( ret_err ) {
1452 return AFPERR_DFULL;
1454 return AFPERR_NOOBJ;
1456 return AFPERR_ACCESS;
1458 return AFPERR_VLOCK;
1460 return AFPERR_PARAM;
1464 /* -----------------------------------
1465 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1466 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1468 when deletefile is called we don't have lock on it, file is closed (for us)
1469 untrue if called by renamefile
1471 ad_open always try to open file RDWR first and ad_lock takes care of
1472 WRITE lock on read only file.
1475 static int check_attrib(struct adouble *adp)
1477 u_int16_t bshort = 0;
1479 ad_getattr(adp, &bshort);
1481 * Does kFPDeleteInhibitBit (bit 8) set?
1483 if ((bshort & htons(ATTRBIT_NODELETE))) {
1484 return AFPERR_OLOCK;
1486 if ((bshort & htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN))) {
1492 int deletefile(const struct vol *vol, char *file, int checkAttrib)
1495 struct adouble *adp = &ad;
1496 int adflags, err = AFP_OK;
1499 LOG(log_debug, logtype_afpd, "begin deletefile:");
1502 /* try to open both forks at once */
1503 adflags = ADFLAGS_DF|ADFLAGS_HF;
1505 /* was EACCESS error try to get only metadata */
1506 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1507 if ( ad_metadata( file , ADFLAGS_OPENFORKS, &ad) == 0 ) {
1508 ad_close( &ad, adflags );
1509 if ((err = check_attrib(&ad))) {
1516 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1517 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1520 if (adflags == ADFLAGS_DF)
1521 return AFPERR_NOOBJ;
1523 /* that failed. now try to open just the data fork */
1524 adflags = ADFLAGS_DF;
1528 adp = NULL; /* maybe it's a file with no write mode for us */
1529 break; /* was return AFPERR_ACCESS;*/
1531 return AFPERR_VLOCK;
1533 return( AFPERR_PARAM );
1536 break; /* from the while */
1539 if (adp && (adflags & ADFLAGS_HF) ) {
1540 /* FIXME we have a pb here because we want to know if a file is open
1541 * there's a 'priority inversion' if you can't open the ressource fork RW
1542 * you can delete it if it's open because you can't get a write lock.
1544 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1547 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1549 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1550 ad_close( &ad, adflags );
1551 return( AFPERR_BUSY );
1555 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1558 else if (!(err = vol->vfs->vfs_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
1560 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1562 cnid_delete(vol->v_cdb, id);
1566 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1569 LOG(log_debug, logtype_afpd, "end deletefile:");
1575 /* ------------------------------------ */
1576 /* return a file id */
1577 int afp_createid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1586 struct path *s_path;
1592 memcpy(&vid, ibuf, sizeof(vid));
1593 ibuf += sizeof(vid);
1595 if (NULL == ( vol = getvolbyvid( vid )) ) {
1596 return( AFPERR_PARAM);
1599 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1603 if (vol->v_flags & AFPVOL_RO)
1604 return AFPERR_VLOCK;
1606 memcpy(&did, ibuf, sizeof( did ));
1607 ibuf += sizeof(did);
1609 if (NULL == ( dir = dirlookup( vol, did )) ) {
1610 return afp_errno; /* was AFPERR_PARAM */
1613 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1614 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1617 if ( path_isadir(s_path) ) {
1618 return( AFPERR_BADTYPE );
1621 upath = s_path->u_name;
1622 switch (s_path->st_errno) {
1624 break; /* success */
1627 return AFPERR_ACCESS;
1629 return AFPERR_NOOBJ;
1631 return AFPERR_PARAM;
1634 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1635 memcpy(rbuf, &id, sizeof(id));
1636 *rbuflen = sizeof(id);
1637 return AFPERR_EXISTID;
1640 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1641 memcpy(rbuf, &id, sizeof(id));
1642 *rbuflen = sizeof(id);
1649 /* ------------------------------- */
1655 static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
1658 struct reenum *param = data;
1659 struct vol *vol = param->vol;
1660 cnid_t did = param->did;
1663 memset(&path, 0, sizeof(path));
1665 if ( stat(de->d_name, &path.st)<0 )
1668 /* update or add to cnid */
1669 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1671 #if AD_VERSION > AD_VERSION1
1672 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1673 struct adouble ad, *adp;
1677 path.u_name = de->d_name;
1679 adp = of_ad(vol, &path, &ad);
1681 if ( ad_open_metadata( de->d_name, 0, 0, adp ) < 0 ) {
1684 if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1687 ad_close_metadata(adp);
1689 #endif /* AD_VERSION > AD_VERSION1 */
1694 /* --------------------
1695 * Ok the db is out of synch with the dir.
1696 * but if it's a deleted file we don't want to do it again and again.
1699 reenumerate_id(struct vol *vol, char *name, struct dir *dir)
1705 if (vol->v_cdb == NULL) {
1709 /* FIXME use of_statdir ? */
1710 if (stat(name, &st)) {
1714 if (dirreenumerate(dir, &st)) {
1715 /* we already did it once and the dir haven't been modified */
1720 data.did = dir->d_did;
1721 if ((ret = for_each_dirent(vol, name, reenumerate_loop, (void *)&data)) >= 0) {
1722 setdiroffcnt(curdir, &st, ret);
1723 dir->d_flags |= DIRF_CNID;
1729 /* ------------------------------
1730 resolve a file id */
1731 int afp_resolveid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1740 u_int16_t vid, bitmap;
1742 static char buffer[12 + MAXPATHLEN + 1];
1743 int len = 12 + MAXPATHLEN + 1;
1748 memcpy(&vid, ibuf, sizeof(vid));
1749 ibuf += sizeof(vid);
1751 if (NULL == ( vol = getvolbyvid( vid )) ) {
1752 return( AFPERR_PARAM);
1755 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1759 memcpy(&id, ibuf, sizeof( id ));
1764 /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
1768 memset(&path, 0, sizeof(path));
1769 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1770 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1773 if (NULL == ( dir = dirlookup( vol, id )) ) {
1774 return AFPERR_NOID; /* idem AFPERR_PARAM */
1776 path.u_name = upath;
1777 if (movecwd(vol, dir) < 0) {
1781 return AFPERR_ACCESS;
1785 return AFPERR_PARAM;
1789 if ( of_stat(&path) < 0 ) {
1791 /* with nfs and our working directory is deleted */
1792 if (errno == ESTALE) {
1796 if ( errno == ENOENT && !retry) {
1797 /* cnid db is out of sync, reenumerate the directory and update ids */
1798 reenumerate_id(vol, ".", dir);
1806 return AFPERR_ACCESS;
1810 return AFPERR_PARAM;
1814 /* directories are bad */
1815 if (S_ISDIR(path.st.st_mode)) {
1816 /* OS9 and OSX don't return the same error code */
1817 return (afp_version >=30)?AFPERR_NOID:AFPERR_BADTYPE;
1820 memcpy(&bitmap, ibuf, sizeof(bitmap));
1821 bitmap = ntohs( bitmap );
1822 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1826 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1827 rbuf + sizeof(bitmap), &buflen))) {
1830 *rbuflen = buflen + sizeof(bitmap);
1831 memcpy(rbuf, ibuf, sizeof(bitmap));
1836 /* ------------------------------ */
1837 int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1847 static char buffer[12 + MAXPATHLEN + 1];
1848 int len = 12 + MAXPATHLEN + 1;
1853 memcpy(&vid, ibuf, sizeof(vid));
1854 ibuf += sizeof(vid);
1856 if (NULL == ( vol = getvolbyvid( vid )) ) {
1857 return( AFPERR_PARAM);
1860 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1864 if (vol->v_flags & AFPVOL_RO)
1865 return AFPERR_VLOCK;
1867 memcpy(&id, ibuf, sizeof( id ));
1871 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1875 if (NULL == ( dir = dirlookup( vol, id )) ) {
1876 return( AFPERR_PARAM );
1880 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1884 return AFPERR_ACCESS;
1889 /* still try to delete the id */
1893 return AFPERR_PARAM;
1896 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1897 return AFPERR_BADTYPE;
1899 if (cnid_delete(vol->v_cdb, fileid)) {
1902 return AFPERR_VLOCK;
1905 return AFPERR_ACCESS;
1907 return AFPERR_PARAM;
1914 /* ------------------------------ */
1915 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1919 if (path->st_errno) {
1920 switch (path->st_errno) {
1922 afp_errno = AFPERR_NOID;
1926 afp_errno = AFPERR_ACCESS;
1929 afp_errno = AFPERR_PARAM;
1934 /* we use file_access both for legacy Mac perm and
1935 * for unix privilege, rename will take care of folder perms
1937 if (file_access(path, OPENACC_WR ) < 0) {
1938 afp_errno = AFPERR_ACCESS;
1942 if ((*of = of_findname(path))) {
1943 /* reuse struct adouble so it won't break locks */
1947 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
1949 if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
1951 * The user must have the Read & Write privilege for both files in order to use this command.
1953 ad_close(adp, ADFLAGS_HF);
1954 afp_errno = AFPERR_ACCESS;
1961 #define APPLETEMP ".AppleTempXXXXXX"
1963 int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1965 struct stat srcst, destst;
1967 struct dir *dir, *sdir;
1968 char *spath, temp[17], *p;
1969 char *supath, *upath;
1974 struct adouble *adsp = NULL;
1975 struct adouble *addp = NULL;
1976 struct ofork *s_of = NULL;
1977 struct ofork *d_of = NULL;
1990 memcpy(&vid, ibuf, sizeof(vid));
1991 ibuf += sizeof(vid);
1993 if (NULL == ( vol = getvolbyvid( vid )) ) {
1994 return( AFPERR_PARAM);
1997 if ((vol->v_flags & AFPVOL_RO))
1998 return AFPERR_VLOCK;
2000 /* source and destination dids */
2001 memcpy(&sid, ibuf, sizeof(sid));
2002 ibuf += sizeof(sid);
2003 memcpy(&did, ibuf, sizeof(did));
2004 ibuf += sizeof(did);
2007 if (NULL == (dir = dirlookup( vol, sid )) ) {
2008 return afp_errno; /* was AFPERR_PARAM */
2011 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2012 return get_afp_errno(AFPERR_NOOBJ);
2015 if ( path_isadir(path) ) {
2016 return AFPERR_BADTYPE; /* it's a dir */
2019 /* save some stuff */
2022 spath = obj->oldtmp;
2023 supath = obj->newtmp;
2024 strcpy(spath, path->m_name);
2025 strcpy(supath, path->u_name); /* this is for the cnid changing */
2026 p = absupath( vol, sdir, supath);
2028 /* pathname too long */
2029 return AFPERR_PARAM ;
2032 ad_init(&ads, vol->v_adouble, vol->v_ad_options);
2033 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2037 /* ***** from here we may have resource fork open **** */
2039 /* look for the source cnid. if it doesn't exist, don't worry about
2041 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2043 if (NULL == ( dir = dirlookup( vol, did )) ) {
2044 err = afp_errno; /* was AFPERR_PARAM */
2045 goto err_exchangefile;
2048 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2049 err = get_afp_errno(AFPERR_NOOBJ);
2050 goto err_exchangefile;
2053 if ( path_isadir(path) ) {
2054 err = AFPERR_BADTYPE;
2055 goto err_exchangefile;
2058 /* FPExchangeFiles is the only call that can return the SameObj
2060 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2061 err = AFPERR_SAMEOBJ;
2062 goto err_exchangefile;
2065 ad_init(&add, vol->v_adouble, vol->v_ad_options);
2066 if (!(addp = find_adouble( path, &d_of, &add))) {
2068 goto err_exchangefile;
2072 /* they are not on the same device and at least one is open
2073 * FIXME broken for for crossdev and adouble v2
2076 crossdev = (srcst.st_dev != destst.st_dev);
2077 if (/* (d_of || s_of) && */ crossdev) {
2079 goto err_exchangefile;
2082 /* look for destination id. */
2083 upath = path->u_name;
2084 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2086 /* construct a temp name.
2087 * NOTE: the temp file will be in the dest file's directory. it
2088 * will also be inaccessible from AFP. */
2089 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2090 if (!mktemp(temp)) {
2092 goto err_exchangefile;
2096 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2097 ad_close(adsp, ADFLAGS_HF);
2098 ad_close(addp, ADFLAGS_HF);
2101 /* now, quickly rename the file. we error if we can't. */
2102 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2103 goto err_exchangefile;
2104 of_rename(vol, s_of, sdir, spath, curdir, temp);
2106 /* rename destination to source */
2107 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2108 goto err_src_to_tmp;
2109 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2111 /* rename temp to destination */
2112 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2113 goto err_dest_to_src;
2114 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2116 /* id's need switching. src -> dest and dest -> src.
2117 * we need to re-stat() if it was a cross device copy.
2120 cnid_delete(vol->v_cdb, sid);
2123 cnid_delete(vol->v_cdb, did);
2125 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2126 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2128 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2129 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2134 err = AFPERR_ACCESS;
2139 goto err_temp_to_dest;
2142 /* here we need to reopen if crossdev */
2143 if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2148 if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2153 /* change perms, src gets dest perm and vice versa */
2158 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2159 err = AFP_OK; /* ignore error */
2160 goto err_temp_to_dest;
2164 * we need to exchange ACL entries as well
2166 /* exchange_acls(vol, p, upath); */
2171 path->m_name = NULL;
2172 path->u_name = upath;
2174 setfilunixmode(vol, path, destst.st_mode);
2175 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2182 setfilunixmode(vol, path, srcst.st_mode);
2183 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2185 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2186 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2191 goto err_exchangefile;
2193 /* all this stuff is so that we can unwind a failed operation
2196 /* rename dest to temp */
2197 renamefile(vol, upath, temp, temp, adsp);
2198 of_rename(vol, s_of, curdir, upath, curdir, temp);
2201 /* rename source back to dest */
2202 renamefile(vol, p, upath, path->m_name, addp);
2203 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2206 /* rename temp back to source */
2207 renamefile(vol, temp, p, spath, adsp);
2208 of_rename(vol, s_of, curdir, temp, sdir, spath);
2211 if ( !s_of && adsp && ad_meta_fileno(adsp) != -1 ) { /* META */
2212 ad_close(adsp, ADFLAGS_HF);
2214 if ( !d_of && addp && ad_meta_fileno(addp) != -1 ) {/* META */
2215 ad_close(addp, ADFLAGS_HF);