2 * $Id: file.c,v 1.92.2.2.2.31.2.9 2005-02-05 14:46:35 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, 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]; /* uninitialized, OK 310105 */
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 adouble ad, *adp;
1747 path.u_name = de->d_name;
1749 adp = of_ad(vol, &path, &ad);
1751 if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, adp ) < 0 ) {
1754 if (ad_setid(adp,(vol->v_flags & AFPVOL_NODEV)?0:path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1755 ad_flush(adp, ADFLAGS_HF);
1757 ad_close(adp, ADFLAGS_HF);
1759 #endif /* AD_VERSION > AD_VERSION1 */
1768 /* ------------------------------
1769 resolve a file id */
1770 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1773 int ibuflen, *rbuflen;
1779 int err, buflen, retry=0;
1781 u_int16_t vid, bitmap;
1783 static char buffer[12 + MAXPATHLEN + 1];
1784 int len = 12 + MAXPATHLEN + 1;
1787 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1793 memcpy(&vid, ibuf, sizeof(vid));
1794 ibuf += sizeof(vid);
1796 if (NULL == ( vol = getvolbyvid( vid )) ) {
1797 return( AFPERR_PARAM);
1800 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1804 memcpy(&id, ibuf, sizeof( id ));
1809 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1810 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1813 if (NULL == ( dir = dirlookup( vol, id )) ) {
1814 return AFPERR_NOID; /* idem AFPERR_PARAM */
1816 path.u_name = upath;
1817 if (movecwd(vol, dir) < 0) {
1821 return AFPERR_ACCESS;
1825 return AFPERR_PARAM;
1829 if ( of_stat(&path) < 0 ) {
1831 /* with nfs and our working directory is deleted */
1832 if (errno == ESTALE) {
1836 if ( errno == ENOENT && !retry) {
1837 /* cnid db is out of sync, reenumerate the directory and updated ids */
1838 reenumerate_id(vol, ".", id);
1846 return AFPERR_ACCESS;
1850 return AFPERR_PARAM;
1854 /* directories are bad */
1855 if (S_ISDIR(path.st.st_mode))
1856 return AFPERR_BADTYPE;
1858 memcpy(&bitmap, ibuf, sizeof(bitmap));
1859 bitmap = ntohs( bitmap );
1860 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1863 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1864 rbuf + sizeof(bitmap), &buflen))) {
1867 *rbuflen = buflen + sizeof(bitmap);
1868 memcpy(rbuf, ibuf, sizeof(bitmap));
1871 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1877 /* ------------------------------ */
1878 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1881 int ibuflen, *rbuflen;
1891 static char buffer[12 + MAXPATHLEN + 1];
1892 int len = 12 + MAXPATHLEN + 1;
1895 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1901 memcpy(&vid, ibuf, sizeof(vid));
1902 ibuf += sizeof(vid);
1904 if (NULL == ( vol = getvolbyvid( vid )) ) {
1905 return( AFPERR_PARAM);
1908 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1912 if (vol->v_flags & AFPVOL_RO)
1913 return AFPERR_VLOCK;
1915 memcpy(&id, ibuf, sizeof( id ));
1919 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1923 if (NULL == ( dir = dirlookup( vol, id )) ) {
1924 return( AFPERR_PARAM );
1928 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1932 return AFPERR_ACCESS;
1937 /* still try to delete the id */
1941 return AFPERR_PARAM;
1944 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1945 return AFPERR_BADTYPE;
1947 if (cnid_delete(vol->v_cdb, fileid)) {
1950 return AFPERR_VLOCK;
1953 return AFPERR_ACCESS;
1955 return AFPERR_PARAM;
1960 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1966 /* ------------------------------ */
1967 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1971 if (path->st_errno) {
1972 switch (path->st_errno) {
1974 afp_errno = AFPERR_NOID;
1978 afp_errno = AFPERR_ACCESS;
1981 afp_errno = AFPERR_PARAM;
1986 /* we use file_access both for legacy Mac perm and
1987 * for unix privilege, rename will take care of folder perms
1989 if (file_access(path, OPENACC_WR ) < 0) {
1990 afp_errno = AFPERR_ACCESS;
1994 if ((*of = of_findname(path))) {
1995 /* reuse struct adouble so it won't break locks */
1999 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
2000 if ( !ret && ad_hfileno(adp) != -1 && !(adp->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) {
2002 * The user must have the Read & Write privilege for both files in order to use this command.
2004 ad_close(adp, ADFLAGS_HF);
2005 afp_errno = AFPERR_ACCESS;
2012 #define APPLETEMP ".AppleTempXXXXXX"
2014 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
2017 int ibuflen, *rbuflen;
2019 struct stat srcst, destst;
2021 struct dir *dir, *sdir;
2022 char *spath, temp[17], *p;
2023 char *supath, *upath;
2028 struct adouble *adsp = NULL;
2029 struct adouble *addp = NULL;
2030 struct ofork *s_of = NULL;
2031 struct ofork *d_of = NULL;
2042 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
2048 memcpy(&vid, ibuf, sizeof(vid));
2049 ibuf += sizeof(vid);
2051 if (NULL == ( vol = getvolbyvid( vid )) ) {
2052 return( AFPERR_PARAM);
2055 if ((vol->v_flags & AFPVOL_RO))
2056 return AFPERR_VLOCK;
2058 /* source and destination dids */
2059 memcpy(&sid, ibuf, sizeof(sid));
2060 ibuf += sizeof(sid);
2061 memcpy(&did, ibuf, sizeof(did));
2062 ibuf += sizeof(did);
2065 if (NULL == (dir = dirlookup( vol, sid )) ) {
2066 return afp_errno; /* was AFPERR_PARAM */
2069 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2070 return get_afp_errno(AFPERR_NOOBJ);
2073 if ( path_isadir(path) ) {
2074 return AFPERR_BADTYPE; /* it's a dir */
2077 /* save some stuff */
2080 spath = obj->oldtmp;
2081 supath = obj->newtmp;
2082 strcpy(spath, path->m_name);
2083 strcpy(supath, path->u_name); /* this is for the cnid changing */
2084 p = absupath( vol, sdir, supath);
2086 /* pathname too long */
2087 return AFPERR_PARAM ;
2090 ad_init(&ads, vol->v_adouble);
2091 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2095 /* ***** from here we may have resource fork open **** */
2097 /* look for the source cnid. if it doesn't exist, don't worry about
2099 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2101 if (NULL == ( dir = dirlookup( vol, did )) ) {
2102 err = afp_errno; /* was AFPERR_PARAM */
2103 goto err_exchangefile;
2106 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2107 err = get_afp_errno(AFPERR_NOOBJ);
2108 goto err_exchangefile;
2111 if ( path_isadir(path) ) {
2112 err = AFPERR_BADTYPE;
2113 goto err_exchangefile;
2116 /* FPExchangeFiles is the only call that can return the SameObj
2118 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2119 err = AFPERR_SAMEOBJ;
2120 goto err_exchangefile;
2123 ad_init(&add, vol->v_adouble);
2124 if (!(addp = find_adouble( path, &d_of, &add))) {
2126 goto err_exchangefile;
2130 /* they are not on the same device and at least one is open
2131 * FIXME broken for for crossdev and adouble v2
2134 crossdev = (srcst.st_dev != destst.st_dev);
2135 if (/* (d_of || s_of) && */ crossdev) {
2137 goto err_exchangefile;
2140 /* look for destination id. */
2141 upath = path->u_name;
2142 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2144 /* construct a temp name.
2145 * NOTE: the temp file will be in the dest file's directory. it
2146 * will also be inaccessible from AFP. */
2147 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2148 if (!mktemp(temp)) {
2150 goto err_exchangefile;
2154 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2155 ad_close(adsp, ADFLAGS_HF);
2156 ad_close(addp, ADFLAGS_HF);
2159 /* now, quickly rename the file. we error if we can't. */
2160 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2161 goto err_exchangefile;
2162 of_rename(vol, s_of, sdir, spath, curdir, temp);
2164 /* rename destination to source */
2165 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2166 goto err_src_to_tmp;
2167 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2169 /* rename temp to destination */
2170 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2171 goto err_dest_to_src;
2172 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2174 /* id's need switching. src -> dest and dest -> src.
2175 * we need to re-stat() if it was a cross device copy.
2178 cnid_delete(vol->v_cdb, sid);
2181 cnid_delete(vol->v_cdb, did);
2183 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2184 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2186 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2187 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2192 err = AFPERR_ACCESS;
2197 goto err_temp_to_dest;
2200 /* here we need to reopen if crossdev */
2201 if (sid && ad_setid(addp,(vol->v_flags & AFPVOL_NODEV)?0:destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2203 ad_flush( addp, ADFLAGS_HF );
2206 if (did && ad_setid(adsp,(vol->v_flags & AFPVOL_NODEV)?0:srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2208 ad_flush( adsp, ADFLAGS_HF );
2211 /* change perms, src gets dest perm and vice versa */
2216 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2217 err = AFP_OK; /* ignore error */
2218 goto err_temp_to_dest;
2222 * we need to exchange ACL entries as well
2224 /* exchange_acls(vol, p, upath); */
2229 path->m_name = NULL;
2230 path->u_name = upath;
2232 setfilunixmode(vol, path, destst.st_mode);
2233 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2240 setfilunixmode(vol, path, srcst.st_mode);
2241 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2243 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2244 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2249 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2253 goto err_exchangefile;
2255 /* all this stuff is so that we can unwind a failed operation
2258 /* rename dest to temp */
2259 renamefile(vol, upath, temp, temp, adsp);
2260 of_rename(vol, s_of, curdir, upath, curdir, temp);
2263 /* rename source back to dest */
2264 renamefile(vol, p, upath, path->m_name, addp);
2265 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2268 /* rename temp back to source */
2269 renamefile(vol, temp, p, spath, adsp);
2270 of_rename(vol, s_of, curdir, temp, sdir, spath);
2273 if ( !s_of && adsp && ad_hfileno(adsp) != -1 ) {
2274 ad_close(adsp, ADFLAGS_HF);
2276 if ( !d_of && addp && ad_hfileno(addp) != -1 ) {
2277 ad_close(addp, ADFLAGS_HF);