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