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