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