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