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