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