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