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