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