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