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