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