Skip site navigation (1)Skip section navigation (2)
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>