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