2 * $Id: file.c,v 1.116 2009-10-27 23:35:17 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_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, size_t *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(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;
579 LOG(log_info, logtype_afpd, "begin afp_createfile:");
584 creatf = (unsigned char) *ibuf++;
586 memcpy(&vid, ibuf, sizeof( vid ));
587 ibuf += sizeof( vid );
589 if (NULL == ( vol = getvolbyvid( vid )) ) {
590 return( AFPERR_PARAM );
593 if (vol->v_flags & AFPVOL_RO)
596 memcpy(&did, ibuf, sizeof( did));
597 ibuf += sizeof( did );
599 if (NULL == ( dir = dirlookup( vol, did )) ) {
603 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
604 return get_afp_errno(AFPERR_PARAM);
607 if ( *s_path->m_name == '\0' ) {
608 return( AFPERR_BADTYPE );
611 upath = s_path->u_name;
613 /* if upath is deleted we already in trouble anyway */
614 if ((of = of_findname(s_path))) {
617 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
621 /* on a hard create, fail if file exists and is open */
624 openf = O_RDWR|O_CREAT|O_TRUNC;
626 /* on a soft create, if the file is open then ad_open won't fail
627 because open syscall is not called
632 openf = O_RDWR|O_CREAT|O_EXCL;
635 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF|ADFLAGS_CREATE,
636 openf, 0666, adp) < 0 ) {
640 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
641 return ( AFPERR_NOOBJ );
643 return( AFPERR_EXIST );
645 return( AFPERR_ACCESS );
648 return( AFPERR_DFULL );
650 return( AFPERR_PARAM );
653 if ( ad_reso_fileno( adp ) == -1 ) { /* Hard META / HF */
654 /* on noadouble volumes, just creating the data fork is ok */
655 if (vol_noadouble(vol)) {
656 ad_close( adp, ADFLAGS_DF );
657 goto createfile_done;
659 /* FIXME with hard create on an existing file, we already
660 * corrupted the data file.
662 netatalk_unlink( upath );
663 ad_close( adp, ADFLAGS_DF );
664 return AFPERR_ACCESS;
667 path = s_path->m_name;
668 ad_setname(adp, path);
670 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
676 if (vol->v_flags & AFPVOL_DROPBOX) {
677 retvalue = matchfile2dirperms(upath, vol, did);
679 #endif /* DROPKLUDGE */
681 setvoltime(obj, vol );
684 LOG(log_info, logtype_afpd, "end afp_createfile");
690 int afp_setfilparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
696 u_int16_t vid, bitmap;
699 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
705 memcpy(&vid, ibuf, sizeof( vid ));
706 ibuf += sizeof( vid );
707 if (NULL == ( vol = getvolbyvid( vid )) ) {
708 return( AFPERR_PARAM );
711 if (vol->v_flags & AFPVOL_RO)
714 memcpy(&did, ibuf, sizeof( did ));
715 ibuf += sizeof( did );
716 if (NULL == ( dir = dirlookup( vol, did )) ) {
717 return afp_errno; /* was AFPERR_NOOBJ */
720 memcpy(&bitmap, ibuf, sizeof( bitmap ));
721 bitmap = ntohs( bitmap );
722 ibuf += sizeof( bitmap );
724 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
725 return get_afp_errno(AFPERR_PARAM);
728 if (path_isadir(s_path)) {
729 return( AFPERR_BADTYPE ); /* it's a directory */
732 if ( s_path->st_errno != 0 ) {
733 return( AFPERR_NOOBJ );
736 if ((u_long)ibuf & 1 ) {
740 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
741 setvoltime(obj, vol );
745 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
752 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
755 extern struct path Cur_Path;
757 int setfilparams(struct vol *vol,
758 struct path *path, u_int16_t f_bitmap, char *buf )
760 struct adouble ad, *adp;
762 int bit, isad = 1, err = AFP_OK;
764 u_char achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
765 u_int16_t ashort, bshort;
768 u_int16_t upriv_bit = 0;
772 int change_mdate = 0;
773 int change_parent_mdate = 0;
778 u_int16_t bitmap = f_bitmap;
779 u_int32_t cdate,bdate;
780 u_char finder_buf[32];
783 LOG(log_info, logtype_afpd, "begin setfilparams:");
786 upath = path->u_name;
787 adp = of_ad(vol, path, &ad);
790 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
791 return AFPERR_ACCESS;
794 /* with unix priv maybe we have to change adouble file priv first */
796 while ( bitmap != 0 ) {
797 while (( bitmap & 1 ) == 0 ) {
804 memcpy(&ashort, buf, sizeof( ashort ));
805 buf += sizeof( ashort );
809 memcpy(&cdate, buf, sizeof(cdate));
810 buf += sizeof( cdate );
813 memcpy(&newdate, buf, sizeof( newdate ));
814 buf += sizeof( newdate );
818 memcpy(&bdate, buf, sizeof( bdate));
819 buf += sizeof( bdate );
823 memcpy(finder_buf, buf, 32 );
826 case FILPBIT_UNIXPR :
827 if (!vol_unix_priv(vol)) {
828 /* this volume doesn't use unix priv */
834 change_parent_mdate = 1;
836 memcpy( &aint, buf, sizeof( aint ));
837 f_uid = ntohl (aint);
838 buf += sizeof( aint );
839 memcpy( &aint, buf, sizeof( aint ));
840 f_gid = ntohl (aint);
841 buf += sizeof( aint );
842 setfilowner(vol, f_uid, f_gid, path);
844 memcpy( &upriv, buf, sizeof( upriv ));
845 buf += sizeof( upriv );
846 upriv = ntohl (upriv);
847 if ((upriv & S_IWUSR)) {
848 setfilunixmode(vol, path, upriv);
855 case FILPBIT_PDINFO :
856 if (afp_version < 30) { /* else it's UTF8 name */
859 /* Keep special case to support crlf translations */
860 if ((unsigned int) achar == 0x04) {
861 fdType = (u_char *)"TEXT";
864 xyy[0] = ( u_char ) 'p';
875 /* break while loop */
884 /* second try with adouble open
886 if ( ad_open_metadata( upath, vol_noadouble(vol), O_CREAT, adp) < 0) {
887 LOG(log_debug, logtype_afpd, "setfilparams: ad_open_metadata error");
889 * For some things, we don't need an adouble header:
890 * - change of modification date
891 * - UNIX privs (Bug-ID #2863424)
893 if ( (f_bitmap & ~(1<<FILPBIT_MDATE | 1<<FILPBIT_UNIXPR))) {
894 LOG(log_debug, logtype_afpd, "setfilparams: need adouble access");
895 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
897 LOG(log_debug, logtype_afpd, "setfilparams: no adouble perms, but only FILPBIT_MDATE and/or FILPBIT_UNIXPR");
899 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
900 ad_setname(adp, path->m_name);
905 while ( bitmap != 0 ) {
906 while (( bitmap & 1 ) == 0 ) {
913 ad_getattr(adp, &bshort);
914 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
915 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
916 change_parent_mdate = 1;
917 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
918 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
922 ad_setattr(adp, bshort);
925 ad_setdate(adp, AD_DATE_CREATE, cdate);
930 ad_setdate(adp, AD_DATE_BACKUP, bdate);
933 if (default_type( ad_entry( adp, ADEID_FINDERI ))
935 ((em = getextmap( path->m_name )) &&
936 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
937 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
938 || ((em = getdefextmap()) &&
939 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
940 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
942 memcpy(finder_buf, ufinderi, 8 );
944 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
946 case FILPBIT_UNIXPR :
948 setfilunixmode(vol, path, upriv);
951 case FILPBIT_PDINFO :
952 if (afp_version < 30) { /* else it's UTF8 name */
953 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
954 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
960 goto setfilparam_done;
967 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
968 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
972 ad_setdate(adp, AD_DATE_MODIFY, newdate);
973 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
979 ad_close_metadata( adp);
983 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
984 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
985 bitmap = 1<<FILPBIT_MDATE;
986 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
990 LOG(log_info, logtype_afpd, "end setfilparams:");
996 * renamefile and copyfile take the old and new unix pathnames
997 * and the new mac name.
999 * src the source path
1000 * dst the dest filename in current dir
1001 * newname the dest mac name
1002 * adp adouble struct of src file, if open, or & zeroed one
1005 int renamefile(const struct vol *vol, char *src, char *dst, char *newname, struct adouble *adp)
1010 LOG(log_info, logtype_afpd, "begin renamefile:");
1013 if ( unix_rename( src, dst ) < 0 ) {
1016 return( AFPERR_NOOBJ );
1019 return( AFPERR_ACCESS );
1021 return AFPERR_VLOCK;
1022 case EXDEV : /* Cross device move -- try copy */
1023 /* NOTE: with open file it's an error because after the copy we will
1024 * get two files, it's fixable for our process (eg reopen the new file, get the
1025 * locks, and so on. But it doesn't solve the case with a second process
1027 if (adp->ad_open_forks) {
1028 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1029 return AFPERR_OLOCK; /* little lie */
1031 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1032 /* on error copyfile delete dest */
1035 return deletefile(vol, src, 0);
1037 return( AFPERR_PARAM );
1041 if (vol->vfs->vfs_renamefile(vol, src, dst) < 0 ) {
1045 /* try to undo the data fork rename,
1046 * we know we are on the same device
1049 unix_rename( dst, src );
1050 /* return the first error */
1053 return AFPERR_NOOBJ;
1056 return AFPERR_ACCESS ;
1058 return AFPERR_VLOCK;
1060 return AFPERR_PARAM ;
1065 /* don't care if we can't open the newly renamed ressource fork
1067 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1068 ad_setname(adp, newname);
1070 ad_close( adp, ADFLAGS_HF );
1073 LOG(log_info, logtype_afpd, "end renamefile:");
1080 convert a Mac long name to an utf8 name,
1082 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1086 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1092 /* ---------------- */
1093 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1100 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1106 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1107 if (afp_version >= 30) {
1108 /* convert it to UTF8
1110 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1)
1114 strncpy( newname, ibuf, plen );
1115 newname[ plen ] = '\0';
1117 if (strlen(newname) != plen) {
1118 /* there's \0 in newname, e.g. it's a pathname not
1126 memcpy(&hint, ibuf, sizeof(hint));
1127 ibuf += sizeof(hint);
1129 memcpy(&len16, ibuf, sizeof(len16));
1130 ibuf += sizeof(len16);
1131 plen = ntohs(len16);
1134 if (plen > AFPOBJ_TMPSIZ) {
1137 strncpy( newname, ibuf, plen );
1138 newname[ plen ] = '\0';
1139 if (strlen(newname) != plen) {
1148 /* -----------------------------------
1150 int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1152 struct vol *s_vol, *d_vol;
1154 char *newname, *p, *upath;
1155 struct path *s_path;
1156 u_int32_t sdid, ddid;
1157 int err, retvalue = AFP_OK;
1158 u_int16_t svid, dvid;
1160 struct adouble ad, *adp;
1164 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1170 memcpy(&svid, ibuf, sizeof( svid ));
1171 ibuf += sizeof( svid );
1172 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1173 return( AFPERR_PARAM );
1176 memcpy(&sdid, ibuf, sizeof( sdid ));
1177 ibuf += sizeof( sdid );
1178 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1182 memcpy(&dvid, ibuf, sizeof( dvid ));
1183 ibuf += sizeof( dvid );
1184 memcpy(&ddid, ibuf, sizeof( ddid ));
1185 ibuf += sizeof( ddid );
1187 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1188 return get_afp_errno(AFPERR_PARAM);
1190 if ( path_isadir(s_path) ) {
1191 return( AFPERR_BADTYPE );
1194 /* don't allow copies when the file is open.
1195 * XXX: the spec only calls for read/deny write access.
1196 * however, copyfile doesn't have any of that info,
1197 * and locks need to stay coherent. as a result,
1198 * we just balk if the file is opened already. */
1200 adp = of_ad(s_vol, s_path, &ad);
1202 if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1203 return AFPERR_DENYCONF;
1205 denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
1206 getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1207 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1209 return AFPERR_DENYCONF;
1212 newname = obj->newtmp;
1213 strcpy( newname, s_path->m_name );
1215 p = ctoupath( s_vol, curdir, newname );
1217 return AFPERR_PARAM;
1221 /* FIXME svid != dvid && dvid's user can't read svid */
1223 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1224 return( AFPERR_PARAM );
1227 if (d_vol->v_flags & AFPVOL_RO)
1228 return AFPERR_VLOCK;
1230 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1234 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1235 return get_afp_errno(AFPERR_NOOBJ);
1237 if ( *s_path->m_name != '\0' ) {
1238 path_error(s_path, AFPERR_PARAM);
1241 /* one of the handful of places that knows about the path type */
1242 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1243 return( AFPERR_PARAM );
1245 /* newname is always only a filename so curdir *is* its
1248 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1249 return( AFPERR_PARAM );
1251 if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1257 if (vol->v_flags & AFPVOL_DROPBOX) {
1258 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1260 #endif /* DROPKLUDGE */
1262 setvoltime(obj, d_vol );
1265 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1271 /* ----------------------- */
1272 static int copy_all(const int dfd, const void *buf,
1278 LOG(log_info, logtype_afpd, "begin copy_all:");
1281 while (buflen > 0) {
1282 if ((cc = write(dfd, buf, buflen)) < 0) {
1294 LOG(log_info, logtype_afpd, "end copy_all:");
1300 /* --------------------------
1301 * copy only the fork data stream
1303 static int copy_fork(int eid, struct adouble *add, struct adouble *ads)
1310 if (eid == ADEID_DFORK) {
1311 sfd = ad_data_fileno(ads);
1312 dfd = ad_data_fileno(add);
1315 sfd = ad_reso_fileno(ads);
1316 dfd = ad_reso_fileno(add);
1319 if ((off_t)-1 == lseek(sfd, ad_getentryoff(ads, eid), SEEK_SET))
1322 if ((off_t)-1 == lseek(dfd, ad_getentryoff(add, eid), SEEK_SET))
1325 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1326 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1330 #define BUF 128*1024*1024
1332 if (fstat(sfd, &st) == 0) {
1335 if ( offset >= st.st_size) {
1338 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1339 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1342 case EINVAL: /* there's no guarantee that all fs support sendfile */
1351 lseek(sfd, offset, SEEK_SET);
1355 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1362 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1369 /* ----------------------------------
1370 * if newname is NULL (from directory.c) we don't want to copy the resource fork.
1371 * because we are doing it elsewhere.
1372 * currently if newname is NULL then adp is NULL.
1374 int copyfile(const struct vol *s_vol, const struct vol*d_vol,
1375 char *src, char *dst, char *newname, struct adouble *adp)
1377 struct adouble ads, add;
1385 LOG(log_info, logtype_afpd, "begin copyfile:");
1389 ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options);
1392 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1393 adflags = ADFLAGS_DF;
1395 adflags |= ADFLAGS_HF;
1398 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1403 if (ad_meta_fileno(adp) == -1 && ad_reso_fileno(adp) == -1) { /* META / HF */
1404 /* no resource fork, don't create one for dst file */
1405 adflags &= ~ADFLAGS_HF;
1408 stat_result = fstat(ad_data_fileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */
1410 if (stat_result < 0) {
1411 /* unlikely but if fstat fails, the default file mode will be 0666. */
1412 st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
1415 if (ad_open(dst , adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
1417 ad_close( adp, adflags );
1418 if (EEXIST != ret_err) {
1419 deletefile(d_vol, dst, 0);
1422 return AFPERR_EXIST;
1426 * XXX if the source and the dest don't use the same resource type it's broken
1428 if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){
1429 /* copy the data fork */
1430 if ((err = copy_fork(ADEID_DFORK, &add, adp)) == 0) {
1431 err = d_vol->vfs->vfs_copyfile(d_vol, src, dst);
1439 if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
1440 /* set the new name in the resource fork */
1441 ad_copy_header(&add, adp);
1442 ad_setname(&add, newname);
1445 ad_close( adp, adflags );
1447 if (ad_close( &add, adflags ) <0) {
1452 deletefile(d_vol, dst, 0);
1454 else if (stat_result == 0) {
1455 /* set dest modification date to src date */
1458 ut.actime = ut.modtime = st.st_mtime;
1460 /* FIXME netatalk doesn't use resource fork file date
1461 * but maybe we should set its modtime too.
1466 LOG(log_info, logtype_afpd, "end copyfile:");
1470 switch ( ret_err ) {
1476 return AFPERR_DFULL;
1478 return AFPERR_NOOBJ;
1480 return AFPERR_ACCESS;
1482 return AFPERR_VLOCK;
1484 return AFPERR_PARAM;
1488 /* -----------------------------------
1489 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1490 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1492 when deletefile is called we don't have lock on it, file is closed (for us)
1493 untrue if called by renamefile
1495 ad_open always try to open file RDWR first and ad_lock takes care of
1496 WRITE lock on read only file.
1499 static int check_attrib(struct adouble *adp)
1501 u_int16_t bshort = 0;
1503 ad_getattr(adp, &bshort);
1505 * Does kFPDeleteInhibitBit (bit 8) set?
1507 if ((bshort & htons(ATTRBIT_NODELETE))) {
1508 return AFPERR_OLOCK;
1510 if ((bshort & htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN))) {
1516 int deletefile(const struct vol *vol, char *file, int checkAttrib)
1519 struct adouble *adp = &ad;
1520 int adflags, err = AFP_OK;
1523 LOG(log_info, logtype_afpd, "begin deletefile:");
1526 /* try to open both forks at once */
1527 adflags = ADFLAGS_DF|ADFLAGS_HF;
1529 /* was EACCESS error try to get only metadata */
1530 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1531 if ( ad_metadata( file , ADFLAGS_OPENFORKS, &ad) == 0 ) {
1532 ad_close( &ad, adflags );
1533 if ((err = check_attrib(&ad))) {
1540 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1541 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1544 if (adflags == ADFLAGS_DF)
1545 return AFPERR_NOOBJ;
1547 /* that failed. now try to open just the data fork */
1548 adflags = ADFLAGS_DF;
1552 adp = NULL; /* maybe it's a file with no write mode for us */
1553 break; /* was return AFPERR_ACCESS;*/
1555 return AFPERR_VLOCK;
1557 return( AFPERR_PARAM );
1560 break; /* from the while */
1563 if (adp && (adflags & ADFLAGS_HF) ) {
1564 /* FIXME we have a pb here because we want to know if a file is open
1565 * there's a 'priority inversion' if you can't open the ressource fork RW
1566 * you can delete it if it's open because you can't get a write lock.
1568 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1571 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1573 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1574 ad_close( &ad, adflags );
1575 return( AFPERR_BUSY );
1579 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1582 else if (!(err = vol->vfs->vfs_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
1584 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1586 cnid_delete(vol->v_cdb, id);
1590 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1593 LOG(log_info, logtype_afpd, "end deletefile:");
1599 /* ------------------------------------ */
1600 /* return a file id */
1601 int afp_createid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1610 struct path *s_path;
1613 LOG(log_info, logtype_afpd, "begin afp_createid:");
1620 memcpy(&vid, ibuf, sizeof(vid));
1621 ibuf += sizeof(vid);
1623 if (NULL == ( vol = getvolbyvid( vid )) ) {
1624 return( AFPERR_PARAM);
1627 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1631 if (vol->v_flags & AFPVOL_RO)
1632 return AFPERR_VLOCK;
1634 memcpy(&did, ibuf, sizeof( did ));
1635 ibuf += sizeof(did);
1637 if (NULL == ( dir = dirlookup( vol, did )) ) {
1638 return afp_errno; /* was AFPERR_PARAM */
1641 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1642 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1645 if ( path_isadir(s_path) ) {
1646 return( AFPERR_BADTYPE );
1649 upath = s_path->u_name;
1650 switch (s_path->st_errno) {
1652 break; /* success */
1655 return AFPERR_ACCESS;
1657 return AFPERR_NOOBJ;
1659 return AFPERR_PARAM;
1662 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1663 memcpy(rbuf, &id, sizeof(id));
1664 *rbuflen = sizeof(id);
1665 return AFPERR_EXISTID;
1668 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1669 memcpy(rbuf, &id, sizeof(id));
1670 *rbuflen = sizeof(id);
1675 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1680 /* ------------------------------- */
1686 static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
1689 struct reenum *param = data;
1690 struct vol *vol = param->vol;
1691 cnid_t did = param->did;
1694 memset(&path, 0, sizeof(path));
1696 if ( stat(de->d_name, &path.st)<0 )
1699 /* update or add to cnid */
1700 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1702 #if AD_VERSION > AD_VERSION1
1703 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1704 struct adouble ad, *adp;
1708 path.u_name = de->d_name;
1710 adp = of_ad(vol, &path, &ad);
1712 if ( ad_open_metadata( de->d_name, 0, 0, adp ) < 0 ) {
1715 if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1718 ad_close_metadata(adp);
1720 #endif /* AD_VERSION > AD_VERSION1 */
1725 /* --------------------
1726 * Ok the db is out of synch with the dir.
1727 * but if it's a deleted file we don't want to do it again and again.
1730 reenumerate_id(struct vol *vol, char *name, struct dir *dir)
1736 if (vol->v_cdb == NULL) {
1740 /* FIXME use of_statdir ? */
1741 if (stat(name, &st)) {
1745 if (dirreenumerate(dir, &st)) {
1746 /* we already did it once and the dir haven't been modified */
1751 data.did = dir->d_did;
1752 if ((ret = for_each_dirent(vol, name, reenumerate_loop, (void *)&data)) >= 0) {
1753 setdiroffcnt(curdir, &st, ret);
1754 dir->d_flags |= DIRF_CNID;
1760 /* ------------------------------
1761 resolve a file id */
1762 int afp_resolveid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1771 u_int16_t vid, bitmap;
1773 static char buffer[12 + MAXPATHLEN + 1];
1774 int len = 12 + MAXPATHLEN + 1;
1777 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1783 memcpy(&vid, ibuf, sizeof(vid));
1784 ibuf += sizeof(vid);
1786 if (NULL == ( vol = getvolbyvid( vid )) ) {
1787 return( AFPERR_PARAM);
1790 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1794 memcpy(&id, ibuf, sizeof( id ));
1799 /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
1803 memset(&path, 0, sizeof(path));
1804 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1805 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1808 if (NULL == ( dir = dirlookup( vol, id )) ) {
1809 return AFPERR_NOID; /* idem AFPERR_PARAM */
1811 path.u_name = upath;
1812 if (movecwd(vol, dir) < 0) {
1816 return AFPERR_ACCESS;
1820 return AFPERR_PARAM;
1824 if ( of_stat(&path) < 0 ) {
1826 /* with nfs and our working directory is deleted */
1827 if (errno == ESTALE) {
1831 if ( errno == ENOENT && !retry) {
1832 /* cnid db is out of sync, reenumerate the directory and update ids */
1833 reenumerate_id(vol, ".", dir);
1841 return AFPERR_ACCESS;
1845 return AFPERR_PARAM;
1849 /* directories are bad */
1850 if (S_ISDIR(path.st.st_mode)) {
1851 /* OS9 and OSX don't return the same error code */
1852 return (afp_version >=30)?AFPERR_NOID:AFPERR_BADTYPE;
1855 memcpy(&bitmap, ibuf, sizeof(bitmap));
1856 bitmap = ntohs( bitmap );
1857 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1861 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1862 rbuf + sizeof(bitmap), &buflen))) {
1865 *rbuflen = buflen + sizeof(bitmap);
1866 memcpy(rbuf, ibuf, sizeof(bitmap));
1869 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1875 /* ------------------------------ */
1876 int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1886 static char buffer[12 + MAXPATHLEN + 1];
1887 int len = 12 + MAXPATHLEN + 1;
1890 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1896 memcpy(&vid, ibuf, sizeof(vid));
1897 ibuf += sizeof(vid);
1899 if (NULL == ( vol = getvolbyvid( vid )) ) {
1900 return( AFPERR_PARAM);
1903 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1907 if (vol->v_flags & AFPVOL_RO)
1908 return AFPERR_VLOCK;
1910 memcpy(&id, ibuf, sizeof( id ));
1914 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1918 if (NULL == ( dir = dirlookup( vol, id )) ) {
1919 return( AFPERR_PARAM );
1923 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1927 return AFPERR_ACCESS;
1932 /* still try to delete the id */
1936 return AFPERR_PARAM;
1939 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1940 return AFPERR_BADTYPE;
1942 if (cnid_delete(vol->v_cdb, fileid)) {
1945 return AFPERR_VLOCK;
1948 return AFPERR_ACCESS;
1950 return AFPERR_PARAM;
1955 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1961 /* ------------------------------ */
1962 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1966 if (path->st_errno) {
1967 switch (path->st_errno) {
1969 afp_errno = AFPERR_NOID;
1973 afp_errno = AFPERR_ACCESS;
1976 afp_errno = AFPERR_PARAM;
1981 /* we use file_access both for legacy Mac perm and
1982 * for unix privilege, rename will take care of folder perms
1984 if (file_access(path, OPENACC_WR ) < 0) {
1985 afp_errno = AFPERR_ACCESS;
1989 if ((*of = of_findname(path))) {
1990 /* reuse struct adouble so it won't break locks */
1994 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
1996 if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
1998 * The user must have the Read & Write privilege for both files in order to use this command.
2000 ad_close(adp, ADFLAGS_HF);
2001 afp_errno = AFPERR_ACCESS;
2008 #define APPLETEMP ".AppleTempXXXXXX"
2010 int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
2012 struct stat srcst, destst;
2014 struct dir *dir, *sdir;
2015 char *spath, temp[17], *p;
2016 char *supath, *upath;
2021 struct adouble *adsp = NULL;
2022 struct adouble *addp = NULL;
2023 struct ofork *s_of = NULL;
2024 struct ofork *d_of = NULL;
2035 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
2041 memcpy(&vid, ibuf, sizeof(vid));
2042 ibuf += sizeof(vid);
2044 if (NULL == ( vol = getvolbyvid( vid )) ) {
2045 return( AFPERR_PARAM);
2048 if ((vol->v_flags & AFPVOL_RO))
2049 return AFPERR_VLOCK;
2051 /* source and destination dids */
2052 memcpy(&sid, ibuf, sizeof(sid));
2053 ibuf += sizeof(sid);
2054 memcpy(&did, ibuf, sizeof(did));
2055 ibuf += sizeof(did);
2058 if (NULL == (dir = dirlookup( vol, sid )) ) {
2059 return afp_errno; /* was AFPERR_PARAM */
2062 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2063 return get_afp_errno(AFPERR_NOOBJ);
2066 if ( path_isadir(path) ) {
2067 return AFPERR_BADTYPE; /* it's a dir */
2070 /* save some stuff */
2073 spath = obj->oldtmp;
2074 supath = obj->newtmp;
2075 strcpy(spath, path->m_name);
2076 strcpy(supath, path->u_name); /* this is for the cnid changing */
2077 p = absupath( vol, sdir, supath);
2079 /* pathname too long */
2080 return AFPERR_PARAM ;
2083 ad_init(&ads, vol->v_adouble, vol->v_ad_options);
2084 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2088 /* ***** from here we may have resource fork open **** */
2090 /* look for the source cnid. if it doesn't exist, don't worry about
2092 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2094 if (NULL == ( dir = dirlookup( vol, did )) ) {
2095 err = afp_errno; /* was AFPERR_PARAM */
2096 goto err_exchangefile;
2099 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2100 err = get_afp_errno(AFPERR_NOOBJ);
2101 goto err_exchangefile;
2104 if ( path_isadir(path) ) {
2105 err = AFPERR_BADTYPE;
2106 goto err_exchangefile;
2109 /* FPExchangeFiles is the only call that can return the SameObj
2111 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2112 err = AFPERR_SAMEOBJ;
2113 goto err_exchangefile;
2116 ad_init(&add, vol->v_adouble, vol->v_ad_options);
2117 if (!(addp = find_adouble( path, &d_of, &add))) {
2119 goto err_exchangefile;
2123 /* they are not on the same device and at least one is open
2124 * FIXME broken for for crossdev and adouble v2
2127 crossdev = (srcst.st_dev != destst.st_dev);
2128 if (/* (d_of || s_of) && */ crossdev) {
2130 goto err_exchangefile;
2133 /* look for destination id. */
2134 upath = path->u_name;
2135 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2137 /* construct a temp name.
2138 * NOTE: the temp file will be in the dest file's directory. it
2139 * will also be inaccessible from AFP. */
2140 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2141 if (!mktemp(temp)) {
2143 goto err_exchangefile;
2147 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2148 ad_close(adsp, ADFLAGS_HF);
2149 ad_close(addp, ADFLAGS_HF);
2152 /* now, quickly rename the file. we error if we can't. */
2153 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2154 goto err_exchangefile;
2155 of_rename(vol, s_of, sdir, spath, curdir, temp);
2157 /* rename destination to source */
2158 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2159 goto err_src_to_tmp;
2160 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2162 /* rename temp to destination */
2163 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2164 goto err_dest_to_src;
2165 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2167 /* id's need switching. src -> dest and dest -> src.
2168 * we need to re-stat() if it was a cross device copy.
2171 cnid_delete(vol->v_cdb, sid);
2174 cnid_delete(vol->v_cdb, did);
2176 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2177 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2179 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2180 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2185 err = AFPERR_ACCESS;
2190 goto err_temp_to_dest;
2193 /* here we need to reopen if crossdev */
2194 if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2199 if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2204 /* change perms, src gets dest perm and vice versa */
2209 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2210 err = AFP_OK; /* ignore error */
2211 goto err_temp_to_dest;
2215 * we need to exchange ACL entries as well
2217 /* exchange_acls(vol, p, upath); */
2222 path->m_name = NULL;
2223 path->u_name = upath;
2225 setfilunixmode(vol, path, destst.st_mode);
2226 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2233 setfilunixmode(vol, path, srcst.st_mode);
2234 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2236 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2237 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2242 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2246 goto err_exchangefile;
2248 /* all this stuff is so that we can unwind a failed operation
2251 /* rename dest to temp */
2252 renamefile(vol, upath, temp, temp, adsp);
2253 of_rename(vol, s_of, curdir, upath, curdir, temp);
2256 /* rename source back to dest */
2257 renamefile(vol, p, upath, path->m_name, addp);
2258 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2261 /* rename temp back to source */
2262 renamefile(vol, temp, p, spath, adsp);
2263 of_rename(vol, s_of, curdir, temp, sdir, spath);
2266 if ( !s_of && adsp && ad_meta_fileno(adsp) != -1 ) { /* META */
2267 ad_close(adsp, ADFLAGS_HF);
2269 if ( !d_of && addp && ad_meta_fileno(addp) != -1 ) {/* META */
2270 ad_close(addp, ADFLAGS_HF);