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