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