2 * $Id: file.c,v 1.128 2010-01-05 15:12:19 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 */
33 #include <sys/param.h>
35 #include <atalk/adouble.h>
36 #include <atalk/vfs.h>
37 #include <atalk/logger.h>
38 #include <atalk/afp.h>
39 #include <atalk/util.h>
40 #include <atalk/cnid.h>
41 #include <atalk/unix.h>
43 #include "directory.h"
52 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
53 * field bytes subfield bytes
56 * ioFlFndrInfo 16 -> type 4 type field
57 * creator 4 creator field
58 * flags 2 finder flags:
60 * location 4 location in window
61 * folder 2 window that contains file
63 * ioFlXFndrInfo 16 -> iconID 2 icon id
65 * script 1 script system
67 * commentID 2 comment id
68 * putawayID 4 home directory id
71 const u_char ufinderi[ADEDLEN_FINDERI] = {
72 0, 0, 0, 0, 0, 0, 0, 0,
73 1, 0, 0, 0, 0, 0, 0, 0,
74 0, 0, 0, 0, 0, 0, 0, 0,
75 0, 0, 0, 0, 0, 0, 0, 0
78 static const u_char old_ufinderi[] = {
79 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X'
82 /* ----------------------
84 static int default_type(void *finder)
86 if (!memcmp(finder, ufinderi, 8) || !memcmp(finder, old_ufinderi, 8))
91 /* FIXME path : unix or mac name ? (for now it's unix name ) */
92 void *get_finderinfo(const struct vol *vol, const char *upath, struct adouble *adp, void *data)
95 void *ad_finder = NULL;
99 ad_finder = ad_entry(adp, ADEID_FINDERI);
102 memcpy(data, ad_finder, ADEDLEN_FINDERI);
104 if (default_type(ad_finder))
108 memcpy(data, ufinderi, ADEDLEN_FINDERI);
110 if (vol_inv_dots(vol) && *upath == '.') { /* make it invisible */
113 ashort = htons(FINDERINFO_INVISIBLE);
114 memcpy((char *)data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
117 /** Only enter if no appledouble information and no finder information found. */
118 if (chk_ext && (em = getextmap( upath ))) {
119 memcpy(data, em->em_type, sizeof( em->em_type ));
120 memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator));
125 /* ---------------------
127 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8)
132 aint = strlen( name );
136 if (utf8_encoding()) {
137 /* but name is an utf8 mac name */
140 /* global static variable... */
142 if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
151 if (aint > MACFILELEN)
158 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
161 utf8 = vol->v_kTextEncoding;
162 memcpy(data, &utf8, sizeof(utf8));
163 data += sizeof(utf8);
166 memcpy(data, &temp, sizeof(temp));
167 data += sizeof(temp);
170 memcpy( data, src, aint );
180 * FIXME: PDINFO is UTF8 and doesn't need adp
182 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
183 (1 << FILPBIT_CDATE) |\
184 (1 << FILPBIT_MDATE) |\
185 (1 << FILPBIT_BDATE) |\
186 (1 << FILPBIT_FINFO) |\
187 (1 << FILPBIT_RFLEN) |\
188 (1 << FILPBIT_EXTRFLEN) |\
189 (1 << FILPBIT_PDINFO) |\
190 (1 << FILPBIT_FNUM) |\
191 (1 << FILPBIT_UNIXPR)))
193 /* -------------------------- */
194 u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st,
195 const cnid_t did, char *upath, const int len)
199 if (vol->v_cdb != NULL) {
200 /* prime aint with what we think is the cnid, set did to zero for
201 catching moved files */
202 aint = ad_getid(adp, st->st_dev, st->st_ino, 0, vol->v_stamp);
204 aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
205 /* Throw errors if cnid_add fails. */
206 if (aint == CNID_INVALID) {
208 case CNID_ERR_CLOSE: /* the db is closed */
211 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
212 afp_errno = AFPERR_PARAM;
215 afp_errno = AFPERR_PARAM;
218 afp_errno = AFPERR_MISC;
223 /* update the ressource fork
224 * for a folder adp is always null
226 if (ad_setid(adp, st->st_dev, st->st_ino, aint, did, vol->v_stamp)) {
234 /* -------------------------- */
235 int getmetadata(struct vol *vol,
237 struct path *path, struct dir *dir,
238 char *buf, size_t *buflen, struct adouble *adp)
240 char *data, *l_nameoff = NULL, *upath;
241 char *utf_nameoff = NULL;
246 u_char achar, fdType[4];
252 LOG(log_debug9, logtype_afpd, "begin getmetadata:");
255 upath = path->u_name;
260 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
261 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
262 || (bitmap & (1 << FILPBIT_FNUM))) {
264 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
270 path->m_name = utompath(vol, upath, id, utf8_encoding());
273 while ( bitmap != 0 ) {
274 while (( bitmap & 1 ) == 0 ) {
282 ad_getattr(adp, &ashort);
283 } else if (vol_inv_dots(vol) && *upath == '.') {
284 ashort = htons(ATTRBIT_INVISIBLE);
288 /* FIXME do we want a visual clue if the file is read only
291 accessmode( ".", &ma, dir , NULL);
292 if ((ma.ma_user & AR_UWRITE)) {
293 accessmode( upath, &ma, dir , st);
294 if (!(ma.ma_user & AR_UWRITE)) {
295 ashort |= htons(ATTRBIT_NOWRITE);
299 memcpy(data, &ashort, sizeof( ashort ));
300 data += sizeof( ashort );
304 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
305 data += sizeof( u_int32_t );
309 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
310 aint = AD_DATE_FROM_UNIX(st->st_mtime);
311 memcpy(data, &aint, sizeof( aint ));
312 data += sizeof( aint );
316 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
317 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
318 aint = AD_DATE_FROM_UNIX(st->st_mtime);
321 aint = AD_DATE_FROM_UNIX(st->st_mtime);
323 memcpy(data, &aint, sizeof( int ));
324 data += sizeof( int );
328 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
329 aint = AD_DATE_START;
330 memcpy(data, &aint, sizeof( int ));
331 data += sizeof( int );
335 get_finderinfo(vol, upath, adp, (char *)data);
336 data += ADEDLEN_FINDERI;
341 data += sizeof( u_int16_t );
345 memset(data, 0, sizeof(u_int16_t));
346 data += sizeof( u_int16_t );
350 memcpy(data, &id, sizeof( id ));
351 data += sizeof( id );
355 if (st->st_size > 0xffffffff)
358 aint = htonl( st->st_size );
359 memcpy(data, &aint, sizeof( aint ));
360 data += sizeof( aint );
365 if (adp->ad_rlen > 0xffffffff)
368 aint = htonl( adp->ad_rlen);
372 memcpy(data, &aint, sizeof( aint ));
373 data += sizeof( aint );
376 /* Current client needs ProDOS info block for this file.
377 Use simple heuristic and let the Mac "type" string tell
378 us what the PD file code should be. Everything gets a
379 subtype of 0x0000 unless the original value was hashed
380 to "pXYZ" when we created it. See IA, Ver 2.
381 <shirsch@adelphia.net> */
382 case FILPBIT_PDINFO :
383 if (afp_version >= 30) { /* UTF8 name */
384 utf8 = kTextEncodingUTF8;
386 data += sizeof( u_int16_t );
388 memcpy(data, &aint, sizeof( aint ));
389 data += sizeof( aint );
393 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
395 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
399 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
403 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
407 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
411 else if ( fdType[0] == 'p' ) {
413 ashort = (fdType[2] * 256) + fdType[3];
427 memcpy(data, &ashort, sizeof( ashort ));
428 data += sizeof( ashort );
429 memset(data, 0, sizeof( ashort ));
430 data += sizeof( ashort );
433 case FILPBIT_EXTDFLEN:
434 aint = htonl(st->st_size >> 32);
435 memcpy(data, &aint, sizeof( aint ));
436 data += sizeof( aint );
437 aint = htonl(st->st_size);
438 memcpy(data, &aint, sizeof( aint ));
439 data += sizeof( aint );
441 case FILPBIT_EXTRFLEN:
444 aint = htonl(adp->ad_rlen >> 32);
445 memcpy(data, &aint, sizeof( aint ));
446 data += sizeof( aint );
448 aint = htonl(adp->ad_rlen);
449 memcpy(data, &aint, sizeof( aint ));
450 data += sizeof( aint );
452 case FILPBIT_UNIXPR :
453 /* accessmode may change st_mode with ACLs */
454 accessmode( upath, &ma, dir , st);
456 aint = htonl(st->st_uid);
457 memcpy( data, &aint, sizeof( aint ));
458 data += sizeof( aint );
459 aint = htonl(st->st_gid);
460 memcpy( data, &aint, sizeof( aint ));
461 data += sizeof( aint );
464 type == slnk indicates an OSX style symlink,
465 we have to add S_IFLNK to the mode, otherwise
466 10.3 clients freak out. */
470 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
471 if ( memcmp( fdType, "slnk", 4 ) == 0 ) {
477 memcpy( data, &aint, sizeof( aint ));
478 data += sizeof( aint );
480 *data++ = ma.ma_user;
481 *data++ = ma.ma_world;
482 *data++ = ma.ma_group;
483 *data++ = ma.ma_owner;
487 return( AFPERR_BITMAP );
493 ashort = htons( data - buf );
494 memcpy(l_nameoff, &ashort, sizeof( ashort ));
495 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
498 ashort = htons( data - buf );
499 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
500 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
502 *buflen = data - buf;
506 /* ----------------------- */
507 int getfilparams(struct vol *vol,
509 struct path *path, struct dir *dir,
510 char *buf, size_t *buflen )
512 struct adouble ad, *adp;
517 LOG(log_debug9, logtype_default, "begin getfilparams:");
520 opened = PARAM_NEED_ADP(bitmap);
525 int flags = (bitmap & (1 << FILPBIT_ATTR))?ADFLAGS_OPENFORKS:0;
527 adp = of_ad(vol, path, &ad);
528 upath = path->u_name;
530 if ( ad_metadata( upath, flags, adp) < 0 ) {
533 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
534 upath, strerror(errno));
535 return AFPERR_ACCESS;
537 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
546 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp);
548 ad_close_metadata( adp);
551 LOG(log_debug9, logtype_afpd, "end getfilparams:");
557 /* ----------------------------- */
558 int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
560 struct adouble ad, *adp;
563 struct ofork *of = NULL;
565 int creatf, did, openf, retvalue = AFP_OK;
571 creatf = (unsigned char) *ibuf++;
573 memcpy(&vid, ibuf, sizeof( vid ));
574 ibuf += sizeof( vid );
576 if (NULL == ( vol = getvolbyvid( vid )) ) {
577 return( AFPERR_PARAM );
580 if (vol->v_flags & AFPVOL_RO)
583 memcpy(&did, ibuf, sizeof( did));
584 ibuf += sizeof( did );
586 if (NULL == ( dir = dirlookup( vol, did )) ) {
590 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
591 return get_afp_errno(AFPERR_PARAM);
594 if ( *s_path->m_name == '\0' ) {
595 return( AFPERR_BADTYPE );
598 upath = s_path->u_name;
600 /* if upath is deleted we already in trouble anyway */
601 if ((of = of_findname(s_path))) {
604 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
608 /* on a hard create, fail if file exists and is open */
611 openf = O_RDWR|O_CREAT|O_TRUNC;
613 /* on a soft create, if the file is open then ad_open won't fail
614 because open syscall is not called
619 openf = O_RDWR|O_CREAT|O_EXCL;
622 if ( ad_open( upath, ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF|ADFLAGS_CREATE,
623 openf, 0666, adp) < 0 ) {
627 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
628 return ( AFPERR_NOOBJ );
630 return( AFPERR_EXIST );
632 return( AFPERR_ACCESS );
635 return( AFPERR_DFULL );
637 return( AFPERR_PARAM );
640 if ( ad_reso_fileno( adp ) == -1 ) { /* Hard META / HF */
641 /* on noadouble volumes, just creating the data fork is ok */
642 if (vol_noadouble(vol)) {
643 ad_close( adp, ADFLAGS_DF );
644 goto createfile_done;
646 /* FIXME with hard create on an existing file, we already
647 * corrupted the data file.
649 netatalk_unlink( upath );
650 ad_close( adp, ADFLAGS_DF );
651 return AFPERR_ACCESS;
654 path = s_path->m_name;
655 ad_setname(adp, path);
657 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
663 if (vol->v_flags & AFPVOL_DROPBOX) {
664 retvalue = matchfile2dirperms(upath, vol, did);
666 #endif /* DROPKLUDGE */
668 setvoltime(obj, vol );
673 int afp_setfilparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
679 u_int16_t vid, bitmap;
684 memcpy(&vid, ibuf, sizeof( vid ));
685 ibuf += sizeof( vid );
686 if (NULL == ( vol = getvolbyvid( vid )) ) {
687 return( AFPERR_PARAM );
690 if (vol->v_flags & AFPVOL_RO)
693 memcpy(&did, ibuf, sizeof( did ));
694 ibuf += sizeof( did );
695 if (NULL == ( dir = dirlookup( vol, did )) ) {
696 return afp_errno; /* was AFPERR_NOOBJ */
699 memcpy(&bitmap, ibuf, sizeof( bitmap ));
700 bitmap = ntohs( bitmap );
701 ibuf += sizeof( bitmap );
703 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
704 return get_afp_errno(AFPERR_PARAM);
707 if (path_isadir(s_path)) {
708 return( AFPERR_BADTYPE ); /* it's a directory */
711 if ( s_path->st_errno != 0 ) {
712 return( AFPERR_NOOBJ );
715 if ((u_long)ibuf & 1 ) {
719 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
720 setvoltime(obj, vol );
727 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
730 extern struct path Cur_Path;
732 int setfilparams(struct vol *vol,
733 struct path *path, u_int16_t f_bitmap, char *buf )
735 struct adouble ad, *adp;
737 int bit, isad = 1, err = AFP_OK;
739 u_char achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
740 u_int16_t ashort, bshort;
743 u_int16_t upriv_bit = 0;
747 int change_mdate = 0;
748 int change_parent_mdate = 0;
753 u_int16_t bitmap = f_bitmap;
754 u_int32_t cdate,bdate;
755 u_char finder_buf[32];
758 LOG(log_debug9, logtype_afpd, "begin setfilparams:");
761 adp = of_ad(vol, path, &ad);
762 upath = path->u_name;
764 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
765 return AFPERR_ACCESS;
768 /* with unix priv maybe we have to change adouble file priv first */
770 while ( bitmap != 0 ) {
771 while (( bitmap & 1 ) == 0 ) {
778 memcpy(&ashort, buf, sizeof( ashort ));
779 buf += sizeof( ashort );
783 memcpy(&cdate, buf, sizeof(cdate));
784 buf += sizeof( cdate );
787 memcpy(&newdate, buf, sizeof( newdate ));
788 buf += sizeof( newdate );
792 memcpy(&bdate, buf, sizeof( bdate));
793 buf += sizeof( bdate );
797 memcpy(finder_buf, buf, 32 );
800 case FILPBIT_UNIXPR :
801 if (!vol_unix_priv(vol)) {
802 /* this volume doesn't use unix priv */
808 change_parent_mdate = 1;
810 memcpy( &aint, buf, sizeof( aint ));
811 f_uid = ntohl (aint);
812 buf += sizeof( aint );
813 memcpy( &aint, buf, sizeof( aint ));
814 f_gid = ntohl (aint);
815 buf += sizeof( aint );
816 setfilowner(vol, f_uid, f_gid, path);
818 memcpy( &upriv, buf, sizeof( upriv ));
819 buf += sizeof( upriv );
820 upriv = ntohl (upriv);
821 if ((upriv & S_IWUSR)) {
822 setfilunixmode(vol, path, upriv);
829 case FILPBIT_PDINFO :
830 if (afp_version < 30) { /* else it's UTF8 name */
833 /* Keep special case to support crlf translations */
834 if ((unsigned int) achar == 0x04) {
835 fdType = (u_char *)"TEXT";
838 xyy[0] = ( u_char ) 'p';
849 /* break while loop */
858 /* second try with adouble open
860 if ( ad_open_metadata( upath, 0, O_CREAT, adp) < 0) {
861 LOG(log_debug, logtype_afpd, "setfilparams: ad_open_metadata error");
863 * For some things, we don't need an adouble header:
864 * - change of modification date
865 * - UNIX privs (Bug-ID #2863424)
867 if ( (f_bitmap & ~(1<<FILPBIT_MDATE | 1<<FILPBIT_UNIXPR))) {
868 LOG(log_debug, logtype_afpd, "setfilparams: need adouble access");
869 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
871 LOG(log_debug, logtype_afpd, "setfilparams: no adouble perms, but only FILPBIT_MDATE and/or FILPBIT_UNIXPR");
873 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
874 ad_setname(adp, path->m_name);
879 while ( bitmap != 0 ) {
880 while (( bitmap & 1 ) == 0 ) {
887 ad_getattr(adp, &bshort);
888 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
889 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
890 change_parent_mdate = 1;
891 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
892 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
896 ad_setattr(adp, bshort);
899 ad_setdate(adp, AD_DATE_CREATE, cdate);
904 ad_setdate(adp, AD_DATE_BACKUP, bdate);
907 if (default_type( ad_entry( adp, ADEID_FINDERI ))
909 ((em = getextmap( path->m_name )) &&
910 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
911 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
912 || ((em = getdefextmap()) &&
913 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
914 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
916 memcpy(finder_buf, ufinderi, 8 );
918 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
920 case FILPBIT_UNIXPR :
922 setfilunixmode(vol, path, upriv);
925 case FILPBIT_PDINFO :
926 if (afp_version < 30) { /* else it's UTF8 name */
927 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
928 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
934 goto setfilparam_done;
941 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
942 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
946 ad_setdate(adp, AD_DATE_MODIFY, newdate);
947 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
953 ad_close_metadata( adp);
957 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
958 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
959 bitmap = 1<<FILPBIT_MDATE;
960 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
964 LOG(log_debug9, logtype_afpd, "end setfilparams:");
970 * renamefile and copyfile take the old and new unix pathnames
971 * and the new mac name.
973 * src the source path
974 * dst the dest filename in current dir
975 * newname the dest mac name
976 * adp adouble struct of src file, if open, or & zeroed one
979 int renamefile(const struct vol *vol, char *src, char *dst, char *newname, struct adouble *adp)
984 LOG(log_debug9, logtype_afpd, "begin renamefile:");
987 if ( unix_rename( src, dst ) < 0 ) {
990 return( AFPERR_NOOBJ );
993 return( AFPERR_ACCESS );
996 case EXDEV : /* Cross device move -- try copy */
997 /* NOTE: with open file it's an error because after the copy we will
998 * get two files, it's fixable for our process (eg reopen the new file, get the
999 * locks, and so on. But it doesn't solve the case with a second process
1001 if (adp->ad_open_forks) {
1002 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1003 return AFPERR_OLOCK; /* little lie */
1005 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1006 /* on error copyfile delete dest */
1009 return deletefile(vol, src, 0);
1011 return( AFPERR_PARAM );
1015 if (vol->vfs->vfs_renamefile(vol, src, dst) < 0 ) {
1019 /* try to undo the data fork rename,
1020 * we know we are on the same device
1023 unix_rename( dst, src );
1024 /* return the first error */
1027 return AFPERR_NOOBJ;
1030 return AFPERR_ACCESS ;
1032 return AFPERR_VLOCK;
1034 return AFPERR_PARAM ;
1039 /* don't care if we can't open the newly renamed ressource fork
1041 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1042 ad_setname(adp, newname);
1044 ad_close( adp, ADFLAGS_HF );
1047 LOG(log_debug9, logtype_afpd, "end renamefile:");
1054 convert a Mac long name to an utf8 name,
1056 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1060 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1066 /* ---------------- */
1067 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1074 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1080 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1081 if (afp_version >= 30) {
1082 /* convert it to UTF8
1084 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1)
1088 strncpy( newname, ibuf, plen );
1089 newname[ plen ] = '\0';
1091 if (strlen(newname) != plen) {
1092 /* there's \0 in newname, e.g. it's a pathname not
1100 memcpy(&hint, ibuf, sizeof(hint));
1101 ibuf += sizeof(hint);
1103 memcpy(&len16, ibuf, sizeof(len16));
1104 ibuf += sizeof(len16);
1105 plen = ntohs(len16);
1108 if (plen > AFPOBJ_TMPSIZ) {
1111 strncpy( newname, ibuf, plen );
1112 newname[ plen ] = '\0';
1113 if (strlen(newname) != plen) {
1122 /* -----------------------------------
1124 int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1126 struct vol *s_vol, *d_vol;
1128 char *newname, *p, *upath;
1129 struct path *s_path;
1130 u_int32_t sdid, ddid;
1131 int err, retvalue = AFP_OK;
1132 u_int16_t svid, dvid;
1134 struct adouble ad, *adp;
1140 memcpy(&svid, ibuf, sizeof( svid ));
1141 ibuf += sizeof( svid );
1142 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1143 return( AFPERR_PARAM );
1146 memcpy(&sdid, ibuf, sizeof( sdid ));
1147 ibuf += sizeof( sdid );
1148 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1152 memcpy(&dvid, ibuf, sizeof( dvid ));
1153 ibuf += sizeof( dvid );
1154 memcpy(&ddid, ibuf, sizeof( ddid ));
1155 ibuf += sizeof( ddid );
1157 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1158 return get_afp_errno(AFPERR_PARAM);
1160 if ( path_isadir(s_path) ) {
1161 return( AFPERR_BADTYPE );
1164 /* don't allow copies when the file is open.
1165 * XXX: the spec only calls for read/deny write access.
1166 * however, copyfile doesn't have any of that info,
1167 * and locks need to stay coherent. as a result,
1168 * we just balk if the file is opened already. */
1170 adp = of_ad(s_vol, s_path, &ad);
1172 if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1173 return AFPERR_DENYCONF;
1175 denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
1176 getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1177 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1179 return AFPERR_DENYCONF;
1182 newname = obj->newtmp;
1183 strcpy( newname, s_path->m_name );
1185 p = ctoupath( s_vol, curdir, newname );
1187 return AFPERR_PARAM;
1191 /* FIXME svid != dvid && dvid's user can't read svid */
1193 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1194 return( AFPERR_PARAM );
1197 if (d_vol->v_flags & AFPVOL_RO)
1198 return AFPERR_VLOCK;
1200 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1204 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1205 return get_afp_errno(AFPERR_NOOBJ);
1207 if ( *s_path->m_name != '\0' ) {
1208 path_error(s_path, AFPERR_PARAM);
1211 /* one of the handful of places that knows about the path type */
1212 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1213 return( AFPERR_PARAM );
1215 /* newname is always only a filename so curdir *is* its
1218 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1219 return( AFPERR_PARAM );
1221 if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1227 if (vol->v_flags & AFPVOL_DROPBOX) {
1228 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1230 #endif /* DROPKLUDGE */
1232 setvoltime(obj, d_vol );
1237 /* ----------------------- */
1238 static int copy_all(const int dfd, const void *buf,
1244 LOG(log_debug9, logtype_afpd, "begin copy_all:");
1247 while (buflen > 0) {
1248 if ((cc = write(dfd, buf, buflen)) < 0) {
1260 LOG(log_debug9, logtype_afpd, "end copy_all:");
1266 /* --------------------------
1267 * copy only the fork data stream
1269 static int copy_fork(int eid, struct adouble *add, struct adouble *ads)
1276 if (eid == ADEID_DFORK) {
1277 sfd = ad_data_fileno(ads);
1278 dfd = ad_data_fileno(add);
1281 sfd = ad_reso_fileno(ads);
1282 dfd = ad_reso_fileno(add);
1285 if ((off_t)-1 == lseek(sfd, ad_getentryoff(ads, eid), SEEK_SET))
1288 if ((off_t)-1 == lseek(dfd, ad_getentryoff(add, eid), SEEK_SET))
1291 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1292 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1296 #define BUF 128*1024*1024
1298 if (fstat(sfd, &st) == 0) {
1301 if ( offset >= st.st_size) {
1304 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1305 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1308 case EINVAL: /* there's no guarantee that all fs support sendfile */
1317 lseek(sfd, offset, SEEK_SET);
1321 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1328 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1335 /* ----------------------------------
1336 * if newname is NULL (from directory.c) we don't want to copy the resource fork.
1337 * because we are doing it elsewhere.
1338 * currently if newname is NULL then adp is NULL.
1340 int copyfile(const struct vol *s_vol, const struct vol*d_vol,
1341 char *src, char *dst, char *newname, struct adouble *adp)
1343 struct adouble ads, add;
1351 LOG(log_debug9, logtype_afpd, "begin copyfile:");
1355 ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options);
1358 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1359 adflags = ADFLAGS_DF;
1361 adflags |= ADFLAGS_HF;
1364 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1369 if (ad_meta_fileno(adp) == -1 && ad_reso_fileno(adp) == -1) { /* META / HF */
1370 /* no resource fork, don't create one for dst file */
1371 adflags &= ~ADFLAGS_HF;
1374 stat_result = fstat(ad_data_fileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */
1376 if (stat_result < 0) {
1377 /* unlikely but if fstat fails, the default file mode will be 0666. */
1378 st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
1381 if (ad_open(dst , adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
1383 ad_close( adp, adflags );
1384 if (EEXIST != ret_err) {
1385 deletefile(d_vol, dst, 0);
1388 return AFPERR_EXIST;
1392 * XXX if the source and the dest don't use the same resource type it's broken
1394 if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){
1395 /* copy the data fork */
1396 if ((err = copy_fork(ADEID_DFORK, &add, adp)) == 0) {
1397 err = d_vol->vfs->vfs_copyfile(d_vol, src, dst);
1405 if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
1406 /* set the new name in the resource fork */
1407 ad_copy_header(&add, adp);
1408 ad_setname(&add, newname);
1411 ad_close( adp, adflags );
1413 if (ad_close( &add, adflags ) <0) {
1418 deletefile(d_vol, dst, 0);
1420 else if (stat_result == 0) {
1421 /* set dest modification date to src date */
1424 ut.actime = ut.modtime = st.st_mtime;
1426 /* FIXME netatalk doesn't use resource fork file date
1427 * but maybe we should set its modtime too.
1432 LOG(log_debug9, logtype_afpd, "end copyfile:");
1436 switch ( ret_err ) {
1442 return AFPERR_DFULL;
1444 return AFPERR_NOOBJ;
1446 return AFPERR_ACCESS;
1448 return AFPERR_VLOCK;
1450 return AFPERR_PARAM;
1454 /* -----------------------------------
1455 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1456 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1458 when deletefile is called we don't have lock on it, file is closed (for us)
1459 untrue if called by renamefile
1461 ad_open always try to open file RDWR first and ad_lock takes care of
1462 WRITE lock on read only file.
1465 static int check_attrib(struct adouble *adp)
1467 u_int16_t bshort = 0;
1469 ad_getattr(adp, &bshort);
1471 * Does kFPDeleteInhibitBit (bit 8) set?
1473 if ((bshort & htons(ATTRBIT_NODELETE))) {
1474 return AFPERR_OLOCK;
1476 if ((bshort & htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN))) {
1482 int deletefile(const struct vol *vol, char *file, int checkAttrib)
1485 struct adouble *adp = &ad;
1486 int adflags, err = AFP_OK;
1489 LOG(log_debug9, logtype_afpd, "begin deletefile:");
1492 /* try to open both forks at once */
1493 adflags = ADFLAGS_DF|ADFLAGS_HF;
1495 /* was EACCESS error try to get only metadata */
1496 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1497 /* we never want to create a resource fork here, we are going to delete it
1498 * moreover sometimes deletefile is called with a no existent file and
1499 * ad_open would create a 0 byte resource fork
1501 if ( ad_metadata( file, ADFLAGS_OPENFORKS, &ad) == 0 ) {
1502 ad_close( &ad, adflags );
1503 if ((err = check_attrib(&ad))) {
1510 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1511 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1514 if (adflags == ADFLAGS_DF)
1515 return AFPERR_NOOBJ;
1517 /* that failed. now try to open just the data fork */
1518 adflags = ADFLAGS_DF;
1522 adp = NULL; /* maybe it's a file with no write mode for us */
1523 break; /* was return AFPERR_ACCESS;*/
1525 return AFPERR_VLOCK;
1527 return( AFPERR_PARAM );
1530 break; /* from the while */
1533 if (adp && (adflags & ADFLAGS_HF) ) {
1534 /* FIXME we have a pb here because we want to know if a file is open
1535 * there's a 'priority inversion' if you can't open the ressource fork RW
1536 * you can delete it if it's open because you can't get a write lock.
1538 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1541 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1543 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1544 ad_close( &ad, adflags );
1545 return( AFPERR_BUSY );
1549 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1552 else if (!(err = vol->vfs->vfs_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
1554 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1556 cnid_delete(vol->v_cdb, id);
1560 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1563 LOG(log_debug9, logtype_afpd, "end deletefile:");
1569 /* ------------------------------------ */
1570 /* return a file id */
1571 int afp_createid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1580 struct path *s_path;
1586 memcpy(&vid, ibuf, sizeof(vid));
1587 ibuf += sizeof(vid);
1589 if (NULL == ( vol = getvolbyvid( vid )) ) {
1590 return( AFPERR_PARAM);
1593 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1597 if (vol->v_flags & AFPVOL_RO)
1598 return AFPERR_VLOCK;
1600 memcpy(&did, ibuf, sizeof( did ));
1601 ibuf += sizeof(did);
1603 if (NULL == ( dir = dirlookup( vol, did )) ) {
1604 return afp_errno; /* was AFPERR_PARAM */
1607 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1608 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1611 if ( path_isadir(s_path) ) {
1612 return( AFPERR_BADTYPE );
1615 upath = s_path->u_name;
1616 switch (s_path->st_errno) {
1618 break; /* success */
1621 return AFPERR_ACCESS;
1623 return AFPERR_NOOBJ;
1625 return AFPERR_PARAM;
1628 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1629 memcpy(rbuf, &id, sizeof(id));
1630 *rbuflen = sizeof(id);
1631 return AFPERR_EXISTID;
1634 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1635 memcpy(rbuf, &id, sizeof(id));
1636 *rbuflen = sizeof(id);
1643 /* ------------------------------- */
1649 static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
1652 struct reenum *param = data;
1653 struct vol *vol = param->vol;
1654 cnid_t did = param->did;
1657 if ( stat(de->d_name, &path.st)<0 )
1660 /* update or add to cnid */
1661 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1663 #if AD_VERSION > AD_VERSION1
1664 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1665 struct adouble ad, *adp;
1669 path.u_name = de->d_name;
1671 adp = of_ad(vol, &path, &ad);
1673 if ( ad_open_metadata( de->d_name, 0, 0, adp ) < 0 ) {
1676 if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1679 ad_close_metadata(adp);
1681 #endif /* AD_VERSION > AD_VERSION1 */
1686 /* --------------------
1687 * Ok the db is out of synch with the dir.
1688 * but if it's a deleted file we don't want to do it again and again.
1691 reenumerate_id(struct vol *vol, char *name, struct dir *dir)
1697 if (vol->v_cdb == NULL) {
1701 /* FIXME use of_statdir ? */
1702 if (stat(name, &st)) {
1706 if (dirreenumerate(dir, &st)) {
1707 /* we already did it once and the dir haven't been modified */
1712 data.did = dir->d_did;
1713 if ((ret = for_each_dirent(vol, name, reenumerate_loop, (void *)&data)) >= 0) {
1714 setdiroffcnt(curdir, &st, ret);
1715 dir->d_flags |= DIRF_CNID;
1721 /* ------------------------------
1722 resolve a file id */
1723 int afp_resolveid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1732 u_int16_t vid, bitmap;
1734 static char buffer[12 + MAXPATHLEN + 1];
1735 int len = 12 + MAXPATHLEN + 1;
1740 memcpy(&vid, ibuf, sizeof(vid));
1741 ibuf += sizeof(vid);
1743 if (NULL == ( vol = getvolbyvid( vid )) ) {
1744 return( AFPERR_PARAM);
1747 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1751 memcpy(&id, ibuf, sizeof( id ));
1756 /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
1760 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1761 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1764 if (NULL == ( dir = dirlookup( vol, id )) ) {
1765 return AFPERR_NOID; /* idem AFPERR_PARAM */
1767 if (movecwd(vol, dir) < 0) {
1771 return AFPERR_ACCESS;
1775 return AFPERR_PARAM;
1779 memset(&path, 0, sizeof(path));
1780 path.u_name = upath;
1781 if ( of_stat(&path) < 0 ) {
1783 /* with nfs and our working directory is deleted */
1784 if (errno == ESTALE) {
1788 if ( errno == ENOENT && !retry) {
1789 /* cnid db is out of sync, reenumerate the directory and update ids */
1790 reenumerate_id(vol, ".", dir);
1798 return AFPERR_ACCESS;
1802 return AFPERR_PARAM;
1806 /* directories are bad */
1807 if (S_ISDIR(path.st.st_mode)) {
1808 /* OS9 and OSX don't return the same error code */
1809 return (afp_version >=30)?AFPERR_NOID:AFPERR_BADTYPE;
1812 memcpy(&bitmap, ibuf, sizeof(bitmap));
1813 bitmap = ntohs( bitmap );
1814 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1818 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1819 rbuf + sizeof(bitmap), &buflen))) {
1822 *rbuflen = buflen + sizeof(bitmap);
1823 memcpy(rbuf, ibuf, sizeof(bitmap));
1828 /* ------------------------------ */
1829 int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1839 static char buffer[12 + MAXPATHLEN + 1];
1840 int len = 12 + MAXPATHLEN + 1;
1845 memcpy(&vid, ibuf, sizeof(vid));
1846 ibuf += sizeof(vid);
1848 if (NULL == ( vol = getvolbyvid( vid )) ) {
1849 return( AFPERR_PARAM);
1852 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1856 if (vol->v_flags & AFPVOL_RO)
1857 return AFPERR_VLOCK;
1859 memcpy(&id, ibuf, sizeof( id ));
1863 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1867 if (NULL == ( dir = dirlookup( vol, id )) ) {
1868 return( AFPERR_PARAM );
1872 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1876 return AFPERR_ACCESS;
1881 /* still try to delete the id */
1885 return AFPERR_PARAM;
1888 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1889 return AFPERR_BADTYPE;
1891 if (cnid_delete(vol->v_cdb, fileid)) {
1894 return AFPERR_VLOCK;
1897 return AFPERR_ACCESS;
1899 return AFPERR_PARAM;
1906 /* ------------------------------ */
1907 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1911 if (path->st_errno) {
1912 switch (path->st_errno) {
1914 afp_errno = AFPERR_NOID;
1918 afp_errno = AFPERR_ACCESS;
1921 afp_errno = AFPERR_PARAM;
1926 /* we use file_access both for legacy Mac perm and
1927 * for unix privilege, rename will take care of folder perms
1929 if (file_access(path, OPENACC_WR ) < 0) {
1930 afp_errno = AFPERR_ACCESS;
1934 if ((*of = of_findname(path))) {
1935 /* reuse struct adouble so it won't break locks */
1939 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
1941 if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
1943 * The user must have the Read & Write privilege for both files in order to use this command.
1945 ad_close(adp, ADFLAGS_HF);
1946 afp_errno = AFPERR_ACCESS;
1953 #define APPLETEMP ".AppleTempXXXXXX"
1955 int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1957 struct stat srcst, destst;
1959 struct dir *dir, *sdir;
1960 char *spath, temp[17], *p;
1961 char *supath, *upath;
1966 struct adouble *adsp = NULL;
1967 struct adouble *addp = NULL;
1968 struct ofork *s_of = NULL;
1969 struct ofork *d_of = NULL;
1982 memcpy(&vid, ibuf, sizeof(vid));
1983 ibuf += sizeof(vid);
1985 if (NULL == ( vol = getvolbyvid( vid )) ) {
1986 return( AFPERR_PARAM);
1989 if ((vol->v_flags & AFPVOL_RO))
1990 return AFPERR_VLOCK;
1992 /* source and destination dids */
1993 memcpy(&sid, ibuf, sizeof(sid));
1994 ibuf += sizeof(sid);
1995 memcpy(&did, ibuf, sizeof(did));
1996 ibuf += sizeof(did);
1999 if (NULL == (dir = dirlookup( vol, sid )) ) {
2000 return afp_errno; /* was AFPERR_PARAM */
2003 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2004 return get_afp_errno(AFPERR_NOOBJ);
2007 if ( path_isadir(path) ) {
2008 return AFPERR_BADTYPE; /* it's a dir */
2011 /* save some stuff */
2014 spath = obj->oldtmp;
2015 supath = obj->newtmp;
2016 strcpy(spath, path->m_name);
2017 strcpy(supath, path->u_name); /* this is for the cnid changing */
2018 p = absupath( vol, sdir, supath);
2020 /* pathname too long */
2021 return AFPERR_PARAM ;
2024 ad_init(&ads, vol->v_adouble, vol->v_ad_options);
2025 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2029 /* ***** from here we may have resource fork open **** */
2031 /* look for the source cnid. if it doesn't exist, don't worry about
2033 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2035 if (NULL == ( dir = dirlookup( vol, did )) ) {
2036 err = afp_errno; /* was AFPERR_PARAM */
2037 goto err_exchangefile;
2040 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2041 err = get_afp_errno(AFPERR_NOOBJ);
2042 goto err_exchangefile;
2045 if ( path_isadir(path) ) {
2046 err = AFPERR_BADTYPE;
2047 goto err_exchangefile;
2050 /* FPExchangeFiles is the only call that can return the SameObj
2052 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2053 err = AFPERR_SAMEOBJ;
2054 goto err_exchangefile;
2057 ad_init(&add, vol->v_adouble, vol->v_ad_options);
2058 if (!(addp = find_adouble( path, &d_of, &add))) {
2060 goto err_exchangefile;
2064 /* they are not on the same device and at least one is open
2065 * FIXME broken for for crossdev and adouble v2
2068 crossdev = (srcst.st_dev != destst.st_dev);
2069 if (/* (d_of || s_of) && */ crossdev) {
2071 goto err_exchangefile;
2074 /* look for destination id. */
2075 upath = path->u_name;
2076 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2078 /* construct a temp name.
2079 * NOTE: the temp file will be in the dest file's directory. it
2080 * will also be inaccessible from AFP. */
2081 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2082 if (!mktemp(temp)) {
2084 goto err_exchangefile;
2088 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2089 ad_close(adsp, ADFLAGS_HF);
2090 ad_close(addp, ADFLAGS_HF);
2093 /* now, quickly rename the file. we error if we can't. */
2094 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2095 goto err_exchangefile;
2096 of_rename(vol, s_of, sdir, spath, curdir, temp);
2098 /* rename destination to source */
2099 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2100 goto err_src_to_tmp;
2101 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2103 /* rename temp to destination */
2104 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2105 goto err_dest_to_src;
2106 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2108 /* id's need switching. src -> dest and dest -> src.
2109 * we need to re-stat() if it was a cross device copy.
2112 cnid_delete(vol->v_cdb, sid);
2115 cnid_delete(vol->v_cdb, did);
2117 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2118 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2120 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2121 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2126 err = AFPERR_ACCESS;
2131 goto err_temp_to_dest;
2134 /* here we need to reopen if crossdev */
2135 if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2140 if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2145 /* change perms, src gets dest perm and vice versa */
2150 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2151 err = AFP_OK; /* ignore error */
2152 goto err_temp_to_dest;
2156 * we need to exchange ACL entries as well
2158 /* exchange_acls(vol, p, upath); */
2163 path->m_name = NULL;
2164 path->u_name = upath;
2166 setfilunixmode(vol, path, destst.st_mode);
2167 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2174 setfilunixmode(vol, path, srcst.st_mode);
2175 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2177 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2178 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2183 goto err_exchangefile;
2185 /* all this stuff is so that we can unwind a failed operation
2188 /* rename dest to temp */
2189 renamefile(vol, upath, temp, temp, adsp);
2190 of_rename(vol, s_of, curdir, upath, curdir, temp);
2193 /* rename source back to dest */
2194 renamefile(vol, p, upath, path->m_name, addp);
2195 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2198 /* rename temp back to source */
2199 renamefile(vol, temp, p, spath, adsp);
2200 of_rename(vol, s_of, curdir, temp, sdir, spath);
2203 if ( !s_of && adsp && ad_meta_fileno(adsp) != -1 ) { /* META */
2204 ad_close(adsp, ADFLAGS_HF);
2206 if ( !d_of && addp && ad_meta_fileno(addp) != -1 ) {/* META */
2207 ad_close(addp, ADFLAGS_HF);