]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/file.c
Check that object has the right type (file, directory) before setdirparams
[netatalk.git] / etc / afpd / file.c
1 /*
2  * $Id: file.c,v 1.47 2002-08-16 00:42:56 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 #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     struct ofork        *opened;
812     char                adsrc[ MAXPATHLEN + 1];
813     int                 len, rc;
814
815     /*
816      * Note that this is only checking the existance of the data file,
817      * not the header file.  The thinking is that if the data file doesn't
818      * exist, but the header file does, the right thing to do is remove
819      * the data file silently.
820      */
821
822     /* existence check moved to afp_moveandrename */
823
824 #ifdef DEBUG
825     LOG(log_info, logtype_afpd, "begin renamefile:");
826 #endif /* DEBUG */
827
828     if ( rename( src, dst ) < 0 ) {
829         switch ( errno ) {
830         case ENOENT :
831             return( AFPERR_NOOBJ );
832         case EPERM:
833         case EACCES :
834             return( AFPERR_ACCESS );
835         case EROFS:
836             return AFPERR_VLOCK;
837         case EXDEV :                    /* Cross device move -- try copy */
838             if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
839                 deletefile( dst, 0 );
840                 return( rc );
841             }
842             return deletefile( src, 0);
843         default :
844             return( AFPERR_PARAM );
845         }
846     }
847
848     strcpy( adsrc, ad_path( src, 0 ));
849     rc = 0;
850 rename_retry:
851     if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
852         struct stat st;
853
854         switch ( errno ) {
855         case ENOENT :
856             /* check for a source appledouble header. if it exists, make
857              * a dest appledouble directory and do the rename again. */
858             if (rc || stat(adsrc, &st) ||
859                     (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
860                 return AFP_OK;
861             rc++;
862             ad_close(adp, ADFLAGS_HF);
863             goto rename_retry;
864         case EPERM:
865         case EACCES :
866             return( AFPERR_ACCESS );
867         case EROFS:
868             return AFPERR_VLOCK;
869         default :
870             return( AFPERR_PARAM );
871         }
872     }
873
874     if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
875         switch ( errno ) {
876         case ENOENT :
877             return( AFPERR_NOOBJ );
878         case EACCES :
879             return( AFPERR_ACCESS );
880         case EROFS:
881             return AFPERR_VLOCK;
882         default :
883             return( AFPERR_PARAM );
884         }
885     }
886
887     len = strlen( newname );
888     ad_setentrylen( adp, ADEID_NAME, len );
889     memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
890     ad_flush( adp, ADFLAGS_HF );
891     ad_close( adp, ADFLAGS_HF );
892
893 #ifdef DEBUG
894     LOG(log_info, logtype_afpd, "end renamefile:");
895 #endif /* DEBUG */
896
897     return( AFP_OK );
898 }
899
900 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
901 AFPObj      *obj;
902 char    *ibuf, *rbuf;
903 int             ibuflen, *rbuflen;
904 {
905     struct vol  *vol;
906     struct dir  *dir;
907     char        *newname, *path, *p;
908     u_int32_t   sdid, ddid;
909     int         plen, err, retvalue = AFP_OK;
910     u_int16_t   svid, dvid;
911
912 #ifdef DEBUG
913     LOG(log_info, logtype_afpd, "begin afp_copyfile:");
914 #endif /* DEBUG */
915
916     *rbuflen = 0;
917     ibuf += 2;
918
919     memcpy(&svid, ibuf, sizeof( svid ));
920     ibuf += sizeof( svid );
921     if (( vol = getvolbyvid( svid )) == NULL ) {
922         return( AFPERR_PARAM );
923     }
924
925     memcpy(&sdid, ibuf, sizeof( sdid ));
926     ibuf += sizeof( sdid );
927     if (( dir = dirsearch( vol, sdid )) == NULL ) {
928         return( AFPERR_PARAM );
929     }
930
931     memcpy(&dvid, ibuf, sizeof( dvid ));
932     ibuf += sizeof( dvid );
933     memcpy(&ddid, ibuf, sizeof( ddid ));
934     ibuf += sizeof( ddid );
935
936     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
937         return( AFPERR_NOOBJ );
938     }
939     if ( *path == '\0' ) {
940         return( AFPERR_BADTYPE );
941     }
942
943     /* don't allow copies when the file is open.
944      * XXX: the spec only calls for read/deny write access.
945      *      however, copyfile doesn't have any of that info,
946      *      and locks need to stay coherent. as a result,
947      *      we just balk if the file is opened already. */
948     if (of_findname(vol, curdir, path))
949         return AFPERR_DENYCONF;
950
951     newname = obj->newtmp;
952     strcpy( newname, path );
953
954     p = ctoupath( vol, curdir, newname );
955
956     if (( vol = getvolbyvid( dvid )) == NULL ) {
957         return( AFPERR_PARAM );
958     }
959
960     if (vol->v_flags & AFPVOL_RO)
961         return AFPERR_VLOCK;
962
963     if (( dir = dirsearch( vol, ddid )) == NULL ) {
964         return( AFPERR_PARAM );
965     }
966
967     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
968         return( AFPERR_NOOBJ );
969     }
970     if ( *path != '\0' ) {
971         return( AFPERR_BADTYPE );
972     }
973
974     /* one of the handful of places that knows about the path type */
975     if ( *ibuf++ != 2 ) {
976         return( AFPERR_PARAM );
977     }
978     if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
979         strncpy( newname, ibuf, plen );
980         newname[ plen ] = '\0';
981     }
982
983     if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
984                          vol_noadouble(vol))) < 0 ) {
985         return err;
986     }
987
988     setvoltime(obj, vol );
989
990 #ifdef DROPKLUDGE
991     if (vol->v_flags & AFPVOL_DROPBOX) {
992         retvalue=matchfile2dirperms(newname, vol, sdid);
993     }
994 #endif /* DROPKLUDGE */
995
996 #ifdef DEBUG
997     LOG(log_info, logtype_afpd, "end afp_copyfile:");
998 #endif /* DEBUG */
999
1000     return( retvalue );
1001 }
1002
1003
1004 static __inline__ int copy_all(const int dfd, const void *buf,
1005                                size_t buflen)
1006 {
1007     ssize_t cc;
1008
1009 #ifdef DEBUG
1010     LOG(log_info, logtype_afpd, "begin copy_all:");
1011 #endif /* DEBUG */
1012
1013     while (buflen > 0) {
1014         if ((cc = write(dfd, buf, buflen)) < 0) {
1015             switch (errno) {
1016             case EINTR:
1017                 continue;
1018             case EDQUOT:
1019             case EFBIG:
1020             case ENOSPC:
1021                 return AFPERR_DFULL;
1022             case EROFS:
1023                 return AFPERR_VLOCK;
1024             default:
1025                 return AFPERR_PARAM;
1026             }
1027         }
1028         buflen -= cc;
1029     }
1030
1031 #ifdef DEBUG
1032     LOG(log_info, logtype_afpd, "end copy_all:");
1033 #endif /* DEBUG */
1034
1035     return AFP_OK;
1036 }
1037
1038 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1039  * pass in vol and path */
1040 int copyfile(src, dst, newname, noadouble )
1041 char    *src, *dst, *newname;
1042 const int   noadouble;
1043 {
1044     struct adouble      ad;
1045     struct stat         st;
1046     char                filebuf[8192];
1047     int                 sfd, dfd, len, err = AFP_OK;
1048     ssize_t             cc;
1049
1050 #ifdef DEBUG
1051     LOG(log_info, logtype_afpd, "begin copyfile:");
1052 #endif /* DEBUG */
1053
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( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
1066                               ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
1067                 close( sfd );
1068                 switch ( errno ) {
1069                 case ENOENT :
1070                     return( AFPERR_NOOBJ );
1071                 case EACCES :
1072                     return( AFPERR_ACCESS );
1073                 case EROFS:
1074                     return AFPERR_VLOCK;
1075                 default :
1076                     return( AFPERR_PARAM );
1077                 }
1078             }
1079
1080             /* copy the file */
1081 #ifdef SENDFILE_FLAVOR_LINUX
1082             if (fstat(sfd, &st) == 0) {
1083                 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1084                     switch (errno) {
1085                     case EDQUOT:
1086                     case EFBIG:
1087                     case ENOSPC:
1088                         err = AFPERR_DFULL;
1089                         break;
1090                     case EROFS:
1091                         err = AFPERR_VLOCK;
1092                         break;
1093                     default:
1094                         err = AFPERR_PARAM;
1095                     }
1096                 }
1097                 goto copyheader_done;
1098             }
1099 #endif /* SENDFILE_FLAVOR_LINUX */
1100             while (1) {
1101                 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1102                     if (errno == EINTR)
1103                         continue;
1104                     err = AFPERR_PARAM;
1105                     break;
1106                 }
1107
1108                 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1109                     break;
1110             }
1111
1112 copyheader_done:
1113             close(sfd);
1114             close(dfd);
1115             if (err < 0) {
1116                 unlink(ad_path(dst, ADFLAGS_HF));
1117                 return err;
1118             }
1119         }
1120     }
1121
1122     /* data fork copying */
1123     if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1124         switch ( errno ) {
1125         case ENOENT :
1126             return( AFPERR_NOOBJ );
1127         case EACCES :
1128             return( AFPERR_ACCESS );
1129         default :
1130             return( AFPERR_PARAM );
1131         }
1132     }
1133
1134     if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1135         close( sfd );
1136         switch ( errno ) {
1137         case ENOENT :
1138             return( AFPERR_NOOBJ );
1139         case EACCES :
1140             return( AFPERR_ACCESS );
1141         case EROFS:
1142             return AFPERR_VLOCK;
1143         default :
1144             return( AFPERR_PARAM );
1145         }
1146     }
1147
1148 #ifdef SENDFILE_FLAVOR_LINUX
1149     if (fstat(sfd, &st) == 0) {
1150         if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1151             switch (errno) {
1152             case EDQUOT:
1153             case EFBIG:
1154             case ENOSPC:
1155                 err = AFPERR_DFULL;
1156                 break;
1157             default:
1158                 err = AFPERR_PARAM;
1159             }
1160         }
1161         goto copydata_done;
1162     }
1163 #endif /* SENDFILE_FLAVOR_LINUX */
1164
1165     while (1) {
1166         if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1167             if (errno == EINTR)
1168                 continue;
1169
1170             err = AFPERR_PARAM;
1171             break;
1172         }
1173
1174         if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1175             break;
1176         }
1177     }
1178
1179 copydata_done:
1180     close(sfd);
1181     close(dfd);
1182     if (err < 0) {
1183         unlink(ad_path(dst, ADFLAGS_HF));
1184         unlink(dst);
1185         return err;
1186     }
1187
1188     if (newname) {
1189         memset(&ad, 0, sizeof(ad));
1190         if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1191                       0666, &ad) < 0 ) {
1192             switch ( errno ) {
1193             case ENOENT :
1194                 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1195             case EACCES :
1196                 return( AFPERR_ACCESS );
1197             case EROFS:
1198                 return AFPERR_VLOCK;
1199             default :
1200                 return( AFPERR_PARAM );
1201             }
1202         }
1203
1204         len = strlen( newname );
1205         ad_setentrylen( &ad, ADEID_NAME, len );
1206         memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1207         ad_flush( &ad, ADFLAGS_HF );
1208         ad_close( &ad, ADFLAGS_HF );
1209     }
1210
1211 #ifdef DEBUG
1212     LOG(log_info, logtype_afpd, "end copyfile:");
1213 #endif /* DEBUG */
1214
1215     return( AFP_OK );
1216 }
1217
1218
1219 /* -----------------------------------
1220    checkAttrib:   1 check kFPDeleteInhibitBit 
1221    ie deletfile called by afp_delete
1222
1223    when deletefile is called we don't have lock on it, file is closed (for us)
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_BADID;
1505     }
1506
1507     if (( dir = dirlookup( vol, id )) == NULL ) {
1508         return( 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        *opened;
1646     
1647 #ifdef CNID_DB
1648     int                 slen, dlen;
1649 #endif /* CNID_DB */
1650     u_int32_t           sid, did;
1651     u_int16_t           vid;
1652
1653 #ifdef DEBUG
1654     LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1655 #endif /* DEBUG */
1656
1657     *rbuflen = 0;
1658     ibuf += 2;
1659
1660     memcpy(&vid, ibuf, sizeof(vid));
1661     ibuf += sizeof(vid);
1662
1663     if (( vol = getvolbyvid( vid )) == NULL ) {
1664         return( AFPERR_PARAM);
1665     }
1666
1667     if (vol->v_flags & AFPVOL_RO)
1668         return AFPERR_VLOCK;
1669
1670     /* source and destination dids */
1671     memcpy(&sid, ibuf, sizeof(sid));
1672     ibuf += sizeof(sid);
1673     memcpy(&did, ibuf, sizeof(did));
1674     ibuf += sizeof(did);
1675
1676     /* source file */
1677     if ((dir = dirsearch( vol, sid )) == NULL ) {
1678         return( AFPERR_PARAM );
1679     }
1680
1681     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1682         return( AFPERR_PARAM );
1683     }
1684
1685     if ( *path == '\0' ) {
1686         return( AFPERR_BADTYPE );   /* it's a dir */
1687     }
1688
1689     upath = mtoupath(vol, path);
1690     if (stat(upath, &srcst) < 0) {
1691         switch (errno) {
1692         case ENOENT:
1693             return AFPERR_NOID;
1694         case EPERM:
1695         case EACCES:
1696             return AFPERR_ACCESS;
1697         default:
1698             return AFPERR_PARAM;
1699         }
1700     }
1701     memset(&ads, 0, sizeof(ads));
1702     adsp = &ads;
1703     if ((opened = of_findname(vol, curdir, path))) {
1704             /* reuse struct adouble so it won't break locks */
1705             adsp = opened->of_ad;
1706     }
1707     /* save some stuff */
1708     sdir = curdir;
1709     spath = obj->oldtmp;
1710     supath = obj->newtmp;
1711     strcpy(spath, path);
1712     strcpy(supath, upath); /* this is for the cnid changing */
1713     p = ctoupath( vol, sdir, spath);
1714
1715     /* look for the source cnid. if it doesn't exist, don't worry about
1716      * it. */
1717 #ifdef CNID_DB
1718     sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1719                       slen = strlen(supath));
1720 #endif /* CNID_DB */
1721
1722     if (( dir = dirsearch( vol, did )) == NULL ) {
1723         return( AFPERR_PARAM );
1724     }
1725
1726     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1727         return( AFPERR_PARAM );
1728     }
1729
1730     if ( *path == '\0' ) {
1731         return( AFPERR_BADTYPE );
1732     }
1733
1734     /* FPExchangeFiles is the only call that can return the SameObj
1735      * error */
1736     if ((curdir == sdir) && strcmp(spath, path) == 0)
1737         return AFPERR_SAMEOBJ;
1738
1739     upath = mtoupath(vol, path);
1740     if (stat(upath, &destst) < 0) {
1741         switch (errno) {
1742         case ENOENT:
1743             return AFPERR_NOID;
1744         case EPERM:
1745         case EACCES:
1746             return AFPERR_ACCESS;
1747         default:
1748             return AFPERR_PARAM;
1749         }
1750     }
1751     memset(&add, 0, sizeof(add));
1752     addp = &add;
1753     if ((opened = of_findname(vol, curdir, path))) {
1754             /* reuse struct adouble so it won't break locks */
1755             addp = opened->of_ad;
1756     }
1757 #ifdef CNID_DB
1758     /* look for destination id. */
1759     did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1760                       dlen = strlen(upath));
1761 #endif /* CNID_DB */
1762
1763     /* construct a temp name.
1764      * NOTE: the temp file will be in the dest file's directory. it
1765      * will also be inaccessible from AFP. */
1766     memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1767     if (!mktemp(temp))
1768         return AFPERR_MISC;
1769
1770     /* now, quickly rename the file. we error if we can't. */
1771     if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1772         goto err_exchangefile;
1773     of_rename(vol, sdir, spath, curdir, temp);
1774
1775     /* rename destination to source */
1776     if ((err = renamefile(path, p, spath, vol_noadouble(vol), addp)) < 0)
1777         goto err_src_to_tmp;
1778     of_rename(vol, curdir, path, sdir, spath);
1779
1780     /* rename temp to destination */
1781     if ((err = renamefile(temp, upath, path, vol_noadouble(vol), adsp)) < 0)
1782         goto err_dest_to_src;
1783     of_rename(vol, curdir, temp, curdir, path);
1784
1785 #ifdef CNID_DB
1786     /* id's need switching. src -> dest and dest -> src. */
1787     if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1788                             upath, dlen) < 0)) {
1789         switch (errno) {
1790         case EPERM:
1791         case EACCES:
1792             err = AFPERR_ACCESS;
1793             break;
1794         default:
1795             err = AFPERR_PARAM;
1796         }
1797         goto err_temp_to_dest;
1798     }
1799
1800     if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1801                             supath, slen) < 0)) {
1802         switch (errno) {
1803         case EPERM:
1804         case EACCES:
1805             err = AFPERR_ACCESS;
1806             break;
1807         default:
1808             err = AFPERR_PARAM;
1809         }
1810
1811         if (sid)
1812             cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1813         goto err_temp_to_dest;
1814     }
1815 #endif /* CNID_DB */
1816
1817 #ifdef DEBUG
1818     LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1819 #endif /* DEBUG */
1820
1821     return AFP_OK;
1822
1823
1824     /* all this stuff is so that we can unwind a failed operation
1825      * properly. */
1826 err_temp_to_dest:
1827     /* rename dest to temp */
1828     renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1829     of_rename(vol, curdir, upath, curdir, temp);
1830
1831 err_dest_to_src:
1832     /* rename source back to dest */
1833     renamefile(p, upath, path, vol_noadouble(vol), addp);
1834     of_rename(vol, sdir, spath, curdir, path);
1835
1836 err_src_to_tmp:
1837     /* rename temp back to source */
1838     renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1839     of_rename(vol, curdir, temp, sdir, spath);
1840
1841 err_exchangefile:
1842     return err;
1843 }