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