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