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