2 * $Id: file.c,v 1.131.2.3 2010-02-04 14:34:31 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(const 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 upath = path->u_name;
257 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
258 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
259 || (bitmap & (1 << FILPBIT_FNUM))) {
261 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
264 if (id == CNID_INVALID)
267 path->m_name = utompath(vol, upath, id, utf8_encoding());
270 while ( bitmap != 0 ) {
271 while (( bitmap & 1 ) == 0 ) {
279 ad_getattr(adp, &ashort);
280 } else if (vol_inv_dots(vol) && *upath == '.') {
281 ashort = htons(ATTRBIT_INVISIBLE);
285 /* FIXME do we want a visual clue if the file is read only
288 accessmode( ".", &ma, dir , NULL);
289 if ((ma.ma_user & AR_UWRITE)) {
290 accessmode( upath, &ma, dir , st);
291 if (!(ma.ma_user & AR_UWRITE)) {
292 ashort |= htons(ATTRBIT_NOWRITE);
296 memcpy(data, &ashort, sizeof( ashort ));
297 data += sizeof( ashort );
298 LOG(log_debug, logtype_afpd, "metadata('%s'): AFP Attributes: %04x",
299 path->u_name, ntohs(ashort));
303 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
304 data += sizeof( u_int32_t );
305 LOG(log_debug, logtype_afpd, "metadata('%s'): Parent DID: %u",
306 path->u_name, ntohl(dir->d_did));
310 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
311 aint = AD_DATE_FROM_UNIX(st->st_mtime);
312 memcpy(data, &aint, sizeof( aint ));
313 data += sizeof( aint );
317 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
318 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
319 aint = AD_DATE_FROM_UNIX(st->st_mtime);
322 aint = AD_DATE_FROM_UNIX(st->st_mtime);
324 memcpy(data, &aint, sizeof( int ));
325 data += sizeof( int );
329 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
330 aint = AD_DATE_START;
331 memcpy(data, &aint, sizeof( int ));
332 data += sizeof( int );
336 get_finderinfo(vol, upath, adp, (char *)data);
337 data += ADEDLEN_FINDERI;
342 data += sizeof( u_int16_t );
346 memset(data, 0, sizeof(u_int16_t));
347 data += sizeof( u_int16_t );
351 memcpy(data, &id, sizeof( id ));
352 data += sizeof( id );
353 LOG(log_debug, logtype_afpd, "metadata('%s'): CNID: %u",
354 path->u_name, ntohl(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, size_t *buflen )
515 struct adouble ad, *adp;
519 opened = PARAM_NEED_ADP(bitmap);
524 int flags = (bitmap & (1 << FILPBIT_ATTR))?ADFLAGS_OPENFORKS:0;
526 adp = of_ad(vol, path, &ad);
527 upath = path->u_name;
529 if ( ad_metadata( upath, flags|ADFLAGS_CREATE, adp) < 0 ) {
532 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
533 upath, strerror(errno));
534 return AFPERR_ACCESS;
536 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
545 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp);
547 ad_close_metadata( adp);
553 /* ----------------------------- */
554 int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
556 struct adouble ad, *adp;
559 struct ofork *of = NULL;
561 int creatf, did, openf, retvalue = AFP_OK;
567 creatf = (unsigned char) *ibuf++;
569 memcpy(&vid, ibuf, sizeof( vid ));
570 ibuf += sizeof( vid );
572 if (NULL == ( vol = getvolbyvid( vid )) ) {
573 return( AFPERR_PARAM );
576 if (vol->v_flags & AFPVOL_RO)
579 memcpy(&did, ibuf, sizeof( did));
580 ibuf += sizeof( did );
582 if (NULL == ( dir = dirlookup( vol, did )) ) {
586 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
587 return get_afp_errno(AFPERR_PARAM);
590 if ( *s_path->m_name == '\0' ) {
591 return( AFPERR_BADTYPE );
594 upath = s_path->u_name;
596 /* if upath is deleted we already in trouble anyway */
597 if ((of = of_findname(s_path))) {
600 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
604 /* on a hard create, fail if file exists and is open */
607 openf = O_RDWR|O_CREAT|O_TRUNC;
609 /* on a soft create, if the file is open then ad_open won't fail
610 because open syscall is not called
615 openf = O_RDWR|O_CREAT|O_EXCL;
618 if ( ad_open( upath, ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF|ADFLAGS_CREATE,
619 openf, 0666, adp) < 0 ) {
623 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
624 return ( AFPERR_NOOBJ );
626 return( AFPERR_EXIST );
628 return( AFPERR_ACCESS );
631 return( AFPERR_DFULL );
633 return( AFPERR_PARAM );
636 if ( ad_reso_fileno( adp ) == -1 ) { /* Hard META / HF */
637 /* on noadouble volumes, just creating the data fork is ok */
638 if (vol_noadouble(vol)) {
639 ad_close( adp, ADFLAGS_DF );
640 goto createfile_done;
642 /* FIXME with hard create on an existing file, we already
643 * corrupted the data file.
645 netatalk_unlink( upath );
646 ad_close( adp, ADFLAGS_DF );
647 return AFPERR_ACCESS;
650 path = s_path->m_name;
651 ad_setname(adp, path);
653 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
659 if (vol->v_flags & AFPVOL_DROPBOX) {
660 retvalue = matchfile2dirperms(upath, vol, did);
662 #endif /* DROPKLUDGE */
664 setvoltime(obj, vol );
669 int afp_setfilparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
675 u_int16_t vid, bitmap;
680 memcpy(&vid, ibuf, sizeof( vid ));
681 ibuf += sizeof( vid );
682 if (NULL == ( vol = getvolbyvid( vid )) ) {
683 return( AFPERR_PARAM );
686 if (vol->v_flags & AFPVOL_RO)
689 memcpy(&did, ibuf, sizeof( did ));
690 ibuf += sizeof( did );
691 if (NULL == ( dir = dirlookup( vol, did )) ) {
692 return afp_errno; /* was AFPERR_NOOBJ */
695 memcpy(&bitmap, ibuf, sizeof( bitmap ));
696 bitmap = ntohs( bitmap );
697 ibuf += sizeof( bitmap );
699 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
700 return get_afp_errno(AFPERR_PARAM);
703 if (path_isadir(s_path)) {
704 return( AFPERR_BADTYPE ); /* it's a directory */
707 if ( s_path->st_errno != 0 ) {
708 return( AFPERR_NOOBJ );
711 if ((u_long)ibuf & 1 ) {
715 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
716 setvoltime(obj, vol );
723 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
726 extern struct path Cur_Path;
728 int setfilparams(struct vol *vol,
729 struct path *path, u_int16_t f_bitmap, char *buf )
731 struct adouble ad, *adp;
733 int bit, isad = 1, err = AFP_OK;
735 u_char achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
736 u_int16_t ashort, bshort, oshort;
739 u_int16_t upriv_bit = 0;
743 int change_mdate = 0;
744 int change_parent_mdate = 0;
749 u_int16_t bitmap = f_bitmap;
750 u_int32_t cdate,bdate;
751 u_char finder_buf[32];
754 LOG(log_debug9, logtype_afpd, "begin setfilparams:");
757 adp = of_ad(vol, path, &ad);
758 upath = path->u_name;
760 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
761 return AFPERR_ACCESS;
764 /* with unix priv maybe we have to change adouble file priv first */
766 while ( bitmap != 0 ) {
767 while (( bitmap & 1 ) == 0 ) {
774 memcpy(&ashort, buf, sizeof( ashort ));
775 buf += sizeof( ashort );
779 memcpy(&cdate, buf, sizeof(cdate));
780 buf += sizeof( cdate );
783 memcpy(&newdate, buf, sizeof( newdate ));
784 buf += sizeof( newdate );
788 memcpy(&bdate, buf, sizeof( bdate));
789 buf += sizeof( bdate );
793 memcpy(finder_buf, buf, 32 );
796 case FILPBIT_UNIXPR :
797 if (!vol_unix_priv(vol)) {
798 /* this volume doesn't use unix priv */
804 change_parent_mdate = 1;
806 memcpy( &aint, buf, sizeof( aint ));
807 f_uid = ntohl (aint);
808 buf += sizeof( aint );
809 memcpy( &aint, buf, sizeof( aint ));
810 f_gid = ntohl (aint);
811 buf += sizeof( aint );
812 setfilowner(vol, f_uid, f_gid, path);
814 memcpy( &upriv, buf, sizeof( upriv ));
815 buf += sizeof( upriv );
816 upriv = ntohl (upriv);
817 if ((upriv & S_IWUSR)) {
818 setfilunixmode(vol, path, upriv);
825 case FILPBIT_PDINFO :
826 if (afp_version < 30) { /* else it's UTF8 name */
829 /* Keep special case to support crlf translations */
830 if ((unsigned int) achar == 0x04) {
831 fdType = (u_char *)"TEXT";
834 xyy[0] = ( u_char ) 'p';
845 /* break while loop */
854 /* second try with adouble open
856 if ( ad_open_metadata( upath, 0, O_CREAT, adp) < 0) {
857 LOG(log_debug, logtype_afpd, "setfilparams: ad_open_metadata error");
859 * For some things, we don't need an adouble header:
860 * - change of modification date
861 * - UNIX privs (Bug-ID #2863424)
863 if ( (f_bitmap & ~(1<<FILPBIT_MDATE | 1<<FILPBIT_UNIXPR))) {
864 LOG(log_debug, logtype_afpd, "setfilparams: need adouble access");
865 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
867 LOG(log_debug, logtype_afpd, "setfilparams: no adouble perms, but only FILPBIT_MDATE and/or FILPBIT_UNIXPR");
869 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
870 ad_setname(adp, path->m_name);
875 while ( bitmap != 0 ) {
876 while (( bitmap & 1 ) == 0 ) {
883 ad_getattr(adp, &bshort);
885 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
886 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
890 if ((bshort & htons(ATTRBIT_INVISIBLE)) != (oshort & htons(ATTRBIT_INVISIBLE)))
891 change_parent_mdate = 1;
892 ad_setattr(adp, bshort);
895 ad_setdate(adp, AD_DATE_CREATE, cdate);
900 ad_setdate(adp, AD_DATE_BACKUP, bdate);
903 if (default_type( ad_entry( adp, ADEID_FINDERI ))
905 ((em = getextmap( path->m_name )) &&
906 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
907 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
908 || ((em = getdefextmap()) &&
909 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
910 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
912 memcpy(finder_buf, ufinderi, 8 );
914 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
916 case FILPBIT_UNIXPR :
918 setfilunixmode(vol, path, upriv);
921 case FILPBIT_PDINFO :
922 if (afp_version < 30) { /* else it's UTF8 name */
923 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
924 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
930 goto setfilparam_done;
937 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
938 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
942 ad_setdate(adp, AD_DATE_MODIFY, newdate);
943 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
949 ad_close_metadata( adp);
953 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
954 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
955 bitmap = 1<<FILPBIT_MDATE;
956 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
960 LOG(log_debug9, logtype_afpd, "end setfilparams:");
966 * renamefile and copyfile take the old and new unix pathnames
967 * and the new mac name.
969 * src the source path
970 * dst the dest filename in current dir
971 * newname the dest mac name
972 * adp adouble struct of src file, if open, or & zeroed one
975 int renamefile(const struct vol *vol, char *src, char *dst, char *newname, struct adouble *adp)
980 LOG(log_debug9, logtype_afpd, "begin renamefile:");
983 if ( unix_rename( src, dst ) < 0 ) {
986 return( AFPERR_NOOBJ );
989 return( AFPERR_ACCESS );
992 case EXDEV : /* Cross device move -- try copy */
993 /* NOTE: with open file it's an error because after the copy we will
994 * get two files, it's fixable for our process (eg reopen the new file, get the
995 * locks, and so on. But it doesn't solve the case with a second process
997 if (adp->ad_open_forks) {
998 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
999 return AFPERR_OLOCK; /* little lie */
1001 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1002 /* on error copyfile delete dest */
1005 return deletefile(vol, src, 0);
1007 return( AFPERR_PARAM );
1011 if (vol->vfs->vfs_renamefile(vol, src, dst) < 0 ) {
1015 /* try to undo the data fork rename,
1016 * we know we are on the same device
1019 unix_rename( dst, src );
1020 /* return the first error */
1023 return AFPERR_NOOBJ;
1026 return AFPERR_ACCESS ;
1028 return AFPERR_VLOCK;
1030 return AFPERR_PARAM ;
1035 /* don't care if we can't open the newly renamed ressource fork
1037 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1038 ad_setname(adp, newname);
1040 ad_close( adp, ADFLAGS_HF );
1043 LOG(log_debug9, logtype_afpd, "end renamefile:");
1050 convert a Mac long name to an utf8 name,
1052 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1056 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1062 /* ---------------- */
1063 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1070 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1076 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1077 if (afp_version >= 30) {
1078 /* convert it to UTF8
1080 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1)
1084 strncpy( newname, ibuf, plen );
1085 newname[ plen ] = '\0';
1087 if (strlen(newname) != plen) {
1088 /* there's \0 in newname, e.g. it's a pathname not
1096 memcpy(&hint, ibuf, sizeof(hint));
1097 ibuf += sizeof(hint);
1099 memcpy(&len16, ibuf, sizeof(len16));
1100 ibuf += sizeof(len16);
1101 plen = ntohs(len16);
1104 if (plen > AFPOBJ_TMPSIZ) {
1107 strncpy( newname, ibuf, plen );
1108 newname[ plen ] = '\0';
1109 if (strlen(newname) != plen) {
1118 /* -----------------------------------
1120 int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1122 struct vol *s_vol, *d_vol;
1124 char *newname, *p, *upath;
1125 struct path *s_path;
1126 u_int32_t sdid, ddid;
1127 int err, retvalue = AFP_OK;
1128 u_int16_t svid, dvid;
1130 struct adouble ad, *adp;
1136 memcpy(&svid, ibuf, sizeof( svid ));
1137 ibuf += sizeof( svid );
1138 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1139 return( AFPERR_PARAM );
1142 memcpy(&sdid, ibuf, sizeof( sdid ));
1143 ibuf += sizeof( sdid );
1144 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1148 memcpy(&dvid, ibuf, sizeof( dvid ));
1149 ibuf += sizeof( dvid );
1150 memcpy(&ddid, ibuf, sizeof( ddid ));
1151 ibuf += sizeof( ddid );
1153 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1154 return get_afp_errno(AFPERR_PARAM);
1156 if ( path_isadir(s_path) ) {
1157 return( AFPERR_BADTYPE );
1160 /* don't allow copies when the file is open.
1161 * XXX: the spec only calls for read/deny write access.
1162 * however, copyfile doesn't have any of that info,
1163 * and locks need to stay coherent. as a result,
1164 * we just balk if the file is opened already. */
1166 adp = of_ad(s_vol, s_path, &ad);
1168 if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1169 return AFPERR_DENYCONF;
1171 denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
1172 getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1173 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1175 return AFPERR_DENYCONF;
1178 newname = obj->newtmp;
1179 strcpy( newname, s_path->m_name );
1181 p = ctoupath( s_vol, curdir, newname );
1183 return AFPERR_PARAM;
1187 /* FIXME svid != dvid && dvid's user can't read svid */
1189 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1190 return( AFPERR_PARAM );
1193 if (d_vol->v_flags & AFPVOL_RO)
1194 return AFPERR_VLOCK;
1196 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1200 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1201 return get_afp_errno(AFPERR_NOOBJ);
1203 if ( *s_path->m_name != '\0' ) {
1204 path_error(s_path, AFPERR_PARAM);
1207 /* one of the handful of places that knows about the path type */
1208 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1209 return( AFPERR_PARAM );
1211 /* newname is always only a filename so curdir *is* its
1214 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1215 return( AFPERR_PARAM );
1217 if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1223 if (vol->v_flags & AFPVOL_DROPBOX) {
1224 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1226 #endif /* DROPKLUDGE */
1228 setvoltime(obj, d_vol );
1233 /* ----------------------- */
1234 static int copy_all(const int dfd, const void *buf,
1240 LOG(log_debug9, logtype_afpd, "begin copy_all:");
1243 while (buflen > 0) {
1244 if ((cc = write(dfd, buf, buflen)) < 0) {
1256 LOG(log_debug9, logtype_afpd, "end copy_all:");
1262 /* --------------------------
1263 * copy only the fork data stream
1265 static int copy_fork(int eid, struct adouble *add, struct adouble *ads)
1272 if (eid == ADEID_DFORK) {
1273 sfd = ad_data_fileno(ads);
1274 dfd = ad_data_fileno(add);
1277 sfd = ad_reso_fileno(ads);
1278 dfd = ad_reso_fileno(add);
1281 if ((off_t)-1 == lseek(sfd, ad_getentryoff(ads, eid), SEEK_SET))
1284 if ((off_t)-1 == lseek(dfd, ad_getentryoff(add, eid), SEEK_SET))
1287 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1288 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1292 #define BUF 128*1024*1024
1294 if (fstat(sfd, &st) == 0) {
1297 if ( offset >= st.st_size) {
1300 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1301 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1304 case EINVAL: /* there's no guarantee that all fs support sendfile */
1313 lseek(sfd, offset, SEEK_SET);
1317 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1324 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1331 /* ----------------------------------
1332 * if newname is NULL (from directory.c) we don't want to copy the resource fork.
1333 * because we are doing it elsewhere.
1334 * currently if newname is NULL then adp is NULL.
1336 int copyfile(const struct vol *s_vol, const struct vol*d_vol,
1337 char *src, char *dst, char *newname, struct adouble *adp)
1339 struct adouble ads, add;
1347 LOG(log_debug9, logtype_afpd, "begin copyfile:");
1351 ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options);
1354 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1355 adflags = ADFLAGS_DF;
1357 adflags |= ADFLAGS_HF;
1360 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1365 if (ad_meta_fileno(adp) == -1 && ad_reso_fileno(adp) == -1) { /* META / HF */
1366 /* no resource fork, don't create one for dst file */
1367 adflags &= ~ADFLAGS_HF;
1370 stat_result = fstat(ad_data_fileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */
1372 if (stat_result < 0) {
1373 /* unlikely but if fstat fails, the default file mode will be 0666. */
1374 st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
1377 if (ad_open(dst , adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
1379 ad_close( adp, adflags );
1380 if (EEXIST != ret_err) {
1381 deletefile(d_vol, dst, 0);
1384 return AFPERR_EXIST;
1388 * XXX if the source and the dest don't use the same resource type it's broken
1390 if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){
1391 /* copy the data fork */
1392 if ((err = copy_fork(ADEID_DFORK, &add, adp)) == 0) {
1393 err = d_vol->vfs->vfs_copyfile(d_vol, src, dst);
1401 if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
1402 /* set the new name in the resource fork */
1403 ad_copy_header(&add, adp);
1404 ad_setname(&add, newname);
1407 ad_close( adp, adflags );
1409 if (ad_close( &add, adflags ) <0) {
1414 deletefile(d_vol, dst, 0);
1416 else if (stat_result == 0) {
1417 /* set dest modification date to src date */
1420 ut.actime = ut.modtime = st.st_mtime;
1422 /* FIXME netatalk doesn't use resource fork file date
1423 * but maybe we should set its modtime too.
1428 LOG(log_debug9, logtype_afpd, "end copyfile:");
1432 switch ( ret_err ) {
1438 return AFPERR_DFULL;
1440 return AFPERR_NOOBJ;
1442 return AFPERR_ACCESS;
1444 return AFPERR_VLOCK;
1446 return AFPERR_PARAM;
1450 /* -----------------------------------
1451 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1452 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1454 when deletefile is called we don't have lock on it, file is closed (for us)
1455 untrue if called by renamefile
1457 ad_open always try to open file RDWR first and ad_lock takes care of
1458 WRITE lock on read only file.
1461 static int check_attrib(struct adouble *adp)
1463 u_int16_t bshort = 0;
1465 ad_getattr(adp, &bshort);
1467 * Does kFPDeleteInhibitBit (bit 8) set?
1469 if ((bshort & htons(ATTRBIT_NODELETE))) {
1470 return AFPERR_OLOCK;
1472 if ((bshort & htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN))) {
1478 int deletefile(const struct vol *vol, char *file, int checkAttrib)
1481 struct adouble *adp = &ad;
1482 int adflags, err = AFP_OK;
1485 LOG(log_debug9, logtype_afpd, "begin deletefile:");
1488 /* try to open both forks at once */
1489 adflags = ADFLAGS_DF|ADFLAGS_HF;
1491 /* was EACCESS error try to get only metadata */
1492 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1493 /* we never want to create a resource fork here, we are going to delete it
1494 * moreover sometimes deletefile is called with a no existent file and
1495 * ad_open would create a 0 byte resource fork
1497 if ( ad_metadata( file, ADFLAGS_OPENFORKS, &ad) == 0 ) {
1498 ad_close( &ad, adflags );
1499 if ((err = check_attrib(&ad))) {
1506 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1507 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1510 if (adflags == ADFLAGS_DF)
1511 return AFPERR_NOOBJ;
1513 /* that failed. now try to open just the data fork */
1514 adflags = ADFLAGS_DF;
1518 adp = NULL; /* maybe it's a file with no write mode for us */
1519 break; /* was return AFPERR_ACCESS;*/
1521 return AFPERR_VLOCK;
1523 return( AFPERR_PARAM );
1526 break; /* from the while */
1529 if (adp && (adflags & ADFLAGS_HF) ) {
1530 /* FIXME we have a pb here because we want to know if a file is open
1531 * there's a 'priority inversion' if you can't open the ressource fork RW
1532 * you can delete it if it's open because you can't get a write lock.
1534 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1537 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1539 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1540 ad_close( &ad, adflags );
1541 return( AFPERR_BUSY );
1545 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1548 else if (!(err = vol->vfs->vfs_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
1550 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1552 cnid_delete(vol->v_cdb, id);
1556 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1559 LOG(log_debug9, logtype_afpd, "end deletefile:");
1565 /* ------------------------------------ */
1566 /* return a file id */
1567 int afp_createid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1576 struct path *s_path;
1582 memcpy(&vid, ibuf, sizeof(vid));
1583 ibuf += sizeof(vid);
1585 if (NULL == ( vol = getvolbyvid( vid )) ) {
1586 return( AFPERR_PARAM);
1589 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1593 if (vol->v_flags & AFPVOL_RO)
1594 return AFPERR_VLOCK;
1596 memcpy(&did, ibuf, sizeof( did ));
1597 ibuf += sizeof(did);
1599 if (NULL == ( dir = dirlookup( vol, did )) ) {
1600 return afp_errno; /* was AFPERR_PARAM */
1603 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1604 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1607 if ( path_isadir(s_path) ) {
1608 return( AFPERR_BADTYPE );
1611 upath = s_path->u_name;
1612 switch (s_path->st_errno) {
1614 break; /* success */
1617 return AFPERR_ACCESS;
1619 return AFPERR_NOOBJ;
1621 return AFPERR_PARAM;
1624 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1625 memcpy(rbuf, &id, sizeof(id));
1626 *rbuflen = sizeof(id);
1627 return AFPERR_EXISTID;
1630 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1631 memcpy(rbuf, &id, sizeof(id));
1632 *rbuflen = sizeof(id);
1639 /* ------------------------------- */
1645 static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
1648 struct reenum *param = data;
1649 struct vol *vol = param->vol;
1650 cnid_t did = param->did;
1653 if ( stat(de->d_name, &path.st)<0 )
1656 /* update or add to cnid */
1657 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1659 #if AD_VERSION > AD_VERSION1
1660 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1661 struct adouble ad, *adp;
1665 path.u_name = de->d_name;
1667 adp = of_ad(vol, &path, &ad);
1669 if ( ad_open_metadata( de->d_name, 0, 0, adp ) < 0 ) {
1672 if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1675 ad_close_metadata(adp);
1677 #endif /* AD_VERSION > AD_VERSION1 */
1682 /* --------------------
1683 * Ok the db is out of synch with the dir.
1684 * but if it's a deleted file we don't want to do it again and again.
1687 reenumerate_id(struct vol *vol, char *name, struct dir *dir)
1693 if (vol->v_cdb == NULL) {
1697 /* FIXME use of_statdir ? */
1698 if (stat(name, &st)) {
1702 if (dirreenumerate(dir, &st)) {
1703 /* we already did it once and the dir haven't been modified */
1708 data.did = dir->d_did;
1709 if ((ret = for_each_dirent(vol, name, reenumerate_loop, (void *)&data)) >= 0) {
1710 setdiroffcnt(curdir, &st, ret);
1711 dir->d_flags |= DIRF_CNID;
1717 /* ------------------------------
1718 resolve a file id */
1719 int afp_resolveid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1728 u_int16_t vid, bitmap;
1730 static char buffer[12 + MAXPATHLEN + 1];
1731 int len = 12 + MAXPATHLEN + 1;
1736 memcpy(&vid, ibuf, sizeof(vid));
1737 ibuf += sizeof(vid);
1739 if (NULL == ( vol = getvolbyvid( vid )) ) {
1740 return( AFPERR_PARAM);
1743 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1747 memcpy(&id, ibuf, sizeof( id ));
1752 /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
1756 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1757 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1760 if (NULL == ( dir = dirlookup( vol, id )) ) {
1761 return AFPERR_NOID; /* idem AFPERR_PARAM */
1763 if (movecwd(vol, dir) < 0) {
1767 return AFPERR_ACCESS;
1771 return AFPERR_PARAM;
1775 memset(&path, 0, sizeof(path));
1776 path.u_name = upath;
1777 if ( of_stat(&path) < 0 ) {
1779 /* with nfs and our working directory is deleted */
1780 if (errno == ESTALE) {
1784 if ( errno == ENOENT && !retry) {
1785 /* cnid db is out of sync, reenumerate the directory and update ids */
1786 reenumerate_id(vol, ".", dir);
1794 return AFPERR_ACCESS;
1798 return AFPERR_PARAM;
1802 /* directories are bad */
1803 if (S_ISDIR(path.st.st_mode)) {
1804 /* OS9 and OSX don't return the same error code */
1805 return (afp_version >=30)?AFPERR_NOID:AFPERR_BADTYPE;
1808 memcpy(&bitmap, ibuf, sizeof(bitmap));
1809 bitmap = ntohs( bitmap );
1810 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1814 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1815 rbuf + sizeof(bitmap), &buflen))) {
1818 *rbuflen = buflen + sizeof(bitmap);
1819 memcpy(rbuf, ibuf, sizeof(bitmap));
1824 /* ------------------------------ */
1825 int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1835 static char buffer[12 + MAXPATHLEN + 1];
1836 int len = 12 + MAXPATHLEN + 1;
1841 memcpy(&vid, ibuf, sizeof(vid));
1842 ibuf += sizeof(vid);
1844 if (NULL == ( vol = getvolbyvid( vid )) ) {
1845 return( AFPERR_PARAM);
1848 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1852 if (vol->v_flags & AFPVOL_RO)
1853 return AFPERR_VLOCK;
1855 memcpy(&id, ibuf, sizeof( id ));
1859 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1863 if (NULL == ( dir = dirlookup( vol, id )) ) {
1864 if (afp_errno == AFPERR_NOOBJ) {
1868 return( AFPERR_PARAM );
1872 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1876 return AFPERR_ACCESS;
1881 /* still try to delete the id */
1885 return AFPERR_PARAM;
1888 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1889 return AFPERR_BADTYPE;
1892 if (cnid_delete(vol->v_cdb, fileid)) {
1895 return AFPERR_VLOCK;
1898 return AFPERR_ACCESS;
1900 return AFPERR_PARAM;
1907 /* ------------------------------ */
1908 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1912 if (path->st_errno) {
1913 switch (path->st_errno) {
1915 afp_errno = AFPERR_NOID;
1919 afp_errno = AFPERR_ACCESS;
1922 afp_errno = AFPERR_PARAM;
1927 /* we use file_access both for legacy Mac perm and
1928 * for unix privilege, rename will take care of folder perms
1930 if (file_access(path, OPENACC_WR ) < 0) {
1931 afp_errno = AFPERR_ACCESS;
1935 if ((*of = of_findname(path))) {
1936 /* reuse struct adouble so it won't break locks */
1940 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
1942 if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
1944 * The user must have the Read & Write privilege for both files in order to use this command.
1946 ad_close(adp, ADFLAGS_HF);
1947 afp_errno = AFPERR_ACCESS;
1954 #define APPLETEMP ".AppleTempXXXXXX"
1956 int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1958 struct stat srcst, destst;
1960 struct dir *dir, *sdir;
1961 char *spath, temp[17], *p;
1962 char *supath, *upath;
1967 struct adouble *adsp = NULL;
1968 struct adouble *addp = NULL;
1969 struct ofork *s_of = NULL;
1970 struct ofork *d_of = NULL;
1983 memcpy(&vid, ibuf, sizeof(vid));
1984 ibuf += sizeof(vid);
1986 if (NULL == ( vol = getvolbyvid( vid )) ) {
1987 return( AFPERR_PARAM);
1990 if ((vol->v_flags & AFPVOL_RO))
1991 return AFPERR_VLOCK;
1993 /* source and destination dids */
1994 memcpy(&sid, ibuf, sizeof(sid));
1995 ibuf += sizeof(sid);
1996 memcpy(&did, ibuf, sizeof(did));
1997 ibuf += sizeof(did);
2000 if (NULL == (dir = dirlookup( vol, sid )) ) {
2001 return afp_errno; /* was AFPERR_PARAM */
2004 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2005 return get_afp_errno(AFPERR_NOOBJ);
2008 if ( path_isadir(path) ) {
2009 return AFPERR_BADTYPE; /* it's a dir */
2012 /* save some stuff */
2015 spath = obj->oldtmp;
2016 supath = obj->newtmp;
2017 strcpy(spath, path->m_name);
2018 strcpy(supath, path->u_name); /* this is for the cnid changing */
2019 p = absupath( vol, sdir, supath);
2021 /* pathname too long */
2022 return AFPERR_PARAM ;
2025 ad_init(&ads, vol->v_adouble, vol->v_ad_options);
2026 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2030 /* ***** from here we may have resource fork open **** */
2032 /* look for the source cnid. if it doesn't exist, don't worry about
2034 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2036 if (NULL == ( dir = dirlookup( vol, did )) ) {
2037 err = afp_errno; /* was AFPERR_PARAM */
2038 goto err_exchangefile;
2041 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2042 err = get_afp_errno(AFPERR_NOOBJ);
2043 goto err_exchangefile;
2046 if ( path_isadir(path) ) {
2047 err = AFPERR_BADTYPE;
2048 goto err_exchangefile;
2051 /* FPExchangeFiles is the only call that can return the SameObj
2053 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2054 err = AFPERR_SAMEOBJ;
2055 goto err_exchangefile;
2058 ad_init(&add, vol->v_adouble, vol->v_ad_options);
2059 if (!(addp = find_adouble( path, &d_of, &add))) {
2061 goto err_exchangefile;
2065 /* they are not on the same device and at least one is open
2066 * FIXME broken for for crossdev and adouble v2
2069 crossdev = (srcst.st_dev != destst.st_dev);
2070 if (/* (d_of || s_of) && */ crossdev) {
2072 goto err_exchangefile;
2075 /* look for destination id. */
2076 upath = path->u_name;
2077 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2079 /* construct a temp name.
2080 * NOTE: the temp file will be in the dest file's directory. it
2081 * will also be inaccessible from AFP. */
2082 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2083 if (!mktemp(temp)) {
2085 goto err_exchangefile;
2089 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2090 ad_close(adsp, ADFLAGS_HF);
2091 ad_close(addp, ADFLAGS_HF);
2094 /* now, quickly rename the file. we error if we can't. */
2095 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2096 goto err_exchangefile;
2097 of_rename(vol, s_of, sdir, spath, curdir, temp);
2099 /* rename destination to source */
2100 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2101 goto err_src_to_tmp;
2102 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2104 /* rename temp to destination */
2105 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2106 goto err_dest_to_src;
2107 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2109 /* id's need switching. src -> dest and dest -> src.
2110 * we need to re-stat() if it was a cross device copy.
2113 cnid_delete(vol->v_cdb, sid);
2116 cnid_delete(vol->v_cdb, did);
2118 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2119 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2121 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2122 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2127 err = AFPERR_ACCESS;
2132 goto err_temp_to_dest;
2135 /* here we need to reopen if crossdev */
2136 if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2141 if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2146 /* change perms, src gets dest perm and vice versa */
2151 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2152 err = AFP_OK; /* ignore error */
2153 goto err_temp_to_dest;
2157 * we need to exchange ACL entries as well
2159 /* exchange_acls(vol, p, upath); */
2164 path->m_name = NULL;
2165 path->u_name = upath;
2167 setfilunixmode(vol, path, destst.st_mode);
2168 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2175 setfilunixmode(vol, path, srcst.st_mode);
2176 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2178 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2179 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2184 goto err_exchangefile;
2186 /* all this stuff is so that we can unwind a failed operation
2189 /* rename dest to temp */
2190 renamefile(vol, upath, temp, temp, adsp);
2191 of_rename(vol, s_of, curdir, upath, curdir, temp);
2194 /* rename source back to dest */
2195 renamefile(vol, p, upath, path->m_name, addp);
2196 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2199 /* rename temp back to source */
2200 renamefile(vol, temp, p, spath, adsp);
2201 of_rename(vol, s_of, curdir, temp, sdir, spath);
2204 if ( !s_of && adsp && ad_meta_fileno(adsp) != -1 ) { /* META */
2205 ad_close(adsp, ADFLAGS_HF);
2207 if ( !d_of && addp && ad_meta_fileno(addp) != -1 ) {/* META */
2208 ad_close(addp, ADFLAGS_HF);