]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/file.c
don't store in struct volume pointers to charset function table, we only need texten...
[netatalk.git] / etc / afpd / file.c
1 /*
2  * $Id: file.c,v 1.121 2009-11-08 23:17:39 didg Exp $
3  *
4  * Copyright (c) 1990,1993 Regents of The University of Michigan.
5  * All Rights Reserved.  See COPYRIGHT.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14
15 /* STDC check */
16 #if STDC_HEADERS
17 #include <string.h>
18 #else /* STDC_HEADERS */
19 #ifndef HAVE_STRCHR
20 #define strchr index
21 #define strrchr index
22 #endif /* HAVE_STRCHR */
23 char *strchr (), *strrchr ();
24
25 #ifndef HAVE_MEMCPY
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 */
30
31 #include <utime.h>
32 #include <errno.h>
33 #include <sys/param.h>
34
35 #include <atalk/adouble.h>
36 #include <atalk/vfs.h>
37 #include <atalk/logger.h>
38 #include <atalk/afp.h>
39 #include <atalk/util.h>
40 #include <atalk/cnid.h>
41 #include <atalk/unix.h>
42
43 #include "directory.h"
44 #include "desktop.h"
45 #include "volume.h"
46 #include "fork.h"
47 #include "file.h"
48 #include "filedir.h"
49 #include "globals.h"
50 #include "unix.h"
51
52 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
53  * field         bytes        subfield    bytes
54  * 
55  * files:
56  * ioFlFndrInfo  16      ->       type    4  type field
57  *                             creator    4  creator field
58  *                               flags    2  finder flags:
59  *                                           alias, bundle, etc.
60  *                            location    4  location in window
61  *                              folder    2  window that contains file
62  * 
63  * ioFlXFndrInfo 16      ->     iconID    2  icon id
64  *                              unused    6  reserved 
65  *                              script    1  script system
66  *                              xflags    1  reserved
67  *                           commentID    2  comment id
68  *                           putawayID    4  home directory id
69  */
70
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
76                           };
77
78 static const u_char old_ufinderi[] = {
79                               'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X'
80                           };
81
82 /* ---------------------- 
83 */
84 static int default_type(void *finder) 
85 {
86     if (!memcmp(finder, ufinderi, 8) || !memcmp(finder, old_ufinderi, 8))
87         return 1;
88     return 0;
89 }
90
91 /* FIXME path : unix or mac name ? (for now it's unix name ) */
92 void *get_finderinfo(const struct vol *vol, const char *upath, struct adouble *adp, void *data)
93 {
94     struct extmap       *em;
95     void                *ad_finder = NULL;
96     int                 chk_ext = 0;
97     
98     if (adp)
99         ad_finder = ad_entry(adp, ADEID_FINDERI);
100
101     if (ad_finder) {
102         memcpy(data, ad_finder, ADEDLEN_FINDERI);
103         /* default type ? */
104         if (default_type(ad_finder)) 
105             chk_ext = 1;
106     }
107     else {
108         memcpy(data, ufinderi, ADEDLEN_FINDERI);
109         chk_ext = 1;
110         if (vol_inv_dots(vol) && *upath == '.') { /* make it invisible */
111             u_int16_t ashort;
112             
113             ashort = htons(FINDERINFO_INVISIBLE);
114             memcpy((char *)data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
115         }
116     }
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));
121     }
122     return data;
123 }
124
125 /* ---------------------
126 */
127 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8) 
128 {
129     u_int32_t   aint;
130     char        *tp = NULL;
131     char        *src = name;
132     aint = strlen( name );
133
134     if (!utf8) {
135         /* want mac name */
136         if (utf8_encoding()) {
137             /* but name is an utf8 mac name */
138             char *u, *m;
139            
140             /* global static variable... */
141             tp = strdup(name);
142             if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
143                aint = 0;
144             }
145             else {
146                 aint = strlen(m);
147                 src = m;
148             }
149             
150         }
151         if (aint > MACFILELEN)
152             aint = MACFILELEN;
153         *data++ = aint;
154     }
155     else {
156         u_int16_t temp;
157
158         if (aint > 255)  /* FIXME safeguard, anyway if no ascii char it's game over*/
159            aint = 255;
160
161         utf8 = vol->v_kTextEncoding;
162         memcpy(data, &utf8, sizeof(utf8));
163         data += sizeof(utf8);
164         
165         temp = htons(aint);
166         memcpy(data, &temp, sizeof(temp));
167         data += sizeof(temp);
168     }
169
170     memcpy( data, src, aint );
171     data += aint;
172     if (tp) {
173         strcpy(name, tp);
174         free(tp);
175     }
176     return data;
177 }
178
179 /*
180  * FIXME: PDINFO is UTF8 and doesn't need adp
181 */
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)))
191
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) 
195 {
196 u_int32_t aint = 0;
197
198 #if AD_VERSION > AD_VERSION1
199
200     if ((aint = ad_getid(adp, st->st_dev, st->st_ino, did, vol->v_stamp))) {
201         return aint;
202     }
203 #endif
204
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) {
209             switch (errno) {
210             case CNID_ERR_CLOSE: /* the db is closed */
211                 break;
212             case CNID_ERR_PARAM:
213                 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
214                 afp_errno = AFPERR_PARAM;
215                 return CNID_INVALID;
216             case CNID_ERR_PATH:
217                 afp_errno = AFPERR_PARAM;
218                 return CNID_INVALID;
219             default:
220                 afp_errno = AFPERR_MISC;
221                 return CNID_INVALID;
222             }
223         }
224 #if AD_VERSION > AD_VERSION1
225         else if (adp ) {
226             /* update the ressource fork
227              * for a folder adp is always null
228              */
229             if (ad_setid(adp, st->st_dev, st->st_ino, aint, did, vol->v_stamp)) {
230                 ad_flush(adp);
231             }
232         }
233 #endif    
234     }
235     return aint;
236 }
237              
238 /* -------------------------- */
239 int getmetadata(struct vol *vol,
240                  u_int16_t bitmap,
241                  struct path *path, struct dir *dir, 
242                  char *buf, size_t *buflen, struct adouble *adp)
243 {
244     char                *data, *l_nameoff = NULL, *upath;
245     char                *utf_nameoff = NULL;
246     int                 bit = 0;
247     u_int32_t           aint;
248     cnid_t              id = 0;
249     u_int16_t           ashort;
250     u_char              achar, fdType[4];
251     u_int32_t           utf8 = 0;
252     struct stat         *st;
253     struct maccess      ma;
254
255 #ifdef DEBUG
256     LOG(log_debug9, logtype_afpd, "begin getmetadata:");
257 #endif /* DEBUG */
258
259     upath = path->u_name;
260     st = &path->st;
261
262     data = buf;
263
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))) {
267         if (!path->id)
268             id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
269         else 
270             id = path->id;
271         if (id == 0)
272             return afp_errno;
273         if (!path->m_name) {
274             path->m_name = utompath(vol, upath, id, utf8_encoding());
275         }
276     }
277     while ( bitmap != 0 ) {
278         while (( bitmap & 1 ) == 0 ) {
279             bitmap = bitmap>>1;
280             bit++;
281         }
282
283         switch ( bit ) {
284         case FILPBIT_ATTR :
285             if ( adp ) {
286                 ad_getattr(adp, &ashort);
287             } else if (vol_inv_dots(vol) && *upath == '.') {
288                 ashort = htons(ATTRBIT_INVISIBLE);
289             } else
290                 ashort = 0;
291 #if 0
292             /* FIXME do we want a visual clue if the file is read only
293              */
294             struct maccess      ma;
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                         ashort |= htons(ATTRBIT_NOWRITE);
300                 }
301             }
302 #endif
303             memcpy(data, &ashort, sizeof( ashort ));
304             data += sizeof( ashort );
305             break;
306
307         case FILPBIT_PDID :
308             memcpy(data, &dir->d_did, sizeof( u_int32_t ));
309             data += sizeof( u_int32_t );
310             break;
311
312         case FILPBIT_CDATE :
313             if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
314                 aint = AD_DATE_FROM_UNIX(st->st_mtime);
315             memcpy(data, &aint, sizeof( aint ));
316             data += sizeof( aint );
317             break;
318
319         case FILPBIT_MDATE :
320             if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
321                 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
322                    aint = AD_DATE_FROM_UNIX(st->st_mtime);
323                 }
324             } else {
325                 aint = AD_DATE_FROM_UNIX(st->st_mtime);
326             }
327             memcpy(data, &aint, sizeof( int ));
328             data += sizeof( int );
329             break;
330
331         case FILPBIT_BDATE :
332             if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
333                 aint = AD_DATE_START;
334             memcpy(data, &aint, sizeof( int ));
335             data += sizeof( int );
336             break;
337
338         case FILPBIT_FINFO :
339             get_finderinfo(vol, upath, adp, (char *)data);
340             data += ADEDLEN_FINDERI;
341             break;
342
343         case FILPBIT_LNAME :
344             l_nameoff = data;
345             data += sizeof( u_int16_t );
346             break;
347
348         case FILPBIT_SNAME :
349             memset(data, 0, sizeof(u_int16_t));
350             data += sizeof( u_int16_t );
351             break;
352
353         case FILPBIT_FNUM :
354             memcpy(data, &id, sizeof( id ));
355             data += sizeof( id );
356             break;
357
358         case FILPBIT_DFLEN :
359             if  (st->st_size > 0xffffffff)
360                aint = 0xffffffff;
361             else
362                aint = htonl( st->st_size );
363             memcpy(data, &aint, sizeof( aint ));
364             data += sizeof( aint );
365             break;
366
367         case FILPBIT_RFLEN :
368             if ( adp ) {
369                 if (adp->ad_rlen > 0xffffffff)
370                     aint = 0xffffffff;
371                 else
372                     aint = htonl( adp->ad_rlen);
373             } else {
374                 aint = 0;
375             }
376             memcpy(data, &aint, sizeof( aint ));
377             data += sizeof( aint );
378             break;
379
380             /* Current client needs ProDOS info block for this file.
381                Use simple heuristic and let the Mac "type" string tell
382                us what the PD file code should be.  Everything gets a
383                subtype of 0x0000 unless the original value was hashed
384                to "pXYZ" when we created it.  See IA, Ver 2.
385                <shirsch@adelphia.net> */
386         case FILPBIT_PDINFO :
387             if (afp_version >= 30) { /* UTF8 name */
388                 utf8 = kTextEncodingUTF8;
389                 utf_nameoff = data;
390                 data += sizeof( u_int16_t );
391                 aint = 0;
392                 memcpy(data, &aint, sizeof( aint ));
393                 data += sizeof( aint );
394             }
395             else {
396                 if ( adp ) {
397                     memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
398
399                     if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
400                         achar = '\x04';
401                         ashort = 0x0000;
402                     }
403                     else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
404                         achar = '\xff';
405                         ashort = 0x0000;
406                     }
407                     else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
408                         achar = '\xb3';
409                         ashort = 0x0000;
410                     }
411                     else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
412                         achar = '\x00';
413                         ashort = 0x0000;
414                     }
415                     else if ( fdType[0] == 'p' ) {
416                         achar = fdType[1];
417                         ashort = (fdType[2] * 256) + fdType[3];
418                     }
419                     else {
420                         achar = '\x00';
421                         ashort = 0x0000;
422                     }
423                 }
424                 else {
425                     achar = '\x00';
426                     ashort = 0x0000;
427                 }
428
429                 *data++ = achar;
430                 *data++ = 0;
431                 memcpy(data, &ashort, sizeof( ashort ));
432                 data += sizeof( ashort );
433                 memset(data, 0, sizeof( ashort ));
434                 data += sizeof( ashort );
435             }
436             break;
437         case FILPBIT_EXTDFLEN:
438             aint = htonl(st->st_size >> 32);
439             memcpy(data, &aint, sizeof( aint ));
440             data += sizeof( aint );
441             aint = htonl(st->st_size);
442             memcpy(data, &aint, sizeof( aint ));
443             data += sizeof( aint );
444             break;
445         case FILPBIT_EXTRFLEN:
446             aint = 0;
447             if (adp) 
448                 aint = htonl(adp->ad_rlen >> 32);
449             memcpy(data, &aint, sizeof( aint ));
450             data += sizeof( aint );
451             if (adp) 
452                 aint = htonl(adp->ad_rlen);
453             memcpy(data, &aint, sizeof( aint ));
454             data += sizeof( aint );
455             break;
456         case FILPBIT_UNIXPR :
457             /* accessmode may change st_mode with ACLs */
458             accessmode( upath, &ma, dir , st);
459
460             aint = htonl(st->st_uid);
461             memcpy( data, &aint, sizeof( aint ));
462             data += sizeof( aint );
463             aint = htonl(st->st_gid);
464             memcpy( data, &aint, sizeof( aint ));
465             data += sizeof( aint );
466
467             /* FIXME: ugly hack
468                type == slnk indicates an OSX style symlink, 
469                we have to add S_IFLNK to the mode, otherwise
470                10.3 clients freak out. */
471
472             aint = st->st_mode;
473             if (adp) {
474                 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
475                 if ( memcmp( fdType, "slnk", 4 ) == 0 ) {
476                     aint |= S_IFLNK;
477                 }
478             }
479             aint = htonl(aint);
480
481             memcpy( data, &aint, sizeof( aint ));
482             data += sizeof( aint );
483
484             *data++ = ma.ma_user;
485             *data++ = ma.ma_world;
486             *data++ = ma.ma_group;
487             *data++ = ma.ma_owner;
488             break;
489             
490         default :
491             return( AFPERR_BITMAP );
492         }
493         bitmap = bitmap>>1;
494         bit++;
495     }
496     if ( l_nameoff ) {
497         ashort = htons( data - buf );
498         memcpy(l_nameoff, &ashort, sizeof( ashort ));
499         data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
500     }
501     if ( utf_nameoff ) {
502         ashort = htons( data - buf );
503         memcpy(utf_nameoff, &ashort, sizeof( ashort ));
504         data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
505     }
506     *buflen = data - buf;
507     return (AFP_OK);
508 }
509                 
510 /* ----------------------- */
511 int getfilparams(struct vol *vol,
512                  u_int16_t bitmap,
513                  struct path *path, struct dir *dir, 
514                  char *buf, size_t *buflen )
515 {
516     struct adouble      ad, *adp;
517     int                 opened = 0;
518     int rc;    
519
520 #ifdef DEBUG
521     LOG(log_debug9, logtype_default, "begin getfilparams:");
522 #endif /* DEBUG */
523
524     opened = PARAM_NEED_ADP(bitmap);
525     adp = NULL;
526
527     if (opened) {
528         char *upath;
529         int  flags = (bitmap & (1 << FILPBIT_ATTR))?ADFLAGS_OPENFORKS:0;
530
531         adp = of_ad(vol, path, &ad);
532         upath = path->u_name;
533
534         if ( ad_metadata( upath, flags, adp) < 0 ) {
535             switch (errno) {
536             case EACCES:
537                 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
538                 upath, strerror(errno));
539                 return AFPERR_ACCESS;
540             case EIO:
541                 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
542                 /* fall through */
543             case ENOENT:
544             default:
545                 adp = NULL;
546                 break;
547             }
548         }
549     }
550     rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp);
551     if ( adp ) {
552         ad_close_metadata( adp);
553     }
554 #ifdef DEBUG
555     LOG(log_debug9, logtype_afpd, "end getfilparams:");
556 #endif /* DEBUG */
557
558     return( rc );
559 }
560
561 /* ----------------------------- */
562 int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
563 {
564     struct adouble      ad, *adp;
565     struct vol          *vol;
566     struct dir          *dir;
567     struct ofork        *of = NULL;
568     char                *path, *upath;
569     int                 creatf, did, openf, retvalue = AFP_OK;
570     u_int16_t           vid;
571     struct path         *s_path;
572     
573     *rbuflen = 0;
574     ibuf++;
575     creatf = (unsigned char) *ibuf++;
576
577     memcpy(&vid, ibuf, sizeof( vid ));
578     ibuf += sizeof( vid );
579
580     if (NULL == ( vol = getvolbyvid( vid )) ) {
581         return( AFPERR_PARAM );
582     }
583
584     if (vol->v_flags & AFPVOL_RO)
585         return AFPERR_VLOCK;
586
587     memcpy(&did, ibuf, sizeof( did));
588     ibuf += sizeof( did );
589
590     if (NULL == ( dir = dirlookup( vol, did )) ) {
591         return afp_errno;
592     }
593
594     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
595         return get_afp_errno(AFPERR_PARAM);
596     }
597
598     if ( *s_path->m_name == '\0' ) {
599         return( AFPERR_BADTYPE );
600     }
601
602     upath = s_path->u_name;
603     
604     /* if upath is deleted we already in trouble anyway */
605     if ((of = of_findname(s_path))) {
606         adp = of->of_ad;
607     } else {
608         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
609         adp = &ad;
610     }
611     if ( creatf) {
612         /* on a hard create, fail if file exists and is open */
613         if (of)
614             return AFPERR_BUSY;
615         openf = O_RDWR|O_CREAT|O_TRUNC;
616     } else {
617         /* on a soft create, if the file is open then ad_open won't fail
618            because open syscall is not called
619         */
620         if (of) {
621                 return AFPERR_EXIST;
622         }
623         openf = O_RDWR|O_CREAT|O_EXCL;
624     }
625
626     if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF|ADFLAGS_CREATE,
627                   openf, 0666, adp) < 0 ) {
628         switch ( errno ) {
629         case EROFS:
630             return AFPERR_VLOCK;
631         case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
632             return ( AFPERR_NOOBJ );
633         case EEXIST :
634             return( AFPERR_EXIST );
635         case EACCES :
636             return( AFPERR_ACCESS );
637         case EDQUOT:
638         case ENOSPC :
639             return( AFPERR_DFULL );
640         default :
641             return( AFPERR_PARAM );
642         }
643     }
644     if ( ad_reso_fileno( adp ) == -1 ) { /* Hard META / HF */
645          /* on noadouble volumes, just creating the data fork is ok */
646          if (vol_noadouble(vol)) {
647              ad_close( adp, ADFLAGS_DF );
648              goto createfile_done;
649          }
650          /* FIXME with hard create on an existing file, we already
651           * corrupted the data file.
652           */
653          netatalk_unlink( upath );
654          ad_close( adp, ADFLAGS_DF );
655          return AFPERR_ACCESS;
656     }
657
658     path = s_path->m_name;
659     ad_setname(adp, path);
660     ad_flush( adp);
661     ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
662
663 createfile_done:
664     curdir->offcnt++;
665
666 #ifdef DROPKLUDGE
667     if (vol->v_flags & AFPVOL_DROPBOX) {
668         retvalue = matchfile2dirperms(upath, vol, did);
669     }
670 #endif /* DROPKLUDGE */
671
672     setvoltime(obj, vol );
673
674     return (retvalue);
675 }
676
677 int afp_setfilparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
678 {
679     struct vol  *vol;
680     struct dir  *dir;
681     struct path *s_path;
682     int         did, rc;
683     u_int16_t   vid, bitmap;
684
685     *rbuflen = 0;
686     ibuf += 2;
687
688     memcpy(&vid, ibuf, sizeof( vid ));
689     ibuf += sizeof( vid );
690     if (NULL == ( vol = getvolbyvid( vid )) ) {
691         return( AFPERR_PARAM );
692     }
693
694     if (vol->v_flags & AFPVOL_RO)
695         return AFPERR_VLOCK;
696
697     memcpy(&did, ibuf, sizeof( did ));
698     ibuf += sizeof( did );
699     if (NULL == ( dir = dirlookup( vol, did )) ) {
700         return afp_errno; /* was AFPERR_NOOBJ */
701     }
702
703     memcpy(&bitmap, ibuf, sizeof( bitmap ));
704     bitmap = ntohs( bitmap );
705     ibuf += sizeof( bitmap );
706
707     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
708         return get_afp_errno(AFPERR_PARAM);
709     }
710
711     if (path_isadir(s_path)) {
712         return( AFPERR_BADTYPE ); /* it's a directory */
713     }
714
715     if ( s_path->st_errno != 0 ) {
716         return( AFPERR_NOOBJ );
717     }
718
719     if ((u_long)ibuf & 1 ) {
720         ibuf++;
721     }
722
723     if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
724         setvoltime(obj, vol );
725     }
726
727     return( rc );
728 }
729
730 /*
731  * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic  
732  * 
733 */
734 extern struct path Cur_Path;
735
736 int setfilparams(struct vol *vol,
737                  struct path *path, u_int16_t f_bitmap, char *buf )
738 {
739     struct adouble      ad, *adp;
740     struct extmap       *em;
741     int                 bit, isad = 1, err = AFP_OK;
742     char                *upath;
743     u_char              achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
744     u_int16_t           ashort, bshort;
745     u_int32_t           aint;
746     u_int32_t           upriv;
747     u_int16_t           upriv_bit = 0;
748     
749     struct utimbuf      ut;
750
751     int                 change_mdate = 0;
752     int                 change_parent_mdate = 0;
753     int                 newdate = 0;
754     struct timeval      tv;
755     uid_t               f_uid;
756     gid_t               f_gid;
757     u_int16_t           bitmap = f_bitmap;
758     u_int32_t           cdate,bdate;
759     u_char              finder_buf[32];
760
761 #ifdef DEBUG
762     LOG(log_debug9, logtype_afpd, "begin setfilparams:");
763 #endif /* DEBUG */
764
765     adp = of_ad(vol, path, &ad);
766     upath = path->u_name;
767
768     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
769         return AFPERR_ACCESS;
770     }
771
772     /* with unix priv maybe we have to change adouble file priv first */
773     bit = 0;
774     while ( bitmap != 0 ) {
775         while (( bitmap & 1 ) == 0 ) {
776             bitmap = bitmap>>1;
777             bit++;
778         }
779         switch(  bit ) {
780         case FILPBIT_ATTR :
781             change_mdate = 1;
782             memcpy(&ashort, buf, sizeof( ashort ));
783             buf += sizeof( ashort );
784             break;
785         case FILPBIT_CDATE :
786             change_mdate = 1;
787             memcpy(&cdate, buf, sizeof(cdate));
788             buf += sizeof( cdate );
789             break;
790         case FILPBIT_MDATE :
791             memcpy(&newdate, buf, sizeof( newdate ));
792             buf += sizeof( newdate );
793             break;
794         case FILPBIT_BDATE :
795             change_mdate = 1;
796             memcpy(&bdate, buf, sizeof( bdate));
797             buf += sizeof( bdate );
798             break;
799         case FILPBIT_FINFO :
800             change_mdate = 1;
801             memcpy(finder_buf, buf, 32 );
802             buf += 32;
803             break;
804         case FILPBIT_UNIXPR :
805             if (!vol_unix_priv(vol)) {
806                 /* this volume doesn't use unix priv */
807                 err = AFPERR_BITMAP;
808                 bitmap = 0;
809                 break;
810             }
811             change_mdate = 1;
812             change_parent_mdate = 1;
813
814             memcpy( &aint, buf, sizeof( aint ));
815             f_uid = ntohl (aint);
816             buf += sizeof( aint );
817             memcpy( &aint, buf, sizeof( aint ));
818             f_gid = ntohl (aint);
819             buf += sizeof( aint );
820             setfilowner(vol, f_uid, f_gid, path);
821
822             memcpy( &upriv, buf, sizeof( upriv ));
823             buf += sizeof( upriv );
824             upriv = ntohl (upriv);
825             if ((upriv & S_IWUSR)) {
826                 setfilunixmode(vol, path, upriv);
827             }
828             else {
829                 /* do it later */
830                 upriv_bit = 1;
831             }
832             break;
833         case FILPBIT_PDINFO :
834             if (afp_version < 30) { /* else it's UTF8 name */
835                 achar = *buf;
836                 buf += 2;
837                 /* Keep special case to support crlf translations */
838                 if ((unsigned int) achar == 0x04) {
839                     fdType = (u_char *)"TEXT";
840                     buf += 2;
841                 } else {
842                     xyy[0] = ( u_char ) 'p';
843                     xyy[1] = achar;
844                     xyy[3] = *buf++;
845                     xyy[2] = *buf++;
846                     fdType = xyy;
847                 }
848                 break;
849             }
850             /* fallthrough */
851         default :
852             err = AFPERR_BITMAP;
853             /* break while loop */
854             bitmap = 0;
855             break;
856         }
857
858         bitmap = bitmap>>1;
859         bit++;
860     }
861
862     /* second try with adouble open 
863     */
864     if ( ad_open_metadata( upath, vol_noadouble(vol), O_CREAT, adp) < 0) {
865         LOG(log_debug, logtype_afpd, "setfilparams: ad_open_metadata error");
866         /*
867          * For some things, we don't need an adouble header:
868          * - change of modification date
869          * - UNIX privs (Bug-ID #2863424)
870          */
871         if ( (f_bitmap & ~(1<<FILPBIT_MDATE | 1<<FILPBIT_UNIXPR))) {
872             LOG(log_debug, logtype_afpd, "setfilparams: need adouble access");
873             return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
874         }
875         LOG(log_debug, logtype_afpd, "setfilparams: no adouble perms, but only FILPBIT_MDATE and/or FILPBIT_UNIXPR");
876         isad = 0;
877     } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
878         ad_setname(adp, path->m_name);
879     }
880     
881     bit = 0;
882     bitmap = f_bitmap;
883     while ( bitmap != 0 ) {
884         while (( bitmap & 1 ) == 0 ) {
885             bitmap = bitmap>>1;
886             bit++;
887         }
888
889         switch(  bit ) {
890         case FILPBIT_ATTR :
891             ad_getattr(adp, &bshort);
892             if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
893                 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
894                 change_parent_mdate = 1;
895             if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
896                 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
897             } else {
898                 bshort &= ~ashort;
899             }
900             ad_setattr(adp, bshort);
901             break;
902         case FILPBIT_CDATE :
903             ad_setdate(adp, AD_DATE_CREATE, cdate);
904             break;
905         case FILPBIT_MDATE :
906             break;
907         case FILPBIT_BDATE :
908             ad_setdate(adp, AD_DATE_BACKUP, bdate);
909             break;
910         case FILPBIT_FINFO :
911             if (default_type( ad_entry( adp, ADEID_FINDERI ))
912                     && ( 
913                      ((em = getextmap( path->m_name )) &&
914                       !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
915                       !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
916                      || ((em = getdefextmap()) &&
917                       !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
918                       !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
919             )) {
920                 memcpy(finder_buf, ufinderi, 8 );
921             }
922             memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
923             break;
924         case FILPBIT_UNIXPR :
925             if (upriv_bit) {
926                 setfilunixmode(vol, path, upriv);
927             }
928             break;
929         case FILPBIT_PDINFO :
930             if (afp_version < 30) { /* else it's UTF8 name */
931                 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
932                 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
933                 break;
934             }
935             /* fallthrough */
936         default :
937             err = AFPERR_BITMAP;
938             goto setfilparam_done;
939         }
940         bitmap = bitmap>>1;
941         bit++;
942     }
943
944 setfilparam_done:
945     if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
946        newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
947     }
948     if (newdate) {
949        if (isad)
950           ad_setdate(adp, AD_DATE_MODIFY, newdate);
951        ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
952        utime(upath, &ut);
953     }
954
955     if (isad) {
956         ad_flush( adp);
957         ad_close_metadata( adp);
958
959     }
960
961     if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
962         newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
963         bitmap = 1<<FILPBIT_MDATE;
964         setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
965     }
966
967 #ifdef DEBUG
968     LOG(log_debug9, logtype_afpd, "end setfilparams:");
969 #endif /* DEBUG */
970     return err;
971 }
972
973 /*
974  * renamefile and copyfile take the old and new unix pathnames
975  * and the new mac name.
976  *
977  * src         the source path 
978  * dst         the dest filename in current dir
979  * newname     the dest mac name
980  * adp         adouble struct of src file, if open, or & zeroed one
981  *
982  */
983 int renamefile(const struct vol *vol, char *src, char *dst, char *newname, struct adouble *adp)
984 {
985     int         rc;
986
987 #ifdef DEBUG
988     LOG(log_debug9, logtype_afpd, "begin renamefile:");
989 #endif /* DEBUG */
990
991     if ( unix_rename( src, dst ) < 0 ) {
992         switch ( errno ) {
993         case ENOENT :
994             return( AFPERR_NOOBJ );
995         case EPERM:
996         case EACCES :
997             return( AFPERR_ACCESS );
998         case EROFS:
999             return AFPERR_VLOCK;
1000         case EXDEV :                    /* Cross device move -- try copy */
1001            /* NOTE: with open file it's an error because after the copy we will 
1002             * get two files, it's fixable for our process (eg reopen the new file, get the
1003             * locks, and so on. But it doesn't solve the case with a second process
1004             */
1005             if (adp->ad_open_forks) {
1006                 /* FIXME  warning in syslog so admin'd know there's a conflict ?*/
1007                 return AFPERR_OLOCK; /* little lie */
1008             }
1009             if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1010                 /* on error copyfile delete dest */
1011                 return( rc );
1012             }
1013             return deletefile(vol, src, 0);
1014         default :
1015             return( AFPERR_PARAM );
1016         }
1017     }
1018
1019     if (vol->vfs->vfs_renamefile(vol, src, dst) < 0 ) {
1020         int err;
1021         
1022         err = errno;        
1023         /* try to undo the data fork rename,
1024          * we know we are on the same device 
1025         */
1026         if (err) {
1027             unix_rename( dst, src ); 
1028             /* return the first error */
1029             switch ( err) {
1030             case ENOENT :
1031                 return AFPERR_NOOBJ;
1032             case EPERM:
1033             case EACCES :
1034                 return AFPERR_ACCESS ;
1035             case EROFS:
1036                 return AFPERR_VLOCK;
1037             default :
1038                 return AFPERR_PARAM ;
1039             }
1040         }
1041     }
1042
1043     /* don't care if we can't open the newly renamed ressource fork
1044      */
1045     if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1046         ad_setname(adp, newname);
1047         ad_flush( adp );
1048         ad_close( adp, ADFLAGS_HF );
1049     }
1050 #ifdef DEBUG
1051     LOG(log_debug9, logtype_afpd, "end renamefile:");
1052 #endif /* DEBUG */
1053
1054     return( AFP_OK );
1055 }
1056
1057 /* ---------------- 
1058    convert a Mac long name to an utf8 name,
1059 */
1060 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1061 {
1062 size_t    outlen;
1063
1064     if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1065         return -1;
1066     }
1067     return outlen;
1068 }
1069
1070 /* ---------------- */
1071 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1072 {
1073 char        type = *ibuf;
1074 size_t      plen = 0;
1075 u_int16_t   len16;
1076 u_int32_t   hint;
1077
1078     if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1079         return -1;
1080     }
1081     ibuf++;
1082     switch (type) {
1083     case 2:
1084         if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1085             if (afp_version >= 30) {
1086                 /* convert it to UTF8 
1087                 */
1088                 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1)
1089                    return -1;
1090             }
1091             else {
1092                 strncpy( newname, ibuf, plen );
1093                 newname[ plen ] = '\0';
1094             }
1095             if (strlen(newname) != plen) {
1096                 /* there's \0 in newname, e.g. it's a pathname not
1097                  * only a filename. 
1098                 */
1099                 return -1;
1100             }
1101         }
1102         break;
1103     case 3:
1104         memcpy(&hint, ibuf, sizeof(hint));
1105         ibuf += sizeof(hint);
1106            
1107         memcpy(&len16, ibuf, sizeof(len16));
1108         ibuf += sizeof(len16);
1109         plen = ntohs(len16);
1110         
1111         if (plen) {
1112             if (plen > AFPOBJ_TMPSIZ) {
1113                 return -1;
1114             }
1115             strncpy( newname, ibuf, plen );
1116             newname[ plen ] = '\0';
1117             if (strlen(newname) != plen) {
1118                 return -1;
1119             }
1120         }
1121         break;
1122     }
1123     return plen;
1124 }
1125
1126 /* -----------------------------------
1127 */
1128 int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1129 {
1130     struct vol  *s_vol, *d_vol;
1131     struct dir  *dir;
1132     char        *newname, *p, *upath;
1133     struct path *s_path;
1134     u_int32_t   sdid, ddid;
1135     int         err, retvalue = AFP_OK;
1136     u_int16_t   svid, dvid;
1137
1138     struct adouble ad, *adp;
1139     int denyreadset;
1140     
1141     *rbuflen = 0;
1142     ibuf += 2;
1143
1144     memcpy(&svid, ibuf, sizeof( svid ));
1145     ibuf += sizeof( svid );
1146     if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1147         return( AFPERR_PARAM );
1148     }
1149
1150     memcpy(&sdid, ibuf, sizeof( sdid ));
1151     ibuf += sizeof( sdid );
1152     if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1153         return afp_errno;
1154     }
1155
1156     memcpy(&dvid, ibuf, sizeof( dvid ));
1157     ibuf += sizeof( dvid );
1158     memcpy(&ddid, ibuf, sizeof( ddid ));
1159     ibuf += sizeof( ddid );
1160
1161     if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1162         return get_afp_errno(AFPERR_PARAM);
1163     }
1164     if ( path_isadir(s_path) ) {
1165         return( AFPERR_BADTYPE );
1166     }
1167
1168     /* don't allow copies when the file is open.
1169      * XXX: the spec only calls for read/deny write access.
1170      *      however, copyfile doesn't have any of that info,
1171      *      and locks need to stay coherent. as a result,
1172      *      we just balk if the file is opened already. */
1173
1174     adp = of_ad(s_vol, s_path, &ad);
1175
1176     if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1177         return AFPERR_DENYCONF;
1178     }
1179     denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 || 
1180                   getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1181     ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1182     if (denyreadset) {
1183         return AFPERR_DENYCONF;
1184     }
1185
1186     newname = obj->newtmp;
1187     strcpy( newname, s_path->m_name );
1188
1189     p = ctoupath( s_vol, curdir, newname );
1190     if (!p) {
1191         return AFPERR_PARAM;
1192     
1193     }
1194 #ifdef FORCE_UIDGID
1195     /* FIXME svid != dvid && dvid's user can't read svid */
1196 #endif
1197     if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1198         return( AFPERR_PARAM );
1199     }
1200
1201     if (d_vol->v_flags & AFPVOL_RO)
1202         return AFPERR_VLOCK;
1203
1204     if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1205         return afp_errno;
1206     }
1207
1208     if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1209         return get_afp_errno(AFPERR_NOOBJ); 
1210     }
1211     if ( *s_path->m_name != '\0' ) {
1212         path_error(s_path, AFPERR_PARAM);
1213     }
1214
1215     /* one of the handful of places that knows about the path type */
1216     if (copy_path_name(d_vol, newname, ibuf) < 0) {
1217         return( AFPERR_PARAM );
1218     }
1219     /* newname is always only a filename so curdir *is* its
1220      * parent folder
1221     */
1222     if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1223         return( AFPERR_PARAM );
1224     }
1225     if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1226         return err;
1227     }
1228     curdir->offcnt++;
1229
1230 #ifdef DROPKLUDGE
1231     if (vol->v_flags & AFPVOL_DROPBOX) {
1232         retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1233     }
1234 #endif /* DROPKLUDGE */
1235
1236     setvoltime(obj, d_vol );
1237
1238     return( retvalue );
1239 }
1240
1241 /* ----------------------- */
1242 static int copy_all(const int dfd, const void *buf,
1243                                size_t buflen)
1244 {
1245     ssize_t cc;
1246
1247 #ifdef DEBUG
1248     LOG(log_debug9, logtype_afpd, "begin copy_all:");
1249 #endif /* DEBUG */
1250
1251     while (buflen > 0) {
1252         if ((cc = write(dfd, buf, buflen)) < 0) {
1253             switch (errno) {
1254             case EINTR:
1255                 continue;
1256             default:
1257                 return -1;
1258             }
1259         }
1260         buflen -= cc;
1261     }
1262
1263 #ifdef DEBUG
1264     LOG(log_debug9, logtype_afpd, "end copy_all:");
1265 #endif /* DEBUG */
1266
1267     return 0;
1268 }
1269
1270 /* -------------------------- 
1271  * copy only the fork data stream
1272 */
1273 static int copy_fork(int eid, struct adouble *add, struct adouble *ads)
1274 {
1275     ssize_t cc;
1276     int     err = 0;
1277     char    filebuf[8192];
1278     int     sfd, dfd;
1279     
1280     if (eid == ADEID_DFORK) {
1281         sfd = ad_data_fileno(ads);
1282         dfd = ad_data_fileno(add);
1283     }
1284     else {
1285         sfd = ad_reso_fileno(ads);
1286         dfd = ad_reso_fileno(add);
1287     }        
1288
1289     if ((off_t)-1 == lseek(sfd, ad_getentryoff(ads, eid), SEEK_SET))
1290         return -1;
1291
1292     if ((off_t)-1 == lseek(dfd, ad_getentryoff(add, eid), SEEK_SET))
1293         return -1;
1294         
1295 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1296     /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1297     off_t   offset = 0;
1298     size_t  size;
1299     struct stat         st;
1300     #define BUF 128*1024*1024
1301
1302     if (fstat(sfd, &st) == 0) {
1303         
1304         while (1) {
1305             if ( offset >= st.st_size) {
1306                return 0;
1307             }
1308             size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1309             if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1310                 switch (errno) {
1311                 case ENOSYS:
1312                 case EINVAL:  /* there's no guarantee that all fs support sendfile */
1313                     goto no_sendfile;
1314                 default:
1315                     return -1;
1316                 }
1317             }
1318         }
1319     }
1320     no_sendfile:
1321     lseek(sfd, offset, SEEK_SET);
1322 #endif 
1323
1324     while (1) {
1325         if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1326             if (errno == EINTR)
1327                 continue;
1328             err = -1;
1329             break;
1330         }
1331
1332         if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1333             break;
1334         }
1335     }
1336     return err;
1337 }
1338
1339 /* ----------------------------------
1340  * if newname is NULL (from directory.c) we don't want to copy the resource fork.
1341  * because we are doing it elsewhere.
1342  * currently if newname is NULL then adp is NULL. 
1343  */
1344 int copyfile(const struct vol *s_vol, const struct vol*d_vol, 
1345     char *src, char *dst, char *newname, struct adouble *adp)
1346 {
1347     struct adouble      ads, add;
1348     int                 err = 0;
1349     int                 ret_err = 0;
1350     int                 adflags;
1351     int                 stat_result;
1352     struct stat         st;
1353     
1354 #ifdef DEBUG
1355     LOG(log_debug9, logtype_afpd, "begin copyfile:");
1356 #endif /* DEBUG */
1357
1358     if (adp == NULL) {
1359         ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options); 
1360         adp = &ads;
1361     }
1362     ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1363     adflags = ADFLAGS_DF;
1364     if (newname) {
1365         adflags |= ADFLAGS_HF;
1366     }
1367
1368     if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1369         ret_err = errno;
1370         goto done;
1371     }
1372
1373     if (ad_meta_fileno(adp) == -1 && ad_reso_fileno(adp) == -1) { /* META / HF */
1374         /* no resource fork, don't create one for dst file */
1375         adflags &= ~ADFLAGS_HF;
1376     }
1377
1378     stat_result = fstat(ad_data_fileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */
1379
1380     if (stat_result < 0) {           
1381       /* unlikely but if fstat fails, the default file mode will be 0666. */
1382       st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
1383     }
1384
1385     if (ad_open(dst , adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
1386         ret_err = errno;
1387         ad_close( adp, adflags );
1388         if (EEXIST != ret_err) {
1389             deletefile(d_vol, dst, 0);
1390             goto done;
1391         }
1392         return AFPERR_EXIST;
1393     }
1394     
1395     /*
1396      * XXX if the source and the dest don't use the same resource type it's broken
1397      */
1398     if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){
1399         /* copy the data fork */
1400         if ((err = copy_fork(ADEID_DFORK, &add, adp)) == 0) {
1401             err = d_vol->vfs->vfs_copyfile(d_vol, src, dst);
1402         }
1403     }
1404
1405     if (err < 0) {
1406        ret_err = errno;
1407     }
1408
1409     if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
1410         /* set the new name in the resource fork */
1411         ad_copy_header(&add, adp);
1412         ad_setname(&add, newname);
1413         ad_flush( &add );
1414     }
1415     ad_close( adp, adflags );
1416
1417     if (ad_close( &add, adflags ) <0) {
1418        ret_err = errno;
1419     } 
1420
1421     if (ret_err) {
1422         deletefile(d_vol, dst, 0);
1423     }
1424     else if (stat_result == 0) {
1425         /* set dest modification date to src date */
1426         struct utimbuf  ut;
1427
1428         ut.actime = ut.modtime = st.st_mtime;
1429         utime(dst, &ut);
1430         /* FIXME netatalk doesn't use resource fork file date
1431          * but maybe we should set its modtime too.
1432         */
1433     }
1434
1435 #ifdef DEBUG
1436     LOG(log_debug9, logtype_afpd, "end copyfile:");
1437 #endif /* DEBUG */
1438
1439 done:
1440     switch ( ret_err ) {
1441     case 0:
1442         return AFP_OK;
1443     case EDQUOT:
1444     case EFBIG:
1445     case ENOSPC:
1446         return AFPERR_DFULL;
1447     case ENOENT:
1448         return AFPERR_NOOBJ;
1449     case EACCES:
1450         return AFPERR_ACCESS;
1451     case EROFS:
1452         return AFPERR_VLOCK;
1453     }
1454     return AFPERR_PARAM;
1455 }
1456
1457
1458 /* -----------------------------------
1459    vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1460    checkAttrib:   1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1461
1462    when deletefile is called we don't have lock on it, file is closed (for us)
1463    untrue if called by renamefile
1464    
1465    ad_open always try to open file RDWR first and ad_lock takes care of
1466    WRITE lock on read only file.
1467 */
1468
1469 static int check_attrib(struct adouble *adp)
1470 {
1471 u_int16_t   bshort = 0;
1472
1473         ad_getattr(adp, &bshort);
1474     /*
1475      * Does kFPDeleteInhibitBit (bit 8) set?
1476      */
1477         if ((bshort & htons(ATTRBIT_NODELETE))) {
1478                 return AFPERR_OLOCK;
1479         }
1480     if ((bshort & htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN))) {
1481         return AFPERR_BUSY;
1482         }
1483         return 0;
1484 }
1485
1486 int deletefile(const struct vol *vol, char *file, int checkAttrib)
1487 {
1488     struct adouble      ad;
1489     struct adouble      *adp = &ad;
1490     int                 adflags, err = AFP_OK;
1491
1492 #ifdef DEBUG
1493     LOG(log_debug9, logtype_afpd, "begin deletefile:");
1494 #endif /* DEBUG */
1495
1496     /* try to open both forks at once */
1497     adflags = ADFLAGS_DF|ADFLAGS_HF;
1498     if (checkAttrib) {
1499         /* was EACCESS error try to get only metadata */
1500         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1501         if ( ad_metadata( file , ADFLAGS_OPENFORKS, &ad) == 0 ) {
1502             ad_close( &ad, adflags );
1503             if ((err = check_attrib(&ad))) {
1504                return err;
1505             }
1506         }
1507     }
1508  
1509     while(1) {
1510         ad_init(&ad, vol->v_adouble, vol->v_ad_options);  /* OK */
1511         if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1512             switch (errno) {
1513             case ENOENT:
1514                 if (adflags == ADFLAGS_DF)
1515                     return AFPERR_NOOBJ;
1516                    
1517                 /* that failed. now try to open just the data fork */
1518                 adflags = ADFLAGS_DF;
1519                 continue;
1520
1521             case EACCES:
1522                 adp = NULL; /* maybe it's a file with no write mode for us */
1523                 break;      /* was return AFPERR_ACCESS;*/
1524             case EROFS:
1525                 return AFPERR_VLOCK;
1526             default:
1527                 return( AFPERR_PARAM );
1528             }
1529         }
1530         break;  /* from the while */
1531     }
1532
1533     if (adp && (adflags & ADFLAGS_HF) ) {
1534         /* FIXME we have a pb here because we want to know if a file is open 
1535          * there's a 'priority inversion' if you can't open the ressource fork RW
1536          * you can delete it if it's open because you can't get a write lock.
1537          * 
1538          * ADLOCK_FILELOCK means the whole ressource fork, not only after the 
1539          * metadatas
1540          *
1541          * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1542          */
1543         if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1544             ad_close( &ad, adflags );
1545             return( AFPERR_BUSY );
1546         }
1547     }
1548
1549     if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1550         err = AFPERR_BUSY;
1551     }
1552     else if (!(err = vol->vfs->vfs_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
1553         cnid_t id;
1554         if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file)))) 
1555         {
1556             cnid_delete(vol->v_cdb, id);
1557         }
1558     }
1559     if (adp)
1560         ad_close( &ad, adflags );  /* ad_close removes locks if any */
1561
1562 #ifdef DEBUG
1563     LOG(log_debug9, logtype_afpd, "end deletefile:");
1564 #endif /* DEBUG */
1565
1566     return err;
1567 }
1568
1569 /* ------------------------------------ */
1570 /* return a file id */
1571 int afp_createid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1572 {
1573     struct stat         *st;
1574     struct vol          *vol;
1575     struct dir          *dir;
1576     char                *upath;
1577     int                 len;
1578     cnid_t              did, id;
1579     u_short             vid;
1580     struct path         *s_path;
1581
1582     *rbuflen = 0;
1583
1584     ibuf += 2;
1585
1586     memcpy(&vid, ibuf, sizeof(vid));
1587     ibuf += sizeof(vid);
1588
1589     if (NULL == ( vol = getvolbyvid( vid )) ) {
1590         return( AFPERR_PARAM);
1591     }
1592
1593     if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1594         return AFPERR_NOOP;
1595     }
1596
1597     if (vol->v_flags & AFPVOL_RO)
1598         return AFPERR_VLOCK;
1599
1600     memcpy(&did, ibuf, sizeof( did ));
1601     ibuf += sizeof(did);
1602
1603     if (NULL == ( dir = dirlookup( vol, did )) ) {
1604         return afp_errno; /* was AFPERR_PARAM */
1605     }
1606
1607     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1608         return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1609     }
1610
1611     if ( path_isadir(s_path) ) {
1612         return( AFPERR_BADTYPE );
1613     }
1614
1615     upath = s_path->u_name;
1616     switch (s_path->st_errno) {
1617         case 0:
1618              break; /* success */
1619         case EPERM:
1620         case EACCES:
1621             return AFPERR_ACCESS;
1622         case ENOENT:
1623             return AFPERR_NOOBJ;
1624         default:
1625             return AFPERR_PARAM;
1626     }
1627     st = &s_path->st;
1628     if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1629         memcpy(rbuf, &id, sizeof(id));
1630         *rbuflen = sizeof(id);
1631         return AFPERR_EXISTID;
1632     }
1633
1634     if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1635         memcpy(rbuf, &id, sizeof(id));
1636         *rbuflen = sizeof(id);
1637         return AFP_OK;
1638     }
1639
1640     return afp_errno;
1641 }
1642
1643 /* ------------------------------- */
1644 struct reenum {
1645     struct vol *vol;
1646     cnid_t     did;
1647 };
1648
1649 static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
1650 {
1651     struct path   path;
1652     struct reenum *param = data;
1653     struct vol    *vol = param->vol;  
1654     cnid_t        did  = param->did;
1655     cnid_t        aint;
1656     
1657     if ( stat(de->d_name, &path.st)<0 )
1658         return 0;
1659     
1660     /* update or add to cnid */
1661     aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1662
1663 #if AD_VERSION > AD_VERSION1
1664     if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1665         struct adouble  ad, *adp;
1666
1667         path.st_errno = 0;
1668         path.st_valid = 1;
1669         path.u_name = de->d_name;
1670             
1671         adp = of_ad(vol, &path, &ad);
1672             
1673         if ( ad_open_metadata( de->d_name, 0, 0, adp ) < 0 ) {
1674             return 0;
1675         }
1676         if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1677             ad_flush(adp);
1678         }
1679         ad_close_metadata(adp);
1680     }
1681 #endif /* AD_VERSION > AD_VERSION1 */
1682
1683     return 0;
1684 }
1685
1686 /* --------------------
1687  * Ok the db is out of synch with the dir.
1688  * but if it's a deleted file we don't want to do it again and again.
1689 */
1690 static int
1691 reenumerate_id(struct vol *vol, char *name, struct dir *dir)
1692 {
1693     int             ret;
1694     struct reenum   data;
1695     struct stat     st;
1696     
1697     if (vol->v_cdb == NULL) {
1698         return -1;
1699     }
1700     
1701     /* FIXME use of_statdir ? */
1702     if (stat(name, &st)) {
1703         return -1;
1704     }
1705
1706     if (dirreenumerate(dir, &st)) {
1707         /* we already did it once and the dir haven't been modified */
1708         return dir->offcnt;
1709     }
1710     
1711     data.vol = vol;
1712     data.did = dir->d_did;
1713     if ((ret = for_each_dirent(vol, name, reenumerate_loop, (void *)&data)) >= 0) {
1714         setdiroffcnt(curdir, &st,  ret);
1715         dir->d_flags |= DIRF_CNID;
1716     }
1717
1718     return ret;
1719 }
1720
1721 /* ------------------------------
1722    resolve a file id */
1723 int afp_resolveid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1724 {
1725     struct vol          *vol;
1726     struct dir          *dir;
1727     char                *upath;
1728     struct path         path;
1729     int                 err, retry=0;
1730     size_t              buflen;
1731     cnid_t              id, cnid;
1732     u_int16_t           vid, bitmap;
1733
1734     static char buffer[12 + MAXPATHLEN + 1];
1735     int len = 12 + MAXPATHLEN + 1;
1736
1737     *rbuflen = 0;
1738     ibuf += 2;
1739
1740     memcpy(&vid, ibuf, sizeof(vid));
1741     ibuf += sizeof(vid);
1742
1743     if (NULL == ( vol = getvolbyvid( vid )) ) {
1744         return( AFPERR_PARAM);
1745     }
1746
1747     if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1748         return AFPERR_NOOP;
1749     }
1750
1751     memcpy(&id, ibuf, sizeof( id ));
1752     ibuf += sizeof(id);
1753     cnid = id;
1754     
1755     if (!id) {
1756         /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
1757         return AFPERR_NOID;
1758     }
1759 retry:
1760     if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1761         return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1762     }
1763
1764     if (NULL == ( dir = dirlookup( vol, id )) ) {
1765         return AFPERR_NOID; /* idem AFPERR_PARAM */
1766     }
1767     if (movecwd(vol, dir) < 0) {
1768         switch (errno) {
1769         case EACCES:
1770         case EPERM:
1771             return AFPERR_ACCESS;
1772         case ENOENT:
1773             return AFPERR_NOID;
1774         default:
1775             return AFPERR_PARAM;
1776         }
1777     }
1778
1779     memset(&path, 0, sizeof(path));
1780     path.u_name = upath;
1781     if ( of_stat(&path) < 0 ) {
1782 #ifdef ESTALE
1783         /* with nfs and our working directory is deleted */
1784         if (errno == ESTALE) {
1785             errno = ENOENT;
1786         }
1787 #endif  
1788         if ( errno == ENOENT && !retry) {
1789             /* cnid db is out of sync, reenumerate the directory and update ids */
1790             reenumerate_id(vol, ".", dir);
1791             id = cnid;
1792             retry = 1;
1793             goto retry;
1794         }
1795         switch (errno) {
1796         case EACCES:
1797         case EPERM:
1798             return AFPERR_ACCESS;
1799         case ENOENT:
1800             return AFPERR_NOID;
1801         default:
1802             return AFPERR_PARAM;
1803         }
1804     }
1805
1806     /* directories are bad */
1807     if (S_ISDIR(path.st.st_mode)) {
1808         /* OS9 and OSX don't return the same error code  */
1809         return (afp_version >=30)?AFPERR_NOID:AFPERR_BADTYPE;
1810     }
1811
1812     memcpy(&bitmap, ibuf, sizeof(bitmap));
1813     bitmap = ntohs( bitmap );
1814     if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1815         return AFPERR_NOID;
1816     }
1817     path.id = cnid;
1818     if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir, 
1819                             rbuf + sizeof(bitmap), &buflen))) {
1820         return err;
1821     }
1822     *rbuflen = buflen + sizeof(bitmap);
1823     memcpy(rbuf, ibuf, sizeof(bitmap));
1824
1825     return AFP_OK;
1826 }
1827
1828 /* ------------------------------ */
1829 int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1830 {
1831     struct stat         st;
1832     struct vol          *vol;
1833     struct dir          *dir;
1834     char                *upath;
1835     int                 err;
1836     cnid_t              id;
1837     cnid_t              fileid;
1838     u_short             vid;
1839     static char buffer[12 + MAXPATHLEN + 1];
1840     int len = 12 + MAXPATHLEN + 1;
1841
1842     *rbuflen = 0;
1843     ibuf += 2;
1844
1845     memcpy(&vid, ibuf, sizeof(vid));
1846     ibuf += sizeof(vid);
1847
1848     if (NULL == ( vol = getvolbyvid( vid )) ) {
1849         return( AFPERR_PARAM);
1850     }
1851
1852     if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1853         return AFPERR_NOOP;
1854     }
1855
1856     if (vol->v_flags & AFPVOL_RO)
1857         return AFPERR_VLOCK;
1858
1859     memcpy(&id, ibuf, sizeof( id ));
1860     ibuf += sizeof(id);
1861     fileid = id;
1862
1863     if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1864         return AFPERR_NOID;
1865     }
1866
1867     if (NULL == ( dir = dirlookup( vol, id )) ) {
1868         return( AFPERR_PARAM );
1869     }
1870
1871     err = AFP_OK;
1872     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1873         switch (errno) {
1874         case EACCES:
1875         case EPERM:
1876             return AFPERR_ACCESS;
1877 #ifdef ESTALE
1878         case ESTALE:
1879 #endif  
1880         case ENOENT:
1881             /* still try to delete the id */
1882             err = AFPERR_NOOBJ;
1883             break;
1884         default:
1885             return AFPERR_PARAM;
1886         }
1887     }
1888     else if (S_ISDIR(st.st_mode)) /* directories are bad */
1889         return AFPERR_BADTYPE;
1890
1891     if (cnid_delete(vol->v_cdb, fileid)) {
1892         switch (errno) {
1893         case EROFS:
1894             return AFPERR_VLOCK;
1895         case EPERM:
1896         case EACCES:
1897             return AFPERR_ACCESS;
1898         default:
1899             return AFPERR_PARAM;
1900         }
1901     }
1902
1903     return err;
1904 }
1905
1906 /* ------------------------------ */
1907 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1908 {
1909     int             ret;
1910
1911     if (path->st_errno) {
1912         switch (path->st_errno) {
1913         case ENOENT:
1914             afp_errno = AFPERR_NOID;
1915             break;
1916         case EPERM:
1917         case EACCES:
1918             afp_errno = AFPERR_ACCESS;
1919             break;
1920         default:
1921             afp_errno = AFPERR_PARAM;
1922             break;
1923         }
1924         return NULL;
1925     }
1926     /* we use file_access both for legacy Mac perm and
1927      * for unix privilege, rename will take care of folder perms
1928     */
1929     if (file_access(path, OPENACC_WR ) < 0) {
1930         afp_errno = AFPERR_ACCESS;
1931         return NULL;
1932     }
1933     
1934     if ((*of = of_findname(path))) {
1935         /* reuse struct adouble so it won't break locks */
1936         adp = (*of)->of_ad;
1937     }
1938     else {
1939         ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
1940         /* META and HF */
1941         if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
1942             /* from AFP spec.
1943              * The user must have the Read & Write privilege for both files in order to use this command.
1944              */
1945             ad_close(adp, ADFLAGS_HF);
1946             afp_errno = AFPERR_ACCESS;
1947             return NULL;
1948         }
1949     }
1950     return adp;
1951 }
1952
1953 #define APPLETEMP ".AppleTempXXXXXX"
1954
1955 int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1956 {
1957     struct stat         srcst, destst;
1958     struct vol          *vol;
1959     struct dir          *dir, *sdir;
1960     char                *spath, temp[17], *p;
1961     char                *supath, *upath;
1962     struct path         *path;
1963     int                 err;
1964     struct adouble      ads;
1965     struct adouble      add;
1966     struct adouble      *adsp = NULL;
1967     struct adouble      *addp = NULL;
1968     struct ofork        *s_of = NULL;
1969     struct ofork        *d_of = NULL;
1970     int                 crossdev;
1971     
1972     int                 slen, dlen;
1973     u_int32_t           sid, did;
1974     u_int16_t           vid;
1975
1976     uid_t              uid;
1977     gid_t              gid;
1978
1979     *rbuflen = 0;
1980     ibuf += 2;
1981
1982     memcpy(&vid, ibuf, sizeof(vid));
1983     ibuf += sizeof(vid);
1984
1985     if (NULL == ( vol = getvolbyvid( vid )) ) {
1986         return( AFPERR_PARAM);
1987     }
1988
1989     if ((vol->v_flags & AFPVOL_RO))
1990         return AFPERR_VLOCK;
1991
1992     /* source and destination dids */
1993     memcpy(&sid, ibuf, sizeof(sid));
1994     ibuf += sizeof(sid);
1995     memcpy(&did, ibuf, sizeof(did));
1996     ibuf += sizeof(did);
1997
1998     /* source file */
1999     if (NULL == (dir = dirlookup( vol, sid )) ) {
2000         return afp_errno; /* was AFPERR_PARAM */
2001     }
2002
2003     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2004         return get_afp_errno(AFPERR_NOOBJ); 
2005     }
2006
2007     if ( path_isadir(path) ) {
2008         return AFPERR_BADTYPE;   /* it's a dir */
2009     }
2010
2011     /* save some stuff */
2012     srcst = path->st;
2013     sdir = curdir;
2014     spath = obj->oldtmp;
2015     supath = obj->newtmp;
2016     strcpy(spath, path->m_name);
2017     strcpy(supath, path->u_name); /* this is for the cnid changing */
2018     p = absupath( vol, sdir, supath);
2019     if (!p) {
2020         /* pathname too long */
2021         return AFPERR_PARAM ;
2022     }
2023     
2024     ad_init(&ads, vol->v_adouble, vol->v_ad_options);
2025     if (!(adsp = find_adouble( path, &s_of, &ads))) {
2026         return afp_errno;
2027     }
2028
2029     /* ***** from here we may have resource fork open **** */
2030     
2031     /* look for the source cnid. if it doesn't exist, don't worry about
2032      * it. */
2033     sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2034
2035     if (NULL == ( dir = dirlookup( vol, did )) ) {
2036         err = afp_errno; /* was AFPERR_PARAM */
2037         goto err_exchangefile;
2038     }
2039
2040     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2041         err = get_afp_errno(AFPERR_NOOBJ); 
2042         goto err_exchangefile;
2043     }
2044
2045     if ( path_isadir(path) ) {
2046         err = AFPERR_BADTYPE;
2047         goto err_exchangefile;
2048     }
2049
2050     /* FPExchangeFiles is the only call that can return the SameObj
2051      * error */
2052     if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2053         err = AFPERR_SAMEOBJ;
2054         goto err_exchangefile;
2055     }
2056
2057     ad_init(&add, vol->v_adouble, vol->v_ad_options);
2058     if (!(addp = find_adouble( path, &d_of, &add))) {
2059         err = afp_errno;
2060         goto err_exchangefile;
2061     }
2062     destst = path->st;
2063
2064     /* they are not on the same device and at least one is open
2065      * FIXME broken for for crossdev and adouble v2
2066      * return an error 
2067     */
2068     crossdev = (srcst.st_dev != destst.st_dev);
2069     if (/* (d_of || s_of)  && */ crossdev) {
2070         err = AFPERR_MISC;
2071         goto err_exchangefile;
2072     }
2073
2074     /* look for destination id. */
2075     upath = path->u_name;
2076     did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2077
2078     /* construct a temp name.
2079      * NOTE: the temp file will be in the dest file's directory. it
2080      * will also be inaccessible from AFP. */
2081     memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2082     if (!mktemp(temp)) {
2083         err = AFPERR_MISC;
2084         goto err_exchangefile;
2085     }
2086     
2087     if (crossdev) {
2088         /* FIXME we need to close fork for copy, both s_of and d_of are null */
2089        ad_close(adsp, ADFLAGS_HF);
2090        ad_close(addp, ADFLAGS_HF);
2091     }
2092
2093     /* now, quickly rename the file. we error if we can't. */
2094     if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2095         goto err_exchangefile;
2096     of_rename(vol, s_of, sdir, spath, curdir, temp);
2097
2098     /* rename destination to source */
2099     if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2100         goto err_src_to_tmp;
2101     of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2102
2103     /* rename temp to destination */
2104     if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2105         goto err_dest_to_src;
2106     of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2107
2108     /* id's need switching. src -> dest and dest -> src. 
2109      * we need to re-stat() if it was a cross device copy.
2110     */
2111     if (sid) {
2112         cnid_delete(vol->v_cdb, sid);
2113     }
2114     if (did) {
2115         cnid_delete(vol->v_cdb, did);
2116     }
2117     if ((did && ( (crossdev && stat( upath, &srcst) < 0) || 
2118                 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2119        ||
2120        (sid && ( (crossdev && stat(p, &destst) < 0) ||
2121                 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2122     ) {
2123         switch (errno) {
2124         case EPERM:
2125         case EACCES:
2126             err = AFPERR_ACCESS;
2127             break;
2128         default:
2129             err = AFPERR_PARAM;
2130         }
2131         goto err_temp_to_dest;
2132     }
2133     
2134     /* here we need to reopen if crossdev */
2135     if (sid && ad_setid(addp, destst.st_dev, destst.st_ino,  sid, sdir->d_did, vol->v_stamp)) 
2136     {
2137        ad_flush( addp );
2138     }
2139         
2140     if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino,  did, curdir->d_did, vol->v_stamp)) 
2141     {
2142        ad_flush( adsp );
2143     }
2144
2145     /* change perms, src gets dest perm and vice versa */
2146
2147     uid = geteuid();
2148     gid = getegid();
2149     if (seteuid(0)) {
2150         LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2151         err = AFP_OK; /* ignore error */
2152         goto err_temp_to_dest;
2153     }
2154
2155     /*
2156      * we need to exchange ACL entries as well
2157      */
2158     /* exchange_acls(vol, p, upath); */
2159
2160     path->st = srcst;
2161     path->st_valid = 1;
2162     path->st_errno = 0;
2163     path->m_name = NULL;
2164     path->u_name = upath;
2165
2166     setfilunixmode(vol, path, destst.st_mode);
2167     setfilowner(vol, destst.st_uid, destst.st_gid, path);
2168
2169     path->st = destst;
2170     path->st_valid = 1;
2171     path->st_errno = 0;
2172     path->u_name = p;
2173
2174     setfilunixmode(vol, path, srcst.st_mode);
2175     setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2176
2177     if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2178         LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2179         exit(EXITERR_SYS);
2180     }
2181
2182     err = AFP_OK;
2183     goto err_exchangefile;
2184
2185     /* all this stuff is so that we can unwind a failed operation
2186      * properly. */
2187 err_temp_to_dest:
2188     /* rename dest to temp */
2189     renamefile(vol, upath, temp, temp, adsp);
2190     of_rename(vol, s_of, curdir, upath, curdir, temp);
2191
2192 err_dest_to_src:
2193     /* rename source back to dest */
2194     renamefile(vol, p, upath, path->m_name, addp);
2195     of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2196
2197 err_src_to_tmp:
2198     /* rename temp back to source */
2199     renamefile(vol, temp, p, spath, adsp);
2200     of_rename(vol, s_of, curdir, temp, sdir, spath);
2201
2202 err_exchangefile:
2203     if ( !s_of && adsp && ad_meta_fileno(adsp) != -1 ) { /* META */
2204        ad_close(adsp, ADFLAGS_HF);
2205     }
2206     if ( !d_of && addp && ad_meta_fileno(addp) != -1 ) {/* META */
2207        ad_close(addp, ADFLAGS_HF);
2208     }
2209
2210     return err;
2211 }