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