2 * $Id: file.c,v 1.92.2.2.2.31.2.3 2004-10-30 21:43:46 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 */
31 #include <atalk/adouble.h>
36 #include <atalk/logger.h>
37 #include <sys/param.h>
40 #include <atalk/afp.h>
41 #include <atalk/util.h>
42 #include <atalk/cnid.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[] = {
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 /* FIXME mpath : unix or mac name ? (for now it's mac name ) */
79 void *get_finderinfo(const char *mpath, struct adouble *adp, void *data)
82 void *ad_finder = NULL;
86 ad_finder = ad_entry(adp, ADEID_FINDERI);
88 if ((ad_finder != NULL)) {
89 memcpy(data, ad_finder, 32);
91 if (!memcmp(ad_finder, ufinderi, 8))
95 memcpy(data, ufinderi, 32);
98 /** Only enter if no appledouble information and no finder information found. */
99 if (chk_ext && (em = getextmap( mpath ))) {
100 memcpy(data, em->em_type, sizeof( em->em_type ));
101 memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator));
106 /* ---------------------
108 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8)
113 aint = strlen( name );
117 if (utf8_encoding()) {
118 /* but name is an utf8 mac name */
121 /* global static variable... */
123 if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
132 if (aint > MACFILELEN)
139 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
142 utf8 = vol->v_mac?htonl(vol->v_mac->kTextEncoding):0; /* htonl(utf8) */
143 memcpy(data, &utf8, sizeof(utf8));
144 data += sizeof(utf8);
147 memcpy(data, &temp, sizeof(temp));
148 data += sizeof(temp);
151 memcpy( data, src, aint );
161 * FIXME: PDINFO is UTF8 and doesn't need adp
163 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
164 (1 << FILPBIT_CDATE) |\
165 (1 << FILPBIT_MDATE) |\
166 (1 << FILPBIT_BDATE) |\
167 (1 << FILPBIT_FINFO) |\
168 (1 << FILPBIT_RFLEN) |\
169 (1 << FILPBIT_EXTRFLEN) |\
170 (1 << FILPBIT_PDINFO)))
172 /* -------------------------- */
173 u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st,
174 const cnid_t did, const char *upath, const int len)
178 #if AD_VERSION > AD_VERSION1
182 char stamp[ADEDLEN_PRIVSYN];
183 /* look in AD v2 header
184 * note inode and device are opaques and not in network order
187 && sizeof(dev_t) == ad_getentrylen(adp, ADEID_PRIVDEV)
188 && sizeof(ino_t) == ad_getentrylen(adp,ADEID_PRIVINO)
189 && sizeof(stamp) == ad_getentrylen(adp,ADEID_PRIVSYN)
190 && sizeof(cnid_t) == ad_getentrylen(adp, ADEID_DID)
191 && sizeof(cnid_t) == ad_getentrylen(adp, ADEID_PRIVID)
194 memcpy(&dev, ad_entry(adp, ADEID_PRIVDEV), sizeof(dev_t));
195 memcpy(&ino, ad_entry(adp, ADEID_PRIVINO), sizeof(ino_t));
196 memcpy(stamp, ad_entry(adp, ADEID_PRIVSYN), sizeof(stamp));
197 memcpy(&a_did, ad_entry(adp, ADEID_DID), sizeof(cnid_t));
199 if ( ( (vol->v_flags & AFPVOL_NODEV) || dev == st->st_dev)
200 && ino == st->st_ino && a_did == did
201 && !memcmp(vol->v_stamp, stamp, sizeof(stamp))) {
202 memcpy(&aint, ad_entry(adp, ADEID_PRIVID), sizeof(aint));
207 if (vol->v_cdb != NULL) {
208 aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
209 /* Throw errors if cnid_add fails. */
210 if (aint == CNID_INVALID) {
212 case CNID_ERR_CLOSE: /* the db is closed */
215 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
216 afp_errno = AFPERR_PARAM;
219 afp_errno = AFPERR_PARAM;
222 afp_errno = AFPERR_MISC;
226 #if AD_VERSION > AD_VERSION1
228 /* update the ressource fork
229 * for a folder adp is always null
231 if (ad_setid(adp,(vol->v_flags & AFPVOL_NODEV)?0:st->st_dev, st->st_ino, aint, did, vol->v_stamp)) {
232 ad_flush(adp, ADFLAGS_HF);
240 /* -------------------------- */
241 int getmetadata(struct vol *vol,
243 struct path *path, struct dir *dir,
244 char *buf, int *buflen, struct adouble *adp, int attrbits )
246 char *data, *l_nameoff = NULL, *upath;
247 char *utf_nameoff = NULL;
252 u_char achar, fdType[4];
258 LOG(log_info, logtype_afpd, "begin getmetadata:");
261 upath = path->u_name;
266 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
267 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
268 || (bitmap & (1 << FILPBIT_FNUM))) {
270 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
274 path->m_name = utompath(vol, upath, id, utf8_encoding());
277 while ( bitmap != 0 ) {
278 while (( bitmap & 1 ) == 0 ) {
286 ad_getattr(adp, &ashort);
287 } else if (*upath == '.') {
288 ashort = htons(ATTRBIT_INVISIBLE);
292 /* FIXME do we want a visual clue if the file is read only
295 accessmode( ".", &ma, dir , NULL);
296 if ((ma.ma_user & AR_UWRITE)) {
297 accessmode( upath, &ma, dir , st);
298 if (!(ma.ma_user & AR_UWRITE)) {
299 attrbits |= ATTRBIT_NOWRITE;
304 ashort = htons(ntohs(ashort) | attrbits);
305 memcpy(data, &ashort, sizeof( ashort ));
306 data += sizeof( ashort );
310 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
311 data += sizeof( u_int32_t );
315 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
316 aint = AD_DATE_FROM_UNIX(st->st_mtime);
317 memcpy(data, &aint, sizeof( aint ));
318 data += sizeof( aint );
322 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
323 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
324 aint = AD_DATE_FROM_UNIX(st->st_mtime);
327 aint = AD_DATE_FROM_UNIX(st->st_mtime);
329 memcpy(data, &aint, sizeof( int ));
330 data += sizeof( int );
334 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
335 aint = AD_DATE_START;
336 memcpy(data, &aint, sizeof( int ));
337 data += sizeof( int );
341 get_finderinfo(path->m_name, adp, (char *)data);
343 if (*upath == '.') { /* make it invisible */
344 ashort = htons(FINDERINFO_INVISIBLE);
345 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
353 data += sizeof( u_int16_t );
357 memset(data, 0, sizeof(u_int16_t));
358 data += sizeof( u_int16_t );
362 memcpy(data, &id, sizeof( id ));
363 data += sizeof( id );
367 if (st->st_size > 0xffffffff)
370 aint = htonl( st->st_size );
371 memcpy(data, &aint, sizeof( aint ));
372 data += sizeof( aint );
377 if (adp->ad_rlen > 0xffffffff)
380 aint = htonl( adp->ad_rlen);
384 memcpy(data, &aint, sizeof( aint ));
385 data += sizeof( aint );
388 /* Current client needs ProDOS info block for this file.
389 Use simple heuristic and let the Mac "type" string tell
390 us what the PD file code should be. Everything gets a
391 subtype of 0x0000 unless the original value was hashed
392 to "pXYZ" when we created it. See IA, Ver 2.
393 <shirsch@adelphia.net> */
394 case FILPBIT_PDINFO :
395 if (afp_version >= 30) { /* UTF8 name */
396 utf8 = kTextEncodingUTF8;
398 data += sizeof( u_int16_t );
400 memcpy(data, &aint, sizeof( aint ));
401 data += sizeof( aint );
405 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
407 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
411 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
415 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
419 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
423 else if ( fdType[0] == 'p' ) {
425 ashort = (fdType[2] * 256) + fdType[3];
439 memcpy(data, &ashort, sizeof( ashort ));
440 data += sizeof( ashort );
441 memset(data, 0, sizeof( ashort ));
442 data += sizeof( ashort );
445 case FILPBIT_EXTDFLEN:
446 aint = htonl(st->st_size >> 32);
447 memcpy(data, &aint, sizeof( aint ));
448 data += sizeof( aint );
449 aint = htonl(st->st_size);
450 memcpy(data, &aint, sizeof( aint ));
451 data += sizeof( aint );
453 case FILPBIT_EXTRFLEN:
456 aint = htonl(adp->ad_rlen >> 32);
457 memcpy(data, &aint, sizeof( aint ));
458 data += sizeof( aint );
460 aint = htonl(adp->ad_rlen);
461 memcpy(data, &aint, sizeof( aint ));
462 data += sizeof( aint );
464 case FILPBIT_UNIXPR :
465 /* accessmode may change st_mode with ACLs */
466 accessmode( upath, &ma, dir , st);
468 aint = htonl(st->st_uid);
469 memcpy( data, &aint, sizeof( aint ));
470 data += sizeof( aint );
471 aint = htonl(st->st_gid);
472 memcpy( data, &aint, sizeof( aint ));
473 data += sizeof( aint );
475 aint = htonl(st->st_mode);
476 memcpy( data, &aint, sizeof( aint ));
477 data += sizeof( aint );
479 *data++ = ma.ma_user;
480 *data++ = ma.ma_world;
481 *data++ = ma.ma_group;
482 *data++ = ma.ma_owner;
486 return( AFPERR_BITMAP );
492 ashort = htons( data - buf );
493 memcpy(l_nameoff, &ashort, sizeof( ashort ));
494 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
497 ashort = htons( data - buf );
498 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
499 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
501 *buflen = data - buf;
505 /* ----------------------- */
506 int getfilparams(struct vol *vol,
508 struct path *path, struct dir *dir,
509 char *buf, int *buflen )
511 struct adouble ad, *adp;
514 u_int16_t attrbits = 0;
519 LOG(log_info, logtype_default, "begin getfilparams:");
522 opened = PARAM_NEED_ADP(bitmap);
525 upath = path->u_name;
526 if ((of = of_findname(path))) {
528 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
529 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
531 ad_init(&ad, vol->v_adouble);
535 if ( ad_metadata( upath, 0, adp) < 0 ) {
538 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
539 upath, strerror(errno));
540 return AFPERR_ACCESS;
542 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
552 we need to check if the file is open by another process.
553 it's slow so we only do it if we have to:
554 - bitmap is requested.
555 - we don't already have the answer!
557 if ((bitmap & (1 << FILPBIT_ATTR))) {
558 if (!(attrbits & ATTRBIT_ROPEN)) {
559 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_ROPEN : 0;
560 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_ROPEN : 0;
562 if (!(attrbits & ATTRBIT_DOPEN)) {
563 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_DOPEN : 0;
564 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_DOPEN : 0;
569 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
571 ad_close( adp, ADFLAGS_HF );
574 LOG(log_info, logtype_afpd, "end getfilparams:");
580 /* ----------------------------- */
581 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
584 int ibuflen, *rbuflen;
586 struct adouble ad, *adp;
589 struct ofork *of = NULL;
591 int creatf, did, openf, retvalue = AFP_OK;
597 LOG(log_info, logtype_afpd, "begin afp_createfile:");
602 creatf = (unsigned char) *ibuf++;
604 memcpy(&vid, ibuf, sizeof( vid ));
605 ibuf += sizeof( vid );
607 if (NULL == ( vol = getvolbyvid( vid )) ) {
608 return( AFPERR_PARAM );
611 if (vol->v_flags & AFPVOL_RO)
614 memcpy(&did, ibuf, sizeof( did));
615 ibuf += sizeof( did );
617 if (NULL == ( dir = dirlookup( vol, did )) ) {
621 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
622 return get_afp_errno(AFPERR_PARAM);
625 if ( *s_path->m_name == '\0' ) {
626 return( AFPERR_BADTYPE );
629 upath = s_path->u_name;
630 if (0 != (ret = check_name(vol, upath)))
633 /* if upath is deleted we already in trouble anyway */
634 if ((of = of_findname(s_path))) {
637 ad_init(&ad, vol->v_adouble);
641 /* on a hard create, fail if file exists and is open */
644 openf = O_RDWR|O_CREAT|O_TRUNC;
646 /* on a soft create, if the file is open then ad_open won't fail
647 because open syscall is not called
652 openf = O_RDWR|O_CREAT|O_EXCL;
655 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
656 openf, 0666, adp) < 0 ) {
660 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
661 return ( AFPERR_NOOBJ );
663 return( AFPERR_EXIST );
665 return( AFPERR_ACCESS );
667 return( AFPERR_PARAM );
670 if ( ad_hfileno( adp ) == -1 ) {
671 /* on noadouble volumes, just creating the data fork is ok */
672 if (vol_noadouble(vol)) {
673 ad_close( adp, ADFLAGS_DF );
674 goto createfile_done;
676 /* FIXME with hard create on an existing file, we already
677 * corrupted the data file.
679 netatalk_unlink( upath );
680 ad_close( adp, ADFLAGS_DF );
681 return AFPERR_ACCESS;
684 path = s_path->m_name;
685 ad_setname(adp, path);
686 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
687 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
693 if (vol->v_flags & AFPVOL_DROPBOX) {
694 retvalue = matchfile2dirperms(upath, vol, did);
696 #endif /* DROPKLUDGE */
698 setvoltime(obj, vol );
701 LOG(log_info, logtype_afpd, "end afp_createfile");
707 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
710 int ibuflen, *rbuflen;
716 u_int16_t vid, bitmap;
719 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
725 memcpy(&vid, ibuf, sizeof( vid ));
726 ibuf += sizeof( vid );
727 if (NULL == ( vol = getvolbyvid( vid )) ) {
728 return( AFPERR_PARAM );
731 if (vol->v_flags & AFPVOL_RO)
734 memcpy(&did, ibuf, sizeof( did ));
735 ibuf += sizeof( did );
736 if (NULL == ( dir = dirlookup( vol, did )) ) {
737 return afp_errno; /* was AFPERR_NOOBJ */
740 memcpy(&bitmap, ibuf, sizeof( bitmap ));
741 bitmap = ntohs( bitmap );
742 ibuf += sizeof( bitmap );
744 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
745 return get_afp_errno(AFPERR_PARAM);
748 if (path_isadir(s_path)) {
749 return( AFPERR_BADTYPE ); /* it's a directory */
752 if ( s_path->st_errno != 0 ) {
753 return( AFPERR_NOOBJ );
756 if ((u_long)ibuf & 1 ) {
760 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
761 setvoltime(obj, vol );
765 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
772 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
775 extern struct path Cur_Path;
777 int setfilparams(struct vol *vol,
778 struct path *path, u_int16_t f_bitmap, char *buf )
780 struct adouble ad, *adp;
783 int bit, isad = 1, err = AFP_OK;
785 u_char achar, *fdType, xyy[4];
786 u_int16_t ashort, bshort;
789 u_int16_t upriv_bit = 0;
793 int change_mdate = 0;
794 int change_parent_mdate = 0;
799 u_int16_t bitmap = f_bitmap;
800 u_int32_t cdate,bdate;
801 u_char finder_buf[32];
804 LOG(log_info, logtype_afpd, "begin setfilparams:");
807 upath = path->u_name;
808 if ((of = of_findname(path))) {
811 ad_init(&ad, vol->v_adouble);
815 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
816 return AFPERR_ACCESS;
819 /* with unix priv maybe we have to change adouble file priv first */
821 while ( bitmap != 0 ) {
822 while (( bitmap & 1 ) == 0 ) {
829 memcpy(&ashort, buf, sizeof( ashort ));
830 buf += sizeof( ashort );
834 memcpy(&cdate, buf, sizeof(cdate));
835 buf += sizeof( cdate );
838 memcpy(&newdate, buf, sizeof( newdate ));
839 buf += sizeof( newdate );
843 memcpy(&bdate, buf, sizeof( bdate));
844 buf += sizeof( bdate );
848 memcpy(finder_buf, buf, 32 );
851 case FILPBIT_UNIXPR :
852 if (!vol_unix_priv(vol)) {
853 /* this volume doesn't use unix priv */
859 change_parent_mdate = 1;
861 memcpy( &aint, buf, sizeof( aint ));
862 f_uid = ntohl (aint);
863 buf += sizeof( aint );
864 memcpy( &aint, buf, sizeof( aint ));
865 f_gid = ntohl (aint);
866 buf += sizeof( aint );
867 setfilowner(vol, f_uid, f_gid, path);
869 memcpy( &upriv, buf, sizeof( upriv ));
870 buf += sizeof( upriv );
871 upriv = ntohl (upriv);
872 if ((upriv & S_IWUSR)) {
873 setfilunixmode(vol, path, upriv);
880 case FILPBIT_PDINFO :
881 if (afp_version < 30) { /* else it's UTF8 name */
884 /* Keep special case to support crlf translations */
885 if ((unsigned int) achar == 0x04) {
886 fdType = (u_char *)"TEXT";
889 xyy[0] = ( u_char ) 'p';
900 /* break while loop */
909 /* second try with adouble open
911 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
912 O_RDWR|O_CREAT, 0666, adp) < 0) {
913 /* for some things, we don't need an adouble header */
914 if (f_bitmap & ~(1<<FILPBIT_MDATE)) {
915 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
918 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
919 ad_setname(adp, path->m_name);
924 while ( bitmap != 0 ) {
925 while (( bitmap & 1 ) == 0 ) {
932 ad_getattr(adp, &bshort);
933 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
934 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
935 change_parent_mdate = 1;
936 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
937 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
941 ad_setattr(adp, bshort);
944 ad_setdate(adp, AD_DATE_CREATE, cdate);
949 ad_setdate(adp, AD_DATE_BACKUP, bdate);
952 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
954 ((em = getextmap( path->m_name )) &&
955 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
956 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
957 || ((em = getdefextmap()) &&
958 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
959 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
961 memcpy(finder_buf, ufinderi, 8 );
963 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
965 case FILPBIT_UNIXPR :
967 setfilunixmode(vol, path, upriv);
970 case FILPBIT_PDINFO :
971 if (afp_version < 30) { /* else it's UTF8 name */
972 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
973 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
979 goto setfilparam_done;
986 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
987 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
991 ad_setdate(adp, AD_DATE_MODIFY, newdate);
992 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
997 ad_flush( adp, ADFLAGS_HF );
998 ad_close( adp, ADFLAGS_HF );
1002 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
1003 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
1004 bitmap = 1<<FILPBIT_MDATE;
1005 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
1009 LOG(log_info, logtype_afpd, "end setfilparams:");
1015 * renamefile and copyfile take the old and new unix pathnames
1016 * and the new mac name.
1018 * src the source path
1019 * dst the dest filename in current dir
1020 * newname the dest mac name
1021 * adp adouble struct of src file, if open, or & zeroed one
1024 int renamefile(vol, src, dst, newname, adp )
1025 const struct vol *vol;
1026 char *src, *dst, *newname;
1027 struct adouble *adp;
1029 char adsrc[ MAXPATHLEN + 1];
1033 LOG(log_info, logtype_afpd, "begin renamefile:");
1036 if ( unix_rename( src, dst ) < 0 ) {
1039 return( AFPERR_NOOBJ );
1042 return( AFPERR_ACCESS );
1044 return AFPERR_VLOCK;
1045 case EXDEV : /* Cross device move -- try copy */
1046 /* NOTE: with open file it's an error because after the copy we will
1047 * get two files, it's fixable for our process (eg reopen the new file, get the
1048 * locks, and so on. But it doesn't solve the case with a second process
1050 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
1051 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1052 return AFPERR_OLOCK; /* little lie */
1054 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname )) ) {
1055 /* on error copyfile delete dest */
1058 return deletefile(vol, src, 0);
1060 return( AFPERR_PARAM );
1064 strcpy( adsrc, vol->ad_path( src, 0 ));
1066 if (unix_rename( adsrc, vol->ad_path( dst, 0 )) < 0 ) {
1071 if (errno == ENOENT) {
1074 if (stat(adsrc, &st)) /* source has no ressource fork, */
1077 /* We are here because :
1078 * -there's no dest folder.
1079 * -there's no .AppleDouble in the dest folder.
1080 * if we use the struct adouble passed in parameter it will not
1081 * create .AppleDouble if the file is already opened, so we
1082 * use a diff one, it's not a pb,ie it's not the same file, yet.
1084 ad_init(&ad, vol->v_adouble);
1085 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
1086 ad_close(&ad, ADFLAGS_HF);
1087 if (!unix_rename( adsrc, vol->ad_path( dst, 0 )) )
1092 else { /* it's something else, bail out */
1096 /* try to undo the data fork rename,
1097 * we know we are on the same device
1100 unix_rename( dst, src );
1101 /* return the first error */
1104 return AFPERR_NOOBJ;
1107 return AFPERR_ACCESS ;
1109 return AFPERR_VLOCK;
1111 return AFPERR_PARAM ;
1116 /* don't care if we can't open the newly renamed ressource fork
1118 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1119 ad_setname(adp, newname);
1120 ad_flush( adp, ADFLAGS_HF );
1121 ad_close( adp, ADFLAGS_HF );
1124 LOG(log_info, logtype_afpd, "end renamefile:");
1130 int copy_path_name(char *newname, char *ibuf)
1137 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1143 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1144 strncpy( newname, ibuf, plen );
1145 newname[ plen ] = '\0';
1146 if (strlen(newname) != plen) {
1147 /* there's \0 in newname, e.g. it's a pathname not
1155 memcpy(&hint, ibuf, sizeof(hint));
1156 ibuf += sizeof(hint);
1158 memcpy(&len16, ibuf, sizeof(len16));
1159 ibuf += sizeof(len16);
1160 plen = ntohs(len16);
1163 if (plen > AFPOBJ_TMPSIZ) {
1166 strncpy( newname, ibuf, plen );
1167 newname[ plen ] = '\0';
1168 if (strlen(newname) != plen) {
1177 /* -----------------------------------
1179 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1182 int ibuflen, *rbuflen;
1184 struct vol *s_vol, *d_vol;
1186 char *newname, *p, *upath;
1187 struct path *s_path;
1188 u_int32_t sdid, ddid;
1189 int err, retvalue = AFP_OK;
1190 u_int16_t svid, dvid;
1193 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1199 memcpy(&svid, ibuf, sizeof( svid ));
1200 ibuf += sizeof( svid );
1201 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1202 return( AFPERR_PARAM );
1205 memcpy(&sdid, ibuf, sizeof( sdid ));
1206 ibuf += sizeof( sdid );
1207 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1211 memcpy(&dvid, ibuf, sizeof( dvid ));
1212 ibuf += sizeof( dvid );
1213 memcpy(&ddid, ibuf, sizeof( ddid ));
1214 ibuf += sizeof( ddid );
1216 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1217 return get_afp_errno(AFPERR_PARAM);
1219 if ( path_isadir(s_path) ) {
1220 return( AFPERR_BADTYPE );
1223 /* don't allow copies when the file is open.
1224 * XXX: the spec only calls for read/deny write access.
1225 * however, copyfile doesn't have any of that info,
1226 * and locks need to stay coherent. as a result,
1227 * we just balk if the file is opened already. */
1229 newname = obj->newtmp;
1230 strcpy( newname, s_path->m_name );
1232 if (of_findname(s_path))
1233 return AFPERR_DENYCONF;
1235 p = ctoupath( s_vol, curdir, newname );
1237 return AFPERR_PARAM;
1241 /* FIXME svid != dvid && dvid's user can't read svid */
1243 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1244 return( AFPERR_PARAM );
1247 if (d_vol->v_flags & AFPVOL_RO)
1248 return AFPERR_VLOCK;
1250 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1254 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1255 return get_afp_errno(AFPERR_NOOBJ);
1257 if ( *s_path->m_name != '\0' ) {
1258 path_error(s_path, AFPERR_PARAM);
1261 /* one of the handful of places that knows about the path type */
1262 if (copy_path_name(newname, ibuf) < 0) {
1263 return( AFPERR_PARAM );
1265 /* newname is always only a filename so curdir *is* its
1268 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1269 return( AFPERR_PARAM );
1271 if ( (err = copyfile(s_vol, d_vol, p, upath , newname)) < 0 ) {
1277 if (vol->v_flags & AFPVOL_DROPBOX) {
1278 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1280 #endif /* DROPKLUDGE */
1282 setvoltime(obj, d_vol );
1285 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1291 /* ----------------------- */
1292 static __inline__ int copy_all(const int dfd, const void *buf,
1298 LOG(log_info, logtype_afpd, "begin copy_all:");
1301 while (buflen > 0) {
1302 if ((cc = write(dfd, buf, buflen)) < 0) {
1314 LOG(log_info, logtype_afpd, "end copy_all:");
1320 /* -------------------------- */
1321 static int copy_fd(int dfd, int sfd)
1327 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1328 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1332 #define BUF 128*1024*1024
1334 if (fstat(sfd, &st) == 0) {
1337 if ( offset >= st.st_size) {
1340 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1341 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1344 case EINVAL: /* there's no guarantee that all fs support sendfile */
1353 lseek(sfd, offset, SEEK_SET);
1357 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1364 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1371 /* ----------------------------------
1372 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1373 * because we are doing it elsewhere.
1375 int copyfile(s_vol, d_vol, src, dst, newname )
1376 const struct vol *s_vol, *d_vol;
1377 char *src, *dst, *newname;
1379 struct adouble ads, add;
1383 int noadouble = vol_noadouble(d_vol);
1387 LOG(log_info, logtype_afpd, "begin copyfile:");
1390 ad_init(&ads, s_vol->v_adouble);
1391 ad_init(&add, d_vol->v_adouble);
1392 adflags = ADFLAGS_DF;
1394 adflags |= ADFLAGS_HF;
1397 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1402 if (ad_hfileno(&ads) == -1) {
1403 /* no resource fork, don't create one for dst file */
1404 adflags &= ~ADFLAGS_HF;
1407 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1409 ad_close( &ads, adflags );
1410 if (EEXIST != ret_err) {
1411 deletefile(d_vol, dst, 0);
1414 return AFPERR_EXIST;
1416 if (ad_hfileno(&ads) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1417 /* copy the data fork */
1418 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1421 /* Now, reopen destination file */
1425 ad_close( &ads, adflags );
1427 if (ad_close( &add, adflags ) <0) {
1428 deletefile(d_vol, dst, 0);
1433 ad_init(&add, d_vol->v_adouble);
1434 if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
1439 if (!ret_err && newname) {
1440 ad_setname(&add, newname);
1443 ad_flush( &add, adflags );
1444 if (ad_close( &add, adflags ) <0) {
1448 deletefile(d_vol, dst, 0);
1450 else if (!stat(src, &st)) {
1451 /* set dest modification date to src date */
1454 ut.actime = ut.modtime = st.st_mtime;
1456 /* FIXME netatalk doesn't use resource fork file date
1457 * but maybe we should set its modtime too.
1462 LOG(log_info, logtype_afpd, "end copyfile:");
1466 switch ( ret_err ) {
1472 return AFPERR_DFULL;
1474 return AFPERR_NOOBJ;
1476 return AFPERR_ACCESS;
1478 return AFPERR_VLOCK;
1480 return AFPERR_PARAM;
1484 /* -----------------------------------
1485 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1486 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1488 when deletefile is called we don't have lock on it, file is closed (for us)
1489 untrue if called by renamefile
1491 ad_open always try to open file RDWR first and ad_lock takes care of
1492 WRITE lock on read only file.
1494 int deletefile( vol, file, checkAttrib )
1495 const struct vol *vol;
1500 struct adouble *adp = &ad;
1501 int adflags, err = AFP_OK;
1504 LOG(log_info, logtype_afpd, "begin deletefile:");
1507 /* try to open both forks at once */
1508 adflags = ADFLAGS_DF|ADFLAGS_HF;
1510 ad_init(&ad, vol->v_adouble); /* OK */
1511 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1514 if (adflags == ADFLAGS_DF)
1515 return AFPERR_NOOBJ;
1517 /* that failed. now try to open just the data fork */
1518 adflags = ADFLAGS_DF;
1522 adp = NULL; /* maybe it's a file we no rw mode for us */
1523 break; /* was return AFPERR_ACCESS;*/
1525 return AFPERR_VLOCK;
1527 return( AFPERR_PARAM );
1530 break; /* from the while */
1533 * Does kFPDeleteInhibitBit (bit 8) set?
1538 if (adp && (adflags & ADFLAGS_HF)) {
1540 ad_getattr(&ad, &bshort);
1541 if ((bshort & htons(ATTRBIT_NODELETE))) {
1542 ad_close( &ad, adflags );
1543 return(AFPERR_OLOCK);
1547 /* was EACCESS error try to get only metadata */
1548 ad_init(&ad, vol->v_adouble); /* OK */
1549 if ( ad_metadata( file , 0, &ad) == 0 ) {
1550 ad_getattr(&ad, &bshort);
1551 ad_close( &ad, ADFLAGS_HF );
1552 if ((bshort & htons(ATTRBIT_NODELETE))) {
1553 return AFPERR_OLOCK;
1559 if (adp && (adflags & ADFLAGS_HF) ) {
1560 /* FIXME we have a pb here because we want to know if a file is open
1561 * there's a 'priority inversion' if you can't open the ressource fork RW
1562 * you can delete it if it's open because you can't get a write lock.
1564 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1567 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1569 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1570 ad_close( &ad, adflags );
1571 return( AFPERR_BUSY );
1575 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1578 else if (!(err = netatalk_unlink( vol->ad_path( file, ADFLAGS_HF)) ) &&
1579 !(err = netatalk_unlink( file )) ) {
1581 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1583 cnid_delete(vol->v_cdb, id);
1588 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1591 LOG(log_info, logtype_afpd, "end deletefile:");
1597 /* ------------------------------------ */
1598 /* return a file id */
1599 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1602 int ibuflen, *rbuflen;
1611 struct path *s_path;
1614 LOG(log_info, logtype_afpd, "begin afp_createid:");
1621 memcpy(&vid, ibuf, sizeof(vid));
1622 ibuf += sizeof(vid);
1624 if (NULL == ( vol = getvolbyvid( vid )) ) {
1625 return( AFPERR_PARAM);
1628 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1632 if (vol->v_flags & AFPVOL_RO)
1633 return AFPERR_VLOCK;
1635 memcpy(&did, ibuf, sizeof( did ));
1636 ibuf += sizeof(did);
1638 if (NULL == ( dir = dirlookup( vol, did )) ) {
1639 return afp_errno; /* was AFPERR_PARAM */
1642 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1643 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1646 if ( path_isadir(s_path) ) {
1647 return( AFPERR_BADTYPE );
1650 upath = s_path->u_name;
1651 switch (s_path->st_errno) {
1653 break; /* success */
1656 return AFPERR_ACCESS;
1658 return AFPERR_NOOBJ;
1660 return AFPERR_PARAM;
1663 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1664 memcpy(rbuf, &id, sizeof(id));
1665 *rbuflen = sizeof(id);
1666 return AFPERR_EXISTID;
1669 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1670 memcpy(rbuf, &id, sizeof(id));
1671 *rbuflen = sizeof(id);
1676 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1682 reenumerate_id(const struct vol *vol, char *name, cnid_t did)
1690 memset(&path, 0, sizeof(path));
1691 if (vol->v_cdb == NULL) {
1694 if (NULL == ( dp = opendir( name)) ) {
1698 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
1699 if (NULL == check_dirent(vol, de->d_name))
1702 if ( stat(de->d_name, &path.st)<0 )
1705 /* update or add to cnid */
1706 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1708 #if AD_VERSION > AD_VERSION1
1709 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1711 struct adouble ad, *adp;
1715 path.u_name = de->d_name;
1717 if (!(of = of_findname(&path))) {
1718 ad_init(&ad, vol->v_adouble);
1723 if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, adp ) < 0 ) {
1726 if (ad_setid(adp,(vol->v_flags & AFPVOL_NODEV)?0:path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1727 ad_flush(adp, ADFLAGS_HF);
1729 ad_close(adp, ADFLAGS_HF);
1731 #endif /* AD_VERSION > AD_VERSION1 */
1740 /* ------------------------------
1741 resolve a file id */
1742 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1745 int ibuflen, *rbuflen;
1751 int err, buflen, retry=0;
1753 u_int16_t vid, bitmap;
1755 static char buffer[12 + MAXPATHLEN + 1];
1756 int len = 12 + MAXPATHLEN + 1;
1759 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1765 memcpy(&vid, ibuf, sizeof(vid));
1766 ibuf += sizeof(vid);
1768 if (NULL == ( vol = getvolbyvid( vid )) ) {
1769 return( AFPERR_PARAM);
1772 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1776 memcpy(&id, ibuf, sizeof( id ));
1781 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1782 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1785 if (NULL == ( dir = dirlookup( vol, id )) ) {
1786 return AFPERR_NOID; /* idem AFPERR_PARAM */
1788 path.u_name = upath;
1789 if (movecwd(vol, dir) < 0) {
1793 return AFPERR_ACCESS;
1797 return AFPERR_PARAM;
1801 if ( of_stat(&path) < 0 ) {
1803 /* with nfs and our working directory is deleted */
1804 if (errno == ESTALE) {
1808 if ( errno == ENOENT && !retry) {
1809 /* cnid db is out of sync, reenumerate the directory and updated ids */
1810 reenumerate_id(vol, ".", id);
1818 return AFPERR_ACCESS;
1822 return AFPERR_PARAM;
1826 /* directories are bad */
1827 if (S_ISDIR(path.st.st_mode))
1828 return AFPERR_BADTYPE;
1830 memcpy(&bitmap, ibuf, sizeof(bitmap));
1831 bitmap = ntohs( bitmap );
1832 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1835 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1836 rbuf + sizeof(bitmap), &buflen))) {
1839 *rbuflen = buflen + sizeof(bitmap);
1840 memcpy(rbuf, ibuf, sizeof(bitmap));
1843 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1849 /* ------------------------------ */
1850 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1853 int ibuflen, *rbuflen;
1863 static char buffer[12 + MAXPATHLEN + 1];
1864 int len = 12 + MAXPATHLEN + 1;
1867 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1873 memcpy(&vid, ibuf, sizeof(vid));
1874 ibuf += sizeof(vid);
1876 if (NULL == ( vol = getvolbyvid( vid )) ) {
1877 return( AFPERR_PARAM);
1880 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1884 if (vol->v_flags & AFPVOL_RO)
1885 return AFPERR_VLOCK;
1887 memcpy(&id, ibuf, sizeof( id ));
1891 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1895 if (NULL == ( dir = dirlookup( vol, id )) ) {
1896 return( AFPERR_PARAM );
1900 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1904 return AFPERR_ACCESS;
1909 /* still try to delete the id */
1913 return AFPERR_PARAM;
1916 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1917 return AFPERR_BADTYPE;
1919 if (cnid_delete(vol->v_cdb, fileid)) {
1922 return AFPERR_VLOCK;
1925 return AFPERR_ACCESS;
1927 return AFPERR_PARAM;
1932 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1938 /* ------------------------------ */
1939 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1943 if (path->st_errno) {
1944 switch (path->st_errno) {
1946 afp_errno = AFPERR_NOID;
1950 afp_errno = AFPERR_ACCESS;
1953 afp_errno = AFPERR_PARAM;
1958 /* we use file_access both for legacy Mac perm and
1959 * for unix privilege, rename will take care of folder perms
1961 if (file_access(path, OPENACC_WR ) < 0) {
1962 afp_errno = AFPERR_ACCESS;
1966 if ((*of = of_findname(path))) {
1967 /* reuse struct adouble so it won't break locks */
1971 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
1972 if ( !ret && ad_hfileno(adp) != -1 && !(adp->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) {
1974 * The user must have the Read & Write privilege for both files in order to use this command.
1976 ad_close(adp, ADFLAGS_HF);
1977 afp_errno = AFPERR_ACCESS;
1984 #define APPLETEMP ".AppleTempXXXXXX"
1986 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1989 int ibuflen, *rbuflen;
1991 struct stat srcst, destst;
1993 struct dir *dir, *sdir;
1994 char *spath, temp[17], *p;
1995 char *supath, *upath;
2000 struct adouble *adsp = NULL;
2001 struct adouble *addp = NULL;
2002 struct ofork *s_of = NULL;
2003 struct ofork *d_of = NULL;
2014 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
2020 memcpy(&vid, ibuf, sizeof(vid));
2021 ibuf += sizeof(vid);
2023 if (NULL == ( vol = getvolbyvid( vid )) ) {
2024 return( AFPERR_PARAM);
2027 if ((vol->v_flags & AFPVOL_RO))
2028 return AFPERR_VLOCK;
2030 /* source and destination dids */
2031 memcpy(&sid, ibuf, sizeof(sid));
2032 ibuf += sizeof(sid);
2033 memcpy(&did, ibuf, sizeof(did));
2034 ibuf += sizeof(did);
2037 if (NULL == (dir = dirlookup( vol, sid )) ) {
2038 return afp_errno; /* was AFPERR_PARAM */
2041 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2042 return get_afp_errno(AFPERR_NOOBJ);
2045 if ( path_isadir(path) ) {
2046 return AFPERR_BADTYPE; /* it's a dir */
2049 /* save some stuff */
2052 spath = obj->oldtmp;
2053 supath = obj->newtmp;
2054 strcpy(spath, path->m_name);
2055 strcpy(supath, path->u_name); /* this is for the cnid changing */
2056 p = absupath( vol, sdir, supath);
2058 /* pathname too long */
2059 return AFPERR_PARAM ;
2062 ad_init(&ads, vol->v_adouble);
2063 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2067 /* ***** from here we may have resource fork open **** */
2069 /* look for the source cnid. if it doesn't exist, don't worry about
2071 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2073 if (NULL == ( dir = dirlookup( vol, did )) ) {
2074 err = afp_errno; /* was AFPERR_PARAM */
2075 goto err_exchangefile;
2078 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2079 err = get_afp_errno(AFPERR_NOOBJ);
2080 goto err_exchangefile;
2083 if ( path_isadir(path) ) {
2084 err = AFPERR_BADTYPE;
2085 goto err_exchangefile;
2088 /* FPExchangeFiles is the only call that can return the SameObj
2090 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2091 err = AFPERR_SAMEOBJ;
2092 goto err_exchangefile;
2095 ad_init(&add, vol->v_adouble);
2096 if (!(addp = find_adouble( path, &d_of, &add))) {
2098 goto err_exchangefile;
2102 /* they are not on the same device and at least one is open
2103 * FIXME broken for for crossdev and adouble v2
2106 crossdev = (srcst.st_dev != destst.st_dev);
2107 if (/* (d_of || s_of) && */ crossdev) {
2109 goto err_exchangefile;
2112 /* look for destination id. */
2113 upath = path->u_name;
2114 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2116 /* construct a temp name.
2117 * NOTE: the temp file will be in the dest file's directory. it
2118 * will also be inaccessible from AFP. */
2119 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2120 if (!mktemp(temp)) {
2122 goto err_exchangefile;
2126 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2127 ad_close(adsp, ADFLAGS_HF);
2128 ad_close(addp, ADFLAGS_HF);
2131 /* now, quickly rename the file. we error if we can't. */
2132 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2133 goto err_exchangefile;
2134 of_rename(vol, s_of, sdir, spath, curdir, temp);
2136 /* rename destination to source */
2137 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2138 goto err_src_to_tmp;
2139 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2141 /* rename temp to destination */
2142 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2143 goto err_dest_to_src;
2144 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2146 /* id's need switching. src -> dest and dest -> src.
2147 * we need to re-stat() if it was a cross device copy.
2150 cnid_delete(vol->v_cdb, sid);
2153 cnid_delete(vol->v_cdb, did);
2155 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2156 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2158 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2159 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2164 err = AFPERR_ACCESS;
2169 goto err_temp_to_dest;
2172 /* here we need to reopen if crossdev */
2173 if (sid && ad_setid(addp,(vol->v_flags & AFPVOL_NODEV)?0:destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2175 ad_flush( addp, ADFLAGS_HF );
2178 if (did && ad_setid(adsp,(vol->v_flags & AFPVOL_NODEV)?0:srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2180 ad_flush( adsp, ADFLAGS_HF );
2183 /* change perms, src gets dest perm and vice versa */
2188 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2189 err = AFP_OK; /* ignore error */
2190 goto err_temp_to_dest;
2194 * we need to exchange ACL entries as well
2196 /* exchange_acls(vol, p, upath); */
2201 path->m_name = NULL;
2202 path->u_name = upath;
2204 setfilunixmode(vol, path, destst.st_mode);
2205 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2212 setfilunixmode(vol, path, srcst.st_mode);
2213 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2215 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2216 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2221 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2225 goto err_exchangefile;
2227 /* all this stuff is so that we can unwind a failed operation
2230 /* rename dest to temp */
2231 renamefile(vol, upath, temp, temp, adsp);
2232 of_rename(vol, s_of, curdir, upath, curdir, temp);
2235 /* rename source back to dest */
2236 renamefile(vol, p, upath, path->m_name, addp);
2237 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2240 /* rename temp back to source */
2241 renamefile(vol, temp, p, spath, adsp);
2242 of_rename(vol, s_of, curdir, temp, sdir, spath);
2245 if ( !s_of && adsp && ad_hfileno(adsp) != -1 ) {
2246 ad_close(adsp, ADFLAGS_HF);
2248 if ( !d_of && addp && ad_hfileno(addp) != -1 ) {
2249 ad_close(addp, ADFLAGS_HF);