2 * $Id: file.c,v 1.96 2005-04-28 20:49:41 bfernhomberg 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) |\
190 (1 << FILPBIT_UNIXPR)))
192 /* -------------------------- */
193 u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st,
194 const cnid_t did, char *upath, const int len)
198 #if AD_VERSION > AD_VERSION1
200 if ((aint = ad_getid(adp, st->st_dev, st->st_ino, did, vol->v_stamp))) {
205 if (vol->v_cdb != NULL) {
206 aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
207 /* Throw errors if cnid_add fails. */
208 if (aint == CNID_INVALID) {
210 case CNID_ERR_CLOSE: /* the db is closed */
213 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
214 afp_errno = AFPERR_PARAM;
217 afp_errno = AFPERR_PARAM;
220 afp_errno = AFPERR_MISC;
224 #if AD_VERSION > AD_VERSION1
226 /* update the ressource fork
227 * for a folder adp is always null
229 if (ad_setid(adp, st->st_dev, st->st_ino, aint, did, vol->v_stamp)) {
230 ad_flush(adp, ADFLAGS_HF);
238 /* -------------------------- */
239 int getmetadata(struct vol *vol,
241 struct path *path, struct dir *dir,
242 char *buf, int *buflen, struct adouble *adp, int attrbits )
244 char *data, *l_nameoff = NULL, *upath;
245 char *utf_nameoff = NULL;
250 u_char achar, fdType[4];
256 LOG(log_info, logtype_afpd, "begin getmetadata:");
259 upath = path->u_name;
264 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
265 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
266 || (bitmap & (1 << FILPBIT_FNUM))) {
268 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
274 path->m_name = utompath(vol, upath, id, utf8_encoding());
277 while ( bitmap != 0 ) {
278 while (( bitmap & 1 ) == 0 ) {
286 ad_getattr(adp, &ashort);
287 } else if (*upath == '.') {
288 ashort = htons(ATTRBIT_INVISIBLE);
292 /* FIXME do we want a visual clue if the file is read only
295 accessmode( ".", &ma, dir , NULL);
296 if ((ma.ma_user & AR_UWRITE)) {
297 accessmode( upath, &ma, dir , st);
298 if (!(ma.ma_user & AR_UWRITE)) {
299 attrbits |= ATTRBIT_NOWRITE;
304 ashort = htons(ntohs(ashort) | attrbits);
305 memcpy(data, &ashort, sizeof( ashort ));
306 data += sizeof( ashort );
310 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
311 data += sizeof( u_int32_t );
315 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
316 aint = AD_DATE_FROM_UNIX(st->st_mtime);
317 memcpy(data, &aint, sizeof( aint ));
318 data += sizeof( aint );
322 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
323 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
324 aint = AD_DATE_FROM_UNIX(st->st_mtime);
327 aint = AD_DATE_FROM_UNIX(st->st_mtime);
329 memcpy(data, &aint, sizeof( int ));
330 data += sizeof( int );
334 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
335 aint = AD_DATE_START;
336 memcpy(data, &aint, sizeof( int ));
337 data += sizeof( int );
341 get_finderinfo(upath, adp, (char *)data);
342 data += ADEDLEN_FINDERI;
347 data += sizeof( u_int16_t );
351 memset(data, 0, sizeof(u_int16_t));
352 data += sizeof( u_int16_t );
356 memcpy(data, &id, sizeof( id ));
357 data += sizeof( id );
361 if (st->st_size > 0xffffffff)
364 aint = htonl( st->st_size );
365 memcpy(data, &aint, sizeof( aint ));
366 data += sizeof( aint );
371 if (adp->ad_rlen > 0xffffffff)
374 aint = htonl( adp->ad_rlen);
378 memcpy(data, &aint, sizeof( aint ));
379 data += sizeof( aint );
382 /* Current client needs ProDOS info block for this file.
383 Use simple heuristic and let the Mac "type" string tell
384 us what the PD file code should be. Everything gets a
385 subtype of 0x0000 unless the original value was hashed
386 to "pXYZ" when we created it. See IA, Ver 2.
387 <shirsch@adelphia.net> */
388 case FILPBIT_PDINFO :
389 if (afp_version >= 30) { /* UTF8 name */
390 utf8 = kTextEncodingUTF8;
392 data += sizeof( u_int16_t );
394 memcpy(data, &aint, sizeof( aint ));
395 data += sizeof( aint );
399 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
401 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
405 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
409 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
413 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
417 else if ( fdType[0] == 'p' ) {
419 ashort = (fdType[2] * 256) + fdType[3];
433 memcpy(data, &ashort, sizeof( ashort ));
434 data += sizeof( ashort );
435 memset(data, 0, sizeof( ashort ));
436 data += sizeof( ashort );
439 case FILPBIT_EXTDFLEN:
440 aint = htonl(st->st_size >> 32);
441 memcpy(data, &aint, sizeof( aint ));
442 data += sizeof( aint );
443 aint = htonl(st->st_size);
444 memcpy(data, &aint, sizeof( aint ));
445 data += sizeof( aint );
447 case FILPBIT_EXTRFLEN:
450 aint = htonl(adp->ad_rlen >> 32);
451 memcpy(data, &aint, sizeof( aint ));
452 data += sizeof( aint );
454 aint = htonl(adp->ad_rlen);
455 memcpy(data, &aint, sizeof( aint ));
456 data += sizeof( aint );
458 case FILPBIT_UNIXPR :
459 /* accessmode may change st_mode with ACLs */
460 accessmode( upath, &ma, dir , st);
462 aint = htonl(st->st_uid);
463 memcpy( data, &aint, sizeof( aint ));
464 data += sizeof( aint );
465 aint = htonl(st->st_gid);
466 memcpy( data, &aint, sizeof( aint ));
467 data += sizeof( aint );
470 type == slnk indicates an OSX style symlink,
471 we have to add S_IFLNK to the mode, otherwise
472 10.3 clients freak out. */
476 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
477 if ( memcmp( fdType, "slnk", 4 ) == 0 ) {
483 memcpy( data, &aint, sizeof( aint ));
484 data += sizeof( aint );
486 *data++ = ma.ma_user;
487 *data++ = ma.ma_world;
488 *data++ = ma.ma_group;
489 *data++ = ma.ma_owner;
493 return( AFPERR_BITMAP );
499 ashort = htons( data - buf );
500 memcpy(l_nameoff, &ashort, sizeof( ashort ));
501 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
504 ashort = htons( data - buf );
505 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
506 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
508 *buflen = data - buf;
512 /* ----------------------- */
513 int getfilparams(struct vol *vol,
515 struct path *path, struct dir *dir,
516 char *buf, int *buflen )
518 struct adouble ad, *adp;
521 u_int16_t attrbits = 0;
526 LOG(log_info, logtype_default, "begin getfilparams:");
529 opened = PARAM_NEED_ADP(bitmap);
532 upath = path->u_name;
533 if ((of = of_findname(path))) {
535 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
536 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
538 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
542 if ( ad_metadata( upath, 0, adp) < 0 ) {
545 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
546 upath, strerror(errno));
547 return AFPERR_ACCESS;
549 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
559 we need to check if the file is open by another process.
560 it's slow so we only do it if we have to:
561 - bitmap is requested.
562 - we don't already have the answer!
564 if ((bitmap & (1 << FILPBIT_ATTR))) {
565 if (!(attrbits & ATTRBIT_ROPEN)) {
566 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_ROPEN : 0;
567 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_ROPEN : 0;
569 if (!(attrbits & ATTRBIT_DOPEN)) {
570 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_DOPEN : 0;
571 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_DOPEN : 0;
576 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
578 ad_close( adp, ADFLAGS_HF );
581 LOG(log_info, logtype_afpd, "end getfilparams:");
587 /* ----------------------------- */
588 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
590 char *ibuf, *rbuf _U_;
591 int ibuflen _U_, *rbuflen;
593 struct adouble ad, *adp;
596 struct ofork *of = NULL;
598 int creatf, did, openf, retvalue = AFP_OK;
604 LOG(log_info, logtype_afpd, "begin afp_createfile:");
609 creatf = (unsigned char) *ibuf++;
611 memcpy(&vid, ibuf, sizeof( vid ));
612 ibuf += sizeof( vid );
614 if (NULL == ( vol = getvolbyvid( vid )) ) {
615 return( AFPERR_PARAM );
618 if (vol->v_flags & AFPVOL_RO)
621 memcpy(&did, ibuf, sizeof( did));
622 ibuf += sizeof( did );
624 if (NULL == ( dir = dirlookup( vol, did )) ) {
628 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
629 return get_afp_errno(AFPERR_PARAM);
632 if ( *s_path->m_name == '\0' ) {
633 return( AFPERR_BADTYPE );
636 upath = s_path->u_name;
637 if (0 != (ret = check_name(vol, upath)))
640 /* if upath is deleted we already in trouble anyway */
641 if ((of = of_findname(s_path))) {
644 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
648 /* on a hard create, fail if file exists and is open */
651 openf = O_RDWR|O_CREAT|O_TRUNC;
653 /* on a soft create, if the file is open then ad_open won't fail
654 because open syscall is not called
659 openf = O_RDWR|O_CREAT|O_EXCL;
662 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
663 openf, 0666, adp) < 0 ) {
667 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
668 return ( AFPERR_NOOBJ );
670 return( AFPERR_EXIST );
672 return( AFPERR_ACCESS );
674 return( AFPERR_PARAM );
677 if ( ad_hfileno( adp ) == -1 ) {
678 /* on noadouble volumes, just creating the data fork is ok */
679 if (vol_noadouble(vol)) {
680 ad_close( adp, ADFLAGS_DF );
681 goto createfile_done;
683 /* FIXME with hard create on an existing file, we already
684 * corrupted the data file.
686 netatalk_unlink( upath );
687 ad_close( adp, ADFLAGS_DF );
688 return AFPERR_ACCESS;
691 path = s_path->m_name;
692 ad_setname(adp, path);
693 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
694 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
700 if (vol->v_flags & AFPVOL_DROPBOX) {
701 retvalue = matchfile2dirperms(upath, vol, did);
703 #endif /* DROPKLUDGE */
705 setvoltime(obj, vol );
708 LOG(log_info, logtype_afpd, "end afp_createfile");
714 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
716 char *ibuf, *rbuf _U_;
717 int ibuflen _U_, *rbuflen;
723 u_int16_t vid, bitmap;
726 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
732 memcpy(&vid, ibuf, sizeof( vid ));
733 ibuf += sizeof( vid );
734 if (NULL == ( vol = getvolbyvid( vid )) ) {
735 return( AFPERR_PARAM );
738 if (vol->v_flags & AFPVOL_RO)
741 memcpy(&did, ibuf, sizeof( did ));
742 ibuf += sizeof( did );
743 if (NULL == ( dir = dirlookup( vol, did )) ) {
744 return afp_errno; /* was AFPERR_NOOBJ */
747 memcpy(&bitmap, ibuf, sizeof( bitmap ));
748 bitmap = ntohs( bitmap );
749 ibuf += sizeof( bitmap );
751 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
752 return get_afp_errno(AFPERR_PARAM);
755 if (path_isadir(s_path)) {
756 return( AFPERR_BADTYPE ); /* it's a directory */
759 if ( s_path->st_errno != 0 ) {
760 return( AFPERR_NOOBJ );
763 if ((u_long)ibuf & 1 ) {
767 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
768 setvoltime(obj, vol );
772 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
779 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
782 extern struct path Cur_Path;
784 int setfilparams(struct vol *vol,
785 struct path *path, u_int16_t f_bitmap, char *buf )
787 struct adouble ad, *adp;
789 int bit, isad = 1, err = AFP_OK;
791 u_char achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
792 u_int16_t ashort, bshort;
795 u_int16_t upriv_bit = 0;
799 int change_mdate = 0;
800 int change_parent_mdate = 0;
805 u_int16_t bitmap = f_bitmap;
806 u_int32_t cdate,bdate;
807 u_char finder_buf[32];
810 LOG(log_info, logtype_afpd, "begin setfilparams:");
813 upath = path->u_name;
814 adp = of_ad(vol, path, &ad);
817 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
818 return AFPERR_ACCESS;
821 /* with unix priv maybe we have to change adouble file priv first */
823 while ( bitmap != 0 ) {
824 while (( bitmap & 1 ) == 0 ) {
831 memcpy(&ashort, buf, sizeof( ashort ));
832 buf += sizeof( ashort );
836 memcpy(&cdate, buf, sizeof(cdate));
837 buf += sizeof( cdate );
840 memcpy(&newdate, buf, sizeof( newdate ));
841 buf += sizeof( newdate );
845 memcpy(&bdate, buf, sizeof( bdate));
846 buf += sizeof( bdate );
850 memcpy(finder_buf, buf, 32 );
853 case FILPBIT_UNIXPR :
854 if (!vol_unix_priv(vol)) {
855 /* this volume doesn't use unix priv */
861 change_parent_mdate = 1;
863 memcpy( &aint, buf, sizeof( aint ));
864 f_uid = ntohl (aint);
865 buf += sizeof( aint );
866 memcpy( &aint, buf, sizeof( aint ));
867 f_gid = ntohl (aint);
868 buf += sizeof( aint );
869 setfilowner(vol, f_uid, f_gid, path);
871 memcpy( &upriv, buf, sizeof( upriv ));
872 buf += sizeof( upriv );
873 upriv = ntohl (upriv);
874 if ((upriv & S_IWUSR)) {
875 setfilunixmode(vol, path, upriv);
882 case FILPBIT_PDINFO :
883 if (afp_version < 30) { /* else it's UTF8 name */
886 /* Keep special case to support crlf translations */
887 if ((unsigned int) achar == 0x04) {
888 fdType = (u_char *)"TEXT";
891 xyy[0] = ( u_char ) 'p';
902 /* break while loop */
911 /* second try with adouble open
913 if ( ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
914 O_RDWR|O_CREAT, 0666, adp) < 0) {
915 /* for some things, we don't need an adouble header */
916 if (f_bitmap & ~(1<<FILPBIT_MDATE)) {
917 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
920 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
921 ad_setname(adp, path->m_name);
926 while ( bitmap != 0 ) {
927 while (( bitmap & 1 ) == 0 ) {
934 ad_getattr(adp, &bshort);
935 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
936 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
937 change_parent_mdate = 1;
938 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
939 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
943 ad_setattr(adp, bshort);
946 ad_setdate(adp, AD_DATE_CREATE, cdate);
951 ad_setdate(adp, AD_DATE_BACKUP, bdate);
954 if (default_type( ad_entry( adp, ADEID_FINDERI ))
956 ((em = getextmap( path->m_name )) &&
957 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
958 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
959 || ((em = getdefextmap()) &&
960 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
961 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
963 memcpy(finder_buf, ufinderi, 8 );
965 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
967 case FILPBIT_UNIXPR :
969 setfilunixmode(vol, path, upriv);
972 case FILPBIT_PDINFO :
973 if (afp_version < 30) { /* else it's UTF8 name */
974 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
975 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
981 goto setfilparam_done;
988 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
989 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
993 ad_setdate(adp, AD_DATE_MODIFY, newdate);
994 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
999 ad_flush( adp, ADFLAGS_HF );
1000 ad_close( adp, ADFLAGS_HF );
1004 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
1005 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
1006 bitmap = 1<<FILPBIT_MDATE;
1007 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
1011 LOG(log_info, logtype_afpd, "end setfilparams:");
1017 * renamefile and copyfile take the old and new unix pathnames
1018 * and the new mac name.
1020 * src the source path
1021 * dst the dest filename in current dir
1022 * newname the dest mac name
1023 * adp adouble struct of src file, if open, or & zeroed one
1026 int renamefile(vol, src, dst, newname, adp )
1027 const struct vol *vol;
1028 char *src, *dst, *newname;
1029 struct adouble *adp;
1034 LOG(log_info, logtype_afpd, "begin renamefile:");
1037 if ( unix_rename( src, dst ) < 0 ) {
1040 return( AFPERR_NOOBJ );
1043 return( AFPERR_ACCESS );
1045 return AFPERR_VLOCK;
1046 case EXDEV : /* Cross device move -- try copy */
1047 /* NOTE: with open file it's an error because after the copy we will
1048 * get two files, it's fixable for our process (eg reopen the new file, get the
1049 * locks, and so on. But it doesn't solve the case with a second process
1051 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
1052 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1053 return AFPERR_OLOCK; /* little lie */
1055 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1056 /* on error copyfile delete dest */
1059 return deletefile(vol, src, 0);
1061 return( AFPERR_PARAM );
1065 if (vol->vfs->rf_renamefile(vol, src, dst) < 0 ) {
1069 /* try to undo the data fork rename,
1070 * we know we are on the same device
1073 unix_rename( dst, src );
1074 /* return the first error */
1077 return AFPERR_NOOBJ;
1080 return AFPERR_ACCESS ;
1082 return AFPERR_VLOCK;
1084 return AFPERR_PARAM ;
1089 /* don't care if we can't open the newly renamed ressource fork
1091 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1092 ad_setname(adp, newname);
1093 ad_flush( adp, ADFLAGS_HF );
1094 ad_close( adp, ADFLAGS_HF );
1097 LOG(log_info, logtype_afpd, "end renamefile:");
1104 convert a Mac long name to an utf8 name,
1106 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1110 if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1116 /* ---------------- */
1117 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1124 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1130 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1131 if (afp_version >= 30) {
1132 /* convert it to UTF8
1134 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1)
1138 strncpy( newname, ibuf, plen );
1139 newname[ plen ] = '\0';
1141 if (strlen(newname) != plen) {
1142 /* there's \0 in newname, e.g. it's a pathname not
1150 memcpy(&hint, ibuf, sizeof(hint));
1151 ibuf += sizeof(hint);
1153 memcpy(&len16, ibuf, sizeof(len16));
1154 ibuf += sizeof(len16);
1155 plen = ntohs(len16);
1158 if (plen > AFPOBJ_TMPSIZ) {
1161 strncpy( newname, ibuf, plen );
1162 newname[ plen ] = '\0';
1163 if (strlen(newname) != plen) {
1172 /* -----------------------------------
1174 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1176 char *ibuf, *rbuf _U_;
1177 int ibuflen _U_, *rbuflen;
1179 struct vol *s_vol, *d_vol;
1181 char *newname, *p, *upath;
1182 struct path *s_path;
1183 u_int32_t sdid, ddid;
1184 int err, retvalue = AFP_OK;
1185 u_int16_t svid, dvid;
1187 struct adouble ad, *adp;
1191 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1197 memcpy(&svid, ibuf, sizeof( svid ));
1198 ibuf += sizeof( svid );
1199 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1200 return( AFPERR_PARAM );
1203 memcpy(&sdid, ibuf, sizeof( sdid ));
1204 ibuf += sizeof( sdid );
1205 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1209 memcpy(&dvid, ibuf, sizeof( dvid ));
1210 ibuf += sizeof( dvid );
1211 memcpy(&ddid, ibuf, sizeof( ddid ));
1212 ibuf += sizeof( ddid );
1214 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1215 return get_afp_errno(AFPERR_PARAM);
1217 if ( path_isadir(s_path) ) {
1218 return( AFPERR_BADTYPE );
1221 /* don't allow copies when the file is open.
1222 * XXX: the spec only calls for read/deny write access.
1223 * however, copyfile doesn't have any of that info,
1224 * and locks need to stay coherent. as a result,
1225 * we just balk if the file is opened already. */
1227 adp = of_ad(s_vol, s_path, &ad);
1229 if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1230 return AFPERR_DENYCONF;
1232 denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
1233 getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1234 ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1236 return AFPERR_DENYCONF;
1239 newname = obj->newtmp;
1240 strcpy( newname, s_path->m_name );
1242 p = ctoupath( s_vol, curdir, newname );
1244 return AFPERR_PARAM;
1248 /* FIXME svid != dvid && dvid's user can't read svid */
1250 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1251 return( AFPERR_PARAM );
1254 if (d_vol->v_flags & AFPVOL_RO)
1255 return AFPERR_VLOCK;
1257 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1261 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1262 return get_afp_errno(AFPERR_NOOBJ);
1264 if ( *s_path->m_name != '\0' ) {
1265 path_error(s_path, AFPERR_PARAM);
1268 /* one of the handful of places that knows about the path type */
1269 if (copy_path_name(d_vol, newname, ibuf) < 0) {
1270 return( AFPERR_PARAM );
1272 /* newname is always only a filename so curdir *is* its
1275 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1276 return( AFPERR_PARAM );
1278 if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1284 if (vol->v_flags & AFPVOL_DROPBOX) {
1285 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1287 #endif /* DROPKLUDGE */
1289 setvoltime(obj, d_vol );
1292 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1298 /* ----------------------- */
1299 static __inline__ int copy_all(const int dfd, const void *buf,
1305 LOG(log_info, logtype_afpd, "begin copy_all:");
1308 while (buflen > 0) {
1309 if ((cc = write(dfd, buf, buflen)) < 0) {
1321 LOG(log_info, logtype_afpd, "end copy_all:");
1327 /* -------------------------- */
1328 static int copy_fd(int dfd, int sfd)
1334 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1335 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1339 #define BUF 128*1024*1024
1341 if (fstat(sfd, &st) == 0) {
1344 if ( offset >= st.st_size) {
1347 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1348 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1351 case EINVAL: /* there's no guarantee that all fs support sendfile */
1360 lseek(sfd, offset, SEEK_SET);
1364 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1371 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1378 /* ----------------------------------
1379 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1380 * because we are doing it elsewhere.
1382 int copyfile(s_vol, d_vol, src, dst, newname, adp )
1383 const struct vol *s_vol, *d_vol;
1384 char *src, *dst, *newname;
1385 struct adouble *adp;
1387 struct adouble ads, add;
1391 int noadouble = vol_noadouble(d_vol);
1395 LOG(log_info, logtype_afpd, "begin copyfile:");
1399 ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options);
1402 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1403 adflags = ADFLAGS_DF;
1405 adflags |= ADFLAGS_HF;
1408 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1413 if (ad_hfileno(adp) == -1) {
1414 /* no resource fork, don't create one for dst file */
1415 adflags &= ~ADFLAGS_HF;
1418 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1420 ad_close( adp, adflags );
1421 if (EEXIST != ret_err) {
1422 deletefile(d_vol, dst, 0);
1425 return AFPERR_EXIST;
1427 if (ad_hfileno(adp) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(adp)))){
1428 /* copy the data fork */
1429 err = copy_fd(ad_dfileno(&add), ad_dfileno(adp));
1432 /* Now, reopen destination file */
1436 ad_close( adp, adflags );
1438 if (ad_close( &add, adflags ) <0) {
1439 deletefile(d_vol, dst, 0);
1444 ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1445 if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
1450 if (!ret_err && newname) {
1451 ad_setname(&add, newname);
1454 ad_flush( &add, adflags );
1455 if (ad_close( &add, adflags ) <0) {
1459 deletefile(d_vol, dst, 0);
1461 else if (!stat(src, &st)) {
1462 /* set dest modification date to src date */
1466 ut.actime = ut.modtime = st.st_mtime;
1468 /* FIXME netatalk doesn't use resource fork file date
1469 * but maybe we should set its modtime too.
1474 LOG(log_info, logtype_afpd, "end copyfile:");
1478 switch ( ret_err ) {
1484 return AFPERR_DFULL;
1486 return AFPERR_NOOBJ;
1488 return AFPERR_ACCESS;
1490 return AFPERR_VLOCK;
1492 return AFPERR_PARAM;
1496 /* -----------------------------------
1497 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1498 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1500 when deletefile is called we don't have lock on it, file is closed (for us)
1501 untrue if called by renamefile
1503 ad_open always try to open file RDWR first and ad_lock takes care of
1504 WRITE lock on read only file.
1506 int deletefile( vol, file, checkAttrib )
1507 const struct vol *vol;
1512 struct adouble *adp = &ad;
1513 int adflags, err = AFP_OK;
1516 LOG(log_info, logtype_afpd, "begin deletefile:");
1519 /* try to open both forks at once */
1520 adflags = ADFLAGS_DF|ADFLAGS_HF;
1521 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1523 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1526 if (adflags == ADFLAGS_DF)
1527 return AFPERR_NOOBJ;
1529 /* that failed. now try to open just the data fork */
1530 adflags = ADFLAGS_DF;
1534 adp = NULL; /* maybe it's a file we no rw mode for us */
1535 break; /* was return AFPERR_ACCESS;*/
1537 return AFPERR_VLOCK;
1539 return( AFPERR_PARAM );
1542 break; /* from the while */
1545 * Does kFPDeleteInhibitBit (bit 8) set?
1550 if (adp && (adflags & ADFLAGS_HF)) {
1552 ad_getattr(&ad, &bshort);
1553 if ((bshort & htons(ATTRBIT_NODELETE))) {
1554 ad_close( &ad, adflags );
1555 return(AFPERR_OLOCK);
1559 /* was EACCESS error try to get only metadata */
1560 ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
1561 if ( ad_metadata( file , 0, &ad) == 0 ) {
1562 ad_getattr(&ad, &bshort);
1563 ad_close( &ad, ADFLAGS_HF );
1564 if ((bshort & htons(ATTRBIT_NODELETE))) {
1565 return AFPERR_OLOCK;
1571 if (adp && (adflags & ADFLAGS_HF) ) {
1572 /* FIXME we have a pb here because we want to know if a file is open
1573 * there's a 'priority inversion' if you can't open the ressource fork RW
1574 * you can delete it if it's open because you can't get a write lock.
1576 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1579 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1581 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1582 ad_close( &ad, adflags );
1583 return( AFPERR_BUSY );
1587 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1590 else if (!(err = vol->vfs->rf_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
1592 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1594 cnid_delete(vol->v_cdb, id);
1598 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1601 LOG(log_info, logtype_afpd, "end deletefile:");
1607 /* ------------------------------------ */
1608 /* return a file id */
1609 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1612 int ibuflen _U_, *rbuflen;
1621 struct path *s_path;
1624 LOG(log_info, logtype_afpd, "begin afp_createid:");
1631 memcpy(&vid, ibuf, sizeof(vid));
1632 ibuf += sizeof(vid);
1634 if (NULL == ( vol = getvolbyvid( vid )) ) {
1635 return( AFPERR_PARAM);
1638 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1642 if (vol->v_flags & AFPVOL_RO)
1643 return AFPERR_VLOCK;
1645 memcpy(&did, ibuf, sizeof( did ));
1646 ibuf += sizeof(did);
1648 if (NULL == ( dir = dirlookup( vol, did )) ) {
1649 return afp_errno; /* was AFPERR_PARAM */
1652 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1653 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1656 if ( path_isadir(s_path) ) {
1657 return( AFPERR_BADTYPE );
1660 upath = s_path->u_name;
1661 switch (s_path->st_errno) {
1663 break; /* success */
1666 return AFPERR_ACCESS;
1668 return AFPERR_NOOBJ;
1670 return AFPERR_PARAM;
1673 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1674 memcpy(rbuf, &id, sizeof(id));
1675 *rbuflen = sizeof(id);
1676 return AFPERR_EXISTID;
1679 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1680 memcpy(rbuf, &id, sizeof(id));
1681 *rbuflen = sizeof(id);
1686 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1691 /* ------------------------------- */
1697 static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
1700 struct reenum *param = data;
1701 struct vol *vol = param->vol;
1702 cnid_t did = param->did;
1705 memset(&path, 0, sizeof(path));
1707 if ( stat(de->d_name, &path.st)<0 )
1710 /* update or add to cnid */
1711 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1713 #if AD_VERSION > AD_VERSION1
1714 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1715 struct adouble ad, *adp;
1719 path.u_name = de->d_name;
1721 adp = of_ad(vol, &path, &ad);
1723 if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, adp ) < 0 ) {
1726 if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1727 ad_flush(adp, ADFLAGS_HF);
1729 ad_close(adp, ADFLAGS_HF);
1731 #endif /* AD_VERSION > AD_VERSION1 */
1736 /* --------------------
1737 * Ok the db is out of synch with the dir.
1738 * but if it's a deleted file we don't want to do it again and again.
1741 reenumerate_id(struct vol *vol, char *name, struct dir *dir)
1747 if (vol->v_cdb == NULL) {
1751 /* FIXME use of_statdir ? */
1752 if (stat(name, &st)) {
1756 if (dirreenumerate(dir, &st)) {
1757 /* we already did it once and the dir haven't been modified */
1762 data.did = dir->d_did;
1763 if ((ret = for_each_dirent(vol, name, reenumerate_loop, (void *)&data)) >= 0) {
1764 setdiroffcnt(curdir, &st, ret);
1765 dir->d_flags |= DIRF_CNID;
1771 /* ------------------------------
1772 resolve a file id */
1773 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1776 int ibuflen _U_, *rbuflen;
1782 int err, buflen, retry=0;
1784 u_int16_t vid, bitmap;
1786 static char buffer[12 + MAXPATHLEN + 1];
1787 int len = 12 + MAXPATHLEN + 1;
1790 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1796 memcpy(&vid, ibuf, sizeof(vid));
1797 ibuf += sizeof(vid);
1799 if (NULL == ( vol = getvolbyvid( vid )) ) {
1800 return( AFPERR_PARAM);
1803 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1807 memcpy(&id, ibuf, sizeof( id ));
1812 /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
1816 memset(&path, 0, sizeof(path));
1817 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1818 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1821 if (NULL == ( dir = dirlookup( vol, id )) ) {
1822 return AFPERR_NOID; /* idem AFPERR_PARAM */
1824 path.u_name = upath;
1825 if (movecwd(vol, dir) < 0) {
1829 return AFPERR_ACCESS;
1833 return AFPERR_PARAM;
1837 if ( of_stat(&path) < 0 ) {
1839 /* with nfs and our working directory is deleted */
1840 if (errno == ESTALE) {
1844 if ( errno == ENOENT && !retry) {
1845 /* cnid db is out of sync, reenumerate the directory and update ids */
1846 reenumerate_id(vol, ".", dir);
1854 return AFPERR_ACCESS;
1858 return AFPERR_PARAM;
1862 /* directories are bad */
1863 if (S_ISDIR(path.st.st_mode))
1864 return AFPERR_BADTYPE;
1866 memcpy(&bitmap, ibuf, sizeof(bitmap));
1867 bitmap = ntohs( bitmap );
1868 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1872 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1873 rbuf + sizeof(bitmap), &buflen))) {
1876 *rbuflen = buflen + sizeof(bitmap);
1877 memcpy(rbuf, ibuf, sizeof(bitmap));
1880 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1886 /* ------------------------------ */
1887 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1889 char *ibuf, *rbuf _U_;
1890 int ibuflen _U_, *rbuflen;
1900 static char buffer[12 + MAXPATHLEN + 1];
1901 int len = 12 + MAXPATHLEN + 1;
1904 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1910 memcpy(&vid, ibuf, sizeof(vid));
1911 ibuf += sizeof(vid);
1913 if (NULL == ( vol = getvolbyvid( vid )) ) {
1914 return( AFPERR_PARAM);
1917 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1921 if (vol->v_flags & AFPVOL_RO)
1922 return AFPERR_VLOCK;
1924 memcpy(&id, ibuf, sizeof( id ));
1928 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1932 if (NULL == ( dir = dirlookup( vol, id )) ) {
1933 return( AFPERR_PARAM );
1937 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1941 return AFPERR_ACCESS;
1946 /* still try to delete the id */
1950 return AFPERR_PARAM;
1953 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1954 return AFPERR_BADTYPE;
1956 if (cnid_delete(vol->v_cdb, fileid)) {
1959 return AFPERR_VLOCK;
1962 return AFPERR_ACCESS;
1964 return AFPERR_PARAM;
1969 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1975 /* ------------------------------ */
1976 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1980 if (path->st_errno) {
1981 switch (path->st_errno) {
1983 afp_errno = AFPERR_NOID;
1987 afp_errno = AFPERR_ACCESS;
1990 afp_errno = AFPERR_PARAM;
1995 /* we use file_access both for legacy Mac perm and
1996 * for unix privilege, rename will take care of folder perms
1998 if (file_access(path, OPENACC_WR ) < 0) {
1999 afp_errno = AFPERR_ACCESS;
2003 if ((*of = of_findname(path))) {
2004 /* reuse struct adouble so it won't break locks */
2008 ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
2009 if ( !ret && ad_hfileno(adp) != -1 && !(adp->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) {
2011 * The user must have the Read & Write privilege for both files in order to use this command.
2013 ad_close(adp, ADFLAGS_HF);
2014 afp_errno = AFPERR_ACCESS;
2021 #define APPLETEMP ".AppleTempXXXXXX"
2023 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
2025 char *ibuf, *rbuf _U_ ;
2026 int ibuflen _U_, *rbuflen;
2028 struct stat srcst, destst;
2030 struct dir *dir, *sdir;
2031 char *spath, temp[17], *p;
2032 char *supath, *upath;
2037 struct adouble *adsp = NULL;
2038 struct adouble *addp = NULL;
2039 struct ofork *s_of = NULL;
2040 struct ofork *d_of = NULL;
2051 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
2057 memcpy(&vid, ibuf, sizeof(vid));
2058 ibuf += sizeof(vid);
2060 if (NULL == ( vol = getvolbyvid( vid )) ) {
2061 return( AFPERR_PARAM);
2064 if ((vol->v_flags & AFPVOL_RO))
2065 return AFPERR_VLOCK;
2067 /* source and destination dids */
2068 memcpy(&sid, ibuf, sizeof(sid));
2069 ibuf += sizeof(sid);
2070 memcpy(&did, ibuf, sizeof(did));
2071 ibuf += sizeof(did);
2074 if (NULL == (dir = dirlookup( vol, sid )) ) {
2075 return afp_errno; /* was AFPERR_PARAM */
2078 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2079 return get_afp_errno(AFPERR_NOOBJ);
2082 if ( path_isadir(path) ) {
2083 return AFPERR_BADTYPE; /* it's a dir */
2086 /* save some stuff */
2089 spath = obj->oldtmp;
2090 supath = obj->newtmp;
2091 strcpy(spath, path->m_name);
2092 strcpy(supath, path->u_name); /* this is for the cnid changing */
2093 p = absupath( vol, sdir, supath);
2095 /* pathname too long */
2096 return AFPERR_PARAM ;
2099 ad_init(&ads, vol->v_adouble, vol->v_ad_options);
2100 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2104 /* ***** from here we may have resource fork open **** */
2106 /* look for the source cnid. if it doesn't exist, don't worry about
2108 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2110 if (NULL == ( dir = dirlookup( vol, did )) ) {
2111 err = afp_errno; /* was AFPERR_PARAM */
2112 goto err_exchangefile;
2115 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2116 err = get_afp_errno(AFPERR_NOOBJ);
2117 goto err_exchangefile;
2120 if ( path_isadir(path) ) {
2121 err = AFPERR_BADTYPE;
2122 goto err_exchangefile;
2125 /* FPExchangeFiles is the only call that can return the SameObj
2127 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2128 err = AFPERR_SAMEOBJ;
2129 goto err_exchangefile;
2132 ad_init(&add, vol->v_adouble, vol->v_ad_options);
2133 if (!(addp = find_adouble( path, &d_of, &add))) {
2135 goto err_exchangefile;
2139 /* they are not on the same device and at least one is open
2140 * FIXME broken for for crossdev and adouble v2
2143 crossdev = (srcst.st_dev != destst.st_dev);
2144 if (/* (d_of || s_of) && */ crossdev) {
2146 goto err_exchangefile;
2149 /* look for destination id. */
2150 upath = path->u_name;
2151 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2153 /* construct a temp name.
2154 * NOTE: the temp file will be in the dest file's directory. it
2155 * will also be inaccessible from AFP. */
2156 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2157 if (!mktemp(temp)) {
2159 goto err_exchangefile;
2163 /* FIXME we need to close fork for copy, both s_of and d_of are null */
2164 ad_close(adsp, ADFLAGS_HF);
2165 ad_close(addp, ADFLAGS_HF);
2168 /* now, quickly rename the file. we error if we can't. */
2169 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2170 goto err_exchangefile;
2171 of_rename(vol, s_of, sdir, spath, curdir, temp);
2173 /* rename destination to source */
2174 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2175 goto err_src_to_tmp;
2176 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2178 /* rename temp to destination */
2179 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2180 goto err_dest_to_src;
2181 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2183 /* id's need switching. src -> dest and dest -> src.
2184 * we need to re-stat() if it was a cross device copy.
2187 cnid_delete(vol->v_cdb, sid);
2190 cnid_delete(vol->v_cdb, did);
2192 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2193 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2195 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2196 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2201 err = AFPERR_ACCESS;
2206 goto err_temp_to_dest;
2209 /* here we need to reopen if crossdev */
2210 if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp))
2212 ad_flush( addp, ADFLAGS_HF );
2215 if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp))
2217 ad_flush( adsp, ADFLAGS_HF );
2220 /* change perms, src gets dest perm and vice versa */
2225 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2226 err = AFP_OK; /* ignore error */
2227 goto err_temp_to_dest;
2231 * we need to exchange ACL entries as well
2233 /* exchange_acls(vol, p, upath); */
2238 path->m_name = NULL;
2239 path->u_name = upath;
2241 setfilunixmode(vol, path, destst.st_mode);
2242 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2249 setfilunixmode(vol, path, srcst.st_mode);
2250 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2252 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2253 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2258 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2262 goto err_exchangefile;
2264 /* all this stuff is so that we can unwind a failed operation
2267 /* rename dest to temp */
2268 renamefile(vol, upath, temp, temp, adsp);
2269 of_rename(vol, s_of, curdir, upath, curdir, temp);
2272 /* rename source back to dest */
2273 renamefile(vol, p, upath, path->m_name, addp);
2274 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2277 /* rename temp back to source */
2278 renamefile(vol, temp, p, spath, adsp);
2279 of_rename(vol, s_of, curdir, temp, sdir, spath);
2282 if ( !s_of && adsp && ad_hfileno(adsp) != -1 ) {
2283 ad_close(adsp, ADFLAGS_HF);
2285 if ( !d_of && addp && ad_hfileno(addp) != -1 ) {
2286 ad_close(addp, ADFLAGS_HF);