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