mirror of
https://github.com/neovim/neovim.git
synced 2024-12-20 03:05:11 -07:00
refactor(shada): remove ShaDaReadDef secondary wrapper
`FileDescriptor` is already a wrapper around an fd and a buffer. By allowing to just use the buffer without an fd, it can already handle in-memory reads.
This commit is contained in:
parent
c272f30b1f
commit
b386334cdb
@ -126,6 +126,7 @@ int file_open_fd(FileDescriptor *const ret_fp, const int fd, const int flags)
|
|||||||
ret_fp->rv->data = ret_fp;
|
ret_fp->rv->data = ret_fp;
|
||||||
ret_fp->rv->full_cb = (rbuffer_callback)&file_rb_write_full_cb;
|
ret_fp->rv->full_cb = (rbuffer_callback)&file_rb_write_full_cb;
|
||||||
}
|
}
|
||||||
|
ret_fp->bytes_read = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,6 +141,18 @@ int file_open_stdin(FileDescriptor *fp)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// opens buffer for reading
|
||||||
|
void file_open_buffer(FileDescriptor *ret_fp, char *data, size_t len)
|
||||||
|
{
|
||||||
|
ret_fp->wr = false;
|
||||||
|
ret_fp->non_blocking = false;
|
||||||
|
ret_fp->fd = -1;
|
||||||
|
ret_fp->eof = true;
|
||||||
|
ret_fp->rv = rbuffer_new_wrap_buf(data, len);
|
||||||
|
ret_fp->_error = 0;
|
||||||
|
ret_fp->bytes_read = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/// Close file and free its buffer
|
/// Close file and free its buffer
|
||||||
///
|
///
|
||||||
/// @param[in,out] fp File to close.
|
/// @param[in,out] fp File to close.
|
||||||
@ -149,6 +162,11 @@ int file_open_stdin(FileDescriptor *fp)
|
|||||||
int file_close(FileDescriptor *const fp, const bool do_fsync)
|
int file_close(FileDescriptor *const fp, const bool do_fsync)
|
||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
|
if (fp->fd < 0) {
|
||||||
|
rbuffer_free(fp->rv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const int flush_error = (do_fsync ? file_fsync(fp) : file_flush(fp));
|
const int flush_error = (do_fsync ? file_fsync(fp) : file_flush(fp));
|
||||||
const int close_error = os_close(fp->fd);
|
const int close_error = os_close(fp->fd);
|
||||||
rbuffer_free(fp->rv);
|
rbuffer_free(fp->rv);
|
||||||
@ -294,6 +312,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf, const size_t
|
|||||||
fp->non_blocking);
|
fp->non_blocking);
|
||||||
if (r_ret >= 0) {
|
if (r_ret >= 0) {
|
||||||
read_remaining -= (size_t)r_ret;
|
read_remaining -= (size_t)r_ret;
|
||||||
|
fp->bytes_read += (size - read_remaining);
|
||||||
return (ptrdiff_t)(size - read_remaining);
|
return (ptrdiff_t)(size - read_remaining);
|
||||||
} else if (r_ret < 0) {
|
} else if (r_ret < 0) {
|
||||||
return r_ret;
|
return r_ret;
|
||||||
@ -314,6 +333,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf, const size_t
|
|||||||
called_read = true;
|
called_read = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fp->bytes_read += (size - read_remaining);
|
||||||
return (ptrdiff_t)(size - read_remaining);
|
return (ptrdiff_t)(size - read_remaining);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "nvim/func_attr.h"
|
#include "nvim/func_attr.h"
|
||||||
#include "nvim/rbuffer_defs.h"
|
#include "nvim/rbuffer_defs.h"
|
||||||
@ -13,6 +14,7 @@ typedef struct {
|
|||||||
bool wr; ///< True if file is in write mode.
|
bool wr; ///< True if file is in write mode.
|
||||||
bool eof; ///< True if end of file was encountered.
|
bool eof; ///< True if end of file was encountered.
|
||||||
bool non_blocking; ///< True if EAGAIN should not restart syscalls.
|
bool non_blocking; ///< True if EAGAIN should not restart syscalls.
|
||||||
|
uint64_t bytes_read; ///< total bytes read so far
|
||||||
} FileDescriptor;
|
} FileDescriptor;
|
||||||
|
|
||||||
static inline bool file_eof(const FileDescriptor *fp)
|
static inline bool file_eof(const FileDescriptor *fp)
|
||||||
|
@ -29,6 +29,23 @@ RBuffer *rbuffer_new(size_t capacity)
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new `RBuffer` instance for reading from a buffer.
|
||||||
|
///
|
||||||
|
/// Must not be used with any write function like rbuffer_write_ptr or rbuffer_produced!
|
||||||
|
RBuffer *rbuffer_new_wrap_buf(char *data, size_t len)
|
||||||
|
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
|
||||||
|
{
|
||||||
|
RBuffer *rv = xcalloc(1, sizeof(RBuffer));
|
||||||
|
rv->full_cb = rv->nonfull_cb = NULL;
|
||||||
|
rv->data = NULL;
|
||||||
|
rv->size = len;
|
||||||
|
rv->read_ptr = data;
|
||||||
|
rv->write_ptr = data + len;
|
||||||
|
rv->end_ptr = NULL;
|
||||||
|
rv->temp = NULL;
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
void rbuffer_free(RBuffer *buf) FUNC_ATTR_NONNULL_ALL
|
void rbuffer_free(RBuffer *buf) FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
xfree(buf->temp);
|
xfree(buf->temp);
|
||||||
@ -129,7 +146,7 @@ void rbuffer_consumed(RBuffer *buf, size_t count)
|
|||||||
assert(count <= buf->size);
|
assert(count <= buf->size);
|
||||||
|
|
||||||
buf->read_ptr += count;
|
buf->read_ptr += count;
|
||||||
if (buf->read_ptr >= buf->end_ptr) {
|
if (buf->end_ptr && buf->read_ptr >= buf->end_ptr) {
|
||||||
buf->read_ptr -= rbuffer_capacity(buf);
|
buf->read_ptr -= rbuffer_capacity(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
290
src/nvim/shada.c
290
src/nvim/shada.c
@ -356,35 +356,6 @@ typedef struct {
|
|||||||
PMap(cstr_t) file_marks; ///< All file marks.
|
PMap(cstr_t) file_marks; ///< All file marks.
|
||||||
} WriteMergerState;
|
} WriteMergerState;
|
||||||
|
|
||||||
typedef struct sd_read_def ShaDaReadDef;
|
|
||||||
|
|
||||||
/// Function used to close files defined by ShaDaReadDef
|
|
||||||
typedef void (*ShaDaReadCloser)(ShaDaReadDef *const sd_reader)
|
|
||||||
REAL_FATTR_NONNULL_ALL;
|
|
||||||
|
|
||||||
/// Function used to read ShaDa files
|
|
||||||
typedef ptrdiff_t (*ShaDaFileReader)(ShaDaReadDef *const sd_reader,
|
|
||||||
void *const dest,
|
|
||||||
const size_t size)
|
|
||||||
REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT;
|
|
||||||
|
|
||||||
/// Function used to skip in ShaDa files
|
|
||||||
typedef int (*ShaDaFileSkipper)(ShaDaReadDef *const sd_reader,
|
|
||||||
const size_t offset)
|
|
||||||
REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT;
|
|
||||||
|
|
||||||
/// Structure containing necessary pointers for reading ShaDa files
|
|
||||||
struct sd_read_def {
|
|
||||||
ShaDaFileReader read; ///< Reader function.
|
|
||||||
ShaDaReadCloser close; ///< Close function.
|
|
||||||
ShaDaFileSkipper skip; ///< Function used to skip some bytes.
|
|
||||||
void *cookie; ///< Data describing object read from.
|
|
||||||
bool eof; ///< True if reader reached end of file.
|
|
||||||
const char *error; ///< Error message in case of error.
|
|
||||||
uintmax_t fpos; ///< Current position (amount of bytes read since
|
|
||||||
///< reader structure initialization). May overflow.
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "shada.c.generated.h"
|
# include "shada.c.generated.h"
|
||||||
#endif
|
#endif
|
||||||
@ -587,70 +558,6 @@ static inline void hmll_dealloc(HMLList *const hmll)
|
|||||||
xfree(hmll->entries);
|
xfree(hmll->entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapper for reading from file descriptors
|
|
||||||
///
|
|
||||||
/// @return -1 or number of bytes read.
|
|
||||||
static ptrdiff_t read_file(ShaDaReadDef *const sd_reader, void *const dest, const size_t size)
|
|
||||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
|
||||||
{
|
|
||||||
const ptrdiff_t ret = file_read(sd_reader->cookie, dest, size);
|
|
||||||
sd_reader->eof = file_eof(sd_reader->cookie);
|
|
||||||
if (ret < 0) {
|
|
||||||
sd_reader->error = os_strerror((int)ret);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
sd_reader->fpos += (size_t)ret;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read one character
|
|
||||||
static int read_char(ShaDaReadDef *const sd_reader)
|
|
||||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
|
||||||
{
|
|
||||||
uint8_t ret;
|
|
||||||
ptrdiff_t read_bytes = sd_reader->read(sd_reader, &ret, 1);
|
|
||||||
if (read_bytes != 1) {
|
|
||||||
return EOF;
|
|
||||||
}
|
|
||||||
return (int)ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wrapper for closing file descriptors opened for reading
|
|
||||||
static void close_sd_reader(ShaDaReadDef *const sd_reader)
|
|
||||||
FUNC_ATTR_NONNULL_ALL
|
|
||||||
{
|
|
||||||
close_file(sd_reader->cookie);
|
|
||||||
xfree(sd_reader->cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wrapper for read that reads to IObuff and ignores bytes read
|
|
||||||
///
|
|
||||||
/// Used for skipping.
|
|
||||||
///
|
|
||||||
/// @param[in,out] sd_reader File read.
|
|
||||||
/// @param[in] offset Amount of bytes to skip.
|
|
||||||
///
|
|
||||||
/// @return FAIL in case of failure, OK in case of success. May set
|
|
||||||
/// sd_reader->eof or sd_reader->error.
|
|
||||||
static int sd_reader_skip_read(ShaDaReadDef *const sd_reader, const size_t offset)
|
|
||||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
|
||||||
{
|
|
||||||
const ptrdiff_t skip_bytes = file_skip(sd_reader->cookie, offset);
|
|
||||||
if (skip_bytes < 0) {
|
|
||||||
sd_reader->error = os_strerror((int)skip_bytes);
|
|
||||||
return FAIL;
|
|
||||||
} else if (skip_bytes != (ptrdiff_t)offset) {
|
|
||||||
assert(skip_bytes < (ptrdiff_t)offset);
|
|
||||||
sd_reader->eof = file_eof(sd_reader->cookie);
|
|
||||||
if (!sd_reader->eof) {
|
|
||||||
sd_reader->error = _("too few bytes read");
|
|
||||||
}
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
sd_reader->fpos += (size_t)skip_bytes;
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wrapper for read that can be used when lseek cannot be used
|
/// Wrapper for read that can be used when lseek cannot be used
|
||||||
///
|
///
|
||||||
/// E.g. when trying to read from a pipe.
|
/// E.g. when trying to read from a pipe.
|
||||||
@ -660,55 +567,30 @@ static int sd_reader_skip_read(ShaDaReadDef *const sd_reader, const size_t offse
|
|||||||
///
|
///
|
||||||
/// @return kSDReadStatusReadError, kSDReadStatusNotShaDa or
|
/// @return kSDReadStatusReadError, kSDReadStatusNotShaDa or
|
||||||
/// kSDReadStatusSuccess.
|
/// kSDReadStatusSuccess.
|
||||||
static ShaDaReadResult sd_reader_skip(ShaDaReadDef *const sd_reader, const size_t offset)
|
static ShaDaReadResult sd_reader_skip(FileDescriptor *const sd_reader, const size_t offset)
|
||||||
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
if (sd_reader->skip(sd_reader, offset) != OK) {
|
const ptrdiff_t skip_bytes = file_skip(sd_reader, offset);
|
||||||
if (sd_reader->error != NULL) {
|
if (skip_bytes < 0) {
|
||||||
semsg(_(SERR "System error while skipping in ShaDa file: %s"),
|
semsg(_(SERR "System error while skipping in ShaDa file: %s"),
|
||||||
sd_reader->error);
|
os_strerror((int)skip_bytes));
|
||||||
return kSDReadStatusReadError;
|
return kSDReadStatusReadError;
|
||||||
} else if (sd_reader->eof) {
|
} else if (skip_bytes != (ptrdiff_t)offset) {
|
||||||
|
assert(skip_bytes < (ptrdiff_t)offset);
|
||||||
|
if (file_eof(sd_reader)) {
|
||||||
semsg(_(RCERR "Error while reading ShaDa file: "
|
semsg(_(RCERR "Error while reading ShaDa file: "
|
||||||
"last entry specified that it occupies %" PRIu64 " bytes, "
|
"last entry specified that it occupies %" PRIu64 " bytes, "
|
||||||
"but file ended earlier"),
|
"but file ended earlier"),
|
||||||
(uint64_t)offset);
|
(uint64_t)offset);
|
||||||
|
} else {
|
||||||
|
semsg(_(SERR "System error while skipping in ShaDa file: %s"),
|
||||||
|
_("too few bytes read"));
|
||||||
|
}
|
||||||
return kSDReadStatusNotShaDa;
|
return kSDReadStatusNotShaDa;
|
||||||
}
|
}
|
||||||
abort();
|
|
||||||
}
|
|
||||||
return kSDReadStatusSuccess;
|
return kSDReadStatusSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Open ShaDa file for reading
|
|
||||||
///
|
|
||||||
/// @param[in] fname File name to open.
|
|
||||||
/// @param[out] sd_reader Location where reader structure will be saved.
|
|
||||||
///
|
|
||||||
/// @return libuv error in case of error, 0 otherwise.
|
|
||||||
static int open_shada_file_for_reading(const char *const fname, ShaDaReadDef *sd_reader)
|
|
||||||
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
|
|
||||||
{
|
|
||||||
*sd_reader = (ShaDaReadDef) {
|
|
||||||
.read = &read_file,
|
|
||||||
.close = &close_sd_reader,
|
|
||||||
.skip = &sd_reader_skip_read,
|
|
||||||
.error = NULL,
|
|
||||||
.eof = false,
|
|
||||||
.fpos = 0,
|
|
||||||
.cookie = xmalloc(sizeof(FileDescriptor)),
|
|
||||||
};
|
|
||||||
int error = file_open(sd_reader->cookie, fname, kFileReadOnly, 0);
|
|
||||||
if (error) {
|
|
||||||
XFREE_CLEAR(sd_reader->cookie);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(strcmp(p_enc, "utf-8") == 0);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wrapper for closing file descriptors
|
/// Wrapper for closing file descriptors
|
||||||
static void close_file(FileDescriptor *cookie)
|
static void close_file(FileDescriptor *cookie)
|
||||||
{
|
{
|
||||||
@ -757,8 +639,8 @@ static int shada_read_file(const char *const file, const int flags)
|
|||||||
|
|
||||||
char *const fname = shada_filename(file);
|
char *const fname = shada_filename(file);
|
||||||
|
|
||||||
ShaDaReadDef sd_reader;
|
FileDescriptor sd_reader;
|
||||||
const int of_ret = open_shada_file_for_reading(fname, &sd_reader);
|
int of_ret = file_open(&sd_reader, fname, kFileReadOnly, 0);
|
||||||
|
|
||||||
if (p_verbose > 1) {
|
if (p_verbose > 1) {
|
||||||
verbose_enter();
|
verbose_enter();
|
||||||
@ -782,7 +664,7 @@ static int shada_read_file(const char *const file, const int flags)
|
|||||||
xfree(fname);
|
xfree(fname);
|
||||||
|
|
||||||
shada_read(&sd_reader, flags);
|
shada_read(&sd_reader, flags);
|
||||||
sd_reader.close(&sd_reader);
|
close_file(&sd_reader);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@ -1094,7 +976,7 @@ static inline bool marks_equal(const pos_T a, const pos_T b)
|
|||||||
///
|
///
|
||||||
/// @param[in] sd_reader Structure containing file reader definition.
|
/// @param[in] sd_reader Structure containing file reader definition.
|
||||||
/// @param[in] flags What to read, see ShaDaReadFileFlags enum.
|
/// @param[in] flags What to read, see ShaDaReadFileFlags enum.
|
||||||
static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
|
static void shada_read(FileDescriptor *const sd_reader, const int flags)
|
||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
list_T *oldfiles_list = get_vim_var_list(VV_OLDFILES);
|
list_T *oldfiles_list = get_vim_var_list(VV_OLDFILES);
|
||||||
@ -1849,13 +1731,13 @@ static int compare_file_marks(const void *a, const void *b)
|
|||||||
///
|
///
|
||||||
/// @return kSDReadStatusNotShaDa, kSDReadStatusReadError or
|
/// @return kSDReadStatusNotShaDa, kSDReadStatusReadError or
|
||||||
/// kSDReadStatusSuccess.
|
/// kSDReadStatusSuccess.
|
||||||
static inline ShaDaReadResult shada_parse_msgpack(ShaDaReadDef *const sd_reader,
|
static inline ShaDaReadResult shada_parse_msgpack(FileDescriptor *const sd_reader,
|
||||||
const size_t length,
|
const size_t length,
|
||||||
msgpack_unpacked *ret_unpacked,
|
msgpack_unpacked *ret_unpacked,
|
||||||
char **const ret_buf)
|
char **const ret_buf)
|
||||||
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
|
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
|
||||||
{
|
{
|
||||||
const uintmax_t initial_fpos = sd_reader->fpos;
|
const uintmax_t initial_fpos = sd_reader->bytes_read;
|
||||||
char *const buf = xmalloc(length);
|
char *const buf = xmalloc(length);
|
||||||
|
|
||||||
const ShaDaReadResult fl_ret = fread_len(sd_reader, buf, length);
|
const ShaDaReadResult fl_ret = fread_len(sd_reader, buf, length);
|
||||||
@ -2021,7 +1903,7 @@ static const char *shada_format_pfreed_entry(const PossiblyFreedShadaEntry pfs_e
|
|||||||
/// @param[in,out] ret_wms Location where results are saved.
|
/// @param[in,out] ret_wms Location where results are saved.
|
||||||
/// @param[out] packer MessagePack packer for entries which are not
|
/// @param[out] packer MessagePack packer for entries which are not
|
||||||
/// merged.
|
/// merged.
|
||||||
static inline ShaDaWriteResult shada_read_when_writing(ShaDaReadDef *const sd_reader,
|
static inline ShaDaWriteResult shada_read_when_writing(FileDescriptor *const sd_reader,
|
||||||
const unsigned srni_flags,
|
const unsigned srni_flags,
|
||||||
const size_t max_kbyte,
|
const size_t max_kbyte,
|
||||||
WriteMergerState *const wms,
|
WriteMergerState *const wms,
|
||||||
@ -2483,7 +2365,8 @@ static int hist_type2char(const int type)
|
|||||||
/// @param[in] sd_reader Structure containing file reader definition. If it is
|
/// @param[in] sd_reader Structure containing file reader definition. If it is
|
||||||
/// not NULL then contents of this file will be merged
|
/// not NULL then contents of this file will be merged
|
||||||
/// with current Neovim runtime.
|
/// with current Neovim runtime.
|
||||||
static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, ShaDaReadDef *const sd_reader)
|
static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer,
|
||||||
|
FileDescriptor *const sd_reader)
|
||||||
FUNC_ATTR_NONNULL_ARG(1)
|
FUNC_ATTR_NONNULL_ARG(1)
|
||||||
{
|
{
|
||||||
ShaDaWriteResult ret = kSDWriteSuccessful;
|
ShaDaWriteResult ret = kSDWriteSuccessful;
|
||||||
@ -2958,12 +2841,13 @@ int shada_write_file(const char *const file, bool nomerge)
|
|||||||
char *const fname = shada_filename(file);
|
char *const fname = shada_filename(file);
|
||||||
char *tempname = NULL;
|
char *tempname = NULL;
|
||||||
FileDescriptor sd_writer;
|
FileDescriptor sd_writer;
|
||||||
ShaDaReadDef sd_reader = { .close = NULL };
|
FileDescriptor sd_reader;
|
||||||
bool did_open_writer = false;
|
bool did_open_writer = false;
|
||||||
|
bool did_open_reader = false;
|
||||||
|
|
||||||
if (!nomerge) {
|
if (!nomerge) {
|
||||||
int error;
|
int error;
|
||||||
if ((error = open_shada_file_for_reading(fname, &sd_reader)) != 0) {
|
if ((error = file_open(&sd_reader, fname, kFileReadOnly, 0)) != 0) {
|
||||||
if (error != UV_ENOENT) {
|
if (error != UV_ENOENT) {
|
||||||
semsg(_(SERR "System error while opening ShaDa file %s for reading "
|
semsg(_(SERR "System error while opening ShaDa file %s for reading "
|
||||||
"to merge before writing it: %s"),
|
"to merge before writing it: %s"),
|
||||||
@ -2973,6 +2857,8 @@ int shada_write_file(const char *const file, bool nomerge)
|
|||||||
}
|
}
|
||||||
nomerge = true;
|
nomerge = true;
|
||||||
goto shada_write_file_nomerge;
|
goto shada_write_file_nomerge;
|
||||||
|
} else {
|
||||||
|
did_open_reader = true;
|
||||||
}
|
}
|
||||||
tempname = modname(fname, ".tmp.a", false);
|
tempname = modname(fname, ".tmp.a", false);
|
||||||
if (tempname == NULL) {
|
if (tempname == NULL) {
|
||||||
@ -3001,8 +2887,9 @@ shada_write_file_open: {}
|
|||||||
fname);
|
fname);
|
||||||
xfree(fname);
|
xfree(fname);
|
||||||
xfree(tempname);
|
xfree(tempname);
|
||||||
assert(sd_reader.close != NULL);
|
if (did_open_reader) {
|
||||||
sd_reader.close(&sd_reader);
|
close_file(&sd_reader);
|
||||||
|
}
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
(*wp)++;
|
(*wp)++;
|
||||||
@ -3047,8 +2934,8 @@ shada_write_file_nomerge: {}
|
|||||||
if (!did_open_writer) {
|
if (!did_open_writer) {
|
||||||
xfree(fname);
|
xfree(fname);
|
||||||
xfree(tempname);
|
xfree(tempname);
|
||||||
if (sd_reader.cookie != NULL) {
|
if (did_open_reader) {
|
||||||
sd_reader.close(&sd_reader);
|
close_file(&sd_reader);
|
||||||
}
|
}
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
@ -3062,7 +2949,9 @@ shada_write_file_nomerge: {}
|
|||||||
const ShaDaWriteResult sw_ret = shada_write(&sd_writer, (nomerge ? NULL : &sd_reader));
|
const ShaDaWriteResult sw_ret = shada_write(&sd_writer, (nomerge ? NULL : &sd_reader));
|
||||||
assert(sw_ret != kSDWriteIgnError);
|
assert(sw_ret != kSDWriteIgnError);
|
||||||
if (!nomerge) {
|
if (!nomerge) {
|
||||||
sd_reader.close(&sd_reader);
|
if (did_open_reader) {
|
||||||
|
close_file(&sd_reader);
|
||||||
|
}
|
||||||
bool did_remove = false;
|
bool did_remove = false;
|
||||||
if (sw_ret == kSDWriteSuccessful) {
|
if (sw_ret == kSDWriteSuccessful) {
|
||||||
FileInfo old_info;
|
FileInfo old_info;
|
||||||
@ -3235,18 +3124,18 @@ static inline uint64_t be64toh(uint64_t big_endian_64_bits)
|
|||||||
/// @return kSDReadStatusSuccess if everything was OK, kSDReadStatusNotShaDa if
|
/// @return kSDReadStatusSuccess if everything was OK, kSDReadStatusNotShaDa if
|
||||||
/// there were not enough bytes to read or kSDReadStatusReadError if
|
/// there were not enough bytes to read or kSDReadStatusReadError if
|
||||||
/// there was some error while reading.
|
/// there was some error while reading.
|
||||||
static ShaDaReadResult fread_len(ShaDaReadDef *const sd_reader, char *const buffer,
|
static ShaDaReadResult fread_len(FileDescriptor *const sd_reader, char *const buffer,
|
||||||
const size_t length)
|
const size_t length)
|
||||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
||||||
{
|
{
|
||||||
const ptrdiff_t read_bytes = sd_reader->read(sd_reader, buffer, length);
|
const ptrdiff_t read_bytes = file_read(sd_reader, buffer, length);
|
||||||
|
if (read_bytes < 0) {
|
||||||
if (read_bytes != (ptrdiff_t)length) {
|
|
||||||
if (sd_reader->error != NULL) {
|
|
||||||
semsg(_(SERR "System error while reading ShaDa file: %s"),
|
semsg(_(SERR "System error while reading ShaDa file: %s"),
|
||||||
sd_reader->error);
|
os_strerror((int)read_bytes));
|
||||||
return kSDReadStatusReadError;
|
return kSDReadStatusReadError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (read_bytes != (ptrdiff_t)length) {
|
||||||
semsg(_(RCERR "Error while reading ShaDa file: "
|
semsg(_(RCERR "Error while reading ShaDa file: "
|
||||||
"last entry specified that it occupies %" PRIu64 " bytes, "
|
"last entry specified that it occupies %" PRIu64 " bytes, "
|
||||||
"but file ended earlier"),
|
"but file ended earlier"),
|
||||||
@ -3272,26 +3161,32 @@ static ShaDaReadResult fread_len(ShaDaReadDef *const sd_reader, char *const buff
|
|||||||
/// @return kSDReadStatusSuccess if reading was successful,
|
/// @return kSDReadStatusSuccess if reading was successful,
|
||||||
/// kSDReadStatusNotShaDa if there were not enough bytes to read or
|
/// kSDReadStatusNotShaDa if there were not enough bytes to read or
|
||||||
/// kSDReadStatusReadError if reading failed for whatever reason.
|
/// kSDReadStatusReadError if reading failed for whatever reason.
|
||||||
static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader, const int first_char,
|
/// kSDReadStatusFinished if eof and that was allowed
|
||||||
|
static ShaDaReadResult msgpack_read_uint64(FileDescriptor *const sd_reader, bool allow_eof,
|
||||||
uint64_t *const result)
|
uint64_t *const result)
|
||||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
||||||
{
|
{
|
||||||
const uintmax_t fpos = sd_reader->fpos - 1;
|
const uintmax_t fpos = sd_reader->bytes_read;
|
||||||
|
|
||||||
if (first_char == EOF) {
|
uint8_t ret;
|
||||||
if (sd_reader->error) {
|
ptrdiff_t read_bytes = file_read(sd_reader, (char *)&ret, 1);
|
||||||
|
|
||||||
|
if (read_bytes < 0) {
|
||||||
semsg(_(SERR "System error while reading integer from ShaDa file: %s"),
|
semsg(_(SERR "System error while reading integer from ShaDa file: %s"),
|
||||||
sd_reader->error);
|
os_strerror((int)read_bytes));
|
||||||
return kSDReadStatusReadError;
|
return kSDReadStatusReadError;
|
||||||
} else if (sd_reader->eof) {
|
} else if (read_bytes == 0) {
|
||||||
|
if (allow_eof && file_eof(sd_reader)) {
|
||||||
|
return kSDReadStatusFinished;
|
||||||
|
}
|
||||||
semsg(_(RCERR "Error while reading ShaDa file: "
|
semsg(_(RCERR "Error while reading ShaDa file: "
|
||||||
"expected positive integer at position %" PRIu64
|
"expected positive integer at position %" PRIu64
|
||||||
", but got nothing"),
|
", but got nothing"),
|
||||||
(uint64_t)fpos);
|
(uint64_t)fpos);
|
||||||
return kSDReadStatusNotShaDa;
|
return kSDReadStatusNotShaDa;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
int first_char = (int)ret;
|
||||||
if (~first_char & 0x80) {
|
if (~first_char & 0x80) {
|
||||||
// Positive fixnum
|
// Positive fixnum
|
||||||
*result = (uint64_t)((uint8_t)first_char);
|
*result = (uint64_t)((uint8_t)first_char);
|
||||||
@ -3465,8 +3360,9 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader, const
|
|||||||
/// greater then given.
|
/// greater then given.
|
||||||
///
|
///
|
||||||
/// @return Any value from ShaDaReadResult enum.
|
/// @return Any value from ShaDaReadResult enum.
|
||||||
static ShaDaReadResult shada_read_next_item(ShaDaReadDef *const sd_reader, ShadaEntry *const entry,
|
static ShaDaReadResult shada_read_next_item(FileDescriptor *const sd_reader,
|
||||||
const unsigned flags, const size_t max_kbyte)
|
ShadaEntry *const entry, const unsigned flags,
|
||||||
|
const size_t max_kbyte)
|
||||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
||||||
{
|
{
|
||||||
ShaDaReadResult ret = kSDReadStatusMalformed;
|
ShaDaReadResult ret = kSDReadStatusMalformed;
|
||||||
@ -3476,7 +3372,7 @@ shada_read_next_item_start:
|
|||||||
// somebody calls goto shada_read_next_item_error before anything is set in
|
// somebody calls goto shada_read_next_item_error before anything is set in
|
||||||
// the switch.
|
// the switch.
|
||||||
CLEAR_POINTER(entry);
|
CLEAR_POINTER(entry);
|
||||||
if (sd_reader->eof) {
|
if (file_eof(sd_reader)) {
|
||||||
return kSDReadStatusFinished;
|
return kSDReadStatusFinished;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3486,19 +3382,15 @@ shada_read_next_item_start:
|
|||||||
uint64_t timestamp_u64;
|
uint64_t timestamp_u64;
|
||||||
uint64_t length_u64;
|
uint64_t length_u64;
|
||||||
|
|
||||||
const uint64_t initial_fpos = (uint64_t)sd_reader->fpos;
|
const uint64_t initial_fpos = sd_reader->bytes_read;
|
||||||
const int first_char = read_char(sd_reader);
|
|
||||||
if (first_char == EOF && sd_reader->eof) {
|
|
||||||
return kSDReadStatusFinished;
|
|
||||||
}
|
|
||||||
|
|
||||||
ShaDaReadResult mru_ret;
|
ShaDaReadResult mru_ret;
|
||||||
if (((mru_ret = msgpack_read_uint64(sd_reader, first_char, &type_u64))
|
if (((mru_ret = msgpack_read_uint64(sd_reader, true, &type_u64))
|
||||||
!= kSDReadStatusSuccess)
|
!= kSDReadStatusSuccess)
|
||||||
|| ((mru_ret = msgpack_read_uint64(sd_reader, read_char(sd_reader),
|
|| ((mru_ret = msgpack_read_uint64(sd_reader, false,
|
||||||
×tamp_u64))
|
×tamp_u64))
|
||||||
!= kSDReadStatusSuccess)
|
!= kSDReadStatusSuccess)
|
||||||
|| ((mru_ret = msgpack_read_uint64(sd_reader, read_char(sd_reader),
|
|| ((mru_ret = msgpack_read_uint64(sd_reader, false,
|
||||||
&length_u64))
|
&length_u64))
|
||||||
!= kSDReadStatusSuccess)) {
|
!= kSDReadStatusSuccess)) {
|
||||||
return mru_ret;
|
return mru_ret;
|
||||||
@ -4158,63 +4050,6 @@ void shada_encode_gvars(msgpack_sbuffer *const sbuf)
|
|||||||
} while (var_iter != NULL);
|
} while (var_iter != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapper for reading from msgpack_sbuffer.
|
|
||||||
///
|
|
||||||
/// @return number of bytes read.
|
|
||||||
static ptrdiff_t read_sbuf(ShaDaReadDef *const sd_reader, void *const dest, const size_t size)
|
|
||||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
|
||||||
{
|
|
||||||
msgpack_sbuffer *sbuf = (msgpack_sbuffer *)sd_reader->cookie;
|
|
||||||
const uintmax_t bytes_read = MIN(size, sbuf->size - sd_reader->fpos);
|
|
||||||
if (bytes_read < size) {
|
|
||||||
sd_reader->eof = true;
|
|
||||||
}
|
|
||||||
memcpy(dest, sbuf->data + sd_reader->fpos, (size_t)bytes_read);
|
|
||||||
sd_reader->fpos += bytes_read;
|
|
||||||
return (ptrdiff_t)bytes_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wrapper for read that ignores bytes read from msgpack_sbuffer.
|
|
||||||
///
|
|
||||||
/// Used for skipping.
|
|
||||||
///
|
|
||||||
/// @param[in,out] sd_reader ShaDaReadDef with msgpack_sbuffer.
|
|
||||||
/// @param[in] offset Amount of bytes to skip.
|
|
||||||
///
|
|
||||||
/// @return FAIL in case of failure, OK in case of success. May set
|
|
||||||
/// sd_reader->eof.
|
|
||||||
static int sd_sbuf_reader_skip_read(ShaDaReadDef *const sd_reader, const size_t offset)
|
|
||||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
|
||||||
{
|
|
||||||
msgpack_sbuffer *sbuf = (msgpack_sbuffer *)sd_reader->cookie;
|
|
||||||
assert(sbuf->size >= sd_reader->fpos);
|
|
||||||
const uintmax_t skip_bytes = MIN(offset, sbuf->size - sd_reader->fpos);
|
|
||||||
if (skip_bytes < offset) {
|
|
||||||
sd_reader->eof = true;
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
sd_reader->fpos += offset;
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Prepare ShaDaReadDef with msgpack_sbuffer for reading.
|
|
||||||
///
|
|
||||||
/// @param[in] sbuf msgpack_sbuffer to read from.
|
|
||||||
/// @param[out] sd_reader Location where reader structure will be saved.
|
|
||||||
static void open_shada_sbuf_for_reading(const msgpack_sbuffer *const sbuf, ShaDaReadDef *sd_reader)
|
|
||||||
FUNC_ATTR_NONNULL_ALL
|
|
||||||
{
|
|
||||||
*sd_reader = (ShaDaReadDef) {
|
|
||||||
.read = &read_sbuf,
|
|
||||||
.close = NULL,
|
|
||||||
.skip = &sd_sbuf_reader_skip_read,
|
|
||||||
.error = NULL,
|
|
||||||
.eof = false,
|
|
||||||
.fpos = 0,
|
|
||||||
.cookie = (void *)sbuf,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read ShaDa from msgpack_sbuffer.
|
/// Read ShaDa from msgpack_sbuffer.
|
||||||
///
|
///
|
||||||
/// @param[in] file msgpack_sbuffer to read from.
|
/// @param[in] file msgpack_sbuffer to read from.
|
||||||
@ -4226,7 +4061,8 @@ void shada_read_sbuf(msgpack_sbuffer *const sbuf, const int flags)
|
|||||||
if (sbuf->data == NULL) {
|
if (sbuf->data == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ShaDaReadDef sd_reader;
|
FileDescriptor sd_reader;
|
||||||
open_shada_sbuf_for_reading(sbuf, &sd_reader);
|
file_open_buffer(&sd_reader, sbuf->data, sbuf->size);
|
||||||
shada_read(&sd_reader, flags);
|
shada_read(&sd_reader, flags);
|
||||||
|
close_file(&sd_reader);
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ describe('ShaDa error handling', function()
|
|||||||
it('fails on zero', function()
|
it('fails on zero', function()
|
||||||
wshada('\000')
|
wshada('\000')
|
||||||
eq(
|
eq(
|
||||||
'Vim(rshada):E576: Error while reading ShaDa file: expected positive integer at position 0, but got nothing',
|
'Vim(rshada):E576: Error while reading ShaDa file: expected positive integer at position 1, but got nothing',
|
||||||
exc_exec(sdrcmd())
|
exc_exec(sdrcmd())
|
||||||
)
|
)
|
||||||
end)
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user