2 * $Id: file.c,v 1.92.2.2.2.31.2.6 2004-12-09 16:10: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 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;
782 int bit, isad = 1, err = AFP_OK;
784 u_char achar, *fdType, xyy[4];
785 u_int16_t ashort, bshort;
788 u_int16_t upriv_bit = 0;
792 int change_mdate = 0;
793 int change_parent_mdate = 0;
798 u_int16_t bitmap = f_bitmap;
799 u_int32_t cdate,bdate;
800 u_char finder_buf[32];
803 LOG(log_info, logtype_afpd, "begin setfilparams:");
806 upath = path->u_name;
807 adp = of_ad(vol, path, &ad);
810 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
811 return AFPERR_ACCESS;
814 /* with unix priv maybe we have to change adouble file priv first */
816 while ( bitmap != 0 ) {
817 while (( bitmap & 1 ) == 0 ) {
824 memcpy(&ashort, buf, sizeof( ashort ));
825 buf += sizeof( ashort );
829 memcpy(&cdate, buf, sizeof(cdate));
830 buf += sizeof( cdate );
833 memcpy(&newdate, buf, sizeof( newdate ));
834 buf += sizeof( newdate );
838 memcpy(&bdate, buf, sizeof( bdate));
839 buf += sizeof( bdate );
843 memcpy(finder_buf, buf, 32 );
846 case FILPBIT_UNIXPR :
847 if (!vol_unix_priv(vol)) {
848 /* this volume doesn't use unix priv */
854 change_parent_mdate = 1;
856 memcpy( &aint, buf, sizeof( aint ));
857 f_uid = ntohl (aint);
858 buf += sizeof( aint );
859 memcpy( &aint, buf, sizeof( aint ));
860 f_gid = ntohl (aint);
861 buf += sizeof( aint );
862 setfilowner(vol, f_uid, f_gid, path);
864 memcpy( &upriv, buf, sizeof( upriv ));
865 buf += sizeof( upriv );
866 upriv = ntohl (upriv);
867 if ((upriv & S_IWUSR)) {
868 setfilunixmode(vol, path, upriv);
875 case FILPBIT_PDINFO :
876 if (afp_version < 30) { /* else it's UTF8 name */
879 /* Keep special case to support crlf translations */
880 if ((unsigned int) achar == 0x04) {
881 fdType = (u_char *)"TEXT";
884 xyy[0] = ( u_char ) 'p';
895 /* break while loop */
904 /* second try with adouble open
906 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
907 O_RDWR|O_CREAT, 0666, adp) < 0) {
908 /* for some things, we don't need an adouble header */
909 if (f_bitmap & ~(1<<FILPBIT_MDATE)) {
910 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
913 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
914 ad_setname(adp, path->m_name);
919 while ( bitmap != 0 ) {
920 while (( bitmap & 1 ) == 0 ) {
927 ad_getattr(adp, &bshort);
928 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
929 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
930 change_parent_mdate = 1;
931 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
932 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
936 ad_setattr(adp, bshort);
939 ad_setdate(adp, AD_DATE_CREATE, cdate);
944 ad_setdate(adp, AD_DATE_BACKUP, bdate);
947 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
949 ((em = getextmap( path->m_name )) &&
950 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
951 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
952 || ((em = getdefextmap()) &&
953 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
954 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
956 memcpy(finder_buf, ufinderi, 8 );
958 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
960 case FILPBIT_UNIXPR :
962 setfilunixmode(vol, path, upriv);
965 case FILPBIT_PDINFO :
966 if (afp_version < 30) { /* else it's UTF8 name */
967 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
968 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
974 goto setfilparam_done;
981 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
982 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
986 ad_setdate(adp, AD_DATE_MODIFY, newdate);
987 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
992 ad_flush( adp, ADFLAGS_HF );
993 ad_close( adp, ADFLAGS_HF );
997 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
998 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
999 bitmap = 1<<FILPBIT_MDATE;
1000 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
1004 LOG(log_info, logtype_afpd, "end setfilparams:");
1010 * renamefile and copyfile take the old and new unix pathnames
1011 * and the new mac name.
1013 * src the source path
1014 * dst the dest filename in current dir
1015 * newname the dest mac name
1016 * adp adouble struct of src file, if open, or & zeroed one
1019 int renamefile(vol, src, dst, newname, adp )
1020 const struct vol *vol;
1021 char *src, *dst, *newname;
1022 struct adouble *adp;
1024 char adsrc[ MAXPATHLEN + 1];
1028 LOG(log_info, logtype_afpd, "begin renamefile:");
1031 if ( unix_rename( src, dst ) < 0 ) {
1034 return( AFPERR_NOOBJ );
1037 return( AFPERR_ACCESS );
1039 return AFPERR_VLOCK;
1040 case EXDEV : /* Cross device move -- try copy */
1041 /* NOTE: with open file it's an error because after the copy we will
1042 * get two files, it's fixable for our process (eg reopen the new file, get the
1043 * locks, and so on. But it doesn't solve the case with a second process
1045 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
1046 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1047 return AFPERR_OLOCK; /* little lie */
1049 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1050 /* on error copyfile delete dest */
1053 return deletefile(vol, src, 0);
1055 return( AFPERR_PARAM );
1059 strcpy( adsrc, vol->ad_path( src, 0 ));
1061 if (unix_rename( adsrc, vol->ad_path( dst, 0 )) < 0 ) {
1066 if (errno == ENOENT) {
1069 if (stat(adsrc, &st)) /* source has no ressource fork, */
1072 /* We are here because :
1073 * -there's no dest folder.
1074 * -there's no .AppleDouble in the dest folder.
1075 * if we use the struct adouble passed in parameter it will not
1076 * create .AppleDouble if the file is already opened, so we
1077 * use a diff one, it's not a pb,ie it's not the same file, yet.
1079 ad_init(&ad, vol->v_adouble);
1080 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
1081 ad_close(&ad, ADFLAGS_HF);
1082 if (!unix_rename( adsrc, vol->ad_path( dst, 0 )) )
1087 else { /* it's something else, bail out */
1091 /* try to undo the data fork rename,
1092 * we know we are on the same device
1095 unix_rename( dst, src );
1096 /* return the first error */
1099 return AFPERR_NOOBJ;
1102 return AFPERR_ACCESS ;
1104 return AFPERR_VLOCK;
1106 return AFPERR_PARAM ;
1111 /* don't care if we can't open the newly renamed ressource fork
1113 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1114 ad_setname(adp, newname);
1115 ad_flush( adp, ADFLAGS_HF );
1116 ad_close( adp, ADFLAGS_HF );
1119 LOG(log_info, logtype_afpd, "end renamefile:");
1126 convert a Mac long name to an utf8 name,
1128 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1132 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1138 /* ---------------- */
1139 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1146 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1152 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1153 if (afp_version >= 30) {
1154 /* convert it to UTF8
1156 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == -1)
1160 strncpy( newname, ibuf, plen );
1161 newname[ plen ] = '\0';
1163 if (strlen(newname) != plen) {
1164 /* there's \0 in newname, e.g. it's a pathname not
1172 memcpy(&hint, ibuf, sizeof(hint));
1173 ibuf += sizeof(hint);
1175 memcpy(&len16, ibuf, sizeof(len16));
1176 ibuf += sizeof(len16);
1177 plen = ntohs(len16);
1180 if (plen > AFPOBJ_TMPSIZ) {
1183 strncpy( newname, ibuf, plen );
1184 newname[ plen ] = '\0';
1185 if (strlen(newname) != plen) {
1194 /* -----------------------------------
1196 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1199 int ibuflen, *rbuflen;
1201 struct vol *s_vol, *d_vol;
1203 char *newname, *p, *upath;
1204 struct path *s_path;
1205 u_int32_t sdid, ddid;
1206 int err, retvalue = AFP_OK;
1207 u_int16_t svid, dvid;
1209 struct adouble ad, *adp;
1213 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1219 memcpy(&svid, ibuf, sizeof( svid ));
1220 ibuf += sizeof( svid );
1221 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1222 return( AFPERR_PARAM );
1225 memcpy(&sdid, ibuf, sizeof( sdid ));
1226 ibuf += sizeof( sdid );
1227 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1231 memcpy(&dvid, ibuf, sizeof( dvid ));
1232 ibuf += sizeof( dvid );
1233 memcpy(&ddid, ibuf, sizeof( ddid ));
1234 ibuf += sizeof( ddid );
1236 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1237 return get_afp_errno(AFPERR_PARAM);
1239 if ( path_isadir(s_path) ) {
1240 return( AFPERR_BADTYPE );
1243 /* don't allow copies when the file is open.
1244 * XXX: the spec only calls for read/deny write access.
1245 * however, copyfile doesn't have any of that info,
1246 * and locks need to stay coherent. as a result,
1247 * we just balk if the file is opened already. */
1249 adp = of_ad(s_vol, s_path, &ad);
1251 if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1252 return AFPERR_DENYCONF;
1254 denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
1255 getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1256 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1258 return AFPERR_DENYCONF;
1261 newname = obj->newtmp;
1262 strcpy( newname, s_path->m_name );
1264 p = ctoupath( s_vol, curdir, newname );
1266 return AFPERR_PARAM;
1270 /* FIXME svid != dvid && dvid's user can't read svid */
1272 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1273 return( AFPERR_PARAM );
1276 if (d_vol->v_flags & AFPVOL_RO)
1277 return AFPERR_VLOCK;
1279 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1283 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1284 return get_afp_errno(AFPERR_NOOBJ);
1286 if ( *s_path->m_name != '\0' ) {
1287 path_error(s_path, AFPERR_PARAM);
1290 /* one of the handful of places that knows about the path type */
1291 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1292 return( AFPERR_PARAM );
1294 /* newname is always only a filename so curdir *is* its
1297 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1298 return( AFPERR_PARAM );
1300 if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1306 if (vol->v_flags & AFPVOL_DROPBOX) {
1307 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1309 #endif /* DROPKLUDGE */
1311 setvoltime(obj, d_vol );
1314 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1320 /* ----------------------- */
1321 static __inline__ int copy_all(const int dfd, const void *buf,
1327 LOG(log_info, logtype_afpd, "begin copy_all:");
1330 while (buflen > 0) {
1331 if ((cc = write(dfd, buf, buflen)) < 0) {
1343 LOG(log_info, logtype_afpd, "end copy_all:");
1349 /* -------------------------- */
1350 static int copy_fd(int dfd, int sfd)
1356 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1357 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1361 #define BUF 128*1024*1024
1363 if (fstat(sfd, &st) == 0) {
1366 if ( offset >= st.st_size) {
1369 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1370 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1373 case EINVAL: /* there's no guarantee that all fs support sendfile */
1382 lseek(sfd, offset, SEEK_SET);
1386 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1393 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1400 /* ----------------------------------
1401 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1402 * because we are doing it elsewhere.
1404 int copyfile(s_vol, d_vol, src, dst, newname, adp )
1405 const struct vol *s_vol, *d_vol;
1406 char *src, *dst, *newname;
1407 struct adouble *adp;
1409 struct adouble ads, add;
1413 int noadouble = vol_noadouble(d_vol);
1417 LOG(log_info, logtype_afpd, "begin copyfile:");
1421 ad_init(&ads, s_vol->v_adouble);
1424 ad_init(&add, d_vol->v_adouble);
1425 adflags = ADFLAGS_DF;
1427 adflags |= ADFLAGS_HF;
1430 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1435 if (ad_hfileno(adp) == -1) {
1436 /* no resource fork, don't create one for dst file */
1437 adflags &= ~ADFLAGS_HF;
1440 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1442 ad_close( adp, adflags );
1443 if (EEXIST != ret_err) {
1444 deletefile(d_vol, dst, 0);
1447 return AFPERR_EXIST;
1449 if (ad_hfileno(adp) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(adp)))){
1450 /* copy the data fork */
1451 err = copy_fd(ad_dfileno(&add), ad_dfileno(adp));
1454 /* Now, reopen destination file */
1458 ad_close( adp, adflags );
1460 if (ad_close( &add, adflags ) <0) {
1461 deletefile(d_vol, dst, 0);
1466 ad_init(&add, d_vol->v_adouble);
1467 if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
1472 if (!ret_err && newname) {
1473 ad_setname(&add, newname);
1476 ad_flush( &add, adflags );
1477 if (ad_close( &add, adflags ) <0) {
1481 deletefile(d_vol, dst, 0);
1483 else if (!stat(src, &st)) {
1484 /* set dest modification date to src date */
1487 ut.actime = ut.modtime = st.st_mtime;
1489 /* FIXME netatalk doesn't use resource fork file date
1490 * but maybe we should set its modtime too.
1495 LOG(log_info, logtype_afpd, "end copyfile:");
1499 switch ( ret_err ) {
1505 return AFPERR_DFULL;
1507 return AFPERR_NOOBJ;
1509 return AFPERR_ACCESS;
1511 return AFPERR_VLOCK;
1513 return AFPERR_PARAM;
1517 /* -----------------------------------
1518 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1519 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1521 when deletefile is called we don't have lock on it, file is closed (for us)
1522 untrue if called by renamefile
1524 ad_open always try to open file RDWR first and ad_lock takes care of
1525 WRITE lock on read only file.
1527 int deletefile( vol, file, checkAttrib )
1528 const struct vol *vol;
1533 struct adouble *adp = &ad;
1534 int adflags, err = AFP_OK;
1537 LOG(log_info, logtype_afpd, "begin deletefile:");
1540 /* try to open both forks at once */
1541 adflags = ADFLAGS_DF|ADFLAGS_HF;
1543 ad_init(&ad, vol->v_adouble); /* OK */
1544 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1547 if (adflags == ADFLAGS_DF)
1548 return AFPERR_NOOBJ;
1550 /* that failed. now try to open just the data fork */
1551 adflags = ADFLAGS_DF;
1555 adp = NULL; /* maybe it's a file we no rw mode for us */
1556 break; /* was return AFPERR_ACCESS;*/
1558 return AFPERR_VLOCK;
1560 return( AFPERR_PARAM );
1563 break; /* from the while */
1566 * Does kFPDeleteInhibitBit (bit 8) set?
1571 if (adp && (adflags & ADFLAGS_HF)) {
1573 ad_getattr(&ad, &bshort);
1574 if ((bshort & htons(ATTRBIT_NODELETE))) {
1575 ad_close( &ad, adflags );
1576 return(AFPERR_OLOCK);
1580 /* was EACCESS error try to get only metadata */
1581 ad_init(&ad, vol->v_adouble); /* OK */
1582 if ( ad_metadata( file , 0, &ad) == 0 ) {
1583 ad_getattr(&ad, &bshort);
1584 ad_close( &ad, ADFLAGS_HF );
1585 if ((bshort & htons(ATTRBIT_NODELETE))) {
1586 return AFPERR_OLOCK;
1592 if (adp && (adflags & ADFLAGS_HF) ) {
1593 /* FIXME we have a pb here because we want to know if a file is open
1594 * there's a 'priority inversion' if you can't open the ressource fork RW
1595 * you can delete it if it's open because you can't get a write lock.
1597 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1600 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1602 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1603 ad_close( &ad, adflags );
1604 return( AFPERR_BUSY );
1608 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1611 else if (!(err = netatalk_unlink( vol->ad_path( file, ADFLAGS_HF)) ) &&
1612 !(err = netatalk_unlink( file )) ) {
1614 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1616 cnid_delete(vol->v_cdb, id);
1621 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1624 LOG(log_info, logtype_afpd, "end deletefile:");
1630 /* ------------------------------------ */
1631 /* return a file id */
1632 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1635 int ibuflen, *rbuflen;
1644 struct path *s_path;
1647 LOG(log_info, logtype_afpd, "begin afp_createid:");
1654 memcpy(&vid, ibuf, sizeof(vid));
1655 ibuf += sizeof(vid);
1657 if (NULL == ( vol = getvolbyvid( vid )) ) {
1658 return( AFPERR_PARAM);
1661 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1665 if (vol->v_flags & AFPVOL_RO)
1666 return AFPERR_VLOCK;
1668 memcpy(&did, ibuf, sizeof( did ));
1669 ibuf += sizeof(did);
1671 if (NULL == ( dir = dirlookup( vol, did )) ) {
1672 return afp_errno; /* was AFPERR_PARAM */
1675 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1676 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1679 if ( path_isadir(s_path) ) {
1680 return( AFPERR_BADTYPE );
1683 upath = s_path->u_name;
1684 switch (s_path->st_errno) {
1686 break; /* success */
1689 return AFPERR_ACCESS;
1691 return AFPERR_NOOBJ;
1693 return AFPERR_PARAM;
1696 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1697 memcpy(rbuf, &id, sizeof(id));
1698 *rbuflen = sizeof(id);
1699 return AFPERR_EXISTID;
1702 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1703 memcpy(rbuf, &id, sizeof(id));
1704 *rbuflen = sizeof(id);
1709 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1715 reenumerate_id(const struct vol *vol, char *name, cnid_t did)
1723 memset(&path, 0, sizeof(path));
1724 if (vol->v_cdb == NULL) {
1727 if (NULL == ( dp = opendir( name)) ) {
1731 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
1732 if (NULL == check_dirent(vol, de->d_name))
1735 if ( stat(de->d_name, &path.st)<0 )
1738 /* update or add to cnid */
1739 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1741 #if AD_VERSION > AD_VERSION1
1742 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1743 // struct ofork *of;
1744 struct adouble ad, *adp;
1748 path.u_name = de->d_name;
1750 adp = of_ad(vol, &path, &ad);
1752 if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, adp ) < 0 ) {
1755 if (ad_setid(adp,(vol->v_flags & AFPVOL_NODEV)?0:path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1756 ad_flush(adp, ADFLAGS_HF);
1758 ad_close(adp, ADFLAGS_HF);
1760 #endif /* AD_VERSION > AD_VERSION1 */
1769 /* ------------------------------
1770 resolve a file id */
1771 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1774 int ibuflen, *rbuflen;
1780 int err, buflen, retry=0;
1782 u_int16_t vid, bitmap;
1784 static char buffer[12 + MAXPATHLEN + 1];
1785 int len = 12 + MAXPATHLEN + 1;
1788 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1794 memcpy(&vid, ibuf, sizeof(vid));
1795 ibuf += sizeof(vid);
1797 if (NULL == ( vol = getvolbyvid( vid )) ) {
1798 return( AFPERR_PARAM);
1801 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1805 memcpy(&id, ibuf, sizeof( id ));
1810 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1811 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1814 if (NULL == ( dir = dirlookup( vol, id )) ) {
1815 return AFPERR_NOID; /* idem AFPERR_PARAM */
1817 path.u_name = upath;
1818 if (movecwd(vol, dir) < 0) {
1822 return AFPERR_ACCESS;
1826 return AFPERR_PARAM;
1830 if ( of_stat(&path) < 0 ) {
1832 /* with nfs and our working directory is deleted */
1833 if (errno == ESTALE) {
1837 if ( errno == ENOENT && !retry) {
1838 /* cnid db is out of sync, reenumerate the directory and updated ids */
1839 reenumerate_id(vol, ".", id);
1847 return AFPERR_ACCESS;
1851 return AFPERR_PARAM;
1855 /* directories are bad */
1856 if (S_ISDIR(path.st.st_mode))
1857 return AFPERR_BADTYPE;
1859 memcpy(&bitmap, ibuf, sizeof(bitmap));
1860 bitmap = ntohs( bitmap );
1861 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1864 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1865 rbuf + sizeof(bitmap), &buflen))) {
1868 *rbuflen = buflen + sizeof(bitmap);
1869 memcpy(rbuf, ibuf, sizeof(bitmap));
1872 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1878 /* ------------------------------ */
1879 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1882 int ibuflen, *rbuflen;
1892 static char buffer[12 + MAXPATHLEN + 1];
1893 int len = 12 + MAXPATHLEN + 1;
1896 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1902 memcpy(&vid, ibuf, sizeof(vid));
1903 ibuf += sizeof(vid);
1905 if (NULL == ( vol = getvolbyvid( vid )) ) {
1906 return( AFPERR_PARAM);
1909 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1913 if (vol->v_flags & AFPVOL_RO)
1914 return AFPERR_VLOCK;
1916 memcpy(&id, ibuf, sizeof( id ));
1920 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1924 if (NULL == ( dir = dirlookup( vol, id )) ) {
1925 return( AFPERR_PARAM );
1929 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1933 return AFPERR_ACCESS;
1938 /* still try to delete the id */
1942 return AFPERR_PARAM;
1945 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1946 return AFPERR_BADTYPE;
1948 if (cnid_delete(vol->v_cdb, fileid)) {
1951 return AFPERR_VLOCK;
1954 return AFPERR_ACCESS;
1956 return AFPERR_PARAM;
1961 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1967 /* ------------------------------ */
1968 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1972 if (path->st_errno) {
1973 switch (path->st_errno) {
1975 afp_errno = AFPERR_NOID;
1979 afp_errno = AFPERR_ACCESS;
1982 afp_errno = AFPERR_PARAM;
1987 /* we use file_access both for legacy Mac perm and
1988 * for unix privilege, rename will take care of folder perms
1990 if (file_access(path, OPENACC_WR ) < 0) {
1991 afp_errno = AFPERR_ACCESS;
1995 if ((*of = of_findname(path))) {
1996 /* reuse struct adouble so it won't break locks */
2000 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
2001 if ( !ret && ad_hfileno(adp) != -1 && !(adp->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) {
2003 * The user must have the Read & Write privilege for both files in order to use this command.
2005 ad_close(adp, ADFLAGS_HF);
2006 afp_errno = AFPERR_ACCESS;
2013 #define APPLETEMP ".AppleTempXXXXXX"
2015 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
2018 int ibuflen, *rbuflen;
2020 struct stat srcst, destst;
2022 struct dir *dir, *sdir;
2023 char *spath, temp[17], *p;
2024 char *supath, *upath;
2029 struct adouble *adsp = NULL;
2030 struct adouble *addp = NULL;
2031 struct ofork *s_of = NULL;
2032 struct ofork *d_of = NULL;
2043 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
2049 memcpy(&vid, ibuf, sizeof(vid));
2050 ibuf += sizeof(vid);
2052 if (NULL == ( vol = getvolbyvid( vid )) ) {
2053 return( AFPERR_PARAM);
2056 if ((vol->v_flags & AFPVOL_RO))
2057 return AFPERR_VLOCK;
2059 /* source and destination dids */
2060 memcpy(&sid, ibuf, sizeof(sid));
2061 ibuf += sizeof(sid);
2062 memcpy(&did, ibuf, sizeof(did));
2063 ibuf += sizeof(did);
2066 if (NULL == (dir = dirlookup( vol, sid )) ) {
2067 return afp_errno; /* was AFPERR_PARAM */
2070 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2071 return get_afp_errno(AFPERR_NOOBJ);
2074 if ( path_isadir(path) ) {
2075 return AFPERR_BADTYPE; /* it's a dir */
2078 /* save some stuff */
2081 spath = obj->oldtmp;
2082 supath = obj->newtmp;
2083 strcpy(spath, path->m_name);
2084 strcpy(supath, path->u_name); /* this is for the cnid changing */
2085 p = absupath( vol, sdir, supath);
2087 /* pathname too long */
2088 return AFPERR_PARAM ;
2091 ad_init(&ads, vol->v_adouble);
2092 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2096 /* ***** from here we may have resource fork open **** */
2098 /* look for the source cnid. if it doesn't exist, don't worry about
2100 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2102 if (NULL == ( dir = dirlookup( vol, did )) ) {
2103 err = afp_errno; /* was AFPERR_PARAM */
2104 goto err_exchangefile;
2107 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2108 err = get_afp_errno(AFPERR_NOOBJ);
2109 goto err_exchangefile;
2112 if ( path_isadir(path) ) {
2113 err = AFPERR_BADTYPE;
2114 goto err_exchangefile;
2117 /* FPExchangeFiles is the only call that can return the SameObj
2119 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2120 err = AFPERR_SAMEOBJ;
2121 goto err_exchangefile;
2124 ad_init(&add, vol->v_adouble);
2125 if (!(addp = find_adouble( path, &d_of, &add))) {
2127 goto err_exchangefile;
2131 /* they are not on the same device and at least one is open
2132 * FIXME broken for for crossdev and adouble v2
2135 crossdev = (srcst.st_dev != destst.st_dev);
2136 if (/* (d_of || s_of) && */ crossdev) {
2138 goto err_exchangefile;
2141 /* look for destination id. */
2142 upath = path->u_name;
2143 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2145 /* construct a temp name.
2146 * NOTE: the temp file will be in the dest file's directory. it
2147 * will also be inaccessible from AFP. */
2148 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2149 if (!mktemp(temp)) {
2151 goto err_exchangefile;
2155 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2156 ad_close(adsp, ADFLAGS_HF);
2157 ad_close(addp, ADFLAGS_HF);
2160 /* now, quickly rename the file. we error if we can't. */
2161 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2162 goto err_exchangefile;
2163 of_rename(vol, s_of, sdir, spath, curdir, temp);
2165 /* rename destination to source */
2166 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2167 goto err_src_to_tmp;
2168 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2170 /* rename temp to destination */
2171 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2172 goto err_dest_to_src;
2173 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2175 /* id's need switching. src -> dest and dest -> src.
2176 * we need to re-stat() if it was a cross device copy.
2179 cnid_delete(vol->v_cdb, sid);
2182 cnid_delete(vol->v_cdb, did);
2184 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2185 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2187 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2188 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2193 err = AFPERR_ACCESS;
2198 goto err_temp_to_dest;
2201 /* here we need to reopen if crossdev */
2202 if (sid && ad_setid(addp,(vol->v_flags & AFPVOL_NODEV)?0:destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2204 ad_flush( addp, ADFLAGS_HF );
2207 if (did && ad_setid(adsp,(vol->v_flags & AFPVOL_NODEV)?0:srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2209 ad_flush( adsp, ADFLAGS_HF );
2212 /* change perms, src gets dest perm and vice versa */
2217 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2218 err = AFP_OK; /* ignore error */
2219 goto err_temp_to_dest;
2223 * we need to exchange ACL entries as well
2225 /* exchange_acls(vol, p, upath); */
2230 path->m_name = NULL;
2231 path->u_name = upath;
2233 setfilunixmode(vol, path, destst.st_mode);
2234 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2241 setfilunixmode(vol, path, srcst.st_mode);
2242 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2244 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2245 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2250 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2254 goto err_exchangefile;
2256 /* all this stuff is so that we can unwind a failed operation
2259 /* rename dest to temp */
2260 renamefile(vol, upath, temp, temp, adsp);
2261 of_rename(vol, s_of, curdir, upath, curdir, temp);
2264 /* rename source back to dest */
2265 renamefile(vol, p, upath, path->m_name, addp);
2266 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2269 /* rename temp back to source */
2270 renamefile(vol, temp, p, spath, adsp);
2271 of_rename(vol, s_of, curdir, temp, sdir, spath);
2274 if ( !s_of && adsp && ad_hfileno(adsp) != -1 ) {
2275 ad_close(adsp, ADFLAGS_HF);
2277 if ( !d_of && addp && ad_hfileno(addp) != -1 ) {
2278 ad_close(addp, ADFLAGS_HF);