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