2 * $Id: file.c,v 1.92.2.2.2.31.2.10 2005-02-10 01:23:12 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
180 if ((aint = ad_getid(adp, st->st_dev, st->st_ino, did, vol->v_stamp))) {
185 if (vol->v_cdb != NULL) {
186 aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
187 /* Throw errors if cnid_add fails. */
188 if (aint == CNID_INVALID) {
190 case CNID_ERR_CLOSE: /* the db is closed */
193 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
194 afp_errno = AFPERR_PARAM;
197 afp_errno = AFPERR_PARAM;
200 afp_errno = AFPERR_MISC;
204 #if AD_VERSION > AD_VERSION1
206 /* update the ressource fork
207 * for a folder adp is always null
209 if (ad_setid(adp, st->st_dev, st->st_ino, aint, did, vol->v_stamp)) {
210 ad_flush(adp, ADFLAGS_HF);
218 /* -------------------------- */
219 int getmetadata(struct vol *vol,
221 struct path *path, struct dir *dir,
222 char *buf, int *buflen, struct adouble *adp, int attrbits )
224 char *data, *l_nameoff = NULL, *upath;
225 char *utf_nameoff = NULL;
230 u_char achar, fdType[4];
236 LOG(log_info, logtype_afpd, "begin getmetadata:");
239 upath = path->u_name;
244 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
245 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
246 || (bitmap & (1 << FILPBIT_FNUM))) {
248 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
252 path->m_name = utompath(vol, upath, id, utf8_encoding());
255 while ( bitmap != 0 ) {
256 while (( bitmap & 1 ) == 0 ) {
264 ad_getattr(adp, &ashort);
265 } else if (*upath == '.') {
266 ashort = htons(ATTRBIT_INVISIBLE);
270 /* FIXME do we want a visual clue if the file is read only
273 accessmode( ".", &ma, dir , NULL);
274 if ((ma.ma_user & AR_UWRITE)) {
275 accessmode( upath, &ma, dir , st);
276 if (!(ma.ma_user & AR_UWRITE)) {
277 attrbits |= ATTRBIT_NOWRITE;
282 ashort = htons(ntohs(ashort) | attrbits);
283 memcpy(data, &ashort, sizeof( ashort ));
284 data += sizeof( ashort );
288 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
289 data += sizeof( u_int32_t );
293 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
294 aint = AD_DATE_FROM_UNIX(st->st_mtime);
295 memcpy(data, &aint, sizeof( aint ));
296 data += sizeof( aint );
300 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
301 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
302 aint = AD_DATE_FROM_UNIX(st->st_mtime);
305 aint = AD_DATE_FROM_UNIX(st->st_mtime);
307 memcpy(data, &aint, sizeof( int ));
308 data += sizeof( int );
312 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
313 aint = AD_DATE_START;
314 memcpy(data, &aint, sizeof( int ));
315 data += sizeof( int );
319 get_finderinfo(path->m_name, adp, (char *)data);
321 if (*upath == '.') { /* make it invisible */
322 ashort = htons(FINDERINFO_INVISIBLE);
323 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
331 data += sizeof( u_int16_t );
335 memset(data, 0, sizeof(u_int16_t));
336 data += sizeof( u_int16_t );
340 memcpy(data, &id, sizeof( id ));
341 data += sizeof( id );
345 if (st->st_size > 0xffffffff)
348 aint = htonl( st->st_size );
349 memcpy(data, &aint, sizeof( aint ));
350 data += sizeof( aint );
355 if (adp->ad_rlen > 0xffffffff)
358 aint = htonl( adp->ad_rlen);
362 memcpy(data, &aint, sizeof( aint ));
363 data += sizeof( aint );
366 /* Current client needs ProDOS info block for this file.
367 Use simple heuristic and let the Mac "type" string tell
368 us what the PD file code should be. Everything gets a
369 subtype of 0x0000 unless the original value was hashed
370 to "pXYZ" when we created it. See IA, Ver 2.
371 <shirsch@adelphia.net> */
372 case FILPBIT_PDINFO :
373 if (afp_version >= 30) { /* UTF8 name */
374 utf8 = kTextEncodingUTF8;
376 data += sizeof( u_int16_t );
378 memcpy(data, &aint, sizeof( aint ));
379 data += sizeof( aint );
383 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
385 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
389 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
393 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
397 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
401 else if ( fdType[0] == 'p' ) {
403 ashort = (fdType[2] * 256) + fdType[3];
417 memcpy(data, &ashort, sizeof( ashort ));
418 data += sizeof( ashort );
419 memset(data, 0, sizeof( ashort ));
420 data += sizeof( ashort );
423 case FILPBIT_EXTDFLEN:
424 aint = htonl(st->st_size >> 32);
425 memcpy(data, &aint, sizeof( aint ));
426 data += sizeof( aint );
427 aint = htonl(st->st_size);
428 memcpy(data, &aint, sizeof( aint ));
429 data += sizeof( aint );
431 case FILPBIT_EXTRFLEN:
434 aint = htonl(adp->ad_rlen >> 32);
435 memcpy(data, &aint, sizeof( aint ));
436 data += sizeof( aint );
438 aint = htonl(adp->ad_rlen);
439 memcpy(data, &aint, sizeof( aint ));
440 data += sizeof( aint );
442 case FILPBIT_UNIXPR :
443 /* accessmode may change st_mode with ACLs */
444 accessmode( upath, &ma, dir , st);
446 aint = htonl(st->st_uid);
447 memcpy( data, &aint, sizeof( aint ));
448 data += sizeof( aint );
449 aint = htonl(st->st_gid);
450 memcpy( data, &aint, sizeof( aint ));
451 data += sizeof( aint );
453 aint = htonl(st->st_mode);
454 memcpy( data, &aint, sizeof( aint ));
455 data += sizeof( aint );
457 *data++ = ma.ma_user;
458 *data++ = ma.ma_world;
459 *data++ = ma.ma_group;
460 *data++ = ma.ma_owner;
464 return( AFPERR_BITMAP );
470 ashort = htons( data - buf );
471 memcpy(l_nameoff, &ashort, sizeof( ashort ));
472 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
475 ashort = htons( data - buf );
476 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
477 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
479 *buflen = data - buf;
483 /* ----------------------- */
484 int getfilparams(struct vol *vol,
486 struct path *path, struct dir *dir,
487 char *buf, int *buflen )
489 struct adouble ad, *adp;
492 u_int16_t attrbits = 0;
497 LOG(log_info, logtype_default, "begin getfilparams:");
500 opened = PARAM_NEED_ADP(bitmap);
503 upath = path->u_name;
504 if ((of = of_findname(path))) {
506 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
507 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
509 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
513 if ( ad_metadata( upath, 0, adp) < 0 ) {
516 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
517 upath, strerror(errno));
518 return AFPERR_ACCESS;
520 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
530 we need to check if the file is open by another process.
531 it's slow so we only do it if we have to:
532 - bitmap is requested.
533 - we don't already have the answer!
535 if ((bitmap & (1 << FILPBIT_ATTR))) {
536 if (!(attrbits & ATTRBIT_ROPEN)) {
537 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_ROPEN : 0;
538 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_ROPEN : 0;
540 if (!(attrbits & ATTRBIT_DOPEN)) {
541 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_DOPEN : 0;
542 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_DOPEN : 0;
547 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
549 ad_close( adp, ADFLAGS_HF );
552 LOG(log_info, logtype_afpd, "end getfilparams:");
558 /* ----------------------------- */
559 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
562 int ibuflen, *rbuflen;
564 struct adouble ad, *adp;
567 struct ofork *of = NULL;
569 int creatf, did, openf, retvalue = AFP_OK;
575 LOG(log_info, logtype_afpd, "begin afp_createfile:");
580 creatf = (unsigned char) *ibuf++;
582 memcpy(&vid, ibuf, sizeof( vid ));
583 ibuf += sizeof( vid );
585 if (NULL == ( vol = getvolbyvid( vid )) ) {
586 return( AFPERR_PARAM );
589 if (vol->v_flags & AFPVOL_RO)
592 memcpy(&did, ibuf, sizeof( did));
593 ibuf += sizeof( did );
595 if (NULL == ( dir = dirlookup( vol, did )) ) {
599 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
600 return get_afp_errno(AFPERR_PARAM);
603 if ( *s_path->m_name == '\0' ) {
604 return( AFPERR_BADTYPE );
607 upath = s_path->u_name;
608 if (0 != (ret = check_name(vol, upath)))
611 /* if upath is deleted we already in trouble anyway */
612 if ((of = of_findname(s_path))) {
615 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
619 /* on a hard create, fail if file exists and is open */
622 openf = O_RDWR|O_CREAT|O_TRUNC;
624 /* on a soft create, if the file is open then ad_open won't fail
625 because open syscall is not called
630 openf = O_RDWR|O_CREAT|O_EXCL;
633 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
634 openf, 0666, adp) < 0 ) {
638 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
639 return ( AFPERR_NOOBJ );
641 return( AFPERR_EXIST );
643 return( AFPERR_ACCESS );
645 return( AFPERR_PARAM );
648 if ( ad_hfileno( adp ) == -1 ) {
649 /* on noadouble volumes, just creating the data fork is ok */
650 if (vol_noadouble(vol)) {
651 ad_close( adp, ADFLAGS_DF );
652 goto createfile_done;
654 /* FIXME with hard create on an existing file, we already
655 * corrupted the data file.
657 netatalk_unlink( upath );
658 ad_close( adp, ADFLAGS_DF );
659 return AFPERR_ACCESS;
662 path = s_path->m_name;
663 ad_setname(adp, path);
664 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
665 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
671 if (vol->v_flags & AFPVOL_DROPBOX) {
672 retvalue = matchfile2dirperms(upath, vol, did);
674 #endif /* DROPKLUDGE */
676 setvoltime(obj, vol );
679 LOG(log_info, logtype_afpd, "end afp_createfile");
685 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
688 int ibuflen, *rbuflen;
694 u_int16_t vid, bitmap;
697 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
703 memcpy(&vid, ibuf, sizeof( vid ));
704 ibuf += sizeof( vid );
705 if (NULL == ( vol = getvolbyvid( vid )) ) {
706 return( AFPERR_PARAM );
709 if (vol->v_flags & AFPVOL_RO)
712 memcpy(&did, ibuf, sizeof( did ));
713 ibuf += sizeof( did );
714 if (NULL == ( dir = dirlookup( vol, did )) ) {
715 return afp_errno; /* was AFPERR_NOOBJ */
718 memcpy(&bitmap, ibuf, sizeof( bitmap ));
719 bitmap = ntohs( bitmap );
720 ibuf += sizeof( bitmap );
722 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
723 return get_afp_errno(AFPERR_PARAM);
726 if (path_isadir(s_path)) {
727 return( AFPERR_BADTYPE ); /* it's a directory */
730 if ( s_path->st_errno != 0 ) {
731 return( AFPERR_NOOBJ );
734 if ((u_long)ibuf & 1 ) {
738 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
739 setvoltime(obj, vol );
743 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
750 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
753 extern struct path Cur_Path;
755 int setfilparams(struct vol *vol,
756 struct path *path, u_int16_t f_bitmap, char *buf )
758 struct adouble ad, *adp;
760 int bit, isad = 1, err = AFP_OK;
762 u_char achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
763 u_int16_t ashort, bshort;
766 u_int16_t upriv_bit = 0;
770 int change_mdate = 0;
771 int change_parent_mdate = 0;
776 u_int16_t bitmap = f_bitmap;
777 u_int32_t cdate,bdate;
778 u_char finder_buf[32];
781 LOG(log_info, logtype_afpd, "begin setfilparams:");
784 upath = path->u_name;
785 adp = of_ad(vol, path, &ad);
788 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
789 return AFPERR_ACCESS;
792 /* with unix priv maybe we have to change adouble file priv first */
794 while ( bitmap != 0 ) {
795 while (( bitmap & 1 ) == 0 ) {
802 memcpy(&ashort, buf, sizeof( ashort ));
803 buf += sizeof( ashort );
807 memcpy(&cdate, buf, sizeof(cdate));
808 buf += sizeof( cdate );
811 memcpy(&newdate, buf, sizeof( newdate ));
812 buf += sizeof( newdate );
816 memcpy(&bdate, buf, sizeof( bdate));
817 buf += sizeof( bdate );
821 memcpy(finder_buf, buf, 32 );
824 case FILPBIT_UNIXPR :
825 if (!vol_unix_priv(vol)) {
826 /* this volume doesn't use unix priv */
832 change_parent_mdate = 1;
834 memcpy( &aint, buf, sizeof( aint ));
835 f_uid = ntohl (aint);
836 buf += sizeof( aint );
837 memcpy( &aint, buf, sizeof( aint ));
838 f_gid = ntohl (aint);
839 buf += sizeof( aint );
840 setfilowner(vol, f_uid, f_gid, path);
842 memcpy( &upriv, buf, sizeof( upriv ));
843 buf += sizeof( upriv );
844 upriv = ntohl (upriv);
845 if ((upriv & S_IWUSR)) {
846 setfilunixmode(vol, path, upriv);
853 case FILPBIT_PDINFO :
854 if (afp_version < 30) { /* else it's UTF8 name */
857 /* Keep special case to support crlf translations */
858 if ((unsigned int) achar == 0x04) {
859 fdType = (u_char *)"TEXT";
862 xyy[0] = ( u_char ) 'p';
873 /* break while loop */
882 /* second try with adouble open
884 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
885 O_RDWR|O_CREAT, 0666, adp) < 0) {
886 /* for some things, we don't need an adouble header */
887 if (f_bitmap & ~(1<<FILPBIT_MDATE)) {
888 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
891 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
892 ad_setname(adp, path->m_name);
897 while ( bitmap != 0 ) {
898 while (( bitmap & 1 ) == 0 ) {
905 ad_getattr(adp, &bshort);
906 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
907 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
908 change_parent_mdate = 1;
909 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
910 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
914 ad_setattr(adp, bshort);
917 ad_setdate(adp, AD_DATE_CREATE, cdate);
922 ad_setdate(adp, AD_DATE_BACKUP, bdate);
925 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
927 ((em = getextmap( path->m_name )) &&
928 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
929 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
930 || ((em = getdefextmap()) &&
931 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
932 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
934 memcpy(finder_buf, ufinderi, 8 );
936 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
938 case FILPBIT_UNIXPR :
940 setfilunixmode(vol, path, upriv);
943 case FILPBIT_PDINFO :
944 if (afp_version < 30) { /* else it's UTF8 name */
945 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
946 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
952 goto setfilparam_done;
959 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
960 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
964 ad_setdate(adp, AD_DATE_MODIFY, newdate);
965 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
970 ad_flush( adp, ADFLAGS_HF );
971 ad_close( adp, ADFLAGS_HF );
975 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
976 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
977 bitmap = 1<<FILPBIT_MDATE;
978 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
982 LOG(log_info, logtype_afpd, "end setfilparams:");
988 * renamefile and copyfile take the old and new unix pathnames
989 * and the new mac name.
991 * src the source path
992 * dst the dest filename in current dir
993 * newname the dest mac name
994 * adp adouble struct of src file, if open, or & zeroed one
997 int renamefile(vol, src, dst, newname, adp )
998 const struct vol *vol;
999 char *src, *dst, *newname;
1000 struct adouble *adp;
1002 char adsrc[ MAXPATHLEN + 1];
1006 LOG(log_info, logtype_afpd, "begin renamefile:");
1009 if ( unix_rename( src, dst ) < 0 ) {
1012 return( AFPERR_NOOBJ );
1015 return( AFPERR_ACCESS );
1017 return AFPERR_VLOCK;
1018 case EXDEV : /* Cross device move -- try copy */
1019 /* NOTE: with open file it's an error because after the copy we will
1020 * get two files, it's fixable for our process (eg reopen the new file, get the
1021 * locks, and so on. But it doesn't solve the case with a second process
1023 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
1024 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1025 return AFPERR_OLOCK; /* little lie */
1027 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1028 /* on error copyfile delete dest */
1031 return deletefile(vol, src, 0);
1033 return( AFPERR_PARAM );
1037 strcpy( adsrc, vol->ad_path( src, 0 ));
1039 if (unix_rename( adsrc, vol->ad_path( dst, 0 )) < 0 ) {
1044 if (errno == ENOENT) {
1047 if (stat(adsrc, &st)) /* source has no ressource fork, */
1050 /* We are here because :
1051 * -there's no dest folder.
1052 * -there's no .AppleDouble in the dest folder.
1053 * if we use the struct adouble passed in parameter it will not
1054 * create .AppleDouble if the file is already opened, so we
1055 * use a diff one, it's not a pb,ie it's not the same file, yet.
1057 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1058 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
1059 ad_close(&ad, ADFLAGS_HF);
1060 if (!unix_rename( adsrc, vol->ad_path( dst, 0 )) )
1065 else { /* it's something else, bail out */
1069 /* try to undo the data fork rename,
1070 * we know we are on the same device
1073 unix_rename( dst, src );
1074 /* return the first error */
1077 return AFPERR_NOOBJ;
1080 return AFPERR_ACCESS ;
1082 return AFPERR_VLOCK;
1084 return AFPERR_PARAM ;
1089 /* don't care if we can't open the newly renamed ressource fork
1091 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1092 ad_setname(adp, newname);
1093 ad_flush( adp, ADFLAGS_HF );
1094 ad_close( adp, ADFLAGS_HF );
1097 LOG(log_info, logtype_afpd, "end renamefile:");
1104 convert a Mac long name to an utf8 name,
1106 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1110 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1116 /* ---------------- */
1117 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1124 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1130 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1131 if (afp_version >= 30) {
1132 /* convert it to UTF8
1134 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == -1)
1138 strncpy( newname, ibuf, plen );
1139 newname[ plen ] = '\0';
1141 if (strlen(newname) != plen) {
1142 /* there's \0 in newname, e.g. it's a pathname not
1150 memcpy(&hint, ibuf, sizeof(hint));
1151 ibuf += sizeof(hint);
1153 memcpy(&len16, ibuf, sizeof(len16));
1154 ibuf += sizeof(len16);
1155 plen = ntohs(len16);
1158 if (plen > AFPOBJ_TMPSIZ) {
1161 strncpy( newname, ibuf, plen );
1162 newname[ plen ] = '\0';
1163 if (strlen(newname) != plen) {
1172 /* -----------------------------------
1174 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1177 int ibuflen, *rbuflen;
1179 struct vol *s_vol, *d_vol;
1181 char *newname, *p, *upath;
1182 struct path *s_path;
1183 u_int32_t sdid, ddid;
1184 int err, retvalue = AFP_OK;
1185 u_int16_t svid, dvid;
1187 struct adouble ad, *adp;
1191 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1197 memcpy(&svid, ibuf, sizeof( svid ));
1198 ibuf += sizeof( svid );
1199 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1200 return( AFPERR_PARAM );
1203 memcpy(&sdid, ibuf, sizeof( sdid ));
1204 ibuf += sizeof( sdid );
1205 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1209 memcpy(&dvid, ibuf, sizeof( dvid ));
1210 ibuf += sizeof( dvid );
1211 memcpy(&ddid, ibuf, sizeof( ddid ));
1212 ibuf += sizeof( ddid );
1214 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1215 return get_afp_errno(AFPERR_PARAM);
1217 if ( path_isadir(s_path) ) {
1218 return( AFPERR_BADTYPE );
1221 /* don't allow copies when the file is open.
1222 * XXX: the spec only calls for read/deny write access.
1223 * however, copyfile doesn't have any of that info,
1224 * and locks need to stay coherent. as a result,
1225 * we just balk if the file is opened already. */
1227 adp = of_ad(s_vol, s_path, &ad);
1229 if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1230 return AFPERR_DENYCONF;
1232 denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
1233 getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1234 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1236 return AFPERR_DENYCONF;
1239 newname = obj->newtmp;
1240 strcpy( newname, s_path->m_name );
1242 p = ctoupath( s_vol, curdir, newname );
1244 return AFPERR_PARAM;
1248 /* FIXME svid != dvid && dvid's user can't read svid */
1250 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1251 return( AFPERR_PARAM );
1254 if (d_vol->v_flags & AFPVOL_RO)
1255 return AFPERR_VLOCK;
1257 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1261 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1262 return get_afp_errno(AFPERR_NOOBJ);
1264 if ( *s_path->m_name != '\0' ) {
1265 path_error(s_path, AFPERR_PARAM);
1268 /* one of the handful of places that knows about the path type */
1269 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1270 return( AFPERR_PARAM );
1272 /* newname is always only a filename so curdir *is* its
1275 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1276 return( AFPERR_PARAM );
1278 if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1284 if (vol->v_flags & AFPVOL_DROPBOX) {
1285 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1287 #endif /* DROPKLUDGE */
1289 setvoltime(obj, d_vol );
1292 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1298 /* ----------------------- */
1299 static __inline__ int copy_all(const int dfd, const void *buf,
1305 LOG(log_info, logtype_afpd, "begin copy_all:");
1308 while (buflen > 0) {
1309 if ((cc = write(dfd, buf, buflen)) < 0) {
1321 LOG(log_info, logtype_afpd, "end copy_all:");
1327 /* -------------------------- */
1328 static int copy_fd(int dfd, int sfd)
1334 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1335 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1339 #define BUF 128*1024*1024
1341 if (fstat(sfd, &st) == 0) {
1344 if ( offset >= st.st_size) {
1347 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1348 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1351 case EINVAL: /* there's no guarantee that all fs support sendfile */
1360 lseek(sfd, offset, SEEK_SET);
1364 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1371 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1378 /* ----------------------------------
1379 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1380 * because we are doing it elsewhere.
1382 int copyfile(s_vol, d_vol, src, dst, newname, adp )
1383 const struct vol *s_vol, *d_vol;
1384 char *src, *dst, *newname;
1385 struct adouble *adp;
1387 struct adouble ads, add;
1391 int noadouble = vol_noadouble(d_vol);
1395 LOG(log_info, logtype_afpd, "begin copyfile:");
1399 ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options);
1402 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1403 adflags = ADFLAGS_DF;
1405 adflags |= ADFLAGS_HF;
1408 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1413 if (ad_hfileno(adp) == -1) {
1414 /* no resource fork, don't create one for dst file */
1415 adflags &= ~ADFLAGS_HF;
1418 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1420 ad_close( adp, adflags );
1421 if (EEXIST != ret_err) {
1422 deletefile(d_vol, dst, 0);
1425 return AFPERR_EXIST;
1427 if (ad_hfileno(adp) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(adp)))){
1428 /* copy the data fork */
1429 err = copy_fd(ad_dfileno(&add), ad_dfileno(adp));
1432 /* Now, reopen destination file */
1436 ad_close( adp, adflags );
1438 if (ad_close( &add, adflags ) <0) {
1439 deletefile(d_vol, dst, 0);
1444 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1445 if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
1450 if (!ret_err && newname) {
1451 ad_setname(&add, newname);
1454 ad_flush( &add, adflags );
1455 if (ad_close( &add, adflags ) <0) {
1459 deletefile(d_vol, dst, 0);
1461 else if (!stat(src, &st)) {
1462 /* set dest modification date to src date */
1465 ut.actime = ut.modtime = st.st_mtime;
1467 /* FIXME netatalk doesn't use resource fork file date
1468 * but maybe we should set its modtime too.
1473 LOG(log_info, logtype_afpd, "end copyfile:");
1477 switch ( ret_err ) {
1483 return AFPERR_DFULL;
1485 return AFPERR_NOOBJ;
1487 return AFPERR_ACCESS;
1489 return AFPERR_VLOCK;
1491 return AFPERR_PARAM;
1495 /* -----------------------------------
1496 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1497 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1499 when deletefile is called we don't have lock on it, file is closed (for us)
1500 untrue if called by renamefile
1502 ad_open always try to open file RDWR first and ad_lock takes care of
1503 WRITE lock on read only file.
1505 int deletefile( vol, file, checkAttrib )
1506 const struct vol *vol;
1511 struct adouble *adp = &ad;
1512 int adflags, err = AFP_OK;
1515 LOG(log_info, logtype_afpd, "begin deletefile:");
1518 /* try to open both forks at once */
1519 adflags = ADFLAGS_DF|ADFLAGS_HF;
1520 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1522 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1525 if (adflags == ADFLAGS_DF)
1526 return AFPERR_NOOBJ;
1528 /* that failed. now try to open just the data fork */
1529 adflags = ADFLAGS_DF;
1533 adp = NULL; /* maybe it's a file we no rw mode for us */
1534 break; /* was return AFPERR_ACCESS;*/
1536 return AFPERR_VLOCK;
1538 return( AFPERR_PARAM );
1541 break; /* from the while */
1544 * Does kFPDeleteInhibitBit (bit 8) set?
1549 if (adp && (adflags & ADFLAGS_HF)) {
1551 ad_getattr(&ad, &bshort);
1552 if ((bshort & htons(ATTRBIT_NODELETE))) {
1553 ad_close( &ad, adflags );
1554 return(AFPERR_OLOCK);
1558 /* was EACCESS error try to get only metadata */
1559 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1560 if ( ad_metadata( file , 0, &ad) == 0 ) {
1561 ad_getattr(&ad, &bshort);
1562 ad_close( &ad, ADFLAGS_HF );
1563 if ((bshort & htons(ATTRBIT_NODELETE))) {
1564 return AFPERR_OLOCK;
1570 if (adp && (adflags & ADFLAGS_HF) ) {
1571 /* FIXME we have a pb here because we want to know if a file is open
1572 * there's a 'priority inversion' if you can't open the ressource fork RW
1573 * you can delete it if it's open because you can't get a write lock.
1575 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1578 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1580 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1581 ad_close( &ad, adflags );
1582 return( AFPERR_BUSY );
1586 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1589 else if (!(err = netatalk_unlink( vol->ad_path( file, ADFLAGS_HF)) ) &&
1590 !(err = netatalk_unlink( file )) ) {
1592 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1594 cnid_delete(vol->v_cdb, id);
1599 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1602 LOG(log_info, logtype_afpd, "end deletefile:");
1608 /* ------------------------------------ */
1609 /* return a file id */
1610 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1613 int ibuflen, *rbuflen;
1622 struct path *s_path;
1625 LOG(log_info, logtype_afpd, "begin afp_createid:");
1632 memcpy(&vid, ibuf, sizeof(vid));
1633 ibuf += sizeof(vid);
1635 if (NULL == ( vol = getvolbyvid( vid )) ) {
1636 return( AFPERR_PARAM);
1639 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1643 if (vol->v_flags & AFPVOL_RO)
1644 return AFPERR_VLOCK;
1646 memcpy(&did, ibuf, sizeof( did ));
1647 ibuf += sizeof(did);
1649 if (NULL == ( dir = dirlookup( vol, did )) ) {
1650 return afp_errno; /* was AFPERR_PARAM */
1653 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1654 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1657 if ( path_isadir(s_path) ) {
1658 return( AFPERR_BADTYPE );
1661 upath = s_path->u_name;
1662 switch (s_path->st_errno) {
1664 break; /* success */
1667 return AFPERR_ACCESS;
1669 return AFPERR_NOOBJ;
1671 return AFPERR_PARAM;
1674 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1675 memcpy(rbuf, &id, sizeof(id));
1676 *rbuflen = sizeof(id);
1677 return AFPERR_EXISTID;
1680 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1681 memcpy(rbuf, &id, sizeof(id));
1682 *rbuflen = sizeof(id);
1687 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1693 reenumerate_id(const struct vol *vol, char *name, cnid_t did)
1701 memset(&path, 0, sizeof(path));
1702 if (vol->v_cdb == NULL) {
1705 if (NULL == ( dp = opendir( name)) ) {
1709 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
1710 if (NULL == check_dirent(vol, de->d_name))
1713 if ( stat(de->d_name, &path.st)<0 )
1716 /* update or add to cnid */
1717 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1719 #if AD_VERSION > AD_VERSION1
1720 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1721 struct adouble ad, *adp;
1725 path.u_name = de->d_name;
1727 adp = of_ad(vol, &path, &ad);
1729 if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, adp ) < 0 ) {
1732 if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1733 ad_flush(adp, ADFLAGS_HF);
1735 ad_close(adp, ADFLAGS_HF);
1737 #endif /* AD_VERSION > AD_VERSION1 */
1746 /* ------------------------------
1747 resolve a file id */
1748 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1751 int ibuflen, *rbuflen;
1757 int err, buflen, retry=0;
1759 u_int16_t vid, bitmap;
1761 static char buffer[12 + MAXPATHLEN + 1];
1762 int len = 12 + MAXPATHLEN + 1;
1765 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1771 memcpy(&vid, ibuf, sizeof(vid));
1772 ibuf += sizeof(vid);
1774 if (NULL == ( vol = getvolbyvid( vid )) ) {
1775 return( AFPERR_PARAM);
1778 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1782 memcpy(&id, ibuf, sizeof( id ));
1787 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1788 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1791 if (NULL == ( dir = dirlookup( vol, id )) ) {
1792 return AFPERR_NOID; /* idem AFPERR_PARAM */
1794 path.u_name = upath;
1795 if (movecwd(vol, dir) < 0) {
1799 return AFPERR_ACCESS;
1803 return AFPERR_PARAM;
1807 if ( of_stat(&path) < 0 ) {
1809 /* with nfs and our working directory is deleted */
1810 if (errno == ESTALE) {
1814 if ( errno == ENOENT && !retry) {
1815 /* cnid db is out of sync, reenumerate the directory and updated ids */
1816 reenumerate_id(vol, ".", id);
1824 return AFPERR_ACCESS;
1828 return AFPERR_PARAM;
1832 /* directories are bad */
1833 if (S_ISDIR(path.st.st_mode))
1834 return AFPERR_BADTYPE;
1836 memcpy(&bitmap, ibuf, sizeof(bitmap));
1837 bitmap = ntohs( bitmap );
1838 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1841 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1842 rbuf + sizeof(bitmap), &buflen))) {
1845 *rbuflen = buflen + sizeof(bitmap);
1846 memcpy(rbuf, ibuf, sizeof(bitmap));
1849 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1855 /* ------------------------------ */
1856 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1859 int ibuflen, *rbuflen;
1869 static char buffer[12 + MAXPATHLEN + 1];
1870 int len = 12 + MAXPATHLEN + 1;
1873 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1879 memcpy(&vid, ibuf, sizeof(vid));
1880 ibuf += sizeof(vid);
1882 if (NULL == ( vol = getvolbyvid( vid )) ) {
1883 return( AFPERR_PARAM);
1886 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1890 if (vol->v_flags & AFPVOL_RO)
1891 return AFPERR_VLOCK;
1893 memcpy(&id, ibuf, sizeof( id ));
1897 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1901 if (NULL == ( dir = dirlookup( vol, id )) ) {
1902 return( AFPERR_PARAM );
1906 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1910 return AFPERR_ACCESS;
1915 /* still try to delete the id */
1919 return AFPERR_PARAM;
1922 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1923 return AFPERR_BADTYPE;
1925 if (cnid_delete(vol->v_cdb, fileid)) {
1928 return AFPERR_VLOCK;
1931 return AFPERR_ACCESS;
1933 return AFPERR_PARAM;
1938 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1944 /* ------------------------------ */
1945 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1949 if (path->st_errno) {
1950 switch (path->st_errno) {
1952 afp_errno = AFPERR_NOID;
1956 afp_errno = AFPERR_ACCESS;
1959 afp_errno = AFPERR_PARAM;
1964 /* we use file_access both for legacy Mac perm and
1965 * for unix privilege, rename will take care of folder perms
1967 if (file_access(path, OPENACC_WR ) < 0) {
1968 afp_errno = AFPERR_ACCESS;
1972 if ((*of = of_findname(path))) {
1973 /* reuse struct adouble so it won't break locks */
1977 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
1978 if ( !ret && ad_hfileno(adp) != -1 && !(adp->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) {
1980 * The user must have the Read & Write privilege for both files in order to use this command.
1982 ad_close(adp, ADFLAGS_HF);
1983 afp_errno = AFPERR_ACCESS;
1990 #define APPLETEMP ".AppleTempXXXXXX"
1992 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1995 int ibuflen, *rbuflen;
1997 struct stat srcst, destst;
1999 struct dir *dir, *sdir;
2000 char *spath, temp[17], *p;
2001 char *supath, *upath;
2006 struct adouble *adsp = NULL;
2007 struct adouble *addp = NULL;
2008 struct ofork *s_of = NULL;
2009 struct ofork *d_of = NULL;
2020 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
2026 memcpy(&vid, ibuf, sizeof(vid));
2027 ibuf += sizeof(vid);
2029 if (NULL == ( vol = getvolbyvid( vid )) ) {
2030 return( AFPERR_PARAM);
2033 if ((vol->v_flags & AFPVOL_RO))
2034 return AFPERR_VLOCK;
2036 /* source and destination dids */
2037 memcpy(&sid, ibuf, sizeof(sid));
2038 ibuf += sizeof(sid);
2039 memcpy(&did, ibuf, sizeof(did));
2040 ibuf += sizeof(did);
2043 if (NULL == (dir = dirlookup( vol, sid )) ) {
2044 return afp_errno; /* was AFPERR_PARAM */
2047 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2048 return get_afp_errno(AFPERR_NOOBJ);
2051 if ( path_isadir(path) ) {
2052 return AFPERR_BADTYPE; /* it's a dir */
2055 /* save some stuff */
2058 spath = obj->oldtmp;
2059 supath = obj->newtmp;
2060 strcpy(spath, path->m_name);
2061 strcpy(supath, path->u_name); /* this is for the cnid changing */
2062 p = absupath( vol, sdir, supath);
2064 /* pathname too long */
2065 return AFPERR_PARAM ;
2068 ad_init(&ads, vol->v_adouble, vol->v_ad_options);
2069 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2073 /* ***** from here we may have resource fork open **** */
2075 /* look for the source cnid. if it doesn't exist, don't worry about
2077 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2079 if (NULL == ( dir = dirlookup( vol, did )) ) {
2080 err = afp_errno; /* was AFPERR_PARAM */
2081 goto err_exchangefile;
2084 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2085 err = get_afp_errno(AFPERR_NOOBJ);
2086 goto err_exchangefile;
2089 if ( path_isadir(path) ) {
2090 err = AFPERR_BADTYPE;
2091 goto err_exchangefile;
2094 /* FPExchangeFiles is the only call that can return the SameObj
2096 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2097 err = AFPERR_SAMEOBJ;
2098 goto err_exchangefile;
2101 ad_init(&add, vol->v_adouble, vol->v_ad_options);
2102 if (!(addp = find_adouble( path, &d_of, &add))) {
2104 goto err_exchangefile;
2108 /* they are not on the same device and at least one is open
2109 * FIXME broken for for crossdev and adouble v2
2112 crossdev = (srcst.st_dev != destst.st_dev);
2113 if (/* (d_of || s_of) && */ crossdev) {
2115 goto err_exchangefile;
2118 /* look for destination id. */
2119 upath = path->u_name;
2120 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2122 /* construct a temp name.
2123 * NOTE: the temp file will be in the dest file's directory. it
2124 * will also be inaccessible from AFP. */
2125 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2126 if (!mktemp(temp)) {
2128 goto err_exchangefile;
2132 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2133 ad_close(adsp, ADFLAGS_HF);
2134 ad_close(addp, ADFLAGS_HF);
2137 /* now, quickly rename the file. we error if we can't. */
2138 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2139 goto err_exchangefile;
2140 of_rename(vol, s_of, sdir, spath, curdir, temp);
2142 /* rename destination to source */
2143 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2144 goto err_src_to_tmp;
2145 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2147 /* rename temp to destination */
2148 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2149 goto err_dest_to_src;
2150 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2152 /* id's need switching. src -> dest and dest -> src.
2153 * we need to re-stat() if it was a cross device copy.
2156 cnid_delete(vol->v_cdb, sid);
2159 cnid_delete(vol->v_cdb, did);
2161 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2162 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2164 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2165 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2170 err = AFPERR_ACCESS;
2175 goto err_temp_to_dest;
2178 /* here we need to reopen if crossdev */
2179 if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2181 ad_flush( addp, ADFLAGS_HF );
2184 if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2186 ad_flush( adsp, ADFLAGS_HF );
2189 /* change perms, src gets dest perm and vice versa */
2194 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2195 err = AFP_OK; /* ignore error */
2196 goto err_temp_to_dest;
2200 * we need to exchange ACL entries as well
2202 /* exchange_acls(vol, p, upath); */
2207 path->m_name = NULL;
2208 path->u_name = upath;
2210 setfilunixmode(vol, path, destst.st_mode);
2211 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2218 setfilunixmode(vol, path, srcst.st_mode);
2219 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2221 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2222 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2227 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2231 goto err_exchangefile;
2233 /* all this stuff is so that we can unwind a failed operation
2236 /* rename dest to temp */
2237 renamefile(vol, upath, temp, temp, adsp);
2238 of_rename(vol, s_of, curdir, upath, curdir, temp);
2241 /* rename source back to dest */
2242 renamefile(vol, p, upath, path->m_name, addp);
2243 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2246 /* rename temp back to source */
2247 renamefile(vol, temp, p, spath, adsp);
2248 of_rename(vol, s_of, curdir, temp, sdir, spath);
2251 if ( !s_of && adsp && ad_hfileno(adsp) != -1 ) {
2252 ad_close(adsp, ADFLAGS_HF);
2254 if ( !d_of && addp && ad_hfileno(addp) != -1 ) {
2255 ad_close(addp, ADFLAGS_HF);