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