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