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