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