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