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