2 * $Id: file.c,v 1.92.2.2.2.26 2004-05-11 08:31:17 didg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
18 #else /* STDC_HEADERS */
22 #endif /* HAVE_STRCHR */
23 char *strchr (), *strrchr ();
26 #define memcpy(d,s,n) bcopy ((s), (d), (n))
27 #define memmove(d,s,n) bcopy ((s), (d), (n))
28 #endif /* ! HAVE_MEMCPY */
29 #endif /* STDC_HEADERS */
31 #include <atalk/adouble.h>
36 #include <atalk/logger.h>
37 #include <sys/param.h>
40 #include <atalk/afp.h>
41 #include <atalk/util.h>
42 #include <atalk/cnid.h>
43 #include "directory.h"
52 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
53 * field bytes subfield bytes
56 * ioFlFndrInfo 16 -> type 4 type field
57 * creator 4 creator field
58 * flags 2 finder flags:
60 * location 4 location in window
61 * folder 2 window that contains file
63 * ioFlXFndrInfo 16 -> iconID 2 icon id
65 * script 1 script system
67 * commentID 2 comment id
68 * putawayID 4 home directory id
71 const u_char ufinderi[] = {
72 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
73 0, 0, 0, 0, 0, 0, 0, 0,
74 0, 0, 0, 0, 0, 0, 0, 0,
75 0, 0, 0, 0, 0, 0, 0, 0
78 /* FIXME mpath : unix or mac name ? (for now it's mac name ) */
79 void *get_finderinfo(const char *mpath, struct adouble *adp, void *data)
84 if (adp && (ad_finder = ad_entry(adp, ADEID_FINDERI))) {
85 memcpy(data, ad_finder, 32);
88 memcpy(data, ufinderi, 32);
91 if ((!adp || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 ))
92 && (em = getextmap( mpath ))
94 memcpy(data, em->em_type, sizeof( em->em_type ));
95 memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator));
100 /* ---------------------
102 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8)
107 aint = strlen( name );
111 if (utf8_encoding()) {
112 /* but name is an utf8 mac name */
115 /* global static variable... */
117 if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
126 if (aint > MACFILELEN)
133 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
136 utf8 = vol->v_mac?htonl(vol->v_mac->kTextEncoding):0; /* htonl(utf8) */
137 memcpy(data, &utf8, sizeof(utf8));
138 data += sizeof(utf8);
141 memcpy(data, &temp, sizeof(temp));
142 data += sizeof(temp);
145 memcpy( data, src, aint );
155 * FIXME: PDINFO is UTF8 and doesn't need adp
157 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
158 (1 << FILPBIT_CDATE) |\
159 (1 << FILPBIT_MDATE) |\
160 (1 << FILPBIT_BDATE) |\
161 (1 << FILPBIT_FINFO) |\
162 (1 << FILPBIT_RFLEN) |\
163 (1 << FILPBIT_EXTRFLEN) |\
164 (1 << FILPBIT_PDINFO)))
166 /* -------------------------- */
167 u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st,
168 const cnid_t did, const char *upath, const int len)
172 #if AD_VERSION > AD_VERSION1
176 char stamp[ADEDLEN_PRIVSYN];
177 /* look in AD v2 header
178 * note inode and device are opaques and not in network order
181 && sizeof(dev_t) == ad_getentrylen(adp, ADEID_PRIVDEV)
182 && sizeof(ino_t) == ad_getentrylen(adp,ADEID_PRIVINO)
183 && sizeof(stamp) == ad_getentrylen(adp,ADEID_PRIVSYN)
184 && sizeof(cnid_t) == ad_getentrylen(adp, ADEID_DID)
185 && sizeof(cnid_t) == ad_getentrylen(adp, ADEID_PRIVID)
188 memcpy(&dev, ad_entry(adp, ADEID_PRIVDEV), sizeof(dev_t));
189 memcpy(&ino, ad_entry(adp, ADEID_PRIVINO), sizeof(ino_t));
190 memcpy(stamp, ad_entry(adp, ADEID_PRIVSYN), sizeof(stamp));
191 memcpy(&a_did, ad_entry(adp, ADEID_DID), sizeof(cnid_t));
193 if ( ( (vol->v_flags & AFPVOL_NODEV) || dev == st->st_dev)
194 && ino == st->st_ino && a_did == did
195 && !memcmp(vol->v_stamp, stamp, sizeof(stamp))) {
196 memcpy(&aint, ad_entry(adp, ADEID_PRIVID), sizeof(aint));
201 if (vol->v_cdb != NULL) {
202 aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
203 /* Throw errors if cnid_add fails. */
204 if (aint == CNID_INVALID) {
206 case CNID_ERR_CLOSE: /* the db is closed */
209 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
210 afp_errno = AFPERR_PARAM;
213 afp_errno = AFPERR_PARAM;
216 afp_errno = AFPERR_MISC;
220 #if AD_VERSION > AD_VERSION1
221 else if (adp && sizeof(dev_t) == ADEDLEN_PRIVDEV && sizeof(ino_t) == ADEDLEN_PRIVINO) {
222 /* update the ressource fork
223 * for a folder adp is always null
225 ad_setid(adp,(vol->v_flags & AFPVOL_NODEV)?0:st->st_dev, st->st_ino, aint, did, vol->v_stamp);
226 ad_flush(adp, ADFLAGS_HF);
233 /* -------------------------- */
234 int getmetadata(struct vol *vol,
236 struct path *path, struct dir *dir,
237 char *buf, int *buflen, struct adouble *adp, int attrbits )
239 char *data, *l_nameoff = NULL, *upath;
240 char *utf_nameoff = NULL;
245 u_char achar, fdType[4];
251 LOG(log_info, logtype_afpd, "begin getmetadata:");
254 upath = path->u_name;
259 if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
260 || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
261 || (bitmap & (1 << FILPBIT_FNUM))) {
263 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
267 path->m_name = utompath(vol, upath, id, utf8_encoding());
270 while ( bitmap != 0 ) {
271 while (( bitmap & 1 ) == 0 ) {
279 ad_getattr(adp, &ashort);
280 } else if (*upath == '.') {
281 ashort = htons(ATTRBIT_INVISIBLE);
285 /* FIXME do we want a visual clue if the file is read only
288 accessmode( ".", &ma, dir , NULL);
289 if ((ma.ma_user & AR_UWRITE)) {
290 accessmode( upath, &ma, dir , st);
291 if (!(ma.ma_user & AR_UWRITE)) {
292 attrbits |= ATTRBIT_NOWRITE;
297 ashort = htons(ntohs(ashort) | attrbits);
298 memcpy(data, &ashort, sizeof( ashort ));
299 data += sizeof( ashort );
303 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
304 data += sizeof( u_int32_t );
308 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
309 aint = AD_DATE_FROM_UNIX(st->st_mtime);
310 memcpy(data, &aint, sizeof( aint ));
311 data += sizeof( aint );
315 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
316 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
317 aint = AD_DATE_FROM_UNIX(st->st_mtime);
320 aint = AD_DATE_FROM_UNIX(st->st_mtime);
322 memcpy(data, &aint, sizeof( int ));
323 data += sizeof( int );
327 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
328 aint = AD_DATE_START;
329 memcpy(data, &aint, sizeof( int ));
330 data += sizeof( int );
334 get_finderinfo(path->m_name, adp, (char *)data);
336 if (*upath == '.') { /* make it invisible */
337 ashort = htons(FINDERINFO_INVISIBLE);
338 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
346 data += sizeof( u_int16_t );
350 memset(data, 0, sizeof(u_int16_t));
351 data += sizeof( u_int16_t );
355 memcpy(data, &id, sizeof( id ));
356 data += sizeof( id );
360 if (st->st_size > 0xffffffff)
363 aint = htonl( st->st_size );
364 memcpy(data, &aint, sizeof( aint ));
365 data += sizeof( aint );
370 if (adp->ad_rlen > 0xffffffff)
373 aint = htonl( adp->ad_rlen);
377 memcpy(data, &aint, sizeof( aint ));
378 data += sizeof( aint );
381 /* Current client needs ProDOS info block for this file.
382 Use simple heuristic and let the Mac "type" string tell
383 us what the PD file code should be. Everything gets a
384 subtype of 0x0000 unless the original value was hashed
385 to "pXYZ" when we created it. See IA, Ver 2.
386 <shirsch@adelphia.net> */
387 case FILPBIT_PDINFO :
388 if (afp_version >= 30) { /* UTF8 name */
389 utf8 = kTextEncodingUTF8;
391 data += sizeof( u_int16_t );
393 memcpy(data, &aint, sizeof( aint ));
394 data += sizeof( aint );
398 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
400 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
404 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
408 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
412 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
416 else if ( fdType[0] == 'p' ) {
418 ashort = (fdType[2] * 256) + fdType[3];
432 memcpy(data, &ashort, sizeof( ashort ));
433 data += sizeof( ashort );
434 memset(data, 0, sizeof( ashort ));
435 data += sizeof( ashort );
438 case FILPBIT_EXTDFLEN:
439 aint = htonl(st->st_size >> 32);
440 memcpy(data, &aint, sizeof( aint ));
441 data += sizeof( aint );
442 aint = htonl(st->st_size);
443 memcpy(data, &aint, sizeof( aint ));
444 data += sizeof( aint );
446 case FILPBIT_EXTRFLEN:
449 aint = htonl(adp->ad_rlen >> 32);
450 memcpy(data, &aint, sizeof( aint ));
451 data += sizeof( aint );
453 aint = htonl(adp->ad_rlen);
454 memcpy(data, &aint, sizeof( aint ));
455 data += sizeof( aint );
457 case FILPBIT_UNIXPR :
458 /* accessmode may change st_mode with ACLs */
459 accessmode( upath, &ma, dir , st);
461 aint = htonl(st->st_uid);
462 memcpy( data, &aint, sizeof( aint ));
463 data += sizeof( aint );
464 aint = htonl(st->st_gid);
465 memcpy( data, &aint, sizeof( aint ));
466 data += sizeof( aint );
468 aint = htonl(st->st_mode);
469 memcpy( data, &aint, sizeof( aint ));
470 data += sizeof( aint );
472 *data++ = ma.ma_user;
473 *data++ = ma.ma_world;
474 *data++ = ma.ma_group;
475 *data++ = ma.ma_owner;
479 return( AFPERR_BITMAP );
485 ashort = htons( data - buf );
486 memcpy(l_nameoff, &ashort, sizeof( ashort ));
487 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
490 ashort = htons( data - buf );
491 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
492 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
494 *buflen = data - buf;
498 /* ----------------------- */
499 int getfilparams(struct vol *vol,
501 struct path *path, struct dir *dir,
502 char *buf, int *buflen )
504 struct adouble ad, *adp;
507 u_int16_t attrbits = 0;
512 LOG(log_info, logtype_default, "begin getfilparams:");
515 opened = PARAM_NEED_ADP(bitmap);
518 upath = path->u_name;
519 if ((of = of_findname(path))) {
521 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
522 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
524 ad_init(&ad, vol->v_adouble);
528 if ( ad_metadata( upath, 0, adp) < 0 ) {
531 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
532 upath, strerror(errno));
533 return AFPERR_ACCESS;
535 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
545 we need to check if the file is open by another process.
546 it's slow so we only do it if we have to:
547 - bitmap is requested.
548 - we don't already have the answer!
550 if ((bitmap & (1 << FILPBIT_ATTR))) {
551 if (!(attrbits & ATTRBIT_ROPEN)) {
552 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_ROPEN : 0;
553 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_ROPEN : 0;
555 if (!(attrbits & ATTRBIT_DOPEN)) {
556 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_DOPEN : 0;
557 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_DOPEN : 0;
562 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
564 ad_close( adp, ADFLAGS_HF );
567 LOG(log_info, logtype_afpd, "end getfilparams:");
573 /* ----------------------------- */
574 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
577 int ibuflen, *rbuflen;
579 struct adouble ad, *adp;
582 struct ofork *of = NULL;
584 int creatf, did, openf, retvalue = AFP_OK;
590 LOG(log_info, logtype_afpd, "begin afp_createfile:");
595 creatf = (unsigned char) *ibuf++;
597 memcpy(&vid, ibuf, sizeof( vid ));
598 ibuf += sizeof( vid );
600 if (NULL == ( vol = getvolbyvid( vid )) ) {
601 return( AFPERR_PARAM );
604 if (vol->v_flags & AFPVOL_RO)
607 memcpy(&did, ibuf, sizeof( did));
608 ibuf += sizeof( did );
610 if (NULL == ( dir = dirlookup( vol, did )) ) {
614 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
615 return get_afp_errno(AFPERR_PARAM);
618 if ( *s_path->m_name == '\0' ) {
619 return( AFPERR_BADTYPE );
622 upath = s_path->u_name;
623 if (0 != (ret = check_name(vol, upath)))
626 /* if upath is deleted we already in trouble anyway */
627 if ((of = of_findname(s_path))) {
630 ad_init(&ad, vol->v_adouble);
634 /* on a hard create, fail if file exists and is open */
637 openf = O_RDWR|O_CREAT|O_TRUNC;
639 /* on a soft create, if the file is open then ad_open won't fail
640 because open syscall is not called
645 openf = O_RDWR|O_CREAT|O_EXCL;
648 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
649 openf, 0666, adp) < 0 ) {
653 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
654 return ( AFPERR_NOOBJ );
656 return( AFPERR_EXIST );
658 return( AFPERR_ACCESS );
660 return( AFPERR_PARAM );
663 if ( ad_hfileno( adp ) == -1 ) {
664 /* on noadouble volumes, just creating the data fork is ok */
665 if (vol_noadouble(vol)) {
666 ad_close( adp, ADFLAGS_DF );
667 goto createfile_done;
669 /* FIXME with hard create on an existing file, we already
670 * corrupted the data file.
672 netatalk_unlink( upath );
673 ad_close( adp, ADFLAGS_DF );
674 return AFPERR_ACCESS;
677 path = s_path->m_name;
678 ad_setname(adp, path);
679 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
680 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
686 if (vol->v_flags & AFPVOL_DROPBOX) {
687 retvalue = matchfile2dirperms(upath, vol, did);
689 #endif /* DROPKLUDGE */
691 setvoltime(obj, vol );
694 LOG(log_info, logtype_afpd, "end afp_createfile");
700 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
703 int ibuflen, *rbuflen;
709 u_int16_t vid, bitmap;
712 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
718 memcpy(&vid, ibuf, sizeof( vid ));
719 ibuf += sizeof( vid );
720 if (NULL == ( vol = getvolbyvid( vid )) ) {
721 return( AFPERR_PARAM );
724 if (vol->v_flags & AFPVOL_RO)
727 memcpy(&did, ibuf, sizeof( did ));
728 ibuf += sizeof( did );
729 if (NULL == ( dir = dirlookup( vol, did )) ) {
730 return afp_errno; /* was AFPERR_NOOBJ */
733 memcpy(&bitmap, ibuf, sizeof( bitmap ));
734 bitmap = ntohs( bitmap );
735 ibuf += sizeof( bitmap );
737 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
738 return get_afp_errno(AFPERR_PARAM);
741 if (path_isadir(s_path)) {
742 return( AFPERR_BADTYPE ); /* it's a directory */
745 if ( s_path->st_errno != 0 ) {
746 return( AFPERR_NOOBJ );
749 if ((u_long)ibuf & 1 ) {
753 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
754 setvoltime(obj, vol );
758 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
765 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
768 extern struct path Cur_Path;
770 int setfilparams(struct vol *vol,
771 struct path *path, u_int16_t f_bitmap, char *buf )
773 struct adouble ad, *adp;
776 int bit, isad = 1, err = AFP_OK;
778 u_char achar, *fdType, xyy[4];
779 u_int16_t ashort, bshort;
782 u_int16_t upriv_bit = 0;
786 int change_mdate = 0;
787 int change_parent_mdate = 0;
792 u_int16_t bitmap = f_bitmap;
793 u_int32_t cdate,bdate;
794 u_char finder_buf[32];
797 LOG(log_info, logtype_afpd, "begin setfilparams:");
800 upath = path->u_name;
801 if ((of = of_findname(path))) {
804 ad_init(&ad, vol->v_adouble);
808 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
809 return AFPERR_ACCESS;
812 /* with unix priv maybe we have to change adouble file priv first */
814 while ( bitmap != 0 ) {
815 while (( bitmap & 1 ) == 0 ) {
822 memcpy(&ashort, buf, sizeof( ashort ));
823 if ((ashort & htons(ATTRBIT_INVISIBLE)))
824 change_parent_mdate = 1;
825 buf += sizeof( ashort );
829 memcpy(&cdate, buf, sizeof(cdate));
830 buf += sizeof( cdate );
833 memcpy(&newdate, buf, sizeof( newdate ));
834 buf += sizeof( newdate );
838 memcpy(&bdate, buf, sizeof( bdate));
839 buf += sizeof( bdate );
843 memcpy(finder_buf, buf, 32 );
846 case FILPBIT_UNIXPR :
847 if (!vol_unix_priv(vol)) {
848 /* this volume doesn't use unix priv */
854 change_parent_mdate = 1;
856 memcpy( &aint, buf, sizeof( aint ));
857 f_uid = ntohl (aint);
858 buf += sizeof( aint );
859 memcpy( &aint, buf, sizeof( aint ));
860 f_gid = ntohl (aint);
861 buf += sizeof( aint );
862 setfilowner(vol, f_uid, f_gid, path);
864 memcpy( &upriv, buf, sizeof( upriv ));
865 buf += sizeof( upriv );
866 upriv = ntohl (upriv);
867 if ((upriv & S_IWUSR)) {
868 setfilunixmode(vol, path, upriv);
875 case FILPBIT_PDINFO :
876 if (afp_version < 30) { /* else it's UTF8 name */
879 /* Keep special case to support crlf translations */
880 if ((unsigned int) achar == 0x04) {
881 fdType = (u_char *)"TEXT";
884 xyy[0] = ( u_char ) 'p';
895 /* break while loop */
904 /* second try with adouble open
906 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
907 O_RDWR|O_CREAT, 0666, adp) < 0) {
908 /* for some things, we don't need an adouble header */
909 if (f_bitmap & ~(1<<FILPBIT_MDATE)) {
910 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
913 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
914 ad_setname(adp, path->m_name);
919 while ( bitmap != 0 ) {
920 while (( bitmap & 1 ) == 0 ) {
927 ad_getattr(adp, &bshort);
928 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
929 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
933 ad_setattr(adp, bshort);
936 ad_setdate(adp, AD_DATE_CREATE, cdate);
941 ad_setdate(adp, AD_DATE_BACKUP, bdate);
944 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
946 ((em = getextmap( path->m_name )) &&
947 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
948 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
949 || ((em = getdefextmap()) &&
950 !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
951 !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
953 memcpy(finder_buf, ufinderi, 8 );
956 memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
958 case FILPBIT_UNIXPR :
960 setfilunixmode(vol, path, upriv);
963 case FILPBIT_PDINFO :
964 if (afp_version < 30) { /* else it's UTF8 name */
965 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
966 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
972 goto setfilparam_done;
979 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
980 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
984 ad_setdate(adp, AD_DATE_MODIFY, newdate);
985 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
990 ad_flush( adp, ADFLAGS_HF );
991 ad_close( adp, ADFLAGS_HF );
995 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
996 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
997 bitmap = 1<<FILPBIT_MDATE;
998 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
1002 LOG(log_info, logtype_afpd, "end setfilparams:");
1008 * renamefile and copyfile take the old and new unix pathnames
1009 * and the new mac name.
1011 * src the source path
1012 * dst the dest filename in current dir
1013 * newname the dest mac name
1014 * adp adouble struct of src file, if open, or & zeroed one
1017 int renamefile(vol, src, dst, newname, adp )
1018 const struct vol *vol;
1019 char *src, *dst, *newname;
1020 struct adouble *adp;
1022 char adsrc[ MAXPATHLEN + 1];
1026 LOG(log_info, logtype_afpd, "begin renamefile:");
1029 if ( unix_rename( src, dst ) < 0 ) {
1032 return( AFPERR_NOOBJ );
1035 return( AFPERR_ACCESS );
1037 return AFPERR_VLOCK;
1038 case EXDEV : /* Cross device move -- try copy */
1039 /* NOTE: with open file it's an error because after the copy we will
1040 * get two files, it's fixable for our process (eg reopen the new file, get the
1041 * locks, and so on. But it doesn't solve the case with a second process
1043 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
1044 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
1045 return AFPERR_OLOCK; /* little lie */
1047 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname )) ) {
1048 /* on error copyfile delete dest */
1051 return deletefile(vol, src, 0);
1053 return( AFPERR_PARAM );
1057 strcpy( adsrc, vol->ad_path( src, 0 ));
1059 if (unix_rename( adsrc, vol->ad_path( dst, 0 )) < 0 ) {
1064 if (errno == ENOENT) {
1067 if (stat(adsrc, &st)) /* source has no ressource fork, */
1070 /* We are here because :
1071 * -there's no dest folder.
1072 * -there's no .AppleDouble in the dest folder.
1073 * if we use the struct adouble passed in parameter it will not
1074 * create .AppleDouble if the file is already opened, so we
1075 * use a diff one, it's not a pb,ie it's not the same file, yet.
1077 ad_init(&ad, vol->v_adouble);
1078 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
1079 ad_close(&ad, ADFLAGS_HF);
1080 if (!unix_rename( adsrc, vol->ad_path( dst, 0 )) )
1085 else { /* it's something else, bail out */
1089 /* try to undo the data fork rename,
1090 * we know we are on the same device
1093 unix_rename( dst, src );
1094 /* return the first error */
1097 return AFPERR_NOOBJ;
1100 return AFPERR_ACCESS ;
1102 return AFPERR_VLOCK;
1104 return AFPERR_PARAM ;
1109 /* don't care if we can't open the newly renamed ressource fork
1111 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1112 ad_setname(adp, newname);
1113 ad_flush( adp, ADFLAGS_HF );
1114 ad_close( adp, ADFLAGS_HF );
1117 LOG(log_info, logtype_afpd, "end renamefile:");
1123 int copy_path_name(char *newname, char *ibuf)
1130 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1136 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1137 strncpy( newname, ibuf, plen );
1138 newname[ plen ] = '\0';
1139 if (strlen(newname) != plen) {
1140 /* there's \0 in newname, e.g. it's a pathname not
1148 memcpy(&hint, ibuf, sizeof(hint));
1149 ibuf += sizeof(hint);
1151 memcpy(&len16, ibuf, sizeof(len16));
1152 ibuf += sizeof(len16);
1153 plen = ntohs(len16);
1156 if (plen > AFPOBJ_TMPSIZ) {
1159 strncpy( newname, ibuf, plen );
1160 newname[ plen ] = '\0';
1161 if (strlen(newname) != plen) {
1170 /* -----------------------------------
1172 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1175 int ibuflen, *rbuflen;
1177 struct vol *s_vol, *d_vol;
1179 char *newname, *p, *upath;
1180 struct path *s_path;
1181 u_int32_t sdid, ddid;
1182 int err, retvalue = AFP_OK;
1183 u_int16_t svid, dvid;
1186 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1192 memcpy(&svid, ibuf, sizeof( svid ));
1193 ibuf += sizeof( svid );
1194 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1195 return( AFPERR_PARAM );
1198 memcpy(&sdid, ibuf, sizeof( sdid ));
1199 ibuf += sizeof( sdid );
1200 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1204 memcpy(&dvid, ibuf, sizeof( dvid ));
1205 ibuf += sizeof( dvid );
1206 memcpy(&ddid, ibuf, sizeof( ddid ));
1207 ibuf += sizeof( ddid );
1209 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1210 return get_afp_errno(AFPERR_PARAM);
1212 if ( path_isadir(s_path) ) {
1213 return( AFPERR_BADTYPE );
1216 /* don't allow copies when the file is open.
1217 * XXX: the spec only calls for read/deny write access.
1218 * however, copyfile doesn't have any of that info,
1219 * and locks need to stay coherent. as a result,
1220 * we just balk if the file is opened already. */
1222 newname = obj->newtmp;
1223 strcpy( newname, s_path->m_name );
1225 if (of_findname(s_path))
1226 return AFPERR_DENYCONF;
1228 p = ctoupath( s_vol, curdir, newname );
1230 return AFPERR_PARAM;
1234 /* FIXME svid != dvid && dvid's user can't read svid */
1236 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1237 return( AFPERR_PARAM );
1240 if (d_vol->v_flags & AFPVOL_RO)
1241 return AFPERR_VLOCK;
1243 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1247 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1248 return get_afp_errno(AFPERR_NOOBJ);
1250 if ( *s_path->m_name != '\0' ) {
1251 path_error(s_path, AFPERR_PARAM);
1254 /* one of the handful of places that knows about the path type */
1255 if (copy_path_name(newname, ibuf) < 0) {
1256 return( AFPERR_PARAM );
1258 /* newname is always only a filename so curdir *is* its
1261 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1262 return( AFPERR_PARAM );
1264 if ( (err = copyfile(s_vol, d_vol, p, upath , newname)) < 0 ) {
1270 if (vol->v_flags & AFPVOL_DROPBOX) {
1271 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1273 #endif /* DROPKLUDGE */
1275 setvoltime(obj, d_vol );
1278 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1284 /* ----------------------- */
1285 static __inline__ int copy_all(const int dfd, const void *buf,
1291 LOG(log_info, logtype_afpd, "begin copy_all:");
1294 while (buflen > 0) {
1295 if ((cc = write(dfd, buf, buflen)) < 0) {
1307 LOG(log_info, logtype_afpd, "end copy_all:");
1313 /* -------------------------- */
1314 static int copy_fd(int dfd, int sfd)
1320 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1321 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1325 #define BUF 128*1024*1024
1327 if (fstat(sfd, &st) == 0) {
1330 if ( offset >= st.st_size) {
1333 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1334 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1337 case EINVAL: /* there's no guarantee that all fs support sendfile */
1346 lseek(sfd, offset, SEEK_SET);
1350 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1357 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1364 /* ----------------------------------
1365 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1366 * because we are doing it elsewhere.
1368 int copyfile(s_vol, d_vol, src, dst, newname )
1369 const struct vol *s_vol, *d_vol;
1370 char *src, *dst, *newname;
1372 struct adouble ads, add;
1376 int noadouble = vol_noadouble(d_vol);
1380 LOG(log_info, logtype_afpd, "begin copyfile:");
1383 ad_init(&ads, s_vol->v_adouble);
1384 ad_init(&add, d_vol->v_adouble);
1385 adflags = ADFLAGS_DF;
1387 adflags |= ADFLAGS_HF;
1390 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1395 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1397 ad_close( &ads, adflags );
1398 if (EEXIST != ret_err) {
1399 deletefile(d_vol, dst, 0);
1402 return AFPERR_EXIST;
1404 if (ad_hfileno(&ads) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1405 /* copy the data fork */
1406 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1409 /* Now, reopen destination file */
1413 ad_close( &ads, adflags );
1415 if (ad_close( &add, adflags ) <0) {
1416 deletefile(d_vol, dst, 0);
1421 ad_init(&add, d_vol->v_adouble);
1422 if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
1427 if (!ret_err && newname) {
1428 ad_setname(&add, newname);
1431 ad_flush( &add, adflags );
1432 if (ad_close( &add, adflags ) <0) {
1436 deletefile(d_vol, dst, 0);
1439 /* set dest modification date to src date */
1440 if (!stat(src, &st)) {
1443 ut.actime = ut.modtime = st.st_mtime;
1448 LOG(log_info, logtype_afpd, "end copyfile:");
1452 switch ( ret_err ) {
1458 return AFPERR_DFULL;
1460 return AFPERR_NOOBJ;
1462 return AFPERR_ACCESS;
1464 return AFPERR_VLOCK;
1466 return AFPERR_PARAM;
1470 /* -----------------------------------
1471 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1472 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1474 when deletefile is called we don't have lock on it, file is closed (for us)
1475 untrue if called by renamefile
1477 ad_open always try to open file RDWR first and ad_lock takes care of
1478 WRITE lock on read only file.
1480 int deletefile( vol, file, checkAttrib )
1481 const struct vol *vol;
1486 struct adouble *adp = &ad;
1487 int adflags, err = AFP_OK;
1490 LOG(log_info, logtype_afpd, "begin deletefile:");
1493 /* try to open both forks at once */
1494 adflags = ADFLAGS_DF|ADFLAGS_HF;
1496 ad_init(&ad, vol->v_adouble); /* OK */
1497 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1500 if (adflags == ADFLAGS_DF)
1501 return AFPERR_NOOBJ;
1503 /* that failed. now try to open just the data fork */
1504 adflags = ADFLAGS_DF;
1508 adp = NULL; /* maybe it's a file we no rw mode for us */
1509 break; /* was return AFPERR_ACCESS;*/
1511 return AFPERR_VLOCK;
1513 return( AFPERR_PARAM );
1516 break; /* from the while */
1519 * Does kFPDeleteInhibitBit (bit 8) set?
1524 if (adp && (adflags & ADFLAGS_HF)) {
1526 ad_getattr(&ad, &bshort);
1527 if ((bshort & htons(ATTRBIT_NODELETE))) {
1528 ad_close( &ad, adflags );
1529 return(AFPERR_OLOCK);
1533 /* was EACCESS error try to get only metadata */
1534 ad_init(&ad, vol->v_adouble); /* OK */
1535 if ( ad_metadata( file , 0, &ad) == 0 ) {
1536 ad_getattr(&ad, &bshort);
1537 ad_close( &ad, ADFLAGS_HF );
1538 if ((bshort & htons(ATTRBIT_NODELETE))) {
1539 return AFPERR_OLOCK;
1545 if (adp && (adflags & ADFLAGS_HF) ) {
1546 /* FIXME we have a pb here because we want to know if a file is open
1547 * there's a 'priority inversion' if you can't open the ressource fork RW
1548 * you can delete it if it's open because you can't get a write lock.
1550 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1553 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1555 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1556 ad_close( &ad, adflags );
1557 return( AFPERR_BUSY );
1561 if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1564 else if (!(err = netatalk_unlink( vol->ad_path( file, ADFLAGS_HF)) ) &&
1565 !(err = netatalk_unlink( file )) ) {
1567 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1569 cnid_delete(vol->v_cdb, id);
1574 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1577 LOG(log_info, logtype_afpd, "end deletefile:");
1583 /* ------------------------------------ */
1584 /* return a file id */
1585 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1588 int ibuflen, *rbuflen;
1597 struct path *s_path;
1600 LOG(log_info, logtype_afpd, "begin afp_createid:");
1607 memcpy(&vid, ibuf, sizeof(vid));
1608 ibuf += sizeof(vid);
1610 if (NULL == ( vol = getvolbyvid( vid )) ) {
1611 return( AFPERR_PARAM);
1614 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1618 if (vol->v_flags & AFPVOL_RO)
1619 return AFPERR_VLOCK;
1621 memcpy(&did, ibuf, sizeof( did ));
1622 ibuf += sizeof(did);
1624 if (NULL == ( dir = dirlookup( vol, did )) ) {
1625 return afp_errno; /* was AFPERR_PARAM */
1628 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1629 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1632 if ( path_isadir(s_path) ) {
1633 return( AFPERR_BADTYPE );
1636 upath = s_path->u_name;
1637 switch (s_path->st_errno) {
1639 break; /* success */
1642 return AFPERR_ACCESS;
1644 return AFPERR_NOOBJ;
1646 return AFPERR_PARAM;
1649 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1650 memcpy(rbuf, &id, sizeof(id));
1651 *rbuflen = sizeof(id);
1652 return AFPERR_EXISTID;
1655 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1656 memcpy(rbuf, &id, sizeof(id));
1657 *rbuflen = sizeof(id);
1662 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1668 reenumerate_id(const struct vol *vol, char *name, cnid_t did)
1676 memset(&path, 0, sizeof(path));
1677 if (vol->v_cdb == NULL) {
1680 if (NULL == ( dp = opendir( name)) ) {
1684 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
1685 if (NULL == check_dirent(vol, de->d_name))
1688 if ( stat(de->d_name, &path.st)<0 )
1691 /* update or add to cnid */
1692 aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1694 #if AD_VERSION > AD_VERSION1
1695 if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1697 struct adouble ad, *adp;
1701 path.u_name = de->d_name;
1703 if (!(of = of_findname(&path))) {
1704 ad_init(&ad, vol->v_adouble);
1709 if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, adp ) < 0 ) {
1712 ad_setid(adp,(vol->v_flags & AFPVOL_NODEV)?0:path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp);
1713 ad_flush(adp, ADFLAGS_HF);
1714 ad_close(adp, ADFLAGS_HF);
1716 #endif /* AD_VERSION > AD_VERSION1 */
1725 /* ------------------------------
1726 resolve a file id */
1727 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1730 int ibuflen, *rbuflen;
1736 int err, buflen, retry=0;
1738 u_int16_t vid, bitmap;
1740 static char buffer[12 + MAXPATHLEN + 1];
1741 int len = 12 + MAXPATHLEN + 1;
1744 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1750 memcpy(&vid, ibuf, sizeof(vid));
1751 ibuf += sizeof(vid);
1753 if (NULL == ( vol = getvolbyvid( vid )) ) {
1754 return( AFPERR_PARAM);
1757 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1761 memcpy(&id, ibuf, sizeof( id ));
1766 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1767 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1770 if (NULL == ( dir = dirlookup( vol, id )) ) {
1771 return AFPERR_NOID; /* idem AFPERR_PARAM */
1773 path.u_name = upath;
1774 if (movecwd(vol, dir) < 0) {
1778 return AFPERR_ACCESS;
1782 return AFPERR_PARAM;
1786 if ( of_stat(&path) < 0 ) {
1787 if ( errno == ENOENT && !retry) {
1788 /* cnid db is out of sync, reenumerate the directory and updated ids */
1789 reenumerate_id(vol, ".", id);
1797 return AFPERR_ACCESS;
1801 return AFPERR_PARAM;
1805 /* directories are bad */
1806 if (S_ISDIR(path.st.st_mode))
1807 return AFPERR_BADTYPE;
1809 memcpy(&bitmap, ibuf, sizeof(bitmap));
1810 bitmap = ntohs( bitmap );
1811 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1814 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1815 rbuf + sizeof(bitmap), &buflen))) {
1818 *rbuflen = buflen + sizeof(bitmap);
1819 memcpy(rbuf, ibuf, sizeof(bitmap));
1822 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1828 /* ------------------------------ */
1829 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1832 int ibuflen, *rbuflen;
1842 static char buffer[12 + MAXPATHLEN + 1];
1843 int len = 12 + MAXPATHLEN + 1;
1846 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1852 memcpy(&vid, ibuf, sizeof(vid));
1853 ibuf += sizeof(vid);
1855 if (NULL == ( vol = getvolbyvid( vid )) ) {
1856 return( AFPERR_PARAM);
1859 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1863 if (vol->v_flags & AFPVOL_RO)
1864 return AFPERR_VLOCK;
1866 memcpy(&id, ibuf, sizeof( id ));
1870 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1874 if (NULL == ( dir = dirlookup( vol, id )) ) {
1875 return( AFPERR_PARAM );
1879 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1883 return AFPERR_ACCESS;
1885 /* still try to delete the id */
1889 return AFPERR_PARAM;
1892 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1893 return AFPERR_BADTYPE;
1895 if (cnid_delete(vol->v_cdb, fileid)) {
1898 return AFPERR_VLOCK;
1901 return AFPERR_ACCESS;
1903 return AFPERR_PARAM;
1908 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1914 /* ------------------------------ */
1915 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1917 if (path->st_errno) {
1918 switch (path->st_errno) {
1920 afp_errno = AFPERR_NOID;
1924 afp_errno = AFPERR_ACCESS;
1927 afp_errno = AFPERR_PARAM;
1933 if ((*of = of_findname(path))) {
1934 /* reuse struct adouble so it won't break locks */
1938 ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
1940 if ( ad_hfileno( adp ) != -1
1941 && !(adp->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))
1942 && sizeof(dev_t) == ad_getentrylen(adp, ADEID_PRIVDEV)
1943 && sizeof(ino_t) == ad_getentrylen(adp,ADEID_PRIVINO)
1945 /* it's an adouble version 2 with cached resource fork
1946 * but the file is not open RW so we can't update cnid
1948 afp_errno = AFPERR_ACCESS;
1954 #define APPLETEMP ".AppleTempXXXXXX"
1956 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1959 int ibuflen, *rbuflen;
1961 struct stat srcst, destst;
1963 struct dir *dir, *sdir;
1964 char *spath, temp[17], *p;
1965 char *supath, *upath;
1970 struct adouble *adsp;
1971 struct adouble *addp;
1984 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1990 memcpy(&vid, ibuf, sizeof(vid));
1991 ibuf += sizeof(vid);
1993 if (NULL == ( vol = getvolbyvid( vid )) ) {
1994 return( AFPERR_PARAM);
1997 if ((vol->v_flags & AFPVOL_RO))
1998 return AFPERR_VLOCK;
2000 /* source and destination dids */
2001 memcpy(&sid, ibuf, sizeof(sid));
2002 ibuf += sizeof(sid);
2003 memcpy(&did, ibuf, sizeof(did));
2004 ibuf += sizeof(did);
2007 if (NULL == (dir = dirlookup( vol, sid )) ) {
2008 return afp_errno; /* was AFPERR_PARAM */
2011 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2012 return get_afp_errno(AFPERR_NOOBJ);
2015 if ( path_isadir(path) ) {
2016 return AFPERR_BADTYPE; /* it's a dir */
2020 * here do we need to switch to root ?
2023 ad_init(&ads, vol->v_adouble);
2024 if (!(adsp = find_adouble( path, &s_of, &ads))) {
2028 /* save some stuff */
2031 spath = obj->oldtmp;
2032 supath = obj->newtmp;
2033 strcpy(spath, path->m_name);
2034 upath = path->u_name;
2035 strcpy(supath, upath); /* this is for the cnid changing */
2036 p = absupath( vol, sdir, upath);
2038 /* pathname too long */
2039 return AFPERR_PARAM ;
2042 /* look for the source cnid. if it doesn't exist, don't worry about
2044 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2046 if (NULL == ( dir = dirlookup( vol, did )) ) {
2047 return afp_errno; /* was AFPERR_PARAM */
2050 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2051 return get_afp_errno(AFPERR_NOOBJ);
2054 if ( path_isadir(path) ) {
2055 return AFPERR_BADTYPE;
2058 /* FPExchangeFiles is the only call that can return the SameObj
2060 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
2061 return AFPERR_SAMEOBJ;
2063 ad_init(&add, vol->v_adouble);
2064 if (!(addp = find_adouble( path, &d_of, &add))) {
2069 /* they are not on the same device and at least one is open
2071 crossdev = (srcst.st_dev != destst.st_dev);
2072 if ((d_of || s_of) && crossdev)
2075 /* look for destination id. */
2076 upath = path->u_name;
2077 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2079 /* construct a temp name.
2080 * NOTE: the temp file will be in the dest file's directory. it
2081 * will also be inaccessible from AFP. */
2082 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2086 /* now, quickly rename the file. we error if we can't. */
2087 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2088 goto err_exchangefile;
2089 of_rename(vol, s_of, sdir, spath, curdir, temp);
2091 /* rename destination to source */
2092 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2093 goto err_src_to_tmp;
2094 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2096 /* rename temp to destination */
2097 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2098 goto err_dest_to_src;
2099 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2101 /* id's need switching. src -> dest and dest -> src.
2102 * we need to re-stat() if it was a cross device copy.
2105 cnid_delete(vol->v_cdb, sid);
2108 cnid_delete(vol->v_cdb, did);
2110 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2111 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2113 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2114 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2119 err = AFPERR_ACCESS;
2124 goto err_temp_to_dest;
2127 ad_setid(addp,(vol->v_flags & AFPVOL_NODEV)?0:destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp);
2129 ad_setid(adsp,(vol->v_flags & AFPVOL_NODEV)?0:srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp);
2132 ad_flush( adsp, ADFLAGS_HF );
2133 ad_close(adsp, ADFLAGS_HF);
2136 ad_flush( addp, ADFLAGS_HF );
2137 ad_close(addp, ADFLAGS_HF);
2140 /* change perms, src gets dest perm and vice versa */
2145 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2146 return AFP_OK; /* ignore error */
2150 * we need to exchange ACL entries as well
2152 /* exchange_acls(vol, p, upath); */
2157 path->m_name = NULL;
2158 path->u_name = upath;
2160 setfilunixmode(vol, path, destst.st_mode);
2161 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2168 setfilunixmode(vol, path, srcst.st_mode);
2169 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2171 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2172 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2177 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2182 /* all this stuff is so that we can unwind a failed operation
2185 /* rename dest to temp */
2186 renamefile(vol, upath, temp, temp, adsp);
2187 of_rename(vol, s_of, curdir, upath, curdir, temp);
2190 /* rename source back to dest */
2191 renamefile(vol, p, upath, path->m_name, addp);
2192 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2195 /* rename temp back to source */
2196 renamefile(vol, temp, p, spath, adsp);
2197 of_rename(vol, s_of, curdir, temp, sdir, spath);