]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/file.c
remove a c++ comment
[netatalk.git] / etc / afpd / file.c
1 /*
2  * $Id: file.c,v 1.92.2.2.2.31.2.9 2005-02-05 14:46:35 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, 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 extmap       *em;
782     int                 bit, isad = 1, err = AFP_OK;
783     char                *upath;
784     u_char              achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
785     u_int16_t           ashort, bshort;
786     u_int32_t           aint;
787     u_int32_t           upriv;
788     u_int16_t           upriv_bit = 0;
789     
790     struct utimbuf      ut;
791
792     int                 change_mdate = 0;
793     int                 change_parent_mdate = 0;
794     int                 newdate = 0;
795     struct timeval      tv;
796     uid_t               f_uid;
797     gid_t               f_gid;
798     u_int16_t           bitmap = f_bitmap;
799     u_int32_t           cdate,bdate;
800     u_char              finder_buf[32];
801
802 #ifdef DEBUG
803     LOG(log_info, logtype_afpd, "begin setfilparams:");
804 #endif /* DEBUG */
805
806     upath = path->u_name;
807     adp = of_ad(vol, path, &ad);
808     
809
810     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
811         return AFPERR_ACCESS;
812     }
813
814     /* with unix priv maybe we have to change adouble file priv first */
815     bit = 0;
816     while ( bitmap != 0 ) {
817         while (( bitmap & 1 ) == 0 ) {
818             bitmap = bitmap>>1;
819             bit++;
820         }
821         switch(  bit ) {
822         case FILPBIT_ATTR :
823             change_mdate = 1;
824             memcpy(&ashort, buf, sizeof( ashort ));
825             buf += sizeof( ashort );
826             break;
827         case FILPBIT_CDATE :
828             change_mdate = 1;
829             memcpy(&cdate, buf, sizeof(cdate));
830             buf += sizeof( cdate );
831             break;
832         case FILPBIT_MDATE :
833             memcpy(&newdate, buf, sizeof( newdate ));
834             buf += sizeof( newdate );
835             break;
836         case FILPBIT_BDATE :
837             change_mdate = 1;
838             memcpy(&bdate, buf, sizeof( bdate));
839             buf += sizeof( bdate );
840             break;
841         case FILPBIT_FINFO :
842             change_mdate = 1;
843             memcpy(finder_buf, buf, 32 );
844             buf += 32;
845             break;
846         case FILPBIT_UNIXPR :
847             if (!vol_unix_priv(vol)) {
848                 /* this volume doesn't use unix priv */
849                 err = AFPERR_BITMAP;
850                 bitmap = 0;
851                 break;
852             }
853             change_mdate = 1;
854             change_parent_mdate = 1;
855
856             memcpy( &aint, buf, sizeof( aint ));
857             f_uid = ntohl (aint);
858             buf += sizeof( aint );
859             memcpy( &aint, buf, sizeof( aint ));
860             f_gid = ntohl (aint);
861             buf += sizeof( aint );
862             setfilowner(vol, f_uid, f_gid, path);
863
864             memcpy( &upriv, buf, sizeof( upriv ));
865             buf += sizeof( upriv );
866             upriv = ntohl (upriv);
867             if ((upriv & S_IWUSR)) {
868                 setfilunixmode(vol, path, upriv);
869             }
870             else {
871                 /* do it later */
872                 upriv_bit = 1;
873             }
874             break;
875         case FILPBIT_PDINFO :
876             if (afp_version < 30) { /* else it's UTF8 name */
877                 achar = *buf;
878                 buf += 2;
879                 /* Keep special case to support crlf translations */
880                 if ((unsigned int) achar == 0x04) {
881                     fdType = (u_char *)"TEXT";
882                     buf += 2;
883                 } else {
884                     xyy[0] = ( u_char ) 'p';
885                     xyy[1] = achar;
886                     xyy[3] = *buf++;
887                     xyy[2] = *buf++;
888                     fdType = xyy;
889                 }
890                 break;
891             }
892             /* fallthrough */
893         default :
894             err = AFPERR_BITMAP;
895             /* break while loop */
896             bitmap = 0;
897             break;
898         }
899
900         bitmap = bitmap>>1;
901         bit++;
902     }
903
904     /* second try with adouble open 
905     */
906     if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
907                  O_RDWR|O_CREAT, 0666, adp) < 0) {
908         /* for some things, we don't need an adouble header */
909         if (f_bitmap & ~(1<<FILPBIT_MDATE)) {
910             return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
911         }
912         isad = 0;
913     } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
914         ad_setname(adp, path->m_name);
915     }
916     
917     bit = 0;
918     bitmap = f_bitmap;
919     while ( bitmap != 0 ) {
920         while (( bitmap & 1 ) == 0 ) {
921             bitmap = bitmap>>1;
922             bit++;
923         }
924
925         switch(  bit ) {
926         case FILPBIT_ATTR :
927             ad_getattr(adp, &bshort);
928             if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
929                 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
930                 change_parent_mdate = 1;
931             if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
932                 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
933             } else {
934                 bshort &= ~ashort;
935             }
936             ad_setattr(adp, bshort);
937             break;
938         case FILPBIT_CDATE :
939             ad_setdate(adp, AD_DATE_CREATE, cdate);
940             break;
941         case FILPBIT_MDATE :
942             break;
943         case FILPBIT_BDATE :
944             ad_setdate(adp, AD_DATE_BACKUP, bdate);
945             break;
946         case FILPBIT_FINFO :
947             if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
948                     && ( 
949                      ((em = getextmap( path->m_name )) &&
950                       !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
951                       !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
952                      || ((em = getdefextmap()) &&
953                       !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
954                       !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
955             )) {
956                 memcpy(finder_buf, ufinderi, 8 );
957             }
958             memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
959             break;
960         case FILPBIT_UNIXPR :
961             if (upriv_bit) {
962                 setfilunixmode(vol, path, upriv);
963             }
964             break;
965         case FILPBIT_PDINFO :
966             if (afp_version < 30) { /* else it's UTF8 name */
967                 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
968                 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
969                 break;
970             }
971             /* fallthrough */
972         default :
973             err = AFPERR_BITMAP;
974             goto setfilparam_done;
975         }
976         bitmap = bitmap>>1;
977         bit++;
978     }
979
980 setfilparam_done:
981     if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
982        newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
983     }
984     if (newdate) {
985        if (isad)
986           ad_setdate(adp, AD_DATE_MODIFY, newdate);
987        ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
988        utime(upath, &ut);
989     }
990
991     if (isad) {
992         ad_flush( adp, ADFLAGS_HF );
993         ad_close( adp, ADFLAGS_HF );
994
995     }
996
997     if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
998         newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
999         bitmap = 1<<FILPBIT_MDATE;
1000         setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
1001     }
1002
1003 #ifdef DEBUG
1004     LOG(log_info, logtype_afpd, "end setfilparams:");
1005 #endif /* DEBUG */
1006     return err;
1007 }
1008
1009 /*
1010  * renamefile and copyfile take the old and new unix pathnames
1011  * and the new mac name.
1012  *
1013  * src         the source path 
1014  * dst         the dest filename in current dir
1015  * newname     the dest mac name
1016  * adp         adouble struct of src file, if open, or & zeroed one
1017  *
1018  */
1019 int renamefile(vol, src, dst, newname, adp )
1020 const struct vol *vol;
1021 char    *src, *dst, *newname;
1022 struct adouble    *adp;
1023 {
1024     char        adsrc[ MAXPATHLEN + 1];
1025     int         rc;
1026
1027 #ifdef DEBUG
1028     LOG(log_info, logtype_afpd, "begin renamefile:");
1029 #endif /* DEBUG */
1030
1031     if ( unix_rename( src, dst ) < 0 ) {
1032         switch ( errno ) {
1033         case ENOENT :
1034             return( AFPERR_NOOBJ );
1035         case EPERM:
1036         case EACCES :
1037             return( AFPERR_ACCESS );
1038         case EROFS:
1039             return AFPERR_VLOCK;
1040         case EXDEV :                    /* Cross device move -- try copy */
1041            /* NOTE: with open file it's an error because after the copy we will 
1042             * get two files, it's fixable for our process (eg reopen the new file, get the
1043             * locks, and so on. But it doesn't solve the case with a second process
1044             */
1045             if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
1046                 /* FIXME  warning in syslog so admin'd know there's a conflict ?*/
1047                 return AFPERR_OLOCK; /* little lie */
1048             }
1049             if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1050                 /* on error copyfile delete dest */
1051                 return( rc );
1052             }
1053             return deletefile(vol, src, 0);
1054         default :
1055             return( AFPERR_PARAM );
1056         }
1057     }
1058
1059     strcpy( adsrc, vol->ad_path( src, 0 ));
1060
1061     if (unix_rename( adsrc, vol->ad_path( dst, 0 )) < 0 ) {
1062         struct stat st;
1063         int err;
1064         
1065         err = errno;        
1066         if (errno == ENOENT) {
1067             struct adouble    ad;
1068
1069             if (stat(adsrc, &st)) /* source has no ressource fork, */
1070                 return AFP_OK;
1071             
1072             /* We are here  because :
1073              * -there's no dest folder. 
1074              * -there's no .AppleDouble in the dest folder.
1075              * if we use the struct adouble passed in parameter it will not
1076              * create .AppleDouble if the file is already opened, so we
1077              * use a diff one, it's not a pb,ie it's not the same file, yet.
1078              */
1079             ad_init(&ad, vol->v_adouble); 
1080             if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
1081                 ad_close(&ad, ADFLAGS_HF);
1082                 if (!unix_rename( adsrc, vol->ad_path( dst, 0 )) ) 
1083                    err = 0;
1084                 else 
1085                    err = errno;
1086             }
1087             else { /* it's something else, bail out */
1088                 err = errno;
1089             }
1090         }
1091         /* try to undo the data fork rename,
1092          * we know we are on the same device 
1093         */
1094         if (err) {
1095             unix_rename( dst, src ); 
1096             /* return the first error */
1097             switch ( err) {
1098             case ENOENT :
1099                 return AFPERR_NOOBJ;
1100             case EPERM:
1101             case EACCES :
1102                 return AFPERR_ACCESS ;
1103             case EROFS:
1104                 return AFPERR_VLOCK;
1105             default :
1106                 return AFPERR_PARAM ;
1107             }
1108         }
1109     }
1110
1111     /* don't care if we can't open the newly renamed ressource fork
1112      */
1113     if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1114         ad_setname(adp, newname);
1115         ad_flush( adp, ADFLAGS_HF );
1116         ad_close( adp, ADFLAGS_HF );
1117     }
1118 #ifdef DEBUG
1119     LOG(log_info, logtype_afpd, "end renamefile:");
1120 #endif /* DEBUG */
1121
1122     return( AFP_OK );
1123 }
1124
1125 /* ---------------- 
1126    convert a Mac long name to an utf8 name,
1127 */
1128 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1129 {
1130 size_t    outlen;
1131
1132     if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1133         return -1;
1134     }
1135     return outlen;
1136 }
1137
1138 /* ---------------- */
1139 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1140 {
1141 char        type = *ibuf;
1142 size_t      plen = 0;
1143 u_int16_t   len16;
1144 u_int32_t   hint;
1145
1146     if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1147         return -1;
1148     }
1149     ibuf++;
1150     switch (type) {
1151     case 2:
1152         if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1153             if (afp_version >= 30) {
1154                 /* convert it to UTF8 
1155                 */
1156                 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == -1)
1157                    return -1;
1158             }
1159             else {
1160                 strncpy( newname, ibuf, plen );
1161                 newname[ plen ] = '\0';
1162             }
1163             if (strlen(newname) != plen) {
1164                 /* there's \0 in newname, e.g. it's a pathname not
1165                  * only a filename. 
1166                 */
1167                 return -1;
1168             }
1169         }
1170         break;
1171     case 3:
1172         memcpy(&hint, ibuf, sizeof(hint));
1173         ibuf += sizeof(hint);
1174            
1175         memcpy(&len16, ibuf, sizeof(len16));
1176         ibuf += sizeof(len16);
1177         plen = ntohs(len16);
1178         
1179         if (plen) {
1180             if (plen > AFPOBJ_TMPSIZ) {
1181                 return -1;
1182             }
1183             strncpy( newname, ibuf, plen );
1184             newname[ plen ] = '\0';
1185             if (strlen(newname) != plen) {
1186                 return -1;
1187             }
1188         }
1189         break;
1190     }
1191     return plen;
1192 }
1193
1194 /* -----------------------------------
1195 */
1196 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1197 AFPObj      *obj;
1198 char    *ibuf, *rbuf;
1199 int             ibuflen, *rbuflen;
1200 {
1201     struct vol  *s_vol, *d_vol;
1202     struct dir  *dir;
1203     char        *newname, *p, *upath;
1204     struct path *s_path;
1205     u_int32_t   sdid, ddid;
1206     int         err, retvalue = AFP_OK;
1207     u_int16_t   svid, dvid;
1208
1209     struct adouble ad, *adp;
1210     int denyreadset;
1211     
1212 #ifdef DEBUG
1213     LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1214 #endif /* DEBUG */
1215
1216     *rbuflen = 0;
1217     ibuf += 2;
1218
1219     memcpy(&svid, ibuf, sizeof( svid ));
1220     ibuf += sizeof( svid );
1221     if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1222         return( AFPERR_PARAM );
1223     }
1224
1225     memcpy(&sdid, ibuf, sizeof( sdid ));
1226     ibuf += sizeof( sdid );
1227     if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1228         return afp_errno;
1229     }
1230
1231     memcpy(&dvid, ibuf, sizeof( dvid ));
1232     ibuf += sizeof( dvid );
1233     memcpy(&ddid, ibuf, sizeof( ddid ));
1234     ibuf += sizeof( ddid );
1235
1236     if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1237         return get_afp_errno(AFPERR_PARAM);
1238     }
1239     if ( path_isadir(s_path) ) {
1240         return( AFPERR_BADTYPE );
1241     }
1242
1243     /* don't allow copies when the file is open.
1244      * XXX: the spec only calls for read/deny write access.
1245      *      however, copyfile doesn't have any of that info,
1246      *      and locks need to stay coherent. as a result,
1247      *      we just balk if the file is opened already. */
1248
1249     adp = of_ad(s_vol, s_path, &ad);
1250
1251     if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1252         return AFPERR_DENYCONF;
1253     }
1254     denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 || 
1255                   getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1256     ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1257     if (denyreadset) {
1258         return AFPERR_DENYCONF;
1259     }
1260
1261     newname = obj->newtmp;
1262     strcpy( newname, s_path->m_name );
1263
1264     p = ctoupath( s_vol, curdir, newname );
1265     if (!p) {
1266         return AFPERR_PARAM;
1267     
1268     }
1269 #ifdef FORCE_UIDGID
1270     /* FIXME svid != dvid && dvid's user can't read svid */
1271 #endif
1272     if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1273         return( AFPERR_PARAM );
1274     }
1275
1276     if (d_vol->v_flags & AFPVOL_RO)
1277         return AFPERR_VLOCK;
1278
1279     if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1280         return afp_errno;
1281     }
1282
1283     if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1284         return get_afp_errno(AFPERR_NOOBJ); 
1285     }
1286     if ( *s_path->m_name != '\0' ) {
1287         path_error(s_path, AFPERR_PARAM);
1288     }
1289
1290     /* one of the handful of places that knows about the path type */
1291     if (copy_path_name(d_vol, newname, ibuf) < 0) {
1292         return( AFPERR_PARAM );
1293     }
1294     /* newname is always only a filename so curdir *is* its
1295      * parent folder
1296     */
1297     if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1298         return( AFPERR_PARAM );
1299     }
1300     if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1301         return err;
1302     }
1303     curdir->offcnt++;
1304
1305 #ifdef DROPKLUDGE
1306     if (vol->v_flags & AFPVOL_DROPBOX) {
1307         retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1308     }
1309 #endif /* DROPKLUDGE */
1310
1311     setvoltime(obj, d_vol );
1312
1313 #ifdef DEBUG
1314     LOG(log_info, logtype_afpd, "end afp_copyfile:");
1315 #endif /* DEBUG */
1316
1317     return( retvalue );
1318 }
1319
1320 /* ----------------------- */
1321 static __inline__ int copy_all(const int dfd, const void *buf,
1322                                size_t buflen)
1323 {
1324     ssize_t cc;
1325
1326 #ifdef DEBUG
1327     LOG(log_info, logtype_afpd, "begin copy_all:");
1328 #endif /* DEBUG */
1329
1330     while (buflen > 0) {
1331         if ((cc = write(dfd, buf, buflen)) < 0) {
1332             switch (errno) {
1333             case EINTR:
1334                 continue;
1335             default:
1336                 return -1;
1337             }
1338         }
1339         buflen -= cc;
1340     }
1341
1342 #ifdef DEBUG
1343     LOG(log_info, logtype_afpd, "end copy_all:");
1344 #endif /* DEBUG */
1345
1346     return 0;
1347 }
1348
1349 /* -------------------------- */
1350 static int copy_fd(int dfd, int sfd)
1351 {
1352     ssize_t cc;
1353     int     err = 0;
1354     char    filebuf[8192];
1355     
1356 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1357     /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1358     off_t   offset = 0;
1359     size_t  size;
1360     struct stat         st;
1361     #define BUF 128*1024*1024
1362
1363     if (fstat(sfd, &st) == 0) {
1364         
1365         while (1) {
1366             if ( offset >= st.st_size) {
1367                return 0;
1368             }
1369             size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1370             if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1371                 switch (errno) {
1372                 case ENOSYS:
1373                 case EINVAL:  /* there's no guarantee that all fs support sendfile */
1374                     goto no_sendfile;
1375                 default:
1376                     return -1;
1377                 }
1378             }
1379         }
1380     }
1381     no_sendfile:
1382     lseek(sfd, offset, SEEK_SET);
1383 #endif 
1384
1385     while (1) {
1386         if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1387             if (errno == EINTR)
1388                 continue;
1389             err = -1;
1390             break;
1391         }
1392
1393         if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1394             break;
1395         }
1396     }
1397     return err;
1398 }
1399
1400 /* ----------------------------------
1401  * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1402  * because we are doing it elsewhere.
1403  */
1404 int copyfile(s_vol, d_vol, src, dst, newname, adp )
1405 const struct vol *s_vol, *d_vol;
1406 char    *src, *dst, *newname;
1407 struct adouble *adp;
1408 {
1409     struct adouble      ads, add;
1410     int                 err = 0;
1411     int                 ret_err = 0;
1412     int                 adflags;
1413     int                 noadouble = vol_noadouble(d_vol);
1414     struct stat         st;
1415     
1416 #ifdef DEBUG
1417     LOG(log_info, logtype_afpd, "begin copyfile:");
1418 #endif /* DEBUG */
1419
1420     if (adp == NULL) {
1421         ad_init(&ads, s_vol->v_adouble); 
1422         adp = &ads;
1423     }
1424     ad_init(&add, d_vol->v_adouble);
1425     adflags = ADFLAGS_DF;
1426     if (newname) {
1427         adflags |= ADFLAGS_HF;
1428     }
1429
1430     if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1431         ret_err = errno;
1432         goto done;
1433     }
1434
1435     if (ad_hfileno(adp) == -1) {
1436         /* no resource fork, don't create one for dst file */
1437         adflags &= ~ADFLAGS_HF;
1438     }
1439
1440     if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1441         ret_err = errno;
1442         ad_close( adp, adflags );
1443         if (EEXIST != ret_err) {
1444             deletefile(d_vol, dst, 0);
1445             goto done;
1446         }
1447         return AFPERR_EXIST;
1448     }
1449     if (ad_hfileno(adp) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(adp)))){
1450         /* copy the data fork */
1451         err = copy_fd(ad_dfileno(&add), ad_dfileno(adp));
1452     }
1453
1454     /* Now, reopen destination file */
1455     if (err < 0) {
1456        ret_err = errno;
1457     }
1458     ad_close( adp, adflags );
1459
1460     if (ad_close( &add, adflags ) <0) {
1461         deletefile(d_vol, dst, 0);
1462         ret_err = errno;
1463         goto done;
1464     } 
1465     else {
1466         ad_init(&add, d_vol->v_adouble);
1467         if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
1468             ret_err = errno;
1469         }
1470     }
1471
1472     if (!ret_err && newname) {
1473         ad_setname(&add, newname);
1474     }
1475
1476     ad_flush( &add, adflags );
1477     if (ad_close( &add, adflags ) <0) {
1478        ret_err = errno;
1479     }
1480     if (ret_err) {
1481         deletefile(d_vol, dst, 0);
1482     }
1483     else if (!stat(src, &st)) {
1484         /* set dest modification date to src date */
1485         struct utimbuf  ut;
1486
1487         ut.actime = ut.modtime = st.st_mtime;
1488         utime(dst, &ut);
1489         /* FIXME netatalk doesn't use resource fork file date
1490          * but maybe we should set its modtime too.
1491         */
1492     }
1493
1494 #ifdef DEBUG
1495     LOG(log_info, logtype_afpd, "end copyfile:");
1496 #endif /* DEBUG */
1497
1498 done:
1499     switch ( ret_err ) {
1500     case 0:
1501         return AFP_OK;
1502     case EDQUOT:
1503     case EFBIG:
1504     case ENOSPC:
1505         return AFPERR_DFULL;
1506     case ENOENT:
1507         return AFPERR_NOOBJ;
1508     case EACCES:
1509         return AFPERR_ACCESS;
1510     case EROFS:
1511         return AFPERR_VLOCK;
1512     }
1513     return AFPERR_PARAM;
1514 }
1515
1516
1517 /* -----------------------------------
1518    vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1519    checkAttrib:   1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1520
1521    when deletefile is called we don't have lock on it, file is closed (for us)
1522    untrue if called by renamefile
1523    
1524    ad_open always try to open file RDWR first and ad_lock takes care of
1525    WRITE lock on read only file.
1526 */
1527 int deletefile( vol, file, checkAttrib )
1528 const struct vol      *vol;
1529 char            *file;
1530 int         checkAttrib;
1531 {
1532     struct adouble      ad;
1533     struct adouble      *adp = &ad;
1534     int                 adflags, err = AFP_OK;
1535
1536 #ifdef DEBUG
1537     LOG(log_info, logtype_afpd, "begin deletefile:");
1538 #endif /* DEBUG */
1539
1540     /* try to open both forks at once */
1541     adflags = ADFLAGS_DF|ADFLAGS_HF;
1542     while(1) {
1543         ad_init(&ad, vol->v_adouble);  /* OK */
1544         if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1545             switch (errno) {
1546             case ENOENT:
1547                 if (adflags == ADFLAGS_DF)
1548                     return AFPERR_NOOBJ;
1549                    
1550                 /* that failed. now try to open just the data fork */
1551                 adflags = ADFLAGS_DF;
1552                 continue;
1553
1554             case EACCES:
1555                 adp = NULL; /* maybe it's a file we no rw mode for us */
1556                 break;      /* was return AFPERR_ACCESS;*/
1557             case EROFS:
1558                 return AFPERR_VLOCK;
1559             default:
1560                 return( AFPERR_PARAM );
1561             }
1562         }
1563         break;  /* from the while */
1564     }
1565     /*
1566      * Does kFPDeleteInhibitBit (bit 8) set?
1567      */
1568     if (checkAttrib) {
1569         u_int16_t   bshort;
1570         
1571         if (adp && (adflags & ADFLAGS_HF)) {
1572
1573             ad_getattr(&ad, &bshort);
1574             if ((bshort & htons(ATTRBIT_NODELETE))) {
1575                 ad_close( &ad, adflags );
1576                 return(AFPERR_OLOCK);
1577             }
1578         }
1579         else if (!adp) {
1580             /* was EACCESS error try to get only metadata */
1581             ad_init(&ad, vol->v_adouble);  /* OK */
1582             if ( ad_metadata( file , 0, &ad) == 0 ) {
1583                 ad_getattr(&ad, &bshort);
1584                 ad_close( &ad, ADFLAGS_HF );
1585                 if ((bshort & htons(ATTRBIT_NODELETE))) {
1586                     return  AFPERR_OLOCK;
1587                 }
1588             }
1589         }
1590     }
1591     
1592     if (adp && (adflags & ADFLAGS_HF) ) {
1593         /* FIXME we have a pb here because we want to know if a file is open 
1594          * there's a 'priority inversion' if you can't open the ressource fork RW
1595          * you can delete it if it's open because you can't get a write lock.
1596          * 
1597          * ADLOCK_FILELOCK means the whole ressource fork, not only after the 
1598          * metadatas
1599          *
1600          * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1601          */
1602         if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1603             ad_close( &ad, adflags );
1604             return( AFPERR_BUSY );
1605         }
1606     }
1607
1608     if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1609         err = AFPERR_BUSY;
1610     }
1611     else if (!(err = netatalk_unlink( vol->ad_path( file, ADFLAGS_HF)) ) &&
1612              !(err = netatalk_unlink( file )) ) {
1613         cnid_t id;
1614         if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file)))) 
1615         {
1616             cnid_delete(vol->v_cdb, id);
1617         }
1618
1619     }
1620     if (adp)
1621         ad_close( &ad, adflags );  /* ad_close removes locks if any */
1622
1623 #ifdef DEBUG
1624     LOG(log_info, logtype_afpd, "end deletefile:");
1625 #endif /* DEBUG */
1626
1627     return err;
1628 }
1629
1630 /* ------------------------------------ */
1631 /* return a file id */
1632 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1633 AFPObj      *obj;
1634 char    *ibuf, *rbuf;
1635 int             ibuflen, *rbuflen;
1636 {
1637     struct stat         *st;
1638     struct vol          *vol;
1639     struct dir          *dir;
1640     char                *upath;
1641     int                 len;
1642     cnid_t              did, id;
1643     u_short             vid;
1644     struct path         *s_path;
1645
1646 #ifdef DEBUG
1647     LOG(log_info, logtype_afpd, "begin afp_createid:");
1648 #endif /* DEBUG */
1649
1650     *rbuflen = 0;
1651
1652     ibuf += 2;
1653
1654     memcpy(&vid, ibuf, sizeof(vid));
1655     ibuf += sizeof(vid);
1656
1657     if (NULL == ( vol = getvolbyvid( vid )) ) {
1658         return( AFPERR_PARAM);
1659     }
1660
1661     if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1662         return AFPERR_NOOP;
1663     }
1664
1665     if (vol->v_flags & AFPVOL_RO)
1666         return AFPERR_VLOCK;
1667
1668     memcpy(&did, ibuf, sizeof( did ));
1669     ibuf += sizeof(did);
1670
1671     if (NULL == ( dir = dirlookup( vol, did )) ) {
1672         return afp_errno; /* was AFPERR_PARAM */
1673     }
1674
1675     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1676         return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1677     }
1678
1679     if ( path_isadir(s_path) ) {
1680         return( AFPERR_BADTYPE );
1681     }
1682
1683     upath = s_path->u_name;
1684     switch (s_path->st_errno) {
1685         case 0:
1686              break; /* success */
1687         case EPERM:
1688         case EACCES:
1689             return AFPERR_ACCESS;
1690         case ENOENT:
1691             return AFPERR_NOOBJ;
1692         default:
1693             return AFPERR_PARAM;
1694     }
1695     st = &s_path->st;
1696     if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1697         memcpy(rbuf, &id, sizeof(id));
1698         *rbuflen = sizeof(id);
1699         return AFPERR_EXISTID;
1700     }
1701
1702     if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1703         memcpy(rbuf, &id, sizeof(id));
1704         *rbuflen = sizeof(id);
1705         return AFP_OK;
1706     }
1707
1708 #ifdef DEBUG
1709     LOG(log_info, logtype_afpd, "ending afp_createid...:");
1710 #endif /* DEBUG */
1711     return afp_errno;
1712 }
1713
1714 static int
1715 reenumerate_id(const struct vol *vol, char *name, cnid_t did)
1716 {
1717     DIR             *dp;
1718     struct dirent   *de;
1719     int             ret;
1720     cnid_t          aint;
1721     struct path     path;
1722     
1723     memset(&path, 0, sizeof(path));
1724     if (vol->v_cdb == NULL) {
1725         return -1;
1726     }
1727     if (NULL == ( dp = opendir( name)) ) {
1728         return -1;
1729     }
1730     ret = 0;
1731     for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
1732         if (NULL == check_dirent(vol, de->d_name))
1733             continue;
1734
1735         if ( stat(de->d_name, &path.st)<0 )
1736             continue;
1737         
1738         /* update or add to cnid */
1739         aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1740
1741 #if AD_VERSION > AD_VERSION1
1742         if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1743             struct adouble  ad, *adp;
1744
1745             path.st_errno = 0;
1746             path.st_valid = 1;
1747             path.u_name = de->d_name;
1748             
1749             adp = of_ad(vol, &path, &ad);
1750             
1751             if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, adp ) < 0 ) {
1752                 continue;
1753             }
1754             if (ad_setid(adp,(vol->v_flags & AFPVOL_NODEV)?0:path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1755                 ad_flush(adp, ADFLAGS_HF);
1756             }
1757             ad_close(adp, ADFLAGS_HF);
1758         }
1759 #endif /* AD_VERSION > AD_VERSION1 */
1760
1761         ret++;
1762     }
1763     closedir(dp);
1764     return ret;
1765 }
1766
1767     
1768 /* ------------------------------
1769    resolve a file id */
1770 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1771 AFPObj      *obj;
1772 char    *ibuf, *rbuf;
1773 int             ibuflen, *rbuflen;
1774 {
1775     struct vol          *vol;
1776     struct dir          *dir;
1777     char                *upath;
1778     struct path         path;
1779     int                 err, buflen, retry=0;
1780     cnid_t              id, cnid;
1781     u_int16_t           vid, bitmap;
1782
1783     static char buffer[12 + MAXPATHLEN + 1];
1784     int len = 12 + MAXPATHLEN + 1;
1785
1786 #ifdef DEBUG
1787     LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1788 #endif /* DEBUG */
1789
1790     *rbuflen = 0;
1791     ibuf += 2;
1792
1793     memcpy(&vid, ibuf, sizeof(vid));
1794     ibuf += sizeof(vid);
1795
1796     if (NULL == ( vol = getvolbyvid( vid )) ) {
1797         return( AFPERR_PARAM);
1798     }
1799
1800     if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1801         return AFPERR_NOOP;
1802     }
1803
1804     memcpy(&id, ibuf, sizeof( id ));
1805     ibuf += sizeof(id);
1806     cnid = id;
1807
1808 retry:
1809     if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1810         return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1811     }
1812
1813     if (NULL == ( dir = dirlookup( vol, id )) ) {
1814         return AFPERR_NOID; /* idem AFPERR_PARAM */
1815     }
1816     path.u_name = upath;
1817     if (movecwd(vol, dir) < 0) {
1818         switch (errno) {
1819         case EACCES:
1820         case EPERM:
1821             return AFPERR_ACCESS;
1822         case ENOENT:
1823             return AFPERR_NOID;
1824         default:
1825             return AFPERR_PARAM;
1826         }
1827     }
1828
1829     if ( of_stat(&path) < 0 ) {
1830 #ifdef ESTALE
1831         /* with nfs and our working directory is deleted */
1832         if (errno == ESTALE) {
1833             errno = ENOENT;
1834         }
1835 #endif  
1836         if ( errno == ENOENT && !retry) {
1837             /* cnid db is out of sync, reenumerate the directory and updated ids */
1838             reenumerate_id(vol, ".", id);
1839             id = cnid;
1840             retry = 1;
1841             goto retry;
1842         }
1843         switch (errno) {
1844         case EACCES:
1845         case EPERM:
1846             return AFPERR_ACCESS;
1847         case ENOENT:
1848             return AFPERR_NOID;
1849         default:
1850             return AFPERR_PARAM;
1851         }
1852     }
1853
1854     /* directories are bad */
1855     if (S_ISDIR(path.st.st_mode))
1856         return AFPERR_BADTYPE;
1857
1858     memcpy(&bitmap, ibuf, sizeof(bitmap));
1859     bitmap = ntohs( bitmap );
1860     if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1861         return AFPERR_NOID;
1862     }
1863     if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir, 
1864                             rbuf + sizeof(bitmap), &buflen))) {
1865         return err;
1866     }
1867     *rbuflen = buflen + sizeof(bitmap);
1868     memcpy(rbuf, ibuf, sizeof(bitmap));
1869
1870 #ifdef DEBUG
1871     LOG(log_info, logtype_afpd, "end afp_resolveid:");
1872 #endif /* DEBUG */
1873
1874     return AFP_OK;
1875 }
1876
1877 /* ------------------------------ */
1878 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1879 AFPObj      *obj;
1880 char    *ibuf, *rbuf;
1881 int             ibuflen, *rbuflen;
1882 {
1883     struct stat         st;
1884     struct vol          *vol;
1885     struct dir          *dir;
1886     char                *upath;
1887     int                 err;
1888     cnid_t              id;
1889     cnid_t              fileid;
1890     u_short             vid;
1891     static char buffer[12 + MAXPATHLEN + 1];
1892     int len = 12 + MAXPATHLEN + 1;
1893
1894 #ifdef DEBUG
1895     LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1896 #endif /* DEBUG */
1897
1898     *rbuflen = 0;
1899     ibuf += 2;
1900
1901     memcpy(&vid, ibuf, sizeof(vid));
1902     ibuf += sizeof(vid);
1903
1904     if (NULL == ( vol = getvolbyvid( vid )) ) {
1905         return( AFPERR_PARAM);
1906     }
1907
1908     if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1909         return AFPERR_NOOP;
1910     }
1911
1912     if (vol->v_flags & AFPVOL_RO)
1913         return AFPERR_VLOCK;
1914
1915     memcpy(&id, ibuf, sizeof( id ));
1916     ibuf += sizeof(id);
1917     fileid = id;
1918
1919     if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1920         return AFPERR_NOID;
1921     }
1922
1923     if (NULL == ( dir = dirlookup( vol, id )) ) {
1924         return( AFPERR_PARAM );
1925     }
1926
1927     err = AFP_OK;
1928     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1929         switch (errno) {
1930         case EACCES:
1931         case EPERM:
1932             return AFPERR_ACCESS;
1933 #ifdef ESTALE
1934         case ESTALE:
1935 #endif  
1936         case ENOENT:
1937             /* still try to delete the id */
1938             err = AFPERR_NOOBJ;
1939             break;
1940         default:
1941             return AFPERR_PARAM;
1942         }
1943     }
1944     else if (S_ISDIR(st.st_mode)) /* directories are bad */
1945         return AFPERR_BADTYPE;
1946
1947     if (cnid_delete(vol->v_cdb, fileid)) {
1948         switch (errno) {
1949         case EROFS:
1950             return AFPERR_VLOCK;
1951         case EPERM:
1952         case EACCES:
1953             return AFPERR_ACCESS;
1954         default:
1955             return AFPERR_PARAM;
1956         }
1957     }
1958
1959 #ifdef DEBUG
1960     LOG(log_info, logtype_afpd, "end afp_deleteid:");
1961 #endif /* DEBUG */
1962
1963     return err;
1964 }
1965
1966 /* ------------------------------ */
1967 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1968 {
1969     int             ret;
1970
1971     if (path->st_errno) {
1972         switch (path->st_errno) {
1973         case ENOENT:
1974             afp_errno = AFPERR_NOID;
1975             break;
1976         case EPERM:
1977         case EACCES:
1978             afp_errno = AFPERR_ACCESS;
1979             break;
1980         default:
1981             afp_errno = AFPERR_PARAM;
1982             break;
1983         }
1984         return NULL;
1985     }
1986     /* we use file_access both for legacy Mac perm and
1987      * for unix privilege, rename will take care of folder perms
1988     */
1989     if (file_access(path, OPENACC_WR ) < 0) {
1990         afp_errno = AFPERR_ACCESS;
1991         return NULL;
1992     }
1993     
1994     if ((*of = of_findname(path))) {
1995         /* reuse struct adouble so it won't break locks */
1996         adp = (*of)->of_ad;
1997     }
1998     else {
1999         ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
2000         if ( !ret && ad_hfileno(adp) != -1 && !(adp->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) {
2001             /* from AFP spec.
2002              * The user must have the Read & Write privilege for both files in order to use this command.
2003              */
2004             ad_close(adp, ADFLAGS_HF);
2005             afp_errno = AFPERR_ACCESS;
2006             return NULL;
2007         }
2008     }
2009     return adp;
2010 }
2011
2012 #define APPLETEMP ".AppleTempXXXXXX"
2013
2014 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
2015 AFPObj      *obj;
2016 char    *ibuf, *rbuf;
2017 int             ibuflen, *rbuflen;
2018 {
2019     struct stat         srcst, destst;
2020     struct vol          *vol;
2021     struct dir          *dir, *sdir;
2022     char                *spath, temp[17], *p;
2023     char                *supath, *upath;
2024     struct path         *path;
2025     int                 err;
2026     struct adouble      ads;
2027     struct adouble      add;
2028     struct adouble      *adsp = NULL;
2029     struct adouble      *addp = NULL;
2030     struct ofork        *s_of = NULL;
2031     struct ofork        *d_of = NULL;
2032     int                 crossdev;
2033     
2034     int                 slen, dlen;
2035     u_int32_t           sid, did;
2036     u_int16_t           vid;
2037
2038     uid_t              uid;
2039     gid_t              gid;
2040
2041 #ifdef DEBUG
2042     LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
2043 #endif /* DEBUG */
2044
2045     *rbuflen = 0;
2046     ibuf += 2;
2047
2048     memcpy(&vid, ibuf, sizeof(vid));
2049     ibuf += sizeof(vid);
2050
2051     if (NULL == ( vol = getvolbyvid( vid )) ) {
2052         return( AFPERR_PARAM);
2053     }
2054
2055     if ((vol->v_flags & AFPVOL_RO))
2056         return AFPERR_VLOCK;
2057
2058     /* source and destination dids */
2059     memcpy(&sid, ibuf, sizeof(sid));
2060     ibuf += sizeof(sid);
2061     memcpy(&did, ibuf, sizeof(did));
2062     ibuf += sizeof(did);
2063
2064     /* source file */
2065     if (NULL == (dir = dirlookup( vol, sid )) ) {
2066         return afp_errno; /* was AFPERR_PARAM */
2067     }
2068
2069     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2070         return get_afp_errno(AFPERR_NOOBJ); 
2071     }
2072
2073     if ( path_isadir(path) ) {
2074         return AFPERR_BADTYPE;   /* it's a dir */
2075     }
2076
2077     /* save some stuff */
2078     srcst = path->st;
2079     sdir = curdir;
2080     spath = obj->oldtmp;
2081     supath = obj->newtmp;
2082     strcpy(spath, path->m_name);
2083     strcpy(supath, path->u_name); /* this is for the cnid changing */
2084     p = absupath( vol, sdir, supath);
2085     if (!p) {
2086         /* pathname too long */
2087         return AFPERR_PARAM ;
2088     }
2089     
2090     ad_init(&ads, vol->v_adouble);
2091     if (!(adsp = find_adouble( path, &s_of, &ads))) {
2092         return afp_errno;
2093     }
2094
2095     /* ***** from here we may have resource fork open **** */
2096     
2097     /* look for the source cnid. if it doesn't exist, don't worry about
2098      * it. */
2099     sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2100
2101     if (NULL == ( dir = dirlookup( vol, did )) ) {
2102         err = afp_errno; /* was AFPERR_PARAM */
2103         goto err_exchangefile;
2104     }
2105
2106     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2107         err = get_afp_errno(AFPERR_NOOBJ); 
2108         goto err_exchangefile;
2109     }
2110
2111     if ( path_isadir(path) ) {
2112         err = AFPERR_BADTYPE;
2113         goto err_exchangefile;
2114     }
2115
2116     /* FPExchangeFiles is the only call that can return the SameObj
2117      * error */
2118     if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2119         err = AFPERR_SAMEOBJ;
2120         goto err_exchangefile;
2121     }
2122
2123     ad_init(&add, vol->v_adouble);
2124     if (!(addp = find_adouble( path, &d_of, &add))) {
2125         err = afp_errno;
2126         goto err_exchangefile;
2127     }
2128     destst = path->st;
2129
2130     /* they are not on the same device and at least one is open
2131      * FIXME broken for for crossdev and adouble v2
2132      * return an error 
2133     */
2134     crossdev = (srcst.st_dev != destst.st_dev);
2135     if (/* (d_of || s_of)  && */ crossdev) {
2136         err = AFPERR_MISC;
2137         goto err_exchangefile;
2138     }
2139
2140     /* look for destination id. */
2141     upath = path->u_name;
2142     did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2143
2144     /* construct a temp name.
2145      * NOTE: the temp file will be in the dest file's directory. it
2146      * will also be inaccessible from AFP. */
2147     memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2148     if (!mktemp(temp)) {
2149         err = AFPERR_MISC;
2150         goto err_exchangefile;
2151     }
2152     
2153     if (crossdev) {
2154         /* FIXME we need to close fork for copy, both s_of and d_of are null */
2155        ad_close(adsp, ADFLAGS_HF);
2156        ad_close(addp, ADFLAGS_HF);
2157     }
2158
2159     /* now, quickly rename the file. we error if we can't. */
2160     if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2161         goto err_exchangefile;
2162     of_rename(vol, s_of, sdir, spath, curdir, temp);
2163
2164     /* rename destination to source */
2165     if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2166         goto err_src_to_tmp;
2167     of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2168
2169     /* rename temp to destination */
2170     if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2171         goto err_dest_to_src;
2172     of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2173
2174     /* id's need switching. src -> dest and dest -> src. 
2175      * we need to re-stat() if it was a cross device copy.
2176     */
2177     if (sid) {
2178         cnid_delete(vol->v_cdb, sid);
2179     }
2180     if (did) {
2181         cnid_delete(vol->v_cdb, did);
2182     }
2183     if ((did && ( (crossdev && stat( upath, &srcst) < 0) || 
2184                 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2185        ||
2186        (sid && ( (crossdev && stat(p, &destst) < 0) ||
2187                 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2188     ) {
2189         switch (errno) {
2190         case EPERM:
2191         case EACCES:
2192             err = AFPERR_ACCESS;
2193             break;
2194         default:
2195             err = AFPERR_PARAM;
2196         }
2197         goto err_temp_to_dest;
2198     }
2199     
2200     /* here we need to reopen if crossdev */
2201     if (sid && ad_setid(addp,(vol->v_flags & AFPVOL_NODEV)?0:destst.st_dev, destst.st_ino,  sid, sdir->d_did, vol->v_stamp)) 
2202     {
2203        ad_flush( addp, ADFLAGS_HF );
2204     }
2205         
2206     if (did && ad_setid(adsp,(vol->v_flags & AFPVOL_NODEV)?0:srcst.st_dev, srcst.st_ino,  did, curdir->d_did, vol->v_stamp)) 
2207     {
2208        ad_flush( adsp, ADFLAGS_HF );
2209     }
2210
2211     /* change perms, src gets dest perm and vice versa */
2212
2213     uid = geteuid();
2214     gid = getegid();
2215     if (seteuid(0)) {
2216         LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2217         err = AFP_OK; /* ignore error */
2218         goto err_temp_to_dest;
2219     }
2220
2221     /*
2222      * we need to exchange ACL entries as well
2223      */
2224     /* exchange_acls(vol, p, upath); */
2225
2226     path->st = srcst;
2227     path->st_valid = 1;
2228     path->st_errno = 0;
2229     path->m_name = NULL;
2230     path->u_name = upath;
2231
2232     setfilunixmode(vol, path, destst.st_mode);
2233     setfilowner(vol, destst.st_uid, destst.st_gid, path);
2234
2235     path->st = destst;
2236     path->st_valid = 1;
2237     path->st_errno = 0;
2238     path->u_name = p;
2239
2240     setfilunixmode(vol, path, srcst.st_mode);
2241     setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2242
2243     if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2244         LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2245         exit(EXITERR_SYS);
2246     }
2247
2248 #ifdef DEBUG
2249     LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2250 #endif /* DEBUG */
2251
2252     err = AFP_OK;
2253     goto err_exchangefile;
2254
2255     /* all this stuff is so that we can unwind a failed operation
2256      * properly. */
2257 err_temp_to_dest:
2258     /* rename dest to temp */
2259     renamefile(vol, upath, temp, temp, adsp);
2260     of_rename(vol, s_of, curdir, upath, curdir, temp);
2261
2262 err_dest_to_src:
2263     /* rename source back to dest */
2264     renamefile(vol, p, upath, path->m_name, addp);
2265     of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2266
2267 err_src_to_tmp:
2268     /* rename temp back to source */
2269     renamefile(vol, temp, p, spath, adsp);
2270     of_rename(vol, s_of, curdir, temp, sdir, spath);
2271
2272 err_exchangefile:
2273     if ( !s_of && adsp && ad_hfileno(adsp) != -1 ) {
2274        ad_close(adsp, ADFLAGS_HF);
2275     }
2276     if ( !d_of && addp && ad_hfileno(addp) != -1 ) {
2277        ad_close(addp, ADFLAGS_HF);
2278     }
2279
2280     return err;
2281 }