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