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