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>