]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/file.c
afp_createfile initalize of pointer before use help :(
[netatalk.git] / etc / afpd / file.c
1 /*
2  * $Id: file.c,v 1.59 2002-09-11 03:03:27 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(upath, st))) {
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 = NULL;
428     char                *path, *upath;
429     int                 creatf, did, openf, retvalue = AFP_OK;
430     u_int16_t           vid;
431     int                 ret;
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     if (0 != (ret = check_name(vol, upath))) 
463        return  ret;
464
465     ret = stat(upath, &st);
466     /* if upath is deleted we already in trouble anyway */
467     if (!ret && (of = of_findname(upath, &st))) {
468         adp = of->of_ad;
469     } else {
470         memset(&ad, 0, sizeof(ad));
471         adp = &ad;
472     }
473     if ( creatf) {
474         /* on a hard create, fail if file exists and is open */
475         if (!ret && of)
476             return AFPERR_BUSY;
477         openf = O_RDWR|O_CREAT|O_TRUNC;
478     } else {
479         /* on a soft create, if the file is open then ad_open won't fail
480            because open syscall is not called
481         */
482         if (of) {
483                 return AFPERR_EXIST;
484         }
485         openf = O_RDWR|O_CREAT|O_EXCL;
486     }
487
488     if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
489                   openf, 0666, adp) < 0 ) {
490         switch ( errno ) {
491         case EEXIST :
492             return( AFPERR_EXIST );
493         case EACCES :
494             return( AFPERR_ACCESS );
495         case ENOENT:
496             /* on noadouble volumes, just creating the data fork is ok */
497             if (vol_noadouble(vol) && (stat(upath, &st) == 0))
498                 goto createfile_done;
499             /* fallthrough */
500         default :
501             return( AFPERR_PARAM );
502         }
503     }
504
505     ad_setentrylen( adp, ADEID_NAME, strlen( path ));
506     memcpy(ad_entry( adp, ADEID_NAME ), path,
507            ad_getentrylen( adp, ADEID_NAME ));
508     ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
509     ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
510
511 createfile_done:
512
513 #ifdef DROPKLUDGE
514     if (vol->v_flags & AFPVOL_DROPBOX) {
515         retvalue = matchfile2dirperms(upath, vol, did);
516     }
517 #endif /* DROPKLUDGE */
518
519     setvoltime(obj, vol );
520
521 #ifdef DEBUG
522     LOG(log_info, logtype_afpd, "end afp_createfile");
523 #endif /* DEBUG */
524
525     return (retvalue);
526 }
527
528 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
529 AFPObj      *obj;
530 char    *ibuf, *rbuf;
531 int             ibuflen, *rbuflen;
532 {
533     struct vol  *vol;
534     struct dir  *dir;
535     char        *path;
536     int         did, rc;
537     u_int16_t   vid, bitmap;
538
539 #ifdef DEBUG
540     LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
541 #endif /* DEBUG */
542
543     *rbuflen = 0;
544     ibuf += 2;
545
546     memcpy(&vid, ibuf, sizeof( vid ));
547     ibuf += sizeof( vid );
548     if (( vol = getvolbyvid( vid )) == NULL ) {
549         return( AFPERR_PARAM );
550     }
551
552     if (vol->v_flags & AFPVOL_RO)
553         return AFPERR_VLOCK;
554
555     memcpy(&did, ibuf, sizeof( did ));
556     ibuf += sizeof( did );
557     if (( dir = dirsearch( vol, did )) == NULL ) {
558         return( AFPERR_NOOBJ );
559     }
560
561     memcpy(&bitmap, ibuf, sizeof( bitmap ));
562     bitmap = ntohs( bitmap );
563     ibuf += sizeof( bitmap );
564
565     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
566         return( AFPERR_NOOBJ );
567     }
568
569     if ( *path == '\0' ) {
570         return( AFPERR_BADTYPE ); /* it's a directory */
571     }
572
573     if ((u_long)ibuf & 1 ) {
574         ibuf++;
575     }
576
577     if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
578         setvoltime(obj, vol );
579     }
580
581 #ifdef DEBUG
582     LOG(log_info, logtype_afpd, "end afp_setfilparams:");
583 #endif /* DEBUG */
584
585     return( rc );
586 }
587
588 /*
589  * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic  
590  *
591 */
592
593 int setfilparams(struct vol *vol,
594                  char *path, u_int16_t bitmap, char *buf )
595 {
596     struct adouble      ad, *adp;
597     struct ofork        *of;
598     struct extmap       *em;
599     int                 bit = 0, isad = 1, err = AFP_OK;
600     char                *upath;
601     u_char              achar, *fdType, xyy[4];
602     u_int16_t           ashort, bshort;
603     u_int32_t           aint;
604     struct utimbuf      ut;
605
606     int                 change_mdate = 0;
607     int                 change_parent_mdate = 0;
608     int                 newdate = 0;
609     struct timeval      tv;
610
611
612 #ifdef DEBUG
613     LOG(log_info, logtype_afpd, "begin setfilparams:");
614 #endif /* DEBUG */
615
616     upath = mtoupath(vol, path);
617     if ((of = of_findname(upath, NULL))) {
618         adp = of->of_ad;
619     } else {
620         memset(&ad, 0, sizeof(ad));
621         adp = &ad;
622     }
623
624     if (check_access(upath, OPENACC_WR ) < 0) {
625         return AFPERR_ACCESS;
626     }
627
628     if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
629                  O_RDWR|O_CREAT, 0666, adp) < 0) {
630         /* for some things, we don't need an adouble header */
631         if (bitmap & ~(1<<FILPBIT_MDATE)) {
632             return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
633         }
634         isad = 0;
635     } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
636         ad_setentrylen( adp, ADEID_NAME, strlen( path ));
637         memcpy(ad_entry( adp, ADEID_NAME ), path,
638                ad_getentrylen( adp, ADEID_NAME ));
639     }
640
641     while ( bitmap != 0 ) {
642         while (( bitmap & 1 ) == 0 ) {
643             bitmap = bitmap>>1;
644             bit++;
645         }
646
647         switch(  bit ) {
648         case FILPBIT_ATTR :
649             change_mdate = 1;
650             memcpy(&ashort, buf, sizeof( ashort ));
651             ad_getattr(adp, &bshort);
652             if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
653                 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
654             } else {
655                 bshort &= ~ashort;
656             }
657             if ((ashort & htons(ATTRBIT_INVISIBLE)))
658                 change_parent_mdate = 1;
659             ad_setattr(adp, bshort);
660             buf += sizeof( ashort );
661             break;
662
663         case FILPBIT_CDATE :
664             change_mdate = 1;
665             memcpy(&aint, buf, sizeof(aint));
666             ad_setdate(adp, AD_DATE_CREATE, aint);
667             buf += sizeof( aint );
668             break;
669
670         case FILPBIT_MDATE :
671             memcpy(&newdate, buf, sizeof( newdate ));
672             buf += sizeof( newdate );
673             break;
674
675         case FILPBIT_BDATE :
676             change_mdate = 1;
677             memcpy(&aint, buf, sizeof(aint));
678             ad_setdate(adp, AD_DATE_BACKUP, aint);
679             buf += sizeof( aint );
680             break;
681
682         case FILPBIT_FINFO :
683             change_mdate = 1;
684
685             if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
686                     && ( 
687                      ((em = getextmap( path )) &&
688                       !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
689                       !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
690                      || ((em = getdefextmap()) &&
691                       !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
692                       !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
693             )) {
694                 memcpy(buf, ufinderi, 8 );
695             }
696
697             memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
698             buf += 32;
699             break;
700
701             /* Client needs to set the ProDOS file info for this file.
702                Use defined strings for the simple cases, and convert
703                all else into pXYY per Inside Appletalk.  Always set
704                the creator as "pdos". <shirsch@ibm.net> */
705         case FILPBIT_PDINFO :
706             achar = *buf;
707             buf += 2;
708             memcpy(&ashort, buf, sizeof( ashort ));
709             ashort = ntohs( ashort );
710             buf += 2;
711
712             switch ( (unsigned int) achar )
713             {
714             case 0x04 :
715                 fdType = ( u_char *) "TEXT";
716                 break;
717
718             case 0xff :
719                 fdType = ( u_char *) "PSYS";
720                 break;
721
722             case 0xb3 :
723                 fdType = ( u_char *) "PS16";
724                 break;
725
726             case 0x00 :
727                 fdType = ( u_char *) "BINA";
728                 break;
729
730             default :
731                 xyy[0] = ( u_char ) 'p';
732                 xyy[1] = achar;
733                 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
734                 xyy[3] = ( u_char ) ashort & 0xff;
735                 fdType = xyy;
736                 break;
737             }
738
739             memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
740             memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
741             break;
742
743
744         default :
745             err = AFPERR_BITMAP;
746             goto setfilparam_done;
747         }
748
749         bitmap = bitmap>>1;
750         bit++;
751     }
752
753 setfilparam_done:
754     if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
755        newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
756     }
757     if (newdate) {
758        if (isad)
759           ad_setdate(adp, AD_DATE_MODIFY, newdate);
760        ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
761        utime(upath, &ut);
762     }
763
764     if (isad) {
765         ad_flush( adp, ADFLAGS_HF );
766         ad_close( adp, ADFLAGS_HF );
767
768     }
769
770     if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
771         newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
772         bitmap = 1<<FILPBIT_MDATE;
773         setdirparams(vol, "", bitmap, (char *)&newdate);
774     }
775
776 #ifdef DEBUG
777     LOG(log_info, logtype_afpd, "end setfilparams:");
778 #endif /* DEBUG */
779     return err;
780 }
781
782 /*
783  * renamefile and copyfile take the old and new unix pathnames
784  * and the new mac name.
785  * NOTE: if we have to copy a file instead of renaming it, locks
786  *       will break. Anyway it's an error because then we have 2 files.
787  *
788  * src         the source path 
789  * dst         the dest filename in current dir
790  * newname     the dest mac name
791  * adp         adouble struct of src file, if open, or & zeroed one
792  *
793  */
794 int renamefile(src, dst, newname, noadouble, adp )
795 char    *src, *dst, *newname;
796 const int         noadouble;
797 struct adouble    *adp;
798 {
799     char                adsrc[ MAXPATHLEN + 1];
800     int                 len, rc;
801
802     /*
803      * Note that this is only checking the existance of the data file,
804      * not the header file.  The thinking is that if the data file doesn't
805      * exist, but the header file does, the right thing to do is remove
806      * the data file silently.
807      */
808
809     /* existence check moved to afp_moveandrename */
810
811 #ifdef DEBUG
812     LOG(log_info, logtype_afpd, "begin renamefile:");
813 #endif /* DEBUG */
814
815     if ( rename( src, dst ) < 0 ) {
816         switch ( errno ) {
817         case ENOENT :
818             return( AFPERR_NOOBJ );
819         case EPERM:
820         case EACCES :
821             return( AFPERR_ACCESS );
822         case EROFS:
823             return AFPERR_VLOCK;
824         case EXDEV :                    /* Cross device move -- try copy */
825             if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
826                 deletefile( dst, 0 );
827                 return( rc );
828             }
829             return deletefile( src, 0);
830         default :
831             return( AFPERR_PARAM );
832         }
833     }
834
835     strcpy( adsrc, ad_path( src, 0 ));
836     rc = 0;
837 rename_retry:
838     if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
839         struct stat st;
840
841         switch ( errno ) {
842         case ENOENT :
843             /* check for a source appledouble header. if it exists, make
844              * a dest appledouble directory and do the rename again. */
845             if (rc || stat(adsrc, &st) ||
846                     (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
847                 return AFP_OK;
848             rc++;
849             ad_close(adp, ADFLAGS_HF);
850             goto rename_retry;
851         case EPERM:
852         case EACCES :
853             return( AFPERR_ACCESS );
854         case EROFS:
855             return AFPERR_VLOCK;
856         default :
857             return( AFPERR_PARAM );
858         }
859     }
860
861     if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
862         switch ( errno ) {
863         case ENOENT :
864             return( AFPERR_NOOBJ );
865         case EACCES :
866             return( AFPERR_ACCESS );
867         case EROFS:
868             return AFPERR_VLOCK;
869         default :
870             return( AFPERR_PARAM );
871         }
872     }
873
874     len = strlen( newname );
875     ad_setentrylen( adp, ADEID_NAME, len );
876     memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
877     ad_flush( adp, ADFLAGS_HF );
878     ad_close( adp, ADFLAGS_HF );
879
880 #ifdef DEBUG
881     LOG(log_info, logtype_afpd, "end renamefile:");
882 #endif /* DEBUG */
883
884     return( AFP_OK );
885 }
886
887 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
888 AFPObj      *obj;
889 char    *ibuf, *rbuf;
890 int             ibuflen, *rbuflen;
891 {
892     struct vol  *vol;
893     struct dir  *dir;
894     char        *newname, *path, *p, *upath;
895     u_int32_t   sdid, ddid;
896     int         plen, err, retvalue = AFP_OK;
897     u_int16_t   svid, dvid;
898
899 #ifdef DEBUG
900     LOG(log_info, logtype_afpd, "begin afp_copyfile:");
901 #endif /* DEBUG */
902
903     *rbuflen = 0;
904     ibuf += 2;
905
906     memcpy(&svid, ibuf, sizeof( svid ));
907     ibuf += sizeof( svid );
908     if (( vol = getvolbyvid( svid )) == NULL ) {
909         return( AFPERR_PARAM );
910     }
911
912     memcpy(&sdid, ibuf, sizeof( sdid ));
913     ibuf += sizeof( sdid );
914     if (( dir = dirsearch( vol, sdid )) == NULL ) {
915         return( AFPERR_PARAM );
916     }
917
918     memcpy(&dvid, ibuf, sizeof( dvid ));
919     ibuf += sizeof( dvid );
920     memcpy(&ddid, ibuf, sizeof( ddid ));
921     ibuf += sizeof( ddid );
922
923     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
924         return( AFPERR_NOOBJ );
925     }
926     if ( *path == '\0' ) {
927         return( AFPERR_BADTYPE );
928     }
929
930     /* don't allow copies when the file is open.
931      * XXX: the spec only calls for read/deny write access.
932      *      however, copyfile doesn't have any of that info,
933      *      and locks need to stay coherent. as a result,
934      *      we just balk if the file is opened already. */
935
936     newname = obj->newtmp;
937     strcpy( newname, path );
938
939     upath = mtoupath(vol, newname );
940     if (of_findname(upath, NULL))
941         return AFPERR_DENYCONF;
942
943     p = ctoupath( vol, curdir, newname );
944 #ifdef FORCE_UIDGID
945     /* FIXME svid != dvid && dvid's user can't read svid */
946 #endif
947     if (( vol = getvolbyvid( dvid )) == NULL ) {
948         return( AFPERR_PARAM );
949     }
950
951     if (vol->v_flags & AFPVOL_RO)
952         return AFPERR_VLOCK;
953
954     if (( dir = dirsearch( vol, ddid )) == NULL ) {
955         return( AFPERR_PARAM );
956     }
957
958     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
959         return( AFPERR_NOOBJ );
960     }
961     if ( *path != '\0' ) {
962         return( AFPERR_BADTYPE ); /* not a directory. AFPERR_PARAM? */
963     }
964
965     /* one of the handful of places that knows about the path type */
966     if ( *ibuf++ != 2 ) {
967         return( AFPERR_PARAM );
968     }
969     if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
970         strncpy( newname, ibuf, plen );
971         newname[ plen ] = '\0';
972         if (strlen(newname) != plen) {
973             /* there's \0 in newname, e.g. it's a pathname not
974              * only a filename. 
975             */
976             return( AFPERR_PARAM );
977         }
978     }
979     upath = mtoupath(vol, newname);
980     if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
981         return err;
982     }
983
984 #ifdef DROPKLUDGE
985     if (vol->v_flags & AFPVOL_DROPBOX) {
986         retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
987     }
988 #endif /* DROPKLUDGE */
989
990     setvoltime(obj, vol );
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[ MAXPATHLEN + 1];
1046     int                 admode;
1047 #ifdef DEBUG
1048     LOG(log_info, logtype_afpd, "begin copyfile:");
1049 #endif /* DEBUG */
1050
1051     strcpy(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        *s_of;
1645     struct ofork        *d_of;
1646     
1647 #ifdef CNID_DB
1648     int                 slen, dlen;
1649 #endif /* CNID_DB */
1650     u_int32_t           sid, did;
1651     u_int16_t           vid;
1652
1653 #ifdef DEBUG
1654     LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1655 #endif /* DEBUG */
1656
1657     *rbuflen = 0;
1658     ibuf += 2;
1659
1660     memcpy(&vid, ibuf, sizeof(vid));
1661     ibuf += sizeof(vid);
1662
1663     if (( vol = getvolbyvid( vid )) == NULL ) {
1664         return( AFPERR_PARAM);
1665     }
1666
1667     if (vol->v_flags & AFPVOL_RO)
1668         return AFPERR_VLOCK;
1669
1670     /* source and destination dids */
1671     memcpy(&sid, ibuf, sizeof(sid));
1672     ibuf += sizeof(sid);
1673     memcpy(&did, ibuf, sizeof(did));
1674     ibuf += sizeof(did);
1675
1676     /* source file */
1677     if ((dir = dirsearch( vol, sid )) == NULL ) {
1678         return( AFPERR_PARAM );
1679     }
1680
1681     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1682         return( AFPERR_PARAM );
1683     }
1684
1685     if ( *path == '\0' ) {
1686         return( AFPERR_BADTYPE );   /* it's a dir */
1687     }
1688
1689     upath = mtoupath(vol, path);
1690     if (stat(upath, &srcst) < 0) {
1691         switch (errno) {
1692         case ENOENT:
1693             return AFPERR_NOID;
1694         case EPERM:
1695         case EACCES:
1696             return AFPERR_ACCESS;
1697         default:
1698             return AFPERR_PARAM;
1699         }
1700     }
1701     memset(&ads, 0, sizeof(ads));
1702     adsp = &ads;
1703     if ((s_of = of_findname(upath, &srcst))) {
1704             /* reuse struct adouble so it won't break locks */
1705             adsp = s_of->of_ad;
1706     }
1707     /* save some stuff */
1708     sdir = curdir;
1709     spath = obj->oldtmp;
1710     supath = obj->newtmp;
1711     strcpy(spath, path);
1712     strcpy(supath, upath); /* this is for the cnid changing */
1713     p = ctoupath( vol, sdir, spath);
1714
1715     /* look for the source cnid. if it doesn't exist, don't worry about
1716      * it. */
1717 #ifdef CNID_DB
1718     sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1719                       slen = strlen(supath));
1720 #endif /* CNID_DB */
1721
1722     if (( dir = dirsearch( vol, did )) == NULL ) {
1723         return( AFPERR_PARAM );
1724     }
1725
1726     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1727         return( AFPERR_PARAM );
1728     }
1729
1730     if ( *path == '\0' ) {
1731         return( AFPERR_BADTYPE );
1732     }
1733
1734     /* FPExchangeFiles is the only call that can return the SameObj
1735      * error */
1736     if ((curdir == sdir) && strcmp(spath, path) == 0)
1737         return AFPERR_SAMEOBJ;
1738
1739     upath = mtoupath(vol, path);
1740     if (stat(upath, &destst) < 0) {
1741         switch (errno) {
1742         case ENOENT:
1743             return AFPERR_NOID;
1744         case EPERM:
1745         case EACCES:
1746             return AFPERR_ACCESS;
1747         default:
1748             return AFPERR_PARAM;
1749         }
1750     }
1751     memset(&add, 0, sizeof(add));
1752     addp = &add;
1753     if ((d_of = of_findname( upath, &destst))) {
1754             /* reuse struct adouble so it won't break locks */
1755             addp = d_of->of_ad;
1756     }
1757
1758     /* they are not on the same device and at least one is open
1759     */
1760     if ((d_of || s_of)  && srcst.st_dev != destst.st_dev)
1761         return AFPERR_MISC;
1762     
1763 #ifdef CNID_DB
1764     /* look for destination id. */
1765     did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1766                       dlen = strlen(upath));
1767 #endif /* CNID_DB */
1768
1769     /* construct a temp name.
1770      * NOTE: the temp file will be in the dest file's directory. it
1771      * will also be inaccessible from AFP. */
1772     memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1773     if (!mktemp(temp))
1774         return AFPERR_MISC;
1775
1776     /* now, quickly rename the file. we error if we can't. */
1777     if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1778         goto err_exchangefile;
1779     of_rename(vol, s_of, sdir, spath, curdir, temp);
1780
1781     /* rename destination to source */
1782     if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1783         goto err_src_to_tmp;
1784     of_rename(vol, d_of, curdir, path, sdir, spath);
1785
1786     /* rename temp to destination */
1787     if ((err = renamefile(temp, upath, path, vol_noadouble(vol), adsp)) < 0)
1788         goto err_dest_to_src;
1789     of_rename(vol, s_of, curdir, temp, curdir, path);
1790
1791 #ifdef CNID_DB
1792     /* id's need switching. src -> dest and dest -> src. */
1793     if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1794                             upath, dlen) < 0)) {
1795         switch (errno) {
1796         case EPERM:
1797         case EACCES:
1798             err = AFPERR_ACCESS;
1799             break;
1800         default:
1801             err = AFPERR_PARAM;
1802         }
1803         goto err_temp_to_dest;
1804     }
1805
1806     if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1807                             supath, slen) < 0)) {
1808         switch (errno) {
1809         case EPERM:
1810         case EACCES:
1811             err = AFPERR_ACCESS;
1812             break;
1813         default:
1814             err = AFPERR_PARAM;
1815         }
1816
1817         if (sid)
1818             cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1819         goto err_temp_to_dest;
1820     }
1821 #endif /* CNID_DB */
1822
1823 #ifdef DEBUG
1824     LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1825 #endif /* DEBUG */
1826
1827     return AFP_OK;
1828
1829
1830     /* all this stuff is so that we can unwind a failed operation
1831      * properly. */
1832 #ifdef CNID_DB
1833 err_temp_to_dest:
1834 #endif
1835     /* rename dest to temp */
1836     renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1837     of_rename(vol, s_of, curdir, upath, curdir, temp);
1838
1839 err_dest_to_src:
1840     /* rename source back to dest */
1841     renamefile(p, upath, path, vol_noadouble(vol), addp);
1842     of_rename(vol, d_of, sdir, spath, curdir, path);
1843
1844 err_src_to_tmp:
1845     /* rename temp back to source */
1846     renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1847     of_rename(vol, s_of, curdir, temp, sdir, spath);
1848
1849 err_exchangefile:
1850     return err;
1851 }