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