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