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