shada: Refactor file reading/writing to use os_open

This commit is contained in:
ZyX
2015-07-05 14:08:13 +03:00
parent d1ae27ceec
commit 98e8c1f37c
2 changed files with 388 additions and 165 deletions

View File

@@ -30,7 +30,7 @@
/// Try to free memory. Used when trying to recover from out of memory errors. /// Try to free memory. Used when trying to recover from out of memory errors.
/// @see {xmalloc} /// @see {xmalloc}
static void try_to_free_memory(void) void try_to_free_memory(void)
{ {
static bool trying_to_free = false; static bool trying_to_free = false;
// avoid recursive calls // avoid recursive calls

View File

@@ -4,6 +4,7 @@
#include <stdint.h> #include <stdint.h>
#include <inttypes.h> #include <inttypes.h>
#include <errno.h> #include <errno.h>
#include <unistd.h>
#include <assert.h> #include <assert.h>
#if defined (__GLIBC__) #if defined (__GLIBC__)
# ifndef _BSD_SOURCE # ifndef _BSD_SOURCE
@@ -24,7 +25,6 @@
#include "nvim/shada.h" #include "nvim/shada.h"
#include "nvim/message.h" #include "nvim/message.h"
#include "nvim/globals.h" #include "nvim/globals.h"
#include "nvim/macros.h"
#include "nvim/memory.h" #include "nvim/memory.h"
#include "nvim/mark.h" #include "nvim/mark.h"
#include "nvim/ops.h" #include "nvim/ops.h"
@@ -64,13 +64,15 @@ KHASH_MAP_INIT_STR(fnamebufs, buf_T *)
((const char *) find_viminfo_parameter(__VA_ARGS__)) ((const char *) find_viminfo_parameter(__VA_ARGS__))
#define emsg2(a, b) emsg2((char_u *) a, (char_u *) b) #define emsg2(a, b) emsg2((char_u *) a, (char_u *) b)
#define emsg3(a, b, c) emsg3((char_u *) a, (char_u *) b, (char_u *) c) #define emsg3(a, b, c) emsg3((char_u *) a, (char_u *) b, (char_u *) c)
#define emsgn(a, ...) emsgn((char_u *) a, __VA_ARGS__) #define emsgu(a, ...) emsgu((char_u *) a, __VA_ARGS__)
#define home_replace_save(a, b) \ #define home_replace_save(a, b) \
((char *)home_replace_save(a, (char_u *)b)) ((char *)home_replace_save(a, (char_u *)b))
#define path_shorten_fname_if_possible(b) \ #define path_shorten_fname_if_possible(b) \
((char *)path_shorten_fname_if_possible((char_u *)b)) ((char *)path_shorten_fname_if_possible((char_u *)b))
#define buflist_new(ffname, sfname, ...) \ #define buflist_new(ffname, sfname, ...) \
(buflist_new((char_u *)ffname, (char_u *)sfname, __VA_ARGS__)) (buflist_new((char_u *)ffname, (char_u *)sfname, __VA_ARGS__))
#define convert_setup(vcp, from, to) \
(convert_setup(vcp, (char_u *)from, (char_u *)to))
// From http://www.boost.org/doc/libs/1_43_0/boost/detail/endian.hpp + some // From http://www.boost.org/doc/libs/1_43_0/boost/detail/endian.hpp + some
// additional checks done after examining `{compiler} -dM -E - < /dev/null` // additional checks done after examining `{compiler} -dM -E - < /dev/null`
@@ -243,12 +245,207 @@ typedef struct {
uint8_t history_type; uint8_t history_type;
} HistoryMergerState; } HistoryMergerState;
struct sd_read_def;
/// Function used to read ShaDa files
typedef ptrdiff_t (*ShaDaFileReader)(struct sd_read_def *const sd_reader,
void *const dest,
const size_t size)
REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT;
/// Structure containing necessary pointers for reading ShaDa files
typedef struct sd_read_def {
ShaDaFileReader read; ///< Reader function.
void *cookie; ///< Reader function last argument.
bool eof; ///< True if reader reached end of file.
char *error; ///< Error message in case of error.
uintmax_t fpos; ///< Current position (amount of bytes read since
///< reader structure initialization). May overflow.
} ShaDaReadDef;
struct sd_write_def;
/// Function used to write ShaDa files
typedef ptrdiff_t (*ShaDaFileWriter)(struct sd_write_def *const sd_writer,
const void *const src,
const size_t size)
REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT;
/// Structure containing necessary pointers for writing ShaDa files
typedef struct sd_write_def {
ShaDaFileWriter write; ///< Writer function.
void *cookie; ///< Writer function last argument.
char *error; ///< Error message in case of error.
} ShaDaWriteDef;
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "shada.c.generated.h" # include "shada.c.generated.h"
#endif #endif
RINGBUF_INIT(HM, hm, ShadaEntry, shada_free_shada_entry) RINGBUF_INIT(HM, hm, ShadaEntry, shada_free_shada_entry)
/// Wrapper for reading from file descriptors
///
/// @return true if read was successfull, false otherwise.
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
{
size_t read_bytes = 0;
bool did_try_to_free = false;
while (read_bytes != size) {
const ptrdiff_t cur_read_bytes = read((int)(intptr_t) sd_reader->cookie,
((char *) dest) + read_bytes,
size - read_bytes);
if (cur_read_bytes > 0) {
read_bytes += (size_t) cur_read_bytes;
sd_reader->fpos += (uintmax_t) cur_read_bytes;
assert(read_bytes <= size);
}
if (errno) {
if (errno == EINTR || errno == EAGAIN) {
errno = 0;
continue;
} else if (errno == ENOMEM && !did_try_to_free) {
try_to_free_memory();
did_try_to_free = true;
errno = 0;
continue;
} else {
sd_reader->error = strerror(errno);
errno = 0;
return -1;
}
}
if (cur_read_bytes == 0) {
sd_reader->eof = true;
break;
}
}
return (ptrdiff_t) read_bytes;
}
/// 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 writing to file descriptors
///
/// @return true if read was successfull, false otherwise.
static ptrdiff_t write_file(ShaDaWriteDef *const sd_writer,
const void *const dest,
const size_t size)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
size_t written_bytes = 0;
while (written_bytes != size) {
const ptrdiff_t cur_written_bytes = write((int)(intptr_t) sd_writer->cookie,
(char *) dest + written_bytes,
size - written_bytes);
if (cur_written_bytes > 0) {
written_bytes += (size_t) cur_written_bytes;
}
if (errno) {
if (errno == EINTR || errno == EAGAIN) {
errno = 0;
continue;
} else {
sd_writer->error = strerror(errno);
errno = 0;
return -1;
}
}
if (cur_written_bytes == 0) {
sd_writer->error = "Zero bytes written.";
return -1;
}
}
return (ptrdiff_t) written_bytes;
}
/// Wrapper for opening file descriptors
///
/// All arguments are passed to os_open().
///
/// @return file descriptor or -1 on failure.
static int open_file(const char *const fname, const int flags, const int mode)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
bool did_try_to_free = false;
int fd;
open_file_start:
fd = os_open(fname, flags, mode);
if (fd < 0) {
if (-fd == ENOENT) {
return -1;
}
if (-fd == ENOMEM && !did_try_to_free) {
try_to_free_memory();
did_try_to_free = true;
goto open_file_start;
}
if (-fd == EINTR) {
goto open_file_start;
}
emsg3("System error while opening ShaDa file %s: %s",
fname, strerror(-fd));
return -1;
}
return fd;
}
/// Open ShaDa file for reading
///
/// @param[in] fname File name to open.
/// @param[out] sd_reader Location where reader structure will be saved.
///
/// @return OK in case of success, FAIL otherwise.
static int open_shada_file_for_reading(const char *const fname,
ShaDaReadDef *sd_reader)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
const intptr_t fd = (intptr_t) open_file(fname, O_RDONLY, 0);
if (fd == -1) {
return FAIL;
}
*sd_reader = (ShaDaReadDef) {
.read = &read_file,
.error = NULL,
.eof = false,
.fpos = 0,
.cookie = (void *) fd,
};
return OK;
}
/// Wrapper for closing file descriptors
static void close_file(int fd)
{
close_file_start:
if (close(fd) == -1) {
if (errno == EINTR) {
errno = 0;
goto close_file_start;
} else {
emsg2("System error while closing ShaDa file: %s",
strerror(errno));
errno = 0;
}
}
}
/// Check whether buffer is in the given set /// Check whether buffer is in the given set
/// ///
/// @param[in] set Set to check within. /// @param[in] set Set to check within.
@@ -270,10 +467,16 @@ static inline bool in_bufset(const khash_t(bufset) *const set, const buf_T *buf)
/// @return true or false. /// @return true or false.
#define SHADA_REMOVABLE(buf) in_bufset(removable_bufs, buf) #define SHADA_REMOVABLE(buf) in_bufset(removable_bufs, buf)
/// Msgpack callback for writing to FILE* /// Msgpack callback for writing to ShaDaWriteDef*
static int msgpack_fbuffer_write(void *data, const char *buf, size_t len) static int msgpack_sd_writer_write(void *data, const char *buf, size_t len)
{ {
return (fwrite(buf, len, 1, (FILE *) data) == 1) ? 0 : -1; ShaDaWriteDef *const sd_writer = (ShaDaWriteDef *) data;
ptrdiff_t written_bytes = sd_writer->write(sd_writer, buf, len);
if (written_bytes == -1) {
emsg2("System error while writing ShaDa file: %s", sd_writer->error);
return -1;
}
return 0;
} }
/// Check whether writing to shada file was disabled with -i NONE /// Check whether writing to shada file was disabled with -i NONE
@@ -294,14 +497,14 @@ static bool shada_disabled(void)
int shada_read_file(const char *const file, const int flags) int shada_read_file(const char *const file, const int flags)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_WARN_UNUSED_RESULT
{ {
FILE *fp;
if (shada_disabled()) { if (shada_disabled()) {
return FAIL; return FAIL;
} }
char *const fname = shada_filename(file); char *const fname = shada_filename(file);
fp = mch_fopen(fname, READBIN);
ShaDaReadDef sd_reader;
const int of_ret = open_shada_file_for_reading(fname, &sd_reader);
if (p_verbose > 0) { if (p_verbose > 0) {
verbose_enter(); verbose_enter();
@@ -310,18 +513,18 @@ int shada_read_file(const char *const file, const int flags)
(flags & kShaDaWantInfo) ? _(" info") : "", (flags & kShaDaWantInfo) ? _(" info") : "",
(flags & kShaDaWantMarks) ? _(" marks") : "", (flags & kShaDaWantMarks) ? _(" marks") : "",
(flags & kShaDaGetOldfiles) ? _(" oldfiles") : "", (flags & kShaDaGetOldfiles) ? _(" oldfiles") : "",
fp == NULL ? _(" FAILED") : ""); of_ret != OK ? _(" FAILED") : "");
verbose_leave(); verbose_leave();
} }
xfree(fname); xfree(fname);
if (fp == NULL) { if (of_ret != OK) {
return FAIL; return of_ret;
} }
shada_read(fp, flags); shada_read(&sd_reader, flags);
fclose(fp); close_file((int)(intptr_t) sd_reader.cookie);
return OK; return OK;
} }
@@ -448,9 +651,9 @@ static inline bool marks_equal(const pos_T a, const pos_T b)
/// Read data from ShaDa file /// Read data from ShaDa file
/// ///
/// @param[in] fp File to read from. /// @param[in] sd_reader Structure containing file reader definition.
/// @param[in] flags What to read. /// @param[in] flags What to read.
static void shada_read(FILE *const fp, const int flags) static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
unsigned srni_flags = 0; unsigned srni_flags = 0;
@@ -488,7 +691,7 @@ static void shada_read(FILE *const fp, const int flags)
ShadaEntry cur_entry; ShadaEntry cur_entry;
khash_t(bufset) *cl_bufs = kh_init(bufset); khash_t(bufset) *cl_bufs = kh_init(bufset);
khash_t(fnamebufs) *fname_bufs = kh_init(fnamebufs); khash_t(fnamebufs) *fname_bufs = kh_init(fnamebufs);
while (shada_read_next_item(fp, &cur_entry, srni_flags) == NOTDONE) { while (shada_read_next_item(sd_reader, &cur_entry, srni_flags) == NOTDONE) {
switch (cur_entry.type) { switch (cur_entry.type) {
case kSDItemMissing: { case kSDItemMissing: {
assert(false); assert(false);
@@ -1136,11 +1339,12 @@ static void shada_pack_entry(msgpack_packer *const packer,
/// Write ShaDa file /// Write ShaDa file
/// ///
/// @param[in] newfp File pointer to write to. Must not be NULL. /// @param[in] sd_writer Structure containing file writer definition.
/// @param[in] oldfp Pointer to the previous ShaDa file. If it is not NULL /// @param[in] sd_reader Structure containing file reader definition. If it is
/// then contents of this file will be merged with current /// not NULL then contents of this file will be merged
/// NeoVim runtime. /// with current NeoVim runtime.
static void shada_write(FILE *const newfp, FILE *const oldfp) static void shada_write(ShaDaWriteDef *const sd_writer,
ShaDaReadDef *const sd_reader)
FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(1)
{ {
khash_t(bufset) *const removable_bufs = kh_init(bufset); khash_t(bufset) *const removable_bufs = kh_init(bufset);
@@ -1153,7 +1357,8 @@ static void shada_write(FILE *const newfp, FILE *const oldfp)
} }
const size_t max_kbyte = (size_t) max_kbyte_i; const size_t max_kbyte = (size_t) max_kbyte_i;
msgpack_packer *packer = msgpack_packer_new(newfp, &msgpack_fbuffer_write); msgpack_packer *packer = msgpack_packer_new(sd_writer,
&msgpack_sd_writer_write);
FOR_ALL_BUFFERS(buf) { FOR_ALL_BUFFERS(buf) {
if (buf->b_ffname != NULL && shada_removable((char *) buf->b_ffname)) { if (buf->b_ffname != NULL && shada_removable((char *) buf->b_ffname)) {
@@ -1162,6 +1367,8 @@ static void shada_write(FILE *const newfp, FILE *const oldfp)
} }
} }
// TODO(ZyX-I): Iterate over sd_reader, keeping “replaced” values in a set.
// First write values that do not require merging // First write values that do not require merging
// 1. Header // 1. Header
shada_pack_entry(packer, (ShadaEntry) { shada_pack_entry(packer, (ShadaEntry) {
@@ -1182,7 +1389,6 @@ static void shada_write(FILE *const newfp, FILE *const oldfp)
} }
} }
}, 0); }, 0);
fflush(newfp);
// 2. Buffer list // 2. Buffer list
if (find_viminfo_parameter('%') != NULL) { if (find_viminfo_parameter('%') != NULL) {
@@ -1440,7 +1646,14 @@ static void shada_write(FILE *const newfp, FILE *const oldfp)
int shada_write_file(const char *const file, const bool nomerge) int shada_write_file(const char *const file, const bool nomerge)
{ {
char *const fname = shada_filename(file); char *const fname = shada_filename(file);
FILE *wfp = mch_fopen(fname, WRITEBIN); ShaDaWriteDef sd_writer = (ShaDaWriteDef) {
.write = &write_file,
.error = NULL,
};
const intptr_t fd = (intptr_t) open_file(fname,
O_CREAT|O_WRONLY|O_NOFOLLOW,
0600);
if (p_verbose > 0) { if (p_verbose > 0) {
verbose_enter(); verbose_enter();
@@ -1449,13 +1662,15 @@ int shada_write_file(const char *const file, const bool nomerge)
} }
xfree(fname); xfree(fname);
if (wfp == NULL) { if (fd == -1) {
return FAIL; return FAIL;
} }
shada_write(wfp, NULL); sd_writer.cookie = (void *) fd;
fclose(wfp); shada_write(&sd_writer, NULL);
close_file((int)(intptr_t) sd_writer.cookie);
return OK; return OK;
} }
@@ -1586,34 +1801,42 @@ static inline uint64_t be64toh(uint64_t big_endian_64_bits)
/// Read given number of bytes into given buffer, display error if needed /// Read given number of bytes into given buffer, display error if needed
/// ///
/// @param[in] fp File to read from. /// @param[in] sd_reader Structure containing file reader definition.
/// @param[out] buffer Where to save the results. May be NULL. /// @param[out] buffer Where to save the results. May be NULL.
/// @param[in] length How many bytes should be read. /// @param[in] length How many bytes should be read.
/// ///
/// @return FAIL if reading was not successfull, OK otherwise. /// @return FAIL if reading was not successfull, OK otherwise.
static int fread_len(FILE *const fp, char *const buffer, const size_t length) static int fread_len(ShaDaReadDef *const sd_reader, char *const buffer,
const size_t length)
FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT
{ {
size_t read_bytes = 0; ptrdiff_t read_bytes = 0;
if (buffer == NULL) { if (buffer == NULL) {
do { do {
read_bytes += fread(IObuff, 1, length > IOSIZE ? IOSIZE : length, fp); ptrdiff_t new_read_bytes = sd_reader->read(
} while (read_bytes < length && !ferror(fp) && !feof(fp)); sd_reader, IObuff, (size_t) (length - (size_t) read_bytes > IOSIZE
? IOSIZE
: length - (size_t) read_bytes));
if (new_read_bytes == -1) {
break;
}
read_bytes += new_read_bytes;
} while ((size_t) read_bytes < length && !sd_reader->eof);
} else { } else {
read_bytes = fread(buffer, 1, length, fp); read_bytes = sd_reader->read(sd_reader, buffer, length);
} }
if (ferror(fp)) { if (sd_reader->error != NULL) {
emsg2("System error while reading ShaDa file: %s", emsg2("System error while reading ShaDa file: %s", sd_reader->error);
strerror(errno));
return FAIL; return FAIL;
} else if (read_bytes != length) { } else if (sd_reader->eof) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"last entry specified that it occupies %" PRId64 " bytes, " "last entry specified that it occupies %" PRIu64 " bytes, "
"but file ended earlier", "but file ended earlier",
(int64_t) length); (uint64_t) length);
return FAIL; return FAIL;
} }
assert(read_bytes >= 0 && (size_t) read_bytes == length);
return OK; return OK;
} }
@@ -1627,27 +1850,26 @@ static int fread_len(FILE *const fp, char *const buffer, const size_t length)
/// ///
/// One byte from file stream is always consumed, even if it is not correct. /// One byte from file stream is always consumed, even if it is not correct.
/// ///
/// @param[in] fp File to read from. /// @param[in] sd_reader Structure containing file reader definition.
/// @param[out] result Location where result is saved. /// @param[out] result Location where result is saved.
/// ///
/// @return OK if read was successfull, FAIL if it was not. /// @return OK if read was successfull, FAIL if it was not.
static int msgpack_read_uint64(FILE *const fp, const int first_char, static int msgpack_read_uint64(ShaDaReadDef *const sd_reader,
const int first_char,
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 long fpos = ftell(fp) - 1; const uintmax_t fpos = sd_reader->fpos - 1;
if (fpos == -2) {
clearerr(fp);
}
if (first_char == EOF) { if (first_char == EOF) {
if (ferror(fp)) { if (sd_reader->error) {
emsg2("System error while reading ShaDa file: %s", emsg2("System error while reading ShaDa file: %s",
strerror(errno)); sd_reader->error);
} else if (feof(fp)) { } else if (sd_reader->eof) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"expected positive integer at position %" PRId64, "expected positive integer at position %" PRIu64
(int64_t) fpos); ", but got nothing",
(uint64_t) fpos);
} }
return FAIL; return FAIL;
} }
@@ -1675,14 +1897,15 @@ static int msgpack_read_uint64(FILE *const fp, const int first_char,
break; break;
} }
default: { default: {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"expected positive integer at position %" PRId64, "expected positive integer at position %" PRIu64,
(int64_t) fpos); (uint64_t) fpos);
return FAIL; return FAIL;
} }
} }
uint8_t buf[sizeof(uint64_t)] = {0, 0, 0, 0, 0, 0, 0, 0}; uint8_t buf[sizeof(uint64_t)] = {0, 0, 0, 0, 0, 0, 0, 0};
if (fread_len(fp, (char *) &(buf[sizeof(uint64_t)-length]), length) != OK) { if (fread_len(sd_reader, (char *) &(buf[sizeof(uint64_t)-length]), length)
!= OK) {
return FAIL; return FAIL;
} }
*result = be64toh(*((uint64_t *) &(buf[0]))); *result = be64toh(*((uint64_t *) &(buf[0])));
@@ -1692,20 +1915,21 @@ static int msgpack_read_uint64(FILE *const fp, const int first_char,
/// Iterate over shada file contents /// Iterate over shada file contents
/// ///
/// @param[in] fp Pointer to the opened ShaDa file. /// @param[in] sd_reader Structure containing file reader definition.
/// @param[out] entry Address where next entry contents will be saved. /// @param[out] entry Address where next entry contents will be saved.
/// @param[in] flags Flags, determining whether and which items should be /// @param[in] flags Flags, determining whether and which items should be
/// skipped (see SRNIFlags enum). /// skipped (see SRNIFlags enum).
/// ///
/// @return NOTDONE if entry was read correctly, FAIL if there were errors and /// @return NOTDONE if entry was read correctly, FAIL if there were errors and
/// OK at EOF. /// OK at EOF.
static int shada_read_next_item(FILE *const fp, ShadaEntry *const entry, static int shada_read_next_item(ShaDaReadDef *const sd_reader,
ShadaEntry *const entry,
const unsigned flags) const unsigned flags)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{ {
shada_read_next_item_start: shada_read_next_item_start:
entry->type = kSDItemMissing; entry->type = kSDItemMissing;
if (feof(fp)) { if (sd_reader->eof) {
return OK; return OK;
} }
@@ -1715,18 +1939,17 @@ shada_read_next_item_start:
uint64_t timestamp_u64; uint64_t timestamp_u64;
uint64_t length_u64; uint64_t length_u64;
const long initial_fpos = ftell(fp); const uintmax_t initial_fpos = sd_reader->fpos;
if (initial_fpos == -1) { const int first_char = read_char(sd_reader);
clearerr(fp); if (first_char == EOF && sd_reader->eof) {
}
const int first_char = fgetc(fp);
if (first_char == EOF && feof(fp)) {
return OK; return OK;
} }
if (msgpack_read_uint64(fp, first_char, &type_u64) != OK if (msgpack_read_uint64(sd_reader, first_char, &type_u64) != OK
|| msgpack_read_uint64(fp, fgetc(fp), &timestamp_u64) != OK || (msgpack_read_uint64(sd_reader, read_char(sd_reader), &timestamp_u64)
|| msgpack_read_uint64(fp, fgetc(fp), &length_u64) != OK) { != OK)
|| (msgpack_read_uint64(sd_reader, read_char(sd_reader), &length_u64)
!= OK)) {
return FAIL; return FAIL;
} }
@@ -1736,7 +1959,7 @@ shada_read_next_item_start:
if ((type_u64 > SHADA_LAST_ENTRY if ((type_u64 > SHADA_LAST_ENTRY
? !(flags & kSDReadUnknown) ? !(flags & kSDReadUnknown)
: !((unsigned) (1 << type_u64) & flags))) { : !((unsigned) (1 << type_u64) & flags))) {
if (fread_len(fp, NULL, length) != OK) { if (fread_len(sd_reader, NULL, length) != OK) {
return FAIL; return FAIL;
} }
goto shada_read_next_item_start; goto shada_read_next_item_start;
@@ -1747,7 +1970,7 @@ shada_read_next_item_start:
entry->data.unknown_item.size = length; entry->data.unknown_item.size = length;
entry->data.unknown_item.type = type_u64; entry->data.unknown_item.type = type_u64;
entry->data.unknown_item.contents = xmalloc(length); entry->data.unknown_item.contents = xmalloc(length);
return fread_len(fp, entry->data.unknown_item.contents, length); return fread_len(sd_reader, entry->data.unknown_item.contents, length);
} }
msgpack_unpacker *const unpacker = msgpack_unpacker_new(length); msgpack_unpacker *const unpacker = msgpack_unpacker_new(length);
@@ -1757,7 +1980,7 @@ shada_read_next_item_start:
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
if (fread_len(fp, msgpack_unpacker_buffer(unpacker), length) != OK) { if (fread_len(sd_reader, msgpack_unpacker_buffer(unpacker), length) != OK) {
msgpack_unpacker_free(unpacker); msgpack_unpacker_free(unpacker);
return FAIL; return FAIL;
} }
@@ -1792,10 +2015,10 @@ shada_read_next_item_start:
proc) \ proc) \
do { \ do { \
if (!(condition)) { \ if (!(condition)) { \
emsgn("Error while reading ShaDa file: " \ emsgu("Error while reading ShaDa file: " \
entry_name " entry at position %" PRId64 " " \ entry_name " entry at position %" PRIu64 " " \
error_desc, \ error_desc, \
(int64_t) initial_fpos); \ (uint64_t) initial_fpos); \
ga_clear(&ad_ga); \ ga_clear(&ad_ga); \
goto shada_read_next_item_error; \ goto shada_read_next_item_error; \
} \ } \
@@ -1804,12 +2027,12 @@ shada_read_next_item_start:
#define CHECK_KEY_IS_STR(entry_name) \ #define CHECK_KEY_IS_STR(entry_name) \
do { \ do { \
if (unpacked.data.via.map.ptr[i].key.type != MSGPACK_OBJECT_STR) { \ if (unpacked.data.via.map.ptr[i].key.type != MSGPACK_OBJECT_STR) { \
emsgn("Error while reading ShaDa file: " \ emsgu("Error while reading ShaDa file: " \
entry_name " entry at position %" PRId64 " " \ entry_name " entry at position %" PRIu64 " " \
"has key which is not a string", \ "has key which is not a string", \
(int64_t) initial_fpos); \ (uint64_t) initial_fpos); \
emsgn("It is %" PRId64 " instead", \ emsgu("It is %" PRIu64 " instead", \
unpacked.data.via.map.ptr[i].key.type ); \ (uint64_t) unpacked.data.via.map.ptr[i].key.type); \
ga_clear(&ad_ga); \ ga_clear(&ad_ga); \
goto shada_read_next_item_error; \ goto shada_read_next_item_error; \
} \ } \
@@ -1854,19 +2077,19 @@ shada_read_next_item_start:
switch ((ShadaEntryType) type_u64) { switch ((ShadaEntryType) type_u64) {
case kSDItemHeader: { case kSDItemHeader: {
if (!msgpack_rpc_to_dictionary(&(unpacked.data), &(entry->data.header))) { if (!msgpack_rpc_to_dictionary(&(unpacked.data), &(entry->data.header))) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"header entry at position %" PRId64 " is not a dictionary", "header entry at position %" PRIu64 " is not a dictionary",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
break; break;
} }
case kSDItemSearchPattern: { case kSDItemSearchPattern: {
if (unpacked.data.type != MSGPACK_OBJECT_MAP) { if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"search pattern entry at position %" PRId64 " " "search pattern entry at position %" PRIu64 " "
"is not a dictionary", "is not a dictionary",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
entry->data.search_pattern = (struct search_pattern) { entry->data.search_pattern = (struct search_pattern) {
@@ -1901,10 +2124,10 @@ shada_read_next_item_start:
else ADDITIONAL_KEY else ADDITIONAL_KEY
} }
if (entry->data.search_pattern.pat == NULL) { if (entry->data.search_pattern.pat == NULL) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"search pattern entry at position %" PRId64 " " "search pattern entry at position %" PRIu64 " "
"has no pattern", "has no pattern",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
ga_clear(&ad_ga); ga_clear(&ad_ga);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
@@ -1938,10 +2161,10 @@ shada_read_next_item_start:
case kSDItemGlobalMark: case kSDItemGlobalMark:
case kSDItemLocalMark: { case kSDItemLocalMark: {
if (unpacked.data.type != MSGPACK_OBJECT_MAP) { if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"mark entry at position %" PRId64 " " "mark entry at position %" PRIu64 " "
"is not a dictionary", "is not a dictionary",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
entry->data.filemark = (struct shada_filemark) { entry->data.filemark = (struct shada_filemark) {
@@ -1968,10 +2191,10 @@ shada_read_next_item_start:
else ADDITIONAL_KEY else ADDITIONAL_KEY
} }
if (entry->data.filemark.mark.lnum == 0) { if (entry->data.filemark.mark.lnum == 0) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"mark entry at position %" PRId64 " " "mark entry at position %" PRIu64 " "
"is missing line number", "is missing line number",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
ga_clear(&ad_ga); ga_clear(&ad_ga);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
@@ -2001,10 +2224,10 @@ shada_read_next_item_start:
} }
case kSDItemRegister: { case kSDItemRegister: {
if (unpacked.data.type != MSGPACK_OBJECT_MAP) { if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"register entry at position %" PRId64 " " "register entry at position %" PRIu64 " "
"is not a dictionary", "is not a dictionary",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
entry->data.reg = (struct reg) { entry->data.reg = (struct reg) {
@@ -2027,18 +2250,18 @@ shada_read_next_item_start:
entry->data.reg.width, POSITIVE_INTEGER, u64, TOSIZE) entry->data.reg.width, POSITIVE_INTEGER, u64, TOSIZE)
else if (CHECK_KEY(unpacked.data.via.map.ptr[i].key, "contents")) { else if (CHECK_KEY(unpacked.data.via.map.ptr[i].key, "contents")) {
if (unpacked.data.via.map.ptr[i].val.type != MSGPACK_OBJECT_ARRAY) { if (unpacked.data.via.map.ptr[i].val.type != MSGPACK_OBJECT_ARRAY) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"register entry at position %" PRId64 " " "register entry at position %" PRIu64 " "
"has contents key with non-array value", "has contents key with non-array value",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
ga_clear(&ad_ga); ga_clear(&ad_ga);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
if (unpacked.data.via.map.ptr[i].val.via.array.size == 0) { if (unpacked.data.via.map.ptr[i].val.via.array.size == 0) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"register entry at position %" PRId64 " " "register entry at position %" PRIu64 " "
"has contents key with empty array", "has contents key with empty array",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
ga_clear(&ad_ga); ga_clear(&ad_ga);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
@@ -2046,10 +2269,10 @@ shada_read_next_item_start:
unpacked.data.via.map.ptr[i].val.via.array; unpacked.data.via.map.ptr[i].val.via.array;
for (size_t i = 0; i < arr.size; i++) { for (size_t i = 0; i < arr.size; i++) {
if (arr.ptr[i].type != MSGPACK_OBJECT_BIN) { if (arr.ptr[i].type != MSGPACK_OBJECT_BIN) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"register entry at position %" PRId64 " " "register entry at position %" PRIu64 " "
"has contents array with non-string value", "has contents array with non-string value",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
ga_clear(&ad_ga); ga_clear(&ad_ga);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
@@ -2063,10 +2286,10 @@ shada_read_next_item_start:
} else ADDITIONAL_KEY } else ADDITIONAL_KEY
} }
if (entry->data.reg.contents == NULL) { if (entry->data.reg.contents == NULL) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"register entry at position %" PRId64 " " "register entry at position %" PRIu64 " "
"has missing contents array", "has missing contents array",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
ga_clear(&ad_ga); ga_clear(&ad_ga);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
@@ -2096,10 +2319,10 @@ shada_read_next_item_start:
} }
case kSDItemHistoryEntry: { case kSDItemHistoryEntry: {
if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) { if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"history entry at position %" PRId64 " " "history entry at position %" PRIu64 " "
"is not an array", "is not an array",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
entry->data.history_item = (struct history_item) { entry->data.history_item = (struct history_item) {
@@ -2109,26 +2332,26 @@ shada_read_next_item_start:
.additional_elements = NULL, .additional_elements = NULL,
}; };
if (unpacked.data.via.array.size < 2) { if (unpacked.data.via.array.size < 2) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"history entry at position %" PRId64 " " "history entry at position %" PRIu64 " "
"does not have enough elements", "does not have enough elements",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
if (unpacked.data.via.array.ptr[0].type if (unpacked.data.via.array.ptr[0].type
!= MSGPACK_OBJECT_POSITIVE_INTEGER) { != MSGPACK_OBJECT_POSITIVE_INTEGER) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"history entry at position %" PRId64 " " "history entry at position %" PRIu64 " "
"has wrong history type type", "has wrong history type type",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
if (unpacked.data.via.array.ptr[1].type if (unpacked.data.via.array.ptr[1].type
!= MSGPACK_OBJECT_BIN) { != MSGPACK_OBJECT_BIN) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"history entry at position %" PRId64 " " "history entry at position %" PRIu64 " "
"has wrong history string type", "has wrong history string type",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
entry->data.history_item.histtype = entry->data.history_item.histtype =
@@ -2137,18 +2360,18 @@ shada_read_next_item_start:
entry->data.history_item.histtype == HIST_SEARCH; entry->data.history_item.histtype == HIST_SEARCH;
if (is_hist_search) { if (is_hist_search) {
if (unpacked.data.via.array.size < 3) { if (unpacked.data.via.array.size < 3) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"search history entry at position %" PRId64 " " "search history entry at position %" PRIu64 " "
"does not have separator character", "does not have separator character",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
if (unpacked.data.via.array.ptr[2].type if (unpacked.data.via.array.ptr[2].type
!= MSGPACK_OBJECT_POSITIVE_INTEGER) { != MSGPACK_OBJECT_POSITIVE_INTEGER) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"search history entry at position %" PRId64 " " "search history entry at position %" PRIu64 " "
"has wrong history separator type", "has wrong history separator type",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
entry->data.history_item.sep = entry->data.history_item.sep =
@@ -2191,10 +2414,10 @@ shada_read_next_item_start:
} }
case kSDItemVariable: { case kSDItemVariable: {
if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) { if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"variable entry at position %" PRId64 " " "variable entry at position %" PRIu64 " "
"is not an array", "is not an array",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
entry->data.global_var = (struct global_var) { entry->data.global_var = (struct global_var) {
@@ -2205,25 +2428,25 @@ shada_read_next_item_start:
.additional_elements = NULL .additional_elements = NULL
}; };
if (unpacked.data.via.array.size < 2) { if (unpacked.data.via.array.size < 2) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"variable entry at position %" PRId64 " " "variable entry at position %" PRIu64 " "
"does not have enough elements", "does not have enough elements",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
if (unpacked.data.via.array.ptr[0].type != MSGPACK_OBJECT_BIN) { if (unpacked.data.via.array.ptr[0].type != MSGPACK_OBJECT_BIN) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"variable entry at position %" PRId64 " " "variable entry at position %" PRIu64 " "
"has wrong variable name type", "has wrong variable name type",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
if (unpacked.data.via.array.ptr[1].type == MSGPACK_OBJECT_NIL if (unpacked.data.via.array.ptr[1].type == MSGPACK_OBJECT_NIL
|| unpacked.data.via.array.ptr[1].type == MSGPACK_OBJECT_EXT) { || unpacked.data.via.array.ptr[1].type == MSGPACK_OBJECT_EXT) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"variable entry at position %" PRId64 " " "variable entry at position %" PRIu64 " "
"has wrong variable value type", "has wrong variable value type",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
entry->data.global_var.name = entry->data.global_var.name =
@@ -2261,10 +2484,10 @@ shada_read_next_item_start:
} }
case kSDItemSubString: { case kSDItemSubString: {
if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) { if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"sub string entry at position %" PRId64 " " "sub string entry at position %" PRIu64 " "
"is not an array", "is not an array",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
entry->data.sub_string = (struct sub_string) { entry->data.sub_string = (struct sub_string) {
@@ -2272,17 +2495,17 @@ shada_read_next_item_start:
.additional_elements = NULL .additional_elements = NULL
}; };
if (unpacked.data.via.array.size < 1) { if (unpacked.data.via.array.size < 1) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"sub string entry at position %" PRId64 " " "sub string entry at position %" PRIu64 " "
"does not have enough elements", "does not have enough elements",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
if (unpacked.data.via.array.ptr[0].type != MSGPACK_OBJECT_BIN) { if (unpacked.data.via.array.ptr[0].type != MSGPACK_OBJECT_BIN) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"sub string entry at position %" PRId64 " " "sub string entry at position %" PRIu64 " "
"has wrong sub string type", "has wrong sub string type",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
entry->data.sub_string.sub = entry->data.sub_string.sub =
@@ -2312,10 +2535,10 @@ shada_read_next_item_start:
} }
case kSDItemBufferList: { case kSDItemBufferList: {
if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) { if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"buffer list entry at position %" PRId64 " " "buffer list entry at position %" PRIu64 " "
"is not an array", "is not an array",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
entry->data.buffer_list = (struct buffer_list) { entry->data.buffer_list = (struct buffer_list) {
@@ -2336,10 +2559,10 @@ shada_read_next_item_start:
{ {
msgpack_unpacked unpacked = unpacked_2; msgpack_unpacked unpacked = unpacked_2;
if (unpacked.data.type != MSGPACK_OBJECT_MAP) { if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"buffer list at position %" PRId64 " " "buffer list at position %" PRIu64 " "
"contains entry that is not a dictionary", "contains entry that is not a dictionary",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
entry->data.buffer_list.buffers[i].pos.lnum = 1; entry->data.buffer_list.buffers[i].pos.lnum = 1;
@@ -2361,10 +2584,10 @@ shada_read_next_item_start:
} }
} }
if (entry->data.buffer_list.buffers[i].fname == NULL) { if (entry->data.buffer_list.buffers[i].fname == NULL) {
emsgn("Error while reading ShaDa file: " emsgu("Error while reading ShaDa file: "
"buffer list at position %" PRId64 " " "buffer list at position %" PRIu64 " "
"contains entry that does not have a file name", "contains entry that does not have a file name",
(int64_t) initial_fpos); (uint64_t) initial_fpos);
ga_clear(&ad_ga); ga_clear(&ad_ga);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }