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