2 * $Id: file.c,v 1.112 2009-10-13 22:55:36 didg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
18 #else /* STDC_HEADERS */
22 #endif /* HAVE_STRCHR */
23 char *strchr (), *strrchr ();
26 #define memcpy(d,s,n) bcopy ((s), (d), (n))
27 #define memmove(d,s,n) bcopy ((s), (d), (n))
28 #endif /* ! HAVE_MEMCPY */
29 #endif /* STDC_HEADERS */
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 "directory.h"
51 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
52 * field bytes subfield bytes
55 * ioFlFndrInfo 16 -> type 4 type field
56 * creator 4 creator field
57 * flags 2 finder flags:
59 * location 4 location in window
60 * folder 2 window that contains file
62 * ioFlXFndrInfo 16 -> iconID 2 icon id
64 * script 1 script system
66 * commentID 2 comment id
67 * putawayID 4 home directory id
70 const u_char ufinderi[ADEDLEN_FINDERI] = {
71 0, 0, 0, 0, 0, 0, 0, 0,
72 1, 0, 0, 0, 0, 0, 0, 0,
73 0, 0, 0, 0, 0, 0, 0, 0,
74 0, 0, 0, 0, 0, 0, 0, 0
77 static const u_char old_ufinderi[] = {
78 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X'
81 /* ----------------------
83 static int default_type(void *finder)
85 if (!memcmp(finder, ufinderi, 8) || !memcmp(finder, old_ufinderi, 8))
90 /* FIXME path : unix or mac name ? (for now it's unix name ) */
91 void *get_finderinfo(const struct vol *vol, const char *upath, struct adouble *adp, void *data)
94 void *ad_finder = NULL;
98 ad_finder = ad_entry(adp, ADEID_FINDERI);
101 memcpy(data, ad_finder, ADEDLEN_FINDERI);
103 if (default_type(ad_finder))
107 memcpy(data, ufinderi, ADEDLEN_FINDERI);
109 if (vol_inv_dots(vol) && *upath == '.') { /* make it invisible */
112 ashort = htons(FINDERINFO_INVISIBLE);
113 memcpy((char *)data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
116 /** Only enter if no appledouble information and no finder information found. */
117 if (chk_ext && (em = getextmap( upath ))) {
118 memcpy(data, em->em_type, sizeof( em->em_type ));
119 memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator));
124 /* ---------------------
126 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8)
131 aint = strlen( name );
135 if (utf8_encoding()) {
136 /* but name is an utf8 mac name */
139 /* global static variable... */
141 if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
150 if (aint > MACFILELEN)
157 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
160 utf8 = vol->v_mac?htonl(vol->v_mac->kTextEncoding):0; /* htonl(utf8) */
161 memcpy(data, &utf8, sizeof(utf8));
162 data += sizeof(utf8);
165 memcpy(data, &temp, sizeof(temp));
166 data += sizeof(temp);
169 memcpy( data, src, aint );
179 * FIXME: PDINFO is UTF8 and doesn't need adp
181 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
182 (1 << FILPBIT_CDATE) |\
183 (1 << FILPBIT_MDATE) |\
184 (1 << FILPBIT_BDATE) |\
185 (1 << FILPBIT_FINFO) |\
186 (1 << FILPBIT_RFLEN) |\
187 (1 << FILPBIT_EXTRFLEN) |\
188 (1 << FILPBIT_PDINFO) |\
189 (1 << FILPBIT_UNIXPR)))
191 /* -------------------------- */
192 u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st,
193 const cnid_t did, char *upath, const int len)
197 #if AD_VERSION > AD_VERSION1
199 if ((aint = ad_getid(adp, st->st_dev, st->st_ino, did, vol->v_stamp))) {
204 if (vol->v_cdb != NULL) {
205 aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
206 /* Throw errors if cnid_add fails. */
207 if (aint == CNID_INVALID) {
209 case CNID_ERR_CLOSE: /* the db is closed */
212 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
213 afp_errno = AFPERR_PARAM;
216 afp_errno = AFPERR_PARAM;
219 afp_errno = AFPERR_MISC;
223 #if AD_VERSION > AD_VERSION1
225 /* update the ressource fork
226 * for a folder adp is always null
228 if (ad_setid(adp, st->st_dev, st->st_ino, aint, did, vol->v_stamp)) {
237 /* -------------------------- */
238 int getmetadata(struct vol *vol,
240 struct path *path, struct dir *dir,
241 char *buf, int *buflen, struct adouble *adp)
243 char *data, *l_nameoff = NULL, *upath;
244 char *utf_nameoff = NULL;
249 u_char achar, fdType[4];
255 LOG(log_info, logtype_afpd, "begin getmetadata:");
258 upath = path->u_name;
263 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
264 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
265 || (bitmap & (1 << FILPBIT_FNUM))) {
267 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
273 path->m_name = utompath(vol, upath, id, utf8_encoding());
276 while ( bitmap != 0 ) {
277 while (( bitmap & 1 ) == 0 ) {
285 ad_getattr(adp, &ashort);
286 } else if (vol_inv_dots(vol) && *upath == '.') {
287 ashort = htons(ATTRBIT_INVISIBLE);
291 /* FIXME do we want a visual clue if the file is read only
294 accessmode( ".", &ma, dir , NULL);
295 if ((ma.ma_user & AR_UWRITE)) {
296 accessmode( upath, &ma, dir , st);
297 if (!(ma.ma_user & AR_UWRITE)) {
298 ashort |= htons(ATTRBIT_NOWRITE);
302 memcpy(data, &ashort, sizeof( ashort ));
303 data += sizeof( ashort );
307 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
308 data += sizeof( u_int32_t );
312 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
313 aint = AD_DATE_FROM_UNIX(st->st_mtime);
314 memcpy(data, &aint, sizeof( aint ));
315 data += sizeof( aint );
319 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
320 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
321 aint = AD_DATE_FROM_UNIX(st->st_mtime);
324 aint = AD_DATE_FROM_UNIX(st->st_mtime);
326 memcpy(data, &aint, sizeof( int ));
327 data += sizeof( int );
331 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
332 aint = AD_DATE_START;
333 memcpy(data, &aint, sizeof( int ));
334 data += sizeof( int );
338 get_finderinfo(vol, upath, adp, (char *)data);
339 data += ADEDLEN_FINDERI;
344 data += sizeof( u_int16_t );
348 memset(data, 0, sizeof(u_int16_t));
349 data += sizeof( u_int16_t );
353 memcpy(data, &id, sizeof( id ));
354 data += sizeof( id );
358 if (st->st_size > 0xffffffff)
361 aint = htonl( st->st_size );
362 memcpy(data, &aint, sizeof( aint ));
363 data += sizeof( aint );
368 if (adp->ad_rlen > 0xffffffff)
371 aint = htonl( adp->ad_rlen);
375 memcpy(data, &aint, sizeof( aint ));
376 data += sizeof( aint );
379 /* Current client needs ProDOS info block for this file.
380 Use simple heuristic and let the Mac "type" string tell
381 us what the PD file code should be. Everything gets a
382 subtype of 0x0000 unless the original value was hashed
383 to "pXYZ" when we created it. See IA, Ver 2.
384 <shirsch@adelphia.net> */
385 case FILPBIT_PDINFO :
386 if (afp_version >= 30) { /* UTF8 name */
387 utf8 = kTextEncodingUTF8;
389 data += sizeof( u_int16_t );
391 memcpy(data, &aint, sizeof( aint ));
392 data += sizeof( aint );
396 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
398 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
402 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
406 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
410 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
414 else if ( fdType[0] == 'p' ) {
416 ashort = (fdType[2] * 256) + fdType[3];
430 memcpy(data, &ashort, sizeof( ashort ));
431 data += sizeof( ashort );
432 memset(data, 0, sizeof( ashort ));
433 data += sizeof( ashort );
436 case FILPBIT_EXTDFLEN:
437 aint = htonl(st->st_size >> 32);
438 memcpy(data, &aint, sizeof( aint ));
439 data += sizeof( aint );
440 aint = htonl(st->st_size);
441 memcpy(data, &aint, sizeof( aint ));
442 data += sizeof( aint );
444 case FILPBIT_EXTRFLEN:
447 aint = htonl(adp->ad_rlen >> 32);
448 memcpy(data, &aint, sizeof( aint ));
449 data += sizeof( aint );
451 aint = htonl(adp->ad_rlen);
452 memcpy(data, &aint, sizeof( aint ));
453 data += sizeof( aint );
455 case FILPBIT_UNIXPR :
456 /* accessmode may change st_mode with ACLs */
457 accessmode( upath, &ma, dir , st);
459 aint = htonl(st->st_uid);
460 memcpy( data, &aint, sizeof( aint ));
461 data += sizeof( aint );
462 aint = htonl(st->st_gid);
463 memcpy( data, &aint, sizeof( aint ));
464 data += sizeof( aint );
467 type == slnk indicates an OSX style symlink,
468 we have to add S_IFLNK to the mode, otherwise
469 10.3 clients freak out. */
473 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
474 if ( memcmp( fdType, "slnk", 4 ) == 0 ) {
480 memcpy( data, &aint, sizeof( aint ));
481 data += sizeof( aint );
483 *data++ = ma.ma_user;
484 *data++ = ma.ma_world;
485 *data++ = ma.ma_group;
486 *data++ = ma.ma_owner;
490 return( AFPERR_BITMAP );
496 ashort = htons( data - buf );
497 memcpy(l_nameoff, &ashort, sizeof( ashort ));
498 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
501 ashort = htons( data - buf );
502 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
503 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
505 *buflen = data - buf;
509 /* ----------------------- */
510 int getfilparams(struct vol *vol,
512 struct path *path, struct dir *dir,
513 char *buf, int *buflen )
515 struct adouble ad, *adp;
522 LOG(log_info, logtype_default, "begin getfilparams:");
525 opened = PARAM_NEED_ADP(bitmap);
529 int flags = (bitmap & (1 << FILPBIT_ATTR))?ADFLAGS_OPENFORKS:0;
530 upath = path->u_name;
531 if ((of = of_findname(path))) {
534 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
538 if ( ad_metadata( upath, flags, adp) < 0 ) {
541 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
542 upath, strerror(errno));
543 return AFPERR_ACCESS;
545 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
554 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp);
556 ad_close_metadata( adp);
559 LOG(log_info, logtype_afpd, "end getfilparams:");
565 /* ----------------------------- */
566 int afp_createfile(AFPObj *obj, char *ibuf, int ibuflen _U_, char *rbuf _U_, int *rbuflen)
568 struct adouble ad, *adp;
571 struct ofork *of = NULL;
573 int creatf, did, openf, retvalue = AFP_OK;
578 LOG(log_info, logtype_afpd, "begin afp_createfile:");
583 creatf = (unsigned char) *ibuf++;
585 memcpy(&vid, ibuf, sizeof( vid ));
586 ibuf += sizeof( vid );
588 if (NULL == ( vol = getvolbyvid( vid )) ) {
589 return( AFPERR_PARAM );
592 if (vol->v_flags & AFPVOL_RO)
595 memcpy(&did, ibuf, sizeof( did));
596 ibuf += sizeof( did );
598 if (NULL == ( dir = dirlookup( vol, did )) ) {
602 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
603 return get_afp_errno(AFPERR_PARAM);
606 if ( *s_path->m_name == '\0' ) {
607 return( AFPERR_BADTYPE );
610 upath = s_path->u_name;
612 /* if upath is deleted we already in trouble anyway */
613 if ((of = of_findname(s_path))) {
616 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
620 /* on a hard create, fail if file exists and is open */
623 openf = O_RDWR|O_CREAT|O_TRUNC;
625 /* on a soft create, if the file is open then ad_open won't fail
626 because open syscall is not called
631 openf = O_RDWR|O_CREAT|O_EXCL;
634 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF|ADFLAGS_CREATE,
635 openf, 0666, adp) < 0 ) {
639 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
640 return ( AFPERR_NOOBJ );
642 return( AFPERR_EXIST );
644 return( AFPERR_ACCESS );
647 return( AFPERR_DFULL );
649 return( AFPERR_PARAM );
652 if ( ad_reso_fileno( adp ) == -1 ) { /* Hard META / HF */
653 /* on noadouble volumes, just creating the data fork is ok */
654 if (vol_noadouble(vol)) {
655 ad_close( adp, ADFLAGS_DF );
656 goto createfile_done;
658 /* FIXME with hard create on an existing file, we already
659 * corrupted the data file.
661 netatalk_unlink( upath );
662 ad_close( adp, ADFLAGS_DF );
663 return AFPERR_ACCESS;
666 path = s_path->m_name;
667 ad_setname(adp, path);
669 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
675 if (vol->v_flags & AFPVOL_DROPBOX) {
676 retvalue = matchfile2dirperms(upath, vol, did);
678 #endif /* DROPKLUDGE */
680 setvoltime(obj, vol );
683 LOG(log_info, logtype_afpd, "end afp_createfile");
689 int afp_setfilparams(AFPObj *obj, char *ibuf, int ibuflen _U_, char *rbuf _U_, int *rbuflen)
695 u_int16_t vid, bitmap;
698 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
704 memcpy(&vid, ibuf, sizeof( vid ));
705 ibuf += sizeof( vid );
706 if (NULL == ( vol = getvolbyvid( vid )) ) {
707 return( AFPERR_PARAM );
710 if (vol->v_flags & AFPVOL_RO)
713 memcpy(&did, ibuf, sizeof( did ));
714 ibuf += sizeof( did );
715 if (NULL == ( dir = dirlookup( vol, did )) ) {
716 return afp_errno; /* was AFPERR_NOOBJ */
719 memcpy(&bitmap, ibuf, sizeof( bitmap ));
720 bitmap = ntohs( bitmap );
721 ibuf += sizeof( bitmap );
723 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
724 return get_afp_errno(AFPERR_PARAM);
727 if (path_isadir(s_path)) {
728 return( AFPERR_BADTYPE ); /* it's a directory */
731 if ( s_path->st_errno != 0 ) {
732 return( AFPERR_NOOBJ );
735 if ((u_long)ibuf & 1 ) {
739 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
740 setvoltime(obj, vol );
744 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
751 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
754 extern struct path Cur_Path;
756 int setfilparams(struct vol *vol,
757 struct path *path, u_int16_t f_bitmap, char *buf )
759 struct adouble ad, *adp;
761 int bit, isad = 1, err = AFP_OK;
763 u_char achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
764 u_int16_t ashort, bshort;
767 u_int16_t upriv_bit = 0;
771 int change_mdate = 0;
772 int change_parent_mdate = 0;
777 u_int16_t bitmap = f_bitmap;
778 u_int32_t cdate,bdate;
779 u_char finder_buf[32];
782 LOG(log_info, logtype_afpd, "begin setfilparams:");
785 upath = path->u_name;
786 adp = of_ad(vol, path, &ad);
789 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
790 return AFPERR_ACCESS;
793 /* with unix priv maybe we have to change adouble file priv first */
795 while ( bitmap != 0 ) {
796 while (( bitmap & 1 ) == 0 ) {
803 memcpy(&ashort, buf, sizeof( ashort ));
804 buf += sizeof( ashort );
808 memcpy(&cdate, buf, sizeof(cdate));
809 buf += sizeof( cdate );
812 memcpy(&newdate, buf, sizeof( newdate ));
813 buf += sizeof( newdate );
817 memcpy(&bdate, buf, sizeof( bdate));
818 buf += sizeof( bdate );
822 memcpy(finder_buf, buf, 32 );
825 case FILPBIT_UNIXPR :
826 if (!vol_unix_priv(vol)) {
827 /* this volume doesn't use unix priv */
833 change_parent_mdate = 1;
835 memcpy( &aint, buf, sizeof( aint ));
836 f_uid = ntohl (aint);
837 buf += sizeof( aint );
838 memcpy( &aint, buf, sizeof( aint ));
839 f_gid = ntohl (aint);
840 buf += sizeof( aint );
841 setfilowner(vol, f_uid, f_gid, path);
843 memcpy( &upriv, buf, sizeof( upriv ));
844 buf += sizeof( upriv );
845 upriv = ntohl (upriv);
846 if ((upriv & S_IWUSR)) {
847 setfilunixmode(vol, path, upriv);
854 case FILPBIT_PDINFO :
855 if (afp_version < 30) { /* else it's UTF8 name */
858 /* Keep special case to support crlf translations */
859 if ((unsigned int) achar == 0x04) {
860 fdType = (u_char *)"TEXT";
863 xyy[0] = ( u_char ) 'p';
874 /* break while loop */
883 /* second try with adouble open
885 if ( ad_open_metadata( upath, vol_noadouble(vol), O_CREAT, adp) < 0) {
886 LOG(log_debug, logtype_afpd, "setfilparams: ad_open_metadata error");
888 * For some things, we don't need an adouble header:
889 * - change of modification date
890 * - UNIX privs (Bug-ID #2863424)
892 if ( (f_bitmap & ~(1<<FILPBIT_MDATE | 1<<FILPBIT_UNIXPR))) {
893 LOG(log_debug, logtype_afpd, "setfilparams: need adouble access");
894 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
896 LOG(log_debug, logtype_afpd, "setfilparams: no adouble perms, but only FILPBIT_MDATE and/or FILPBIT_UNIXPR");
898 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
899 ad_setname(adp, path->m_name);
904 while ( bitmap != 0 ) {
905 while (( bitmap & 1 ) == 0 ) {
912 ad_getattr(adp, &bshort);
913 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
914 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
915 change_parent_mdate = 1;
916 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
917 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
921 ad_setattr(adp, bshort);
924 ad_setdate(adp, AD_DATE_CREATE, cdate);
929 ad_setdate(adp, AD_DATE_BACKUP, bdate);
932 if (default_type( ad_entry( adp, ADEID_FINDERI ))
934 ((em = getextmap( path->m_name )) &&
935 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
936 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
937 || ((em = getdefextmap()) &&
938 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
939 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
941 memcpy(finder_buf, ufinderi, 8 );
943 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
945 case FILPBIT_UNIXPR :
947 setfilunixmode(vol, path, upriv);
950 case FILPBIT_PDINFO :
951 if (afp_version < 30) { /* else it's UTF8 name */
952 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
953 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
959 goto setfilparam_done;
966 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
967 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
971 ad_setdate(adp, AD_DATE_MODIFY, newdate);
972 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
978 ad_close_metadata( adp);
982 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
983 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
984 bitmap = 1<<FILPBIT_MDATE;
985 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
989 LOG(log_info, logtype_afpd, "end setfilparams:");
995 * renamefile and copyfile take the old and new unix pathnames
996 * and the new mac name.
998 * src the source path
999 * dst the dest filename in current dir
1000 * newname the dest mac name
1001 * adp adouble struct of src file, if open, or & zeroed one
1004 int renamefile(const struct vol *vol, char *src, char *dst, char *newname, struct adouble *adp)
1009 LOG(log_info, logtype_afpd, "begin renamefile:");
1012 if ( unix_rename( src, dst ) < 0 ) {
1015 return( AFPERR_NOOBJ );
1018 return( AFPERR_ACCESS );
1020 return AFPERR_VLOCK;
1021 case EXDEV : /* Cross device move -- try copy */
1022 /* NOTE: with open file it's an error because after the copy we will
1023 * get two files, it's fixable for our process (eg reopen the new file, get the
1024 * locks, and so on. But it doesn't solve the case with a second process
1026 if (adp->ad_open_forks) {
1027 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1028 return AFPERR_OLOCK; /* little lie */
1030 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1031 /* on error copyfile delete dest */
1034 return deletefile(vol, src, 0);
1036 return( AFPERR_PARAM );
1040 if (vol->vfs->rf_renamefile(vol, src, dst) < 0 ) {
1044 /* try to undo the data fork rename,
1045 * we know we are on the same device
1048 unix_rename( dst, src );
1049 /* return the first error */
1052 return AFPERR_NOOBJ;
1055 return AFPERR_ACCESS ;
1057 return AFPERR_VLOCK;
1059 return AFPERR_PARAM ;
1064 /* don't care if we can't open the newly renamed ressource fork
1066 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1067 ad_setname(adp, newname);
1069 ad_close( adp, ADFLAGS_HF );
1072 LOG(log_info, logtype_afpd, "end renamefile:");
1079 convert a Mac long name to an utf8 name,
1081 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1085 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1091 /* ---------------- */
1092 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1099 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1105 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1106 if (afp_version >= 30) {
1107 /* convert it to UTF8
1109 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1)
1113 strncpy( newname, ibuf, plen );
1114 newname[ plen ] = '\0';
1116 if (strlen(newname) != plen) {
1117 /* there's \0 in newname, e.g. it's a pathname not
1125 memcpy(&hint, ibuf, sizeof(hint));
1126 ibuf += sizeof(hint);
1128 memcpy(&len16, ibuf, sizeof(len16));
1129 ibuf += sizeof(len16);
1130 plen = ntohs(len16);
1133 if (plen > AFPOBJ_TMPSIZ) {
1136 strncpy( newname, ibuf, plen );
1137 newname[ plen ] = '\0';
1138 if (strlen(newname) != plen) {
1147 /* -----------------------------------
1149 int afp_copyfile(AFPObj *obj, char *ibuf, int ibuflen _U_, char *rbuf _U_, int *rbuflen)
1151 struct vol *s_vol, *d_vol;
1153 char *newname, *p, *upath;
1154 struct path *s_path;
1155 u_int32_t sdid, ddid;
1156 int err, retvalue = AFP_OK;
1157 u_int16_t svid, dvid;
1159 struct adouble ad, *adp;
1163 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1169 memcpy(&svid, ibuf, sizeof( svid ));
1170 ibuf += sizeof( svid );
1171 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1172 return( AFPERR_PARAM );
1175 memcpy(&sdid, ibuf, sizeof( sdid ));
1176 ibuf += sizeof( sdid );
1177 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1181 memcpy(&dvid, ibuf, sizeof( dvid ));
1182 ibuf += sizeof( dvid );
1183 memcpy(&ddid, ibuf, sizeof( ddid ));
1184 ibuf += sizeof( ddid );
1186 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1187 return get_afp_errno(AFPERR_PARAM);
1189 if ( path_isadir(s_path) ) {
1190 return( AFPERR_BADTYPE );
1193 /* don't allow copies when the file is open.
1194 * XXX: the spec only calls for read/deny write access.
1195 * however, copyfile doesn't have any of that info,
1196 * and locks need to stay coherent. as a result,
1197 * we just balk if the file is opened already. */
1199 adp = of_ad(s_vol, s_path, &ad);
1201 if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1202 return AFPERR_DENYCONF;
1204 denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
1205 getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1206 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1208 return AFPERR_DENYCONF;
1211 newname = obj->newtmp;
1212 strcpy( newname, s_path->m_name );
1214 p = ctoupath( s_vol, curdir, newname );
1216 return AFPERR_PARAM;
1220 /* FIXME svid != dvid && dvid's user can't read svid */
1222 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1223 return( AFPERR_PARAM );
1226 if (d_vol->v_flags & AFPVOL_RO)
1227 return AFPERR_VLOCK;
1229 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1233 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1234 return get_afp_errno(AFPERR_NOOBJ);
1236 if ( *s_path->m_name != '\0' ) {
1237 path_error(s_path, AFPERR_PARAM);
1240 /* one of the handful of places that knows about the path type */
1241 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1242 return( AFPERR_PARAM );
1244 /* newname is always only a filename so curdir *is* its
1247 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1248 return( AFPERR_PARAM );
1250 if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1256 if (vol->v_flags & AFPVOL_DROPBOX) {
1257 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1259 #endif /* DROPKLUDGE */
1261 setvoltime(obj, d_vol );
1264 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1270 /* ----------------------- */
1271 static int copy_all(const int dfd, const void *buf,
1277 LOG(log_info, logtype_afpd, "begin copy_all:");
1280 while (buflen > 0) {
1281 if ((cc = write(dfd, buf, buflen)) < 0) {
1293 LOG(log_info, logtype_afpd, "end copy_all:");
1299 /* --------------------------
1300 * copy only the fork data stream
1302 static int copy_fork(int eid, struct adouble *add, struct adouble *ads)
1309 if (eid == ADEID_DFORK) {
1310 sfd = ad_data_fileno(ads);
1311 dfd = ad_data_fileno(add);
1314 sfd = ad_reso_fileno(ads);
1315 dfd = ad_reso_fileno(add);
1318 if ((off_t)-1 == lseek(sfd, ad_getentryoff(ads, eid), SEEK_SET))
1321 if ((off_t)-1 == lseek(dfd, ad_getentryoff(add, eid), SEEK_SET))
1324 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1325 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1329 #define BUF 128*1024*1024
1331 if (fstat(sfd, &st) == 0) {
1334 if ( offset >= st.st_size) {
1337 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1338 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1341 case EINVAL: /* there's no guarantee that all fs support sendfile */
1350 lseek(sfd, offset, SEEK_SET);
1354 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1361 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1368 /* ----------------------------------
1369 * if newname is NULL (from directory.c) we don't want to copy the resource fork.
1370 * because we are doing it elsewhere.
1371 * currently if newname is NULL then adp is NULL.
1373 int copyfile(const struct vol *s_vol, const struct vol*d_vol,
1374 char *src, char *dst, char *newname, struct adouble *adp)
1376 struct adouble ads, add;
1384 LOG(log_info, logtype_afpd, "begin copyfile:");
1388 ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options);
1391 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1392 adflags = ADFLAGS_DF;
1394 adflags |= ADFLAGS_HF;
1397 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1402 if (ad_meta_fileno(adp) == -1 && ad_reso_fileno(adp) == -1) { /* META / HF */
1403 /* no resource fork, don't create one for dst file */
1404 adflags &= ~ADFLAGS_HF;
1407 stat_result = fstat(ad_data_fileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */
1409 if (stat_result < 0) {
1410 /* unlikely but if fstat fails, the default file mode will be 0666. */
1411 st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
1414 if (ad_open(dst , adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
1416 ad_close( adp, adflags );
1417 if (EEXIST != ret_err) {
1418 deletefile(d_vol, dst, 0);
1421 return AFPERR_EXIST;
1423 /* XXX if the source and the dest don't use the same resource type it's broken
1425 if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){
1426 /* copy the data fork */
1427 err = copy_fork(ADEID_DFORK, &add, adp);
1434 if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
1435 /* set the new name in the resource fork */
1436 ad_copy_header(&add, adp);
1437 ad_setname(&add, newname);
1440 ad_close( adp, adflags );
1442 if (ad_close( &add, adflags ) <0) {
1447 deletefile(d_vol, dst, 0);
1449 else if (stat_result == 0) {
1450 /* set dest modification date to src date */
1453 ut.actime = ut.modtime = st.st_mtime;
1455 /* FIXME netatalk doesn't use resource fork file date
1456 * but maybe we should set its modtime too.
1461 LOG(log_info, logtype_afpd, "end copyfile:");
1465 switch ( ret_err ) {
1471 return AFPERR_DFULL;
1473 return AFPERR_NOOBJ;
1475 return AFPERR_ACCESS;
1477 return AFPERR_VLOCK;
1479 return AFPERR_PARAM;
1483 /* -----------------------------------
1484 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1485 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1487 when deletefile is called we don't have lock on it, file is closed (for us)
1488 untrue if called by renamefile
1490 ad_open always try to open file RDWR first and ad_lock takes care of
1491 WRITE lock on read only file.
1494 static int check_attrib(struct adouble *adp)
1496 u_int16_t bshort = 0;
1498 ad_getattr(adp, &bshort);
1500 * Does kFPDeleteInhibitBit (bit 8) set?
1502 if ((bshort & htons(ATTRBIT_NODELETE))) {
1503 return AFPERR_OLOCK;
1505 if ((bshort & htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN))) {
1511 int deletefile(const struct vol *vol, char *file, int checkAttrib)
1514 struct adouble *adp = &ad;
1515 int adflags, err = AFP_OK;
1518 LOG(log_info, logtype_afpd, "begin deletefile:");
1521 /* try to open both forks at once */
1522 adflags = ADFLAGS_DF|ADFLAGS_HF;
1524 /* was EACCESS error try to get only metadata */
1525 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1526 if ( ad_metadata( file , ADFLAGS_OPENFORKS, &ad) == 0 ) {
1527 ad_close( &ad, adflags );
1528 if ((err = check_attrib(&ad))) {
1535 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1536 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1539 if (adflags == ADFLAGS_DF)
1540 return AFPERR_NOOBJ;
1542 /* that failed. now try to open just the data fork */
1543 adflags = ADFLAGS_DF;
1547 adp = NULL; /* maybe it's a file with no write mode for us */
1548 break; /* was return AFPERR_ACCESS;*/
1550 return AFPERR_VLOCK;
1552 return( AFPERR_PARAM );
1555 break; /* from the while */
1558 if (adp && (adflags & ADFLAGS_HF) ) {
1559 /* FIXME we have a pb here because we want to know if a file is open
1560 * there's a 'priority inversion' if you can't open the ressource fork RW
1561 * you can delete it if it's open because you can't get a write lock.
1563 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1566 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1568 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1569 ad_close( &ad, adflags );
1570 return( AFPERR_BUSY );
1574 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1577 else if (!(err = vol->vfs->rf_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
1579 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1581 cnid_delete(vol->v_cdb, id);
1585 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1588 LOG(log_info, logtype_afpd, "end deletefile:");
1594 /* ------------------------------------ */
1595 /* return a file id */
1596 int afp_createid(AFPObj *obj _U_, char *ibuf, int ibuflen _U_, char *rbuf, int *rbuflen)
1605 struct path *s_path;
1608 LOG(log_info, logtype_afpd, "begin afp_createid:");
1615 memcpy(&vid, ibuf, sizeof(vid));
1616 ibuf += sizeof(vid);
1618 if (NULL == ( vol = getvolbyvid( vid )) ) {
1619 return( AFPERR_PARAM);
1622 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1626 if (vol->v_flags & AFPVOL_RO)
1627 return AFPERR_VLOCK;
1629 memcpy(&did, ibuf, sizeof( did ));
1630 ibuf += sizeof(did);
1632 if (NULL == ( dir = dirlookup( vol, did )) ) {
1633 return afp_errno; /* was AFPERR_PARAM */
1636 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1637 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1640 if ( path_isadir(s_path) ) {
1641 return( AFPERR_BADTYPE );
1644 upath = s_path->u_name;
1645 switch (s_path->st_errno) {
1647 break; /* success */
1650 return AFPERR_ACCESS;
1652 return AFPERR_NOOBJ;
1654 return AFPERR_PARAM;
1657 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1658 memcpy(rbuf, &id, sizeof(id));
1659 *rbuflen = sizeof(id);
1660 return AFPERR_EXISTID;
1663 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1664 memcpy(rbuf, &id, sizeof(id));
1665 *rbuflen = sizeof(id);
1670 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1675 /* ------------------------------- */
1681 static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
1684 struct reenum *param = data;
1685 struct vol *vol = param->vol;
1686 cnid_t did = param->did;
1689 memset(&path, 0, sizeof(path));
1691 if ( stat(de->d_name, &path.st)<0 )
1694 /* update or add to cnid */
1695 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1697 #if AD_VERSION > AD_VERSION1
1698 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1699 struct adouble ad, *adp;
1703 path.u_name = de->d_name;
1705 adp = of_ad(vol, &path, &ad);
1707 if ( ad_open_metadata( de->d_name, 0, 0, adp ) < 0 ) {
1710 if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1713 ad_close_metadata(adp);
1715 #endif /* AD_VERSION > AD_VERSION1 */
1720 /* --------------------
1721 * Ok the db is out of synch with the dir.
1722 * but if it's a deleted file we don't want to do it again and again.
1725 reenumerate_id(struct vol *vol, char *name, struct dir *dir)
1731 if (vol->v_cdb == NULL) {
1735 /* FIXME use of_statdir ? */
1736 if (stat(name, &st)) {
1740 if (dirreenumerate(dir, &st)) {
1741 /* we already did it once and the dir haven't been modified */
1746 data.did = dir->d_did;
1747 if ((ret = for_each_dirent(vol, name, reenumerate_loop, (void *)&data)) >= 0) {
1748 setdiroffcnt(curdir, &st, ret);
1749 dir->d_flags |= DIRF_CNID;
1755 /* ------------------------------
1756 resolve a file id */
1757 int afp_resolveid(AFPObj *obj _U_, char *ibuf, int ibuflen _U_, char *rbuf, int *rbuflen)
1763 int err, buflen, retry=0;
1765 u_int16_t vid, bitmap;
1767 static char buffer[12 + MAXPATHLEN + 1];
1768 int len = 12 + MAXPATHLEN + 1;
1771 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1777 memcpy(&vid, ibuf, sizeof(vid));
1778 ibuf += sizeof(vid);
1780 if (NULL == ( vol = getvolbyvid( vid )) ) {
1781 return( AFPERR_PARAM);
1784 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1788 memcpy(&id, ibuf, sizeof( id ));
1793 /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
1797 memset(&path, 0, sizeof(path));
1798 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1799 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1802 if (NULL == ( dir = dirlookup( vol, id )) ) {
1803 return AFPERR_NOID; /* idem AFPERR_PARAM */
1805 path.u_name = upath;
1806 if (movecwd(vol, dir) < 0) {
1810 return AFPERR_ACCESS;
1814 return AFPERR_PARAM;
1818 if ( of_stat(&path) < 0 ) {
1820 /* with nfs and our working directory is deleted */
1821 if (errno == ESTALE) {
1825 if ( errno == ENOENT && !retry) {
1826 /* cnid db is out of sync, reenumerate the directory and update ids */
1827 reenumerate_id(vol, ".", dir);
1835 return AFPERR_ACCESS;
1839 return AFPERR_PARAM;
1843 /* directories are bad */
1844 if (S_ISDIR(path.st.st_mode)) {
1845 /* OS9 and OSX don't return the same error code */
1846 return (afp_version >=30)?AFPERR_NOID:AFPERR_BADTYPE;
1849 memcpy(&bitmap, ibuf, sizeof(bitmap));
1850 bitmap = ntohs( bitmap );
1851 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1855 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1856 rbuf + sizeof(bitmap), &buflen))) {
1859 *rbuflen = buflen + sizeof(bitmap);
1860 memcpy(rbuf, ibuf, sizeof(bitmap));
1863 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1869 /* ------------------------------ */
1870 int afp_deleteid(AFPObj *obj _U_, char *ibuf, int ibuflen _U_, char *rbuf _U_, int *rbuflen)
1880 static char buffer[12 + MAXPATHLEN + 1];
1881 int len = 12 + MAXPATHLEN + 1;
1884 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1890 memcpy(&vid, ibuf, sizeof(vid));
1891 ibuf += sizeof(vid);
1893 if (NULL == ( vol = getvolbyvid( vid )) ) {
1894 return( AFPERR_PARAM);
1897 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1901 if (vol->v_flags & AFPVOL_RO)
1902 return AFPERR_VLOCK;
1904 memcpy(&id, ibuf, sizeof( id ));
1908 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1912 if (NULL == ( dir = dirlookup( vol, id )) ) {
1913 return( AFPERR_PARAM );
1917 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1921 return AFPERR_ACCESS;
1926 /* still try to delete the id */
1930 return AFPERR_PARAM;
1933 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1934 return AFPERR_BADTYPE;
1936 if (cnid_delete(vol->v_cdb, fileid)) {
1939 return AFPERR_VLOCK;
1942 return AFPERR_ACCESS;
1944 return AFPERR_PARAM;
1949 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1955 /* ------------------------------ */
1956 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1960 if (path->st_errno) {
1961 switch (path->st_errno) {
1963 afp_errno = AFPERR_NOID;
1967 afp_errno = AFPERR_ACCESS;
1970 afp_errno = AFPERR_PARAM;
1975 /* we use file_access both for legacy Mac perm and
1976 * for unix privilege, rename will take care of folder perms
1978 if (file_access(path, OPENACC_WR ) < 0) {
1979 afp_errno = AFPERR_ACCESS;
1983 if ((*of = of_findname(path))) {
1984 /* reuse struct adouble so it won't break locks */
1988 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
1990 if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
1992 * The user must have the Read & Write privilege for both files in order to use this command.
1994 ad_close(adp, ADFLAGS_HF);
1995 afp_errno = AFPERR_ACCESS;
2002 #define APPLETEMP ".AppleTempXXXXXX"
2004 int afp_exchangefiles(AFPObj *obj, char *ibuf, int ibuflen _U_, char *rbuf _U_, int *rbuflen)
2006 struct stat srcst, destst;
2008 struct dir *dir, *sdir;
2009 char *spath, temp[17], *p;
2010 char *supath, *upath;
2015 struct adouble *adsp = NULL;
2016 struct adouble *addp = NULL;
2017 struct ofork *s_of = NULL;
2018 struct ofork *d_of = NULL;
2029 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
2035 memcpy(&vid, ibuf, sizeof(vid));
2036 ibuf += sizeof(vid);
2038 if (NULL == ( vol = getvolbyvid( vid )) ) {
2039 return( AFPERR_PARAM);
2042 if ((vol->v_flags & AFPVOL_RO))
2043 return AFPERR_VLOCK;
2045 /* source and destination dids */
2046 memcpy(&sid, ibuf, sizeof(sid));
2047 ibuf += sizeof(sid);
2048 memcpy(&did, ibuf, sizeof(did));
2049 ibuf += sizeof(did);
2052 if (NULL == (dir = dirlookup( vol, sid )) ) {
2053 return afp_errno; /* was AFPERR_PARAM */
2056 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2057 return get_afp_errno(AFPERR_NOOBJ);
2060 if ( path_isadir(path) ) {
2061 return AFPERR_BADTYPE; /* it's a dir */
2064 /* save some stuff */
2067 spath = obj->oldtmp;
2068 supath = obj->newtmp;
2069 strcpy(spath, path->m_name);
2070 strcpy(supath, path->u_name); /* this is for the cnid changing */
2071 p = absupath( vol, sdir, supath);
2073 /* pathname too long */
2074 return AFPERR_PARAM ;
2077 ad_init(&ads, vol->v_adouble, vol->v_ad_options);
2078 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2082 /* ***** from here we may have resource fork open **** */
2084 /* look for the source cnid. if it doesn't exist, don't worry about
2086 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2088 if (NULL == ( dir = dirlookup( vol, did )) ) {
2089 err = afp_errno; /* was AFPERR_PARAM */
2090 goto err_exchangefile;
2093 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2094 err = get_afp_errno(AFPERR_NOOBJ);
2095 goto err_exchangefile;
2098 if ( path_isadir(path) ) {
2099 err = AFPERR_BADTYPE;
2100 goto err_exchangefile;
2103 /* FPExchangeFiles is the only call that can return the SameObj
2105 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2106 err = AFPERR_SAMEOBJ;
2107 goto err_exchangefile;
2110 ad_init(&add, vol->v_adouble, vol->v_ad_options);
2111 if (!(addp = find_adouble( path, &d_of, &add))) {
2113 goto err_exchangefile;
2117 /* they are not on the same device and at least one is open
2118 * FIXME broken for for crossdev and adouble v2
2121 crossdev = (srcst.st_dev != destst.st_dev);
2122 if (/* (d_of || s_of) && */ crossdev) {
2124 goto err_exchangefile;
2127 /* look for destination id. */
2128 upath = path->u_name;
2129 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2131 /* construct a temp name.
2132 * NOTE: the temp file will be in the dest file's directory. it
2133 * will also be inaccessible from AFP. */
2134 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2135 if (!mktemp(temp)) {
2137 goto err_exchangefile;
2141 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2142 ad_close(adsp, ADFLAGS_HF);
2143 ad_close(addp, ADFLAGS_HF);
2146 /* now, quickly rename the file. we error if we can't. */
2147 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2148 goto err_exchangefile;
2149 of_rename(vol, s_of, sdir, spath, curdir, temp);
2151 /* rename destination to source */
2152 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2153 goto err_src_to_tmp;
2154 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2156 /* rename temp to destination */
2157 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2158 goto err_dest_to_src;
2159 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2161 /* id's need switching. src -> dest and dest -> src.
2162 * we need to re-stat() if it was a cross device copy.
2165 cnid_delete(vol->v_cdb, sid);
2168 cnid_delete(vol->v_cdb, did);
2170 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2171 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2173 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2174 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2179 err = AFPERR_ACCESS;
2184 goto err_temp_to_dest;
2187 /* here we need to reopen if crossdev */
2188 if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2193 if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2198 /* change perms, src gets dest perm and vice versa */
2203 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2204 err = AFP_OK; /* ignore error */
2205 goto err_temp_to_dest;
2209 * we need to exchange ACL entries as well
2211 /* exchange_acls(vol, p, upath); */
2216 path->m_name = NULL;
2217 path->u_name = upath;
2219 setfilunixmode(vol, path, destst.st_mode);
2220 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2227 setfilunixmode(vol, path, srcst.st_mode);
2228 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2230 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2231 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2236 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2240 goto err_exchangefile;
2242 /* all this stuff is so that we can unwind a failed operation
2245 /* rename dest to temp */
2246 renamefile(vol, upath, temp, temp, adsp);
2247 of_rename(vol, s_of, curdir, upath, curdir, temp);
2250 /* rename source back to dest */
2251 renamefile(vol, p, upath, path->m_name, addp);
2252 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2255 /* rename temp back to source */
2256 renamefile(vol, temp, p, spath, adsp);
2257 of_rename(vol, s_of, curdir, temp, sdir, spath);
2260 if ( !s_of && adsp && ad_meta_fileno(adsp) != -1 ) { /* META */
2261 ad_close(adsp, ADFLAGS_HF);
2263 if ( !d_of && addp && ad_meta_fileno(addp) != -1 ) {/* META */
2264 ad_close(addp, ADFLAGS_HF);