]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/file.c
Added DROPKLUDGE file copying support, modularized DROPKLUDGE operations,
[netatalk.git] / etc / afpd / file.c
1 /*
2  * Copyright (c) 1990,1993 Regents of The University of Michigan.
3  * All Rights Reserved.  See COPYRIGHT.
4  */
5
6 #ifdef HAVE_CONFIG_H
7 #include "config.h"
8 #endif
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <string.h>
14 #include <utime.h>
15 #include <fcntl.h>
16 #include <dirent.h>
17 #include <sys/mman.h>
18 #include <errno.h>
19
20 #include <sys/syslog.h>
21 #include <sys/types.h>
22 #include <sys/time.h>
23 #include <sys/param.h>
24 #include <sys/stat.h>
25
26 #include <netatalk/endian.h>
27 #include <atalk/adouble.h>
28 #include <atalk/afp.h>
29 #include <atalk/util.h>
30 #include <atalk/cnid.h>
31
32 #include "directory.h"
33 #include "desktop.h"
34 #include "volume.h"
35 #include "fork.h"
36 #include "file.h"
37 #include "filedir.h"
38 #include "globals.h"
39
40 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
41  * field         bytes        subfield    bytes
42  * 
43  * files:
44  * ioFlFndrInfo  16      ->       type    4  type field
45  *                             creator    4  creator field
46  *                               flags    2  finder flags: 
47  *                                           alias, bundle, etc.
48  *                            location    4  location in window
49  *                              folder    2  window that contains file
50  * 
51  * ioFlXFndrInfo 16      ->     iconID    2  icon id
52  *                              unused    6  reserved 
53  *                              script    1  script system
54  *                              xflags    1  reserved
55  *                           commentID    2  comment id
56  *                           putawayID    4  home directory id
57  */
58
59 const u_char ufinderi[] = {
60     'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
61     0, 0, 0, 0, 0, 0, 0, 0, 
62     0, 0, 0, 0, 0, 0, 0, 0,
63     0, 0, 0, 0, 0, 0, 0, 0
64 };
65
66 int getfilparams(vol, bitmap, path, dir, st, buf, buflen )
67     struct vol  *vol;
68     u_int16_t   bitmap;
69     char        *path;
70     struct dir  *dir;
71     struct stat *st;
72     char        *buf;
73     int         *buflen;
74 {
75     struct stat         hst, lst, *lstp;
76     struct adouble      ad, *adp;
77     struct ofork        *of;
78     struct extmap       *em;
79     char                *data, *nameoff = NULL, *upath;
80     int                 bit = 0, isad = 1, aint;
81     u_int16_t           ashort;
82     u_char              achar, fdType[4];
83
84 #ifdef DEBUG
85     syslog(LOG_INFO, "begin getfilparams:");
86 #endif DEBUG
87
88     upath = mtoupath(vol, path);
89     if ((of = of_findname(vol, curdir, path))) {
90       adp = of->of_ad;
91     } else {
92       memset(&ad, 0, sizeof(ad));
93       adp = &ad;
94     }
95
96     if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
97         isad = 0;
98     } else if ( fstat( ad_hfileno( adp ), &hst ) < 0 ) {
99             syslog( LOG_ERR, "getfilparams fstat: %m" );
100     }
101
102     data = buf;
103     while ( bitmap != 0 ) {
104         while (( bitmap & 1 ) == 0 ) {
105             bitmap = bitmap>>1;
106             bit++;
107         }
108
109         switch ( bit ) {
110         case FILPBIT_ATTR :
111             if ( isad ) {
112                 ad_getattr(adp, &ashort);
113             } else if (*upath == '.') {
114                 ashort = htons(ATTRBIT_INVISIBLE);
115             } else
116                 ashort = 0;
117             memcpy(data, &ashort, sizeof( ashort ));
118             data += sizeof( u_short );
119             break;
120
121         case FILPBIT_PDID :
122             memcpy(data, &dir->d_did, sizeof( int ));
123             data += sizeof( int );
124             break;
125
126         case FILPBIT_CDATE :
127             if (!isad || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
128                 aint = AD_DATE_FROM_UNIX(st->st_mtime);
129             memcpy(data, &aint, sizeof( aint ));
130             data += sizeof( aint );
131             break;
132
133         case FILPBIT_MDATE :
134             if ( isad && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
135                 if ((st->st_mtime > AD_DATE_TO_UNIX(aint)) && 
136                     (hst.st_mtime < st->st_mtime)) {
137                     aint = AD_DATE_FROM_UNIX(st->st_mtime);
138                 }
139             } else {
140                 aint = AD_DATE_FROM_UNIX(st->st_mtime);
141             }
142             memcpy(data, &aint, sizeof( int ));
143             data += sizeof( int );
144             break;
145
146         case FILPBIT_BDATE :
147             if (!isad || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
148                 aint = AD_DATE_START;
149             memcpy(data, &aint, sizeof( int ));
150             data += sizeof( int );
151             break;
152
153         case FILPBIT_FINFO :
154             if (isad) 
155               memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
156             else {
157               memcpy(data, ufinderi, 32);
158               if (*upath == '.') { /* make it invisible */
159                 ashort = htons(FINDERINFO_INVISIBLE);
160                 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
161               }
162             } 
163
164             if ((!isad || (memcmp(ad_entry(adp, ADEID_FINDERI),
165                                   ufinderi, 8 ) == 0)) &&
166                 (em = getextmap( path ))) {
167               memcpy(data, em->em_type, sizeof( em->em_type ));
168               memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
169             }
170             data += 32;
171             break;
172
173         case FILPBIT_LNAME :
174             nameoff = data;
175             data += sizeof( u_int16_t );
176             break;
177
178         case FILPBIT_SNAME :
179             memset(data, 0, sizeof(u_int16_t));
180             data += sizeof( u_int16_t );
181             break;
182
183         case FILPBIT_FNUM :
184 #if AD_VERSION > AD_VERSION1
185           /* use the CNID database if we're using AD v2 */
186             if (isad)
187               memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
188             else
189               aint = 0;
190
191             if (!(aint = cnid_add(vol->v_db, st, dir->d_did, upath, 
192                                   strlen(upath), aint))) {
193 #endif
194             /*
195              * What a fucking mess.  First thing:  DID and FNUMs are
196              * in the same space for purposes of enumerate (and several
197              * other wierd places).  While we consider this Apple's bug,
198              * this is the work-around:  In order to maintain constant and
199              * unique DIDs and FNUMs, we monotonically generate the DIDs
200              * during the session, and derive the FNUMs from the filesystem.
201              * Since the DIDs are small, we insure that the FNUMs are fairly
202              * large by setting thier high bits to the device number.
203              *
204              * AFS already does something very similar to this for the
205              * inode number, so we don't repeat the procedure.
206              *
207              * new algorithm:
208              * due to complaints over did's being non-persistent,
209              * here's the current hack to provide semi-persistent
210              * did's: 
211              *      1) we reserve the first bit for file ids.
212              *      2) the next 7 bits are for the device.
213              *      3) the remaining 24 bits are for the inode.
214              *
215              * both the inode and device information are actually hashes
216              * that are then truncated to the requisite bit length.
217              *
218              * it should be okay to use lstat to deal with symlinks.
219              */
220               lstp = (lstat(upath, &lst) < 0) ? st : &lst;
221               aint = htonl(CNID(lstp, 1));
222 #if AD_VERSION > AD_VERSION1
223             }
224 #endif
225             memcpy(data, &aint, sizeof( aint ));
226             data += sizeof( aint );
227             break;
228
229         case FILPBIT_DFLEN :
230             aint = htonl( st->st_size );
231             memcpy(data, &aint, sizeof( aint ));
232             data += sizeof( aint );
233             break;
234
235         case FILPBIT_RFLEN :
236             if ( isad ) {
237                 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
238             } else {
239                 aint = 0;
240             }
241             memcpy(data, &aint, sizeof( aint ));
242             data += sizeof( aint );
243             break;
244
245             /* Current client needs ProDOS info block for this file.
246                Use simple heuristic and let the Mac "type" string tell
247                us what the PD file code should be.  Everything gets a
248                subtype of 0x0000 unless the original value was hashed
249                to "pXYZ" when we created it.  See IA, Ver 2.
250                <shirsch@ibm.net> */
251         case FILPBIT_PDINFO :
252             if ( isad ) {
253               memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
254               
255               if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
256                 achar = '\x04';
257                 ashort = 0x0000;
258               }
259               else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
260                 achar = '\xff';
261                 ashort = 0x0000;
262               }
263               else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
264                 achar = '\xb3';
265                 ashort = 0x0000;
266               }
267               else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
268                 achar = '\x00';
269                 ashort = 0x0000;
270               }
271               else if ( fdType[0] == 'p' ) {
272                 achar = fdType[1];
273                 ashort = (fdType[2] * 256) + fdType[3];
274               } 
275               else {
276                 achar = '\x00';
277                 ashort = 0x0000;
278               }
279             } 
280             else {
281               achar = '\x00';
282               ashort = 0x0000;
283             }
284             
285             *data++ = achar;
286             *data++ = 0;
287             memcpy(data, &ashort, sizeof( ashort ));
288             data += sizeof( ashort );
289             memset(data, 0, sizeof( ashort ));
290             data += sizeof( ashort );
291             break;
292
293         default :
294             if ( isad ) {
295                 ad_close( adp, ADFLAGS_HF );
296             }
297             return( AFPERR_BITMAP );
298         }
299         bitmap = bitmap>>1;
300         bit++;
301     }
302     if ( nameoff ) {
303         ashort = htons( data - buf );
304         memcpy(nameoff, &ashort, sizeof( ashort ));
305         if ((aint = strlen( path )) > MACFILELEN)
306           aint = MACFILELEN;
307         *data++ = aint;
308         memcpy(data, path, aint );
309         data += aint;
310     }
311     if ( isad ) {
312         ad_close( adp, ADFLAGS_HF );
313     }
314     *buflen = data - buf;
315
316 #ifdef DEBUG
317     syslog(LOG_INFO, "end getfilparams:");
318 #endif DEBUG
319
320     return( AFP_OK );
321 }
322
323 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
324     AFPObj      *obj;
325     char        *ibuf, *rbuf;
326     int         ibuflen, *rbuflen;
327 {
328     struct stat         st;
329     struct adouble      ad, *adp;
330     struct vol          *vol;
331     struct dir          *dir;
332     struct ofork        *of;
333     char                *path, *upath;
334     int                 creatf, did, openf, retvalue = AFP_OK;
335     u_int16_t           vid;
336
337 #ifdef DEBUG
338     syslog(LOG_INFO, "begin afp_createfile:");
339 #endif DEBUG
340
341     *rbuflen = 0;
342     ibuf++;
343     creatf = (unsigned char) *ibuf++;
344
345     memcpy(&vid, ibuf, sizeof( vid ));
346     ibuf += sizeof( vid );
347
348     if (( vol = getvolbyvid( vid )) == NULL ) {
349         return( AFPERR_PARAM );
350     }
351
352     if (vol->v_flags & AFPVOL_RO)
353         return AFPERR_VLOCK;
354
355     memcpy(&did, ibuf, sizeof( did));
356     ibuf += sizeof( did );
357
358     if (( dir = dirsearch( vol, did )) == NULL ) {
359         return( AFPERR_NOOBJ );
360     }
361
362     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
363         return( AFPERR_NOOBJ );
364     }
365
366     if ((vol->v_flags & AFPVOL_MSWINDOWS) && 
367         strpbrk(path, MSWINDOWS_BADCHARS))
368         return AFPERR_PARAM;
369
370     upath = mtoupath(vol, path);
371
372     if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
373       return AFPERR_PARAM;
374
375     if (!validupath(vol, upath))
376       return AFPERR_EXIST;
377
378     if ((of = of_findname(vol, curdir, path))) {
379       adp = of->of_ad;
380     } else {
381       memset(&ad, 0, sizeof(ad));
382       adp = &ad;
383     }
384     if ( creatf) {
385         /* on a hard create, fail if file exists and is open */
386         if ((stat(upath, &st) == 0) && of)
387           return AFPERR_BUSY;
388         openf = O_RDWR|O_CREAT|O_TRUNC;
389     } else {
390         openf = O_RDWR|O_CREAT|O_EXCL;
391     }
392
393     if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
394                   openf, 0666, adp) < 0 ) {
395       switch ( errno ) {
396         case EEXIST :
397             return( AFPERR_EXIST );
398         case EACCES :
399             return( AFPERR_ACCESS );
400         case ENOENT:
401             /* on noadouble volumes, just creating the data fork is ok */
402             if (vol_noadouble(vol) && (stat(upath, &st) == 0))
403               goto createfile_done;
404             /* fallthrough */
405         default :
406             return( AFPERR_PARAM );
407         }
408     }
409
410     ad_setentrylen( adp, ADEID_NAME, strlen( path ));
411     memcpy(ad_entry( adp, ADEID_NAME ), path, 
412            ad_getentrylen( adp, ADEID_NAME ));
413     ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
414     ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
415
416 createfile_done:
417
418 #ifdef DROPKLUDGE
419     retvalue=matchfile2dirperms(upath, vol, did);
420 #endif DROPKLUDGE
421
422     setvoltime(obj, vol );
423
424 #ifdef DEBUG
425     syslog(LOG_INFO, "end afp_createfile");
426 #endif DEBUG
427
428     return (retvalue);
429 }
430
431 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
432     AFPObj      *obj;
433     char        *ibuf, *rbuf;
434     int         ibuflen, *rbuflen;
435 {
436     struct vol  *vol;
437     struct dir  *dir;
438     char        *path;
439     int         did, rc;
440     u_int16_t   vid, bitmap;
441
442 #ifdef DEBUG
443     syslog(LOG_INFO, "begin afp_setfilparams:");
444 #endif DEBUG
445
446     *rbuflen = 0;
447     ibuf += 2;
448
449     memcpy(&vid, ibuf, sizeof( vid ));
450     ibuf += sizeof( vid );
451     if (( vol = getvolbyvid( vid )) == NULL ) {
452         return( AFPERR_PARAM );
453     }
454
455     if (vol->v_flags & AFPVOL_RO)
456         return AFPERR_VLOCK;
457
458     memcpy(&did, ibuf, sizeof( did ));
459     ibuf += sizeof( did );
460     if (( dir = dirsearch( vol, did )) == NULL ) {
461         return( AFPERR_NOOBJ );
462     }
463
464     memcpy(&bitmap, ibuf, sizeof( bitmap ));
465     bitmap = ntohs( bitmap );
466     ibuf += sizeof( bitmap );
467
468     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
469         return( AFPERR_NOOBJ );
470     }
471
472     if ((u_long)ibuf & 1 ) {
473         ibuf++;
474     }
475
476     if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
477         setvoltime(obj, vol );
478     }
479
480 #ifdef DEBUG
481     syslog(LOG_INFO, "end afp_setfilparams:");
482 #endif DEBUG
483
484     return( rc );
485 }
486
487
488 int setfilparams(vol, path, bitmap, buf )
489     struct vol  *vol;
490     char        *path, *buf;
491     u_int16_t   bitmap;
492 {
493     struct adouble      ad, *adp;
494     struct ofork        *of;
495     struct extmap       *em;
496     int                 bit = 0, isad = 1, err = AFP_OK;
497     char                *upath;
498     u_char              achar, *fdType, xyy[4];
499     u_int16_t           ashort, bshort;
500     u_int32_t           aint;
501     struct utimbuf      ut;
502
503 #ifdef DEBUG
504     syslog(LOG_INFO, "begin setfilparams:");
505 #endif DEBUG
506
507     upath = mtoupath(vol, path);
508     if ((of = of_findname(vol, curdir, path))) {
509       adp = of->of_ad;
510     } else {
511       memset(&ad, 0, sizeof(ad));
512       adp = &ad;
513     }
514     if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF, 
515                  O_RDWR|O_CREAT, 0666, adp) < 0) {
516       /* for some things, we don't need an adouble header */
517       if (bitmap & ~(1<<FILPBIT_MDATE)) {
518         return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
519       }
520       isad = 0;
521     } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
522         ad_setentrylen( adp, ADEID_NAME, strlen( path ));
523         memcpy(ad_entry( adp, ADEID_NAME ), path, 
524                ad_getentrylen( adp, ADEID_NAME ));
525     }
526
527     while ( bitmap != 0 ) {
528         while (( bitmap & 1 ) == 0 ) {
529             bitmap = bitmap>>1;
530             bit++;
531         }
532
533         switch(  bit ) {
534         case FILPBIT_ATTR :
535             memcpy(&ashort, buf, sizeof( ashort ));
536             ad_getattr(adp, &bshort);
537             if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
538               bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
539             } else {
540               bshort &= ~ashort;
541             }
542             ad_setattr(adp, bshort);
543             buf += sizeof( ashort );
544             break;
545
546         case FILPBIT_CDATE :
547             memcpy(&aint, buf, sizeof(aint));
548             ad_setdate(adp, AD_DATE_CREATE, aint);
549             buf += sizeof( aint );
550             break;
551
552         case FILPBIT_MDATE :
553             memcpy(&aint, buf, sizeof( aint ));
554             if (isad)
555               ad_setdate(adp, AD_DATE_MODIFY, aint);
556             ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
557             utime(upath, &ut);
558             buf += sizeof( aint );
559             break;
560
561         case FILPBIT_BDATE :
562             memcpy(&aint, buf, sizeof(aint));
563             ad_setdate(adp, AD_DATE_BACKUP, aint);
564             buf += sizeof( aint );
565             break;
566
567         case FILPBIT_FINFO :
568             if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
569                 && (em = getextmap( path )) && 
570                 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
571                 (memcmp(buf + 4, em->em_creator,
572                         sizeof( em->em_creator )) == 0)) {
573               memcpy(buf, ufinderi, 8 );
574             }
575             memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
576             buf += 32;
577             break;
578
579             /* Client needs to set the ProDOS file info for this file.
580                Use defined strings for the simple cases, and convert
581                all else into pXYY per Inside Appletalk.  Always set
582                the creator as "pdos". <shirsch@ibm.net> */
583         case FILPBIT_PDINFO :
584             achar = *buf;
585             buf += 2;
586             memcpy(&ashort, buf, sizeof( ashort ));
587             ashort = ntohs( ashort );
588             buf += 2;
589  
590             switch ( (unsigned int) achar )
591               {
592               case 0x04 :
593                 fdType = ( u_char *) "TEXT";
594                 break;
595                 
596               case 0xff :
597                 fdType = ( u_char *) "PSYS";
598                 break;
599  
600               case 0xb3 :
601                 fdType = ( u_char *) "PS16";
602                 break;
603  
604               case 0x00 :
605                 fdType = ( u_char *) "BINA";
606                 break;
607  
608               default :
609                 xyy[0] = ( u_char ) 'p';
610                 xyy[1] = achar;
611                 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
612                 xyy[3] = ( u_char ) ashort & 0xff;
613                 fdType = xyy;
614                 break;
615               }
616             
617             memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
618             memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
619             break;
620  
621
622         default :
623             err = AFPERR_BITMAP;
624             goto setfilparam_done;
625         }
626
627         bitmap = bitmap>>1;
628         bit++;
629     }
630
631 setfilparam_done:
632     if (isad) {
633       ad_flush( adp, ADFLAGS_HF );
634       ad_close( adp, ADFLAGS_HF );
635     }
636
637 #ifdef DEBUG
638     syslog(LOG_INFO, "end setfilparams:");
639 #endif DEBUG
640
641     return err;
642 }
643
644 /*
645  * renamefile and copyfile take the old and new unix pathnames
646  * and the new mac name.
647  * NOTE: if we have to copy a file instead of renaming it, locks
648  *       will break.
649  */
650 int renamefile(src, dst, newname, noadouble )
651     char        *src, *dst, *newname;
652     const int         noadouble;
653 {
654     struct adouble      ad;
655     char                adsrc[ MAXPATHLEN + 1];
656     int                 len, rc;
657
658     /*
659      * Note that this is only checking the existance of the data file,
660      * not the header file.  The thinking is that if the data file doesn't
661      * exist, but the header file does, the right thing to do is remove
662      * the data file silently.
663      */
664
665     /* existence check moved to afp_moveandrename */
666
667 #ifdef DEBUG
668     syslog (LOG_INFO, "begin renamefile:");
669 #endif DEBUG
670
671     if ( rename( src, dst ) < 0 ) {
672         switch ( errno ) {
673         case ENOENT :
674             return( AFPERR_NOOBJ );
675         case EPERM:
676         case EACCES :
677             return( AFPERR_ACCESS );
678         case EROFS:
679             return AFPERR_VLOCK;
680         case EXDEV :                    /* Cross device move -- try copy */
681             if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
682                 deletefile( dst );
683                 return( rc );
684             }
685             return deletefile( src );
686         default :
687             return( AFPERR_PARAM );
688         }
689     }
690
691     strcpy( adsrc, ad_path( src, 0 ));
692     rc = 0;
693 rename_retry:
694     if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
695         struct stat st;
696
697         switch ( errno ) {
698         case ENOENT :
699           /* check for a source appledouble header. if it exists, make
700            * a dest appledouble directory and do the rename again. */
701           memset(&ad, 0, sizeof(ad));
702           if (rc || stat(adsrc, &st) ||
703               (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
704             return AFP_OK;
705           rc++;
706           ad_close(&ad, ADFLAGS_HF);
707           goto rename_retry;
708         case EPERM:
709         case EACCES :
710             return( AFPERR_ACCESS );
711         case EROFS:
712             return AFPERR_VLOCK;
713         default :
714             return( AFPERR_PARAM );
715         }
716     }
717
718     memset(&ad, 0, sizeof(ad));
719     if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
720         switch ( errno ) {
721         case ENOENT :
722             return( AFPERR_NOOBJ );
723         case EACCES :
724             return( AFPERR_ACCESS );
725         case EROFS:
726             return AFPERR_VLOCK;
727         default :
728             return( AFPERR_PARAM );
729         }
730     }
731
732     len = strlen( newname );
733     ad_setentrylen( &ad, ADEID_NAME, len );
734     memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
735     ad_flush( &ad, ADFLAGS_HF );
736     ad_close( &ad, ADFLAGS_HF );
737
738 #ifdef DEBUG
739     syslog (LOG_INFO, "end renamefile:");
740 #endif DEBUG
741
742     return( AFP_OK );
743 }
744
745 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
746     AFPObj      *obj;
747     char        *ibuf, *rbuf;
748     int         ibuflen, *rbuflen;
749 {
750     struct vol  *vol;
751     struct dir  *dir;
752     char        *newname, *path, *p;
753     u_int32_t   sdid, ddid;
754     int         plen, err, did, retvalue = AFP_OK;
755     u_int16_t   svid, dvid;
756
757 #ifdef DEBUG
758     syslog (LOG_INFO, "begin afp_copyfile:");
759 #endif DEBUG
760
761     *rbuflen = 0;
762     ibuf += 2;
763
764     memcpy(&svid, ibuf, sizeof( svid ));
765     ibuf += sizeof( svid );
766     if (( vol = getvolbyvid( svid )) == NULL ) {
767         return( AFPERR_PARAM );
768     }
769
770     memcpy(&sdid, ibuf, sizeof( sdid ));
771     ibuf += sizeof( sdid );
772     if (( dir = dirsearch( vol, sdid )) == NULL ) {
773         return( AFPERR_PARAM );
774     }
775
776     memcpy(&dvid, ibuf, sizeof( dvid ));
777     ibuf += sizeof( dvid );
778     memcpy(&ddid, ibuf, sizeof( ddid ));
779     ibuf += sizeof( ddid );
780
781     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
782         return( AFPERR_NOOBJ );
783     }
784     if ( *path == '\0' ) {
785         return( AFPERR_BADTYPE );
786     }
787
788     /* don't allow copies when the file is open.
789      * XXX: the spec only calls for read/deny write access.
790      *      however, copyfile doesn't have any of that info,
791      *      and locks need to stay coherent. as a result,
792      *      we just balk if the file is opened already. */
793     if (of_findname(vol, curdir, path))
794       return AFPERR_DENYCONF;
795     
796     newname = obj->newtmp;
797     strcpy( newname, path );
798
799     p = ctoupath( vol, curdir, newname );
800
801     if (( vol = getvolbyvid( dvid )) == NULL ) {
802         return( AFPERR_PARAM );
803     }
804
805     if (vol->v_flags & AFPVOL_RO)
806         return AFPERR_VLOCK;
807
808     if (( dir = dirsearch( vol, ddid )) == NULL ) {
809         return( AFPERR_PARAM );
810     }
811
812     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
813         return( AFPERR_NOOBJ );
814     }
815     if ( *path != '\0' ) {
816         return( AFPERR_BADTYPE );
817     }
818
819     /* one of the handful of places that knows about the path type */
820     if ( *ibuf++ != 2 ) {
821         return( AFPERR_PARAM );
822     }
823     if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
824         strncpy( newname, ibuf, plen );
825         newname[ plen ] = '\0';
826     }
827
828     if ( (err = copyfile(p, mtoupath(vol, newname ), newname, 
829                   vol_noadouble(vol))) < 0 ) {
830         return err;
831     }
832
833     setvoltime(obj, vol );
834
835 #ifdef DROPKLUDGE
836     retvalue=matchfile2dirperms(newname, vol, sdid);
837 #endif DROPKLUDGE
838
839 #ifdef DEBUG
840     syslog (LOG_INFO, "end afp_copyfile:");
841 #endif DEBUG
842
843     return( retvalue );
844 }
845
846
847 static __inline__ int copy_all(const int dfd, const void *buf,
848                                size_t buflen)
849 {
850   ssize_t cc;
851
852 #ifdef DEBUG
853   syslog(LOG_INFO, "begin copy_all:");
854 #endif DEBUG
855
856   while (buflen > 0) {
857     if ((cc = write(dfd, buf, buflen)) < 0) {
858       switch (errno) {
859       case EINTR:
860         continue;
861       case EDQUOT:
862       case EFBIG:
863       case ENOSPC:
864         return AFPERR_DFULL;
865       case EROFS:
866         return AFPERR_VLOCK;
867       default:
868         return AFPERR_PARAM;
869       }
870     }
871     buflen -= cc;
872   }
873
874 #ifdef DEBUG
875   syslog(LOG_INFO, "end copy_all:");
876 #endif DEBUG
877
878   return AFP_OK;
879 }
880
881 /* XXX: this needs to use ad_open and ad_lock. so, we need to
882  * pass in vol and path */
883 int copyfile(src, dst, newname, noadouble )
884     char        *src, *dst, *newname;
885     const int   noadouble;
886 {
887     struct adouble      ad;
888     struct stat         st;
889     char                filebuf[8192];
890     int                 sfd, dfd, len, err = AFP_OK;
891     ssize_t             cc;
892
893 #ifdef DEBUG
894     syslog(LOG_INFO, "begin copyfile:");
895 #endif DEBUG
896
897     if (newname) { 
898       if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
899         switch ( errno ) {
900         case ENOENT :
901             break; /* just copy the data fork */
902         case EACCES :
903             return( AFPERR_ACCESS );
904         default :
905             return( AFPERR_PARAM );
906         }
907       } else {
908         if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
909                 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
910             close( sfd );
911             switch ( errno ) {
912             case ENOENT :
913                 return( AFPERR_NOOBJ );
914             case EACCES :
915                 return( AFPERR_ACCESS );
916             case EROFS:
917                 return AFPERR_VLOCK;
918             default :
919                 return( AFPERR_PARAM );
920             }
921         }
922
923         /* copy the file */
924 #ifdef SENDFILE_FLAVOR_LINUX
925         if (fstat(sfd, &st) == 0) {
926           if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
927             switch (errno) {
928             case EDQUOT:
929             case EFBIG:
930             case ENOSPC:
931               err = AFPERR_DFULL;
932               break;
933             case EROFS:
934               err = AFPERR_VLOCK;
935               break;
936             default:
937               err = AFPERR_PARAM;
938             }
939           }
940           goto copyheader_done;
941         }
942 #endif
943         while (1) {
944           if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
945             if (errno == EINTR) 
946               continue;
947             err = AFPERR_PARAM;
948             break;
949           }
950
951           if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
952             break;
953         }
954
955 copyheader_done:
956         close(sfd);
957         close(dfd);
958         if (err < 0) {
959           unlink(ad_path(dst, ADFLAGS_HF));
960           return err;
961         }
962       }
963     }
964
965     /* data fork copying */
966     if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
967         switch ( errno ) {
968         case ENOENT :
969             return( AFPERR_NOOBJ );
970         case EACCES :
971             return( AFPERR_ACCESS );
972         default :
973             return( AFPERR_PARAM );
974         }
975     }
976
977     if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
978         close( sfd );
979         switch ( errno ) {
980         case ENOENT :
981             return( AFPERR_NOOBJ );
982         case EACCES :
983             return( AFPERR_ACCESS );
984         case EROFS:
985             return AFPERR_VLOCK;
986         default :
987             return( AFPERR_PARAM );
988         }
989     }
990
991 #ifdef SENDFILE_FLAVOR_LINUX
992     if (fstat(sfd, &st) == 0) {
993       if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
994         switch (errno) {
995         case EDQUOT:
996         case EFBIG:
997         case ENOSPC:
998           err = AFPERR_DFULL;
999           break;
1000         default:
1001           err = AFPERR_PARAM;
1002         }
1003       }
1004       goto copydata_done;
1005     }
1006 #endif
1007
1008     while (1) {
1009       if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1010         if (errno == EINTR)
1011           continue;
1012         
1013         err = AFPERR_PARAM;
1014         break;
1015       }
1016       
1017       if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1018         break;
1019       }
1020     }
1021     
1022 copydata_done:
1023     close(sfd);
1024     close(dfd);
1025     if (err < 0) {
1026       unlink(ad_path(dst, ADFLAGS_HF));
1027       unlink(dst);
1028       return err;
1029     }
1030     
1031     if (newname) {
1032       memset(&ad, 0, sizeof(ad));
1033       if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1034                     0666, &ad) < 0 ) {
1035         switch ( errno ) {
1036         case ENOENT :
1037           return noadouble ? AFP_OK : AFPERR_NOOBJ;
1038         case EACCES :
1039           return( AFPERR_ACCESS );
1040         case EROFS:
1041           return AFPERR_VLOCK;
1042         default :
1043           return( AFPERR_PARAM );
1044         }
1045       }
1046
1047       len = strlen( newname );
1048       ad_setentrylen( &ad, ADEID_NAME, len );
1049       memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1050       ad_flush( &ad, ADFLAGS_HF );
1051       ad_close( &ad, ADFLAGS_HF );
1052     }
1053     
1054 #ifdef DEBUG
1055     syslog(LOG_INFO, "end copyfile:");
1056 #endif DEBUG
1057
1058     return( AFP_OK );
1059 }
1060
1061
1062 int deletefile( file )
1063     char                *file;
1064 {
1065     struct adouble      ad;
1066     int                 adflags, err = AFP_OK;
1067
1068 #ifdef DEBUG
1069     syslog(LOG_INFO, "begin deletefile:");
1070 #endif DEBUG
1071
1072     /* try to open both at once */
1073     adflags = ADFLAGS_DF|ADFLAGS_HF;
1074     memset(&ad, 0, sizeof(ad));
1075     if ( ad_open( file, adflags, O_RDWR, 0, &ad ) < 0 ) {
1076           switch (errno) {
1077           case ENOENT:
1078             adflags = ADFLAGS_DF;
1079             /* that failed. now try to open just the data fork */
1080             memset(&ad, 0, sizeof(ad));
1081             if ( ad_open( file, adflags, O_RDWR, 0, &ad ) < 0 ) {
1082               switch (errno) {
1083               case ENOENT:
1084                 return AFPERR_NOOBJ;
1085               case EACCES:
1086                 return AFPERR_ACCESS;
1087               default:
1088                 return AFPERR_PARAM;
1089               }
1090             }
1091             break;
1092
1093           case EACCES:
1094             return( AFPERR_ACCESS );
1095           case EROFS:
1096             return AFPERR_VLOCK;
1097           default:
1098             return( AFPERR_PARAM );
1099           }
1100     }
1101
1102     if ((adflags & ADFLAGS_HF) &&
1103         (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR, 0, 0) < 0 )) {
1104       ad_close( &ad, adflags );
1105       return( AFPERR_BUSY );
1106     }
1107
1108     if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0 ) < 0) {
1109       err = AFPERR_BUSY;
1110       goto delete_unlock;
1111     }
1112
1113     if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1114         switch ( errno ) {
1115         case EPERM:
1116         case EACCES :
1117             err = AFPERR_ACCESS;
1118             goto delete_unlock;
1119         case EROFS:
1120             err = AFPERR_VLOCK;
1121             goto delete_unlock;
1122         case ENOENT :
1123             break;
1124         default :
1125             err = AFPERR_PARAM;
1126             goto delete_unlock;
1127         }
1128     }
1129
1130     if ( unlink( file ) < 0 ) {
1131         switch ( errno ) {
1132         case EPERM:
1133         case EACCES :
1134             err = AFPERR_ACCESS;
1135             break;
1136         case EROFS:
1137             err = AFPERR_VLOCK;
1138             break;
1139         case ENOENT :
1140             break;
1141         default :
1142             err = AFPERR_PARAM;
1143             break;
1144         }
1145     }
1146
1147 delete_unlock:
1148     if (adflags & ADFLAGS_HF)
1149       ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1150     ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1151     ad_close( &ad, adflags );
1152
1153 #ifdef DEBUG
1154     syslog(LOG_INFO, "end deletefile:");
1155 #endif DEBUG
1156
1157     return err;
1158 }
1159
1160
1161 #if AD_VERSION > AD_VERSION1
1162 /* return a file id */
1163 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1164     AFPObj      *obj;
1165     char        *ibuf, *rbuf;
1166     int         ibuflen, *rbuflen;
1167 {
1168     struct stat         st;
1169     struct adouble      ad;
1170     struct vol          *vol;
1171     struct dir          *dir;
1172     char                *path, *upath;
1173     int                 len;
1174     cnid_t              did, id;
1175     u_short             vid;
1176
1177 #ifdef DEBUG
1178     syslog(LOG_INFO, "begin afp_createid:");
1179 #endif DEBUG
1180     
1181     *rbuflen = 0;
1182     ibuf += 2;
1183
1184     memcpy(&vid, ibuf, sizeof(vid));
1185     ibuf += sizeof(vid);
1186
1187     if (( vol = getvolbyvid( vid )) == NULL ) {
1188         return( AFPERR_PARAM);
1189     }
1190
1191     if (vol->v_flags & AFPVOL_RO)
1192         return AFPERR_VLOCK;
1193
1194     memcpy(&did, ibuf, sizeof( did ));
1195     ibuf += sizeof(did);
1196
1197     if (( dir = dirsearch( vol, did )) == NULL ) {
1198         return( AFPERR_PARAM );
1199     }
1200
1201     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1202         return( AFPERR_PARAM );
1203     }
1204
1205     if ( *path == '\0' ) {
1206         return( AFPERR_BADTYPE );
1207     }
1208
1209     upath = mtoupath(vol, path);
1210     if (stat(upath, &st) < 0) {
1211       switch (errno) {
1212       case EPERM:
1213       case EACCES:
1214         return AFPERR_ACCESS;
1215       case ENOENT:
1216         return AFPERR_NOOBJ;
1217       default:
1218         return AFPERR_PARAM;
1219       }
1220     }
1221
1222     if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1223       memcpy(rbuf, &id, sizeof(id));
1224       *rbuflen = sizeof(id);
1225       return AFPERR_EXISTID;
1226     }
1227
1228     memset(&ad, 0, sizeof(ad));
1229     if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) < 0)
1230       id = 0;
1231     else {
1232       memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1233       ad_close(upath, ADFLAGS_HF);
1234     }
1235
1236     if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1237       memcpy(rbuf, &id, sizeof(id));
1238       *rbuflen = sizeof(id);
1239       return AFP_OK;
1240     }
1241
1242 #ifdef DEBUG
1243     syslog(LOG_INFO, "ending afp_createid...:");
1244 #endif DEBUG
1245
1246     switch (errno) {
1247     case EROFS:
1248       return AFPERR_VLOCK;
1249       break;
1250     case EPERM:
1251     case EACCES:
1252       return AFPERR_ACCESS;
1253       break;
1254     default:
1255       syslog(LOG_ERR, "afp_createid: cnid_add: %m");
1256       return AFPERR_PARAM;
1257     }
1258 }
1259
1260 /* resolve a file id */
1261 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1262     AFPObj      *obj;
1263     char        *ibuf, *rbuf;
1264     int         ibuflen, *rbuflen;
1265 {
1266     struct stat         st;
1267     struct vol          *vol;
1268     struct dir          *dir;
1269     char                *upath;
1270     int                 err, buflen;
1271     cnid_t              id;
1272     u_int16_t           vid, bitmap;
1273
1274 #ifdef DEBUG
1275     syslog(LOG_INFO, "begin afp_resolveid:");
1276 #endif DEBUG
1277     
1278     *rbuflen = 0;
1279     ibuf += 2;
1280
1281     memcpy(&vid, ibuf, sizeof(vid));
1282     ibuf += sizeof(vid);
1283
1284     if (( vol = getvolbyvid( vid )) == NULL ) {
1285         return( AFPERR_PARAM);
1286     }
1287
1288     memcpy(&id, ibuf, sizeof( id ));
1289     ibuf += sizeof(id);
1290
1291     if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1292       return AFPERR_BADID;
1293     }
1294
1295     if (( dir = dirsearch( vol, id )) == NULL ) {
1296       return( AFPERR_PARAM );
1297     }
1298
1299     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1300       switch (errno) {
1301       case EACCES:
1302       case EPERM:
1303         return AFPERR_ACCESS;
1304       case ENOENT:
1305         return AFPERR_NOID;
1306       default:
1307         return AFPERR_PARAM;
1308       }
1309     }
1310
1311     /* directories are bad */
1312     if (S_ISDIR(st.st_mode))
1313       return AFPERR_BADTYPE;
1314
1315     memcpy(&bitmap, ibuf, sizeof(bitmap));
1316     bitmap = ntohs( bitmap );
1317
1318     if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1319                            rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1320       return err;
1321
1322     *rbuflen = buflen + sizeof(bitmap);
1323     memcpy(rbuf, ibuf, sizeof(bitmap));
1324
1325 #ifdef DEBUG
1326     syslog(LOG_INFO, "end afp_resolveid:");
1327 #endif DEBUG
1328     
1329     return AFP_OK;
1330 }
1331
1332 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1333     AFPObj      *obj;
1334     char        *ibuf, *rbuf;
1335     int         ibuflen, *rbuflen;
1336 {
1337     struct stat         st;
1338     struct vol          *vol;
1339     struct dir          *dir;
1340     char                *upath;
1341     int                 err;
1342     cnid_t              id;
1343     u_short             vid;
1344
1345 #ifdef DEBUG
1346     syslog(LOG_INFO, "begin afp_deleteid:");
1347 #endif DEBUG
1348
1349     *rbuflen = 0;
1350     ibuf += 2;
1351
1352     memcpy(&vid, ibuf, sizeof(vid));
1353     ibuf += sizeof(vid);
1354
1355     if (( vol = getvolbyvid( vid )) == NULL ) {
1356         return( AFPERR_PARAM);
1357     }
1358
1359     if (vol->v_flags & AFPVOL_RO)
1360         return AFPERR_VLOCK;
1361
1362     memcpy(&id, ibuf, sizeof( id ));
1363     ibuf += sizeof(id);
1364
1365     if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1366       return AFPERR_NOID;
1367     }
1368
1369     if (( dir = dirsearch( vol, id )) == NULL ) {
1370       return( AFPERR_PARAM );
1371     }
1372
1373     err = AFP_OK;
1374     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1375       switch (errno) {
1376       case EACCES:
1377       case EPERM:
1378         return AFPERR_ACCESS;
1379       case ENOENT:
1380         /* still try to delete the id */
1381         err = AFPERR_NOOBJ;
1382         break;
1383       default:
1384         return AFPERR_PARAM;
1385       }
1386     }
1387
1388     /* directories are bad */
1389     if (S_ISDIR(st.st_mode))
1390       return AFPERR_BADTYPE;
1391
1392     if (cnid_delete(vol->v_db, id)) {
1393       switch (errno) {
1394       case EROFS:
1395         return AFPERR_VLOCK;
1396       case EPERM:
1397       case EACCES:
1398         return AFPERR_ACCESS;
1399       default:
1400         return AFPERR_PARAM;
1401       }
1402     }
1403
1404 #ifdef DEBUG
1405     syslog(LOG_INFO, "end afp_deleteid:");
1406 #endif DEBUG
1407
1408     return err;
1409 }
1410 #endif
1411
1412 #define APPLETEMP ".AppleTempXXXXXX"
1413 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1414     AFPObj      *obj;
1415     char        *ibuf, *rbuf;
1416     int         ibuflen, *rbuflen;
1417 {
1418     struct stat         srcst, destst;
1419     struct vol          *vol;
1420     struct dir          *dir, *sdir;
1421     char                *spath, temp[17], *path, *p;
1422     char                *supath, *upath;
1423     int                 err;
1424 #if AD_VERSION > AD_VERSION1
1425     int                 slen, dlen;
1426 #endif
1427     cnid_t              sid, did;
1428     u_int16_t           vid;
1429
1430 #ifdef DEBUG
1431     syslog(LOG_INFO, "begin afp_exchangefiles:");
1432 #endif DEBUG
1433
1434     *rbuflen = 0;
1435     ibuf += 2;
1436
1437     memcpy(&vid, ibuf, sizeof(vid));
1438     ibuf += sizeof(vid);
1439
1440     if (( vol = getvolbyvid( vid )) == NULL ) {
1441         return( AFPERR_PARAM);
1442     }
1443
1444     if (vol->v_flags & AFPVOL_RO)
1445         return AFPERR_VLOCK;
1446
1447     /* source and destination dids */
1448     memcpy(&sid, ibuf, sizeof(sid));
1449     ibuf += sizeof(sid);
1450     memcpy(&did, ibuf, sizeof(did));
1451     ibuf += sizeof(did);
1452
1453     /* source file */
1454     if ((dir = dirsearch( vol, sid )) == NULL ) {
1455         return( AFPERR_PARAM );
1456     }
1457
1458     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1459         return( AFPERR_PARAM );
1460     }
1461
1462     if ( *path == '\0' ) {
1463         return( AFPERR_BADTYPE );
1464     }
1465
1466     upath = mtoupath(vol, path);
1467     if (stat(upath, &srcst) < 0) {
1468       switch (errno) {
1469       case ENOENT:
1470         return AFPERR_NOID;
1471       case EPERM:
1472       case EACCES:
1473         return AFPERR_ACCESS;
1474       default:
1475         return AFPERR_PARAM;
1476       }
1477     }
1478
1479     /* save some stuff */
1480     sdir = curdir;
1481     spath = obj->oldtmp;
1482     supath = obj->newtmp;
1483     strcpy(spath, path);
1484     strcpy(supath, upath); /* this is for the cnid changing */
1485     p = ctoupath( vol, sdir, spath);
1486
1487     /* look for the source cnid. if it doesn't exist, don't worry about
1488      * it. */
1489 #if AD_VERSION > AD_VERSION1
1490     sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath, 
1491                       slen = strlen(supath));
1492 #endif
1493
1494     if (( dir = dirsearch( vol, did )) == NULL ) {
1495         return( AFPERR_PARAM );
1496     }
1497
1498     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1499         return( AFPERR_PARAM );
1500     }
1501
1502     if ( *path == '\0' ) {
1503         return( AFPERR_BADTYPE );
1504     }
1505
1506     /* FPExchangeFiles is the only call that can return the SameObj
1507      * error */
1508     if ((curdir == sdir) && strcmp(spath, path) == 0)
1509       return AFPERR_SAMEOBJ;
1510
1511     upath = mtoupath(vol, path);
1512     if (stat(upath, &destst) < 0) {
1513       switch (errno) {
1514       case ENOENT:
1515         return AFPERR_NOID;
1516       case EPERM:
1517       case EACCES:
1518         return AFPERR_ACCESS;
1519       default:
1520         return AFPERR_PARAM;
1521       }
1522     }
1523
1524 #if AD_VERSION > AD_VERSION1
1525     /* look for destination id. */
1526     did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath, 
1527                       dlen = strlen(upath));
1528 #endif
1529
1530     /* construct a temp name. 
1531      * NOTE: the temp file will be in the dest file's directory. it
1532      * will also be inaccessible from AFP. */
1533     memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1534     if (!mktemp(temp))
1535       return AFPERR_MISC;
1536
1537     /* now, quickly rename the file. we error if we can't. */
1538     if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1539       goto err_exchangefile;
1540     of_rename(vol, sdir, spath, curdir, temp);
1541
1542     /* rename destination to source */
1543     if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0) 
1544       goto err_src_to_tmp;
1545     of_rename(vol, curdir, path, sdir, spath);
1546
1547     /* rename temp to destination */
1548     if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0) 
1549       goto err_dest_to_src;
1550     of_rename(vol, curdir, temp, curdir, path);
1551     
1552 #if AD_VERSION > AD_VERSION1
1553     /* id's need switching. src -> dest and dest -> src. */
1554     if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did, 
1555                             upath, dlen) < 0)) {
1556       switch (errno) {
1557       case EPERM:
1558       case EACCES:
1559         err = AFPERR_ACCESS;
1560       default:
1561         err = AFPERR_PARAM;
1562       }
1563       goto err_temp_to_dest;
1564     }
1565
1566     if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1567                             supath, slen) < 0)) {
1568       switch (errno) {
1569       case EPERM:
1570       case EACCES:
1571         err = AFPERR_ACCESS;
1572       default:
1573         err = AFPERR_PARAM;
1574       }
1575
1576       if (sid)
1577         cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1578       goto err_temp_to_dest;
1579     }
1580 #endif
1581
1582 #ifdef DEBUG
1583     syslog(LOG_INFO, "ending afp_exchangefiles:");
1584 #endif DEBUG
1585
1586     return AFP_OK;
1587
1588
1589     /* all this stuff is so that we can unwind a failed operation 
1590      * properly. */
1591 err_temp_to_dest:
1592     /* rename dest to temp */
1593     renamefile(upath, temp, temp, vol_noadouble(vol));
1594     of_rename(vol, curdir, upath, curdir, temp);
1595
1596 err_dest_to_src:
1597     /* rename source back to dest */
1598     renamefile(p, upath, path, vol_noadouble(vol));
1599     of_rename(vol, sdir, spath, curdir, path);
1600
1601 err_src_to_tmp:
1602     /* rename temp back to source */
1603     renamefile(temp, p, spath, vol_noadouble(vol));
1604     of_rename(vol, curdir, temp, sdir, spath);
1605
1606 err_exchangefile:
1607     return err;
1608 }