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