]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/file.c
more bits set in files/folders attributes. Fix error -51 in inspiration
[netatalk.git] / etc / afpd / file.c
1 /*
2  * $Id: file.c,v 1.46 2002-06-17 18:23:03 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 ((u_long)ibuf & 1 ) {
600         ibuf++;
601     }
602
603     if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
604         setvoltime(obj, vol );
605     }
606
607 #ifdef DEBUG
608     LOG(log_info, logtype_afpd, "end afp_setfilparams:");
609 #endif /* DEBUG */
610
611     return( rc );
612 }
613
614
615 int setfilparams(struct vol *vol,
616                  char *path, u_int16_t bitmap, char *buf )
617 {
618     struct adouble      ad, *adp;
619     struct ofork        *of;
620     struct extmap       *em;
621     int                 bit = 0, isad = 1, err = AFP_OK;
622     char                *upath;
623     u_char              achar, *fdType, xyy[4];
624     u_int16_t           ashort, bshort;
625     u_int32_t           aint;
626     struct utimbuf      ut;
627
628 #ifdef FORCE_UIDGID
629     uidgidset           *uidgid;
630
631     uidgid = malloc(sizeof(uidgidset));
632 #endif /* FORCE_UIDGID */
633
634 #ifdef DEBUG
635     LOG(log_info, logtype_afpd, "begin setfilparams:");
636 #endif /* DEBUG */
637
638     upath = mtoupath(vol, path);
639     if ((of = of_findname(vol, curdir, path))) {
640         adp = of->of_ad;
641     } else {
642         memset(&ad, 0, sizeof(ad));
643         adp = &ad;
644     }
645
646 #ifdef FORCE_UIDGID
647     save_uidgid ( uidgid );
648     set_uidgid ( vol );
649 #endif /* FORCE_UIDGID */
650
651     if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
652                  O_RDWR|O_CREAT, 0666, adp) < 0) {
653         /* for some things, we don't need an adouble header */
654         if (bitmap & ~(1<<FILPBIT_MDATE)) {
655 #ifdef FORCE_UIDGID
656             restore_uidgid ( uidgid );
657 #endif /* FORCE_UIDGID */
658             return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
659         }
660         isad = 0;
661     } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
662         ad_setentrylen( adp, ADEID_NAME, strlen( path ));
663         memcpy(ad_entry( adp, ADEID_NAME ), path,
664                ad_getentrylen( adp, ADEID_NAME ));
665     }
666
667     while ( bitmap != 0 ) {
668         while (( bitmap & 1 ) == 0 ) {
669             bitmap = bitmap>>1;
670             bit++;
671         }
672
673         switch(  bit ) {
674         case FILPBIT_ATTR :
675             memcpy(&ashort, buf, sizeof( ashort ));
676             ad_getattr(adp, &bshort);
677             if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
678                 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
679             } else {
680                 bshort &= ~ashort;
681             }
682             ad_setattr(adp, bshort);
683             buf += sizeof( ashort );
684             break;
685
686         case FILPBIT_CDATE :
687             memcpy(&aint, buf, sizeof(aint));
688             ad_setdate(adp, AD_DATE_CREATE, aint);
689             buf += sizeof( aint );
690             break;
691
692         case FILPBIT_MDATE :
693             memcpy(&aint, buf, sizeof( aint ));
694             if (isad)
695                 ad_setdate(adp, AD_DATE_MODIFY, aint);
696             ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
697             utime(upath, &ut);
698             buf += sizeof( aint );
699             break;
700
701         case FILPBIT_BDATE :
702             memcpy(&aint, buf, sizeof(aint));
703             ad_setdate(adp, AD_DATE_BACKUP, aint);
704             buf += sizeof( aint );
705             break;
706
707         case FILPBIT_FINFO :
708             if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
709                     && (em = getextmap( path )) &&
710                     (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
711                     (memcmp(buf + 4, em->em_creator,
712                             sizeof( em->em_creator )) == 0)) {
713                 memcpy(buf, ufinderi, 8 );
714             }
715             memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
716             buf += 32;
717             break;
718
719             /* Client needs to set the ProDOS file info for this file.
720                Use defined strings for the simple cases, and convert
721                all else into pXYY per Inside Appletalk.  Always set
722                the creator as "pdos". <shirsch@ibm.net> */
723         case FILPBIT_PDINFO :
724             achar = *buf;
725             buf += 2;
726             memcpy(&ashort, buf, sizeof( ashort ));
727             ashort = ntohs( ashort );
728             buf += 2;
729
730             switch ( (unsigned int) achar )
731             {
732             case 0x04 :
733                 fdType = ( u_char *) "TEXT";
734                 break;
735
736             case 0xff :
737                 fdType = ( u_char *) "PSYS";
738                 break;
739
740             case 0xb3 :
741                 fdType = ( u_char *) "PS16";
742                 break;
743
744             case 0x00 :
745                 fdType = ( u_char *) "BINA";
746                 break;
747
748             default :
749                 xyy[0] = ( u_char ) 'p';
750                 xyy[1] = achar;
751                 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
752                 xyy[3] = ( u_char ) ashort & 0xff;
753                 fdType = xyy;
754                 break;
755             }
756
757             memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
758             memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
759             break;
760
761
762         default :
763             err = AFPERR_BITMAP;
764             goto setfilparam_done;
765         }
766
767         bitmap = bitmap>>1;
768         bit++;
769     }
770
771 setfilparam_done:
772     if (isad) {
773         ad_flush( adp, ADFLAGS_HF );
774         ad_close( adp, ADFLAGS_HF );
775
776 #ifdef FORCE_UIDGID
777         restore_uidgid ( uidgid );
778 #endif /* FORCE_UIDGID */
779
780     }
781
782 #ifdef DEBUG
783     LOG(log_info, logtype_afpd, "end setfilparams:");
784 #endif /* DEBUG */
785
786     return err;
787 }
788
789 /*
790  * renamefile and copyfile take the old and new unix pathnames
791  * and the new mac name.
792  * NOTE: if we have to copy a file instead of renaming it, locks
793  *       will break.
794  * FIXME: locks on ressource fork will always break thanks to ad_close, done ?
795  *
796  * src         the full source absolute path 
797  * dst         the dest filename in current dir
798  * newname     the dest mac name
799  * adp         adouble struct of src file, if open, or & zeroed one
800  *
801  */
802 int renamefile(src, dst, newname, noadouble, adp )
803 char    *src, *dst, *newname;
804 const int         noadouble;
805 struct adouble    *adp;
806 {
807     struct ofork        *opened;
808     char                adsrc[ MAXPATHLEN + 1];
809     int                 len, rc;
810
811     /*
812      * Note that this is only checking the existance of the data file,
813      * not the header file.  The thinking is that if the data file doesn't
814      * exist, but the header file does, the right thing to do is remove
815      * the data file silently.
816      */
817
818     /* existence check moved to afp_moveandrename */
819
820 #ifdef DEBUG
821     LOG(log_info, logtype_afpd, "begin renamefile:");
822 #endif /* DEBUG */
823
824     if ( rename( src, dst ) < 0 ) {
825         switch ( errno ) {
826         case ENOENT :
827             return( AFPERR_NOOBJ );
828         case EPERM:
829         case EACCES :
830             return( AFPERR_ACCESS );
831         case EROFS:
832             return AFPERR_VLOCK;
833         case EXDEV :                    /* Cross device move -- try copy */
834             if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
835                 deletefile( dst, 0 );
836                 return( rc );
837             }
838             return deletefile( src, 0);
839         default :
840             return( AFPERR_PARAM );
841         }
842     }
843
844     strcpy( adsrc, ad_path( src, 0 ));
845     rc = 0;
846 rename_retry:
847     if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
848         struct stat st;
849
850         switch ( errno ) {
851         case ENOENT :
852             /* check for a source appledouble header. if it exists, make
853              * a dest appledouble directory and do the rename again. */
854             if (rc || stat(adsrc, &st) ||
855                     (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
856                 return AFP_OK;
857             rc++;
858             ad_close(adp, ADFLAGS_HF);
859             goto rename_retry;
860         case EPERM:
861         case EACCES :
862             return( AFPERR_ACCESS );
863         case EROFS:
864             return AFPERR_VLOCK;
865         default :
866             return( AFPERR_PARAM );
867         }
868     }
869
870     if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
871         switch ( errno ) {
872         case ENOENT :
873             return( AFPERR_NOOBJ );
874         case EACCES :
875             return( AFPERR_ACCESS );
876         case EROFS:
877             return AFPERR_VLOCK;
878         default :
879             return( AFPERR_PARAM );
880         }
881     }
882
883     len = strlen( newname );
884     ad_setentrylen( adp, ADEID_NAME, len );
885     memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
886     ad_flush( adp, ADFLAGS_HF );
887     ad_close( adp, ADFLAGS_HF );
888
889 #ifdef DEBUG
890     LOG(log_info, logtype_afpd, "end renamefile:");
891 #endif /* DEBUG */
892
893     return( AFP_OK );
894 }
895
896 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
897 AFPObj      *obj;
898 char    *ibuf, *rbuf;
899 int             ibuflen, *rbuflen;
900 {
901     struct vol  *vol;
902     struct dir  *dir;
903     char        *newname, *path, *p;
904     u_int32_t   sdid, ddid;
905     int         plen, err, retvalue = AFP_OK;
906     u_int16_t   svid, dvid;
907
908 #ifdef DEBUG
909     LOG(log_info, logtype_afpd, "begin afp_copyfile:");
910 #endif /* DEBUG */
911
912     *rbuflen = 0;
913     ibuf += 2;
914
915     memcpy(&svid, ibuf, sizeof( svid ));
916     ibuf += sizeof( svid );
917     if (( vol = getvolbyvid( svid )) == NULL ) {
918         return( AFPERR_PARAM );
919     }
920
921     memcpy(&sdid, ibuf, sizeof( sdid ));
922     ibuf += sizeof( sdid );
923     if (( dir = dirsearch( vol, sdid )) == NULL ) {
924         return( AFPERR_PARAM );
925     }
926
927     memcpy(&dvid, ibuf, sizeof( dvid ));
928     ibuf += sizeof( dvid );
929     memcpy(&ddid, ibuf, sizeof( ddid ));
930     ibuf += sizeof( ddid );
931
932     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
933         return( AFPERR_NOOBJ );
934     }
935     if ( *path == '\0' ) {
936         return( AFPERR_BADTYPE );
937     }
938
939     /* don't allow copies when the file is open.
940      * XXX: the spec only calls for read/deny write access.
941      *      however, copyfile doesn't have any of that info,
942      *      and locks need to stay coherent. as a result,
943      *      we just balk if the file is opened already. */
944     if (of_findname(vol, curdir, path))
945         return AFPERR_DENYCONF;
946
947     newname = obj->newtmp;
948     strcpy( newname, path );
949
950     p = ctoupath( vol, curdir, newname );
951
952     if (( vol = getvolbyvid( dvid )) == NULL ) {
953         return( AFPERR_PARAM );
954     }
955
956     if (vol->v_flags & AFPVOL_RO)
957         return AFPERR_VLOCK;
958
959     if (( dir = dirsearch( vol, ddid )) == NULL ) {
960         return( AFPERR_PARAM );
961     }
962
963     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
964         return( AFPERR_NOOBJ );
965     }
966     if ( *path != '\0' ) {
967         return( AFPERR_BADTYPE );
968     }
969
970     /* one of the handful of places that knows about the path type */
971     if ( *ibuf++ != 2 ) {
972         return( AFPERR_PARAM );
973     }
974     if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
975         strncpy( newname, ibuf, plen );
976         newname[ plen ] = '\0';
977     }
978
979     if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
980                          vol_noadouble(vol))) < 0 ) {
981         return err;
982     }
983
984     setvoltime(obj, vol );
985
986 #ifdef DROPKLUDGE
987     if (vol->v_flags & AFPVOL_DROPBOX) {
988         retvalue=matchfile2dirperms(newname, vol, sdid);
989     }
990 #endif /* DROPKLUDGE */
991
992 #ifdef DEBUG
993     LOG(log_info, logtype_afpd, "end afp_copyfile:");
994 #endif /* DEBUG */
995
996     return( retvalue );
997 }
998
999
1000 static __inline__ int copy_all(const int dfd, const void *buf,
1001                                size_t buflen)
1002 {
1003     ssize_t cc;
1004
1005 #ifdef DEBUG
1006     LOG(log_info, logtype_afpd, "begin copy_all:");
1007 #endif /* DEBUG */
1008
1009     while (buflen > 0) {
1010         if ((cc = write(dfd, buf, buflen)) < 0) {
1011             switch (errno) {
1012             case EINTR:
1013                 continue;
1014             case EDQUOT:
1015             case EFBIG:
1016             case ENOSPC:
1017                 return AFPERR_DFULL;
1018             case EROFS:
1019                 return AFPERR_VLOCK;
1020             default:
1021                 return AFPERR_PARAM;
1022             }
1023         }
1024         buflen -= cc;
1025     }
1026
1027 #ifdef DEBUG
1028     LOG(log_info, logtype_afpd, "end copy_all:");
1029 #endif /* DEBUG */
1030
1031     return AFP_OK;
1032 }
1033
1034 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1035  * pass in vol and path */
1036 int copyfile(src, dst, newname, noadouble )
1037 char    *src, *dst, *newname;
1038 const int   noadouble;
1039 {
1040     struct adouble      ad;
1041     struct stat         st;
1042     char                filebuf[8192];
1043     int                 sfd, dfd, len, err = AFP_OK;
1044     ssize_t             cc;
1045
1046 #ifdef DEBUG
1047     LOG(log_info, logtype_afpd, "begin copyfile:");
1048 #endif /* DEBUG */
1049
1050     if (newname) {
1051         if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1052             switch ( errno ) {
1053             case ENOENT :
1054                 break; /* just copy the data fork */
1055             case EACCES :
1056                 return( AFPERR_ACCESS );
1057             default :
1058                 return( AFPERR_PARAM );
1059             }
1060         } else {
1061             if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
1062                               ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
1063                 close( sfd );
1064                 switch ( errno ) {
1065                 case ENOENT :
1066                     return( AFPERR_NOOBJ );
1067                 case EACCES :
1068                     return( AFPERR_ACCESS );
1069                 case EROFS:
1070                     return AFPERR_VLOCK;
1071                 default :
1072                     return( AFPERR_PARAM );
1073                 }
1074             }
1075
1076             /* copy the file */
1077 #ifdef SENDFILE_FLAVOR_LINUX
1078             if (fstat(sfd, &st) == 0) {
1079                 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1080                     switch (errno) {
1081                     case EDQUOT:
1082                     case EFBIG:
1083                     case ENOSPC:
1084                         err = AFPERR_DFULL;
1085                         break;
1086                     case EROFS:
1087                         err = AFPERR_VLOCK;
1088                         break;
1089                     default:
1090                         err = AFPERR_PARAM;
1091                     }
1092                 }
1093                 goto copyheader_done;
1094             }
1095 #endif /* SENDFILE_FLAVOR_LINUX */
1096             while (1) {
1097                 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1098                     if (errno == EINTR)
1099                         continue;
1100                     err = AFPERR_PARAM;
1101                     break;
1102                 }
1103
1104                 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1105                     break;
1106             }
1107
1108 copyheader_done:
1109             close(sfd);
1110             close(dfd);
1111             if (err < 0) {
1112                 unlink(ad_path(dst, ADFLAGS_HF));
1113                 return err;
1114             }
1115         }
1116     }
1117
1118     /* data fork copying */
1119     if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1120         switch ( errno ) {
1121         case ENOENT :
1122             return( AFPERR_NOOBJ );
1123         case EACCES :
1124             return( AFPERR_ACCESS );
1125         default :
1126             return( AFPERR_PARAM );
1127         }
1128     }
1129
1130     if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1131         close( sfd );
1132         switch ( errno ) {
1133         case ENOENT :
1134             return( AFPERR_NOOBJ );
1135         case EACCES :
1136             return( AFPERR_ACCESS );
1137         case EROFS:
1138             return AFPERR_VLOCK;
1139         default :
1140             return( AFPERR_PARAM );
1141         }
1142     }
1143
1144 #ifdef SENDFILE_FLAVOR_LINUX
1145     if (fstat(sfd, &st) == 0) {
1146         if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1147             switch (errno) {
1148             case EDQUOT:
1149             case EFBIG:
1150             case ENOSPC:
1151                 err = AFPERR_DFULL;
1152                 break;
1153             default:
1154                 err = AFPERR_PARAM;
1155             }
1156         }
1157         goto copydata_done;
1158     }
1159 #endif /* SENDFILE_FLAVOR_LINUX */
1160
1161     while (1) {
1162         if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1163             if (errno == EINTR)
1164                 continue;
1165
1166             err = AFPERR_PARAM;
1167             break;
1168         }
1169
1170         if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1171             break;
1172         }
1173     }
1174
1175 copydata_done:
1176     close(sfd);
1177     close(dfd);
1178     if (err < 0) {
1179         unlink(ad_path(dst, ADFLAGS_HF));
1180         unlink(dst);
1181         return err;
1182     }
1183
1184     if (newname) {
1185         memset(&ad, 0, sizeof(ad));
1186         if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1187                       0666, &ad) < 0 ) {
1188             switch ( errno ) {
1189             case ENOENT :
1190                 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1191             case EACCES :
1192                 return( AFPERR_ACCESS );
1193             case EROFS:
1194                 return AFPERR_VLOCK;
1195             default :
1196                 return( AFPERR_PARAM );
1197             }
1198         }
1199
1200         len = strlen( newname );
1201         ad_setentrylen( &ad, ADEID_NAME, len );
1202         memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1203         ad_flush( &ad, ADFLAGS_HF );
1204         ad_close( &ad, ADFLAGS_HF );
1205     }
1206
1207 #ifdef DEBUG
1208     LOG(log_info, logtype_afpd, "end copyfile:");
1209 #endif /* DEBUG */
1210
1211     return( AFP_OK );
1212 }
1213
1214
1215 /* -----------------------------------
1216    checkAttrib:   1 check kFPDeleteInhibitBit 
1217    ie deletfile called by afp_delete
1218
1219    when deletefile is called we don't have lock on it, file is closed (for us)
1220 */
1221 int deletefile( file, checkAttrib )
1222 char            *file;
1223 int         checkAttrib;
1224 {
1225     struct adouble      ad;
1226     int                 adflags, err = AFP_OK;
1227     int                 locktype = ADLOCK_WR;
1228     int                 openmode = O_RDWR;
1229
1230 #ifdef DEBUG
1231     LOG(log_info, logtype_afpd, "begin deletefile:");
1232 #endif /* DEBUG */
1233
1234     while(1) {
1235         /*
1236          * If can't open read/write then try again read-only.  If it's open
1237          * read-only, we must do a read lock instead of a write lock.
1238          */
1239         /* try to open both at once */
1240         adflags = ADFLAGS_DF|ADFLAGS_HF;
1241         memset(&ad, 0, sizeof(ad));
1242         if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1243             switch (errno) {
1244             case ENOENT:
1245                 adflags = ADFLAGS_DF;
1246                 /* that failed. now try to open just the data fork */
1247                 memset(&ad, 0, sizeof(ad));
1248                 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1249                     switch (errno) {
1250                     case ENOENT:
1251                         return AFPERR_NOOBJ;
1252                     case EACCES:
1253                         if(openmode == O_RDWR) {
1254                             openmode = O_RDONLY;
1255                             locktype = ADLOCK_RD;
1256                             continue;
1257                         } else {
1258                             return AFPERR_ACCESS;
1259                         }
1260                     case EROFS:
1261                         return AFPERR_VLOCK;
1262                     default:
1263                         return AFPERR_PARAM;
1264                     }
1265                 }
1266                 break;
1267
1268             case EACCES:
1269                 if(openmode == O_RDWR) {
1270                     openmode = O_RDONLY;
1271                     locktype = ADLOCK_RD;
1272                     continue;
1273                 } else {
1274                     return AFPERR_ACCESS;
1275                 }
1276             case EROFS:
1277                 return AFPERR_VLOCK;
1278             default:
1279                 return( AFPERR_PARAM );
1280             }
1281         }
1282         break;  /* from the while */
1283     }
1284     /*
1285      * Does kFPDeleteInhibitBit (bit 8) set?
1286      */
1287     if (checkAttrib && (adflags & ADFLAGS_HF)) {
1288         u_int16_t   bshort;
1289
1290         ad_getattr(&ad, &bshort);
1291         if ((bshort & htons(ATTRBIT_NODELETE))) {
1292             ad_close( &ad, adflags );
1293             return(AFPERR_OLOCK);
1294         }
1295     }
1296     
1297     if ((adflags & ADFLAGS_HF) ) {
1298         /* FIXME we have a pb here because we want to know if a file is open 
1299          * there's a 'priority inversion' if you can't open the ressource fork RW
1300          * you can delete it if it's open because you can't get a write lock.
1301          * 
1302          * ADLOCK_FILELOCK means the whole ressource fork, not only after the 
1303          * metadatas
1304          *
1305          * FIXME it doesn't for RFORK open read only and fork open without deny mode
1306          */
1307         if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) {
1308             ad_close( &ad, adflags );
1309             return( AFPERR_BUSY );
1310         }
1311     }
1312
1313     if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1314         err = AFPERR_BUSY;
1315         goto delete_unlock;
1316     }
1317
1318     if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1319         switch ( errno ) {
1320         case EPERM:
1321         case EACCES :
1322             err = AFPERR_ACCESS;
1323             goto delete_unlock;
1324         case EROFS:
1325             err = AFPERR_VLOCK;
1326             goto delete_unlock;
1327         case ENOENT :
1328             break;
1329         default :
1330             err = AFPERR_PARAM;
1331             goto delete_unlock;
1332         }
1333     }
1334
1335     if ( unlink( file ) < 0 ) {
1336         switch ( errno ) {
1337         case EPERM:
1338         case EACCES :
1339             err = AFPERR_ACCESS;
1340             break;
1341         case EROFS:
1342             err = AFPERR_VLOCK;
1343             break;
1344         case ENOENT :
1345             break;
1346         default :
1347             err = AFPERR_PARAM;
1348             break;
1349         }
1350     }
1351
1352 delete_unlock:
1353     if (adflags & ADFLAGS_HF)
1354         ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0);
1355     ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1356     ad_close( &ad, adflags );
1357
1358 #ifdef DEBUG
1359     LOG(log_info, logtype_afpd, "end deletefile:");
1360 #endif /* DEBUG */
1361
1362     return err;
1363 }
1364
1365
1366 #ifdef CNID_DB
1367 /* return a file id */
1368 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1369 AFPObj      *obj;
1370 char    *ibuf, *rbuf;
1371 int             ibuflen, *rbuflen;
1372 {
1373     struct stat         st;
1374     struct adouble      ad;
1375     struct vol          *vol;
1376     struct dir          *dir;
1377     char                *path, *upath;
1378     int                 len;
1379     cnid_t              did, id;
1380     u_short             vid;
1381
1382 #ifdef DEBUG
1383     LOG(log_info, logtype_afpd, "begin afp_createid:");
1384 #endif /* DEBUG */
1385
1386     *rbuflen = 0;
1387     ibuf += 2;
1388
1389     memcpy(&vid, ibuf, sizeof(vid));
1390     ibuf += sizeof(vid);
1391
1392     if (( vol = getvolbyvid( vid )) == NULL ) {
1393         return( AFPERR_PARAM);
1394     }
1395
1396     if (vol->v_flags & AFPVOL_RO)
1397         return AFPERR_VLOCK;
1398
1399     memcpy(&did, ibuf, sizeof( did ));
1400     ibuf += sizeof(did);
1401
1402     if (( dir = dirsearch( vol, did )) == NULL ) {
1403         return( AFPERR_PARAM );
1404     }
1405
1406     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1407         return( AFPERR_PARAM );
1408     }
1409
1410     if ( *path == '\0' ) {
1411         return( AFPERR_BADTYPE );
1412     }
1413
1414     upath = mtoupath(vol, path);
1415     if (stat(upath, &st) < 0) {
1416         switch (errno) {
1417         case EPERM:
1418         case EACCES:
1419             return AFPERR_ACCESS;
1420         case ENOENT:
1421             return AFPERR_NOOBJ;
1422         default:
1423             return AFPERR_PARAM;
1424         }
1425     }
1426
1427     if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1428         memcpy(rbuf, &id, sizeof(id));
1429         *rbuflen = sizeof(id);
1430         return AFPERR_EXISTID;
1431     }
1432
1433 #if AD_VERSION > AD_VERSION1
1434     memset(&ad, 0, sizeof(ad));
1435     if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1436         memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1437         ad_close(&ad, ADFLAGS_HF);
1438     }
1439 #endif /* AD_VERSION > AD_VERSION1 */
1440
1441     if (id = cnid_add(vol->v_db, &st, did, upath, len, id) != CNID_INVALID) {
1442         memcpy(rbuf, &id, sizeof(id));
1443         *rbuflen = sizeof(id);
1444         return AFP_OK;
1445     }
1446
1447 #ifdef DEBUG
1448     LOG(log_info, logtype_afpd, "ending afp_createid...:");
1449 #endif /* DEBUG */
1450
1451     switch (errno) {
1452     case EROFS:
1453         return AFPERR_VLOCK;
1454         break;
1455     case EPERM:
1456     case EACCES:
1457         return AFPERR_ACCESS;
1458         break;
1459     default:
1460         LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1461         return AFPERR_PARAM;
1462     }
1463 }
1464
1465 /* resolve a file id */
1466 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1467 AFPObj      *obj;
1468 char    *ibuf, *rbuf;
1469 int             ibuflen, *rbuflen;
1470 {
1471     struct stat         st;
1472     struct vol          *vol;
1473     struct dir          *dir;
1474     char                *upath;
1475     int                 err, buflen;
1476     cnid_t              id;
1477     u_int16_t           vid, bitmap;
1478
1479     static char buffer[12 + MAXPATHLEN + 1];
1480     int len = 12 + MAXPATHLEN + 1;
1481
1482 #ifdef DEBUG
1483     LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1484 #endif /* DEBUG */
1485
1486     *rbuflen = 0;
1487     ibuf += 2;
1488
1489     memcpy(&vid, ibuf, sizeof(vid));
1490     ibuf += sizeof(vid);
1491
1492     if (( vol = getvolbyvid( vid )) == NULL ) {
1493         return( AFPERR_PARAM);
1494     }
1495
1496     memcpy(&id, ibuf, sizeof( id ));
1497     ibuf += sizeof(id);
1498
1499     if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1500         return AFPERR_BADID;
1501     }
1502
1503     if (( dir = dirlookup( vol, id )) == NULL ) {
1504         return( AFPERR_PARAM );
1505     }
1506
1507     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1508         switch (errno) {
1509         case EACCES:
1510         case EPERM:
1511             return AFPERR_ACCESS;
1512         case ENOENT:
1513             return AFPERR_NOID;
1514         default:
1515             return AFPERR_PARAM;
1516         }
1517     }
1518
1519     /* directories are bad */
1520     if (S_ISDIR(st.st_mode))
1521         return AFPERR_BADTYPE;
1522
1523     memcpy(&bitmap, ibuf, sizeof(bitmap));
1524     bitmap = ntohs( bitmap );
1525
1526     if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1527                             rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1528         return err;
1529
1530     *rbuflen = buflen + sizeof(bitmap);
1531     memcpy(rbuf, ibuf, sizeof(bitmap));
1532
1533 #ifdef DEBUG
1534     LOG(log_info, logtype_afpd, "end afp_resolveid:");
1535 #endif /* DEBUG */
1536
1537     return AFP_OK;
1538 }
1539
1540 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1541 AFPObj      *obj;
1542 char    *ibuf, *rbuf;
1543 int             ibuflen, *rbuflen;
1544 {
1545     struct stat         st;
1546     struct vol          *vol;
1547     struct dir          *dir;
1548     char                *upath;
1549     int                 err;
1550     cnid_t              id;
1551     cnid_t              fileid;
1552     u_short             vid;
1553     static char buffer[12 + MAXPATHLEN + 1];
1554     int len = 12 + MAXPATHLEN + 1;
1555
1556 #ifdef DEBUG
1557     LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1558 #endif /* DEBUG */
1559
1560     *rbuflen = 0;
1561     ibuf += 2;
1562
1563     memcpy(&vid, ibuf, sizeof(vid));
1564     ibuf += sizeof(vid);
1565
1566     if (( vol = getvolbyvid( vid )) == NULL ) {
1567         return( AFPERR_PARAM);
1568     }
1569
1570     if (vol->v_flags & AFPVOL_RO)
1571         return AFPERR_VLOCK;
1572
1573     memcpy(&id, ibuf, sizeof( id ));
1574     ibuf += sizeof(id);
1575     fileid = id;
1576
1577     if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1578         return AFPERR_NOID;
1579     }
1580
1581     if (( dir = dirlookup( vol, id )) == NULL ) {
1582         return( AFPERR_PARAM );
1583     }
1584
1585     err = AFP_OK;
1586     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1587         switch (errno) {
1588         case EACCES:
1589         case EPERM:
1590             return AFPERR_ACCESS;
1591         case ENOENT:
1592             /* still try to delete the id */
1593             err = AFPERR_NOOBJ;
1594             break;
1595         default:
1596             return AFPERR_PARAM;
1597         }
1598     }
1599
1600     /* directories are bad */
1601     if (S_ISDIR(st.st_mode))
1602         return AFPERR_BADTYPE;
1603
1604     if (cnid_delete(vol->v_db, fileid)) {
1605         switch (errno) {
1606         case EROFS:
1607             return AFPERR_VLOCK;
1608         case EPERM:
1609         case EACCES:
1610             return AFPERR_ACCESS;
1611         default:
1612             return AFPERR_PARAM;
1613         }
1614     }
1615
1616 #ifdef DEBUG
1617     LOG(log_info, logtype_afpd, "end afp_deleteid:");
1618 #endif /* DEBUG */
1619
1620     return err;
1621 }
1622 #endif /* CNID_DB */
1623
1624 #define APPLETEMP ".AppleTempXXXXXX"
1625
1626 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1627 AFPObj      *obj;
1628 char    *ibuf, *rbuf;
1629 int             ibuflen, *rbuflen;
1630 {
1631     struct stat         srcst, destst;
1632     struct vol          *vol;
1633     struct dir          *dir, *sdir;
1634     char                *spath, temp[17], *path, *p;
1635     char                *supath, *upath;
1636     int                 err;
1637     struct adouble      ads;
1638     struct adouble      add;
1639     struct adouble      *adsp;
1640     struct adouble      *addp;
1641     struct ofork        *opened;
1642     
1643 #ifdef CNID_DB
1644     int                 slen, dlen;
1645 #endif /* CNID_DB */
1646     u_int32_t           sid, did;
1647     u_int16_t           vid;
1648
1649 #ifdef DEBUG
1650     LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1651 #endif /* DEBUG */
1652
1653     *rbuflen = 0;
1654     ibuf += 2;
1655
1656     memcpy(&vid, ibuf, sizeof(vid));
1657     ibuf += sizeof(vid);
1658
1659     if (( vol = getvolbyvid( vid )) == NULL ) {
1660         return( AFPERR_PARAM);
1661     }
1662
1663     if (vol->v_flags & AFPVOL_RO)
1664         return AFPERR_VLOCK;
1665
1666     /* source and destination dids */
1667     memcpy(&sid, ibuf, sizeof(sid));
1668     ibuf += sizeof(sid);
1669     memcpy(&did, ibuf, sizeof(did));
1670     ibuf += sizeof(did);
1671
1672     /* source file */
1673     if ((dir = dirsearch( vol, sid )) == NULL ) {
1674         return( AFPERR_PARAM );
1675     }
1676
1677     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1678         return( AFPERR_PARAM );
1679     }
1680
1681     if ( *path == '\0' ) {
1682         return( AFPERR_BADTYPE );   /* it's a dir */
1683     }
1684
1685     upath = mtoupath(vol, path);
1686     if (stat(upath, &srcst) < 0) {
1687         switch (errno) {
1688         case ENOENT:
1689             return AFPERR_NOID;
1690         case EPERM:
1691         case EACCES:
1692             return AFPERR_ACCESS;
1693         default:
1694             return AFPERR_PARAM;
1695         }
1696     }
1697     memset(&ads, 0, sizeof(ads));
1698     adsp = &ads;
1699     if ((opened = of_findname(vol, curdir, path))) {
1700             /* reuse struct adouble so it won't break locks */
1701             adsp = opened->of_ad;
1702     }
1703     /* save some stuff */
1704     sdir = curdir;
1705     spath = obj->oldtmp;
1706     supath = obj->newtmp;
1707     strcpy(spath, path);
1708     strcpy(supath, upath); /* this is for the cnid changing */
1709     p = ctoupath( vol, sdir, spath);
1710
1711     /* look for the source cnid. if it doesn't exist, don't worry about
1712      * it. */
1713 #ifdef CNID_DB
1714     sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1715                       slen = strlen(supath));
1716 #endif /* CNID_DB */
1717
1718     if (( dir = dirsearch( vol, did )) == NULL ) {
1719         return( AFPERR_PARAM );
1720     }
1721
1722     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1723         return( AFPERR_PARAM );
1724     }
1725
1726     if ( *path == '\0' ) {
1727         return( AFPERR_BADTYPE );
1728     }
1729
1730     /* FPExchangeFiles is the only call that can return the SameObj
1731      * error */
1732     if ((curdir == sdir) && strcmp(spath, path) == 0)
1733         return AFPERR_SAMEOBJ;
1734
1735     upath = mtoupath(vol, path);
1736     if (stat(upath, &destst) < 0) {
1737         switch (errno) {
1738         case ENOENT:
1739             return AFPERR_NOID;
1740         case EPERM:
1741         case EACCES:
1742             return AFPERR_ACCESS;
1743         default:
1744             return AFPERR_PARAM;
1745         }
1746     }
1747     memset(&add, 0, sizeof(add));
1748     addp = &add;
1749     if ((opened = of_findname(vol, curdir, path))) {
1750             /* reuse struct adouble so it won't break locks */
1751             addp = opened->of_ad;
1752     }
1753 #ifdef CNID_DB
1754     /* look for destination id. */
1755     did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1756                       dlen = strlen(upath));
1757 #endif /* CNID_DB */
1758
1759     /* construct a temp name.
1760      * NOTE: the temp file will be in the dest file's directory. it
1761      * will also be inaccessible from AFP. */
1762     memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1763     if (!mktemp(temp))
1764         return AFPERR_MISC;
1765
1766     /* now, quickly rename the file. we error if we can't. */
1767     if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1768         goto err_exchangefile;
1769     of_rename(vol, sdir, spath, curdir, temp);
1770
1771     /* rename destination to source */
1772     if ((err = renamefile(path, p, spath, vol_noadouble(vol), addp)) < 0)
1773         goto err_src_to_tmp;
1774     of_rename(vol, curdir, path, sdir, spath);
1775
1776     /* rename temp to destination */
1777     if ((err = renamefile(temp, upath, path, vol_noadouble(vol), adsp)) < 0)
1778         goto err_dest_to_src;
1779     of_rename(vol, curdir, temp, curdir, path);
1780
1781 #ifdef CNID_DB
1782     /* id's need switching. src -> dest and dest -> src. */
1783     if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1784                             upath, dlen) < 0)) {
1785         switch (errno) {
1786         case EPERM:
1787         case EACCES:
1788             err = AFPERR_ACCESS;
1789             break;
1790         default:
1791             err = AFPERR_PARAM;
1792         }
1793         goto err_temp_to_dest;
1794     }
1795
1796     if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1797                             supath, slen) < 0)) {
1798         switch (errno) {
1799         case EPERM:
1800         case EACCES:
1801             err = AFPERR_ACCESS;
1802             break;
1803         default:
1804             err = AFPERR_PARAM;
1805         }
1806
1807         if (sid)
1808             cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1809         goto err_temp_to_dest;
1810     }
1811 #endif /* CNID_DB */
1812
1813 #ifdef DEBUG
1814     LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1815 #endif /* DEBUG */
1816
1817     return AFP_OK;
1818
1819
1820     /* all this stuff is so that we can unwind a failed operation
1821      * properly. */
1822 err_temp_to_dest:
1823     /* rename dest to temp */
1824     renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1825     of_rename(vol, curdir, upath, curdir, temp);
1826
1827 err_dest_to_src:
1828     /* rename source back to dest */
1829     renamefile(p, upath, path, vol_noadouble(vol), addp);
1830     of_rename(vol, sdir, spath, curdir, path);
1831
1832 err_src_to_tmp:
1833     /* rename temp back to source */
1834     renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1835     of_rename(vol, curdir, temp, sdir, spath);
1836
1837 err_exchangefile:
1838     return err;
1839 }