2 * $Id: file.c,v 1.92.2.2.2.24 2004-05-04 15:38:24 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 );
473 *data++ = ma.ma_user;
474 *data++ = ma.ma_world;
475 *data++ = ma.ma_group;
476 *data++ = ma.ma_owner;
480 return( AFPERR_BITMAP );
486 ashort = htons( data - buf );
487 memcpy(l_nameoff, &ashort, sizeof( ashort ));
488 data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
491 ashort = htons( data - buf );
492 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
493 data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
495 *buflen = data - buf;
499 /* ----------------------- */
500 int getfilparams(struct vol *vol,
502 struct path *path, struct dir *dir,
503 char *buf, int *buflen )
505 struct adouble ad, *adp;
508 u_int16_t attrbits = 0;
513 LOG(log_info, logtype_default, "begin getfilparams:");
516 opened = PARAM_NEED_ADP(bitmap);
519 upath = path->u_name;
520 if ((of = of_findname(path))) {
522 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
523 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
525 ad_init(&ad, vol->v_adouble);
529 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
534 we need to check if the file is open by another process.
535 it's slow so we only do it if we have to:
536 - bitmap is requested.
537 - we don't already have the answer!
539 if ((bitmap & (1 << FILPBIT_ATTR))) {
540 if (!(attrbits & ATTRBIT_ROPEN)) {
541 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_ROPEN : 0;
542 attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_ROPEN : 0;
544 if (!(attrbits & ATTRBIT_DOPEN)) {
545 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_DOPEN : 0;
546 attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_DOPEN : 0;
551 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
553 ad_close( adp, ADFLAGS_HF );
556 LOG(log_info, logtype_afpd, "end getfilparams:");
562 /* ----------------------------- */
563 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
566 int ibuflen, *rbuflen;
568 struct adouble ad, *adp;
571 struct ofork *of = NULL;
573 int creatf, did, openf, retvalue = AFP_OK;
579 LOG(log_info, logtype_afpd, "begin afp_createfile:");
584 creatf = (unsigned char) *ibuf++;
586 memcpy(&vid, ibuf, sizeof( vid ));
587 ibuf += sizeof( vid );
589 if (NULL == ( vol = getvolbyvid( vid )) ) {
590 return( AFPERR_PARAM );
593 if (vol->v_flags & AFPVOL_RO)
596 memcpy(&did, ibuf, sizeof( did));
597 ibuf += sizeof( did );
599 if (NULL == ( dir = dirlookup( vol, did )) ) {
603 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
604 return get_afp_errno(AFPERR_PARAM);
607 if ( *s_path->m_name == '\0' ) {
608 return( AFPERR_BADTYPE );
611 upath = s_path->u_name;
612 if (0 != (ret = check_name(vol, upath)))
615 /* if upath is deleted we already in trouble anyway */
616 if ((of = of_findname(s_path))) {
619 ad_init(&ad, vol->v_adouble);
623 /* on a hard create, fail if file exists and is open */
626 openf = O_RDWR|O_CREAT|O_TRUNC;
628 /* on a soft create, if the file is open then ad_open won't fail
629 because open syscall is not called
634 openf = O_RDWR|O_CREAT|O_EXCL;
637 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
638 openf, 0666, adp) < 0 ) {
642 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
643 return ( AFPERR_NOOBJ );
645 return( AFPERR_EXIST );
647 return( AFPERR_ACCESS );
649 return( AFPERR_PARAM );
652 if ( ad_hfileno( adp ) == -1 ) {
653 /* on noadouble volumes, just creating the data fork is ok */
654 if (vol_noadouble(vol)) {
655 ad_close( adp, ADFLAGS_DF );
656 goto createfile_done;
658 /* FIXME with hard create on an existing file, we already
659 * corrupted the data file.
661 netatalk_unlink( upath );
662 ad_close( adp, ADFLAGS_DF );
663 return AFPERR_ACCESS;
666 path = s_path->m_name;
667 ad_setname(adp, path);
668 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
669 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
675 if (vol->v_flags & AFPVOL_DROPBOX) {
676 retvalue = matchfile2dirperms(upath, vol, did);
678 #endif /* DROPKLUDGE */
680 setvoltime(obj, vol );
683 LOG(log_info, logtype_afpd, "end afp_createfile");
689 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
692 int ibuflen, *rbuflen;
698 u_int16_t vid, bitmap;
701 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
707 memcpy(&vid, ibuf, sizeof( vid ));
708 ibuf += sizeof( vid );
709 if (NULL == ( vol = getvolbyvid( vid )) ) {
710 return( AFPERR_PARAM );
713 if (vol->v_flags & AFPVOL_RO)
716 memcpy(&did, ibuf, sizeof( did ));
717 ibuf += sizeof( did );
718 if (NULL == ( dir = dirlookup( vol, did )) ) {
719 return afp_errno; /* was AFPERR_NOOBJ */
722 memcpy(&bitmap, ibuf, sizeof( bitmap ));
723 bitmap = ntohs( bitmap );
724 ibuf += sizeof( bitmap );
726 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
727 return get_afp_errno(AFPERR_PARAM);
730 if (path_isadir(s_path)) {
731 return( AFPERR_BADTYPE ); /* it's a directory */
734 if ( s_path->st_errno != 0 ) {
735 return( AFPERR_NOOBJ );
738 if ((u_long)ibuf & 1 ) {
742 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
743 setvoltime(obj, vol );
747 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
754 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
757 extern struct path Cur_Path;
759 int setfilparams(struct vol *vol,
760 struct path *path, u_int16_t bitmap, char *buf )
762 struct adouble ad, *adp;
765 int bit = 0, isad = 1, err = AFP_OK;
767 u_char achar, *fdType, xyy[4];
768 u_int16_t ashort, bshort;
772 int change_mdate = 0;
773 int change_parent_mdate = 0;
781 LOG(log_info, logtype_afpd, "begin setfilparams:");
784 upath = path->u_name;
785 if ((of = of_findname(path))) {
788 ad_init(&ad, vol->v_adouble);
792 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
793 return AFPERR_ACCESS;
796 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
797 O_RDWR|O_CREAT, 0666, adp) < 0) {
798 /* for some things, we don't need an adouble header */
799 if (bitmap & ~(1<<FILPBIT_MDATE)) {
800 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
803 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
804 ad_setname(adp, path->m_name);
807 while ( bitmap != 0 ) {
808 while (( bitmap & 1 ) == 0 ) {
816 memcpy(&ashort, buf, sizeof( ashort ));
817 ad_getattr(adp, &bshort);
818 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
819 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
823 if ((ashort & htons(ATTRBIT_INVISIBLE)))
824 change_parent_mdate = 1;
825 ad_setattr(adp, bshort);
826 buf += sizeof( ashort );
831 memcpy(&aint, buf, sizeof(aint));
832 ad_setdate(adp, AD_DATE_CREATE, aint);
833 buf += sizeof( aint );
837 memcpy(&newdate, buf, sizeof( newdate ));
838 buf += sizeof( newdate );
843 memcpy(&aint, buf, sizeof(aint));
844 ad_setdate(adp, AD_DATE_BACKUP, aint);
845 buf += sizeof( aint );
851 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
853 ((em = getextmap( path->m_name )) &&
854 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
855 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
856 || ((em = getdefextmap()) &&
857 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
858 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
860 memcpy(buf, ufinderi, 8 );
863 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
867 case FILPBIT_UNIXPR :
869 change_parent_mdate = 1;
871 memcpy( &aint, buf, sizeof( aint ));
872 f_uid = ntohl (aint);
873 buf += sizeof( aint );
874 memcpy( &aint, buf, sizeof( aint ));
875 f_gid = ntohl (aint);
876 buf += sizeof( aint );
877 setfilowner(vol, f_uid, f_gid, path);
879 memcpy( &aint, buf, sizeof( aint ));
880 buf += sizeof( aint );
882 setfilunixmode(vol, path, aint);
884 /* Client needs to set the ProDOS file info for this file.
885 Use a defined string for TEXT to support crlf
886 translations and convert all else into pXYY per Inside
887 Appletalk. Always set the creator as "pdos". Changes
888 from original by Marsha Jackson. */
889 case FILPBIT_PDINFO :
890 if (afp_version < 30) { /* else it's UTF8 name */
893 /* Keep special case to support crlf translations */
894 if ((unsigned int) achar == 0x04) {
895 fdType = (u_char *)"TEXT";
898 xyy[0] = ( u_char ) 'p';
904 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
905 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
911 goto setfilparam_done;
919 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
920 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
924 ad_setdate(adp, AD_DATE_MODIFY, newdate);
925 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
930 ad_flush( adp, ADFLAGS_HF );
931 ad_close( adp, ADFLAGS_HF );
935 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
936 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
937 bitmap = 1<<FILPBIT_MDATE;
938 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
942 LOG(log_info, logtype_afpd, "end setfilparams:");
948 * renamefile and copyfile take the old and new unix pathnames
949 * and the new mac name.
951 * src the source path
952 * dst the dest filename in current dir
953 * newname the dest mac name
954 * adp adouble struct of src file, if open, or & zeroed one
957 int renamefile(vol, src, dst, newname, adp )
958 const struct vol *vol;
959 char *src, *dst, *newname;
962 char adsrc[ MAXPATHLEN + 1];
966 LOG(log_info, logtype_afpd, "begin renamefile:");
969 if ( unix_rename( src, dst ) < 0 ) {
972 return( AFPERR_NOOBJ );
975 return( AFPERR_ACCESS );
978 case EXDEV : /* Cross device move -- try copy */
979 /* NOTE: with open file it's an error because after the copy we will
980 * get two files, it's fixable for our process (eg reopen the new file, get the
981 * locks, and so on. But it doesn't solve the case with a second process
983 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
984 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
985 return AFPERR_OLOCK; /* little lie */
987 if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname )) ) {
988 /* on error copyfile delete dest */
991 return deletefile(vol, src, 0);
993 return( AFPERR_PARAM );
997 strcpy( adsrc, vol->ad_path( src, 0 ));
999 if (unix_rename( adsrc, vol->ad_path( dst, 0 )) < 0 ) {
1004 if (errno == ENOENT) {
1007 if (stat(adsrc, &st)) /* source has no ressource fork, */
1010 /* We are here because :
1011 * -there's no dest folder.
1012 * -there's no .AppleDouble in the dest folder.
1013 * if we use the struct adouble passed in parameter it will not
1014 * create .AppleDouble if the file is already opened, so we
1015 * use a diff one, it's not a pb,ie it's not the same file, yet.
1017 ad_init(&ad, vol->v_adouble);
1018 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
1019 ad_close(&ad, ADFLAGS_HF);
1020 if (!unix_rename( adsrc, vol->ad_path( dst, 0 )) )
1025 else { /* it's something else, bail out */
1029 /* try to undo the data fork rename,
1030 * we know we are on the same device
1033 unix_rename( dst, src );
1034 /* return the first error */
1037 return AFPERR_NOOBJ;
1040 return AFPERR_ACCESS ;
1042 return AFPERR_VLOCK;
1044 return AFPERR_PARAM ;
1049 /* don't care if we can't open the newly renamed ressource fork
1051 if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1052 ad_setname(adp, newname);
1053 ad_flush( adp, ADFLAGS_HF );
1054 ad_close( adp, ADFLAGS_HF );
1057 LOG(log_info, logtype_afpd, "end renamefile:");
1063 int copy_path_name(char *newname, char *ibuf)
1070 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1076 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1077 strncpy( newname, ibuf, plen );
1078 newname[ plen ] = '\0';
1079 if (strlen(newname) != plen) {
1080 /* there's \0 in newname, e.g. it's a pathname not
1088 memcpy(&hint, ibuf, sizeof(hint));
1089 ibuf += sizeof(hint);
1091 memcpy(&len16, ibuf, sizeof(len16));
1092 ibuf += sizeof(len16);
1093 plen = ntohs(len16);
1096 if (plen > AFPOBJ_TMPSIZ) {
1099 strncpy( newname, ibuf, plen );
1100 newname[ plen ] = '\0';
1101 if (strlen(newname) != plen) {
1110 /* -----------------------------------
1112 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1115 int ibuflen, *rbuflen;
1117 struct vol *s_vol, *d_vol;
1119 char *newname, *p, *upath;
1120 struct path *s_path;
1121 u_int32_t sdid, ddid;
1122 int err, retvalue = AFP_OK;
1123 u_int16_t svid, dvid;
1126 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1132 memcpy(&svid, ibuf, sizeof( svid ));
1133 ibuf += sizeof( svid );
1134 if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1135 return( AFPERR_PARAM );
1138 memcpy(&sdid, ibuf, sizeof( sdid ));
1139 ibuf += sizeof( sdid );
1140 if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1144 memcpy(&dvid, ibuf, sizeof( dvid ));
1145 ibuf += sizeof( dvid );
1146 memcpy(&ddid, ibuf, sizeof( ddid ));
1147 ibuf += sizeof( ddid );
1149 if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1150 return get_afp_errno(AFPERR_PARAM);
1152 if ( path_isadir(s_path) ) {
1153 return( AFPERR_BADTYPE );
1156 /* don't allow copies when the file is open.
1157 * XXX: the spec only calls for read/deny write access.
1158 * however, copyfile doesn't have any of that info,
1159 * and locks need to stay coherent. as a result,
1160 * we just balk if the file is opened already. */
1162 newname = obj->newtmp;
1163 strcpy( newname, s_path->m_name );
1165 if (of_findname(s_path))
1166 return AFPERR_DENYCONF;
1168 p = ctoupath( s_vol, curdir, newname );
1170 return AFPERR_PARAM;
1174 /* FIXME svid != dvid && dvid's user can't read svid */
1176 if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1177 return( AFPERR_PARAM );
1180 if (d_vol->v_flags & AFPVOL_RO)
1181 return AFPERR_VLOCK;
1183 if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1187 if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1188 return get_afp_errno(AFPERR_NOOBJ);
1190 if ( *s_path->m_name != '\0' ) {
1192 return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1194 path_error(s_path, AFPERR_PARAM);
1197 /* one of the handful of places that knows about the path type */
1198 if (copy_path_name(newname, ibuf) < 0) {
1199 return( AFPERR_PARAM );
1201 /* newname is always only a filename so curdir *is* its
1204 if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1205 return( AFPERR_PARAM );
1207 if ( (err = copyfile(s_vol, d_vol, p, upath , newname)) < 0 ) {
1213 if (vol->v_flags & AFPVOL_DROPBOX) {
1214 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1216 #endif /* DROPKLUDGE */
1218 setvoltime(obj, d_vol );
1221 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1227 /* ----------------------- */
1228 static __inline__ int copy_all(const int dfd, const void *buf,
1234 LOG(log_info, logtype_afpd, "begin copy_all:");
1237 while (buflen > 0) {
1238 if ((cc = write(dfd, buf, buflen)) < 0) {
1250 LOG(log_info, logtype_afpd, "end copy_all:");
1256 /* -------------------------- */
1257 static int copy_fd(int dfd, int sfd)
1263 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1264 /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1268 #define BUF 128*1024*1024
1270 if (fstat(sfd, &st) == 0) {
1273 if ( offset >= st.st_size) {
1276 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1277 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1280 case EINVAL: /* there's no guarantee that all fs support sendfile */
1289 lseek(sfd, offset, SEEK_SET);
1293 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1300 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1307 /* ----------------------------------
1308 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1309 * because we are doing it elsewhere.
1311 int copyfile(s_vol, d_vol, src, dst, newname )
1312 const struct vol *s_vol, *d_vol;
1313 char *src, *dst, *newname;
1315 struct adouble ads, add;
1319 int noadouble = vol_noadouble(d_vol);
1323 LOG(log_info, logtype_afpd, "begin copyfile:");
1326 ad_init(&ads, s_vol->v_adouble);
1327 ad_init(&add, d_vol->v_adouble);
1328 adflags = ADFLAGS_DF;
1330 adflags |= ADFLAGS_HF;
1333 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1338 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1340 ad_close( &ads, adflags );
1341 if (EEXIST != ret_err) {
1342 deletefile(d_vol, dst, 0);
1345 return AFPERR_EXIST;
1347 if (ad_hfileno(&ads) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1348 /* copy the data fork */
1349 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1352 /* Now, reopen destination file */
1356 ad_close( &ads, adflags );
1358 if (ad_close( &add, adflags ) <0) {
1359 deletefile(d_vol, dst, 0);
1364 ad_init(&add, d_vol->v_adouble);
1365 if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
1370 if (!ret_err && newname) {
1371 ad_setname(&add, newname);
1374 ad_flush( &add, adflags );
1375 if (ad_close( &add, adflags ) <0) {
1379 deletefile(d_vol, dst, 0);
1382 /* set dest modification date to src date */
1383 if (!stat(src, &st)) {
1386 ut.actime = ut.modtime = st.st_mtime;
1391 LOG(log_info, logtype_afpd, "end copyfile:");
1395 switch ( ret_err ) {
1401 return AFPERR_DFULL;
1403 return AFPERR_NOOBJ;
1405 return AFPERR_ACCESS;
1407 return AFPERR_VLOCK;
1409 return AFPERR_PARAM;
1413 /* -----------------------------------
1414 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1415 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1417 when deletefile is called we don't have lock on it, file is closed (for us)
1418 untrue if called by renamefile
1420 ad_open always try to open file RDWR first and ad_lock takes care of
1421 WRITE lock on read only file.
1423 int deletefile( vol, file, checkAttrib )
1424 const struct vol *vol;
1429 int adflags, err = AFP_OK;
1432 LOG(log_info, logtype_afpd, "begin deletefile:");
1435 /* try to open both forks at once */
1436 adflags = ADFLAGS_DF|ADFLAGS_HF;
1438 ad_init(&ad, vol->v_adouble); /* OK */
1439 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1442 if (adflags == ADFLAGS_DF)
1443 return AFPERR_NOOBJ;
1445 /* that failed. now try to open just the data fork */
1446 adflags = ADFLAGS_DF;
1450 return AFPERR_ACCESS;
1452 return AFPERR_VLOCK;
1454 return( AFPERR_PARAM );
1457 break; /* from the while */
1460 * Does kFPDeleteInhibitBit (bit 8) set?
1462 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1465 ad_getattr(&ad, &bshort);
1466 if ((bshort & htons(ATTRBIT_NODELETE))) {
1467 ad_close( &ad, adflags );
1468 return(AFPERR_OLOCK);
1472 if ((adflags & ADFLAGS_HF) ) {
1473 /* FIXME we have a pb here because we want to know if a file is open
1474 * there's a 'priority inversion' if you can't open the ressource fork RW
1475 * you can delete it if it's open because you can't get a write lock.
1477 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1480 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1482 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1483 ad_close( &ad, adflags );
1484 return( AFPERR_BUSY );
1488 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1491 else if (!(err = netatalk_unlink( vol->ad_path( file, ADFLAGS_HF)) ) &&
1492 !(err = netatalk_unlink( file )) ) {
1494 if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1496 cnid_delete(vol->v_cdb, id);
1500 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1503 LOG(log_info, logtype_afpd, "end deletefile:");
1509 /* ------------------------------------ */
1510 /* return a file id */
1511 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1514 int ibuflen, *rbuflen;
1523 struct path *s_path;
1526 LOG(log_info, logtype_afpd, "begin afp_createid:");
1533 memcpy(&vid, ibuf, sizeof(vid));
1534 ibuf += sizeof(vid);
1536 if (NULL == ( vol = getvolbyvid( vid )) ) {
1537 return( AFPERR_PARAM);
1540 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1544 if (vol->v_flags & AFPVOL_RO)
1545 return AFPERR_VLOCK;
1547 memcpy(&did, ibuf, sizeof( did ));
1548 ibuf += sizeof(did);
1550 if (NULL == ( dir = dirlookup( vol, did )) ) {
1551 return afp_errno; /* was AFPERR_PARAM */
1554 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1555 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1558 if ( path_isadir(s_path) ) {
1559 return( AFPERR_BADTYPE );
1562 upath = s_path->u_name;
1563 switch (s_path->st_errno) {
1565 break; /* success */
1568 return AFPERR_ACCESS;
1570 return AFPERR_NOOBJ;
1572 return AFPERR_PARAM;
1575 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1576 memcpy(rbuf, &id, sizeof(id));
1577 *rbuflen = sizeof(id);
1578 return AFPERR_EXISTID;
1581 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1582 memcpy(rbuf, &id, sizeof(id));
1583 *rbuflen = sizeof(id);
1588 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1594 reenumerate_id(const struct vol *vol, char *name, cnid_t did)
1604 if (vol->v_cdb == NULL) {
1607 if (NULL == ( dp = opendir( name)) ) {
1611 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
1612 if (NULL == check_dirent(vol, de->d_name))
1615 if ( stat(de->d_name, &st)<0 )
1618 /* update or add to cnid */
1619 aint = cnid_add(vol->v_cdb, &st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1621 #if AD_VERSION > AD_VERSION1
1622 if (aint != CNID_INVALID && !S_ISDIR(st.st_mode)) {
1623 ad_init(&ad, 0); /* OK */
1624 if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, &ad ) < 0 ) {
1628 ad_setid(&ad,(vol->v_flags & AFPVOL_NODEV)?0:st.st_dev, st.st_ino, aint, did, vol->v_stamp);
1629 ad_flush(&ad, ADFLAGS_HF);
1630 ad_close(&ad, ADFLAGS_HF);
1633 #endif /* AD_VERSION > AD_VERSION1 */
1642 /* ------------------------------
1643 resolve a file id */
1644 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1647 int ibuflen, *rbuflen;
1653 int err, buflen, retry=0;
1655 u_int16_t vid, bitmap;
1657 static char buffer[12 + MAXPATHLEN + 1];
1658 int len = 12 + MAXPATHLEN + 1;
1661 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1667 memcpy(&vid, ibuf, sizeof(vid));
1668 ibuf += sizeof(vid);
1670 if (NULL == ( vol = getvolbyvid( vid )) ) {
1671 return( AFPERR_PARAM);
1674 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1678 memcpy(&id, ibuf, sizeof( id ));
1683 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1684 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1687 if (NULL == ( dir = dirlookup( vol, id )) ) {
1688 return AFPERR_NOID; /* idem AFPERR_PARAM */
1690 path.u_name = upath;
1691 if (movecwd(vol, dir) < 0) {
1695 return AFPERR_ACCESS;
1699 return AFPERR_PARAM;
1703 if ( of_stat(&path) < 0 ) {
1704 if ( errno == ENOENT && !retry) {
1705 /* cnid db is out of sync, reenumerate the directory and updated ids */
1706 reenumerate_id(vol, ".", id);
1714 return AFPERR_ACCESS;
1718 return AFPERR_PARAM;
1722 /* directories are bad */
1723 if (S_ISDIR(path.st.st_mode))
1724 return AFPERR_BADTYPE;
1726 memcpy(&bitmap, ibuf, sizeof(bitmap));
1727 bitmap = ntohs( bitmap );
1728 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1731 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1732 rbuf + sizeof(bitmap), &buflen))) {
1735 *rbuflen = buflen + sizeof(bitmap);
1736 memcpy(rbuf, ibuf, sizeof(bitmap));
1739 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1745 /* ------------------------------ */
1746 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1749 int ibuflen, *rbuflen;
1759 static char buffer[12 + MAXPATHLEN + 1];
1760 int len = 12 + MAXPATHLEN + 1;
1763 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1769 memcpy(&vid, ibuf, sizeof(vid));
1770 ibuf += sizeof(vid);
1772 if (NULL == ( vol = getvolbyvid( vid )) ) {
1773 return( AFPERR_PARAM);
1776 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1780 if (vol->v_flags & AFPVOL_RO)
1781 return AFPERR_VLOCK;
1783 memcpy(&id, ibuf, sizeof( id ));
1787 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1791 if (NULL == ( dir = dirlookup( vol, id )) ) {
1792 return( AFPERR_PARAM );
1796 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1800 return AFPERR_ACCESS;
1802 /* still try to delete the id */
1806 return AFPERR_PARAM;
1809 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1810 return AFPERR_BADTYPE;
1812 if (cnid_delete(vol->v_cdb, fileid)) {
1815 return AFPERR_VLOCK;
1818 return AFPERR_ACCESS;
1820 return AFPERR_PARAM;
1825 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1831 /* ------------------------------ */
1832 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1834 if (path->st_errno) {
1835 switch (path->st_errno) {
1837 afp_errno = AFPERR_NOID;
1841 afp_errno = AFPERR_ACCESS;
1844 afp_errno = AFPERR_PARAM;
1850 if ((*of = of_findname(path))) {
1851 /* reuse struct adouble so it won't break locks */
1855 ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
1857 if ( ad_hfileno( adp ) != -1
1858 && !(adp->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))
1859 && sizeof(dev_t) == ad_getentrylen(adp, ADEID_PRIVDEV)
1860 && sizeof(ino_t) == ad_getentrylen(adp,ADEID_PRIVINO)
1862 /* it's an adouble version 2 with cached resource fork
1863 * but the file is not open RW so we can't update cnid
1865 afp_errno = AFPERR_ACCESS;
1871 #define APPLETEMP ".AppleTempXXXXXX"
1873 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1876 int ibuflen, *rbuflen;
1878 struct stat srcst, destst;
1880 struct dir *dir, *sdir;
1881 char *spath, temp[17], *p;
1882 char *supath, *upath;
1887 struct adouble *adsp;
1888 struct adouble *addp;
1901 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1907 memcpy(&vid, ibuf, sizeof(vid));
1908 ibuf += sizeof(vid);
1910 if (NULL == ( vol = getvolbyvid( vid )) ) {
1911 return( AFPERR_PARAM);
1914 if ((vol->v_flags & AFPVOL_RO))
1915 return AFPERR_VLOCK;
1917 /* source and destination dids */
1918 memcpy(&sid, ibuf, sizeof(sid));
1919 ibuf += sizeof(sid);
1920 memcpy(&did, ibuf, sizeof(did));
1921 ibuf += sizeof(did);
1924 if (NULL == (dir = dirlookup( vol, sid )) ) {
1925 return afp_errno; /* was AFPERR_PARAM */
1928 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1929 return get_afp_errno(AFPERR_NOOBJ);
1932 if ( path_isadir(path) ) {
1933 return AFPERR_BADTYPE; /* it's a dir */
1937 * here do we need to switch to root ?
1940 ad_init(&ads, vol->v_adouble);
1941 if (!(adsp = find_adouble( path, &s_of, &ads))) {
1945 /* save some stuff */
1948 spath = obj->oldtmp;
1949 supath = obj->newtmp;
1950 strcpy(spath, path->m_name);
1951 upath = path->u_name;
1952 strcpy(supath, upath); /* this is for the cnid changing */
1953 p = absupath( vol, sdir, upath);
1955 /* pathname too long */
1956 return AFPERR_PARAM ;
1959 /* look for the source cnid. if it doesn't exist, don't worry about
1961 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
1963 if (NULL == ( dir = dirlookup( vol, did )) ) {
1964 return afp_errno; /* was AFPERR_PARAM */
1967 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1968 return get_afp_errno(AFPERR_NOOBJ);
1971 if ( path_isadir(path) ) {
1972 return AFPERR_BADTYPE;
1975 /* FPExchangeFiles is the only call that can return the SameObj
1977 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1978 return AFPERR_SAMEOBJ;
1980 ad_init(&add, vol->v_adouble);
1981 if (!(addp = find_adouble( path, &d_of, &add))) {
1986 /* they are not on the same device and at least one is open
1988 crossdev = (srcst.st_dev != destst.st_dev);
1989 if ((d_of || s_of) && crossdev)
1992 /* look for destination id. */
1993 upath = path->u_name;
1994 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
1996 /* construct a temp name.
1997 * NOTE: the temp file will be in the dest file's directory. it
1998 * will also be inaccessible from AFP. */
1999 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2003 /* now, quickly rename the file. we error if we can't. */
2004 if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2005 goto err_exchangefile;
2006 of_rename(vol, s_of, sdir, spath, curdir, temp);
2008 /* rename destination to source */
2009 if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2010 goto err_src_to_tmp;
2011 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2013 /* rename temp to destination */
2014 if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2015 goto err_dest_to_src;
2016 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2018 /* id's need switching. src -> dest and dest -> src.
2019 * we need to re-stat() if it was a cross device copy.
2022 cnid_delete(vol->v_cdb, sid);
2025 cnid_delete(vol->v_cdb, did);
2027 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
2028 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2030 (sid && ( (crossdev && stat(p, &destst) < 0) ||
2031 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2036 err = AFPERR_ACCESS;
2041 goto err_temp_to_dest;
2044 ad_setid(addp,(vol->v_flags & AFPVOL_NODEV)?0:destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp);
2046 ad_setid(adsp,(vol->v_flags & AFPVOL_NODEV)?0:srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp);
2049 ad_flush( adsp, ADFLAGS_HF );
2050 ad_close(adsp, ADFLAGS_HF);
2053 ad_flush( addp, ADFLAGS_HF );
2054 ad_close(addp, ADFLAGS_HF);
2057 /* change perms, src gets dest perm and vice versa */
2062 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2063 return AFP_OK; /* ignore error */
2067 * we need to exchange ACL entries as well
2069 /* exchange_acls(vol, p, upath); */
2074 path->m_name = NULL;
2075 path->u_name = upath;
2077 setfilunixmode(vol, path, destst.st_mode);
2078 setfilowner(vol, destst.st_uid, destst.st_gid, path);
2085 setfilunixmode(vol, path, srcst.st_mode);
2086 setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2088 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2089 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2094 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2099 /* all this stuff is so that we can unwind a failed operation
2102 /* rename dest to temp */
2103 renamefile(vol, upath, temp, temp, adsp);
2104 of_rename(vol, s_of, curdir, upath, curdir, temp);
2107 /* rename source back to dest */
2108 renamefile(vol, p, upath, path->m_name, addp);
2109 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2112 /* rename temp back to source */
2113 renamefile(vol, temp, p, spath, adsp);
2114 of_rename(vol, s_of, curdir, temp, sdir, spath);