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