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