2 * $Id: file.c,v 1.92.2.2.2.31.2.4 2004-12-07 02:58:09 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 if ((of = of_findname(path))) {
811 ad_init(&ad, vol->v_adouble);
815 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
816 return AFPERR_ACCESS;
819 /* with unix priv maybe we have to change adouble file priv first */
821 while ( bitmap != 0 ) {
822 while (( bitmap & 1 ) == 0 ) {
829 memcpy(&ashort, buf, sizeof( ashort ));
830 buf += sizeof( ashort );
834 memcpy(&cdate, buf, sizeof(cdate));
835 buf += sizeof( cdate );
838 memcpy(&newdate, buf, sizeof( newdate ));
839 buf += sizeof( newdate );
843 memcpy(&bdate, buf, sizeof( bdate));
844 buf += sizeof( bdate );
848 memcpy(finder_buf, buf, 32 );
851 case FILPBIT_UNIXPR :
852 if (!vol_unix_priv(vol)) {
853 /* this volume doesn't use unix priv */
859 change_parent_mdate = 1;
861 memcpy( &aint, buf, sizeof( aint ));
862 f_uid = ntohl (aint);
863 buf += sizeof( aint );
864 memcpy( &aint, buf, sizeof( aint ));
865 f_gid = ntohl (aint);
866 buf += sizeof( aint );
867 setfilowner(vol, f_uid, f_gid, path);
869 memcpy( &upriv, buf, sizeof( upriv ));
870 buf += sizeof( upriv );
871 upriv = ntohl (upriv);
872 if ((upriv & S_IWUSR)) {
873 setfilunixmode(vol, path, upriv);
880 case FILPBIT_PDINFO :
881 if (afp_version < 30) { /* else it's UTF8 name */
884 /* Keep special case to support crlf translations */
885 if ((unsigned int) achar == 0x04) {
886 fdType = (u_char *)"TEXT";
889 xyy[0] = ( u_char ) 'p';
900 /* break while loop */
909 /* second try with adouble open
911 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
912 O_RDWR|O_CREAT, 0666, adp) < 0) {
913 /* for some things, we don't need an adouble header */
914 if (f_bitmap & ~(1<<FILPBIT_MDATE)) {
915 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
918 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
919 ad_setname(adp, path->m_name);
924 while ( bitmap != 0 ) {
925 while (( bitmap & 1 ) == 0 ) {
932 ad_getattr(adp, &bshort);
933 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
934 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
935 change_parent_mdate = 1;
936 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
937 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
941 ad_setattr(adp, bshort);
944 ad_setdate(adp, AD_DATE_CREATE, cdate);
949 ad_setdate(adp, AD_DATE_BACKUP, bdate);
952 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
954 ((em = getextmap( path->m_name )) &&
955 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
956 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
957 || ((em = getdefextmap()) &&
958 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
959 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
961 memcpy(finder_buf, ufinderi, 8 );
963 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
965 case FILPBIT_UNIXPR :
967 setfilunixmode(vol, path, upriv);
970 case FILPBIT_PDINFO :
971 if (afp_version < 30) { /* else it's UTF8 name */
972 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
973 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
979 goto setfilparam_done;
986 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
987 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
991 ad_setdate(adp, AD_DATE_MODIFY, newdate);
992 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
997 ad_flush( adp, ADFLAGS_HF );
998 ad_close( adp, ADFLAGS_HF );
1002 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
1003 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
1004 bitmap = 1<<FILPBIT_MDATE;
1005 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
1009 LOG(log_info, logtype_afpd, "end setfilparams:");
1015 * renamefile and copyfile take the old and new unix pathnames
1016 * and the new mac name.
1018 * src the source path
1019 * dst the dest filename in current dir
1020 * newname the dest mac name
1021 * adp adouble struct of src file, if open, or & zeroed one
1024 int renamefile(vol, src, dst, newname, adp )
1025 const struct vol *vol;
1026 char *src, *dst, *newname;
1027 struct adouble *adp;
1029 char adsrc[ MAXPATHLEN + 1];
1033 LOG(log_info, logtype_afpd, "begin renamefile:");
1036 if ( unix_rename( src, dst ) < 0 ) {
1039 return( AFPERR_NOOBJ );
1042 return( AFPERR_ACCESS );
1044 return AFPERR_VLOCK;
1045 case EXDEV : /* Cross device move -- try copy */
1046 /* NOTE: with open file it's an error because after the copy we will
1047 * get two files, it's fixable for our process (eg reopen the new file, get the
1048 * locks, and so on. But it doesn't solve the case with a second process
1050 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
1051 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1052 return AFPERR_OLOCK; /* little lie */
1054 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname )) ) {
1055 /* on error copyfile delete dest */
1058 return deletefile(vol, src, 0);
1060 return( AFPERR_PARAM );
1064 strcpy( adsrc, vol->ad_path( src, 0 ));
1066 if (unix_rename( adsrc, vol->ad_path( dst, 0 )) < 0 ) {
1071 if (errno == ENOENT) {
1074 if (stat(adsrc, &st)) /* source has no ressource fork, */
1077 /* We are here because :
1078 * -there's no dest folder.
1079 * -there's no .AppleDouble in the dest folder.
1080 * if we use the struct adouble passed in parameter it will not
1081 * create .AppleDouble if the file is already opened, so we
1082 * use a diff one, it's not a pb,ie it's not the same file, yet.
1084 ad_init(&ad, vol->v_adouble);
1085 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
1086 ad_close(&ad, ADFLAGS_HF);
1087 if (!unix_rename( adsrc, vol->ad_path( dst, 0 )) )
1092 else { /* it's something else, bail out */
1096 /* try to undo the data fork rename,
1097 * we know we are on the same device
1100 unix_rename( dst, src );
1101 /* return the first error */
1104 return AFPERR_NOOBJ;
1107 return AFPERR_ACCESS ;
1109 return AFPERR_VLOCK;
1111 return AFPERR_PARAM ;
1116 /* don't care if we can't open the newly renamed ressource fork
1118 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1119 ad_setname(adp, newname);
1120 ad_flush( adp, ADFLAGS_HF );
1121 ad_close( adp, ADFLAGS_HF );
1124 LOG(log_info, logtype_afpd, "end renamefile:");
1131 convert a Mac long name to an utf8 name,
1133 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1137 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1143 /* ---------------- */
1144 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1151 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1157 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1158 if (afp_version >= 30) {
1159 /* convert it to UTF8
1161 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == -1)
1165 strncpy( newname, ibuf, plen );
1166 newname[ plen ] = '\0';
1168 if (strlen(newname) != plen) {
1169 /* there's \0 in newname, e.g. it's a pathname not
1177 memcpy(&hint, ibuf, sizeof(hint));
1178 ibuf += sizeof(hint);
1180 memcpy(&len16, ibuf, sizeof(len16));
1181 ibuf += sizeof(len16);
1182 plen = ntohs(len16);
1185 if (plen > AFPOBJ_TMPSIZ) {
1188 strncpy( newname, ibuf, plen );
1189 newname[ plen ] = '\0';
1190 if (strlen(newname) != plen) {
1199 /* -----------------------------------
1201 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1204 int ibuflen, *rbuflen;
1206 struct vol *s_vol, *d_vol;
1208 char *newname, *p, *upath;
1209 struct path *s_path;
1210 u_int32_t sdid, ddid;
1211 int err, retvalue = AFP_OK;
1212 u_int16_t svid, dvid;
1215 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1221 memcpy(&svid, ibuf, sizeof( svid ));
1222 ibuf += sizeof( svid );
1223 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1224 return( AFPERR_PARAM );
1227 memcpy(&sdid, ibuf, sizeof( sdid ));
1228 ibuf += sizeof( sdid );
1229 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1233 memcpy(&dvid, ibuf, sizeof( dvid ));
1234 ibuf += sizeof( dvid );
1235 memcpy(&ddid, ibuf, sizeof( ddid ));
1236 ibuf += sizeof( ddid );
1238 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1239 return get_afp_errno(AFPERR_PARAM);
1241 if ( path_isadir(s_path) ) {
1242 return( AFPERR_BADTYPE );
1245 /* don't allow copies when the file is open.
1246 * XXX: the spec only calls for read/deny write access.
1247 * however, copyfile doesn't have any of that info,
1248 * and locks need to stay coherent. as a result,
1249 * we just balk if the file is opened already. */
1251 newname = obj->newtmp;
1252 strcpy( newname, s_path->m_name );
1254 if (of_findname(s_path))
1255 return AFPERR_DENYCONF;
1257 p = ctoupath( s_vol, curdir, newname );
1259 return AFPERR_PARAM;
1263 /* FIXME svid != dvid && dvid's user can't read svid */
1265 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1266 return( AFPERR_PARAM );
1269 if (d_vol->v_flags & AFPVOL_RO)
1270 return AFPERR_VLOCK;
1272 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1276 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1277 return get_afp_errno(AFPERR_NOOBJ);
1279 if ( *s_path->m_name != '\0' ) {
1280 path_error(s_path, AFPERR_PARAM);
1283 /* one of the handful of places that knows about the path type */
1284 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1285 return( AFPERR_PARAM );
1287 /* newname is always only a filename so curdir *is* its
1290 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1291 return( AFPERR_PARAM );
1293 if ( (err = copyfile(s_vol, d_vol, p, upath , newname)) < 0 ) {
1299 if (vol->v_flags & AFPVOL_DROPBOX) {
1300 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1302 #endif /* DROPKLUDGE */
1304 setvoltime(obj, d_vol );
1307 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1313 /* ----------------------- */
1314 static __inline__ int copy_all(const int dfd, const void *buf,
1320 LOG(log_info, logtype_afpd, "begin copy_all:");
1323 while (buflen > 0) {
1324 if ((cc = write(dfd, buf, buflen)) < 0) {
1336 LOG(log_info, logtype_afpd, "end copy_all:");
1342 /* -------------------------- */
1343 static int copy_fd(int dfd, int sfd)
1349 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1350 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1354 #define BUF 128*1024*1024
1356 if (fstat(sfd, &st) == 0) {
1359 if ( offset >= st.st_size) {
1362 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1363 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1366 case EINVAL: /* there's no guarantee that all fs support sendfile */
1375 lseek(sfd, offset, SEEK_SET);
1379 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1386 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1393 /* ----------------------------------
1394 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1395 * because we are doing it elsewhere.
1397 int copyfile(s_vol, d_vol, src, dst, newname )
1398 const struct vol *s_vol, *d_vol;
1399 char *src, *dst, *newname;
1401 struct adouble ads, add;
1405 int noadouble = vol_noadouble(d_vol);
1409 LOG(log_info, logtype_afpd, "begin copyfile:");
1412 ad_init(&ads, s_vol->v_adouble);
1413 ad_init(&add, d_vol->v_adouble);
1414 adflags = ADFLAGS_DF;
1416 adflags |= ADFLAGS_HF;
1419 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1424 if (ad_hfileno(&ads) == -1) {
1425 /* no resource fork, don't create one for dst file */
1426 adflags &= ~ADFLAGS_HF;
1429 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1431 ad_close( &ads, adflags );
1432 if (EEXIST != ret_err) {
1433 deletefile(d_vol, dst, 0);
1436 return AFPERR_EXIST;
1438 if (ad_hfileno(&ads) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1439 /* copy the data fork */
1440 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1443 /* Now, reopen destination file */
1447 ad_close( &ads, adflags );
1449 if (ad_close( &add, adflags ) <0) {
1450 deletefile(d_vol, dst, 0);
1455 ad_init(&add, d_vol->v_adouble);
1456 if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
1461 if (!ret_err && newname) {
1462 ad_setname(&add, newname);
1465 ad_flush( &add, adflags );
1466 if (ad_close( &add, adflags ) <0) {
1470 deletefile(d_vol, dst, 0);
1472 else if (!stat(src, &st)) {
1473 /* set dest modification date to src date */
1476 ut.actime = ut.modtime = st.st_mtime;
1478 /* FIXME netatalk doesn't use resource fork file date
1479 * but maybe we should set its modtime too.
1484 LOG(log_info, logtype_afpd, "end copyfile:");
1488 switch ( ret_err ) {
1494 return AFPERR_DFULL;
1496 return AFPERR_NOOBJ;
1498 return AFPERR_ACCESS;
1500 return AFPERR_VLOCK;
1502 return AFPERR_PARAM;
1506 /* -----------------------------------
1507 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1508 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1510 when deletefile is called we don't have lock on it, file is closed (for us)
1511 untrue if called by renamefile
1513 ad_open always try to open file RDWR first and ad_lock takes care of
1514 WRITE lock on read only file.
1516 int deletefile( vol, file, checkAttrib )
1517 const struct vol *vol;
1522 struct adouble *adp = &ad;
1523 int adflags, err = AFP_OK;
1526 LOG(log_info, logtype_afpd, "begin deletefile:");
1529 /* try to open both forks at once */
1530 adflags = ADFLAGS_DF|ADFLAGS_HF;
1532 ad_init(&ad, vol->v_adouble); /* OK */
1533 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1536 if (adflags == ADFLAGS_DF)
1537 return AFPERR_NOOBJ;
1539 /* that failed. now try to open just the data fork */
1540 adflags = ADFLAGS_DF;
1544 adp = NULL; /* maybe it's a file we no rw mode for us */
1545 break; /* was return AFPERR_ACCESS;*/
1547 return AFPERR_VLOCK;
1549 return( AFPERR_PARAM );
1552 break; /* from the while */
1555 * Does kFPDeleteInhibitBit (bit 8) set?
1560 if (adp && (adflags & ADFLAGS_HF)) {
1562 ad_getattr(&ad, &bshort);
1563 if ((bshort & htons(ATTRBIT_NODELETE))) {
1564 ad_close( &ad, adflags );
1565 return(AFPERR_OLOCK);
1569 /* was EACCESS error try to get only metadata */
1570 ad_init(&ad, vol->v_adouble); /* OK */
1571 if ( ad_metadata( file , 0, &ad) == 0 ) {
1572 ad_getattr(&ad, &bshort);
1573 ad_close( &ad, ADFLAGS_HF );
1574 if ((bshort & htons(ATTRBIT_NODELETE))) {
1575 return AFPERR_OLOCK;
1581 if (adp && (adflags & ADFLAGS_HF) ) {
1582 /* FIXME we have a pb here because we want to know if a file is open
1583 * there's a 'priority inversion' if you can't open the ressource fork RW
1584 * you can delete it if it's open because you can't get a write lock.
1586 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1589 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1591 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1592 ad_close( &ad, adflags );
1593 return( AFPERR_BUSY );
1597 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1600 else if (!(err = netatalk_unlink( vol->ad_path( file, ADFLAGS_HF)) ) &&
1601 !(err = netatalk_unlink( file )) ) {
1603 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1605 cnid_delete(vol->v_cdb, id);
1610 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1613 LOG(log_info, logtype_afpd, "end deletefile:");
1619 /* ------------------------------------ */
1620 /* return a file id */
1621 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1624 int ibuflen, *rbuflen;
1633 struct path *s_path;
1636 LOG(log_info, logtype_afpd, "begin afp_createid:");
1643 memcpy(&vid, ibuf, sizeof(vid));
1644 ibuf += sizeof(vid);
1646 if (NULL == ( vol = getvolbyvid( vid )) ) {
1647 return( AFPERR_PARAM);
1650 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1654 if (vol->v_flags & AFPVOL_RO)
1655 return AFPERR_VLOCK;
1657 memcpy(&did, ibuf, sizeof( did ));
1658 ibuf += sizeof(did);
1660 if (NULL == ( dir = dirlookup( vol, did )) ) {
1661 return afp_errno; /* was AFPERR_PARAM */
1664 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1665 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1668 if ( path_isadir(s_path) ) {
1669 return( AFPERR_BADTYPE );
1672 upath = s_path->u_name;
1673 switch (s_path->st_errno) {
1675 break; /* success */
1678 return AFPERR_ACCESS;
1680 return AFPERR_NOOBJ;
1682 return AFPERR_PARAM;
1685 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1686 memcpy(rbuf, &id, sizeof(id));
1687 *rbuflen = sizeof(id);
1688 return AFPERR_EXISTID;
1691 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1692 memcpy(rbuf, &id, sizeof(id));
1693 *rbuflen = sizeof(id);
1698 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1704 reenumerate_id(const struct vol *vol, char *name, cnid_t did)
1712 memset(&path, 0, sizeof(path));
1713 if (vol->v_cdb == NULL) {
1716 if (NULL == ( dp = opendir( name)) ) {
1720 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
1721 if (NULL == check_dirent(vol, de->d_name))
1724 if ( stat(de->d_name, &path.st)<0 )
1727 /* update or add to cnid */
1728 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1730 #if AD_VERSION > AD_VERSION1
1731 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1733 struct adouble ad, *adp;
1737 path.u_name = de->d_name;
1739 if (!(of = of_findname(&path))) {
1740 ad_init(&ad, vol->v_adouble);
1745 if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, adp ) < 0 ) {
1748 if (ad_setid(adp,(vol->v_flags & AFPVOL_NODEV)?0:path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1749 ad_flush(adp, ADFLAGS_HF);
1751 ad_close(adp, ADFLAGS_HF);
1753 #endif /* AD_VERSION > AD_VERSION1 */
1762 /* ------------------------------
1763 resolve a file id */
1764 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1767 int ibuflen, *rbuflen;
1773 int err, buflen, retry=0;
1775 u_int16_t vid, bitmap;
1777 static char buffer[12 + MAXPATHLEN + 1];
1778 int len = 12 + MAXPATHLEN + 1;
1781 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1787 memcpy(&vid, ibuf, sizeof(vid));
1788 ibuf += sizeof(vid);
1790 if (NULL == ( vol = getvolbyvid( vid )) ) {
1791 return( AFPERR_PARAM);
1794 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1798 memcpy(&id, ibuf, sizeof( id ));
1803 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1804 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1807 if (NULL == ( dir = dirlookup( vol, id )) ) {
1808 return AFPERR_NOID; /* idem AFPERR_PARAM */
1810 path.u_name = upath;
1811 if (movecwd(vol, dir) < 0) {
1815 return AFPERR_ACCESS;
1819 return AFPERR_PARAM;
1823 if ( of_stat(&path) < 0 ) {
1825 /* with nfs and our working directory is deleted */
1826 if (errno == ESTALE) {
1830 if ( errno == ENOENT && !retry) {
1831 /* cnid db is out of sync, reenumerate the directory and updated ids */
1832 reenumerate_id(vol, ".", id);
1840 return AFPERR_ACCESS;
1844 return AFPERR_PARAM;
1848 /* directories are bad */
1849 if (S_ISDIR(path.st.st_mode))
1850 return AFPERR_BADTYPE;
1852 memcpy(&bitmap, ibuf, sizeof(bitmap));
1853 bitmap = ntohs( bitmap );
1854 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1857 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1858 rbuf + sizeof(bitmap), &buflen))) {
1861 *rbuflen = buflen + sizeof(bitmap);
1862 memcpy(rbuf, ibuf, sizeof(bitmap));
1865 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1871 /* ------------------------------ */
1872 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1875 int ibuflen, *rbuflen;
1885 static char buffer[12 + MAXPATHLEN + 1];
1886 int len = 12 + MAXPATHLEN + 1;
1889 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1895 memcpy(&vid, ibuf, sizeof(vid));
1896 ibuf += sizeof(vid);
1898 if (NULL == ( vol = getvolbyvid( vid )) ) {
1899 return( AFPERR_PARAM);
1902 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1906 if (vol->v_flags & AFPVOL_RO)
1907 return AFPERR_VLOCK;
1909 memcpy(&id, ibuf, sizeof( id ));
1913 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1917 if (NULL == ( dir = dirlookup( vol, id )) ) {
1918 return( AFPERR_PARAM );
1922 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1926 return AFPERR_ACCESS;
1931 /* still try to delete the id */
1935 return AFPERR_PARAM;
1938 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1939 return AFPERR_BADTYPE;
1941 if (cnid_delete(vol->v_cdb, fileid)) {
1944 return AFPERR_VLOCK;
1947 return AFPERR_ACCESS;
1949 return AFPERR_PARAM;
1954 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1960 /* ------------------------------ */
1961 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1965 if (path->st_errno) {
1966 switch (path->st_errno) {
1968 afp_errno = AFPERR_NOID;
1972 afp_errno = AFPERR_ACCESS;
1975 afp_errno = AFPERR_PARAM;
1980 /* we use file_access both for legacy Mac perm and
1981 * for unix privilege, rename will take care of folder perms
1983 if (file_access(path, OPENACC_WR ) < 0) {
1984 afp_errno = AFPERR_ACCESS;
1988 if ((*of = of_findname(path))) {
1989 /* reuse struct adouble so it won't break locks */
1993 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
1994 if ( !ret && ad_hfileno(adp) != -1 && !(adp->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) {
1996 * The user must have the Read & Write privilege for both files in order to use this command.
1998 ad_close(adp, ADFLAGS_HF);
1999 afp_errno = AFPERR_ACCESS;
2006 #define APPLETEMP ".AppleTempXXXXXX"
2008 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
2011 int ibuflen, *rbuflen;
2013 struct stat srcst, destst;
2015 struct dir *dir, *sdir;
2016 char *spath, temp[17], *p;
2017 char *supath, *upath;
2022 struct adouble *adsp = NULL;
2023 struct adouble *addp = NULL;
2024 struct ofork *s_of = NULL;
2025 struct ofork *d_of = NULL;
2036 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
2042 memcpy(&vid, ibuf, sizeof(vid));
2043 ibuf += sizeof(vid);
2045 if (NULL == ( vol = getvolbyvid( vid )) ) {
2046 return( AFPERR_PARAM);
2049 if ((vol->v_flags & AFPVOL_RO))
2050 return AFPERR_VLOCK;
2052 /* source and destination dids */
2053 memcpy(&sid, ibuf, sizeof(sid));
2054 ibuf += sizeof(sid);
2055 memcpy(&did, ibuf, sizeof(did));
2056 ibuf += sizeof(did);
2059 if (NULL == (dir = dirlookup( vol, sid )) ) {
2060 return afp_errno; /* was AFPERR_PARAM */
2063 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2064 return get_afp_errno(AFPERR_NOOBJ);
2067 if ( path_isadir(path) ) {
2068 return AFPERR_BADTYPE; /* it's a dir */
2071 /* save some stuff */
2074 spath = obj->oldtmp;
2075 supath = obj->newtmp;
2076 strcpy(spath, path->m_name);
2077 strcpy(supath, path->u_name); /* this is for the cnid changing */
2078 p = absupath( vol, sdir, supath);
2080 /* pathname too long */
2081 return AFPERR_PARAM ;
2084 ad_init(&ads, vol->v_adouble);
2085 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2089 /* ***** from here we may have resource fork open **** */
2091 /* look for the source cnid. if it doesn't exist, don't worry about
2093 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2095 if (NULL == ( dir = dirlookup( vol, did )) ) {
2096 err = afp_errno; /* was AFPERR_PARAM */
2097 goto err_exchangefile;
2100 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2101 err = get_afp_errno(AFPERR_NOOBJ);
2102 goto err_exchangefile;
2105 if ( path_isadir(path) ) {
2106 err = AFPERR_BADTYPE;
2107 goto err_exchangefile;
2110 /* FPExchangeFiles is the only call that can return the SameObj
2112 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2113 err = AFPERR_SAMEOBJ;
2114 goto err_exchangefile;
2117 ad_init(&add, vol->v_adouble);
2118 if (!(addp = find_adouble( path, &d_of, &add))) {
2120 goto err_exchangefile;
2124 /* they are not on the same device and at least one is open
2125 * FIXME broken for for crossdev and adouble v2
2128 crossdev = (srcst.st_dev != destst.st_dev);
2129 if (/* (d_of || s_of) && */ crossdev) {
2131 goto err_exchangefile;
2134 /* look for destination id. */
2135 upath = path->u_name;
2136 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2138 /* construct a temp name.
2139 * NOTE: the temp file will be in the dest file's directory. it
2140 * will also be inaccessible from AFP. */
2141 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2142 if (!mktemp(temp)) {
2144 goto err_exchangefile;
2148 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2149 ad_close(adsp, ADFLAGS_HF);
2150 ad_close(addp, ADFLAGS_HF);
2153 /* now, quickly rename the file. we error if we can't. */
2154 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2155 goto err_exchangefile;
2156 of_rename(vol, s_of, sdir, spath, curdir, temp);
2158 /* rename destination to source */
2159 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2160 goto err_src_to_tmp;
2161 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2163 /* rename temp to destination */
2164 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2165 goto err_dest_to_src;
2166 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2168 /* id's need switching. src -> dest and dest -> src.
2169 * we need to re-stat() if it was a cross device copy.
2172 cnid_delete(vol->v_cdb, sid);
2175 cnid_delete(vol->v_cdb, did);
2177 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2178 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2180 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2181 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2186 err = AFPERR_ACCESS;
2191 goto err_temp_to_dest;
2194 /* here we need to reopen if crossdev */
2195 if (sid && ad_setid(addp,(vol->v_flags & AFPVOL_NODEV)?0:destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2197 ad_flush( addp, ADFLAGS_HF );
2200 if (did && ad_setid(adsp,(vol->v_flags & AFPVOL_NODEV)?0:srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2202 ad_flush( adsp, ADFLAGS_HF );
2205 /* change perms, src gets dest perm and vice versa */
2210 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2211 err = AFP_OK; /* ignore error */
2212 goto err_temp_to_dest;
2216 * we need to exchange ACL entries as well
2218 /* exchange_acls(vol, p, upath); */
2223 path->m_name = NULL;
2224 path->u_name = upath;
2226 setfilunixmode(vol, path, destst.st_mode);
2227 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2234 setfilunixmode(vol, path, srcst.st_mode);
2235 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2237 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2238 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2243 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2247 goto err_exchangefile;
2249 /* all this stuff is so that we can unwind a failed operation
2252 /* rename dest to temp */
2253 renamefile(vol, upath, temp, temp, adsp);
2254 of_rename(vol, s_of, curdir, upath, curdir, temp);
2257 /* rename source back to dest */
2258 renamefile(vol, p, upath, path->m_name, addp);
2259 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2262 /* rename temp back to source */
2263 renamefile(vol, temp, p, spath, adsp);
2264 of_rename(vol, s_of, curdir, temp, sdir, spath);
2267 if ( !s_of && adsp && ad_hfileno(adsp) != -1 ) {
2268 ad_close(adsp, ADFLAGS_HF);
2270 if ( !d_of && addp && ad_hfileno(addp) != -1 ) {
2271 ad_close(addp, ADFLAGS_HF);