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