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