2 * $Id: file.c,v 1.110 2009-09-21 12:35:05 franklahm Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
18 #else /* STDC_HEADERS */
22 #endif /* HAVE_STRCHR */
23 char *strchr (), *strrchr ();
26 #define memcpy(d,s,n) bcopy ((s), (d), (n))
27 #define memmove(d,s,n) bcopy ((s), (d), (n))
28 #endif /* ! HAVE_MEMCPY */
29 #endif /* STDC_HEADERS */
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 LOG(log_debug, logtype_afpd, "setfilparams: ad_open_metadata error");
895 * For some things, we don't need an adouble header:
896 * - change of modification date
897 * - UNIX privs (Bug-ID #2863424)
899 if ( (f_bitmap & ~(1<<FILPBIT_MDATE | 1<<FILPBIT_UNIXPR))) {
900 LOG(log_debug, logtype_afpd, "setfilparams: need adouble access");
901 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
903 LOG(log_debug, logtype_afpd, "setfilparams: no adouble perms, but only FILPBIT_MDATE and/or FILPBIT_UNIXPR");
905 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
906 ad_setname(adp, path->m_name);
911 while ( bitmap != 0 ) {
912 while (( bitmap & 1 ) == 0 ) {
919 ad_getattr(adp, &bshort);
920 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
921 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
922 change_parent_mdate = 1;
923 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
924 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
928 ad_setattr(adp, bshort);
931 ad_setdate(adp, AD_DATE_CREATE, cdate);
936 ad_setdate(adp, AD_DATE_BACKUP, bdate);
939 if (default_type( ad_entry( adp, ADEID_FINDERI ))
941 ((em = getextmap( path->m_name )) &&
942 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
943 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
944 || ((em = getdefextmap()) &&
945 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
946 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
948 memcpy(finder_buf, ufinderi, 8 );
950 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
952 case FILPBIT_UNIXPR :
954 setfilunixmode(vol, path, upriv);
957 case FILPBIT_PDINFO :
958 if (afp_version < 30) { /* else it's UTF8 name */
959 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
960 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
966 goto setfilparam_done;
973 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
974 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
978 ad_setdate(adp, AD_DATE_MODIFY, newdate);
979 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
985 ad_close_metadata( adp);
989 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
990 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
991 bitmap = 1<<FILPBIT_MDATE;
992 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
996 LOG(log_info, logtype_afpd, "end setfilparams:");
1002 * renamefile and copyfile take the old and new unix pathnames
1003 * and the new mac name.
1005 * src the source path
1006 * dst the dest filename in current dir
1007 * newname the dest mac name
1008 * adp adouble struct of src file, if open, or & zeroed one
1011 int renamefile(vol, src, dst, newname, adp )
1012 const struct vol *vol;
1013 char *src, *dst, *newname;
1014 struct adouble *adp;
1019 LOG(log_info, logtype_afpd, "begin renamefile:");
1022 if ( unix_rename( src, dst ) < 0 ) {
1025 return( AFPERR_NOOBJ );
1028 return( AFPERR_ACCESS );
1030 return AFPERR_VLOCK;
1031 case EXDEV : /* Cross device move -- try copy */
1032 /* NOTE: with open file it's an error because after the copy we will
1033 * get two files, it's fixable for our process (eg reopen the new file, get the
1034 * locks, and so on. But it doesn't solve the case with a second process
1036 if (adp->ad_open_forks) {
1037 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1038 return AFPERR_OLOCK; /* little lie */
1040 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1041 /* on error copyfile delete dest */
1044 return deletefile(vol, src, 0);
1046 return( AFPERR_PARAM );
1050 if (vol->vfs->rf_renamefile(vol, src, dst) < 0 ) {
1054 /* try to undo the data fork rename,
1055 * we know we are on the same device
1058 unix_rename( dst, src );
1059 /* return the first error */
1062 return AFPERR_NOOBJ;
1065 return AFPERR_ACCESS ;
1067 return AFPERR_VLOCK;
1069 return AFPERR_PARAM ;
1074 /* don't care if we can't open the newly renamed ressource fork
1076 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1077 ad_setname(adp, newname);
1079 ad_close( adp, ADFLAGS_HF );
1082 LOG(log_info, logtype_afpd, "end renamefile:");
1089 convert a Mac long name to an utf8 name,
1091 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1095 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1101 /* ---------------- */
1102 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1109 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1115 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1116 if (afp_version >= 30) {
1117 /* convert it to UTF8
1119 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1)
1123 strncpy( newname, ibuf, plen );
1124 newname[ plen ] = '\0';
1126 if (strlen(newname) != plen) {
1127 /* there's \0 in newname, e.g. it's a pathname not
1135 memcpy(&hint, ibuf, sizeof(hint));
1136 ibuf += sizeof(hint);
1138 memcpy(&len16, ibuf, sizeof(len16));
1139 ibuf += sizeof(len16);
1140 plen = ntohs(len16);
1143 if (plen > AFPOBJ_TMPSIZ) {
1146 strncpy( newname, ibuf, plen );
1147 newname[ plen ] = '\0';
1148 if (strlen(newname) != plen) {
1157 /* -----------------------------------
1159 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1161 char *ibuf, *rbuf _U_;
1162 int ibuflen _U_, *rbuflen;
1164 struct vol *s_vol, *d_vol;
1166 char *newname, *p, *upath;
1167 struct path *s_path;
1168 u_int32_t sdid, ddid;
1169 int err, retvalue = AFP_OK;
1170 u_int16_t svid, dvid;
1172 struct adouble ad, *adp;
1176 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1182 memcpy(&svid, ibuf, sizeof( svid ));
1183 ibuf += sizeof( svid );
1184 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1185 return( AFPERR_PARAM );
1188 memcpy(&sdid, ibuf, sizeof( sdid ));
1189 ibuf += sizeof( sdid );
1190 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1194 memcpy(&dvid, ibuf, sizeof( dvid ));
1195 ibuf += sizeof( dvid );
1196 memcpy(&ddid, ibuf, sizeof( ddid ));
1197 ibuf += sizeof( ddid );
1199 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1200 return get_afp_errno(AFPERR_PARAM);
1202 if ( path_isadir(s_path) ) {
1203 return( AFPERR_BADTYPE );
1206 /* don't allow copies when the file is open.
1207 * XXX: the spec only calls for read/deny write access.
1208 * however, copyfile doesn't have any of that info,
1209 * and locks need to stay coherent. as a result,
1210 * we just balk if the file is opened already. */
1212 adp = of_ad(s_vol, s_path, &ad);
1214 if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1215 return AFPERR_DENYCONF;
1217 denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
1218 getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1219 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1221 return AFPERR_DENYCONF;
1224 newname = obj->newtmp;
1225 strcpy( newname, s_path->m_name );
1227 p = ctoupath( s_vol, curdir, newname );
1229 return AFPERR_PARAM;
1233 /* FIXME svid != dvid && dvid's user can't read svid */
1235 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1236 return( AFPERR_PARAM );
1239 if (d_vol->v_flags & AFPVOL_RO)
1240 return AFPERR_VLOCK;
1242 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1246 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1247 return get_afp_errno(AFPERR_NOOBJ);
1249 if ( *s_path->m_name != '\0' ) {
1250 path_error(s_path, AFPERR_PARAM);
1253 /* one of the handful of places that knows about the path type */
1254 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1255 return( AFPERR_PARAM );
1257 /* newname is always only a filename so curdir *is* its
1260 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1261 return( AFPERR_PARAM );
1263 if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1269 if (vol->v_flags & AFPVOL_DROPBOX) {
1270 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1272 #endif /* DROPKLUDGE */
1274 setvoltime(obj, d_vol );
1277 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1283 /* ----------------------- */
1284 static int copy_all(const int dfd, const void *buf,
1290 LOG(log_info, logtype_afpd, "begin copy_all:");
1293 while (buflen > 0) {
1294 if ((cc = write(dfd, buf, buflen)) < 0) {
1306 LOG(log_info, logtype_afpd, "end copy_all:");
1312 /* --------------------------
1313 * copy only the fork data stream
1315 static int copy_fork(int eid, struct adouble *add, struct adouble *ads)
1322 if (eid == ADEID_DFORK) {
1323 sfd = ad_data_fileno(ads);
1324 dfd = ad_data_fileno(add);
1327 sfd = ad_reso_fileno(ads);
1328 dfd = ad_reso_fileno(add);
1331 if ((off_t)-1 == lseek(sfd, ad_getentryoff(ads, eid), SEEK_SET))
1334 if ((off_t)-1 == lseek(dfd, ad_getentryoff(add, eid), SEEK_SET))
1337 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1338 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1342 #define BUF 128*1024*1024
1344 if (fstat(sfd, &st) == 0) {
1347 if ( offset >= st.st_size) {
1350 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1351 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1354 case EINVAL: /* there's no guarantee that all fs support sendfile */
1363 lseek(sfd, offset, SEEK_SET);
1367 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1374 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1381 /* ----------------------------------
1382 * if newname is NULL (from directory.c) we don't want to copy the resource fork.
1383 * because we are doing it elsewhere.
1384 * currently if newname is NULL then adp is NULL.
1386 int copyfile(s_vol, d_vol, src, dst, newname, adp )
1387 const struct vol *s_vol, *d_vol;
1388 char *src, *dst, *newname;
1389 struct adouble *adp;
1391 struct adouble ads, add;
1399 LOG(log_info, logtype_afpd, "begin copyfile:");
1403 ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options);
1406 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1407 adflags = ADFLAGS_DF;
1409 adflags |= ADFLAGS_HF;
1412 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1417 if (ad_meta_fileno(adp) == -1 && ad_reso_fileno(adp) == -1) { /* META / HF */
1418 /* no resource fork, don't create one for dst file */
1419 adflags &= ~ADFLAGS_HF;
1422 stat_result = fstat(ad_data_fileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */
1424 if (stat_result < 0) {
1425 /* unlikely but if fstat fails, the default file mode will be 0666. */
1426 st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
1429 if (ad_open(dst , adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
1431 ad_close( adp, adflags );
1432 if (EEXIST != ret_err) {
1433 deletefile(d_vol, dst, 0);
1436 return AFPERR_EXIST;
1438 /* XXX if the source and the dest don't use the same resource type it's broken
1440 if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){
1441 /* copy the data fork */
1442 err = copy_fork(ADEID_DFORK, &add, adp);
1449 if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
1450 /* set the new name in the resource fork */
1451 ad_copy_header(&add, adp);
1452 ad_setname(&add, newname);
1455 ad_close( adp, adflags );
1457 if (ad_close( &add, adflags ) <0) {
1462 deletefile(d_vol, dst, 0);
1464 else if (stat_result == 0) {
1465 /* set dest modification date to src date */
1468 ut.actime = ut.modtime = st.st_mtime;
1470 /* FIXME netatalk doesn't use resource fork file date
1471 * but maybe we should set its modtime too.
1476 LOG(log_info, logtype_afpd, "end copyfile:");
1480 switch ( ret_err ) {
1486 return AFPERR_DFULL;
1488 return AFPERR_NOOBJ;
1490 return AFPERR_ACCESS;
1492 return AFPERR_VLOCK;
1494 return AFPERR_PARAM;
1498 /* -----------------------------------
1499 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1500 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1502 when deletefile is called we don't have lock on it, file is closed (for us)
1503 untrue if called by renamefile
1505 ad_open always try to open file RDWR first and ad_lock takes care of
1506 WRITE lock on read only file.
1509 static int check_attrib(struct adouble *adp)
1511 u_int16_t bshort = 0;
1513 ad_getattr(adp, &bshort);
1515 * Does kFPDeleteInhibitBit (bit 8) set?
1517 if ((bshort & htons(ATTRBIT_NODELETE))) {
1518 return AFPERR_OLOCK;
1520 if ((bshort & htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN))) {
1526 int deletefile( vol, file, checkAttrib )
1527 const struct vol *vol;
1532 struct adouble *adp = &ad;
1533 int adflags, err = AFP_OK;
1536 LOG(log_info, logtype_afpd, "begin deletefile:");
1539 /* try to open both forks at once */
1540 adflags = ADFLAGS_DF|ADFLAGS_HF;
1542 /* was EACCESS error try to get only metadata */
1543 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1544 if ( ad_metadata( file , ADFLAGS_OPENFORKS, &ad) == 0 ) {
1545 ad_close( &ad, adflags );
1546 if ((err = check_attrib(&ad))) {
1553 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1554 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1557 if (adflags == ADFLAGS_DF)
1558 return AFPERR_NOOBJ;
1560 /* that failed. now try to open just the data fork */
1561 adflags = ADFLAGS_DF;
1565 adp = NULL; /* maybe it's a file with no write mode for us */
1566 break; /* was return AFPERR_ACCESS;*/
1568 return AFPERR_VLOCK;
1570 return( AFPERR_PARAM );
1573 break; /* from the while */
1576 if (adp && (adflags & ADFLAGS_HF) ) {
1577 /* FIXME we have a pb here because we want to know if a file is open
1578 * there's a 'priority inversion' if you can't open the ressource fork RW
1579 * you can delete it if it's open because you can't get a write lock.
1581 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1584 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1586 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1587 ad_close( &ad, adflags );
1588 return( AFPERR_BUSY );
1592 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1595 else if (!(err = vol->vfs->rf_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
1597 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1599 cnid_delete(vol->v_cdb, id);
1603 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1606 LOG(log_info, logtype_afpd, "end deletefile:");
1612 /* ------------------------------------ */
1613 /* return a file id */
1614 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1617 int ibuflen _U_, *rbuflen;
1626 struct path *s_path;
1629 LOG(log_info, logtype_afpd, "begin afp_createid:");
1636 memcpy(&vid, ibuf, sizeof(vid));
1637 ibuf += sizeof(vid);
1639 if (NULL == ( vol = getvolbyvid( vid )) ) {
1640 return( AFPERR_PARAM);
1643 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1647 if (vol->v_flags & AFPVOL_RO)
1648 return AFPERR_VLOCK;
1650 memcpy(&did, ibuf, sizeof( did ));
1651 ibuf += sizeof(did);
1653 if (NULL == ( dir = dirlookup( vol, did )) ) {
1654 return afp_errno; /* was AFPERR_PARAM */
1657 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1658 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1661 if ( path_isadir(s_path) ) {
1662 return( AFPERR_BADTYPE );
1665 upath = s_path->u_name;
1666 switch (s_path->st_errno) {
1668 break; /* success */
1671 return AFPERR_ACCESS;
1673 return AFPERR_NOOBJ;
1675 return AFPERR_PARAM;
1678 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1679 memcpy(rbuf, &id, sizeof(id));
1680 *rbuflen = sizeof(id);
1681 return AFPERR_EXISTID;
1684 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1685 memcpy(rbuf, &id, sizeof(id));
1686 *rbuflen = sizeof(id);
1691 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1696 /* ------------------------------- */
1702 static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
1705 struct reenum *param = data;
1706 struct vol *vol = param->vol;
1707 cnid_t did = param->did;
1710 memset(&path, 0, sizeof(path));
1712 if ( stat(de->d_name, &path.st)<0 )
1715 /* update or add to cnid */
1716 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1718 #if AD_VERSION > AD_VERSION1
1719 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1720 struct adouble ad, *adp;
1724 path.u_name = de->d_name;
1726 adp = of_ad(vol, &path, &ad);
1728 if ( ad_open_metadata( de->d_name, 0, 0, adp ) < 0 ) {
1731 if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1734 ad_close_metadata(adp);
1736 #endif /* AD_VERSION > AD_VERSION1 */
1741 /* --------------------
1742 * Ok the db is out of synch with the dir.
1743 * but if it's a deleted file we don't want to do it again and again.
1746 reenumerate_id(struct vol *vol, char *name, struct dir *dir)
1752 if (vol->v_cdb == NULL) {
1756 /* FIXME use of_statdir ? */
1757 if (stat(name, &st)) {
1761 if (dirreenumerate(dir, &st)) {
1762 /* we already did it once and the dir haven't been modified */
1767 data.did = dir->d_did;
1768 if ((ret = for_each_dirent(vol, name, reenumerate_loop, (void *)&data)) >= 0) {
1769 setdiroffcnt(curdir, &st, ret);
1770 dir->d_flags |= DIRF_CNID;
1776 /* ------------------------------
1777 resolve a file id */
1778 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1781 int ibuflen _U_, *rbuflen;
1787 int err, buflen, retry=0;
1789 u_int16_t vid, bitmap;
1791 static char buffer[12 + MAXPATHLEN + 1];
1792 int len = 12 + MAXPATHLEN + 1;
1795 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1801 memcpy(&vid, ibuf, sizeof(vid));
1802 ibuf += sizeof(vid);
1804 if (NULL == ( vol = getvolbyvid( vid )) ) {
1805 return( AFPERR_PARAM);
1808 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1812 memcpy(&id, ibuf, sizeof( id ));
1817 /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
1821 memset(&path, 0, sizeof(path));
1822 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1823 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1826 if (NULL == ( dir = dirlookup( vol, id )) ) {
1827 return AFPERR_NOID; /* idem AFPERR_PARAM */
1829 path.u_name = upath;
1830 if (movecwd(vol, dir) < 0) {
1834 return AFPERR_ACCESS;
1838 return AFPERR_PARAM;
1842 if ( of_stat(&path) < 0 ) {
1844 /* with nfs and our working directory is deleted */
1845 if (errno == ESTALE) {
1849 if ( errno == ENOENT && !retry) {
1850 /* cnid db is out of sync, reenumerate the directory and update ids */
1851 reenumerate_id(vol, ".", dir);
1859 return AFPERR_ACCESS;
1863 return AFPERR_PARAM;
1867 /* directories are bad */
1868 if (S_ISDIR(path.st.st_mode)) {
1869 /* OS9 and OSX don't return the same error code */
1870 return (afp_version >=30)?AFPERR_NOID:AFPERR_BADTYPE;
1873 memcpy(&bitmap, ibuf, sizeof(bitmap));
1874 bitmap = ntohs( bitmap );
1875 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1879 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1880 rbuf + sizeof(bitmap), &buflen))) {
1883 *rbuflen = buflen + sizeof(bitmap);
1884 memcpy(rbuf, ibuf, sizeof(bitmap));
1887 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1893 /* ------------------------------ */
1894 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1896 char *ibuf, *rbuf _U_;
1897 int ibuflen _U_, *rbuflen;
1907 static char buffer[12 + MAXPATHLEN + 1];
1908 int len = 12 + MAXPATHLEN + 1;
1911 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1917 memcpy(&vid, ibuf, sizeof(vid));
1918 ibuf += sizeof(vid);
1920 if (NULL == ( vol = getvolbyvid( vid )) ) {
1921 return( AFPERR_PARAM);
1924 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1928 if (vol->v_flags & AFPVOL_RO)
1929 return AFPERR_VLOCK;
1931 memcpy(&id, ibuf, sizeof( id ));
1935 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1939 if (NULL == ( dir = dirlookup( vol, id )) ) {
1940 return( AFPERR_PARAM );
1944 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1948 return AFPERR_ACCESS;
1953 /* still try to delete the id */
1957 return AFPERR_PARAM;
1960 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1961 return AFPERR_BADTYPE;
1963 if (cnid_delete(vol->v_cdb, fileid)) {
1966 return AFPERR_VLOCK;
1969 return AFPERR_ACCESS;
1971 return AFPERR_PARAM;
1976 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1982 /* ------------------------------ */
1983 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1987 if (path->st_errno) {
1988 switch (path->st_errno) {
1990 afp_errno = AFPERR_NOID;
1994 afp_errno = AFPERR_ACCESS;
1997 afp_errno = AFPERR_PARAM;
2002 /* we use file_access both for legacy Mac perm and
2003 * for unix privilege, rename will take care of folder perms
2005 if (file_access(path, OPENACC_WR ) < 0) {
2006 afp_errno = AFPERR_ACCESS;
2010 if ((*of = of_findname(path))) {
2011 /* reuse struct adouble so it won't break locks */
2015 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
2017 if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
2019 * The user must have the Read & Write privilege for both files in order to use this command.
2021 ad_close(adp, ADFLAGS_HF);
2022 afp_errno = AFPERR_ACCESS;
2029 #define APPLETEMP ".AppleTempXXXXXX"
2031 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
2033 char *ibuf, *rbuf _U_ ;
2034 int ibuflen _U_, *rbuflen;
2036 struct stat srcst, destst;
2038 struct dir *dir, *sdir;
2039 char *spath, temp[17], *p;
2040 char *supath, *upath;
2045 struct adouble *adsp = NULL;
2046 struct adouble *addp = NULL;
2047 struct ofork *s_of = NULL;
2048 struct ofork *d_of = NULL;
2059 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
2065 memcpy(&vid, ibuf, sizeof(vid));
2066 ibuf += sizeof(vid);
2068 if (NULL == ( vol = getvolbyvid( vid )) ) {
2069 return( AFPERR_PARAM);
2072 if ((vol->v_flags & AFPVOL_RO))
2073 return AFPERR_VLOCK;
2075 /* source and destination dids */
2076 memcpy(&sid, ibuf, sizeof(sid));
2077 ibuf += sizeof(sid);
2078 memcpy(&did, ibuf, sizeof(did));
2079 ibuf += sizeof(did);
2082 if (NULL == (dir = dirlookup( vol, sid )) ) {
2083 return afp_errno; /* was AFPERR_PARAM */
2086 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2087 return get_afp_errno(AFPERR_NOOBJ);
2090 if ( path_isadir(path) ) {
2091 return AFPERR_BADTYPE; /* it's a dir */
2094 /* save some stuff */
2097 spath = obj->oldtmp;
2098 supath = obj->newtmp;
2099 strcpy(spath, path->m_name);
2100 strcpy(supath, path->u_name); /* this is for the cnid changing */
2101 p = absupath( vol, sdir, supath);
2103 /* pathname too long */
2104 return AFPERR_PARAM ;
2107 ad_init(&ads, vol->v_adouble, vol->v_ad_options);
2108 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2112 /* ***** from here we may have resource fork open **** */
2114 /* look for the source cnid. if it doesn't exist, don't worry about
2116 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2118 if (NULL == ( dir = dirlookup( vol, did )) ) {
2119 err = afp_errno; /* was AFPERR_PARAM */
2120 goto err_exchangefile;
2123 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2124 err = get_afp_errno(AFPERR_NOOBJ);
2125 goto err_exchangefile;
2128 if ( path_isadir(path) ) {
2129 err = AFPERR_BADTYPE;
2130 goto err_exchangefile;
2133 /* FPExchangeFiles is the only call that can return the SameObj
2135 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2136 err = AFPERR_SAMEOBJ;
2137 goto err_exchangefile;
2140 ad_init(&add, vol->v_adouble, vol->v_ad_options);
2141 if (!(addp = find_adouble( path, &d_of, &add))) {
2143 goto err_exchangefile;
2147 /* they are not on the same device and at least one is open
2148 * FIXME broken for for crossdev and adouble v2
2151 crossdev = (srcst.st_dev != destst.st_dev);
2152 if (/* (d_of || s_of) && */ crossdev) {
2154 goto err_exchangefile;
2157 /* look for destination id. */
2158 upath = path->u_name;
2159 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2161 /* construct a temp name.
2162 * NOTE: the temp file will be in the dest file's directory. it
2163 * will also be inaccessible from AFP. */
2164 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2165 if (!mktemp(temp)) {
2167 goto err_exchangefile;
2171 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2172 ad_close(adsp, ADFLAGS_HF);
2173 ad_close(addp, ADFLAGS_HF);
2176 /* now, quickly rename the file. we error if we can't. */
2177 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2178 goto err_exchangefile;
2179 of_rename(vol, s_of, sdir, spath, curdir, temp);
2181 /* rename destination to source */
2182 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2183 goto err_src_to_tmp;
2184 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2186 /* rename temp to destination */
2187 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2188 goto err_dest_to_src;
2189 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2191 /* id's need switching. src -> dest and dest -> src.
2192 * we need to re-stat() if it was a cross device copy.
2195 cnid_delete(vol->v_cdb, sid);
2198 cnid_delete(vol->v_cdb, did);
2200 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2201 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2203 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2204 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2209 err = AFPERR_ACCESS;
2214 goto err_temp_to_dest;
2217 /* here we need to reopen if crossdev */
2218 if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2223 if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2228 /* change perms, src gets dest perm and vice versa */
2233 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2234 err = AFP_OK; /* ignore error */
2235 goto err_temp_to_dest;
2239 * we need to exchange ACL entries as well
2241 /* exchange_acls(vol, p, upath); */
2246 path->m_name = NULL;
2247 path->u_name = upath;
2249 setfilunixmode(vol, path, destst.st_mode);
2250 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2257 setfilunixmode(vol, path, srcst.st_mode);
2258 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2260 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2261 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2266 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2270 goto err_exchangefile;
2272 /* all this stuff is so that we can unwind a failed operation
2275 /* rename dest to temp */
2276 renamefile(vol, upath, temp, temp, adsp);
2277 of_rename(vol, s_of, curdir, upath, curdir, temp);
2280 /* rename source back to dest */
2281 renamefile(vol, p, upath, path->m_name, addp);
2282 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2285 /* rename temp back to source */
2286 renamefile(vol, temp, p, spath, adsp);
2287 of_rename(vol, s_of, curdir, temp, sdir, spath);
2290 if ( !s_of && adsp && ad_meta_fileno(adsp) != -1 ) { /* META */
2291 ad_close(adsp, ADFLAGS_HF);
2293 if ( !d_of && addp && ad_meta_fileno(addp) != -1 ) {/* META */
2294 ad_close(addp, ADFLAGS_HF);