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