]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/file.c
bugfix: renamefile's first parameter is the unix name not the mac one. from
[netatalk.git] / etc / afpd / file.c
1 /*
2  * $Id: file.c,v 1.51 2002-08-28 15:08:16 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                    aint = AD_DATE_FROM_UNIX(st->st_mtime);
157                 }
158             } else {
159                 aint = AD_DATE_FROM_UNIX(st->st_mtime);
160             }
161             memcpy(data, &aint, sizeof( int ));
162             data += sizeof( int );
163             break;
164
165         case FILPBIT_BDATE :
166             if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
167                 aint = AD_DATE_START;
168             memcpy(data, &aint, sizeof( int ));
169             data += sizeof( int );
170             break;
171
172         case FILPBIT_FINFO :
173             if (adp)
174                 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
175             else {
176                 memcpy(data, ufinderi, 32);
177                 if (*upath == '.') { /* make it invisible */
178                     ashort = htons(FINDERINFO_INVISIBLE);
179                     memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
180                 }
181             }
182
183             if ((!adp  || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 )) 
184                 && (em = getextmap( path ))
185             ) {
186                 memcpy(data, em->em_type, sizeof( em->em_type ));
187                 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
188             }
189             data += 32;
190             break;
191
192         case FILPBIT_LNAME :
193             nameoff = data;
194             data += sizeof( u_int16_t );
195             break;
196
197         case FILPBIT_SNAME :
198             memset(data, 0, sizeof(u_int16_t));
199             data += sizeof( u_int16_t );
200             break;
201
202         case FILPBIT_FNUM :
203             aint = 0;
204 #if AD_VERSION > AD_VERSION1
205             /* look in AD v2 header */
206             if (adp)
207                 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
208 #endif /* AD_VERSION > AD_VERSION1 */
209
210 #ifdef CNID_DB
211             aint = cnid_add(vol->v_db, st, dir->d_did, upath,
212                             strlen(upath), aint);
213             /* Throw errors if cnid_add fails. */
214             if (aint == CNID_INVALID) {
215                 switch (errno) {
216                 case CNID_ERR_PARAM:
217                     LOG(log_error, logtype_afpd, "getfilparams: Incorrect parameters passed to cnid_add");
218                     return(AFPERR_PARAM);
219                 case CNID_ERR_PATH:
220                     return(AFPERR_PARAM);
221                 case CNID_ERR_DB:
222                 case CNID_ERR_MAX:
223                     return(AFPERR_MISC);
224                 }
225             }
226 #endif /* CNID_DB */
227
228             if (aint == 0) {
229                 /*
230                  * What a fucking mess.  First thing:  DID and FNUMs are
231                  * in the same space for purposes of enumerate (and several
232                  * other wierd places).  While we consider this Apple's bug,
233                  * this is the work-around:  In order to maintain constant and
234                  * unique DIDs and FNUMs, we monotonically generate the DIDs
235                  * during the session, and derive the FNUMs from the filesystem.
236                  * Since the DIDs are small, we insure that the FNUMs are fairly
237                  * large by setting thier high bits to the device number.
238                  *
239                  * AFS already does something very similar to this for the
240                  * inode number, so we don't repeat the procedure.
241                  *
242                  * new algorithm:
243                  * due to complaints over did's being non-persistent,
244                  * here's the current hack to provide semi-persistent
245                  * did's:
246                  *      1) we reserve the first bit for file ids.
247                  *      2) the next 7 bits are for the device.
248                  *      3) the remaining 24 bits are for the inode.
249                  *
250                  * both the inode and device information are actually hashes
251                  * that are then truncated to the requisite bit length.
252                  *
253                  * it should be okay to use lstat to deal with symlinks.
254                  */
255 #ifdef USE_LASTDID
256                 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
257 #else /* USE_LASTDID */
258                 lstp = lstat(upath, &lst) < 0 ? st : &lst;
259 #ifdef DID_MTAB
260                 aint = htonl( afpd_st_cnid ( lstp ) );
261 #else /* DID_MTAB */
262                 aint = htonl(CNID(lstp, 1));
263 #endif /* DID_MTAB */
264 #endif /* USE_LASTDID */
265             }
266
267             memcpy(data, &aint, sizeof( aint ));
268             data += sizeof( aint );
269             break;
270
271         case FILPBIT_DFLEN :
272             aint = htonl( st->st_size );
273             memcpy(data, &aint, sizeof( aint ));
274             data += sizeof( aint );
275             break;
276
277         case FILPBIT_RFLEN :
278             if ( adp ) {
279                 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
280             } else {
281                 aint = 0;
282             }
283             memcpy(data, &aint, sizeof( aint ));
284             data += sizeof( aint );
285             break;
286
287             /* Current client needs ProDOS info block for this file.
288                Use simple heuristic and let the Mac "type" string tell
289                us what the PD file code should be.  Everything gets a
290                subtype of 0x0000 unless the original value was hashed
291                to "pXYZ" when we created it.  See IA, Ver 2.
292                <shirsch@ibm.net> */
293         case FILPBIT_PDINFO :
294             if ( adp ) {
295                 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
296
297                 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
298                     achar = '\x04';
299                     ashort = 0x0000;
300                 }
301                 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
302                     achar = '\xff';
303                     ashort = 0x0000;
304                 }
305                 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
306                     achar = '\xb3';
307                     ashort = 0x0000;
308                 }
309                 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
310                     achar = '\x00';
311                     ashort = 0x0000;
312                 }
313                 else if ( fdType[0] == 'p' ) {
314                     achar = fdType[1];
315                     ashort = (fdType[2] * 256) + fdType[3];
316                 }
317                 else {
318                     achar = '\x00';
319                     ashort = 0x0000;
320                 }
321             }
322             else {
323                 achar = '\x00';
324                 ashort = 0x0000;
325             }
326
327             *data++ = achar;
328             *data++ = 0;
329             memcpy(data, &ashort, sizeof( ashort ));
330             data += sizeof( ashort );
331             memset(data, 0, sizeof( ashort ));
332             data += sizeof( ashort );
333             break;
334
335         default :
336             return( AFPERR_BITMAP );
337         }
338         bitmap = bitmap>>1;
339         bit++;
340     }
341     if ( nameoff ) {
342         ashort = htons( data - buf );
343         memcpy(nameoff, &ashort, sizeof( ashort ));
344         if ((aint = strlen( path )) > MACFILELEN)
345             aint = MACFILELEN;
346         *data++ = aint;
347         memcpy(data, path, aint );
348         data += aint;
349     }
350     *buflen = data - buf;
351     return (AFP_OK);
352 }
353                 
354 /* ----------------------- */
355 int getfilparams(struct vol *vol,
356                  u_int16_t bitmap,
357                  char *path, struct dir *dir, struct stat *st,
358                  char *buf, int *buflen )
359 {
360     struct adouble      ad, *adp;
361     struct ofork        *of;
362     char                    *upath;
363     u_int16_t           attrbits = 0;
364     int rc;    
365 #ifdef DEBUG
366     LOG(log_info, logtype_default, "begin getfilparams:");
367 #endif /* DEBUG */
368
369     upath = mtoupath(vol, path);
370     if ((of = of_findname(vol, dir, path))) {
371         adp = of->of_ad;
372         attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
373         attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
374
375     } else {
376         memset(&ad, 0, sizeof(ad));
377         adp = &ad;
378     }
379
380     if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
381         adp = NULL;
382     }
383     else {
384 #if 0
385         /* FIXME 
386            we need to check if the file is open by another process.
387            it's slow so we only do it if we have to:
388            - bitmap is requested.
389            - we don't already have the answer!
390         */
391         if ((bitmap & (1 << FILPBIT_ATTR))) {
392                 if (!(attrbits & ATTRBIT_ROPEN)) {
393                 }
394                 if (!(attrbits & ATTRBIT_DOPEN)) {
395                 }
396         }
397 #endif          
398     }
399     rc = getmetadata(vol, bitmap, path, dir, st, buf, buflen, adp, attrbits);
400     if ( adp ) {
401         ad_close( adp, ADFLAGS_HF );
402     }
403 #ifdef DEBUG
404     LOG(log_info, logtype_afpd, "end getfilparams:");
405 #endif /* DEBUG */
406
407     return( rc );
408 }
409
410 /* ----------------------------- */
411 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
412 AFPObj      *obj;
413 char    *ibuf, *rbuf;
414 int             ibuflen, *rbuflen;
415 {
416     struct stat         st;
417     struct adouble      ad, *adp;
418     struct vol          *vol;
419     struct dir          *dir;
420     struct ofork        *of;
421     char                *path, *upath;
422     int                 creatf, did, openf, retvalue = AFP_OK;
423     u_int16_t           vid;
424 #ifdef FORCE_UIDGID
425     uidgidset           *uidgid;
426 #endif /* FORCE_UIDGID */
427
428 #ifdef DEBUG
429     LOG(log_info, logtype_afpd, "begin afp_createfile:");
430 #endif /* DEBUG */
431
432     *rbuflen = 0;
433     ibuf++;
434     creatf = (unsigned char) *ibuf++;
435
436     memcpy(&vid, ibuf, sizeof( vid ));
437     ibuf += sizeof( vid );
438
439     if (( vol = getvolbyvid( vid )) == NULL ) {
440         return( AFPERR_PARAM );
441     }
442
443     if (vol->v_flags & AFPVOL_RO)
444         return AFPERR_VLOCK;
445
446     memcpy(&did, ibuf, sizeof( did));
447     ibuf += sizeof( did );
448
449     if (( dir = dirsearch( vol, did )) == NULL ) {
450         return( AFPERR_NOOBJ );
451     }
452
453     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
454         return( AFPERR_NOOBJ );
455     }
456
457     upath = mtoupath(vol, path);
458     {
459     int ret;
460         if (0 != (ret = check_name(vol, upath))) 
461             return  ret;
462     }
463
464     if ((of = of_findname(vol, curdir, path))) {
465         adp = of->of_ad;
466     } else {
467         memset(&ad, 0, sizeof(ad));
468         adp = &ad;
469     }
470     if ( creatf) {
471         /* on a hard create, fail if file exists and is open */
472         if ((stat(upath, &st) == 0) && of)
473             return AFPERR_BUSY;
474         openf = O_RDWR|O_CREAT|O_TRUNC;
475     } else {
476         /* on a soft create, if the file is open then ad_open won't failed 
477            because open syscall is not called
478         */
479         if (of) {
480                 return AFPERR_EXIST;
481         }
482         openf = O_RDWR|O_CREAT|O_EXCL;
483     }
484
485 #ifdef FORCE_UIDGID
486
487     /* preserve current euid, egid */
488     save_uidgid ( uidgid );
489
490     /* perform all switching of users */
491     set_uidgid ( vol );
492
493 #endif /* FORCE_UIDGID */
494
495     if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
496                   openf, 0666, adp) < 0 ) {
497         switch ( errno ) {
498         case EEXIST :
499 #ifdef FORCE_UIDGID
500             /* bring everything back to old euid, egid */
501             restore_uidgid ( uidgid );
502 #endif /* FORCE_UIDGID */
503             return( AFPERR_EXIST );
504         case EACCES :
505 #ifdef FORCE_UIDGID
506             /* bring everything back to old euid, egid */
507             restore_uidgid ( uidgid );
508 #endif /* FORCE_UIDGID */
509             return( AFPERR_ACCESS );
510         case ENOENT:
511             /* on noadouble volumes, just creating the data fork is ok */
512             if (vol_noadouble(vol) && (stat(upath, &st) == 0))
513                 goto createfile_done;
514             /* fallthrough */
515         default :
516 #ifdef FORCE_UIDGID
517             /* bring everything back to old euid, egid */
518             restore_uidgid ( uidgid );
519 #endif /* FORCE_UIDGID */
520             return( AFPERR_PARAM );
521         }
522     }
523
524     ad_setentrylen( adp, ADEID_NAME, strlen( path ));
525     memcpy(ad_entry( adp, ADEID_NAME ), path,
526            ad_getentrylen( adp, ADEID_NAME ));
527     ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
528     ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
529
530 createfile_done:
531
532 #ifdef DROPKLUDGE
533     if (vol->v_flags & AFPVOL_DROPBOX) {
534         retvalue = matchfile2dirperms(upath, vol, did);
535     }
536 #endif /* DROPKLUDGE */
537
538     setvoltime(obj, vol );
539
540 #ifdef DEBUG
541     LOG(log_info, logtype_afpd, "end afp_createfile");
542 #endif /* DEBUG */
543
544 #ifdef FORCE_UIDGID
545     /* bring everything back to old euid, egid */
546     restore_uidgid ( uidgid );
547 #endif /* FORCE_UIDGID */
548
549     return (retvalue);
550 }
551
552 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
553 AFPObj      *obj;
554 char    *ibuf, *rbuf;
555 int             ibuflen, *rbuflen;
556 {
557     struct vol  *vol;
558     struct dir  *dir;
559     char        *path;
560     int         did, rc;
561     u_int16_t   vid, bitmap;
562
563 #ifdef DEBUG
564     LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
565 #endif /* DEBUG */
566
567     *rbuflen = 0;
568     ibuf += 2;
569
570     memcpy(&vid, ibuf, sizeof( vid ));
571     ibuf += sizeof( vid );
572     if (( vol = getvolbyvid( vid )) == NULL ) {
573         return( AFPERR_PARAM );
574     }
575
576     if (vol->v_flags & AFPVOL_RO)
577         return AFPERR_VLOCK;
578
579     memcpy(&did, ibuf, sizeof( did ));
580     ibuf += sizeof( did );
581     if (( dir = dirsearch( vol, did )) == NULL ) {
582         return( AFPERR_NOOBJ );
583     }
584
585     memcpy(&bitmap, ibuf, sizeof( bitmap ));
586     bitmap = ntohs( bitmap );
587     ibuf += sizeof( bitmap );
588
589     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
590         return( AFPERR_NOOBJ );
591     }
592
593     if ( *path == '\0' ) {
594         return( AFPERR_BADTYPE ); /* it's a directory */
595     }
596
597     if ((u_long)ibuf & 1 ) {
598         ibuf++;
599     }
600
601     if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
602         setvoltime(obj, vol );
603     }
604
605 #ifdef DEBUG
606     LOG(log_info, logtype_afpd, "end afp_setfilparams:");
607 #endif /* DEBUG */
608
609     return( rc );
610 }
611
612 /*
613  * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic  
614  *
615 */
616
617 int setfilparams(struct vol *vol,
618                  char *path, u_int16_t bitmap, char *buf )
619 {
620     struct adouble      ad, *adp;
621     struct ofork        *of;
622     struct extmap       *em;
623     int                 bit = 0, isad = 1, err = AFP_OK;
624     char                *upath;
625     u_char              achar, *fdType, xyy[4];
626     u_int16_t           ashort, bshort;
627     u_int32_t           aint;
628     struct utimbuf      ut;
629
630     int                 change_mdate = 0;
631     int                 change_parent_mdate = 0;
632     int                 newdate = 0;
633     struct timeval      tv;
634
635 #ifdef FORCE_UIDGID
636     uidgidset           *uidgid;
637
638     uidgid = malloc(sizeof(uidgidset));
639 #endif /* FORCE_UIDGID */
640
641 #ifdef DEBUG
642     LOG(log_info, logtype_afpd, "begin setfilparams:");
643 #endif /* DEBUG */
644
645     upath = mtoupath(vol, path);
646     if ((of = of_findname(vol, curdir, path))) {
647         adp = of->of_ad;
648     } else {
649         memset(&ad, 0, sizeof(ad));
650         adp = &ad;
651     }
652
653 #ifdef FORCE_UIDGID
654     save_uidgid ( uidgid );
655     set_uidgid ( vol );
656 #endif /* FORCE_UIDGID */
657
658     if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
659                  O_RDWR|O_CREAT, 0666, adp) < 0) {
660         /* for some things, we don't need an adouble header */
661         if (bitmap & ~(1<<FILPBIT_MDATE)) {
662 #ifdef FORCE_UIDGID
663             restore_uidgid ( uidgid );
664 #endif /* FORCE_UIDGID */
665             return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
666         }
667         isad = 0;
668     } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
669         ad_setentrylen( adp, ADEID_NAME, strlen( path ));
670         memcpy(ad_entry( adp, ADEID_NAME ), path,
671                ad_getentrylen( adp, ADEID_NAME ));
672     }
673
674     while ( bitmap != 0 ) {
675         while (( bitmap & 1 ) == 0 ) {
676             bitmap = bitmap>>1;
677             bit++;
678         }
679
680         switch(  bit ) {
681         case FILPBIT_ATTR :
682             change_mdate = 1;
683             memcpy(&ashort, buf, sizeof( ashort ));
684             ad_getattr(adp, &bshort);
685             if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
686                 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
687             } else {
688                 bshort &= ~ashort;
689             }
690             if ((ashort & htons(ATTRBIT_INVISIBLE)))
691                 change_parent_mdate = 1;
692             ad_setattr(adp, bshort);
693             buf += sizeof( ashort );
694             break;
695
696         case FILPBIT_CDATE :
697             change_mdate = 1;
698             memcpy(&aint, buf, sizeof(aint));
699             ad_setdate(adp, AD_DATE_CREATE, aint);
700             buf += sizeof( aint );
701             break;
702
703         case FILPBIT_MDATE :
704             memcpy(&newdate, buf, sizeof( newdate ));
705             buf += sizeof( newdate );
706             break;
707
708         case FILPBIT_BDATE :
709             change_mdate = 1;
710             memcpy(&aint, buf, sizeof(aint));
711             ad_setdate(adp, AD_DATE_BACKUP, aint);
712             buf += sizeof( aint );
713             break;
714
715         case FILPBIT_FINFO :
716             change_mdate = 1;
717
718             if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
719                     && ( 
720                      ((em = getextmap( path )) &&
721                       !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
722                       !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
723                      || ((em = getdefextmap()) &&
724                       !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
725                       !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
726             )) {
727                 memcpy(buf, ufinderi, 8 );
728             }
729
730             memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
731             buf += 32;
732             break;
733
734             /* Client needs to set the ProDOS file info for this file.
735                Use defined strings for the simple cases, and convert
736                all else into pXYY per Inside Appletalk.  Always set
737                the creator as "pdos". <shirsch@ibm.net> */
738         case FILPBIT_PDINFO :
739             achar = *buf;
740             buf += 2;
741             memcpy(&ashort, buf, sizeof( ashort ));
742             ashort = ntohs( ashort );
743             buf += 2;
744
745             switch ( (unsigned int) achar )
746             {
747             case 0x04 :
748                 fdType = ( u_char *) "TEXT";
749                 break;
750
751             case 0xff :
752                 fdType = ( u_char *) "PSYS";
753                 break;
754
755             case 0xb3 :
756                 fdType = ( u_char *) "PS16";
757                 break;
758
759             case 0x00 :
760                 fdType = ( u_char *) "BINA";
761                 break;
762
763             default :
764                 xyy[0] = ( u_char ) 'p';
765                 xyy[1] = achar;
766                 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
767                 xyy[3] = ( u_char ) ashort & 0xff;
768                 fdType = xyy;
769                 break;
770             }
771
772             memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
773             memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
774             break;
775
776
777         default :
778             err = AFPERR_BITMAP;
779             goto setfilparam_done;
780         }
781
782         bitmap = bitmap>>1;
783         bit++;
784     }
785
786 setfilparam_done:
787     if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
788        newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
789     }
790     if (newdate) {
791        if (isad)
792           ad_setdate(adp, AD_DATE_MODIFY, newdate);
793        ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
794        utime(upath, &ut);
795     }
796
797     if (isad) {
798         ad_flush( adp, ADFLAGS_HF );
799         ad_close( adp, ADFLAGS_HF );
800
801 #ifdef FORCE_UIDGID
802         restore_uidgid ( uidgid );
803 #endif /* FORCE_UIDGID */
804
805     }
806
807     if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
808         newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
809         bitmap = 1<<FILPBIT_MDATE;
810         setdirparams(vol, "", bitmap, (char *)&newdate);
811     }
812
813 #ifdef DEBUG
814     LOG(log_info, logtype_afpd, "end setfilparams:");
815 #endif /* DEBUG */
816     return err;
817 }
818
819 /*
820  * renamefile and copyfile take the old and new unix pathnames
821  * and the new mac name.
822  * NOTE: if we have to copy a file instead of renaming it, locks
823  *       will break. Anyway it's an error because then we have 2 files.
824  * FIXME: locks on ressource fork will always break thanks to ad_close, done ?
825  *
826  * src         the full source absolute path 
827  * dst         the dest filename in current dir
828  * newname     the dest mac name
829  * adp         adouble struct of src file, if open, or & zeroed one
830  *
831  */
832 int renamefile(src, dst, newname, noadouble, adp )
833 char    *src, *dst, *newname;
834 const int         noadouble;
835 struct adouble    *adp;
836 {
837     char                adsrc[ MAXPATHLEN + 1];
838     int                 len, rc;
839
840     /*
841      * Note that this is only checking the existance of the data file,
842      * not the header file.  The thinking is that if the data file doesn't
843      * exist, but the header file does, the right thing to do is remove
844      * the data file silently.
845      */
846
847     /* existence check moved to afp_moveandrename */
848
849 #ifdef DEBUG
850     LOG(log_info, logtype_afpd, "begin renamefile:");
851 #endif /* DEBUG */
852
853     if ( rename( src, dst ) < 0 ) {
854         switch ( errno ) {
855         case ENOENT :
856             return( AFPERR_NOOBJ );
857         case EPERM:
858         case EACCES :
859             return( AFPERR_ACCESS );
860         case EROFS:
861             return AFPERR_VLOCK;
862         case EXDEV :                    /* Cross device move -- try copy */
863             /* if source is open bail out */
864             if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
865                 deletefile( dst, 0 );
866                 return( rc );
867             }
868             return deletefile( src, 0);
869         default :
870             return( AFPERR_PARAM );
871         }
872     }
873
874     strcpy( adsrc, ad_path( src, 0 ));
875     rc = 0;
876 rename_retry:
877     if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
878         struct stat st;
879
880         switch ( errno ) {
881         case ENOENT :
882             /* check for a source appledouble header. if it exists, make
883              * a dest appledouble directory and do the rename again. */
884             if (rc || stat(adsrc, &st) ||
885                     (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
886                 return AFP_OK;
887             rc++;
888             ad_close(adp, ADFLAGS_HF);
889             goto rename_retry;
890         case EPERM:
891         case EACCES :
892             return( AFPERR_ACCESS );
893         case EROFS:
894             return AFPERR_VLOCK;
895         default :
896             return( AFPERR_PARAM );
897         }
898     }
899
900     if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
901         switch ( errno ) {
902         case ENOENT :
903             return( AFPERR_NOOBJ );
904         case EACCES :
905             return( AFPERR_ACCESS );
906         case EROFS:
907             return AFPERR_VLOCK;
908         default :
909             return( AFPERR_PARAM );
910         }
911     }
912
913     len = strlen( newname );
914     ad_setentrylen( adp, ADEID_NAME, len );
915     memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
916     ad_flush( adp, ADFLAGS_HF );
917     ad_close( adp, ADFLAGS_HF );
918
919 #ifdef DEBUG
920     LOG(log_info, logtype_afpd, "end renamefile:");
921 #endif /* DEBUG */
922
923     return( AFP_OK );
924 }
925
926 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
927 AFPObj      *obj;
928 char    *ibuf, *rbuf;
929 int             ibuflen, *rbuflen;
930 {
931     struct vol  *vol;
932     struct dir  *dir;
933     char        *newname, *path, *p;
934     u_int32_t   sdid, ddid;
935     int         plen, err, retvalue = AFP_OK;
936     u_int16_t   svid, dvid;
937
938 #ifdef DEBUG
939     LOG(log_info, logtype_afpd, "begin afp_copyfile:");
940 #endif /* DEBUG */
941
942     *rbuflen = 0;
943     ibuf += 2;
944
945     memcpy(&svid, ibuf, sizeof( svid ));
946     ibuf += sizeof( svid );
947     if (( vol = getvolbyvid( svid )) == NULL ) {
948         return( AFPERR_PARAM );
949     }
950
951     memcpy(&sdid, ibuf, sizeof( sdid ));
952     ibuf += sizeof( sdid );
953     if (( dir = dirsearch( vol, sdid )) == NULL ) {
954         return( AFPERR_PARAM );
955     }
956
957     memcpy(&dvid, ibuf, sizeof( dvid ));
958     ibuf += sizeof( dvid );
959     memcpy(&ddid, ibuf, sizeof( ddid ));
960     ibuf += sizeof( ddid );
961
962     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
963         return( AFPERR_NOOBJ );
964     }
965     if ( *path == '\0' ) {
966         return( AFPERR_BADTYPE );
967     }
968
969     /* don't allow copies when the file is open.
970      * XXX: the spec only calls for read/deny write access.
971      *      however, copyfile doesn't have any of that info,
972      *      and locks need to stay coherent. as a result,
973      *      we just balk if the file is opened already. */
974     if (of_findname(vol, curdir, path))
975         return AFPERR_DENYCONF;
976
977     newname = obj->newtmp;
978     strcpy( newname, path );
979
980     p = ctoupath( vol, curdir, newname );
981
982     if (( vol = getvolbyvid( dvid )) == NULL ) {
983         return( AFPERR_PARAM );
984     }
985
986     if (vol->v_flags & AFPVOL_RO)
987         return AFPERR_VLOCK;
988
989     if (( dir = dirsearch( vol, ddid )) == NULL ) {
990         return( AFPERR_PARAM );
991     }
992
993     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
994         return( AFPERR_NOOBJ );
995     }
996     if ( *path != '\0' ) {
997         return( AFPERR_BADTYPE );
998     }
999
1000     /* one of the handful of places that knows about the path type */
1001     if ( *ibuf++ != 2 ) {
1002         return( AFPERR_PARAM );
1003     }
1004     if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1005         strncpy( newname, ibuf, plen );
1006         newname[ plen ] = '\0';
1007     }
1008
1009     if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
1010                          vol_noadouble(vol))) < 0 ) {
1011         return err;
1012     }
1013
1014     setvoltime(obj, vol );
1015
1016 #ifdef DROPKLUDGE
1017     if (vol->v_flags & AFPVOL_DROPBOX) {
1018         retvalue=matchfile2dirperms(newname, vol, sdid);
1019     }
1020 #endif /* DROPKLUDGE */
1021
1022 #ifdef DEBUG
1023     LOG(log_info, logtype_afpd, "end afp_copyfile:");
1024 #endif /* DEBUG */
1025
1026     return( retvalue );
1027 }
1028
1029
1030 static __inline__ int copy_all(const int dfd, const void *buf,
1031                                size_t buflen)
1032 {
1033     ssize_t cc;
1034
1035 #ifdef DEBUG
1036     LOG(log_info, logtype_afpd, "begin copy_all:");
1037 #endif /* DEBUG */
1038
1039     while (buflen > 0) {
1040         if ((cc = write(dfd, buf, buflen)) < 0) {
1041             switch (errno) {
1042             case EINTR:
1043                 continue;
1044             case EDQUOT:
1045             case EFBIG:
1046             case ENOSPC:
1047                 return AFPERR_DFULL;
1048             case EROFS:
1049                 return AFPERR_VLOCK;
1050             default:
1051                 return AFPERR_PARAM;
1052             }
1053         }
1054         buflen -= cc;
1055     }
1056
1057 #ifdef DEBUG
1058     LOG(log_info, logtype_afpd, "end copy_all:");
1059 #endif /* DEBUG */
1060
1061     return AFP_OK;
1062 }
1063
1064 /* XXX: this needs to use ad_open and ad_lock. so, we need to
1065  * pass in vol and path */
1066 int copyfile(src, dst, newname, noadouble )
1067 char    *src, *dst, *newname;
1068 const int   noadouble;
1069 {
1070     struct adouble      ad;
1071     struct stat         st;
1072     char                filebuf[8192];
1073     int                 sfd, dfd, len, err = AFP_OK;
1074     ssize_t             cc;
1075
1076 #ifdef DEBUG
1077     LOG(log_info, logtype_afpd, "begin copyfile:");
1078 #endif /* DEBUG */
1079
1080     if (newname) {
1081         if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1082             switch ( errno ) {
1083             case ENOENT :
1084                 break; /* just copy the data fork */
1085             case EACCES :
1086                 return( AFPERR_ACCESS );
1087             default :
1088                 return( AFPERR_PARAM );
1089             }
1090         } else {
1091             if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
1092                               ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
1093                 close( sfd );
1094                 switch ( errno ) {
1095                 case ENOENT :
1096                     return( AFPERR_NOOBJ );
1097                 case EACCES :
1098                     return( AFPERR_ACCESS );
1099                 case EROFS:
1100                     return AFPERR_VLOCK;
1101                 default :
1102                     return( AFPERR_PARAM );
1103                 }
1104             }
1105
1106             /* copy the file */
1107 #ifdef SENDFILE_FLAVOR_LINUX
1108             if (fstat(sfd, &st) == 0) {
1109                 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1110                     switch (errno) {
1111                     case EDQUOT:
1112                     case EFBIG:
1113                     case ENOSPC:
1114                         err = AFPERR_DFULL;
1115                         break;
1116                     case EROFS:
1117                         err = AFPERR_VLOCK;
1118                         break;
1119                     default:
1120                         err = AFPERR_PARAM;
1121                     }
1122                 }
1123                 goto copyheader_done;
1124             }
1125 #endif /* SENDFILE_FLAVOR_LINUX */
1126             while (1) {
1127                 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1128                     if (errno == EINTR)
1129                         continue;
1130                     err = AFPERR_PARAM;
1131                     break;
1132                 }
1133
1134                 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1135                     break;
1136             }
1137
1138 copyheader_done:
1139             close(sfd);
1140             close(dfd);
1141             if (err < 0) {
1142                 unlink(ad_path(dst, ADFLAGS_HF));
1143                 return err;
1144             }
1145         }
1146     }
1147
1148     /* data fork copying */
1149     if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1150         switch ( errno ) {
1151         case ENOENT :
1152             return( AFPERR_NOOBJ );
1153         case EACCES :
1154             return( AFPERR_ACCESS );
1155         default :
1156             return( AFPERR_PARAM );
1157         }
1158     }
1159
1160     if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1161         close( sfd );
1162         switch ( errno ) {
1163         case ENOENT :
1164             return( AFPERR_NOOBJ );
1165         case EACCES :
1166             return( AFPERR_ACCESS );
1167         case EROFS:
1168             return AFPERR_VLOCK;
1169         default :
1170             return( AFPERR_PARAM );
1171         }
1172     }
1173
1174 #ifdef SENDFILE_FLAVOR_LINUX
1175     if (fstat(sfd, &st) == 0) {
1176         if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1177             switch (errno) {
1178             case EDQUOT:
1179             case EFBIG:
1180             case ENOSPC:
1181                 err = AFPERR_DFULL;
1182                 break;
1183             default:
1184                 err = AFPERR_PARAM;
1185             }
1186         }
1187         goto copydata_done;
1188     }
1189 #endif /* SENDFILE_FLAVOR_LINUX */
1190
1191     while (1) {
1192         if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1193             if (errno == EINTR)
1194                 continue;
1195
1196             err = AFPERR_PARAM;
1197             break;
1198         }
1199
1200         if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1201             break;
1202         }
1203     }
1204
1205 copydata_done:
1206     close(sfd);
1207     close(dfd);
1208     if (err < 0) {
1209         unlink(ad_path(dst, ADFLAGS_HF));
1210         unlink(dst);
1211         return err;
1212     }
1213
1214     if (newname) {
1215         memset(&ad, 0, sizeof(ad));
1216         if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1217                       0666, &ad) < 0 ) {
1218             switch ( errno ) {
1219             case ENOENT :
1220                 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1221             case EACCES :
1222                 return( AFPERR_ACCESS );
1223             case EROFS:
1224                 return AFPERR_VLOCK;
1225             default :
1226                 return( AFPERR_PARAM );
1227             }
1228         }
1229
1230         len = strlen( newname );
1231         ad_setentrylen( &ad, ADEID_NAME, len );
1232         memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1233         ad_flush( &ad, ADFLAGS_HF );
1234         ad_close( &ad, ADFLAGS_HF );
1235     }
1236
1237 #ifdef DEBUG
1238     LOG(log_info, logtype_afpd, "end copyfile:");
1239 #endif /* DEBUG */
1240
1241     return( AFP_OK );
1242 }
1243
1244
1245 /* -----------------------------------
1246    checkAttrib:   1 check kFPDeleteInhibitBit 
1247    ie deletfile called by afp_delete
1248
1249    when deletefile is called we don't have lock on it, file is closed (for us)
1250 */
1251 int deletefile( file, checkAttrib )
1252 char            *file;
1253 int         checkAttrib;
1254 {
1255     struct adouble      ad;
1256     int                 adflags, err = AFP_OK;
1257     int                 locktype = ADLOCK_WR;
1258     int                 openmode = O_RDWR;
1259
1260 #ifdef DEBUG
1261     LOG(log_info, logtype_afpd, "begin deletefile:");
1262 #endif /* DEBUG */
1263
1264     while(1) {
1265         /*
1266          * If can't open read/write then try again read-only.  If it's open
1267          * read-only, we must do a read lock instead of a write lock.
1268          */
1269         /* try to open both at once */
1270         adflags = ADFLAGS_DF|ADFLAGS_HF;
1271         memset(&ad, 0, sizeof(ad));
1272         if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1273             switch (errno) {
1274             case ENOENT:
1275                 adflags = ADFLAGS_DF;
1276                 /* that failed. now try to open just the data fork */
1277                 memset(&ad, 0, sizeof(ad));
1278                 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1279                     switch (errno) {
1280                     case ENOENT:
1281                         return AFPERR_NOOBJ;
1282                     case EACCES:
1283                         if(openmode == O_RDWR) {
1284                             openmode = O_RDONLY;
1285                             locktype = ADLOCK_RD;
1286                             continue;
1287                         } else {
1288                             return AFPERR_ACCESS;
1289                         }
1290                     case EROFS:
1291                         return AFPERR_VLOCK;
1292                     default:
1293                         return AFPERR_PARAM;
1294                     }
1295                 }
1296                 break;
1297
1298             case EACCES:
1299                 if(openmode == O_RDWR) {
1300                     openmode = O_RDONLY;
1301                     locktype = ADLOCK_RD;
1302                     continue;
1303                 } else {
1304                     return AFPERR_ACCESS;
1305                 }
1306             case EROFS:
1307                 return AFPERR_VLOCK;
1308             default:
1309                 return( AFPERR_PARAM );
1310             }
1311         }
1312         break;  /* from the while */
1313     }
1314     /*
1315      * Does kFPDeleteInhibitBit (bit 8) set?
1316      */
1317     if (checkAttrib && (adflags & ADFLAGS_HF)) {
1318         u_int16_t   bshort;
1319
1320         ad_getattr(&ad, &bshort);
1321         if ((bshort & htons(ATTRBIT_NODELETE))) {
1322             ad_close( &ad, adflags );
1323             return(AFPERR_OLOCK);
1324         }
1325     }
1326     
1327     if ((adflags & ADFLAGS_HF) ) {
1328         /* FIXME we have a pb here because we want to know if a file is open 
1329          * there's a 'priority inversion' if you can't open the ressource fork RW
1330          * you can delete it if it's open because you can't get a write lock.
1331          * 
1332          * ADLOCK_FILELOCK means the whole ressource fork, not only after the 
1333          * metadatas
1334          *
1335          * FIXME it doesn't for RFORK open read only and fork open without deny mode
1336          */
1337         if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) {
1338             ad_close( &ad, adflags );
1339             return( AFPERR_BUSY );
1340         }
1341     }
1342
1343     if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1344         err = AFPERR_BUSY;
1345         goto delete_unlock;
1346     }
1347
1348     if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1349         switch ( errno ) {
1350         case EPERM:
1351         case EACCES :
1352             err = AFPERR_ACCESS;
1353             goto delete_unlock;
1354         case EROFS:
1355             err = AFPERR_VLOCK;
1356             goto delete_unlock;
1357         case ENOENT :
1358             break;
1359         default :
1360             err = AFPERR_PARAM;
1361             goto delete_unlock;
1362         }
1363     }
1364
1365     if ( unlink( file ) < 0 ) {
1366         switch ( errno ) {
1367         case EPERM:
1368         case EACCES :
1369             err = AFPERR_ACCESS;
1370             break;
1371         case EROFS:
1372             err = AFPERR_VLOCK;
1373             break;
1374         case ENOENT :
1375             break;
1376         default :
1377             err = AFPERR_PARAM;
1378             break;
1379         }
1380     }
1381
1382 delete_unlock:
1383     if (adflags & ADFLAGS_HF)
1384         ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0);
1385     ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1386     ad_close( &ad, adflags );
1387
1388 #ifdef DEBUG
1389     LOG(log_info, logtype_afpd, "end deletefile:");
1390 #endif /* DEBUG */
1391
1392     return err;
1393 }
1394
1395
1396 #ifdef CNID_DB
1397 /* return a file id */
1398 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1399 AFPObj      *obj;
1400 char    *ibuf, *rbuf;
1401 int             ibuflen, *rbuflen;
1402 {
1403     struct stat         st;
1404     struct adouble      ad;
1405     struct vol          *vol;
1406     struct dir          *dir;
1407     char                *path, *upath;
1408     int                 len;
1409     cnid_t              did, id;
1410     u_short             vid;
1411
1412 #ifdef DEBUG
1413     LOG(log_info, logtype_afpd, "begin afp_createid:");
1414 #endif /* DEBUG */
1415
1416     *rbuflen = 0;
1417     ibuf += 2;
1418
1419     memcpy(&vid, ibuf, sizeof(vid));
1420     ibuf += sizeof(vid);
1421
1422     if (( vol = getvolbyvid( vid )) == NULL ) {
1423         return( AFPERR_PARAM);
1424     }
1425
1426     if (vol->v_flags & AFPVOL_RO)
1427         return AFPERR_VLOCK;
1428
1429     memcpy(&did, ibuf, sizeof( did ));
1430     ibuf += sizeof(did);
1431
1432     if (( dir = dirsearch( vol, did )) == NULL ) {
1433         return( AFPERR_PARAM );
1434     }
1435
1436     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1437         return( AFPERR_PARAM );
1438     }
1439
1440     if ( *path == '\0' ) {
1441         return( AFPERR_BADTYPE );
1442     }
1443
1444     upath = mtoupath(vol, path);
1445     if (stat(upath, &st) < 0) {
1446         switch (errno) {
1447         case EPERM:
1448         case EACCES:
1449             return AFPERR_ACCESS;
1450         case ENOENT:
1451             return AFPERR_NOOBJ;
1452         default:
1453             return AFPERR_PARAM;
1454         }
1455     }
1456
1457     if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1458         memcpy(rbuf, &id, sizeof(id));
1459         *rbuflen = sizeof(id);
1460         return AFPERR_EXISTID;
1461     }
1462
1463 #if AD_VERSION > AD_VERSION1
1464     memset(&ad, 0, sizeof(ad));
1465     if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1466         memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1467         ad_close(&ad, ADFLAGS_HF);
1468     }
1469 #endif /* AD_VERSION > AD_VERSION1 */
1470
1471     if (id = cnid_add(vol->v_db, &st, did, upath, len, id) != CNID_INVALID) {
1472         memcpy(rbuf, &id, sizeof(id));
1473         *rbuflen = sizeof(id);
1474         return AFP_OK;
1475     }
1476
1477 #ifdef DEBUG
1478     LOG(log_info, logtype_afpd, "ending afp_createid...:");
1479 #endif /* DEBUG */
1480
1481     switch (errno) {
1482     case EROFS:
1483         return AFPERR_VLOCK;
1484         break;
1485     case EPERM:
1486     case EACCES:
1487         return AFPERR_ACCESS;
1488         break;
1489     default:
1490         LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1491         return AFPERR_PARAM;
1492     }
1493 }
1494
1495 /* resolve a file id */
1496 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1497 AFPObj      *obj;
1498 char    *ibuf, *rbuf;
1499 int             ibuflen, *rbuflen;
1500 {
1501     struct stat         st;
1502     struct vol          *vol;
1503     struct dir          *dir;
1504     char                *upath;
1505     int                 err, buflen;
1506     cnid_t              id;
1507     u_int16_t           vid, bitmap;
1508
1509     static char buffer[12 + MAXPATHLEN + 1];
1510     int len = 12 + MAXPATHLEN + 1;
1511
1512 #ifdef DEBUG
1513     LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1514 #endif /* DEBUG */
1515
1516     *rbuflen = 0;
1517     ibuf += 2;
1518
1519     memcpy(&vid, ibuf, sizeof(vid));
1520     ibuf += sizeof(vid);
1521
1522     if (( vol = getvolbyvid( vid )) == NULL ) {
1523         return( AFPERR_PARAM);
1524     }
1525
1526     memcpy(&id, ibuf, sizeof( id ));
1527     ibuf += sizeof(id);
1528
1529     if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1530         return AFPERR_BADID;
1531     }
1532
1533     if (( dir = dirlookup( vol, id )) == NULL ) {
1534         return( AFPERR_PARAM );
1535     }
1536
1537     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1538         switch (errno) {
1539         case EACCES:
1540         case EPERM:
1541             return AFPERR_ACCESS;
1542         case ENOENT:
1543             return AFPERR_NOID;
1544         default:
1545             return AFPERR_PARAM;
1546         }
1547     }
1548
1549     /* directories are bad */
1550     if (S_ISDIR(st.st_mode))
1551         return AFPERR_BADTYPE;
1552
1553     memcpy(&bitmap, ibuf, sizeof(bitmap));
1554     bitmap = ntohs( bitmap );
1555
1556     if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1557                             rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1558         return err;
1559
1560     *rbuflen = buflen + sizeof(bitmap);
1561     memcpy(rbuf, ibuf, sizeof(bitmap));
1562
1563 #ifdef DEBUG
1564     LOG(log_info, logtype_afpd, "end afp_resolveid:");
1565 #endif /* DEBUG */
1566
1567     return AFP_OK;
1568 }
1569
1570 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1571 AFPObj      *obj;
1572 char    *ibuf, *rbuf;
1573 int             ibuflen, *rbuflen;
1574 {
1575     struct stat         st;
1576     struct vol          *vol;
1577     struct dir          *dir;
1578     char                *upath;
1579     int                 err;
1580     cnid_t              id;
1581     cnid_t              fileid;
1582     u_short             vid;
1583     static char buffer[12 + MAXPATHLEN + 1];
1584     int len = 12 + MAXPATHLEN + 1;
1585
1586 #ifdef DEBUG
1587     LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1588 #endif /* DEBUG */
1589
1590     *rbuflen = 0;
1591     ibuf += 2;
1592
1593     memcpy(&vid, ibuf, sizeof(vid));
1594     ibuf += sizeof(vid);
1595
1596     if (( vol = getvolbyvid( vid )) == NULL ) {
1597         return( AFPERR_PARAM);
1598     }
1599
1600     if (vol->v_flags & AFPVOL_RO)
1601         return AFPERR_VLOCK;
1602
1603     memcpy(&id, ibuf, sizeof( id ));
1604     ibuf += sizeof(id);
1605     fileid = id;
1606
1607     if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1608         return AFPERR_NOID;
1609     }
1610
1611     if (( dir = dirlookup( vol, id )) == NULL ) {
1612         return( AFPERR_PARAM );
1613     }
1614
1615     err = AFP_OK;
1616     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1617         switch (errno) {
1618         case EACCES:
1619         case EPERM:
1620             return AFPERR_ACCESS;
1621         case ENOENT:
1622             /* still try to delete the id */
1623             err = AFPERR_NOOBJ;
1624             break;
1625         default:
1626             return AFPERR_PARAM;
1627         }
1628     }
1629
1630     /* directories are bad */
1631     if (S_ISDIR(st.st_mode))
1632         return AFPERR_BADTYPE;
1633
1634     if (cnid_delete(vol->v_db, fileid)) {
1635         switch (errno) {
1636         case EROFS:
1637             return AFPERR_VLOCK;
1638         case EPERM:
1639         case EACCES:
1640             return AFPERR_ACCESS;
1641         default:
1642             return AFPERR_PARAM;
1643         }
1644     }
1645
1646 #ifdef DEBUG
1647     LOG(log_info, logtype_afpd, "end afp_deleteid:");
1648 #endif /* DEBUG */
1649
1650     return err;
1651 }
1652 #endif /* CNID_DB */
1653
1654 #define APPLETEMP ".AppleTempXXXXXX"
1655
1656 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1657 AFPObj      *obj;
1658 char    *ibuf, *rbuf;
1659 int             ibuflen, *rbuflen;
1660 {
1661     struct stat         srcst, destst;
1662     struct vol          *vol;
1663     struct dir          *dir, *sdir;
1664     char                *spath, temp[17], *path, *p;
1665     char                *supath, *upath;
1666     int                 err;
1667     struct adouble      ads;
1668     struct adouble      add;
1669     struct adouble      *adsp;
1670     struct adouble      *addp;
1671     struct ofork        *opened;
1672     
1673 #ifdef CNID_DB
1674     int                 slen, dlen;
1675 #endif /* CNID_DB */
1676     u_int32_t           sid, did;
1677     u_int16_t           vid;
1678
1679 #ifdef DEBUG
1680     LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1681 #endif /* DEBUG */
1682
1683     *rbuflen = 0;
1684     ibuf += 2;
1685
1686     memcpy(&vid, ibuf, sizeof(vid));
1687     ibuf += sizeof(vid);
1688
1689     if (( vol = getvolbyvid( vid )) == NULL ) {
1690         return( AFPERR_PARAM);
1691     }
1692
1693     if (vol->v_flags & AFPVOL_RO)
1694         return AFPERR_VLOCK;
1695
1696     /* source and destination dids */
1697     memcpy(&sid, ibuf, sizeof(sid));
1698     ibuf += sizeof(sid);
1699     memcpy(&did, ibuf, sizeof(did));
1700     ibuf += sizeof(did);
1701
1702     /* source file */
1703     if ((dir = dirsearch( vol, sid )) == NULL ) {
1704         return( AFPERR_PARAM );
1705     }
1706
1707     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1708         return( AFPERR_PARAM );
1709     }
1710
1711     if ( *path == '\0' ) {
1712         return( AFPERR_BADTYPE );   /* it's a dir */
1713     }
1714
1715     upath = mtoupath(vol, path);
1716     if (stat(upath, &srcst) < 0) {
1717         switch (errno) {
1718         case ENOENT:
1719             return AFPERR_NOID;
1720         case EPERM:
1721         case EACCES:
1722             return AFPERR_ACCESS;
1723         default:
1724             return AFPERR_PARAM;
1725         }
1726     }
1727     memset(&ads, 0, sizeof(ads));
1728     adsp = &ads;
1729     if ((opened = of_findname(vol, curdir, path))) {
1730             /* reuse struct adouble so it won't break locks */
1731             adsp = opened->of_ad;
1732     }
1733     /* save some stuff */
1734     sdir = curdir;
1735     spath = obj->oldtmp;
1736     supath = obj->newtmp;
1737     strcpy(spath, path);
1738     strcpy(supath, upath); /* this is for the cnid changing */
1739     p = ctoupath( vol, sdir, spath);
1740
1741     /* look for the source cnid. if it doesn't exist, don't worry about
1742      * it. */
1743 #ifdef CNID_DB
1744     sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1745                       slen = strlen(supath));
1746 #endif /* CNID_DB */
1747
1748     if (( dir = dirsearch( vol, did )) == NULL ) {
1749         return( AFPERR_PARAM );
1750     }
1751
1752     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1753         return( AFPERR_PARAM );
1754     }
1755
1756     if ( *path == '\0' ) {
1757         return( AFPERR_BADTYPE );
1758     }
1759
1760     /* FPExchangeFiles is the only call that can return the SameObj
1761      * error */
1762     if ((curdir == sdir) && strcmp(spath, path) == 0)
1763         return AFPERR_SAMEOBJ;
1764
1765     upath = mtoupath(vol, path);
1766     if (stat(upath, &destst) < 0) {
1767         switch (errno) {
1768         case ENOENT:
1769             return AFPERR_NOID;
1770         case EPERM:
1771         case EACCES:
1772             return AFPERR_ACCESS;
1773         default:
1774             return AFPERR_PARAM;
1775         }
1776     }
1777     memset(&add, 0, sizeof(add));
1778     addp = &add;
1779     if ((opened = of_findname(vol, curdir, path))) {
1780             /* reuse struct adouble so it won't break locks */
1781             addp = opened->of_ad;
1782     }
1783 #ifdef CNID_DB
1784     /* look for destination id. */
1785     did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1786                       dlen = strlen(upath));
1787 #endif /* CNID_DB */
1788
1789     /* construct a temp name.
1790      * NOTE: the temp file will be in the dest file's directory. it
1791      * will also be inaccessible from AFP. */
1792     memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1793     if (!mktemp(temp))
1794         return AFPERR_MISC;
1795
1796     /* now, quickly rename the file. we error if we can't. */
1797     if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1798         goto err_exchangefile;
1799     of_rename(vol, sdir, spath, curdir, temp);
1800
1801     /* rename destination to source */
1802     if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1803         goto err_src_to_tmp;
1804     of_rename(vol, curdir, path, sdir, spath);
1805
1806     /* rename temp to destination */
1807     if ((err = renamefile(temp, upath, path, vol_noadouble(vol), adsp)) < 0)
1808         goto err_dest_to_src;
1809     of_rename(vol, curdir, temp, curdir, path);
1810
1811 #ifdef CNID_DB
1812     /* id's need switching. src -> dest and dest -> src. */
1813     if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1814                             upath, dlen) < 0)) {
1815         switch (errno) {
1816         case EPERM:
1817         case EACCES:
1818             err = AFPERR_ACCESS;
1819             break;
1820         default:
1821             err = AFPERR_PARAM;
1822         }
1823         goto err_temp_to_dest;
1824     }
1825
1826     if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1827                             supath, slen) < 0)) {
1828         switch (errno) {
1829         case EPERM:
1830         case EACCES:
1831             err = AFPERR_ACCESS;
1832             break;
1833         default:
1834             err = AFPERR_PARAM;
1835         }
1836
1837         if (sid)
1838             cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1839         goto err_temp_to_dest;
1840     }
1841 #endif /* CNID_DB */
1842
1843 #ifdef DEBUG
1844     LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1845 #endif /* DEBUG */
1846
1847     return AFP_OK;
1848
1849
1850     /* all this stuff is so that we can unwind a failed operation
1851      * properly. */
1852 #ifdef CNID_DB
1853 err_temp_to_dest:
1854 #endif
1855     /* rename dest to temp */
1856     renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1857     of_rename(vol, curdir, upath, curdir, temp);
1858
1859 err_dest_to_src:
1860     /* rename source back to dest */
1861     renamefile(p, upath, path, vol_noadouble(vol), addp);
1862     of_rename(vol, sdir, spath, curdir, path);
1863
1864 err_src_to_tmp:
1865     /* rename temp back to source */
1866     renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1867     of_rename(vol, curdir, temp, sdir, spath);
1868
1869 err_exchangefile:
1870     return err;
1871 }