diff options
Diffstat (limited to 'src/nvim/os/fileio.c')
| -rw-r--r-- | src/nvim/os/fileio.c | 121 | 
1 files changed, 105 insertions, 16 deletions
| diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c index 4b7b53fc7f..ccf35fd57c 100644 --- a/src/nvim/os/fileio.c +++ b/src/nvim/os/fileio.c @@ -1,7 +1,10 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +  /// @file fileio.c  ///  /// Buffered reading/writing to a file. Unlike fileio.c this is not dealing with -/// Neovim stuctures for buffer, with autocommands, etc: just fopen/fread/fwrite +/// Nvim stuctures for buffer, with autocommands, etc: just fopen/fread/fwrite  /// replacement.  #include <assert.h> @@ -23,6 +26,7 @@  #include "nvim/globals.h"  #include "nvim/rbuffer.h"  #include "nvim/macros.h" +#include "nvim/message.h"  #ifdef INCLUDE_GENERATED_DECLARATIONS  # include "os/fileio.c.generated.h" @@ -35,18 +39,18 @@  /// @param[in]  fname  File name to open.  /// @param[in]  flags  Flags, @see FileOpenFlags. Currently reading from and  ///                    writing to the file at once is not supported, so either -///                    FILE_WRITE_ONLY or FILE_READ_ONLY is required. +///                    kFileWriteOnly or kFileReadOnly is required.  /// @param[in]  mode  Permissions for the newly created file (ignored if flags -///                   does not have FILE_CREATE\*). +///                   does not have kFileCreate\*).  /// -/// @return Error code (@see os_strerror()) or 0. +/// @return Error code, or 0 on success. @see os_strerror()  int file_open(FileDescriptor *const ret_fp, const char *const fname,                const int flags, const int mode)    FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT  {    int os_open_flags = 0; -  int fd;    TriState wr = kNone; +  // -V:FLAG:501  #define FLAG(flags, flag, fcntl_flags, wrval, cond) \    do { \      if (flags & flag) { \ @@ -69,14 +73,44 @@ int file_open(FileDescriptor *const ret_fp, const char *const fname,    FLAG(flags, kFileNoSymlink, O_NOFOLLOW, kNone, true);  #endif  #undef FLAG +  // wr is used for kFileReadOnly flag, but on +  // QB:neovim-qb-slave-ubuntu-12-04-64bit it still errors out with +  // `error: variable ‘wr’ set but not used [-Werror=unused-but-set-variable]` +  (void)wr; -  fd = os_open(fname, os_open_flags, mode); +  const int fd = os_open(fname, os_open_flags, mode);    if (fd < 0) {      return fd;    } +  return file_open_fd(ret_fp, fd, flags); +} -  ret_fp->wr = (wr == kTrue); +/// Wrap file descriptor with FileDescriptor structure +/// +/// @warning File descriptor wrapped like this must not be accessed by other +///          means. +/// +/// @param[out]  ret_fp  Address where information needed for reading from or +///                      writing to a file is saved +/// @param[in]  fd  File descriptor to wrap. +/// @param[in]  flags  Flags, @see FileOpenFlags. Currently reading from and +///                    writing to the file at once is not supported, so either +///                    FILE_WRITE_ONLY or FILE_READ_ONLY is required. +/// +/// @return Error code (@see os_strerror()) or 0. Currently always returns 0. +int file_open_fd(FileDescriptor *const ret_fp, const int fd, +                 const int flags) +  FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +{ +  ret_fp->wr = !!(flags & (kFileCreate +                           |kFileCreateOnly +                           |kFileTruncate +                           |kFileAppend +                           |kFileWriteOnly)); +  ret_fp->non_blocking = !!(flags & kFileNonBlocking); +  // Non-blocking writes not supported currently. +  assert(!ret_fp->wr || !ret_fp->non_blocking);    ret_fp->fd = fd;    ret_fp->eof = false;    ret_fp->rv = rbuffer_new(kRWBufferSize); @@ -90,17 +124,16 @@ int file_open(FileDescriptor *const ret_fp, const char *const fname,  /// Like file_open(), but allocate and return ret_fp  /// -/// @param[out]  error  Error code, @see os_strerror(). Is set to zero on -///                     success. +/// @param[out]  error  Error code, or 0 on success. @see os_strerror()  /// @param[in]  fname  File name to open.  /// @param[in]  flags  Flags, @see FileOpenFlags.  /// @param[in]  mode  Permissions for the newly created file (ignored if flags -///                   does not have FILE_CREATE\*). +///                   does not have kFileCreate\*).  ///  /// @return [allocated] Opened file or NULL in case of error.  FileDescriptor *file_open_new(int *const error, const char *const fname,                                const int flags, const int mode) -  FUNC_ATTR_NONNULL_ALL FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT +  FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT  {    FileDescriptor *const fp = xmalloc(sizeof(*fp));    if ((*error = file_open(fp, fname, flags, mode)) != 0) { @@ -110,6 +143,27 @@ FileDescriptor *file_open_new(int *const error, const char *const fname,    return fp;  } +/// Like file_open_fd(), but allocate and return ret_fp +/// +/// @param[out]  error  Error code, or 0 on success. @see os_strerror() +/// @param[in]  fd  File descriptor to wrap. +/// @param[in]  flags  Flags, @see FileOpenFlags. +/// @param[in]  mode  Permissions for the newly created file (ignored if flags +///                   does not have FILE_CREATE\*). +/// +/// @return [allocated] Opened file or NULL in case of error. +FileDescriptor *file_open_fd_new(int *const error, const int fd, +                                 const int flags) +  FUNC_ATTR_NONNULL_ALL FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT +{ +  FileDescriptor *const fp = xmalloc(sizeof(*fp)); +  if ((*error = file_open_fd(fp, fd, flags)) != 0) { +    xfree(fp); +    return NULL; +  } +  return fp; +} +  /// Close file and free its buffer  ///  /// @param[in,out]  fp  File to close. @@ -201,7 +255,8 @@ static void file_rb_write_full_cb(RBuffer *const rv, FileDescriptor *const fp)      return;    }    const size_t read_bytes = rbuffer_read(rv, writebuf, kRWBufferSize); -  const ptrdiff_t wres = os_write(fp->fd, writebuf, read_bytes); +  const ptrdiff_t wres = os_write(fp->fd, writebuf, read_bytes, +                                  fp->non_blocking);    if (wres != (ptrdiff_t)read_bytes) {      if (wres >= 0) {        fp->_error = UV_EIO; @@ -227,6 +282,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,    char *buf = ret_buf;    size_t read_remaining = size;    RBuffer *const rv = fp->rv; +  bool called_read = false;    while (read_remaining) {      const size_t rv_size = rbuffer_size(rv);      if (rv_size > 0) { @@ -234,7 +290,9 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,        buf += rsize;        read_remaining -= rsize;      } -    if (fp->eof) { +    if (fp->eof +        // Allow only at most one os_read[v] call. +        || (called_read && fp->non_blocking)) {        break;      }      if (read_remaining) { @@ -251,7 +309,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,        };        assert(write_count == kRWBufferSize);        const ptrdiff_t r_ret = os_readv(fp->fd, &fp->eof, iov, -                                       ARRAY_SIZE(iov)); +                                       ARRAY_SIZE(iov), fp->non_blocking);        if (r_ret > 0) {          if (r_ret > (ptrdiff_t)read_remaining) {            rbuffer_produced(rv, (size_t)(r_ret - (ptrdiff_t)read_remaining)); @@ -267,7 +325,8 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,        if (read_remaining >= kRWBufferSize) {          // …otherwise leave RBuffer empty and populate only target buffer,          // because filtering information through rbuffer will be more syscalls. -        const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, buf, read_remaining); +        const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, buf, read_remaining, +                                        fp->non_blocking);          if (r_ret >= 0) {            read_remaining -= (size_t)r_ret;            return (ptrdiff_t)(size - read_remaining); @@ -278,7 +337,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,          size_t write_count;          const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof,                                          rbuffer_write_ptr(rv, &write_count), -                                        kRWBufferSize); +                                        kRWBufferSize, fp->non_blocking);          assert(write_count == kRWBufferSize);          if (r_ret > 0) {            rbuffer_produced(rv, (size_t)r_ret); @@ -287,6 +346,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,          }        }  #endif +      called_read = true;      }    }    return (ptrdiff_t)(size - read_remaining); @@ -341,3 +401,32 @@ ptrdiff_t file_skip(FileDescriptor *const fp, const size_t size)    return (ptrdiff_t)read_bytes;  } + +/// Msgpack callback for writing to a file +/// +/// @param  data  File to write to. +/// @param[in]  buf  Data to write. +/// @param[in]  len  Length of the data to write. +/// +/// @return 0 in case of success, -1 in case of error. +int msgpack_file_write(void *data, const char *buf, size_t len) +  FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +{ +  assert(len < PTRDIFF_MAX); +  const ptrdiff_t written_bytes = file_write((FileDescriptor *)data, buf, len); +  if (written_bytes < 0) { +    return msgpack_file_write_error((int)written_bytes); +  } +  return 0; +} + +/// Print error which occurs when failing to write msgpack data +/// +/// @param[in]  error  Error code of the error to print. +/// +/// @return -1 (error return for msgpack_packer callbacks). +int msgpack_file_write_error(const int error) +{ +  emsgf(_("E5420: Failed to write to file: %s"), os_strerror(error)); +  return -1; +} | 
