2 * $Id: file.c,v 1.124 2009-11-27 12:37:24 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_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 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_debug9, 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;
521 LOG(log_debug9, logtype_default, "begin getfilparams:");
524 opened = PARAM_NEED_ADP(bitmap);
529 int flags = (bitmap & (1 << FILPBIT_ATTR))?ADFLAGS_OPENFORKS:0;
531 adp = of_ad(vol, path, &ad);
532 upath = path->u_name;
534 if ( ad_metadata( upath, vol_noadouble(vol) | flags, adp) < 0 ) {
537 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
538 upath, strerror(errno));
539 return AFPERR_ACCESS;
541 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
550 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp);
552 ad_close_metadata( adp);
555 LOG(log_debug9, logtype_afpd, "end getfilparams:");
561 /* ----------------------------- */
562 int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
564 struct adouble ad, *adp;
567 struct ofork *of = NULL;
569 int creatf, did, openf, retvalue = AFP_OK;
575 creatf = (unsigned char) *ibuf++;
577 memcpy(&vid, ibuf, sizeof( vid ));
578 ibuf += sizeof( vid );
580 if (NULL == ( vol = getvolbyvid( vid )) ) {
581 return( AFPERR_PARAM );
584 if (vol->v_flags & AFPVOL_RO)
587 memcpy(&did, ibuf, sizeof( did));
588 ibuf += sizeof( did );
590 if (NULL == ( dir = dirlookup( vol, did )) ) {
594 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
595 return get_afp_errno(AFPERR_PARAM);
598 if ( *s_path->m_name == '\0' ) {
599 return( AFPERR_BADTYPE );
602 upath = s_path->u_name;
604 /* if upath is deleted we already in trouble anyway */
605 if ((of = of_findname(s_path))) {
608 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
612 /* on a hard create, fail if file exists and is open */
615 openf = O_RDWR|O_CREAT|O_TRUNC;
617 /* on a soft create, if the file is open then ad_open won't fail
618 because open syscall is not called
623 openf = O_RDWR|O_CREAT|O_EXCL;
626 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF|ADFLAGS_CREATE,
627 openf, 0666, adp) < 0 ) {
631 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
632 return ( AFPERR_NOOBJ );
634 return( AFPERR_EXIST );
636 return( AFPERR_ACCESS );
639 return( AFPERR_DFULL );
641 return( AFPERR_PARAM );
644 if ( ad_reso_fileno( adp ) == -1 ) { /* Hard META / HF */
645 /* on noadouble volumes, just creating the data fork is ok */
646 if (vol_noadouble(vol)) {
647 ad_close( adp, ADFLAGS_DF );
648 goto createfile_done;
650 /* FIXME with hard create on an existing file, we already
651 * corrupted the data file.
653 netatalk_unlink( upath );
654 ad_close( adp, ADFLAGS_DF );
655 return AFPERR_ACCESS;
658 path = s_path->m_name;
659 ad_setname(adp, path);
661 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
667 if (vol->v_flags & AFPVOL_DROPBOX) {
668 retvalue = matchfile2dirperms(upath, vol, did);
670 #endif /* DROPKLUDGE */
672 setvoltime(obj, vol );
677 int afp_setfilparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
683 u_int16_t vid, bitmap;
688 memcpy(&vid, ibuf, sizeof( vid ));
689 ibuf += sizeof( vid );
690 if (NULL == ( vol = getvolbyvid( vid )) ) {
691 return( AFPERR_PARAM );
694 if (vol->v_flags & AFPVOL_RO)
697 memcpy(&did, ibuf, sizeof( did ));
698 ibuf += sizeof( did );
699 if (NULL == ( dir = dirlookup( vol, did )) ) {
700 return afp_errno; /* was AFPERR_NOOBJ */
703 memcpy(&bitmap, ibuf, sizeof( bitmap ));
704 bitmap = ntohs( bitmap );
705 ibuf += sizeof( bitmap );
707 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
708 return get_afp_errno(AFPERR_PARAM);
711 if (path_isadir(s_path)) {
712 return( AFPERR_BADTYPE ); /* it's a directory */
715 if ( s_path->st_errno != 0 ) {
716 return( AFPERR_NOOBJ );
719 if ((u_long)ibuf & 1 ) {
723 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
724 setvoltime(obj, vol );
731 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
734 extern struct path Cur_Path;
736 int setfilparams(struct vol *vol,
737 struct path *path, u_int16_t f_bitmap, char *buf )
739 struct adouble ad, *adp;
741 int bit, isad = 1, err = AFP_OK;
743 u_char achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
744 u_int16_t ashort, bshort;
747 u_int16_t upriv_bit = 0;
751 int change_mdate = 0;
752 int change_parent_mdate = 0;
757 u_int16_t bitmap = f_bitmap;
758 u_int32_t cdate,bdate;
759 u_char finder_buf[32];
762 LOG(log_debug9, logtype_afpd, "begin setfilparams:");
765 adp = of_ad(vol, path, &ad);
766 upath = path->u_name;
768 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
769 return AFPERR_ACCESS;
772 /* with unix priv maybe we have to change adouble file priv first */
774 while ( bitmap != 0 ) {
775 while (( bitmap & 1 ) == 0 ) {
782 memcpy(&ashort, buf, sizeof( ashort ));
783 buf += sizeof( ashort );
787 memcpy(&cdate, buf, sizeof(cdate));
788 buf += sizeof( cdate );
791 memcpy(&newdate, buf, sizeof( newdate ));
792 buf += sizeof( newdate );
796 memcpy(&bdate, buf, sizeof( bdate));
797 buf += sizeof( bdate );
801 memcpy(finder_buf, buf, 32 );
804 case FILPBIT_UNIXPR :
805 if (!vol_unix_priv(vol)) {
806 /* this volume doesn't use unix priv */
812 change_parent_mdate = 1;
814 memcpy( &aint, buf, sizeof( aint ));
815 f_uid = ntohl (aint);
816 buf += sizeof( aint );
817 memcpy( &aint, buf, sizeof( aint ));
818 f_gid = ntohl (aint);
819 buf += sizeof( aint );
820 setfilowner(vol, f_uid, f_gid, path);
822 memcpy( &upriv, buf, sizeof( upriv ));
823 buf += sizeof( upriv );
824 upriv = ntohl (upriv);
825 if ((upriv & S_IWUSR)) {
826 setfilunixmode(vol, path, upriv);
833 case FILPBIT_PDINFO :
834 if (afp_version < 30) { /* else it's UTF8 name */
837 /* Keep special case to support crlf translations */
838 if ((unsigned int) achar == 0x04) {
839 fdType = (u_char *)"TEXT";
842 xyy[0] = ( u_char ) 'p';
853 /* break while loop */
862 /* second try with adouble open
864 if ( ad_open_metadata( upath, vol_noadouble(vol), O_CREAT, adp) < 0) {
865 LOG(log_debug, logtype_afpd, "setfilparams: ad_open_metadata error");
867 * For some things, we don't need an adouble header:
868 * - change of modification date
869 * - UNIX privs (Bug-ID #2863424)
871 if ( (f_bitmap & ~(1<<FILPBIT_MDATE | 1<<FILPBIT_UNIXPR))) {
872 LOG(log_debug, logtype_afpd, "setfilparams: need adouble access");
873 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
875 LOG(log_debug, logtype_afpd, "setfilparams: no adouble perms, but only FILPBIT_MDATE and/or FILPBIT_UNIXPR");
877 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
878 ad_setname(adp, path->m_name);
883 while ( bitmap != 0 ) {
884 while (( bitmap & 1 ) == 0 ) {
891 ad_getattr(adp, &bshort);
892 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
893 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
894 change_parent_mdate = 1;
895 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
896 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
900 ad_setattr(adp, bshort);
903 ad_setdate(adp, AD_DATE_CREATE, cdate);
908 ad_setdate(adp, AD_DATE_BACKUP, bdate);
911 if (default_type( ad_entry( adp, ADEID_FINDERI ))
913 ((em = getextmap( path->m_name )) &&
914 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
915 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
916 || ((em = getdefextmap()) &&
917 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
918 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
920 memcpy(finder_buf, ufinderi, 8 );
922 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
924 case FILPBIT_UNIXPR :
926 setfilunixmode(vol, path, upriv);
929 case FILPBIT_PDINFO :
930 if (afp_version < 30) { /* else it's UTF8 name */
931 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
932 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
938 goto setfilparam_done;
945 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
946 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
950 ad_setdate(adp, AD_DATE_MODIFY, newdate);
951 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
957 ad_close_metadata( adp);
961 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
962 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
963 bitmap = 1<<FILPBIT_MDATE;
964 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
968 LOG(log_debug9, logtype_afpd, "end setfilparams:");
974 * renamefile and copyfile take the old and new unix pathnames
975 * and the new mac name.
977 * src the source path
978 * dst the dest filename in current dir
979 * newname the dest mac name
980 * adp adouble struct of src file, if open, or & zeroed one
983 int renamefile(const struct vol *vol, char *src, char *dst, char *newname, struct adouble *adp)
988 LOG(log_debug9, logtype_afpd, "begin renamefile:");
991 if ( unix_rename( src, dst ) < 0 ) {
994 return( AFPERR_NOOBJ );
997 return( AFPERR_ACCESS );
1000 case EXDEV : /* Cross device move -- try copy */
1001 /* NOTE: with open file it's an error because after the copy we will
1002 * get two files, it's fixable for our process (eg reopen the new file, get the
1003 * locks, and so on. But it doesn't solve the case with a second process
1005 if (adp->ad_open_forks) {
1006 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1007 return AFPERR_OLOCK; /* little lie */
1009 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1010 /* on error copyfile delete dest */
1013 return deletefile(vol, src, 0);
1015 return( AFPERR_PARAM );
1019 if (vol->vfs->vfs_renamefile(vol, src, dst) < 0 ) {
1023 /* try to undo the data fork rename,
1024 * we know we are on the same device
1027 unix_rename( dst, src );
1028 /* return the first error */
1031 return AFPERR_NOOBJ;
1034 return AFPERR_ACCESS ;
1036 return AFPERR_VLOCK;
1038 return AFPERR_PARAM ;
1043 /* don't care if we can't open the newly renamed ressource fork
1045 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1046 ad_setname(adp, newname);
1048 ad_close( adp, ADFLAGS_HF );
1051 LOG(log_debug9, logtype_afpd, "end renamefile:");
1058 convert a Mac long name to an utf8 name,
1060 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1064 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1070 /* ---------------- */
1071 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1078 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1084 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1085 if (afp_version >= 30) {
1086 /* convert it to UTF8
1088 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1)
1092 strncpy( newname, ibuf, plen );
1093 newname[ plen ] = '\0';
1095 if (strlen(newname) != plen) {
1096 /* there's \0 in newname, e.g. it's a pathname not
1104 memcpy(&hint, ibuf, sizeof(hint));
1105 ibuf += sizeof(hint);
1107 memcpy(&len16, ibuf, sizeof(len16));
1108 ibuf += sizeof(len16);
1109 plen = ntohs(len16);
1112 if (plen > AFPOBJ_TMPSIZ) {
1115 strncpy( newname, ibuf, plen );
1116 newname[ plen ] = '\0';
1117 if (strlen(newname) != plen) {
1126 /* -----------------------------------
1128 int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1130 struct vol *s_vol, *d_vol;
1132 char *newname, *p, *upath;
1133 struct path *s_path;
1134 u_int32_t sdid, ddid;
1135 int err, retvalue = AFP_OK;
1136 u_int16_t svid, dvid;
1138 struct adouble ad, *adp;
1144 memcpy(&svid, ibuf, sizeof( svid ));
1145 ibuf += sizeof( svid );
1146 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1147 return( AFPERR_PARAM );
1150 memcpy(&sdid, ibuf, sizeof( sdid ));
1151 ibuf += sizeof( sdid );
1152 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1156 memcpy(&dvid, ibuf, sizeof( dvid ));
1157 ibuf += sizeof( dvid );
1158 memcpy(&ddid, ibuf, sizeof( ddid ));
1159 ibuf += sizeof( ddid );
1161 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1162 return get_afp_errno(AFPERR_PARAM);
1164 if ( path_isadir(s_path) ) {
1165 return( AFPERR_BADTYPE );
1168 /* don't allow copies when the file is open.
1169 * XXX: the spec only calls for read/deny write access.
1170 * however, copyfile doesn't have any of that info,
1171 * and locks need to stay coherent. as a result,
1172 * we just balk if the file is opened already. */
1174 adp = of_ad(s_vol, s_path, &ad);
1176 if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1177 return AFPERR_DENYCONF;
1179 denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
1180 getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1181 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1183 return AFPERR_DENYCONF;
1186 newname = obj->newtmp;
1187 strcpy( newname, s_path->m_name );
1189 p = ctoupath( s_vol, curdir, newname );
1191 return AFPERR_PARAM;
1195 /* FIXME svid != dvid && dvid's user can't read svid */
1197 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1198 return( AFPERR_PARAM );
1201 if (d_vol->v_flags & AFPVOL_RO)
1202 return AFPERR_VLOCK;
1204 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1208 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1209 return get_afp_errno(AFPERR_NOOBJ);
1211 if ( *s_path->m_name != '\0' ) {
1212 path_error(s_path, AFPERR_PARAM);
1215 /* one of the handful of places that knows about the path type */
1216 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1217 return( AFPERR_PARAM );
1219 /* newname is always only a filename so curdir *is* its
1222 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1223 return( AFPERR_PARAM );
1225 if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1231 if (vol->v_flags & AFPVOL_DROPBOX) {
1232 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1234 #endif /* DROPKLUDGE */
1236 setvoltime(obj, d_vol );
1241 /* ----------------------- */
1242 static int copy_all(const int dfd, const void *buf,
1248 LOG(log_debug9, logtype_afpd, "begin copy_all:");
1251 while (buflen > 0) {
1252 if ((cc = write(dfd, buf, buflen)) < 0) {
1264 LOG(log_debug9, logtype_afpd, "end copy_all:");
1270 /* --------------------------
1271 * copy only the fork data stream
1273 static int copy_fork(int eid, struct adouble *add, struct adouble *ads)
1280 if (eid == ADEID_DFORK) {
1281 sfd = ad_data_fileno(ads);
1282 dfd = ad_data_fileno(add);
1285 sfd = ad_reso_fileno(ads);
1286 dfd = ad_reso_fileno(add);
1289 if ((off_t)-1 == lseek(sfd, ad_getentryoff(ads, eid), SEEK_SET))
1292 if ((off_t)-1 == lseek(dfd, ad_getentryoff(add, eid), SEEK_SET))
1295 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1296 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1300 #define BUF 128*1024*1024
1302 if (fstat(sfd, &st) == 0) {
1305 if ( offset >= st.st_size) {
1308 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1309 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1312 case EINVAL: /* there's no guarantee that all fs support sendfile */
1321 lseek(sfd, offset, SEEK_SET);
1325 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1332 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1339 /* ----------------------------------
1340 * if newname is NULL (from directory.c) we don't want to copy the resource fork.
1341 * because we are doing it elsewhere.
1342 * currently if newname is NULL then adp is NULL.
1344 int copyfile(const struct vol *s_vol, const struct vol*d_vol,
1345 char *src, char *dst, char *newname, struct adouble *adp)
1347 struct adouble ads, add;
1355 LOG(log_debug9, logtype_afpd, "begin copyfile:");
1359 ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options);
1362 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1363 adflags = ADFLAGS_DF;
1365 adflags |= ADFLAGS_HF;
1368 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1373 if (ad_meta_fileno(adp) == -1 && ad_reso_fileno(adp) == -1) { /* META / HF */
1374 /* no resource fork, don't create one for dst file */
1375 adflags &= ~ADFLAGS_HF;
1378 stat_result = fstat(ad_data_fileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */
1380 if (stat_result < 0) {
1381 /* unlikely but if fstat fails, the default file mode will be 0666. */
1382 st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
1385 if (ad_open(dst , adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
1387 ad_close( adp, adflags );
1388 if (EEXIST != ret_err) {
1389 deletefile(d_vol, dst, 0);
1392 return AFPERR_EXIST;
1396 * XXX if the source and the dest don't use the same resource type it's broken
1398 if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){
1399 /* copy the data fork */
1400 if ((err = copy_fork(ADEID_DFORK, &add, adp)) == 0) {
1401 err = d_vol->vfs->vfs_copyfile(d_vol, src, dst);
1409 if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
1410 /* set the new name in the resource fork */
1411 ad_copy_header(&add, adp);
1412 ad_setname(&add, newname);
1415 ad_close( adp, adflags );
1417 if (ad_close( &add, adflags ) <0) {
1422 deletefile(d_vol, dst, 0);
1424 else if (stat_result == 0) {
1425 /* set dest modification date to src date */
1428 ut.actime = ut.modtime = st.st_mtime;
1430 /* FIXME netatalk doesn't use resource fork file date
1431 * but maybe we should set its modtime too.
1436 LOG(log_debug9, logtype_afpd, "end copyfile:");
1440 switch ( ret_err ) {
1446 return AFPERR_DFULL;
1448 return AFPERR_NOOBJ;
1450 return AFPERR_ACCESS;
1452 return AFPERR_VLOCK;
1454 return AFPERR_PARAM;
1458 /* -----------------------------------
1459 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1460 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1462 when deletefile is called we don't have lock on it, file is closed (for us)
1463 untrue if called by renamefile
1465 ad_open always try to open file RDWR first and ad_lock takes care of
1466 WRITE lock on read only file.
1469 static int check_attrib(struct adouble *adp)
1471 u_int16_t bshort = 0;
1473 ad_getattr(adp, &bshort);
1475 * Does kFPDeleteInhibitBit (bit 8) set?
1477 if ((bshort & htons(ATTRBIT_NODELETE))) {
1478 return AFPERR_OLOCK;
1480 if ((bshort & htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN))) {
1486 int deletefile(const struct vol *vol, char *file, int checkAttrib)
1489 struct adouble *adp = &ad;
1490 int adflags, err = AFP_OK;
1493 LOG(log_debug9, logtype_afpd, "begin deletefile:");
1496 /* try to open both forks at once */
1497 adflags = ADFLAGS_DF|ADFLAGS_HF;
1499 /* was EACCESS error try to get only metadata */
1500 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1501 /* we never want to create a resource fork here, we are going to delete it
1502 * moreover sometimes deletefile is called with a no existent file and
1503 * ad_open would create a 0 byte resource fork
1505 if ( ad_metadata( file , ADFLAGS_NOADOUBLE | ADFLAGS_OPENFORKS, &ad) == 0 ) {
1506 ad_close( &ad, adflags );
1507 if ((err = check_attrib(&ad))) {
1514 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1515 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1518 if (adflags == ADFLAGS_DF)
1519 return AFPERR_NOOBJ;
1521 /* that failed. now try to open just the data fork */
1522 adflags = ADFLAGS_DF;
1526 adp = NULL; /* maybe it's a file with no write mode for us */
1527 break; /* was return AFPERR_ACCESS;*/
1529 return AFPERR_VLOCK;
1531 return( AFPERR_PARAM );
1534 break; /* from the while */
1537 if (adp && (adflags & ADFLAGS_HF) ) {
1538 /* FIXME we have a pb here because we want to know if a file is open
1539 * there's a 'priority inversion' if you can't open the ressource fork RW
1540 * you can delete it if it's open because you can't get a write lock.
1542 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1545 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1547 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1548 ad_close( &ad, adflags );
1549 return( AFPERR_BUSY );
1553 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1556 else if (!(err = vol->vfs->vfs_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
1558 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1560 cnid_delete(vol->v_cdb, id);
1564 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1567 LOG(log_debug9, logtype_afpd, "end deletefile:");
1573 /* ------------------------------------ */
1574 /* return a file id */
1575 int afp_createid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1584 struct path *s_path;
1590 memcpy(&vid, ibuf, sizeof(vid));
1591 ibuf += sizeof(vid);
1593 if (NULL == ( vol = getvolbyvid( vid )) ) {
1594 return( AFPERR_PARAM);
1597 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1601 if (vol->v_flags & AFPVOL_RO)
1602 return AFPERR_VLOCK;
1604 memcpy(&did, ibuf, sizeof( did ));
1605 ibuf += sizeof(did);
1607 if (NULL == ( dir = dirlookup( vol, did )) ) {
1608 return afp_errno; /* was AFPERR_PARAM */
1611 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1612 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1615 if ( path_isadir(s_path) ) {
1616 return( AFPERR_BADTYPE );
1619 upath = s_path->u_name;
1620 switch (s_path->st_errno) {
1622 break; /* success */
1625 return AFPERR_ACCESS;
1627 return AFPERR_NOOBJ;
1629 return AFPERR_PARAM;
1632 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1633 memcpy(rbuf, &id, sizeof(id));
1634 *rbuflen = sizeof(id);
1635 return AFPERR_EXISTID;
1638 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1639 memcpy(rbuf, &id, sizeof(id));
1640 *rbuflen = sizeof(id);
1647 /* ------------------------------- */
1653 static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
1656 struct reenum *param = data;
1657 struct vol *vol = param->vol;
1658 cnid_t did = param->did;
1661 if ( stat(de->d_name, &path.st)<0 )
1664 /* update or add to cnid */
1665 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1667 #if AD_VERSION > AD_VERSION1
1668 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1669 struct adouble ad, *adp;
1673 path.u_name = de->d_name;
1675 adp = of_ad(vol, &path, &ad);
1677 if ( ad_open_metadata( de->d_name, 0, 0, adp ) < 0 ) {
1680 if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1683 ad_close_metadata(adp);
1685 #endif /* AD_VERSION > AD_VERSION1 */
1690 /* --------------------
1691 * Ok the db is out of synch with the dir.
1692 * but if it's a deleted file we don't want to do it again and again.
1695 reenumerate_id(struct vol *vol, char *name, struct dir *dir)
1701 if (vol->v_cdb == NULL) {
1705 /* FIXME use of_statdir ? */
1706 if (stat(name, &st)) {
1710 if (dirreenumerate(dir, &st)) {
1711 /* we already did it once and the dir haven't been modified */
1716 data.did = dir->d_did;
1717 if ((ret = for_each_dirent(vol, name, reenumerate_loop, (void *)&data)) >= 0) {
1718 setdiroffcnt(curdir, &st, ret);
1719 dir->d_flags |= DIRF_CNID;
1725 /* ------------------------------
1726 resolve a file id */
1727 int afp_resolveid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1736 u_int16_t vid, bitmap;
1738 static char buffer[12 + MAXPATHLEN + 1];
1739 int len = 12 + MAXPATHLEN + 1;
1744 memcpy(&vid, ibuf, sizeof(vid));
1745 ibuf += sizeof(vid);
1747 if (NULL == ( vol = getvolbyvid( vid )) ) {
1748 return( AFPERR_PARAM);
1751 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1755 memcpy(&id, ibuf, sizeof( id ));
1760 /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
1764 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1765 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1768 if (NULL == ( dir = dirlookup( vol, id )) ) {
1769 return AFPERR_NOID; /* idem AFPERR_PARAM */
1771 if (movecwd(vol, dir) < 0) {
1775 return AFPERR_ACCESS;
1779 return AFPERR_PARAM;
1783 memset(&path, 0, sizeof(path));
1784 path.u_name = upath;
1785 if ( of_stat(&path) < 0 ) {
1787 /* with nfs and our working directory is deleted */
1788 if (errno == ESTALE) {
1792 if ( errno == ENOENT && !retry) {
1793 /* cnid db is out of sync, reenumerate the directory and update ids */
1794 reenumerate_id(vol, ".", dir);
1802 return AFPERR_ACCESS;
1806 return AFPERR_PARAM;
1810 /* directories are bad */
1811 if (S_ISDIR(path.st.st_mode)) {
1812 /* OS9 and OSX don't return the same error code */
1813 return (afp_version >=30)?AFPERR_NOID:AFPERR_BADTYPE;
1816 memcpy(&bitmap, ibuf, sizeof(bitmap));
1817 bitmap = ntohs( bitmap );
1818 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1822 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1823 rbuf + sizeof(bitmap), &buflen))) {
1826 *rbuflen = buflen + sizeof(bitmap);
1827 memcpy(rbuf, ibuf, sizeof(bitmap));
1832 /* ------------------------------ */
1833 int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1843 static char buffer[12 + MAXPATHLEN + 1];
1844 int len = 12 + MAXPATHLEN + 1;
1849 memcpy(&vid, ibuf, sizeof(vid));
1850 ibuf += sizeof(vid);
1852 if (NULL == ( vol = getvolbyvid( vid )) ) {
1853 return( AFPERR_PARAM);
1856 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1860 if (vol->v_flags & AFPVOL_RO)
1861 return AFPERR_VLOCK;
1863 memcpy(&id, ibuf, sizeof( id ));
1867 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1871 if (NULL == ( dir = dirlookup( vol, id )) ) {
1872 return( AFPERR_PARAM );
1876 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1880 return AFPERR_ACCESS;
1885 /* still try to delete the id */
1889 return AFPERR_PARAM;
1892 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1893 return AFPERR_BADTYPE;
1895 if (cnid_delete(vol->v_cdb, fileid)) {
1898 return AFPERR_VLOCK;
1901 return AFPERR_ACCESS;
1903 return AFPERR_PARAM;
1910 /* ------------------------------ */
1911 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1915 if (path->st_errno) {
1916 switch (path->st_errno) {
1918 afp_errno = AFPERR_NOID;
1922 afp_errno = AFPERR_ACCESS;
1925 afp_errno = AFPERR_PARAM;
1930 /* we use file_access both for legacy Mac perm and
1931 * for unix privilege, rename will take care of folder perms
1933 if (file_access(path, OPENACC_WR ) < 0) {
1934 afp_errno = AFPERR_ACCESS;
1938 if ((*of = of_findname(path))) {
1939 /* reuse struct adouble so it won't break locks */
1943 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
1945 if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
1947 * The user must have the Read & Write privilege for both files in order to use this command.
1949 ad_close(adp, ADFLAGS_HF);
1950 afp_errno = AFPERR_ACCESS;
1957 #define APPLETEMP ".AppleTempXXXXXX"
1959 int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1961 struct stat srcst, destst;
1963 struct dir *dir, *sdir;
1964 char *spath, temp[17], *p;
1965 char *supath, *upath;
1970 struct adouble *adsp = NULL;
1971 struct adouble *addp = NULL;
1972 struct ofork *s_of = NULL;
1973 struct ofork *d_of = NULL;
1986 memcpy(&vid, ibuf, sizeof(vid));
1987 ibuf += sizeof(vid);
1989 if (NULL == ( vol = getvolbyvid( vid )) ) {
1990 return( AFPERR_PARAM);
1993 if ((vol->v_flags & AFPVOL_RO))
1994 return AFPERR_VLOCK;
1996 /* source and destination dids */
1997 memcpy(&sid, ibuf, sizeof(sid));
1998 ibuf += sizeof(sid);
1999 memcpy(&did, ibuf, sizeof(did));
2000 ibuf += sizeof(did);
2003 if (NULL == (dir = dirlookup( vol, sid )) ) {
2004 return afp_errno; /* was AFPERR_PARAM */
2007 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2008 return get_afp_errno(AFPERR_NOOBJ);
2011 if ( path_isadir(path) ) {
2012 return AFPERR_BADTYPE; /* it's a dir */
2015 /* save some stuff */
2018 spath = obj->oldtmp;
2019 supath = obj->newtmp;
2020 strcpy(spath, path->m_name);
2021 strcpy(supath, path->u_name); /* this is for the cnid changing */
2022 p = absupath( vol, sdir, supath);
2024 /* pathname too long */
2025 return AFPERR_PARAM ;
2028 ad_init(&ads, vol->v_adouble, vol->v_ad_options);
2029 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2033 /* ***** from here we may have resource fork open **** */
2035 /* look for the source cnid. if it doesn't exist, don't worry about
2037 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2039 if (NULL == ( dir = dirlookup( vol, did )) ) {
2040 err = afp_errno; /* was AFPERR_PARAM */
2041 goto err_exchangefile;
2044 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2045 err = get_afp_errno(AFPERR_NOOBJ);
2046 goto err_exchangefile;
2049 if ( path_isadir(path) ) {
2050 err = AFPERR_BADTYPE;
2051 goto err_exchangefile;
2054 /* FPExchangeFiles is the only call that can return the SameObj
2056 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2057 err = AFPERR_SAMEOBJ;
2058 goto err_exchangefile;
2061 ad_init(&add, vol->v_adouble, vol->v_ad_options);
2062 if (!(addp = find_adouble( path, &d_of, &add))) {
2064 goto err_exchangefile;
2068 /* they are not on the same device and at least one is open
2069 * FIXME broken for for crossdev and adouble v2
2072 crossdev = (srcst.st_dev != destst.st_dev);
2073 if (/* (d_of || s_of) && */ crossdev) {
2075 goto err_exchangefile;
2078 /* look for destination id. */
2079 upath = path->u_name;
2080 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2082 /* construct a temp name.
2083 * NOTE: the temp file will be in the dest file's directory. it
2084 * will also be inaccessible from AFP. */
2085 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2086 if (!mktemp(temp)) {
2088 goto err_exchangefile;
2092 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2093 ad_close(adsp, ADFLAGS_HF);
2094 ad_close(addp, ADFLAGS_HF);
2097 /* now, quickly rename the file. we error if we can't. */
2098 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2099 goto err_exchangefile;
2100 of_rename(vol, s_of, sdir, spath, curdir, temp);
2102 /* rename destination to source */
2103 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2104 goto err_src_to_tmp;
2105 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2107 /* rename temp to destination */
2108 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2109 goto err_dest_to_src;
2110 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2112 /* id's need switching. src -> dest and dest -> src.
2113 * we need to re-stat() if it was a cross device copy.
2116 cnid_delete(vol->v_cdb, sid);
2119 cnid_delete(vol->v_cdb, did);
2121 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2122 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2124 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2125 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2130 err = AFPERR_ACCESS;
2135 goto err_temp_to_dest;
2138 /* here we need to reopen if crossdev */
2139 if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2144 if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2149 /* change perms, src gets dest perm and vice versa */
2154 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2155 err = AFP_OK; /* ignore error */
2156 goto err_temp_to_dest;
2160 * we need to exchange ACL entries as well
2162 /* exchange_acls(vol, p, upath); */
2167 path->m_name = NULL;
2168 path->u_name = upath;
2170 setfilunixmode(vol, path, destst.st_mode);
2171 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2178 setfilunixmode(vol, path, srcst.st_mode);
2179 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2181 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2182 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2187 goto err_exchangefile;
2189 /* all this stuff is so that we can unwind a failed operation
2192 /* rename dest to temp */
2193 renamefile(vol, upath, temp, temp, adsp);
2194 of_rename(vol, s_of, curdir, upath, curdir, temp);
2197 /* rename source back to dest */
2198 renamefile(vol, p, upath, path->m_name, addp);
2199 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2202 /* rename temp back to source */
2203 renamefile(vol, temp, p, spath, adsp);
2204 of_rename(vol, s_of, curdir, temp, sdir, spath);
2207 if ( !s_of && adsp && ad_meta_fileno(adsp) != -1 ) { /* META */
2208 ad_close(adsp, ADFLAGS_HF);
2210 if ( !d_of && addp && ad_meta_fileno(addp) != -1 ) {/* META */
2211 ad_close(addp, ADFLAGS_HF);