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