]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/file.c
bugfix: close the right fork in renamefile, copy and paste error...
[netatalk.git] / etc / afpd / file.c
1 /*
2  * $Id: file.c,v 1.83 2003-02-04 18:26:20 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_get_HF_flags( adp ) & 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  *
869  * src         the source path 
870  * dst         the dest filename in current dir
871  * newname     the dest mac name
872  * adp         adouble struct of src file, if open, or & zeroed one
873  *
874  */
875 int renamefile(src, dst, newname, noadouble, adp )
876 char    *src, *dst, *newname;
877 const int         noadouble;
878 struct adouble    *adp;
879 {
880     char        adsrc[ MAXPATHLEN + 1];
881     int         len;
882     int         rc;
883
884 #ifdef DEBUG
885     LOG(log_info, logtype_afpd, "begin renamefile:");
886 #endif /* DEBUG */
887
888     if ( unix_rename( src, dst ) < 0 ) {
889         switch ( errno ) {
890         case ENOENT :
891             return( AFPERR_NOOBJ );
892         case EPERM:
893         case EACCES :
894             return( AFPERR_ACCESS );
895         case EROFS:
896             return AFPERR_VLOCK;
897         case EXDEV :                    /* Cross device move -- try copy */
898            /* NOTE: with open file it's an error because after the copy we will 
899             * get two files, it's fixable for our process (eg reopen the new file, get the
900             * locks, and so on. But it doesn't solve the case with a second process
901             */
902             if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
903                 /* FIXME  warning in syslog so admin'd know there's a conflict ?*/
904                 return AFPERR_OLOCK; /* little lie */
905             }
906             if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
907                 deletefile( dst, 0 );
908                 return( rc );
909             }
910             return deletefile( src, 0);
911         default :
912             return( AFPERR_PARAM );
913         }
914     }
915
916     strcpy( adsrc, ad_path( src, 0 ));
917
918     if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
919         struct stat st;
920         int err;
921         
922         err = errno;        
923         if (errno == ENOENT) {
924             struct adouble    ad;
925
926             if (stat(adsrc, &st)) /* source has no ressource fork, */
927                 return AFP_OK;
928             
929             /* We are here  because :
930              * -there's no dest folder. 
931              * -there's no .AppleDouble in the dest folder.
932              * if we use the struct adouble passed in parameter it will not
933              * create .AppleDouble if the file is already opened, so we
934              * use a diff one, it's not a pb,ie it's not the same file, yet.
935              */
936             memset(&ad, 0, sizeof(ad));
937             if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
938                 ad_close(&ad, ADFLAGS_HF);
939                 if (!unix_rename( adsrc, ad_path( dst, 0 )) ) 
940                    err = 0;
941                 else 
942                    err = errno;
943             }
944             else { /* it's something else, bail out */
945                 err = errno;
946             }
947         }
948         /* try to undo the data fork rename,
949          * we know we are on the same device 
950         */
951         if (err) {
952             unix_rename( dst, src ); 
953             /* return the first error */
954             switch ( err) {
955             case ENOENT :
956                 return AFPERR_NOOBJ;
957             case EPERM:
958             case EACCES :
959                 return AFPERR_ACCESS ;
960             case EROFS:
961                 return AFPERR_VLOCK;
962             default :
963                 return AFPERR_PARAM ;
964             }
965         }
966     }
967
968     /* don't care if we can't open the newly renamed ressource fork
969      */
970     if ( !ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
971         len = strlen( newname );
972         ad_setentrylen( adp, ADEID_NAME, len );
973         memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
974         ad_flush( adp, ADFLAGS_HF );
975         ad_close( adp, ADFLAGS_HF );
976     }
977 #ifdef DEBUG
978     LOG(log_info, logtype_afpd, "end renamefile:");
979 #endif /* DEBUG */
980
981     return( AFP_OK );
982 }
983
984 int copy_path_name(char *newname, char *ibuf)
985 {
986 char        type = *ibuf;
987 size_t      plen = 0;
988 u_int16_t   len16;
989 u_int32_t   hint;
990
991     if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
992         return -1;
993     }
994     ibuf++;
995     switch (type) {
996     case 2:
997         if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
998             strncpy( newname, ibuf, plen );
999             newname[ plen ] = '\0';
1000             if (strlen(newname) != plen) {
1001                 /* there's \0 in newname, e.g. it's a pathname not
1002                  * only a filename. 
1003                 */
1004                 return -1;
1005             }
1006         }
1007         break;
1008     case 3:
1009         memcpy(&hint, ibuf, sizeof(hint));
1010         ibuf += sizeof(hint);
1011            
1012         memcpy(&len16, ibuf, sizeof(len16));
1013         ibuf += sizeof(len16);
1014         plen = ntohs(len16);
1015         if (plen) {
1016             strncpy( newname, ibuf, plen );
1017             newname[ plen ] = '\0';
1018             if (strlen(newname) != plen) {
1019                 return -1;
1020             }
1021         }
1022         break;
1023     }
1024     return plen;
1025 }
1026
1027 /* -----------------------------------
1028 */
1029 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1030 AFPObj      *obj;
1031 char    *ibuf, *rbuf;
1032 int             ibuflen, *rbuflen;
1033 {
1034     struct vol  *vol;
1035     struct dir  *dir;
1036     char        *newname, *p, *upath;
1037     struct path *s_path;
1038     u_int32_t   sdid, ddid;
1039     int         err, retvalue = AFP_OK;
1040     u_int16_t   svid, dvid;
1041
1042 #ifdef DEBUG
1043     LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1044 #endif /* DEBUG */
1045
1046     *rbuflen = 0;
1047     ibuf += 2;
1048
1049     memcpy(&svid, ibuf, sizeof( svid ));
1050     ibuf += sizeof( svid );
1051     if (NULL == ( vol = getvolbyvid( svid )) ) {
1052         return( AFPERR_PARAM );
1053     }
1054
1055     memcpy(&sdid, ibuf, sizeof( sdid ));
1056     ibuf += sizeof( sdid );
1057     if (NULL == ( dir = dirlookup( vol, sdid )) ) {
1058         return afp_errno;
1059     }
1060
1061     memcpy(&dvid, ibuf, sizeof( dvid ));
1062     ibuf += sizeof( dvid );
1063     memcpy(&ddid, ibuf, sizeof( ddid ));
1064     ibuf += sizeof( ddid );
1065
1066     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1067         return afp_errno;
1068     }
1069     if ( path_isadir(s_path) ) {
1070         return( AFPERR_BADTYPE );
1071     }
1072
1073     /* don't allow copies when the file is open.
1074      * XXX: the spec only calls for read/deny write access.
1075      *      however, copyfile doesn't have any of that info,
1076      *      and locks need to stay coherent. as a result,
1077      *      we just balk if the file is opened already. */
1078
1079     newname = obj->newtmp;
1080     strcpy( newname, s_path->m_name );
1081
1082     if (of_findname(s_path))
1083         return AFPERR_DENYCONF;
1084
1085     p = ctoupath( vol, curdir, newname );
1086     if (!p) {
1087         return AFPERR_PARAM;
1088     
1089     }
1090 #ifdef FORCE_UIDGID
1091     /* FIXME svid != dvid && dvid's user can't read svid */
1092 #endif
1093     if (NULL == ( vol = getvolbyvid( dvid )) ) {
1094         return( AFPERR_PARAM );
1095     }
1096
1097     if (vol->v_flags & AFPVOL_RO)
1098         return AFPERR_VLOCK;
1099
1100     if (NULL == ( dir = dirlookup( vol, ddid )) ) {
1101         return afp_errno;
1102     }
1103
1104     if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1105         return afp_errno;
1106     }
1107     if ( *s_path->m_name != '\0' ) {
1108         return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1109     }
1110
1111     /* one of the handful of places that knows about the path type */
1112     if (copy_path_name(newname, ibuf) < 0) {
1113         return( AFPERR_PARAM );
1114     }
1115
1116     upath = mtoupath(vol, newname);
1117     if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1118         return err;
1119     }
1120     curdir->offcnt++;
1121
1122 #ifdef DROPKLUDGE
1123     if (vol->v_flags & AFPVOL_DROPBOX) {
1124         retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1125     }
1126 #endif /* DROPKLUDGE */
1127
1128     setvoltime(obj, vol );
1129
1130 #ifdef DEBUG
1131     LOG(log_info, logtype_afpd, "end afp_copyfile:");
1132 #endif /* DEBUG */
1133
1134     return( retvalue );
1135 }
1136
1137
1138 static __inline__ int copy_all(const int dfd, const void *buf,
1139                                size_t buflen)
1140 {
1141     ssize_t cc;
1142
1143 #ifdef DEBUG
1144     LOG(log_info, logtype_afpd, "begin copy_all:");
1145 #endif /* DEBUG */
1146
1147     while (buflen > 0) {
1148         if ((cc = write(dfd, buf, buflen)) < 0) {
1149             switch (errno) {
1150             case EINTR:
1151                 continue;
1152             case EDQUOT:
1153             case EFBIG:
1154             case ENOSPC:
1155                 return AFPERR_DFULL;
1156             case EROFS:
1157                 return AFPERR_VLOCK;
1158             default:
1159                 return AFPERR_PARAM;
1160             }
1161         }
1162         buflen -= cc;
1163     }
1164
1165 #ifdef DEBUG
1166     LOG(log_info, logtype_afpd, "end copy_all:");
1167 #endif /* DEBUG */
1168
1169     return AFP_OK;
1170 }
1171
1172 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1173  * pass in vol and path */
1174 int copyfile(src, dst, newname, noadouble )
1175 char    *src, *dst, *newname;
1176 const int   noadouble;
1177 {
1178     struct adouble      ad;
1179 #ifdef SENDFILE_FLAVOR_LINUX
1180     struct stat         st;
1181 #endif
1182     char                filebuf[8192];
1183     int                 sfd, dfd, len, err = AFP_OK;
1184     ssize_t             cc;
1185     char                dpath[ MAXPATHLEN + 1];
1186     int                 admode;
1187 #ifdef DEBUG
1188     LOG(log_info, logtype_afpd, "begin copyfile:");
1189 #endif /* DEBUG */
1190
1191     strcpy(dpath, ad_path( dst, ADFLAGS_HF ));
1192     admode = ad_mode( dst, 0666 );
1193     if (newname) {
1194         if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1195             switch ( errno ) {
1196             case ENOENT :
1197                 break; /* just copy the data fork */
1198             case EACCES :
1199                 return( AFPERR_ACCESS );
1200             default :
1201                 return( AFPERR_PARAM );
1202             }
1203         } else {
1204             if (( dfd = open( dpath, O_WRONLY|O_CREAT,ad_hf_mode(admode))) < 0 ) {
1205                 close( sfd );
1206                 switch ( errno ) {
1207                 case ENOENT :
1208                     return( AFPERR_NOOBJ );
1209                 case EACCES :
1210                     return( AFPERR_ACCESS );
1211                 case EROFS:
1212                     return AFPERR_VLOCK;
1213                 default :
1214                     return( AFPERR_PARAM );
1215                 }
1216             }
1217
1218             /* copy the file */
1219 #ifdef SENDFILE_FLAVOR_LINUX
1220             if (fstat(sfd, &st) == 0) {
1221                 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1222                     switch (errno) {
1223                     case EDQUOT:
1224                     case EFBIG:
1225                     case ENOSPC:
1226                         err = AFPERR_DFULL;
1227                         break;
1228                     case EROFS:
1229                         err = AFPERR_VLOCK;
1230                         break;
1231                     default:
1232                         err = AFPERR_PARAM;
1233                     }
1234                 }
1235                 goto copyheader_done;
1236             }
1237 #endif /* SENDFILE_FLAVOR_LINUX */
1238             while (1) {
1239                 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1240                     if (errno == EINTR)
1241                         continue;
1242                     err = AFPERR_PARAM;
1243                     break;
1244                 }
1245
1246                 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1247                     break;
1248             }
1249
1250 copyheader_done:
1251             close(sfd);
1252             close(dfd);
1253             if (err < 0) {
1254                 unlink(dpath);
1255                 return err;
1256             }
1257         }
1258     }
1259
1260     /* data fork copying */
1261     if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1262         switch ( errno ) {
1263         case ENOENT :
1264             return( AFPERR_NOOBJ );
1265         case EACCES :
1266             return( AFPERR_ACCESS );
1267         default :
1268             return( AFPERR_PARAM );
1269         }
1270     }
1271
1272     if (( dfd = open( dst, O_WRONLY|O_CREAT, admode)) < 0 ) {
1273         close( sfd );
1274         switch ( errno ) {
1275         case ENOENT :
1276             return( AFPERR_NOOBJ );
1277         case EACCES :
1278             return( AFPERR_ACCESS );
1279         case EROFS:
1280             return AFPERR_VLOCK;
1281         default :
1282             return( AFPERR_PARAM );
1283         }
1284     }
1285
1286 #ifdef SENDFILE_FLAVOR_LINUX
1287     if (fstat(sfd, &st) == 0) {
1288         if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1289             switch (errno) {
1290             case EDQUOT:
1291             case EFBIG:
1292             case ENOSPC:
1293                 err = AFPERR_DFULL;
1294                 break;
1295             default:
1296                 err = AFPERR_PARAM;
1297             }
1298         }
1299         goto copydata_done;
1300     }
1301 #endif /* SENDFILE_FLAVOR_LINUX */
1302
1303     while (1) {
1304         if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1305             if (errno == EINTR)
1306                 continue;
1307
1308             err = AFPERR_PARAM;
1309             break;
1310         }
1311
1312         if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1313             break;
1314         }
1315     }
1316
1317 copydata_done:
1318     close(sfd);
1319     close(dfd);
1320     if (err < 0) {
1321         unlink(dpath);
1322         unlink(dst);
1323         return err;
1324     }
1325
1326     if (newname) {
1327         memset(&ad, 0, sizeof(ad));
1328         if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1329                       0666, &ad) < 0 ) {
1330             switch ( errno ) {
1331             case ENOENT :
1332                 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1333             case EACCES :
1334                 return( AFPERR_ACCESS );
1335             case EROFS:
1336                 return AFPERR_VLOCK;
1337             default :
1338                 return( AFPERR_PARAM );
1339             }
1340         }
1341
1342         len = strlen( newname );
1343         ad_setentrylen( &ad, ADEID_NAME, len );
1344         memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1345         ad_flush( &ad, ADFLAGS_HF );
1346         ad_close( &ad, ADFLAGS_HF );
1347     }
1348
1349 #ifdef DEBUG
1350     LOG(log_info, logtype_afpd, "end copyfile:");
1351 #endif /* DEBUG */
1352
1353     return( AFP_OK );
1354 }
1355
1356
1357 /* -----------------------------------
1358    checkAttrib:   1 check kFPDeleteInhibitBit 
1359    ie deletfile called by afp_delete
1360
1361    when deletefile is called we don't have lock on it, file is closed (for us)
1362    untrue if called by renamefile
1363    
1364    ad_open always try to open file RDWR first and ad_lock takes care of
1365    WRITE lock on read only file.
1366 */
1367 int deletefile( file, checkAttrib )
1368 char            *file;
1369 int         checkAttrib;
1370 {
1371     struct adouble      ad;
1372     int                 adflags, err = AFP_OK;
1373
1374 #ifdef DEBUG
1375     LOG(log_info, logtype_afpd, "begin deletefile:");
1376 #endif /* DEBUG */
1377
1378     /* try to open both forks at once */
1379     adflags = ADFLAGS_DF|ADFLAGS_HF;
1380     while(1) {
1381         memset(&ad, 0, sizeof(ad));
1382         if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1383             switch (errno) {
1384             case ENOENT:
1385                 if (adflags == ADFLAGS_DF)
1386                     return AFPERR_NOOBJ;
1387                    
1388                 /* that failed. now try to open just the data fork */
1389                 adflags = ADFLAGS_DF;
1390                 continue;
1391
1392             case EACCES:
1393                 return AFPERR_ACCESS;
1394             case EROFS:
1395                 return AFPERR_VLOCK;
1396             default:
1397                 return( AFPERR_PARAM );
1398             }
1399         }
1400         break;  /* from the while */
1401     }
1402     /*
1403      * Does kFPDeleteInhibitBit (bit 8) set?
1404      */
1405     if (checkAttrib && (adflags & ADFLAGS_HF)) {
1406         u_int16_t   bshort;
1407
1408         ad_getattr(&ad, &bshort);
1409         if ((bshort & htons(ATTRBIT_NODELETE))) {
1410             ad_close( &ad, adflags );
1411             return(AFPERR_OLOCK);
1412         }
1413     }
1414     
1415     if ((adflags & ADFLAGS_HF) ) {
1416         /* FIXME we have a pb here because we want to know if a file is open 
1417          * there's a 'priority inversion' if you can't open the ressource fork RW
1418          * you can delete it if it's open because you can't get a write lock.
1419          * 
1420          * ADLOCK_FILELOCK means the whole ressource fork, not only after the 
1421          * metadatas
1422          *
1423          * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1424          */
1425         if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1426             ad_close( &ad, adflags );
1427             return( AFPERR_BUSY );
1428         }
1429     }
1430
1431     if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1432         err = AFPERR_BUSY;
1433     }
1434     else if ( 0 == (err = netatalk_unlink( ad_path( file, ADFLAGS_HF )) )) {
1435         err = netatalk_unlink( file );
1436     }
1437     ad_close( &ad, adflags );  /* ad_close removes locks if any */
1438
1439 #ifdef DEBUG
1440     LOG(log_info, logtype_afpd, "end deletefile:");
1441 #endif /* DEBUG */
1442
1443     return err;
1444 }
1445
1446 /* ------------------------------------ */
1447 #ifdef CNID_DB
1448 /* return a file id */
1449 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1450 AFPObj      *obj;
1451 char    *ibuf, *rbuf;
1452 int             ibuflen, *rbuflen;
1453 {
1454     struct stat         *st;
1455 #if AD_VERSION > AD_VERSION1
1456     struct adouble      ad;
1457 #endif
1458     struct vol          *vol;
1459     struct dir          *dir;
1460     char                *upath;
1461     int                 len;
1462     cnid_t              did, id;
1463     u_short             vid;
1464     struct path         *s_path;
1465
1466 #ifdef DEBUG
1467     LOG(log_info, logtype_afpd, "begin afp_createid:");
1468 #endif /* DEBUG */
1469
1470     *rbuflen = 0;
1471     ibuf += 2;
1472
1473     memcpy(&vid, ibuf, sizeof(vid));
1474     ibuf += sizeof(vid);
1475
1476     if (NULL == ( vol = getvolbyvid( vid )) ) {
1477         return( AFPERR_PARAM);
1478     }
1479
1480     if (vol->v_flags & AFPVOL_RO)
1481         return AFPERR_VLOCK;
1482
1483     memcpy(&did, ibuf, sizeof( did ));
1484     ibuf += sizeof(did);
1485
1486     if (NULL == ( dir = dirlookup( vol, did )) ) {
1487         return( AFPERR_PARAM );
1488     }
1489
1490     if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1491         return afp_errno; /* was AFPERR_PARAM */
1492     }
1493
1494     if ( path_isadir(s_path) ) {
1495         return( AFPERR_BADTYPE );
1496     }
1497
1498     upath = s_path->u_name;
1499     switch (s_path->st_errno) {
1500         case 0:
1501              break; /* success */
1502         case EPERM:
1503         case EACCES:
1504             return AFPERR_ACCESS;
1505         case ENOENT:
1506             return AFPERR_NOOBJ;
1507         default:
1508             return AFPERR_PARAM;
1509     }
1510     st = &s_path->st;
1511     if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1512         memcpy(rbuf, &id, sizeof(id));
1513         *rbuflen = sizeof(id);
1514         return AFPERR_EXISTID;
1515     }
1516
1517 #if AD_VERSION > AD_VERSION1
1518     memset(&ad, 0, sizeof(ad));
1519     if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1520         memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1521         ad_close(&ad, ADFLAGS_HF);
1522     }
1523 #endif /* AD_VERSION > AD_VERSION1 */
1524
1525     if ((id = cnid_add(vol->v_db, st, did, upath, len, id)) != CNID_INVALID) {
1526         memcpy(rbuf, &id, sizeof(id));
1527         *rbuflen = sizeof(id);
1528         return AFP_OK;
1529     }
1530
1531 #ifdef DEBUG
1532     LOG(log_info, logtype_afpd, "ending afp_createid...:");
1533 #endif /* DEBUG */
1534
1535     switch (errno) {
1536     case EROFS:
1537         return AFPERR_VLOCK;
1538         break;
1539     case EPERM:
1540     case EACCES:
1541         return AFPERR_ACCESS;
1542         break;
1543     default:
1544         LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1545         return AFPERR_PARAM;
1546     }
1547 }
1548
1549 /* ------------------------------
1550    resolve a file id */
1551 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1552 AFPObj      *obj;
1553 char    *ibuf, *rbuf;
1554 int             ibuflen, *rbuflen;
1555 {
1556     struct vol          *vol;
1557     struct dir          *dir;
1558     char                *upath;
1559     struct path         path;
1560     int                 err, buflen;
1561     cnid_t              id;
1562     u_int16_t           vid, bitmap;
1563
1564     static char buffer[12 + MAXPATHLEN + 1];
1565     int len = 12 + MAXPATHLEN + 1;
1566
1567 #ifdef DEBUG
1568     LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1569 #endif /* DEBUG */
1570
1571     *rbuflen = 0;
1572     ibuf += 2;
1573
1574     memcpy(&vid, ibuf, sizeof(vid));
1575     ibuf += sizeof(vid);
1576
1577     if (NULL == ( vol = getvolbyvid( vid )) ) {
1578         return( AFPERR_PARAM);
1579     }
1580
1581     memcpy(&id, ibuf, sizeof( id ));
1582     ibuf += sizeof(id);
1583
1584     if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1585         return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1586     }
1587
1588     if (( dir = dirlookup( vol, id )) == NULL ) {
1589         return AFPERR_NOID; /* idem AFPERR_PARAM */
1590     }
1591     path.u_name = upath;
1592     if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1593         switch (errno) {
1594         case EACCES:
1595         case EPERM:
1596             return AFPERR_ACCESS;
1597         case ENOENT:
1598             return AFPERR_NOID;
1599         default:
1600             return AFPERR_PARAM;
1601         }
1602     }
1603     /* directories are bad */
1604     if (S_ISDIR(path.st.st_mode))
1605         return AFPERR_BADTYPE;
1606
1607     memcpy(&bitmap, ibuf, sizeof(bitmap));
1608     bitmap = ntohs( bitmap );
1609     path.m_name = utompath(vol, upath);
1610     if ((err = getfilparams(vol, bitmap, &path , curdir, 
1611                             rbuf + sizeof(bitmap), &buflen)) != AFP_OK) {
1612         return err;
1613     }
1614     *rbuflen = buflen + sizeof(bitmap);
1615     memcpy(rbuf, ibuf, sizeof(bitmap));
1616
1617 #ifdef DEBUG
1618     LOG(log_info, logtype_afpd, "end afp_resolveid:");
1619 #endif /* DEBUG */
1620
1621     return AFP_OK;
1622 }
1623
1624 /* ------------------------------ */
1625 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1626 AFPObj      *obj;
1627 char    *ibuf, *rbuf;
1628 int             ibuflen, *rbuflen;
1629 {
1630     struct stat         st;
1631     struct vol          *vol;
1632     struct dir          *dir;
1633     char                *upath;
1634     int                 err;
1635     cnid_t              id;
1636     cnid_t              fileid;
1637     u_short             vid;
1638     static char buffer[12 + MAXPATHLEN + 1];
1639     int len = 12 + MAXPATHLEN + 1;
1640
1641 #ifdef DEBUG
1642     LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1643 #endif /* DEBUG */
1644
1645     *rbuflen = 0;
1646     ibuf += 2;
1647
1648     memcpy(&vid, ibuf, sizeof(vid));
1649     ibuf += sizeof(vid);
1650
1651     if (NULL == ( vol = getvolbyvid( vid )) ) {
1652         return( AFPERR_PARAM);
1653     }
1654
1655     if (vol->v_flags & AFPVOL_RO)
1656         return AFPERR_VLOCK;
1657
1658     memcpy(&id, ibuf, sizeof( id ));
1659     ibuf += sizeof(id);
1660     fileid = id;
1661
1662     if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1663         return AFPERR_NOID;
1664     }
1665
1666     if (( dir = dirlookup( vol, id )) == NULL ) {
1667         return( AFPERR_PARAM );
1668     }
1669
1670     err = AFP_OK;
1671     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1672         switch (errno) {
1673         case EACCES:
1674         case EPERM:
1675             return AFPERR_ACCESS;
1676         case ENOENT:
1677             /* still try to delete the id */
1678             err = AFPERR_NOOBJ;
1679             break;
1680         default:
1681             return AFPERR_PARAM;
1682         }
1683     }
1684
1685     /* directories are bad */
1686     if (S_ISDIR(st.st_mode))
1687         return AFPERR_BADTYPE;
1688
1689     if (cnid_delete(vol->v_db, fileid)) {
1690         switch (errno) {
1691         case EROFS:
1692             return AFPERR_VLOCK;
1693         case EPERM:
1694         case EACCES:
1695             return AFPERR_ACCESS;
1696         default:
1697             return AFPERR_PARAM;
1698         }
1699     }
1700
1701 #ifdef DEBUG
1702     LOG(log_info, logtype_afpd, "end afp_deleteid:");
1703 #endif /* DEBUG */
1704
1705     return err;
1706 }
1707 #endif /* CNID_DB */
1708
1709 #define APPLETEMP ".AppleTempXXXXXX"
1710
1711 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1712 AFPObj      *obj;
1713 char    *ibuf, *rbuf;
1714 int             ibuflen, *rbuflen;
1715 {
1716     struct stat         srcst, destst;
1717     struct vol          *vol;
1718     struct dir          *dir, *sdir;
1719     char                *spath, temp[17], *p;
1720     char                *supath, *upath;
1721     struct path         *path;
1722     int                 err;
1723     struct adouble      ads;
1724     struct adouble      add;
1725     struct adouble      *adsp;
1726     struct adouble      *addp;
1727     struct ofork        *s_of;
1728     struct ofork        *d_of;
1729     int                 crossdev;
1730     
1731 #ifdef CNID_DB
1732     int                 slen, dlen;
1733 #endif /* CNID_DB */
1734     u_int32_t           sid, did;
1735     u_int16_t           vid;
1736
1737 #ifdef DEBUG
1738     LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1739 #endif /* DEBUG */
1740
1741     *rbuflen = 0;
1742     ibuf += 2;
1743
1744     memcpy(&vid, ibuf, sizeof(vid));
1745     ibuf += sizeof(vid);
1746
1747     if (NULL == ( vol = getvolbyvid( vid )) ) {
1748         return( AFPERR_PARAM);
1749     }
1750
1751     if (vol->v_flags & AFPVOL_RO)
1752         return AFPERR_VLOCK;
1753
1754     /* source and destination dids */
1755     memcpy(&sid, ibuf, sizeof(sid));
1756     ibuf += sizeof(sid);
1757     memcpy(&did, ibuf, sizeof(did));
1758     ibuf += sizeof(did);
1759
1760     /* source file */
1761     if (NULL == (dir = dirlookup( vol, sid )) ) {
1762         return( AFPERR_PARAM );
1763     }
1764
1765     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1766         return afp_errno; /* was AFPERR_PARAM */
1767     }
1768
1769     if ( path_isadir(path) ) {
1770         return( AFPERR_BADTYPE );   /* it's a dir */
1771     }
1772
1773     upath = path->u_name;
1774     switch (path->st_errno) {
1775         case 0:
1776              break;
1777         case ENOENT:
1778             return AFPERR_NOID;
1779         case EPERM:
1780         case EACCES:
1781             return AFPERR_ACCESS;
1782         default:
1783             return AFPERR_PARAM;
1784     }
1785     memset(&ads, 0, sizeof(ads));
1786     adsp = &ads;
1787     if ((s_of = of_findname(path))) {
1788             /* reuse struct adouble so it won't break locks */
1789             adsp = s_of->of_ad;
1790     }
1791     memcpy(&srcst, &path->st, sizeof(struct stat));
1792     /* save some stuff */
1793     sdir = curdir;
1794     spath = obj->oldtmp;
1795     supath = obj->newtmp;
1796     strcpy(spath, path->m_name);
1797     strcpy(supath, upath); /* this is for the cnid changing */
1798     p = absupath( vol, sdir, upath);
1799     if (!p) {
1800         /* pathname too long */
1801         return AFPERR_PARAM ;
1802     }
1803
1804     /* look for the source cnid. if it doesn't exist, don't worry about
1805      * it. */
1806 #ifdef CNID_DB
1807     sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1808                       slen = strlen(supath));
1809 #endif /* CNID_DB */
1810
1811     if (NULL == ( dir = dirlookup( vol, did )) ) {
1812         return( AFPERR_PARAM );
1813     }
1814
1815     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1816         return( AFPERR_PARAM );
1817     }
1818
1819     if ( path_isadir(path) ) {
1820         return( AFPERR_BADTYPE );
1821     }
1822
1823     /* FPExchangeFiles is the only call that can return the SameObj
1824      * error */
1825     if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1826         return AFPERR_SAMEOBJ;
1827
1828     switch (path->st_errno) {
1829         case 0:
1830              break;
1831         case ENOENT:
1832             return AFPERR_NOID;
1833         case EPERM:
1834         case EACCES:
1835             return AFPERR_ACCESS;
1836         default:
1837             return AFPERR_PARAM;
1838     }
1839     memset(&add, 0, sizeof(add));
1840     addp = &add;
1841     if ((d_of = of_findname( path))) {
1842             /* reuse struct adouble so it won't break locks */
1843             addp = d_of->of_ad;
1844     }
1845     memcpy(&destst, &path->st, sizeof(struct stat));
1846
1847     /* they are not on the same device and at least one is open
1848     */
1849     crossdev = (srcst.st_dev != destst.st_dev);
1850     if ((d_of || s_of)  && crossdev)
1851         return AFPERR_MISC;
1852     
1853     upath = path->u_name;
1854 #ifdef CNID_DB
1855     /* look for destination id. */
1856     did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1857                       dlen = strlen(upath));
1858 #endif /* CNID_DB */
1859
1860     /* construct a temp name.
1861      * NOTE: the temp file will be in the dest file's directory. it
1862      * will also be inaccessible from AFP. */
1863     memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1864     if (!mktemp(temp))
1865         return AFPERR_MISC;
1866
1867     /* now, quickly rename the file. we error if we can't. */
1868     if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1869         goto err_exchangefile;
1870     of_rename(vol, s_of, sdir, spath, curdir, temp);
1871
1872     /* rename destination to source */
1873     if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1874         goto err_src_to_tmp;
1875     of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1876
1877     /* rename temp to destination */
1878     if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1879         goto err_dest_to_src;
1880     of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1881
1882 #ifdef CNID_DB
1883     /* id's need switching. src -> dest and dest -> src. 
1884      * we need to re-stat() if it was a cross device copy.
1885     */
1886     if (sid) {
1887         cnid_delete(vol->v_db, sid);
1888     }
1889     if (did) {
1890         cnid_delete(vol->v_db, did);
1891     }
1892     if ((did && ( (crossdev && stat( upath, &srcst) < 0) || 
1893                 cnid_update(vol->v_db, did, &srcst, curdir->d_did,upath, dlen) < 0))
1894        ||
1895        (sid && ( (crossdev && stat(p, &destst) < 0) ||
1896                 cnid_update(vol->v_db, sid, &destst, sdir->d_did,supath, slen) < 0))
1897     ) {
1898         switch (errno) {
1899         case EPERM:
1900         case EACCES:
1901             err = AFPERR_ACCESS;
1902             break;
1903         default:
1904             err = AFPERR_PARAM;
1905         }
1906         goto err_temp_to_dest;
1907     }
1908 #endif /* CNID_DB */
1909
1910 #ifdef DEBUG
1911     LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1912 #endif /* DEBUG */
1913
1914     return AFP_OK;
1915
1916
1917     /* all this stuff is so that we can unwind a failed operation
1918      * properly. */
1919 #ifdef CNID_DB
1920 err_temp_to_dest:
1921 #endif
1922     /* rename dest to temp */
1923     renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1924     of_rename(vol, s_of, curdir, upath, curdir, temp);
1925
1926 err_dest_to_src:
1927     /* rename source back to dest */
1928     renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1929     of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1930
1931 err_src_to_tmp:
1932     /* rename temp back to source */
1933     renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1934     of_rename(vol, s_of, curdir, temp, sdir, spath);
1935
1936 err_exchangefile:
1937     return err;
1938 }