]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/file.c
Cleaned up DROPKLUDGE tags.
[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     char                adpath[50];
323     int                 uid;
324 #endif DROPKLUDGE
325     struct adouble      ad, *adp;
326     struct vol          *vol;
327     struct dir          *dir;
328     struct ofork        *of;
329     char                *path, *upath;
330     int                 creatf, did, openf;
331     u_int16_t           vid;
332
333     *rbuflen = 0;
334     ibuf++;
335     creatf = (unsigned char) *ibuf++;
336
337     memcpy(&vid, ibuf, sizeof( vid ));
338     ibuf += sizeof( vid );
339
340     if (( vol = getvolbyvid( vid )) == NULL ) {
341         return( AFPERR_PARAM );
342     }
343
344     if (vol->v_flags & AFPVOL_RO)
345         return AFPERR_VLOCK;
346
347     memcpy(&did, ibuf, sizeof( did));
348     ibuf += sizeof( did );
349
350     if (( dir = dirsearch( vol, did )) == NULL ) {
351         return( AFPERR_NOOBJ );
352     }
353
354     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
355         return( AFPERR_NOOBJ );
356     }
357
358     if ((vol->v_flags & AFPVOL_MSWINDOWS) && 
359         strpbrk(path, MSWINDOWS_BADCHARS))
360         return AFPERR_PARAM;
361
362     upath = mtoupath(vol, path);
363
364     if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
365       return AFPERR_PARAM;
366
367     if (!validupath(vol, upath))
368       return AFPERR_EXIST;
369
370     if ((of = of_findname(vol, curdir, path))) {
371       adp = of->of_ad;
372     } else {
373       memset(&ad, 0, sizeof(ad));
374       adp = &ad;
375     }
376     if ( creatf) {
377         /* on a hard create, fail if file exists and is open */
378         if ((stat(upath, &st) == 0) && of)
379           return AFPERR_BUSY;
380         openf = O_RDWR|O_CREAT|O_TRUNC;
381     } else {
382         openf = O_RDWR|O_CREAT|O_EXCL;
383     }
384
385     if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
386                   openf, 0666, adp) < 0 ) {
387       switch ( errno ) {
388         case EEXIST :
389             return( AFPERR_EXIST );
390         case EACCES :
391             return( AFPERR_ACCESS );
392         case ENOENT:
393             /* on noadouble volumes, just creating the data fork is ok */
394             if (vol_noadouble(vol) && (stat(upath, &st) == 0))
395               goto createfile_done;
396             /* fallthrough */
397         default :
398             return( AFPERR_PARAM );
399         }
400     }
401
402     ad_setentrylen( adp, ADEID_NAME, strlen( path ));
403     memcpy(ad_entry( adp, ADEID_NAME ), path, 
404            ad_getentrylen( adp, ADEID_NAME ));
405     ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
406     ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
407
408 createfile_done:
409
410 #ifdef DROPKLUDGE
411
412 /* The below code is an experimental, untested, incomplete kludge which 
413 provides better dropbox support.  It should NOT be turned on yet unless
414 you are a developer who wants to try it out and fix it. */
415     if (stat(".", &sb) == -1) 
416       syslog (LOG_ERR, "Error checking directory %s: %m", dir->d_name);
417     else {
418       uid=geteuid();
419       strcpy (adpath, "./.AppleDouble/");
420       strcat (adpath, path);
421       seteuid(0); /* Become root to change the owner of the file */
422       syslog (LOG_INFO, "Changing %s to uid=%d gid=%d", path, sb.st_uid, sb.st_gid);
423       if (chown(path, sb.st_uid, -1)==-1)
424         syslog (LOG_ERR, "Error changing permissions: %m");
425       if (chown(adpath, sb.st_uid, -1)==-1)
426         syslog (LOG_ERR, "Error changing AppleDouble permissions: %m");
427       syslog (LOG_INFO, "Changing afpd owner back to %d", uid);
428       seteuid(uid); /* Restore process ownership to normal */
429     }
430
431 #endif DROPKLUDGE
432
433     setvoltime(obj, vol );
434     return AFP_OK;
435 }
436
437 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
438     AFPObj      *obj;
439     char        *ibuf, *rbuf;
440     int         ibuflen, *rbuflen;
441 {
442     struct vol  *vol;
443     struct dir  *dir;
444     char        *path;
445     int         did, rc;
446     u_int16_t   vid, bitmap;
447
448     *rbuflen = 0;
449     ibuf += 2;
450
451     memcpy(&vid, ibuf, sizeof( vid ));
452     ibuf += sizeof( vid );
453     if (( vol = getvolbyvid( vid )) == NULL ) {
454         return( AFPERR_PARAM );
455     }
456
457     if (vol->v_flags & AFPVOL_RO)
458         return AFPERR_VLOCK;
459
460     memcpy(&did, ibuf, sizeof( did ));
461     ibuf += sizeof( did );
462     if (( dir = dirsearch( vol, did )) == NULL ) {
463         return( AFPERR_NOOBJ );
464     }
465
466     memcpy(&bitmap, ibuf, sizeof( bitmap ));
467     bitmap = ntohs( bitmap );
468     ibuf += sizeof( bitmap );
469
470     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
471         return( AFPERR_NOOBJ );
472     }
473
474     if ((u_long)ibuf & 1 ) {
475         ibuf++;
476     }
477
478     if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
479         setvoltime(obj, vol );
480     }
481
482     return( rc );
483 }
484
485
486 int setfilparams(vol, path, bitmap, buf )
487     struct vol  *vol;
488     char        *path, *buf;
489     u_int16_t   bitmap;
490 {
491     struct adouble      ad, *adp;
492     struct ofork        *of;
493     struct extmap       *em;
494     int                 bit = 0, isad = 1, err = AFP_OK;
495     char                *upath;
496     u_char              achar, *fdType, xyy[4];
497     u_int16_t           ashort, bshort;
498     u_int32_t           aint;
499     struct utimbuf      ut;
500
501     upath = mtoupath(vol, path);
502     if ((of = of_findname(vol, curdir, path))) {
503       adp = of->of_ad;
504     } else {
505       memset(&ad, 0, sizeof(ad));
506       adp = &ad;
507     }
508     if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF, 
509                  O_RDWR|O_CREAT, 0666, adp) < 0) {
510       /* for some things, we don't need an adouble header */
511       if (bitmap & ~(1<<FILPBIT_MDATE)) {
512         return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
513       }
514       isad = 0;
515     } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
516         ad_setentrylen( adp, ADEID_NAME, strlen( path ));
517         memcpy(ad_entry( adp, ADEID_NAME ), path, 
518                ad_getentrylen( adp, ADEID_NAME ));
519     }
520
521     while ( bitmap != 0 ) {
522         while (( bitmap & 1 ) == 0 ) {
523             bitmap = bitmap>>1;
524             bit++;
525         }
526
527         switch(  bit ) {
528         case FILPBIT_ATTR :
529             memcpy(&ashort, buf, sizeof( ashort ));
530             ad_getattr(adp, &bshort);
531             if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
532               bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
533             } else {
534               bshort &= ~ashort;
535             }
536             ad_setattr(adp, bshort);
537             buf += sizeof( ashort );
538             break;
539
540         case FILPBIT_CDATE :
541             memcpy(&aint, buf, sizeof(aint));
542             ad_setdate(adp, AD_DATE_CREATE, aint);
543             buf += sizeof( aint );
544             break;
545
546         case FILPBIT_MDATE :
547             memcpy(&aint, buf, sizeof( aint ));
548             if (isad)
549               ad_setdate(adp, AD_DATE_MODIFY, aint);
550             ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
551             utime(upath, &ut);
552             buf += sizeof( aint );
553             break;
554
555         case FILPBIT_BDATE :
556             memcpy(&aint, buf, sizeof(aint));
557             ad_setdate(adp, AD_DATE_BACKUP, aint);
558             buf += sizeof( aint );
559             break;
560
561         case FILPBIT_FINFO :
562             if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
563                 && (em = getextmap( path )) && 
564                 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
565                 (memcmp(buf + 4, em->em_creator,
566                         sizeof( em->em_creator )) == 0)) {
567               memcpy(buf, ufinderi, 8 );
568             }
569             memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
570             buf += 32;
571             break;
572
573             /* Client needs to set the ProDOS file info for this file.
574                Use defined strings for the simple cases, and convert
575                all else into pXYY per Inside Appletalk.  Always set
576                the creator as "pdos". <shirsch@ibm.net> */
577         case FILPBIT_PDINFO :
578             achar = *buf;
579             buf += 2;
580             memcpy(&ashort, buf, sizeof( ashort ));
581             ashort = ntohs( ashort );
582             buf += 2;
583  
584             switch ( (unsigned int) achar )
585               {
586               case 0x04 :
587                 fdType = ( u_char *) "TEXT";
588                 break;
589                 
590               case 0xff :
591                 fdType = ( u_char *) "PSYS";
592                 break;
593  
594               case 0xb3 :
595                 fdType = ( u_char *) "PS16";
596                 break;
597  
598               case 0x00 :
599                 fdType = ( u_char *) "BINA";
600                 break;
601  
602               default :
603                 xyy[0] = ( u_char ) 'p';
604                 xyy[1] = achar;
605                 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
606                 xyy[3] = ( u_char ) ashort & 0xff;
607                 fdType = xyy;
608                 break;
609               }
610             
611             memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
612             memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
613             break;
614  
615
616         default :
617             err = AFPERR_BITMAP;
618             goto setfilparam_done;
619         }
620
621         bitmap = bitmap>>1;
622         bit++;
623     }
624
625 setfilparam_done:
626     if (isad) {
627       ad_flush( adp, ADFLAGS_HF );
628       ad_close( adp, ADFLAGS_HF );
629     }
630     return err;
631 }
632
633 /*
634  * renamefile and copyfile take the old and new unix pathnames
635  * and the new mac name.
636  * NOTE: if we have to copy a file instead of renaming it, locks
637  *       will break.
638  */
639 int renamefile(src, dst, newname, noadouble )
640     char        *src, *dst, *newname;
641     const int         noadouble;
642 {
643     struct adouble      ad;
644     char                adsrc[ MAXPATHLEN + 1];
645     int                 len, rc;
646
647     /*
648      * Note that this is only checking the existance of the data file,
649      * not the header file.  The thinking is that if the data file doesn't
650      * exist, but the header file does, the right thing to do is remove
651      * the data file silently.
652      */
653
654     /* existence check moved to afp_moveandrename */
655
656     if ( rename( src, dst ) < 0 ) {
657         switch ( errno ) {
658         case ENOENT :
659             return( AFPERR_NOOBJ );
660         case EPERM:
661         case EACCES :
662             return( AFPERR_ACCESS );
663         case EROFS:
664             return AFPERR_VLOCK;
665         case EXDEV :                    /* Cross device move -- try copy */
666             if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
667                 deletefile( dst );
668                 return( rc );
669             }
670             return deletefile( src );
671         default :
672             return( AFPERR_PARAM );
673         }
674     }
675
676     strcpy( adsrc, ad_path( src, 0 ));
677     rc = 0;
678 rename_retry:
679     if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
680         struct stat st;
681
682         switch ( errno ) {
683         case ENOENT :
684           /* check for a source appledouble header. if it exists, make
685            * a dest appledouble directory and do the rename again. */
686           memset(&ad, 0, sizeof(ad));
687           if (rc || stat(adsrc, &st) ||
688               (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
689             return AFP_OK;
690           rc++;
691           ad_close(&ad, ADFLAGS_HF);
692           goto rename_retry;
693         case EPERM:
694         case EACCES :
695             return( AFPERR_ACCESS );
696         case EROFS:
697             return AFPERR_VLOCK;
698         default :
699             return( AFPERR_PARAM );
700         }
701     }
702
703     memset(&ad, 0, sizeof(ad));
704     if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
705         switch ( errno ) {
706         case ENOENT :
707             return( AFPERR_NOOBJ );
708         case EACCES :
709             return( AFPERR_ACCESS );
710         case EROFS:
711             return AFPERR_VLOCK;
712         default :
713             return( AFPERR_PARAM );
714         }
715     }
716
717     len = strlen( newname );
718     ad_setentrylen( &ad, ADEID_NAME, len );
719     memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
720     ad_flush( &ad, ADFLAGS_HF );
721     ad_close( &ad, ADFLAGS_HF );
722
723     return( AFP_OK );
724 }
725
726 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
727     AFPObj      *obj;
728     char        *ibuf, *rbuf;
729     int         ibuflen, *rbuflen;
730 {
731     struct vol  *vol;
732     struct dir  *dir;
733     char        *newname, *path, *p;
734     u_int32_t   sdid, ddid;
735     int         plen, err;
736     u_int16_t   svid, dvid;
737
738     *rbuflen = 0;
739     ibuf += 2;
740
741     memcpy(&svid, ibuf, sizeof( svid ));
742     ibuf += sizeof( svid );
743     if (( vol = getvolbyvid( svid )) == NULL ) {
744         return( AFPERR_PARAM );
745     }
746
747     memcpy(&sdid, ibuf, sizeof( sdid ));
748     ibuf += sizeof( sdid );
749     if (( dir = dirsearch( vol, sdid )) == NULL ) {
750         return( AFPERR_PARAM );
751     }
752
753     memcpy(&dvid, ibuf, sizeof( dvid ));
754     ibuf += sizeof( dvid );
755     memcpy(&ddid, ibuf, sizeof( ddid ));
756     ibuf += sizeof( ddid );
757
758     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
759         return( AFPERR_NOOBJ );
760     }
761     if ( *path == '\0' ) {
762         return( AFPERR_BADTYPE );
763     }
764
765     /* don't allow copies when the file is open.
766      * XXX: the spec only calls for read/deny write access.
767      *      however, copyfile doesn't have any of that info,
768      *      and locks need to stay coherent. as a result,
769      *      we just balk if the file is opened already. */
770     if (of_findname(vol, curdir, path))
771       return AFPERR_DENYCONF;
772     
773     newname = obj->newtmp;
774     strcpy( newname, path );
775
776     p = ctoupath( vol, curdir, newname );
777
778     if (( vol = getvolbyvid( dvid )) == NULL ) {
779         return( AFPERR_PARAM );
780     }
781
782     if (vol->v_flags & AFPVOL_RO)
783         return AFPERR_VLOCK;
784
785     if (( dir = dirsearch( vol, ddid )) == NULL ) {
786         return( AFPERR_PARAM );
787     }
788
789     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
790         return( AFPERR_NOOBJ );
791     }
792     if ( *path != '\0' ) {
793         return( AFPERR_BADTYPE );
794     }
795
796     /* one of the handful of places that knows about the path type */
797     if ( *ibuf++ != 2 ) {
798         return( AFPERR_PARAM );
799     }
800     if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
801         strncpy( newname, ibuf, plen );
802         newname[ plen ] = '\0';
803     }
804
805     if ( (err = copyfile(p, mtoupath(vol, newname ), newname, 
806                   vol_noadouble(vol))) < 0 ) {
807         return err;
808     }
809
810     setvoltime(obj, vol );
811     return( AFP_OK );
812 }
813
814
815 static __inline__ int copy_all(const int dfd, const void *buf,
816                                size_t buflen)
817 {
818   ssize_t cc;
819
820   while (buflen > 0) {
821     if ((cc = write(dfd, buf, buflen)) < 0) {
822       switch (errno) {
823       case EINTR:
824         continue;
825       case EDQUOT:
826       case EFBIG:
827       case ENOSPC:
828         return AFPERR_DFULL;
829       case EROFS:
830         return AFPERR_VLOCK;
831       default:
832         return AFPERR_PARAM;
833       }
834     }
835     buflen -= cc;
836   }
837
838   return 0;
839 }
840
841 /* XXX: this needs to use ad_open and ad_lock. so, we need to
842  * pass in vol and path */
843 int copyfile(src, dst, newname, noadouble )
844     char        *src, *dst, *newname;
845     const int   noadouble;
846 {
847     struct adouble      ad;
848     struct stat         st;
849     char                filebuf[8192];
850     int                 sfd, dfd, len, err = AFP_OK;
851     ssize_t             cc;
852
853
854     if (newname) { 
855       if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
856         switch ( errno ) {
857         case ENOENT :
858             break; /* just copy the data fork */
859         case EACCES :
860             return( AFPERR_ACCESS );
861         default :
862             return( AFPERR_PARAM );
863         }
864       } else {
865         if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
866                 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
867             close( sfd );
868             switch ( errno ) {
869             case ENOENT :
870                 return( AFPERR_NOOBJ );
871             case EACCES :
872                 return( AFPERR_ACCESS );
873             case EROFS:
874                 return AFPERR_VLOCK;
875             default :
876                 return( AFPERR_PARAM );
877             }
878         }
879
880         /* copy the file */
881 #ifdef SENDFILE_FLAVOR_LINUX
882         if (fstat(sfd, &st) == 0) {
883           if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
884             switch (errno) {
885             case EDQUOT:
886             case EFBIG:
887             case ENOSPC:
888               err = AFPERR_DFULL;
889               break;
890             case EROFS:
891               err = AFPERR_VLOCK;
892               break;
893             default:
894               err = AFPERR_PARAM;
895             }
896           }
897           goto copyheader_done;
898         }
899 #endif
900         while (1) {
901           if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
902             if (errno == EINTR) 
903               continue;
904             err = AFPERR_PARAM;
905             break;
906           }
907
908           if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
909             break;
910         }
911
912 copyheader_done:
913         close(sfd);
914         close(dfd);
915         if (err < 0) {
916           unlink(ad_path(dst, ADFLAGS_HF));
917           return err;
918         }
919       }
920     }
921
922     /* data fork copying */
923     if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
924         switch ( errno ) {
925         case ENOENT :
926             return( AFPERR_NOOBJ );
927         case EACCES :
928             return( AFPERR_ACCESS );
929         default :
930             return( AFPERR_PARAM );
931         }
932     }
933
934     if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
935         close( sfd );
936         switch ( errno ) {
937         case ENOENT :
938             return( AFPERR_NOOBJ );
939         case EACCES :
940             return( AFPERR_ACCESS );
941         case EROFS:
942             return AFPERR_VLOCK;
943         default :
944             return( AFPERR_PARAM );
945         }
946     }
947
948 #ifdef SENDFILE_FLAVOR_LINUX
949     if (fstat(sfd, &st) == 0) {
950       if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
951         switch (errno) {
952         case EDQUOT:
953         case EFBIG:
954         case ENOSPC:
955           err = AFPERR_DFULL;
956           break;
957         default:
958           err = AFPERR_PARAM;
959         }
960       }
961       goto copydata_done;
962     }
963 #endif
964
965     while (1) {
966       if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
967         if (errno == EINTR)
968           continue;
969         
970         err = AFPERR_PARAM;
971         break;
972       }
973       
974       if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
975         break;
976       }
977     }
978     
979 copydata_done:
980     close(sfd);
981     close(dfd);
982     if (err < 0) {
983       unlink(ad_path(dst, ADFLAGS_HF));
984       unlink(dst);
985       return err;
986     }
987     
988     if (newname) {
989       memset(&ad, 0, sizeof(ad));
990       if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
991                     0666, &ad) < 0 ) {
992         switch ( errno ) {
993         case ENOENT :
994           return noadouble ? AFP_OK : AFPERR_NOOBJ;
995         case EACCES :
996           return( AFPERR_ACCESS );
997         case EROFS:
998           return AFPERR_VLOCK;
999         default :
1000           return( AFPERR_PARAM );
1001         }
1002       }
1003
1004       len = strlen( newname );
1005       ad_setentrylen( &ad, ADEID_NAME, len );
1006       memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1007       ad_flush( &ad, ADFLAGS_HF );
1008       ad_close( &ad, ADFLAGS_HF );
1009     }
1010     
1011     return( AFP_OK );
1012 }
1013
1014
1015 int deletefile( file )
1016     char                *file;
1017 {
1018     struct adouble      ad;
1019     int                 adflags, err = AFP_OK;
1020
1021     /* try to open both at once */
1022     adflags = ADFLAGS_DF|ADFLAGS_HF;
1023     memset(&ad, 0, sizeof(ad));
1024     if ( ad_open( file, adflags, O_RDWR, 0, &ad ) < 0 ) {
1025           switch (errno) {
1026           case ENOENT:
1027             adflags = ADFLAGS_DF;
1028             /* that failed. now try to open just the data fork */
1029             memset(&ad, 0, sizeof(ad));
1030             if ( ad_open( file, adflags, O_RDWR, 0, &ad ) < 0 ) {
1031               switch (errno) {
1032               case ENOENT:
1033                 return AFPERR_NOOBJ;
1034               case EACCES:
1035                 return AFPERR_ACCESS;
1036               default:
1037                 return AFPERR_PARAM;
1038               }
1039             }
1040             break;
1041
1042           case EACCES:
1043             return( AFPERR_ACCESS );
1044           case EROFS:
1045             return AFPERR_VLOCK;
1046           default:
1047             return( AFPERR_PARAM );
1048           }
1049     }
1050
1051     if ((adflags & ADFLAGS_HF) &&
1052         (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR, 0, 0) < 0 )) {
1053       ad_close( &ad, adflags );
1054       return( AFPERR_BUSY );
1055     }
1056
1057     if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0 ) < 0) {
1058       err = AFPERR_BUSY;
1059       goto delete_unlock;
1060     }
1061
1062     if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1063         switch ( errno ) {
1064         case EPERM:
1065         case EACCES :
1066             err = AFPERR_ACCESS;
1067             goto delete_unlock;
1068         case EROFS:
1069             err = AFPERR_VLOCK;
1070             goto delete_unlock;
1071         case ENOENT :
1072             break;
1073         default :
1074             err = AFPERR_PARAM;
1075             goto delete_unlock;
1076         }
1077     }
1078
1079     if ( unlink( file ) < 0 ) {
1080         switch ( errno ) {
1081         case EPERM:
1082         case EACCES :
1083             err = AFPERR_ACCESS;
1084             break;
1085         case EROFS:
1086             err = AFPERR_VLOCK;
1087             break;
1088         case ENOENT :
1089             break;
1090         default :
1091             err = AFPERR_PARAM;
1092             break;
1093         }
1094     }
1095
1096 delete_unlock:
1097     if (adflags & ADFLAGS_HF)
1098       ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1099     ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1100     ad_close( &ad, adflags );
1101     return err;
1102 }
1103
1104
1105 #if AD_VERSION > AD_VERSION1
1106 /* return a file id */
1107 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1108     AFPObj      *obj;
1109     char        *ibuf, *rbuf;
1110     int         ibuflen, *rbuflen;
1111 {
1112     struct stat         st;
1113     struct adouble      ad;
1114     struct vol          *vol;
1115     struct dir          *dir;
1116     char                *path, *upath;
1117     int                 len;
1118     cnid_t              did, id;
1119     u_short             vid;
1120     
1121
1122     *rbuflen = 0;
1123     ibuf += 2;
1124
1125     memcpy(&vid, ibuf, sizeof(vid));
1126     ibuf += sizeof(vid);
1127
1128     if (( vol = getvolbyvid( vid )) == NULL ) {
1129         return( AFPERR_PARAM);
1130     }
1131
1132     if (vol->v_flags & AFPVOL_RO)
1133         return AFPERR_VLOCK;
1134
1135     memcpy(&did, ibuf, sizeof( did ));
1136     ibuf += sizeof(did);
1137
1138     if (( dir = dirsearch( vol, did )) == NULL ) {
1139         return( AFPERR_PARAM );
1140     }
1141
1142     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1143         return( AFPERR_PARAM );
1144     }
1145
1146     if ( *path == '\0' ) {
1147         return( AFPERR_BADTYPE );
1148     }
1149
1150     upath = mtoupath(vol, path);
1151     if (stat(upath, &st) < 0) {
1152       switch (errno) {
1153       case EPERM:
1154       case EACCES:
1155         return AFPERR_ACCESS;
1156       case ENOENT:
1157         return AFPERR_NOOBJ;
1158       default:
1159         return AFPERR_PARAM;
1160       }
1161     }
1162
1163     if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1164       memcpy(rbuf, &id, sizeof(id));
1165       *rbuflen = sizeof(id);
1166       return AFPERR_EXISTID;
1167     }
1168
1169     memset(&ad, 0, sizeof(ad));
1170     if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) < 0)
1171       id = 0;
1172     else {
1173       memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1174       ad_close(upath, ADFLAGS_HF);
1175     }
1176
1177     if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1178       memcpy(rbuf, &id, sizeof(id));
1179       *rbuflen = sizeof(id);
1180       return AFP_OK;
1181     }
1182
1183     switch (errno) {
1184     case EROFS:
1185       return AFPERR_VLOCK;
1186       break;
1187     case EPERM:
1188     case EACCES:
1189       return AFPERR_ACCESS;
1190       break;
1191     default:
1192       syslog(LOG_ERR, "afp_createid: cnid_add: %m");
1193       return AFPERR_PARAM;
1194     }
1195 }
1196
1197 /* resolve a file id */
1198 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1199     AFPObj      *obj;
1200     char        *ibuf, *rbuf;
1201     int         ibuflen, *rbuflen;
1202 {
1203     struct stat         st;
1204     struct vol          *vol;
1205     struct dir          *dir;
1206     char                *upath;
1207     int                 err, buflen;
1208     cnid_t              id;
1209     u_int16_t           vid, bitmap;
1210     
1211
1212     *rbuflen = 0;
1213     ibuf += 2;
1214
1215     memcpy(&vid, ibuf, sizeof(vid));
1216     ibuf += sizeof(vid);
1217
1218     if (( vol = getvolbyvid( vid )) == NULL ) {
1219         return( AFPERR_PARAM);
1220     }
1221
1222     memcpy(&id, ibuf, sizeof( id ));
1223     ibuf += sizeof(id);
1224
1225     if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1226       return AFPERR_BADID;
1227     }
1228
1229     if (( dir = dirsearch( vol, id )) == NULL ) {
1230       return( AFPERR_PARAM );
1231     }
1232
1233     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1234       switch (errno) {
1235       case EACCES:
1236       case EPERM:
1237         return AFPERR_ACCESS;
1238       case ENOENT:
1239         return AFPERR_NOID;
1240       default:
1241         return AFPERR_PARAM;
1242       }
1243     }
1244
1245     /* directories are bad */
1246     if (S_ISDIR(st.st_mode))
1247       return AFPERR_BADTYPE;
1248
1249     memcpy(&bitmap, ibuf, sizeof(bitmap));
1250     bitmap = ntohs( bitmap );
1251
1252     if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1253                            rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1254       return err;
1255
1256     *rbuflen = buflen + sizeof(bitmap);
1257     memcpy(rbuf, ibuf, sizeof(bitmap));
1258     return AFP_OK;
1259 }
1260
1261 int afp_deleteid(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;
1271     cnid_t              id;
1272     u_short             vid;
1273     
1274
1275     *rbuflen = 0;
1276     ibuf += 2;
1277
1278     memcpy(&vid, ibuf, sizeof(vid));
1279     ibuf += sizeof(vid);
1280
1281     if (( vol = getvolbyvid( vid )) == NULL ) {
1282         return( AFPERR_PARAM);
1283     }
1284
1285     if (vol->v_flags & AFPVOL_RO)
1286         return AFPERR_VLOCK;
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_NOID;
1293     }
1294
1295     if (( dir = dirsearch( vol, id )) == NULL ) {
1296       return( AFPERR_PARAM );
1297     }
1298
1299     err = AFP_OK;
1300     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1301       switch (errno) {
1302       case EACCES:
1303       case EPERM:
1304         return AFPERR_ACCESS;
1305       case ENOENT:
1306         /* still try to delete the id */
1307         err = AFPERR_NOOBJ;
1308         break;
1309       default:
1310         return AFPERR_PARAM;
1311       }
1312     }
1313
1314     /* directories are bad */
1315     if (S_ISDIR(st.st_mode))
1316       return AFPERR_BADTYPE;
1317
1318     if (cnid_delete(vol->v_db, id)) {
1319       switch (errno) {
1320       case EROFS:
1321         return AFPERR_VLOCK;
1322       case EPERM:
1323       case EACCES:
1324         return AFPERR_ACCESS;
1325       default:
1326         return AFPERR_PARAM;
1327       }
1328     }
1329
1330     return err;
1331 }
1332 #endif
1333
1334 #define APPLETEMP ".AppleTempXXXXXX"
1335 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1336     AFPObj      *obj;
1337     char        *ibuf, *rbuf;
1338     int         ibuflen, *rbuflen;
1339 {
1340     struct stat         srcst, destst;
1341     struct vol          *vol;
1342     struct dir          *dir, *sdir;
1343     char                *spath, temp[17], *path, *p;
1344     char                *supath, *upath;
1345     int                 err;
1346 #if AD_VERSION > AD_VERSION1
1347     int                 slen, dlen;
1348 #endif
1349     cnid_t              sid, did;
1350     u_int16_t           vid;
1351     
1352
1353     *rbuflen = 0;
1354     ibuf += 2;
1355
1356     memcpy(&vid, ibuf, sizeof(vid));
1357     ibuf += sizeof(vid);
1358
1359     if (( vol = getvolbyvid( vid )) == NULL ) {
1360         return( AFPERR_PARAM);
1361     }
1362
1363     if (vol->v_flags & AFPVOL_RO)
1364         return AFPERR_VLOCK;
1365
1366     /* source and destination dids */
1367     memcpy(&sid, ibuf, sizeof(sid));
1368     ibuf += sizeof(sid);
1369     memcpy(&did, ibuf, sizeof(did));
1370     ibuf += sizeof(did);
1371
1372     /* source file */
1373     if ((dir = dirsearch( vol, sid )) == NULL ) {
1374         return( AFPERR_PARAM );
1375     }
1376
1377     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1378         return( AFPERR_PARAM );
1379     }
1380
1381     if ( *path == '\0' ) {
1382         return( AFPERR_BADTYPE );
1383     }
1384
1385     upath = mtoupath(vol, path);
1386     if (stat(upath, &srcst) < 0) {
1387       switch (errno) {
1388       case ENOENT:
1389         return AFPERR_NOID;
1390       case EPERM:
1391       case EACCES:
1392         return AFPERR_ACCESS;
1393       default:
1394         return AFPERR_PARAM;
1395       }
1396     }
1397
1398     /* save some stuff */
1399     sdir = curdir;
1400     spath = obj->oldtmp;
1401     supath = obj->newtmp;
1402     strcpy(spath, path);
1403     strcpy(supath, upath); /* this is for the cnid changing */
1404     p = ctoupath( vol, sdir, spath);
1405
1406     /* look for the source cnid. if it doesn't exist, don't worry about
1407      * it. */
1408 #if AD_VERSION > AD_VERSION1
1409     sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath, 
1410                       slen = strlen(supath));
1411 #endif
1412
1413     if (( dir = dirsearch( vol, did )) == NULL ) {
1414         return( AFPERR_PARAM );
1415     }
1416
1417     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1418         return( AFPERR_PARAM );
1419     }
1420
1421     if ( *path == '\0' ) {
1422         return( AFPERR_BADTYPE );
1423     }
1424
1425     /* FPExchangeFiles is the only call that can return the SameObj
1426      * error */
1427     if ((curdir == sdir) && strcmp(spath, path) == 0)
1428       return AFPERR_SAMEOBJ;
1429
1430     upath = mtoupath(vol, path);
1431     if (stat(upath, &destst) < 0) {
1432       switch (errno) {
1433       case ENOENT:
1434         return AFPERR_NOID;
1435       case EPERM:
1436       case EACCES:
1437         return AFPERR_ACCESS;
1438       default:
1439         return AFPERR_PARAM;
1440       }
1441     }
1442
1443 #if AD_VERSION > AD_VERSION1
1444     /* look for destination id. */
1445     did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath, 
1446                       dlen = strlen(upath));
1447 #endif
1448
1449     /* construct a temp name. 
1450      * NOTE: the temp file will be in the dest file's directory. it
1451      * will also be inaccessible from AFP. */
1452     memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1453     if (!mktemp(temp))
1454       return AFPERR_MISC;
1455
1456     /* now, quickly rename the file. we error if we can't. */
1457     if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1458       goto err_exchangefile;
1459     of_rename(vol, sdir, spath, curdir, temp);
1460
1461     /* rename destination to source */
1462     if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0) 
1463       goto err_src_to_tmp;
1464     of_rename(vol, curdir, path, sdir, spath);
1465
1466     /* rename temp to destination */
1467     if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0) 
1468       goto err_dest_to_src;
1469     of_rename(vol, curdir, temp, curdir, path);
1470     
1471 #if AD_VERSION > AD_VERSION1
1472     /* id's need switching. src -> dest and dest -> src. */
1473     if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did, 
1474                             upath, dlen) < 0)) {
1475       switch (errno) {
1476       case EPERM:
1477       case EACCES:
1478         err = AFPERR_ACCESS;
1479       default:
1480         err = AFPERR_PARAM;
1481       }
1482       goto err_temp_to_dest;
1483     }
1484
1485     if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1486                             supath, slen) < 0)) {
1487       switch (errno) {
1488       case EPERM:
1489       case EACCES:
1490         err = AFPERR_ACCESS;
1491       default:
1492         err = AFPERR_PARAM;
1493       }
1494
1495       if (sid)
1496         cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1497       goto err_temp_to_dest;
1498     }
1499 #endif
1500     return AFP_OK;
1501
1502
1503     /* all this stuff is so that we can unwind a failed operation 
1504      * properly. */
1505 err_temp_to_dest:
1506     /* rename dest to temp */
1507     renamefile(upath, temp, temp, vol_noadouble(vol));
1508     of_rename(vol, curdir, upath, curdir, temp);
1509
1510 err_dest_to_src:
1511     /* rename source back to dest */
1512     renamefile(p, upath, path, vol_noadouble(vol));
1513     of_rename(vol, sdir, spath, curdir, path);
1514
1515 err_src_to_tmp:
1516     /* rename temp back to source */
1517     renamefile(temp, p, spath, vol_noadouble(vol));
1518     of_rename(vol, curdir, temp, sdir, spath);
1519
1520 err_exchangefile:
1521     return err;
1522 }