]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/fork.c
BIG commit to improve code style using astyle as well as fix up CNID DB
[netatalk.git] / etc / afpd / fork.c
1 /*
2  * $Id: fork.c,v 1.12 2001-12-03 05:03:38 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 #ifdef HAVE_UNISTD_H
14 #include <unistd.h>
15 #endif /* HAVE_UNISTD_H */
16 #ifdef HAVE_FCNTL_H
17 #include <fcntl.h>
18 #endif /* HAVE_FCNTL_H */
19 #include <dirent.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <syslog.h>
23
24 #include <sys/param.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <sys/time.h>
28 #include <sys/socket.h>
29
30 #include <netatalk/endian.h>
31 #include <netatalk/at.h>
32
33 #include <atalk/dsi.h>
34 #include <atalk/atp.h>
35 #include <atalk/asp.h>
36 #include <atalk/afp.h>
37 #include <atalk/adouble.h>
38 #include <atalk/util.h>
39 #ifdef CNID_DB
40 #include <atalk/cnid.h>
41 #endif
42
43 #include "fork.h"
44 #include "file.h"
45 #include "globals.h"
46 #include "directory.h"
47 #include "desktop.h"
48 #include "volume.h"
49
50 #define BYTELOCK_MAX 0x7FFFFFFFU
51
52 struct ofork            *writtenfork;
53
54 static int getforkparams(ofork, bitmap, buf, buflen, attrbits )
55 struct ofork    *ofork;
56 u_int16_t               bitmap;
57 char            *buf;
58 int                     *buflen;
59 const u_int16_t     attrbits;
60 {
61     struct stat         st;
62     struct extmap       *em;
63     char                *data, *nameoff = NULL, *upath;
64     int                 bit = 0, isad = 1;
65     u_int32_t           aint;
66     u_int16_t           ashort;
67
68     if ( ad_hfileno( ofork->of_ad ) == -1 ) {
69         isad = 0;
70     } else {
71         aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
72         if ( ad_refresh( ofork->of_ad ) < 0 ) {
73             syslog( LOG_ERR, "getforkparams: ad_refresh: %s", strerror(errno) );
74             return( AFPERR_PARAM );
75         }
76         /* See afp_closefork() for why this is bad */
77         ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
78     }
79
80     /* can only get the length of the opened fork */
81     if (((bitmap & (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_RSRC)) ||
82             ((bitmap & (1<<FILPBIT_RFLEN)) && (ofork->of_flags & AFPFORK_DATA))) {
83         return( AFPERR_BITMAP );
84     }
85
86     if ( bitmap & ( 1<<FILPBIT_DFLEN | 1<<FILPBIT_FNUM |
87                     (1 << FILPBIT_CDATE) | (1 << FILPBIT_MDATE) |
88                     (1 << FILPBIT_BDATE))) {
89         upath = mtoupath(ofork->of_vol, ofork->of_name);
90         if ( ad_dfileno( ofork->of_ad ) == -1 ) {
91             if ( stat( upath, &st ) < 0 )
92                 return( AFPERR_NOOBJ );
93         } else {
94             if ( fstat( ad_dfileno( ofork->of_ad ), &st ) < 0 ) {
95                 return( AFPERR_BITMAP );
96             }
97         }
98     }
99
100     data = buf;
101     while ( bitmap != 0 ) {
102         while (( bitmap & 1 ) == 0 ) {
103             bitmap = bitmap>>1;
104             bit++;
105         }
106
107         switch ( bit ) {
108         case FILPBIT_ATTR :
109             if ( isad ) {
110                 ad_getattr(ofork->of_ad, &ashort);
111             } else {
112                 ashort = 0;
113             }
114             if (attrbits)
115                 ashort = htons(ntohs(ashort) | attrbits);
116             memcpy(data, &ashort, sizeof( ashort ));
117             data += sizeof( ashort );
118             break;
119
120         case FILPBIT_PDID :
121             memcpy(data, &ofork->of_dir->d_did, sizeof( aint ));
122             data += sizeof( aint );
123             break;
124
125         case FILPBIT_CDATE :
126             if (!isad ||
127                     (ad_getdate(ofork->of_ad, AD_DATE_CREATE, &aint) < 0))
128                 aint = AD_DATE_FROM_UNIX(st.st_mtime);
129             memcpy(data, &aint, sizeof( aint ));
130             data += sizeof( aint );
131             break;
132
133         case FILPBIT_MDATE :
134             if (!isad ||
135                     (ad_getdate(ofork->of_ad, AD_DATE_MODIFY, &aint) < 0) ||
136                     (AD_DATE_TO_UNIX(aint) < st.st_mtime))
137                 aint = AD_DATE_FROM_UNIX(st.st_mtime);
138             memcpy(data, &aint, sizeof( aint ));
139             data += sizeof( aint );
140             break;
141
142         case FILPBIT_BDATE :
143             if (!isad ||
144                     (ad_getdate(ofork->of_ad, AD_DATE_BACKUP, &aint) < 0))
145                 aint = AD_DATE_START;
146             memcpy(data, &aint, sizeof( aint ));
147             data += sizeof( aint );
148             break;
149
150         case FILPBIT_FINFO :
151             memcpy(data, isad ?
152                    (void *) ad_entry(ofork->of_ad, ADEID_FINDERI) :
153                    (void *) ufinderi, 32);
154             if ( !isad ||
155                     memcmp( ad_entry( ofork->of_ad, ADEID_FINDERI ),
156                             ufinderi, 8 ) == 0 ) {
157                 memcpy(data, ufinderi, 8 );
158                 if (( em = getextmap( ofork->of_name )) != NULL ) {
159                     memcpy(data, em->em_type, sizeof( em->em_type ));
160                     memcpy(data + 4, em->em_creator,
161                            sizeof( em->em_creator ));
162                 }
163             }
164             data += 32;
165             break;
166
167         case FILPBIT_LNAME :
168             nameoff = data;
169             data += sizeof(u_int16_t);
170             break;
171
172         case FILPBIT_SNAME :
173             memset(data, 0, sizeof(u_int16_t));
174             data += sizeof(u_int16_t);
175             break;
176
177         case FILPBIT_FNUM :
178             aint = 0;
179 #if AD_VERSION > AD_VERSION1
180             /* look in AD v2 header */
181             if (isad)
182                 memcpy(&aint, ad_entry(ofork->of_ad, ADEID_DID), sizeof(aint));
183 #endif /* AD_VERSION > AD_VERSION1 */
184
185 #ifdef CNID_DB
186             aint = cnid_add(ofork->of_vol->v_db, &st,
187                             ofork->of_dir->d_did,
188                             upath, strlen(upath), aint);
189 #endif /* CNID_DB */
190
191             if (aint == 0) {
192 #ifdef AFS
193                 aint = st.st_ino;
194 #else /* AFS */
195                 aint = ( st.st_dev << 16 ) | ( st.st_ino & 0x0000ffff );
196 #endif /* AFS */
197             }
198
199             memcpy(data, &aint, sizeof( aint ));
200             data += sizeof( aint );
201             break;
202
203         case FILPBIT_DFLEN :
204             aint = htonl( st.st_size );
205             memcpy(data, &aint, sizeof( aint ));
206             data += sizeof( aint );
207             break;
208
209         case FILPBIT_RFLEN :
210             if ( isad ) {
211                 aint = htonl( ad_getentrylen( ofork->of_ad, ADEID_RFORK ));
212             } else {
213                 aint = 0;
214             }
215             memcpy(data, &aint, sizeof( aint ));
216             data += sizeof( aint );
217             break;
218
219         default :
220             return( AFPERR_BITMAP );
221         }
222         bitmap = bitmap>>1;
223         bit++;
224     }
225
226     if ( nameoff ) {
227         ashort = htons( data - buf );
228         memcpy(nameoff, &ashort, sizeof( ashort ));
229         aint = strlen( ofork->of_name );
230         aint = ( aint > MACFILELEN ) ? MACFILELEN : aint;
231         *data++ = aint;
232         memcpy(data, ofork->of_name, aint );
233         data += aint;
234     }
235
236     *buflen = data - buf;
237     return( AFP_OK );
238 }
239
240 int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
241 AFPObj      *obj;
242 char    *ibuf, *rbuf;
243 int             ibuflen, *rbuflen;
244 {
245     struct vol          *vol;
246     struct dir          *dir;
247     struct ofork        *ofork, *opened;
248     struct adouble      *adsame = NULL;
249     int                 buflen, ret, adflags, eid, lockop;
250     u_int32_t           did;
251     u_int16_t           vid, bitmap, access, ofrefnum, attrbits = 0;
252     char                fork, *path, *upath;
253
254     ibuf++;
255     fork = *ibuf++;
256     memcpy(&vid, ibuf, sizeof( vid ));
257     ibuf += sizeof(vid);
258
259     *rbuflen = 0;
260     if (( vol = getvolbyvid( vid )) == NULL ) {
261         return( AFPERR_PARAM );
262     }
263
264     memcpy(&did, ibuf, sizeof( did ));
265     ibuf += sizeof( int );
266
267     if (( dir = dirsearch( vol, did )) == NULL ) {
268         return( AFPERR_NOOBJ );
269     }
270
271     memcpy(&bitmap, ibuf, sizeof( bitmap ));
272     bitmap = ntohs( bitmap );
273     ibuf += sizeof( bitmap );
274     memcpy(&access, ibuf, sizeof( access ));
275     access = ntohs( access );
276     ibuf += sizeof( access );
277
278     if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
279         return AFPERR_VLOCK;
280     }
281
282     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
283         return( AFPERR_NOOBJ );
284     }
285
286     if ( fork == OPENFORK_DATA ) {
287         eid = ADEID_DFORK;
288         adflags = ADFLAGS_DF|ADFLAGS_HF;
289     } else {
290         eid = ADEID_RFORK;
291         adflags = ADFLAGS_HF;
292     }
293
294     /* XXX: this probably isn't the best way to do this. the already
295        open bits should really be set if the fork is opened by any
296        program, not just this one. however, that's problematic to do
297        if we can't write lock files somewhere. opened is also passed to 
298        ad_open so that we can keep file locks together. */
299     if ((opened = of_findname(vol, curdir, path))) {
300         attrbits = ((opened->of_flags & AFPFORK_RSRC) ? ATTRBIT_ROPEN : 0) |
301                    ((opened->of_flags & AFPFORK_DATA) ? ATTRBIT_DOPEN : 0);
302         adsame = opened->of_ad;
303     }
304
305     if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
306                            adsame)) == NULL ) {
307         return( AFPERR_NFILE );
308     }
309     if (access & OPENACC_WR) {
310         /* try opening in read-write mode */
311         upath = mtoupath(vol, path);
312         ret = AFPERR_NOOBJ;
313         if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
314             switch ( errno ) {
315             case EROFS:
316                 ret = AFPERR_VLOCK;
317             case EACCES:
318                 goto openfork_err;
319
320                 break;
321             case ENOENT:
322                 {
323                     struct stat st;
324
325                     /* see if client asked for the data fork */
326                     if (fork == OPENFORK_DATA) {
327                         if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
328                             goto openfork_err;
329                         }
330                         adflags = ADFLAGS_DF;
331
332                     } else if (stat(upath, &st) == 0) {
333                         /* here's the deal. we only try to create the resource
334                          * fork if the user wants to open it for write acess. */
335                         if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
336                             goto openfork_err;
337                     } else
338                         goto openfork_err;
339                 }
340                 break;
341             case EMFILE :
342             case ENFILE :
343                 ret = AFPERR_NFILE;
344                 goto openfork_err;
345                 break;
346             case EISDIR :
347                 ret = AFPERR_BADTYPE;
348                 goto openfork_err;
349                 break;
350             default:
351                 syslog( LOG_ERR, "afp_openfork: ad_open: %s", strerror(errno) );
352                 ret = AFPERR_PARAM;
353                 goto openfork_err;
354                 break;
355             }
356         }
357     } else {
358         /* try opening in read-only mode */
359         upath = mtoupath(vol, path);
360         ret = AFPERR_NOOBJ;
361         if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
362             switch ( errno ) {
363             case EROFS:
364                 ret = AFPERR_VLOCK;
365             case EACCES:
366                 /* check for a read-only data fork */
367                 if ((adflags != ADFLAGS_HF) &&
368                         (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0))
369                     goto openfork_err;
370
371                 adflags = ADFLAGS_DF;
372                 break;
373             case ENOENT:
374                 {
375                     struct stat st;
376
377                     /* see if client asked for the data fork */
378                     if (fork == OPENFORK_DATA) {
379                         if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
380                             goto openfork_err;
381                         }
382                         adflags = ADFLAGS_DF;
383
384                     } else if (stat(upath, &st) != 0) {
385                         goto openfork_err;
386                     }
387                 }
388                 break;
389             case EMFILE :
390             case ENFILE :
391                 ret = AFPERR_NFILE;
392                 goto openfork_err;
393                 break;
394             case EISDIR :
395                 ret = AFPERR_BADTYPE;
396                 goto openfork_err;
397                 break;
398             default:
399                 syslog( LOG_ERR, "afp_openfork: ad_open: %s", strerror(errno) );
400                 goto openfork_err;
401                 break;
402             }
403         }
404     }
405
406     if ((adflags & ADFLAGS_HF) &&
407             (ad_getoflags( ofork->of_ad, ADFLAGS_HF ) & O_CREAT)) {
408         ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
409         memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
410                ad_getentrylen( ofork->of_ad, ADEID_NAME ));
411         ad_flush( ofork->of_ad, adflags );
412     }
413
414     if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
415                               &buflen, attrbits )) != AFP_OK ) {
416         ad_close( ofork->of_ad, adflags );
417         goto openfork_err;
418     }
419
420     *rbuflen = buflen + 2 * sizeof( u_int16_t );
421     bitmap = htons( bitmap );
422     memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
423     rbuf += sizeof( u_int16_t );
424
425     /*
426      * synchronization locks:
427      *
428      * here's the ritual:
429      *  1) attempt a read lock to see if we have read or write
430      *     privileges.
431      *  2) if that succeeds, set a write lock to correspond to the
432      *     deny mode requested.
433      *  3) whenever a file is read/written, locks get set which
434      *     prevent conflicts.
435      */
436
437     /* don't try to lock non-existent rforks. */
438     if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
439
440         /* try to see if we have access. */
441         ret = 0;
442         if (access & OPENACC_WR) {
443             ofork->of_flags |= AFPFORK_ACCWR;
444             ret = ad_lock(ofork->of_ad, eid, ADLOCK_RD | ADLOCK_FILELOCK,
445                           AD_FILELOCK_WR, 1, ofrefnum);
446         }
447
448         if (!ret && (access & OPENACC_RD)) {
449             ofork->of_flags |= AFPFORK_ACCRD;
450             ret = ad_lock(ofork->of_ad, eid, ADLOCK_RD | ADLOCK_FILELOCK,
451                           AD_FILELOCK_RD, 1, ofrefnum);
452         }
453
454         /* can we access the fork? */
455         if (ret < 0) {
456             ad_close( ofork->of_ad, adflags );
457             of_dealloc( ofork );
458             ofrefnum = 0;
459             memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
460             return (AFPERR_DENYCONF);
461         }
462
463         /* now try to set the deny lock. if the fork is open for read or
464          * write, a read lock will already have been set. otherwise, we upgrade
465          * our lock to a write lock. 
466          *
467          * NOTE: we can't write lock a read-only file. on those, we just
468          * make sure that we have a read lock set. that way, we at least prevent
469          * someone else from really setting a deny read/write on the file. */
470         lockop = (ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
471                  ADLOCK_WR : ADLOCK_RD;
472         ret = (access & OPENACC_DWR) ? ad_lock(ofork->of_ad, eid,
473                                                lockop | ADLOCK_FILELOCK |
474                                                ADLOCK_UPGRADE, AD_FILELOCK_WR, 1,
475                                                ofrefnum) : 0;
476         if (!ret && (access & OPENACC_DRD))
477             ret = ad_lock(ofork->of_ad, eid, lockop | ADLOCK_FILELOCK |
478                           ADLOCK_UPGRADE, AD_FILELOCK_RD, 1, ofrefnum);
479
480         if (ret < 0) {
481             ret = errno;
482             ad_close( ofork->of_ad, adflags );
483             of_dealloc( ofork );
484             switch (ret) {
485             case EAGAIN: /* return data anyway */
486             case EACCES:
487             case EINVAL:
488                 ofrefnum = 0;
489                 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
490                 return( AFPERR_DENYCONF );
491                 break;
492             default:
493                 *rbuflen = 0;
494                 syslog( LOG_ERR, "afp_openfork: ad_lock: %s", strerror(errno) );
495                 return( AFPERR_PARAM );
496             }
497         }
498     }
499
500     memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
501     return( AFP_OK );
502
503 openfork_err:
504     of_dealloc( ofork );
505     if (errno == EACCES)
506         return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
507     return ret;
508 }
509
510 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
511 AFPObj      *obj;
512 char    *ibuf, *rbuf;
513 int             ibuflen, *rbuflen;
514 {
515     struct ofork        *ofork;
516     int32_t             size;
517     u_int16_t           ofrefnum, bitmap;
518     int                 err;
519
520     ibuf += 2;
521     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
522     ibuf += sizeof( ofrefnum );
523     memcpy(&bitmap, ibuf, sizeof(bitmap));
524     bitmap = ntohs(bitmap);
525     ibuf += sizeof( bitmap );
526     memcpy(&size, ibuf, sizeof( size ));
527     size = ntohl( size );
528
529     *rbuflen = 0;
530     if (( ofork = of_find( ofrefnum )) == NULL ) {
531         syslog( LOG_ERR, "afp_setforkparams: of_find: %s", strerror(errno) );
532         return( AFPERR_PARAM );
533     }
534
535     if (ofork->of_vol->v_flags & AFPVOL_RO)
536         return AFPERR_VLOCK;
537
538     if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
539         return AFPERR_ACCESS;
540
541     if (size < 0)
542         return AFPERR_PARAM;
543
544     if ((bitmap == (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_DATA)) {
545         err = ad_dtruncate( ofork->of_ad, size );
546         if (err < 0)
547             goto afp_setfork_err;
548     } else if ((bitmap == (1<<FILPBIT_RFLEN)) &&
549                (ofork->of_flags & AFPFORK_RSRC)) {
550         ad_refresh( ofork->of_ad );
551         err = ad_rtruncate(ofork->of_ad, size);
552         if (err < 0)
553             goto afp_setfork_err;
554
555         if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
556             syslog( LOG_ERR, "afp_setforkparams: ad_flush: %s",
557                     strerror(errno) );
558             return( AFPERR_PARAM );
559         }
560     } else
561         return AFPERR_BITMAP;
562
563 #ifdef AFS
564     if ( flushfork( ofork ) < 0 ) {
565         syslog( LOG_ERR, "afp_setforkparams: flushfork: %s", strerror(errno) );
566     }
567 #endif /* AFS */
568
569     return( AFP_OK );
570
571 afp_setfork_err:
572     if (err == -2)
573         return AFPERR_LOCK;
574     else {
575         switch (errno) {
576         case EROFS:
577             return AFPERR_VLOCK;
578         case EPERM:
579         case EACCES:
580             return AFPERR_ACCESS;
581         case EDQUOT:
582         case EFBIG:
583         case ENOSPC:
584             return AFPERR_DFULL;
585         default:
586             return AFPERR_PARAM;
587         }
588     }
589 }
590
591 /* for this to work correctly, we need to check for locks before each
592  * read and write. that's most easily handled by always doing an
593  * appropriate check before each ad_read/ad_write. other things
594  * that can change files like truncate are handled internally to those
595  * functions. 
596  */
597 #define ENDBIT(a)  ((a) & 0x80)
598 #define UNLOCKBIT(a) ((a) & 0x01)
599 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
600 AFPObj      *obj;
601 char    *ibuf, *rbuf;
602 int             ibuflen, *rbuflen;
603 {
604     struct ofork        *ofork;
605     int32_t             offset, length;
606     int                 eid;
607     u_int16_t           ofrefnum;
608     u_int8_t            flags;
609
610     *rbuflen = 0;
611
612     /* figure out parameters */
613     ibuf++;
614     flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
615     ibuf++;
616     memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
617     ibuf += sizeof(ofrefnum);
618
619     if (( ofork = of_find( ofrefnum )) == NULL ) {
620         syslog( LOG_ERR, "afp_bytelock: of_find: %s", strerror(errno) );
621         return( AFPERR_PARAM );
622     }
623
624     if ( ofork->of_flags & AFPFORK_DATA) {
625         eid = ADEID_DFORK;
626     } else if (ofork->of_flags & AFPFORK_RSRC) {
627         eid = ADEID_RFORK;
628     } else
629         return AFPERR_PARAM;
630
631     memcpy(&offset, ibuf, sizeof( offset ));
632     offset = ntohl(offset);
633     ibuf += sizeof(offset);
634
635     memcpy(&length, ibuf, sizeof( length ));
636     length = ntohl(length);
637     if (length == 0xFFFFFFFF)
638         length = BYTELOCK_MAX;
639     else if (length <= 0) {
640         return AFPERR_PARAM;
641     } else if ((length >= AD_FILELOCK_BASE) &&
642                (ad_hfileno(ofork->of_ad) == -1))
643         return AFPERR_LOCK;
644
645     if (ENDBIT(flags))
646         offset += ad_size(ofork->of_ad, eid);
647
648     if (offset < 0)    /* error if we have a negative offset */
649         return AFPERR_PARAM;
650
651     /* if the file is a read-only file, we use read locks instead of
652      * write locks. that way, we can prevent anyone from initiating
653      * a write lock. */
654     if (ad_lock(ofork->of_ad, eid, UNLOCKBIT(flags) ? ADLOCK_CLR :
655                 ((ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
656                  ADLOCK_WR : ADLOCK_RD), offset, length,
657                 ofork->of_refnum) < 0) {
658         switch (errno) {
659         case EACCES:
660         case EAGAIN:
661             return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
662             break;
663         case ENOLCK:
664             return AFPERR_NLOCK;
665             break;
666         case EINVAL:
667             return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
668             break;
669         case EBADF:
670         default:
671             return AFPERR_PARAM;
672             break;
673         }
674     }
675
676     offset = htonl(offset);
677     memcpy(rbuf, &offset, sizeof( offset ));
678     *rbuflen = sizeof( offset );
679     return( AFP_OK );
680 }
681 #undef UNLOCKBIT
682
683
684 static __inline__ int crlf( of )
685 struct ofork    *of;
686 {
687     struct extmap       *em;
688
689     if ( ad_hfileno( of->of_ad ) == -1 ||
690             memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
691                     8) == 0 ) {
692         if (( em = getextmap( of->of_name )) == NULL ||
693                 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
694             return( 1 );
695         } else {
696             return( 0 );
697         }
698     } else {
699         if ( memcmp( ufinderi,
700                      ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
701             return( 1 );
702         } else {
703             return( 0 );
704         }
705     }
706 }
707
708
709 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
710                                     int offset, u_char nlmask,
711                                     u_char nlchar, char *rbuf,
712                                     int *rbuflen, const int xlate)
713 {
714     ssize_t cc;
715     int eof = 0;
716     char *p, *q;
717
718     cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
719     if ( cc < 0 ) {
720         syslog( LOG_ERR, "afp_read: ad_read: %s", strerror(errno) );
721         *rbuflen = 0;
722         return( AFPERR_PARAM );
723     }
724     if ( cc < *rbuflen ) {
725         eof = 1;
726     }
727
728     /*
729      * Do Newline check.
730      */
731     if ( nlmask != 0 ) {
732         for ( p = rbuf, q = p + cc; p < q; ) {
733             if (( *p++ & nlmask ) == nlchar ) {
734                 break;
735             }
736         }
737         if ( p != q ) {
738             cc = p - rbuf;
739             eof = 0;
740         }
741     }
742
743     /*
744      * If this file is of type TEXT, then swap \012 to \015.
745      */
746     if (xlate) {
747         for ( p = rbuf, q = p + cc; p < q; p++ ) {
748             if ( *p == '\012' ) {
749                 *p = '\015';
750             } else if ( *p == '\015' ) {
751                 *p = '\012';
752             }
753
754         }
755     }
756
757     *rbuflen = cc;
758     if ( eof ) {
759         return( AFPERR_EOF );
760     }
761     return AFP_OK;
762 }
763
764 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
765 AFPObj      *obj;
766 char    *ibuf, *rbuf;
767 int             ibuflen, *rbuflen;
768 {
769     struct ofork        *ofork;
770     off_t               size;
771     int32_t             offset, saveoff, reqcount;
772     int                 cc, err, eid, xlate = 0;
773     u_int16_t           ofrefnum;
774     u_char              nlmask, nlchar;
775
776     ibuf += 2;
777     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
778     ibuf += sizeof( u_short );
779
780     if (( ofork = of_find( ofrefnum )) == NULL ) {
781         syslog( LOG_ERR, "afp_read: of_find: %s", strerror(errno) );
782         err = AFPERR_PARAM;
783         goto afp_read_err;
784     }
785
786     if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
787         err = AFPERR_ACCESS;
788         goto afp_read_err;
789     }
790
791     memcpy(&offset, ibuf, sizeof( offset ));
792     offset = ntohl( offset );
793     ibuf += sizeof( offset );
794     memcpy(&reqcount, ibuf, sizeof( reqcount ));
795     reqcount = ntohl( reqcount );
796     ibuf += sizeof( reqcount );
797
798     nlmask = *ibuf++;
799     nlchar = *ibuf++;
800
801     /* if we wanted to be picky, we could add in the following
802      * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
803      */
804     if (reqcount < 0 || offset < 0) {
805         err = AFPERR_PARAM;
806         goto afp_read_err;
807     }
808
809     if ( ofork->of_flags & AFPFORK_DATA) {
810         eid = ADEID_DFORK;
811         xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
812     } else if (ofork->of_flags & AFPFORK_RSRC) {
813         eid = ADEID_RFORK;
814     } else { /* fork wasn't opened. this should never really happen. */
815         err = AFPERR_ACCESS;
816         goto afp_read_err;
817     }
818
819     /* zero request count */
820     if (!reqcount) {
821         err = AFP_OK;
822         goto afp_read_err;
823     }
824
825     /* reqcount isn't always truthful. we need to deal with that. */
826     if ((size = ad_size(ofork->of_ad, eid)) == 0) {
827         err = AFPERR_EOF;
828         goto afp_read_err;
829     }
830
831     saveoff = offset;
832     if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, reqcount) < 0) {
833         err = AFPERR_LOCK;
834         goto afp_read_err;
835     }
836
837 #define min(a,b)        ((a)<(b)?(a):(b))
838     *rbuflen = min( reqcount, *rbuflen );
839     err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
840                     xlate);
841     if (err < 0)
842         goto afp_read_done;
843
844     /* dsi can stream requests. we can only do this if we're not checking
845      * for an end-of-line character. oh well. */
846     if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
847         DSI *dsi = obj->handle;
848
849         /* subtract off the offset */
850         size -= offset;
851         if (reqcount > size) {
852             reqcount = size;
853             err = AFPERR_EOF;
854         }
855
856         if (obj->options.flags & OPTION_DEBUG) {
857             printf( "(read) reply: %d/%d, %d\n", *rbuflen,
858                     reqcount, dsi->clientID);
859             bprint(rbuf, *rbuflen);
860         }
861
862         offset += *rbuflen;
863
864         /* dsi_readinit() returns size of next read buffer. by this point,
865          * we know that we're sending some data. if we fail, something
866          * horrible happened. */
867         if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
868             goto afp_read_exit;
869
870         /* due to the nature of afp packets, we have to exit if we get
871            an error. we can't do this with translation on. */
872 #ifdef HAVE_SENDFILE_READ
873         if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
874             if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
875                             dsi->datasize) < 0) {
876                 if (errno == EINVAL)
877                     goto afp_read_loop;
878                 else {
879                     syslog(LOG_ERR, "afp_read: ad_readfile: %s", strerror(errno));
880                     goto afp_read_exit;
881                 }
882             }
883
884             dsi_readdone(dsi);
885             goto afp_read_done;
886         }
887
888 afp_read_loop:
889 #endif /* HAVE_SENDFILE_READ */
890
891         /* fill up our buffer. */
892         while (*rbuflen > 0) {
893             cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
894                            rbuflen, xlate);
895             if (cc < 0)
896                 goto afp_read_exit;
897
898             offset += *rbuflen;
899             if (obj->options.flags & OPTION_DEBUG) {
900                 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
901                 bprint(rbuf, *rbuflen);
902             }
903
904             /* dsi_read() also returns buffer size of next allocation */
905             cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
906             if (cc < 0)
907                 goto afp_read_exit;
908             *rbuflen = cc;
909         }
910         dsi_readdone(dsi);
911         goto afp_read_done;
912
913 afp_read_exit:
914         syslog(LOG_ERR, "afp_read: %s", strerror(errno));
915         dsi_readdone(dsi);
916         ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
917         obj->exit(1);
918     }
919
920 afp_read_done:
921     ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
922     return err;
923
924 afp_read_err:
925     *rbuflen = 0;
926     return err;
927 }
928
929 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
930 AFPObj      *obj;
931 char    *ibuf, *rbuf;
932 int             ibuflen, *rbuflen;
933 {
934     struct vol *vol;
935     u_int16_t vid;
936
937     *rbuflen = 0;
938     ibuf += 2;
939
940     memcpy(&vid, ibuf, sizeof(vid));
941     if (( vol = getvolbyvid( vid )) == NULL ) {
942         return( AFPERR_PARAM );
943     }
944
945     of_flush(vol);
946     return( AFP_OK );
947 }
948
949 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
950 AFPObj      *obj;
951 char    *ibuf, *rbuf;
952 int             ibuflen, *rbuflen;
953 {
954     struct ofork        *ofork;
955     u_int16_t           ofrefnum;
956
957     *rbuflen = 0;
958     ibuf += 2;
959     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
960
961     if (( ofork = of_find( ofrefnum )) == NULL ) {
962         syslog( LOG_ERR, "afp_flushfork: of_find: %s", strerror(errno) );
963         return( AFPERR_PARAM );
964     }
965
966     if ( flushfork( ofork ) < 0 ) {
967         syslog( LOG_ERR, "afp_flushfork: %s", strerror(errno) );
968     }
969
970     return( AFP_OK );
971 }
972
973 /* this is very similar to closefork */
974 int flushfork( ofork )
975 struct ofork    *ofork;
976 {
977     struct timeval tv;
978     int len, err = 0, doflush = 0;
979
980     if ( ad_dfileno( ofork->of_ad ) != -1 &&
981             fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
982         syslog( LOG_ERR, "flushfork: dfile(%d) %s",
983                 ad_dfileno(ofork->of_ad), strerror(errno) );
984         err = -1;
985     }
986
987     if ( ad_hfileno( ofork->of_ad ) != -1 ) {
988
989         /* read in the rfork length */
990         len = ad_getentrylen(ofork->of_ad, ADEID_RFORK);
991         ad_refresh(ofork->of_ad);
992
993         /* set the date if we're dirty */
994         if ((ofork->of_flags & AFPFORK_DIRTY) &&
995                 (gettimeofday(&tv, NULL) == 0)) {
996             ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
997             ofork->of_flags &= ~AFPFORK_DIRTY;
998             doflush++;
999         }
1000
1001         /* if we're actually flushing this fork, make sure to set the
1002          * length. otherwise, just use the stored length */
1003         if ((ofork->of_flags & AFPFORK_RSRC) &&
1004                 (len != ad_getentrylen(ofork->of_ad, ADEID_RFORK))) {
1005             ad_setentrylen(ofork->of_ad, ADEID_RFORK, len);
1006             doflush++;
1007         }
1008
1009
1010         /* flush the header (if it is a resource fork) */
1011         if (ofork->of_flags & AFPFORK_RSRC)
1012             if (doflush && (ad_flush(ofork->of_ad, ADFLAGS_HF) < 0))
1013                 err = -1;
1014
1015         if (fsync( ad_hfileno( ofork->of_ad )) < 0)
1016             err = -1;
1017
1018         if (err < 0)
1019             syslog( LOG_ERR, "flushfork: hfile(%d) %s",
1020                     ad_hfileno(ofork->of_ad), strerror(errno) );
1021     }
1022
1023     return( err );
1024 }
1025
1026 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
1027 AFPObj      *obj;
1028 char    *ibuf, *rbuf;
1029 int             ibuflen, *rbuflen;
1030 {
1031     struct ofork        *ofork;
1032     struct timeval      tv;
1033     int                 adflags, aint, doflush = 0;
1034     u_int16_t           ofrefnum;
1035
1036     *rbuflen = 0;
1037     ibuf += 2;
1038     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1039
1040     if (( ofork = of_find( ofrefnum )) == NULL ) {
1041         syslog( LOG_ERR, "afp_closefork: of_find: %s", strerror(errno) );
1042         return( AFPERR_PARAM );
1043     }
1044
1045     adflags = 0;
1046     if ((ofork->of_flags & AFPFORK_DATA) &&
1047             (ad_dfileno( ofork->of_ad ) != -1)) {
1048         adflags |= ADFLAGS_DF;
1049     }
1050
1051     if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1052         adflags |= ADFLAGS_HF;
1053
1054         aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
1055         ad_refresh( ofork->of_ad );
1056         if ((ofork->of_flags & AFPFORK_DIRTY) &&
1057                 (gettimeofday(&tv, NULL) == 0)) {
1058             ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,
1059                        tv.tv_sec);
1060             doflush++;
1061         }
1062
1063         /*
1064          * Only set the rfork's length if we're closing the rfork.
1065          */
1066         if ((ofork->of_flags & AFPFORK_RSRC) && aint !=
1067                 ad_getentrylen( ofork->of_ad, ADEID_RFORK )) {
1068             ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
1069             doflush++;
1070         }
1071         if ( doflush ) {
1072             ad_flush( ofork->of_ad, adflags );
1073         }
1074     }
1075
1076     if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1077         syslog( LOG_ERR, "afp_closefork: ad_close: %s", strerror(errno) );
1078         return( AFPERR_PARAM );
1079     }
1080
1081     of_dealloc( ofork );
1082     return( AFP_OK );
1083 }
1084
1085
1086 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1087                                      off_t offset, char *rbuf,
1088                                      size_t rbuflen, const int xlate)
1089 {
1090     char *p, *q;
1091     ssize_t cc;
1092
1093     /*
1094      * If this file is of type TEXT, swap \015 to \012.
1095      */
1096     if (xlate) {
1097         for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1098             if ( *p == '\015' ) {
1099                 *p = '\012';
1100             } else if ( *p == '\012' ) {
1101                 *p = '\015';
1102             }
1103         }
1104     }
1105
1106     if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1107                         rbuf, rbuflen)) < 0 ) {
1108         switch ( errno ) {
1109         case EDQUOT :
1110         case EFBIG :
1111         case ENOSPC :
1112             return( AFPERR_DFULL );
1113         default :
1114             syslog( LOG_ERR, "afp_write: ad_write: %s", strerror(errno) );
1115             return( AFPERR_PARAM );
1116         }
1117     }
1118
1119     return cc;
1120 }
1121
1122 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1123  * the client may have sent us a bunch of data that's not reflected 
1124  * in reqcount et al. */
1125 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1126 AFPObj              *obj;
1127 char                *ibuf, *rbuf;
1128 int                 ibuflen, *rbuflen;
1129 {
1130     struct ofork        *ofork;
1131     int32_t             offset, saveoff, reqcount;
1132     int                 endflag, eid, xlate = 0, err = AFP_OK;
1133     u_int16_t           ofrefnum;
1134     ssize_t             cc;
1135
1136     /* figure out parameters */
1137     ibuf++;
1138     endflag = ENDBIT(*ibuf);
1139     ibuf++;
1140     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1141     ibuf += sizeof( ofrefnum );
1142     memcpy(&offset, ibuf, sizeof( offset ));
1143     offset = ntohl( offset );
1144     ibuf += sizeof( offset );
1145     memcpy(&reqcount, ibuf, sizeof( reqcount ));
1146     reqcount = ntohl( reqcount );
1147     ibuf += sizeof( reqcount );
1148
1149     if (( ofork = of_find( ofrefnum )) == NULL ) {
1150         syslog( LOG_ERR, "afp_write: of_find: %s", strerror(errno) );
1151         err = AFPERR_PARAM;
1152         goto afp_write_err;
1153     }
1154
1155     if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1156         err = AFPERR_ACCESS;
1157         goto afp_write_err;
1158     }
1159
1160 #ifdef AFS
1161     writtenfork = ofork;
1162 #endif /* AFS */
1163
1164     if ( ofork->of_flags & AFPFORK_DATA) {
1165         eid = ADEID_DFORK;
1166         xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1167     } else if (ofork->of_flags & AFPFORK_RSRC) {
1168         eid = ADEID_RFORK;
1169     } else {
1170         err = AFPERR_ACCESS; /* should never happen */
1171         goto afp_write_err;
1172     }
1173
1174     if (endflag)
1175         offset += ad_size(ofork->of_ad, eid);
1176
1177     /* handle bogus parameters */
1178     if (reqcount < 0 || offset < 0) {
1179         err = AFPERR_PARAM;
1180         goto afp_write_err;
1181     }
1182
1183     /* offset can overflow on 64-bit capable filesystems.
1184      * report disk full if that's going to happen. */
1185     if (offset + reqcount < 0) {
1186         err = AFPERR_DFULL;
1187         goto afp_write_err;
1188     }
1189
1190     if (!reqcount) { /* handle request counts of 0 */
1191         err = AFP_OK;
1192         offset = htonl(offset);
1193         memcpy(rbuf, &offset, sizeof(offset));
1194         goto afp_write_err;
1195     }
1196
1197     saveoff = offset;
1198     if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1199                    reqcount) < 0) {
1200         err = AFPERR_LOCK;
1201         goto afp_write_err;
1202     }
1203
1204     /* this is yucky, but dsi can stream i/o and asp can't */
1205     switch (obj->proto) {
1206 #ifndef NO_DDP
1207     case AFPPROTO_ASP:
1208         if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1209             *rbuflen = 0;
1210             syslog( LOG_ERR, "afp_write: asp_wrtcont: %s", strerror(errno) );
1211             return( AFPERR_PARAM );
1212         }
1213
1214         if (obj->options.flags & OPTION_DEBUG) {
1215             printf("(write) len: %d\n", *rbuflen);
1216             bprint(rbuf, *rbuflen);
1217         }
1218
1219         if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1220                              xlate)) < 0) {
1221             *rbuflen = 0;
1222             ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1223             return cc;
1224         }
1225         offset += cc;
1226         break;
1227 #endif /* no afp/asp */
1228
1229     case AFPPROTO_DSI:
1230         {
1231             DSI *dsi = obj->handle;
1232
1233             /* find out what we have already and write it out. */
1234             cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1235             if (!cc ||
1236                     (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1237                 dsi_writeflush(dsi);
1238                 *rbuflen = 0;
1239                 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1240                 return cc;
1241             }
1242             offset += cc;
1243
1244 #if 0 /*def HAVE_SENDFILE_WRITE*/
1245             if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1246                 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1247                                        offset, dsi->datasize)) < 0) {
1248                     switch (errno) {
1249                     case EDQUOT :
1250                     case EFBIG :
1251                     case ENOSPC :
1252                         cc = AFPERR_DFULL;
1253                         break;
1254                     default :
1255                         syslog( LOG_ERR, "afp_write: ad_writefile: %s", strerror(errno) );
1256                         goto afp_write_loop;
1257                     }
1258                     dsi_writeflush(dsi);
1259                     *rbuflen = 0;
1260                     ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1261                                reqcount);
1262                     return cc;
1263                 }
1264
1265                 offset += cc;
1266                 goto afp_write_done;
1267             }
1268 #endif /* 0, was HAVE_SENDFILE_WRITE */
1269
1270             /* loop until everything gets written. currently
1271                     * dsi_write handles the end case by itself. */
1272 afp_write_loop:
1273             while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1274                 if ( obj->options.flags & OPTION_DEBUG ) {
1275                     printf("(write) command cont'd: %d\n", cc);
1276                     bprint(rbuf, cc);
1277                 }
1278
1279                 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1280                     dsi_writeflush(dsi);
1281                     *rbuflen = 0;
1282                     ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1283                                reqcount);
1284                     return cc;
1285                 }
1286                 offset += cc;
1287             }
1288         }
1289         break;
1290     }
1291
1292 afp_write_done:
1293     ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1294     if ( ad_hfileno( ofork->of_ad ) != -1 )
1295         ofork->of_flags |= AFPFORK_DIRTY;
1296
1297     offset = htonl( offset );
1298 #if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG)
1299     bcopy(&offset, rbuf, sizeof(offset));
1300 #else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1301     memcpy(rbuf, &offset, sizeof(offset));
1302 #endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1303     *rbuflen = sizeof(offset);
1304     return( AFP_OK );
1305
1306 afp_write_err:
1307     if (obj->proto == AFPPROTO_DSI) {
1308         dsi_writeinit(obj->handle, rbuf, *rbuflen);
1309         dsi_writeflush(obj->handle);
1310     }
1311
1312     *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1313     return err;
1314 }
1315
1316
1317 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1318 AFPObj      *obj;
1319 char    *ibuf, *rbuf;
1320 int             ibuflen, *rbuflen;
1321 {
1322     struct ofork        *ofork;
1323     int                 buflen, ret;
1324     u_int16_t           ofrefnum, bitmap;
1325
1326     ibuf += 2;
1327     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1328     ibuf += sizeof( ofrefnum );
1329     memcpy(&bitmap, ibuf, sizeof( bitmap ));
1330     bitmap = ntohs( bitmap );
1331     ibuf += sizeof( bitmap );
1332
1333     *rbuflen = 0;
1334     if (( ofork = of_find( ofrefnum )) == NULL ) {
1335         syslog( LOG_ERR, "afp_getforkparams: of_find: %s", strerror(errno) );
1336         return( AFPERR_PARAM );
1337     }
1338
1339     if (( ret = getforkparams( ofork, bitmap,
1340                                rbuf + sizeof( u_short ), &buflen, 0 )) != AFP_OK ) {
1341         return( ret );
1342     }
1343
1344     *rbuflen = buflen + sizeof( u_short );
1345     bitmap = htons( bitmap );
1346     memcpy(rbuf, &bitmap, sizeof( bitmap ));
1347     return( AFP_OK );
1348 }
1349