2 * $Id: file.c,v 1.92.2.2.2.28 2004-06-15 22:53:54 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 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
73 0, 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)
84 if (adp && (ad_finder = ad_entry(adp, ADEID_FINDERI))) {
85 memcpy(data, ad_finder, 32);
88 memcpy(data, ufinderi, 32);
91 if ((!adp || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 ))
92 && (em = getextmap( mpath ))
94 memcpy(data, em->em_type, sizeof( em->em_type ));
95 memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator));
100 /* ---------------------
102 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8)
107 aint = strlen( name );
111 if (utf8_encoding()) {
112 /* but name is an utf8 mac name */
115 /* global static variable... */
117 if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
126 if (aint > MACFILELEN)
133 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
136 utf8 = vol->v_mac?htonl(vol->v_mac->kTextEncoding):0; /* htonl(utf8) */
137 memcpy(data, &utf8, sizeof(utf8));
138 data += sizeof(utf8);
141 memcpy(data, &temp, sizeof(temp));
142 data += sizeof(temp);
145 memcpy( data, src, aint );
155 * FIXME: PDINFO is UTF8 and doesn't need adp
157 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
158 (1 << FILPBIT_CDATE) |\
159 (1 << FILPBIT_MDATE) |\
160 (1 << FILPBIT_BDATE) |\
161 (1 << FILPBIT_FINFO) |\
162 (1 << FILPBIT_RFLEN) |\
163 (1 << FILPBIT_EXTRFLEN) |\
164 (1 << FILPBIT_PDINFO)))
166 /* -------------------------- */
167 u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st,
168 const cnid_t did, const char *upath, const int len)
172 #if AD_VERSION > AD_VERSION1
176 char stamp[ADEDLEN_PRIVSYN];
177 /* look in AD v2 header
178 * note inode and device are opaques and not in network order
181 && sizeof(dev_t) == ad_getentrylen(adp, ADEID_PRIVDEV)
182 && sizeof(ino_t) == ad_getentrylen(adp,ADEID_PRIVINO)
183 && sizeof(stamp) == ad_getentrylen(adp,ADEID_PRIVSYN)
184 && sizeof(cnid_t) == ad_getentrylen(adp, ADEID_DID)
185 && sizeof(cnid_t) == ad_getentrylen(adp, ADEID_PRIVID)
188 memcpy(&dev, ad_entry(adp, ADEID_PRIVDEV), sizeof(dev_t));
189 memcpy(&ino, ad_entry(adp, ADEID_PRIVINO), sizeof(ino_t));
190 memcpy(stamp, ad_entry(adp, ADEID_PRIVSYN), sizeof(stamp));
191 memcpy(&a_did, ad_entry(adp, ADEID_DID), sizeof(cnid_t));
193 if ( ( (vol->v_flags & AFPVOL_NODEV) || dev == st->st_dev)
194 && ino == st->st_ino && a_did == did
195 && !memcmp(vol->v_stamp, stamp, sizeof(stamp))) {
196 memcpy(&aint, ad_entry(adp, ADEID_PRIVID), sizeof(aint));
201 if (vol->v_cdb != NULL) {
202 aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
203 /* Throw errors if cnid_add fails. */
204 if (aint == CNID_INVALID) {
206 case CNID_ERR_CLOSE: /* the db is closed */
209 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
210 afp_errno = AFPERR_PARAM;
213 afp_errno = AFPERR_PARAM;
216 afp_errno = AFPERR_MISC;
220 #if AD_VERSION > AD_VERSION1
221 else if (adp && sizeof(dev_t) == ADEDLEN_PRIVDEV && sizeof(ino_t) == ADEDLEN_PRIVINO) {
222 /* update the ressource fork
223 * for a folder adp is always null
225 ad_setid(adp,(vol->v_flags & AFPVOL_NODEV)?0:st->st_dev, st->st_ino, aint, did, vol->v_stamp);
226 ad_flush(adp, ADFLAGS_HF);
233 /* -------------------------- */
234 int getmetadata(struct vol *vol,
236 struct path *path, struct dir *dir,
237 char *buf, int *buflen, struct adouble *adp, int attrbits )
239 char *data, *l_nameoff = NULL, *upath;
240 char *utf_nameoff = NULL;
245 u_char achar, fdType[4];
251 LOG(log_info, logtype_afpd, "begin getmetadata:");
254 upath = path->u_name;
259 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
260 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
261 || (bitmap & (1 << FILPBIT_FNUM))) {
263 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
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 (*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 attrbits |= ATTRBIT_NOWRITE;
297 ashort = htons(ntohs(ashort) | attrbits);
298 memcpy(data, &ashort, sizeof( ashort ));
299 data += sizeof( ashort );
303 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
304 data += sizeof( u_int32_t );
308 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
309 aint = AD_DATE_FROM_UNIX(st->st_mtime);
310 memcpy(data, &aint, sizeof( aint ));
311 data += sizeof( aint );
315 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
316 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
317 aint = AD_DATE_FROM_UNIX(st->st_mtime);
320 aint = AD_DATE_FROM_UNIX(st->st_mtime);
322 memcpy(data, &aint, sizeof( int ));
323 data += sizeof( int );
327 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
328 aint = AD_DATE_START;
329 memcpy(data, &aint, sizeof( int ));
330 data += sizeof( int );
334 get_finderinfo(path->m_name, adp, (char *)data);
336 if (*upath == '.') { /* make it invisible */
337 ashort = htons(FINDERINFO_INVISIBLE);
338 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
346 data += sizeof( u_int16_t );
350 memset(data, 0, sizeof(u_int16_t));
351 data += sizeof( u_int16_t );
355 memcpy(data, &id, sizeof( id ));
356 data += sizeof( id );
360 if (st->st_size > 0xffffffff)
363 aint = htonl( st->st_size );
364 memcpy(data, &aint, sizeof( aint ));
365 data += sizeof( aint );
370 if (adp->ad_rlen > 0xffffffff)
373 aint = htonl( adp->ad_rlen);
377 memcpy(data, &aint, sizeof( aint ));
378 data += sizeof( aint );
381 /* Current client needs ProDOS info block for this file.
382 Use simple heuristic and let the Mac "type" string tell
383 us what the PD file code should be. Everything gets a
384 subtype of 0x0000 unless the original value was hashed
385 to "pXYZ" when we created it. See IA, Ver 2.
386 <shirsch@adelphia.net> */
387 case FILPBIT_PDINFO :
388 if (afp_version >= 30) { /* UTF8 name */
389 utf8 = kTextEncodingUTF8;
391 data += sizeof( u_int16_t );
393 memcpy(data, &aint, sizeof( aint ));
394 data += sizeof( aint );
398 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
400 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
404 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
408 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
412 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
416 else if ( fdType[0] == 'p' ) {
418 ashort = (fdType[2] * 256) + fdType[3];
432 memcpy(data, &ashort, sizeof( ashort ));
433 data += sizeof( ashort );
434 memset(data, 0, sizeof( ashort ));
435 data += sizeof( ashort );
438 case FILPBIT_EXTDFLEN:
439 aint = htonl(st->st_size >> 32);
440 memcpy(data, &aint, sizeof( aint ));
441 data += sizeof( aint );
442 aint = htonl(st->st_size);
443 memcpy(data, &aint, sizeof( aint ));
444 data += sizeof( aint );
446 case FILPBIT_EXTRFLEN:
449 aint = htonl(adp->ad_rlen >> 32);
450 memcpy(data, &aint, sizeof( aint ));
451 data += sizeof( aint );
453 aint = htonl(adp->ad_rlen);
454 memcpy(data, &aint, sizeof( aint ));
455 data += sizeof( aint );
457 case FILPBIT_UNIXPR :
458 /* accessmode may change st_mode with ACLs */
459 accessmode( upath, &ma, dir , st);
461 aint = htonl(st->st_uid);
462 memcpy( data, &aint, sizeof( aint ));
463 data += sizeof( aint );
464 aint = htonl(st->st_gid);
465 memcpy( data, &aint, sizeof( aint ));
466 data += sizeof( aint );
468 aint = htonl(st->st_mode);
469 memcpy( data, &aint, sizeof( aint ));
470 data += sizeof( aint );
472 *data++ = ma.ma_user;
473 *data++ = ma.ma_world;
474 *data++ = ma.ma_group;
475 *data++ = ma.ma_owner;
479 return( AFPERR_BITMAP );
485 ashort = htons( data - buf );
486 memcpy(l_nameoff, &ashort, sizeof( ashort ));
487 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
490 ashort = htons( data - buf );
491 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
492 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
494 *buflen = data - buf;
498 /* ----------------------- */
499 int getfilparams(struct vol *vol,
501 struct path *path, struct dir *dir,
502 char *buf, int *buflen )
504 struct adouble ad, *adp;
507 u_int16_t attrbits = 0;
512 LOG(log_info, logtype_default, "begin getfilparams:");
515 opened = PARAM_NEED_ADP(bitmap);
518 upath = path->u_name;
519 if ((of = of_findname(path))) {
521 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
522 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
524 ad_init(&ad, vol->v_adouble);
528 if ( ad_metadata( upath, 0, adp) < 0 ) {
531 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
532 upath, strerror(errno));
533 return AFPERR_ACCESS;
535 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
545 we need to check if the file is open by another process.
546 it's slow so we only do it if we have to:
547 - bitmap is requested.
548 - we don't already have the answer!
550 if ((bitmap & (1 << FILPBIT_ATTR))) {
551 if (!(attrbits & ATTRBIT_ROPEN)) {
552 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_ROPEN : 0;
553 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_ROPEN : 0;
555 if (!(attrbits & ATTRBIT_DOPEN)) {
556 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_DOPEN : 0;
557 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_DOPEN : 0;
562 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
564 ad_close( adp, ADFLAGS_HF );
567 LOG(log_info, logtype_afpd, "end getfilparams:");
573 /* ----------------------------- */
574 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
577 int ibuflen, *rbuflen;
579 struct adouble ad, *adp;
582 struct ofork *of = NULL;
584 int creatf, did, openf, retvalue = AFP_OK;
590 LOG(log_info, logtype_afpd, "begin afp_createfile:");
595 creatf = (unsigned char) *ibuf++;
597 memcpy(&vid, ibuf, sizeof( vid ));
598 ibuf += sizeof( vid );
600 if (NULL == ( vol = getvolbyvid( vid )) ) {
601 return( AFPERR_PARAM );
604 if (vol->v_flags & AFPVOL_RO)
607 memcpy(&did, ibuf, sizeof( did));
608 ibuf += sizeof( did );
610 if (NULL == ( dir = dirlookup( vol, did )) ) {
614 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
615 return get_afp_errno(AFPERR_PARAM);
618 if ( *s_path->m_name == '\0' ) {
619 return( AFPERR_BADTYPE );
622 upath = s_path->u_name;
623 if (0 != (ret = check_name(vol, upath)))
626 /* if upath is deleted we already in trouble anyway */
627 if ((of = of_findname(s_path))) {
630 ad_init(&ad, vol->v_adouble);
634 /* on a hard create, fail if file exists and is open */
637 openf = O_RDWR|O_CREAT|O_TRUNC;
639 /* on a soft create, if the file is open then ad_open won't fail
640 because open syscall is not called
645 openf = O_RDWR|O_CREAT|O_EXCL;
648 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
649 openf, 0666, adp) < 0 ) {
653 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
654 return ( AFPERR_NOOBJ );
656 return( AFPERR_EXIST );
658 return( AFPERR_ACCESS );
660 return( AFPERR_PARAM );
663 if ( ad_hfileno( adp ) == -1 ) {
664 /* on noadouble volumes, just creating the data fork is ok */
665 if (vol_noadouble(vol)) {
666 ad_close( adp, ADFLAGS_DF );
667 goto createfile_done;
669 /* FIXME with hard create on an existing file, we already
670 * corrupted the data file.
672 netatalk_unlink( upath );
673 ad_close( adp, ADFLAGS_DF );
674 return AFPERR_ACCESS;
677 path = s_path->m_name;
678 ad_setname(adp, path);
679 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
680 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
686 if (vol->v_flags & AFPVOL_DROPBOX) {
687 retvalue = matchfile2dirperms(upath, vol, did);
689 #endif /* DROPKLUDGE */
691 setvoltime(obj, vol );
694 LOG(log_info, logtype_afpd, "end afp_createfile");
700 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
703 int ibuflen, *rbuflen;
709 u_int16_t vid, bitmap;
712 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
718 memcpy(&vid, ibuf, sizeof( vid ));
719 ibuf += sizeof( vid );
720 if (NULL == ( vol = getvolbyvid( vid )) ) {
721 return( AFPERR_PARAM );
724 if (vol->v_flags & AFPVOL_RO)
727 memcpy(&did, ibuf, sizeof( did ));
728 ibuf += sizeof( did );
729 if (NULL == ( dir = dirlookup( vol, did )) ) {
730 return afp_errno; /* was AFPERR_NOOBJ */
733 memcpy(&bitmap, ibuf, sizeof( bitmap ));
734 bitmap = ntohs( bitmap );
735 ibuf += sizeof( bitmap );
737 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
738 return get_afp_errno(AFPERR_PARAM);
741 if (path_isadir(s_path)) {
742 return( AFPERR_BADTYPE ); /* it's a directory */
745 if ( s_path->st_errno != 0 ) {
746 return( AFPERR_NOOBJ );
749 if ((u_long)ibuf & 1 ) {
753 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
754 setvoltime(obj, vol );
758 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
765 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
768 extern struct path Cur_Path;
770 int setfilparams(struct vol *vol,
771 struct path *path, u_int16_t f_bitmap, char *buf )
773 struct adouble ad, *adp;
776 int bit, isad = 1, err = AFP_OK;
778 u_char achar, *fdType, xyy[4];
779 u_int16_t ashort, bshort;
782 u_int16_t upriv_bit = 0;
786 int change_mdate = 0;
787 int change_parent_mdate = 0;
792 u_int16_t bitmap = f_bitmap;
793 u_int32_t cdate,bdate;
794 u_char finder_buf[32];
797 LOG(log_info, logtype_afpd, "begin setfilparams:");
800 upath = path->u_name;
801 if ((of = of_findname(path))) {
804 ad_init(&ad, vol->v_adouble);
808 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
809 return AFPERR_ACCESS;
812 /* with unix priv maybe we have to change adouble file priv first */
814 while ( bitmap != 0 ) {
815 while (( bitmap & 1 ) == 0 ) {
822 memcpy(&ashort, buf, sizeof( ashort ));
823 buf += sizeof( ashort );
827 memcpy(&cdate, buf, sizeof(cdate));
828 buf += sizeof( cdate );
831 memcpy(&newdate, buf, sizeof( newdate ));
832 buf += sizeof( newdate );
836 memcpy(&bdate, buf, sizeof( bdate));
837 buf += sizeof( bdate );
841 memcpy(finder_buf, buf, 32 );
844 case FILPBIT_UNIXPR :
845 if (!vol_unix_priv(vol)) {
846 /* this volume doesn't use unix priv */
852 change_parent_mdate = 1;
854 memcpy( &aint, buf, sizeof( aint ));
855 f_uid = ntohl (aint);
856 buf += sizeof( aint );
857 memcpy( &aint, buf, sizeof( aint ));
858 f_gid = ntohl (aint);
859 buf += sizeof( aint );
860 setfilowner(vol, f_uid, f_gid, path);
862 memcpy( &upriv, buf, sizeof( upriv ));
863 buf += sizeof( upriv );
864 upriv = ntohl (upriv);
865 if ((upriv & S_IWUSR)) {
866 setfilunixmode(vol, path, upriv);
873 case FILPBIT_PDINFO :
874 if (afp_version < 30) { /* else it's UTF8 name */
877 /* Keep special case to support crlf translations */
878 if ((unsigned int) achar == 0x04) {
879 fdType = (u_char *)"TEXT";
882 xyy[0] = ( u_char ) 'p';
893 /* break while loop */
902 /* second try with adouble open
904 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
905 O_RDWR|O_CREAT, 0666, adp) < 0) {
906 /* for some things, we don't need an adouble header */
907 if (f_bitmap & ~(1<<FILPBIT_MDATE)) {
908 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
911 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
912 ad_setname(adp, path->m_name);
917 while ( bitmap != 0 ) {
918 while (( bitmap & 1 ) == 0 ) {
925 ad_getattr(adp, &bshort);
926 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
927 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
928 change_parent_mdate = 1;
929 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
930 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
934 ad_setattr(adp, bshort);
937 ad_setdate(adp, AD_DATE_CREATE, cdate);
942 ad_setdate(adp, AD_DATE_BACKUP, bdate);
945 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
947 ((em = getextmap( path->m_name )) &&
948 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
949 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
950 || ((em = getdefextmap()) &&
951 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
952 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
954 memcpy(finder_buf, ufinderi, 8 );
957 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
959 case FILPBIT_UNIXPR :
961 setfilunixmode(vol, path, upriv);
964 case FILPBIT_PDINFO :
965 if (afp_version < 30) { /* else it's UTF8 name */
966 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
967 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
973 goto setfilparam_done;
980 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
981 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
985 ad_setdate(adp, AD_DATE_MODIFY, newdate);
986 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
991 ad_flush( adp, ADFLAGS_HF );
992 ad_close( adp, ADFLAGS_HF );
996 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
997 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
998 bitmap = 1<<FILPBIT_MDATE;
999 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
1003 LOG(log_info, logtype_afpd, "end setfilparams:");
1009 * renamefile and copyfile take the old and new unix pathnames
1010 * and the new mac name.
1012 * src the source path
1013 * dst the dest filename in current dir
1014 * newname the dest mac name
1015 * adp adouble struct of src file, if open, or & zeroed one
1018 int renamefile(vol, src, dst, newname, adp )
1019 const struct vol *vol;
1020 char *src, *dst, *newname;
1021 struct adouble *adp;
1023 char adsrc[ MAXPATHLEN + 1];
1027 LOG(log_info, logtype_afpd, "begin renamefile:");
1030 if ( unix_rename( src, dst ) < 0 ) {
1033 return( AFPERR_NOOBJ );
1036 return( AFPERR_ACCESS );
1038 return AFPERR_VLOCK;
1039 case EXDEV : /* Cross device move -- try copy */
1040 /* NOTE: with open file it's an error because after the copy we will
1041 * get two files, it's fixable for our process (eg reopen the new file, get the
1042 * locks, and so on. But it doesn't solve the case with a second process
1044 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
1045 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1046 return AFPERR_OLOCK; /* little lie */
1048 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname )) ) {
1049 /* on error copyfile delete dest */
1052 return deletefile(vol, src, 0);
1054 return( AFPERR_PARAM );
1058 strcpy( adsrc, vol->ad_path( src, 0 ));
1060 if (unix_rename( adsrc, vol->ad_path( dst, 0 )) < 0 ) {
1065 if (errno == ENOENT) {
1068 if (stat(adsrc, &st)) /* source has no ressource fork, */
1071 /* We are here because :
1072 * -there's no dest folder.
1073 * -there's no .AppleDouble in the dest folder.
1074 * if we use the struct adouble passed in parameter it will not
1075 * create .AppleDouble if the file is already opened, so we
1076 * use a diff one, it's not a pb,ie it's not the same file, yet.
1078 ad_init(&ad, vol->v_adouble);
1079 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
1080 ad_close(&ad, ADFLAGS_HF);
1081 if (!unix_rename( adsrc, vol->ad_path( dst, 0 )) )
1086 else { /* it's something else, bail out */
1090 /* try to undo the data fork rename,
1091 * we know we are on the same device
1094 unix_rename( dst, src );
1095 /* return the first error */
1098 return AFPERR_NOOBJ;
1101 return AFPERR_ACCESS ;
1103 return AFPERR_VLOCK;
1105 return AFPERR_PARAM ;
1110 /* don't care if we can't open the newly renamed ressource fork
1112 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1113 ad_setname(adp, newname);
1114 ad_flush( adp, ADFLAGS_HF );
1115 ad_close( adp, ADFLAGS_HF );
1118 LOG(log_info, logtype_afpd, "end renamefile:");
1124 int copy_path_name(char *newname, char *ibuf)
1131 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1137 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1138 strncpy( newname, ibuf, plen );
1139 newname[ plen ] = '\0';
1140 if (strlen(newname) != plen) {
1141 /* there's \0 in newname, e.g. it's a pathname not
1149 memcpy(&hint, ibuf, sizeof(hint));
1150 ibuf += sizeof(hint);
1152 memcpy(&len16, ibuf, sizeof(len16));
1153 ibuf += sizeof(len16);
1154 plen = ntohs(len16);
1157 if (plen > AFPOBJ_TMPSIZ) {
1160 strncpy( newname, ibuf, plen );
1161 newname[ plen ] = '\0';
1162 if (strlen(newname) != plen) {
1171 /* -----------------------------------
1173 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1176 int ibuflen, *rbuflen;
1178 struct vol *s_vol, *d_vol;
1180 char *newname, *p, *upath;
1181 struct path *s_path;
1182 u_int32_t sdid, ddid;
1183 int err, retvalue = AFP_OK;
1184 u_int16_t svid, dvid;
1187 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1193 memcpy(&svid, ibuf, sizeof( svid ));
1194 ibuf += sizeof( svid );
1195 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1196 return( AFPERR_PARAM );
1199 memcpy(&sdid, ibuf, sizeof( sdid ));
1200 ibuf += sizeof( sdid );
1201 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1205 memcpy(&dvid, ibuf, sizeof( dvid ));
1206 ibuf += sizeof( dvid );
1207 memcpy(&ddid, ibuf, sizeof( ddid ));
1208 ibuf += sizeof( ddid );
1210 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1211 return get_afp_errno(AFPERR_PARAM);
1213 if ( path_isadir(s_path) ) {
1214 return( AFPERR_BADTYPE );
1217 /* don't allow copies when the file is open.
1218 * XXX: the spec only calls for read/deny write access.
1219 * however, copyfile doesn't have any of that info,
1220 * and locks need to stay coherent. as a result,
1221 * we just balk if the file is opened already. */
1223 newname = obj->newtmp;
1224 strcpy( newname, s_path->m_name );
1226 if (of_findname(s_path))
1227 return AFPERR_DENYCONF;
1229 p = ctoupath( s_vol, curdir, newname );
1231 return AFPERR_PARAM;
1235 /* FIXME svid != dvid && dvid's user can't read svid */
1237 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1238 return( AFPERR_PARAM );
1241 if (d_vol->v_flags & AFPVOL_RO)
1242 return AFPERR_VLOCK;
1244 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1248 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1249 return get_afp_errno(AFPERR_NOOBJ);
1251 if ( *s_path->m_name != '\0' ) {
1252 path_error(s_path, AFPERR_PARAM);
1255 /* one of the handful of places that knows about the path type */
1256 if (copy_path_name(newname, ibuf) < 0) {
1257 return( AFPERR_PARAM );
1259 /* newname is always only a filename so curdir *is* its
1262 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1263 return( AFPERR_PARAM );
1265 if ( (err = copyfile(s_vol, d_vol, p, upath , newname)) < 0 ) {
1271 if (vol->v_flags & AFPVOL_DROPBOX) {
1272 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1274 #endif /* DROPKLUDGE */
1276 setvoltime(obj, d_vol );
1279 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1285 /* ----------------------- */
1286 static __inline__ int copy_all(const int dfd, const void *buf,
1292 LOG(log_info, logtype_afpd, "begin copy_all:");
1295 while (buflen > 0) {
1296 if ((cc = write(dfd, buf, buflen)) < 0) {
1308 LOG(log_info, logtype_afpd, "end copy_all:");
1314 /* -------------------------- */
1315 static int copy_fd(int dfd, int sfd)
1321 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1322 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1326 #define BUF 128*1024*1024
1328 if (fstat(sfd, &st) == 0) {
1331 if ( offset >= st.st_size) {
1334 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1335 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1338 case EINVAL: /* there's no guarantee that all fs support sendfile */
1347 lseek(sfd, offset, SEEK_SET);
1351 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1358 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1365 /* ----------------------------------
1366 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1367 * because we are doing it elsewhere.
1369 int copyfile(s_vol, d_vol, src, dst, newname )
1370 const struct vol *s_vol, *d_vol;
1371 char *src, *dst, *newname;
1373 struct adouble ads, add;
1377 int noadouble = vol_noadouble(d_vol);
1381 LOG(log_info, logtype_afpd, "begin copyfile:");
1384 ad_init(&ads, s_vol->v_adouble);
1385 ad_init(&add, d_vol->v_adouble);
1386 adflags = ADFLAGS_DF;
1388 adflags |= ADFLAGS_HF;
1391 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1396 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1398 ad_close( &ads, adflags );
1399 if (EEXIST != ret_err) {
1400 deletefile(d_vol, dst, 0);
1403 return AFPERR_EXIST;
1405 if (ad_hfileno(&ads) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1406 /* copy the data fork */
1407 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1410 /* Now, reopen destination file */
1414 ad_close( &ads, adflags );
1416 if (ad_close( &add, adflags ) <0) {
1417 deletefile(d_vol, dst, 0);
1422 ad_init(&add, d_vol->v_adouble);
1423 if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
1428 if (!ret_err && newname) {
1429 ad_setname(&add, newname);
1432 ad_flush( &add, adflags );
1433 if (ad_close( &add, adflags ) <0) {
1437 deletefile(d_vol, dst, 0);
1440 /* set dest modification date to src date */
1441 if (!stat(src, &st)) {
1444 ut.actime = ut.modtime = st.st_mtime;
1449 LOG(log_info, logtype_afpd, "end copyfile:");
1453 switch ( ret_err ) {
1459 return AFPERR_DFULL;
1461 return AFPERR_NOOBJ;
1463 return AFPERR_ACCESS;
1465 return AFPERR_VLOCK;
1467 return AFPERR_PARAM;
1471 /* -----------------------------------
1472 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1473 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1475 when deletefile is called we don't have lock on it, file is closed (for us)
1476 untrue if called by renamefile
1478 ad_open always try to open file RDWR first and ad_lock takes care of
1479 WRITE lock on read only file.
1481 int deletefile( vol, file, checkAttrib )
1482 const struct vol *vol;
1487 struct adouble *adp = &ad;
1488 int adflags, err = AFP_OK;
1491 LOG(log_info, logtype_afpd, "begin deletefile:");
1494 /* try to open both forks at once */
1495 adflags = ADFLAGS_DF|ADFLAGS_HF;
1497 ad_init(&ad, vol->v_adouble); /* OK */
1498 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1501 if (adflags == ADFLAGS_DF)
1502 return AFPERR_NOOBJ;
1504 /* that failed. now try to open just the data fork */
1505 adflags = ADFLAGS_DF;
1509 adp = NULL; /* maybe it's a file we no rw mode for us */
1510 break; /* was return AFPERR_ACCESS;*/
1512 return AFPERR_VLOCK;
1514 return( AFPERR_PARAM );
1517 break; /* from the while */
1520 * Does kFPDeleteInhibitBit (bit 8) set?
1525 if (adp && (adflags & ADFLAGS_HF)) {
1527 ad_getattr(&ad, &bshort);
1528 if ((bshort & htons(ATTRBIT_NODELETE))) {
1529 ad_close( &ad, adflags );
1530 return(AFPERR_OLOCK);
1534 /* was EACCESS error try to get only metadata */
1535 ad_init(&ad, vol->v_adouble); /* OK */
1536 if ( ad_metadata( file , 0, &ad) == 0 ) {
1537 ad_getattr(&ad, &bshort);
1538 ad_close( &ad, ADFLAGS_HF );
1539 if ((bshort & htons(ATTRBIT_NODELETE))) {
1540 return AFPERR_OLOCK;
1546 if (adp && (adflags & ADFLAGS_HF) ) {
1547 /* FIXME we have a pb here because we want to know if a file is open
1548 * there's a 'priority inversion' if you can't open the ressource fork RW
1549 * you can delete it if it's open because you can't get a write lock.
1551 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1554 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1556 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1557 ad_close( &ad, adflags );
1558 return( AFPERR_BUSY );
1562 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1565 else if (!(err = netatalk_unlink( vol->ad_path( file, ADFLAGS_HF)) ) &&
1566 !(err = netatalk_unlink( file )) ) {
1568 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1570 cnid_delete(vol->v_cdb, id);
1575 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1578 LOG(log_info, logtype_afpd, "end deletefile:");
1584 /* ------------------------------------ */
1585 /* return a file id */
1586 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1589 int ibuflen, *rbuflen;
1598 struct path *s_path;
1601 LOG(log_info, logtype_afpd, "begin afp_createid:");
1608 memcpy(&vid, ibuf, sizeof(vid));
1609 ibuf += sizeof(vid);
1611 if (NULL == ( vol = getvolbyvid( vid )) ) {
1612 return( AFPERR_PARAM);
1615 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1619 if (vol->v_flags & AFPVOL_RO)
1620 return AFPERR_VLOCK;
1622 memcpy(&did, ibuf, sizeof( did ));
1623 ibuf += sizeof(did);
1625 if (NULL == ( dir = dirlookup( vol, did )) ) {
1626 return afp_errno; /* was AFPERR_PARAM */
1629 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1630 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1633 if ( path_isadir(s_path) ) {
1634 return( AFPERR_BADTYPE );
1637 upath = s_path->u_name;
1638 switch (s_path->st_errno) {
1640 break; /* success */
1643 return AFPERR_ACCESS;
1645 return AFPERR_NOOBJ;
1647 return AFPERR_PARAM;
1650 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1651 memcpy(rbuf, &id, sizeof(id));
1652 *rbuflen = sizeof(id);
1653 return AFPERR_EXISTID;
1656 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1657 memcpy(rbuf, &id, sizeof(id));
1658 *rbuflen = sizeof(id);
1663 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1669 reenumerate_id(const struct vol *vol, char *name, cnid_t did)
1677 memset(&path, 0, sizeof(path));
1678 if (vol->v_cdb == NULL) {
1681 if (NULL == ( dp = opendir( name)) ) {
1685 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
1686 if (NULL == check_dirent(vol, de->d_name))
1689 if ( stat(de->d_name, &path.st)<0 )
1692 /* update or add to cnid */
1693 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1695 #if AD_VERSION > AD_VERSION1
1696 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1698 struct adouble ad, *adp;
1702 path.u_name = de->d_name;
1704 if (!(of = of_findname(&path))) {
1705 ad_init(&ad, vol->v_adouble);
1710 if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, adp ) < 0 ) {
1713 ad_setid(adp,(vol->v_flags & AFPVOL_NODEV)?0:path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp);
1714 ad_flush(adp, ADFLAGS_HF);
1715 ad_close(adp, ADFLAGS_HF);
1717 #endif /* AD_VERSION > AD_VERSION1 */
1726 /* ------------------------------
1727 resolve a file id */
1728 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1731 int ibuflen, *rbuflen;
1737 int err, buflen, retry=0;
1739 u_int16_t vid, bitmap;
1741 static char buffer[12 + MAXPATHLEN + 1];
1742 int len = 12 + MAXPATHLEN + 1;
1745 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1751 memcpy(&vid, ibuf, sizeof(vid));
1752 ibuf += sizeof(vid);
1754 if (NULL == ( vol = getvolbyvid( vid )) ) {
1755 return( AFPERR_PARAM);
1758 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1762 memcpy(&id, ibuf, sizeof( id ));
1767 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1768 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1771 if (NULL == ( dir = dirlookup( vol, id )) ) {
1772 return AFPERR_NOID; /* idem AFPERR_PARAM */
1774 path.u_name = upath;
1775 if (movecwd(vol, dir) < 0) {
1779 return AFPERR_ACCESS;
1783 return AFPERR_PARAM;
1787 if ( of_stat(&path) < 0 ) {
1789 /* with nfs and our working directory is deleted */
1790 if (errno == ESTALE) {
1794 if ( errno == ENOENT && !retry) {
1795 /* cnid db is out of sync, reenumerate the directory and updated ids */
1796 reenumerate_id(vol, ".", id);
1804 return AFPERR_ACCESS;
1808 return AFPERR_PARAM;
1812 /* directories are bad */
1813 if (S_ISDIR(path.st.st_mode))
1814 return AFPERR_BADTYPE;
1816 memcpy(&bitmap, ibuf, sizeof(bitmap));
1817 bitmap = ntohs( bitmap );
1818 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1821 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1822 rbuf + sizeof(bitmap), &buflen))) {
1825 *rbuflen = buflen + sizeof(bitmap);
1826 memcpy(rbuf, ibuf, sizeof(bitmap));
1829 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1835 /* ------------------------------ */
1836 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1839 int ibuflen, *rbuflen;
1849 static char buffer[12 + MAXPATHLEN + 1];
1850 int len = 12 + MAXPATHLEN + 1;
1853 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1859 memcpy(&vid, ibuf, sizeof(vid));
1860 ibuf += sizeof(vid);
1862 if (NULL == ( vol = getvolbyvid( vid )) ) {
1863 return( AFPERR_PARAM);
1866 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1870 if (vol->v_flags & AFPVOL_RO)
1871 return AFPERR_VLOCK;
1873 memcpy(&id, ibuf, sizeof( id ));
1877 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1881 if (NULL == ( dir = dirlookup( vol, id )) ) {
1882 return( AFPERR_PARAM );
1886 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1890 return AFPERR_ACCESS;
1895 /* still try to delete the id */
1899 return AFPERR_PARAM;
1902 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1903 return AFPERR_BADTYPE;
1905 if (cnid_delete(vol->v_cdb, fileid)) {
1908 return AFPERR_VLOCK;
1911 return AFPERR_ACCESS;
1913 return AFPERR_PARAM;
1918 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1924 /* ------------------------------ */
1925 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1929 if (path->st_errno) {
1930 switch (path->st_errno) {
1932 afp_errno = AFPERR_NOID;
1936 afp_errno = AFPERR_ACCESS;
1939 afp_errno = AFPERR_PARAM;
1944 /* we use file_access both for legacy Mac perm and
1945 * for unix privilege, rename will take care of folder perms
1947 if (file_access(path, OPENACC_WR ) < 0) {
1948 afp_errno = AFPERR_ACCESS;
1952 if ((*of = of_findname(path))) {
1953 /* reuse struct adouble so it won't break locks */
1957 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
1958 if ( !ret && ad_hfileno(adp) != -1 && !(adp->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) {
1960 * The user must have the Read & Write privilege for both files in order to use this command.
1962 ad_close(adp, ADFLAGS_HF);
1963 afp_errno = AFPERR_ACCESS;
1970 #define APPLETEMP ".AppleTempXXXXXX"
1972 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1975 int ibuflen, *rbuflen;
1977 struct stat srcst, destst;
1979 struct dir *dir, *sdir;
1980 char *spath, temp[17], *p;
1981 char *supath, *upath;
1986 struct adouble *adsp = NULL;
1987 struct adouble *addp = NULL;
1988 struct ofork *s_of = NULL;
1989 struct ofork *d_of = NULL;
2000 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
2006 memcpy(&vid, ibuf, sizeof(vid));
2007 ibuf += sizeof(vid);
2009 if (NULL == ( vol = getvolbyvid( vid )) ) {
2010 return( AFPERR_PARAM);
2013 if ((vol->v_flags & AFPVOL_RO))
2014 return AFPERR_VLOCK;
2016 /* source and destination dids */
2017 memcpy(&sid, ibuf, sizeof(sid));
2018 ibuf += sizeof(sid);
2019 memcpy(&did, ibuf, sizeof(did));
2020 ibuf += sizeof(did);
2023 if (NULL == (dir = dirlookup( vol, sid )) ) {
2024 return afp_errno; /* was AFPERR_PARAM */
2027 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2028 return get_afp_errno(AFPERR_NOOBJ);
2031 if ( path_isadir(path) ) {
2032 return AFPERR_BADTYPE; /* it's a dir */
2035 /* save some stuff */
2038 spath = obj->oldtmp;
2039 supath = obj->newtmp;
2040 strcpy(spath, path->m_name);
2041 strcpy(supath, path->u_name); /* this is for the cnid changing */
2042 p = absupath( vol, sdir, supath);
2044 /* pathname too long */
2045 return AFPERR_PARAM ;
2048 ad_init(&ads, vol->v_adouble);
2049 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2053 /* ***** from here we may have resource fork open **** */
2055 /* look for the source cnid. if it doesn't exist, don't worry about
2057 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2059 if (NULL == ( dir = dirlookup( vol, did )) ) {
2060 err = afp_errno; /* was AFPERR_PARAM */
2061 goto err_exchangefile;
2064 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2065 err = get_afp_errno(AFPERR_NOOBJ);
2066 goto err_exchangefile;
2069 if ( path_isadir(path) ) {
2070 err = AFPERR_BADTYPE;
2071 goto err_exchangefile;
2074 /* FPExchangeFiles is the only call that can return the SameObj
2076 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2077 err = AFPERR_SAMEOBJ;
2078 goto err_exchangefile;
2081 ad_init(&add, vol->v_adouble);
2082 if (!(addp = find_adouble( path, &d_of, &add))) {
2084 goto err_exchangefile;
2088 /* they are not on the same device and at least one is open
2089 * FIXME broken for for crossdev and adouble v2
2092 crossdev = (srcst.st_dev != destst.st_dev);
2093 if (/* (d_of || s_of) && */ crossdev) {
2095 goto err_exchangefile;
2098 /* look for destination id. */
2099 upath = path->u_name;
2100 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2102 /* construct a temp name.
2103 * NOTE: the temp file will be in the dest file's directory. it
2104 * will also be inaccessible from AFP. */
2105 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2106 if (!mktemp(temp)) {
2108 goto err_exchangefile;
2112 /* we need to close fork for copy, both s_of and d_of are null */
2113 ad_close(adsp, ADFLAGS_HF);
2114 ad_close(addp, ADFLAGS_HF);
2117 /* now, quickly rename the file. we error if we can't. */
2118 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2119 goto err_exchangefile;
2120 of_rename(vol, s_of, sdir, spath, curdir, temp);
2122 /* rename destination to source */
2123 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2124 goto err_src_to_tmp;
2125 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2127 /* rename temp to destination */
2128 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2129 goto err_dest_to_src;
2130 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2132 /* id's need switching. src -> dest and dest -> src.
2133 * we need to re-stat() if it was a cross device copy.
2136 cnid_delete(vol->v_cdb, sid);
2139 cnid_delete(vol->v_cdb, did);
2141 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2142 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2144 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2145 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2150 err = AFPERR_ACCESS;
2155 goto err_temp_to_dest;
2158 /* here we need to reopen if crossdev */
2160 ad_setid(addp,(vol->v_flags & AFPVOL_NODEV)?0:destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp);
2162 ad_setid(adsp,(vol->v_flags & AFPVOL_NODEV)?0:srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp);
2164 /* change perms, src gets dest perm and vice versa */
2169 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2170 err = AFP_OK; /* ignore error */
2171 goto err_temp_to_dest;
2175 * we need to exchange ACL entries as well
2177 /* exchange_acls(vol, p, upath); */
2182 path->m_name = NULL;
2183 path->u_name = upath;
2185 setfilunixmode(vol, path, destst.st_mode);
2186 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2193 setfilunixmode(vol, path, srcst.st_mode);
2194 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2196 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2197 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2202 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2206 goto err_exchangefile;
2208 /* all this stuff is so that we can unwind a failed operation
2211 /* rename dest to temp */
2212 renamefile(vol, upath, temp, temp, adsp);
2213 of_rename(vol, s_of, curdir, upath, curdir, temp);
2216 /* rename source back to dest */
2217 renamefile(vol, p, upath, path->m_name, addp);
2218 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2221 /* rename temp back to source */
2222 renamefile(vol, temp, p, spath, adsp);
2223 of_rename(vol, s_of, curdir, temp, sdir, spath);
2226 if ( !s_of && adsp && ad_hfileno(adsp) != -1 ) {
2227 ad_flush( adsp, ADFLAGS_HF );
2228 ad_close(adsp, ADFLAGS_HF);
2230 if ( !d_of && addp && ad_hfileno(addp) != -1 ) {
2231 ad_flush( addp, ADFLAGS_HF );
2232 ad_close(addp, ADFLAGS_HF);