]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/file.c
Warning fixes.
[netatalk.git] / etc / afpd / file.c
1 /*
2  * $Id: file.c,v 1.48 2002-08-20 19:40:43 srittau 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 #ifdef FORCE_UIDGID
68 #warning UIDGID
69 #include "uid.h"
70 #endif /* FORCE_UIDGID */
71
72 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
73  * field         bytes        subfield    bytes
74  * 
75  * files:
76  * ioFlFndrInfo  16      ->       type    4  type field
77  *                             creator    4  creator field
78  *                               flags    2  finder flags:
79  *                                           alias, bundle, etc.
80  *                            location    4  location in window
81  *                              folder    2  window that contains file
82  * 
83  * ioFlXFndrInfo 16      ->     iconID    2  icon id
84  *                              unused    6  reserved 
85  *                              script    1  script system
86  *                              xflags    1  reserved
87  *                           commentID    2  comment id
88  *                           putawayID    4  home directory id
89  */
90
91 const u_char ufinderi[] = {
92                               'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
93                               0, 0, 0, 0, 0, 0, 0, 0,
94                               0, 0, 0, 0, 0, 0, 0, 0,
95                               0, 0, 0, 0, 0, 0, 0, 0
96                           };
97
98 int getmetadata(struct vol *vol,
99                  u_int16_t bitmap,
100                  char *path, struct dir *dir, struct stat *st,
101                  char *buf, int *buflen, struct adouble *adp, int attrbits )
102 {
103 #ifndef USE_LASTDID
104     struct stat         lst, *lstp;
105 #endif /* USE_LASTDID */
106     struct stat         hst;
107     struct extmap       *em;
108     char                *data, *nameoff = NULL, *upath;
109     int                 bit = 0;
110     u_int32_t           aint;
111     u_int16_t           ashort;
112     u_char              achar, fdType[4];
113
114 #ifdef DEBUG
115     LOG(log_info, logtype_afpd, "begin getmetadata:");
116 #endif /* DEBUG */
117
118     upath = mtoupath(vol, path);
119
120     data = buf;
121     while ( bitmap != 0 ) {
122         while (( bitmap & 1 ) == 0 ) {
123             bitmap = bitmap>>1;
124             bit++;
125         }
126
127         switch ( bit ) {
128         case FILPBIT_ATTR :
129             if ( adp ) {
130                 ad_getattr(adp, &ashort);
131             } else if (*upath == '.') {
132                 ashort = htons(ATTRBIT_INVISIBLE);
133             } else
134                 ashort = 0;
135             if (attrbits)
136                 ashort = htons(ntohs(ashort) | attrbits);
137             memcpy(data, &ashort, sizeof( ashort ));
138             data += sizeof( ashort );
139             break;
140
141         case FILPBIT_PDID :
142             memcpy(data, &dir->d_did, sizeof( u_int32_t ));
143             data += sizeof( u_int32_t );
144             break;
145
146         case FILPBIT_CDATE :
147             if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
148                 aint = AD_DATE_FROM_UNIX(st->st_mtime);
149             memcpy(data, &aint, sizeof( aint ));
150             data += sizeof( aint );
151             break;
152
153         case FILPBIT_MDATE :
154             if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
155                 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
156                         if ( fstat( ad_hfileno( adp ), &hst ) < 0 ) {
157                             LOG(log_error, logtype_default, "getfilparams fstat: %s", strerror(errno) );
158                         }
159                         else if (hst.st_mtime < st->st_mtime) 
160                             aint = AD_DATE_FROM_UNIX(st->st_mtime);
161                         else 
162                             aint = AD_DATE_FROM_UNIX(hst.st_mtime);
163                 }
164             } else {
165                 aint = AD_DATE_FROM_UNIX(st->st_mtime);
166             }
167             memcpy(data, &aint, sizeof( int ));
168             data += sizeof( int );
169             break;
170
171         case FILPBIT_BDATE :
172             if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
173                 aint = AD_DATE_START;
174             memcpy(data, &aint, sizeof( int ));
175             data += sizeof( int );
176             break;
177
178         case FILPBIT_FINFO :
179             if (adp)
180                 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
181             else {
182                 memcpy(data, ufinderi, 32);
183                 if (*upath == '.') { /* make it invisible */
184                     ashort = htons(FINDERINFO_INVISIBLE);
185                     memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
186                 }
187             }
188
189             if ((!adp || (memcmp(ad_entry(adp, ADEID_FINDERI),
190                                   ufinderi, 8 ) == 0)) &&
191                     (em = getextmap( path ))) {
192                 memcpy(data, em->em_type, sizeof( em->em_type ));
193                 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
194             }
195             data += 32;
196             break;
197
198         case FILPBIT_LNAME :
199             nameoff = data;
200             data += sizeof( u_int16_t );
201             break;
202
203         case FILPBIT_SNAME :
204             memset(data, 0, sizeof(u_int16_t));
205             data += sizeof( u_int16_t );
206             break;
207
208         case FILPBIT_FNUM :
209             aint = 0;
210 #if AD_VERSION > AD_VERSION1
211             /* look in AD v2 header */
212             if (adp)
213                 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
214 #endif /* AD_VERSION > AD_VERSION1 */
215
216 #ifdef CNID_DB
217             aint = cnid_add(vol->v_db, st, dir->d_did, upath,
218                             strlen(upath), aint);
219             /* Throw errors if cnid_add fails. */
220             if (aint == CNID_INVALID) {
221                 switch (errno) {
222                 case CNID_ERR_PARAM:
223                     LOG(log_error, logtype_afpd, "getfilparams: Incorrect parameters passed to cnid_add");
224                     return(AFPERR_PARAM);
225                 case CNID_ERR_PATH:
226                     return(AFPERR_PARAM);
227                 case CNID_ERR_DB:
228                 case CNID_ERR_MAX:
229                     return(AFPERR_MISC);
230                 }
231             }
232 #endif /* CNID_DB */
233
234             if (aint == 0) {
235                 /*
236                  * What a fucking mess.  First thing:  DID and FNUMs are
237                  * in the same space for purposes of enumerate (and several
238                  * other wierd places).  While we consider this Apple's bug,
239                  * this is the work-around:  In order to maintain constant and
240                  * unique DIDs and FNUMs, we monotonically generate the DIDs
241                  * during the session, and derive the FNUMs from the filesystem.
242                  * Since the DIDs are small, we insure that the FNUMs are fairly
243                  * large by setting thier high bits to the device number.
244                  *
245                  * AFS already does something very similar to this for the
246                  * inode number, so we don't repeat the procedure.
247                  *
248                  * new algorithm:
249                  * due to complaints over did's being non-persistent,
250                  * here's the current hack to provide semi-persistent
251                  * did's:
252                  *      1) we reserve the first bit for file ids.
253                  *      2) the next 7 bits are for the device.
254                  *      3) the remaining 24 bits are for the inode.
255                  *
256                  * both the inode and device information are actually hashes
257                  * that are then truncated to the requisite bit length.
258                  *
259                  * it should be okay to use lstat to deal with symlinks.
260                  */
261 #ifdef USE_LASTDID
262                 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
263 #else /* USE_LASTDID */
264                 lstp = lstat(upath, &lst) < 0 ? st : &lst;
265 #ifdef DID_MTAB
266                 aint = htonl( afpd_st_cnid ( lstp ) );
267 #else /* DID_MTAB */
268                 aint = htonl(CNID(lstp, 1));
269 #endif /* DID_MTAB */
270 #endif /* USE_LASTDID */
271             }
272
273             memcpy(data, &aint, sizeof( aint ));
274             data += sizeof( aint );
275             break;
276
277         case FILPBIT_DFLEN :
278             aint = htonl( st->st_size );
279             memcpy(data, &aint, sizeof( aint ));
280             data += sizeof( aint );
281             break;
282
283         case FILPBIT_RFLEN :
284             if ( adp ) {
285                 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
286             } else {
287                 aint = 0;
288             }
289             memcpy(data, &aint, sizeof( aint ));
290             data += sizeof( aint );
291             break;
292
293             /* Current client needs ProDOS info block for this file.
294                Use simple heuristic and let the Mac "type" string tell
295                us what the PD file code should be.  Everything gets a
296                subtype of 0x0000 unless the original value was hashed
297                to "pXYZ" when we created it.  See IA, Ver 2.
298                <shirsch@ibm.net> */
299         case FILPBIT_PDINFO :
300             if ( adp ) {
301                 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
302
303                 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
304                     achar = '\x04';
305                     ashort = 0x0000;
306                 }
307                 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
308                     achar = '\xff';
309                     ashort = 0x0000;
310                 }
311                 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
312                     achar = '\xb3';
313                     ashort = 0x0000;
314                 }
315                 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
316                     achar = '\x00';
317                     ashort = 0x0000;
318                 }
319                 else if ( fdType[0] == 'p' ) {
320                     achar = fdType[1];
321                     ashort = (fdType[2] * 256) + fdType[3];
322                 }
323                 else {
324                     achar = '\x00';
325                     ashort = 0x0000;
326                 }
327             }
328             else {
329                 achar = '\x00';
330                 ashort = 0x0000;
331             }
332
333             *data++ = achar;
334             *data++ = 0;
335             memcpy(data, &ashort, sizeof( ashort ));
336             data += sizeof( ashort );
337             memset(data, 0, sizeof( ashort ));
338             data += sizeof( ashort );
339             break;
340
341         default :
342             return( AFPERR_BITMAP );
343         }
344         bitmap = bitmap>>1;
345         bit++;
346     }
347     if ( nameoff ) {
348         ashort = htons( data - buf );
349         memcpy(nameoff, &ashort, sizeof( ashort ));
350         if ((aint = strlen( path )) > MACFILELEN)
351             aint = MACFILELEN;
352         *data++ = aint;
353         memcpy(data, path, aint );
354         data += aint;
355     }
356     *buflen = data - buf;
357     return (AFP_OK);
358 }
359                 
360 /* ----------------------- */
361 int getfilparams(struct vol *vol,
362                  u_int16_t bitmap,
363                  char *path, struct dir *dir, struct stat *st,
364                  char *buf, int *buflen )
365 {
366     struct adouble      ad, *adp;
367     struct ofork        *of;
368     char                    *upath;
369     u_int16_t           attrbits = 0;
370     int rc;    
371 #ifdef DEBUG
372     LOG(log_info, logtype_default, "begin getfilparams:");
373 #endif /* DEBUG */
374
375     upath = mtoupath(vol, path);
376     if ((of = of_findname(vol, dir, path))) {
377         adp = of->of_ad;
378         attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
379         attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
380
381     } else {
382         memset(&ad, 0, sizeof(ad));
383         adp = &ad;
384     }
385
386     if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
387         adp = NULL;
388     }
389     else {
390 #if 0
391         /* FIXME 
392            we need to check if the file is open by another process.
393            it's slow so we only do it if we have to:
394            - bitmap is requested.
395            - we don't already have the answer!
396         */
397         if ((bitmap & (1 << FILPBIT_ATTR))) {
398                 if (!(attrbits & ATTRBIT_ROPEN)) {
399                 }
400                 if (!(attrbits & ATTRBIT_DOPEN)) {
401                 }
402         }
403 #endif          
404     }
405     rc = getmetadata(vol, bitmap, path, dir, st, buf, buflen, adp, attrbits);
406     if ( adp ) {
407         ad_close( adp, ADFLAGS_HF );
408     }
409 #ifdef DEBUG
410     LOG(log_info, logtype_afpd, "end getfilparams:");
411 #endif /* DEBUG */
412
413     return( rc );
414 }
415
416 /* ----------------------------- */
417 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
418 AFPObj      *obj;
419 char    *ibuf, *rbuf;
420 int             ibuflen, *rbuflen;
421 {
422     struct stat         st;
423     struct adouble      ad, *adp;
424     struct vol          *vol;
425     struct dir          *dir;
426     struct ofork        *of;
427     char                *path, *upath;
428     int                 creatf, did, openf, retvalue = AFP_OK;
429     u_int16_t           vid;
430 #ifdef FORCE_UIDGID
431     uidgidset           *uidgid;
432 #endif /* FORCE_UIDGID */
433
434 #ifdef DEBUG
435     LOG(log_info, logtype_afpd, "begin afp_createfile:");
436 #endif /* DEBUG */
437
438     *rbuflen = 0;
439     ibuf++;
440     creatf = (unsigned char) *ibuf++;
441
442     memcpy(&vid, ibuf, sizeof( vid ));
443     ibuf += sizeof( vid );
444
445     if (( vol = getvolbyvid( vid )) == NULL ) {
446         return( AFPERR_PARAM );
447     }
448
449     if (vol->v_flags & AFPVOL_RO)
450         return AFPERR_VLOCK;
451
452     memcpy(&did, ibuf, sizeof( did));
453     ibuf += sizeof( did );
454
455     if (( dir = dirsearch( vol, did )) == NULL ) {
456         return( AFPERR_NOOBJ );
457     }
458
459     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
460         return( AFPERR_NOOBJ );
461     }
462
463     upath = mtoupath(vol, path);
464     {
465     int ret;
466         if (0 != (ret = check_name(vol, upath))) 
467             return  ret;
468     }
469
470     if ((of = of_findname(vol, curdir, path))) {
471         adp = of->of_ad;
472     } else {
473         memset(&ad, 0, sizeof(ad));
474         adp = &ad;
475     }
476     if ( creatf) {
477         /* on a hard create, fail if file exists and is open */
478         if ((stat(upath, &st) == 0) && of)
479             return AFPERR_BUSY;
480         openf = O_RDWR|O_CREAT|O_TRUNC;
481     } else {
482         /* on a soft create, if the file is open then ad_open won't failed 
483            because open syscall is not called
484         */
485         if (of) {
486                 return AFPERR_EXIST;
487         }
488         openf = O_RDWR|O_CREAT|O_EXCL;
489     }
490
491 #ifdef FORCE_UIDGID
492
493     /* preserve current euid, egid */
494     save_uidgid ( uidgid );
495
496     /* perform all switching of users */
497     set_uidgid ( vol );
498
499 #endif /* FORCE_UIDGID */
500
501     if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
502                   openf, 0666, adp) < 0 ) {
503         switch ( errno ) {
504         case EEXIST :
505 #ifdef FORCE_UIDGID
506             /* bring everything back to old euid, egid */
507             restore_uidgid ( uidgid );
508 #endif /* FORCE_UIDGID */
509             return( AFPERR_EXIST );
510         case EACCES :
511 #ifdef FORCE_UIDGID
512             /* bring everything back to old euid, egid */
513             restore_uidgid ( uidgid );
514 #endif /* FORCE_UIDGID */
515             return( AFPERR_ACCESS );
516         case ENOENT:
517             /* on noadouble volumes, just creating the data fork is ok */
518             if (vol_noadouble(vol) && (stat(upath, &st) == 0))
519                 goto createfile_done;
520             /* fallthrough */
521         default :
522 #ifdef FORCE_UIDGID
523             /* bring everything back to old euid, egid */
524             restore_uidgid ( uidgid );
525 #endif /* FORCE_UIDGID */
526             return( AFPERR_PARAM );
527         }
528     }
529
530     ad_setentrylen( adp, ADEID_NAME, strlen( path ));
531     memcpy(ad_entry( adp, ADEID_NAME ), path,
532            ad_getentrylen( adp, ADEID_NAME ));
533     ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
534     ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
535
536 createfile_done:
537
538 #ifdef DROPKLUDGE
539     if (vol->v_flags & AFPVOL_DROPBOX) {
540         retvalue = matchfile2dirperms(upath, vol, did);
541     }
542 #endif /* DROPKLUDGE */
543
544     setvoltime(obj, vol );
545
546 #ifdef DEBUG
547     LOG(log_info, logtype_afpd, "end afp_createfile");
548 #endif /* DEBUG */
549
550 #ifdef FORCE_UIDGID
551     /* bring everything back to old euid, egid */
552     restore_uidgid ( uidgid );
553 #endif /* FORCE_UIDGID */
554
555     return (retvalue);
556 }
557
558 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
559 AFPObj      *obj;
560 char    *ibuf, *rbuf;
561 int             ibuflen, *rbuflen;
562 {
563     struct vol  *vol;
564     struct dir  *dir;
565     char        *path;
566     int         did, rc;
567     u_int16_t   vid, bitmap;
568
569 #ifdef DEBUG
570     LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
571 #endif /* DEBUG */
572
573     *rbuflen = 0;
574     ibuf += 2;
575
576     memcpy(&vid, ibuf, sizeof( vid ));
577     ibuf += sizeof( vid );
578     if (( vol = getvolbyvid( vid )) == NULL ) {
579         return( AFPERR_PARAM );
580     }
581
582     if (vol->v_flags & AFPVOL_RO)
583         return AFPERR_VLOCK;
584
585     memcpy(&did, ibuf, sizeof( did ));
586     ibuf += sizeof( did );
587     if (( dir = dirsearch( vol, did )) == NULL ) {
588         return( AFPERR_NOOBJ );
589     }
590
591     memcpy(&bitmap, ibuf, sizeof( bitmap ));
592     bitmap = ntohs( bitmap );
593     ibuf += sizeof( bitmap );
594
595     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
596         return( AFPERR_NOOBJ );
597     }
598
599     if ( *path == '\0' ) {
600         return( AFPERR_BADTYPE ); /* it's a directory */
601     }
602
603     if ((u_long)ibuf & 1 ) {
604         ibuf++;
605     }
606
607     if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
608         setvoltime(obj, vol );
609     }
610
611 #ifdef DEBUG
612     LOG(log_info, logtype_afpd, "end afp_setfilparams:");
613 #endif /* DEBUG */
614
615     return( rc );
616 }
617
618
619 int setfilparams(struct vol *vol,
620                  char *path, u_int16_t bitmap, char *buf )
621 {
622     struct adouble      ad, *adp;
623     struct ofork        *of;
624     struct extmap       *em;
625     int                 bit = 0, isad = 1, err = AFP_OK;
626     char                *upath;
627     u_char              achar, *fdType, xyy[4];
628     u_int16_t           ashort, bshort;
629     u_int32_t           aint;
630     struct utimbuf      ut;
631
632 #ifdef FORCE_UIDGID
633     uidgidset           *uidgid;
634
635     uidgid = malloc(sizeof(uidgidset));
636 #endif /* FORCE_UIDGID */
637
638 #ifdef DEBUG
639     LOG(log_info, logtype_afpd, "begin setfilparams:");
640 #endif /* DEBUG */
641
642     upath = mtoupath(vol, path);
643     if ((of = of_findname(vol, curdir, path))) {
644         adp = of->of_ad;
645     } else {
646         memset(&ad, 0, sizeof(ad));
647         adp = &ad;
648     }
649
650 #ifdef FORCE_UIDGID
651     save_uidgid ( uidgid );
652     set_uidgid ( vol );
653 #endif /* FORCE_UIDGID */
654
655     if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
656                  O_RDWR|O_CREAT, 0666, adp) < 0) {
657         /* for some things, we don't need an adouble header */
658         if (bitmap & ~(1<<FILPBIT_MDATE)) {
659 #ifdef FORCE_UIDGID
660             restore_uidgid ( uidgid );
661 #endif /* FORCE_UIDGID */
662             return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
663         }
664         isad = 0;
665     } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
666         ad_setentrylen( adp, ADEID_NAME, strlen( path ));
667         memcpy(ad_entry( adp, ADEID_NAME ), path,
668                ad_getentrylen( adp, ADEID_NAME ));
669     }
670
671     while ( bitmap != 0 ) {
672         while (( bitmap & 1 ) == 0 ) {
673             bitmap = bitmap>>1;
674             bit++;
675         }
676
677         switch(  bit ) {
678         case FILPBIT_ATTR :
679             memcpy(&ashort, buf, sizeof( ashort ));
680             ad_getattr(adp, &bshort);
681             if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
682                 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
683             } else {
684                 bshort &= ~ashort;
685             }
686             ad_setattr(adp, bshort);
687             buf += sizeof( ashort );
688             break;
689
690         case FILPBIT_CDATE :
691             memcpy(&aint, buf, sizeof(aint));
692             ad_setdate(adp, AD_DATE_CREATE, aint);
693             buf += sizeof( aint );
694             break;
695
696         case FILPBIT_MDATE :
697             memcpy(&aint, buf, sizeof( aint ));
698             if (isad)
699                 ad_setdate(adp, AD_DATE_MODIFY, aint);
700             ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
701             utime(upath, &ut);
702             buf += sizeof( aint );
703             break;
704
705         case FILPBIT_BDATE :
706             memcpy(&aint, buf, sizeof(aint));
707             ad_setdate(adp, AD_DATE_BACKUP, aint);
708             buf += sizeof( aint );
709             break;
710
711         case FILPBIT_FINFO :
712             if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
713                     && (em = getextmap( path )) &&
714                     (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
715                     (memcmp(buf + 4, em->em_creator,
716                             sizeof( em->em_creator )) == 0)) {
717                 memcpy(buf, ufinderi, 8 );
718             }
719             memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
720             buf += 32;
721             break;
722
723             /* Client needs to set the ProDOS file info for this file.
724                Use defined strings for the simple cases, and convert
725                all else into pXYY per Inside Appletalk.  Always set
726                the creator as "pdos". <shirsch@ibm.net> */
727         case FILPBIT_PDINFO :
728             achar = *buf;
729             buf += 2;
730             memcpy(&ashort, buf, sizeof( ashort ));
731             ashort = ntohs( ashort );
732             buf += 2;
733
734             switch ( (unsigned int) achar )
735             {
736             case 0x04 :
737                 fdType = ( u_char *) "TEXT";
738                 break;
739
740             case 0xff :
741                 fdType = ( u_char *) "PSYS";
742                 break;
743
744             case 0xb3 :
745                 fdType = ( u_char *) "PS16";
746                 break;
747
748             case 0x00 :
749                 fdType = ( u_char *) "BINA";
750                 break;
751
752             default :
753                 xyy[0] = ( u_char ) 'p';
754                 xyy[1] = achar;
755                 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
756                 xyy[3] = ( u_char ) ashort & 0xff;
757                 fdType = xyy;
758                 break;
759             }
760
761             memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
762             memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
763             break;
764
765
766         default :
767             err = AFPERR_BITMAP;
768             goto setfilparam_done;
769         }
770
771         bitmap = bitmap>>1;
772         bit++;
773     }
774
775 setfilparam_done:
776     if (isad) {
777         ad_flush( adp, ADFLAGS_HF );
778         ad_close( adp, ADFLAGS_HF );
779
780 #ifdef FORCE_UIDGID
781         restore_uidgid ( uidgid );
782 #endif /* FORCE_UIDGID */
783
784     }
785
786 #ifdef DEBUG
787     LOG(log_info, logtype_afpd, "end setfilparams:");
788 #endif /* DEBUG */
789
790     return err;
791 }
792
793 /*
794  * renamefile and copyfile take the old and new unix pathnames
795  * and the new mac name.
796  * NOTE: if we have to copy a file instead of renaming it, locks
797  *       will break.
798  * FIXME: locks on ressource fork will always break thanks to ad_close, done ?
799  *
800  * src         the full source absolute path 
801  * dst         the dest filename in current dir
802  * newname     the dest mac name
803  * adp         adouble struct of src file, if open, or & zeroed one
804  *
805  */
806 int renamefile(src, dst, newname, noadouble, adp )
807 char    *src, *dst, *newname;
808 const int         noadouble;
809 struct adouble    *adp;
810 {
811     char                adsrc[ MAXPATHLEN + 1];
812     int                 len, rc;
813
814     /*
815      * Note that this is only checking the existance of the data file,
816      * not the header file.  The thinking is that if the data file doesn't
817      * exist, but the header file does, the right thing to do is remove
818      * the data file silently.
819      */
820
821     /* existence check moved to afp_moveandrename */
822
823 #ifdef DEBUG
824     LOG(log_info, logtype_afpd, "begin renamefile:");
825 #endif /* DEBUG */
826
827     if ( rename( src, dst ) < 0 ) {
828         switch ( errno ) {
829         case ENOENT :
830             return( AFPERR_NOOBJ );
831         case EPERM:
832         case EACCES :
833             return( AFPERR_ACCESS );
834         case EROFS:
835             return AFPERR_VLOCK;
836         case EXDEV :                    /* Cross device move -- try copy */
837             if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
838                 deletefile( dst, 0 );
839                 return( rc );
840             }
841             return deletefile( src, 0);
842         default :
843             return( AFPERR_PARAM );
844         }
845     }
846
847     strcpy( adsrc, ad_path( src, 0 ));
848     rc = 0;
849 rename_retry:
850     if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
851         struct stat st;
852
853         switch ( errno ) {
854         case ENOENT :
855             /* check for a source appledouble header. if it exists, make
856              * a dest appledouble directory and do the rename again. */
857             if (rc || stat(adsrc, &st) ||
858                     (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
859                 return AFP_OK;
860             rc++;
861             ad_close(adp, ADFLAGS_HF);
862             goto rename_retry;
863         case EPERM:
864         case EACCES :
865             return( AFPERR_ACCESS );
866         case EROFS:
867             return AFPERR_VLOCK;
868         default :
869             return( AFPERR_PARAM );
870         }
871     }
872
873     if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
874         switch ( errno ) {
875         case ENOENT :
876             return( AFPERR_NOOBJ );
877         case EACCES :
878             return( AFPERR_ACCESS );
879         case EROFS:
880             return AFPERR_VLOCK;
881         default :
882             return( AFPERR_PARAM );
883         }
884     }
885
886     len = strlen( newname );
887     ad_setentrylen( adp, ADEID_NAME, len );
888     memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
889     ad_flush( adp, ADFLAGS_HF );
890     ad_close( adp, ADFLAGS_HF );
891
892 #ifdef DEBUG
893     LOG(log_info, logtype_afpd, "end renamefile:");
894 #endif /* DEBUG */
895
896     return( AFP_OK );
897 }
898
899 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
900 AFPObj      *obj;
901 char    *ibuf, *rbuf;
902 int             ibuflen, *rbuflen;
903 {
904     struct vol  *vol;
905     struct dir  *dir;
906     char        *newname, *path, *p;
907     u_int32_t   sdid, ddid;
908     int         plen, err, retvalue = AFP_OK;
909     u_int16_t   svid, dvid;
910
911 #ifdef DEBUG
912     LOG(log_info, logtype_afpd, "begin afp_copyfile:");
913 #endif /* DEBUG */
914
915     *rbuflen = 0;
916     ibuf += 2;
917
918     memcpy(&svid, ibuf, sizeof( svid ));
919     ibuf += sizeof( svid );
920     if (( vol = getvolbyvid( svid )) == NULL ) {
921         return( AFPERR_PARAM );
922     }
923
924     memcpy(&sdid, ibuf, sizeof( sdid ));
925     ibuf += sizeof( sdid );
926     if (( dir = dirsearch( vol, sdid )) == NULL ) {
927         return( AFPERR_PARAM );
928     }
929
930     memcpy(&dvid, ibuf, sizeof( dvid ));
931     ibuf += sizeof( dvid );
932     memcpy(&ddid, ibuf, sizeof( ddid ));
933     ibuf += sizeof( ddid );
934
935     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
936         return( AFPERR_NOOBJ );
937     }
938     if ( *path == '\0' ) {
939         return( AFPERR_BADTYPE );
940     }
941
942     /* don't allow copies when the file is open.
943      * XXX: the spec only calls for read/deny write access.
944      *      however, copyfile doesn't have any of that info,
945      *      and locks need to stay coherent. as a result,
946      *      we just balk if the file is opened already. */
947     if (of_findname(vol, curdir, path))
948         return AFPERR_DENYCONF;
949
950     newname = obj->newtmp;
951     strcpy( newname, path );
952
953     p = ctoupath( vol, curdir, newname );
954
955     if (( vol = getvolbyvid( dvid )) == NULL ) {
956         return( AFPERR_PARAM );
957     }
958
959     if (vol->v_flags & AFPVOL_RO)
960         return AFPERR_VLOCK;
961
962     if (( dir = dirsearch( vol, ddid )) == NULL ) {
963         return( AFPERR_PARAM );
964     }
965
966     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
967         return( AFPERR_NOOBJ );
968     }
969     if ( *path != '\0' ) {
970         return( AFPERR_BADTYPE );
971     }
972
973     /* one of the handful of places that knows about the path type */
974     if ( *ibuf++ != 2 ) {
975         return( AFPERR_PARAM );
976     }
977     if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
978         strncpy( newname, ibuf, plen );
979         newname[ plen ] = '\0';
980     }
981
982     if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
983                          vol_noadouble(vol))) < 0 ) {
984         return err;
985     }
986
987     setvoltime(obj, vol );
988
989 #ifdef DROPKLUDGE
990     if (vol->v_flags & AFPVOL_DROPBOX) {
991         retvalue=matchfile2dirperms(newname, vol, sdid);
992     }
993 #endif /* DROPKLUDGE */
994
995 #ifdef DEBUG
996     LOG(log_info, logtype_afpd, "end afp_copyfile:");
997 #endif /* DEBUG */
998
999     return( retvalue );
1000 }
1001
1002
1003 static __inline__ int copy_all(const int dfd, const void *buf,
1004                                size_t buflen)
1005 {
1006     ssize_t cc;
1007
1008 #ifdef DEBUG
1009     LOG(log_info, logtype_afpd, "begin copy_all:");
1010 #endif /* DEBUG */
1011
1012     while (buflen > 0) {
1013         if ((cc = write(dfd, buf, buflen)) < 0) {
1014             switch (errno) {
1015             case EINTR:
1016                 continue;
1017             case EDQUOT:
1018             case EFBIG:
1019             case ENOSPC:
1020                 return AFPERR_DFULL;
1021             case EROFS:
1022                 return AFPERR_VLOCK;
1023             default:
1024                 return AFPERR_PARAM;
1025             }
1026         }
1027         buflen -= cc;
1028     }
1029
1030 #ifdef DEBUG
1031     LOG(log_info, logtype_afpd, "end copy_all:");
1032 #endif /* DEBUG */
1033
1034     return AFP_OK;
1035 }
1036
1037 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1038  * pass in vol and path */
1039 int copyfile(src, dst, newname, noadouble )
1040 char    *src, *dst, *newname;
1041 const int   noadouble;
1042 {
1043     struct adouble      ad;
1044     struct stat         st;
1045     char                filebuf[8192];
1046     int                 sfd, dfd, len, err = AFP_OK;
1047     ssize_t             cc;
1048
1049 #ifdef DEBUG
1050     LOG(log_info, logtype_afpd, "begin copyfile:");
1051 #endif /* DEBUG */
1052
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( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
1065                               ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 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(ad_path(dst, ADFLAGS_HF));
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, ad_mode( dst, 0666 ))) < 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(ad_path(dst, ADFLAGS_HF));
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 */
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_BADID;
1504     }
1505
1506     if (( dir = dirlookup( vol, id )) == NULL ) {
1507         return( AFPERR_PARAM );
1508     }
1509
1510     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1511         switch (errno) {
1512         case EACCES:
1513         case EPERM:
1514             return AFPERR_ACCESS;
1515         case ENOENT:
1516             return AFPERR_NOID;
1517         default:
1518             return AFPERR_PARAM;
1519         }
1520     }
1521
1522     /* directories are bad */
1523     if (S_ISDIR(st.st_mode))
1524         return AFPERR_BADTYPE;
1525
1526     memcpy(&bitmap, ibuf, sizeof(bitmap));
1527     bitmap = ntohs( bitmap );
1528
1529     if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1530                             rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1531         return err;
1532
1533     *rbuflen = buflen + sizeof(bitmap);
1534     memcpy(rbuf, ibuf, sizeof(bitmap));
1535
1536 #ifdef DEBUG
1537     LOG(log_info, logtype_afpd, "end afp_resolveid:");
1538 #endif /* DEBUG */
1539
1540     return AFP_OK;
1541 }
1542
1543 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1544 AFPObj      *obj;
1545 char    *ibuf, *rbuf;
1546 int             ibuflen, *rbuflen;
1547 {
1548     struct stat         st;
1549     struct vol          *vol;
1550     struct dir          *dir;
1551     char                *upath;
1552     int                 err;
1553     cnid_t              id;
1554     cnid_t              fileid;
1555     u_short             vid;
1556     static char buffer[12 + MAXPATHLEN + 1];
1557     int len = 12 + MAXPATHLEN + 1;
1558
1559 #ifdef DEBUG
1560     LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1561 #endif /* DEBUG */
1562
1563     *rbuflen = 0;
1564     ibuf += 2;
1565
1566     memcpy(&vid, ibuf, sizeof(vid));
1567     ibuf += sizeof(vid);
1568
1569     if (( vol = getvolbyvid( vid )) == NULL ) {
1570         return( AFPERR_PARAM);
1571     }
1572
1573     if (vol->v_flags & AFPVOL_RO)
1574         return AFPERR_VLOCK;
1575
1576     memcpy(&id, ibuf, sizeof( id ));
1577     ibuf += sizeof(id);
1578     fileid = id;
1579
1580     if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1581         return AFPERR_NOID;
1582     }
1583
1584     if (( dir = dirlookup( vol, id )) == NULL ) {
1585         return( AFPERR_PARAM );
1586     }
1587
1588     err = AFP_OK;
1589     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1590         switch (errno) {
1591         case EACCES:
1592         case EPERM:
1593             return AFPERR_ACCESS;
1594         case ENOENT:
1595             /* still try to delete the id */
1596             err = AFPERR_NOOBJ;
1597             break;
1598         default:
1599             return AFPERR_PARAM;
1600         }
1601     }
1602
1603     /* directories are bad */
1604     if (S_ISDIR(st.st_mode))
1605         return AFPERR_BADTYPE;
1606
1607     if (cnid_delete(vol->v_db, fileid)) {
1608         switch (errno) {
1609         case EROFS:
1610             return AFPERR_VLOCK;
1611         case EPERM:
1612         case EACCES:
1613             return AFPERR_ACCESS;
1614         default:
1615             return AFPERR_PARAM;
1616         }
1617     }
1618
1619 #ifdef DEBUG
1620     LOG(log_info, logtype_afpd, "end afp_deleteid:");
1621 #endif /* DEBUG */
1622
1623     return err;
1624 }
1625 #endif /* CNID_DB */
1626
1627 #define APPLETEMP ".AppleTempXXXXXX"
1628
1629 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1630 AFPObj      *obj;
1631 char    *ibuf, *rbuf;
1632 int             ibuflen, *rbuflen;
1633 {
1634     struct stat         srcst, destst;
1635     struct vol          *vol;
1636     struct dir          *dir, *sdir;
1637     char                *spath, temp[17], *path, *p;
1638     char                *supath, *upath;
1639     int                 err;
1640     struct adouble      ads;
1641     struct adouble      add;
1642     struct adouble      *adsp;
1643     struct adouble      *addp;
1644     struct ofork        *opened;
1645     
1646 #ifdef CNID_DB
1647     int                 slen, dlen;
1648 #endif /* CNID_DB */
1649     u_int32_t           sid, did;
1650     u_int16_t           vid;
1651
1652 #ifdef DEBUG
1653     LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1654 #endif /* DEBUG */
1655
1656     *rbuflen = 0;
1657     ibuf += 2;
1658
1659     memcpy(&vid, ibuf, sizeof(vid));
1660     ibuf += sizeof(vid);
1661
1662     if (( vol = getvolbyvid( vid )) == NULL ) {
1663         return( AFPERR_PARAM);
1664     }
1665
1666     if (vol->v_flags & AFPVOL_RO)
1667         return AFPERR_VLOCK;
1668
1669     /* source and destination dids */
1670     memcpy(&sid, ibuf, sizeof(sid));
1671     ibuf += sizeof(sid);
1672     memcpy(&did, ibuf, sizeof(did));
1673     ibuf += sizeof(did);
1674
1675     /* source file */
1676     if ((dir = dirsearch( vol, sid )) == NULL ) {
1677         return( AFPERR_PARAM );
1678     }
1679
1680     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1681         return( AFPERR_PARAM );
1682     }
1683
1684     if ( *path == '\0' ) {
1685         return( AFPERR_BADTYPE );   /* it's a dir */
1686     }
1687
1688     upath = mtoupath(vol, path);
1689     if (stat(upath, &srcst) < 0) {
1690         switch (errno) {
1691         case ENOENT:
1692             return AFPERR_NOID;
1693         case EPERM:
1694         case EACCES:
1695             return AFPERR_ACCESS;
1696         default:
1697             return AFPERR_PARAM;
1698         }
1699     }
1700     memset(&ads, 0, sizeof(ads));
1701     adsp = &ads;
1702     if ((opened = of_findname(vol, curdir, path))) {
1703             /* reuse struct adouble so it won't break locks */
1704             adsp = opened->of_ad;
1705     }
1706     /* save some stuff */
1707     sdir = curdir;
1708     spath = obj->oldtmp;
1709     supath = obj->newtmp;
1710     strcpy(spath, path);
1711     strcpy(supath, upath); /* this is for the cnid changing */
1712     p = ctoupath( vol, sdir, spath);
1713
1714     /* look for the source cnid. if it doesn't exist, don't worry about
1715      * it. */
1716 #ifdef CNID_DB
1717     sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1718                       slen = strlen(supath));
1719 #endif /* CNID_DB */
1720
1721     if (( dir = dirsearch( vol, did )) == NULL ) {
1722         return( AFPERR_PARAM );
1723     }
1724
1725     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1726         return( AFPERR_PARAM );
1727     }
1728
1729     if ( *path == '\0' ) {
1730         return( AFPERR_BADTYPE );
1731     }
1732
1733     /* FPExchangeFiles is the only call that can return the SameObj
1734      * error */
1735     if ((curdir == sdir) && strcmp(spath, path) == 0)
1736         return AFPERR_SAMEOBJ;
1737
1738     upath = mtoupath(vol, path);
1739     if (stat(upath, &destst) < 0) {
1740         switch (errno) {
1741         case ENOENT:
1742             return AFPERR_NOID;
1743         case EPERM:
1744         case EACCES:
1745             return AFPERR_ACCESS;
1746         default:
1747             return AFPERR_PARAM;
1748         }
1749     }
1750     memset(&add, 0, sizeof(add));
1751     addp = &add;
1752     if ((opened = of_findname(vol, curdir, path))) {
1753             /* reuse struct adouble so it won't break locks */
1754             addp = opened->of_ad;
1755     }
1756 #ifdef CNID_DB
1757     /* look for destination id. */
1758     did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1759                       dlen = strlen(upath));
1760 #endif /* CNID_DB */
1761
1762     /* construct a temp name.
1763      * NOTE: the temp file will be in the dest file's directory. it
1764      * will also be inaccessible from AFP. */
1765     memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1766     if (!mktemp(temp))
1767         return AFPERR_MISC;
1768
1769     /* now, quickly rename the file. we error if we can't. */
1770     if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1771         goto err_exchangefile;
1772     of_rename(vol, sdir, spath, curdir, temp);
1773
1774     /* rename destination to source */
1775     if ((err = renamefile(path, p, spath, vol_noadouble(vol), addp)) < 0)
1776         goto err_src_to_tmp;
1777     of_rename(vol, curdir, path, sdir, spath);
1778
1779     /* rename temp to destination */
1780     if ((err = renamefile(temp, upath, path, vol_noadouble(vol), adsp)) < 0)
1781         goto err_dest_to_src;
1782     of_rename(vol, curdir, temp, curdir, path);
1783
1784 #ifdef CNID_DB
1785     /* id's need switching. src -> dest and dest -> src. */
1786     if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1787                             upath, dlen) < 0)) {
1788         switch (errno) {
1789         case EPERM:
1790         case EACCES:
1791             err = AFPERR_ACCESS;
1792             break;
1793         default:
1794             err = AFPERR_PARAM;
1795         }
1796         goto err_temp_to_dest;
1797     }
1798
1799     if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1800                             supath, slen) < 0)) {
1801         switch (errno) {
1802         case EPERM:
1803         case EACCES:
1804             err = AFPERR_ACCESS;
1805             break;
1806         default:
1807             err = AFPERR_PARAM;
1808         }
1809
1810         if (sid)
1811             cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1812         goto err_temp_to_dest;
1813     }
1814 #endif /* CNID_DB */
1815
1816 #ifdef DEBUG
1817     LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1818 #endif /* DEBUG */
1819
1820     return AFP_OK;
1821
1822
1823     /* all this stuff is so that we can unwind a failed operation
1824      * properly. */
1825 #ifdef CNID_DB
1826 err_temp_to_dest:
1827 #endif
1828     /* rename dest to temp */
1829     renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1830     of_rename(vol, curdir, upath, curdir, temp);
1831
1832 err_dest_to_src:
1833     /* rename source back to dest */
1834     renamefile(p, upath, path, vol_noadouble(vol), addp);
1835     of_rename(vol, sdir, spath, curdir, path);
1836
1837 err_src_to_tmp:
1838     /* rename temp back to source */
1839     renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1840     of_rename(vol, curdir, temp, sdir, spath);
1841
1842 err_exchangefile:
1843     return err;
1844 }