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