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