Date: Thu, 22 Aug 2019 13:28:30 -0700 From: Conrad Meyer <cem@freebsd.org> To: Farhan Khan <farhan@farhan.codes> Cc: "freebsd-hackers@freebsd.org" <freebsd-hackers@freebsd.org> Subject: Re: Trouble using and understanding funopen(3) Message-ID: <CAG6CVpWryJeA5DXZMNZ5cfrfexzEx_ewy9CB5HbFgNtjj=GwPg@mail.gmail.com> In-Reply-To: <519c2fce85fe0db1cd189d2060f09a0f@farhan.codes> References: <519c2fce85fe0db1cd189d2060f09a0f@farhan.codes>
next in thread | previous in thread | raw e-mail | index | archive | help
Hi Farhan,
First, I'd suggest using the more portable fopencookie(3) interface,
which is similar to funopen(3).
Second, read functions return 0 to indicate end of file.
Finally, the file cookie routines are stateful. If you want to create
a pseudo-FILE that only has 10 bytes in it, you have to track the
current file offset by creating a cookie. Here is a minimal example
of using a cookie.
struct my_file {
off_t offset;
};
my_read(void *v, buf, len)
{
struct my_file *f =3D v;
size_t rlen;
/* Indicate EOF for reads past EOF. */
if (f->offset >=3D 10)
return (0);
rlen =3D MIN(len, 10 - f->offset);
memcpy(buf, "AAAAAAAAAA", rlen);
f->offset +=3D rlen;
return ((int)rlen);
}
main()
{
struct my_file *cookie;
FILE *f;
char buf[100];
size_t x;
cookie =3D calloc(1, sizeof(*cookie));
f =3D fopencookie(cookie, "rb", { .read =3D my_read, });
x =3D fread(buf, 1, sizeof(buf), f);
...
}
Conrad
On Thu, Aug 22, 2019 at 9:24 AM Farhan Khan via freebsd-hackers
<freebsd-hackers@freebsd.org> wrote:
>
> Hi all,
>
> I am having trouble understanding how funopen(3)'s read function works. S=
pecifically, how do I have the readfn return with less than the requested a=
mount of bytes.
>
> My understanding: I believe that funopen(3) allows you to assign the read=
, write and close methods to a FILE stream. When a program runs fread(3) on=
a FILE stream opened by funopen(3), the program will run the readfn handle=
r in a loop until it returns either returns the requested number of bytes, =
0 or -1 (error).
>
> Question: How do I structure the code so that readfn returns with less th=
an the numbe of requested bytes? For example, what if the calling fread() f=
unction requests 100 bytes, but the readfn can only return 10 bytes? What m=
echanism do I need to implement so that the fread(3) returns "10" bytes rat=
her than the readfn handler running 10 times? This results in the fread()'s=
return value as 100, even though only 10 bytes were *actually* read.
>
> I have looked at a few examples from the src tree. Clearly they have to u=
se buffering and append the bytes they read to the memory object they were =
initially passed. Somehow they return with the number of bytes they actuall=
y read, not necessarily the requested amount. But it is not clear to me how=
they make this distinction and avoid having their respective readfn functi=
on re-rerun. Also, in the examples I did look up there does not appear to b=
e any use of setvbuf().
>
> Below is a very simple test case to illustrate the issue.
>
> ------
> #include <stdio.h>
> #include <string.h>
> #include <stdlib.h>
>
> static int
> ssh_readfn(void *v, char *buf, int len)
> {
> printf("Running readfn handler\n");
> memcpy(buf, "AAAAAAAAAA", 10);
> return 10;
> }
>
> static int
> ssh_writefn(void *v, const char *buf, int len)
> {
> return 0;
> }
>
> int
> main()
> {
> int x;
> char buf[1000];
> FILE *f;
>
> f =3D funopen(NULL, ssh_readfn, ssh_writefn, NULL, NULL);
> if (f =3D=3D NULL) {
> printf("funopen failed, exiting.\n");
> exit(0);
> }
>
> x =3D fread(buf, 1, 100, f);
> printf("Bytes read: %d\n", x);
> }
> ------
>
> This displays 10 "Running readfn handler" lines fllowed by "Bytes read: 1=
00" even though I am explicitly returning 10 in ssh_readfn. Please advise w=
hat the mechanism is only return with less than the requested number of byt=
es.
>
> Thanks!
> ---
> Farhan Khan
> PGP Fingerprint: 1312 89CE 663E 1EB2 179C 1C83 C41D 2281 F8DA C0DE
> _______________________________________________
> freebsd-hackers@freebsd.org mailing list
> https://lists.freebsd.org/mailman/listinfo/freebsd-hackers
> To unsubscribe, send any mail to "freebsd-hackers-unsubscribe@freebsd.org=
"
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAG6CVpWryJeA5DXZMNZ5cfrfexzEx_ewy9CB5HbFgNtjj=GwPg>
