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