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