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