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