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