]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/file.c
- better error reporting, don't always return noobj.
[netatalk.git] / etc / afpd / file.c
1 /*
2  * $Id: file.c,v 1.70 2003-01-08 15:01:34 didg Exp $
3  *
4  * Copyright (c) 1990,1993 Regents of The University of Michigan.
5  * All Rights Reserved.  See COPYRIGHT.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #ifdef HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif /* HAVE_UNISTD_H */
17
18 /* STDC check */
19 #if STDC_HEADERS
20 #include <string.h>
21 #else /* STDC_HEADERS */
22 #ifndef HAVE_STRCHR
23 #define strchr index
24 #define strrchr index
25 #endif /* HAVE_STRCHR */
26 char *strchr (), *strrchr ();
27 #ifndef HAVE_MEMCPY
28 #define memcpy(d,s,n) bcopy ((s), (d), (n))
29 #define memmove(d,s,n) bcopy ((s), (d), (n))
30 #endif /* ! HAVE_MEMCPY */
31 #endif /* STDC_HEADERS */
32
33 #include <utime.h>
34 #ifdef HAVE_FCNTL_H
35 #include <fcntl.h>
36 #endif /* HAVE_FCNTL_H */
37 #include <dirent.h>
38 #include <sys/mman.h>
39 #include <errno.h>
40
41 #include <atalk/logger.h>
42 #include <sys/types.h>
43 #include <sys/time.h>
44 #include <sys/param.h>
45 #include <sys/stat.h>
46
47 #include <netatalk/endian.h>
48 #include <atalk/adouble.h>
49 #include <atalk/afp.h>
50 #include <atalk/util.h>
51 #ifdef CNID_DB
52 #include <atalk/cnid.h>
53 #endif /* CNID_DB */
54 #include "directory.h"
55 #include "desktop.h"
56 #include "volume.h"
57 #include "fork.h"
58 #include "file.h"
59 #include "filedir.h"
60 #include "globals.h"
61
62 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
63  * field         bytes        subfield    bytes
64  * 
65  * files:
66  * ioFlFndrInfo  16      ->       type    4  type field
67  *                             creator    4  creator field
68  *                               flags    2  finder flags:
69  *                                           alias, bundle, etc.
70  *                            location    4  location in window
71  *                              folder    2  window that contains file
72  * 
73  * ioFlXFndrInfo 16      ->     iconID    2  icon id
74  *                              unused    6  reserved 
75  *                              script    1  script system
76  *                              xflags    1  reserved
77  *                           commentID    2  comment id
78  *                           putawayID    4  home directory id
79  */
80
81 const u_char ufinderi[] = {
82                               'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
83                               0, 0, 0, 0, 0, 0, 0, 0,
84                               0, 0, 0, 0, 0, 0, 0, 0,
85                               0, 0, 0, 0, 0, 0, 0, 0
86                           };
87
88 /* FIXME mpath : unix or mac name ? (for now it's mac name ) */
89 void *get_finderinfo(const char *mpath, struct adouble *adp, void *data)
90 {
91     struct extmap       *em;
92
93     if (adp) {
94         memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
95     }
96     else {
97         memcpy(data, ufinderi, 32);
98     }
99
100     if ((!adp  || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 )) 
101                 && (em = getextmap( mpath ))
102     ) {
103         memcpy(data, em->em_type, sizeof( em->em_type ));
104         memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
105     }
106     return data;
107 }
108
109 /* ---------------------
110 */
111 char *set_name(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@ibm.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 (( vol = getvolbyvid( vid )) == NULL ) {
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 (( dir = dirlookup( vol, did )) == NULL ) {
549         return afp_errno;
550     }
551
552     if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
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 (( vol = getvolbyvid( vid )) == NULL ) {
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 (( dir = dirlookup( vol, did )) == NULL ) {
658         return( AFPERR_NOOBJ );
659     }
660
661     memcpy(&bitmap, ibuf, sizeof( bitmap ));
662     bitmap = ntohs( bitmap );
663     ibuf += sizeof( bitmap );
664
665     if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
666         return afp_errno;
667     }
668
669     if ( *s_path->m_name == '\0' ) {
670         return( AFPERR_BADTYPE ); /* it's a directory */
671     }
672
673     if ((u_long)ibuf & 1 ) {
674         ibuf++;
675     }
676
677     if (( rc = setfilparams(vol, s_path, bitmap, ibuf )) == AFP_OK ) {
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 defined strings for the simple cases, and convert
804                all else into pXYY per Inside Appletalk.  Always set
805                the creator as "pdos". <shirsch@ibm.net> */
806         case FILPBIT_PDINFO :
807             achar = *buf;
808             buf += 2;
809             memcpy(&ashort, buf, sizeof( ashort ));
810             ashort = ntohs( ashort );
811             buf += 2;
812
813             switch ( (unsigned int) achar )
814             {
815             case 0x04 :
816                 fdType = ( u_char *) "TEXT";
817                 break;
818
819             case 0xff :
820                 fdType = ( u_char *) "PSYS";
821                 break;
822
823             case 0xb3 :
824                 fdType = ( u_char *) "PS16";
825                 break;
826
827             case 0x00 :
828                 fdType = ( u_char *) "BINA";
829                 break;
830
831             default :
832                 xyy[0] = ( u_char ) 'p';
833                 xyy[1] = achar;
834                 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
835                 xyy[3] = ( u_char ) ashort & 0xff;
836                 fdType = xyy;
837                 break;
838             }
839
840             memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
841             memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
842             break;
843
844
845         default :
846             err = AFPERR_BITMAP;
847             goto setfilparam_done;
848         }
849
850         bitmap = bitmap>>1;
851         bit++;
852     }
853
854 setfilparam_done:
855     if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
856        newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
857     }
858     if (newdate) {
859        if (isad)
860           ad_setdate(adp, AD_DATE_MODIFY, newdate);
861        ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
862        utime(upath, &ut);
863     }
864
865     if (isad) {
866         ad_flush( adp, ADFLAGS_HF );
867         ad_close( adp, ADFLAGS_HF );
868
869     }
870
871     if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
872         newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
873         bitmap = 1<<FILPBIT_MDATE;
874         setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
875     }
876
877 #ifdef DEBUG
878     LOG(log_info, logtype_afpd, "end setfilparams:");
879 #endif /* DEBUG */
880     return err;
881 }
882
883 /*
884  * renamefile and copyfile take the old and new unix pathnames
885  * and the new mac name.
886  * NOTE: if we have to copy a file instead of renaming it, locks
887  *       will break. Anyway it's an error because then we have 2 files.
888  *
889  * src         the source path 
890  * dst         the dest filename in current dir
891  * newname     the dest mac name
892  * adp         adouble struct of src file, if open, or & zeroed one
893  *
894  */
895 int renamefile(src, dst, newname, noadouble, adp )
896 char    *src, *dst, *newname;
897 const int         noadouble;
898 struct adouble    *adp;
899 {
900     char                adsrc[ MAXPATHLEN + 1];
901     int                 len, rc;
902
903     /*
904      * Note that this is only checking the existance of the data file,
905      * not the header file.  The thinking is that if the data file doesn't
906      * exist, but the header file does, the right thing to do is remove
907      * the data file silently.
908      */
909
910     /* existence check moved to afp_moveandrename */
911
912 #ifdef DEBUG
913     LOG(log_info, logtype_afpd, "begin renamefile:");
914 #endif /* DEBUG */
915
916     if ( unix_rename( src, dst ) < 0 ) {
917         switch ( errno ) {
918         case ENOENT :
919             return( AFPERR_NOOBJ );
920         case EPERM:
921         case EACCES :
922             return( AFPERR_ACCESS );
923         case EROFS:
924             return AFPERR_VLOCK;
925         case EXDEV :                    /* Cross device move -- try copy */
926             if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
927                 deletefile( dst, 0 );
928                 return( rc );
929             }
930             return deletefile( src, 0);
931         default :
932             return( AFPERR_PARAM );
933         }
934     }
935
936     strcpy( adsrc, ad_path( src, 0 ));
937     rc = 0;
938 rename_retry:
939     if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
940         struct stat st;
941
942         switch ( errno ) {
943         case ENOENT :
944             /* check for a source appledouble header. if it exists, make
945              * a dest appledouble directory and do the rename again. */
946             if (rc || stat(adsrc, &st) ||
947                     (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
948                 return AFP_OK;
949             rc++;
950             ad_close(adp, ADFLAGS_HF);
951             goto rename_retry;
952         case EPERM:
953         case EACCES :
954             return( AFPERR_ACCESS );
955         case EROFS:
956             return AFPERR_VLOCK;
957         default :
958             return( AFPERR_PARAM );
959         }
960     }
961
962     if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
963         switch ( errno ) {
964         case ENOENT :
965             return( AFPERR_NOOBJ );
966         case EACCES :
967             return( AFPERR_ACCESS );
968         case EROFS:
969             return AFPERR_VLOCK;
970         default :
971             return( AFPERR_PARAM );
972         }
973     }
974
975     len = strlen( newname );
976     ad_setentrylen( adp, ADEID_NAME, len );
977     memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
978     ad_flush( adp, ADFLAGS_HF );
979     ad_close( adp, ADFLAGS_HF );
980
981 #ifdef DEBUG
982     LOG(log_info, logtype_afpd, "end renamefile:");
983 #endif /* DEBUG */
984
985     return( AFP_OK );
986 }
987
988 int copy_path_name(char *newname, char *ibuf)
989 {
990 char        type = *ibuf;
991 size_t      plen = 0;
992 u_int16_t   len16;
993 u_int32_t   hint;
994
995     if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
996         return -1;
997     }
998     ibuf++;
999     switch (type) {
1000     case 2:
1001         if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1002             strncpy( newname, ibuf, plen );
1003             newname[ plen ] = '\0';
1004             if (strlen(newname) != plen) {
1005                 /* there's \0 in newname, e.g. it's a pathname not
1006                  * only a filename. 
1007                 */
1008                 return -1;
1009             }
1010         }
1011         break;
1012     case 3:
1013         memcpy(&hint, ibuf, sizeof(hint));
1014         ibuf += sizeof(hint);
1015            
1016         memcpy(&len16, ibuf, sizeof(len16));
1017         ibuf += sizeof(len16);
1018         plen = ntohs(len16);
1019         if (plen) {
1020             strncpy( newname, ibuf, plen );
1021             newname[ plen ] = '\0';
1022             if (strchr(newname,'/')) {
1023                 return -1;
1024             }
1025         }
1026         break;
1027     }
1028     return plen;
1029 }
1030
1031 /* -----------------------------------
1032 */
1033 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1034 AFPObj      *obj;
1035 char    *ibuf, *rbuf;
1036 int             ibuflen, *rbuflen;
1037 {
1038     struct vol  *vol;
1039     struct dir  *dir;
1040     char        *newname, *p, *upath;
1041     struct path *s_path;
1042     u_int32_t   sdid, ddid;
1043     int         err, retvalue = AFP_OK;
1044     u_int16_t   svid, dvid;
1045
1046 #ifdef DEBUG
1047     LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1048 #endif /* DEBUG */
1049
1050     *rbuflen = 0;
1051     ibuf += 2;
1052
1053     memcpy(&svid, ibuf, sizeof( svid ));
1054     ibuf += sizeof( svid );
1055     if (( vol = getvolbyvid( svid )) == NULL ) {
1056         return( AFPERR_PARAM );
1057     }
1058
1059     memcpy(&sdid, ibuf, sizeof( sdid ));
1060     ibuf += sizeof( sdid );
1061     if (( dir = dirlookup( vol, sdid )) == NULL ) {
1062         return afp_errno;
1063     }
1064
1065     memcpy(&dvid, ibuf, sizeof( dvid ));
1066     ibuf += sizeof( dvid );
1067     memcpy(&ddid, ibuf, sizeof( ddid ));
1068     ibuf += sizeof( ddid );
1069
1070     if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1071         return afp_errno;
1072     }
1073     if ( *s_path->m_name == '\0' ) {
1074         return( AFPERR_BADTYPE );
1075     }
1076
1077     /* don't allow copies when the file is open.
1078      * XXX: the spec only calls for read/deny write access.
1079      *      however, copyfile doesn't have any of that info,
1080      *      and locks need to stay coherent. as a result,
1081      *      we just balk if the file is opened already. */
1082
1083     newname = obj->newtmp;
1084     strcpy( newname, s_path->m_name );
1085
1086     if (of_findname(s_path))
1087         return AFPERR_DENYCONF;
1088
1089     p = ctoupath( vol, curdir, newname );
1090 #ifdef FORCE_UIDGID
1091     /* FIXME svid != dvid && dvid's user can't read svid */
1092 #endif
1093     if (( vol = getvolbyvid( dvid )) == NULL ) {
1094         return( AFPERR_PARAM );
1095     }
1096
1097     if (vol->v_flags & AFPVOL_RO)
1098         return AFPERR_VLOCK;
1099
1100     if (( dir = dirlookup( vol, ddid )) == NULL ) {
1101         return afp_errno;
1102     }
1103
1104     if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1105         return afp_errno;
1106     }
1107     if ( *s_path->m_name != '\0' ) {
1108         return( AFPERR_BADTYPE ); /* not a directory. AFPERR_PARAM? */
1109     }
1110
1111     /* one of the handful of places that knows about the path type */
1112     if (copy_path_name(newname, ibuf) < 0) {
1113         return( AFPERR_PARAM );
1114     }
1115
1116     upath = mtoupath(vol, newname);
1117     if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1118         return err;
1119     }
1120     curdir->offcnt++;
1121
1122 #ifdef DROPKLUDGE
1123     if (vol->v_flags & AFPVOL_DROPBOX) {
1124         retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1125     }
1126 #endif /* DROPKLUDGE */
1127
1128     setvoltime(obj, vol );
1129
1130 #ifdef DEBUG
1131     LOG(log_info, logtype_afpd, "end afp_copyfile:");
1132 #endif /* DEBUG */
1133
1134     return( retvalue );
1135 }
1136
1137
1138 static __inline__ int copy_all(const int dfd, const void *buf,
1139                                size_t buflen)
1140 {
1141     ssize_t cc;
1142
1143 #ifdef DEBUG
1144     LOG(log_info, logtype_afpd, "begin copy_all:");
1145 #endif /* DEBUG */
1146
1147     while (buflen > 0) {
1148         if ((cc = write(dfd, buf, buflen)) < 0) {
1149             switch (errno) {
1150             case EINTR:
1151                 continue;
1152             case EDQUOT:
1153             case EFBIG:
1154             case ENOSPC:
1155                 return AFPERR_DFULL;
1156             case EROFS:
1157                 return AFPERR_VLOCK;
1158             default:
1159                 return AFPERR_PARAM;
1160             }
1161         }
1162         buflen -= cc;
1163     }
1164
1165 #ifdef DEBUG
1166     LOG(log_info, logtype_afpd, "end copy_all:");
1167 #endif /* DEBUG */
1168
1169     return AFP_OK;
1170 }
1171
1172 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1173  * pass in vol and path */
1174 int copyfile(src, dst, newname, noadouble )
1175 char    *src, *dst, *newname;
1176 const int   noadouble;
1177 {
1178     struct adouble      ad;
1179 #ifdef SENDFILE_FLAVOR_LINUX
1180     struct stat         st;
1181 #endif
1182     char                filebuf[8192];
1183     int                 sfd, dfd, len, err = AFP_OK;
1184     ssize_t             cc;
1185     char                dpath[ MAXPATHLEN + 1];
1186     int                 admode;
1187 #ifdef DEBUG
1188     LOG(log_info, logtype_afpd, "begin copyfile:");
1189 #endif /* DEBUG */
1190
1191     strcpy(dpath, ad_path( dst, ADFLAGS_HF ));
1192     admode = ad_mode( dst, 0666 );
1193     if (newname) {
1194         if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1195             switch ( errno ) {
1196             case ENOENT :
1197                 break; /* just copy the data fork */
1198             case EACCES :
1199                 return( AFPERR_ACCESS );
1200             default :
1201                 return( AFPERR_PARAM );
1202             }
1203         } else {
1204             if (( dfd = open( dpath, O_WRONLY|O_CREAT,ad_hf_mode(admode))) < 0 ) {
1205                 close( sfd );
1206                 switch ( errno ) {
1207                 case ENOENT :
1208                     return( AFPERR_NOOBJ );
1209                 case EACCES :
1210                     return( AFPERR_ACCESS );
1211                 case EROFS:
1212                     return AFPERR_VLOCK;
1213                 default :
1214                     return( AFPERR_PARAM );
1215                 }
1216             }
1217
1218             /* copy the file */
1219 #ifdef SENDFILE_FLAVOR_LINUX
1220             if (fstat(sfd, &st) == 0) {
1221                 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1222                     switch (errno) {
1223                     case EDQUOT:
1224                     case EFBIG:
1225                     case ENOSPC:
1226                         err = AFPERR_DFULL;
1227                         break;
1228                     case EROFS:
1229                         err = AFPERR_VLOCK;
1230                         break;
1231                     default:
1232                         err = AFPERR_PARAM;
1233                     }
1234                 }
1235                 goto copyheader_done;
1236             }
1237 #endif /* SENDFILE_FLAVOR_LINUX */
1238             while (1) {
1239                 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1240                     if (errno == EINTR)
1241                         continue;
1242                     err = AFPERR_PARAM;
1243                     break;
1244                 }
1245
1246                 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1247                     break;
1248             }
1249
1250 copyheader_done:
1251             close(sfd);
1252             close(dfd);
1253             if (err < 0) {
1254                 unlink(dpath);
1255                 return err;
1256             }
1257         }
1258     }
1259
1260     /* data fork copying */
1261     if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1262         switch ( errno ) {
1263         case ENOENT :
1264             return( AFPERR_NOOBJ );
1265         case EACCES :
1266             return( AFPERR_ACCESS );
1267         default :
1268             return( AFPERR_PARAM );
1269         }
1270     }
1271
1272     if (( dfd = open( dst, O_WRONLY|O_CREAT, admode)) < 0 ) {
1273         close( sfd );
1274         switch ( errno ) {
1275         case ENOENT :
1276             return( AFPERR_NOOBJ );
1277         case EACCES :
1278             return( AFPERR_ACCESS );
1279         case EROFS:
1280             return AFPERR_VLOCK;
1281         default :
1282             return( AFPERR_PARAM );
1283         }
1284     }
1285
1286 #ifdef SENDFILE_FLAVOR_LINUX
1287     if (fstat(sfd, &st) == 0) {
1288         if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1289             switch (errno) {
1290             case EDQUOT:
1291             case EFBIG:
1292             case ENOSPC:
1293                 err = AFPERR_DFULL;
1294                 break;
1295             default:
1296                 err = AFPERR_PARAM;
1297             }
1298         }
1299         goto copydata_done;
1300     }
1301 #endif /* SENDFILE_FLAVOR_LINUX */
1302
1303     while (1) {
1304         if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1305             if (errno == EINTR)
1306                 continue;
1307
1308             err = AFPERR_PARAM;
1309             break;
1310         }
1311
1312         if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1313             break;
1314         }
1315     }
1316
1317 copydata_done:
1318     close(sfd);
1319     close(dfd);
1320     if (err < 0) {
1321         unlink(dpath);
1322         unlink(dst);
1323         return err;
1324     }
1325
1326     if (newname) {
1327         memset(&ad, 0, sizeof(ad));
1328         if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1329                       0666, &ad) < 0 ) {
1330             switch ( errno ) {
1331             case ENOENT :
1332                 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1333             case EACCES :
1334                 return( AFPERR_ACCESS );
1335             case EROFS:
1336                 return AFPERR_VLOCK;
1337             default :
1338                 return( AFPERR_PARAM );
1339             }
1340         }
1341
1342         len = strlen( newname );
1343         ad_setentrylen( &ad, ADEID_NAME, len );
1344         memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1345         ad_flush( &ad, ADFLAGS_HF );
1346         ad_close( &ad, ADFLAGS_HF );
1347     }
1348
1349 #ifdef DEBUG
1350     LOG(log_info, logtype_afpd, "end copyfile:");
1351 #endif /* DEBUG */
1352
1353     return( AFP_OK );
1354 }
1355
1356
1357 /* -----------------------------------
1358    checkAttrib:   1 check kFPDeleteInhibitBit 
1359    ie deletfile called by afp_delete
1360
1361    when deletefile is called we don't have lock on it, file is closed (for us)
1362    untrue if called by renamefile
1363 */
1364 int deletefile( file, checkAttrib )
1365 char            *file;
1366 int         checkAttrib;
1367 {
1368     struct adouble      ad;
1369     int                 adflags, err = AFP_OK;
1370     int                 locktype = ADLOCK_WR;
1371     int                 openmode = O_RDWR;
1372
1373 #ifdef DEBUG
1374     LOG(log_info, logtype_afpd, "begin deletefile:");
1375 #endif /* DEBUG */
1376
1377     while(1) {
1378         /*
1379          * If can't open read/write then try again read-only.  If it's open
1380          * read-only, we must do a read lock instead of a write lock.
1381          */
1382         /* try to open both at once */
1383         adflags = ADFLAGS_DF|ADFLAGS_HF;
1384         memset(&ad, 0, sizeof(ad));
1385         if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1386             switch (errno) {
1387             case ENOENT:
1388                 adflags = ADFLAGS_DF;
1389                 /* that failed. now try to open just the data fork */
1390                 memset(&ad, 0, sizeof(ad));
1391                 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1392                     switch (errno) {
1393                     case ENOENT:
1394                         return AFPERR_NOOBJ;
1395                     case EACCES:
1396                         if(openmode == O_RDWR) {
1397                             openmode = O_RDONLY;
1398                             locktype = ADLOCK_RD;
1399                             continue;
1400                         } else {
1401                             return AFPERR_ACCESS;
1402                         }
1403                     case EROFS:
1404                         return AFPERR_VLOCK;
1405                     default:
1406                         return AFPERR_PARAM;
1407                     }
1408                 }
1409                 break;
1410
1411             case EACCES:
1412                 if(openmode == O_RDWR) {
1413                     openmode = O_RDONLY;
1414                     locktype = ADLOCK_RD;
1415                     continue;
1416                 } else {
1417                     return AFPERR_ACCESS;
1418                 }
1419             case EROFS:
1420                 return AFPERR_VLOCK;
1421             default:
1422                 return( AFPERR_PARAM );
1423             }
1424         }
1425         break;  /* from the while */
1426     }
1427     /*
1428      * Does kFPDeleteInhibitBit (bit 8) set?
1429      */
1430     if (checkAttrib && (adflags & ADFLAGS_HF)) {
1431         u_int16_t   bshort;
1432
1433         ad_getattr(&ad, &bshort);
1434         if ((bshort & htons(ATTRBIT_NODELETE))) {
1435             ad_close( &ad, adflags );
1436             return(AFPERR_OLOCK);
1437         }
1438     }
1439     
1440     if ((adflags & ADFLAGS_HF) ) {
1441         /* FIXME we have a pb here because we want to know if a file is open 
1442          * there's a 'priority inversion' if you can't open the ressource fork RW
1443          * you can delete it if it's open because you can't get a write lock.
1444          * 
1445          * ADLOCK_FILELOCK means the whole ressource fork, not only after the 
1446          * metadatas
1447          *
1448          * FIXME it doesn't for RFORK open read only and fork open without deny mode
1449          */
1450         if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) {
1451             ad_close( &ad, adflags );
1452             return( AFPERR_BUSY );
1453         }
1454     }
1455
1456     if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1457         err = AFPERR_BUSY;
1458         goto delete_unlock;
1459     }
1460
1461     if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1462         switch ( errno ) {
1463         case EPERM:
1464         case EACCES :
1465             err = AFPERR_ACCESS;
1466             goto delete_unlock;
1467         case EROFS:
1468             err = AFPERR_VLOCK;
1469             goto delete_unlock;
1470         case ENOENT :
1471             break;
1472         default :
1473             err = AFPERR_PARAM;
1474             goto delete_unlock;
1475         }
1476     }
1477
1478     if ( unlink( file ) < 0 ) {
1479         switch ( errno ) {
1480         case EPERM:
1481         case EACCES :
1482             err = AFPERR_ACCESS;
1483             break;
1484         case EROFS:
1485             err = AFPERR_VLOCK;
1486             break;
1487         case ENOENT :
1488             break;
1489         default :
1490             err = AFPERR_PARAM;
1491             break;
1492         }
1493     }
1494
1495 delete_unlock:
1496     if (adflags & ADFLAGS_HF)
1497         ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0);
1498     ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1499     ad_close( &ad, adflags );
1500
1501 #ifdef DEBUG
1502     LOG(log_info, logtype_afpd, "end deletefile:");
1503 #endif /* DEBUG */
1504
1505     return err;
1506 }
1507
1508 /* ------------------------------------ */
1509 #ifdef CNID_DB
1510 /* return a file id */
1511 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1512 AFPObj      *obj;
1513 char    *ibuf, *rbuf;
1514 int             ibuflen, *rbuflen;
1515 {
1516     struct stat         *st;
1517 #if AD_VERSION > AD_VERSION1
1518     struct adouble      ad;
1519 #endif
1520     struct vol          *vol;
1521     struct dir          *dir;
1522     char                *upath;
1523     int                 len;
1524     cnid_t              did, id;
1525     u_short             vid;
1526     struct path         *s_path;
1527
1528 #ifdef DEBUG
1529     LOG(log_info, logtype_afpd, "begin afp_createid:");
1530 #endif /* DEBUG */
1531
1532     *rbuflen = 0;
1533     ibuf += 2;
1534
1535     memcpy(&vid, ibuf, sizeof(vid));
1536     ibuf += sizeof(vid);
1537
1538     if (( vol = getvolbyvid( vid )) == NULL ) {
1539         return( AFPERR_PARAM);
1540     }
1541
1542     if (vol->v_flags & AFPVOL_RO)
1543         return AFPERR_VLOCK;
1544
1545     memcpy(&did, ibuf, sizeof( did ));
1546     ibuf += sizeof(did);
1547
1548     if (( dir = dirlookup( vol, did )) == NULL ) {
1549         return( AFPERR_PARAM );
1550     }
1551
1552     if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1553         return( AFPERR_PARAM );
1554     }
1555
1556     if ( *s_path->m_name == '\0' ) {
1557         return( AFPERR_BADTYPE );
1558     }
1559
1560     upath = s_path->u_name;
1561     switch (s_path->st_errno) {
1562         case 0:
1563              break; /* success */
1564         case EPERM:
1565         case EACCES:
1566             return AFPERR_ACCESS;
1567         case ENOENT:
1568             return AFPERR_NOOBJ;
1569         default:
1570             return AFPERR_PARAM;
1571     }
1572     st = &s_path->st;
1573     if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1574         memcpy(rbuf, &id, sizeof(id));
1575         *rbuflen = sizeof(id);
1576         return AFPERR_EXISTID;
1577     }
1578
1579 #if AD_VERSION > AD_VERSION1
1580     memset(&ad, 0, sizeof(ad));
1581     if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1582         memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1583         ad_close(&ad, ADFLAGS_HF);
1584     }
1585 #endif /* AD_VERSION > AD_VERSION1 */
1586
1587     if ((id = cnid_add(vol->v_db, st, did, upath, len, id)) != CNID_INVALID) {
1588         memcpy(rbuf, &id, sizeof(id));
1589         *rbuflen = sizeof(id);
1590         return AFP_OK;
1591     }
1592
1593 #ifdef DEBUG
1594     LOG(log_info, logtype_afpd, "ending afp_createid...:");
1595 #endif /* DEBUG */
1596
1597     switch (errno) {
1598     case EROFS:
1599         return AFPERR_VLOCK;
1600         break;
1601     case EPERM:
1602     case EACCES:
1603         return AFPERR_ACCESS;
1604         break;
1605     default:
1606         LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1607         return AFPERR_PARAM;
1608     }
1609 }
1610
1611 /* ------------------------------
1612    resolve a file id */
1613 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1614 AFPObj      *obj;
1615 char    *ibuf, *rbuf;
1616 int             ibuflen, *rbuflen;
1617 {
1618     struct vol          *vol;
1619     struct dir          *dir;
1620     char                *upath;
1621     struct path         path;
1622     int                 err, buflen;
1623     cnid_t              id;
1624     u_int16_t           vid, bitmap;
1625
1626     static char buffer[12 + MAXPATHLEN + 1];
1627     int len = 12 + MAXPATHLEN + 1;
1628
1629 #ifdef DEBUG
1630     LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1631 #endif /* DEBUG */
1632
1633     *rbuflen = 0;
1634     ibuf += 2;
1635
1636     memcpy(&vid, ibuf, sizeof(vid));
1637     ibuf += sizeof(vid);
1638
1639     if (( vol = getvolbyvid( vid )) == NULL ) {
1640         return( AFPERR_PARAM);
1641     }
1642
1643     memcpy(&id, ibuf, sizeof( id ));
1644     ibuf += sizeof(id);
1645
1646     if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1647         return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1648     }
1649
1650     if (( dir = dirlookup( vol, id )) == NULL ) {
1651         return AFPERR_NOID; /* idem AFPERR_PARAM */
1652     }
1653     path.u_name = upath;
1654     if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1655         switch (errno) {
1656         case EACCES:
1657         case EPERM:
1658             return AFPERR_ACCESS;
1659         case ENOENT:
1660             return AFPERR_NOID;
1661         default:
1662             return AFPERR_PARAM;
1663         }
1664     }
1665     /* directories are bad */
1666     if (S_ISDIR(path.st.st_mode))
1667         return AFPERR_BADTYPE;
1668
1669     memcpy(&bitmap, ibuf, sizeof(bitmap));
1670     bitmap = ntohs( bitmap );
1671     path.m_name = utompath(vol, upath);
1672     if ((err = getfilparams(vol, bitmap, &path , curdir, 
1673                             rbuf + sizeof(bitmap), &buflen)) != AFP_OK) {
1674         return err;
1675     }
1676     *rbuflen = buflen + sizeof(bitmap);
1677     memcpy(rbuf, ibuf, sizeof(bitmap));
1678
1679 #ifdef DEBUG
1680     LOG(log_info, logtype_afpd, "end afp_resolveid:");
1681 #endif /* DEBUG */
1682
1683     return AFP_OK;
1684 }
1685
1686 /* ------------------------------ */
1687 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1688 AFPObj      *obj;
1689 char    *ibuf, *rbuf;
1690 int             ibuflen, *rbuflen;
1691 {
1692     struct stat         st;
1693     struct vol          *vol;
1694     struct dir          *dir;
1695     char                *upath;
1696     int                 err;
1697     cnid_t              id;
1698     cnid_t              fileid;
1699     u_short             vid;
1700     static char buffer[12 + MAXPATHLEN + 1];
1701     int len = 12 + MAXPATHLEN + 1;
1702
1703 #ifdef DEBUG
1704     LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1705 #endif /* DEBUG */
1706
1707     *rbuflen = 0;
1708     ibuf += 2;
1709
1710     memcpy(&vid, ibuf, sizeof(vid));
1711     ibuf += sizeof(vid);
1712
1713     if (( vol = getvolbyvid( vid )) == NULL ) {
1714         return( AFPERR_PARAM);
1715     }
1716
1717     if (vol->v_flags & AFPVOL_RO)
1718         return AFPERR_VLOCK;
1719
1720     memcpy(&id, ibuf, sizeof( id ));
1721     ibuf += sizeof(id);
1722     fileid = id;
1723
1724     if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1725         return AFPERR_NOID;
1726     }
1727
1728     if (( dir = dirlookup( vol, id )) == NULL ) {
1729         return( AFPERR_PARAM );
1730     }
1731
1732     err = AFP_OK;
1733     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1734         switch (errno) {
1735         case EACCES:
1736         case EPERM:
1737             return AFPERR_ACCESS;
1738         case ENOENT:
1739             /* still try to delete the id */
1740             err = AFPERR_NOOBJ;
1741             break;
1742         default:
1743             return AFPERR_PARAM;
1744         }
1745     }
1746
1747     /* directories are bad */
1748     if (S_ISDIR(st.st_mode))
1749         return AFPERR_BADTYPE;
1750
1751     if (cnid_delete(vol->v_db, fileid)) {
1752         switch (errno) {
1753         case EROFS:
1754             return AFPERR_VLOCK;
1755         case EPERM:
1756         case EACCES:
1757             return AFPERR_ACCESS;
1758         default:
1759             return AFPERR_PARAM;
1760         }
1761     }
1762
1763 #ifdef DEBUG
1764     LOG(log_info, logtype_afpd, "end afp_deleteid:");
1765 #endif /* DEBUG */
1766
1767     return err;
1768 }
1769 #endif /* CNID_DB */
1770
1771 #define APPLETEMP ".AppleTempXXXXXX"
1772
1773 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1774 AFPObj      *obj;
1775 char    *ibuf, *rbuf;
1776 int             ibuflen, *rbuflen;
1777 {
1778     struct stat         srcst, destst;
1779     struct vol          *vol;
1780     struct dir          *dir, *sdir;
1781     char                *spath, temp[17], *p;
1782     char                *supath, *upath;
1783     struct path         *path;
1784     int                 err;
1785     struct adouble      ads;
1786     struct adouble      add;
1787     struct adouble      *adsp;
1788     struct adouble      *addp;
1789     struct ofork        *s_of;
1790     struct ofork        *d_of;
1791     
1792 #ifdef CNID_DB
1793     int                 slen, dlen;
1794 #endif /* CNID_DB */
1795     u_int32_t           sid, did;
1796     u_int16_t           vid;
1797
1798 #ifdef DEBUG
1799     LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1800 #endif /* DEBUG */
1801
1802     *rbuflen = 0;
1803     ibuf += 2;
1804
1805     memcpy(&vid, ibuf, sizeof(vid));
1806     ibuf += sizeof(vid);
1807
1808     if (( vol = getvolbyvid( vid )) == NULL ) {
1809         return( AFPERR_PARAM);
1810     }
1811
1812     if (vol->v_flags & AFPVOL_RO)
1813         return AFPERR_VLOCK;
1814
1815     /* source and destination dids */
1816     memcpy(&sid, ibuf, sizeof(sid));
1817     ibuf += sizeof(sid);
1818     memcpy(&did, ibuf, sizeof(did));
1819     ibuf += sizeof(did);
1820
1821     /* source file */
1822     if ((dir = dirlookup( vol, sid )) == NULL ) {
1823         return( AFPERR_PARAM );
1824     }
1825
1826     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1827         return( AFPERR_PARAM );
1828     }
1829
1830     if ( *path->m_name == '\0' ) {
1831         return( AFPERR_BADTYPE );   /* it's a dir */
1832     }
1833
1834     upath = path->u_name;
1835     switch (path->st_errno) {
1836         case 0:
1837              break;
1838         case ENOENT:
1839             return AFPERR_NOID;
1840         case EPERM:
1841         case EACCES:
1842             return AFPERR_ACCESS;
1843         default:
1844             return AFPERR_PARAM;
1845     }
1846     memset(&ads, 0, sizeof(ads));
1847     adsp = &ads;
1848     if ((s_of = of_findname(path))) {
1849             /* reuse struct adouble so it won't break locks */
1850             adsp = s_of->of_ad;
1851     }
1852     memcpy(&srcst, &path->st, sizeof(struct stat));
1853     /* save some stuff */
1854     sdir = curdir;
1855     spath = obj->oldtmp;
1856     supath = obj->newtmp;
1857     strcpy(spath, path->m_name);
1858     strcpy(supath, upath); /* this is for the cnid changing */
1859     p = absupath( vol, sdir, upath);
1860
1861     /* look for the source cnid. if it doesn't exist, don't worry about
1862      * it. */
1863 #ifdef CNID_DB
1864     sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1865                       slen = strlen(supath));
1866 #endif /* CNID_DB */
1867
1868     if (( dir = dirlookup( vol, did )) == NULL ) {
1869         return( AFPERR_PARAM );
1870     }
1871
1872     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1873         return( AFPERR_PARAM );
1874     }
1875
1876     if ( *path->m_name == '\0' ) {
1877         return( AFPERR_BADTYPE );
1878     }
1879
1880     /* FPExchangeFiles is the only call that can return the SameObj
1881      * error */
1882     if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1883         return AFPERR_SAMEOBJ;
1884     memcpy(&srcst, &path->st, sizeof(struct stat));
1885
1886     switch (errno) {
1887         case 0:
1888              break;
1889         case ENOENT:
1890             return AFPERR_NOID;
1891         case EPERM:
1892         case EACCES:
1893             return AFPERR_ACCESS;
1894         default:
1895             return AFPERR_PARAM;
1896     }
1897     memset(&add, 0, sizeof(add));
1898     addp = &add;
1899     if ((d_of = of_findname( path))) {
1900             /* reuse struct adouble so it won't break locks */
1901             addp = d_of->of_ad;
1902     }
1903     memcpy(&destst, &path->st, sizeof(struct stat));
1904
1905     /* they are not on the same device and at least one is open
1906     */
1907     if ((d_of || s_of)  && srcst.st_dev != destst.st_dev)
1908         return AFPERR_MISC;
1909     
1910     upath = path->u_name;
1911 #ifdef CNID_DB
1912     /* look for destination id. */
1913     did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1914                       dlen = strlen(upath));
1915 #endif /* CNID_DB */
1916
1917     /* construct a temp name.
1918      * NOTE: the temp file will be in the dest file's directory. it
1919      * will also be inaccessible from AFP. */
1920     memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1921     if (!mktemp(temp))
1922         return AFPERR_MISC;
1923
1924     /* now, quickly rename the file. we error if we can't. */
1925     if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1926         goto err_exchangefile;
1927     of_rename(vol, s_of, sdir, spath, curdir, temp);
1928
1929     /* rename destination to source */
1930     if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1931         goto err_src_to_tmp;
1932     of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1933
1934     /* rename temp to destination */
1935     if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1936         goto err_dest_to_src;
1937     of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1938
1939 #ifdef CNID_DB
1940     /* id's need switching. src -> dest and dest -> src. */
1941     if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1942                             upath, dlen) < 0)) {
1943         switch (errno) {
1944         case EPERM:
1945         case EACCES:
1946             err = AFPERR_ACCESS;
1947             break;
1948         default:
1949             err = AFPERR_PARAM;
1950         }
1951         goto err_temp_to_dest;
1952     }
1953
1954     if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1955                             supath, slen) < 0)) {
1956         switch (errno) {
1957         case EPERM:
1958         case EACCES:
1959             err = AFPERR_ACCESS;
1960             break;
1961         default:
1962             err = AFPERR_PARAM;
1963         }
1964
1965         if (sid)
1966             cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1967         goto err_temp_to_dest;
1968     }
1969 #endif /* CNID_DB */
1970
1971 #ifdef DEBUG
1972     LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1973 #endif /* DEBUG */
1974
1975     return AFP_OK;
1976
1977
1978     /* all this stuff is so that we can unwind a failed operation
1979      * properly. */
1980 #ifdef CNID_DB
1981 err_temp_to_dest:
1982 #endif
1983     /* rename dest to temp */
1984     renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1985     of_rename(vol, s_of, curdir, upath, curdir, temp);
1986
1987 err_dest_to_src:
1988     /* rename source back to dest */
1989     renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1990     of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1991
1992 err_src_to_tmp:
1993     /* rename temp back to source */
1994     renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1995     of_rename(vol, s_of, curdir, temp, sdir, spath);
1996
1997 err_exchangefile:
1998     return err;
1999 }