From 006528b144e8c624bb1303fa5ee6943ba58c3b50 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 22 Nov 2015 08:38:55 -0600 Subject: [PATCH] Add support for freopen() --- ChangeLog | 2 + drivers/pipes/pipe_common.c | 2 +- fs/vfs/fs_open.c | 1 + include/fcntl.h | 2 +- include/stdio.h | 3 +- libc/lib_internal.h | 6 +- libc/stdio/Make.defs | 17 +++-- libc/stdio/lib_fileno.c | 1 + libc/stdio/lib_fopen.c | 130 +++++++++++++++----------------- libc/stdio/lib_freopen.c | 143 ++++++++++++++++++++++++++++++++++++ 10 files changed, 226 insertions(+), 81 deletions(-) create mode 100644 libc/stdio/lib_freopen.c diff --git a/ChangeLog b/ChangeLog index cd40ad5570..d3a5f291cb 100755 --- a/ChangeLog +++ b/ChangeLog @@ -11138,3 +11138,5 @@ * fs/vfs/open.c: If the use attempts to open a block driver, use block_proxy() to insert a character driver conversion layer in front of the block driver (2015-11-21). + * libc/stdio/lib_freopen.c and include/stdio.h: Add support for + freopen() (2015-11-22). diff --git a/drivers/pipes/pipe_common.c b/drivers/pipes/pipe_common.c index 37e1fc18cd..346bb5dc69 100644 --- a/drivers/pipes/pipe_common.c +++ b/drivers/pipes/pipe_common.c @@ -371,7 +371,7 @@ int pipecommon_close(FAR struct file *filep) } } - /* What is the buffer management policy? Do we free the buffe when the + /* What is the buffer management policy? Do we free the buffer when the * last client closes the pipe policy 0, or when the buffer becomes empty. * In the latter case, the buffer data will remain valid and can be * obtained when the pipe is re-opened. diff --git a/fs/vfs/fs_open.c b/fs/vfs/fs_open.c index b0a5ca2c50..81a2ef7f7c 100644 --- a/fs/vfs/fs_open.c +++ b/fs/vfs/fs_open.c @@ -51,6 +51,7 @@ #include #include "inode/inode.h" +#include "driver/driver.h" /**************************************************************************** * Private Functions diff --git a/include/fcntl.h b/include/fcntl.h index 6bec04f0ac..6145c11fd6 100644 --- a/include/fcntl.h +++ b/include/fcntl.h @@ -102,7 +102,7 @@ #define F_GETSIG 6 /* Get the signal sent */ #define F_NOTIFY 7 /* Provide notification when directory referred to by fd changes (linux)*/ #define F_SETFD 8 /* Set the file descriptor flags to value */ -#define F_SETFL 9 /* Set the file status flags to the value */ +#define F_SETFL 9 /* Set the file status flags to the value */ #define F_SETLEASE 10 /* Set or remove file lease (linux) */ #define F_SETLK 11 /* Acquire or release a lock on range of bytes */ #define F_SETLKW 12 /* Like F_SETLK, but wait for lock to become available */ diff --git a/include/stdio.h b/include/stdio.h index 057a58c9a8..d8f0c3479a 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -1,7 +1,7 @@ /**************************************************************************** * include/stdio.h * - * Copyright (C) 2007-2009, 2011, 2013-2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011, 2013-2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -147,6 +147,7 @@ int fprintf(FAR FILE *stream, FAR const char *format, ...); int fputc(int c, FAR FILE *stream); int fputs(FAR const char *s, FAR FILE *stream); size_t fread(FAR void *ptr, size_t size, size_t n_items, FAR FILE *stream); +FAR FILE *freopen(FAR const char *path, FAR const char *mode, FAR FILE *stream); int fseek(FAR FILE *stream, long int offset, int whence); int fsetpos(FAR FILE *stream, FAR fpos_t *pos); long ftell(FAR FILE *stream); diff --git a/libc/lib_internal.h b/libc/lib_internal.h index c4610dfe62..29bbd136f5 100644 --- a/libc/lib_internal.h +++ b/libc/lib_internal.h @@ -155,7 +155,11 @@ char *__dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve); #endif -/* Defined in lib_libwrite.c */ +/* Defined in lib_fopen.c */ + +int lib_mode2oflags(FAR const char *mode); + +/* Defined in lib_libfwrite.c */ ssize_t lib_fwrite(FAR const void *ptr, size_t count, FAR FILE *stream); diff --git a/libc/stdio/Make.defs b/libc/stdio/Make.defs index fbda15caaa..595a222b27 100644 --- a/libc/stdio/Make.defs +++ b/libc/stdio/Make.defs @@ -56,14 +56,15 @@ CSRCS += lib_rawsostream.c ifneq ($(CONFIG_NFILE_STREAMS),0) -CSRCS += lib_fopen.c lib_fclose.c lib_fread.c lib_libfread.c lib_fseek.c -CSRCS += lib_ftell.c lib_fsetpos.c lib_fgetpos.c lib_fgetc.c lib_fgets.c -CSRCS += lib_gets_s.c lib_gets.c lib_libfgets.c lib_fwrite.c lib_libfwrite.c -CSRCS += lib_fflush.c lib_libflushall.c lib_libfflush.c lib_rdflush.c -CSRCS += lib_wrflush.c lib_fputc.c lib_puts.c lib_fputs.c lib_ungetc.c -CSRCS += lib_vprintf.c lib_fprintf.c lib_vfprintf.c lib_stdinstream.c -CSRCS += lib_stdoutstream.c lib_stdsistream.c lib_stdsostream.c lib_perror.c -CSRCS += lib_feof.c lib_ferror.c lib_clearerr.c +CSRCS += lib_fopen.c lib_freopen.c lib_fclose.c lib_fread.c lib_libfread.c +CSRCS += lib_fseek.c lib_ftell.c lib_fsetpos.c lib_fgetpos.c lib_fgetc.c +CSRCS += lib_fgets.c lib_gets_s.c lib_gets.c lib_libfgets.c lib_fwrite.c +CSRCS += lib_libfwrite.c lib_fflush.c lib_libflushall.c lib_libfflush.c +CSRCS += lib_rdflush.c lib_wrflush.c lib_fputc.c lib_puts.c lib_fputs.c +CSRCS += lib_ungetc.c lib_vprintf.c lib_fprintf.c lib_vfprintf.c +CSRCS += lib_stdinstream.c lib_stdoutstream.c lib_stdsistream.c +CSRCS += lib_stdsostream.c lib_perror.c lib_feof.c lib_ferror.c +CSRCS += lib_clearerr.c endif diff --git a/libc/stdio/lib_fileno.c b/libc/stdio/lib_fileno.c index 555d288759..73e6951da0 100644 --- a/libc/stdio/lib_fileno.c +++ b/libc/stdio/lib_fileno.c @@ -53,6 +53,7 @@ int fileno(FAR FILE *stream) { int ret = -1; + if (stream) { ret = stream->fs_fd; diff --git a/libc/stdio/lib_fopen.c b/libc/stdio/lib_fopen.c index fc0856ce5b..957e439b19 100644 --- a/libc/stdio/lib_fopen.c +++ b/libc/stdio/lib_fopen.c @@ -69,18 +69,76 @@ #define MODE_MASK (MODE_R | MODE_W | MODE_A) /**************************************************************************** - * Private Types + * Public Functions ****************************************************************************/ /**************************************************************************** - * Private Functions + * Name: fdopen ****************************************************************************/ +FAR FILE *fdopen(int fd, FAR const char *mode) +{ + FAR FILE *ret = NULL; + int oflags; + + /* Map the open mode string to open flags */ + + oflags = lib_mode2oflags(mode); + if (oflags >= 0) + { + ret = fs_fdopen(fd, oflags, NULL); + } + + return ret; +} + +/**************************************************************************** + * Name: fopen + ****************************************************************************/ + +FAR FILE *fopen(FAR const char *path, FAR const char *mode) +{ + FAR FILE *ret = NULL; + int oflags; + int fd; + + /* Map the open mode string to open flags */ + + oflags = lib_mode2oflags(mode); + if (oflags < 0) + { + return NULL; + } + + /* Open the file */ + + fd = open(path, oflags, 0666); + + /* If the open was successful, then fdopen() the fil using the file + * descriptor returned by open. If open failed, then just return the + * NULL stream -- open() has already set the errno. + */ + + if (fd >= 0) + { + ret = fs_fdopen(fd, oflags, NULL); + if (!ret) + { + /* Don't forget to close the file descriptor if any other + * failures are reported by fdopen(). + */ + + (void)close(fd); + } + } + return ret; +} + /**************************************************************************** * Name: lib_mode2oflags ****************************************************************************/ -static int lib_mode2oflags(FAR const char *mode) +int lib_mode2oflags(FAR const char *mode) { unsigned int state; int oflags; @@ -246,69 +304,3 @@ errout: set_errno(EINVAL); return ERROR; } - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: fdopen - ****************************************************************************/ - -FAR FILE *fdopen(int fd, FAR const char *mode) -{ - FAR FILE *ret = NULL; - int oflags; - - /* Map the open mode string to open flags */ - - oflags = lib_mode2oflags(mode); - if (oflags >= 0) - { - ret = fs_fdopen(fd, oflags, NULL); - } - - return ret; -} - -/**************************************************************************** - * Name: fopen - ****************************************************************************/ - -FAR FILE *fopen(FAR const char *path, FAR const char *mode) -{ - FAR FILE *ret = NULL; - int oflags; - int fd; - - /* Map the open mode string to open flags */ - - oflags = lib_mode2oflags(mode); - if (oflags < 0) - { - return NULL; - } - - /* Open the file */ - - fd = open(path, oflags, 0666); - - /* If the open was successful, then fdopen() the fil using the file - * descriptor returned by open. If open failed, then just return the - * NULL stream -- open() has already set the errno. - */ - - if (fd >= 0) - { - ret = fs_fdopen(fd, oflags, NULL); - if (!ret) - { - /* Don't forget to close the file descriptor if any other - * failures are reported by fdopen(). - */ - - (void)close(fd); - } - } - return ret; -} diff --git a/libc/stdio/lib_freopen.c b/libc/stdio/lib_freopen.c new file mode 100644 index 0000000000..f90546067e --- /dev/null +++ b/libc/stdio/lib_freopen.c @@ -0,0 +1,143 @@ +/**************************************************************************** + * libc/stdio/lib_freopen.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include "lib_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: freopen + * + * Description: + * Reuses stream to either open the file specified by path or to change + * its access mode. + * + * If a new path is specified, the function first attempts to close + * any file already associated with stream (third parameter) and + * disassociates it. Then, independently of whether that stream was + * successfuly closed or not, freopen opens the file specified by path + * and associates it with the stream just as fopen would do using the + * specified mode. + * + * If path is a null pointer, the function attempts to change the mode + * of the stream. Although a particular library implementation is allowed + * to restrict the changes permitted, and under which circumstances. + * + * The error indicator and eof indicator are automatically cleared (as if + * clearerr was called). + * + * Input Paramters: + * path - If non-NULL, refers to the name of the file to be opened. + * mode - String describing the new file access mode + * stream - Pointer to the type FILE to be reopened. + * + * Returned Value: + * If the file is successfully reopened, the function returns the pointer + * passed as parameter stream, which can be used to identify the reopened + * stream. Otherwise, a null pointer is returned and the errno variable + * is also set to a system-specific error code on failure. + * + ****************************************************************************/ + +FAR FILE *freopen(FAR const char *path, FAR const char *mode, + FAR FILE *stream) +{ + int oflags; + int ret; + int fd; + + /* Was a file name provided? */ + + if (path != NULL) + { + /* Yes, close the stream */ + + if (stream) + { + (void)fclose(stream); + } + + /* And attempt to reopen the file at the provided path */ + + return fopen(path, mode); + } + + /* Otherwise, we are just changing the mode of the current file. */ + + if (stream) + { + /* Convert the mode string into standard file open mode flags. */ + + oflags = lib_mode2oflags(mode); + if (oflags == 0) + { + return NULL; + } + + /* Get the underlying file descriptor from the stream */ + + fd = fileno(stream); + if (fd < 0) + { + return NULL; + } + + /* Set the new file mode for the file descriptor */ + + ret = fcntl(fd, F_SETFL, oflags); + if (ret < 0) + { + return NULL; + } + + clearerr(stream); + return stream; + } + + set_errno(EINVAL); + return NULL; +}