2 * $Id: file.c,v 1.109 2009-07-20 18:31:04 didg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
18 #else /* STDC_HEADERS */
22 #endif /* HAVE_STRCHR */
23 char *strchr (), *strrchr ();
26 #define memcpy(d,s,n) bcopy ((s), (d), (n))
27 #define memmove(d,s,n) bcopy ((s), (d), (n))
28 #endif /* ! HAVE_MEMCPY */
29 #endif /* STDC_HEADERS */
31 #include <atalk/adouble.h>
36 #include <atalk/logger.h>
37 #include <sys/param.h>
40 #include <atalk/afp.h>
41 #include <atalk/util.h>
42 #include <atalk/cnid.h>
43 #include "directory.h"
52 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
53 * field bytes subfield bytes
56 * ioFlFndrInfo 16 -> type 4 type field
57 * creator 4 creator field
58 * flags 2 finder flags:
60 * location 4 location in window
61 * folder 2 window that contains file
63 * ioFlXFndrInfo 16 -> iconID 2 icon id
65 * script 1 script system
67 * commentID 2 comment id
68 * putawayID 4 home directory id
71 const u_char ufinderi[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, int *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_info, 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, int *buflen )
516 struct adouble ad, *adp;
523 LOG(log_info, 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_info, logtype_afpd, "end getfilparams:");
566 /* ----------------------------- */
567 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
569 char *ibuf, *rbuf _U_;
570 int ibuflen _U_, *rbuflen;
572 struct adouble ad, *adp;
575 struct ofork *of = NULL;
577 int creatf, did, openf, retvalue = AFP_OK;
582 LOG(log_info, logtype_afpd, "begin afp_createfile:");
587 creatf = (unsigned char) *ibuf++;
589 memcpy(&vid, ibuf, sizeof( vid ));
590 ibuf += sizeof( vid );
592 if (NULL == ( vol = getvolbyvid( vid )) ) {
593 return( AFPERR_PARAM );
596 if (vol->v_flags & AFPVOL_RO)
599 memcpy(&did, ibuf, sizeof( did));
600 ibuf += sizeof( did );
602 if (NULL == ( dir = dirlookup( vol, did )) ) {
606 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
607 return get_afp_errno(AFPERR_PARAM);
610 if ( *s_path->m_name == '\0' ) {
611 return( AFPERR_BADTYPE );
614 upath = s_path->u_name;
616 /* if upath is deleted we already in trouble anyway */
617 if ((of = of_findname(s_path))) {
620 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
624 /* on a hard create, fail if file exists and is open */
627 openf = O_RDWR|O_CREAT|O_TRUNC;
629 /* on a soft create, if the file is open then ad_open won't fail
630 because open syscall is not called
635 openf = O_RDWR|O_CREAT|O_EXCL;
638 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF|ADFLAGS_CREATE,
639 openf, 0666, adp) < 0 ) {
643 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
644 return ( AFPERR_NOOBJ );
646 return( AFPERR_EXIST );
648 return( AFPERR_ACCESS );
651 return( AFPERR_DFULL );
653 return( AFPERR_PARAM );
656 if ( ad_reso_fileno( adp ) == -1 ) { /* Hard META / HF */
657 /* on noadouble volumes, just creating the data fork is ok */
658 if (vol_noadouble(vol)) {
659 ad_close( adp, ADFLAGS_DF );
660 goto createfile_done;
662 /* FIXME with hard create on an existing file, we already
663 * corrupted the data file.
665 netatalk_unlink( upath );
666 ad_close( adp, ADFLAGS_DF );
667 return AFPERR_ACCESS;
670 path = s_path->m_name;
671 ad_setname(adp, path);
673 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
679 if (vol->v_flags & AFPVOL_DROPBOX) {
680 retvalue = matchfile2dirperms(upath, vol, did);
682 #endif /* DROPKLUDGE */
684 setvoltime(obj, vol );
687 LOG(log_info, logtype_afpd, "end afp_createfile");
693 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
695 char *ibuf, *rbuf _U_;
696 int ibuflen _U_, *rbuflen;
702 u_int16_t vid, bitmap;
705 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
711 memcpy(&vid, ibuf, sizeof( vid ));
712 ibuf += sizeof( vid );
713 if (NULL == ( vol = getvolbyvid( vid )) ) {
714 return( AFPERR_PARAM );
717 if (vol->v_flags & AFPVOL_RO)
720 memcpy(&did, ibuf, sizeof( did ));
721 ibuf += sizeof( did );
722 if (NULL == ( dir = dirlookup( vol, did )) ) {
723 return afp_errno; /* was AFPERR_NOOBJ */
726 memcpy(&bitmap, ibuf, sizeof( bitmap ));
727 bitmap = ntohs( bitmap );
728 ibuf += sizeof( bitmap );
730 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
731 return get_afp_errno(AFPERR_PARAM);
734 if (path_isadir(s_path)) {
735 return( AFPERR_BADTYPE ); /* it's a directory */
738 if ( s_path->st_errno != 0 ) {
739 return( AFPERR_NOOBJ );
742 if ((u_long)ibuf & 1 ) {
746 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
747 setvoltime(obj, vol );
751 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
758 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
761 extern struct path Cur_Path;
763 int setfilparams(struct vol *vol,
764 struct path *path, u_int16_t f_bitmap, char *buf )
766 struct adouble ad, *adp;
768 int bit, isad = 1, err = AFP_OK;
770 u_char achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
771 u_int16_t ashort, bshort;
774 u_int16_t upriv_bit = 0;
778 int change_mdate = 0;
779 int change_parent_mdate = 0;
784 u_int16_t bitmap = f_bitmap;
785 u_int32_t cdate,bdate;
786 u_char finder_buf[32];
789 LOG(log_info, logtype_afpd, "begin setfilparams:");
792 upath = path->u_name;
793 adp = of_ad(vol, path, &ad);
796 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
797 return AFPERR_ACCESS;
800 /* with unix priv maybe we have to change adouble file priv first */
802 while ( bitmap != 0 ) {
803 while (( bitmap & 1 ) == 0 ) {
810 memcpy(&ashort, buf, sizeof( ashort ));
811 buf += sizeof( ashort );
815 memcpy(&cdate, buf, sizeof(cdate));
816 buf += sizeof( cdate );
819 memcpy(&newdate, buf, sizeof( newdate ));
820 buf += sizeof( newdate );
824 memcpy(&bdate, buf, sizeof( bdate));
825 buf += sizeof( bdate );
829 memcpy(finder_buf, buf, 32 );
832 case FILPBIT_UNIXPR :
833 if (!vol_unix_priv(vol)) {
834 /* this volume doesn't use unix priv */
840 change_parent_mdate = 1;
842 memcpy( &aint, buf, sizeof( aint ));
843 f_uid = ntohl (aint);
844 buf += sizeof( aint );
845 memcpy( &aint, buf, sizeof( aint ));
846 f_gid = ntohl (aint);
847 buf += sizeof( aint );
848 setfilowner(vol, f_uid, f_gid, path);
850 memcpy( &upriv, buf, sizeof( upriv ));
851 buf += sizeof( upriv );
852 upriv = ntohl (upriv);
853 if ((upriv & S_IWUSR)) {
854 setfilunixmode(vol, path, upriv);
861 case FILPBIT_PDINFO :
862 if (afp_version < 30) { /* else it's UTF8 name */
865 /* Keep special case to support crlf translations */
866 if ((unsigned int) achar == 0x04) {
867 fdType = (u_char *)"TEXT";
870 xyy[0] = ( u_char ) 'p';
881 /* break while loop */
890 /* second try with adouble open
892 if ( ad_open_metadata( upath, vol_noadouble(vol), O_CREAT, adp) < 0) {
893 /* for some things, we don't need an adouble header */
894 if (f_bitmap & ~(1<<FILPBIT_MDATE)) {
895 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
898 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
899 ad_setname(adp, path->m_name);
904 while ( bitmap != 0 ) {
905 while (( bitmap & 1 ) == 0 ) {
912 ad_getattr(adp, &bshort);
913 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
914 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
915 change_parent_mdate = 1;
916 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
917 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
921 ad_setattr(adp, bshort);
924 ad_setdate(adp, AD_DATE_CREATE, cdate);
929 ad_setdate(adp, AD_DATE_BACKUP, bdate);
932 if (default_type( ad_entry( adp, ADEID_FINDERI ))
934 ((em = getextmap( path->m_name )) &&
935 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
936 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
937 || ((em = getdefextmap()) &&
938 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
939 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
941 memcpy(finder_buf, ufinderi, 8 );
943 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
945 case FILPBIT_UNIXPR :
947 setfilunixmode(vol, path, upriv);
950 case FILPBIT_PDINFO :
951 if (afp_version < 30) { /* else it's UTF8 name */
952 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
953 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
959 goto setfilparam_done;
966 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
967 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
971 ad_setdate(adp, AD_DATE_MODIFY, newdate);
972 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
978 ad_close_metadata( adp);
982 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
983 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
984 bitmap = 1<<FILPBIT_MDATE;
985 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
989 LOG(log_info, logtype_afpd, "end setfilparams:");
995 * renamefile and copyfile take the old and new unix pathnames
996 * and the new mac name.
998 * src the source path
999 * dst the dest filename in current dir
1000 * newname the dest mac name
1001 * adp adouble struct of src file, if open, or & zeroed one
1004 int renamefile(vol, src, dst, newname, adp )
1005 const struct vol *vol;
1006 char *src, *dst, *newname;
1007 struct adouble *adp;
1012 LOG(log_info, logtype_afpd, "begin renamefile:");
1015 if ( unix_rename( src, dst ) < 0 ) {
1018 return( AFPERR_NOOBJ );
1021 return( AFPERR_ACCESS );
1023 return AFPERR_VLOCK;
1024 case EXDEV : /* Cross device move -- try copy */
1025 /* NOTE: with open file it's an error because after the copy we will
1026 * get two files, it's fixable for our process (eg reopen the new file, get the
1027 * locks, and so on. But it doesn't solve the case with a second process
1029 if (adp->ad_open_forks) {
1030 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1031 return AFPERR_OLOCK; /* little lie */
1033 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1034 /* on error copyfile delete dest */
1037 return deletefile(vol, src, 0);
1039 return( AFPERR_PARAM );
1043 if (vol->vfs->rf_renamefile(vol, src, dst) < 0 ) {
1047 /* try to undo the data fork rename,
1048 * we know we are on the same device
1051 unix_rename( dst, src );
1052 /* return the first error */
1055 return AFPERR_NOOBJ;
1058 return AFPERR_ACCESS ;
1060 return AFPERR_VLOCK;
1062 return AFPERR_PARAM ;
1067 /* don't care if we can't open the newly renamed ressource fork
1069 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1070 ad_setname(adp, newname);
1072 ad_close( adp, ADFLAGS_HF );
1075 LOG(log_info, logtype_afpd, "end renamefile:");
1082 convert a Mac long name to an utf8 name,
1084 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1088 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1094 /* ---------------- */
1095 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1102 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1108 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1109 if (afp_version >= 30) {
1110 /* convert it to UTF8
1112 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1)
1116 strncpy( newname, ibuf, plen );
1117 newname[ plen ] = '\0';
1119 if (strlen(newname) != plen) {
1120 /* there's \0 in newname, e.g. it's a pathname not
1128 memcpy(&hint, ibuf, sizeof(hint));
1129 ibuf += sizeof(hint);
1131 memcpy(&len16, ibuf, sizeof(len16));
1132 ibuf += sizeof(len16);
1133 plen = ntohs(len16);
1136 if (plen > AFPOBJ_TMPSIZ) {
1139 strncpy( newname, ibuf, plen );
1140 newname[ plen ] = '\0';
1141 if (strlen(newname) != plen) {
1150 /* -----------------------------------
1152 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1154 char *ibuf, *rbuf _U_;
1155 int ibuflen _U_, *rbuflen;
1157 struct vol *s_vol, *d_vol;
1159 char *newname, *p, *upath;
1160 struct path *s_path;
1161 u_int32_t sdid, ddid;
1162 int err, retvalue = AFP_OK;
1163 u_int16_t svid, dvid;
1165 struct adouble ad, *adp;
1169 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1175 memcpy(&svid, ibuf, sizeof( svid ));
1176 ibuf += sizeof( svid );
1177 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1178 return( AFPERR_PARAM );
1181 memcpy(&sdid, ibuf, sizeof( sdid ));
1182 ibuf += sizeof( sdid );
1183 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1187 memcpy(&dvid, ibuf, sizeof( dvid ));
1188 ibuf += sizeof( dvid );
1189 memcpy(&ddid, ibuf, sizeof( ddid ));
1190 ibuf += sizeof( ddid );
1192 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1193 return get_afp_errno(AFPERR_PARAM);
1195 if ( path_isadir(s_path) ) {
1196 return( AFPERR_BADTYPE );
1199 /* don't allow copies when the file is open.
1200 * XXX: the spec only calls for read/deny write access.
1201 * however, copyfile doesn't have any of that info,
1202 * and locks need to stay coherent. as a result,
1203 * we just balk if the file is opened already. */
1205 adp = of_ad(s_vol, s_path, &ad);
1207 if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1208 return AFPERR_DENYCONF;
1210 denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
1211 getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1212 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1214 return AFPERR_DENYCONF;
1217 newname = obj->newtmp;
1218 strcpy( newname, s_path->m_name );
1220 p = ctoupath( s_vol, curdir, newname );
1222 return AFPERR_PARAM;
1226 /* FIXME svid != dvid && dvid's user can't read svid */
1228 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1229 return( AFPERR_PARAM );
1232 if (d_vol->v_flags & AFPVOL_RO)
1233 return AFPERR_VLOCK;
1235 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1239 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1240 return get_afp_errno(AFPERR_NOOBJ);
1242 if ( *s_path->m_name != '\0' ) {
1243 path_error(s_path, AFPERR_PARAM);
1246 /* one of the handful of places that knows about the path type */
1247 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1248 return( AFPERR_PARAM );
1250 /* newname is always only a filename so curdir *is* its
1253 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1254 return( AFPERR_PARAM );
1256 if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1262 if (vol->v_flags & AFPVOL_DROPBOX) {
1263 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1265 #endif /* DROPKLUDGE */
1267 setvoltime(obj, d_vol );
1270 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1276 /* ----------------------- */
1277 static int copy_all(const int dfd, const void *buf,
1283 LOG(log_info, logtype_afpd, "begin copy_all:");
1286 while (buflen > 0) {
1287 if ((cc = write(dfd, buf, buflen)) < 0) {
1299 LOG(log_info, logtype_afpd, "end copy_all:");
1305 /* --------------------------
1306 * copy only the fork data stream
1308 static int copy_fork(int eid, struct adouble *add, struct adouble *ads)
1315 if (eid == ADEID_DFORK) {
1316 sfd = ad_data_fileno(ads);
1317 dfd = ad_data_fileno(add);
1320 sfd = ad_reso_fileno(ads);
1321 dfd = ad_reso_fileno(add);
1324 if ((off_t)-1 == lseek(sfd, ad_getentryoff(ads, eid), SEEK_SET))
1327 if ((off_t)-1 == lseek(dfd, ad_getentryoff(add, eid), SEEK_SET))
1330 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1331 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1335 #define BUF 128*1024*1024
1337 if (fstat(sfd, &st) == 0) {
1340 if ( offset >= st.st_size) {
1343 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1344 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1347 case EINVAL: /* there's no guarantee that all fs support sendfile */
1356 lseek(sfd, offset, SEEK_SET);
1360 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1367 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1374 /* ----------------------------------
1375 * if newname is NULL (from directory.c) we don't want to copy the resource fork.
1376 * because we are doing it elsewhere.
1377 * currently if newname is NULL then adp is NULL.
1379 int copyfile(s_vol, d_vol, src, dst, newname, adp )
1380 const struct vol *s_vol, *d_vol;
1381 char *src, *dst, *newname;
1382 struct adouble *adp;
1384 struct adouble ads, add;
1392 LOG(log_info, logtype_afpd, "begin copyfile:");
1396 ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options);
1399 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1400 adflags = ADFLAGS_DF;
1402 adflags |= ADFLAGS_HF;
1405 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1410 if (ad_meta_fileno(adp) == -1 && ad_reso_fileno(adp) == -1) { /* META / HF */
1411 /* no resource fork, don't create one for dst file */
1412 adflags &= ~ADFLAGS_HF;
1415 stat_result = fstat(ad_data_fileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */
1417 if (stat_result < 0) {
1418 /* unlikely but if fstat fails, the default file mode will be 0666. */
1419 st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
1422 if (ad_open(dst , adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
1424 ad_close( adp, adflags );
1425 if (EEXIST != ret_err) {
1426 deletefile(d_vol, dst, 0);
1429 return AFPERR_EXIST;
1431 /* XXX if the source and the dest don't use the same resource type it's broken
1433 if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){
1434 /* copy the data fork */
1435 err = copy_fork(ADEID_DFORK, &add, adp);
1442 if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
1443 /* set the new name in the resource fork */
1444 ad_copy_header(&add, adp);
1445 ad_setname(&add, newname);
1448 ad_close( adp, adflags );
1450 if (ad_close( &add, adflags ) <0) {
1455 deletefile(d_vol, dst, 0);
1457 else if (stat_result == 0) {
1458 /* set dest modification date to src date */
1461 ut.actime = ut.modtime = st.st_mtime;
1463 /* FIXME netatalk doesn't use resource fork file date
1464 * but maybe we should set its modtime too.
1469 LOG(log_info, logtype_afpd, "end copyfile:");
1473 switch ( ret_err ) {
1479 return AFPERR_DFULL;
1481 return AFPERR_NOOBJ;
1483 return AFPERR_ACCESS;
1485 return AFPERR_VLOCK;
1487 return AFPERR_PARAM;
1491 /* -----------------------------------
1492 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1493 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1495 when deletefile is called we don't have lock on it, file is closed (for us)
1496 untrue if called by renamefile
1498 ad_open always try to open file RDWR first and ad_lock takes care of
1499 WRITE lock on read only file.
1502 static int check_attrib(struct adouble *adp)
1504 u_int16_t bshort = 0;
1506 ad_getattr(adp, &bshort);
1508 * Does kFPDeleteInhibitBit (bit 8) set?
1510 if ((bshort & htons(ATTRBIT_NODELETE))) {
1511 return AFPERR_OLOCK;
1513 if ((bshort & htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN))) {
1519 int deletefile( vol, file, checkAttrib )
1520 const struct vol *vol;
1525 struct adouble *adp = &ad;
1526 int adflags, err = AFP_OK;
1529 LOG(log_info, logtype_afpd, "begin deletefile:");
1532 /* try to open both forks at once */
1533 adflags = ADFLAGS_DF|ADFLAGS_HF;
1535 /* was EACCESS error try to get only metadata */
1536 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1537 if ( ad_metadata( file , ADFLAGS_OPENFORKS, &ad) == 0 ) {
1538 ad_close( &ad, adflags );
1539 if ((err = check_attrib(&ad))) {
1546 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1547 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1550 if (adflags == ADFLAGS_DF)
1551 return AFPERR_NOOBJ;
1553 /* that failed. now try to open just the data fork */
1554 adflags = ADFLAGS_DF;
1558 adp = NULL; /* maybe it's a file with no write mode for us */
1559 break; /* was return AFPERR_ACCESS;*/
1561 return AFPERR_VLOCK;
1563 return( AFPERR_PARAM );
1566 break; /* from the while */
1569 if (adp && (adflags & ADFLAGS_HF) ) {
1570 /* FIXME we have a pb here because we want to know if a file is open
1571 * there's a 'priority inversion' if you can't open the ressource fork RW
1572 * you can delete it if it's open because you can't get a write lock.
1574 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1577 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1579 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1580 ad_close( &ad, adflags );
1581 return( AFPERR_BUSY );
1585 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1588 else if (!(err = vol->vfs->rf_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
1590 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1592 cnid_delete(vol->v_cdb, id);
1596 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1599 LOG(log_info, logtype_afpd, "end deletefile:");
1605 /* ------------------------------------ */
1606 /* return a file id */
1607 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1610 int ibuflen _U_, *rbuflen;
1619 struct path *s_path;
1622 LOG(log_info, logtype_afpd, "begin afp_createid:");
1629 memcpy(&vid, ibuf, sizeof(vid));
1630 ibuf += sizeof(vid);
1632 if (NULL == ( vol = getvolbyvid( vid )) ) {
1633 return( AFPERR_PARAM);
1636 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1640 if (vol->v_flags & AFPVOL_RO)
1641 return AFPERR_VLOCK;
1643 memcpy(&did, ibuf, sizeof( did ));
1644 ibuf += sizeof(did);
1646 if (NULL == ( dir = dirlookup( vol, did )) ) {
1647 return afp_errno; /* was AFPERR_PARAM */
1650 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1651 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1654 if ( path_isadir(s_path) ) {
1655 return( AFPERR_BADTYPE );
1658 upath = s_path->u_name;
1659 switch (s_path->st_errno) {
1661 break; /* success */
1664 return AFPERR_ACCESS;
1666 return AFPERR_NOOBJ;
1668 return AFPERR_PARAM;
1671 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1672 memcpy(rbuf, &id, sizeof(id));
1673 *rbuflen = sizeof(id);
1674 return AFPERR_EXISTID;
1677 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1678 memcpy(rbuf, &id, sizeof(id));
1679 *rbuflen = sizeof(id);
1684 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1689 /* ------------------------------- */
1695 static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
1698 struct reenum *param = data;
1699 struct vol *vol = param->vol;
1700 cnid_t did = param->did;
1703 memset(&path, 0, sizeof(path));
1705 if ( stat(de->d_name, &path.st)<0 )
1708 /* update or add to cnid */
1709 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1711 #if AD_VERSION > AD_VERSION1
1712 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1713 struct adouble ad, *adp;
1717 path.u_name = de->d_name;
1719 adp = of_ad(vol, &path, &ad);
1721 if ( ad_open_metadata( de->d_name, 0, 0, adp ) < 0 ) {
1724 if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1727 ad_close_metadata(adp);
1729 #endif /* AD_VERSION > AD_VERSION1 */
1734 /* --------------------
1735 * Ok the db is out of synch with the dir.
1736 * but if it's a deleted file we don't want to do it again and again.
1739 reenumerate_id(struct vol *vol, char *name, struct dir *dir)
1745 if (vol->v_cdb == NULL) {
1749 /* FIXME use of_statdir ? */
1750 if (stat(name, &st)) {
1754 if (dirreenumerate(dir, &st)) {
1755 /* we already did it once and the dir haven't been modified */
1760 data.did = dir->d_did;
1761 if ((ret = for_each_dirent(vol, name, reenumerate_loop, (void *)&data)) >= 0) {
1762 setdiroffcnt(curdir, &st, ret);
1763 dir->d_flags |= DIRF_CNID;
1769 /* ------------------------------
1770 resolve a file id */
1771 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1774 int ibuflen _U_, *rbuflen;
1780 int err, buflen, retry=0;
1782 u_int16_t vid, bitmap;
1784 static char buffer[12 + MAXPATHLEN + 1];
1785 int len = 12 + MAXPATHLEN + 1;
1788 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1794 memcpy(&vid, ibuf, sizeof(vid));
1795 ibuf += sizeof(vid);
1797 if (NULL == ( vol = getvolbyvid( vid )) ) {
1798 return( AFPERR_PARAM);
1801 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1805 memcpy(&id, ibuf, sizeof( id ));
1810 /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
1814 memset(&path, 0, sizeof(path));
1815 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1816 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1819 if (NULL == ( dir = dirlookup( vol, id )) ) {
1820 return AFPERR_NOID; /* idem AFPERR_PARAM */
1822 path.u_name = upath;
1823 if (movecwd(vol, dir) < 0) {
1827 return AFPERR_ACCESS;
1831 return AFPERR_PARAM;
1835 if ( of_stat(&path) < 0 ) {
1837 /* with nfs and our working directory is deleted */
1838 if (errno == ESTALE) {
1842 if ( errno == ENOENT && !retry) {
1843 /* cnid db is out of sync, reenumerate the directory and update ids */
1844 reenumerate_id(vol, ".", dir);
1852 return AFPERR_ACCESS;
1856 return AFPERR_PARAM;
1860 /* directories are bad */
1861 if (S_ISDIR(path.st.st_mode)) {
1862 /* OS9 and OSX don't return the same error code */
1863 return (afp_version >=30)?AFPERR_NOID:AFPERR_BADTYPE;
1866 memcpy(&bitmap, ibuf, sizeof(bitmap));
1867 bitmap = ntohs( bitmap );
1868 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1872 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1873 rbuf + sizeof(bitmap), &buflen))) {
1876 *rbuflen = buflen + sizeof(bitmap);
1877 memcpy(rbuf, ibuf, sizeof(bitmap));
1880 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1886 /* ------------------------------ */
1887 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1889 char *ibuf, *rbuf _U_;
1890 int ibuflen _U_, *rbuflen;
1900 static char buffer[12 + MAXPATHLEN + 1];
1901 int len = 12 + MAXPATHLEN + 1;
1904 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1910 memcpy(&vid, ibuf, sizeof(vid));
1911 ibuf += sizeof(vid);
1913 if (NULL == ( vol = getvolbyvid( vid )) ) {
1914 return( AFPERR_PARAM);
1917 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1921 if (vol->v_flags & AFPVOL_RO)
1922 return AFPERR_VLOCK;
1924 memcpy(&id, ibuf, sizeof( id ));
1928 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1932 if (NULL == ( dir = dirlookup( vol, id )) ) {
1933 return( AFPERR_PARAM );
1937 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1941 return AFPERR_ACCESS;
1946 /* still try to delete the id */
1950 return AFPERR_PARAM;
1953 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1954 return AFPERR_BADTYPE;
1956 if (cnid_delete(vol->v_cdb, fileid)) {
1959 return AFPERR_VLOCK;
1962 return AFPERR_ACCESS;
1964 return AFPERR_PARAM;
1969 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1975 /* ------------------------------ */
1976 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1980 if (path->st_errno) {
1981 switch (path->st_errno) {
1983 afp_errno = AFPERR_NOID;
1987 afp_errno = AFPERR_ACCESS;
1990 afp_errno = AFPERR_PARAM;
1995 /* we use file_access both for legacy Mac perm and
1996 * for unix privilege, rename will take care of folder perms
1998 if (file_access(path, OPENACC_WR ) < 0) {
1999 afp_errno = AFPERR_ACCESS;
2003 if ((*of = of_findname(path))) {
2004 /* reuse struct adouble so it won't break locks */
2008 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
2010 if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
2012 * The user must have the Read & Write privilege for both files in order to use this command.
2014 ad_close(adp, ADFLAGS_HF);
2015 afp_errno = AFPERR_ACCESS;
2022 #define APPLETEMP ".AppleTempXXXXXX"
2024 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
2026 char *ibuf, *rbuf _U_ ;
2027 int ibuflen _U_, *rbuflen;
2029 struct stat srcst, destst;
2031 struct dir *dir, *sdir;
2032 char *spath, temp[17], *p;
2033 char *supath, *upath;
2038 struct adouble *adsp = NULL;
2039 struct adouble *addp = NULL;
2040 struct ofork *s_of = NULL;
2041 struct ofork *d_of = NULL;
2052 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
2058 memcpy(&vid, ibuf, sizeof(vid));
2059 ibuf += sizeof(vid);
2061 if (NULL == ( vol = getvolbyvid( vid )) ) {
2062 return( AFPERR_PARAM);
2065 if ((vol->v_flags & AFPVOL_RO))
2066 return AFPERR_VLOCK;
2068 /* source and destination dids */
2069 memcpy(&sid, ibuf, sizeof(sid));
2070 ibuf += sizeof(sid);
2071 memcpy(&did, ibuf, sizeof(did));
2072 ibuf += sizeof(did);
2075 if (NULL == (dir = dirlookup( vol, sid )) ) {
2076 return afp_errno; /* was AFPERR_PARAM */
2079 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2080 return get_afp_errno(AFPERR_NOOBJ);
2083 if ( path_isadir(path) ) {
2084 return AFPERR_BADTYPE; /* it's a dir */
2087 /* save some stuff */
2090 spath = obj->oldtmp;
2091 supath = obj->newtmp;
2092 strcpy(spath, path->m_name);
2093 strcpy(supath, path->u_name); /* this is for the cnid changing */
2094 p = absupath( vol, sdir, supath);
2096 /* pathname too long */
2097 return AFPERR_PARAM ;
2100 ad_init(&ads, vol->v_adouble, vol->v_ad_options);
2101 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2105 /* ***** from here we may have resource fork open **** */
2107 /* look for the source cnid. if it doesn't exist, don't worry about
2109 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2111 if (NULL == ( dir = dirlookup( vol, did )) ) {
2112 err = afp_errno; /* was AFPERR_PARAM */
2113 goto err_exchangefile;
2116 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2117 err = get_afp_errno(AFPERR_NOOBJ);
2118 goto err_exchangefile;
2121 if ( path_isadir(path) ) {
2122 err = AFPERR_BADTYPE;
2123 goto err_exchangefile;
2126 /* FPExchangeFiles is the only call that can return the SameObj
2128 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2129 err = AFPERR_SAMEOBJ;
2130 goto err_exchangefile;
2133 ad_init(&add, vol->v_adouble, vol->v_ad_options);
2134 if (!(addp = find_adouble( path, &d_of, &add))) {
2136 goto err_exchangefile;
2140 /* they are not on the same device and at least one is open
2141 * FIXME broken for for crossdev and adouble v2
2144 crossdev = (srcst.st_dev != destst.st_dev);
2145 if (/* (d_of || s_of) && */ crossdev) {
2147 goto err_exchangefile;
2150 /* look for destination id. */
2151 upath = path->u_name;
2152 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2154 /* construct a temp name.
2155 * NOTE: the temp file will be in the dest file's directory. it
2156 * will also be inaccessible from AFP. */
2157 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2158 if (!mktemp(temp)) {
2160 goto err_exchangefile;
2164 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2165 ad_close(adsp, ADFLAGS_HF);
2166 ad_close(addp, ADFLAGS_HF);
2169 /* now, quickly rename the file. we error if we can't. */
2170 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2171 goto err_exchangefile;
2172 of_rename(vol, s_of, sdir, spath, curdir, temp);
2174 /* rename destination to source */
2175 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2176 goto err_src_to_tmp;
2177 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2179 /* rename temp to destination */
2180 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2181 goto err_dest_to_src;
2182 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2184 /* id's need switching. src -> dest and dest -> src.
2185 * we need to re-stat() if it was a cross device copy.
2188 cnid_delete(vol->v_cdb, sid);
2191 cnid_delete(vol->v_cdb, did);
2193 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2194 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2196 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2197 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2202 err = AFPERR_ACCESS;
2207 goto err_temp_to_dest;
2210 /* here we need to reopen if crossdev */
2211 if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2216 if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2221 /* change perms, src gets dest perm and vice versa */
2226 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2227 err = AFP_OK; /* ignore error */
2228 goto err_temp_to_dest;
2232 * we need to exchange ACL entries as well
2234 /* exchange_acls(vol, p, upath); */
2239 path->m_name = NULL;
2240 path->u_name = upath;
2242 setfilunixmode(vol, path, destst.st_mode);
2243 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2250 setfilunixmode(vol, path, srcst.st_mode);
2251 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2253 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2254 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2259 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2263 goto err_exchangefile;
2265 /* all this stuff is so that we can unwind a failed operation
2268 /* rename dest to temp */
2269 renamefile(vol, upath, temp, temp, adsp);
2270 of_rename(vol, s_of, curdir, upath, curdir, temp);
2273 /* rename source back to dest */
2274 renamefile(vol, p, upath, path->m_name, addp);
2275 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2278 /* rename temp back to source */
2279 renamefile(vol, temp, p, spath, adsp);
2280 of_rename(vol, s_of, curdir, temp, sdir, spath);
2283 if ( !s_of && adsp && ad_meta_fileno(adsp) != -1 ) { /* META */
2284 ad_close(adsp, ADFLAGS_HF);
2286 if ( !d_of && addp && ad_meta_fileno(addp) != -1 ) {/* META */
2287 ad_close(addp, ADFLAGS_HF);