]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/file.c
move of_findname key from filename to dev, inode.
[netatalk.git] / etc / afpd / file.c
1 /*
2  * $Id: file.c,v 1.54 2002-09-04 17:28:08 didg Exp $
3  *
4  * Copyright (c) 1990,1993 Regents of The University of Michigan.
5  * All Rights Reserved.  See COPYRIGHT.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #ifdef HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif /* HAVE_UNISTD_H */
17
18 /* STDC check */
19 #if STDC_HEADERS
20 #include <string.h>
21 #else /* STDC_HEADERS */
22 #ifndef HAVE_STRCHR
23 #define strchr index
24 #define strrchr index
25 #endif /* HAVE_STRCHR */
26 char *strchr (), *strrchr ();
27 #ifndef HAVE_MEMCPY
28 #define memcpy(d,s,n) bcopy ((s), (d), (n))
29 #define memmove(d,s,n) bcopy ((s), (d), (n))
30 #endif /* ! HAVE_MEMCPY */
31 #endif /* STDC_HEADERS */
32
33 #include <utime.h>
34 #ifdef HAVE_FCNTL_H
35 #include <fcntl.h>
36 #endif /* HAVE_FCNTL_H */
37 #include <dirent.h>
38 #include <sys/mman.h>
39 #include <errno.h>
40
41 #include <atalk/logger.h>
42 #include <sys/types.h>
43 #include <sys/time.h>
44 #include <sys/param.h>
45 #include <sys/stat.h>
46
47 #include <netatalk/endian.h>
48 #include <atalk/adouble.h>
49 #include <atalk/afp.h>
50 #include <atalk/util.h>
51 #ifdef CNID_DB
52 #include <atalk/cnid.h>
53 #endif /* CNID_DB */
54 #include "directory.h"
55 #include "desktop.h"
56 #include "volume.h"
57 #include "fork.h"
58 #include "file.h"
59 #include "filedir.h"
60 #include "globals.h"
61
62 /* check for mtab DID code */
63 #ifdef DID_MTAB
64 #include "parse_mtab.h"
65 #endif /* DID_MTAB */
66
67 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
68  * field         bytes        subfield    bytes
69  * 
70  * files:
71  * ioFlFndrInfo  16      ->       type    4  type field
72  *                             creator    4  creator field
73  *                               flags    2  finder flags:
74  *                                           alias, bundle, etc.
75  *                            location    4  location in window
76  *                              folder    2  window that contains file
77  * 
78  * ioFlXFndrInfo 16      ->     iconID    2  icon id
79  *                              unused    6  reserved 
80  *                              script    1  script system
81  *                              xflags    1  reserved
82  *                           commentID    2  comment id
83  *                           putawayID    4  home directory id
84  */
85
86 const u_char ufinderi[] = {
87                               'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
88                               0, 0, 0, 0, 0, 0, 0, 0,
89                               0, 0, 0, 0, 0, 0, 0, 0,
90                               0, 0, 0, 0, 0, 0, 0, 0
91                           };
92
93 int getmetadata(struct vol *vol,
94                  u_int16_t bitmap,
95                  char *path, struct dir *dir, struct stat *st,
96                  char *buf, int *buflen, struct adouble *adp, int attrbits )
97 {
98 #ifndef USE_LASTDID
99     struct stat         lst, *lstp;
100 #endif /* USE_LASTDID */
101     struct stat         hst;
102     struct extmap       *em;
103     char                *data, *nameoff = NULL, *upath;
104     int                 bit = 0;
105     u_int32_t           aint;
106     u_int16_t           ashort;
107     u_char              achar, fdType[4];
108     struct maccess      ma;
109
110 #ifdef DEBUG
111     LOG(log_info, logtype_afpd, "begin getmetadata:");
112 #endif /* DEBUG */
113
114     upath = mtoupath(vol, path);
115
116     data = buf;
117     while ( bitmap != 0 ) {
118         while (( bitmap & 1 ) == 0 ) {
119             bitmap = bitmap>>1;
120             bit++;
121         }
122
123         switch ( bit ) {
124         case FILPBIT_ATTR :
125             if ( adp ) {
126                 ad_getattr(adp, &ashort);
127             } else if (*upath == '.') {
128                 ashort = htons(ATTRBIT_INVISIBLE);
129             } else
130                 ashort = 0;
131 #if 0
132             /* FIXME do we want a visual clue if the file is read only
133              */
134             accessmode( ".", &ma, dir , NULL);
135             if ((ma.ma_user & AR_UWRITE)) {
136                 accessmode( upath, &ma, dir , st);
137                 if (!(ma.ma_user & AR_UWRITE)) {
138                         attrbits |= ATTRBIT_NOWRITE;
139                 }
140             }
141 #endif
142             if (attrbits)
143                 ashort = htons(ntohs(ashort) | attrbits);
144             memcpy(data, &ashort, sizeof( ashort ));
145             data += sizeof( ashort );
146             break;
147
148         case FILPBIT_PDID :
149             memcpy(data, &dir->d_did, sizeof( u_int32_t ));
150             data += sizeof( u_int32_t );
151             break;
152
153         case FILPBIT_CDATE :
154             if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
155                 aint = AD_DATE_FROM_UNIX(st->st_mtime);
156             memcpy(data, &aint, sizeof( aint ));
157             data += sizeof( aint );
158             break;
159
160         case FILPBIT_MDATE :
161             if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
162                 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
163                    aint = AD_DATE_FROM_UNIX(st->st_mtime);
164                 }
165             } else {
166                 aint = AD_DATE_FROM_UNIX(st->st_mtime);
167             }
168             memcpy(data, &aint, sizeof( int ));
169             data += sizeof( int );
170             break;
171
172         case FILPBIT_BDATE :
173             if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
174                 aint = AD_DATE_START;
175             memcpy(data, &aint, sizeof( int ));
176             data += sizeof( int );
177             break;
178
179         case FILPBIT_FINFO :
180             if (adp)
181                 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
182             else {
183                 memcpy(data, ufinderi, 32);
184                 if (*upath == '.') { /* make it invisible */
185                     ashort = htons(FINDERINFO_INVISIBLE);
186                     memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
187                 }
188             }
189
190             if ((!adp  || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 )) 
191                 && (em = getextmap( path ))
192             ) {
193                 memcpy(data, em->em_type, sizeof( em->em_type ));
194                 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
195             }
196             data += 32;
197             break;
198
199         case FILPBIT_LNAME :
200             nameoff = data;
201             data += sizeof( u_int16_t );
202             break;
203
204         case FILPBIT_SNAME :
205             memset(data, 0, sizeof(u_int16_t));
206             data += sizeof( u_int16_t );
207             break;
208
209         case FILPBIT_FNUM :
210             aint = 0;
211 #if AD_VERSION > AD_VERSION1
212             /* look in AD v2 header */
213             if (adp)
214                 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
215 #endif /* AD_VERSION > AD_VERSION1 */
216
217 #ifdef CNID_DB
218             aint = cnid_add(vol->v_db, st, dir->d_did, upath,
219                             strlen(upath), aint);
220             /* Throw errors if cnid_add fails. */
221             if (aint == CNID_INVALID) {
222                 switch (errno) {
223                 case CNID_ERR_PARAM:
224                     LOG(log_error, logtype_afpd, "getfilparams: Incorrect parameters passed to cnid_add");
225                     return(AFPERR_PARAM);
226                 case CNID_ERR_PATH:
227                     return(AFPERR_PARAM);
228                 case CNID_ERR_DB:
229                 case CNID_ERR_MAX:
230                     return(AFPERR_MISC);
231                 }
232             }
233 #endif /* CNID_DB */
234
235             if (aint == 0) {
236                 /*
237                  * What a fucking mess.  First thing:  DID and FNUMs are
238                  * in the same space for purposes of enumerate (and several
239                  * other wierd places).  While we consider this Apple's bug,
240                  * this is the work-around:  In order to maintain constant and
241                  * unique DIDs and FNUMs, we monotonically generate the DIDs
242                  * during the session, and derive the FNUMs from the filesystem.
243                  * Since the DIDs are small, we insure that the FNUMs are fairly
244                  * large by setting thier high bits to the device number.
245                  *
246                  * AFS already does something very similar to this for the
247                  * inode number, so we don't repeat the procedure.
248                  *
249                  * new algorithm:
250                  * due to complaints over did's being non-persistent,
251                  * here's the current hack to provide semi-persistent
252                  * did's:
253                  *      1) we reserve the first bit for file ids.
254                  *      2) the next 7 bits are for the device.
255                  *      3) the remaining 24 bits are for the inode.
256                  *
257                  * both the inode and device information are actually hashes
258                  * that are then truncated to the requisite bit length.
259                  *
260                  * it should be okay to use lstat to deal with symlinks.
261                  */
262 #ifdef USE_LASTDID
263                 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
264 #else /* USE_LASTDID */
265                 lstp = lstat(upath, &lst) < 0 ? st : &lst;
266 #ifdef DID_MTAB
267                 aint = htonl( afpd_st_cnid ( lstp ) );
268 #else /* DID_MTAB */
269                 aint = htonl(CNID(lstp, 1));
270 #endif /* DID_MTAB */
271 #endif /* USE_LASTDID */
272             }
273
274             memcpy(data, &aint, sizeof( aint ));
275             data += sizeof( aint );
276             break;
277
278         case FILPBIT_DFLEN :
279             aint = htonl( st->st_size );
280             memcpy(data, &aint, sizeof( aint ));
281             data += sizeof( aint );
282             break;
283
284         case FILPBIT_RFLEN :
285             if ( adp ) {
286                 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
287             } else {
288                 aint = 0;
289             }
290             memcpy(data, &aint, sizeof( aint ));
291             data += sizeof( aint );
292             break;
293
294             /* Current client needs ProDOS info block for this file.
295                Use simple heuristic and let the Mac "type" string tell
296                us what the PD file code should be.  Everything gets a
297                subtype of 0x0000 unless the original value was hashed
298                to "pXYZ" when we created it.  See IA, Ver 2.
299                <shirsch@ibm.net> */
300         case FILPBIT_PDINFO :
301             if ( adp ) {
302                 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
303
304                 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
305                     achar = '\x04';
306                     ashort = 0x0000;
307                 }
308                 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
309                     achar = '\xff';
310                     ashort = 0x0000;
311                 }
312                 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
313                     achar = '\xb3';
314                     ashort = 0x0000;
315                 }
316                 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
317                     achar = '\x00';
318                     ashort = 0x0000;
319                 }
320                 else if ( fdType[0] == 'p' ) {
321                     achar = fdType[1];
322                     ashort = (fdType[2] * 256) + fdType[3];
323                 }
324                 else {
325                     achar = '\x00';
326                     ashort = 0x0000;
327                 }
328             }
329             else {
330                 achar = '\x00';
331                 ashort = 0x0000;
332             }
333
334             *data++ = achar;
335             *data++ = 0;
336             memcpy(data, &ashort, sizeof( ashort ));
337             data += sizeof( ashort );
338             memset(data, 0, sizeof( ashort ));
339             data += sizeof( ashort );
340             break;
341
342         default :
343             return( AFPERR_BITMAP );
344         }
345         bitmap = bitmap>>1;
346         bit++;
347     }
348     if ( nameoff ) {
349         ashort = htons( data - buf );
350         memcpy(nameoff, &ashort, sizeof( ashort ));
351         if ((aint = strlen( path )) > MACFILELEN)
352             aint = MACFILELEN;
353         *data++ = aint;
354         memcpy(data, path, aint );
355         data += aint;
356     }
357     *buflen = data - buf;
358     return (AFP_OK);
359 }
360                 
361 /* ----------------------- */
362 int getfilparams(struct vol *vol,
363                  u_int16_t bitmap,
364                  char *path, struct dir *dir, struct stat *st,
365                  char *buf, int *buflen )
366 {
367     struct adouble      ad, *adp;
368     struct ofork        *of;
369     char                    *upath;
370     u_int16_t           attrbits = 0;
371     int rc;    
372 #ifdef DEBUG
373     LOG(log_info, logtype_default, "begin getfilparams:");
374 #endif /* DEBUG */
375
376     upath = mtoupath(vol, path);
377     if ((of = of_findname(vol, dir, 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;
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(vol, curdir, 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(vol, curdir, 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     upath = mtoupath(vol, newname );
937     if (of_findname(vol, curdir, upath, NULL))
938         return AFPERR_DENYCONF;
939
940     newname = obj->newtmp;
941     strcpy( newname, path );
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
980     if ( (err = copyfile(p, upath, newname,
981                          vol_noadouble(vol))) < 0 ) {
982         return err;
983     }
984
985     setvoltime(obj, vol );
986
987 #ifdef DROPKLUDGE
988     if (vol->v_flags & AFPVOL_DROPBOX) {
989         retvalue=matchfile2dirperms(newname, vol, sdid);
990     }
991 #endif /* DROPKLUDGE */
992
993 #ifdef DEBUG
994     LOG(log_info, logtype_afpd, "end afp_copyfile:");
995 #endif /* DEBUG */
996
997     return( retvalue );
998 }
999
1000
1001 static __inline__ int copy_all(const int dfd, const void *buf,
1002                                size_t buflen)
1003 {
1004     ssize_t cc;
1005
1006 #ifdef DEBUG
1007     LOG(log_info, logtype_afpd, "begin copy_all:");
1008 #endif /* DEBUG */
1009
1010     while (buflen > 0) {
1011         if ((cc = write(dfd, buf, buflen)) < 0) {
1012             switch (errno) {
1013             case EINTR:
1014                 continue;
1015             case EDQUOT:
1016             case EFBIG:
1017             case ENOSPC:
1018                 return AFPERR_DFULL;
1019             case EROFS:
1020                 return AFPERR_VLOCK;
1021             default:
1022                 return AFPERR_PARAM;
1023             }
1024         }
1025         buflen -= cc;
1026     }
1027
1028 #ifdef DEBUG
1029     LOG(log_info, logtype_afpd, "end copy_all:");
1030 #endif /* DEBUG */
1031
1032     return AFP_OK;
1033 }
1034
1035 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1036  * pass in vol and path */
1037 int copyfile(src, dst, newname, noadouble )
1038 char    *src, *dst, *newname;
1039 const int   noadouble;
1040 {
1041     struct adouble      ad;
1042     struct stat         st;
1043     char                filebuf[8192];
1044     int                 sfd, dfd, len, err = AFP_OK;
1045     ssize_t             cc;
1046     char                *dpath;
1047     int                 admode;
1048 #ifdef DEBUG
1049     LOG(log_info, logtype_afpd, "begin copyfile:");
1050 #endif /* DEBUG */
1051
1052     dpath = ad_path( dst, ADFLAGS_HF );
1053     admode = ad_mode( dst, 0666 );
1054     if (newname) {
1055         if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1056             switch ( errno ) {
1057             case ENOENT :
1058                 break; /* just copy the data fork */
1059             case EACCES :
1060                 return( AFPERR_ACCESS );
1061             default :
1062                 return( AFPERR_PARAM );
1063             }
1064         } else {
1065             if (( dfd = open( dpath, O_WRONLY|O_CREAT,ad_hf_mode(admode))) < 0 ) {
1066                 close( sfd );
1067                 switch ( errno ) {
1068                 case ENOENT :
1069                     return( AFPERR_NOOBJ );
1070                 case EACCES :
1071                     return( AFPERR_ACCESS );
1072                 case EROFS:
1073                     return AFPERR_VLOCK;
1074                 default :
1075                     return( AFPERR_PARAM );
1076                 }
1077             }
1078
1079             /* copy the file */
1080 #ifdef SENDFILE_FLAVOR_LINUX
1081             if (fstat(sfd, &st) == 0) {
1082                 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1083                     switch (errno) {
1084                     case EDQUOT:
1085                     case EFBIG:
1086                     case ENOSPC:
1087                         err = AFPERR_DFULL;
1088                         break;
1089                     case EROFS:
1090                         err = AFPERR_VLOCK;
1091                         break;
1092                     default:
1093                         err = AFPERR_PARAM;
1094                     }
1095                 }
1096                 goto copyheader_done;
1097             }
1098 #endif /* SENDFILE_FLAVOR_LINUX */
1099             while (1) {
1100                 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1101                     if (errno == EINTR)
1102                         continue;
1103                     err = AFPERR_PARAM;
1104                     break;
1105                 }
1106
1107                 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1108                     break;
1109             }
1110
1111 copyheader_done:
1112             close(sfd);
1113             close(dfd);
1114             if (err < 0) {
1115                 unlink(dpath);
1116                 return err;
1117             }
1118         }
1119     }
1120
1121     /* data fork copying */
1122     if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1123         switch ( errno ) {
1124         case ENOENT :
1125             return( AFPERR_NOOBJ );
1126         case EACCES :
1127             return( AFPERR_ACCESS );
1128         default :
1129             return( AFPERR_PARAM );
1130         }
1131     }
1132
1133     if (( dfd = open( dst, O_WRONLY|O_CREAT, admode)) < 0 ) {
1134         close( sfd );
1135         switch ( errno ) {
1136         case ENOENT :
1137             return( AFPERR_NOOBJ );
1138         case EACCES :
1139             return( AFPERR_ACCESS );
1140         case EROFS:
1141             return AFPERR_VLOCK;
1142         default :
1143             return( AFPERR_PARAM );
1144         }
1145     }
1146
1147 #ifdef SENDFILE_FLAVOR_LINUX
1148     if (fstat(sfd, &st) == 0) {
1149         if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1150             switch (errno) {
1151             case EDQUOT:
1152             case EFBIG:
1153             case ENOSPC:
1154                 err = AFPERR_DFULL;
1155                 break;
1156             default:
1157                 err = AFPERR_PARAM;
1158             }
1159         }
1160         goto copydata_done;
1161     }
1162 #endif /* SENDFILE_FLAVOR_LINUX */
1163
1164     while (1) {
1165         if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1166             if (errno == EINTR)
1167                 continue;
1168
1169             err = AFPERR_PARAM;
1170             break;
1171         }
1172
1173         if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1174             break;
1175         }
1176     }
1177
1178 copydata_done:
1179     close(sfd);
1180     close(dfd);
1181     if (err < 0) {
1182         unlink(dpath);
1183         unlink(dst);
1184         return err;
1185     }
1186
1187     if (newname) {
1188         memset(&ad, 0, sizeof(ad));
1189         if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1190                       0666, &ad) < 0 ) {
1191             switch ( errno ) {
1192             case ENOENT :
1193                 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1194             case EACCES :
1195                 return( AFPERR_ACCESS );
1196             case EROFS:
1197                 return AFPERR_VLOCK;
1198             default :
1199                 return( AFPERR_PARAM );
1200             }
1201         }
1202
1203         len = strlen( newname );
1204         ad_setentrylen( &ad, ADEID_NAME, len );
1205         memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1206         ad_flush( &ad, ADFLAGS_HF );
1207         ad_close( &ad, ADFLAGS_HF );
1208     }
1209
1210 #ifdef DEBUG
1211     LOG(log_info, logtype_afpd, "end copyfile:");
1212 #endif /* DEBUG */
1213
1214     return( AFP_OK );
1215 }
1216
1217
1218 /* -----------------------------------
1219    checkAttrib:   1 check kFPDeleteInhibitBit 
1220    ie deletfile called by afp_delete
1221
1222    when deletefile is called we don't have lock on it, file is closed (for us)
1223    untrue if called by renamefile
1224 */
1225 int deletefile( file, checkAttrib )
1226 char            *file;
1227 int         checkAttrib;
1228 {
1229     struct adouble      ad;
1230     int                 adflags, err = AFP_OK;
1231     int                 locktype = ADLOCK_WR;
1232     int                 openmode = O_RDWR;
1233
1234 #ifdef DEBUG
1235     LOG(log_info, logtype_afpd, "begin deletefile:");
1236 #endif /* DEBUG */
1237
1238     while(1) {
1239         /*
1240          * If can't open read/write then try again read-only.  If it's open
1241          * read-only, we must do a read lock instead of a write lock.
1242          */
1243         /* try to open both at once */
1244         adflags = ADFLAGS_DF|ADFLAGS_HF;
1245         memset(&ad, 0, sizeof(ad));
1246         if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1247             switch (errno) {
1248             case ENOENT:
1249                 adflags = ADFLAGS_DF;
1250                 /* that failed. now try to open just the data fork */
1251                 memset(&ad, 0, sizeof(ad));
1252                 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1253                     switch (errno) {
1254                     case ENOENT:
1255                         return AFPERR_NOOBJ;
1256                     case EACCES:
1257                         if(openmode == O_RDWR) {
1258                             openmode = O_RDONLY;
1259                             locktype = ADLOCK_RD;
1260                             continue;
1261                         } else {
1262                             return AFPERR_ACCESS;
1263                         }
1264                     case EROFS:
1265                         return AFPERR_VLOCK;
1266                     default:
1267                         return AFPERR_PARAM;
1268                     }
1269                 }
1270                 break;
1271
1272             case EACCES:
1273                 if(openmode == O_RDWR) {
1274                     openmode = O_RDONLY;
1275                     locktype = ADLOCK_RD;
1276                     continue;
1277                 } else {
1278                     return AFPERR_ACCESS;
1279                 }
1280             case EROFS:
1281                 return AFPERR_VLOCK;
1282             default:
1283                 return( AFPERR_PARAM );
1284             }
1285         }
1286         break;  /* from the while */
1287     }
1288     /*
1289      * Does kFPDeleteInhibitBit (bit 8) set?
1290      */
1291     if (checkAttrib && (adflags & ADFLAGS_HF)) {
1292         u_int16_t   bshort;
1293
1294         ad_getattr(&ad, &bshort);
1295         if ((bshort & htons(ATTRBIT_NODELETE))) {
1296             ad_close( &ad, adflags );
1297             return(AFPERR_OLOCK);
1298         }
1299     }
1300     
1301     if ((adflags & ADFLAGS_HF) ) {
1302         /* FIXME we have a pb here because we want to know if a file is open 
1303          * there's a 'priority inversion' if you can't open the ressource fork RW
1304          * you can delete it if it's open because you can't get a write lock.
1305          * 
1306          * ADLOCK_FILELOCK means the whole ressource fork, not only after the 
1307          * metadatas
1308          *
1309          * FIXME it doesn't for RFORK open read only and fork open without deny mode
1310          */
1311         if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) {
1312             ad_close( &ad, adflags );
1313             return( AFPERR_BUSY );
1314         }
1315     }
1316
1317     if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1318         err = AFPERR_BUSY;
1319         goto delete_unlock;
1320     }
1321
1322     if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1323         switch ( errno ) {
1324         case EPERM:
1325         case EACCES :
1326             err = AFPERR_ACCESS;
1327             goto delete_unlock;
1328         case EROFS:
1329             err = AFPERR_VLOCK;
1330             goto delete_unlock;
1331         case ENOENT :
1332             break;
1333         default :
1334             err = AFPERR_PARAM;
1335             goto delete_unlock;
1336         }
1337     }
1338
1339     if ( unlink( file ) < 0 ) {
1340         switch ( errno ) {
1341         case EPERM:
1342         case EACCES :
1343             err = AFPERR_ACCESS;
1344             break;
1345         case EROFS:
1346             err = AFPERR_VLOCK;
1347             break;
1348         case ENOENT :
1349             break;
1350         default :
1351             err = AFPERR_PARAM;
1352             break;
1353         }
1354     }
1355
1356 delete_unlock:
1357     if (adflags & ADFLAGS_HF)
1358         ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0);
1359     ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1360     ad_close( &ad, adflags );
1361
1362 #ifdef DEBUG
1363     LOG(log_info, logtype_afpd, "end deletefile:");
1364 #endif /* DEBUG */
1365
1366     return err;
1367 }
1368
1369
1370 #ifdef CNID_DB
1371 /* return a file id */
1372 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1373 AFPObj      *obj;
1374 char    *ibuf, *rbuf;
1375 int             ibuflen, *rbuflen;
1376 {
1377     struct stat         st;
1378     struct adouble      ad;
1379     struct vol          *vol;
1380     struct dir          *dir;
1381     char                *path, *upath;
1382     int                 len;
1383     cnid_t              did, id;
1384     u_short             vid;
1385
1386 #ifdef DEBUG
1387     LOG(log_info, logtype_afpd, "begin afp_createid:");
1388 #endif /* DEBUG */
1389
1390     *rbuflen = 0;
1391     ibuf += 2;
1392
1393     memcpy(&vid, ibuf, sizeof(vid));
1394     ibuf += sizeof(vid);
1395
1396     if (( vol = getvolbyvid( vid )) == NULL ) {
1397         return( AFPERR_PARAM);
1398     }
1399
1400     if (vol->v_flags & AFPVOL_RO)
1401         return AFPERR_VLOCK;
1402
1403     memcpy(&did, ibuf, sizeof( did ));
1404     ibuf += sizeof(did);
1405
1406     if (( dir = dirsearch( vol, did )) == NULL ) {
1407         return( AFPERR_PARAM );
1408     }
1409
1410     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1411         return( AFPERR_PARAM );
1412     }
1413
1414     if ( *path == '\0' ) {
1415         return( AFPERR_BADTYPE );
1416     }
1417
1418     upath = mtoupath(vol, path);
1419     if (stat(upath, &st) < 0) {
1420         switch (errno) {
1421         case EPERM:
1422         case EACCES:
1423             return AFPERR_ACCESS;
1424         case ENOENT:
1425             return AFPERR_NOOBJ;
1426         default:
1427             return AFPERR_PARAM;
1428         }
1429     }
1430
1431     if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1432         memcpy(rbuf, &id, sizeof(id));
1433         *rbuflen = sizeof(id);
1434         return AFPERR_EXISTID;
1435     }
1436
1437 #if AD_VERSION > AD_VERSION1
1438     memset(&ad, 0, sizeof(ad));
1439     if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1440         memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1441         ad_close(&ad, ADFLAGS_HF);
1442     }
1443 #endif /* AD_VERSION > AD_VERSION1 */
1444
1445     if (id = cnid_add(vol->v_db, &st, did, upath, len, id) != CNID_INVALID) {
1446         memcpy(rbuf, &id, sizeof(id));
1447         *rbuflen = sizeof(id);
1448         return AFP_OK;
1449     }
1450
1451 #ifdef DEBUG
1452     LOG(log_info, logtype_afpd, "ending afp_createid...:");
1453 #endif /* DEBUG */
1454
1455     switch (errno) {
1456     case EROFS:
1457         return AFPERR_VLOCK;
1458         break;
1459     case EPERM:
1460     case EACCES:
1461         return AFPERR_ACCESS;
1462         break;
1463     default:
1464         LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1465         return AFPERR_PARAM;
1466     }
1467 }
1468
1469 /* resolve a file id */
1470 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1471 AFPObj      *obj;
1472 char    *ibuf, *rbuf;
1473 int             ibuflen, *rbuflen;
1474 {
1475     struct stat         st;
1476     struct vol          *vol;
1477     struct dir          *dir;
1478     char                *upath;
1479     int                 err, buflen;
1480     cnid_t              id;
1481     u_int16_t           vid, bitmap;
1482
1483     static char buffer[12 + MAXPATHLEN + 1];
1484     int len = 12 + MAXPATHLEN + 1;
1485
1486 #ifdef DEBUG
1487     LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1488 #endif /* DEBUG */
1489
1490     *rbuflen = 0;
1491     ibuf += 2;
1492
1493     memcpy(&vid, ibuf, sizeof(vid));
1494     ibuf += sizeof(vid);
1495
1496     if (( vol = getvolbyvid( vid )) == NULL ) {
1497         return( AFPERR_PARAM);
1498     }
1499
1500     memcpy(&id, ibuf, sizeof( id ));
1501     ibuf += sizeof(id);
1502
1503     if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1504         return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1505     }
1506
1507     if (( dir = dirlookup( vol, id )) == NULL ) {
1508         return AFPERR_NOID; /* idem AFPERR_PARAM */
1509     }
1510
1511     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1512         switch (errno) {
1513         case EACCES:
1514         case EPERM:
1515             return AFPERR_ACCESS;
1516         case ENOENT:
1517             return AFPERR_NOID;
1518         default:
1519             return AFPERR_PARAM;
1520         }
1521     }
1522
1523     /* directories are bad */
1524     if (S_ISDIR(st.st_mode))
1525         return AFPERR_BADTYPE;
1526
1527     memcpy(&bitmap, ibuf, sizeof(bitmap));
1528     bitmap = ntohs( bitmap );
1529
1530     if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1531                             rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1532         return err;
1533
1534     *rbuflen = buflen + sizeof(bitmap);
1535     memcpy(rbuf, ibuf, sizeof(bitmap));
1536
1537 #ifdef DEBUG
1538     LOG(log_info, logtype_afpd, "end afp_resolveid:");
1539 #endif /* DEBUG */
1540
1541     return AFP_OK;
1542 }
1543
1544 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1545 AFPObj      *obj;
1546 char    *ibuf, *rbuf;
1547 int             ibuflen, *rbuflen;
1548 {
1549     struct stat         st;
1550     struct vol          *vol;
1551     struct dir          *dir;
1552     char                *upath;
1553     int                 err;
1554     cnid_t              id;
1555     cnid_t              fileid;
1556     u_short             vid;
1557     static char buffer[12 + MAXPATHLEN + 1];
1558     int len = 12 + MAXPATHLEN + 1;
1559
1560 #ifdef DEBUG
1561     LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1562 #endif /* DEBUG */
1563
1564     *rbuflen = 0;
1565     ibuf += 2;
1566
1567     memcpy(&vid, ibuf, sizeof(vid));
1568     ibuf += sizeof(vid);
1569
1570     if (( vol = getvolbyvid( vid )) == NULL ) {
1571         return( AFPERR_PARAM);
1572     }
1573
1574     if (vol->v_flags & AFPVOL_RO)
1575         return AFPERR_VLOCK;
1576
1577     memcpy(&id, ibuf, sizeof( id ));
1578     ibuf += sizeof(id);
1579     fileid = id;
1580
1581     if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1582         return AFPERR_NOID;
1583     }
1584
1585     if (( dir = dirlookup( vol, id )) == NULL ) {
1586         return( AFPERR_PARAM );
1587     }
1588
1589     err = AFP_OK;
1590     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1591         switch (errno) {
1592         case EACCES:
1593         case EPERM:
1594             return AFPERR_ACCESS;
1595         case ENOENT:
1596             /* still try to delete the id */
1597             err = AFPERR_NOOBJ;
1598             break;
1599         default:
1600             return AFPERR_PARAM;
1601         }
1602     }
1603
1604     /* directories are bad */
1605     if (S_ISDIR(st.st_mode))
1606         return AFPERR_BADTYPE;
1607
1608     if (cnid_delete(vol->v_db, fileid)) {
1609         switch (errno) {
1610         case EROFS:
1611             return AFPERR_VLOCK;
1612         case EPERM:
1613         case EACCES:
1614             return AFPERR_ACCESS;
1615         default:
1616             return AFPERR_PARAM;
1617         }
1618     }
1619
1620 #ifdef DEBUG
1621     LOG(log_info, logtype_afpd, "end afp_deleteid:");
1622 #endif /* DEBUG */
1623
1624     return err;
1625 }
1626 #endif /* CNID_DB */
1627
1628 #define APPLETEMP ".AppleTempXXXXXX"
1629
1630 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1631 AFPObj      *obj;
1632 char    *ibuf, *rbuf;
1633 int             ibuflen, *rbuflen;
1634 {
1635     struct stat         srcst, destst;
1636     struct vol          *vol;
1637     struct dir          *dir, *sdir;
1638     char                *spath, temp[17], *path, *p;
1639     char                *supath, *upath;
1640     int                 err;
1641     struct adouble      ads;
1642     struct adouble      add;
1643     struct adouble      *adsp;
1644     struct adouble      *addp;
1645     struct ofork        *s_of;
1646     struct ofork        *d_of;
1647     
1648 #ifdef CNID_DB
1649     int                 slen, dlen;
1650 #endif /* CNID_DB */
1651     u_int32_t           sid, did;
1652     u_int16_t           vid;
1653
1654 #ifdef DEBUG
1655     LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1656 #endif /* DEBUG */
1657
1658     *rbuflen = 0;
1659     ibuf += 2;
1660
1661     memcpy(&vid, ibuf, sizeof(vid));
1662     ibuf += sizeof(vid);
1663
1664     if (( vol = getvolbyvid( vid )) == NULL ) {
1665         return( AFPERR_PARAM);
1666     }
1667
1668     if (vol->v_flags & AFPVOL_RO)
1669         return AFPERR_VLOCK;
1670
1671     /* source and destination dids */
1672     memcpy(&sid, ibuf, sizeof(sid));
1673     ibuf += sizeof(sid);
1674     memcpy(&did, ibuf, sizeof(did));
1675     ibuf += sizeof(did);
1676
1677     /* source file */
1678     if ((dir = dirsearch( vol, sid )) == NULL ) {
1679         return( AFPERR_PARAM );
1680     }
1681
1682     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1683         return( AFPERR_PARAM );
1684     }
1685
1686     if ( *path == '\0' ) {
1687         return( AFPERR_BADTYPE );   /* it's a dir */
1688     }
1689
1690     upath = mtoupath(vol, path);
1691     if (stat(upath, &srcst) < 0) {
1692         switch (errno) {
1693         case ENOENT:
1694             return AFPERR_NOID;
1695         case EPERM:
1696         case EACCES:
1697             return AFPERR_ACCESS;
1698         default:
1699             return AFPERR_PARAM;
1700         }
1701     }
1702     memset(&ads, 0, sizeof(ads));
1703     adsp = &ads;
1704     if ((s_of = of_findname(vol, curdir, upath, &srcst))) {
1705             /* reuse struct adouble so it won't break locks */
1706             adsp = s_of->of_ad;
1707     }
1708     /* save some stuff */
1709     sdir = curdir;
1710     spath = obj->oldtmp;
1711     supath = obj->newtmp;
1712     strcpy(spath, path);
1713     strcpy(supath, upath); /* this is for the cnid changing */
1714     p = ctoupath( vol, sdir, spath);
1715
1716     /* look for the source cnid. if it doesn't exist, don't worry about
1717      * it. */
1718 #ifdef CNID_DB
1719     sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1720                       slen = strlen(supath));
1721 #endif /* CNID_DB */
1722
1723     if (( dir = dirsearch( vol, did )) == NULL ) {
1724         return( AFPERR_PARAM );
1725     }
1726
1727     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1728         return( AFPERR_PARAM );
1729     }
1730
1731     if ( *path == '\0' ) {
1732         return( AFPERR_BADTYPE );
1733     }
1734
1735     /* FPExchangeFiles is the only call that can return the SameObj
1736      * error */
1737     if ((curdir == sdir) && strcmp(spath, path) == 0)
1738         return AFPERR_SAMEOBJ;
1739
1740     upath = mtoupath(vol, path);
1741     if (stat(upath, &destst) < 0) {
1742         switch (errno) {
1743         case ENOENT:
1744             return AFPERR_NOID;
1745         case EPERM:
1746         case EACCES:
1747             return AFPERR_ACCESS;
1748         default:
1749             return AFPERR_PARAM;
1750         }
1751     }
1752     memset(&add, 0, sizeof(add));
1753     addp = &add;
1754     if ((d_of = of_findname(vol, curdir, upath, &destst))) {
1755             /* reuse struct adouble so it won't break locks */
1756             addp = d_of->of_ad;
1757     }
1758
1759     /* they are not on the same device and at least one is open
1760     */
1761     if ((d_of || s_of)  && srcst.st_dev != destst.st_dev)
1762         return AFPERR_MISC;
1763     
1764 #ifdef CNID_DB
1765     /* look for destination id. */
1766     did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1767                       dlen = strlen(upath));
1768 #endif /* CNID_DB */
1769
1770     /* construct a temp name.
1771      * NOTE: the temp file will be in the dest file's directory. it
1772      * will also be inaccessible from AFP. */
1773     memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1774     if (!mktemp(temp))
1775         return AFPERR_MISC;
1776
1777     /* now, quickly rename the file. we error if we can't. */
1778     if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1779         goto err_exchangefile;
1780     of_rename(vol, s_of, sdir, spath, curdir, temp);
1781
1782     /* rename destination to source */
1783     if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1784         goto err_src_to_tmp;
1785     of_rename(vol, d_of, curdir, path, sdir, spath);
1786
1787     /* rename temp to destination */
1788     if ((err = renamefile(temp, upath, path, vol_noadouble(vol), adsp)) < 0)
1789         goto err_dest_to_src;
1790     of_rename(vol, s_of, curdir, temp, curdir, path);
1791
1792 #ifdef CNID_DB
1793     /* id's need switching. src -> dest and dest -> src. */
1794     if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1795                             upath, dlen) < 0)) {
1796         switch (errno) {
1797         case EPERM:
1798         case EACCES:
1799             err = AFPERR_ACCESS;
1800             break;
1801         default:
1802             err = AFPERR_PARAM;
1803         }
1804         goto err_temp_to_dest;
1805     }
1806
1807     if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1808                             supath, slen) < 0)) {
1809         switch (errno) {
1810         case EPERM:
1811         case EACCES:
1812             err = AFPERR_ACCESS;
1813             break;
1814         default:
1815             err = AFPERR_PARAM;
1816         }
1817
1818         if (sid)
1819             cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1820         goto err_temp_to_dest;
1821     }
1822 #endif /* CNID_DB */
1823
1824 #ifdef DEBUG
1825     LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1826 #endif /* DEBUG */
1827
1828     return AFP_OK;
1829
1830
1831     /* all this stuff is so that we can unwind a failed operation
1832      * properly. */
1833 #ifdef CNID_DB
1834 err_temp_to_dest:
1835 #endif
1836     /* rename dest to temp */
1837     renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1838     of_rename(vol, s_of, curdir, upath, curdir, temp);
1839
1840 err_dest_to_src:
1841     /* rename source back to dest */
1842     renamefile(p, upath, path, vol_noadouble(vol), addp);
1843     of_rename(vol, d_of, sdir, spath, curdir, path);
1844
1845 err_src_to_tmp:
1846     /* rename temp back to source */
1847     renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1848     of_rename(vol, s_of, curdir, temp, sdir, spath);
1849
1850 err_exchangefile:
1851     return err;
1852 }