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