]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/file.c
BIG commit to improve code style using astyle as well as fix up CNID DB
[netatalk.git] / etc / afpd / file.c
1 /*
2  * $Id: file.c,v 1.30 2001-12-03 05:03:38 jmarcus 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 }