2 * $Id: file.c,v 1.92.2.2.2.31.2.11 2005-02-12 11:22:04 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[ADEDLEN_FINDERI] = {
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 path : unix or mac name ? (for now it's unix name ) */
79 void *get_finderinfo(const char *upath, struct adouble *adp, void *data)
82 void *ad_finder = NULL;
86 ad_finder = ad_entry(adp, ADEID_FINDERI);
89 memcpy(data, ad_finder, ADEDLEN_FINDERI);
91 if (!memcmp(ad_finder, ufinderi, 8))
95 memcpy(data, ufinderi, ADEDLEN_FINDERI);
97 if (*upath == '.') { /* make it invisible */
100 ashort = htons(FINDERINFO_INVISIBLE);
101 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
104 /** Only enter if no appledouble information and no finder information found. */
105 if (chk_ext && (em = getextmap( upath ))) {
106 memcpy(data, em->em_type, sizeof( em->em_type ));
107 memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator));
112 /* ---------------------
114 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8)
119 aint = strlen( name );
123 if (utf8_encoding()) {
124 /* but name is an utf8 mac name */
127 /* global static variable... */
129 if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
138 if (aint > MACFILELEN)
145 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
148 utf8 = vol->v_mac?htonl(vol->v_mac->kTextEncoding):0; /* htonl(utf8) */
149 memcpy(data, &utf8, sizeof(utf8));
150 data += sizeof(utf8);
153 memcpy(data, &temp, sizeof(temp));
154 data += sizeof(temp);
157 memcpy( data, src, aint );
167 * FIXME: PDINFO is UTF8 and doesn't need adp
169 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
170 (1 << FILPBIT_CDATE) |\
171 (1 << FILPBIT_MDATE) |\
172 (1 << FILPBIT_BDATE) |\
173 (1 << FILPBIT_FINFO) |\
174 (1 << FILPBIT_RFLEN) |\
175 (1 << FILPBIT_EXTRFLEN) |\
176 (1 << FILPBIT_PDINFO)))
178 /* -------------------------- */
179 u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st,
180 const cnid_t did, char *upath, const int len)
184 #if AD_VERSION > AD_VERSION1
186 if ((aint = ad_getid(adp, st->st_dev, st->st_ino, did, vol->v_stamp))) {
191 if (vol->v_cdb != NULL) {
192 aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
193 /* Throw errors if cnid_add fails. */
194 if (aint == CNID_INVALID) {
196 case CNID_ERR_CLOSE: /* the db is closed */
199 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
200 afp_errno = AFPERR_PARAM;
203 afp_errno = AFPERR_PARAM;
206 afp_errno = AFPERR_MISC;
210 #if AD_VERSION > AD_VERSION1
212 /* update the ressource fork
213 * for a folder adp is always null
215 if (ad_setid(adp, st->st_dev, st->st_ino, aint, did, vol->v_stamp)) {
216 ad_flush(adp, ADFLAGS_HF);
224 /* -------------------------- */
225 int getmetadata(struct vol *vol,
227 struct path *path, struct dir *dir,
228 char *buf, int *buflen, struct adouble *adp, int attrbits )
230 char *data, *l_nameoff = NULL, *upath;
231 char *utf_nameoff = NULL;
236 u_char achar, fdType[4];
242 LOG(log_info, logtype_afpd, "begin getmetadata:");
245 upath = path->u_name;
250 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
251 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
252 || (bitmap & (1 << FILPBIT_FNUM))) {
254 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
258 path->m_name = utompath(vol, upath, id, utf8_encoding());
261 while ( bitmap != 0 ) {
262 while (( bitmap & 1 ) == 0 ) {
270 ad_getattr(adp, &ashort);
271 } else if (*upath == '.') {
272 ashort = htons(ATTRBIT_INVISIBLE);
276 /* FIXME do we want a visual clue if the file is read only
279 accessmode( ".", &ma, dir , NULL);
280 if ((ma.ma_user & AR_UWRITE)) {
281 accessmode( upath, &ma, dir , st);
282 if (!(ma.ma_user & AR_UWRITE)) {
283 attrbits |= ATTRBIT_NOWRITE;
288 ashort = htons(ntohs(ashort) | attrbits);
289 memcpy(data, &ashort, sizeof( ashort ));
290 data += sizeof( ashort );
294 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
295 data += sizeof( u_int32_t );
299 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
300 aint = AD_DATE_FROM_UNIX(st->st_mtime);
301 memcpy(data, &aint, sizeof( aint ));
302 data += sizeof( aint );
306 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
307 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
308 aint = AD_DATE_FROM_UNIX(st->st_mtime);
311 aint = AD_DATE_FROM_UNIX(st->st_mtime);
313 memcpy(data, &aint, sizeof( int ));
314 data += sizeof( int );
318 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
319 aint = AD_DATE_START;
320 memcpy(data, &aint, sizeof( int ));
321 data += sizeof( int );
325 get_finderinfo(upath, adp, (char *)data);
326 data += ADEDLEN_FINDERI;
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)) == (size_t)-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 /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
1791 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1792 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1795 if (NULL == ( dir = dirlookup( vol, id )) ) {
1796 return AFPERR_NOID; /* idem AFPERR_PARAM */
1798 path.u_name = upath;
1799 if (movecwd(vol, dir) < 0) {
1803 return AFPERR_ACCESS;
1807 return AFPERR_PARAM;
1811 if ( of_stat(&path) < 0 ) {
1813 /* with nfs and our working directory is deleted */
1814 if (errno == ESTALE) {
1818 if ( errno == ENOENT && !retry) {
1819 /* cnid db is out of sync, reenumerate the directory and updated ids */
1820 reenumerate_id(vol, ".", id);
1828 return AFPERR_ACCESS;
1832 return AFPERR_PARAM;
1836 /* directories are bad */
1837 if (S_ISDIR(path.st.st_mode))
1838 return AFPERR_BADTYPE;
1840 memcpy(&bitmap, ibuf, sizeof(bitmap));
1841 bitmap = ntohs( bitmap );
1842 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1845 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1846 rbuf + sizeof(bitmap), &buflen))) {
1849 *rbuflen = buflen + sizeof(bitmap);
1850 memcpy(rbuf, ibuf, sizeof(bitmap));
1853 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1859 /* ------------------------------ */
1860 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1863 int ibuflen, *rbuflen;
1873 static char buffer[12 + MAXPATHLEN + 1];
1874 int len = 12 + MAXPATHLEN + 1;
1877 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1883 memcpy(&vid, ibuf, sizeof(vid));
1884 ibuf += sizeof(vid);
1886 if (NULL == ( vol = getvolbyvid( vid )) ) {
1887 return( AFPERR_PARAM);
1890 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1894 if (vol->v_flags & AFPVOL_RO)
1895 return AFPERR_VLOCK;
1897 memcpy(&id, ibuf, sizeof( id ));
1901 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1905 if (NULL == ( dir = dirlookup( vol, id )) ) {
1906 return( AFPERR_PARAM );
1910 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1914 return AFPERR_ACCESS;
1919 /* still try to delete the id */
1923 return AFPERR_PARAM;
1926 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1927 return AFPERR_BADTYPE;
1929 if (cnid_delete(vol->v_cdb, fileid)) {
1932 return AFPERR_VLOCK;
1935 return AFPERR_ACCESS;
1937 return AFPERR_PARAM;
1942 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1948 /* ------------------------------ */
1949 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1953 if (path->st_errno) {
1954 switch (path->st_errno) {
1956 afp_errno = AFPERR_NOID;
1960 afp_errno = AFPERR_ACCESS;
1963 afp_errno = AFPERR_PARAM;
1968 /* we use file_access both for legacy Mac perm and
1969 * for unix privilege, rename will take care of folder perms
1971 if (file_access(path, OPENACC_WR ) < 0) {
1972 afp_errno = AFPERR_ACCESS;
1976 if ((*of = of_findname(path))) {
1977 /* reuse struct adouble so it won't break locks */
1981 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
1982 if ( !ret && ad_hfileno(adp) != -1 && !(adp->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) {
1984 * The user must have the Read & Write privilege for both files in order to use this command.
1986 ad_close(adp, ADFLAGS_HF);
1987 afp_errno = AFPERR_ACCESS;
1994 #define APPLETEMP ".AppleTempXXXXXX"
1996 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1999 int ibuflen, *rbuflen;
2001 struct stat srcst, destst;
2003 struct dir *dir, *sdir;
2004 char *spath, temp[17], *p;
2005 char *supath, *upath;
2010 struct adouble *adsp = NULL;
2011 struct adouble *addp = NULL;
2012 struct ofork *s_of = NULL;
2013 struct ofork *d_of = NULL;
2024 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
2030 memcpy(&vid, ibuf, sizeof(vid));
2031 ibuf += sizeof(vid);
2033 if (NULL == ( vol = getvolbyvid( vid )) ) {
2034 return( AFPERR_PARAM);
2037 if ((vol->v_flags & AFPVOL_RO))
2038 return AFPERR_VLOCK;
2040 /* source and destination dids */
2041 memcpy(&sid, ibuf, sizeof(sid));
2042 ibuf += sizeof(sid);
2043 memcpy(&did, ibuf, sizeof(did));
2044 ibuf += sizeof(did);
2047 if (NULL == (dir = dirlookup( vol, sid )) ) {
2048 return afp_errno; /* was AFPERR_PARAM */
2051 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2052 return get_afp_errno(AFPERR_NOOBJ);
2055 if ( path_isadir(path) ) {
2056 return AFPERR_BADTYPE; /* it's a dir */
2059 /* save some stuff */
2062 spath = obj->oldtmp;
2063 supath = obj->newtmp;
2064 strcpy(spath, path->m_name);
2065 strcpy(supath, path->u_name); /* this is for the cnid changing */
2066 p = absupath( vol, sdir, supath);
2068 /* pathname too long */
2069 return AFPERR_PARAM ;
2072 ad_init(&ads, vol->v_adouble, vol->v_ad_options);
2073 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2077 /* ***** from here we may have resource fork open **** */
2079 /* look for the source cnid. if it doesn't exist, don't worry about
2081 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2083 if (NULL == ( dir = dirlookup( vol, did )) ) {
2084 err = afp_errno; /* was AFPERR_PARAM */
2085 goto err_exchangefile;
2088 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2089 err = get_afp_errno(AFPERR_NOOBJ);
2090 goto err_exchangefile;
2093 if ( path_isadir(path) ) {
2094 err = AFPERR_BADTYPE;
2095 goto err_exchangefile;
2098 /* FPExchangeFiles is the only call that can return the SameObj
2100 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2101 err = AFPERR_SAMEOBJ;
2102 goto err_exchangefile;
2105 ad_init(&add, vol->v_adouble, vol->v_ad_options);
2106 if (!(addp = find_adouble( path, &d_of, &add))) {
2108 goto err_exchangefile;
2112 /* they are not on the same device and at least one is open
2113 * FIXME broken for for crossdev and adouble v2
2116 crossdev = (srcst.st_dev != destst.st_dev);
2117 if (/* (d_of || s_of) && */ crossdev) {
2119 goto err_exchangefile;
2122 /* look for destination id. */
2123 upath = path->u_name;
2124 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2126 /* construct a temp name.
2127 * NOTE: the temp file will be in the dest file's directory. it
2128 * will also be inaccessible from AFP. */
2129 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2130 if (!mktemp(temp)) {
2132 goto err_exchangefile;
2136 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2137 ad_close(adsp, ADFLAGS_HF);
2138 ad_close(addp, ADFLAGS_HF);
2141 /* now, quickly rename the file. we error if we can't. */
2142 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2143 goto err_exchangefile;
2144 of_rename(vol, s_of, sdir, spath, curdir, temp);
2146 /* rename destination to source */
2147 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2148 goto err_src_to_tmp;
2149 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2151 /* rename temp to destination */
2152 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2153 goto err_dest_to_src;
2154 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2156 /* id's need switching. src -> dest and dest -> src.
2157 * we need to re-stat() if it was a cross device copy.
2160 cnid_delete(vol->v_cdb, sid);
2163 cnid_delete(vol->v_cdb, did);
2165 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2166 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2168 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2169 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2174 err = AFPERR_ACCESS;
2179 goto err_temp_to_dest;
2182 /* here we need to reopen if crossdev */
2183 if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2185 ad_flush( addp, ADFLAGS_HF );
2188 if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2190 ad_flush( adsp, ADFLAGS_HF );
2193 /* change perms, src gets dest perm and vice versa */
2198 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2199 err = AFP_OK; /* ignore error */
2200 goto err_temp_to_dest;
2204 * we need to exchange ACL entries as well
2206 /* exchange_acls(vol, p, upath); */
2211 path->m_name = NULL;
2212 path->u_name = upath;
2214 setfilunixmode(vol, path, destst.st_mode);
2215 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2222 setfilunixmode(vol, path, srcst.st_mode);
2223 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2225 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2226 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2231 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2235 goto err_exchangefile;
2237 /* all this stuff is so that we can unwind a failed operation
2240 /* rename dest to temp */
2241 renamefile(vol, upath, temp, temp, adsp);
2242 of_rename(vol, s_of, curdir, upath, curdir, temp);
2245 /* rename source back to dest */
2246 renamefile(vol, p, upath, path->m_name, addp);
2247 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2250 /* rename temp back to source */
2251 renamefile(vol, temp, p, spath, adsp);
2252 of_rename(vol, s_of, curdir, temp, sdir, spath);
2255 if ( !s_of && adsp && ad_hfileno(adsp) != -1 ) {
2256 ad_close(adsp, ADFLAGS_HF);
2258 if ( !d_of && addp && ad_hfileno(addp) != -1 ) {
2259 ad_close(addp, ADFLAGS_HF);