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