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