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