From 2dd154457ceb4bbc122b9e1ad34bf693ee3dd510 Mon Sep 17 00:00:00 2001 From: ZyX Date: Thu, 23 Jun 2016 21:17:24 +0300 Subject: file: Move src/nvim/file.* to src/nvim/os/fileio.* --- src/nvim/file.c | 318 --------------------------------------------------- src/nvim/file.h | 72 ------------ src/nvim/os/fileio.c | 318 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/nvim/os/fileio.h | 72 ++++++++++++ src/nvim/shada.c | 2 +- 5 files changed, 391 insertions(+), 391 deletions(-) delete mode 100644 src/nvim/file.c delete mode 100644 src/nvim/file.h create mode 100644 src/nvim/os/fileio.c create mode 100644 src/nvim/os/fileio.h (limited to 'src') diff --git a/src/nvim/file.c b/src/nvim/file.c deleted file mode 100644 index 2730e5b5f9..0000000000 --- a/src/nvim/file.c +++ /dev/null @@ -1,318 +0,0 @@ -/// @file file.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 -/// replacement. - -#include -#include -#include -#include -#include - -#include "auto/config.h" - -#ifdef HAVE_SYS_UIO_H -# include -#endif - -#include - -#include "nvim/file.h" -#include "nvim/memory.h" -#include "nvim/os/os.h" -#include "nvim/globals.h" -#include "nvim/rbuffer.h" -#include "nvim/macros.h" - -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "file.c.generated.h" -#endif - -/// Open file -/// -/// @param[out] ret_fp Address where information needed for reading from or -/// writing to a file is saved -/// @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. -/// @param[in] mode Permissions for the newly created file (ignored if flags -/// does not have FILE_CREATE\*). -/// -/// @return Error code (@see os_strerror()) or 0. -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; -#define FLAG(flags, flag, fcntl_flags, wrval, cond) \ - do { \ - if (flags & flag) { \ - os_open_flags |= fcntl_flags; \ - assert(cond); \ - if (wrval != kNone) { \ - wr = wrval; \ - } \ - } \ - } while (0) - FLAG(flags, kFileWriteOnly, O_WRONLY, kTrue, true); - FLAG(flags, kFileCreateOnly, O_CREAT|O_EXCL|O_WRONLY, kTrue, true); - FLAG(flags, kFileCreate, O_CREAT|O_WRONLY, kTrue, !(flags & kFileCreateOnly)); - FLAG(flags, kFileTruncate, O_TRUNC|O_WRONLY, kTrue, - !(flags & kFileCreateOnly)); - FLAG(flags, kFileReadOnly, O_RDONLY, kFalse, wr != kTrue); -#ifdef O_NOFOLLOW - FLAG(flags, kFileNoSymlink, O_NOFOLLOW, kNone, true); -#endif -#undef FLAG - - fd = os_open(fname, os_open_flags, mode); - - if (fd < 0) { - return fd; - } - - ret_fp->wr = (wr == kTrue); - ret_fp->fd = fd; - ret_fp->eof = false; - ret_fp->rv = rbuffer_new(kRWBufferSize); - ret_fp->_error = 0; - if (ret_fp->wr) { - ret_fp->rv->data = ret_fp; - ret_fp->rv->full_cb = (rbuffer_callback)&file_rb_write_full_cb; - } - return 0; -} - -/// Like file_open(), but allocate and return ret_fp -/// -/// @param[out] error Error code, @see os_strerror(). Is set to zero on -/// success. -/// @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\*). -/// -/// @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 -{ - FileDescriptor *const fp = xmalloc(sizeof(*fp)); - if ((*error = file_open(fp, fname, flags, mode)) != 0) { - xfree(fp); - return NULL; - } - return fp; -} - -/// Close file and free its buffer -/// -/// @param[in,out] fp File to close. -/// -/// @return 0 or error code. -int file_close(FileDescriptor *const fp) FUNC_ATTR_NONNULL_ALL -{ - const int error = file_fsync(fp); - const int error2 = os_close(fp->fd); - rbuffer_free(fp->rv); - if (error2 != 0) { - return error2; - } - return error; -} - -/// Close and free file obtained using file_open_new() -/// -/// @param[in,out] fp File to close. -/// -/// @return 0 or error code. -int file_free(FileDescriptor *const fp) FUNC_ATTR_NONNULL_ALL -{ - const int ret = file_close(fp); - xfree(fp); - return ret; -} - -/// Flush file modifications to disk -/// -/// @param[in,out] fp File to work with. -/// -/// @return 0 or error code. -int file_fsync(FileDescriptor *const fp) - FUNC_ATTR_NONNULL_ALL -{ - if (!fp->wr) { - return 0; - } - file_rb_write_full_cb(fp->rv, fp); - if (fp->_error != 0) { - const int error = fp->_error; - fp->_error = 0; - return error; - } - return os_fsync(fp->fd); -} - -/// Buffer used for writing -/// -/// Like IObuff, but allows file_\* callers not to care about spoiling it. -static char writebuf[kRWBufferSize]; - -/// Function run when RBuffer is full when writing to a file -/// -/// Actually does writing to the file, may also be invoked directly. -/// -/// @param[in,out] rv RBuffer instance used. -/// @param[in,out] fp File to work with. -static void file_rb_write_full_cb(RBuffer *const rv, FileDescriptor *const fp) - FUNC_ATTR_NONNULL_ALL -{ - assert(fp->wr); - assert(rv->data == (void *)fp); - if (rbuffer_size(rv) == 0) { - return; - } - const size_t read_bytes = rbuffer_read(rv, writebuf, kRWBufferSize); - const ptrdiff_t wres = os_write(fp->fd, writebuf, read_bytes); - if (wres != (ptrdiff_t)read_bytes) { - if (wres >= 0) { - fp->_error = UV_EIO; - } else { - fp->_error = (int)wres; - } - } -} - -/// Read from file -/// -/// @param[in,out] fp File to work with. -/// @param[out] ret_buf Buffer to read to. Must not be NULL. -/// @param[in] size Number of bytes to read. Buffer must have at least ret_buf -/// bytes. -/// -/// @return error_code (< 0) or number of bytes read. -ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf, - const size_t size) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - assert(!fp->wr); - char *buf = ret_buf; - size_t read_remaining = size; - RBuffer *const rv = fp->rv; - while (read_remaining) { - const size_t rv_size = rbuffer_size(rv); - if (rv_size > 0) { - const size_t rsize = rbuffer_read(rv, buf, MIN(rv_size, read_remaining)); - buf += rsize; - read_remaining -= rsize; - } - if (fp->eof) { - break; - } - if (read_remaining) { - assert(rbuffer_size(rv) == 0); - rbuffer_reset(rv); - if (read_remaining >= kRWBufferSize) { -#ifdef HAVE_READV - // If there is readv() syscall, then take an opportunity to populate - // both target buffer and RBuffer at once, … - size_t write_count; - struct iovec iov[] = { - { .iov_base = buf, .iov_len = read_remaining }, - { .iov_base = rbuffer_write_ptr(rv, &write_count), - .iov_len = kRWBufferSize }, - }; - assert(write_count == kRWBufferSize); - const ptrdiff_t r_ret = os_readv(fp->fd, &fp->eof, iov, - ARRAY_SIZE(iov)); - if (r_ret > 0) { - if (r_ret > (ptrdiff_t)read_remaining) { - read_remaining = 0; - rbuffer_produced(rv, (size_t)(r_ret - (ptrdiff_t)read_remaining)); - } else { - read_remaining -= (size_t)r_ret; - } - } else if (r_ret < 0) { - return r_ret; - } -#else - // …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); - if (r_ret >= 0) { - read_remaining -= (size_t)r_ret; - return (ptrdiff_t)(size - read_remaining); - } else if (r_ret < 0) { - return r_ret; - } -#endif - } else { - size_t write_count; - const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, - rbuffer_write_ptr(rv, &write_count), - kRWBufferSize); - assert(write_count == kRWBufferSize); - if (r_ret > 0) { - rbuffer_produced(rv, (size_t)r_ret); - } else if (r_ret < 0) { - return r_ret; - } - } - } - } - return (ptrdiff_t)(size - read_remaining); -} - -/// Write to a file -/// -/// @param[in] fd File descriptor to write to. -/// @param[in] buf Data to write. May be NULL if size is zero. -/// @param[in] size Amount of bytes to write. -/// -/// @return Number of bytes written or libuv error code (< 0). -ptrdiff_t file_write(FileDescriptor *const fp, const char *const buf, - const size_t size) - FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) -{ - assert(fp->wr); - const size_t written = rbuffer_write(fp->rv, buf, size); - if (fp->_error != 0) { - const int error = fp->_error; - fp->_error = 0; - return error; - } else if (written != size) { - return UV_EIO; - } - return (ptrdiff_t)written; -} - -/// Buffer used for skipping. Its contents is undefined and should never be -/// used. -static char skipbuf[kRWBufferSize]; - -/// Skip some bytes -/// -/// This is like `fseek(fp, size, SEEK_CUR)`, but actual implementation simply -/// reads to a buffer and discards the result. -ptrdiff_t file_skip(FileDescriptor *const fp, const size_t size) - FUNC_ATTR_NONNULL_ALL -{ - assert(!fp->wr); - size_t read_bytes = 0; - do { - const ptrdiff_t new_read_bytes = file_read( - fp, skipbuf, MIN(size - read_bytes, sizeof(skipbuf))); - if (new_read_bytes < 0) { - return new_read_bytes; - } else if (new_read_bytes == 0) { - break; - } - read_bytes += (size_t)new_read_bytes; - } while (read_bytes < size && !file_eof(fp)); - - return (ptrdiff_t)read_bytes; -} diff --git a/src/nvim/file.h b/src/nvim/file.h deleted file mode 100644 index 2ba415d2b9..0000000000 --- a/src/nvim/file.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef NVIM_FILE_H -#define NVIM_FILE_H - -#include -#include - -#include "nvim/func_attr.h" -#include "nvim/rbuffer.h" - -/// Structure used to read from/write to file -typedef struct { - int fd; ///< File descriptor. - int _error; ///< Error code for use with RBuffer callbacks or zero. - RBuffer *rv; ///< Read or write buffer. - bool wr; ///< True if file is in write mode. - bool eof; ///< True if end of file was encountered. -} FileDescriptor; - -/// file_open() flags -typedef enum { - kFileReadOnly = 1, ///< Open file read-only. Default. - kFileCreate = 2, ///< Create file if it does not exist yet. - ///< Implies kFileWriteOnly. - kFileWriteOnly = 4, ///< Open file for writing only. - ///< Cannot be used with kFileReadOnly. - kFileNoSymlink = 8, ///< Do not allow symbolic links. - kFileCreateOnly = 16, ///< Only create the file, failing if it already - ///< exists. Implies kFileWriteOnly. Cannot be used - ///< with kFileCreate. - kFileTruncate = 32, ///< Truncate the file if it exists. - ///< Implies kFileWriteOnly. Cannot be used with - ///< kFileCreateOnly. -} FileOpenFlags; - -static inline bool file_eof(const FileDescriptor *const fp) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL; - -/// Check whether end of file was encountered -/// -/// @param[in] fp File to check. -/// -/// @return true if it was, false if it was not or read operation was never -/// performed. -static inline bool file_eof(const FileDescriptor *const fp) -{ - return fp->eof && rbuffer_size(fp->rv) == 0; -} - -static inline int file_fd(const FileDescriptor *const fp) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL; - -/// Return the file descriptor associated with the FileDescriptor structure -/// -/// @param[in] fp File to check. -/// -/// @return File descriptor. -static inline int file_fd(const FileDescriptor *const fp) -{ - return fp->fd; -} - -enum { - /// Read or write buffer size - /// - /// Currently equal to (IOSIZE - 1), but they do not need to be connected. - kRWBufferSize = 1024 -}; - -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "file.h.generated.h" -#endif -#endif // NVIM_FILE_H diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c new file mode 100644 index 0000000000..6abcceb485 --- /dev/null +++ b/src/nvim/os/fileio.c @@ -0,0 +1,318 @@ +/// @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 +/// replacement. + +#include +#include +#include +#include +#include + +#include "auto/config.h" + +#ifdef HAVE_SYS_UIO_H +# include +#endif + +#include + +#include "nvim/os/fileio.h" +#include "nvim/memory.h" +#include "nvim/os/os.h" +#include "nvim/globals.h" +#include "nvim/rbuffer.h" +#include "nvim/macros.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "os/fileio.c.generated.h" +#endif + +/// Open file +/// +/// @param[out] ret_fp Address where information needed for reading from or +/// writing to a file is saved +/// @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. +/// @param[in] mode Permissions for the newly created file (ignored if flags +/// does not have FILE_CREATE\*). +/// +/// @return Error code (@see os_strerror()) or 0. +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; +#define FLAG(flags, flag, fcntl_flags, wrval, cond) \ + do { \ + if (flags & flag) { \ + os_open_flags |= fcntl_flags; \ + assert(cond); \ + if (wrval != kNone) { \ + wr = wrval; \ + } \ + } \ + } while (0) + FLAG(flags, kFileWriteOnly, O_WRONLY, kTrue, true); + FLAG(flags, kFileCreateOnly, O_CREAT|O_EXCL|O_WRONLY, kTrue, true); + FLAG(flags, kFileCreate, O_CREAT|O_WRONLY, kTrue, !(flags & kFileCreateOnly)); + FLAG(flags, kFileTruncate, O_TRUNC|O_WRONLY, kTrue, + !(flags & kFileCreateOnly)); + FLAG(flags, kFileReadOnly, O_RDONLY, kFalse, wr != kTrue); +#ifdef O_NOFOLLOW + FLAG(flags, kFileNoSymlink, O_NOFOLLOW, kNone, true); +#endif +#undef FLAG + + fd = os_open(fname, os_open_flags, mode); + + if (fd < 0) { + return fd; + } + + ret_fp->wr = (wr == kTrue); + ret_fp->fd = fd; + ret_fp->eof = false; + ret_fp->rv = rbuffer_new(kRWBufferSize); + ret_fp->_error = 0; + if (ret_fp->wr) { + ret_fp->rv->data = ret_fp; + ret_fp->rv->full_cb = (rbuffer_callback)&file_rb_write_full_cb; + } + return 0; +} + +/// Like file_open(), but allocate and return ret_fp +/// +/// @param[out] error Error code, @see os_strerror(). Is set to zero on +/// success. +/// @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\*). +/// +/// @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 +{ + FileDescriptor *const fp = xmalloc(sizeof(*fp)); + if ((*error = file_open(fp, fname, flags, mode)) != 0) { + xfree(fp); + return NULL; + } + return fp; +} + +/// Close file and free its buffer +/// +/// @param[in,out] fp File to close. +/// +/// @return 0 or error code. +int file_close(FileDescriptor *const fp) FUNC_ATTR_NONNULL_ALL +{ + const int error = file_fsync(fp); + const int error2 = os_close(fp->fd); + rbuffer_free(fp->rv); + if (error2 != 0) { + return error2; + } + return error; +} + +/// Close and free file obtained using file_open_new() +/// +/// @param[in,out] fp File to close. +/// +/// @return 0 or error code. +int file_free(FileDescriptor *const fp) FUNC_ATTR_NONNULL_ALL +{ + const int ret = file_close(fp); + xfree(fp); + return ret; +} + +/// Flush file modifications to disk +/// +/// @param[in,out] fp File to work with. +/// +/// @return 0 or error code. +int file_fsync(FileDescriptor *const fp) + FUNC_ATTR_NONNULL_ALL +{ + if (!fp->wr) { + return 0; + } + file_rb_write_full_cb(fp->rv, fp); + if (fp->_error != 0) { + const int error = fp->_error; + fp->_error = 0; + return error; + } + return os_fsync(fp->fd); +} + +/// Buffer used for writing +/// +/// Like IObuff, but allows file_\* callers not to care about spoiling it. +static char writebuf[kRWBufferSize]; + +/// Function run when RBuffer is full when writing to a file +/// +/// Actually does writing to the file, may also be invoked directly. +/// +/// @param[in,out] rv RBuffer instance used. +/// @param[in,out] fp File to work with. +static void file_rb_write_full_cb(RBuffer *const rv, FileDescriptor *const fp) + FUNC_ATTR_NONNULL_ALL +{ + assert(fp->wr); + assert(rv->data == (void *)fp); + if (rbuffer_size(rv) == 0) { + return; + } + const size_t read_bytes = rbuffer_read(rv, writebuf, kRWBufferSize); + const ptrdiff_t wres = os_write(fp->fd, writebuf, read_bytes); + if (wres != (ptrdiff_t)read_bytes) { + if (wres >= 0) { + fp->_error = UV_EIO; + } else { + fp->_error = (int)wres; + } + } +} + +/// Read from file +/// +/// @param[in,out] fp File to work with. +/// @param[out] ret_buf Buffer to read to. Must not be NULL. +/// @param[in] size Number of bytes to read. Buffer must have at least ret_buf +/// bytes. +/// +/// @return error_code (< 0) or number of bytes read. +ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf, + const size_t size) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +{ + assert(!fp->wr); + char *buf = ret_buf; + size_t read_remaining = size; + RBuffer *const rv = fp->rv; + while (read_remaining) { + const size_t rv_size = rbuffer_size(rv); + if (rv_size > 0) { + const size_t rsize = rbuffer_read(rv, buf, MIN(rv_size, read_remaining)); + buf += rsize; + read_remaining -= rsize; + } + if (fp->eof) { + break; + } + if (read_remaining) { + assert(rbuffer_size(rv) == 0); + rbuffer_reset(rv); + if (read_remaining >= kRWBufferSize) { +#ifdef HAVE_READV + // If there is readv() syscall, then take an opportunity to populate + // both target buffer and RBuffer at once, … + size_t write_count; + struct iovec iov[] = { + { .iov_base = buf, .iov_len = read_remaining }, + { .iov_base = rbuffer_write_ptr(rv, &write_count), + .iov_len = kRWBufferSize }, + }; + assert(write_count == kRWBufferSize); + const ptrdiff_t r_ret = os_readv(fp->fd, &fp->eof, iov, + ARRAY_SIZE(iov)); + if (r_ret > 0) { + if (r_ret > (ptrdiff_t)read_remaining) { + read_remaining = 0; + rbuffer_produced(rv, (size_t)(r_ret - (ptrdiff_t)read_remaining)); + } else { + read_remaining -= (size_t)r_ret; + } + } else if (r_ret < 0) { + return r_ret; + } +#else + // …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); + if (r_ret >= 0) { + read_remaining -= (size_t)r_ret; + return (ptrdiff_t)(size - read_remaining); + } else if (r_ret < 0) { + return r_ret; + } +#endif + } else { + size_t write_count; + const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, + rbuffer_write_ptr(rv, &write_count), + kRWBufferSize); + assert(write_count == kRWBufferSize); + if (r_ret > 0) { + rbuffer_produced(rv, (size_t)r_ret); + } else if (r_ret < 0) { + return r_ret; + } + } + } + } + return (ptrdiff_t)(size - read_remaining); +} + +/// Write to a file +/// +/// @param[in] fd File descriptor to write to. +/// @param[in] buf Data to write. May be NULL if size is zero. +/// @param[in] size Amount of bytes to write. +/// +/// @return Number of bytes written or libuv error code (< 0). +ptrdiff_t file_write(FileDescriptor *const fp, const char *const buf, + const size_t size) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) +{ + assert(fp->wr); + const size_t written = rbuffer_write(fp->rv, buf, size); + if (fp->_error != 0) { + const int error = fp->_error; + fp->_error = 0; + return error; + } else if (written != size) { + return UV_EIO; + } + return (ptrdiff_t)written; +} + +/// Buffer used for skipping. Its contents is undefined and should never be +/// used. +static char skipbuf[kRWBufferSize]; + +/// Skip some bytes +/// +/// This is like `fseek(fp, size, SEEK_CUR)`, but actual implementation simply +/// reads to a buffer and discards the result. +ptrdiff_t file_skip(FileDescriptor *const fp, const size_t size) + FUNC_ATTR_NONNULL_ALL +{ + assert(!fp->wr); + size_t read_bytes = 0; + do { + const ptrdiff_t new_read_bytes = file_read( + fp, skipbuf, MIN(size - read_bytes, sizeof(skipbuf))); + if (new_read_bytes < 0) { + return new_read_bytes; + } else if (new_read_bytes == 0) { + break; + } + read_bytes += (size_t)new_read_bytes; + } while (read_bytes < size && !file_eof(fp)); + + return (ptrdiff_t)read_bytes; +} diff --git a/src/nvim/os/fileio.h b/src/nvim/os/fileio.h new file mode 100644 index 0000000000..2cffd5c851 --- /dev/null +++ b/src/nvim/os/fileio.h @@ -0,0 +1,72 @@ +#ifndef NVIM_OS_FILEIO_H +#define NVIM_OS_FILEIO_H + +#include +#include + +#include "nvim/func_attr.h" +#include "nvim/rbuffer.h" + +/// Structure used to read from/write to file +typedef struct { + int fd; ///< File descriptor. + int _error; ///< Error code for use with RBuffer callbacks or zero. + RBuffer *rv; ///< Read or write buffer. + bool wr; ///< True if file is in write mode. + bool eof; ///< True if end of file was encountered. +} FileDescriptor; + +/// file_open() flags +typedef enum { + kFileReadOnly = 1, ///< Open file read-only. Default. + kFileCreate = 2, ///< Create file if it does not exist yet. + ///< Implies kFileWriteOnly. + kFileWriteOnly = 4, ///< Open file for writing only. + ///< Cannot be used with kFileReadOnly. + kFileNoSymlink = 8, ///< Do not allow symbolic links. + kFileCreateOnly = 16, ///< Only create the file, failing if it already + ///< exists. Implies kFileWriteOnly. Cannot be used + ///< with kFileCreate. + kFileTruncate = 32, ///< Truncate the file if it exists. + ///< Implies kFileWriteOnly. Cannot be used with + ///< kFileCreateOnly. +} FileOpenFlags; + +static inline bool file_eof(const FileDescriptor *const fp) + REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL; + +/// Check whether end of file was encountered +/// +/// @param[in] fp File to check. +/// +/// @return true if it was, false if it was not or read operation was never +/// performed. +static inline bool file_eof(const FileDescriptor *const fp) +{ + return fp->eof && rbuffer_size(fp->rv) == 0; +} + +static inline int file_fd(const FileDescriptor *const fp) + REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL; + +/// Return the file descriptor associated with the FileDescriptor structure +/// +/// @param[in] fp File to check. +/// +/// @return File descriptor. +static inline int file_fd(const FileDescriptor *const fp) +{ + return fp->fd; +} + +enum { + /// Read or write buffer size + /// + /// Currently equal to (IOSIZE - 1), but they do not need to be connected. + kRWBufferSize = 1024 +}; + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "os/fileio.h.generated.h" +#endif +#endif // NVIM_OS_FILEIO_H diff --git a/src/nvim/shada.c b/src/nvim/shada.c index a833b958b9..5047ef9647 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -35,7 +35,7 @@ #include "nvim/version.h" #include "nvim/path.h" #include "nvim/fileio.h" -#include "nvim/file.h" +#include "nvim/os/fileio.h" #include "nvim/strings.h" #include "nvim/quickfix.h" #include "nvim/eval/encode.h" -- cgit