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