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