[v2,2/3] tools/nolibc: implement fd-based FILE streams
Commit Message
This enables the usage of the stream APIs with arbitrary filedescriptors.
It will be used by a future testcase.
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
---
Willy:
This uses intptr_t instead of uintptr_t as proposed because uintptr_t
can not be negative.
---
tools/include/nolibc/stdio.h | 60 ++++++++++++++++++++++++--------------------
1 file changed, 33 insertions(+), 27 deletions(-)
Comments
On Sun, Apr 02, 2023 at 01:02:46PM +0000, Thomas Weißschuh wrote:
> Willy:
>
> This uses intptr_t instead of uintptr_t as proposed because uintptr_t
> can not be negative.
Ah yes good point.
> +/* provides the fd from of stream. */
> +static __attribute__((unused))
> +int fileno(FILE *stream)
> +{
> + intptr_t i = (intptr_t)stream;
> +
> + if (i > 0) {
If you don't mind I'll change this to "if (i >= 0)" since we also want
to set errno on NULL.
> + SET_ERRNO(EBADF);
> + return -1;
> + }
> + return ~i;
> +}
OK for the rest of the series.
Thanks!
Willy
On 2023-04-02 16:03:38+0200, Willy Tarreau wrote:
> On Sun, Apr 02, 2023 at 01:02:46PM +0000, Thomas Weißschuh wrote:
> > Willy:
> >
> > This uses intptr_t instead of uintptr_t as proposed because uintptr_t
> > can not be negative.
>
> Ah yes good point.
>
> > +/* provides the fd from of stream. */
> > +static __attribute__((unused))
> > +int fileno(FILE *stream)
> > +{
> > + intptr_t i = (intptr_t)stream;
> > +
> > + if (i > 0) {
>
> If you don't mind I'll change this to "if (i >= 0)" since we also want
> to set errno on NULL.
Sounds good.
> > + SET_ERRNO(EBADF);
> > + return -1;
> > + }
> > + return ~i;
> > +}
>
> OK for the rest of the series.
Thanks,
Thomas
@@ -21,17 +21,40 @@
#define EOF (-1)
#endif
-/* just define FILE as a non-empty type */
+/* just define FILE as a non-empty type. The value of the pointer gives
+ * the FD: FILE=~fd for fd>=0 or NULL for fd<0. This way positive FILE
+ * are immediately identified as abnormal entries (i.e. possible copies
+ * of valid pointers to something else).
+ */
typedef struct FILE {
char dummy[1];
} FILE;
-/* We define the 3 common stdio files as constant invalid pointers that
- * are easily recognized.
- */
-static __attribute__((unused)) FILE* const stdin = (FILE*)-3;
-static __attribute__((unused)) FILE* const stdout = (FILE*)-2;
-static __attribute__((unused)) FILE* const stderr = (FILE*)-1;
+static __attribute__((unused)) FILE* const stdin = (FILE*)(intptr_t)~STDIN_FILENO;
+static __attribute__((unused)) FILE* const stdout = (FILE*)(intptr_t)~STDOUT_FILENO;
+static __attribute__((unused)) FILE* const stderr = (FILE*)(intptr_t)~STDERR_FILENO;
+
+/* provides a FILE* equivalent of fd. The mode is ignored. */
+static __attribute__((unused))
+FILE *fdopen(int fd, const char *mode __attribute__((unused)))
+{
+ if (fd < 0)
+ return NULL;
+ return (FILE*)(intptr_t)~fd;
+}
+
+/* provides the fd from of stream. */
+static __attribute__((unused))
+int fileno(FILE *stream)
+{
+ intptr_t i = (intptr_t)stream;
+
+ if (i > 0) {
+ SET_ERRNO(EBADF);
+ return -1;
+ }
+ return ~i;
+}
/* getc(), fgetc(), getchar() */
@@ -41,14 +64,8 @@ static __attribute__((unused))
int fgetc(FILE* stream)
{
unsigned char ch;
- int fd;
- if (stream < stdin || stream > stderr)
- return EOF;
-
- fd = 3 + (long)stream;
-
- if (read(fd, &ch, 1) <= 0)
+ if (read(fileno(stream), &ch, 1) <= 0)
return EOF;
return ch;
}
@@ -68,14 +85,8 @@ static __attribute__((unused))
int fputc(int c, FILE* stream)
{
unsigned char ch = c;
- int fd;
-
- if (stream < stdin || stream > stderr)
- return EOF;
-
- fd = 3 + (long)stream;
- if (write(fd, &ch, 1) <= 0)
+ if (write(fileno(stream), &ch, 1) <= 0)
return EOF;
return ch;
}
@@ -96,12 +107,7 @@ static __attribute__((unused))
int _fwrite(const void *buf, size_t size, FILE *stream)
{
ssize_t ret;
- int fd;
-
- if (stream < stdin || stream > stderr)
- return EOF;
-
- fd = 3 + (long)stream;
+ int fd = fileno(stream);
while (size) {
ret = write(fd, buf, size);