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