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