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