mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
shada,documentation: Extend read error handling, handle write errors
Modifications: - If file was not written due to write error then writing stops and temporary file will not be renamed. - If NeoVim detects that target file is not a ShaDa file then temporary file will not be renamed.
This commit is contained in:
parent
f8169ff24d
commit
56174572bc
@ -896,7 +896,7 @@ To automatically save and restore views for *.c files: >
|
|||||||
au BufWinEnter *.c silent loadview
|
au BufWinEnter *.c silent loadview
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
8. The ShaDa file *shada* *shada-file* *E575*
|
8. The ShaDa file *shada* *shada-file* *E575* *E576*
|
||||||
If you exit Vim and later start it again, you would normally lose a lot of
|
If you exit Vim and later start it again, you would normally lose a lot of
|
||||||
information. The ShaDa file can be used to remember that information, which
|
information. The ShaDa file can be used to remember that information, which
|
||||||
enables you to continue where you left off.
|
enables you to continue where you left off.
|
||||||
@ -1110,8 +1110,19 @@ that file. This was done to avoid accidentally destroying a file when the
|
|||||||
file name of the ShaDa file is wrong. This could happen when accidentally
|
file name of the ShaDa file is wrong. This could happen when accidentally
|
||||||
typing "nvim -i file" when you wanted "nvim -R file" (yes, somebody
|
typing "nvim -i file" when you wanted "nvim -R file" (yes, somebody
|
||||||
accidentally did that!). If you want to overwrite a ShaDa file with an error
|
accidentally did that!). If you want to overwrite a ShaDa file with an error
|
||||||
in it, you will either have to fix the error, or delete the file (while NeoVim
|
in it, you will either have to fix the error, delete the file (while NeoVim is
|
||||||
is running, so most of the information will be restored).
|
running, so most of the information will be restored) or write it explicitly
|
||||||
|
with |:wshada| and a bang.
|
||||||
|
*E136* *E138*
|
||||||
|
Note: when NeoVim finds out that it failed to write part of the ShaDa file
|
||||||
|
(e.g. because there is no space left to write the file) or when it appears
|
||||||
|
that already present ShaDa file contains errors that indicate that this file
|
||||||
|
is likely not a ShaDa file then ShaDa file with `.tmp.X` suffix is left on the
|
||||||
|
file system (where X is any latin small letter: from U+0061 to U+007A). You
|
||||||
|
may use such file to recover the data if you want, but in any case it needs to
|
||||||
|
be cleaned up after you resolve the issue that prevented old ShaDa file from
|
||||||
|
being overwritten. If NeoVim fails to find unexisting `.tmp.X` file it will
|
||||||
|
not write ShaDa file at all.
|
||||||
|
|
||||||
*:rsh* *:rshada* *E886*
|
*:rsh* *:rshada* *E886*
|
||||||
:rsh[ada][!] [file] Read from ShaDa file [file] (default: see above).
|
:rsh[ada][!] [file] Read from ShaDa file [file] (default: see above).
|
||||||
@ -1122,7 +1133,7 @@ is running, so most of the information will be restored).
|
|||||||
*:rv* *:rviminfo*
|
*:rv* *:rviminfo*
|
||||||
:rv[iminfo][!] [file] Deprecated alias to |:rshada| command.
|
:rv[iminfo][!] [file] Deprecated alias to |:rshada| command.
|
||||||
|
|
||||||
*:wsh* *:wshada* *E136* *E137* *E138*
|
*:wsh* *:wshada* *E137*
|
||||||
:wsh[ada][!] [file] Write to ShaDa file [file] (default: see above).
|
:wsh[ada][!] [file] Write to ShaDa file [file] (default: see above).
|
||||||
The information in the file is first read in to make
|
The information in the file is first read in to make
|
||||||
a merge between old and new info. When [!] is used,
|
a merge between old and new info. When [!] is used,
|
||||||
|
375
src/nvim/shada.c
375
src/nvim/shada.c
@ -156,7 +156,8 @@ KHASH_SET_INIT_STR(strset)
|
|||||||
// Now only five of them are used:
|
// Now only five of them are used:
|
||||||
// E137: ShaDa file is not writeable (for pre-open checks)
|
// E137: ShaDa file is not writeable (for pre-open checks)
|
||||||
// E138: All %s.tmp.X files exist, cannot write ShaDa file!
|
// E138: All %s.tmp.X files exist, cannot write ShaDa file!
|
||||||
// E136: Can't rename ShaDa file from %s to %s!
|
// RCERR (E576) for critical read errors.
|
||||||
|
// RNERR (E136) for various errors when renaming.
|
||||||
// RERR (E575) for various errors inside read ShaDa file.
|
// RERR (E575) for various errors inside read ShaDa file.
|
||||||
// SERR (E886) for various “system” errors (always contains output of
|
// SERR (E886) for various “system” errors (always contains output of
|
||||||
// strerror)
|
// strerror)
|
||||||
@ -167,9 +168,17 @@ KHASH_SET_INIT_STR(strset)
|
|||||||
/// reading.
|
/// reading.
|
||||||
#define RERR "E575: "
|
#define RERR "E575: "
|
||||||
|
|
||||||
|
/// Common prefix for critical read errors
|
||||||
|
///
|
||||||
|
/// I.e. errors that make shada_read_next_item return kSDReadStatusNotShaDa.
|
||||||
|
#define RCERR "E576: "
|
||||||
|
|
||||||
/// Common prefix for all “system” errors
|
/// Common prefix for all “system” errors
|
||||||
#define SERR "E886: "
|
#define SERR "E886: "
|
||||||
|
|
||||||
|
/// Common prefix for all “rename” errors
|
||||||
|
#define RNERR "E136: "
|
||||||
|
|
||||||
/// Flags for shada_read_file and children
|
/// Flags for shada_read_file and children
|
||||||
enum {
|
enum {
|
||||||
kShaDaWantInfo = 1, ///< Load non-mark information
|
kShaDaWantInfo = 1, ///< Load non-mark information
|
||||||
@ -203,6 +212,25 @@ typedef enum {
|
|||||||
#define SHADA_LAST_ENTRY ((uint64_t) kSDItemChange)
|
#define SHADA_LAST_ENTRY ((uint64_t) kSDItemChange)
|
||||||
} ShadaEntryType;
|
} ShadaEntryType;
|
||||||
|
|
||||||
|
/// Possible results when reading ShaDa file
|
||||||
|
typedef enum {
|
||||||
|
kSDReadStatusSuccess, ///< Reading was successfull.
|
||||||
|
kSDReadStatusFinished, ///< Nothing more to read.
|
||||||
|
kSDReadStatusReadError, ///< Failed to read from file.
|
||||||
|
kSDReadStatusNotShaDa, ///< Input is most likely not a ShaDa file.
|
||||||
|
kSDReadStatusMalformed, ///< Error in the currently read item.
|
||||||
|
} ShaDaReadResult;
|
||||||
|
|
||||||
|
/// Possible results of shada_write function.
|
||||||
|
typedef enum {
|
||||||
|
kSDWriteSuccessfull, ///< Writing was successfull.
|
||||||
|
kSDWriteReadNotShada, ///< Writing was successfull, but when reading it
|
||||||
|
///< attempted to read file that did not look like
|
||||||
|
///< a ShaDa file.
|
||||||
|
kSDWriteFailed, ///< Writing was not successfull (e.g. because there
|
||||||
|
///< was no space left on device).
|
||||||
|
} ShaDaWriteResult;
|
||||||
|
|
||||||
/// Flags for shada_read_next_item
|
/// Flags for shada_read_next_item
|
||||||
enum SRNIFlags {
|
enum SRNIFlags {
|
||||||
kSDReadHeader = (1 << kSDItemHeader), ///< Determines whether header should
|
kSDReadHeader = (1 << kSDItemHeader), ///< Determines whether header should
|
||||||
@ -1115,8 +1143,25 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
|
|||||||
set_vim_var_list(VV_OLDFILES, oldfiles_list);
|
set_vim_var_list(VV_OLDFILES, oldfiles_list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (shada_read_next_item(sd_reader, &cur_entry, srni_flags, 0)
|
ShaDaReadResult srni_ret;
|
||||||
== NOTDONE) {
|
while ((srni_ret = shada_read_next_item(sd_reader, &cur_entry, srni_flags, 0))
|
||||||
|
!= kSDReadStatusFinished) {
|
||||||
|
switch (srni_ret) {
|
||||||
|
case kSDReadStatusSuccess: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case kSDReadStatusFinished: {
|
||||||
|
// Should be handled by the while condition.
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
case kSDReadStatusNotShaDa:
|
||||||
|
case kSDReadStatusReadError: {
|
||||||
|
goto shada_read_main_cycle_end;
|
||||||
|
}
|
||||||
|
case kSDReadStatusMalformed: {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
switch (cur_entry.type) {
|
switch (cur_entry.type) {
|
||||||
case kSDItemMissing: {
|
case kSDItemMissing: {
|
||||||
assert(false);
|
assert(false);
|
||||||
@ -1424,6 +1469,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
shada_read_main_cycle_end:
|
||||||
// Warning: shada_hist_iter returns ShadaEntry elements which use strings from
|
// Warning: shada_hist_iter returns ShadaEntry elements which use strings from
|
||||||
// original history list. This means that once such entry is removed
|
// original history list. This means that once such entry is removed
|
||||||
// from the history NeoVim array will no longer be valid. To reduce
|
// from the history NeoVim array will no longer be valid. To reduce
|
||||||
@ -1520,14 +1566,11 @@ static char *shada_filename(const char *file)
|
|||||||
/// @param[in] entry Entry written.
|
/// @param[in] entry Entry written.
|
||||||
/// @param[in] max_kbyte Maximum size of an item in KiB. Zero means no
|
/// @param[in] max_kbyte Maximum size of an item in KiB. Zero means no
|
||||||
/// restrictions.
|
/// restrictions.
|
||||||
static void shada_pack_entry(msgpack_packer *const packer,
|
static bool shada_pack_entry(msgpack_packer *const packer,
|
||||||
const ShadaEntry entry,
|
const ShadaEntry entry,
|
||||||
const size_t max_kbyte)
|
const size_t max_kbyte)
|
||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
if (entry.type == kSDItemMissing) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
msgpack_sbuffer sbuf;
|
msgpack_sbuffer sbuf;
|
||||||
msgpack_sbuffer_init(&sbuf);
|
msgpack_sbuffer_init(&sbuf);
|
||||||
msgpack_packer *spacker = msgpack_packer_new(&sbuf, &msgpack_sbuffer_write);
|
msgpack_packer *spacker = msgpack_packer_new(&sbuf, &msgpack_sbuffer_write);
|
||||||
@ -1536,9 +1579,13 @@ static void shada_pack_entry(msgpack_packer *const packer,
|
|||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
case kSDItemUnknown: {
|
case kSDItemUnknown: {
|
||||||
msgpack_pack_uint64(packer, (uint64_t) entry.data.unknown_item.size);
|
if ((msgpack_pack_uint64(packer, (uint64_t) entry.data.unknown_item.size)
|
||||||
packer->callback(packer->data, entry.data.unknown_item.contents,
|
== -1)
|
||||||
(unsigned) entry.data.unknown_item.size);
|
|| (packer->callback(packer->data, entry.data.unknown_item.contents,
|
||||||
|
(unsigned) entry.data.unknown_item.size)
|
||||||
|
== -1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kSDItemHistoryEntry: {
|
case kSDItemHistoryEntry: {
|
||||||
@ -1782,18 +1829,29 @@ static void shada_pack_entry(msgpack_packer *const packer,
|
|||||||
}
|
}
|
||||||
if (!max_kbyte || sbuf.size <= max_kbyte * 1024) {
|
if (!max_kbyte || sbuf.size <= max_kbyte * 1024) {
|
||||||
if (entry.type == kSDItemUnknown) {
|
if (entry.type == kSDItemUnknown) {
|
||||||
msgpack_pack_uint64(packer, (uint64_t) entry.data.unknown_item.type);
|
if (msgpack_pack_uint64(packer, (uint64_t) entry.data.unknown_item.type)
|
||||||
|
== -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
msgpack_pack_uint64(packer, (uint64_t) entry.type);
|
if (msgpack_pack_uint64(packer, (uint64_t) entry.type) == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (msgpack_pack_uint64(packer, (uint64_t) entry.timestamp) == -1) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
msgpack_pack_uint64(packer, (uint64_t) entry.timestamp);
|
|
||||||
if (sbuf.size > 0) {
|
if (sbuf.size > 0) {
|
||||||
msgpack_pack_uint64(packer, (uint64_t) sbuf.size);
|
if ((msgpack_pack_uint64(packer, (uint64_t) sbuf.size) == -1)
|
||||||
packer->callback(packer->data, sbuf.data, (unsigned) sbuf.size);
|
|| (packer->callback(packer->data, sbuf.data,
|
||||||
|
(unsigned) sbuf.size) == -1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
msgpack_packer_free(spacker);
|
msgpack_packer_free(spacker);
|
||||||
msgpack_sbuffer_destroy(&sbuf);
|
msgpack_sbuffer_destroy(&sbuf);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write single ShaDa entry, converting it if needed
|
/// Write single ShaDa entry, converting it if needed
|
||||||
@ -1807,16 +1865,17 @@ static void shada_pack_entry(msgpack_packer *const packer,
|
|||||||
/// is assumed that entry was already converted.
|
/// is assumed that entry was already converted.
|
||||||
/// @param[in] max_kbyte Maximum size of an item in KiB. Zero means no
|
/// @param[in] max_kbyte Maximum size of an item in KiB. Zero means no
|
||||||
/// restrictions.
|
/// restrictions.
|
||||||
static void shada_pack_encoded_entry(msgpack_packer *const packer,
|
static bool shada_pack_encoded_entry(msgpack_packer *const packer,
|
||||||
const vimconv_T *const sd_conv,
|
const vimconv_T *const sd_conv,
|
||||||
PossiblyFreedShadaEntry entry,
|
PossiblyFreedShadaEntry entry,
|
||||||
const size_t max_kbyte)
|
const size_t max_kbyte)
|
||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
|
bool ret = true;
|
||||||
if (entry.can_free_entry) {
|
if (entry.can_free_entry) {
|
||||||
shada_pack_entry(packer, entry.data, max_kbyte);
|
ret = shada_pack_entry(packer, entry.data, max_kbyte);
|
||||||
shada_free_shada_entry(&entry.data);
|
shada_free_shada_entry(&entry.data);
|
||||||
return;
|
return ret;
|
||||||
}
|
}
|
||||||
#define RUN_WITH_CONVERTED_STRING(cstr, code) \
|
#define RUN_WITH_CONVERTED_STRING(cstr, code) \
|
||||||
do { \
|
do { \
|
||||||
@ -1840,19 +1899,19 @@ static void shada_pack_encoded_entry(msgpack_packer *const packer,
|
|||||||
}
|
}
|
||||||
case kSDItemSearchPattern: {
|
case kSDItemSearchPattern: {
|
||||||
RUN_WITH_CONVERTED_STRING(entry.data.data.search_pattern.pat, {
|
RUN_WITH_CONVERTED_STRING(entry.data.data.search_pattern.pat, {
|
||||||
shada_pack_entry(packer, entry.data, max_kbyte);
|
ret = shada_pack_entry(packer, entry.data, max_kbyte);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kSDItemHistoryEntry: {
|
case kSDItemHistoryEntry: {
|
||||||
RUN_WITH_CONVERTED_STRING(entry.data.data.history_item.string, {
|
RUN_WITH_CONVERTED_STRING(entry.data.data.history_item.string, {
|
||||||
shada_pack_entry(packer, entry.data, max_kbyte);
|
ret = shada_pack_entry(packer, entry.data, max_kbyte);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kSDItemSubString: {
|
case kSDItemSubString: {
|
||||||
RUN_WITH_CONVERTED_STRING(entry.data.data.sub_string.sub, {
|
RUN_WITH_CONVERTED_STRING(entry.data.data.sub_string.sub, {
|
||||||
shada_pack_entry(packer, entry.data, max_kbyte);
|
ret = shada_pack_entry(packer, entry.data, max_kbyte);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1860,7 +1919,7 @@ static void shada_pack_encoded_entry(msgpack_packer *const packer,
|
|||||||
if (sd_conv->vc_type != CONV_NONE) {
|
if (sd_conv->vc_type != CONV_NONE) {
|
||||||
convert_object(sd_conv, &entry.data.data.global_var.value);
|
convert_object(sd_conv, &entry.data.data.global_var.value);
|
||||||
}
|
}
|
||||||
shada_pack_entry(packer, entry.data, max_kbyte);
|
ret = shada_pack_entry(packer, entry.data, max_kbyte);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kSDItemRegister: {
|
case kSDItemRegister: {
|
||||||
@ -1892,7 +1951,7 @@ static void shada_pack_encoded_entry(msgpack_packer *const packer,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
shada_pack_entry(packer, entry.data, max_kbyte);
|
ret = shada_pack_entry(packer, entry.data, max_kbyte);
|
||||||
if (did_convert) {
|
if (did_convert) {
|
||||||
for (size_t i = 0; i < entry.data.data.reg.contents_size; i++) {
|
for (size_t i = 0; i < entry.data.data.reg.contents_size; i++) {
|
||||||
xfree(entry.data.data.reg.contents[i]);
|
xfree(entry.data.data.reg.contents[i]);
|
||||||
@ -1907,11 +1966,12 @@ static void shada_pack_encoded_entry(msgpack_packer *const packer,
|
|||||||
case kSDItemBufferList:
|
case kSDItemBufferList:
|
||||||
case kSDItemLocalMark:
|
case kSDItemLocalMark:
|
||||||
case kSDItemChange: {
|
case kSDItemChange: {
|
||||||
shada_pack_entry(packer, entry.data, max_kbyte);
|
ret = shada_pack_entry(packer, entry.data, max_kbyte);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#undef RUN_WITH_CONVERTED_STRING
|
#undef RUN_WITH_CONVERTED_STRING
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compare two FileMarks structure to order them by greatest_timestamp
|
/// Compare two FileMarks structure to order them by greatest_timestamp
|
||||||
@ -1936,16 +1996,17 @@ static int compare_file_marks(const void *a, const void *b)
|
|||||||
/// @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 void shada_write(ShaDaWriteDef *const sd_writer,
|
static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
|
||||||
ShaDaReadDef *const sd_reader)
|
ShaDaReadDef *const sd_reader)
|
||||||
FUNC_ATTR_NONNULL_ARG(1)
|
FUNC_ATTR_NONNULL_ARG(1)
|
||||||
{
|
{
|
||||||
|
ShaDaWriteResult ret = kSDWriteSuccessfull;
|
||||||
int max_kbyte_i = get_shada_parameter('s');
|
int max_kbyte_i = get_shada_parameter('s');
|
||||||
if (max_kbyte_i < 0) {
|
if (max_kbyte_i < 0) {
|
||||||
max_kbyte_i = 10;
|
max_kbyte_i = 10;
|
||||||
}
|
}
|
||||||
if (max_kbyte_i == 0) {
|
if (max_kbyte_i == 0) {
|
||||||
return;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteMergerState *const wms = xcalloc(1, sizeof(*wms));
|
WriteMergerState *const wms = xcalloc(1, sizeof(*wms));
|
||||||
@ -1999,7 +2060,7 @@ static void shada_write(ShaDaWriteDef *const sd_writer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write header
|
// Write header
|
||||||
shada_pack_entry(packer, (ShadaEntry) {
|
if (!shada_pack_entry(packer, (ShadaEntry) {
|
||||||
.type = kSDItemHeader,
|
.type = kSDItemHeader,
|
||||||
.timestamp = os_time(),
|
.timestamp = os_time(),
|
||||||
.data = {
|
.data = {
|
||||||
@ -2018,7 +2079,10 @@ static void shada_write(ShaDaWriteDef *const sd_writer,
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 0);
|
}, 0)) {
|
||||||
|
ret = kSDWriteFailed;
|
||||||
|
goto shada_write_exit;
|
||||||
|
}
|
||||||
|
|
||||||
// Write buffer list
|
// Write buffer list
|
||||||
if (find_shada_parameter('%') != NULL) {
|
if (find_shada_parameter('%') != NULL) {
|
||||||
@ -2052,7 +2116,11 @@ static void shada_write(ShaDaWriteDef *const sd_writer,
|
|||||||
};
|
};
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
shada_pack_entry(packer, buflist_entry, 0);
|
if (!shada_pack_entry(packer, buflist_entry, 0)) {
|
||||||
|
xfree(buflist_entry.data.buffer_list.buffers);
|
||||||
|
ret = kSDWriteFailed;
|
||||||
|
goto shada_write_exit;
|
||||||
|
}
|
||||||
xfree(buflist_entry.data.buffer_list.buffers);
|
xfree(buflist_entry.data.buffer_list.buffers);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2071,7 +2139,7 @@ static void shada_write(ShaDaWriteDef *const sd_writer,
|
|||||||
if (sd_writer->sd_conv.vc_type != CONV_NONE) {
|
if (sd_writer->sd_conv.vc_type != CONV_NONE) {
|
||||||
convert_object(&sd_writer->sd_conv, &obj);
|
convert_object(&sd_writer->sd_conv, &obj);
|
||||||
}
|
}
|
||||||
shada_pack_entry(packer, (ShadaEntry) {
|
if (!shada_pack_entry(packer, (ShadaEntry) {
|
||||||
.type = kSDItemVariable,
|
.type = kSDItemVariable,
|
||||||
.timestamp = cur_timestamp,
|
.timestamp = cur_timestamp,
|
||||||
.data = {
|
.data = {
|
||||||
@ -2081,7 +2149,12 @@ static void shada_write(ShaDaWriteDef *const sd_writer,
|
|||||||
.additional_elements = NULL,
|
.additional_elements = NULL,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, max_kbyte);
|
}, max_kbyte)) {
|
||||||
|
api_free_object(obj);
|
||||||
|
clear_tv(&vartv);
|
||||||
|
ret = kSDWriteFailed;
|
||||||
|
goto shada_write_exit;
|
||||||
|
}
|
||||||
api_free_object(obj);
|
api_free_object(obj);
|
||||||
clear_tv(&vartv);
|
clear_tv(&vartv);
|
||||||
int kh_ret;
|
int kh_ret;
|
||||||
@ -2344,12 +2417,33 @@ static void shada_write(ShaDaWriteDef *const sd_writer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sd_reader == NULL) {
|
if (sd_reader == NULL) {
|
||||||
goto shada_write_remaining;
|
goto shada_write_main_cycle_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShadaEntry entry;
|
ShadaEntry entry;
|
||||||
while (shada_read_next_item(sd_reader, &entry, srni_flags, max_kbyte)
|
ShaDaReadResult srni_ret;
|
||||||
== NOTDONE) {
|
while ((srni_ret = shada_read_next_item(sd_reader, &entry, srni_flags,
|
||||||
|
max_kbyte))
|
||||||
|
!= kSDReadStatusFinished) {
|
||||||
|
switch (srni_ret) {
|
||||||
|
case kSDReadStatusSuccess: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case kSDReadStatusFinished: {
|
||||||
|
// Should be handled by the while condition.
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
case kSDReadStatusNotShaDa: {
|
||||||
|
ret = kSDWriteReadNotShada;
|
||||||
|
// fallthrough
|
||||||
|
}
|
||||||
|
case kSDReadStatusReadError: {
|
||||||
|
goto shada_write_main_cycle_end;
|
||||||
|
}
|
||||||
|
case kSDReadStatusMalformed: {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
#define COMPARE_WITH_ENTRY(wms_entry_, entry) \
|
#define COMPARE_WITH_ENTRY(wms_entry_, entry) \
|
||||||
do { \
|
do { \
|
||||||
PossiblyFreedShadaEntry *const wms_entry = (wms_entry_); \
|
PossiblyFreedShadaEntry *const wms_entry = (wms_entry_); \
|
||||||
@ -2374,7 +2468,9 @@ static void shada_write(ShaDaWriteDef *const sd_writer,
|
|||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
case kSDItemUnknown: {
|
case kSDItemUnknown: {
|
||||||
shada_pack_entry(packer, entry, 0);
|
if (!shada_pack_entry(packer, entry, 0)) {
|
||||||
|
ret = kSDWriteFailed;
|
||||||
|
}
|
||||||
shada_free_shada_entry(&entry);
|
shada_free_shada_entry(&entry);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2390,7 +2486,9 @@ static void shada_write(ShaDaWriteDef *const sd_writer,
|
|||||||
}
|
}
|
||||||
case kSDItemHistoryEntry: {
|
case kSDItemHistoryEntry: {
|
||||||
if (entry.data.history_item.histtype >= HIST_COUNT) {
|
if (entry.data.history_item.histtype >= HIST_COUNT) {
|
||||||
shada_pack_entry(packer, entry, 0);
|
if (!shada_pack_entry(packer, entry, 0)) {
|
||||||
|
ret = kSDWriteFailed;
|
||||||
|
}
|
||||||
shada_free_shada_entry(&entry);
|
shada_free_shada_entry(&entry);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2401,7 +2499,9 @@ static void shada_write(ShaDaWriteDef *const sd_writer,
|
|||||||
case kSDItemRegister: {
|
case kSDItemRegister: {
|
||||||
const int idx = op_reg_index(entry.data.reg.name);
|
const int idx = op_reg_index(entry.data.reg.name);
|
||||||
if (idx < 0) {
|
if (idx < 0) {
|
||||||
shada_pack_entry(packer, entry, 0);
|
if (!shada_pack_entry(packer, entry, 0)) {
|
||||||
|
ret = kSDWriteFailed;
|
||||||
|
}
|
||||||
shada_free_shada_entry(&entry);
|
shada_free_shada_entry(&entry);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2410,7 +2510,9 @@ static void shada_write(ShaDaWriteDef *const sd_writer,
|
|||||||
}
|
}
|
||||||
case kSDItemVariable: {
|
case kSDItemVariable: {
|
||||||
if (!in_strset(&wms->dumped_variables, entry.data.global_var.name)) {
|
if (!in_strset(&wms->dumped_variables, entry.data.global_var.name)) {
|
||||||
shada_pack_entry(packer, entry, 0);
|
if (!shada_pack_entry(packer, entry, 0)) {
|
||||||
|
ret = kSDWriteFailed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
shada_free_shada_entry(&entry);
|
shada_free_shada_entry(&entry);
|
||||||
break;
|
break;
|
||||||
@ -2418,7 +2520,9 @@ static void shada_write(ShaDaWriteDef *const sd_writer,
|
|||||||
case kSDItemGlobalMark: {
|
case kSDItemGlobalMark: {
|
||||||
const int idx = mark_global_index(entry.data.filemark.name);
|
const int idx = mark_global_index(entry.data.filemark.name);
|
||||||
if (idx < 0) {
|
if (idx < 0) {
|
||||||
shada_pack_entry(packer, entry, 0);
|
if (!shada_pack_entry(packer, entry, 0)) {
|
||||||
|
ret = kSDWriteFailed;
|
||||||
|
}
|
||||||
shada_free_shada_entry(&entry);
|
shada_free_shada_entry(&entry);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2556,27 +2660,37 @@ static void shada_write(ShaDaWriteDef *const sd_writer,
|
|||||||
#undef COMPARE_WITH_ENTRY
|
#undef COMPARE_WITH_ENTRY
|
||||||
|
|
||||||
// Write the rest
|
// Write the rest
|
||||||
shada_write_remaining:
|
shada_write_main_cycle_end:
|
||||||
#define PACK_WMS_ARRAY(wms_array) \
|
#define PACK_WMS_ARRAY(wms_array) \
|
||||||
do { \
|
do { \
|
||||||
for (size_t i_ = 0; i_ < ARRAY_SIZE(wms_array); i_++) { \
|
for (size_t i_ = 0; i_ < ARRAY_SIZE(wms_array); i_++) { \
|
||||||
if (wms_array[i_].data.type != kSDItemMissing) { \
|
if (wms_array[i_].data.type != kSDItemMissing) { \
|
||||||
shada_pack_encoded_entry(packer, &sd_writer->sd_conv, wms_array[i_], \
|
if (!shada_pack_encoded_entry(packer, &sd_writer->sd_conv, \
|
||||||
max_kbyte); \
|
wms_array[i_], \
|
||||||
|
max_kbyte)) { \
|
||||||
|
ret = kSDWriteFailed; \
|
||||||
|
goto shada_write_exit; \
|
||||||
|
} \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
PACK_WMS_ARRAY(wms->global_marks);
|
PACK_WMS_ARRAY(wms->global_marks);
|
||||||
PACK_WMS_ARRAY(wms->registers);
|
PACK_WMS_ARRAY(wms->registers);
|
||||||
for (size_t i = 0; i < wms->jumps_size; i++) {
|
for (size_t i = 0; i < wms->jumps_size; i++) {
|
||||||
shada_pack_encoded_entry(packer, &sd_writer->sd_conv, wms->jumps[i],
|
if (!shada_pack_encoded_entry(packer, &sd_writer->sd_conv, wms->jumps[i],
|
||||||
max_kbyte);
|
max_kbyte)) {
|
||||||
|
ret = kSDWriteFailed;
|
||||||
|
goto shada_write_exit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#define PACK_WMS_ENTRY(wms_entry) \
|
#define PACK_WMS_ENTRY(wms_entry) \
|
||||||
do { \
|
do { \
|
||||||
if (wms_entry.data.type != kSDItemMissing) { \
|
if (wms_entry.data.type != kSDItemMissing) { \
|
||||||
shada_pack_encoded_entry(packer, &sd_writer->sd_conv, wms_entry, \
|
if (!shada_pack_encoded_entry(packer, &sd_writer->sd_conv, wms_entry, \
|
||||||
max_kbyte); \
|
max_kbyte)) { \
|
||||||
|
ret = kSDWriteFailed; \
|
||||||
|
goto shada_write_exit; \
|
||||||
|
} \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
PACK_WMS_ENTRY(wms->search_pattern);
|
PACK_WMS_ENTRY(wms->search_pattern);
|
||||||
@ -2602,11 +2716,20 @@ shada_write_remaining:
|
|||||||
for (size_t i = 0; i < file_markss_to_dump; i++) {
|
for (size_t i = 0; i < file_markss_to_dump; i++) {
|
||||||
PACK_WMS_ARRAY(all_file_markss[i]->marks);
|
PACK_WMS_ARRAY(all_file_markss[i]->marks);
|
||||||
for (size_t j = 0; j < all_file_markss[i]->changes_size; j++) {
|
for (size_t j = 0; j < all_file_markss[i]->changes_size; j++) {
|
||||||
shada_pack_encoded_entry(packer, &sd_writer->sd_conv,
|
if (!shada_pack_encoded_entry(packer, &sd_writer->sd_conv,
|
||||||
all_file_markss[i]->changes[j], max_kbyte);
|
all_file_markss[i]->changes[j],
|
||||||
|
max_kbyte)) {
|
||||||
|
ret = kSDWriteFailed;
|
||||||
|
goto shada_write_exit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (size_t j = 0; j < all_file_markss[i]->additional_marks_size; j++) {
|
for (size_t j = 0; j < all_file_markss[i]->additional_marks_size; j++) {
|
||||||
shada_pack_entry(packer, all_file_markss[i]->additional_marks[j], 0);
|
if (!shada_pack_entry(packer, all_file_markss[i]->additional_marks[j],
|
||||||
|
0)) {
|
||||||
|
shada_free_shada_entry(&all_file_markss[i]->additional_marks[j]);
|
||||||
|
ret = kSDWriteFailed;
|
||||||
|
goto shada_write_exit;
|
||||||
|
}
|
||||||
shada_free_shada_entry(&all_file_markss[i]->additional_marks[j]);
|
shada_free_shada_entry(&all_file_markss[i]->additional_marks[j]);
|
||||||
}
|
}
|
||||||
xfree(all_file_markss[i]->additional_marks);
|
xfree(all_file_markss[i]->additional_marks);
|
||||||
@ -2619,23 +2742,31 @@ shada_write_remaining:
|
|||||||
if (dump_one_history[i]) {
|
if (dump_one_history[i]) {
|
||||||
hms_insert_whole_neovim_history(&wms->hms[i]);
|
hms_insert_whole_neovim_history(&wms->hms[i]);
|
||||||
HMS_ITER(&wms->hms[i], cur_entry) {
|
HMS_ITER(&wms->hms[i], cur_entry) {
|
||||||
shada_pack_encoded_entry(packer, &sd_writer->sd_conv,
|
if (!shada_pack_encoded_entry(packer, &sd_writer->sd_conv,
|
||||||
(PossiblyFreedShadaEntry) {
|
(PossiblyFreedShadaEntry) {
|
||||||
.data = cur_entry->data,
|
.data = cur_entry->data,
|
||||||
.can_free_entry =
|
.can_free_entry =
|
||||||
cur_entry->can_free_entry,
|
cur_entry->can_free_entry,
|
||||||
}, max_kbyte);
|
}, max_kbyte)) {
|
||||||
|
ret = kSDWriteFailed;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
hms_dealloc(&wms->hms[i]);
|
hms_dealloc(&wms->hms[i]);
|
||||||
|
if (ret == kSDWriteFailed) {
|
||||||
|
goto shada_write_exit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shada_write_exit:
|
||||||
kh_dealloc(file_marks, &wms->file_marks);
|
kh_dealloc(file_marks, &wms->file_marks);
|
||||||
kh_destroy(bufset, removable_bufs);
|
kh_destroy(bufset, removable_bufs);
|
||||||
msgpack_packer_free(packer);
|
msgpack_packer_free(packer);
|
||||||
kh_dealloc(strset, &wms->dumped_variables);
|
kh_dealloc(strset, &wms->dumped_variables);
|
||||||
xfree(wms);
|
xfree(wms);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef PACK_STATIC_STR
|
#undef PACK_STATIC_STR
|
||||||
@ -2661,7 +2792,6 @@ int shada_write_file(const char *const file, bool nomerge)
|
|||||||
intptr_t fd;
|
intptr_t fd;
|
||||||
|
|
||||||
if (!nomerge) {
|
if (!nomerge) {
|
||||||
// TODO(ZyX-I): Fail on read error.
|
|
||||||
if (open_shada_file_for_reading(fname, &sd_reader) != 0) {
|
if (open_shada_file_for_reading(fname, &sd_reader) != 0) {
|
||||||
nomerge = true;
|
nomerge = true;
|
||||||
goto shada_write_file_nomerge;
|
goto shada_write_file_nomerge;
|
||||||
@ -2764,16 +2894,28 @@ shada_write_file_nomerge: {}
|
|||||||
|
|
||||||
convert_setup(&sd_writer.sd_conv, p_enc, "utf-8");
|
convert_setup(&sd_writer.sd_conv, p_enc, "utf-8");
|
||||||
|
|
||||||
shada_write(&sd_writer, (nomerge ? NULL : &sd_reader));
|
const ShaDaWriteResult sw_ret = shada_write(&sd_writer, (nomerge
|
||||||
|
? NULL
|
||||||
|
: &sd_reader));
|
||||||
sd_writer.close(&sd_writer);
|
sd_writer.close(&sd_writer);
|
||||||
|
|
||||||
if (!nomerge) {
|
if (!nomerge) {
|
||||||
sd_reader.close(&sd_reader);
|
sd_reader.close(&sd_reader);
|
||||||
if (vim_rename(tempname, fname) == -1) {
|
if (sw_ret == kSDWriteSuccessfull) {
|
||||||
EMSG3(_("E136: Can't rename ShaDa file from %s to %s!"),
|
if (vim_rename(tempname, fname) == -1) {
|
||||||
tempname, fname);
|
EMSG3(_(RNERR "Can't rename ShaDa file from %s to %s!"),
|
||||||
|
tempname, fname);
|
||||||
|
} else {
|
||||||
|
os_remove(tempname);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
os_remove(tempname);
|
if (sw_ret == kSDWriteReadNotShada) {
|
||||||
|
EMSG3(_(RNERR "Did not rename %s because %s "
|
||||||
|
"does not looks like a ShaDa file"), tempname, fname);
|
||||||
|
} else {
|
||||||
|
EMSG3(_(RNERR "Did not rename %s to %s because there were errors "
|
||||||
|
"during writing it"), tempname, fname);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
xfree(tempname);
|
xfree(tempname);
|
||||||
}
|
}
|
||||||
@ -2918,9 +3060,12 @@ static inline uint64_t be64toh(uint64_t big_endian_64_bits)
|
|||||||
/// @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 kSDReadStatusSuccess if everything was OK, kSDReadStatusNotShaDa if
|
||||||
static int fread_len(ShaDaReadDef *const sd_reader, char *const buffer,
|
/// there were not enough bytes to read or kSDReadStatusReadError if
|
||||||
const size_t length)
|
/// there was some error while reading.
|
||||||
|
static ShaDaReadResult 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
|
||||||
{
|
{
|
||||||
ptrdiff_t read_bytes = 0;
|
ptrdiff_t read_bytes = 0;
|
||||||
@ -2942,16 +3087,16 @@ static int fread_len(ShaDaReadDef *const sd_reader, char *const buffer,
|
|||||||
if (sd_reader->error != NULL) {
|
if (sd_reader->error != NULL) {
|
||||||
emsg2(_(SERR "System error while reading ShaDa file: %s"),
|
emsg2(_(SERR "System error while reading ShaDa file: %s"),
|
||||||
sd_reader->error);
|
sd_reader->error);
|
||||||
return FAIL;
|
return kSDReadStatusReadError;
|
||||||
} else if (sd_reader->eof) {
|
} else if (sd_reader->eof) {
|
||||||
emsgu(_(RERR "Error while reading ShaDa file: "
|
emsgu(_(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) length);
|
(uint64_t) length);
|
||||||
return FAIL;
|
return kSDReadStatusNotShaDa;
|
||||||
}
|
}
|
||||||
assert(read_bytes >= 0 && (size_t) read_bytes == length);
|
assert(read_bytes >= 0 && (size_t) read_bytes == length);
|
||||||
return OK;
|
return kSDReadStatusSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read next unsigned integer from file
|
/// Read next unsigned integer from file
|
||||||
@ -2967,10 +3112,12 @@ static int fread_len(ShaDaReadDef *const sd_reader, char *const buffer,
|
|||||||
/// @param[in] sd_reader Structure containing file reader definition.
|
/// @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 kSDReadStatusSuccess if reading was successfull,
|
||||||
static int msgpack_read_uint64(ShaDaReadDef *const sd_reader,
|
/// kSDReadStatusNotShaDa if there were not enough bytes to read or
|
||||||
const int first_char,
|
/// kSDReadStatusReadError if reading failed for whatever reason.
|
||||||
uint64_t *const result)
|
static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader,
|
||||||
|
const int first_char,
|
||||||
|
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->fpos - 1;
|
||||||
@ -2979,13 +3126,14 @@ static int msgpack_read_uint64(ShaDaReadDef *const sd_reader,
|
|||||||
if (sd_reader->error) {
|
if (sd_reader->error) {
|
||||||
emsg2(_(SERR "System error while reading integer from ShaDa file: %s"),
|
emsg2(_(SERR "System error while reading integer from ShaDa file: %s"),
|
||||||
sd_reader->error);
|
sd_reader->error);
|
||||||
|
return kSDReadStatusReadError;
|
||||||
} else if (sd_reader->eof) {
|
} else if (sd_reader->eof) {
|
||||||
emsgu(_(RERR "Error while reading ShaDa file: "
|
emsgu(_(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 FAIL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (~first_char & 0x80) {
|
if (~first_char & 0x80) {
|
||||||
@ -3011,20 +3159,22 @@ static int msgpack_read_uint64(ShaDaReadDef *const sd_reader,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
emsgu(_(RERR "Error while reading ShaDa file: "
|
emsgu(_(RCERR "Error while reading ShaDa file: "
|
||||||
"expected positive integer at position %" PRIu64),
|
"expected positive integer at position %" PRIu64),
|
||||||
(uint64_t) fpos);
|
(uint64_t) fpos);
|
||||||
return FAIL;
|
return kSDReadStatusNotShaDa;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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(sd_reader, (char *) &(buf[sizeof(uint64_t)-length]), length)
|
ShaDaReadResult fl_ret;
|
||||||
!= OK) {
|
if ((fl_ret = fread_len(sd_reader, (char *) &(buf[sizeof(uint64_t)-length]),
|
||||||
return FAIL;
|
length))
|
||||||
|
!= kSDReadStatusSuccess) {
|
||||||
|
return fl_ret;
|
||||||
}
|
}
|
||||||
*result = be64toh(*((uint64_t *) &(buf[0])));
|
*result = be64toh(*((uint64_t *) &(buf[0])));
|
||||||
}
|
}
|
||||||
return OK;
|
return kSDReadStatusSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert all strings in one Object instance
|
/// Convert all strings in one Object instance
|
||||||
@ -3129,14 +3279,14 @@ static inline char *get_converted_string(const vimconv_T *const sd_conv,
|
|||||||
/// @param[in] max_kbyte If non-zero, skip reading entries which have length
|
/// @param[in] max_kbyte If non-zero, skip reading entries which have length
|
||||||
/// greater then given.
|
/// greater then given.
|
||||||
///
|
///
|
||||||
/// @return NOTDONE if entry was read correctly, FAIL if there were errors and
|
/// @return Any value from ShaDaReadResult enum.
|
||||||
/// OK at EOF.
|
static ShaDaReadResult shada_read_next_item(ShaDaReadDef *const sd_reader,
|
||||||
static int shada_read_next_item(ShaDaReadDef *const sd_reader,
|
ShadaEntry *const entry,
|
||||||
ShadaEntry *const entry,
|
const unsigned flags,
|
||||||
const unsigned flags,
|
const size_t max_kbyte)
|
||||||
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;
|
||||||
shada_read_next_item_start:
|
shada_read_next_item_start:
|
||||||
// Set entry type to kSDItemMissing and also make sure that all pointers in
|
// Set entry type to kSDItemMissing and also make sure that all pointers in
|
||||||
// data union are NULL so they are safe to xfree(). This is needed in case
|
// data union are NULL so they are safe to xfree(). This is needed in case
|
||||||
@ -3144,7 +3294,7 @@ shada_read_next_item_start:
|
|||||||
// the switch.
|
// the switch.
|
||||||
memset(entry, 0, sizeof(*entry));
|
memset(entry, 0, sizeof(*entry));
|
||||||
if (sd_reader->eof) {
|
if (sd_reader->eof) {
|
||||||
return OK;
|
return kSDReadStatusFinished;
|
||||||
}
|
}
|
||||||
|
|
||||||
// First: manually unpack type, timestamp and length.
|
// First: manually unpack type, timestamp and length.
|
||||||
@ -3156,15 +3306,19 @@ shada_read_next_item_start:
|
|||||||
const uintmax_t initial_fpos = sd_reader->fpos;
|
const uintmax_t initial_fpos = sd_reader->fpos;
|
||||||
const int first_char = read_char(sd_reader);
|
const int first_char = read_char(sd_reader);
|
||||||
if (first_char == EOF && sd_reader->eof) {
|
if (first_char == EOF && sd_reader->eof) {
|
||||||
return OK;
|
return kSDReadStatusFinished;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msgpack_read_uint64(sd_reader, first_char, &type_u64) != OK
|
ShaDaReadResult mru_ret;
|
||||||
|| (msgpack_read_uint64(sd_reader, read_char(sd_reader), ×tamp_u64)
|
if (((mru_ret = msgpack_read_uint64(sd_reader, first_char, &type_u64))
|
||||||
!= OK)
|
!= kSDReadStatusSuccess)
|
||||||
|| (msgpack_read_uint64(sd_reader, read_char(sd_reader), &length_u64)
|
|| ((mru_ret = msgpack_read_uint64(sd_reader, read_char(sd_reader),
|
||||||
!= OK)) {
|
×tamp_u64))
|
||||||
return FAIL;
|
!= kSDReadStatusSuccess)
|
||||||
|
|| ((mru_ret = msgpack_read_uint64(sd_reader, read_char(sd_reader),
|
||||||
|
&length_u64))
|
||||||
|
!= kSDReadStatusSuccess)) {
|
||||||
|
return mru_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t length = (size_t) length_u64;
|
const size_t length = (size_t) length_u64;
|
||||||
@ -3174,20 +3328,21 @@ shada_read_next_item_start:
|
|||||||
// kSDItemUnknown cannot possibly pass that far because it is -1 and that
|
// kSDItemUnknown cannot possibly pass that far because it is -1 and that
|
||||||
// will fail in msgpack_read_uint64. But kSDItemMissing may and it will
|
// will fail in msgpack_read_uint64. But kSDItemMissing may and it will
|
||||||
// otherwise be skipped because (1 << 0) will never appear in flags.
|
// otherwise be skipped because (1 << 0) will never appear in flags.
|
||||||
emsgu(_(RERR "Error while reading ShaDa file: "
|
emsgu(_(RCERR "Error while reading ShaDa file: "
|
||||||
"there is an item at position %" PRIu64 " "
|
"there is an item at position %" PRIu64 " "
|
||||||
"that must not be there: Missing items are "
|
"that must not be there: Missing items are "
|
||||||
"for internal uses only"),
|
"for internal uses only"),
|
||||||
(uint64_t) initial_fpos);
|
(uint64_t) initial_fpos);
|
||||||
return FAIL;
|
return kSDReadStatusNotShaDa;
|
||||||
}
|
}
|
||||||
|
|
||||||
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))
|
||||||
|| (max_kbyte && length > max_kbyte * 1024)) {
|
|| (max_kbyte && length > max_kbyte * 1024)) {
|
||||||
if (fread_len(sd_reader, NULL, length) != OK) {
|
const ShaDaReadResult fl_ret = fread_len(sd_reader, NULL, length);
|
||||||
return FAIL;
|
if (fl_ret != kSDReadStatusSuccess) {
|
||||||
|
return fl_ret;
|
||||||
}
|
}
|
||||||
goto shada_read_next_item_start;
|
goto shada_read_next_item_start;
|
||||||
}
|
}
|
||||||
@ -3202,9 +3357,12 @@ shada_read_next_item_start:
|
|||||||
|
|
||||||
char *const buf = xmalloc(length);
|
char *const buf = xmalloc(length);
|
||||||
|
|
||||||
if (fread_len(sd_reader, buf, length) != OK) {
|
{
|
||||||
xfree(buf);
|
const ShaDaReadResult fl_ret = fread_len(sd_reader, buf, length);
|
||||||
return FAIL;
|
if (fl_ret != kSDReadStatusSuccess) {
|
||||||
|
xfree(buf);
|
||||||
|
return fl_ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
msgpack_unpacked unpacked;
|
msgpack_unpacked unpacked;
|
||||||
@ -3215,6 +3373,7 @@ shada_read_next_item_read_next: {}
|
|||||||
size_t off = 0;
|
size_t off = 0;
|
||||||
const msgpack_unpack_return result =
|
const msgpack_unpack_return result =
|
||||||
msgpack_unpack_next(&unpacked, buf, length, &off);
|
msgpack_unpack_next(&unpacked, buf, length, &off);
|
||||||
|
ret = kSDReadStatusNotShaDa;
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case MSGPACK_UNPACK_SUCCESS: {
|
case MSGPACK_UNPACK_SUCCESS: {
|
||||||
if (off < length) {
|
if (off < length) {
|
||||||
@ -3223,7 +3382,7 @@ shada_read_next_item_read_next: {}
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MSGPACK_UNPACK_PARSE_ERROR: {
|
case MSGPACK_UNPACK_PARSE_ERROR: {
|
||||||
emsgu(_(RERR "Failed to parse ShaDa file due to a msgpack parser error "
|
emsgu(_(RCERR "Failed to parse ShaDa file due to a msgpack parser error "
|
||||||
"at position %" PRIu64),
|
"at position %" PRIu64),
|
||||||
(uint64_t) initial_fpos);
|
(uint64_t) initial_fpos);
|
||||||
goto shada_read_next_item_error;
|
goto shada_read_next_item_error;
|
||||||
@ -3235,22 +3394,24 @@ shada_read_next_item_read_next: {}
|
|||||||
goto shada_read_next_item_read_next;
|
goto shada_read_next_item_read_next;
|
||||||
}
|
}
|
||||||
EMSG(_(e_outofmem));
|
EMSG(_(e_outofmem));
|
||||||
|
ret = kSDReadStatusReadError;
|
||||||
goto shada_read_next_item_error;
|
goto shada_read_next_item_error;
|
||||||
}
|
}
|
||||||
case MSGPACK_UNPACK_CONTINUE: {
|
case MSGPACK_UNPACK_CONTINUE: {
|
||||||
emsgu(_(RERR "Failed to parse ShaDa file: incomplete msgpack string "
|
emsgu(_(RCERR "Failed to parse ShaDa file: incomplete msgpack string "
|
||||||
"at position %" PRIu64),
|
"at position %" PRIu64),
|
||||||
(uint64_t) initial_fpos);
|
(uint64_t) initial_fpos);
|
||||||
goto shada_read_next_item_error;
|
goto shada_read_next_item_error;
|
||||||
}
|
}
|
||||||
case MSGPACK_UNPACK_EXTRA_BYTES: {
|
case MSGPACK_UNPACK_EXTRA_BYTES: {
|
||||||
shada_read_next_item_extra_bytes:
|
shada_read_next_item_extra_bytes:
|
||||||
emsgu(_(RERR "Failed to parse ShaDa file: extra bytes in msgpack string "
|
emsgu(_(RCERR "Failed to parse ShaDa file: extra bytes in msgpack string "
|
||||||
"at position %" PRIu64),
|
"at position %" PRIu64),
|
||||||
(uint64_t) initial_fpos);
|
(uint64_t) initial_fpos);
|
||||||
goto shada_read_next_item_error;
|
goto shada_read_next_item_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ret = kSDReadStatusMalformed;
|
||||||
#define CHECK_KEY(key, expected) \
|
#define CHECK_KEY(key, expected) \
|
||||||
(key.via.str.size == sizeof(expected) - 1 \
|
(key.via.str.size == sizeof(expected) - 1 \
|
||||||
&& STRNCMP(key.via.str.ptr, expected, sizeof(expected) - 1) == 0)
|
&& STRNCMP(key.via.str.ptr, expected, sizeof(expected) - 1) == 0)
|
||||||
@ -3977,11 +4138,11 @@ shada_read_next_item_error:
|
|||||||
entry->type = (ShadaEntryType) type_u64;
|
entry->type = (ShadaEntryType) type_u64;
|
||||||
shada_free_shada_entry(entry);
|
shada_free_shada_entry(entry);
|
||||||
entry->type = kSDItemMissing;
|
entry->type = kSDItemMissing;
|
||||||
return FAIL;
|
return ret;
|
||||||
shada_read_next_item_end:
|
shada_read_next_item_end:
|
||||||
msgpack_unpacked_destroy(&unpacked);
|
msgpack_unpacked_destroy(&unpacked);
|
||||||
xfree(buf);
|
xfree(buf);
|
||||||
return NOTDONE;
|
return kSDReadStatusSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check whether "name" is on removable media (according to 'shada')
|
/// Check whether "name" is on removable media (according to 'shada')
|
||||||
|
@ -44,17 +44,17 @@ describe('ShaDa error handling', function()
|
|||||||
|
|
||||||
it('fails on zero', function()
|
it('fails on zero', function()
|
||||||
wshada('\000')
|
wshada('\000')
|
||||||
eq('Vim(rshada):E575: Error while reading ShaDa file: expected positive integer at position 0, but got nothing', exc_exec(sdrcmd()))
|
eq('Vim(rshada):E576: Error while reading ShaDa file: expected positive integer at position 0, but got nothing', exc_exec(sdrcmd()))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('fails on missing item', function()
|
it('fails on missing item', function()
|
||||||
wshada('\000\000\000')
|
wshada('\000\000\000')
|
||||||
eq('Vim(rshada):E575: Error while reading ShaDa file: there is an item at position 0 that must not be there: Missing items are for internal uses only', exc_exec(sdrcmd()))
|
eq('Vim(rshada):E576: Error while reading ShaDa file: there is an item at position 0 that must not be there: Missing items are for internal uses only', exc_exec(sdrcmd()))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('fails on -2 type', function()
|
it('fails on -2 type', function()
|
||||||
wshada('\254\000\000')
|
wshada('\254\000\000')
|
||||||
eq('Vim(rshada):E575: Error while reading ShaDa file: expected positive integer at position 0', exc_exec(sdrcmd()))
|
eq('Vim(rshada):E576: Error while reading ShaDa file: expected positive integer at position 0', exc_exec(sdrcmd()))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('does not fail on header with zero length', function()
|
it('does not fail on header with zero length', function()
|
||||||
@ -65,22 +65,22 @@ describe('ShaDa error handling', function()
|
|||||||
|
|
||||||
it('fails on search pattern item with zero length', function()
|
it('fails on search pattern item with zero length', function()
|
||||||
wshada('\002\000\000')
|
wshada('\002\000\000')
|
||||||
eq('Vim(rshada):E575: Failed to parse ShaDa file: incomplete msgpack string at position 0', exc_exec(sdrcmd()))
|
eq('Vim(rshada):E576: Failed to parse ShaDa file: incomplete msgpack string at position 0', exc_exec(sdrcmd()))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('fails on search pattern item with -2 timestamp', function()
|
it('fails on search pattern item with -2 timestamp', function()
|
||||||
wshada('\002\254\000')
|
wshada('\002\254\000')
|
||||||
eq('Vim(rshada):E575: Error while reading ShaDa file: expected positive integer at position 1', exc_exec(sdrcmd()))
|
eq('Vim(rshada):E576: Error while reading ShaDa file: expected positive integer at position 1', exc_exec(sdrcmd()))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('fails on search pattern item with -2 length', function()
|
it('fails on search pattern item with -2 length', function()
|
||||||
wshada('\002\000\254')
|
wshada('\002\000\254')
|
||||||
eq('Vim(rshada):E575: Error while reading ShaDa file: expected positive integer at position 2', exc_exec(sdrcmd()))
|
eq('Vim(rshada):E576: Error while reading ShaDa file: expected positive integer at position 2', exc_exec(sdrcmd()))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('fails on search pattern item with length greater then file length', function()
|
it('fails on search pattern item with length greater then file length', function()
|
||||||
wshada('\002\000\002\000')
|
wshada('\002\000\002\000')
|
||||||
eq('Vim(rshada):E575: Error while reading ShaDa file: last entry specified that it occupies 2 bytes, but file ended earlier', exc_exec(sdrcmd()))
|
eq('Vim(rshada):E576: Error while reading ShaDa file: last entry specified that it occupies 2 bytes, but file ended earlier', exc_exec(sdrcmd()))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('fails on search pattern item with invalid byte', function()
|
it('fails on search pattern item with invalid byte', function()
|
||||||
@ -95,12 +95,12 @@ describe('ShaDa error handling', function()
|
|||||||
-- get MSGPACK_UNPACK_PARSE_ERROR and not MSGPACK_UNPACK_CONTINUE or
|
-- get MSGPACK_UNPACK_PARSE_ERROR and not MSGPACK_UNPACK_CONTINUE or
|
||||||
-- MSGPACK_UNPACK_EXTRA_BYTES.
|
-- MSGPACK_UNPACK_EXTRA_BYTES.
|
||||||
wshada('\002\000\001\193')
|
wshada('\002\000\001\193')
|
||||||
eq('Vim(rshada):E575: Failed to parse ShaDa file due to a msgpack parser error at position 0', exc_exec(sdrcmd()))
|
eq('Vim(rshada):E576: Failed to parse ShaDa file due to a msgpack parser error at position 0', exc_exec(sdrcmd()))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('fails on search pattern item with incomplete map', function()
|
it('fails on search pattern item with incomplete map', function()
|
||||||
wshada('\002\000\001\129')
|
wshada('\002\000\001\129')
|
||||||
eq('Vim(rshada):E575: Failed to parse ShaDa file: incomplete msgpack string at position 0', exc_exec(sdrcmd()))
|
eq('Vim(rshada):E576: Failed to parse ShaDa file: incomplete msgpack string at position 0', exc_exec(sdrcmd()))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('fails on search pattern item without a pattern', function()
|
it('fails on search pattern item without a pattern', function()
|
||||||
@ -110,7 +110,7 @@ describe('ShaDa error handling', function()
|
|||||||
|
|
||||||
it('fails on search pattern with extra bytes', function()
|
it('fails on search pattern with extra bytes', function()
|
||||||
wshada('\002\000\002\128\000')
|
wshada('\002\000\002\128\000')
|
||||||
eq('Vim(rshada):E575: Failed to parse ShaDa file: extra bytes in msgpack string at position 0', exc_exec(sdrcmd()))
|
eq('Vim(rshada):E576: Failed to parse ShaDa file: extra bytes in msgpack string at position 0', exc_exec(sdrcmd()))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('fails on search pattern item with NIL value', function()
|
it('fails on search pattern item with NIL value', function()
|
||||||
|
Loading…
Reference in New Issue
Block a user