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