2 * $Id: file.c,v 1.111 2009-10-02 09:32:40 franklahm 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 */
34 #include <sys/param.h>
36 #include <atalk/adouble.h>
37 #include <atalk/vfs.h>
38 #include <atalk/logger.h>
39 #include <atalk/afp.h>
40 #include <atalk/util.h>
41 #include <atalk/cnid.h>
42 #include "directory.h"
51 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
52 * field bytes subfield bytes
55 * ioFlFndrInfo 16 -> type 4 type field
56 * creator 4 creator field
57 * flags 2 finder flags:
59 * location 4 location in window
60 * folder 2 window that contains file
62 * ioFlXFndrInfo 16 -> iconID 2 icon id
64 * script 1 script system
66 * commentID 2 comment id
67 * putawayID 4 home directory id
70 const u_char ufinderi[ADEDLEN_FINDERI] = {
71 0, 0, 0, 0, 0, 0, 0, 0,
72 1, 0, 0, 0, 0, 0, 0, 0,
73 0, 0, 0, 0, 0, 0, 0, 0,
74 0, 0, 0, 0, 0, 0, 0, 0
77 static const u_char old_ufinderi[] = {
78 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X'
81 /* ----------------------
83 static int default_type(void *finder)
85 if (!memcmp(finder, ufinderi, 8) || !memcmp(finder, old_ufinderi, 8))
90 /* FIXME path : unix or mac name ? (for now it's unix name ) */
91 void *get_finderinfo(const struct vol *vol, const char *upath, struct adouble *adp, void *data)
94 void *ad_finder = NULL;
98 ad_finder = ad_entry(adp, ADEID_FINDERI);
101 memcpy(data, ad_finder, ADEDLEN_FINDERI);
103 if (default_type(ad_finder))
107 memcpy(data, ufinderi, ADEDLEN_FINDERI);
109 if (vol_inv_dots(vol) && *upath == '.') { /* make it invisible */
112 ashort = htons(FINDERINFO_INVISIBLE);
113 memcpy((char *)data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
116 /** Only enter if no appledouble information and no finder information found. */
117 if (chk_ext && (em = getextmap( upath ))) {
118 memcpy(data, em->em_type, sizeof( em->em_type ));
119 memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator));
124 /* ---------------------
126 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8)
131 aint = strlen( name );
135 if (utf8_encoding()) {
136 /* but name is an utf8 mac name */
139 /* global static variable... */
141 if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
150 if (aint > MACFILELEN)
157 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
160 utf8 = vol->v_mac?htonl(vol->v_mac->kTextEncoding):0; /* htonl(utf8) */
161 memcpy(data, &utf8, sizeof(utf8));
162 data += sizeof(utf8);
165 memcpy(data, &temp, sizeof(temp));
166 data += sizeof(temp);
169 memcpy( data, src, aint );
179 * FIXME: PDINFO is UTF8 and doesn't need adp
181 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
182 (1 << FILPBIT_CDATE) |\
183 (1 << FILPBIT_MDATE) |\
184 (1 << FILPBIT_BDATE) |\
185 (1 << FILPBIT_FINFO) |\
186 (1 << FILPBIT_RFLEN) |\
187 (1 << FILPBIT_EXTRFLEN) |\
188 (1 << FILPBIT_PDINFO) |\
189 (1 << FILPBIT_UNIXPR)))
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)) {
237 /* -------------------------- */
238 int getmetadata(struct vol *vol,
240 struct path *path, struct dir *dir,
241 char *buf, int *buflen, struct adouble *adp)
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));
273 path->m_name = utompath(vol, upath, id, utf8_encoding());
276 while ( bitmap != 0 ) {
277 while (( bitmap & 1 ) == 0 ) {
285 ad_getattr(adp, &ashort);
286 } else if (vol_inv_dots(vol) && *upath == '.') {
287 ashort = htons(ATTRBIT_INVISIBLE);
291 /* FIXME do we want a visual clue if the file is read only
294 accessmode( ".", &ma, dir , NULL);
295 if ((ma.ma_user & AR_UWRITE)) {
296 accessmode( upath, &ma, dir , st);
297 if (!(ma.ma_user & AR_UWRITE)) {
298 ashort |= htons(ATTRBIT_NOWRITE);
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(vol, 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 );
467 type == slnk indicates an OSX style symlink,
468 we have to add S_IFLNK to the mode, otherwise
469 10.3 clients freak out. */
473 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
474 if ( memcmp( fdType, "slnk", 4 ) == 0 ) {
480 memcpy( data, &aint, sizeof( aint ));
481 data += sizeof( aint );
483 *data++ = ma.ma_user;
484 *data++ = ma.ma_world;
485 *data++ = ma.ma_group;
486 *data++ = ma.ma_owner;
490 return( AFPERR_BITMAP );
496 ashort = htons( data - buf );
497 memcpy(l_nameoff, &ashort, sizeof( ashort ));
498 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
501 ashort = htons( data - buf );
502 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
503 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
505 *buflen = data - buf;
509 /* ----------------------- */
510 int getfilparams(struct vol *vol,
512 struct path *path, struct dir *dir,
513 char *buf, int *buflen )
515 struct adouble ad, *adp;
522 LOG(log_info, logtype_default, "begin getfilparams:");
525 opened = PARAM_NEED_ADP(bitmap);
529 int flags = (bitmap & (1 << FILPBIT_ATTR))?ADFLAGS_OPENFORKS:0;
530 upath = path->u_name;
531 if ((of = of_findname(path))) {
534 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
538 if ( ad_metadata( upath, flags, adp) < 0 ) {
541 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
542 upath, strerror(errno));
543 return AFPERR_ACCESS;
545 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
554 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp);
556 ad_close_metadata( adp);
559 LOG(log_info, logtype_afpd, "end getfilparams:");
565 /* ----------------------------- */
566 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
568 char *ibuf, *rbuf _U_;
569 int ibuflen _U_, *rbuflen;
571 struct adouble ad, *adp;
574 struct ofork *of = NULL;
576 int creatf, did, openf, retvalue = AFP_OK;
581 LOG(log_info, logtype_afpd, "begin afp_createfile:");
586 creatf = (unsigned char) *ibuf++;
588 memcpy(&vid, ibuf, sizeof( vid ));
589 ibuf += sizeof( vid );
591 if (NULL == ( vol = getvolbyvid( vid )) ) {
592 return( AFPERR_PARAM );
595 if (vol->v_flags & AFPVOL_RO)
598 memcpy(&did, ibuf, sizeof( did));
599 ibuf += sizeof( did );
601 if (NULL == ( dir = dirlookup( vol, did )) ) {
605 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
606 return get_afp_errno(AFPERR_PARAM);
609 if ( *s_path->m_name == '\0' ) {
610 return( AFPERR_BADTYPE );
613 upath = s_path->u_name;
615 /* if upath is deleted we already in trouble anyway */
616 if ((of = of_findname(s_path))) {
619 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
623 /* on a hard create, fail if file exists and is open */
626 openf = O_RDWR|O_CREAT|O_TRUNC;
628 /* on a soft create, if the file is open then ad_open won't fail
629 because open syscall is not called
634 openf = O_RDWR|O_CREAT|O_EXCL;
637 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF|ADFLAGS_CREATE,
638 openf, 0666, adp) < 0 ) {
642 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
643 return ( AFPERR_NOOBJ );
645 return( AFPERR_EXIST );
647 return( AFPERR_ACCESS );
650 return( AFPERR_DFULL );
652 return( AFPERR_PARAM );
655 if ( ad_reso_fileno( adp ) == -1 ) { /* Hard META / HF */
656 /* on noadouble volumes, just creating the data fork is ok */
657 if (vol_noadouble(vol)) {
658 ad_close( adp, ADFLAGS_DF );
659 goto createfile_done;
661 /* FIXME with hard create on an existing file, we already
662 * corrupted the data file.
664 netatalk_unlink( upath );
665 ad_close( adp, ADFLAGS_DF );
666 return AFPERR_ACCESS;
669 path = s_path->m_name;
670 ad_setname(adp, path);
672 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
678 if (vol->v_flags & AFPVOL_DROPBOX) {
679 retvalue = matchfile2dirperms(upath, vol, did);
681 #endif /* DROPKLUDGE */
683 setvoltime(obj, vol );
686 LOG(log_info, logtype_afpd, "end afp_createfile");
692 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
694 char *ibuf, *rbuf _U_;
695 int ibuflen _U_, *rbuflen;
701 u_int16_t vid, bitmap;
704 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
710 memcpy(&vid, ibuf, sizeof( vid ));
711 ibuf += sizeof( vid );
712 if (NULL == ( vol = getvolbyvid( vid )) ) {
713 return( AFPERR_PARAM );
716 if (vol->v_flags & AFPVOL_RO)
719 memcpy(&did, ibuf, sizeof( did ));
720 ibuf += sizeof( did );
721 if (NULL == ( dir = dirlookup( vol, did )) ) {
722 return afp_errno; /* was AFPERR_NOOBJ */
725 memcpy(&bitmap, ibuf, sizeof( bitmap ));
726 bitmap = ntohs( bitmap );
727 ibuf += sizeof( bitmap );
729 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
730 return get_afp_errno(AFPERR_PARAM);
733 if (path_isadir(s_path)) {
734 return( AFPERR_BADTYPE ); /* it's a directory */
737 if ( s_path->st_errno != 0 ) {
738 return( AFPERR_NOOBJ );
741 if ((u_long)ibuf & 1 ) {
745 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
746 setvoltime(obj, vol );
750 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
757 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
760 extern struct path Cur_Path;
762 int setfilparams(struct vol *vol,
763 struct path *path, u_int16_t f_bitmap, char *buf )
765 struct adouble ad, *adp;
767 int bit, isad = 1, err = AFP_OK;
769 u_char achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
770 u_int16_t ashort, bshort;
773 u_int16_t upriv_bit = 0;
777 int change_mdate = 0;
778 int change_parent_mdate = 0;
783 u_int16_t bitmap = f_bitmap;
784 u_int32_t cdate,bdate;
785 u_char finder_buf[32];
788 LOG(log_info, logtype_afpd, "begin setfilparams:");
791 upath = path->u_name;
792 adp = of_ad(vol, path, &ad);
795 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
796 return AFPERR_ACCESS;
799 /* with unix priv maybe we have to change adouble file priv first */
801 while ( bitmap != 0 ) {
802 while (( bitmap & 1 ) == 0 ) {
809 memcpy(&ashort, buf, sizeof( ashort ));
810 buf += sizeof( ashort );
814 memcpy(&cdate, buf, sizeof(cdate));
815 buf += sizeof( cdate );
818 memcpy(&newdate, buf, sizeof( newdate ));
819 buf += sizeof( newdate );
823 memcpy(&bdate, buf, sizeof( bdate));
824 buf += sizeof( bdate );
828 memcpy(finder_buf, buf, 32 );
831 case FILPBIT_UNIXPR :
832 if (!vol_unix_priv(vol)) {
833 /* this volume doesn't use unix priv */
839 change_parent_mdate = 1;
841 memcpy( &aint, buf, sizeof( aint ));
842 f_uid = ntohl (aint);
843 buf += sizeof( aint );
844 memcpy( &aint, buf, sizeof( aint ));
845 f_gid = ntohl (aint);
846 buf += sizeof( aint );
847 setfilowner(vol, f_uid, f_gid, path);
849 memcpy( &upriv, buf, sizeof( upriv ));
850 buf += sizeof( upriv );
851 upriv = ntohl (upriv);
852 if ((upriv & S_IWUSR)) {
853 setfilunixmode(vol, path, upriv);
860 case FILPBIT_PDINFO :
861 if (afp_version < 30) { /* else it's UTF8 name */
864 /* Keep special case to support crlf translations */
865 if ((unsigned int) achar == 0x04) {
866 fdType = (u_char *)"TEXT";
869 xyy[0] = ( u_char ) 'p';
880 /* break while loop */
889 /* second try with adouble open
891 if ( ad_open_metadata( upath, vol_noadouble(vol), O_CREAT, adp) < 0) {
892 LOG(log_debug, logtype_afpd, "setfilparams: ad_open_metadata error");
894 * For some things, we don't need an adouble header:
895 * - change of modification date
896 * - UNIX privs (Bug-ID #2863424)
898 if ( (f_bitmap & ~(1<<FILPBIT_MDATE | 1<<FILPBIT_UNIXPR))) {
899 LOG(log_debug, logtype_afpd, "setfilparams: need adouble access");
900 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
902 LOG(log_debug, logtype_afpd, "setfilparams: no adouble perms, but only FILPBIT_MDATE and/or FILPBIT_UNIXPR");
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);
984 ad_close_metadata( adp);
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;
1018 LOG(log_info, logtype_afpd, "begin renamefile:");
1021 if ( unix_rename( src, dst ) < 0 ) {
1024 return( AFPERR_NOOBJ );
1027 return( AFPERR_ACCESS );
1029 return AFPERR_VLOCK;
1030 case EXDEV : /* Cross device move -- try copy */
1031 /* NOTE: with open file it's an error because after the copy we will
1032 * get two files, it's fixable for our process (eg reopen the new file, get the
1033 * locks, and so on. But it doesn't solve the case with a second process
1035 if (adp->ad_open_forks) {
1036 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1037 return AFPERR_OLOCK; /* little lie */
1039 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1040 /* on error copyfile delete dest */
1043 return deletefile(vol, src, 0);
1045 return( AFPERR_PARAM );
1049 if (vol->vfs->rf_renamefile(vol, src, dst) < 0 ) {
1053 /* try to undo the data fork rename,
1054 * we know we are on the same device
1057 unix_rename( dst, src );
1058 /* return the first error */
1061 return AFPERR_NOOBJ;
1064 return AFPERR_ACCESS ;
1066 return AFPERR_VLOCK;
1068 return AFPERR_PARAM ;
1073 /* don't care if we can't open the newly renamed ressource fork
1075 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1076 ad_setname(adp, newname);
1078 ad_close( adp, ADFLAGS_HF );
1081 LOG(log_info, logtype_afpd, "end renamefile:");
1088 convert a Mac long name to an utf8 name,
1090 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1094 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1100 /* ---------------- */
1101 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1108 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1114 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1115 if (afp_version >= 30) {
1116 /* convert it to UTF8
1118 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1)
1122 strncpy( newname, ibuf, plen );
1123 newname[ plen ] = '\0';
1125 if (strlen(newname) != plen) {
1126 /* there's \0 in newname, e.g. it's a pathname not
1134 memcpy(&hint, ibuf, sizeof(hint));
1135 ibuf += sizeof(hint);
1137 memcpy(&len16, ibuf, sizeof(len16));
1138 ibuf += sizeof(len16);
1139 plen = ntohs(len16);
1142 if (plen > AFPOBJ_TMPSIZ) {
1145 strncpy( newname, ibuf, plen );
1146 newname[ plen ] = '\0';
1147 if (strlen(newname) != plen) {
1156 /* -----------------------------------
1158 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1160 char *ibuf, *rbuf _U_;
1161 int ibuflen _U_, *rbuflen;
1163 struct vol *s_vol, *d_vol;
1165 char *newname, *p, *upath;
1166 struct path *s_path;
1167 u_int32_t sdid, ddid;
1168 int err, retvalue = AFP_OK;
1169 u_int16_t svid, dvid;
1171 struct adouble ad, *adp;
1175 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1181 memcpy(&svid, ibuf, sizeof( svid ));
1182 ibuf += sizeof( svid );
1183 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1184 return( AFPERR_PARAM );
1187 memcpy(&sdid, ibuf, sizeof( sdid ));
1188 ibuf += sizeof( sdid );
1189 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1193 memcpy(&dvid, ibuf, sizeof( dvid ));
1194 ibuf += sizeof( dvid );
1195 memcpy(&ddid, ibuf, sizeof( ddid ));
1196 ibuf += sizeof( ddid );
1198 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1199 return get_afp_errno(AFPERR_PARAM);
1201 if ( path_isadir(s_path) ) {
1202 return( AFPERR_BADTYPE );
1205 /* don't allow copies when the file is open.
1206 * XXX: the spec only calls for read/deny write access.
1207 * however, copyfile doesn't have any of that info,
1208 * and locks need to stay coherent. as a result,
1209 * we just balk if the file is opened already. */
1211 adp = of_ad(s_vol, s_path, &ad);
1213 if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1214 return AFPERR_DENYCONF;
1216 denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
1217 getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1218 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1220 return AFPERR_DENYCONF;
1223 newname = obj->newtmp;
1224 strcpy( newname, s_path->m_name );
1226 p = ctoupath( s_vol, curdir, newname );
1228 return AFPERR_PARAM;
1232 /* FIXME svid != dvid && dvid's user can't read svid */
1234 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1235 return( AFPERR_PARAM );
1238 if (d_vol->v_flags & AFPVOL_RO)
1239 return AFPERR_VLOCK;
1241 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1245 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1246 return get_afp_errno(AFPERR_NOOBJ);
1248 if ( *s_path->m_name != '\0' ) {
1249 path_error(s_path, AFPERR_PARAM);
1252 /* one of the handful of places that knows about the path type */
1253 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1254 return( AFPERR_PARAM );
1256 /* newname is always only a filename so curdir *is* its
1259 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1260 return( AFPERR_PARAM );
1262 if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1268 if (vol->v_flags & AFPVOL_DROPBOX) {
1269 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1271 #endif /* DROPKLUDGE */
1273 setvoltime(obj, d_vol );
1276 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1282 /* ----------------------- */
1283 static int copy_all(const int dfd, const void *buf,
1289 LOG(log_info, logtype_afpd, "begin copy_all:");
1292 while (buflen > 0) {
1293 if ((cc = write(dfd, buf, buflen)) < 0) {
1305 LOG(log_info, logtype_afpd, "end copy_all:");
1311 /* --------------------------
1312 * copy only the fork data stream
1314 static int copy_fork(int eid, struct adouble *add, struct adouble *ads)
1321 if (eid == ADEID_DFORK) {
1322 sfd = ad_data_fileno(ads);
1323 dfd = ad_data_fileno(add);
1326 sfd = ad_reso_fileno(ads);
1327 dfd = ad_reso_fileno(add);
1330 if ((off_t)-1 == lseek(sfd, ad_getentryoff(ads, eid), SEEK_SET))
1333 if ((off_t)-1 == lseek(dfd, ad_getentryoff(add, eid), SEEK_SET))
1336 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1337 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1341 #define BUF 128*1024*1024
1343 if (fstat(sfd, &st) == 0) {
1346 if ( offset >= st.st_size) {
1349 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1350 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1353 case EINVAL: /* there's no guarantee that all fs support sendfile */
1362 lseek(sfd, offset, SEEK_SET);
1366 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1373 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1380 /* ----------------------------------
1381 * if newname is NULL (from directory.c) we don't want to copy the resource fork.
1382 * because we are doing it elsewhere.
1383 * currently if newname is NULL then adp is NULL.
1385 int copyfile(s_vol, d_vol, src, dst, newname, adp )
1386 const struct vol *s_vol, *d_vol;
1387 char *src, *dst, *newname;
1388 struct adouble *adp;
1390 struct adouble ads, add;
1398 LOG(log_info, logtype_afpd, "begin copyfile:");
1402 ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options);
1405 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1406 adflags = ADFLAGS_DF;
1408 adflags |= ADFLAGS_HF;
1411 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1416 if (ad_meta_fileno(adp) == -1 && ad_reso_fileno(adp) == -1) { /* META / HF */
1417 /* no resource fork, don't create one for dst file */
1418 adflags &= ~ADFLAGS_HF;
1421 stat_result = fstat(ad_data_fileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */
1423 if (stat_result < 0) {
1424 /* unlikely but if fstat fails, the default file mode will be 0666. */
1425 st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
1428 if (ad_open(dst , adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
1430 ad_close( adp, adflags );
1431 if (EEXIST != ret_err) {
1432 deletefile(d_vol, dst, 0);
1435 return AFPERR_EXIST;
1437 /* XXX if the source and the dest don't use the same resource type it's broken
1439 if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){
1440 /* copy the data fork */
1441 err = copy_fork(ADEID_DFORK, &add, adp);
1448 if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
1449 /* set the new name in the resource fork */
1450 ad_copy_header(&add, adp);
1451 ad_setname(&add, newname);
1454 ad_close( adp, adflags );
1456 if (ad_close( &add, adflags ) <0) {
1461 deletefile(d_vol, dst, 0);
1463 else if (stat_result == 0) {
1464 /* set dest modification date to src date */
1467 ut.actime = ut.modtime = st.st_mtime;
1469 /* FIXME netatalk doesn't use resource fork file date
1470 * but maybe we should set its modtime too.
1475 LOG(log_info, logtype_afpd, "end copyfile:");
1479 switch ( ret_err ) {
1485 return AFPERR_DFULL;
1487 return AFPERR_NOOBJ;
1489 return AFPERR_ACCESS;
1491 return AFPERR_VLOCK;
1493 return AFPERR_PARAM;
1497 /* -----------------------------------
1498 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1499 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1501 when deletefile is called we don't have lock on it, file is closed (for us)
1502 untrue if called by renamefile
1504 ad_open always try to open file RDWR first and ad_lock takes care of
1505 WRITE lock on read only file.
1508 static int check_attrib(struct adouble *adp)
1510 u_int16_t bshort = 0;
1512 ad_getattr(adp, &bshort);
1514 * Does kFPDeleteInhibitBit (bit 8) set?
1516 if ((bshort & htons(ATTRBIT_NODELETE))) {
1517 return AFPERR_OLOCK;
1519 if ((bshort & htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN))) {
1525 int deletefile( vol, file, checkAttrib )
1526 const struct vol *vol;
1531 struct adouble *adp = &ad;
1532 int adflags, err = AFP_OK;
1535 LOG(log_info, logtype_afpd, "begin deletefile:");
1538 /* try to open both forks at once */
1539 adflags = ADFLAGS_DF|ADFLAGS_HF;
1541 /* was EACCESS error try to get only metadata */
1542 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1543 if ( ad_metadata( file , ADFLAGS_OPENFORKS, &ad) == 0 ) {
1544 ad_close( &ad, adflags );
1545 if ((err = check_attrib(&ad))) {
1552 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1553 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1556 if (adflags == ADFLAGS_DF)
1557 return AFPERR_NOOBJ;
1559 /* that failed. now try to open just the data fork */
1560 adflags = ADFLAGS_DF;
1564 adp = NULL; /* maybe it's a file with no write mode for us */
1565 break; /* was return AFPERR_ACCESS;*/
1567 return AFPERR_VLOCK;
1569 return( AFPERR_PARAM );
1572 break; /* from the while */
1575 if (adp && (adflags & ADFLAGS_HF) ) {
1576 /* FIXME we have a pb here because we want to know if a file is open
1577 * there's a 'priority inversion' if you can't open the ressource fork RW
1578 * you can delete it if it's open because you can't get a write lock.
1580 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1583 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1585 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1586 ad_close( &ad, adflags );
1587 return( AFPERR_BUSY );
1591 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1594 else if (!(err = vol->vfs->rf_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
1596 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1598 cnid_delete(vol->v_cdb, id);
1602 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1605 LOG(log_info, logtype_afpd, "end deletefile:");
1611 /* ------------------------------------ */
1612 /* return a file id */
1613 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1616 int ibuflen _U_, *rbuflen;
1625 struct path *s_path;
1628 LOG(log_info, logtype_afpd, "begin afp_createid:");
1635 memcpy(&vid, ibuf, sizeof(vid));
1636 ibuf += sizeof(vid);
1638 if (NULL == ( vol = getvolbyvid( vid )) ) {
1639 return( AFPERR_PARAM);
1642 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1646 if (vol->v_flags & AFPVOL_RO)
1647 return AFPERR_VLOCK;
1649 memcpy(&did, ibuf, sizeof( did ));
1650 ibuf += sizeof(did);
1652 if (NULL == ( dir = dirlookup( vol, did )) ) {
1653 return afp_errno; /* was AFPERR_PARAM */
1656 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1657 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1660 if ( path_isadir(s_path) ) {
1661 return( AFPERR_BADTYPE );
1664 upath = s_path->u_name;
1665 switch (s_path->st_errno) {
1667 break; /* success */
1670 return AFPERR_ACCESS;
1672 return AFPERR_NOOBJ;
1674 return AFPERR_PARAM;
1677 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1678 memcpy(rbuf, &id, sizeof(id));
1679 *rbuflen = sizeof(id);
1680 return AFPERR_EXISTID;
1683 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1684 memcpy(rbuf, &id, sizeof(id));
1685 *rbuflen = sizeof(id);
1690 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1695 /* ------------------------------- */
1701 static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
1704 struct reenum *param = data;
1705 struct vol *vol = param->vol;
1706 cnid_t did = param->did;
1709 memset(&path, 0, sizeof(path));
1711 if ( stat(de->d_name, &path.st)<0 )
1714 /* update or add to cnid */
1715 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1717 #if AD_VERSION > AD_VERSION1
1718 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1719 struct adouble ad, *adp;
1723 path.u_name = de->d_name;
1725 adp = of_ad(vol, &path, &ad);
1727 if ( ad_open_metadata( de->d_name, 0, 0, adp ) < 0 ) {
1730 if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1733 ad_close_metadata(adp);
1735 #endif /* AD_VERSION > AD_VERSION1 */
1740 /* --------------------
1741 * Ok the db is out of synch with the dir.
1742 * but if it's a deleted file we don't want to do it again and again.
1745 reenumerate_id(struct vol *vol, char *name, struct dir *dir)
1751 if (vol->v_cdb == NULL) {
1755 /* FIXME use of_statdir ? */
1756 if (stat(name, &st)) {
1760 if (dirreenumerate(dir, &st)) {
1761 /* we already did it once and the dir haven't been modified */
1766 data.did = dir->d_did;
1767 if ((ret = for_each_dirent(vol, name, reenumerate_loop, (void *)&data)) >= 0) {
1768 setdiroffcnt(curdir, &st, ret);
1769 dir->d_flags |= DIRF_CNID;
1775 /* ------------------------------
1776 resolve a file id */
1777 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1780 int ibuflen _U_, *rbuflen;
1786 int err, buflen, retry=0;
1788 u_int16_t vid, bitmap;
1790 static char buffer[12 + MAXPATHLEN + 1];
1791 int len = 12 + MAXPATHLEN + 1;
1794 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1800 memcpy(&vid, ibuf, sizeof(vid));
1801 ibuf += sizeof(vid);
1803 if (NULL == ( vol = getvolbyvid( vid )) ) {
1804 return( AFPERR_PARAM);
1807 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1811 memcpy(&id, ibuf, sizeof( id ));
1816 /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
1820 memset(&path, 0, sizeof(path));
1821 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1822 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1825 if (NULL == ( dir = dirlookup( vol, id )) ) {
1826 return AFPERR_NOID; /* idem AFPERR_PARAM */
1828 path.u_name = upath;
1829 if (movecwd(vol, dir) < 0) {
1833 return AFPERR_ACCESS;
1837 return AFPERR_PARAM;
1841 if ( of_stat(&path) < 0 ) {
1843 /* with nfs and our working directory is deleted */
1844 if (errno == ESTALE) {
1848 if ( errno == ENOENT && !retry) {
1849 /* cnid db is out of sync, reenumerate the directory and update ids */
1850 reenumerate_id(vol, ".", dir);
1858 return AFPERR_ACCESS;
1862 return AFPERR_PARAM;
1866 /* directories are bad */
1867 if (S_ISDIR(path.st.st_mode)) {
1868 /* OS9 and OSX don't return the same error code */
1869 return (afp_version >=30)?AFPERR_NOID:AFPERR_BADTYPE;
1872 memcpy(&bitmap, ibuf, sizeof(bitmap));
1873 bitmap = ntohs( bitmap );
1874 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1878 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1879 rbuf + sizeof(bitmap), &buflen))) {
1882 *rbuflen = buflen + sizeof(bitmap);
1883 memcpy(rbuf, ibuf, sizeof(bitmap));
1886 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1892 /* ------------------------------ */
1893 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1895 char *ibuf, *rbuf _U_;
1896 int ibuflen _U_, *rbuflen;
1906 static char buffer[12 + MAXPATHLEN + 1];
1907 int len = 12 + MAXPATHLEN + 1;
1910 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1916 memcpy(&vid, ibuf, sizeof(vid));
1917 ibuf += sizeof(vid);
1919 if (NULL == ( vol = getvolbyvid( vid )) ) {
1920 return( AFPERR_PARAM);
1923 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1927 if (vol->v_flags & AFPVOL_RO)
1928 return AFPERR_VLOCK;
1930 memcpy(&id, ibuf, sizeof( id ));
1934 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1938 if (NULL == ( dir = dirlookup( vol, id )) ) {
1939 return( AFPERR_PARAM );
1943 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1947 return AFPERR_ACCESS;
1952 /* still try to delete the id */
1956 return AFPERR_PARAM;
1959 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1960 return AFPERR_BADTYPE;
1962 if (cnid_delete(vol->v_cdb, fileid)) {
1965 return AFPERR_VLOCK;
1968 return AFPERR_ACCESS;
1970 return AFPERR_PARAM;
1975 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1981 /* ------------------------------ */
1982 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1986 if (path->st_errno) {
1987 switch (path->st_errno) {
1989 afp_errno = AFPERR_NOID;
1993 afp_errno = AFPERR_ACCESS;
1996 afp_errno = AFPERR_PARAM;
2001 /* we use file_access both for legacy Mac perm and
2002 * for unix privilege, rename will take care of folder perms
2004 if (file_access(path, OPENACC_WR ) < 0) {
2005 afp_errno = AFPERR_ACCESS;
2009 if ((*of = of_findname(path))) {
2010 /* reuse struct adouble so it won't break locks */
2014 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
2016 if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
2018 * The user must have the Read & Write privilege for both files in order to use this command.
2020 ad_close(adp, ADFLAGS_HF);
2021 afp_errno = AFPERR_ACCESS;
2028 #define APPLETEMP ".AppleTempXXXXXX"
2030 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
2032 char *ibuf, *rbuf _U_ ;
2033 int ibuflen _U_, *rbuflen;
2035 struct stat srcst, destst;
2037 struct dir *dir, *sdir;
2038 char *spath, temp[17], *p;
2039 char *supath, *upath;
2044 struct adouble *adsp = NULL;
2045 struct adouble *addp = NULL;
2046 struct ofork *s_of = NULL;
2047 struct ofork *d_of = NULL;
2058 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
2064 memcpy(&vid, ibuf, sizeof(vid));
2065 ibuf += sizeof(vid);
2067 if (NULL == ( vol = getvolbyvid( vid )) ) {
2068 return( AFPERR_PARAM);
2071 if ((vol->v_flags & AFPVOL_RO))
2072 return AFPERR_VLOCK;
2074 /* source and destination dids */
2075 memcpy(&sid, ibuf, sizeof(sid));
2076 ibuf += sizeof(sid);
2077 memcpy(&did, ibuf, sizeof(did));
2078 ibuf += sizeof(did);
2081 if (NULL == (dir = dirlookup( vol, sid )) ) {
2082 return afp_errno; /* was AFPERR_PARAM */
2085 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2086 return get_afp_errno(AFPERR_NOOBJ);
2089 if ( path_isadir(path) ) {
2090 return AFPERR_BADTYPE; /* it's a dir */
2093 /* save some stuff */
2096 spath = obj->oldtmp;
2097 supath = obj->newtmp;
2098 strcpy(spath, path->m_name);
2099 strcpy(supath, path->u_name); /* this is for the cnid changing */
2100 p = absupath( vol, sdir, supath);
2102 /* pathname too long */
2103 return AFPERR_PARAM ;
2106 ad_init(&ads, vol->v_adouble, vol->v_ad_options);
2107 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2111 /* ***** from here we may have resource fork open **** */
2113 /* look for the source cnid. if it doesn't exist, don't worry about
2115 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2117 if (NULL == ( dir = dirlookup( vol, did )) ) {
2118 err = afp_errno; /* was AFPERR_PARAM */
2119 goto err_exchangefile;
2122 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2123 err = get_afp_errno(AFPERR_NOOBJ);
2124 goto err_exchangefile;
2127 if ( path_isadir(path) ) {
2128 err = AFPERR_BADTYPE;
2129 goto err_exchangefile;
2132 /* FPExchangeFiles is the only call that can return the SameObj
2134 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2135 err = AFPERR_SAMEOBJ;
2136 goto err_exchangefile;
2139 ad_init(&add, vol->v_adouble, vol->v_ad_options);
2140 if (!(addp = find_adouble( path, &d_of, &add))) {
2142 goto err_exchangefile;
2146 /* they are not on the same device and at least one is open
2147 * FIXME broken for for crossdev and adouble v2
2150 crossdev = (srcst.st_dev != destst.st_dev);
2151 if (/* (d_of || s_of) && */ crossdev) {
2153 goto err_exchangefile;
2156 /* look for destination id. */
2157 upath = path->u_name;
2158 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2160 /* construct a temp name.
2161 * NOTE: the temp file will be in the dest file's directory. it
2162 * will also be inaccessible from AFP. */
2163 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2164 if (!mktemp(temp)) {
2166 goto err_exchangefile;
2170 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2171 ad_close(adsp, ADFLAGS_HF);
2172 ad_close(addp, ADFLAGS_HF);
2175 /* now, quickly rename the file. we error if we can't. */
2176 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2177 goto err_exchangefile;
2178 of_rename(vol, s_of, sdir, spath, curdir, temp);
2180 /* rename destination to source */
2181 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2182 goto err_src_to_tmp;
2183 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2185 /* rename temp to destination */
2186 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2187 goto err_dest_to_src;
2188 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2190 /* id's need switching. src -> dest and dest -> src.
2191 * we need to re-stat() if it was a cross device copy.
2194 cnid_delete(vol->v_cdb, sid);
2197 cnid_delete(vol->v_cdb, did);
2199 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2200 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2202 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2203 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2208 err = AFPERR_ACCESS;
2213 goto err_temp_to_dest;
2216 /* here we need to reopen if crossdev */
2217 if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2222 if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2227 /* change perms, src gets dest perm and vice versa */
2232 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2233 err = AFP_OK; /* ignore error */
2234 goto err_temp_to_dest;
2238 * we need to exchange ACL entries as well
2240 /* exchange_acls(vol, p, upath); */
2245 path->m_name = NULL;
2246 path->u_name = upath;
2248 setfilunixmode(vol, path, destst.st_mode);
2249 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2256 setfilunixmode(vol, path, srcst.st_mode);
2257 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2259 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2260 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2265 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2269 goto err_exchangefile;
2271 /* all this stuff is so that we can unwind a failed operation
2274 /* rename dest to temp */
2275 renamefile(vol, upath, temp, temp, adsp);
2276 of_rename(vol, s_of, curdir, upath, curdir, temp);
2279 /* rename source back to dest */
2280 renamefile(vol, p, upath, path->m_name, addp);
2281 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2284 /* rename temp back to source */
2285 renamefile(vol, temp, p, spath, adsp);
2286 of_rename(vol, s_of, curdir, temp, sdir, spath);
2289 if ( !s_of && adsp && ad_meta_fileno(adsp) != -1 ) { /* META */
2290 ad_close(adsp, ADFLAGS_HF);
2292 if ( !d_of && addp && ad_meta_fileno(addp) != -1 ) {/* META */
2293 ad_close(addp, ADFLAGS_HF);