]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/file.c
AFP 3.0 changes
[netatalk.git] / etc / afpd / file.c
1 /*
2  * $Id: file.c,v 1.66 2002-10-13 16:12: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  * 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                 aint = 0;
361                 memcpy(data, &aint, sizeof( aint ));
362                 data += sizeof( aint );
363             }
364             else {
365                 if ( adp ) {
366                     memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
367
368                     if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
369                         achar = '\x04';
370                         ashort = 0x0000;
371                     }
372                     else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
373                         achar = '\xff';
374                         ashort = 0x0000;
375                     }
376                     else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
377                         achar = '\xb3';
378                         ashort = 0x0000;
379                     }
380                     else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
381                         achar = '\x00';
382                         ashort = 0x0000;
383                     }
384                     else if ( fdType[0] == 'p' ) {
385                         achar = fdType[1];
386                         ashort = (fdType[2] * 256) + fdType[3];
387                     }
388                     else {
389                         achar = '\x00';
390                         ashort = 0x0000;
391                     }
392                 }
393                 else {
394                     achar = '\x00';
395                     ashort = 0x0000;
396                 }
397
398                 *data++ = achar;
399                 *data++ = 0;
400                 memcpy(data, &ashort, sizeof( ashort ));
401                 data += sizeof( ashort );
402                 memset(data, 0, sizeof( ashort ));
403                 data += sizeof( ashort );
404             }
405             break;
406         case FILPBIT_EXTDFLEN:
407             aint = htonl(st->st_size >> 32);
408             memcpy(data, &aint, sizeof( aint ));
409             data += sizeof( aint );
410             aint = htonl(st->st_size);
411             memcpy(data, &aint, sizeof( aint ));
412             data += sizeof( aint );
413             break;
414         case FILPBIT_EXTRFLEN:
415             aint = 0;
416             if (adp) 
417                 aint = htonl(adp->ad_rlen >> 32);
418             memcpy(data, &aint, sizeof( aint ));
419             data += sizeof( aint );
420             if (adp) 
421                 aint = htonl(adp->ad_rlen);
422             memcpy(data, &aint, sizeof( aint ));
423             data += sizeof( aint );
424             break;
425         default :
426             return( AFPERR_BITMAP );
427         }
428         bitmap = bitmap>>1;
429         bit++;
430     }
431     if ( nameoff ) {
432         ashort = htons( data - buf );
433         memcpy(nameoff, &ashort, sizeof( ashort ));
434         data = set_name(data, path, utf8);
435     }
436     *buflen = data - buf;
437     return (AFP_OK);
438 }
439                 
440 /* ----------------------- */
441 int getfilparams(struct vol *vol,
442                  u_int16_t bitmap,
443                  struct path *path, struct dir *dir, 
444                  char *buf, int *buflen )
445 {
446     struct adouble      ad, *adp;
447     struct ofork        *of;
448     char                    *upath;
449     u_int16_t           attrbits = 0;
450     int                 opened = 0;
451     int rc;    
452
453 #ifdef DEBUG
454     LOG(log_info, logtype_default, "begin getfilparams:");
455 #endif /* DEBUG */
456
457     opened = PARAM_NEED_ADP(bitmap);
458     adp = NULL;
459     if (opened) {
460         upath = path->u_name;
461         if ((of = of_findname(path))) {
462             adp = of->of_ad;
463             attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
464             attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
465         } else {
466             memset(&ad, 0, sizeof(ad));
467             adp = &ad;
468         }
469
470         if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
471              adp = NULL;
472         }
473         else {
474             /* FIXME 
475                we need to check if the file is open by another process.
476                it's slow so we only do it if we have to:
477                - bitmap is requested.
478                - we don't already have the answer!
479             */
480             if ((bitmap & (1 << FILPBIT_ATTR))) {
481                  if (!(attrbits & ATTRBIT_ROPEN)) {
482                  }
483                  if (!(attrbits & ATTRBIT_DOPEN)) {
484                  }
485             }
486         }
487     }
488     rc = getmetadata(vol, bitmap, path->m_name, dir, &path->st, buf, buflen, adp, attrbits);
489     if ( adp ) {
490         ad_close( adp, ADFLAGS_HF );
491     }
492 #ifdef DEBUG
493     LOG(log_info, logtype_afpd, "end getfilparams:");
494 #endif /* DEBUG */
495
496     return( rc );
497 }
498
499 /* ----------------------------- */
500 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
501 AFPObj      *obj;
502 char    *ibuf, *rbuf;
503 int             ibuflen, *rbuflen;
504 {
505     struct stat         *st;
506     struct adouble      ad, *adp;
507     struct vol          *vol;
508     struct dir          *dir;
509     struct ofork        *of = NULL;
510     char                *path, *upath;
511     int                 creatf, did, openf, retvalue = AFP_OK;
512     u_int16_t           vid;
513     int                 ret;
514     struct path         *s_path;
515     
516 #ifdef DEBUG
517     LOG(log_info, logtype_afpd, "begin afp_createfile:");
518 #endif /* DEBUG */
519
520     *rbuflen = 0;
521     ibuf++;
522     creatf = (unsigned char) *ibuf++;
523
524     memcpy(&vid, ibuf, sizeof( vid ));
525     ibuf += sizeof( vid );
526
527     if (( vol = getvolbyvid( vid )) == NULL ) {
528         return( AFPERR_PARAM );
529     }
530
531     if (vol->v_flags & AFPVOL_RO)
532         return AFPERR_VLOCK;
533
534     memcpy(&did, ibuf, sizeof( did));
535     ibuf += sizeof( did );
536
537     if (( dir = dirlookup( vol, did )) == NULL ) {
538         return( AFPERR_NOOBJ );
539     }
540
541     if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
542         return( AFPERR_NOOBJ );
543     }
544
545     if ( *s_path->m_name == '\0' ) {
546         return( AFPERR_BADTYPE );
547     }
548
549     upath = s_path->u_name;
550     if (0 != (ret = check_name(vol, upath))) 
551        return  ret;
552     
553     /* if upath is deleted we already in trouble anyway */
554     if ((of = of_findname(s_path))) {
555         adp = of->of_ad;
556     } else {
557         memset(&ad, 0, sizeof(ad));
558         adp = &ad;
559     }
560     if ( creatf) {
561         /* on a hard create, fail if file exists and is open */
562         if (of)
563             return AFPERR_BUSY;
564         openf = O_RDWR|O_CREAT|O_TRUNC;
565     } else {
566         /* on a soft create, if the file is open then ad_open won't fail
567            because open syscall is not called
568         */
569         if (of) {
570                 return AFPERR_EXIST;
571         }
572         openf = O_RDWR|O_CREAT|O_EXCL;
573     }
574
575     if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
576                   openf, 0666, adp) < 0 ) {
577         switch ( errno ) {
578         case EEXIST :
579             return( AFPERR_EXIST );
580         case EACCES :
581             return( AFPERR_ACCESS );
582         case ENOENT:
583             /* on noadouble volumes, just creating the data fork is ok */
584             st = &s_path->st;
585             if (vol_noadouble(vol) && (stat(upath, st) == 0))
586                 goto createfile_done;
587             /* fallthrough */
588         default :
589             return( AFPERR_PARAM );
590         }
591     }
592     path = s_path->m_name;
593     ad_setentrylen( adp, ADEID_NAME, strlen( path ));
594     memcpy(ad_entry( adp, ADEID_NAME ), path,
595            ad_getentrylen( adp, ADEID_NAME ));
596     ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
597     ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
598
599 createfile_done:
600
601 #ifdef DROPKLUDGE
602     if (vol->v_flags & AFPVOL_DROPBOX) {
603         retvalue = matchfile2dirperms(upath, vol, did);
604     }
605 #endif /* DROPKLUDGE */
606
607     setvoltime(obj, vol );
608
609 #ifdef DEBUG
610     LOG(log_info, logtype_afpd, "end afp_createfile");
611 #endif /* DEBUG */
612
613     return (retvalue);
614 }
615
616 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
617 AFPObj      *obj;
618 char    *ibuf, *rbuf;
619 int             ibuflen, *rbuflen;
620 {
621     struct vol  *vol;
622     struct dir  *dir;
623     struct path *s_path;
624     int         did, rc;
625     u_int16_t   vid, bitmap;
626
627 #ifdef DEBUG
628     LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
629 #endif /* DEBUG */
630
631     *rbuflen = 0;
632     ibuf += 2;
633
634     memcpy(&vid, ibuf, sizeof( vid ));
635     ibuf += sizeof( vid );
636     if (( vol = getvolbyvid( vid )) == NULL ) {
637         return( AFPERR_PARAM );
638     }
639
640     if (vol->v_flags & AFPVOL_RO)
641         return AFPERR_VLOCK;
642
643     memcpy(&did, ibuf, sizeof( did ));
644     ibuf += sizeof( did );
645     if (( dir = dirlookup( vol, did )) == NULL ) {
646         return( AFPERR_NOOBJ );
647     }
648
649     memcpy(&bitmap, ibuf, sizeof( bitmap ));
650     bitmap = ntohs( bitmap );
651     ibuf += sizeof( bitmap );
652
653     if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
654         return( AFPERR_NOOBJ );
655     }
656
657     if ( *s_path->m_name == '\0' ) {
658         return( AFPERR_BADTYPE ); /* it's a directory */
659     }
660
661     if ((u_long)ibuf & 1 ) {
662         ibuf++;
663     }
664
665     if (( rc = setfilparams(vol, s_path, bitmap, ibuf )) == AFP_OK ) {
666         setvoltime(obj, vol );
667     }
668
669 #ifdef DEBUG
670     LOG(log_info, logtype_afpd, "end afp_setfilparams:");
671 #endif /* DEBUG */
672
673     return( rc );
674 }
675
676 /*
677  * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic  
678  *
679 */
680 extern struct path Cur_Path;
681
682 int setfilparams(struct vol *vol,
683                  struct path *path, u_int16_t bitmap, char *buf )
684 {
685     struct adouble      ad, *adp;
686     struct ofork        *of;
687     struct extmap       *em;
688     int                 bit = 0, isad = 1, err = AFP_OK;
689     char                *upath;
690     u_char              achar, *fdType, xyy[4];
691     u_int16_t           ashort, bshort;
692     u_int32_t           aint;
693     struct utimbuf      ut;
694
695     int                 change_mdate = 0;
696     int                 change_parent_mdate = 0;
697     int                 newdate = 0;
698     struct timeval      tv;
699
700
701 #ifdef DEBUG
702     LOG(log_info, logtype_afpd, "begin setfilparams:");
703 #endif /* DEBUG */
704
705     upath = path->u_name;
706     if ((of = of_findname(path))) {
707         adp = of->of_ad;
708     } else {
709         memset(&ad, 0, sizeof(ad));
710         adp = &ad;
711     }
712
713     if (check_access(upath, OPENACC_WR ) < 0) {
714         return AFPERR_ACCESS;
715     }
716
717     if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
718                  O_RDWR|O_CREAT, 0666, adp) < 0) {
719         /* for some things, we don't need an adouble header */
720         if (bitmap & ~(1<<FILPBIT_MDATE)) {
721             return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
722         }
723         isad = 0;
724     } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
725         ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
726         memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
727                ad_getentrylen( adp, ADEID_NAME ));
728     }
729
730     while ( bitmap != 0 ) {
731         while (( bitmap & 1 ) == 0 ) {
732             bitmap = bitmap>>1;
733             bit++;
734         }
735
736         switch(  bit ) {
737         case FILPBIT_ATTR :
738             change_mdate = 1;
739             memcpy(&ashort, buf, sizeof( ashort ));
740             ad_getattr(adp, &bshort);
741             if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
742                 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
743             } else {
744                 bshort &= ~ashort;
745             }
746             if ((ashort & htons(ATTRBIT_INVISIBLE)))
747                 change_parent_mdate = 1;
748             ad_setattr(adp, bshort);
749             buf += sizeof( ashort );
750             break;
751
752         case FILPBIT_CDATE :
753             change_mdate = 1;
754             memcpy(&aint, buf, sizeof(aint));
755             ad_setdate(adp, AD_DATE_CREATE, aint);
756             buf += sizeof( aint );
757             break;
758
759         case FILPBIT_MDATE :
760             memcpy(&newdate, buf, sizeof( newdate ));
761             buf += sizeof( newdate );
762             break;
763
764         case FILPBIT_BDATE :
765             change_mdate = 1;
766             memcpy(&aint, buf, sizeof(aint));
767             ad_setdate(adp, AD_DATE_BACKUP, aint);
768             buf += sizeof( aint );
769             break;
770
771         case FILPBIT_FINFO :
772             change_mdate = 1;
773
774             if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
775                     && ( 
776                      ((em = getextmap( path->m_name )) &&
777                       !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
778                       !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
779                      || ((em = getdefextmap()) &&
780                       !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
781                       !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
782             )) {
783                 memcpy(buf, ufinderi, 8 );
784             }
785
786             memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
787             buf += 32;
788             break;
789
790             /* Client needs to set the ProDOS file info for this file.
791                Use defined strings for the simple cases, and convert
792                all else into pXYY per Inside Appletalk.  Always set
793                the creator as "pdos". <shirsch@ibm.net> */
794         case FILPBIT_PDINFO :
795             achar = *buf;
796             buf += 2;
797             memcpy(&ashort, buf, sizeof( ashort ));
798             ashort = ntohs( ashort );
799             buf += 2;
800
801             switch ( (unsigned int) achar )
802             {
803             case 0x04 :
804                 fdType = ( u_char *) "TEXT";
805                 break;
806
807             case 0xff :
808                 fdType = ( u_char *) "PSYS";
809                 break;
810
811             case 0xb3 :
812                 fdType = ( u_char *) "PS16";
813                 break;
814
815             case 0x00 :
816                 fdType = ( u_char *) "BINA";
817                 break;
818
819             default :
820                 xyy[0] = ( u_char ) 'p';
821                 xyy[1] = achar;
822                 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
823                 xyy[3] = ( u_char ) ashort & 0xff;
824                 fdType = xyy;
825                 break;
826             }
827
828             memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
829             memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
830             break;
831
832
833         default :
834             err = AFPERR_BITMAP;
835             goto setfilparam_done;
836         }
837
838         bitmap = bitmap>>1;
839         bit++;
840     }
841
842 setfilparam_done:
843     if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
844        newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
845     }
846     if (newdate) {
847        if (isad)
848           ad_setdate(adp, AD_DATE_MODIFY, newdate);
849        ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
850        utime(upath, &ut);
851     }
852
853     if (isad) {
854         ad_flush( adp, ADFLAGS_HF );
855         ad_close( adp, ADFLAGS_HF );
856
857     }
858
859     if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
860         newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
861         bitmap = 1<<FILPBIT_MDATE;
862         setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
863     }
864
865 #ifdef DEBUG
866     LOG(log_info, logtype_afpd, "end setfilparams:");
867 #endif /* DEBUG */
868     return err;
869 }
870
871 /*
872  * renamefile and copyfile take the old and new unix pathnames
873  * and the new mac name.
874  * NOTE: if we have to copy a file instead of renaming it, locks
875  *       will break. Anyway it's an error because then we have 2 files.
876  *
877  * src         the source path 
878  * dst         the dest filename in current dir
879  * newname     the dest mac name
880  * adp         adouble struct of src file, if open, or & zeroed one
881  *
882  */
883 int renamefile(src, dst, newname, noadouble, adp )
884 char    *src, *dst, *newname;
885 const int         noadouble;
886 struct adouble    *adp;
887 {
888     char                adsrc[ MAXPATHLEN + 1];
889     int                 len, rc;
890
891     /*
892      * Note that this is only checking the existance of the data file,
893      * not the header file.  The thinking is that if the data file doesn't
894      * exist, but the header file does, the right thing to do is remove
895      * the data file silently.
896      */
897
898     /* existence check moved to afp_moveandrename */
899
900 #ifdef DEBUG
901     LOG(log_info, logtype_afpd, "begin renamefile:");
902 #endif /* DEBUG */
903
904     if ( rename( src, dst ) < 0 ) {
905         switch ( errno ) {
906         case ENOENT :
907             return( AFPERR_NOOBJ );
908         case EPERM:
909         case EACCES :
910             return( AFPERR_ACCESS );
911         case EROFS:
912             return AFPERR_VLOCK;
913         case EXDEV :                    /* Cross device move -- try copy */
914             if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
915                 deletefile( dst, 0 );
916                 return( rc );
917             }
918             return deletefile( src, 0);
919         default :
920             return( AFPERR_PARAM );
921         }
922     }
923
924     strcpy( adsrc, ad_path( src, 0 ));
925     rc = 0;
926 rename_retry:
927     if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
928         struct stat st;
929
930         switch ( errno ) {
931         case ENOENT :
932             /* check for a source appledouble header. if it exists, make
933              * a dest appledouble directory and do the rename again. */
934             if (rc || stat(adsrc, &st) ||
935                     (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
936                 return AFP_OK;
937             rc++;
938             ad_close(adp, ADFLAGS_HF);
939             goto rename_retry;
940         case EPERM:
941         case EACCES :
942             return( AFPERR_ACCESS );
943         case EROFS:
944             return AFPERR_VLOCK;
945         default :
946             return( AFPERR_PARAM );
947         }
948     }
949
950     if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
951         switch ( errno ) {
952         case ENOENT :
953             return( AFPERR_NOOBJ );
954         case EACCES :
955             return( AFPERR_ACCESS );
956         case EROFS:
957             return AFPERR_VLOCK;
958         default :
959             return( AFPERR_PARAM );
960         }
961     }
962
963     len = strlen( newname );
964     ad_setentrylen( adp, ADEID_NAME, len );
965     memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
966     ad_flush( adp, ADFLAGS_HF );
967     ad_close( adp, ADFLAGS_HF );
968
969 #ifdef DEBUG
970     LOG(log_info, logtype_afpd, "end renamefile:");
971 #endif /* DEBUG */
972
973     return( AFP_OK );
974 }
975
976 int copy_path_name(char *newname, char *ibuf)
977 {
978 char        type = *ibuf;
979 size_t      plen = 0;
980 u_int16_t   len16;
981 u_int32_t   hint;
982
983     if ( type != 2 || (afp_version >= 30 && type != 3) ) {
984         return -1;
985     }
986     ibuf++;
987     switch (type) {
988     case 2:
989         if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
990             strncpy( newname, ibuf, plen );
991             newname[ plen ] = '\0';
992             if (strlen(newname) != plen) {
993                 /* there's \0 in newname, e.g. it's a pathname not
994                  * only a filename. 
995                 */
996                 return -1;
997             }
998         }
999         break;
1000     case 3:
1001         memcpy(&hint, ibuf, sizeof(hint));
1002         ibuf += sizeof(hint);
1003            
1004         memcpy(&len16, ibuf, sizeof(len16));
1005         ibuf += sizeof(len16);
1006         plen = ntohs(len16);
1007         if (plen) {
1008             strncpy( newname, ibuf, plen );
1009             newname[ plen ] = '\0';
1010             if (strchr(newname,'/')) {
1011                 return -1;
1012             }
1013         }
1014         break;
1015     }
1016     return plen;
1017 }
1018
1019 /* -----------------------------------
1020 */
1021 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1022 AFPObj      *obj;
1023 char    *ibuf, *rbuf;
1024 int             ibuflen, *rbuflen;
1025 {
1026     struct vol  *vol;
1027     struct dir  *dir;
1028     char        *newname, *p, *upath;
1029     struct path *s_path;
1030     u_int32_t   sdid, ddid;
1031     int         err, retvalue = AFP_OK;
1032     u_int16_t   svid, dvid;
1033
1034 #ifdef DEBUG
1035     LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1036 #endif /* DEBUG */
1037
1038     *rbuflen = 0;
1039     ibuf += 2;
1040
1041     memcpy(&svid, ibuf, sizeof( svid ));
1042     ibuf += sizeof( svid );
1043     if (( vol = getvolbyvid( svid )) == NULL ) {
1044         return( AFPERR_PARAM );
1045     }
1046
1047     memcpy(&sdid, ibuf, sizeof( sdid ));
1048     ibuf += sizeof( sdid );
1049     if (( dir = dirlookup( vol, sdid )) == NULL ) {
1050         return( AFPERR_PARAM );
1051     }
1052
1053     memcpy(&dvid, ibuf, sizeof( dvid ));
1054     ibuf += sizeof( dvid );
1055     memcpy(&ddid, ibuf, sizeof( ddid ));
1056     ibuf += sizeof( ddid );
1057
1058     if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1059         return( AFPERR_NOOBJ );
1060     }
1061     if ( *s_path->m_name == '\0' ) {
1062         return( AFPERR_BADTYPE );
1063     }
1064
1065     /* don't allow copies when the file is open.
1066      * XXX: the spec only calls for read/deny write access.
1067      *      however, copyfile doesn't have any of that info,
1068      *      and locks need to stay coherent. as a result,
1069      *      we just balk if the file is opened already. */
1070
1071     newname = obj->newtmp;
1072     strcpy( newname, s_path->m_name );
1073
1074     if (of_findname(s_path))
1075         return AFPERR_DENYCONF;
1076
1077     p = ctoupath( vol, curdir, newname );
1078 #ifdef FORCE_UIDGID
1079     /* FIXME svid != dvid && dvid's user can't read svid */
1080 #endif
1081     if (( vol = getvolbyvid( dvid )) == NULL ) {
1082         return( AFPERR_PARAM );
1083     }
1084
1085     if (vol->v_flags & AFPVOL_RO)
1086         return AFPERR_VLOCK;
1087
1088     if (( dir = dirlookup( vol, ddid )) == NULL ) {
1089         return( AFPERR_PARAM );
1090     }
1091
1092     if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1093         return( AFPERR_NOOBJ );
1094     }
1095     if ( *s_path->m_name != '\0' ) {
1096         return( AFPERR_BADTYPE ); /* not a directory. AFPERR_PARAM? */
1097     }
1098
1099     /* one of the handful of places that knows about the path type */
1100     if (copy_path_name(newname, ibuf) < 0) {
1101         return( AFPERR_PARAM );
1102     }
1103
1104     upath = mtoupath(vol, newname);
1105     if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1106         return err;
1107     }
1108
1109 #ifdef DROPKLUDGE
1110     if (vol->v_flags & AFPVOL_DROPBOX) {
1111         retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1112     }
1113 #endif /* DROPKLUDGE */
1114
1115     setvoltime(obj, vol );
1116
1117 #ifdef DEBUG
1118     LOG(log_info, logtype_afpd, "end afp_copyfile:");
1119 #endif /* DEBUG */
1120
1121     return( retvalue );
1122 }
1123
1124
1125 static __inline__ int copy_all(const int dfd, const void *buf,
1126                                size_t buflen)
1127 {
1128     ssize_t cc;
1129
1130 #ifdef DEBUG
1131     LOG(log_info, logtype_afpd, "begin copy_all:");
1132 #endif /* DEBUG */
1133
1134     while (buflen > 0) {
1135         if ((cc = write(dfd, buf, buflen)) < 0) {
1136             switch (errno) {
1137             case EINTR:
1138                 continue;
1139             case EDQUOT:
1140             case EFBIG:
1141             case ENOSPC:
1142                 return AFPERR_DFULL;
1143             case EROFS:
1144                 return AFPERR_VLOCK;
1145             default:
1146                 return AFPERR_PARAM;
1147             }
1148         }
1149         buflen -= cc;
1150     }
1151
1152 #ifdef DEBUG
1153     LOG(log_info, logtype_afpd, "end copy_all:");
1154 #endif /* DEBUG */
1155
1156     return AFP_OK;
1157 }
1158
1159 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1160  * pass in vol and path */
1161 int copyfile(src, dst, newname, noadouble )
1162 char    *src, *dst, *newname;
1163 const int   noadouble;
1164 {
1165     struct adouble      ad;
1166 #ifdef SENDFILE_FLAVOR_LINUX
1167     struct stat         st;
1168 #endif
1169     char                filebuf[8192];
1170     int                 sfd, dfd, len, err = AFP_OK;
1171     ssize_t             cc;
1172     char                dpath[ MAXPATHLEN + 1];
1173     int                 admode;
1174 #ifdef DEBUG
1175     LOG(log_info, logtype_afpd, "begin copyfile:");
1176 #endif /* DEBUG */
1177
1178     strcpy(dpath, ad_path( dst, ADFLAGS_HF ));
1179     admode = ad_mode( dst, 0666 );
1180     if (newname) {
1181         if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1182             switch ( errno ) {
1183             case ENOENT :
1184                 break; /* just copy the data fork */
1185             case EACCES :
1186                 return( AFPERR_ACCESS );
1187             default :
1188                 return( AFPERR_PARAM );
1189             }
1190         } else {
1191             if (( dfd = open( dpath, O_WRONLY|O_CREAT,ad_hf_mode(admode))) < 0 ) {
1192                 close( sfd );
1193                 switch ( errno ) {
1194                 case ENOENT :
1195                     return( AFPERR_NOOBJ );
1196                 case EACCES :
1197                     return( AFPERR_ACCESS );
1198                 case EROFS:
1199                     return AFPERR_VLOCK;
1200                 default :
1201                     return( AFPERR_PARAM );
1202                 }
1203             }
1204
1205             /* copy the file */
1206 #ifdef SENDFILE_FLAVOR_LINUX
1207             if (fstat(sfd, &st) == 0) {
1208                 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1209                     switch (errno) {
1210                     case EDQUOT:
1211                     case EFBIG:
1212                     case ENOSPC:
1213                         err = AFPERR_DFULL;
1214                         break;
1215                     case EROFS:
1216                         err = AFPERR_VLOCK;
1217                         break;
1218                     default:
1219                         err = AFPERR_PARAM;
1220                     }
1221                 }
1222                 goto copyheader_done;
1223             }
1224 #endif /* SENDFILE_FLAVOR_LINUX */
1225             while (1) {
1226                 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1227                     if (errno == EINTR)
1228                         continue;
1229                     err = AFPERR_PARAM;
1230                     break;
1231                 }
1232
1233                 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1234                     break;
1235             }
1236
1237 copyheader_done:
1238             close(sfd);
1239             close(dfd);
1240             if (err < 0) {
1241                 unlink(dpath);
1242                 return err;
1243             }
1244         }
1245     }
1246
1247     /* data fork copying */
1248     if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1249         switch ( errno ) {
1250         case ENOENT :
1251             return( AFPERR_NOOBJ );
1252         case EACCES :
1253             return( AFPERR_ACCESS );
1254         default :
1255             return( AFPERR_PARAM );
1256         }
1257     }
1258
1259     if (( dfd = open( dst, O_WRONLY|O_CREAT, admode)) < 0 ) {
1260         close( sfd );
1261         switch ( errno ) {
1262         case ENOENT :
1263             return( AFPERR_NOOBJ );
1264         case EACCES :
1265             return( AFPERR_ACCESS );
1266         case EROFS:
1267             return AFPERR_VLOCK;
1268         default :
1269             return( AFPERR_PARAM );
1270         }
1271     }
1272
1273 #ifdef SENDFILE_FLAVOR_LINUX
1274     if (fstat(sfd, &st) == 0) {
1275         if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1276             switch (errno) {
1277             case EDQUOT:
1278             case EFBIG:
1279             case ENOSPC:
1280                 err = AFPERR_DFULL;
1281                 break;
1282             default:
1283                 err = AFPERR_PARAM;
1284             }
1285         }
1286         goto copydata_done;
1287     }
1288 #endif /* SENDFILE_FLAVOR_LINUX */
1289
1290     while (1) {
1291         if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1292             if (errno == EINTR)
1293                 continue;
1294
1295             err = AFPERR_PARAM;
1296             break;
1297         }
1298
1299         if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1300             break;
1301         }
1302     }
1303
1304 copydata_done:
1305     close(sfd);
1306     close(dfd);
1307     if (err < 0) {
1308         unlink(dpath);
1309         unlink(dst);
1310         return err;
1311     }
1312
1313     if (newname) {
1314         memset(&ad, 0, sizeof(ad));
1315         if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1316                       0666, &ad) < 0 ) {
1317             switch ( errno ) {
1318             case ENOENT :
1319                 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1320             case EACCES :
1321                 return( AFPERR_ACCESS );
1322             case EROFS:
1323                 return AFPERR_VLOCK;
1324             default :
1325                 return( AFPERR_PARAM );
1326             }
1327         }
1328
1329         len = strlen( newname );
1330         ad_setentrylen( &ad, ADEID_NAME, len );
1331         memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1332         ad_flush( &ad, ADFLAGS_HF );
1333         ad_close( &ad, ADFLAGS_HF );
1334     }
1335
1336 #ifdef DEBUG
1337     LOG(log_info, logtype_afpd, "end copyfile:");
1338 #endif /* DEBUG */
1339
1340     return( AFP_OK );
1341 }
1342
1343
1344 /* -----------------------------------
1345    checkAttrib:   1 check kFPDeleteInhibitBit 
1346    ie deletfile called by afp_delete
1347
1348    when deletefile is called we don't have lock on it, file is closed (for us)
1349    untrue if called by renamefile
1350 */
1351 int deletefile( file, checkAttrib )
1352 char            *file;
1353 int         checkAttrib;
1354 {
1355     struct adouble      ad;
1356     int                 adflags, err = AFP_OK;
1357     int                 locktype = ADLOCK_WR;
1358     int                 openmode = O_RDWR;
1359
1360 #ifdef DEBUG
1361     LOG(log_info, logtype_afpd, "begin deletefile:");
1362 #endif /* DEBUG */
1363
1364     while(1) {
1365         /*
1366          * If can't open read/write then try again read-only.  If it's open
1367          * read-only, we must do a read lock instead of a write lock.
1368          */
1369         /* try to open both at once */
1370         adflags = ADFLAGS_DF|ADFLAGS_HF;
1371         memset(&ad, 0, sizeof(ad));
1372         if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1373             switch (errno) {
1374             case ENOENT:
1375                 adflags = ADFLAGS_DF;
1376                 /* that failed. now try to open just the data fork */
1377                 memset(&ad, 0, sizeof(ad));
1378                 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1379                     switch (errno) {
1380                     case ENOENT:
1381                         return AFPERR_NOOBJ;
1382                     case EACCES:
1383                         if(openmode == O_RDWR) {
1384                             openmode = O_RDONLY;
1385                             locktype = ADLOCK_RD;
1386                             continue;
1387                         } else {
1388                             return AFPERR_ACCESS;
1389                         }
1390                     case EROFS:
1391                         return AFPERR_VLOCK;
1392                     default:
1393                         return AFPERR_PARAM;
1394                     }
1395                 }
1396                 break;
1397
1398             case EACCES:
1399                 if(openmode == O_RDWR) {
1400                     openmode = O_RDONLY;
1401                     locktype = ADLOCK_RD;
1402                     continue;
1403                 } else {
1404                     return AFPERR_ACCESS;
1405                 }
1406             case EROFS:
1407                 return AFPERR_VLOCK;
1408             default:
1409                 return( AFPERR_PARAM );
1410             }
1411         }
1412         break;  /* from the while */
1413     }
1414     /*
1415      * Does kFPDeleteInhibitBit (bit 8) set?
1416      */
1417     if (checkAttrib && (adflags & ADFLAGS_HF)) {
1418         u_int16_t   bshort;
1419
1420         ad_getattr(&ad, &bshort);
1421         if ((bshort & htons(ATTRBIT_NODELETE))) {
1422             ad_close( &ad, adflags );
1423             return(AFPERR_OLOCK);
1424         }
1425     }
1426     
1427     if ((adflags & ADFLAGS_HF) ) {
1428         /* FIXME we have a pb here because we want to know if a file is open 
1429          * there's a 'priority inversion' if you can't open the ressource fork RW
1430          * you can delete it if it's open because you can't get a write lock.
1431          * 
1432          * ADLOCK_FILELOCK means the whole ressource fork, not only after the 
1433          * metadatas
1434          *
1435          * FIXME it doesn't for RFORK open read only and fork open without deny mode
1436          */
1437         if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) {
1438             ad_close( &ad, adflags );
1439             return( AFPERR_BUSY );
1440         }
1441     }
1442
1443     if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1444         err = AFPERR_BUSY;
1445         goto delete_unlock;
1446     }
1447
1448     if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1449         switch ( errno ) {
1450         case EPERM:
1451         case EACCES :
1452             err = AFPERR_ACCESS;
1453             goto delete_unlock;
1454         case EROFS:
1455             err = AFPERR_VLOCK;
1456             goto delete_unlock;
1457         case ENOENT :
1458             break;
1459         default :
1460             err = AFPERR_PARAM;
1461             goto delete_unlock;
1462         }
1463     }
1464
1465     if ( unlink( file ) < 0 ) {
1466         switch ( errno ) {
1467         case EPERM:
1468         case EACCES :
1469             err = AFPERR_ACCESS;
1470             break;
1471         case EROFS:
1472             err = AFPERR_VLOCK;
1473             break;
1474         case ENOENT :
1475             break;
1476         default :
1477             err = AFPERR_PARAM;
1478             break;
1479         }
1480     }
1481
1482 delete_unlock:
1483     if (adflags & ADFLAGS_HF)
1484         ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0);
1485     ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1486     ad_close( &ad, adflags );
1487
1488 #ifdef DEBUG
1489     LOG(log_info, logtype_afpd, "end deletefile:");
1490 #endif /* DEBUG */
1491
1492     return err;
1493 }
1494
1495 /* ------------------------------------ */
1496 #ifdef CNID_DB
1497 /* return a file id */
1498 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1499 AFPObj      *obj;
1500 char    *ibuf, *rbuf;
1501 int             ibuflen, *rbuflen;
1502 {
1503     struct stat         *st;
1504 #if AD_VERSION > AD_VERSION1
1505     struct adouble      ad;
1506 #endif
1507     struct vol          *vol;
1508     struct dir          *dir;
1509     char                *upath;
1510     int                 len;
1511     cnid_t              did, id;
1512     u_short             vid;
1513     struct path         *s_path;
1514
1515 #ifdef DEBUG
1516     LOG(log_info, logtype_afpd, "begin afp_createid:");
1517 #endif /* DEBUG */
1518
1519     *rbuflen = 0;
1520     ibuf += 2;
1521
1522     memcpy(&vid, ibuf, sizeof(vid));
1523     ibuf += sizeof(vid);
1524
1525     if (( vol = getvolbyvid( vid )) == NULL ) {
1526         return( AFPERR_PARAM);
1527     }
1528
1529     if (vol->v_flags & AFPVOL_RO)
1530         return AFPERR_VLOCK;
1531
1532     memcpy(&did, ibuf, sizeof( did ));
1533     ibuf += sizeof(did);
1534
1535     if (( dir = dirlookup( vol, did )) == NULL ) {
1536         return( AFPERR_PARAM );
1537     }
1538
1539     if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1540         return( AFPERR_PARAM );
1541     }
1542
1543     if ( *s_path->m_name == '\0' ) {
1544         return( AFPERR_BADTYPE );
1545     }
1546
1547     upath = s_path->u_name;
1548     switch (s_path->st_errno) {
1549         case 0:
1550              break; /* success */
1551         case EPERM:
1552         case EACCES:
1553             return AFPERR_ACCESS;
1554         case ENOENT:
1555             return AFPERR_NOOBJ;
1556         default:
1557             return AFPERR_PARAM;
1558     }
1559     st = &s_path->st;
1560     if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1561         memcpy(rbuf, &id, sizeof(id));
1562         *rbuflen = sizeof(id);
1563         return AFPERR_EXISTID;
1564     }
1565
1566 #if AD_VERSION > AD_VERSION1
1567     memset(&ad, 0, sizeof(ad));
1568     if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1569         memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1570         ad_close(&ad, ADFLAGS_HF);
1571     }
1572 #endif /* AD_VERSION > AD_VERSION1 */
1573
1574     if ((id = cnid_add(vol->v_db, st, did, upath, len, id)) != CNID_INVALID) {
1575         memcpy(rbuf, &id, sizeof(id));
1576         *rbuflen = sizeof(id);
1577         return AFP_OK;
1578     }
1579
1580 #ifdef DEBUG
1581     LOG(log_info, logtype_afpd, "ending afp_createid...:");
1582 #endif /* DEBUG */
1583
1584     switch (errno) {
1585     case EROFS:
1586         return AFPERR_VLOCK;
1587         break;
1588     case EPERM:
1589     case EACCES:
1590         return AFPERR_ACCESS;
1591         break;
1592     default:
1593         LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1594         return AFPERR_PARAM;
1595     }
1596 }
1597
1598 /* ------------------------------
1599    resolve a file id */
1600 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1601 AFPObj      *obj;
1602 char    *ibuf, *rbuf;
1603 int             ibuflen, *rbuflen;
1604 {
1605     struct vol          *vol;
1606     struct dir          *dir;
1607     char                *upath;
1608     struct path         path;
1609     int                 err, buflen;
1610     cnid_t              id;
1611     u_int16_t           vid, bitmap;
1612
1613     static char buffer[12 + MAXPATHLEN + 1];
1614     int len = 12 + MAXPATHLEN + 1;
1615
1616 #ifdef DEBUG
1617     LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1618 #endif /* DEBUG */
1619
1620     *rbuflen = 0;
1621     ibuf += 2;
1622
1623     memcpy(&vid, ibuf, sizeof(vid));
1624     ibuf += sizeof(vid);
1625
1626     if (( vol = getvolbyvid( vid )) == NULL ) {
1627         return( AFPERR_PARAM);
1628     }
1629
1630     memcpy(&id, ibuf, sizeof( id ));
1631     ibuf += sizeof(id);
1632
1633     if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1634         return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1635     }
1636
1637     if (( dir = dirlookup( vol, id )) == NULL ) {
1638         return AFPERR_NOID; /* idem AFPERR_PARAM */
1639     }
1640     path.u_name = upath;
1641     if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1642         switch (errno) {
1643         case EACCES:
1644         case EPERM:
1645             return AFPERR_ACCESS;
1646         case ENOENT:
1647             return AFPERR_NOID;
1648         default:
1649             return AFPERR_PARAM;
1650         }
1651     }
1652     /* directories are bad */
1653     if (S_ISDIR(path.st.st_mode))
1654         return AFPERR_BADTYPE;
1655
1656     memcpy(&bitmap, ibuf, sizeof(bitmap));
1657     bitmap = ntohs( bitmap );
1658     path.m_name = utompath(vol, upath);
1659     if ((err = getfilparams(vol, bitmap, &path , curdir, 
1660                             rbuf + sizeof(bitmap), &buflen)) != AFP_OK) {
1661         return err;
1662     }
1663     *rbuflen = buflen + sizeof(bitmap);
1664     memcpy(rbuf, ibuf, sizeof(bitmap));
1665
1666 #ifdef DEBUG
1667     LOG(log_info, logtype_afpd, "end afp_resolveid:");
1668 #endif /* DEBUG */
1669
1670     return AFP_OK;
1671 }
1672
1673 /* ------------------------------ */
1674 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1675 AFPObj      *obj;
1676 char    *ibuf, *rbuf;
1677 int             ibuflen, *rbuflen;
1678 {
1679     struct stat         st;
1680     struct vol          *vol;
1681     struct dir          *dir;
1682     char                *upath;
1683     int                 err;
1684     cnid_t              id;
1685     cnid_t              fileid;
1686     u_short             vid;
1687     static char buffer[12 + MAXPATHLEN + 1];
1688     int len = 12 + MAXPATHLEN + 1;
1689
1690 #ifdef DEBUG
1691     LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1692 #endif /* DEBUG */
1693
1694     *rbuflen = 0;
1695     ibuf += 2;
1696
1697     memcpy(&vid, ibuf, sizeof(vid));
1698     ibuf += sizeof(vid);
1699
1700     if (( vol = getvolbyvid( vid )) == NULL ) {
1701         return( AFPERR_PARAM);
1702     }
1703
1704     if (vol->v_flags & AFPVOL_RO)
1705         return AFPERR_VLOCK;
1706
1707     memcpy(&id, ibuf, sizeof( id ));
1708     ibuf += sizeof(id);
1709     fileid = id;
1710
1711     if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1712         return AFPERR_NOID;
1713     }
1714
1715     if (( dir = dirlookup( vol, id )) == NULL ) {
1716         return( AFPERR_PARAM );
1717     }
1718
1719     err = AFP_OK;
1720     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1721         switch (errno) {
1722         case EACCES:
1723         case EPERM:
1724             return AFPERR_ACCESS;
1725         case ENOENT:
1726             /* still try to delete the id */
1727             err = AFPERR_NOOBJ;
1728             break;
1729         default:
1730             return AFPERR_PARAM;
1731         }
1732     }
1733
1734     /* directories are bad */
1735     if (S_ISDIR(st.st_mode))
1736         return AFPERR_BADTYPE;
1737
1738     if (cnid_delete(vol->v_db, fileid)) {
1739         switch (errno) {
1740         case EROFS:
1741             return AFPERR_VLOCK;
1742         case EPERM:
1743         case EACCES:
1744             return AFPERR_ACCESS;
1745         default:
1746             return AFPERR_PARAM;
1747         }
1748     }
1749
1750 #ifdef DEBUG
1751     LOG(log_info, logtype_afpd, "end afp_deleteid:");
1752 #endif /* DEBUG */
1753
1754     return err;
1755 }
1756 #endif /* CNID_DB */
1757
1758 #define APPLETEMP ".AppleTempXXXXXX"
1759
1760 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1761 AFPObj      *obj;
1762 char    *ibuf, *rbuf;
1763 int             ibuflen, *rbuflen;
1764 {
1765     struct stat         srcst, destst;
1766     struct vol          *vol;
1767     struct dir          *dir, *sdir;
1768     char                *spath, temp[17], *p;
1769     char                *supath, *upath;
1770     struct path         *path;
1771     int                 err;
1772     struct adouble      ads;
1773     struct adouble      add;
1774     struct adouble      *adsp;
1775     struct adouble      *addp;
1776     struct ofork        *s_of;
1777     struct ofork        *d_of;
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 (( vol = getvolbyvid( vid )) == NULL ) {
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 ((dir = dirlookup( vol, sid )) == NULL ) {
1810         return( AFPERR_PARAM );
1811     }
1812
1813     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1814         return( AFPERR_PARAM );
1815     }
1816
1817     if ( *path->m_name == '\0' ) {
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
1848     /* look for the source cnid. if it doesn't exist, don't worry about
1849      * it. */
1850 #ifdef CNID_DB
1851     sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1852                       slen = strlen(supath));
1853 #endif /* CNID_DB */
1854
1855     if (( dir = dirlookup( vol, did )) == NULL ) {
1856         return( AFPERR_PARAM );
1857     }
1858
1859     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1860         return( AFPERR_PARAM );
1861     }
1862
1863     if ( *path->m_name == '\0' ) {
1864         return( AFPERR_BADTYPE );
1865     }
1866
1867     /* FPExchangeFiles is the only call that can return the SameObj
1868      * error */
1869     if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1870         return AFPERR_SAMEOBJ;
1871     memcpy(&srcst, &path->st, sizeof(struct stat));
1872
1873     switch (errno) {
1874         case 0:
1875              break;
1876         case ENOENT:
1877             return AFPERR_NOID;
1878         case EPERM:
1879         case EACCES:
1880             return AFPERR_ACCESS;
1881         default:
1882             return AFPERR_PARAM;
1883     }
1884     memset(&add, 0, sizeof(add));
1885     addp = &add;
1886     if ((d_of = of_findname( path))) {
1887             /* reuse struct adouble so it won't break locks */
1888             addp = d_of->of_ad;
1889     }
1890     memcpy(&destst, &path->st, sizeof(struct stat));
1891
1892     /* they are not on the same device and at least one is open
1893     */
1894     if ((d_of || s_of)  && srcst.st_dev != destst.st_dev)
1895         return AFPERR_MISC;
1896     
1897     upath = path->u_name;
1898 #ifdef CNID_DB
1899     /* look for destination id. */
1900     did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1901                       dlen = strlen(upath));
1902 #endif /* CNID_DB */
1903
1904     /* construct a temp name.
1905      * NOTE: the temp file will be in the dest file's directory. it
1906      * will also be inaccessible from AFP. */
1907     memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1908     if (!mktemp(temp))
1909         return AFPERR_MISC;
1910
1911     /* now, quickly rename the file. we error if we can't. */
1912     if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1913         goto err_exchangefile;
1914     of_rename(vol, s_of, sdir, spath, curdir, temp);
1915
1916     /* rename destination to source */
1917     if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1918         goto err_src_to_tmp;
1919     of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1920
1921     /* rename temp to destination */
1922     if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1923         goto err_dest_to_src;
1924     of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1925
1926 #ifdef CNID_DB
1927     /* id's need switching. src -> dest and dest -> src. */
1928     if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1929                             upath, dlen) < 0)) {
1930         switch (errno) {
1931         case EPERM:
1932         case EACCES:
1933             err = AFPERR_ACCESS;
1934             break;
1935         default:
1936             err = AFPERR_PARAM;
1937         }
1938         goto err_temp_to_dest;
1939     }
1940
1941     if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1942                             supath, slen) < 0)) {
1943         switch (errno) {
1944         case EPERM:
1945         case EACCES:
1946             err = AFPERR_ACCESS;
1947             break;
1948         default:
1949             err = AFPERR_PARAM;
1950         }
1951
1952         if (sid)
1953             cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
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 }