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