2 * $Id: file.c,v 1.132 2010-02-04 10:52:29 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)
198 u_int32_t dbcnid = CNID_INVALID;
200 if (vol->v_cdb != NULL) {
201 /* prime aint with what we think is the cnid, set did to zero for
202 catching moved files */
203 adcnid = ad_getid(adp, st->st_dev, st->st_ino, 0, vol->v_stamp);
205 dbcnid = cnid_add(vol->v_cdb, st, did, upath, len, adcnid);
206 /* Throw errors if cnid_add fails. */
207 if (dbcnid == 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 else if (adp && (adcnid != dbcnid)) {
224 /* Update the ressource fork. For a folder adp is always null */
225 LOG(log_debug, logtype_afpd, "get_id: calling ad_setid. adcnid: %u, dbcnid: %u", htonl(adcnid), htonl(dbcnid));
226 if (ad_setid(adp, st->st_dev, st->st_ino, dbcnid, 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));
267 if (id == CNID_INVALID)
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|ADFLAGS_CREATE, 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 );
670 /* Check if this is the magic debugfile */
671 if (retvalue == AFP_OK
672 && curdir->d_did == htonl(2)
674 && strcmp(upath, vol->v_debugfile) == 0) {
675 char *path = absupath(vol, curdir, upath);
676 char *logstring = malloc(strlen("default log_maxdebug ") + strlen(path) + 1);
677 sprintf(logstring, "default log_maxdebug %s", path);
685 int afp_setfilparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
691 u_int16_t vid, bitmap;
696 memcpy(&vid, ibuf, sizeof( vid ));
697 ibuf += sizeof( vid );
698 if (NULL == ( vol = getvolbyvid( vid )) ) {
699 return( AFPERR_PARAM );
702 if (vol->v_flags & AFPVOL_RO)
705 memcpy(&did, ibuf, sizeof( did ));
706 ibuf += sizeof( did );
707 if (NULL == ( dir = dirlookup( vol, did )) ) {
708 return afp_errno; /* was AFPERR_NOOBJ */
711 memcpy(&bitmap, ibuf, sizeof( bitmap ));
712 bitmap = ntohs( bitmap );
713 ibuf += sizeof( bitmap );
715 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
716 return get_afp_errno(AFPERR_PARAM);
719 if (path_isadir(s_path)) {
720 return( AFPERR_BADTYPE ); /* it's a directory */
723 if ( s_path->st_errno != 0 ) {
724 return( AFPERR_NOOBJ );
727 if ((u_long)ibuf & 1 ) {
731 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
732 setvoltime(obj, vol );
739 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
742 extern struct path Cur_Path;
744 int setfilparams(struct vol *vol,
745 struct path *path, u_int16_t f_bitmap, char *buf )
747 struct adouble ad, *adp;
749 int bit, isad = 1, err = AFP_OK;
751 u_char achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
752 u_int16_t ashort, bshort, oshort;
755 u_int16_t upriv_bit = 0;
759 int change_mdate = 0;
760 int change_parent_mdate = 0;
765 u_int16_t bitmap = f_bitmap;
766 u_int32_t cdate,bdate;
767 u_char finder_buf[32];
770 LOG(log_debug9, logtype_afpd, "begin setfilparams:");
773 adp = of_ad(vol, path, &ad);
774 upath = path->u_name;
776 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
777 return AFPERR_ACCESS;
780 /* with unix priv maybe we have to change adouble file priv first */
782 while ( bitmap != 0 ) {
783 while (( bitmap & 1 ) == 0 ) {
790 memcpy(&ashort, buf, sizeof( ashort ));
791 buf += sizeof( ashort );
795 memcpy(&cdate, buf, sizeof(cdate));
796 buf += sizeof( cdate );
799 memcpy(&newdate, buf, sizeof( newdate ));
800 buf += sizeof( newdate );
804 memcpy(&bdate, buf, sizeof( bdate));
805 buf += sizeof( bdate );
809 memcpy(finder_buf, buf, 32 );
812 case FILPBIT_UNIXPR :
813 if (!vol_unix_priv(vol)) {
814 /* this volume doesn't use unix priv */
820 change_parent_mdate = 1;
822 memcpy( &aint, buf, sizeof( aint ));
823 f_uid = ntohl (aint);
824 buf += sizeof( aint );
825 memcpy( &aint, buf, sizeof( aint ));
826 f_gid = ntohl (aint);
827 buf += sizeof( aint );
828 setfilowner(vol, f_uid, f_gid, path);
830 memcpy( &upriv, buf, sizeof( upriv ));
831 buf += sizeof( upriv );
832 upriv = ntohl (upriv);
833 if ((upriv & S_IWUSR)) {
834 setfilunixmode(vol, path, upriv);
841 case FILPBIT_PDINFO :
842 if (afp_version < 30) { /* else it's UTF8 name */
845 /* Keep special case to support crlf translations */
846 if ((unsigned int) achar == 0x04) {
847 fdType = (u_char *)"TEXT";
850 xyy[0] = ( u_char ) 'p';
861 /* break while loop */
870 /* second try with adouble open
872 if ( ad_open_metadata( upath, 0, O_CREAT, adp) < 0) {
873 LOG(log_debug, logtype_afpd, "setfilparams: ad_open_metadata error");
875 * For some things, we don't need an adouble header:
876 * - change of modification date
877 * - UNIX privs (Bug-ID #2863424)
879 if ( (f_bitmap & ~(1<<FILPBIT_MDATE | 1<<FILPBIT_UNIXPR))) {
880 LOG(log_debug, logtype_afpd, "setfilparams: need adouble access");
881 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
883 LOG(log_debug, logtype_afpd, "setfilparams: no adouble perms, but only FILPBIT_MDATE and/or FILPBIT_UNIXPR");
885 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
886 ad_setname(adp, path->m_name);
891 while ( bitmap != 0 ) {
892 while (( bitmap & 1 ) == 0 ) {
899 ad_getattr(adp, &bshort);
901 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
902 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
906 if ((bshort & htons(ATTRBIT_INVISIBLE)) != (oshort & htons(ATTRBIT_INVISIBLE)))
907 change_parent_mdate = 1;
908 ad_setattr(adp, bshort);
911 ad_setdate(adp, AD_DATE_CREATE, cdate);
916 ad_setdate(adp, AD_DATE_BACKUP, bdate);
919 if (default_type( ad_entry( adp, ADEID_FINDERI ))
921 ((em = getextmap( path->m_name )) &&
922 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
923 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
924 || ((em = getdefextmap()) &&
925 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
926 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
928 memcpy(finder_buf, ufinderi, 8 );
930 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
932 case FILPBIT_UNIXPR :
934 setfilunixmode(vol, path, upriv);
937 case FILPBIT_PDINFO :
938 if (afp_version < 30) { /* else it's UTF8 name */
939 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
940 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
946 goto setfilparam_done;
953 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
954 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
958 ad_setdate(adp, AD_DATE_MODIFY, newdate);
959 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
965 ad_close_metadata( adp);
969 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
970 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
971 bitmap = 1<<FILPBIT_MDATE;
972 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
976 LOG(log_debug9, logtype_afpd, "end setfilparams:");
982 * renamefile and copyfile take the old and new unix pathnames
983 * and the new mac name.
985 * src the source path
986 * dst the dest filename in current dir
987 * newname the dest mac name
988 * adp adouble struct of src file, if open, or & zeroed one
991 int renamefile(const struct vol *vol, char *src, char *dst, char *newname, struct adouble *adp)
996 LOG(log_debug9, logtype_afpd, "begin renamefile:");
999 if ( unix_rename( src, dst ) < 0 ) {
1002 return( AFPERR_NOOBJ );
1005 return( AFPERR_ACCESS );
1007 return AFPERR_VLOCK;
1008 case EXDEV : /* Cross device move -- try copy */
1009 /* NOTE: with open file it's an error because after the copy we will
1010 * get two files, it's fixable for our process (eg reopen the new file, get the
1011 * locks, and so on. But it doesn't solve the case with a second process
1013 if (adp->ad_open_forks) {
1014 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1015 return AFPERR_OLOCK; /* little lie */
1017 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1018 /* on error copyfile delete dest */
1021 return deletefile(vol, src, 0);
1023 return( AFPERR_PARAM );
1027 if (vol->vfs->vfs_renamefile(vol, src, dst) < 0 ) {
1031 /* try to undo the data fork rename,
1032 * we know we are on the same device
1035 unix_rename( dst, src );
1036 /* return the first error */
1039 return AFPERR_NOOBJ;
1042 return AFPERR_ACCESS ;
1044 return AFPERR_VLOCK;
1046 return AFPERR_PARAM ;
1051 /* don't care if we can't open the newly renamed ressource fork
1053 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1054 ad_setname(adp, newname);
1056 ad_close( adp, ADFLAGS_HF );
1059 LOG(log_debug9, logtype_afpd, "end renamefile:");
1066 convert a Mac long name to an utf8 name,
1068 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1072 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1078 /* ---------------- */
1079 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1086 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1092 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1093 if (afp_version >= 30) {
1094 /* convert it to UTF8
1096 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1)
1100 strncpy( newname, ibuf, plen );
1101 newname[ plen ] = '\0';
1103 if (strlen(newname) != plen) {
1104 /* there's \0 in newname, e.g. it's a pathname not
1112 memcpy(&hint, ibuf, sizeof(hint));
1113 ibuf += sizeof(hint);
1115 memcpy(&len16, ibuf, sizeof(len16));
1116 ibuf += sizeof(len16);
1117 plen = ntohs(len16);
1120 if (plen > AFPOBJ_TMPSIZ) {
1123 strncpy( newname, ibuf, plen );
1124 newname[ plen ] = '\0';
1125 if (strlen(newname) != plen) {
1134 /* -----------------------------------
1136 int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1138 struct vol *s_vol, *d_vol;
1140 char *newname, *p, *upath;
1141 struct path *s_path;
1142 u_int32_t sdid, ddid;
1143 int err, retvalue = AFP_OK;
1144 u_int16_t svid, dvid;
1146 struct adouble ad, *adp;
1152 memcpy(&svid, ibuf, sizeof( svid ));
1153 ibuf += sizeof( svid );
1154 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1155 return( AFPERR_PARAM );
1158 memcpy(&sdid, ibuf, sizeof( sdid ));
1159 ibuf += sizeof( sdid );
1160 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1164 memcpy(&dvid, ibuf, sizeof( dvid ));
1165 ibuf += sizeof( dvid );
1166 memcpy(&ddid, ibuf, sizeof( ddid ));
1167 ibuf += sizeof( ddid );
1169 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1170 return get_afp_errno(AFPERR_PARAM);
1172 if ( path_isadir(s_path) ) {
1173 return( AFPERR_BADTYPE );
1176 /* don't allow copies when the file is open.
1177 * XXX: the spec only calls for read/deny write access.
1178 * however, copyfile doesn't have any of that info,
1179 * and locks need to stay coherent. as a result,
1180 * we just balk if the file is opened already. */
1182 adp = of_ad(s_vol, s_path, &ad);
1184 if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1185 return AFPERR_DENYCONF;
1187 denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
1188 getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1189 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1191 return AFPERR_DENYCONF;
1194 newname = obj->newtmp;
1195 strcpy( newname, s_path->m_name );
1197 p = ctoupath( s_vol, curdir, newname );
1199 return AFPERR_PARAM;
1203 /* FIXME svid != dvid && dvid's user can't read svid */
1205 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1206 return( AFPERR_PARAM );
1209 if (d_vol->v_flags & AFPVOL_RO)
1210 return AFPERR_VLOCK;
1212 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1216 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1217 return get_afp_errno(AFPERR_NOOBJ);
1219 if ( *s_path->m_name != '\0' ) {
1220 path_error(s_path, AFPERR_PARAM);
1223 /* one of the handful of places that knows about the path type */
1224 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1225 return( AFPERR_PARAM );
1227 /* newname is always only a filename so curdir *is* its
1230 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1231 return( AFPERR_PARAM );
1233 if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1239 if (vol->v_flags & AFPVOL_DROPBOX) {
1240 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1242 #endif /* DROPKLUDGE */
1244 setvoltime(obj, d_vol );
1249 /* ----------------------- */
1250 static int copy_all(const int dfd, const void *buf,
1256 LOG(log_debug9, logtype_afpd, "begin copy_all:");
1259 while (buflen > 0) {
1260 if ((cc = write(dfd, buf, buflen)) < 0) {
1272 LOG(log_debug9, logtype_afpd, "end copy_all:");
1278 /* --------------------------
1279 * copy only the fork data stream
1281 static int copy_fork(int eid, struct adouble *add, struct adouble *ads)
1288 if (eid == ADEID_DFORK) {
1289 sfd = ad_data_fileno(ads);
1290 dfd = ad_data_fileno(add);
1293 sfd = ad_reso_fileno(ads);
1294 dfd = ad_reso_fileno(add);
1297 if ((off_t)-1 == lseek(sfd, ad_getentryoff(ads, eid), SEEK_SET))
1300 if ((off_t)-1 == lseek(dfd, ad_getentryoff(add, eid), SEEK_SET))
1303 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1304 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1308 #define BUF 128*1024*1024
1310 if (fstat(sfd, &st) == 0) {
1313 if ( offset >= st.st_size) {
1316 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1317 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1320 case EINVAL: /* there's no guarantee that all fs support sendfile */
1329 lseek(sfd, offset, SEEK_SET);
1333 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1340 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1347 /* ----------------------------------
1348 * if newname is NULL (from directory.c) we don't want to copy the resource fork.
1349 * because we are doing it elsewhere.
1350 * currently if newname is NULL then adp is NULL.
1352 int copyfile(const struct vol *s_vol, const struct vol*d_vol,
1353 char *src, char *dst, char *newname, struct adouble *adp)
1355 struct adouble ads, add;
1363 LOG(log_debug9, logtype_afpd, "begin copyfile:");
1367 ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options);
1370 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1371 adflags = ADFLAGS_DF;
1373 adflags |= ADFLAGS_HF;
1376 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1381 if (ad_meta_fileno(adp) == -1 && ad_reso_fileno(adp) == -1) { /* META / HF */
1382 /* no resource fork, don't create one for dst file */
1383 adflags &= ~ADFLAGS_HF;
1386 stat_result = fstat(ad_data_fileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */
1388 if (stat_result < 0) {
1389 /* unlikely but if fstat fails, the default file mode will be 0666. */
1390 st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
1393 if (ad_open(dst , adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
1395 ad_close( adp, adflags );
1396 if (EEXIST != ret_err) {
1397 deletefile(d_vol, dst, 0);
1400 return AFPERR_EXIST;
1404 * XXX if the source and the dest don't use the same resource type it's broken
1406 if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){
1407 /* copy the data fork */
1408 if ((err = copy_fork(ADEID_DFORK, &add, adp)) == 0) {
1409 err = d_vol->vfs->vfs_copyfile(d_vol, src, dst);
1417 if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
1418 /* set the new name in the resource fork */
1419 ad_copy_header(&add, adp);
1420 ad_setname(&add, newname);
1423 ad_close( adp, adflags );
1425 if (ad_close( &add, adflags ) <0) {
1430 deletefile(d_vol, dst, 0);
1432 else if (stat_result == 0) {
1433 /* set dest modification date to src date */
1436 ut.actime = ut.modtime = st.st_mtime;
1438 /* FIXME netatalk doesn't use resource fork file date
1439 * but maybe we should set its modtime too.
1444 LOG(log_debug9, logtype_afpd, "end copyfile:");
1448 switch ( ret_err ) {
1454 return AFPERR_DFULL;
1456 return AFPERR_NOOBJ;
1458 return AFPERR_ACCESS;
1460 return AFPERR_VLOCK;
1462 return AFPERR_PARAM;
1466 /* -----------------------------------
1467 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1468 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1470 when deletefile is called we don't have lock on it, file is closed (for us)
1471 untrue if called by renamefile
1473 ad_open always try to open file RDWR first and ad_lock takes care of
1474 WRITE lock on read only file.
1477 static int check_attrib(struct adouble *adp)
1479 u_int16_t bshort = 0;
1481 ad_getattr(adp, &bshort);
1483 * Does kFPDeleteInhibitBit (bit 8) set?
1485 if ((bshort & htons(ATTRBIT_NODELETE))) {
1486 return AFPERR_OLOCK;
1488 if ((bshort & htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN))) {
1494 int deletefile(const struct vol *vol, char *file, int checkAttrib)
1497 struct adouble *adp = &ad;
1498 int adflags, err = AFP_OK;
1501 LOG(log_debug9, logtype_afpd, "begin deletefile:");
1504 /* try to open both forks at once */
1505 adflags = ADFLAGS_DF|ADFLAGS_HF;
1507 /* was EACCESS error try to get only metadata */
1508 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1509 /* we never want to create a resource fork here, we are going to delete it
1510 * moreover sometimes deletefile is called with a no existent file and
1511 * ad_open would create a 0 byte resource fork
1513 if ( ad_metadata( file, ADFLAGS_OPENFORKS, &ad) == 0 ) {
1514 ad_close( &ad, adflags );
1515 if ((err = check_attrib(&ad))) {
1522 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1523 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1526 if (adflags == ADFLAGS_DF)
1527 return AFPERR_NOOBJ;
1529 /* that failed. now try to open just the data fork */
1530 adflags = ADFLAGS_DF;
1534 adp = NULL; /* maybe it's a file with no write mode for us */
1535 break; /* was return AFPERR_ACCESS;*/
1537 return AFPERR_VLOCK;
1539 return( AFPERR_PARAM );
1542 break; /* from the while */
1545 if (adp && (adflags & ADFLAGS_HF) ) {
1546 /* FIXME we have a pb here because we want to know if a file is open
1547 * there's a 'priority inversion' if you can't open the ressource fork RW
1548 * you can delete it if it's open because you can't get a write lock.
1550 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1553 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1555 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1556 ad_close( &ad, adflags );
1557 return( AFPERR_BUSY );
1561 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1564 else if (!(err = vol->vfs->vfs_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
1566 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1568 cnid_delete(vol->v_cdb, id);
1572 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1575 LOG(log_debug9, logtype_afpd, "end deletefile:");
1581 /* ------------------------------------ */
1582 /* return a file id */
1583 int afp_createid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1592 struct path *s_path;
1598 memcpy(&vid, ibuf, sizeof(vid));
1599 ibuf += sizeof(vid);
1601 if (NULL == ( vol = getvolbyvid( vid )) ) {
1602 return( AFPERR_PARAM);
1605 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1609 if (vol->v_flags & AFPVOL_RO)
1610 return AFPERR_VLOCK;
1612 memcpy(&did, ibuf, sizeof( did ));
1613 ibuf += sizeof(did);
1615 if (NULL == ( dir = dirlookup( vol, did )) ) {
1616 return afp_errno; /* was AFPERR_PARAM */
1619 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1620 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1623 if ( path_isadir(s_path) ) {
1624 return( AFPERR_BADTYPE );
1627 upath = s_path->u_name;
1628 switch (s_path->st_errno) {
1630 break; /* success */
1633 return AFPERR_ACCESS;
1635 return AFPERR_NOOBJ;
1637 return AFPERR_PARAM;
1640 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1641 memcpy(rbuf, &id, sizeof(id));
1642 *rbuflen = sizeof(id);
1643 return AFPERR_EXISTID;
1646 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1647 memcpy(rbuf, &id, sizeof(id));
1648 *rbuflen = sizeof(id);
1655 /* ------------------------------- */
1661 static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
1664 struct reenum *param = data;
1665 struct vol *vol = param->vol;
1666 cnid_t did = param->did;
1669 if ( stat(de->d_name, &path.st)<0 )
1672 /* update or add to cnid */
1673 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1675 #if AD_VERSION > AD_VERSION1
1676 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1677 struct adouble ad, *adp;
1681 path.u_name = de->d_name;
1683 adp = of_ad(vol, &path, &ad);
1685 if ( ad_open_metadata( de->d_name, 0, 0, adp ) < 0 ) {
1688 if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1691 ad_close_metadata(adp);
1693 #endif /* AD_VERSION > AD_VERSION1 */
1698 /* --------------------
1699 * Ok the db is out of synch with the dir.
1700 * but if it's a deleted file we don't want to do it again and again.
1703 reenumerate_id(struct vol *vol, char *name, struct dir *dir)
1709 if (vol->v_cdb == NULL) {
1713 /* FIXME use of_statdir ? */
1714 if (stat(name, &st)) {
1718 if (dirreenumerate(dir, &st)) {
1719 /* we already did it once and the dir haven't been modified */
1724 data.did = dir->d_did;
1725 if ((ret = for_each_dirent(vol, name, reenumerate_loop, (void *)&data)) >= 0) {
1726 setdiroffcnt(curdir, &st, ret);
1727 dir->d_flags |= DIRF_CNID;
1733 /* ------------------------------
1734 resolve a file id */
1735 int afp_resolveid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1744 u_int16_t vid, bitmap;
1746 static char buffer[12 + MAXPATHLEN + 1];
1747 int len = 12 + MAXPATHLEN + 1;
1752 memcpy(&vid, ibuf, sizeof(vid));
1753 ibuf += sizeof(vid);
1755 if (NULL == ( vol = getvolbyvid( vid )) ) {
1756 return( AFPERR_PARAM);
1759 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1763 memcpy(&id, ibuf, sizeof( id ));
1768 /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
1772 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1773 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1776 if (NULL == ( dir = dirlookup( vol, id )) ) {
1777 return AFPERR_NOID; /* idem AFPERR_PARAM */
1779 if (movecwd(vol, dir) < 0) {
1783 return AFPERR_ACCESS;
1787 return AFPERR_PARAM;
1791 memset(&path, 0, sizeof(path));
1792 path.u_name = upath;
1793 if ( of_stat(&path) < 0 ) {
1795 /* with nfs and our working directory is deleted */
1796 if (errno == ESTALE) {
1800 if ( errno == ENOENT && !retry) {
1801 /* cnid db is out of sync, reenumerate the directory and update ids */
1802 reenumerate_id(vol, ".", dir);
1810 return AFPERR_ACCESS;
1814 return AFPERR_PARAM;
1818 /* directories are bad */
1819 if (S_ISDIR(path.st.st_mode)) {
1820 /* OS9 and OSX don't return the same error code */
1821 return (afp_version >=30)?AFPERR_NOID:AFPERR_BADTYPE;
1824 memcpy(&bitmap, ibuf, sizeof(bitmap));
1825 bitmap = ntohs( bitmap );
1826 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1830 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1831 rbuf + sizeof(bitmap), &buflen))) {
1834 *rbuflen = buflen + sizeof(bitmap);
1835 memcpy(rbuf, ibuf, sizeof(bitmap));
1840 /* ------------------------------ */
1841 int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1851 static char buffer[12 + MAXPATHLEN + 1];
1852 int len = 12 + MAXPATHLEN + 1;
1857 memcpy(&vid, ibuf, sizeof(vid));
1858 ibuf += sizeof(vid);
1860 if (NULL == ( vol = getvolbyvid( vid )) ) {
1861 return( AFPERR_PARAM);
1864 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1868 if (vol->v_flags & AFPVOL_RO)
1869 return AFPERR_VLOCK;
1871 memcpy(&id, ibuf, sizeof( id ));
1875 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1879 if (NULL == ( dir = dirlookup( vol, id )) ) {
1880 return( AFPERR_PARAM );
1884 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1888 return AFPERR_ACCESS;
1893 /* still try to delete the id */
1897 return AFPERR_PARAM;
1900 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1901 return AFPERR_BADTYPE;
1903 if (cnid_delete(vol->v_cdb, fileid)) {
1906 return AFPERR_VLOCK;
1909 return AFPERR_ACCESS;
1911 return AFPERR_PARAM;
1918 /* ------------------------------ */
1919 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1923 if (path->st_errno) {
1924 switch (path->st_errno) {
1926 afp_errno = AFPERR_NOID;
1930 afp_errno = AFPERR_ACCESS;
1933 afp_errno = AFPERR_PARAM;
1938 /* we use file_access both for legacy Mac perm and
1939 * for unix privilege, rename will take care of folder perms
1941 if (file_access(path, OPENACC_WR ) < 0) {
1942 afp_errno = AFPERR_ACCESS;
1946 if ((*of = of_findname(path))) {
1947 /* reuse struct adouble so it won't break locks */
1951 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
1953 if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
1955 * The user must have the Read & Write privilege for both files in order to use this command.
1957 ad_close(adp, ADFLAGS_HF);
1958 afp_errno = AFPERR_ACCESS;
1965 #define APPLETEMP ".AppleTempXXXXXX"
1967 int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1969 struct stat srcst, destst;
1971 struct dir *dir, *sdir;
1972 char *spath, temp[17], *p;
1973 char *supath, *upath;
1978 struct adouble *adsp = NULL;
1979 struct adouble *addp = NULL;
1980 struct ofork *s_of = NULL;
1981 struct ofork *d_of = NULL;
1994 memcpy(&vid, ibuf, sizeof(vid));
1995 ibuf += sizeof(vid);
1997 if (NULL == ( vol = getvolbyvid( vid )) ) {
1998 return( AFPERR_PARAM);
2001 if ((vol->v_flags & AFPVOL_RO))
2002 return AFPERR_VLOCK;
2004 /* source and destination dids */
2005 memcpy(&sid, ibuf, sizeof(sid));
2006 ibuf += sizeof(sid);
2007 memcpy(&did, ibuf, sizeof(did));
2008 ibuf += sizeof(did);
2011 if (NULL == (dir = dirlookup( vol, sid )) ) {
2012 return afp_errno; /* was AFPERR_PARAM */
2015 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2016 return get_afp_errno(AFPERR_NOOBJ);
2019 if ( path_isadir(path) ) {
2020 return AFPERR_BADTYPE; /* it's a dir */
2023 /* save some stuff */
2026 spath = obj->oldtmp;
2027 supath = obj->newtmp;
2028 strcpy(spath, path->m_name);
2029 strcpy(supath, path->u_name); /* this is for the cnid changing */
2030 p = absupath( vol, sdir, supath);
2032 /* pathname too long */
2033 return AFPERR_PARAM ;
2036 ad_init(&ads, vol->v_adouble, vol->v_ad_options);
2037 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2041 /* ***** from here we may have resource fork open **** */
2043 /* look for the source cnid. if it doesn't exist, don't worry about
2045 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2047 if (NULL == ( dir = dirlookup( vol, did )) ) {
2048 err = afp_errno; /* was AFPERR_PARAM */
2049 goto err_exchangefile;
2052 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2053 err = get_afp_errno(AFPERR_NOOBJ);
2054 goto err_exchangefile;
2057 if ( path_isadir(path) ) {
2058 err = AFPERR_BADTYPE;
2059 goto err_exchangefile;
2062 /* FPExchangeFiles is the only call that can return the SameObj
2064 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2065 err = AFPERR_SAMEOBJ;
2066 goto err_exchangefile;
2069 ad_init(&add, vol->v_adouble, vol->v_ad_options);
2070 if (!(addp = find_adouble( path, &d_of, &add))) {
2072 goto err_exchangefile;
2076 /* they are not on the same device and at least one is open
2077 * FIXME broken for for crossdev and adouble v2
2080 crossdev = (srcst.st_dev != destst.st_dev);
2081 if (/* (d_of || s_of) && */ crossdev) {
2083 goto err_exchangefile;
2086 /* look for destination id. */
2087 upath = path->u_name;
2088 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2090 /* construct a temp name.
2091 * NOTE: the temp file will be in the dest file's directory. it
2092 * will also be inaccessible from AFP. */
2093 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2094 if (!mktemp(temp)) {
2096 goto err_exchangefile;
2100 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2101 ad_close(adsp, ADFLAGS_HF);
2102 ad_close(addp, ADFLAGS_HF);
2105 /* now, quickly rename the file. we error if we can't. */
2106 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2107 goto err_exchangefile;
2108 of_rename(vol, s_of, sdir, spath, curdir, temp);
2110 /* rename destination to source */
2111 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2112 goto err_src_to_tmp;
2113 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2115 /* rename temp to destination */
2116 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2117 goto err_dest_to_src;
2118 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2120 /* id's need switching. src -> dest and dest -> src.
2121 * we need to re-stat() if it was a cross device copy.
2124 cnid_delete(vol->v_cdb, sid);
2127 cnid_delete(vol->v_cdb, did);
2129 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2130 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2132 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2133 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2138 err = AFPERR_ACCESS;
2143 goto err_temp_to_dest;
2146 /* here we need to reopen if crossdev */
2147 if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2152 if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2157 /* change perms, src gets dest perm and vice versa */
2162 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2163 err = AFP_OK; /* ignore error */
2164 goto err_temp_to_dest;
2168 * we need to exchange ACL entries as well
2170 /* exchange_acls(vol, p, upath); */
2175 path->m_name = NULL;
2176 path->u_name = upath;
2178 setfilunixmode(vol, path, destst.st_mode);
2179 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2186 setfilunixmode(vol, path, srcst.st_mode);
2187 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2189 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2190 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2195 goto err_exchangefile;
2197 /* all this stuff is so that we can unwind a failed operation
2200 /* rename dest to temp */
2201 renamefile(vol, upath, temp, temp, adsp);
2202 of_rename(vol, s_of, curdir, upath, curdir, temp);
2205 /* rename source back to dest */
2206 renamefile(vol, p, upath, path->m_name, addp);
2207 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2210 /* rename temp back to source */
2211 renamefile(vol, temp, p, spath, adsp);
2212 of_rename(vol, s_of, curdir, temp, sdir, spath);
2215 if ( !s_of && adsp && ad_meta_fileno(adsp) != -1 ) { /* META */
2216 ad_close(adsp, ADFLAGS_HF);
2218 if ( !d_of && addp && ad_meta_fileno(addp) != -1 ) {/* META */
2219 ad_close(addp, ADFLAGS_HF);