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