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