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