]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/file.c
1. Respect the kFPDeleteInhibitBit attribute
[netatalk.git] / etc / afpd / file.c
1 /*
2  * $Id: file.c,v 1.43 2002-03-24 17:43:39 jmarcus 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, 0 );
793                 return( rc );
794             }
795             return deletefile( src, 0);
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 /* -----------------------------------
1175    checkAttrib:   1 check kFPDeleteInhibitBit 
1176    ie deletfile called from afp_delete
1177    
1178 */
1179 int deletefile( file, checkAttrib )
1180 char            *file;
1181 int         checkAttrib;
1182 {
1183     struct adouble      ad;
1184     int                 adflags, err = AFP_OK;
1185     int                 locktype = ADLOCK_WR;
1186     int                 openmode = O_RDWR;
1187
1188 #ifdef DEBUG
1189     LOG(log_info, logtype_afpd, "begin deletefile:");
1190 #endif /* DEBUG */
1191
1192     while(1) {
1193         /*
1194          * If can't open read/write then try again read-only.  If it's open
1195          * read-only, we must do a read lock instead of a write lock.
1196          */
1197         /* try to open both at once */
1198         adflags = ADFLAGS_DF|ADFLAGS_HF;
1199         memset(&ad, 0, sizeof(ad));
1200         if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1201             switch (errno) {
1202             case ENOENT:
1203                 adflags = ADFLAGS_DF;
1204                 /* that failed. now try to open just the data fork */
1205                 memset(&ad, 0, sizeof(ad));
1206                 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1207                     switch (errno) {
1208                     case ENOENT:
1209                         return AFPERR_NOOBJ;
1210                     case EACCES:
1211                         if(openmode == O_RDWR) {
1212                             openmode = O_RDONLY;
1213                             locktype = ADLOCK_RD;
1214                             continue;
1215                         } else {
1216                             return AFPERR_ACCESS;
1217                         }
1218                     case EROFS:
1219                         return AFPERR_VLOCK;
1220                     default:
1221                         return AFPERR_PARAM;
1222                     }
1223                 }
1224                 break;
1225
1226             case EACCES:
1227                 if(openmode == O_RDWR) {
1228                     openmode = O_RDONLY;
1229                     locktype = ADLOCK_RD;
1230                     continue;
1231                 } else {
1232                     return AFPERR_ACCESS;
1233                 }
1234             case EROFS:
1235                 return AFPERR_VLOCK;
1236             default:
1237                 return( AFPERR_PARAM );
1238             }
1239         }
1240         break;  /* from the while */
1241     }
1242     /*
1243      * Does kFPDeleteInhibitBit (bit 8) set?
1244      */
1245     if (checkAttrib && (adflags & ADFLAGS_HF)) {
1246         u_int16_t   bshort;
1247
1248         ad_getattr(&ad, &bshort);
1249         if ((bshort & htons(ATTRBIT_NODELETE))) {
1250             ad_close( &ad, adflags );
1251             return(AFPERR_OLOCK);
1252         }
1253     }
1254
1255     if ((adflags & ADFLAGS_HF) &&
1256             (ad_tmplock(&ad, ADEID_RFORK, locktype, 0, 0) < 0 )) {
1257         ad_close( &ad, adflags );
1258         return( AFPERR_BUSY );
1259     }
1260
1261     if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1262         err = AFPERR_BUSY;
1263         goto delete_unlock;
1264     }
1265
1266     if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1267         switch ( errno ) {
1268         case EPERM:
1269         case EACCES :
1270             err = AFPERR_ACCESS;
1271             goto delete_unlock;
1272         case EROFS:
1273             err = AFPERR_VLOCK;
1274             goto delete_unlock;
1275         case ENOENT :
1276             break;
1277         default :
1278             err = AFPERR_PARAM;
1279             goto delete_unlock;
1280         }
1281     }
1282
1283     if ( unlink( file ) < 0 ) {
1284         switch ( errno ) {
1285         case EPERM:
1286         case EACCES :
1287             err = AFPERR_ACCESS;
1288             break;
1289         case EROFS:
1290             err = AFPERR_VLOCK;
1291             break;
1292         case ENOENT :
1293             break;
1294         default :
1295             err = AFPERR_PARAM;
1296             break;
1297         }
1298     }
1299
1300 delete_unlock:
1301     if (adflags & ADFLAGS_HF)
1302         ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1303     ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1304     ad_close( &ad, adflags );
1305
1306 #ifdef DEBUG
1307     LOG(log_info, logtype_afpd, "end deletefile:");
1308 #endif /* DEBUG */
1309
1310     return err;
1311 }
1312
1313
1314 #ifdef CNID_DB
1315 /* return a file id */
1316 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1317 AFPObj      *obj;
1318 char    *ibuf, *rbuf;
1319 int             ibuflen, *rbuflen;
1320 {
1321     struct stat         st;
1322     struct adouble      ad;
1323     struct vol          *vol;
1324     struct dir          *dir;
1325     char                *path, *upath;
1326     int                 len;
1327     cnid_t              did, id;
1328     u_short             vid;
1329
1330 #ifdef DEBUG
1331     LOG(log_info, logtype_afpd, "begin afp_createid:");
1332 #endif /* DEBUG */
1333
1334     *rbuflen = 0;
1335     ibuf += 2;
1336
1337     memcpy(&vid, ibuf, sizeof(vid));
1338     ibuf += sizeof(vid);
1339
1340     if (( vol = getvolbyvid( vid )) == NULL ) {
1341         return( AFPERR_PARAM);
1342     }
1343
1344     if (vol->v_flags & AFPVOL_RO)
1345         return AFPERR_VLOCK;
1346
1347     memcpy(&did, ibuf, sizeof( did ));
1348     ibuf += sizeof(did);
1349
1350     if (( dir = dirsearch( vol, did )) == NULL ) {
1351         return( AFPERR_PARAM );
1352     }
1353
1354     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1355         return( AFPERR_PARAM );
1356     }
1357
1358     if ( *path == '\0' ) {
1359         return( AFPERR_BADTYPE );
1360     }
1361
1362     upath = mtoupath(vol, path);
1363     if (stat(upath, &st) < 0) {
1364         switch (errno) {
1365         case EPERM:
1366         case EACCES:
1367             return AFPERR_ACCESS;
1368         case ENOENT:
1369             return AFPERR_NOOBJ;
1370         default:
1371             return AFPERR_PARAM;
1372         }
1373     }
1374
1375     if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1376         memcpy(rbuf, &id, sizeof(id));
1377         *rbuflen = sizeof(id);
1378         return AFPERR_EXISTID;
1379     }
1380
1381 #if AD_VERSION > AD_VERSION1
1382     memset(&ad, 0, sizeof(ad));
1383     if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1384         memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1385         ad_close(&ad, ADFLAGS_HF);
1386     }
1387 #endif /* AD_VERSION > AD_VERSION1 */
1388
1389     if (id = cnid_add(vol->v_db, &st, did, upath, len, id) != CNID_INVALID) {
1390         memcpy(rbuf, &id, sizeof(id));
1391         *rbuflen = sizeof(id);
1392         return AFP_OK;
1393     }
1394
1395 #ifdef DEBUG
1396     LOG(log_info, logtype_afpd, "ending afp_createid...:");
1397 #endif /* DEBUG */
1398
1399     switch (errno) {
1400     case EROFS:
1401         return AFPERR_VLOCK;
1402         break;
1403     case EPERM:
1404     case EACCES:
1405         return AFPERR_ACCESS;
1406         break;
1407     default:
1408         LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1409         return AFPERR_PARAM;
1410     }
1411 }
1412
1413 /* resolve a file id */
1414 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1415 AFPObj      *obj;
1416 char    *ibuf, *rbuf;
1417 int             ibuflen, *rbuflen;
1418 {
1419     struct stat         st;
1420     struct vol          *vol;
1421     struct dir          *dir;
1422     char                *upath;
1423     int                 err, buflen;
1424     cnid_t              id;
1425     u_int16_t           vid, bitmap;
1426
1427     static char buffer[12 + MAXPATHLEN + 1];
1428     int len = 12 + MAXPATHLEN + 1;
1429
1430 #ifdef DEBUG
1431     LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1432 #endif /* DEBUG */
1433
1434     *rbuflen = 0;
1435     ibuf += 2;
1436
1437     memcpy(&vid, ibuf, sizeof(vid));
1438     ibuf += sizeof(vid);
1439
1440     if (( vol = getvolbyvid( vid )) == NULL ) {
1441         return( AFPERR_PARAM);
1442     }
1443
1444     memcpy(&id, ibuf, sizeof( id ));
1445     ibuf += sizeof(id);
1446
1447     if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1448         return AFPERR_BADID;
1449     }
1450
1451     if (( dir = dirlookup( vol, id )) == NULL ) {
1452         return( AFPERR_PARAM );
1453     }
1454
1455     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1456         switch (errno) {
1457         case EACCES:
1458         case EPERM:
1459             return AFPERR_ACCESS;
1460         case ENOENT:
1461             return AFPERR_NOID;
1462         default:
1463             return AFPERR_PARAM;
1464         }
1465     }
1466
1467     /* directories are bad */
1468     if (S_ISDIR(st.st_mode))
1469         return AFPERR_BADTYPE;
1470
1471     memcpy(&bitmap, ibuf, sizeof(bitmap));
1472     bitmap = ntohs( bitmap );
1473
1474     if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1475                             rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1476         return err;
1477
1478     *rbuflen = buflen + sizeof(bitmap);
1479     memcpy(rbuf, ibuf, sizeof(bitmap));
1480
1481 #ifdef DEBUG
1482     LOG(log_info, logtype_afpd, "end afp_resolveid:");
1483 #endif /* DEBUG */
1484
1485     return AFP_OK;
1486 }
1487
1488 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1489 AFPObj      *obj;
1490 char    *ibuf, *rbuf;
1491 int             ibuflen, *rbuflen;
1492 {
1493     struct stat         st;
1494     struct vol          *vol;
1495     struct dir          *dir;
1496     char                *upath;
1497     int                 err;
1498     cnid_t              id;
1499     cnid_t              fileid;
1500     u_short             vid;
1501     static char buffer[12 + MAXPATHLEN + 1];
1502     int len = 12 + MAXPATHLEN + 1;
1503
1504 #ifdef DEBUG
1505     LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1506 #endif /* DEBUG */
1507
1508     *rbuflen = 0;
1509     ibuf += 2;
1510
1511     memcpy(&vid, ibuf, sizeof(vid));
1512     ibuf += sizeof(vid);
1513
1514     if (( vol = getvolbyvid( vid )) == NULL ) {
1515         return( AFPERR_PARAM);
1516     }
1517
1518     if (vol->v_flags & AFPVOL_RO)
1519         return AFPERR_VLOCK;
1520
1521     memcpy(&id, ibuf, sizeof( id ));
1522     ibuf += sizeof(id);
1523     fileid = id;
1524
1525     if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1526         return AFPERR_NOID;
1527     }
1528
1529     if (( dir = dirlookup( vol, id )) == NULL ) {
1530         return( AFPERR_PARAM );
1531     }
1532
1533     err = AFP_OK;
1534     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1535         switch (errno) {
1536         case EACCES:
1537         case EPERM:
1538             return AFPERR_ACCESS;
1539         case ENOENT:
1540             /* still try to delete the id */
1541             err = AFPERR_NOOBJ;
1542             break;
1543         default:
1544             return AFPERR_PARAM;
1545         }
1546     }
1547
1548     /* directories are bad */
1549     if (S_ISDIR(st.st_mode))
1550         return AFPERR_BADTYPE;
1551
1552     if (cnid_delete(vol->v_db, fileid)) {
1553         switch (errno) {
1554         case EROFS:
1555             return AFPERR_VLOCK;
1556         case EPERM:
1557         case EACCES:
1558             return AFPERR_ACCESS;
1559         default:
1560             return AFPERR_PARAM;
1561         }
1562     }
1563
1564 #ifdef DEBUG
1565     LOG(log_info, logtype_afpd, "end afp_deleteid:");
1566 #endif /* DEBUG */
1567
1568     return err;
1569 }
1570 #endif /* CNID_DB */
1571
1572 #define APPLETEMP ".AppleTempXXXXXX"
1573
1574 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1575 AFPObj      *obj;
1576 char    *ibuf, *rbuf;
1577 int             ibuflen, *rbuflen;
1578 {
1579     struct stat         srcst, destst;
1580     struct vol          *vol;
1581     struct dir          *dir, *sdir;
1582     char                *spath, temp[17], *path, *p;
1583     char                *supath, *upath;
1584     int                 err;
1585 #ifdef CNID_DB
1586     int                 slen, dlen;
1587 #endif /* CNID_DB */
1588     u_int32_t           sid, did;
1589     u_int16_t           vid;
1590
1591 #ifdef DEBUG
1592     LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1593 #endif /* DEBUG */
1594
1595     *rbuflen = 0;
1596     ibuf += 2;
1597
1598     memcpy(&vid, ibuf, sizeof(vid));
1599     ibuf += sizeof(vid);
1600
1601     if (( vol = getvolbyvid( vid )) == NULL ) {
1602         return( AFPERR_PARAM);
1603     }
1604
1605     if (vol->v_flags & AFPVOL_RO)
1606         return AFPERR_VLOCK;
1607
1608     /* source and destination dids */
1609     memcpy(&sid, ibuf, sizeof(sid));
1610     ibuf += sizeof(sid);
1611     memcpy(&did, ibuf, sizeof(did));
1612     ibuf += sizeof(did);
1613
1614     /* source file */
1615     if ((dir = dirsearch( vol, sid )) == NULL ) {
1616         return( AFPERR_PARAM );
1617     }
1618
1619     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1620         return( AFPERR_PARAM );
1621     }
1622
1623     if ( *path == '\0' ) {
1624         return( AFPERR_BADTYPE );
1625     }
1626
1627     upath = mtoupath(vol, path);
1628     if (stat(upath, &srcst) < 0) {
1629         switch (errno) {
1630         case ENOENT:
1631             return AFPERR_NOID;
1632         case EPERM:
1633         case EACCES:
1634             return AFPERR_ACCESS;
1635         default:
1636             return AFPERR_PARAM;
1637         }
1638     }
1639
1640     /* save some stuff */
1641     sdir = curdir;
1642     spath = obj->oldtmp;
1643     supath = obj->newtmp;
1644     strcpy(spath, path);
1645     strcpy(supath, upath); /* this is for the cnid changing */
1646     p = ctoupath( vol, sdir, spath);
1647
1648     /* look for the source cnid. if it doesn't exist, don't worry about
1649      * it. */
1650 #ifdef CNID_DB
1651     sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1652                       slen = strlen(supath));
1653 #endif /* CNID_DB */
1654
1655     if (( dir = dirsearch( vol, did )) == NULL ) {
1656         return( AFPERR_PARAM );
1657     }
1658
1659     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1660         return( AFPERR_PARAM );
1661     }
1662
1663     if ( *path == '\0' ) {
1664         return( AFPERR_BADTYPE );
1665     }
1666
1667     /* FPExchangeFiles is the only call that can return the SameObj
1668      * error */
1669     if ((curdir == sdir) && strcmp(spath, path) == 0)
1670         return AFPERR_SAMEOBJ;
1671
1672     upath = mtoupath(vol, path);
1673     if (stat(upath, &destst) < 0) {
1674         switch (errno) {
1675         case ENOENT:
1676             return AFPERR_NOID;
1677         case EPERM:
1678         case EACCES:
1679             return AFPERR_ACCESS;
1680         default:
1681             return AFPERR_PARAM;
1682         }
1683     }
1684
1685 #ifdef CNID_DB
1686     /* look for destination id. */
1687     did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1688                       dlen = strlen(upath));
1689 #endif /* CNID_DB */
1690
1691     /* construct a temp name.
1692      * NOTE: the temp file will be in the dest file's directory. it
1693      * will also be inaccessible from AFP. */
1694     memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1695     if (!mktemp(temp))
1696         return AFPERR_MISC;
1697
1698     /* now, quickly rename the file. we error if we can't. */
1699     if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1700         goto err_exchangefile;
1701     of_rename(vol, sdir, spath, curdir, temp);
1702
1703     /* rename destination to source */
1704     if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1705         goto err_src_to_tmp;
1706     of_rename(vol, curdir, path, sdir, spath);
1707
1708     /* rename temp to destination */
1709     if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1710         goto err_dest_to_src;
1711     of_rename(vol, curdir, temp, curdir, path);
1712
1713 #ifdef CNID_DB
1714     /* id's need switching. src -> dest and dest -> src. */
1715     if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1716                             upath, dlen) < 0)) {
1717         switch (errno) {
1718         case EPERM:
1719         case EACCES:
1720             err = AFPERR_ACCESS;
1721             break;
1722         default:
1723             err = AFPERR_PARAM;
1724         }
1725         goto err_temp_to_dest;
1726     }
1727
1728     if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1729                             supath, slen) < 0)) {
1730         switch (errno) {
1731         case EPERM:
1732         case EACCES:
1733             err = AFPERR_ACCESS;
1734             break;
1735         default:
1736             err = AFPERR_PARAM;
1737         }
1738
1739         if (sid)
1740             cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1741         goto err_temp_to_dest;
1742     }
1743 #endif /* CNID_DB */
1744
1745 #ifdef DEBUG
1746     LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1747 #endif /* DEBUG */
1748
1749     return AFP_OK;
1750
1751
1752     /* all this stuff is so that we can unwind a failed operation
1753      * properly. */
1754 err_temp_to_dest:
1755     /* rename dest to temp */
1756     renamefile(upath, temp, temp, vol_noadouble(vol));
1757     of_rename(vol, curdir, upath, curdir, temp);
1758
1759 err_dest_to_src:
1760     /* rename source back to dest */
1761     renamefile(p, upath, path, vol_noadouble(vol));
1762     of_rename(vol, sdir, spath, curdir, path);
1763
1764 err_src_to_tmp:
1765     /* rename temp back to source */
1766     renamefile(temp, p, spath, vol_noadouble(vol));
1767     of_rename(vol, curdir, temp, sdir, spath);
1768
1769 err_exchangefile:
1770     return err;
1771 }