2 * $Id: file.c,v 1.92.2.2.2.31.2.12 2005-03-11 17:36:20 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 static const u_char old_ufinderi[] = {
79 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X'
82 /* ----------------------
84 static int default_type(void *finder)
86 if (!memcmp(finder, ufinderi, 8) || !memcmp(finder, old_ufinderi, 8))
91 /* FIXME path : unix or mac name ? (for now it's unix name ) */
92 void *get_finderinfo(const char *upath, struct adouble *adp, void *data)
95 void *ad_finder = NULL;
99 ad_finder = ad_entry(adp, ADEID_FINDERI);
102 memcpy(data, ad_finder, ADEDLEN_FINDERI);
104 if (default_type(ad_finder))
108 memcpy(data, ufinderi, ADEDLEN_FINDERI);
110 if (*upath == '.') { /* make it invisible */
113 ashort = htons(FINDERINFO_INVISIBLE);
114 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
117 /** Only enter if no appledouble information and no finder information found. */
118 if (chk_ext && (em = getextmap( upath ))) {
119 memcpy(data, em->em_type, sizeof( em->em_type ));
120 memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator));
125 /* ---------------------
127 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8)
132 aint = strlen( name );
136 if (utf8_encoding()) {
137 /* but name is an utf8 mac name */
140 /* global static variable... */
142 if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
151 if (aint > MACFILELEN)
158 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
161 utf8 = vol->v_mac?htonl(vol->v_mac->kTextEncoding):0; /* htonl(utf8) */
162 memcpy(data, &utf8, sizeof(utf8));
163 data += sizeof(utf8);
166 memcpy(data, &temp, sizeof(temp));
167 data += sizeof(temp);
170 memcpy( data, src, aint );
180 * FIXME: PDINFO is UTF8 and doesn't need adp
182 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
183 (1 << FILPBIT_CDATE) |\
184 (1 << FILPBIT_MDATE) |\
185 (1 << FILPBIT_BDATE) |\
186 (1 << FILPBIT_FINFO) |\
187 (1 << FILPBIT_RFLEN) |\
188 (1 << FILPBIT_EXTRFLEN) |\
189 (1 << FILPBIT_PDINFO)))
191 /* -------------------------- */
192 u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st,
193 const cnid_t did, char *upath, const int len)
197 #if AD_VERSION > AD_VERSION1
199 if ((aint = ad_getid(adp, st->st_dev, st->st_ino, did, vol->v_stamp))) {
204 if (vol->v_cdb != NULL) {
205 aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
206 /* Throw errors if cnid_add fails. */
207 if (aint == CNID_INVALID) {
209 case CNID_ERR_CLOSE: /* the db is closed */
212 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
213 afp_errno = AFPERR_PARAM;
216 afp_errno = AFPERR_PARAM;
219 afp_errno = AFPERR_MISC;
223 #if AD_VERSION > AD_VERSION1
225 /* update the ressource fork
226 * for a folder adp is always null
228 if (ad_setid(adp, st->st_dev, st->st_ino, aint, did, vol->v_stamp)) {
229 ad_flush(adp, ADFLAGS_HF);
237 /* -------------------------- */
238 int getmetadata(struct vol *vol,
240 struct path *path, struct dir *dir,
241 char *buf, int *buflen, struct adouble *adp, int attrbits )
243 char *data, *l_nameoff = NULL, *upath;
244 char *utf_nameoff = NULL;
249 u_char achar, fdType[4];
255 LOG(log_info, logtype_afpd, "begin getmetadata:");
258 upath = path->u_name;
263 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
264 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
265 || (bitmap & (1 << FILPBIT_FNUM))) {
267 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
271 path->m_name = utompath(vol, upath, id, utf8_encoding());
274 while ( bitmap != 0 ) {
275 while (( bitmap & 1 ) == 0 ) {
283 ad_getattr(adp, &ashort);
284 } else if (*upath == '.') {
285 ashort = htons(ATTRBIT_INVISIBLE);
289 /* FIXME do we want a visual clue if the file is read only
292 accessmode( ".", &ma, dir , NULL);
293 if ((ma.ma_user & AR_UWRITE)) {
294 accessmode( upath, &ma, dir , st);
295 if (!(ma.ma_user & AR_UWRITE)) {
296 attrbits |= ATTRBIT_NOWRITE;
301 ashort = htons(ntohs(ashort) | attrbits);
302 memcpy(data, &ashort, sizeof( ashort ));
303 data += sizeof( ashort );
307 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
308 data += sizeof( u_int32_t );
312 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
313 aint = AD_DATE_FROM_UNIX(st->st_mtime);
314 memcpy(data, &aint, sizeof( aint ));
315 data += sizeof( aint );
319 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
320 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
321 aint = AD_DATE_FROM_UNIX(st->st_mtime);
324 aint = AD_DATE_FROM_UNIX(st->st_mtime);
326 memcpy(data, &aint, sizeof( int ));
327 data += sizeof( int );
331 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
332 aint = AD_DATE_START;
333 memcpy(data, &aint, sizeof( int ));
334 data += sizeof( int );
338 get_finderinfo(upath, adp, (char *)data);
339 data += ADEDLEN_FINDERI;
344 data += sizeof( u_int16_t );
348 memset(data, 0, sizeof(u_int16_t));
349 data += sizeof( u_int16_t );
353 memcpy(data, &id, sizeof( id ));
354 data += sizeof( id );
358 if (st->st_size > 0xffffffff)
361 aint = htonl( st->st_size );
362 memcpy(data, &aint, sizeof( aint ));
363 data += sizeof( aint );
368 if (adp->ad_rlen > 0xffffffff)
371 aint = htonl( adp->ad_rlen);
375 memcpy(data, &aint, sizeof( aint ));
376 data += sizeof( aint );
379 /* Current client needs ProDOS info block for this file.
380 Use simple heuristic and let the Mac "type" string tell
381 us what the PD file code should be. Everything gets a
382 subtype of 0x0000 unless the original value was hashed
383 to "pXYZ" when we created it. See IA, Ver 2.
384 <shirsch@adelphia.net> */
385 case FILPBIT_PDINFO :
386 if (afp_version >= 30) { /* UTF8 name */
387 utf8 = kTextEncodingUTF8;
389 data += sizeof( u_int16_t );
391 memcpy(data, &aint, sizeof( aint ));
392 data += sizeof( aint );
396 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
398 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
402 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
406 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
410 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
414 else if ( fdType[0] == 'p' ) {
416 ashort = (fdType[2] * 256) + fdType[3];
430 memcpy(data, &ashort, sizeof( ashort ));
431 data += sizeof( ashort );
432 memset(data, 0, sizeof( ashort ));
433 data += sizeof( ashort );
436 case FILPBIT_EXTDFLEN:
437 aint = htonl(st->st_size >> 32);
438 memcpy(data, &aint, sizeof( aint ));
439 data += sizeof( aint );
440 aint = htonl(st->st_size);
441 memcpy(data, &aint, sizeof( aint ));
442 data += sizeof( aint );
444 case FILPBIT_EXTRFLEN:
447 aint = htonl(adp->ad_rlen >> 32);
448 memcpy(data, &aint, sizeof( aint ));
449 data += sizeof( aint );
451 aint = htonl(adp->ad_rlen);
452 memcpy(data, &aint, sizeof( aint ));
453 data += sizeof( aint );
455 case FILPBIT_UNIXPR :
456 /* accessmode may change st_mode with ACLs */
457 accessmode( upath, &ma, dir , st);
459 aint = htonl(st->st_uid);
460 memcpy( data, &aint, sizeof( aint ));
461 data += sizeof( aint );
462 aint = htonl(st->st_gid);
463 memcpy( data, &aint, sizeof( aint ));
464 data += sizeof( aint );
466 aint = htonl(st->st_mode);
467 memcpy( data, &aint, sizeof( aint ));
468 data += sizeof( aint );
470 *data++ = ma.ma_user;
471 *data++ = ma.ma_world;
472 *data++ = ma.ma_group;
473 *data++ = ma.ma_owner;
477 return( AFPERR_BITMAP );
483 ashort = htons( data - buf );
484 memcpy(l_nameoff, &ashort, sizeof( ashort ));
485 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
488 ashort = htons( data - buf );
489 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
490 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
492 *buflen = data - buf;
496 /* ----------------------- */
497 int getfilparams(struct vol *vol,
499 struct path *path, struct dir *dir,
500 char *buf, int *buflen )
502 struct adouble ad, *adp;
505 u_int16_t attrbits = 0;
510 LOG(log_info, logtype_default, "begin getfilparams:");
513 opened = PARAM_NEED_ADP(bitmap);
516 upath = path->u_name;
517 if ((of = of_findname(path))) {
519 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
520 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
522 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
526 if ( ad_metadata( upath, 0, adp) < 0 ) {
529 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
530 upath, strerror(errno));
531 return AFPERR_ACCESS;
533 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
543 we need to check if the file is open by another process.
544 it's slow so we only do it if we have to:
545 - bitmap is requested.
546 - we don't already have the answer!
548 if ((bitmap & (1 << FILPBIT_ATTR))) {
549 if (!(attrbits & ATTRBIT_ROPEN)) {
550 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_ROPEN : 0;
551 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_ROPEN : 0;
553 if (!(attrbits & ATTRBIT_DOPEN)) {
554 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_DOPEN : 0;
555 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_DOPEN : 0;
560 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
562 ad_close( adp, ADFLAGS_HF );
565 LOG(log_info, logtype_afpd, "end getfilparams:");
571 /* ----------------------------- */
572 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
575 int ibuflen, *rbuflen;
577 struct adouble ad, *adp;
580 struct ofork *of = NULL;
582 int creatf, did, openf, retvalue = AFP_OK;
588 LOG(log_info, logtype_afpd, "begin afp_createfile:");
593 creatf = (unsigned char) *ibuf++;
595 memcpy(&vid, ibuf, sizeof( vid ));
596 ibuf += sizeof( vid );
598 if (NULL == ( vol = getvolbyvid( vid )) ) {
599 return( AFPERR_PARAM );
602 if (vol->v_flags & AFPVOL_RO)
605 memcpy(&did, ibuf, sizeof( did));
606 ibuf += sizeof( did );
608 if (NULL == ( dir = dirlookup( vol, did )) ) {
612 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
613 return get_afp_errno(AFPERR_PARAM);
616 if ( *s_path->m_name == '\0' ) {
617 return( AFPERR_BADTYPE );
620 upath = s_path->u_name;
621 if (0 != (ret = check_name(vol, upath)))
624 /* if upath is deleted we already in trouble anyway */
625 if ((of = of_findname(s_path))) {
628 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
632 /* on a hard create, fail if file exists and is open */
635 openf = O_RDWR|O_CREAT|O_TRUNC;
637 /* on a soft create, if the file is open then ad_open won't fail
638 because open syscall is not called
643 openf = O_RDWR|O_CREAT|O_EXCL;
646 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
647 openf, 0666, adp) < 0 ) {
651 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
652 return ( AFPERR_NOOBJ );
654 return( AFPERR_EXIST );
656 return( AFPERR_ACCESS );
658 return( AFPERR_PARAM );
661 if ( ad_hfileno( adp ) == -1 ) {
662 /* on noadouble volumes, just creating the data fork is ok */
663 if (vol_noadouble(vol)) {
664 ad_close( adp, ADFLAGS_DF );
665 goto createfile_done;
667 /* FIXME with hard create on an existing file, we already
668 * corrupted the data file.
670 netatalk_unlink( upath );
671 ad_close( adp, ADFLAGS_DF );
672 return AFPERR_ACCESS;
675 path = s_path->m_name;
676 ad_setname(adp, path);
677 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
678 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
684 if (vol->v_flags & AFPVOL_DROPBOX) {
685 retvalue = matchfile2dirperms(upath, vol, did);
687 #endif /* DROPKLUDGE */
689 setvoltime(obj, vol );
692 LOG(log_info, logtype_afpd, "end afp_createfile");
698 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
701 int ibuflen, *rbuflen;
707 u_int16_t vid, bitmap;
710 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
716 memcpy(&vid, ibuf, sizeof( vid ));
717 ibuf += sizeof( vid );
718 if (NULL == ( vol = getvolbyvid( vid )) ) {
719 return( AFPERR_PARAM );
722 if (vol->v_flags & AFPVOL_RO)
725 memcpy(&did, ibuf, sizeof( did ));
726 ibuf += sizeof( did );
727 if (NULL == ( dir = dirlookup( vol, did )) ) {
728 return afp_errno; /* was AFPERR_NOOBJ */
731 memcpy(&bitmap, ibuf, sizeof( bitmap ));
732 bitmap = ntohs( bitmap );
733 ibuf += sizeof( bitmap );
735 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
736 return get_afp_errno(AFPERR_PARAM);
739 if (path_isadir(s_path)) {
740 return( AFPERR_BADTYPE ); /* it's a directory */
743 if ( s_path->st_errno != 0 ) {
744 return( AFPERR_NOOBJ );
747 if ((u_long)ibuf & 1 ) {
751 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
752 setvoltime(obj, vol );
756 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
763 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
766 extern struct path Cur_Path;
768 int setfilparams(struct vol *vol,
769 struct path *path, u_int16_t f_bitmap, char *buf )
771 struct adouble ad, *adp;
773 int bit, isad = 1, err = AFP_OK;
775 u_char achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
776 u_int16_t ashort, bshort;
779 u_int16_t upriv_bit = 0;
783 int change_mdate = 0;
784 int change_parent_mdate = 0;
789 u_int16_t bitmap = f_bitmap;
790 u_int32_t cdate,bdate;
791 u_char finder_buf[32];
794 LOG(log_info, logtype_afpd, "begin setfilparams:");
797 upath = path->u_name;
798 adp = of_ad(vol, path, &ad);
801 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
802 return AFPERR_ACCESS;
805 /* with unix priv maybe we have to change adouble file priv first */
807 while ( bitmap != 0 ) {
808 while (( bitmap & 1 ) == 0 ) {
815 memcpy(&ashort, buf, sizeof( ashort ));
816 buf += sizeof( ashort );
820 memcpy(&cdate, buf, sizeof(cdate));
821 buf += sizeof( cdate );
824 memcpy(&newdate, buf, sizeof( newdate ));
825 buf += sizeof( newdate );
829 memcpy(&bdate, buf, sizeof( bdate));
830 buf += sizeof( bdate );
834 memcpy(finder_buf, buf, 32 );
837 case FILPBIT_UNIXPR :
838 if (!vol_unix_priv(vol)) {
839 /* this volume doesn't use unix priv */
845 change_parent_mdate = 1;
847 memcpy( &aint, buf, sizeof( aint ));
848 f_uid = ntohl (aint);
849 buf += sizeof( aint );
850 memcpy( &aint, buf, sizeof( aint ));
851 f_gid = ntohl (aint);
852 buf += sizeof( aint );
853 setfilowner(vol, f_uid, f_gid, path);
855 memcpy( &upriv, buf, sizeof( upriv ));
856 buf += sizeof( upriv );
857 upriv = ntohl (upriv);
858 if ((upriv & S_IWUSR)) {
859 setfilunixmode(vol, path, upriv);
866 case FILPBIT_PDINFO :
867 if (afp_version < 30) { /* else it's UTF8 name */
870 /* Keep special case to support crlf translations */
871 if ((unsigned int) achar == 0x04) {
872 fdType = (u_char *)"TEXT";
875 xyy[0] = ( u_char ) 'p';
886 /* break while loop */
895 /* second try with adouble open
897 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
898 O_RDWR|O_CREAT, 0666, adp) < 0) {
899 /* for some things, we don't need an adouble header */
900 if (f_bitmap & ~(1<<FILPBIT_MDATE)) {
901 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
904 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
905 ad_setname(adp, path->m_name);
910 while ( bitmap != 0 ) {
911 while (( bitmap & 1 ) == 0 ) {
918 ad_getattr(adp, &bshort);
919 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
920 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
921 change_parent_mdate = 1;
922 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
923 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
927 ad_setattr(adp, bshort);
930 ad_setdate(adp, AD_DATE_CREATE, cdate);
935 ad_setdate(adp, AD_DATE_BACKUP, bdate);
938 if (default_type( ad_entry( adp, ADEID_FINDERI ))
940 ((em = getextmap( path->m_name )) &&
941 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
942 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
943 || ((em = getdefextmap()) &&
944 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
945 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
947 memcpy(finder_buf, ufinderi, 8 );
949 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
951 case FILPBIT_UNIXPR :
953 setfilunixmode(vol, path, upriv);
956 case FILPBIT_PDINFO :
957 if (afp_version < 30) { /* else it's UTF8 name */
958 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
959 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
965 goto setfilparam_done;
972 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
973 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
977 ad_setdate(adp, AD_DATE_MODIFY, newdate);
978 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
983 ad_flush( adp, ADFLAGS_HF );
984 ad_close( adp, ADFLAGS_HF );
988 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
989 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
990 bitmap = 1<<FILPBIT_MDATE;
991 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
995 LOG(log_info, logtype_afpd, "end setfilparams:");
1001 * renamefile and copyfile take the old and new unix pathnames
1002 * and the new mac name.
1004 * src the source path
1005 * dst the dest filename in current dir
1006 * newname the dest mac name
1007 * adp adouble struct of src file, if open, or & zeroed one
1010 int renamefile(vol, src, dst, newname, adp )
1011 const struct vol *vol;
1012 char *src, *dst, *newname;
1013 struct adouble *adp;
1015 char adsrc[ MAXPATHLEN + 1];
1019 LOG(log_info, logtype_afpd, "begin renamefile:");
1022 if ( unix_rename( src, dst ) < 0 ) {
1025 return( AFPERR_NOOBJ );
1028 return( AFPERR_ACCESS );
1030 return AFPERR_VLOCK;
1031 case EXDEV : /* Cross device move -- try copy */
1032 /* NOTE: with open file it's an error because after the copy we will
1033 * get two files, it's fixable for our process (eg reopen the new file, get the
1034 * locks, and so on. But it doesn't solve the case with a second process
1036 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
1037 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1038 return AFPERR_OLOCK; /* little lie */
1040 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1041 /* on error copyfile delete dest */
1044 return deletefile(vol, src, 0);
1046 return( AFPERR_PARAM );
1050 strcpy( adsrc, vol->ad_path( src, 0 ));
1052 if (unix_rename( adsrc, vol->ad_path( dst, 0 )) < 0 ) {
1057 if (errno == ENOENT) {
1060 if (stat(adsrc, &st)) /* source has no ressource fork, */
1063 /* We are here because :
1064 * -there's no dest folder.
1065 * -there's no .AppleDouble in the dest folder.
1066 * if we use the struct adouble passed in parameter it will not
1067 * create .AppleDouble if the file is already opened, so we
1068 * use a diff one, it's not a pb,ie it's not the same file, yet.
1070 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1071 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
1072 ad_close(&ad, ADFLAGS_HF);
1073 if (!unix_rename( adsrc, vol->ad_path( dst, 0 )) )
1078 else { /* it's something else, bail out */
1082 /* try to undo the data fork rename,
1083 * we know we are on the same device
1086 unix_rename( dst, src );
1087 /* return the first error */
1090 return AFPERR_NOOBJ;
1093 return AFPERR_ACCESS ;
1095 return AFPERR_VLOCK;
1097 return AFPERR_PARAM ;
1102 /* don't care if we can't open the newly renamed ressource fork
1104 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1105 ad_setname(adp, newname);
1106 ad_flush( adp, ADFLAGS_HF );
1107 ad_close( adp, ADFLAGS_HF );
1110 LOG(log_info, logtype_afpd, "end renamefile:");
1117 convert a Mac long name to an utf8 name,
1119 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1123 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1129 /* ---------------- */
1130 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1137 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1143 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1144 if (afp_version >= 30) {
1145 /* convert it to UTF8
1147 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1)
1151 strncpy( newname, ibuf, plen );
1152 newname[ plen ] = '\0';
1154 if (strlen(newname) != plen) {
1155 /* there's \0 in newname, e.g. it's a pathname not
1163 memcpy(&hint, ibuf, sizeof(hint));
1164 ibuf += sizeof(hint);
1166 memcpy(&len16, ibuf, sizeof(len16));
1167 ibuf += sizeof(len16);
1168 plen = ntohs(len16);
1171 if (plen > AFPOBJ_TMPSIZ) {
1174 strncpy( newname, ibuf, plen );
1175 newname[ plen ] = '\0';
1176 if (strlen(newname) != plen) {
1185 /* -----------------------------------
1187 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1190 int ibuflen, *rbuflen;
1192 struct vol *s_vol, *d_vol;
1194 char *newname, *p, *upath;
1195 struct path *s_path;
1196 u_int32_t sdid, ddid;
1197 int err, retvalue = AFP_OK;
1198 u_int16_t svid, dvid;
1200 struct adouble ad, *adp;
1204 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1210 memcpy(&svid, ibuf, sizeof( svid ));
1211 ibuf += sizeof( svid );
1212 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1213 return( AFPERR_PARAM );
1216 memcpy(&sdid, ibuf, sizeof( sdid ));
1217 ibuf += sizeof( sdid );
1218 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1222 memcpy(&dvid, ibuf, sizeof( dvid ));
1223 ibuf += sizeof( dvid );
1224 memcpy(&ddid, ibuf, sizeof( ddid ));
1225 ibuf += sizeof( ddid );
1227 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1228 return get_afp_errno(AFPERR_PARAM);
1230 if ( path_isadir(s_path) ) {
1231 return( AFPERR_BADTYPE );
1234 /* don't allow copies when the file is open.
1235 * XXX: the spec only calls for read/deny write access.
1236 * however, copyfile doesn't have any of that info,
1237 * and locks need to stay coherent. as a result,
1238 * we just balk if the file is opened already. */
1240 adp = of_ad(s_vol, s_path, &ad);
1242 if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1243 return AFPERR_DENYCONF;
1245 denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
1246 getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1247 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1249 return AFPERR_DENYCONF;
1252 newname = obj->newtmp;
1253 strcpy( newname, s_path->m_name );
1255 p = ctoupath( s_vol, curdir, newname );
1257 return AFPERR_PARAM;
1261 /* FIXME svid != dvid && dvid's user can't read svid */
1263 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1264 return( AFPERR_PARAM );
1267 if (d_vol->v_flags & AFPVOL_RO)
1268 return AFPERR_VLOCK;
1270 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1274 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1275 return get_afp_errno(AFPERR_NOOBJ);
1277 if ( *s_path->m_name != '\0' ) {
1278 path_error(s_path, AFPERR_PARAM);
1281 /* one of the handful of places that knows about the path type */
1282 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1283 return( AFPERR_PARAM );
1285 /* newname is always only a filename so curdir *is* its
1288 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1289 return( AFPERR_PARAM );
1291 if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1297 if (vol->v_flags & AFPVOL_DROPBOX) {
1298 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1300 #endif /* DROPKLUDGE */
1302 setvoltime(obj, d_vol );
1305 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1311 /* ----------------------- */
1312 static __inline__ int copy_all(const int dfd, const void *buf,
1318 LOG(log_info, logtype_afpd, "begin copy_all:");
1321 while (buflen > 0) {
1322 if ((cc = write(dfd, buf, buflen)) < 0) {
1334 LOG(log_info, logtype_afpd, "end copy_all:");
1340 /* -------------------------- */
1341 static int copy_fd(int dfd, int sfd)
1347 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1348 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1352 #define BUF 128*1024*1024
1354 if (fstat(sfd, &st) == 0) {
1357 if ( offset >= st.st_size) {
1360 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1361 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1364 case EINVAL: /* there's no guarantee that all fs support sendfile */
1373 lseek(sfd, offset, SEEK_SET);
1377 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1384 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1391 /* ----------------------------------
1392 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1393 * because we are doing it elsewhere.
1395 int copyfile(s_vol, d_vol, src, dst, newname, adp )
1396 const struct vol *s_vol, *d_vol;
1397 char *src, *dst, *newname;
1398 struct adouble *adp;
1400 struct adouble ads, add;
1404 int noadouble = vol_noadouble(d_vol);
1408 LOG(log_info, logtype_afpd, "begin copyfile:");
1412 ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options);
1415 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1416 adflags = ADFLAGS_DF;
1418 adflags |= ADFLAGS_HF;
1421 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1426 if (ad_hfileno(adp) == -1) {
1427 /* no resource fork, don't create one for dst file */
1428 adflags &= ~ADFLAGS_HF;
1431 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1433 ad_close( adp, adflags );
1434 if (EEXIST != ret_err) {
1435 deletefile(d_vol, dst, 0);
1438 return AFPERR_EXIST;
1440 if (ad_hfileno(adp) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(adp)))){
1441 /* copy the data fork */
1442 err = copy_fd(ad_dfileno(&add), ad_dfileno(adp));
1445 /* Now, reopen destination file */
1449 ad_close( adp, adflags );
1451 if (ad_close( &add, adflags ) <0) {
1452 deletefile(d_vol, dst, 0);
1457 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1458 if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
1463 if (!ret_err && newname) {
1464 ad_setname(&add, newname);
1467 ad_flush( &add, adflags );
1468 if (ad_close( &add, adflags ) <0) {
1472 deletefile(d_vol, dst, 0);
1474 else if (!stat(src, &st)) {
1475 /* set dest modification date to src date */
1478 ut.actime = ut.modtime = st.st_mtime;
1480 /* FIXME netatalk doesn't use resource fork file date
1481 * but maybe we should set its modtime too.
1486 LOG(log_info, logtype_afpd, "end copyfile:");
1490 switch ( ret_err ) {
1496 return AFPERR_DFULL;
1498 return AFPERR_NOOBJ;
1500 return AFPERR_ACCESS;
1502 return AFPERR_VLOCK;
1504 return AFPERR_PARAM;
1508 /* -----------------------------------
1509 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1510 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1512 when deletefile is called we don't have lock on it, file is closed (for us)
1513 untrue if called by renamefile
1515 ad_open always try to open file RDWR first and ad_lock takes care of
1516 WRITE lock on read only file.
1518 int deletefile( vol, file, checkAttrib )
1519 const struct vol *vol;
1524 struct adouble *adp = &ad;
1525 int adflags, err = AFP_OK;
1528 LOG(log_info, logtype_afpd, "begin deletefile:");
1531 /* try to open both forks at once */
1532 adflags = ADFLAGS_DF|ADFLAGS_HF;
1533 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1535 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1538 if (adflags == ADFLAGS_DF)
1539 return AFPERR_NOOBJ;
1541 /* that failed. now try to open just the data fork */
1542 adflags = ADFLAGS_DF;
1546 adp = NULL; /* maybe it's a file we no rw mode for us */
1547 break; /* was return AFPERR_ACCESS;*/
1549 return AFPERR_VLOCK;
1551 return( AFPERR_PARAM );
1554 break; /* from the while */
1557 * Does kFPDeleteInhibitBit (bit 8) set?
1562 if (adp && (adflags & ADFLAGS_HF)) {
1564 ad_getattr(&ad, &bshort);
1565 if ((bshort & htons(ATTRBIT_NODELETE))) {
1566 ad_close( &ad, adflags );
1567 return(AFPERR_OLOCK);
1571 /* was EACCESS error try to get only metadata */
1572 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1573 if ( ad_metadata( file , 0, &ad) == 0 ) {
1574 ad_getattr(&ad, &bshort);
1575 ad_close( &ad, ADFLAGS_HF );
1576 if ((bshort & htons(ATTRBIT_NODELETE))) {
1577 return AFPERR_OLOCK;
1583 if (adp && (adflags & ADFLAGS_HF) ) {
1584 /* FIXME we have a pb here because we want to know if a file is open
1585 * there's a 'priority inversion' if you can't open the ressource fork RW
1586 * you can delete it if it's open because you can't get a write lock.
1588 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1591 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1593 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1594 ad_close( &ad, adflags );
1595 return( AFPERR_BUSY );
1599 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1602 else if (!(err = netatalk_unlink( vol->ad_path( file, ADFLAGS_HF)) ) &&
1603 !(err = netatalk_unlink( file )) ) {
1605 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1607 cnid_delete(vol->v_cdb, id);
1612 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1615 LOG(log_info, logtype_afpd, "end deletefile:");
1621 /* ------------------------------------ */
1622 /* return a file id */
1623 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1626 int ibuflen, *rbuflen;
1635 struct path *s_path;
1638 LOG(log_info, logtype_afpd, "begin afp_createid:");
1645 memcpy(&vid, ibuf, sizeof(vid));
1646 ibuf += sizeof(vid);
1648 if (NULL == ( vol = getvolbyvid( vid )) ) {
1649 return( AFPERR_PARAM);
1652 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1656 if (vol->v_flags & AFPVOL_RO)
1657 return AFPERR_VLOCK;
1659 memcpy(&did, ibuf, sizeof( did ));
1660 ibuf += sizeof(did);
1662 if (NULL == ( dir = dirlookup( vol, did )) ) {
1663 return afp_errno; /* was AFPERR_PARAM */
1666 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1667 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1670 if ( path_isadir(s_path) ) {
1671 return( AFPERR_BADTYPE );
1674 upath = s_path->u_name;
1675 switch (s_path->st_errno) {
1677 break; /* success */
1680 return AFPERR_ACCESS;
1682 return AFPERR_NOOBJ;
1684 return AFPERR_PARAM;
1687 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1688 memcpy(rbuf, &id, sizeof(id));
1689 *rbuflen = sizeof(id);
1690 return AFPERR_EXISTID;
1693 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1694 memcpy(rbuf, &id, sizeof(id));
1695 *rbuflen = sizeof(id);
1700 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1706 reenumerate_id(const struct vol *vol, char *name, cnid_t did)
1714 memset(&path, 0, sizeof(path));
1715 if (vol->v_cdb == NULL) {
1718 if (NULL == ( dp = opendir( name)) ) {
1722 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
1723 if (NULL == check_dirent(vol, de->d_name))
1726 if ( stat(de->d_name, &path.st)<0 )
1729 /* update or add to cnid */
1730 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1732 #if AD_VERSION > AD_VERSION1
1733 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1734 struct adouble ad, *adp;
1738 path.u_name = de->d_name;
1740 adp = of_ad(vol, &path, &ad);
1742 if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, adp ) < 0 ) {
1745 if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1746 ad_flush(adp, ADFLAGS_HF);
1748 ad_close(adp, ADFLAGS_HF);
1750 #endif /* AD_VERSION > AD_VERSION1 */
1759 /* ------------------------------
1760 resolve a file id */
1761 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1764 int ibuflen, *rbuflen;
1770 int err, buflen, retry=0;
1772 u_int16_t vid, bitmap;
1774 static char buffer[12 + MAXPATHLEN + 1];
1775 int len = 12 + MAXPATHLEN + 1;
1778 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1784 memcpy(&vid, ibuf, sizeof(vid));
1785 ibuf += sizeof(vid);
1787 if (NULL == ( vol = getvolbyvid( vid )) ) {
1788 return( AFPERR_PARAM);
1791 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1795 memcpy(&id, ibuf, sizeof( id ));
1800 /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
1804 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1805 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1808 if (NULL == ( dir = dirlookup( vol, id )) ) {
1809 return AFPERR_NOID; /* idem AFPERR_PARAM */
1811 path.u_name = upath;
1812 if (movecwd(vol, dir) < 0) {
1816 return AFPERR_ACCESS;
1820 return AFPERR_PARAM;
1824 if ( of_stat(&path) < 0 ) {
1826 /* with nfs and our working directory is deleted */
1827 if (errno == ESTALE) {
1831 if ( errno == ENOENT && !retry) {
1832 /* cnid db is out of sync, reenumerate the directory and updated ids */
1833 reenumerate_id(vol, ".", id);
1841 return AFPERR_ACCESS;
1845 return AFPERR_PARAM;
1849 /* directories are bad */
1850 if (S_ISDIR(path.st.st_mode))
1851 return AFPERR_BADTYPE;
1853 memcpy(&bitmap, ibuf, sizeof(bitmap));
1854 bitmap = ntohs( bitmap );
1855 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1858 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1859 rbuf + sizeof(bitmap), &buflen))) {
1862 *rbuflen = buflen + sizeof(bitmap);
1863 memcpy(rbuf, ibuf, sizeof(bitmap));
1866 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1872 /* ------------------------------ */
1873 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1876 int ibuflen, *rbuflen;
1886 static char buffer[12 + MAXPATHLEN + 1];
1887 int len = 12 + MAXPATHLEN + 1;
1890 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1896 memcpy(&vid, ibuf, sizeof(vid));
1897 ibuf += sizeof(vid);
1899 if (NULL == ( vol = getvolbyvid( vid )) ) {
1900 return( AFPERR_PARAM);
1903 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1907 if (vol->v_flags & AFPVOL_RO)
1908 return AFPERR_VLOCK;
1910 memcpy(&id, ibuf, sizeof( id ));
1914 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1918 if (NULL == ( dir = dirlookup( vol, id )) ) {
1919 return( AFPERR_PARAM );
1923 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1927 return AFPERR_ACCESS;
1932 /* still try to delete the id */
1936 return AFPERR_PARAM;
1939 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1940 return AFPERR_BADTYPE;
1942 if (cnid_delete(vol->v_cdb, fileid)) {
1945 return AFPERR_VLOCK;
1948 return AFPERR_ACCESS;
1950 return AFPERR_PARAM;
1955 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1961 /* ------------------------------ */
1962 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1966 if (path->st_errno) {
1967 switch (path->st_errno) {
1969 afp_errno = AFPERR_NOID;
1973 afp_errno = AFPERR_ACCESS;
1976 afp_errno = AFPERR_PARAM;
1981 /* we use file_access both for legacy Mac perm and
1982 * for unix privilege, rename will take care of folder perms
1984 if (file_access(path, OPENACC_WR ) < 0) {
1985 afp_errno = AFPERR_ACCESS;
1989 if ((*of = of_findname(path))) {
1990 /* reuse struct adouble so it won't break locks */
1994 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
1995 if ( !ret && ad_hfileno(adp) != -1 && !(adp->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) {
1997 * The user must have the Read & Write privilege for both files in order to use this command.
1999 ad_close(adp, ADFLAGS_HF);
2000 afp_errno = AFPERR_ACCESS;
2007 #define APPLETEMP ".AppleTempXXXXXX"
2009 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
2012 int ibuflen, *rbuflen;
2014 struct stat srcst, destst;
2016 struct dir *dir, *sdir;
2017 char *spath, temp[17], *p;
2018 char *supath, *upath;
2023 struct adouble *adsp = NULL;
2024 struct adouble *addp = NULL;
2025 struct ofork *s_of = NULL;
2026 struct ofork *d_of = NULL;
2037 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
2043 memcpy(&vid, ibuf, sizeof(vid));
2044 ibuf += sizeof(vid);
2046 if (NULL == ( vol = getvolbyvid( vid )) ) {
2047 return( AFPERR_PARAM);
2050 if ((vol->v_flags & AFPVOL_RO))
2051 return AFPERR_VLOCK;
2053 /* source and destination dids */
2054 memcpy(&sid, ibuf, sizeof(sid));
2055 ibuf += sizeof(sid);
2056 memcpy(&did, ibuf, sizeof(did));
2057 ibuf += sizeof(did);
2060 if (NULL == (dir = dirlookup( vol, sid )) ) {
2061 return afp_errno; /* was AFPERR_PARAM */
2064 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2065 return get_afp_errno(AFPERR_NOOBJ);
2068 if ( path_isadir(path) ) {
2069 return AFPERR_BADTYPE; /* it's a dir */
2072 /* save some stuff */
2075 spath = obj->oldtmp;
2076 supath = obj->newtmp;
2077 strcpy(spath, path->m_name);
2078 strcpy(supath, path->u_name); /* this is for the cnid changing */
2079 p = absupath( vol, sdir, supath);
2081 /* pathname too long */
2082 return AFPERR_PARAM ;
2085 ad_init(&ads, vol->v_adouble, vol->v_ad_options);
2086 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2090 /* ***** from here we may have resource fork open **** */
2092 /* look for the source cnid. if it doesn't exist, don't worry about
2094 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2096 if (NULL == ( dir = dirlookup( vol, did )) ) {
2097 err = afp_errno; /* was AFPERR_PARAM */
2098 goto err_exchangefile;
2101 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2102 err = get_afp_errno(AFPERR_NOOBJ);
2103 goto err_exchangefile;
2106 if ( path_isadir(path) ) {
2107 err = AFPERR_BADTYPE;
2108 goto err_exchangefile;
2111 /* FPExchangeFiles is the only call that can return the SameObj
2113 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2114 err = AFPERR_SAMEOBJ;
2115 goto err_exchangefile;
2118 ad_init(&add, vol->v_adouble, vol->v_ad_options);
2119 if (!(addp = find_adouble( path, &d_of, &add))) {
2121 goto err_exchangefile;
2125 /* they are not on the same device and at least one is open
2126 * FIXME broken for for crossdev and adouble v2
2129 crossdev = (srcst.st_dev != destst.st_dev);
2130 if (/* (d_of || s_of) && */ crossdev) {
2132 goto err_exchangefile;
2135 /* look for destination id. */
2136 upath = path->u_name;
2137 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2139 /* construct a temp name.
2140 * NOTE: the temp file will be in the dest file's directory. it
2141 * will also be inaccessible from AFP. */
2142 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2143 if (!mktemp(temp)) {
2145 goto err_exchangefile;
2149 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2150 ad_close(adsp, ADFLAGS_HF);
2151 ad_close(addp, ADFLAGS_HF);
2154 /* now, quickly rename the file. we error if we can't. */
2155 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2156 goto err_exchangefile;
2157 of_rename(vol, s_of, sdir, spath, curdir, temp);
2159 /* rename destination to source */
2160 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2161 goto err_src_to_tmp;
2162 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2164 /* rename temp to destination */
2165 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2166 goto err_dest_to_src;
2167 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2169 /* id's need switching. src -> dest and dest -> src.
2170 * we need to re-stat() if it was a cross device copy.
2173 cnid_delete(vol->v_cdb, sid);
2176 cnid_delete(vol->v_cdb, did);
2178 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2179 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2181 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2182 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2187 err = AFPERR_ACCESS;
2192 goto err_temp_to_dest;
2195 /* here we need to reopen if crossdev */
2196 if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2198 ad_flush( addp, ADFLAGS_HF );
2201 if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2203 ad_flush( adsp, ADFLAGS_HF );
2206 /* change perms, src gets dest perm and vice versa */
2211 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2212 err = AFP_OK; /* ignore error */
2213 goto err_temp_to_dest;
2217 * we need to exchange ACL entries as well
2219 /* exchange_acls(vol, p, upath); */
2224 path->m_name = NULL;
2225 path->u_name = upath;
2227 setfilunixmode(vol, path, destst.st_mode);
2228 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2235 setfilunixmode(vol, path, srcst.st_mode);
2236 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2238 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2239 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2244 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2248 goto err_exchangefile;
2250 /* all this stuff is so that we can unwind a failed operation
2253 /* rename dest to temp */
2254 renamefile(vol, upath, temp, temp, adsp);
2255 of_rename(vol, s_of, curdir, upath, curdir, temp);
2258 /* rename source back to dest */
2259 renamefile(vol, p, upath, path->m_name, addp);
2260 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2263 /* rename temp back to source */
2264 renamefile(vol, temp, p, spath, adsp);
2265 of_rename(vol, s_of, curdir, temp, sdir, spath);
2268 if ( !s_of && adsp && ad_hfileno(adsp) != -1 ) {
2269 ad_close(adsp, ADFLAGS_HF);
2271 if ( !d_of && addp && ad_hfileno(addp) != -1 ) {
2272 ad_close(addp, ADFLAGS_HF);