2 * $Id: file.c,v 1.92.2.2.2.31.2.5 2004-12-07 03:23:49 didg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
18 #else /* STDC_HEADERS */
22 #endif /* HAVE_STRCHR */
23 char *strchr (), *strrchr ();
26 #define memcpy(d,s,n) bcopy ((s), (d), (n))
27 #define memmove(d,s,n) bcopy ((s), (d), (n))
28 #endif /* ! HAVE_MEMCPY */
29 #endif /* STDC_HEADERS */
31 #include <atalk/adouble.h>
36 #include <atalk/logger.h>
37 #include <sys/param.h>
40 #include <atalk/afp.h>
41 #include <atalk/util.h>
42 #include <atalk/cnid.h>
43 #include "directory.h"
52 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
53 * field bytes subfield bytes
56 * ioFlFndrInfo 16 -> type 4 type field
57 * creator 4 creator field
58 * flags 2 finder flags:
60 * location 4 location in window
61 * folder 2 window that contains file
63 * ioFlXFndrInfo 16 -> iconID 2 icon id
65 * script 1 script system
67 * commentID 2 comment id
68 * putawayID 4 home directory id
71 const u_char ufinderi[] = {
72 0, 0, 0, 0, 0, 0, 0, 0,
73 1, 0, 0, 0, 0, 0, 0, 0,
74 0, 0, 0, 0, 0, 0, 0, 0,
75 0, 0, 0, 0, 0, 0, 0, 0
78 /* FIXME mpath : unix or mac name ? (for now it's mac name ) */
79 void *get_finderinfo(const char *mpath, struct adouble *adp, void *data)
82 void *ad_finder = NULL;
86 ad_finder = ad_entry(adp, ADEID_FINDERI);
88 if ((ad_finder != NULL)) {
89 memcpy(data, ad_finder, 32);
91 if (!memcmp(ad_finder, ufinderi, 8))
95 memcpy(data, ufinderi, 32);
98 /** Only enter if no appledouble information and no finder information found. */
99 if (chk_ext && (em = getextmap( mpath ))) {
100 memcpy(data, em->em_type, sizeof( em->em_type ));
101 memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator));
106 /* ---------------------
108 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8)
113 aint = strlen( name );
117 if (utf8_encoding()) {
118 /* but name is an utf8 mac name */
121 /* global static variable... */
123 if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
132 if (aint > MACFILELEN)
139 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
142 utf8 = vol->v_mac?htonl(vol->v_mac->kTextEncoding):0; /* htonl(utf8) */
143 memcpy(data, &utf8, sizeof(utf8));
144 data += sizeof(utf8);
147 memcpy(data, &temp, sizeof(temp));
148 data += sizeof(temp);
151 memcpy( data, src, aint );
161 * FIXME: PDINFO is UTF8 and doesn't need adp
163 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
164 (1 << FILPBIT_CDATE) |\
165 (1 << FILPBIT_MDATE) |\
166 (1 << FILPBIT_BDATE) |\
167 (1 << FILPBIT_FINFO) |\
168 (1 << FILPBIT_RFLEN) |\
169 (1 << FILPBIT_EXTRFLEN) |\
170 (1 << FILPBIT_PDINFO)))
172 /* -------------------------- */
173 u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st,
174 const cnid_t did, const char *upath, const int len)
178 #if AD_VERSION > AD_VERSION1
182 char stamp[ADEDLEN_PRIVSYN];
183 /* look in AD v2 header
184 * note inode and device are opaques and not in network order
187 && sizeof(dev_t) == ad_getentrylen(adp, ADEID_PRIVDEV)
188 && sizeof(ino_t) == ad_getentrylen(adp,ADEID_PRIVINO)
189 && sizeof(stamp) == ad_getentrylen(adp,ADEID_PRIVSYN)
190 && sizeof(cnid_t) == ad_getentrylen(adp, ADEID_DID)
191 && sizeof(cnid_t) == ad_getentrylen(adp, ADEID_PRIVID)
194 memcpy(&dev, ad_entry(adp, ADEID_PRIVDEV), sizeof(dev_t));
195 memcpy(&ino, ad_entry(adp, ADEID_PRIVINO), sizeof(ino_t));
196 memcpy(stamp, ad_entry(adp, ADEID_PRIVSYN), sizeof(stamp));
197 memcpy(&a_did, ad_entry(adp, ADEID_DID), sizeof(cnid_t));
199 if ( ( (vol->v_flags & AFPVOL_NODEV) || dev == st->st_dev)
200 && ino == st->st_ino && a_did == did
201 && !memcmp(vol->v_stamp, stamp, sizeof(stamp))) {
202 memcpy(&aint, ad_entry(adp, ADEID_PRIVID), sizeof(aint));
207 if (vol->v_cdb != NULL) {
208 aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
209 /* Throw errors if cnid_add fails. */
210 if (aint == CNID_INVALID) {
212 case CNID_ERR_CLOSE: /* the db is closed */
215 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
216 afp_errno = AFPERR_PARAM;
219 afp_errno = AFPERR_PARAM;
222 afp_errno = AFPERR_MISC;
226 #if AD_VERSION > AD_VERSION1
228 /* update the ressource fork
229 * for a folder adp is always null
231 if (ad_setid(adp,(vol->v_flags & AFPVOL_NODEV)?0:st->st_dev, st->st_ino, aint, did, vol->v_stamp)) {
232 ad_flush(adp, ADFLAGS_HF);
240 /* -------------------------- */
241 int getmetadata(struct vol *vol,
243 struct path *path, struct dir *dir,
244 char *buf, int *buflen, struct adouble *adp, int attrbits )
246 char *data, *l_nameoff = NULL, *upath;
247 char *utf_nameoff = NULL;
252 u_char achar, fdType[4];
258 LOG(log_info, logtype_afpd, "begin getmetadata:");
261 upath = path->u_name;
266 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
267 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
268 || (bitmap & (1 << FILPBIT_FNUM))) {
270 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
274 path->m_name = utompath(vol, upath, id, utf8_encoding());
277 while ( bitmap != 0 ) {
278 while (( bitmap & 1 ) == 0 ) {
286 ad_getattr(adp, &ashort);
287 } else if (*upath == '.') {
288 ashort = htons(ATTRBIT_INVISIBLE);
292 /* FIXME do we want a visual clue if the file is read only
295 accessmode( ".", &ma, dir , NULL);
296 if ((ma.ma_user & AR_UWRITE)) {
297 accessmode( upath, &ma, dir , st);
298 if (!(ma.ma_user & AR_UWRITE)) {
299 attrbits |= ATTRBIT_NOWRITE;
304 ashort = htons(ntohs(ashort) | attrbits);
305 memcpy(data, &ashort, sizeof( ashort ));
306 data += sizeof( ashort );
310 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
311 data += sizeof( u_int32_t );
315 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
316 aint = AD_DATE_FROM_UNIX(st->st_mtime);
317 memcpy(data, &aint, sizeof( aint ));
318 data += sizeof( aint );
322 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
323 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
324 aint = AD_DATE_FROM_UNIX(st->st_mtime);
327 aint = AD_DATE_FROM_UNIX(st->st_mtime);
329 memcpy(data, &aint, sizeof( int ));
330 data += sizeof( int );
334 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
335 aint = AD_DATE_START;
336 memcpy(data, &aint, sizeof( int ));
337 data += sizeof( int );
341 get_finderinfo(path->m_name, adp, (char *)data);
343 if (*upath == '.') { /* make it invisible */
344 ashort = htons(FINDERINFO_INVISIBLE);
345 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
353 data += sizeof( u_int16_t );
357 memset(data, 0, sizeof(u_int16_t));
358 data += sizeof( u_int16_t );
362 memcpy(data, &id, sizeof( id ));
363 data += sizeof( id );
367 if (st->st_size > 0xffffffff)
370 aint = htonl( st->st_size );
371 memcpy(data, &aint, sizeof( aint ));
372 data += sizeof( aint );
377 if (adp->ad_rlen > 0xffffffff)
380 aint = htonl( adp->ad_rlen);
384 memcpy(data, &aint, sizeof( aint ));
385 data += sizeof( aint );
388 /* Current client needs ProDOS info block for this file.
389 Use simple heuristic and let the Mac "type" string tell
390 us what the PD file code should be. Everything gets a
391 subtype of 0x0000 unless the original value was hashed
392 to "pXYZ" when we created it. See IA, Ver 2.
393 <shirsch@adelphia.net> */
394 case FILPBIT_PDINFO :
395 if (afp_version >= 30) { /* UTF8 name */
396 utf8 = kTextEncodingUTF8;
398 data += sizeof( u_int16_t );
400 memcpy(data, &aint, sizeof( aint ));
401 data += sizeof( aint );
405 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
407 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
411 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
415 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
419 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
423 else if ( fdType[0] == 'p' ) {
425 ashort = (fdType[2] * 256) + fdType[3];
439 memcpy(data, &ashort, sizeof( ashort ));
440 data += sizeof( ashort );
441 memset(data, 0, sizeof( ashort ));
442 data += sizeof( ashort );
445 case FILPBIT_EXTDFLEN:
446 aint = htonl(st->st_size >> 32);
447 memcpy(data, &aint, sizeof( aint ));
448 data += sizeof( aint );
449 aint = htonl(st->st_size);
450 memcpy(data, &aint, sizeof( aint ));
451 data += sizeof( aint );
453 case FILPBIT_EXTRFLEN:
456 aint = htonl(adp->ad_rlen >> 32);
457 memcpy(data, &aint, sizeof( aint ));
458 data += sizeof( aint );
460 aint = htonl(adp->ad_rlen);
461 memcpy(data, &aint, sizeof( aint ));
462 data += sizeof( aint );
464 case FILPBIT_UNIXPR :
465 /* accessmode may change st_mode with ACLs */
466 accessmode( upath, &ma, dir , st);
468 aint = htonl(st->st_uid);
469 memcpy( data, &aint, sizeof( aint ));
470 data += sizeof( aint );
471 aint = htonl(st->st_gid);
472 memcpy( data, &aint, sizeof( aint ));
473 data += sizeof( aint );
475 aint = htonl(st->st_mode);
476 memcpy( data, &aint, sizeof( aint ));
477 data += sizeof( aint );
479 *data++ = ma.ma_user;
480 *data++ = ma.ma_world;
481 *data++ = ma.ma_group;
482 *data++ = ma.ma_owner;
486 return( AFPERR_BITMAP );
492 ashort = htons( data - buf );
493 memcpy(l_nameoff, &ashort, sizeof( ashort ));
494 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
497 ashort = htons( data - buf );
498 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
499 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
501 *buflen = data - buf;
505 /* ----------------------- */
506 int getfilparams(struct vol *vol,
508 struct path *path, struct dir *dir,
509 char *buf, int *buflen )
511 struct adouble ad, *adp;
514 u_int16_t attrbits = 0;
519 LOG(log_info, logtype_default, "begin getfilparams:");
522 opened = PARAM_NEED_ADP(bitmap);
525 upath = path->u_name;
526 if ((of = of_findname(path))) {
528 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
529 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
531 ad_init(&ad, vol->v_adouble);
535 if ( ad_metadata( upath, 0, adp) < 0 ) {
538 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
539 upath, strerror(errno));
540 return AFPERR_ACCESS;
542 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
552 we need to check if the file is open by another process.
553 it's slow so we only do it if we have to:
554 - bitmap is requested.
555 - we don't already have the answer!
557 if ((bitmap & (1 << FILPBIT_ATTR))) {
558 if (!(attrbits & ATTRBIT_ROPEN)) {
559 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_ROPEN : 0;
560 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_ROPEN : 0;
562 if (!(attrbits & ATTRBIT_DOPEN)) {
563 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_DOPEN : 0;
564 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_DOPEN : 0;
569 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
571 ad_close( adp, ADFLAGS_HF );
574 LOG(log_info, logtype_afpd, "end getfilparams:");
580 /* ----------------------------- */
581 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
584 int ibuflen, *rbuflen;
586 struct adouble ad, *adp;
589 struct ofork *of = NULL;
591 int creatf, did, openf, retvalue = AFP_OK;
597 LOG(log_info, logtype_afpd, "begin afp_createfile:");
602 creatf = (unsigned char) *ibuf++;
604 memcpy(&vid, ibuf, sizeof( vid ));
605 ibuf += sizeof( vid );
607 if (NULL == ( vol = getvolbyvid( vid )) ) {
608 return( AFPERR_PARAM );
611 if (vol->v_flags & AFPVOL_RO)
614 memcpy(&did, ibuf, sizeof( did));
615 ibuf += sizeof( did );
617 if (NULL == ( dir = dirlookup( vol, did )) ) {
621 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
622 return get_afp_errno(AFPERR_PARAM);
625 if ( *s_path->m_name == '\0' ) {
626 return( AFPERR_BADTYPE );
629 upath = s_path->u_name;
630 if (0 != (ret = check_name(vol, upath)))
633 /* if upath is deleted we already in trouble anyway */
634 if ((of = of_findname(s_path))) {
637 ad_init(&ad, vol->v_adouble);
641 /* on a hard create, fail if file exists and is open */
644 openf = O_RDWR|O_CREAT|O_TRUNC;
646 /* on a soft create, if the file is open then ad_open won't fail
647 because open syscall is not called
652 openf = O_RDWR|O_CREAT|O_EXCL;
655 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
656 openf, 0666, adp) < 0 ) {
660 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
661 return ( AFPERR_NOOBJ );
663 return( AFPERR_EXIST );
665 return( AFPERR_ACCESS );
667 return( AFPERR_PARAM );
670 if ( ad_hfileno( adp ) == -1 ) {
671 /* on noadouble volumes, just creating the data fork is ok */
672 if (vol_noadouble(vol)) {
673 ad_close( adp, ADFLAGS_DF );
674 goto createfile_done;
676 /* FIXME with hard create on an existing file, we already
677 * corrupted the data file.
679 netatalk_unlink( upath );
680 ad_close( adp, ADFLAGS_DF );
681 return AFPERR_ACCESS;
684 path = s_path->m_name;
685 ad_setname(adp, path);
686 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
687 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
693 if (vol->v_flags & AFPVOL_DROPBOX) {
694 retvalue = matchfile2dirperms(upath, vol, did);
696 #endif /* DROPKLUDGE */
698 setvoltime(obj, vol );
701 LOG(log_info, logtype_afpd, "end afp_createfile");
707 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
710 int ibuflen, *rbuflen;
716 u_int16_t vid, bitmap;
719 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
725 memcpy(&vid, ibuf, sizeof( vid ));
726 ibuf += sizeof( vid );
727 if (NULL == ( vol = getvolbyvid( vid )) ) {
728 return( AFPERR_PARAM );
731 if (vol->v_flags & AFPVOL_RO)
734 memcpy(&did, ibuf, sizeof( did ));
735 ibuf += sizeof( did );
736 if (NULL == ( dir = dirlookup( vol, did )) ) {
737 return afp_errno; /* was AFPERR_NOOBJ */
740 memcpy(&bitmap, ibuf, sizeof( bitmap ));
741 bitmap = ntohs( bitmap );
742 ibuf += sizeof( bitmap );
744 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
745 return get_afp_errno(AFPERR_PARAM);
748 if (path_isadir(s_path)) {
749 return( AFPERR_BADTYPE ); /* it's a directory */
752 if ( s_path->st_errno != 0 ) {
753 return( AFPERR_NOOBJ );
756 if ((u_long)ibuf & 1 ) {
760 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
761 setvoltime(obj, vol );
765 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
772 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
775 extern struct path Cur_Path;
777 int setfilparams(struct vol *vol,
778 struct path *path, u_int16_t f_bitmap, char *buf )
780 struct adouble ad, *adp;
783 int bit, isad = 1, err = AFP_OK;
785 u_char achar, *fdType, xyy[4];
786 u_int16_t ashort, bshort;
789 u_int16_t upriv_bit = 0;
793 int change_mdate = 0;
794 int change_parent_mdate = 0;
799 u_int16_t bitmap = f_bitmap;
800 u_int32_t cdate,bdate;
801 u_char finder_buf[32];
804 LOG(log_info, logtype_afpd, "begin setfilparams:");
807 upath = path->u_name;
808 adp = of_ad(vol, path, &ad);
811 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
812 return AFPERR_ACCESS;
815 /* with unix priv maybe we have to change adouble file priv first */
817 while ( bitmap != 0 ) {
818 while (( bitmap & 1 ) == 0 ) {
825 memcpy(&ashort, buf, sizeof( ashort ));
826 buf += sizeof( ashort );
830 memcpy(&cdate, buf, sizeof(cdate));
831 buf += sizeof( cdate );
834 memcpy(&newdate, buf, sizeof( newdate ));
835 buf += sizeof( newdate );
839 memcpy(&bdate, buf, sizeof( bdate));
840 buf += sizeof( bdate );
844 memcpy(finder_buf, buf, 32 );
847 case FILPBIT_UNIXPR :
848 if (!vol_unix_priv(vol)) {
849 /* this volume doesn't use unix priv */
855 change_parent_mdate = 1;
857 memcpy( &aint, buf, sizeof( aint ));
858 f_uid = ntohl (aint);
859 buf += sizeof( aint );
860 memcpy( &aint, buf, sizeof( aint ));
861 f_gid = ntohl (aint);
862 buf += sizeof( aint );
863 setfilowner(vol, f_uid, f_gid, path);
865 memcpy( &upriv, buf, sizeof( upriv ));
866 buf += sizeof( upriv );
867 upriv = ntohl (upriv);
868 if ((upriv & S_IWUSR)) {
869 setfilunixmode(vol, path, upriv);
876 case FILPBIT_PDINFO :
877 if (afp_version < 30) { /* else it's UTF8 name */
880 /* Keep special case to support crlf translations */
881 if ((unsigned int) achar == 0x04) {
882 fdType = (u_char *)"TEXT";
885 xyy[0] = ( u_char ) 'p';
896 /* break while loop */
905 /* second try with adouble open
907 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
908 O_RDWR|O_CREAT, 0666, adp) < 0) {
909 /* for some things, we don't need an adouble header */
910 if (f_bitmap & ~(1<<FILPBIT_MDATE)) {
911 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
914 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
915 ad_setname(adp, path->m_name);
920 while ( bitmap != 0 ) {
921 while (( bitmap & 1 ) == 0 ) {
928 ad_getattr(adp, &bshort);
929 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
930 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
931 change_parent_mdate = 1;
932 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
933 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
937 ad_setattr(adp, bshort);
940 ad_setdate(adp, AD_DATE_CREATE, cdate);
945 ad_setdate(adp, AD_DATE_BACKUP, bdate);
948 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
950 ((em = getextmap( path->m_name )) &&
951 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
952 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
953 || ((em = getdefextmap()) &&
954 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
955 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
957 memcpy(finder_buf, ufinderi, 8 );
959 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
961 case FILPBIT_UNIXPR :
963 setfilunixmode(vol, path, upriv);
966 case FILPBIT_PDINFO :
967 if (afp_version < 30) { /* else it's UTF8 name */
968 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
969 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
975 goto setfilparam_done;
982 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
983 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
987 ad_setdate(adp, AD_DATE_MODIFY, newdate);
988 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
993 ad_flush( adp, ADFLAGS_HF );
994 ad_close( adp, ADFLAGS_HF );
998 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
999 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
1000 bitmap = 1<<FILPBIT_MDATE;
1001 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
1005 LOG(log_info, logtype_afpd, "end setfilparams:");
1011 * renamefile and copyfile take the old and new unix pathnames
1012 * and the new mac name.
1014 * src the source path
1015 * dst the dest filename in current dir
1016 * newname the dest mac name
1017 * adp adouble struct of src file, if open, or & zeroed one
1020 int renamefile(vol, src, dst, newname, adp )
1021 const struct vol *vol;
1022 char *src, *dst, *newname;
1023 struct adouble *adp;
1025 char adsrc[ MAXPATHLEN + 1];
1029 LOG(log_info, logtype_afpd, "begin renamefile:");
1032 if ( unix_rename( src, dst ) < 0 ) {
1035 return( AFPERR_NOOBJ );
1038 return( AFPERR_ACCESS );
1040 return AFPERR_VLOCK;
1041 case EXDEV : /* Cross device move -- try copy */
1042 /* NOTE: with open file it's an error because after the copy we will
1043 * get two files, it's fixable for our process (eg reopen the new file, get the
1044 * locks, and so on. But it doesn't solve the case with a second process
1046 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
1047 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1048 return AFPERR_OLOCK; /* little lie */
1050 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1051 /* on error copyfile delete dest */
1054 return deletefile(vol, src, 0);
1056 return( AFPERR_PARAM );
1060 strcpy( adsrc, vol->ad_path( src, 0 ));
1062 if (unix_rename( adsrc, vol->ad_path( dst, 0 )) < 0 ) {
1067 if (errno == ENOENT) {
1070 if (stat(adsrc, &st)) /* source has no ressource fork, */
1073 /* We are here because :
1074 * -there's no dest folder.
1075 * -there's no .AppleDouble in the dest folder.
1076 * if we use the struct adouble passed in parameter it will not
1077 * create .AppleDouble if the file is already opened, so we
1078 * use a diff one, it's not a pb,ie it's not the same file, yet.
1080 ad_init(&ad, vol->v_adouble);
1081 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
1082 ad_close(&ad, ADFLAGS_HF);
1083 if (!unix_rename( adsrc, vol->ad_path( dst, 0 )) )
1088 else { /* it's something else, bail out */
1092 /* try to undo the data fork rename,
1093 * we know we are on the same device
1096 unix_rename( dst, src );
1097 /* return the first error */
1100 return AFPERR_NOOBJ;
1103 return AFPERR_ACCESS ;
1105 return AFPERR_VLOCK;
1107 return AFPERR_PARAM ;
1112 /* don't care if we can't open the newly renamed ressource fork
1114 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1115 ad_setname(adp, newname);
1116 ad_flush( adp, ADFLAGS_HF );
1117 ad_close( adp, ADFLAGS_HF );
1120 LOG(log_info, logtype_afpd, "end renamefile:");
1127 convert a Mac long name to an utf8 name,
1129 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1133 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1139 /* ---------------- */
1140 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1147 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1153 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1154 if (afp_version >= 30) {
1155 /* convert it to UTF8
1157 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == -1)
1161 strncpy( newname, ibuf, plen );
1162 newname[ plen ] = '\0';
1164 if (strlen(newname) != plen) {
1165 /* there's \0 in newname, e.g. it's a pathname not
1173 memcpy(&hint, ibuf, sizeof(hint));
1174 ibuf += sizeof(hint);
1176 memcpy(&len16, ibuf, sizeof(len16));
1177 ibuf += sizeof(len16);
1178 plen = ntohs(len16);
1181 if (plen > AFPOBJ_TMPSIZ) {
1184 strncpy( newname, ibuf, plen );
1185 newname[ plen ] = '\0';
1186 if (strlen(newname) != plen) {
1195 /* -----------------------------------
1197 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1200 int ibuflen, *rbuflen;
1202 struct vol *s_vol, *d_vol;
1204 char *newname, *p, *upath;
1205 struct path *s_path;
1206 u_int32_t sdid, ddid;
1207 int err, retvalue = AFP_OK;
1208 u_int16_t svid, dvid;
1210 struct adouble ad, *adp;
1214 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1220 memcpy(&svid, ibuf, sizeof( svid ));
1221 ibuf += sizeof( svid );
1222 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1223 return( AFPERR_PARAM );
1226 memcpy(&sdid, ibuf, sizeof( sdid ));
1227 ibuf += sizeof( sdid );
1228 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1232 memcpy(&dvid, ibuf, sizeof( dvid ));
1233 ibuf += sizeof( dvid );
1234 memcpy(&ddid, ibuf, sizeof( ddid ));
1235 ibuf += sizeof( ddid );
1237 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1238 return get_afp_errno(AFPERR_PARAM);
1240 if ( path_isadir(s_path) ) {
1241 return( AFPERR_BADTYPE );
1244 /* don't allow copies when the file is open.
1245 * XXX: the spec only calls for read/deny write access.
1246 * however, copyfile doesn't have any of that info,
1247 * and locks need to stay coherent. as a result,
1248 * we just balk if the file is opened already. */
1250 adp = of_ad(s_vol, s_path, &ad);
1252 if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1253 return AFPERR_DENYCONF;
1255 denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
1256 getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1257 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1259 return AFPERR_DENYCONF;
1262 newname = obj->newtmp;
1263 strcpy( newname, s_path->m_name );
1265 p = ctoupath( s_vol, curdir, newname );
1267 return AFPERR_PARAM;
1271 /* FIXME svid != dvid && dvid's user can't read svid */
1273 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1274 return( AFPERR_PARAM );
1277 if (d_vol->v_flags & AFPVOL_RO)
1278 return AFPERR_VLOCK;
1280 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1284 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1285 return get_afp_errno(AFPERR_NOOBJ);
1287 if ( *s_path->m_name != '\0' ) {
1288 path_error(s_path, AFPERR_PARAM);
1291 /* one of the handful of places that knows about the path type */
1292 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1293 return( AFPERR_PARAM );
1295 /* newname is always only a filename so curdir *is* its
1298 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1299 return( AFPERR_PARAM );
1301 if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1307 if (vol->v_flags & AFPVOL_DROPBOX) {
1308 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1310 #endif /* DROPKLUDGE */
1312 setvoltime(obj, d_vol );
1315 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1321 /* ----------------------- */
1322 static __inline__ int copy_all(const int dfd, const void *buf,
1328 LOG(log_info, logtype_afpd, "begin copy_all:");
1331 while (buflen > 0) {
1332 if ((cc = write(dfd, buf, buflen)) < 0) {
1344 LOG(log_info, logtype_afpd, "end copy_all:");
1350 /* -------------------------- */
1351 static int copy_fd(int dfd, int sfd)
1357 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1358 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1362 #define BUF 128*1024*1024
1364 if (fstat(sfd, &st) == 0) {
1367 if ( offset >= st.st_size) {
1370 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1371 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1374 case EINVAL: /* there's no guarantee that all fs support sendfile */
1383 lseek(sfd, offset, SEEK_SET);
1387 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1394 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1401 /* ----------------------------------
1402 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1403 * because we are doing it elsewhere.
1405 int copyfile(s_vol, d_vol, src, dst, newname, adp )
1406 const struct vol *s_vol, *d_vol;
1407 char *src, *dst, *newname;
1408 struct adouble *adp;
1410 struct adouble ads, add;
1414 int noadouble = vol_noadouble(d_vol);
1418 LOG(log_info, logtype_afpd, "begin copyfile:");
1422 ad_init(&ads, s_vol->v_adouble);
1425 ad_init(&add, d_vol->v_adouble);
1426 adflags = ADFLAGS_DF;
1428 adflags |= ADFLAGS_HF;
1431 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1436 if (ad_hfileno(adp) == -1) {
1437 /* no resource fork, don't create one for dst file */
1438 adflags &= ~ADFLAGS_HF;
1441 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1443 ad_close( adp, adflags );
1444 if (EEXIST != ret_err) {
1445 deletefile(d_vol, dst, 0);
1448 return AFPERR_EXIST;
1450 if (ad_hfileno(adp) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(adp)))){
1451 /* copy the data fork */
1452 err = copy_fd(ad_dfileno(&add), ad_dfileno(adp));
1455 /* Now, reopen destination file */
1459 ad_close( adp, adflags );
1461 if (ad_close( &add, adflags ) <0) {
1462 deletefile(d_vol, dst, 0);
1467 ad_init(&add, d_vol->v_adouble);
1468 if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
1473 if (!ret_err && newname) {
1474 ad_setname(&add, newname);
1477 ad_flush( &add, adflags );
1478 if (ad_close( &add, adflags ) <0) {
1482 deletefile(d_vol, dst, 0);
1484 else if (!stat(src, &st)) {
1485 /* set dest modification date to src date */
1488 ut.actime = ut.modtime = st.st_mtime;
1490 /* FIXME netatalk doesn't use resource fork file date
1491 * but maybe we should set its modtime too.
1496 LOG(log_info, logtype_afpd, "end copyfile:");
1500 switch ( ret_err ) {
1506 return AFPERR_DFULL;
1508 return AFPERR_NOOBJ;
1510 return AFPERR_ACCESS;
1512 return AFPERR_VLOCK;
1514 return AFPERR_PARAM;
1518 /* -----------------------------------
1519 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1520 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1522 when deletefile is called we don't have lock on it, file is closed (for us)
1523 untrue if called by renamefile
1525 ad_open always try to open file RDWR first and ad_lock takes care of
1526 WRITE lock on read only file.
1528 int deletefile( vol, file, checkAttrib )
1529 const struct vol *vol;
1534 struct adouble *adp = &ad;
1535 int adflags, err = AFP_OK;
1538 LOG(log_info, logtype_afpd, "begin deletefile:");
1541 /* try to open both forks at once */
1542 adflags = ADFLAGS_DF|ADFLAGS_HF;
1544 ad_init(&ad, vol->v_adouble); /* OK */
1545 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1548 if (adflags == ADFLAGS_DF)
1549 return AFPERR_NOOBJ;
1551 /* that failed. now try to open just the data fork */
1552 adflags = ADFLAGS_DF;
1556 adp = NULL; /* maybe it's a file we no rw mode for us */
1557 break; /* was return AFPERR_ACCESS;*/
1559 return AFPERR_VLOCK;
1561 return( AFPERR_PARAM );
1564 break; /* from the while */
1567 * Does kFPDeleteInhibitBit (bit 8) set?
1572 if (adp && (adflags & ADFLAGS_HF)) {
1574 ad_getattr(&ad, &bshort);
1575 if ((bshort & htons(ATTRBIT_NODELETE))) {
1576 ad_close( &ad, adflags );
1577 return(AFPERR_OLOCK);
1581 /* was EACCESS error try to get only metadata */
1582 ad_init(&ad, vol->v_adouble); /* OK */
1583 if ( ad_metadata( file , 0, &ad) == 0 ) {
1584 ad_getattr(&ad, &bshort);
1585 ad_close( &ad, ADFLAGS_HF );
1586 if ((bshort & htons(ATTRBIT_NODELETE))) {
1587 return AFPERR_OLOCK;
1593 if (adp && (adflags & ADFLAGS_HF) ) {
1594 /* FIXME we have a pb here because we want to know if a file is open
1595 * there's a 'priority inversion' if you can't open the ressource fork RW
1596 * you can delete it if it's open because you can't get a write lock.
1598 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1601 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1603 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1604 ad_close( &ad, adflags );
1605 return( AFPERR_BUSY );
1609 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1612 else if (!(err = netatalk_unlink( vol->ad_path( file, ADFLAGS_HF)) ) &&
1613 !(err = netatalk_unlink( file )) ) {
1615 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1617 cnid_delete(vol->v_cdb, id);
1622 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1625 LOG(log_info, logtype_afpd, "end deletefile:");
1631 /* ------------------------------------ */
1632 /* return a file id */
1633 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1636 int ibuflen, *rbuflen;
1645 struct path *s_path;
1648 LOG(log_info, logtype_afpd, "begin afp_createid:");
1655 memcpy(&vid, ibuf, sizeof(vid));
1656 ibuf += sizeof(vid);
1658 if (NULL == ( vol = getvolbyvid( vid )) ) {
1659 return( AFPERR_PARAM);
1662 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1666 if (vol->v_flags & AFPVOL_RO)
1667 return AFPERR_VLOCK;
1669 memcpy(&did, ibuf, sizeof( did ));
1670 ibuf += sizeof(did);
1672 if (NULL == ( dir = dirlookup( vol, did )) ) {
1673 return afp_errno; /* was AFPERR_PARAM */
1676 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1677 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1680 if ( path_isadir(s_path) ) {
1681 return( AFPERR_BADTYPE );
1684 upath = s_path->u_name;
1685 switch (s_path->st_errno) {
1687 break; /* success */
1690 return AFPERR_ACCESS;
1692 return AFPERR_NOOBJ;
1694 return AFPERR_PARAM;
1697 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1698 memcpy(rbuf, &id, sizeof(id));
1699 *rbuflen = sizeof(id);
1700 return AFPERR_EXISTID;
1703 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1704 memcpy(rbuf, &id, sizeof(id));
1705 *rbuflen = sizeof(id);
1710 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1716 reenumerate_id(const struct vol *vol, char *name, cnid_t did)
1724 memset(&path, 0, sizeof(path));
1725 if (vol->v_cdb == NULL) {
1728 if (NULL == ( dp = opendir( name)) ) {
1732 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
1733 if (NULL == check_dirent(vol, de->d_name))
1736 if ( stat(de->d_name, &path.st)<0 )
1739 /* update or add to cnid */
1740 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1742 #if AD_VERSION > AD_VERSION1
1743 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1744 // struct ofork *of;
1745 struct adouble ad, *adp;
1749 path.u_name = de->d_name;
1751 adp = of_ad(vol, &path, &ad);
1753 if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, adp ) < 0 ) {
1756 if (ad_setid(adp,(vol->v_flags & AFPVOL_NODEV)?0:path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1757 ad_flush(adp, ADFLAGS_HF);
1759 ad_close(adp, ADFLAGS_HF);
1761 #endif /* AD_VERSION > AD_VERSION1 */
1770 /* ------------------------------
1771 resolve a file id */
1772 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1775 int ibuflen, *rbuflen;
1781 int err, buflen, retry=0;
1783 u_int16_t vid, bitmap;
1785 static char buffer[12 + MAXPATHLEN + 1];
1786 int len = 12 + MAXPATHLEN + 1;
1789 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1795 memcpy(&vid, ibuf, sizeof(vid));
1796 ibuf += sizeof(vid);
1798 if (NULL == ( vol = getvolbyvid( vid )) ) {
1799 return( AFPERR_PARAM);
1802 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1806 memcpy(&id, ibuf, sizeof( id ));
1811 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1812 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1815 if (NULL == ( dir = dirlookup( vol, id )) ) {
1816 return AFPERR_NOID; /* idem AFPERR_PARAM */
1818 path.u_name = upath;
1819 if (movecwd(vol, dir) < 0) {
1823 return AFPERR_ACCESS;
1827 return AFPERR_PARAM;
1831 if ( of_stat(&path) < 0 ) {
1833 /* with nfs and our working directory is deleted */
1834 if (errno == ESTALE) {
1838 if ( errno == ENOENT && !retry) {
1839 /* cnid db is out of sync, reenumerate the directory and updated ids */
1840 reenumerate_id(vol, ".", id);
1848 return AFPERR_ACCESS;
1852 return AFPERR_PARAM;
1856 /* directories are bad */
1857 if (S_ISDIR(path.st.st_mode))
1858 return AFPERR_BADTYPE;
1860 memcpy(&bitmap, ibuf, sizeof(bitmap));
1861 bitmap = ntohs( bitmap );
1862 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1865 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1866 rbuf + sizeof(bitmap), &buflen))) {
1869 *rbuflen = buflen + sizeof(bitmap);
1870 memcpy(rbuf, ibuf, sizeof(bitmap));
1873 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1879 /* ------------------------------ */
1880 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1883 int ibuflen, *rbuflen;
1893 static char buffer[12 + MAXPATHLEN + 1];
1894 int len = 12 + MAXPATHLEN + 1;
1897 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1903 memcpy(&vid, ibuf, sizeof(vid));
1904 ibuf += sizeof(vid);
1906 if (NULL == ( vol = getvolbyvid( vid )) ) {
1907 return( AFPERR_PARAM);
1910 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1914 if (vol->v_flags & AFPVOL_RO)
1915 return AFPERR_VLOCK;
1917 memcpy(&id, ibuf, sizeof( id ));
1921 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1925 if (NULL == ( dir = dirlookup( vol, id )) ) {
1926 return( AFPERR_PARAM );
1930 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1934 return AFPERR_ACCESS;
1939 /* still try to delete the id */
1943 return AFPERR_PARAM;
1946 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1947 return AFPERR_BADTYPE;
1949 if (cnid_delete(vol->v_cdb, fileid)) {
1952 return AFPERR_VLOCK;
1955 return AFPERR_ACCESS;
1957 return AFPERR_PARAM;
1962 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1968 /* ------------------------------ */
1969 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1973 if (path->st_errno) {
1974 switch (path->st_errno) {
1976 afp_errno = AFPERR_NOID;
1980 afp_errno = AFPERR_ACCESS;
1983 afp_errno = AFPERR_PARAM;
1988 /* we use file_access both for legacy Mac perm and
1989 * for unix privilege, rename will take care of folder perms
1991 if (file_access(path, OPENACC_WR ) < 0) {
1992 afp_errno = AFPERR_ACCESS;
1996 if ((*of = of_findname(path))) {
1997 /* reuse struct adouble so it won't break locks */
2001 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
2002 if ( !ret && ad_hfileno(adp) != -1 && !(adp->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) {
2004 * The user must have the Read & Write privilege for both files in order to use this command.
2006 ad_close(adp, ADFLAGS_HF);
2007 afp_errno = AFPERR_ACCESS;
2014 #define APPLETEMP ".AppleTempXXXXXX"
2016 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
2019 int ibuflen, *rbuflen;
2021 struct stat srcst, destst;
2023 struct dir *dir, *sdir;
2024 char *spath, temp[17], *p;
2025 char *supath, *upath;
2030 struct adouble *adsp = NULL;
2031 struct adouble *addp = NULL;
2032 struct ofork *s_of = NULL;
2033 struct ofork *d_of = NULL;
2044 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
2050 memcpy(&vid, ibuf, sizeof(vid));
2051 ibuf += sizeof(vid);
2053 if (NULL == ( vol = getvolbyvid( vid )) ) {
2054 return( AFPERR_PARAM);
2057 if ((vol->v_flags & AFPVOL_RO))
2058 return AFPERR_VLOCK;
2060 /* source and destination dids */
2061 memcpy(&sid, ibuf, sizeof(sid));
2062 ibuf += sizeof(sid);
2063 memcpy(&did, ibuf, sizeof(did));
2064 ibuf += sizeof(did);
2067 if (NULL == (dir = dirlookup( vol, sid )) ) {
2068 return afp_errno; /* was AFPERR_PARAM */
2071 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2072 return get_afp_errno(AFPERR_NOOBJ);
2075 if ( path_isadir(path) ) {
2076 return AFPERR_BADTYPE; /* it's a dir */
2079 /* save some stuff */
2082 spath = obj->oldtmp;
2083 supath = obj->newtmp;
2084 strcpy(spath, path->m_name);
2085 strcpy(supath, path->u_name); /* this is for the cnid changing */
2086 p = absupath( vol, sdir, supath);
2088 /* pathname too long */
2089 return AFPERR_PARAM ;
2092 ad_init(&ads, vol->v_adouble);
2093 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2097 /* ***** from here we may have resource fork open **** */
2099 /* look for the source cnid. if it doesn't exist, don't worry about
2101 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2103 if (NULL == ( dir = dirlookup( vol, did )) ) {
2104 err = afp_errno; /* was AFPERR_PARAM */
2105 goto err_exchangefile;
2108 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2109 err = get_afp_errno(AFPERR_NOOBJ);
2110 goto err_exchangefile;
2113 if ( path_isadir(path) ) {
2114 err = AFPERR_BADTYPE;
2115 goto err_exchangefile;
2118 /* FPExchangeFiles is the only call that can return the SameObj
2120 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2121 err = AFPERR_SAMEOBJ;
2122 goto err_exchangefile;
2125 ad_init(&add, vol->v_adouble);
2126 if (!(addp = find_adouble( path, &d_of, &add))) {
2128 goto err_exchangefile;
2132 /* they are not on the same device and at least one is open
2133 * FIXME broken for for crossdev and adouble v2
2136 crossdev = (srcst.st_dev != destst.st_dev);
2137 if (/* (d_of || s_of) && */ crossdev) {
2139 goto err_exchangefile;
2142 /* look for destination id. */
2143 upath = path->u_name;
2144 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2146 /* construct a temp name.
2147 * NOTE: the temp file will be in the dest file's directory. it
2148 * will also be inaccessible from AFP. */
2149 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2150 if (!mktemp(temp)) {
2152 goto err_exchangefile;
2156 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2157 ad_close(adsp, ADFLAGS_HF);
2158 ad_close(addp, ADFLAGS_HF);
2161 /* now, quickly rename the file. we error if we can't. */
2162 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2163 goto err_exchangefile;
2164 of_rename(vol, s_of, sdir, spath, curdir, temp);
2166 /* rename destination to source */
2167 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2168 goto err_src_to_tmp;
2169 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2171 /* rename temp to destination */
2172 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2173 goto err_dest_to_src;
2174 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2176 /* id's need switching. src -> dest and dest -> src.
2177 * we need to re-stat() if it was a cross device copy.
2180 cnid_delete(vol->v_cdb, sid);
2183 cnid_delete(vol->v_cdb, did);
2185 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2186 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2188 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2189 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2194 err = AFPERR_ACCESS;
2199 goto err_temp_to_dest;
2202 /* here we need to reopen if crossdev */
2203 if (sid && ad_setid(addp,(vol->v_flags & AFPVOL_NODEV)?0:destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2205 ad_flush( addp, ADFLAGS_HF );
2208 if (did && ad_setid(adsp,(vol->v_flags & AFPVOL_NODEV)?0:srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2210 ad_flush( adsp, ADFLAGS_HF );
2213 /* change perms, src gets dest perm and vice versa */
2218 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2219 err = AFP_OK; /* ignore error */
2220 goto err_temp_to_dest;
2224 * we need to exchange ACL entries as well
2226 /* exchange_acls(vol, p, upath); */
2231 path->m_name = NULL;
2232 path->u_name = upath;
2234 setfilunixmode(vol, path, destst.st_mode);
2235 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2242 setfilunixmode(vol, path, srcst.st_mode);
2243 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2245 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2246 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2251 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2255 goto err_exchangefile;
2257 /* all this stuff is so that we can unwind a failed operation
2260 /* rename dest to temp */
2261 renamefile(vol, upath, temp, temp, adsp);
2262 of_rename(vol, s_of, curdir, upath, curdir, temp);
2265 /* rename source back to dest */
2266 renamefile(vol, p, upath, path->m_name, addp);
2267 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2270 /* rename temp back to source */
2271 renamefile(vol, temp, p, spath, adsp);
2272 of_rename(vol, s_of, curdir, temp, sdir, spath);
2275 if ( !s_of && adsp && ad_hfileno(adsp) != -1 ) {
2276 ad_close(adsp, ADFLAGS_HF);
2278 if ( !d_of && addp && ad_hfileno(addp) != -1 ) {
2279 ad_close(addp, ADFLAGS_HF);