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