2 * $Id: file.c,v 1.136 2010-02-17 01:19:51 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 */
33 #include <sys/param.h>
35 #include <atalk/adouble.h>
36 #include <atalk/vfs.h>
37 #include <atalk/logger.h>
38 #include <atalk/afp.h>
39 #include <atalk/util.h>
40 #include <atalk/cnid.h>
41 #include <atalk/unix.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 struct vol *vol, const char *upath, struct adouble *adp, void *data, int islink)
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 (vol_inv_dots(vol) && *upath == '.') { /* make it invisible */
113 ashort = htons(FINDERINFO_INVISIBLE);
114 memcpy((char *)data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
120 memcpy(&linkflag, (char *)data + FINDERINFO_FRFLAGOFF, 2);
121 linkflag |= htons(FINDERINFO_ISALIAS);
122 memcpy((char *)data + FINDERINFO_FRFLAGOFF, &linkflag, 2);
123 memcpy((char *)data + FINDERINFO_FRTYPEOFF,"slnk",4);
124 memcpy((char *)data + FINDERINFO_FRCREATOFF,"rhap",4);
128 /** Only enter if no appledouble information and no finder information found. */
129 if (chk_ext && (em = getextmap( upath ))) {
130 memcpy(data, em->em_type, sizeof( em->em_type ));
131 memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator));
136 /* ---------------------
138 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8)
143 aint = strlen( name );
147 if (utf8_encoding()) {
148 /* but name is an utf8 mac name */
151 /* global static variable... */
153 if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
162 if (aint > MACFILELEN)
169 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
172 utf8 = vol->v_kTextEncoding;
173 memcpy(data, &utf8, sizeof(utf8));
174 data += sizeof(utf8);
177 memcpy(data, &temp, sizeof(temp));
178 data += sizeof(temp);
181 memcpy( data, src, aint );
191 * FIXME: PDINFO is UTF8 and doesn't need adp
193 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
194 (1 << FILPBIT_CDATE) |\
195 (1 << FILPBIT_MDATE) |\
196 (1 << FILPBIT_BDATE) |\
197 (1 << FILPBIT_FINFO) |\
198 (1 << FILPBIT_RFLEN) |\
199 (1 << FILPBIT_EXTRFLEN) |\
200 (1 << FILPBIT_PDINFO) |\
201 (1 << FILPBIT_FNUM) |\
202 (1 << FILPBIT_UNIXPR)))
204 /* -------------------------- */
205 u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st,
206 const cnid_t did, char *upath, const int len)
209 u_int32_t dbcnid = CNID_INVALID;
211 if (vol->v_cdb != NULL) {
212 /* prime aint with what we think is the cnid, set did to zero for
213 catching moved files */
214 adcnid = ad_getid(adp, st->st_dev, st->st_ino, 0, vol->v_stamp);
216 dbcnid = cnid_add(vol->v_cdb, st, did, upath, len, adcnid);
217 /* Throw errors if cnid_add fails. */
218 if (dbcnid == CNID_INVALID) {
220 case CNID_ERR_CLOSE: /* the db is closed */
223 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
224 afp_errno = AFPERR_PARAM;
227 afp_errno = AFPERR_PARAM;
230 afp_errno = AFPERR_MISC;
234 else if (adp && (adcnid != dbcnid)) {
235 /* Update the ressource fork. For a folder adp is always null */
236 LOG(log_debug, logtype_afpd, "get_id: calling ad_setid. adcnid: %u, dbcnid: %u", htonl(adcnid), htonl(dbcnid));
237 if (ad_setid(adp, st->st_dev, st->st_ino, dbcnid, did, vol->v_stamp)) {
245 /* -------------------------- */
246 int getmetadata(struct vol *vol,
248 struct path *path, struct dir *dir,
249 char *buf, size_t *buflen, struct adouble *adp)
251 char *data, *l_nameoff = NULL, *upath;
252 char *utf_nameoff = NULL;
257 u_char achar, fdType[4];
263 LOG(log_debug9, logtype_afpd, "begin getmetadata:");
266 upath = path->u_name;
271 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
272 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
273 || (bitmap & (1 << FILPBIT_FNUM))) {
275 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
278 if (id == CNID_INVALID)
281 path->m_name = utompath(vol, upath, id, utf8_encoding());
284 while ( bitmap != 0 ) {
285 while (( bitmap & 1 ) == 0 ) {
293 ad_getattr(adp, &ashort);
294 } else if (vol_inv_dots(vol) && *upath == '.') {
295 ashort = htons(ATTRBIT_INVISIBLE);
299 /* FIXME do we want a visual clue if the file is read only
302 accessmode( ".", &ma, dir , NULL);
303 if ((ma.ma_user & AR_UWRITE)) {
304 accessmode( upath, &ma, dir , st);
305 if (!(ma.ma_user & AR_UWRITE)) {
306 ashort |= htons(ATTRBIT_NOWRITE);
310 memcpy(data, &ashort, sizeof( ashort ));
311 data += sizeof( ashort );
315 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
316 data += sizeof( u_int32_t );
320 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
321 aint = AD_DATE_FROM_UNIX(st->st_mtime);
322 memcpy(data, &aint, sizeof( aint ));
323 data += sizeof( aint );
327 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
328 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
329 aint = AD_DATE_FROM_UNIX(st->st_mtime);
332 aint = AD_DATE_FROM_UNIX(st->st_mtime);
334 memcpy(data, &aint, sizeof( int ));
335 data += sizeof( int );
339 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
340 aint = AD_DATE_START;
341 memcpy(data, &aint, sizeof( int ));
342 data += sizeof( int );
346 get_finderinfo(vol, upath, adp, (char *)data,S_ISLNK(st->st_mode));
347 data += ADEDLEN_FINDERI;
352 data += sizeof( u_int16_t );
356 memset(data, 0, sizeof(u_int16_t));
357 data += sizeof( u_int16_t );
361 memcpy(data, &id, sizeof( id ));
362 data += sizeof( id );
366 if (st->st_size > 0xffffffff)
369 aint = htonl( st->st_size );
370 memcpy(data, &aint, sizeof( aint ));
371 data += sizeof( aint );
376 if (adp->ad_rlen > 0xffffffff)
379 aint = htonl( adp->ad_rlen);
383 memcpy(data, &aint, sizeof( aint ));
384 data += sizeof( aint );
387 /* Current client needs ProDOS info block for this file.
388 Use simple heuristic and let the Mac "type" string tell
389 us what the PD file code should be. Everything gets a
390 subtype of 0x0000 unless the original value was hashed
391 to "pXYZ" when we created it. See IA, Ver 2.
392 <shirsch@adelphia.net> */
393 case FILPBIT_PDINFO :
394 if (afp_version >= 30) { /* UTF8 name */
395 utf8 = kTextEncodingUTF8;
397 data += sizeof( u_int16_t );
399 memcpy(data, &aint, sizeof( aint ));
400 data += sizeof( aint );
404 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
406 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
410 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
414 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
418 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
422 else if ( fdType[0] == 'p' ) {
424 ashort = (fdType[2] * 256) + fdType[3];
438 memcpy(data, &ashort, sizeof( ashort ));
439 data += sizeof( ashort );
440 memset(data, 0, sizeof( ashort ));
441 data += sizeof( ashort );
444 case FILPBIT_EXTDFLEN:
445 aint = htonl(st->st_size >> 32);
446 memcpy(data, &aint, sizeof( aint ));
447 data += sizeof( aint );
448 aint = htonl(st->st_size);
449 memcpy(data, &aint, sizeof( aint ));
450 data += sizeof( aint );
452 case FILPBIT_EXTRFLEN:
455 aint = htonl(adp->ad_rlen >> 32);
456 memcpy(data, &aint, sizeof( aint ));
457 data += sizeof( aint );
459 aint = htonl(adp->ad_rlen);
460 memcpy(data, &aint, sizeof( aint ));
461 data += sizeof( aint );
463 case FILPBIT_UNIXPR :
464 /* accessmode may change st_mode with ACLs */
465 accessmode( upath, &ma, dir , st);
467 aint = htonl(st->st_uid);
468 memcpy( data, &aint, sizeof( aint ));
469 data += sizeof( aint );
470 aint = htonl(st->st_gid);
471 memcpy( data, &aint, sizeof( aint ));
472 data += sizeof( aint );
475 type == slnk indicates an OSX style symlink,
476 we have to add S_IFLNK to the mode, otherwise
477 10.3 clients freak out. */
481 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
482 if ( memcmp( fdType, "slnk", 4 ) == 0 ) {
488 memcpy( data, &aint, sizeof( aint ));
489 data += sizeof( aint );
491 *data++ = ma.ma_user;
492 *data++ = ma.ma_world;
493 *data++ = ma.ma_group;
494 *data++ = ma.ma_owner;
498 return( AFPERR_BITMAP );
504 ashort = htons( data - buf );
505 memcpy(l_nameoff, &ashort, sizeof( ashort ));
506 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
509 ashort = htons( data - buf );
510 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
511 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
513 *buflen = data - buf;
517 /* ----------------------- */
518 int getfilparams(struct vol *vol,
520 struct path *path, struct dir *dir,
521 char *buf, size_t *buflen )
523 struct adouble ad, *adp;
528 LOG(log_debug9, logtype_default, "begin getfilparams:");
531 opened = PARAM_NEED_ADP(bitmap);
536 int flags = (bitmap & (1 << FILPBIT_ATTR))?ADFLAGS_OPENFORKS:0;
538 adp = of_ad(vol, path, &ad);
539 upath = path->u_name;
541 if ( ad_metadata( upath, flags|ADFLAGS_CREATE, adp) < 0 ) {
544 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
545 upath, strerror(errno));
546 return AFPERR_ACCESS;
548 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
557 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp);
559 ad_close_metadata( adp);
562 LOG(log_debug9, logtype_afpd, "end getfilparams:");
568 /* ----------------------------- */
569 int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
571 struct adouble ad, *adp;
574 struct ofork *of = NULL;
576 int creatf, did, openf, retvalue = AFP_OK;
582 creatf = (unsigned char) *ibuf++;
584 memcpy(&vid, ibuf, sizeof( vid ));
585 ibuf += sizeof( vid );
587 if (NULL == ( vol = getvolbyvid( vid )) ) {
588 return( AFPERR_PARAM );
591 if (vol->v_flags & AFPVOL_RO)
594 memcpy(&did, ibuf, sizeof( did));
595 ibuf += sizeof( did );
597 if (NULL == ( dir = dirlookup( vol, did )) ) {
601 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
602 return get_afp_errno(AFPERR_PARAM);
605 if ( *s_path->m_name == '\0' ) {
606 return( AFPERR_BADTYPE );
609 upath = s_path->u_name;
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, ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF|ADFLAGS_CREATE,
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 );
646 return( AFPERR_DFULL );
648 return( AFPERR_PARAM );
651 if ( ad_reso_fileno( adp ) == -1 ) { /* Hard META / HF */
652 /* on noadouble volumes, just creating the data fork is ok */
653 if (vol_noadouble(vol)) {
654 ad_close( adp, ADFLAGS_DF );
655 goto createfile_done;
657 /* FIXME with hard create on an existing file, we already
658 * corrupted the data file.
660 netatalk_unlink( upath );
661 ad_close( adp, ADFLAGS_DF );
662 return AFPERR_ACCESS;
665 path = s_path->m_name;
666 ad_setname(adp, path);
668 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
674 if (vol->v_flags & AFPVOL_DROPBOX) {
675 retvalue = matchfile2dirperms(upath, vol, did);
677 #endif /* DROPKLUDGE */
679 setvoltime(obj, vol );
684 int afp_setfilparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
690 u_int16_t vid, bitmap;
695 memcpy(&vid, ibuf, sizeof( vid ));
696 ibuf += sizeof( vid );
697 if (NULL == ( vol = getvolbyvid( vid )) ) {
698 return( AFPERR_PARAM );
701 if (vol->v_flags & AFPVOL_RO)
704 memcpy(&did, ibuf, sizeof( did ));
705 ibuf += sizeof( did );
706 if (NULL == ( dir = dirlookup( vol, did )) ) {
707 return afp_errno; /* was AFPERR_NOOBJ */
710 memcpy(&bitmap, ibuf, sizeof( bitmap ));
711 bitmap = ntohs( bitmap );
712 ibuf += sizeof( bitmap );
714 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
715 return get_afp_errno(AFPERR_PARAM);
718 if (path_isadir(s_path)) {
719 return( AFPERR_BADTYPE ); /* it's a directory */
722 if ( s_path->st_errno != 0 ) {
723 return( AFPERR_NOOBJ );
726 if ((u_long)ibuf & 1 ) {
730 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
731 setvoltime(obj, vol );
738 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
741 extern struct path Cur_Path;
743 int setfilparams(struct vol *vol,
744 struct path *path, u_int16_t f_bitmap, char *buf )
746 struct adouble ad, *adp;
748 int bit, isad = 1, err = AFP_OK;
750 u_char achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
751 u_int16_t ashort, bshort, oshort;
754 u_int16_t upriv_bit = 0;
758 int change_mdate = 0;
759 int change_parent_mdate = 0;
764 u_int16_t bitmap = f_bitmap;
765 u_int32_t cdate,bdate;
766 u_char finder_buf[32];
769 LOG(log_debug9, logtype_afpd, "begin setfilparams:");
772 adp = of_ad(vol, path, &ad);
773 upath = path->u_name;
775 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
776 return AFPERR_ACCESS;
779 /* with unix priv maybe we have to change adouble file priv first */
781 while ( bitmap != 0 ) {
782 while (( bitmap & 1 ) == 0 ) {
789 memcpy(&ashort, buf, sizeof( ashort ));
790 buf += sizeof( ashort );
794 memcpy(&cdate, buf, sizeof(cdate));
795 buf += sizeof( cdate );
798 memcpy(&newdate, buf, sizeof( newdate ));
799 buf += sizeof( newdate );
803 memcpy(&bdate, buf, sizeof( bdate));
804 buf += sizeof( bdate );
808 memcpy(finder_buf, buf, 32 );
809 if (memcmp(buf,"slnkrhap",8)==0 && !S_ISLNK(path->st.st_mode)){
814 char buf[PATH_MAX+1];
815 if ((fp=open(path->u_name,O_RDONLY))>=0){
816 if ((len=read(fp,buf,PATH_MAX+1))){
817 if (unlink(path->u_name)==0){
819 erc=symlink(buf,path->u_name);
820 lstat(path->u_name,&(path->st));
827 goto setfilparam_done;
832 case FILPBIT_UNIXPR :
833 if (!vol_unix_priv(vol)) {
834 /* this volume doesn't use unix priv */
840 change_parent_mdate = 1;
842 memcpy( &aint, buf, sizeof( aint ));
843 f_uid = ntohl (aint);
844 buf += sizeof( aint );
845 memcpy( &aint, buf, sizeof( aint ));
846 f_gid = ntohl (aint);
847 buf += sizeof( aint );
848 setfilowner(vol, f_uid, f_gid, path);
850 memcpy( &upriv, buf, sizeof( upriv ));
851 buf += sizeof( upriv );
852 upriv = ntohl (upriv);
853 if ((upriv & S_IWUSR)) {
854 setfilunixmode(vol, path, upriv);
861 case FILPBIT_PDINFO :
862 if (afp_version < 30) { /* else it's UTF8 name */
865 /* Keep special case to support crlf translations */
866 if ((unsigned int) achar == 0x04) {
867 fdType = (u_char *)"TEXT";
870 xyy[0] = ( u_char ) 'p';
881 /* break while loop */
890 /* second try with adouble open
892 if ( ad_open_metadata( upath, 0, O_CREAT, adp) < 0) {
893 LOG(log_debug, logtype_afpd, "setfilparams: ad_open_metadata error");
895 * For some things, we don't need an adouble header:
896 * - change of modification date
897 * - UNIX privs (Bug-ID #2863424)
899 if (!vol_noadouble(vol) && (f_bitmap & ~(1<<FILPBIT_MDATE | 1<<FILPBIT_UNIXPR))) {
900 LOG(log_debug, logtype_afpd, "setfilparams: need adouble access");
901 return AFPERR_ACCESS;
903 LOG(log_debug, logtype_afpd, "setfilparams: no adouble perms, but only FILPBIT_MDATE and/or FILPBIT_UNIXPR");
905 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
906 ad_setname(adp, path->m_name);
911 while ( bitmap != 0 ) {
912 while (( bitmap & 1 ) == 0 ) {
919 ad_getattr(adp, &bshort);
921 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
922 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
926 if ((bshort & htons(ATTRBIT_INVISIBLE)) != (oshort & htons(ATTRBIT_INVISIBLE)))
927 change_parent_mdate = 1;
928 ad_setattr(adp, bshort);
931 ad_setdate(adp, AD_DATE_CREATE, cdate);
936 ad_setdate(adp, AD_DATE_BACKUP, bdate);
939 if (default_type( ad_entry( adp, ADEID_FINDERI ))
941 ((em = getextmap( path->m_name )) &&
942 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
943 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
944 || ((em = getdefextmap()) &&
945 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
946 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
948 memcpy(finder_buf, ufinderi, 8 );
950 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
952 case FILPBIT_UNIXPR :
954 setfilunixmode(vol, path, upriv);
957 case FILPBIT_PDINFO :
958 if (afp_version < 30) { /* else it's UTF8 name */
959 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
960 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
966 goto setfilparam_done;
973 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
974 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
978 ad_setdate(adp, AD_DATE_MODIFY, newdate);
979 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
985 ad_close_metadata( adp);
989 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
990 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
991 bitmap = 1<<FILPBIT_MDATE;
992 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
996 LOG(log_debug9, logtype_afpd, "end setfilparams:");
1002 * renamefile and copyfile take the old and new unix pathnames
1003 * and the new mac name.
1005 * src the source path
1006 * dst the dest filename in current dir
1007 * newname the dest mac name
1008 * adp adouble struct of src file, if open, or & zeroed one
1011 int renamefile(const struct vol *vol, char *src, char *dst, char *newname, struct adouble *adp)
1016 LOG(log_debug9, logtype_afpd, "begin renamefile:");
1019 if ( unix_rename( src, dst ) < 0 ) {
1022 return( AFPERR_NOOBJ );
1025 return( AFPERR_ACCESS );
1027 return AFPERR_VLOCK;
1028 case EXDEV : /* Cross device move -- try copy */
1029 /* NOTE: with open file it's an error because after the copy we will
1030 * get two files, it's fixable for our process (eg reopen the new file, get the
1031 * locks, and so on. But it doesn't solve the case with a second process
1033 if (adp->ad_open_forks) {
1034 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1035 return AFPERR_OLOCK; /* little lie */
1037 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1038 /* on error copyfile delete dest */
1041 return deletefile(vol, src, 0);
1043 return( AFPERR_PARAM );
1047 if (vol->vfs->vfs_renamefile(vol, src, dst) < 0 ) {
1051 /* try to undo the data fork rename,
1052 * we know we are on the same device
1055 unix_rename( dst, src );
1056 /* return the first error */
1059 return AFPERR_NOOBJ;
1062 return AFPERR_ACCESS ;
1064 return AFPERR_VLOCK;
1066 return AFPERR_PARAM ;
1071 /* don't care if we can't open the newly renamed ressource fork
1073 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1074 ad_setname(adp, newname);
1076 ad_close( adp, ADFLAGS_HF );
1079 LOG(log_debug9, logtype_afpd, "end renamefile:");
1086 convert a Mac long name to an utf8 name,
1088 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1092 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1098 /* ---------------- */
1099 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1106 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1112 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1113 if (afp_version >= 30) {
1114 /* convert it to UTF8
1116 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1)
1120 strncpy( newname, ibuf, plen );
1121 newname[ plen ] = '\0';
1123 if (strlen(newname) != plen) {
1124 /* there's \0 in newname, e.g. it's a pathname not
1132 memcpy(&hint, ibuf, sizeof(hint));
1133 ibuf += sizeof(hint);
1135 memcpy(&len16, ibuf, sizeof(len16));
1136 ibuf += sizeof(len16);
1137 plen = ntohs(len16);
1140 if (plen > AFPOBJ_TMPSIZ) {
1143 strncpy( newname, ibuf, plen );
1144 newname[ plen ] = '\0';
1145 if (strlen(newname) != plen) {
1154 /* -----------------------------------
1156 int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1158 struct vol *s_vol, *d_vol;
1160 char *newname, *p, *upath;
1161 struct path *s_path;
1162 u_int32_t sdid, ddid;
1163 int err, retvalue = AFP_OK;
1164 u_int16_t svid, dvid;
1166 struct adouble ad, *adp;
1172 memcpy(&svid, ibuf, sizeof( svid ));
1173 ibuf += sizeof( svid );
1174 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1175 return( AFPERR_PARAM );
1178 memcpy(&sdid, ibuf, sizeof( sdid ));
1179 ibuf += sizeof( sdid );
1180 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1184 memcpy(&dvid, ibuf, sizeof( dvid ));
1185 ibuf += sizeof( dvid );
1186 memcpy(&ddid, ibuf, sizeof( ddid ));
1187 ibuf += sizeof( ddid );
1189 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1190 return get_afp_errno(AFPERR_PARAM);
1192 if ( path_isadir(s_path) ) {
1193 return( AFPERR_BADTYPE );
1196 /* don't allow copies when the file is open.
1197 * XXX: the spec only calls for read/deny write access.
1198 * however, copyfile doesn't have any of that info,
1199 * and locks need to stay coherent. as a result,
1200 * we just balk if the file is opened already. */
1202 adp = of_ad(s_vol, s_path, &ad);
1204 if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1205 return AFPERR_DENYCONF;
1207 denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
1208 getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1209 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1211 return AFPERR_DENYCONF;
1214 newname = obj->newtmp;
1215 strcpy( newname, s_path->m_name );
1217 p = ctoupath( s_vol, curdir, newname );
1219 return AFPERR_PARAM;
1223 /* FIXME svid != dvid && dvid's user can't read svid */
1225 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1226 return( AFPERR_PARAM );
1229 if (d_vol->v_flags & AFPVOL_RO)
1230 return AFPERR_VLOCK;
1232 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1236 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1237 return get_afp_errno(AFPERR_NOOBJ);
1239 if ( *s_path->m_name != '\0' ) {
1240 path_error(s_path, AFPERR_PARAM);
1243 /* one of the handful of places that knows about the path type */
1244 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1245 return( AFPERR_PARAM );
1247 /* newname is always only a filename so curdir *is* its
1250 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1251 return( AFPERR_PARAM );
1253 if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1259 if (vol->v_flags & AFPVOL_DROPBOX) {
1260 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1262 #endif /* DROPKLUDGE */
1264 setvoltime(obj, d_vol );
1269 /* ----------------------- */
1270 static int copy_all(const int dfd, const void *buf,
1276 LOG(log_debug9, logtype_afpd, "begin copy_all:");
1279 while (buflen > 0) {
1280 if ((cc = write(dfd, buf, buflen)) < 0) {
1292 LOG(log_debug9, logtype_afpd, "end copy_all:");
1298 /* --------------------------
1299 * copy only the fork data stream
1301 static int copy_fork(int eid, struct adouble *add, struct adouble *ads)
1308 if (eid == ADEID_DFORK) {
1309 sfd = ad_data_fileno(ads);
1310 dfd = ad_data_fileno(add);
1313 sfd = ad_reso_fileno(ads);
1314 dfd = ad_reso_fileno(add);
1317 if ((off_t)-1 == lseek(sfd, ad_getentryoff(ads, eid), SEEK_SET))
1320 if ((off_t)-1 == lseek(dfd, ad_getentryoff(add, eid), SEEK_SET))
1323 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1324 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1328 #define BUF 128*1024*1024
1330 if (fstat(sfd, &st) == 0) {
1333 if ( offset >= st.st_size) {
1336 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1337 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1340 case EINVAL: /* there's no guarantee that all fs support sendfile */
1349 lseek(sfd, offset, SEEK_SET);
1353 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1360 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1367 /* ----------------------------------
1368 * if newname is NULL (from directory.c) we don't want to copy the resource fork.
1369 * because we are doing it elsewhere.
1370 * currently if newname is NULL then adp is NULL.
1372 int copyfile(const struct vol *s_vol, const struct vol*d_vol,
1373 char *src, char *dst, char *newname, struct adouble *adp)
1375 struct adouble ads, add;
1383 LOG(log_debug9, logtype_afpd, "begin copyfile:");
1387 ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options);
1390 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1391 adflags = ADFLAGS_DF;
1393 adflags |= ADFLAGS_HF;
1396 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1401 if (ad_meta_fileno(adp) == -1 && ad_reso_fileno(adp) == -1) { /* META / HF */
1402 /* no resource fork, don't create one for dst file */
1403 adflags &= ~ADFLAGS_HF;
1406 stat_result = fstat(ad_data_fileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */
1408 if (stat_result < 0) {
1409 /* unlikely but if fstat fails, the default file mode will be 0666. */
1410 st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
1413 if (ad_open(dst , adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
1415 ad_close( adp, adflags );
1416 if (EEXIST != ret_err) {
1417 deletefile(d_vol, dst, 0);
1420 return AFPERR_EXIST;
1424 * XXX if the source and the dest don't use the same resource type it's broken
1426 if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){
1427 /* copy the data fork */
1428 if ((err = copy_fork(ADEID_DFORK, &add, adp)) == 0) {
1429 err = d_vol->vfs->vfs_copyfile(d_vol, src, dst);
1437 if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
1438 /* set the new name in the resource fork */
1439 ad_copy_header(&add, adp);
1440 ad_setname(&add, newname);
1443 ad_close( adp, adflags );
1445 if (ad_close( &add, adflags ) <0) {
1450 deletefile(d_vol, dst, 0);
1452 else if (stat_result == 0) {
1453 /* set dest modification date to src date */
1456 ut.actime = ut.modtime = st.st_mtime;
1458 /* FIXME netatalk doesn't use resource fork file date
1459 * but maybe we should set its modtime too.
1464 LOG(log_debug9, logtype_afpd, "end copyfile:");
1468 switch ( ret_err ) {
1474 return AFPERR_DFULL;
1476 return AFPERR_NOOBJ;
1478 return AFPERR_ACCESS;
1480 return AFPERR_VLOCK;
1482 return AFPERR_PARAM;
1486 /* -----------------------------------
1487 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1488 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1490 when deletefile is called we don't have lock on it, file is closed (for us)
1491 untrue if called by renamefile
1493 ad_open always try to open file RDWR first and ad_lock takes care of
1494 WRITE lock on read only file.
1497 static int check_attrib(struct adouble *adp)
1499 u_int16_t bshort = 0;
1501 ad_getattr(adp, &bshort);
1503 * Does kFPDeleteInhibitBit (bit 8) set?
1505 if ((bshort & htons(ATTRBIT_NODELETE))) {
1506 return AFPERR_OLOCK;
1508 if ((bshort & htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN))) {
1514 int deletefile(const struct vol *vol, char *file, int checkAttrib)
1517 struct adouble *adp = &ad;
1518 int adflags, err = AFP_OK;
1521 LOG(log_debug9, logtype_afpd, "begin deletefile:");
1524 /* try to open both forks at once */
1525 adflags = ADFLAGS_DF|ADFLAGS_HF;
1527 /* was EACCESS error try to get only metadata */
1528 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1529 /* we never want to create a resource fork here, we are going to delete it
1530 * moreover sometimes deletefile is called with a no existent file and
1531 * ad_open would create a 0 byte resource fork
1533 if ( ad_metadata( file, ADFLAGS_OPENFORKS, &ad) == 0 ) {
1534 ad_close( &ad, adflags );
1535 if ((err = check_attrib(&ad))) {
1542 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1543 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1546 if (adflags == ADFLAGS_DF)
1547 return AFPERR_NOOBJ;
1549 /* that failed. now try to open just the data fork */
1550 adflags = ADFLAGS_DF;
1554 adp = NULL; /* maybe it's a file with no write mode for us */
1555 break; /* was return AFPERR_ACCESS;*/
1557 return AFPERR_VLOCK;
1559 return( AFPERR_PARAM );
1562 break; /* from the while */
1565 if (adp && (adflags & ADFLAGS_HF) ) {
1566 /* FIXME we have a pb here because we want to know if a file is open
1567 * there's a 'priority inversion' if you can't open the ressource fork RW
1568 * you can delete it if it's open because you can't get a write lock.
1570 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1573 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1575 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1576 ad_close( &ad, adflags );
1577 return( AFPERR_BUSY );
1581 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1584 else if (!(err = vol->vfs->vfs_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
1586 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1588 cnid_delete(vol->v_cdb, id);
1592 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1595 LOG(log_debug9, logtype_afpd, "end deletefile:");
1601 /* ------------------------------------ */
1602 /* return a file id */
1603 int afp_createid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1612 struct path *s_path;
1618 memcpy(&vid, ibuf, sizeof(vid));
1619 ibuf += sizeof(vid);
1621 if (NULL == ( vol = getvolbyvid( vid )) ) {
1622 return( AFPERR_PARAM);
1625 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1629 if (vol->v_flags & AFPVOL_RO)
1630 return AFPERR_VLOCK;
1632 memcpy(&did, ibuf, sizeof( did ));
1633 ibuf += sizeof(did);
1635 if (NULL == ( dir = dirlookup( vol, did )) ) {
1636 return afp_errno; /* was AFPERR_PARAM */
1639 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1640 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1643 if ( path_isadir(s_path) ) {
1644 return( AFPERR_BADTYPE );
1647 upath = s_path->u_name;
1648 switch (s_path->st_errno) {
1650 break; /* success */
1653 return AFPERR_ACCESS;
1655 return AFPERR_NOOBJ;
1657 return AFPERR_PARAM;
1660 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1661 memcpy(rbuf, &id, sizeof(id));
1662 *rbuflen = sizeof(id);
1663 return AFPERR_EXISTID;
1666 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1667 memcpy(rbuf, &id, sizeof(id));
1668 *rbuflen = sizeof(id);
1675 /* ------------------------------- */
1681 static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
1684 struct reenum *param = data;
1685 struct vol *vol = param->vol;
1686 cnid_t did = param->did;
1689 if ( lstat(de->d_name, &path.st)<0 )
1692 /* update or add to cnid */
1693 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1695 #if AD_VERSION > AD_VERSION1
1696 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1697 struct adouble ad, *adp;
1701 path.u_name = de->d_name;
1703 adp = of_ad(vol, &path, &ad);
1705 if ( ad_open_metadata( de->d_name, 0, 0, adp ) < 0 ) {
1708 if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1711 ad_close_metadata(adp);
1713 #endif /* AD_VERSION > AD_VERSION1 */
1718 /* --------------------
1719 * Ok the db is out of synch with the dir.
1720 * but if it's a deleted file we don't want to do it again and again.
1723 reenumerate_id(struct vol *vol, char *name, struct dir *dir)
1729 if (vol->v_cdb == NULL) {
1733 /* FIXME use of_statdir ? */
1734 if (lstat(name, &st)) {
1738 if (dirreenumerate(dir, &st)) {
1739 /* we already did it once and the dir haven't been modified */
1744 data.did = dir->d_did;
1745 if ((ret = for_each_dirent(vol, name, reenumerate_loop, (void *)&data)) >= 0) {
1746 setdiroffcnt(curdir, &st, ret);
1747 dir->d_flags |= DIRF_CNID;
1753 /* ------------------------------
1754 resolve a file id */
1755 int afp_resolveid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1764 u_int16_t vid, bitmap;
1766 static char buffer[12 + MAXPATHLEN + 1];
1767 int len = 12 + MAXPATHLEN + 1;
1772 memcpy(&vid, ibuf, sizeof(vid));
1773 ibuf += sizeof(vid);
1775 if (NULL == ( vol = getvolbyvid( vid )) ) {
1776 return( AFPERR_PARAM);
1779 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1783 memcpy(&id, ibuf, sizeof( id ));
1788 /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
1792 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1793 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1796 if (NULL == ( dir = dirlookup( vol, id )) ) {
1797 return AFPERR_NOID; /* idem AFPERR_PARAM */
1799 if (movecwd(vol, dir) < 0) {
1803 return AFPERR_ACCESS;
1807 return AFPERR_PARAM;
1811 memset(&path, 0, sizeof(path));
1812 path.u_name = upath;
1813 if ( of_stat(&path) < 0 ) {
1815 /* with nfs and our working directory is deleted */
1816 if (errno == ESTALE) {
1820 if ( errno == ENOENT && !retry) {
1821 /* cnid db is out of sync, reenumerate the directory and update ids */
1822 reenumerate_id(vol, ".", dir);
1830 return AFPERR_ACCESS;
1834 return AFPERR_PARAM;
1838 /* directories are bad */
1839 if (S_ISDIR(path.st.st_mode)) {
1840 /* OS9 and OSX don't return the same error code */
1841 return (afp_version >=30)?AFPERR_NOID:AFPERR_BADTYPE;
1844 memcpy(&bitmap, ibuf, sizeof(bitmap));
1845 bitmap = ntohs( bitmap );
1846 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1850 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1851 rbuf + sizeof(bitmap), &buflen))) {
1854 *rbuflen = buflen + sizeof(bitmap);
1855 memcpy(rbuf, ibuf, sizeof(bitmap));
1860 /* ------------------------------ */
1861 int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1871 static char buffer[12 + MAXPATHLEN + 1];
1872 int len = 12 + MAXPATHLEN + 1;
1877 memcpy(&vid, ibuf, sizeof(vid));
1878 ibuf += sizeof(vid);
1880 if (NULL == ( vol = getvolbyvid( vid )) ) {
1881 return( AFPERR_PARAM);
1884 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1888 if (vol->v_flags & AFPVOL_RO)
1889 return AFPERR_VLOCK;
1891 memcpy(&id, ibuf, sizeof( id ));
1895 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1899 if (NULL == ( dir = dirlookup( vol, id )) ) {
1900 return( AFPERR_PARAM );
1904 if ((movecwd(vol, dir) < 0) || (lstat(upath, &st) < 0)) {
1908 return AFPERR_ACCESS;
1913 /* still try to delete the id */
1917 return AFPERR_PARAM;
1920 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1921 return AFPERR_BADTYPE;
1923 if (cnid_delete(vol->v_cdb, fileid)) {
1926 return AFPERR_VLOCK;
1929 return AFPERR_ACCESS;
1931 return AFPERR_PARAM;
1938 /* ------------------------------ */
1939 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1943 if (path->st_errno) {
1944 switch (path->st_errno) {
1946 afp_errno = AFPERR_NOID;
1950 afp_errno = AFPERR_ACCESS;
1953 afp_errno = AFPERR_PARAM;
1958 /* we use file_access both for legacy Mac perm and
1959 * for unix privilege, rename will take care of folder perms
1961 if (file_access(path, OPENACC_WR ) < 0) {
1962 afp_errno = AFPERR_ACCESS;
1966 if ((*of = of_findname(path))) {
1967 /* reuse struct adouble so it won't break locks */
1971 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
1973 if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
1975 * The user must have the Read & Write privilege for both files in order to use this command.
1977 ad_close(adp, ADFLAGS_HF);
1978 afp_errno = AFPERR_ACCESS;
1985 #define APPLETEMP ".AppleTempXXXXXX"
1987 int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1989 struct stat srcst, destst;
1991 struct dir *dir, *sdir;
1992 char *spath, temp[17], *p;
1993 char *supath, *upath;
1998 struct adouble *adsp = NULL;
1999 struct adouble *addp = NULL;
2000 struct ofork *s_of = NULL;
2001 struct ofork *d_of = NULL;
2014 memcpy(&vid, ibuf, sizeof(vid));
2015 ibuf += sizeof(vid);
2017 if (NULL == ( vol = getvolbyvid( vid )) ) {
2018 return( AFPERR_PARAM);
2021 if ((vol->v_flags & AFPVOL_RO))
2022 return AFPERR_VLOCK;
2024 /* source and destination dids */
2025 memcpy(&sid, ibuf, sizeof(sid));
2026 ibuf += sizeof(sid);
2027 memcpy(&did, ibuf, sizeof(did));
2028 ibuf += sizeof(did);
2031 if (NULL == (dir = dirlookup( vol, sid )) ) {
2032 return afp_errno; /* was AFPERR_PARAM */
2035 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2036 return get_afp_errno(AFPERR_NOOBJ);
2039 if ( path_isadir(path) ) {
2040 return AFPERR_BADTYPE; /* it's a dir */
2043 /* save some stuff */
2046 spath = obj->oldtmp;
2047 supath = obj->newtmp;
2048 strcpy(spath, path->m_name);
2049 strcpy(supath, path->u_name); /* this is for the cnid changing */
2050 p = absupath( vol, sdir, supath);
2052 /* pathname too long */
2053 return AFPERR_PARAM ;
2056 ad_init(&ads, vol->v_adouble, vol->v_ad_options);
2057 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2061 /* ***** from here we may have resource fork open **** */
2063 /* look for the source cnid. if it doesn't exist, don't worry about
2065 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2067 if (NULL == ( dir = dirlookup( vol, did )) ) {
2068 err = afp_errno; /* was AFPERR_PARAM */
2069 goto err_exchangefile;
2072 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2073 err = get_afp_errno(AFPERR_NOOBJ);
2074 goto err_exchangefile;
2077 if ( path_isadir(path) ) {
2078 err = AFPERR_BADTYPE;
2079 goto err_exchangefile;
2082 /* FPExchangeFiles is the only call that can return the SameObj
2084 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2085 err = AFPERR_SAMEOBJ;
2086 goto err_exchangefile;
2089 ad_init(&add, vol->v_adouble, vol->v_ad_options);
2090 if (!(addp = find_adouble( path, &d_of, &add))) {
2092 goto err_exchangefile;
2096 /* they are not on the same device and at least one is open
2097 * FIXME broken for for crossdev and adouble v2
2100 crossdev = (srcst.st_dev != destst.st_dev);
2101 if (/* (d_of || s_of) && */ crossdev) {
2103 goto err_exchangefile;
2106 /* look for destination id. */
2107 upath = path->u_name;
2108 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2110 /* construct a temp name.
2111 * NOTE: the temp file will be in the dest file's directory. it
2112 * will also be inaccessible from AFP. */
2113 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2114 if (!mktemp(temp)) {
2116 goto err_exchangefile;
2120 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2121 ad_close(adsp, ADFLAGS_HF);
2122 ad_close(addp, ADFLAGS_HF);
2125 /* now, quickly rename the file. we error if we can't. */
2126 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2127 goto err_exchangefile;
2128 of_rename(vol, s_of, sdir, spath, curdir, temp);
2130 /* rename destination to source */
2131 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2132 goto err_src_to_tmp;
2133 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2135 /* rename temp to destination */
2136 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2137 goto err_dest_to_src;
2138 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2140 /* id's need switching. src -> dest and dest -> src.
2141 * we need to re-stat() if it was a cross device copy.
2144 cnid_delete(vol->v_cdb, sid);
2147 cnid_delete(vol->v_cdb, did);
2149 if ((did && ( (crossdev && lstat( upath, &srcst) < 0) ||
2150 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2152 (sid && ( (crossdev && lstat(p, &destst) < 0) ||
2153 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2158 err = AFPERR_ACCESS;
2163 goto err_temp_to_dest;
2166 /* here we need to reopen if crossdev */
2167 if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2172 if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2177 /* change perms, src gets dest perm and vice versa */
2182 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2183 err = AFP_OK; /* ignore error */
2184 goto err_temp_to_dest;
2188 * we need to exchange ACL entries as well
2190 /* exchange_acls(vol, p, upath); */
2195 path->m_name = NULL;
2196 path->u_name = upath;
2198 setfilunixmode(vol, path, destst.st_mode);
2199 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2206 setfilunixmode(vol, path, srcst.st_mode);
2207 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2209 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2210 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2215 goto err_exchangefile;
2217 /* all this stuff is so that we can unwind a failed operation
2220 /* rename dest to temp */
2221 renamefile(vol, upath, temp, temp, adsp);
2222 of_rename(vol, s_of, curdir, upath, curdir, temp);
2225 /* rename source back to dest */
2226 renamefile(vol, p, upath, path->m_name, addp);
2227 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2230 /* rename temp back to source */
2231 renamefile(vol, temp, p, spath, adsp);
2232 of_rename(vol, s_of, curdir, temp, sdir, spath);
2235 if ( !s_of && adsp && ad_meta_fileno(adsp) != -1 ) { /* META */
2236 ad_close(adsp, ADFLAGS_HF);
2238 if ( !d_of && addp && ad_meta_fileno(addp) != -1 ) {/* META */
2239 ad_close(addp, ADFLAGS_HF);