2 * $Id: file.c,v 1.92.2.2.2.31.2.1 2004-10-20 19:48:38 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 ((adp != NULL) && (ad_finder != NULL)) {
89 memcpy(data, ad_finder, 32);
92 memcpy(data, ufinderi, 32);
95 /** Only enter if no appledouble information and no finder information found. */
96 if (chk_ext && (em = getextmap( mpath ))) {
97 memcpy(data, em->em_type, sizeof( em->em_type ));
98 memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator));
103 /* ---------------------
105 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8)
110 aint = strlen( name );
114 if (utf8_encoding()) {
115 /* but name is an utf8 mac name */
118 /* global static variable... */
120 if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
129 if (aint > MACFILELEN)
136 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
139 utf8 = vol->v_mac?htonl(vol->v_mac->kTextEncoding):0; /* htonl(utf8) */
140 memcpy(data, &utf8, sizeof(utf8));
141 data += sizeof(utf8);
144 memcpy(data, &temp, sizeof(temp));
145 data += sizeof(temp);
148 memcpy( data, src, aint );
158 * FIXME: PDINFO is UTF8 and doesn't need adp
160 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
161 (1 << FILPBIT_CDATE) |\
162 (1 << FILPBIT_MDATE) |\
163 (1 << FILPBIT_BDATE) |\
164 (1 << FILPBIT_FINFO) |\
165 (1 << FILPBIT_RFLEN) |\
166 (1 << FILPBIT_EXTRFLEN) |\
167 (1 << FILPBIT_PDINFO)))
169 /* -------------------------- */
170 u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st,
171 const cnid_t did, const char *upath, const int len)
175 #if AD_VERSION > AD_VERSION1
179 char stamp[ADEDLEN_PRIVSYN];
180 /* look in AD v2 header
181 * note inode and device are opaques and not in network order
184 && sizeof(dev_t) == ad_getentrylen(adp, ADEID_PRIVDEV)
185 && sizeof(ino_t) == ad_getentrylen(adp,ADEID_PRIVINO)
186 && sizeof(stamp) == ad_getentrylen(adp,ADEID_PRIVSYN)
187 && sizeof(cnid_t) == ad_getentrylen(adp, ADEID_DID)
188 && sizeof(cnid_t) == ad_getentrylen(adp, ADEID_PRIVID)
191 memcpy(&dev, ad_entry(adp, ADEID_PRIVDEV), sizeof(dev_t));
192 memcpy(&ino, ad_entry(adp, ADEID_PRIVINO), sizeof(ino_t));
193 memcpy(stamp, ad_entry(adp, ADEID_PRIVSYN), sizeof(stamp));
194 memcpy(&a_did, ad_entry(adp, ADEID_DID), sizeof(cnid_t));
196 if ( ( (vol->v_flags & AFPVOL_NODEV) || dev == st->st_dev)
197 && ino == st->st_ino && a_did == did
198 && !memcmp(vol->v_stamp, stamp, sizeof(stamp))) {
199 memcpy(&aint, ad_entry(adp, ADEID_PRIVID), sizeof(aint));
204 if (vol->v_cdb != NULL) {
205 aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
206 /* Throw errors if cnid_add fails. */
207 if (aint == CNID_INVALID) {
209 case CNID_ERR_CLOSE: /* the db is closed */
212 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
213 afp_errno = AFPERR_PARAM;
216 afp_errno = AFPERR_PARAM;
219 afp_errno = AFPERR_MISC;
223 #if AD_VERSION > AD_VERSION1
225 /* update the ressource fork
226 * for a folder adp is always null
228 if (ad_setid(adp,(vol->v_flags & AFPVOL_NODEV)?0:st->st_dev, st->st_ino, aint, did, vol->v_stamp)) {
229 ad_flush(adp, ADFLAGS_HF);
237 /* -------------------------- */
238 int getmetadata(struct vol *vol,
240 struct path *path, struct dir *dir,
241 char *buf, int *buflen, struct adouble *adp, int attrbits )
243 char *data, *l_nameoff = NULL, *upath;
244 char *utf_nameoff = NULL;
249 u_char achar, fdType[4];
255 LOG(log_info, logtype_afpd, "begin getmetadata:");
258 upath = path->u_name;
263 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
264 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
265 || (bitmap & (1 << FILPBIT_FNUM))) {
267 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
271 path->m_name = utompath(vol, upath, id, utf8_encoding());
274 while ( bitmap != 0 ) {
275 while (( bitmap & 1 ) == 0 ) {
283 ad_getattr(adp, &ashort);
284 } else if (*upath == '.') {
285 ashort = htons(ATTRBIT_INVISIBLE);
289 /* FIXME do we want a visual clue if the file is read only
292 accessmode( ".", &ma, dir , NULL);
293 if ((ma.ma_user & AR_UWRITE)) {
294 accessmode( upath, &ma, dir , st);
295 if (!(ma.ma_user & AR_UWRITE)) {
296 attrbits |= ATTRBIT_NOWRITE;
301 ashort = htons(ntohs(ashort) | attrbits);
302 memcpy(data, &ashort, sizeof( ashort ));
303 data += sizeof( ashort );
307 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
308 data += sizeof( u_int32_t );
312 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
313 aint = AD_DATE_FROM_UNIX(st->st_mtime);
314 memcpy(data, &aint, sizeof( aint ));
315 data += sizeof( aint );
319 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
320 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
321 aint = AD_DATE_FROM_UNIX(st->st_mtime);
324 aint = AD_DATE_FROM_UNIX(st->st_mtime);
326 memcpy(data, &aint, sizeof( int ));
327 data += sizeof( int );
331 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
332 aint = AD_DATE_START;
333 memcpy(data, &aint, sizeof( int ));
334 data += sizeof( int );
338 get_finderinfo(path->m_name, adp, (char *)data);
340 if (*upath == '.') { /* make it invisible */
341 ashort = htons(FINDERINFO_INVISIBLE);
342 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
350 data += sizeof( u_int16_t );
354 memset(data, 0, sizeof(u_int16_t));
355 data += sizeof( u_int16_t );
359 memcpy(data, &id, sizeof( id ));
360 data += sizeof( id );
364 if (st->st_size > 0xffffffff)
367 aint = htonl( st->st_size );
368 memcpy(data, &aint, sizeof( aint ));
369 data += sizeof( aint );
374 if (adp->ad_rlen > 0xffffffff)
377 aint = htonl( adp->ad_rlen);
381 memcpy(data, &aint, sizeof( aint ));
382 data += sizeof( aint );
385 /* Current client needs ProDOS info block for this file.
386 Use simple heuristic and let the Mac "type" string tell
387 us what the PD file code should be. Everything gets a
388 subtype of 0x0000 unless the original value was hashed
389 to "pXYZ" when we created it. See IA, Ver 2.
390 <shirsch@adelphia.net> */
391 case FILPBIT_PDINFO :
392 if (afp_version >= 30) { /* UTF8 name */
393 utf8 = kTextEncodingUTF8;
395 data += sizeof( u_int16_t );
397 memcpy(data, &aint, sizeof( aint ));
398 data += sizeof( aint );
402 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
404 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
408 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
412 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
416 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
420 else if ( fdType[0] == 'p' ) {
422 ashort = (fdType[2] * 256) + fdType[3];
436 memcpy(data, &ashort, sizeof( ashort ));
437 data += sizeof( ashort );
438 memset(data, 0, sizeof( ashort ));
439 data += sizeof( ashort );
442 case FILPBIT_EXTDFLEN:
443 aint = htonl(st->st_size >> 32);
444 memcpy(data, &aint, sizeof( aint ));
445 data += sizeof( aint );
446 aint = htonl(st->st_size);
447 memcpy(data, &aint, sizeof( aint ));
448 data += sizeof( aint );
450 case FILPBIT_EXTRFLEN:
453 aint = htonl(adp->ad_rlen >> 32);
454 memcpy(data, &aint, sizeof( aint ));
455 data += sizeof( aint );
457 aint = htonl(adp->ad_rlen);
458 memcpy(data, &aint, sizeof( aint ));
459 data += sizeof( aint );
461 case FILPBIT_UNIXPR :
462 /* accessmode may change st_mode with ACLs */
463 accessmode( upath, &ma, dir , st);
465 aint = htonl(st->st_uid);
466 memcpy( data, &aint, sizeof( aint ));
467 data += sizeof( aint );
468 aint = htonl(st->st_gid);
469 memcpy( data, &aint, sizeof( aint ));
470 data += sizeof( aint );
472 aint = htonl(st->st_mode);
473 memcpy( data, &aint, sizeof( aint ));
474 data += sizeof( aint );
476 *data++ = ma.ma_user;
477 *data++ = ma.ma_world;
478 *data++ = ma.ma_group;
479 *data++ = ma.ma_owner;
483 return( AFPERR_BITMAP );
489 ashort = htons( data - buf );
490 memcpy(l_nameoff, &ashort, sizeof( ashort ));
491 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
494 ashort = htons( data - buf );
495 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
496 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
498 *buflen = data - buf;
502 /* ----------------------- */
503 int getfilparams(struct vol *vol,
505 struct path *path, struct dir *dir,
506 char *buf, int *buflen )
508 struct adouble ad, *adp;
511 u_int16_t attrbits = 0;
516 LOG(log_info, logtype_default, "begin getfilparams:");
519 opened = PARAM_NEED_ADP(bitmap);
522 upath = path->u_name;
523 if ((of = of_findname(path))) {
525 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
526 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
528 ad_init(&ad, vol->v_adouble);
532 if ( ad_metadata( upath, 0, adp) < 0 ) {
535 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
536 upath, strerror(errno));
537 return AFPERR_ACCESS;
539 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
549 we need to check if the file is open by another process.
550 it's slow so we only do it if we have to:
551 - bitmap is requested.
552 - we don't already have the answer!
554 if ((bitmap & (1 << FILPBIT_ATTR))) {
555 if (!(attrbits & ATTRBIT_ROPEN)) {
556 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_ROPEN : 0;
557 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_ROPEN : 0;
559 if (!(attrbits & ATTRBIT_DOPEN)) {
560 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_DOPEN : 0;
561 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_DOPEN : 0;
566 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
568 ad_close( adp, ADFLAGS_HF );
571 LOG(log_info, logtype_afpd, "end getfilparams:");
577 /* ----------------------------- */
578 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
581 int ibuflen, *rbuflen;
583 struct adouble ad, *adp;
586 struct ofork *of = NULL;
588 int creatf, did, openf, retvalue = AFP_OK;
594 LOG(log_info, logtype_afpd, "begin afp_createfile:");
599 creatf = (unsigned char) *ibuf++;
601 memcpy(&vid, ibuf, sizeof( vid ));
602 ibuf += sizeof( vid );
604 if (NULL == ( vol = getvolbyvid( vid )) ) {
605 return( AFPERR_PARAM );
608 if (vol->v_flags & AFPVOL_RO)
611 memcpy(&did, ibuf, sizeof( did));
612 ibuf += sizeof( did );
614 if (NULL == ( dir = dirlookup( vol, did )) ) {
618 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
619 return get_afp_errno(AFPERR_PARAM);
622 if ( *s_path->m_name == '\0' ) {
623 return( AFPERR_BADTYPE );
626 upath = s_path->u_name;
627 if (0 != (ret = check_name(vol, upath)))
630 /* if upath is deleted we already in trouble anyway */
631 if ((of = of_findname(s_path))) {
634 ad_init(&ad, vol->v_adouble);
638 /* on a hard create, fail if file exists and is open */
641 openf = O_RDWR|O_CREAT|O_TRUNC;
643 /* on a soft create, if the file is open then ad_open won't fail
644 because open syscall is not called
649 openf = O_RDWR|O_CREAT|O_EXCL;
652 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
653 openf, 0666, adp) < 0 ) {
657 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
658 return ( AFPERR_NOOBJ );
660 return( AFPERR_EXIST );
662 return( AFPERR_ACCESS );
664 return( AFPERR_PARAM );
667 if ( ad_hfileno( adp ) == -1 ) {
668 /* on noadouble volumes, just creating the data fork is ok */
669 if (vol_noadouble(vol)) {
670 ad_close( adp, ADFLAGS_DF );
671 goto createfile_done;
673 /* FIXME with hard create on an existing file, we already
674 * corrupted the data file.
676 netatalk_unlink( upath );
677 ad_close( adp, ADFLAGS_DF );
678 return AFPERR_ACCESS;
681 path = s_path->m_name;
682 ad_setname(adp, path);
683 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
684 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
690 if (vol->v_flags & AFPVOL_DROPBOX) {
691 retvalue = matchfile2dirperms(upath, vol, did);
693 #endif /* DROPKLUDGE */
695 setvoltime(obj, vol );
698 LOG(log_info, logtype_afpd, "end afp_createfile");
704 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
707 int ibuflen, *rbuflen;
713 u_int16_t vid, bitmap;
716 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
722 memcpy(&vid, ibuf, sizeof( vid ));
723 ibuf += sizeof( vid );
724 if (NULL == ( vol = getvolbyvid( vid )) ) {
725 return( AFPERR_PARAM );
728 if (vol->v_flags & AFPVOL_RO)
731 memcpy(&did, ibuf, sizeof( did ));
732 ibuf += sizeof( did );
733 if (NULL == ( dir = dirlookup( vol, did )) ) {
734 return afp_errno; /* was AFPERR_NOOBJ */
737 memcpy(&bitmap, ibuf, sizeof( bitmap ));
738 bitmap = ntohs( bitmap );
739 ibuf += sizeof( bitmap );
741 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
742 return get_afp_errno(AFPERR_PARAM);
745 if (path_isadir(s_path)) {
746 return( AFPERR_BADTYPE ); /* it's a directory */
749 if ( s_path->st_errno != 0 ) {
750 return( AFPERR_NOOBJ );
753 if ((u_long)ibuf & 1 ) {
757 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
758 setvoltime(obj, vol );
762 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
769 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
772 extern struct path Cur_Path;
774 int setfilparams(struct vol *vol,
775 struct path *path, u_int16_t f_bitmap, char *buf )
777 struct adouble ad, *adp;
780 int bit, isad = 1, err = AFP_OK;
782 u_char achar, *fdType, xyy[4];
783 u_int16_t ashort, bshort;
786 u_int16_t upriv_bit = 0;
790 int change_mdate = 0;
791 int change_parent_mdate = 0;
796 u_int16_t bitmap = f_bitmap;
797 u_int32_t cdate,bdate;
798 u_char finder_buf[32];
801 LOG(log_info, logtype_afpd, "begin setfilparams:");
804 upath = path->u_name;
805 if ((of = of_findname(path))) {
808 ad_init(&ad, vol->v_adouble);
812 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
813 return AFPERR_ACCESS;
816 /* with unix priv maybe we have to change adouble file priv first */
818 while ( bitmap != 0 ) {
819 while (( bitmap & 1 ) == 0 ) {
826 memcpy(&ashort, buf, sizeof( ashort ));
827 buf += sizeof( ashort );
831 memcpy(&cdate, buf, sizeof(cdate));
832 buf += sizeof( cdate );
835 memcpy(&newdate, buf, sizeof( newdate ));
836 buf += sizeof( newdate );
840 memcpy(&bdate, buf, sizeof( bdate));
841 buf += sizeof( bdate );
845 memcpy(finder_buf, buf, 32 );
848 case FILPBIT_UNIXPR :
849 if (!vol_unix_priv(vol)) {
850 /* this volume doesn't use unix priv */
856 change_parent_mdate = 1;
858 memcpy( &aint, buf, sizeof( aint ));
859 f_uid = ntohl (aint);
860 buf += sizeof( aint );
861 memcpy( &aint, buf, sizeof( aint ));
862 f_gid = ntohl (aint);
863 buf += sizeof( aint );
864 setfilowner(vol, f_uid, f_gid, path);
866 memcpy( &upriv, buf, sizeof( upriv ));
867 buf += sizeof( upriv );
868 upriv = ntohl (upriv);
869 if ((upriv & S_IWUSR)) {
870 setfilunixmode(vol, path, upriv);
877 case FILPBIT_PDINFO :
878 if (afp_version < 30) { /* else it's UTF8 name */
881 /* Keep special case to support crlf translations */
882 if ((unsigned int) achar == 0x04) {
883 fdType = (u_char *)"TEXT";
886 xyy[0] = ( u_char ) 'p';
897 /* break while loop */
906 /* second try with adouble open
908 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
909 O_RDWR|O_CREAT, 0666, adp) < 0) {
910 /* for some things, we don't need an adouble header */
911 if (f_bitmap & ~(1<<FILPBIT_MDATE)) {
912 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
915 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
916 ad_setname(adp, path->m_name);
921 while ( bitmap != 0 ) {
922 while (( bitmap & 1 ) == 0 ) {
929 ad_getattr(adp, &bshort);
930 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
931 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
932 change_parent_mdate = 1;
933 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
934 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
938 ad_setattr(adp, bshort);
941 ad_setdate(adp, AD_DATE_CREATE, cdate);
946 ad_setdate(adp, AD_DATE_BACKUP, bdate);
949 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
951 ((em = getextmap( path->m_name )) &&
952 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
953 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
954 || ((em = getdefextmap()) &&
955 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
956 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
958 memcpy(finder_buf, ufinderi, 8 );
961 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
963 case FILPBIT_UNIXPR :
965 setfilunixmode(vol, path, upriv);
968 case FILPBIT_PDINFO :
969 if (afp_version < 30) { /* else it's UTF8 name */
970 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
971 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
977 goto setfilparam_done;
984 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
985 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
989 ad_setdate(adp, AD_DATE_MODIFY, newdate);
990 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
995 ad_flush( adp, ADFLAGS_HF );
996 ad_close( adp, ADFLAGS_HF );
1000 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
1001 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
1002 bitmap = 1<<FILPBIT_MDATE;
1003 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
1007 LOG(log_info, logtype_afpd, "end setfilparams:");
1013 * renamefile and copyfile take the old and new unix pathnames
1014 * and the new mac name.
1016 * src the source path
1017 * dst the dest filename in current dir
1018 * newname the dest mac name
1019 * adp adouble struct of src file, if open, or & zeroed one
1022 int renamefile(vol, src, dst, newname, adp )
1023 const struct vol *vol;
1024 char *src, *dst, *newname;
1025 struct adouble *adp;
1027 char adsrc[ MAXPATHLEN + 1];
1031 LOG(log_info, logtype_afpd, "begin renamefile:");
1034 if ( unix_rename( src, dst ) < 0 ) {
1037 return( AFPERR_NOOBJ );
1040 return( AFPERR_ACCESS );
1042 return AFPERR_VLOCK;
1043 case EXDEV : /* Cross device move -- try copy */
1044 /* NOTE: with open file it's an error because after the copy we will
1045 * get two files, it's fixable for our process (eg reopen the new file, get the
1046 * locks, and so on. But it doesn't solve the case with a second process
1048 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
1049 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1050 return AFPERR_OLOCK; /* little lie */
1052 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname )) ) {
1053 /* on error copyfile delete dest */
1056 return deletefile(vol, src, 0);
1058 return( AFPERR_PARAM );
1062 strcpy( adsrc, vol->ad_path( src, 0 ));
1064 if (unix_rename( adsrc, vol->ad_path( dst, 0 )) < 0 ) {
1069 if (errno == ENOENT) {
1072 if (stat(adsrc, &st)) /* source has no ressource fork, */
1075 /* We are here because :
1076 * -there's no dest folder.
1077 * -there's no .AppleDouble in the dest folder.
1078 * if we use the struct adouble passed in parameter it will not
1079 * create .AppleDouble if the file is already opened, so we
1080 * use a diff one, it's not a pb,ie it's not the same file, yet.
1082 ad_init(&ad, vol->v_adouble);
1083 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
1084 ad_close(&ad, ADFLAGS_HF);
1085 if (!unix_rename( adsrc, vol->ad_path( dst, 0 )) )
1090 else { /* it's something else, bail out */
1094 /* try to undo the data fork rename,
1095 * we know we are on the same device
1098 unix_rename( dst, src );
1099 /* return the first error */
1102 return AFPERR_NOOBJ;
1105 return AFPERR_ACCESS ;
1107 return AFPERR_VLOCK;
1109 return AFPERR_PARAM ;
1114 /* don't care if we can't open the newly renamed ressource fork
1116 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1117 ad_setname(adp, newname);
1118 ad_flush( adp, ADFLAGS_HF );
1119 ad_close( adp, ADFLAGS_HF );
1122 LOG(log_info, logtype_afpd, "end renamefile:");
1128 int copy_path_name(char *newname, char *ibuf)
1135 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1141 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1142 strncpy( newname, ibuf, plen );
1143 newname[ plen ] = '\0';
1144 if (strlen(newname) != plen) {
1145 /* there's \0 in newname, e.g. it's a pathname not
1153 memcpy(&hint, ibuf, sizeof(hint));
1154 ibuf += sizeof(hint);
1156 memcpy(&len16, ibuf, sizeof(len16));
1157 ibuf += sizeof(len16);
1158 plen = ntohs(len16);
1161 if (plen > AFPOBJ_TMPSIZ) {
1164 strncpy( newname, ibuf, plen );
1165 newname[ plen ] = '\0';
1166 if (strlen(newname) != plen) {
1175 /* -----------------------------------
1177 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1180 int ibuflen, *rbuflen;
1182 struct vol *s_vol, *d_vol;
1184 char *newname, *p, *upath;
1185 struct path *s_path;
1186 u_int32_t sdid, ddid;
1187 int err, retvalue = AFP_OK;
1188 u_int16_t svid, dvid;
1191 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1197 memcpy(&svid, ibuf, sizeof( svid ));
1198 ibuf += sizeof( svid );
1199 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1200 return( AFPERR_PARAM );
1203 memcpy(&sdid, ibuf, sizeof( sdid ));
1204 ibuf += sizeof( sdid );
1205 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1209 memcpy(&dvid, ibuf, sizeof( dvid ));
1210 ibuf += sizeof( dvid );
1211 memcpy(&ddid, ibuf, sizeof( ddid ));
1212 ibuf += sizeof( ddid );
1214 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1215 return get_afp_errno(AFPERR_PARAM);
1217 if ( path_isadir(s_path) ) {
1218 return( AFPERR_BADTYPE );
1221 /* don't allow copies when the file is open.
1222 * XXX: the spec only calls for read/deny write access.
1223 * however, copyfile doesn't have any of that info,
1224 * and locks need to stay coherent. as a result,
1225 * we just balk if the file is opened already. */
1227 newname = obj->newtmp;
1228 strcpy( newname, s_path->m_name );
1230 if (of_findname(s_path))
1231 return AFPERR_DENYCONF;
1233 p = ctoupath( s_vol, curdir, newname );
1235 return AFPERR_PARAM;
1239 /* FIXME svid != dvid && dvid's user can't read svid */
1241 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1242 return( AFPERR_PARAM );
1245 if (d_vol->v_flags & AFPVOL_RO)
1246 return AFPERR_VLOCK;
1248 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1252 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1253 return get_afp_errno(AFPERR_NOOBJ);
1255 if ( *s_path->m_name != '\0' ) {
1256 path_error(s_path, AFPERR_PARAM);
1259 /* one of the handful of places that knows about the path type */
1260 if (copy_path_name(newname, ibuf) < 0) {
1261 return( AFPERR_PARAM );
1263 /* newname is always only a filename so curdir *is* its
1266 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1267 return( AFPERR_PARAM );
1269 if ( (err = copyfile(s_vol, d_vol, p, upath , newname)) < 0 ) {
1275 if (vol->v_flags & AFPVOL_DROPBOX) {
1276 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1278 #endif /* DROPKLUDGE */
1280 setvoltime(obj, d_vol );
1283 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1289 /* ----------------------- */
1290 static __inline__ int copy_all(const int dfd, const void *buf,
1296 LOG(log_info, logtype_afpd, "begin copy_all:");
1299 while (buflen > 0) {
1300 if ((cc = write(dfd, buf, buflen)) < 0) {
1312 LOG(log_info, logtype_afpd, "end copy_all:");
1318 /* -------------------------- */
1319 static int copy_fd(int dfd, int sfd)
1325 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1326 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1330 #define BUF 128*1024*1024
1332 if (fstat(sfd, &st) == 0) {
1335 if ( offset >= st.st_size) {
1338 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1339 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1342 case EINVAL: /* there's no guarantee that all fs support sendfile */
1351 lseek(sfd, offset, SEEK_SET);
1355 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1362 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1369 /* ----------------------------------
1370 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1371 * because we are doing it elsewhere.
1373 int copyfile(s_vol, d_vol, src, dst, newname )
1374 const struct vol *s_vol, *d_vol;
1375 char *src, *dst, *newname;
1377 struct adouble ads, add;
1381 int noadouble = vol_noadouble(d_vol);
1385 LOG(log_info, logtype_afpd, "begin copyfile:");
1388 ad_init(&ads, s_vol->v_adouble);
1389 ad_init(&add, d_vol->v_adouble);
1390 adflags = ADFLAGS_DF;
1392 adflags |= ADFLAGS_HF;
1395 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1400 if (ad_hfileno(&ads) == -1) {
1401 /* no resource fork, don't create one for dst file */
1402 adflags &= ~ADFLAGS_HF;
1405 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1407 ad_close( &ads, adflags );
1408 if (EEXIST != ret_err) {
1409 deletefile(d_vol, dst, 0);
1412 return AFPERR_EXIST;
1414 if (ad_hfileno(&ads) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1415 /* copy the data fork */
1416 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1419 /* Now, reopen destination file */
1423 ad_close( &ads, adflags );
1425 if (ad_close( &add, adflags ) <0) {
1426 deletefile(d_vol, dst, 0);
1431 ad_init(&add, d_vol->v_adouble);
1432 if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
1437 if (!ret_err && newname) {
1438 ad_setname(&add, newname);
1441 ad_flush( &add, adflags );
1442 if (ad_close( &add, adflags ) <0) {
1446 deletefile(d_vol, dst, 0);
1448 else if (!stat(src, &st)) {
1449 /* set dest modification date to src date */
1452 ut.actime = ut.modtime = st.st_mtime;
1454 /* FIXME netatalk doesn't use resource fork file date
1455 * but maybe we should set its modtime too.
1460 LOG(log_info, logtype_afpd, "end copyfile:");
1464 switch ( ret_err ) {
1470 return AFPERR_DFULL;
1472 return AFPERR_NOOBJ;
1474 return AFPERR_ACCESS;
1476 return AFPERR_VLOCK;
1478 return AFPERR_PARAM;
1482 /* -----------------------------------
1483 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1484 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1486 when deletefile is called we don't have lock on it, file is closed (for us)
1487 untrue if called by renamefile
1489 ad_open always try to open file RDWR first and ad_lock takes care of
1490 WRITE lock on read only file.
1492 int deletefile( vol, file, checkAttrib )
1493 const struct vol *vol;
1498 struct adouble *adp = &ad;
1499 int adflags, err = AFP_OK;
1502 LOG(log_info, logtype_afpd, "begin deletefile:");
1505 /* try to open both forks at once */
1506 adflags = ADFLAGS_DF|ADFLAGS_HF;
1508 ad_init(&ad, vol->v_adouble); /* OK */
1509 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1512 if (adflags == ADFLAGS_DF)
1513 return AFPERR_NOOBJ;
1515 /* that failed. now try to open just the data fork */
1516 adflags = ADFLAGS_DF;
1520 adp = NULL; /* maybe it's a file we no rw mode for us */
1521 break; /* was return AFPERR_ACCESS;*/
1523 return AFPERR_VLOCK;
1525 return( AFPERR_PARAM );
1528 break; /* from the while */
1531 * Does kFPDeleteInhibitBit (bit 8) set?
1536 if (adp && (adflags & ADFLAGS_HF)) {
1538 ad_getattr(&ad, &bshort);
1539 if ((bshort & htons(ATTRBIT_NODELETE))) {
1540 ad_close( &ad, adflags );
1541 return(AFPERR_OLOCK);
1545 /* was EACCESS error try to get only metadata */
1546 ad_init(&ad, vol->v_adouble); /* OK */
1547 if ( ad_metadata( file , 0, &ad) == 0 ) {
1548 ad_getattr(&ad, &bshort);
1549 ad_close( &ad, ADFLAGS_HF );
1550 if ((bshort & htons(ATTRBIT_NODELETE))) {
1551 return AFPERR_OLOCK;
1557 if (adp && (adflags & ADFLAGS_HF) ) {
1558 /* FIXME we have a pb here because we want to know if a file is open
1559 * there's a 'priority inversion' if you can't open the ressource fork RW
1560 * you can delete it if it's open because you can't get a write lock.
1562 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1565 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1567 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1568 ad_close( &ad, adflags );
1569 return( AFPERR_BUSY );
1573 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1576 else if (!(err = netatalk_unlink( vol->ad_path( file, ADFLAGS_HF)) ) &&
1577 !(err = netatalk_unlink( file )) ) {
1579 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1581 cnid_delete(vol->v_cdb, id);
1586 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1589 LOG(log_info, logtype_afpd, "end deletefile:");
1595 /* ------------------------------------ */
1596 /* return a file id */
1597 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1600 int ibuflen, *rbuflen;
1609 struct path *s_path;
1612 LOG(log_info, logtype_afpd, "begin afp_createid:");
1619 memcpy(&vid, ibuf, sizeof(vid));
1620 ibuf += sizeof(vid);
1622 if (NULL == ( vol = getvolbyvid( vid )) ) {
1623 return( AFPERR_PARAM);
1626 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1630 if (vol->v_flags & AFPVOL_RO)
1631 return AFPERR_VLOCK;
1633 memcpy(&did, ibuf, sizeof( did ));
1634 ibuf += sizeof(did);
1636 if (NULL == ( dir = dirlookup( vol, did )) ) {
1637 return afp_errno; /* was AFPERR_PARAM */
1640 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1641 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1644 if ( path_isadir(s_path) ) {
1645 return( AFPERR_BADTYPE );
1648 upath = s_path->u_name;
1649 switch (s_path->st_errno) {
1651 break; /* success */
1654 return AFPERR_ACCESS;
1656 return AFPERR_NOOBJ;
1658 return AFPERR_PARAM;
1661 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1662 memcpy(rbuf, &id, sizeof(id));
1663 *rbuflen = sizeof(id);
1664 return AFPERR_EXISTID;
1667 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1668 memcpy(rbuf, &id, sizeof(id));
1669 *rbuflen = sizeof(id);
1674 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1680 reenumerate_id(const struct vol *vol, char *name, cnid_t did)
1688 memset(&path, 0, sizeof(path));
1689 if (vol->v_cdb == NULL) {
1692 if (NULL == ( dp = opendir( name)) ) {
1696 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
1697 if (NULL == check_dirent(vol, de->d_name))
1700 if ( stat(de->d_name, &path.st)<0 )
1703 /* update or add to cnid */
1704 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1706 #if AD_VERSION > AD_VERSION1
1707 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1709 struct adouble ad, *adp;
1713 path.u_name = de->d_name;
1715 if (!(of = of_findname(&path))) {
1716 ad_init(&ad, vol->v_adouble);
1721 if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, adp ) < 0 ) {
1724 if (ad_setid(adp,(vol->v_flags & AFPVOL_NODEV)?0:path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1725 ad_flush(adp, ADFLAGS_HF);
1727 ad_close(adp, ADFLAGS_HF);
1729 #endif /* AD_VERSION > AD_VERSION1 */
1738 /* ------------------------------
1739 resolve a file id */
1740 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1743 int ibuflen, *rbuflen;
1749 int err, buflen, retry=0;
1751 u_int16_t vid, bitmap;
1753 static char buffer[12 + MAXPATHLEN + 1];
1754 int len = 12 + MAXPATHLEN + 1;
1757 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1763 memcpy(&vid, ibuf, sizeof(vid));
1764 ibuf += sizeof(vid);
1766 if (NULL == ( vol = getvolbyvid( vid )) ) {
1767 return( AFPERR_PARAM);
1770 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1774 memcpy(&id, ibuf, sizeof( id ));
1779 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1780 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1783 if (NULL == ( dir = dirlookup( vol, id )) ) {
1784 return AFPERR_NOID; /* idem AFPERR_PARAM */
1786 path.u_name = upath;
1787 if (movecwd(vol, dir) < 0) {
1791 return AFPERR_ACCESS;
1795 return AFPERR_PARAM;
1799 if ( of_stat(&path) < 0 ) {
1801 /* with nfs and our working directory is deleted */
1802 if (errno == ESTALE) {
1806 if ( errno == ENOENT && !retry) {
1807 /* cnid db is out of sync, reenumerate the directory and updated ids */
1808 reenumerate_id(vol, ".", id);
1816 return AFPERR_ACCESS;
1820 return AFPERR_PARAM;
1824 /* directories are bad */
1825 if (S_ISDIR(path.st.st_mode))
1826 return AFPERR_BADTYPE;
1828 memcpy(&bitmap, ibuf, sizeof(bitmap));
1829 bitmap = ntohs( bitmap );
1830 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1833 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1834 rbuf + sizeof(bitmap), &buflen))) {
1837 *rbuflen = buflen + sizeof(bitmap);
1838 memcpy(rbuf, ibuf, sizeof(bitmap));
1841 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1847 /* ------------------------------ */
1848 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1851 int ibuflen, *rbuflen;
1861 static char buffer[12 + MAXPATHLEN + 1];
1862 int len = 12 + MAXPATHLEN + 1;
1865 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1871 memcpy(&vid, ibuf, sizeof(vid));
1872 ibuf += sizeof(vid);
1874 if (NULL == ( vol = getvolbyvid( vid )) ) {
1875 return( AFPERR_PARAM);
1878 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1882 if (vol->v_flags & AFPVOL_RO)
1883 return AFPERR_VLOCK;
1885 memcpy(&id, ibuf, sizeof( id ));
1889 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1893 if (NULL == ( dir = dirlookup( vol, id )) ) {
1894 return( AFPERR_PARAM );
1898 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1902 return AFPERR_ACCESS;
1907 /* still try to delete the id */
1911 return AFPERR_PARAM;
1914 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1915 return AFPERR_BADTYPE;
1917 if (cnid_delete(vol->v_cdb, fileid)) {
1920 return AFPERR_VLOCK;
1923 return AFPERR_ACCESS;
1925 return AFPERR_PARAM;
1930 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1936 /* ------------------------------ */
1937 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1941 if (path->st_errno) {
1942 switch (path->st_errno) {
1944 afp_errno = AFPERR_NOID;
1948 afp_errno = AFPERR_ACCESS;
1951 afp_errno = AFPERR_PARAM;
1956 /* we use file_access both for legacy Mac perm and
1957 * for unix privilege, rename will take care of folder perms
1959 if (file_access(path, OPENACC_WR ) < 0) {
1960 afp_errno = AFPERR_ACCESS;
1964 if ((*of = of_findname(path))) {
1965 /* reuse struct adouble so it won't break locks */
1969 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
1970 if ( !ret && ad_hfileno(adp) != -1 && !(adp->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) {
1972 * The user must have the Read & Write privilege for both files in order to use this command.
1974 ad_close(adp, ADFLAGS_HF);
1975 afp_errno = AFPERR_ACCESS;
1982 #define APPLETEMP ".AppleTempXXXXXX"
1984 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1987 int ibuflen, *rbuflen;
1989 struct stat srcst, destst;
1991 struct dir *dir, *sdir;
1992 char *spath, temp[17], *p;
1993 char *supath, *upath;
1998 struct adouble *adsp = NULL;
1999 struct adouble *addp = NULL;
2000 struct ofork *s_of = NULL;
2001 struct ofork *d_of = NULL;
2012 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
2018 memcpy(&vid, ibuf, sizeof(vid));
2019 ibuf += sizeof(vid);
2021 if (NULL == ( vol = getvolbyvid( vid )) ) {
2022 return( AFPERR_PARAM);
2025 if ((vol->v_flags & AFPVOL_RO))
2026 return AFPERR_VLOCK;
2028 /* source and destination dids */
2029 memcpy(&sid, ibuf, sizeof(sid));
2030 ibuf += sizeof(sid);
2031 memcpy(&did, ibuf, sizeof(did));
2032 ibuf += sizeof(did);
2035 if (NULL == (dir = dirlookup( vol, sid )) ) {
2036 return afp_errno; /* was AFPERR_PARAM */
2039 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2040 return get_afp_errno(AFPERR_NOOBJ);
2043 if ( path_isadir(path) ) {
2044 return AFPERR_BADTYPE; /* it's a dir */
2047 /* save some stuff */
2050 spath = obj->oldtmp;
2051 supath = obj->newtmp;
2052 strcpy(spath, path->m_name);
2053 strcpy(supath, path->u_name); /* this is for the cnid changing */
2054 p = absupath( vol, sdir, supath);
2056 /* pathname too long */
2057 return AFPERR_PARAM ;
2060 ad_init(&ads, vol->v_adouble);
2061 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2065 /* ***** from here we may have resource fork open **** */
2067 /* look for the source cnid. if it doesn't exist, don't worry about
2069 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2071 if (NULL == ( dir = dirlookup( vol, did )) ) {
2072 err = afp_errno; /* was AFPERR_PARAM */
2073 goto err_exchangefile;
2076 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2077 err = get_afp_errno(AFPERR_NOOBJ);
2078 goto err_exchangefile;
2081 if ( path_isadir(path) ) {
2082 err = AFPERR_BADTYPE;
2083 goto err_exchangefile;
2086 /* FPExchangeFiles is the only call that can return the SameObj
2088 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2089 err = AFPERR_SAMEOBJ;
2090 goto err_exchangefile;
2093 ad_init(&add, vol->v_adouble);
2094 if (!(addp = find_adouble( path, &d_of, &add))) {
2096 goto err_exchangefile;
2100 /* they are not on the same device and at least one is open
2101 * FIXME broken for for crossdev and adouble v2
2104 crossdev = (srcst.st_dev != destst.st_dev);
2105 if (/* (d_of || s_of) && */ crossdev) {
2107 goto err_exchangefile;
2110 /* look for destination id. */
2111 upath = path->u_name;
2112 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2114 /* construct a temp name.
2115 * NOTE: the temp file will be in the dest file's directory. it
2116 * will also be inaccessible from AFP. */
2117 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2118 if (!mktemp(temp)) {
2120 goto err_exchangefile;
2124 /* we need to close fork for copy, both s_of and d_of are null */
2125 ad_close(adsp, ADFLAGS_HF);
2126 ad_close(addp, ADFLAGS_HF);
2129 /* now, quickly rename the file. we error if we can't. */
2130 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2131 goto err_exchangefile;
2132 of_rename(vol, s_of, sdir, spath, curdir, temp);
2134 /* rename destination to source */
2135 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2136 goto err_src_to_tmp;
2137 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2139 /* rename temp to destination */
2140 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2141 goto err_dest_to_src;
2142 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2144 /* id's need switching. src -> dest and dest -> src.
2145 * we need to re-stat() if it was a cross device copy.
2148 cnid_delete(vol->v_cdb, sid);
2151 cnid_delete(vol->v_cdb, did);
2153 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2154 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2156 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2157 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2162 err = AFPERR_ACCESS;
2167 goto err_temp_to_dest;
2170 /* here we need to reopen if crossdev */
2172 ad_setid(addp,(vol->v_flags & AFPVOL_NODEV)?0:destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp);
2174 ad_setid(adsp,(vol->v_flags & AFPVOL_NODEV)?0:srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp);
2176 /* change perms, src gets dest perm and vice versa */
2181 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2182 err = AFP_OK; /* ignore error */
2183 goto err_temp_to_dest;
2187 * we need to exchange ACL entries as well
2189 /* exchange_acls(vol, p, upath); */
2194 path->m_name = NULL;
2195 path->u_name = upath;
2197 setfilunixmode(vol, path, destst.st_mode);
2198 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2205 setfilunixmode(vol, path, srcst.st_mode);
2206 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2208 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2209 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2214 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2218 goto err_exchangefile;
2220 /* all this stuff is so that we can unwind a failed operation
2223 /* rename dest to temp */
2224 renamefile(vol, upath, temp, temp, adsp);
2225 of_rename(vol, s_of, curdir, upath, curdir, temp);
2228 /* rename source back to dest */
2229 renamefile(vol, p, upath, path->m_name, addp);
2230 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2233 /* rename temp back to source */
2234 renamefile(vol, temp, p, spath, adsp);
2235 of_rename(vol, s_of, curdir, temp, sdir, spath);
2238 if ( !s_of && adsp && ad_hfileno(adsp) != -1 ) {
2239 ad_flush( adsp, ADFLAGS_HF );
2240 ad_close(adsp, ADFLAGS_HF);
2242 if ( !d_of && addp && ad_hfileno(addp) != -1 ) {
2243 ad_flush( addp, ADFLAGS_HF );
2244 ad_close(addp, ADFLAGS_HF);