]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/file.c
error code for dirlookup, cname.
[netatalk.git] / etc / afpd / file.c
1 /*
2  * $Id: file.c,v 1.88 2003-03-15 01:34:35 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 get_afp_errno(AFPERR_PARAM);
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 ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
621             return ( AFPERR_NOOBJ );
622         case EEXIST :
623             return( AFPERR_EXIST );
624         case EACCES :
625             return( AFPERR_ACCESS );
626         default :
627             return( AFPERR_PARAM );
628         }
629     }
630     if ( ad_hfileno( adp ) == -1 ) {
631          /* on noadouble volumes, just creating the data fork is ok */
632          if (vol_noadouble(vol))
633              goto createfile_done;
634          /* FIXME with hard create on an existing file, we already
635           * corrupted the data file.
636           */
637          netatalk_unlink( upath );
638          ad_close( adp, ADFLAGS_DF );
639          return AFPERR_ACCESS;
640     }
641
642     path = s_path->m_name;
643     ad_setentrylen( adp, ADEID_NAME, strlen( path ));
644     memcpy(ad_entry( adp, ADEID_NAME ), path,
645            ad_getentrylen( adp, ADEID_NAME ));
646     ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
647     ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
648
649 createfile_done:
650     curdir->offcnt++;
651
652 #ifdef DROPKLUDGE
653     if (vol->v_flags & AFPVOL_DROPBOX) {
654         retvalue = matchfile2dirperms(upath, vol, did);
655     }
656 #endif /* DROPKLUDGE */
657
658     setvoltime(obj, vol );
659
660 #ifdef DEBUG
661     LOG(log_info, logtype_afpd, "end afp_createfile");
662 #endif /* DEBUG */
663
664     return (retvalue);
665 }
666
667 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
668 AFPObj      *obj;
669 char    *ibuf, *rbuf;
670 int             ibuflen, *rbuflen;
671 {
672     struct vol  *vol;
673     struct dir  *dir;
674     struct path *s_path;
675     int         did, rc;
676     u_int16_t   vid, bitmap;
677
678 #ifdef DEBUG
679     LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
680 #endif /* DEBUG */
681
682     *rbuflen = 0;
683     ibuf += 2;
684
685     memcpy(&vid, ibuf, sizeof( vid ));
686     ibuf += sizeof( vid );
687     if (NULL == ( vol = getvolbyvid( vid )) ) {
688         return( AFPERR_PARAM );
689     }
690
691     if (vol->v_flags & AFPVOL_RO)
692         return AFPERR_VLOCK;
693
694     memcpy(&did, ibuf, sizeof( did ));
695     ibuf += sizeof( did );
696     if (NULL == ( dir = dirlookup( vol, did )) ) {
697         return afp_errno; /* was AFPERR_NOOBJ */
698     }
699
700     memcpy(&bitmap, ibuf, sizeof( bitmap ));
701     bitmap = ntohs( bitmap );
702     ibuf += sizeof( bitmap );
703
704     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
705         return get_afp_errno(AFPERR_PARAM);
706     }
707
708     if (path_isadir(s_path)) {
709         return( AFPERR_BADTYPE ); /* it's a directory */
710     }
711
712     if ((u_long)ibuf & 1 ) {
713         ibuf++;
714     }
715
716     if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
717         setvoltime(obj, vol );
718     }
719
720 #ifdef DEBUG
721     LOG(log_info, logtype_afpd, "end afp_setfilparams:");
722 #endif /* DEBUG */
723
724     return( rc );
725 }
726
727 /*
728  * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic  
729  *
730 */
731 extern struct path Cur_Path;
732
733 int setfilparams(struct vol *vol,
734                  struct path *path, u_int16_t bitmap, char *buf )
735 {
736     struct adouble      ad, *adp;
737     struct ofork        *of;
738     struct extmap       *em;
739     int                 bit = 0, isad = 1, err = AFP_OK;
740     char                *upath;
741     u_char              achar, *fdType, xyy[4];
742     u_int16_t           ashort, bshort;
743     u_int32_t           aint;
744     struct utimbuf      ut;
745
746     int                 change_mdate = 0;
747     int                 change_parent_mdate = 0;
748     int                 newdate = 0;
749     struct timeval      tv;
750
751
752 #ifdef DEBUG
753     LOG(log_info, logtype_afpd, "begin setfilparams:");
754 #endif /* DEBUG */
755
756     upath = path->u_name;
757     if ((of = of_findname(path))) {
758         adp = of->of_ad;
759     } else {
760         memset(&ad, 0, sizeof(ad));
761         adp = &ad;
762     }
763
764     if (check_access(upath, OPENACC_WR ) < 0) {
765         return AFPERR_ACCESS;
766     }
767
768     if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
769                  O_RDWR|O_CREAT, 0666, adp) < 0) {
770         /* for some things, we don't need an adouble header */
771         if (bitmap & ~(1<<FILPBIT_MDATE)) {
772             return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
773         }
774         isad = 0;
775     } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
776         ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
777         memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
778                ad_getentrylen( adp, ADEID_NAME ));
779     }
780
781     while ( bitmap != 0 ) {
782         while (( bitmap & 1 ) == 0 ) {
783             bitmap = bitmap>>1;
784             bit++;
785         }
786
787         switch(  bit ) {
788         case FILPBIT_ATTR :
789             change_mdate = 1;
790             memcpy(&ashort, buf, sizeof( ashort ));
791             ad_getattr(adp, &bshort);
792             if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
793                 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
794             } else {
795                 bshort &= ~ashort;
796             }
797             if ((ashort & htons(ATTRBIT_INVISIBLE)))
798                 change_parent_mdate = 1;
799             ad_setattr(adp, bshort);
800             buf += sizeof( ashort );
801             break;
802
803         case FILPBIT_CDATE :
804             change_mdate = 1;
805             memcpy(&aint, buf, sizeof(aint));
806             ad_setdate(adp, AD_DATE_CREATE, aint);
807             buf += sizeof( aint );
808             break;
809
810         case FILPBIT_MDATE :
811             memcpy(&newdate, buf, sizeof( newdate ));
812             buf += sizeof( newdate );
813             break;
814
815         case FILPBIT_BDATE :
816             change_mdate = 1;
817             memcpy(&aint, buf, sizeof(aint));
818             ad_setdate(adp, AD_DATE_BACKUP, aint);
819             buf += sizeof( aint );
820             break;
821
822         case FILPBIT_FINFO :
823             change_mdate = 1;
824
825             if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
826                     && ( 
827                      ((em = getextmap( path->m_name )) &&
828                       !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
829                       !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
830                      || ((em = getdefextmap()) &&
831                       !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
832                       !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
833             )) {
834                 memcpy(buf, ufinderi, 8 );
835             }
836
837             memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
838             buf += 32;
839             break;
840
841             /* Client needs to set the ProDOS file info for this file.
842                Use a defined string for TEXT to support crlf
843                translations and convert all else into pXYY per Inside
844                Appletalk.  Always set the creator as "pdos".  Changes
845                from original by Marsha Jackson. */
846         case FILPBIT_PDINFO :
847             if (afp_version < 30) { /* else it's UTF8 name */
848                 achar = *buf;
849                 buf += 2;
850                 /* Keep special case to support crlf translations */
851                 if ((unsigned int) achar == 0x04) {
852                     fdType = (u_char *)"TEXT";
853                     buf += 2;
854                 } else {
855                     xyy[0] = ( u_char ) 'p';
856                     xyy[1] = achar;
857                     xyy[3] = *buf++;
858                     xyy[2] = *buf++;
859                     fdType = xyy;
860                 }
861                 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
862                 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
863                 break;
864             }
865             /* fallthrough */
866         default :
867             err = AFPERR_BITMAP;
868             goto setfilparam_done;
869         }
870
871         bitmap = bitmap>>1;
872         bit++;
873     }
874
875 setfilparam_done:
876     if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
877        newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
878     }
879     if (newdate) {
880        if (isad)
881           ad_setdate(adp, AD_DATE_MODIFY, newdate);
882        ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
883        utime(upath, &ut);
884     }
885
886     if (isad) {
887         ad_flush( adp, ADFLAGS_HF );
888         ad_close( adp, ADFLAGS_HF );
889
890     }
891
892     if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
893         newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
894         bitmap = 1<<FILPBIT_MDATE;
895         setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
896     }
897
898 #ifdef DEBUG
899     LOG(log_info, logtype_afpd, "end setfilparams:");
900 #endif /* DEBUG */
901     return err;
902 }
903
904 /*
905  * renamefile and copyfile take the old and new unix pathnames
906  * and the new mac name.
907  *
908  * src         the source path 
909  * dst         the dest filename in current dir
910  * newname     the dest mac name
911  * adp         adouble struct of src file, if open, or & zeroed one
912  *
913  */
914 int renamefile(src, dst, newname, noadouble, adp )
915 char    *src, *dst, *newname;
916 const int         noadouble;
917 struct adouble    *adp;
918 {
919     char        adsrc[ MAXPATHLEN + 1];
920     int         len;
921     int         rc;
922
923 #ifdef DEBUG
924     LOG(log_info, logtype_afpd, "begin renamefile:");
925 #endif /* DEBUG */
926
927     if ( unix_rename( src, dst ) < 0 ) {
928         switch ( errno ) {
929         case ENOENT :
930             return( AFPERR_NOOBJ );
931         case EPERM:
932         case EACCES :
933             return( AFPERR_ACCESS );
934         case EROFS:
935             return AFPERR_VLOCK;
936         case EXDEV :                    /* Cross device move -- try copy */
937            /* NOTE: with open file it's an error because after the copy we will 
938             * get two files, it's fixable for our process (eg reopen the new file, get the
939             * locks, and so on. But it doesn't solve the case with a second process
940             */
941             if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
942                 /* FIXME  warning in syslog so admin'd know there's a conflict ?*/
943                 return AFPERR_OLOCK; /* little lie */
944             }
945             if (AFP_OK != ( rc = copyfile(src, dst, newname, noadouble )) ) {
946                 /* on error copyfile delete dest */
947                 return( rc );
948             }
949             return deletefile(NULL, src, 0);
950         default :
951             return( AFPERR_PARAM );
952         }
953     }
954
955     strcpy( adsrc, ad_path( src, 0 ));
956
957     if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
958         struct stat st;
959         int err;
960         
961         err = errno;        
962         if (errno == ENOENT) {
963             struct adouble    ad;
964
965             if (stat(adsrc, &st)) /* source has no ressource fork, */
966                 return AFP_OK;
967             
968             /* We are here  because :
969              * -there's no dest folder. 
970              * -there's no .AppleDouble in the dest folder.
971              * if we use the struct adouble passed in parameter it will not
972              * create .AppleDouble if the file is already opened, so we
973              * use a diff one, it's not a pb,ie it's not the same file, yet.
974              */
975             memset(&ad, 0, sizeof(ad));
976             if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
977                 ad_close(&ad, ADFLAGS_HF);
978                 if (!unix_rename( adsrc, ad_path( dst, 0 )) ) 
979                    err = 0;
980                 else 
981                    err = errno;
982             }
983             else { /* it's something else, bail out */
984                 err = errno;
985             }
986         }
987         /* try to undo the data fork rename,
988          * we know we are on the same device 
989         */
990         if (err) {
991             unix_rename( dst, src ); 
992             /* return the first error */
993             switch ( err) {
994             case ENOENT :
995                 return AFPERR_NOOBJ;
996             case EPERM:
997             case EACCES :
998                 return AFPERR_ACCESS ;
999             case EROFS:
1000                 return AFPERR_VLOCK;
1001             default :
1002                 return AFPERR_PARAM ;
1003             }
1004         }
1005     }
1006
1007     /* don't care if we can't open the newly renamed ressource fork
1008      */
1009     if ( !ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1010         len = strlen( newname );
1011         ad_setentrylen( adp, ADEID_NAME, len );
1012         memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
1013         ad_flush( adp, ADFLAGS_HF );
1014         ad_close( adp, ADFLAGS_HF );
1015     }
1016 #ifdef DEBUG
1017     LOG(log_info, logtype_afpd, "end renamefile:");
1018 #endif /* DEBUG */
1019
1020     return( AFP_OK );
1021 }
1022
1023 int copy_path_name(char *newname, char *ibuf)
1024 {
1025 char        type = *ibuf;
1026 size_t      plen = 0;
1027 u_int16_t   len16;
1028 u_int32_t   hint;
1029
1030     if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1031         return -1;
1032     }
1033     ibuf++;
1034     switch (type) {
1035     case 2:
1036         if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1037             strncpy( newname, ibuf, plen );
1038             newname[ plen ] = '\0';
1039             if (strlen(newname) != plen) {
1040                 /* there's \0 in newname, e.g. it's a pathname not
1041                  * only a filename. 
1042                 */
1043                 return -1;
1044             }
1045         }
1046         break;
1047     case 3:
1048         memcpy(&hint, ibuf, sizeof(hint));
1049         ibuf += sizeof(hint);
1050            
1051         memcpy(&len16, ibuf, sizeof(len16));
1052         ibuf += sizeof(len16);
1053         plen = ntohs(len16);
1054         if (plen) {
1055             strncpy( newname, ibuf, plen );
1056             newname[ plen ] = '\0';
1057             if (strlen(newname) != plen) {
1058                 return -1;
1059             }
1060         }
1061         break;
1062     }
1063     return plen;
1064 }
1065
1066 /* -----------------------------------
1067 */
1068 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1069 AFPObj      *obj;
1070 char    *ibuf, *rbuf;
1071 int             ibuflen, *rbuflen;
1072 {
1073     struct vol  *vol;
1074     struct dir  *dir;
1075     char        *newname, *p, *upath;
1076     struct path *s_path;
1077     u_int32_t   sdid, ddid;
1078     int         err, retvalue = AFP_OK;
1079     u_int16_t   svid, dvid;
1080
1081 #ifdef DEBUG
1082     LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1083 #endif /* DEBUG */
1084
1085     *rbuflen = 0;
1086     ibuf += 2;
1087
1088     memcpy(&svid, ibuf, sizeof( svid ));
1089     ibuf += sizeof( svid );
1090     if (NULL == ( vol = getvolbyvid( svid )) ) {
1091         return( AFPERR_PARAM );
1092     }
1093
1094     memcpy(&sdid, ibuf, sizeof( sdid ));
1095     ibuf += sizeof( sdid );
1096     if (NULL == ( dir = dirlookup( vol, sdid )) ) {
1097         return afp_errno;
1098     }
1099
1100     memcpy(&dvid, ibuf, sizeof( dvid ));
1101     ibuf += sizeof( dvid );
1102     memcpy(&ddid, ibuf, sizeof( ddid ));
1103     ibuf += sizeof( ddid );
1104
1105     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1106         return get_afp_errno(AFPERR_PARAM);
1107     }
1108     if ( path_isadir(s_path) ) {
1109         return( AFPERR_BADTYPE );
1110     }
1111
1112     /* don't allow copies when the file is open.
1113      * XXX: the spec only calls for read/deny write access.
1114      *      however, copyfile doesn't have any of that info,
1115      *      and locks need to stay coherent. as a result,
1116      *      we just balk if the file is opened already. */
1117
1118     newname = obj->newtmp;
1119     strcpy( newname, s_path->m_name );
1120
1121     if (of_findname(s_path))
1122         return AFPERR_DENYCONF;
1123
1124     p = ctoupath( vol, curdir, newname );
1125     if (!p) {
1126         return AFPERR_PARAM;
1127     
1128     }
1129 #ifdef FORCE_UIDGID
1130     /* FIXME svid != dvid && dvid's user can't read svid */
1131 #endif
1132     if (NULL == ( vol = getvolbyvid( dvid )) ) {
1133         return( AFPERR_PARAM );
1134     }
1135
1136     if (vol->v_flags & AFPVOL_RO)
1137         return AFPERR_VLOCK;
1138
1139     if (NULL == ( dir = dirlookup( vol, ddid )) ) {
1140         return afp_errno;
1141     }
1142
1143     if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1144         return get_afp_errno(AFPERR_NOOBJ); 
1145     }
1146     if ( *s_path->m_name != '\0' ) {
1147         return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1148     }
1149
1150     /* one of the handful of places that knows about the path type */
1151     if (copy_path_name(newname, ibuf) < 0) {
1152         return( AFPERR_PARAM );
1153     }
1154
1155     if (NULL == (upath = mtoupath(vol, newname, utf8_encoding()))) {
1156         return( AFPERR_PARAM );
1157     }
1158     if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1159         return err;
1160     }
1161     curdir->offcnt++;
1162
1163 #ifdef DROPKLUDGE
1164     if (vol->v_flags & AFPVOL_DROPBOX) {
1165         retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1166     }
1167 #endif /* DROPKLUDGE */
1168
1169     setvoltime(obj, vol );
1170
1171 #ifdef DEBUG
1172     LOG(log_info, logtype_afpd, "end afp_copyfile:");
1173 #endif /* DEBUG */
1174
1175     return( retvalue );
1176 }
1177
1178
1179 static __inline__ int copy_all(const int dfd, const void *buf,
1180                                size_t buflen)
1181 {
1182     ssize_t cc;
1183
1184 #ifdef DEBUG
1185     LOG(log_info, logtype_afpd, "begin copy_all:");
1186 #endif /* DEBUG */
1187
1188     while (buflen > 0) {
1189         if ((cc = write(dfd, buf, buflen)) < 0) {
1190             switch (errno) {
1191             case EINTR:
1192                 continue;
1193             case EDQUOT:
1194             case EFBIG:
1195             case ENOSPC:
1196                 return AFPERR_DFULL;
1197             case EROFS:
1198                 return AFPERR_VLOCK;
1199             default:
1200                 return AFPERR_PARAM;
1201             }
1202         }
1203         buflen -= cc;
1204     }
1205
1206 #ifdef DEBUG
1207     LOG(log_info, logtype_afpd, "end copy_all:");
1208 #endif /* DEBUG */
1209
1210     return AFP_OK;
1211 }
1212
1213 /* -------------------------- */
1214 static int copy_fd(int dfd, int sfd)
1215 {
1216     ssize_t cc;
1217     int     err = AFP_OK;
1218     char    filebuf[8192];
1219
1220 #ifdef SENDFILE_FLAVOR_LINUX
1221     struct stat         st;
1222
1223     if (fstat(sfd, &st) == 0) {
1224         if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1225             switch (errno) {
1226             case EINVAL:  /* there's no guarantee that all fs support sendfile */
1227                 break;
1228             case EDQUOT:
1229             case EFBIG:
1230             case ENOSPC:
1231                 return AFPERR_DFULL;
1232             case EROFS:
1233                 return AFPERR_VLOCK;
1234             default:
1235                 return AFPERR_PARAM;
1236             }
1237         }
1238         else {
1239            return AFP_OK;
1240         }
1241     }
1242 #endif /* SENDFILE_FLAVOR_LINUX */
1243
1244     while (1) {
1245         if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1246             if (errno == EINTR)
1247                 continue;
1248             err = AFPERR_PARAM;
1249             break;
1250         }
1251
1252         if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1253             break;
1254     }
1255     return err;
1256 }
1257
1258 /* ----------------------------------
1259  * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1260  * because we are doing it elsewhere.
1261  */
1262 int copyfile(src, dst, newname, noadouble )
1263 char    *src, *dst, *newname;
1264 const int   noadouble;
1265 {
1266     struct adouble      ads, add;
1267     int                 len, err = AFP_OK;
1268     int                 adflags;
1269     
1270 #ifdef DEBUG
1271     LOG(log_info, logtype_afpd, "begin copyfile:");
1272 #endif /* DEBUG */
1273
1274     memset(&ads, 0, sizeof(ads));
1275     memset(&add, 0, sizeof(add));
1276     adflags = ADFLAGS_DF;
1277     if (newname) {
1278         adflags |= ADFLAGS_HF;
1279     }
1280
1281     if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1282         switch ( errno ) {
1283         case ENOENT :
1284             return( AFPERR_NOOBJ );
1285         case EACCES :
1286             return( AFPERR_ACCESS );
1287         default :
1288             return( AFPERR_PARAM );
1289         }
1290     }
1291     if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1292         ad_close( &ads, adflags );
1293         if (EEXIST != (err = errno)) {
1294             deletefile(NULL, dst, 0);
1295         }
1296         switch ( err ) {
1297         case EEXIST :
1298             return AFPERR_EXIST;
1299         case ENOENT :
1300             return( AFPERR_NOOBJ );
1301         case EACCES :
1302             return( AFPERR_ACCESS );
1303         case EROFS:
1304             return AFPERR_VLOCK;
1305         default :
1306             return( AFPERR_PARAM );
1307         }
1308     }
1309     if (ad_hfileno(&ads) == -1 || AFP_OK == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1310         /* copy the data fork */
1311         err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1312     }
1313
1314     if (newname) {
1315         len = strlen( newname );
1316         ad_setentrylen( &add, ADEID_NAME, len );
1317         memcpy(ad_entry( &add, ADEID_NAME ), newname, len );
1318     }
1319
1320     ad_close( &ads, adflags );
1321     ad_flush( &add, adflags );
1322     if (ad_close( &add, adflags ) <0) {
1323        err = errno;
1324     }
1325     if (err != AFP_OK) {
1326         deletefile(NULL, dst, 0);
1327         switch ( err ) {
1328         case ENOENT :
1329             return( AFPERR_NOOBJ );
1330         case EACCES :
1331             return( AFPERR_ACCESS );
1332         default :
1333             return( AFPERR_PARAM );
1334         }
1335     }
1336
1337 #ifdef DEBUG
1338     LOG(log_info, logtype_afpd, "end copyfile:");
1339 #endif /* DEBUG */
1340
1341     return( AFP_OK );
1342 }
1343
1344
1345 /* -----------------------------------
1346    vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1347    checkAttrib:   1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1348
1349    when deletefile is called we don't have lock on it, file is closed (for us)
1350    untrue if called by renamefile
1351    
1352    ad_open always try to open file RDWR first and ad_lock takes care of
1353    WRITE lock on read only file.
1354 */
1355 int deletefile( vol, file, checkAttrib )
1356 struct vol      *vol;
1357 char            *file;
1358 int         checkAttrib;
1359 {
1360     struct adouble      ad;
1361     int                 adflags, err = AFP_OK;
1362
1363 #ifdef DEBUG
1364     LOG(log_info, logtype_afpd, "begin deletefile:");
1365 #endif /* DEBUG */
1366
1367     /* try to open both forks at once */
1368     adflags = ADFLAGS_DF|ADFLAGS_HF;
1369     while(1) {
1370         memset(&ad, 0, sizeof(ad));
1371         if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1372             switch (errno) {
1373             case ENOENT:
1374                 if (adflags == ADFLAGS_DF)
1375                     return AFPERR_NOOBJ;
1376                    
1377                 /* that failed. now try to open just the data fork */
1378                 adflags = ADFLAGS_DF;
1379                 continue;
1380
1381             case EACCES:
1382                 return AFPERR_ACCESS;
1383             case EROFS:
1384                 return AFPERR_VLOCK;
1385             default:
1386                 return( AFPERR_PARAM );
1387             }
1388         }
1389         break;  /* from the while */
1390     }
1391     /*
1392      * Does kFPDeleteInhibitBit (bit 8) set?
1393      */
1394     if (checkAttrib && (adflags & ADFLAGS_HF)) {
1395         u_int16_t   bshort;
1396
1397         ad_getattr(&ad, &bshort);
1398         if ((bshort & htons(ATTRBIT_NODELETE))) {
1399             ad_close( &ad, adflags );
1400             return(AFPERR_OLOCK);
1401         }
1402     }
1403     
1404     if ((adflags & ADFLAGS_HF) ) {
1405         /* FIXME we have a pb here because we want to know if a file is open 
1406          * there's a 'priority inversion' if you can't open the ressource fork RW
1407          * you can delete it if it's open because you can't get a write lock.
1408          * 
1409          * ADLOCK_FILELOCK means the whole ressource fork, not only after the 
1410          * metadatas
1411          *
1412          * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1413          */
1414         if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1415             ad_close( &ad, adflags );
1416             return( AFPERR_BUSY );
1417         }
1418     }
1419
1420     if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1421         err = AFPERR_BUSY;
1422     }
1423     else if (!(err = netatalk_unlink( ad_path( file, ADFLAGS_HF)) ) &&
1424              !(err = netatalk_unlink( file )) ) {
1425 #ifdef CNID_DB /* get rid of entry */
1426         cnid_t id;
1427         if (vol && (id = cnid_get(vol->v_db, curdir->d_did, file, strlen(file)))) 
1428         {
1429             cnid_delete(vol->v_db, id);
1430         }
1431 #endif /* CNID_DB */
1432
1433     }
1434     ad_close( &ad, adflags );  /* ad_close removes locks if any */
1435
1436 #ifdef DEBUG
1437     LOG(log_info, logtype_afpd, "end deletefile:");
1438 #endif /* DEBUG */
1439
1440     return err;
1441 }
1442
1443 /* ------------------------------------ */
1444 #ifdef CNID_DB
1445 /* return a file id */
1446 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1447 AFPObj      *obj;
1448 char    *ibuf, *rbuf;
1449 int             ibuflen, *rbuflen;
1450 {
1451     struct stat         *st;
1452     struct vol          *vol;
1453     struct dir          *dir;
1454     char                *upath;
1455     int                 len;
1456     cnid_t              did, id;
1457     u_short             vid;
1458     struct path         *s_path;
1459
1460 #ifdef DEBUG
1461     LOG(log_info, logtype_afpd, "begin afp_createid:");
1462 #endif /* DEBUG */
1463
1464     *rbuflen = 0;
1465
1466     ibuf += 2;
1467
1468     memcpy(&vid, ibuf, sizeof(vid));
1469     ibuf += sizeof(vid);
1470
1471     if (NULL == ( vol = getvolbyvid( vid )) ) {
1472         return( AFPERR_PARAM);
1473     }
1474
1475     if (vol->v_db == NULL) {
1476         return AFPERR_NOOP;
1477     }
1478
1479     if (vol->v_flags & AFPVOL_RO)
1480         return AFPERR_VLOCK;
1481
1482     memcpy(&did, ibuf, sizeof( did ));
1483     ibuf += sizeof(did);
1484
1485     if (NULL == ( dir = dirlookup( vol, did )) ) {
1486         return afp_errno; /* was AFPERR_PARAM */
1487     }
1488
1489     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1490         return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1491     }
1492
1493     if ( path_isadir(s_path) ) {
1494         return( AFPERR_BADTYPE );
1495     }
1496
1497     upath = s_path->u_name;
1498     switch (s_path->st_errno) {
1499         case 0:
1500              break; /* success */
1501         case EPERM:
1502         case EACCES:
1503             return AFPERR_ACCESS;
1504         case ENOENT:
1505             return AFPERR_NOOBJ;
1506         default:
1507             return AFPERR_PARAM;
1508     }
1509     st = &s_path->st;
1510     if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1511         memcpy(rbuf, &id, sizeof(id));
1512         *rbuflen = sizeof(id);
1513         return AFPERR_EXISTID;
1514     }
1515
1516     if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1517         memcpy(rbuf, &id, sizeof(id));
1518         *rbuflen = sizeof(id);
1519         return AFP_OK;
1520     }
1521
1522 #ifdef DEBUG
1523     LOG(log_info, logtype_afpd, "ending afp_createid...:");
1524 #endif /* DEBUG */
1525     return afp_errno;
1526 }
1527
1528 /* ------------------------------
1529    resolve a file id */
1530 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1531 AFPObj      *obj;
1532 char    *ibuf, *rbuf;
1533 int             ibuflen, *rbuflen;
1534 {
1535     struct vol          *vol;
1536     struct dir          *dir;
1537     char                *upath;
1538     struct path         path;
1539     int                 err, buflen;
1540     cnid_t              id;
1541     u_int16_t           vid, bitmap;
1542
1543     static char buffer[12 + MAXPATHLEN + 1];
1544     int len = 12 + MAXPATHLEN + 1;
1545
1546 #ifdef DEBUG
1547     LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1548 #endif /* DEBUG */
1549
1550     *rbuflen = 0;
1551     ibuf += 2;
1552
1553     memcpy(&vid, ibuf, sizeof(vid));
1554     ibuf += sizeof(vid);
1555
1556     if (NULL == ( vol = getvolbyvid( vid )) ) {
1557         return( AFPERR_PARAM);
1558     }
1559
1560     if (vol->v_db == NULL) {
1561         return AFPERR_NOOP;
1562     }
1563
1564     memcpy(&id, ibuf, sizeof( id ));
1565     ibuf += sizeof(id);
1566
1567     if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1568         return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1569     }
1570
1571     if (NULL == ( dir = dirlookup( vol, id )) ) {
1572         return AFPERR_NOID; /* idem AFPERR_PARAM */
1573     }
1574     path.u_name = upath;
1575     if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1576         switch (errno) {
1577         case EACCES:
1578         case EPERM:
1579             return AFPERR_ACCESS;
1580         case ENOENT:
1581             return AFPERR_NOID;
1582         default:
1583             return AFPERR_PARAM;
1584         }
1585     }
1586     /* directories are bad */
1587     if (S_ISDIR(path.st.st_mode))
1588         return AFPERR_BADTYPE;
1589
1590     memcpy(&bitmap, ibuf, sizeof(bitmap));
1591     bitmap = ntohs( bitmap );
1592     if (NULL == (path.m_name = utompath(vol, upath, utf8_encoding()))) {
1593         return AFPERR_NOID;
1594     }
1595     if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir, 
1596                             rbuf + sizeof(bitmap), &buflen))) {
1597         return err;
1598     }
1599     *rbuflen = buflen + sizeof(bitmap);
1600     memcpy(rbuf, ibuf, sizeof(bitmap));
1601
1602 #ifdef DEBUG
1603     LOG(log_info, logtype_afpd, "end afp_resolveid:");
1604 #endif /* DEBUG */
1605
1606     return AFP_OK;
1607 }
1608
1609 /* ------------------------------ */
1610 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1611 AFPObj      *obj;
1612 char    *ibuf, *rbuf;
1613 int             ibuflen, *rbuflen;
1614 {
1615     struct stat         st;
1616     struct vol          *vol;
1617     struct dir          *dir;
1618     char                *upath;
1619     int                 err;
1620     cnid_t              id;
1621     cnid_t              fileid;
1622     u_short             vid;
1623     static char buffer[12 + MAXPATHLEN + 1];
1624     int len = 12 + MAXPATHLEN + 1;
1625
1626 #ifdef DEBUG
1627     LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1628 #endif /* DEBUG */
1629
1630     *rbuflen = 0;
1631     ibuf += 2;
1632
1633     memcpy(&vid, ibuf, sizeof(vid));
1634     ibuf += sizeof(vid);
1635
1636     if (NULL == ( vol = getvolbyvid( vid )) ) {
1637         return( AFPERR_PARAM);
1638     }
1639
1640     if (vol->v_db == NULL) {
1641         return AFPERR_NOOP;
1642     }
1643
1644     if (vol->v_flags & AFPVOL_RO)
1645         return AFPERR_VLOCK;
1646
1647     memcpy(&id, ibuf, sizeof( id ));
1648     ibuf += sizeof(id);
1649     fileid = id;
1650
1651     if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1652         return AFPERR_NOID;
1653     }
1654
1655     if (NULL == ( dir = dirlookup( vol, id )) ) {
1656         return( AFPERR_PARAM );
1657     }
1658
1659     err = AFP_OK;
1660     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1661         switch (errno) {
1662         case EACCES:
1663         case EPERM:
1664             return AFPERR_ACCESS;
1665         case ENOENT:
1666             /* still try to delete the id */
1667             err = AFPERR_NOOBJ;
1668             break;
1669         default:
1670             return AFPERR_PARAM;
1671         }
1672     }
1673     else if (S_ISDIR(st.st_mode)) /* directories are bad */
1674         return AFPERR_BADTYPE;
1675
1676     if (cnid_delete(vol->v_db, fileid)) {
1677         switch (errno) {
1678         case EROFS:
1679             return AFPERR_VLOCK;
1680         case EPERM:
1681         case EACCES:
1682             return AFPERR_ACCESS;
1683         default:
1684             return AFPERR_PARAM;
1685         }
1686     }
1687
1688 #ifdef DEBUG
1689     LOG(log_info, logtype_afpd, "end afp_deleteid:");
1690 #endif /* DEBUG */
1691
1692     return err;
1693 }
1694 #endif /* CNID_DB */
1695
1696 #define APPLETEMP ".AppleTempXXXXXX"
1697
1698 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1699 AFPObj      *obj;
1700 char    *ibuf, *rbuf;
1701 int             ibuflen, *rbuflen;
1702 {
1703     struct stat         srcst, destst;
1704     struct vol          *vol;
1705     struct dir          *dir, *sdir;
1706     char                *spath, temp[17], *p;
1707     char                *supath, *upath;
1708     struct path         *path;
1709     int                 err;
1710     struct adouble      ads;
1711     struct adouble      add;
1712     struct adouble      *adsp;
1713     struct adouble      *addp;
1714     struct ofork        *s_of;
1715     struct ofork        *d_of;
1716     int                 crossdev;
1717     
1718 #ifdef CNID_DB
1719     int                 slen, dlen;
1720 #endif /* CNID_DB */
1721     u_int32_t           sid, did;
1722     u_int16_t           vid;
1723
1724 #ifdef DEBUG
1725     LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1726 #endif /* DEBUG */
1727
1728     *rbuflen = 0;
1729     ibuf += 2;
1730
1731     memcpy(&vid, ibuf, sizeof(vid));
1732     ibuf += sizeof(vid);
1733
1734     if (NULL == ( vol = getvolbyvid( vid )) ) {
1735         return( AFPERR_PARAM);
1736     }
1737
1738     if (vol->v_flags & AFPVOL_RO)
1739         return AFPERR_VLOCK;
1740
1741     /* source and destination dids */
1742     memcpy(&sid, ibuf, sizeof(sid));
1743     ibuf += sizeof(sid);
1744     memcpy(&did, ibuf, sizeof(did));
1745     ibuf += sizeof(did);
1746
1747     /* source file */
1748     if (NULL == (dir = dirlookup( vol, sid )) ) {
1749         return afp_errno; /* was AFPERR_PARAM */
1750     }
1751
1752     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1753         return get_afp_errno(AFPERR_NOOBJ); 
1754     }
1755
1756     if ( path_isadir(path) ) {
1757         return( AFPERR_BADTYPE );   /* it's a dir */
1758     }
1759
1760     upath = path->u_name;
1761     switch (path->st_errno) {
1762         case 0:
1763              break;
1764         case ENOENT:
1765             return AFPERR_NOID;
1766         case EPERM:
1767         case EACCES:
1768             return AFPERR_ACCESS;
1769         default:
1770             return AFPERR_PARAM;
1771     }
1772     memset(&ads, 0, sizeof(ads));
1773     adsp = &ads;
1774     if ((s_of = of_findname(path))) {
1775             /* reuse struct adouble so it won't break locks */
1776             adsp = s_of->of_ad;
1777     }
1778     memcpy(&srcst, &path->st, sizeof(struct stat));
1779     /* save some stuff */
1780     sdir = curdir;
1781     spath = obj->oldtmp;
1782     supath = obj->newtmp;
1783     strcpy(spath, path->m_name);
1784     strcpy(supath, upath); /* this is for the cnid changing */
1785     p = absupath( vol, sdir, upath);
1786     if (!p) {
1787         /* pathname too long */
1788         return AFPERR_PARAM ;
1789     }
1790
1791     /* look for the source cnid. if it doesn't exist, don't worry about
1792      * it. */
1793 #ifdef CNID_DB
1794     sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1795                       slen = strlen(supath));
1796 #endif /* CNID_DB */
1797
1798     if (NULL == ( dir = dirlookup( vol, did )) ) {
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 );
1808     }
1809
1810     /* FPExchangeFiles is the only call that can return the SameObj
1811      * error */
1812     if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1813         return AFPERR_SAMEOBJ;
1814
1815     switch (path->st_errno) {
1816         case 0:
1817              break;
1818         case ENOENT:
1819             return AFPERR_NOID;
1820         case EPERM:
1821         case EACCES:
1822             return AFPERR_ACCESS;
1823         default:
1824             return AFPERR_PARAM;
1825     }
1826     memset(&add, 0, sizeof(add));
1827     addp = &add;
1828     if ((d_of = of_findname( path))) {
1829             /* reuse struct adouble so it won't break locks */
1830             addp = d_of->of_ad;
1831     }
1832     memcpy(&destst, &path->st, sizeof(struct stat));
1833
1834     /* they are not on the same device and at least one is open
1835     */
1836     crossdev = (srcst.st_dev != destst.st_dev);
1837     if ((d_of || s_of)  && crossdev)
1838         return AFPERR_MISC;
1839     
1840     upath = path->u_name;
1841 #ifdef CNID_DB
1842     /* look for destination id. */
1843     did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1844                       dlen = strlen(upath));
1845 #endif /* CNID_DB */
1846
1847     /* construct a temp name.
1848      * NOTE: the temp file will be in the dest file's directory. it
1849      * will also be inaccessible from AFP. */
1850     memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1851     if (!mktemp(temp))
1852         return AFPERR_MISC;
1853
1854     /* now, quickly rename the file. we error if we can't. */
1855     if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1856         goto err_exchangefile;
1857     of_rename(vol, s_of, sdir, spath, curdir, temp);
1858
1859     /* rename destination to source */
1860     if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1861         goto err_src_to_tmp;
1862     of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1863
1864     /* rename temp to destination */
1865     if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1866         goto err_dest_to_src;
1867     of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1868
1869 #ifdef CNID_DB
1870     /* id's need switching. src -> dest and dest -> src. 
1871      * we need to re-stat() if it was a cross device copy.
1872     */
1873     if (sid) {
1874         cnid_delete(vol->v_db, sid);
1875     }
1876     if (did) {
1877         cnid_delete(vol->v_db, did);
1878     }
1879     if ((did && ( (crossdev && stat( upath, &srcst) < 0) || 
1880                 cnid_update(vol->v_db, did, &srcst, curdir->d_did,upath, dlen) < 0))
1881        ||
1882        (sid && ( (crossdev && stat(p, &destst) < 0) ||
1883                 cnid_update(vol->v_db, sid, &destst, sdir->d_did,supath, slen) < 0))
1884     ) {
1885         switch (errno) {
1886         case EPERM:
1887         case EACCES:
1888             err = AFPERR_ACCESS;
1889             break;
1890         default:
1891             err = AFPERR_PARAM;
1892         }
1893         goto err_temp_to_dest;
1894     }
1895 #endif /* CNID_DB */
1896
1897 #ifdef DEBUG
1898     LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1899 #endif /* DEBUG */
1900
1901     return AFP_OK;
1902
1903
1904     /* all this stuff is so that we can unwind a failed operation
1905      * properly. */
1906 #ifdef CNID_DB
1907 err_temp_to_dest:
1908 #endif
1909     /* rename dest to temp */
1910     renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1911     of_rename(vol, s_of, curdir, upath, curdir, temp);
1912
1913 err_dest_to_src:
1914     /* rename source back to dest */
1915     renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1916     of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1917
1918 err_src_to_tmp:
1919     /* rename temp back to source */
1920     renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1921     of_rename(vol, s_of, curdir, temp, sdir, spath);
1922
1923 err_exchangefile:
1924     return err;
1925 }