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