| /**************************************************************************** |
| * libs/libc/stdio/lib_libfflush.c |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <sys/types.h> |
| #include <stdbool.h> |
| #include <unistd.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| |
| #include <nuttx/fs/fs.h> |
| |
| #include "libc.h" |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: lib_fflush |
| * |
| * Description: |
| * The function lib_fflush() forces a write of all user-space buffered data |
| * for the given output or update stream via the stream's underlying write |
| * function. The open status of the stream is unaffected. |
| * |
| * Input Parameters: |
| * stream - the stream to flush |
| * |
| * Returned Value: |
| * A negated errno value on failure, otherwise the number of bytes remaining |
| * in the buffer. |
| * |
| ****************************************************************************/ |
| |
| ssize_t lib_fflush_unlocked(FAR FILE *stream) |
| { |
| #ifndef CONFIG_STDIO_DISABLE_BUFFERING |
| FAR const char *src; |
| ssize_t bytes_written; |
| ssize_t nbuffer; |
| |
| /* Return EBADF if the file is not opened for writing */ |
| |
| if ((stream->fs_oflags & O_WROK) == 0) |
| { |
| return -EBADF; |
| } |
| |
| /* Check if there is an allocated I/O buffer */ |
| |
| if (stream->fs_bufstart == NULL) |
| { |
| /* No, then there can be nothing remaining in the buffer. */ |
| |
| return 0; |
| } |
| |
| /* Make sure that the buffer holds valid data */ |
| |
| if (stream->fs_bufpos != stream->fs_bufstart) |
| { |
| /* Make sure that the buffer holds buffered write data. We do not |
| * support concurrent read/write buffer usage. |
| */ |
| |
| if (stream->fs_bufread != stream->fs_bufstart) |
| { |
| /* The buffer holds read data... just return zero meaning "no bytes |
| * remaining in the buffer." |
| */ |
| |
| return 0; |
| } |
| |
| /* How many bytes of write data are used in the buffer now */ |
| |
| nbuffer = stream->fs_bufpos - stream->fs_bufstart; |
| |
| /* Try to write that amount */ |
| |
| src = stream->fs_bufstart; |
| do |
| { |
| /* Perform the write */ |
| |
| if (stream->fs_iofunc.write != NULL) |
| { |
| bytes_written = stream->fs_iofunc.write(stream->fs_cookie, |
| src, |
| nbuffer); |
| } |
| else |
| { |
| bytes_written = _NX_WRITE((int)(intptr_t)stream->fs_cookie, |
| src, nbuffer); |
| } |
| |
| if (bytes_written < 0) |
| { |
| /* Write failed. The cause of the failure is in 'errno'. |
| * returned the negated errno value. |
| */ |
| |
| stream->fs_flags |= __FS_FLAG_ERROR; |
| return _NX_GETERRVAL(bytes_written); |
| } |
| |
| /* Handle partial writes. fflush() must either return with |
| * an error condition or with the data successfully flushed |
| * from the buffer. |
| */ |
| |
| src += bytes_written; |
| nbuffer -= bytes_written; |
| } |
| while (nbuffer > 0); |
| |
| /* Reset the buffer position to the beginning of the buffer */ |
| |
| stream->fs_bufpos = stream->fs_bufstart; |
| |
| /* For the case of an incomplete write, nbuffer will be non-zero |
| * It will hold the number of bytes that were not written. |
| * Move the data down in the buffer to handle this (rare) case |
| */ |
| |
| while (nbuffer) |
| { |
| *stream->fs_bufpos++ = *src++; |
| --nbuffer; |
| } |
| } |
| |
| /* Restore normal access to the stream and return the number of bytes |
| * remaining in the buffer. |
| */ |
| |
| return stream->fs_bufpos - stream->fs_bufstart; |
| |
| #else |
| /* Return no bytes remaining in the buffer */ |
| |
| return 0; |
| #endif |
| } |
| |
| ssize_t lib_fflush(FAR FILE *stream) |
| { |
| ssize_t ret; |
| |
| /* Make sure that we have exclusive access to the stream */ |
| |
| flockfile(stream); |
| ret = lib_fflush_unlocked(stream); |
| funlockfile(stream); |
| return ret; |
| } |