2 * $Id: file.c,v 1.115 2009-10-15 12:06:07 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 */
34 #include <sys/param.h>
36 #include <atalk/adouble.h>
37 #include <atalk/vfs.h>
38 #include <atalk/logger.h>
39 #include <atalk/afp.h>
40 #include <atalk/util.h>
41 #include <atalk/cnid.h>
42 #include <atalk/unix.h>
44 #include "directory.h"
53 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
54 * field bytes subfield bytes
57 * ioFlFndrInfo 16 -> type 4 type field
58 * creator 4 creator field
59 * flags 2 finder flags:
61 * location 4 location in window
62 * folder 2 window that contains file
64 * ioFlXFndrInfo 16 -> iconID 2 icon id
66 * script 1 script system
68 * commentID 2 comment id
69 * putawayID 4 home directory id
72 const u_char ufinderi[ADEDLEN_FINDERI] = {
73 0, 0, 0, 0, 0, 0, 0, 0,
74 1, 0, 0, 0, 0, 0, 0, 0,
75 0, 0, 0, 0, 0, 0, 0, 0,
76 0, 0, 0, 0, 0, 0, 0, 0
79 static const u_char old_ufinderi[] = {
80 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X'
83 /* ----------------------
85 static int default_type(void *finder)
87 if (!memcmp(finder, ufinderi, 8) || !memcmp(finder, old_ufinderi, 8))
92 /* FIXME path : unix or mac name ? (for now it's unix name ) */
93 void *get_finderinfo(const struct vol *vol, const char *upath, struct adouble *adp, void *data)
96 void *ad_finder = NULL;
100 ad_finder = ad_entry(adp, ADEID_FINDERI);
103 memcpy(data, ad_finder, ADEDLEN_FINDERI);
105 if (default_type(ad_finder))
109 memcpy(data, ufinderi, ADEDLEN_FINDERI);
111 if (vol_inv_dots(vol) && *upath == '.') { /* make it invisible */
114 ashort = htons(FINDERINFO_INVISIBLE);
115 memcpy((char *)data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
118 /** Only enter if no appledouble information and no finder information found. */
119 if (chk_ext && (em = getextmap( upath ))) {
120 memcpy(data, em->em_type, sizeof( em->em_type ));
121 memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator));
126 /* ---------------------
128 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8)
133 aint = strlen( name );
137 if (utf8_encoding()) {
138 /* but name is an utf8 mac name */
141 /* global static variable... */
143 if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
152 if (aint > MACFILELEN)
159 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
162 utf8 = vol->v_mac?htonl(vol->v_mac->kTextEncoding):0; /* htonl(utf8) */
163 memcpy(data, &utf8, sizeof(utf8));
164 data += sizeof(utf8);
167 memcpy(data, &temp, sizeof(temp));
168 data += sizeof(temp);
171 memcpy( data, src, aint );
181 * FIXME: PDINFO is UTF8 and doesn't need adp
183 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
184 (1 << FILPBIT_CDATE) |\
185 (1 << FILPBIT_MDATE) |\
186 (1 << FILPBIT_BDATE) |\
187 (1 << FILPBIT_FINFO) |\
188 (1 << FILPBIT_RFLEN) |\
189 (1 << FILPBIT_EXTRFLEN) |\
190 (1 << FILPBIT_PDINFO) |\
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 AD_VERSION > AD_VERSION1
201 if ((aint = ad_getid(adp, st->st_dev, st->st_ino, did, vol->v_stamp))) {
206 if (vol->v_cdb != NULL) {
207 aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
208 /* Throw errors if cnid_add fails. */
209 if (aint == CNID_INVALID) {
211 case CNID_ERR_CLOSE: /* the db is closed */
214 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
215 afp_errno = AFPERR_PARAM;
218 afp_errno = AFPERR_PARAM;
221 afp_errno = AFPERR_MISC;
225 #if AD_VERSION > AD_VERSION1
227 /* update the ressource fork
228 * for a folder adp is always null
230 if (ad_setid(adp, st->st_dev, st->st_ino, aint, did, vol->v_stamp)) {
239 /* -------------------------- */
240 int getmetadata(struct vol *vol,
242 struct path *path, struct dir *dir,
243 char *buf, size_t *buflen, struct adouble *adp)
245 char *data, *l_nameoff = NULL, *upath;
246 char *utf_nameoff = NULL;
251 u_char achar, fdType[4];
257 LOG(log_info, logtype_afpd, "begin getmetadata:");
260 upath = path->u_name;
265 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
266 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
267 || (bitmap & (1 << FILPBIT_FNUM))) {
269 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
275 path->m_name = utompath(vol, upath, id, utf8_encoding());
278 while ( bitmap != 0 ) {
279 while (( bitmap & 1 ) == 0 ) {
287 ad_getattr(adp, &ashort);
288 } else if (vol_inv_dots(vol) && *upath == '.') {
289 ashort = htons(ATTRBIT_INVISIBLE);
293 /* FIXME do we want a visual clue if the file is read only
296 accessmode( ".", &ma, dir , NULL);
297 if ((ma.ma_user & AR_UWRITE)) {
298 accessmode( upath, &ma, dir , st);
299 if (!(ma.ma_user & AR_UWRITE)) {
300 ashort |= htons(ATTRBIT_NOWRITE);
304 memcpy(data, &ashort, sizeof( ashort ));
305 data += sizeof( ashort );
309 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
310 data += sizeof( u_int32_t );
314 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
315 aint = AD_DATE_FROM_UNIX(st->st_mtime);
316 memcpy(data, &aint, sizeof( aint ));
317 data += sizeof( aint );
321 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
322 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
323 aint = AD_DATE_FROM_UNIX(st->st_mtime);
326 aint = AD_DATE_FROM_UNIX(st->st_mtime);
328 memcpy(data, &aint, sizeof( int ));
329 data += sizeof( int );
333 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
334 aint = AD_DATE_START;
335 memcpy(data, &aint, sizeof( int ));
336 data += sizeof( int );
340 get_finderinfo(vol, upath, adp, (char *)data);
341 data += ADEDLEN_FINDERI;
346 data += sizeof( u_int16_t );
350 memset(data, 0, sizeof(u_int16_t));
351 data += sizeof( u_int16_t );
355 memcpy(data, &id, sizeof( id ));
356 data += sizeof( id );
360 if (st->st_size > 0xffffffff)
363 aint = htonl( st->st_size );
364 memcpy(data, &aint, sizeof( aint ));
365 data += sizeof( aint );
370 if (adp->ad_rlen > 0xffffffff)
373 aint = htonl( adp->ad_rlen);
377 memcpy(data, &aint, sizeof( aint ));
378 data += sizeof( aint );
381 /* Current client needs ProDOS info block for this file.
382 Use simple heuristic and let the Mac "type" string tell
383 us what the PD file code should be. Everything gets a
384 subtype of 0x0000 unless the original value was hashed
385 to "pXYZ" when we created it. See IA, Ver 2.
386 <shirsch@adelphia.net> */
387 case FILPBIT_PDINFO :
388 if (afp_version >= 30) { /* UTF8 name */
389 utf8 = kTextEncodingUTF8;
391 data += sizeof( u_int16_t );
393 memcpy(data, &aint, sizeof( aint ));
394 data += sizeof( aint );
398 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
400 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
404 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
408 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
412 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
416 else if ( fdType[0] == 'p' ) {
418 ashort = (fdType[2] * 256) + fdType[3];
432 memcpy(data, &ashort, sizeof( ashort ));
433 data += sizeof( ashort );
434 memset(data, 0, sizeof( ashort ));
435 data += sizeof( ashort );
438 case FILPBIT_EXTDFLEN:
439 aint = htonl(st->st_size >> 32);
440 memcpy(data, &aint, sizeof( aint ));
441 data += sizeof( aint );
442 aint = htonl(st->st_size);
443 memcpy(data, &aint, sizeof( aint ));
444 data += sizeof( aint );
446 case FILPBIT_EXTRFLEN:
449 aint = htonl(adp->ad_rlen >> 32);
450 memcpy(data, &aint, sizeof( aint ));
451 data += sizeof( aint );
453 aint = htonl(adp->ad_rlen);
454 memcpy(data, &aint, sizeof( aint ));
455 data += sizeof( aint );
457 case FILPBIT_UNIXPR :
458 /* accessmode may change st_mode with ACLs */
459 accessmode( upath, &ma, dir , st);
461 aint = htonl(st->st_uid);
462 memcpy( data, &aint, sizeof( aint ));
463 data += sizeof( aint );
464 aint = htonl(st->st_gid);
465 memcpy( data, &aint, sizeof( aint ));
466 data += sizeof( aint );
469 type == slnk indicates an OSX style symlink,
470 we have to add S_IFLNK to the mode, otherwise
471 10.3 clients freak out. */
475 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
476 if ( memcmp( fdType, "slnk", 4 ) == 0 ) {
482 memcpy( data, &aint, sizeof( aint ));
483 data += sizeof( aint );
485 *data++ = ma.ma_user;
486 *data++ = ma.ma_world;
487 *data++ = ma.ma_group;
488 *data++ = ma.ma_owner;
492 return( AFPERR_BITMAP );
498 ashort = htons( data - buf );
499 memcpy(l_nameoff, &ashort, sizeof( ashort ));
500 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
503 ashort = htons( data - buf );
504 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
505 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
507 *buflen = data - buf;
511 /* ----------------------- */
512 int getfilparams(struct vol *vol,
514 struct path *path, struct dir *dir,
515 char *buf, size_t *buflen )
517 struct adouble ad, *adp;
524 LOG(log_info, logtype_default, "begin getfilparams:");
527 opened = PARAM_NEED_ADP(bitmap);
531 int flags = (bitmap & (1 << FILPBIT_ATTR))?ADFLAGS_OPENFORKS:0;
532 upath = path->u_name;
533 if ((of = of_findname(path))) {
536 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
540 if ( ad_metadata( upath, flags, adp) < 0 ) {
543 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
544 upath, strerror(errno));
545 return AFPERR_ACCESS;
547 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
556 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp);
558 ad_close_metadata( adp);
561 LOG(log_info, logtype_afpd, "end getfilparams:");
567 /* ----------------------------- */
568 int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
570 struct adouble ad, *adp;
573 struct ofork *of = NULL;
575 int creatf, did, openf, retvalue = AFP_OK;
580 LOG(log_info, logtype_afpd, "begin afp_createfile:");
585 creatf = (unsigned char) *ibuf++;
587 memcpy(&vid, ibuf, sizeof( vid ));
588 ibuf += sizeof( vid );
590 if (NULL == ( vol = getvolbyvid( vid )) ) {
591 return( AFPERR_PARAM );
594 if (vol->v_flags & AFPVOL_RO)
597 memcpy(&did, ibuf, sizeof( did));
598 ibuf += sizeof( did );
600 if (NULL == ( dir = dirlookup( vol, did )) ) {
604 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
605 return get_afp_errno(AFPERR_PARAM);
608 if ( *s_path->m_name == '\0' ) {
609 return( AFPERR_BADTYPE );
612 upath = s_path->u_name;
614 /* if upath is deleted we already in trouble anyway */
615 if ((of = of_findname(s_path))) {
618 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
622 /* on a hard create, fail if file exists and is open */
625 openf = O_RDWR|O_CREAT|O_TRUNC;
627 /* on a soft create, if the file is open then ad_open won't fail
628 because open syscall is not called
633 openf = O_RDWR|O_CREAT|O_EXCL;
636 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF|ADFLAGS_CREATE,
637 openf, 0666, adp) < 0 ) {
641 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
642 return ( AFPERR_NOOBJ );
644 return( AFPERR_EXIST );
646 return( AFPERR_ACCESS );
649 return( AFPERR_DFULL );
651 return( AFPERR_PARAM );
654 if ( ad_reso_fileno( adp ) == -1 ) { /* Hard META / HF */
655 /* on noadouble volumes, just creating the data fork is ok */
656 if (vol_noadouble(vol)) {
657 ad_close( adp, ADFLAGS_DF );
658 goto createfile_done;
660 /* FIXME with hard create on an existing file, we already
661 * corrupted the data file.
663 netatalk_unlink( upath );
664 ad_close( adp, ADFLAGS_DF );
665 return AFPERR_ACCESS;
668 path = s_path->m_name;
669 ad_setname(adp, path);
671 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
677 if (vol->v_flags & AFPVOL_DROPBOX) {
678 retvalue = matchfile2dirperms(upath, vol, did);
680 #endif /* DROPKLUDGE */
682 setvoltime(obj, vol );
685 LOG(log_info, logtype_afpd, "end afp_createfile");
691 int afp_setfilparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
697 u_int16_t vid, bitmap;
700 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
706 memcpy(&vid, ibuf, sizeof( vid ));
707 ibuf += sizeof( vid );
708 if (NULL == ( vol = getvolbyvid( vid )) ) {
709 return( AFPERR_PARAM );
712 if (vol->v_flags & AFPVOL_RO)
715 memcpy(&did, ibuf, sizeof( did ));
716 ibuf += sizeof( did );
717 if (NULL == ( dir = dirlookup( vol, did )) ) {
718 return afp_errno; /* was AFPERR_NOOBJ */
721 memcpy(&bitmap, ibuf, sizeof( bitmap ));
722 bitmap = ntohs( bitmap );
723 ibuf += sizeof( bitmap );
725 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
726 return get_afp_errno(AFPERR_PARAM);
729 if (path_isadir(s_path)) {
730 return( AFPERR_BADTYPE ); /* it's a directory */
733 if ( s_path->st_errno != 0 ) {
734 return( AFPERR_NOOBJ );
737 if ((u_long)ibuf & 1 ) {
741 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
742 setvoltime(obj, vol );
746 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
753 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
756 extern struct path Cur_Path;
758 int setfilparams(struct vol *vol,
759 struct path *path, u_int16_t f_bitmap, char *buf )
761 struct adouble ad, *adp;
763 int bit, isad = 1, err = AFP_OK;
765 u_char achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
766 u_int16_t ashort, bshort;
769 u_int16_t upriv_bit = 0;
773 int change_mdate = 0;
774 int change_parent_mdate = 0;
779 u_int16_t bitmap = f_bitmap;
780 u_int32_t cdate,bdate;
781 u_char finder_buf[32];
784 LOG(log_info, logtype_afpd, "begin setfilparams:");
787 upath = path->u_name;
788 adp = of_ad(vol, path, &ad);
791 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
792 return AFPERR_ACCESS;
795 /* with unix priv maybe we have to change adouble file priv first */
797 while ( bitmap != 0 ) {
798 while (( bitmap & 1 ) == 0 ) {
805 memcpy(&ashort, buf, sizeof( ashort ));
806 buf += sizeof( ashort );
810 memcpy(&cdate, buf, sizeof(cdate));
811 buf += sizeof( cdate );
814 memcpy(&newdate, buf, sizeof( newdate ));
815 buf += sizeof( newdate );
819 memcpy(&bdate, buf, sizeof( bdate));
820 buf += sizeof( bdate );
824 memcpy(finder_buf, buf, 32 );
827 case FILPBIT_UNIXPR :
828 if (!vol_unix_priv(vol)) {
829 /* this volume doesn't use unix priv */
835 change_parent_mdate = 1;
837 memcpy( &aint, buf, sizeof( aint ));
838 f_uid = ntohl (aint);
839 buf += sizeof( aint );
840 memcpy( &aint, buf, sizeof( aint ));
841 f_gid = ntohl (aint);
842 buf += sizeof( aint );
843 setfilowner(vol, f_uid, f_gid, path);
845 memcpy( &upriv, buf, sizeof( upriv ));
846 buf += sizeof( upriv );
847 upriv = ntohl (upriv);
848 if ((upriv & S_IWUSR)) {
849 setfilunixmode(vol, path, upriv);
856 case FILPBIT_PDINFO :
857 if (afp_version < 30) { /* else it's UTF8 name */
860 /* Keep special case to support crlf translations */
861 if ((unsigned int) achar == 0x04) {
862 fdType = (u_char *)"TEXT";
865 xyy[0] = ( u_char ) 'p';
876 /* break while loop */
885 /* second try with adouble open
887 if ( ad_open_metadata( upath, vol_noadouble(vol), O_CREAT, adp) < 0) {
888 LOG(log_debug, logtype_afpd, "setfilparams: ad_open_metadata error");
890 * For some things, we don't need an adouble header:
891 * - change of modification date
892 * - UNIX privs (Bug-ID #2863424)
894 if ( (f_bitmap & ~(1<<FILPBIT_MDATE | 1<<FILPBIT_UNIXPR))) {
895 LOG(log_debug, logtype_afpd, "setfilparams: need adouble access");
896 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
898 LOG(log_debug, logtype_afpd, "setfilparams: no adouble perms, but only FILPBIT_MDATE and/or FILPBIT_UNIXPR");
900 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
901 ad_setname(adp, path->m_name);
906 while ( bitmap != 0 ) {
907 while (( bitmap & 1 ) == 0 ) {
914 ad_getattr(adp, &bshort);
915 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
916 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
917 change_parent_mdate = 1;
918 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
919 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
923 ad_setattr(adp, bshort);
926 ad_setdate(adp, AD_DATE_CREATE, cdate);
931 ad_setdate(adp, AD_DATE_BACKUP, bdate);
934 if (default_type( ad_entry( adp, ADEID_FINDERI ))
936 ((em = getextmap( path->m_name )) &&
937 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
938 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
939 || ((em = getdefextmap()) &&
940 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
941 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
943 memcpy(finder_buf, ufinderi, 8 );
945 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
947 case FILPBIT_UNIXPR :
949 setfilunixmode(vol, path, upriv);
952 case FILPBIT_PDINFO :
953 if (afp_version < 30) { /* else it's UTF8 name */
954 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
955 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
961 goto setfilparam_done;
968 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
969 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
973 ad_setdate(adp, AD_DATE_MODIFY, newdate);
974 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
980 ad_close_metadata( adp);
984 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
985 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
986 bitmap = 1<<FILPBIT_MDATE;
987 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
991 LOG(log_info, logtype_afpd, "end setfilparams:");
997 * renamefile and copyfile take the old and new unix pathnames
998 * and the new mac name.
1000 * src the source path
1001 * dst the dest filename in current dir
1002 * newname the dest mac name
1003 * adp adouble struct of src file, if open, or & zeroed one
1006 int renamefile(const struct vol *vol, char *src, char *dst, char *newname, struct adouble *adp)
1011 LOG(log_info, logtype_afpd, "begin renamefile:");
1014 if ( unix_rename( src, dst ) < 0 ) {
1017 return( AFPERR_NOOBJ );
1020 return( AFPERR_ACCESS );
1022 return AFPERR_VLOCK;
1023 case EXDEV : /* Cross device move -- try copy */
1024 /* NOTE: with open file it's an error because after the copy we will
1025 * get two files, it's fixable for our process (eg reopen the new file, get the
1026 * locks, and so on. But it doesn't solve the case with a second process
1028 if (adp->ad_open_forks) {
1029 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1030 return AFPERR_OLOCK; /* little lie */
1032 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1033 /* on error copyfile delete dest */
1036 return deletefile(vol, src, 0);
1038 return( AFPERR_PARAM );
1042 if (vol->vfs->vfs_renamefile(vol, src, dst) < 0 ) {
1046 /* try to undo the data fork rename,
1047 * we know we are on the same device
1050 unix_rename( dst, src );
1051 /* return the first error */
1054 return AFPERR_NOOBJ;
1057 return AFPERR_ACCESS ;
1059 return AFPERR_VLOCK;
1061 return AFPERR_PARAM ;
1066 /* don't care if we can't open the newly renamed ressource fork
1068 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1069 ad_setname(adp, newname);
1071 ad_close( adp, ADFLAGS_HF );
1074 LOG(log_info, logtype_afpd, "end renamefile:");
1081 convert a Mac long name to an utf8 name,
1083 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1087 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1093 /* ---------------- */
1094 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1101 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1107 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1108 if (afp_version >= 30) {
1109 /* convert it to UTF8
1111 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1)
1115 strncpy( newname, ibuf, plen );
1116 newname[ plen ] = '\0';
1118 if (strlen(newname) != plen) {
1119 /* there's \0 in newname, e.g. it's a pathname not
1127 memcpy(&hint, ibuf, sizeof(hint));
1128 ibuf += sizeof(hint);
1130 memcpy(&len16, ibuf, sizeof(len16));
1131 ibuf += sizeof(len16);
1132 plen = ntohs(len16);
1135 if (plen > AFPOBJ_TMPSIZ) {
1138 strncpy( newname, ibuf, plen );
1139 newname[ plen ] = '\0';
1140 if (strlen(newname) != plen) {
1149 /* -----------------------------------
1151 int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1153 struct vol *s_vol, *d_vol;
1155 char *newname, *p, *upath;
1156 struct path *s_path;
1157 u_int32_t sdid, ddid;
1158 int err, retvalue = AFP_OK;
1159 u_int16_t svid, dvid;
1161 struct adouble ad, *adp;
1165 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1171 memcpy(&svid, ibuf, sizeof( svid ));
1172 ibuf += sizeof( svid );
1173 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1174 return( AFPERR_PARAM );
1177 memcpy(&sdid, ibuf, sizeof( sdid ));
1178 ibuf += sizeof( sdid );
1179 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1183 memcpy(&dvid, ibuf, sizeof( dvid ));
1184 ibuf += sizeof( dvid );
1185 memcpy(&ddid, ibuf, sizeof( ddid ));
1186 ibuf += sizeof( ddid );
1188 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1189 return get_afp_errno(AFPERR_PARAM);
1191 if ( path_isadir(s_path) ) {
1192 return( AFPERR_BADTYPE );
1195 /* don't allow copies when the file is open.
1196 * XXX: the spec only calls for read/deny write access.
1197 * however, copyfile doesn't have any of that info,
1198 * and locks need to stay coherent. as a result,
1199 * we just balk if the file is opened already. */
1201 adp = of_ad(s_vol, s_path, &ad);
1203 if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1204 return AFPERR_DENYCONF;
1206 denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
1207 getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1208 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1210 return AFPERR_DENYCONF;
1213 newname = obj->newtmp;
1214 strcpy( newname, s_path->m_name );
1216 p = ctoupath( s_vol, curdir, newname );
1218 return AFPERR_PARAM;
1222 /* FIXME svid != dvid && dvid's user can't read svid */
1224 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1225 return( AFPERR_PARAM );
1228 if (d_vol->v_flags & AFPVOL_RO)
1229 return AFPERR_VLOCK;
1231 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1235 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1236 return get_afp_errno(AFPERR_NOOBJ);
1238 if ( *s_path->m_name != '\0' ) {
1239 path_error(s_path, AFPERR_PARAM);
1242 /* one of the handful of places that knows about the path type */
1243 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1244 return( AFPERR_PARAM );
1246 /* newname is always only a filename so curdir *is* its
1249 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1250 return( AFPERR_PARAM );
1252 if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1258 if (vol->v_flags & AFPVOL_DROPBOX) {
1259 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1261 #endif /* DROPKLUDGE */
1263 setvoltime(obj, d_vol );
1266 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1272 /* ----------------------- */
1273 static int copy_all(const int dfd, const void *buf,
1279 LOG(log_info, logtype_afpd, "begin copy_all:");
1282 while (buflen > 0) {
1283 if ((cc = write(dfd, buf, buflen)) < 0) {
1295 LOG(log_info, logtype_afpd, "end copy_all:");
1301 /* --------------------------
1302 * copy only the fork data stream
1304 static int copy_fork(int eid, struct adouble *add, struct adouble *ads)
1311 if (eid == ADEID_DFORK) {
1312 sfd = ad_data_fileno(ads);
1313 dfd = ad_data_fileno(add);
1316 sfd = ad_reso_fileno(ads);
1317 dfd = ad_reso_fileno(add);
1320 if ((off_t)-1 == lseek(sfd, ad_getentryoff(ads, eid), SEEK_SET))
1323 if ((off_t)-1 == lseek(dfd, ad_getentryoff(add, eid), SEEK_SET))
1326 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1327 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1331 #define BUF 128*1024*1024
1333 if (fstat(sfd, &st) == 0) {
1336 if ( offset >= st.st_size) {
1339 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1340 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1343 case EINVAL: /* there's no guarantee that all fs support sendfile */
1352 lseek(sfd, offset, SEEK_SET);
1356 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1363 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1370 /* ----------------------------------
1371 * if newname is NULL (from directory.c) we don't want to copy the resource fork.
1372 * because we are doing it elsewhere.
1373 * currently if newname is NULL then adp is NULL.
1375 int copyfile(const struct vol *s_vol, const struct vol*d_vol,
1376 char *src, char *dst, char *newname, struct adouble *adp)
1378 struct adouble ads, add;
1386 LOG(log_info, logtype_afpd, "begin copyfile:");
1390 ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options);
1393 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1394 adflags = ADFLAGS_DF;
1396 adflags |= ADFLAGS_HF;
1399 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1404 if (ad_meta_fileno(adp) == -1 && ad_reso_fileno(adp) == -1) { /* META / HF */
1405 /* no resource fork, don't create one for dst file */
1406 adflags &= ~ADFLAGS_HF;
1409 stat_result = fstat(ad_data_fileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */
1411 if (stat_result < 0) {
1412 /* unlikely but if fstat fails, the default file mode will be 0666. */
1413 st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
1416 if (ad_open(dst , adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
1418 ad_close( adp, adflags );
1419 if (EEXIST != ret_err) {
1420 deletefile(d_vol, dst, 0);
1423 return AFPERR_EXIST;
1427 * XXX if the source and the dest don't use the same resource type it's broken
1429 if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){
1430 /* copy the data fork */
1431 if ((err = copy_fork(ADEID_DFORK, &add, adp)) == 0) {
1432 err = d_vol->vfs->vfs_copyfile(d_vol, src, dst);
1440 if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
1441 /* set the new name in the resource fork */
1442 ad_copy_header(&add, adp);
1443 ad_setname(&add, newname);
1446 ad_close( adp, adflags );
1448 if (ad_close( &add, adflags ) <0) {
1453 deletefile(d_vol, dst, 0);
1455 else if (stat_result == 0) {
1456 /* set dest modification date to src date */
1459 ut.actime = ut.modtime = st.st_mtime;
1461 /* FIXME netatalk doesn't use resource fork file date
1462 * but maybe we should set its modtime too.
1467 LOG(log_info, logtype_afpd, "end copyfile:");
1471 switch ( ret_err ) {
1477 return AFPERR_DFULL;
1479 return AFPERR_NOOBJ;
1481 return AFPERR_ACCESS;
1483 return AFPERR_VLOCK;
1485 return AFPERR_PARAM;
1489 /* -----------------------------------
1490 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1491 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1493 when deletefile is called we don't have lock on it, file is closed (for us)
1494 untrue if called by renamefile
1496 ad_open always try to open file RDWR first and ad_lock takes care of
1497 WRITE lock on read only file.
1500 static int check_attrib(struct adouble *adp)
1502 u_int16_t bshort = 0;
1504 ad_getattr(adp, &bshort);
1506 * Does kFPDeleteInhibitBit (bit 8) set?
1508 if ((bshort & htons(ATTRBIT_NODELETE))) {
1509 return AFPERR_OLOCK;
1511 if ((bshort & htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN))) {
1517 int deletefile(const struct vol *vol, char *file, int checkAttrib)
1520 struct adouble *adp = &ad;
1521 int adflags, err = AFP_OK;
1524 LOG(log_info, logtype_afpd, "begin deletefile:");
1527 /* try to open both forks at once */
1528 adflags = ADFLAGS_DF|ADFLAGS_HF;
1530 /* was EACCESS error try to get only metadata */
1531 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1532 if ( ad_metadata( file , ADFLAGS_OPENFORKS, &ad) == 0 ) {
1533 ad_close( &ad, adflags );
1534 if ((err = check_attrib(&ad))) {
1541 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1542 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1545 if (adflags == ADFLAGS_DF)
1546 return AFPERR_NOOBJ;
1548 /* that failed. now try to open just the data fork */
1549 adflags = ADFLAGS_DF;
1553 adp = NULL; /* maybe it's a file with no write mode for us */
1554 break; /* was return AFPERR_ACCESS;*/
1556 return AFPERR_VLOCK;
1558 return( AFPERR_PARAM );
1561 break; /* from the while */
1564 if (adp && (adflags & ADFLAGS_HF) ) {
1565 /* FIXME we have a pb here because we want to know if a file is open
1566 * there's a 'priority inversion' if you can't open the ressource fork RW
1567 * you can delete it if it's open because you can't get a write lock.
1569 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1572 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1574 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1575 ad_close( &ad, adflags );
1576 return( AFPERR_BUSY );
1580 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1583 else if (!(err = vol->vfs->vfs_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
1585 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1587 cnid_delete(vol->v_cdb, id);
1591 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1594 LOG(log_info, logtype_afpd, "end deletefile:");
1600 /* ------------------------------------ */
1601 /* return a file id */
1602 int afp_createid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1611 struct path *s_path;
1614 LOG(log_info, logtype_afpd, "begin afp_createid:");
1621 memcpy(&vid, ibuf, sizeof(vid));
1622 ibuf += sizeof(vid);
1624 if (NULL == ( vol = getvolbyvid( vid )) ) {
1625 return( AFPERR_PARAM);
1628 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1632 if (vol->v_flags & AFPVOL_RO)
1633 return AFPERR_VLOCK;
1635 memcpy(&did, ibuf, sizeof( did ));
1636 ibuf += sizeof(did);
1638 if (NULL == ( dir = dirlookup( vol, did )) ) {
1639 return afp_errno; /* was AFPERR_PARAM */
1642 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1643 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1646 if ( path_isadir(s_path) ) {
1647 return( AFPERR_BADTYPE );
1650 upath = s_path->u_name;
1651 switch (s_path->st_errno) {
1653 break; /* success */
1656 return AFPERR_ACCESS;
1658 return AFPERR_NOOBJ;
1660 return AFPERR_PARAM;
1663 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1664 memcpy(rbuf, &id, sizeof(id));
1665 *rbuflen = sizeof(id);
1666 return AFPERR_EXISTID;
1669 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1670 memcpy(rbuf, &id, sizeof(id));
1671 *rbuflen = sizeof(id);
1676 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1681 /* ------------------------------- */
1687 static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
1690 struct reenum *param = data;
1691 struct vol *vol = param->vol;
1692 cnid_t did = param->did;
1695 memset(&path, 0, sizeof(path));
1697 if ( stat(de->d_name, &path.st)<0 )
1700 /* update or add to cnid */
1701 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1703 #if AD_VERSION > AD_VERSION1
1704 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1705 struct adouble ad, *adp;
1709 path.u_name = de->d_name;
1711 adp = of_ad(vol, &path, &ad);
1713 if ( ad_open_metadata( de->d_name, 0, 0, adp ) < 0 ) {
1716 if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1719 ad_close_metadata(adp);
1721 #endif /* AD_VERSION > AD_VERSION1 */
1726 /* --------------------
1727 * Ok the db is out of synch with the dir.
1728 * but if it's a deleted file we don't want to do it again and again.
1731 reenumerate_id(struct vol *vol, char *name, struct dir *dir)
1737 if (vol->v_cdb == NULL) {
1741 /* FIXME use of_statdir ? */
1742 if (stat(name, &st)) {
1746 if (dirreenumerate(dir, &st)) {
1747 /* we already did it once and the dir haven't been modified */
1752 data.did = dir->d_did;
1753 if ((ret = for_each_dirent(vol, name, reenumerate_loop, (void *)&data)) >= 0) {
1754 setdiroffcnt(curdir, &st, ret);
1755 dir->d_flags |= DIRF_CNID;
1761 /* ------------------------------
1762 resolve a file id */
1763 int afp_resolveid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1772 u_int16_t vid, bitmap;
1774 static char buffer[12 + MAXPATHLEN + 1];
1775 int len = 12 + MAXPATHLEN + 1;
1778 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1784 memcpy(&vid, ibuf, sizeof(vid));
1785 ibuf += sizeof(vid);
1787 if (NULL == ( vol = getvolbyvid( vid )) ) {
1788 return( AFPERR_PARAM);
1791 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1795 memcpy(&id, ibuf, sizeof( id ));
1800 /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
1804 memset(&path, 0, sizeof(path));
1805 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1806 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1809 if (NULL == ( dir = dirlookup( vol, id )) ) {
1810 return AFPERR_NOID; /* idem AFPERR_PARAM */
1812 path.u_name = upath;
1813 if (movecwd(vol, dir) < 0) {
1817 return AFPERR_ACCESS;
1821 return AFPERR_PARAM;
1825 if ( of_stat(&path) < 0 ) {
1827 /* with nfs and our working directory is deleted */
1828 if (errno == ESTALE) {
1832 if ( errno == ENOENT && !retry) {
1833 /* cnid db is out of sync, reenumerate the directory and update ids */
1834 reenumerate_id(vol, ".", dir);
1842 return AFPERR_ACCESS;
1846 return AFPERR_PARAM;
1850 /* directories are bad */
1851 if (S_ISDIR(path.st.st_mode)) {
1852 /* OS9 and OSX don't return the same error code */
1853 return (afp_version >=30)?AFPERR_NOID:AFPERR_BADTYPE;
1856 memcpy(&bitmap, ibuf, sizeof(bitmap));
1857 bitmap = ntohs( bitmap );
1858 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1862 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1863 rbuf + sizeof(bitmap), &buflen))) {
1866 *rbuflen = buflen + sizeof(bitmap);
1867 memcpy(rbuf, ibuf, sizeof(bitmap));
1870 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1876 /* ------------------------------ */
1877 int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1887 static char buffer[12 + MAXPATHLEN + 1];
1888 int len = 12 + MAXPATHLEN + 1;
1891 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1897 memcpy(&vid, ibuf, sizeof(vid));
1898 ibuf += sizeof(vid);
1900 if (NULL == ( vol = getvolbyvid( vid )) ) {
1901 return( AFPERR_PARAM);
1904 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1908 if (vol->v_flags & AFPVOL_RO)
1909 return AFPERR_VLOCK;
1911 memcpy(&id, ibuf, sizeof( id ));
1915 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1919 if (NULL == ( dir = dirlookup( vol, id )) ) {
1920 return( AFPERR_PARAM );
1924 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1928 return AFPERR_ACCESS;
1933 /* still try to delete the id */
1937 return AFPERR_PARAM;
1940 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1941 return AFPERR_BADTYPE;
1943 if (cnid_delete(vol->v_cdb, fileid)) {
1946 return AFPERR_VLOCK;
1949 return AFPERR_ACCESS;
1951 return AFPERR_PARAM;
1956 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1962 /* ------------------------------ */
1963 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1967 if (path->st_errno) {
1968 switch (path->st_errno) {
1970 afp_errno = AFPERR_NOID;
1974 afp_errno = AFPERR_ACCESS;
1977 afp_errno = AFPERR_PARAM;
1982 /* we use file_access both for legacy Mac perm and
1983 * for unix privilege, rename will take care of folder perms
1985 if (file_access(path, OPENACC_WR ) < 0) {
1986 afp_errno = AFPERR_ACCESS;
1990 if ((*of = of_findname(path))) {
1991 /* reuse struct adouble so it won't break locks */
1995 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
1997 if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
1999 * The user must have the Read & Write privilege for both files in order to use this command.
2001 ad_close(adp, ADFLAGS_HF);
2002 afp_errno = AFPERR_ACCESS;
2009 #define APPLETEMP ".AppleTempXXXXXX"
2011 int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
2013 struct stat srcst, destst;
2015 struct dir *dir, *sdir;
2016 char *spath, temp[17], *p;
2017 char *supath, *upath;
2022 struct adouble *adsp = NULL;
2023 struct adouble *addp = NULL;
2024 struct ofork *s_of = NULL;
2025 struct ofork *d_of = NULL;
2036 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
2042 memcpy(&vid, ibuf, sizeof(vid));
2043 ibuf += sizeof(vid);
2045 if (NULL == ( vol = getvolbyvid( vid )) ) {
2046 return( AFPERR_PARAM);
2049 if ((vol->v_flags & AFPVOL_RO))
2050 return AFPERR_VLOCK;
2052 /* source and destination dids */
2053 memcpy(&sid, ibuf, sizeof(sid));
2054 ibuf += sizeof(sid);
2055 memcpy(&did, ibuf, sizeof(did));
2056 ibuf += sizeof(did);
2059 if (NULL == (dir = dirlookup( vol, sid )) ) {
2060 return afp_errno; /* was AFPERR_PARAM */
2063 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2064 return get_afp_errno(AFPERR_NOOBJ);
2067 if ( path_isadir(path) ) {
2068 return AFPERR_BADTYPE; /* it's a dir */
2071 /* save some stuff */
2074 spath = obj->oldtmp;
2075 supath = obj->newtmp;
2076 strcpy(spath, path->m_name);
2077 strcpy(supath, path->u_name); /* this is for the cnid changing */
2078 p = absupath( vol, sdir, supath);
2080 /* pathname too long */
2081 return AFPERR_PARAM ;
2084 ad_init(&ads, vol->v_adouble, vol->v_ad_options);
2085 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2089 /* ***** from here we may have resource fork open **** */
2091 /* look for the source cnid. if it doesn't exist, don't worry about
2093 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2095 if (NULL == ( dir = dirlookup( vol, did )) ) {
2096 err = afp_errno; /* was AFPERR_PARAM */
2097 goto err_exchangefile;
2100 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2101 err = get_afp_errno(AFPERR_NOOBJ);
2102 goto err_exchangefile;
2105 if ( path_isadir(path) ) {
2106 err = AFPERR_BADTYPE;
2107 goto err_exchangefile;
2110 /* FPExchangeFiles is the only call that can return the SameObj
2112 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2113 err = AFPERR_SAMEOBJ;
2114 goto err_exchangefile;
2117 ad_init(&add, vol->v_adouble, vol->v_ad_options);
2118 if (!(addp = find_adouble( path, &d_of, &add))) {
2120 goto err_exchangefile;
2124 /* they are not on the same device and at least one is open
2125 * FIXME broken for for crossdev and adouble v2
2128 crossdev = (srcst.st_dev != destst.st_dev);
2129 if (/* (d_of || s_of) && */ crossdev) {
2131 goto err_exchangefile;
2134 /* look for destination id. */
2135 upath = path->u_name;
2136 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2138 /* construct a temp name.
2139 * NOTE: the temp file will be in the dest file's directory. it
2140 * will also be inaccessible from AFP. */
2141 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2142 if (!mktemp(temp)) {
2144 goto err_exchangefile;
2148 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2149 ad_close(adsp, ADFLAGS_HF);
2150 ad_close(addp, ADFLAGS_HF);
2153 /* now, quickly rename the file. we error if we can't. */
2154 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2155 goto err_exchangefile;
2156 of_rename(vol, s_of, sdir, spath, curdir, temp);
2158 /* rename destination to source */
2159 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2160 goto err_src_to_tmp;
2161 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2163 /* rename temp to destination */
2164 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2165 goto err_dest_to_src;
2166 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2168 /* id's need switching. src -> dest and dest -> src.
2169 * we need to re-stat() if it was a cross device copy.
2172 cnid_delete(vol->v_cdb, sid);
2175 cnid_delete(vol->v_cdb, did);
2177 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2178 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2180 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2181 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2186 err = AFPERR_ACCESS;
2191 goto err_temp_to_dest;
2194 /* here we need to reopen if crossdev */
2195 if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2200 if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2205 /* change perms, src gets dest perm and vice versa */
2210 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2211 err = AFP_OK; /* ignore error */
2212 goto err_temp_to_dest;
2216 * we need to exchange ACL entries as well
2218 /* exchange_acls(vol, p, upath); */
2223 path->m_name = NULL;
2224 path->u_name = upath;
2226 setfilunixmode(vol, path, destst.st_mode);
2227 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2234 setfilunixmode(vol, path, srcst.st_mode);
2235 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2237 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2238 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2243 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2247 goto err_exchangefile;
2249 /* all this stuff is so that we can unwind a failed operation
2252 /* rename dest to temp */
2253 renamefile(vol, upath, temp, temp, adsp);
2254 of_rename(vol, s_of, curdir, upath, curdir, temp);
2257 /* rename source back to dest */
2258 renamefile(vol, p, upath, path->m_name, addp);
2259 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2262 /* rename temp back to source */
2263 renamefile(vol, temp, p, spath, adsp);
2264 of_rename(vol, s_of, curdir, temp, sdir, spath);
2267 if ( !s_of && adsp && ad_meta_fileno(adsp) != -1 ) { /* META */
2268 ad_close(adsp, ADFLAGS_HF);
2270 if ( !d_of && addp && ad_meta_fileno(addp) != -1 ) {/* META */
2271 ad_close(addp, ADFLAGS_HF);