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