diff options
Diffstat (limited to 'src/nvim/shada.c')
-rw-r--r-- | src/nvim/shada.c | 476 |
1 files changed, 223 insertions, 253 deletions
diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 51c8597d53..197b029591 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -5,7 +5,6 @@ #include <stdint.h> #include <inttypes.h> #include <errno.h> -#include <fcntl.h> #include <assert.h> #include <msgpack.h> @@ -28,7 +27,6 @@ #include "nvim/api/private/helpers.h" #include "nvim/buffer.h" #include "nvim/buffer_defs.h" -#include "nvim/misc2.h" #include "nvim/ex_getln.h" #include "nvim/search.h" #include "nvim/regexp.h" @@ -36,6 +34,7 @@ #include "nvim/version.h" #include "nvim/path.h" #include "nvim/fileio.h" +#include "nvim/os/fileio.h" #include "nvim/strings.h" #include "nvim/quickfix.h" #include "nvim/eval/encode.h" @@ -119,9 +118,10 @@ KHASH_SET_INIT_STR(strset) // E576: Missing '>' // E577: Illegal register name // E886: Can't rename viminfo file to %s! +// E929: Too many viminfo temp files, like %s! // Now only six of them are used: // E137: ShaDa file is not writeable (for pre-open checks) -// E138: All %s.tmp.X files exist, cannot write ShaDa file! +// E929: All %s.tmp.X files exist, cannot write ShaDa file! // RCERR (E576) for critical read errors. // RNERR (E136) for various errors when renaming. // RERR (E575) for various errors inside read ShaDa file. @@ -149,6 +149,9 @@ KHASH_SET_INIT_STR(strset) /// Common prefix for all ignorable “write” errors #define WERR "E574: " +/// Callback function for add_search_pattern +typedef void (*SearchPatternGetter)(SearchPattern *); + /// Flags for shada_read_file and children typedef enum { kShaDaWantInfo = 1, ///< Load non-mark information @@ -409,7 +412,7 @@ typedef struct sd_read_def { ShaDaFileSkipper skip; ///< Function used to skip some bytes. void *cookie; ///< Data describing object read from. bool eof; ///< True if reader reached end of file. - char *error; ///< Error message in case of error. + const char *error; ///< Error message in case of error. uintmax_t fpos; ///< Current position (amount of bytes read since ///< reader structure initialization). May overflow. vimconv_T sd_conv; ///< Structure used for converting encodings of some @@ -433,7 +436,7 @@ typedef struct sd_write_def { ShaDaFileWriter write; ///< Writer function. ShaDaWriteCloser close; ///< Close function. void *cookie; ///< Data describing object written to. - char *error; ///< Error message in case of error. + const char *error; ///< Error message in case of error. vimconv_T sd_conv; ///< Structure used for converting encodings of some ///< items. } ShaDaWriteDef; @@ -666,38 +669,14 @@ 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; - const int fd = (int)(intptr_t) sd_reader->cookie; - while (read_bytes != size) { - const ptrdiff_t cur_read_bytes = read(fd, ((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 (cur_read_bytes < 0) { - 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; - } + 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; } - return (ptrdiff_t) read_bytes; + sd_reader->fpos += (size_t)ret; + return ret; } /// Read one character @@ -720,50 +699,26 @@ static ptrdiff_t write_file(ShaDaWriteDef *const sd_writer, const size_t size) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - size_t written_bytes = 0; - const int fd = (int)(intptr_t) sd_writer->cookie; - while (written_bytes != size) { - const ptrdiff_t cur_written_bytes = write(fd, (char *) dest + written_bytes, - size - written_bytes); - if (cur_written_bytes > 0) { - written_bytes += (size_t) cur_written_bytes; - } - if (cur_written_bytes < 0) { - 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; - } + const ptrdiff_t ret = file_write(sd_writer->cookie, dest, size); + if (ret < 0) { + sd_writer->error = os_strerror((int)ret); + return -1; } - return (ptrdiff_t) written_bytes; + return ret; } /// Wrapper for closing file descriptors opened for reading static void close_sd_reader(ShaDaReadDef *const sd_reader) FUNC_ATTR_NONNULL_ALL { - close_file((int)(intptr_t) sd_reader->cookie); + close_file(sd_reader->cookie); } /// Wrapper for closing file descriptors opened for writing static void close_sd_writer(ShaDaWriteDef *const sd_writer) FUNC_ATTR_NONNULL_ALL { - const int fd = (int)(intptr_t) sd_writer->cookie; - if (os_fsync(fd) < 0) { - emsgf(_(SERR "System error while synchronizing ShaDa file: %s"), - os_strerror(errno)); - errno = 0; - } - close_file(fd); + close_file(sd_writer->cookie); } /// Wrapper for read that reads to IObuff and ignores bytes read @@ -779,19 +734,20 @@ static int sd_reader_skip_read(ShaDaReadDef *const sd_reader, const size_t offset) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - size_t read_bytes = 0; - do { - ptrdiff_t new_read_bytes = sd_reader->read( - sd_reader, IObuff, (size_t) (offset - read_bytes > IOSIZE - ? IOSIZE - : offset - read_bytes)); - if (new_read_bytes == -1) { - return FAIL; + 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"); } - read_bytes += (size_t) new_read_bytes; - } while (read_bytes < offset && !sd_reader->eof); - - return (read_bytes == offset ? OK : FAIL); + return FAIL; + } + sd_reader->fpos += (size_t)skip_bytes; + return OK; } /// Wrapper for read that can be used when lseek cannot be used @@ -824,37 +780,6 @@ static ShaDaReadResult sd_reader_skip(ShaDaReadDef *const sd_reader, return kSDReadStatusSuccess; } -/// Wrapper for opening file descriptors -/// -/// All arguments are passed to os_open(). -/// -/// @return file descriptor or libuv error 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 == UV_ENOENT) { - return fd; - } - if (fd == UV_ENOMEM && !did_try_to_free) { - try_to_free_memory(); - did_try_to_free = true; - goto open_file_start; - } - if (fd != UV_EEXIST) { - emsgf(_(SERR "System error while opening ShaDa file %s: %s"), - fname, os_strerror(fd)); - } - return fd; - } - return fd; -} - /// Open ShaDa file for reading /// /// @param[in] fname File name to open. @@ -865,11 +790,7 @@ 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 < 0) { - return (int) fd; - } + int error; *sd_reader = (ShaDaReadDef) { .read = &read_file, @@ -878,8 +799,11 @@ static int open_shada_file_for_reading(const char *const fname, .error = NULL, .eof = false, .fpos = 0, - .cookie = (void *) fd, + .cookie = file_open_new(&error, fname, kFileReadOnly, 0), }; + if (sd_reader->cookie == NULL) { + return error; + } convert_setup(&sd_reader->sd_conv, "utf-8", p_enc); @@ -887,18 +811,12 @@ static int open_shada_file_for_reading(const char *const fname, } /// Wrapper for closing file descriptors -static void close_file(int fd) +static void close_file(void *cookie) { -close_file_start: - if (close(fd) == -1) { - if (errno == EINTR) { - errno = 0; - goto close_file_start; - } else { - emsgf(_(SERR "System error while closing ShaDa file: %s"), - strerror(errno)); - errno = 0; - } + const int error = file_free(cookie); + if (error != 0) { + emsgf(_(SERR "System error while closing ShaDa file: %s"), + os_strerror(error)); } } @@ -978,7 +896,7 @@ static int shada_read_file(const char *const file, const int flags) } if (of_ret != 0) { - if (of_ret == UV_ENOENT && (flags & kShaDaMissingError)) { + if (of_ret != UV_ENOENT || (flags & kShaDaMissingError)) { emsgf(_(SERR "System error while opening ShaDa file %s for reading: %s"), fname, os_strerror(of_ret)); } @@ -1421,8 +1339,8 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) } } if (!op_register_set(cur_entry.data.reg.name, (yankreg_T) { - .y_array = (char_u **) cur_entry.data.reg.contents, - .y_size = (linenr_T) cur_entry.data.reg.contents_size, + .y_array = (char_u **)cur_entry.data.reg.contents, + .y_size = cur_entry.data.reg.contents_size, .y_type = cur_entry.data.reg.type, .y_width = (colnr_T) cur_entry.data.reg.width, .timestamp = cur_entry.timestamp, @@ -1609,7 +1527,7 @@ static const char *shada_get_default_file(void) FUNC_ATTR_WARN_UNUSED_RESULT { if (default_shada_file == NULL) { - char *shada_dir = stdpaths_user_data_subpath("shada", 0); + char *shada_dir = stdpaths_user_data_subpath("shada", 0, false); default_shada_file = concat_fnames_realloc(shada_dir, "main.shada", true); } return default_shada_file; @@ -1661,7 +1579,9 @@ static char *shada_filename(const char *file) do { \ const String s_ = (s); \ msgpack_pack_bin(spacker, s_.size); \ - msgpack_pack_bin_body(spacker, s_.data, s_.size); \ + if (s_.size > 0) { \ + msgpack_pack_bin_body(spacker, s_.data, s_.size); \ + } \ } while (0) /// Write single ShaDa entry @@ -2066,7 +1986,7 @@ static ShaDaWriteResult shada_pack_encoded_entry(msgpack_packer *const packer, entry.data.data.reg.contents = xmemdup(entry.data.data.reg.contents, (entry.data.data.reg.contents_size - * sizeof(entry.data.data.reg.contents))); + * sizeof(entry.data.data.reg.contents[0]))); for (size_t i = 0; i < entry.data.data.reg.contents_size; i++) { if (i >= first_non_ascii) { entry.data.data.reg.contents[i] = get_converted_string( @@ -2402,6 +2322,113 @@ static inline ShaDaWriteResult shada_read_when_writing( return ret; } +/// Get list of buffers to write to the shada file +/// +/// @param[in] removable_bufs Buffers which are ignored +/// +/// @return ShadaEntry List of buffers to save, kSDItemBufferList entry. +static inline ShadaEntry shada_get_buflist( + khash_t(bufset) *const removable_bufs) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE +{ + int max_bufs = get_shada_parameter('%'); + size_t buf_count = 0; +#define IGNORE_BUF(buf)\ + (buf->b_ffname == NULL || !buf->b_p_bl || bt_quickfix(buf) \ + || in_bufset(removable_bufs, buf)) // NOLINT(whitespace/indent) + FOR_ALL_BUFFERS(buf) { + if (!IGNORE_BUF(buf) && (max_bufs < 0 || buf_count < (size_t)max_bufs)) { + buf_count++; + } + } + + ShadaEntry buflist_entry = (ShadaEntry) { + .type = kSDItemBufferList, + .timestamp = os_time(), + .data = { + .buffer_list = { + .size = buf_count, + .buffers = xmalloc(buf_count + * sizeof(*buflist_entry.data.buffer_list.buffers)), + }, + }, + }; + size_t i = 0; + FOR_ALL_BUFFERS(buf) { + if (IGNORE_BUF(buf)) { + continue; + } + if (i >= buf_count) { + break; + } + buflist_entry.data.buffer_list.buffers[i] = (struct buffer_list_buffer) { + .pos = buf->b_last_cursor.mark, + .fname = (char *)buf->b_ffname, + .additional_data = buf->additional_data, + }; + i++; + } + +#undef IGNORE_BUF + return buflist_entry; +} + +/// Save search pattern to PossiblyFreedShadaEntry +/// +/// @param[out] ret_pse Location where result will be saved. +/// @param[in] get_pattern Function used to get pattern. +/// @param[in] is_substitute_pattern True if pattern in question is substitute +/// pattern. Also controls whether some +/// fields should be initialized to default +/// or values from get_pattern. +/// @param[in] search_last_used Result of search_was_last_used(). +/// @param[in] search_highlighted True if search pattern was highlighted by +/// &hlsearch and this information should be +/// saved. +static inline void add_search_pattern(PossiblyFreedShadaEntry *const ret_pse, + const SearchPatternGetter get_pattern, + const bool is_substitute_pattern, + const bool search_last_used, + const bool search_highlighted) + FUNC_ATTR_ALWAYS_INLINE +{ + const ShadaEntry defaults = sd_default_values[kSDItemSearchPattern]; + SearchPattern pat; + get_pattern(&pat); + if (pat.pat != NULL) { + *ret_pse = (PossiblyFreedShadaEntry) { + .can_free_entry = false, + .data = { + .type = kSDItemSearchPattern, + .timestamp = pat.timestamp, + .data = { + .search_pattern = { + .magic = pat.magic, + .smartcase = !pat.no_scs, + .has_line_offset = (is_substitute_pattern + ? defaults.data.search_pattern.has_line_offset + : pat.off.line), + .place_cursor_at_end = ( + is_substitute_pattern + ? defaults.data.search_pattern.place_cursor_at_end + : pat.off.end), + .offset = (is_substitute_pattern + ? defaults.data.search_pattern.offset + : pat.off.off), + .is_last_used = (is_substitute_pattern ^ search_last_used), + .is_substitute_pattern = is_substitute_pattern, + .highlighted = ((is_substitute_pattern ^ search_last_used) + && search_highlighted), + .pat = (char *)pat.pat, + .additional_data = pat.additional_data, + .search_backward = (!is_substitute_pattern && pat.off.dir == '?'), + } + } + } + }; + } +} + /// Write ShaDa file /// /// @param[in] sd_writer Structure containing file writer definition. @@ -2508,46 +2535,13 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, // Write buffer list if (find_shada_parameter('%') != NULL) { - size_t buf_count = 0; -#define IGNORE_BUF(buf)\ - (buf->b_ffname == NULL || !buf->b_p_bl || bt_quickfix(buf) \ - || in_bufset(&removable_bufs, buf)) - FOR_ALL_BUFFERS(buf) { - if (!IGNORE_BUF(buf)) { - buf_count++; - } - } - - ShadaEntry buflist_entry = (ShadaEntry) { - .type = kSDItemBufferList, - .timestamp = os_time(), - .data = { - .buffer_list = { - .size = buf_count, - .buffers = xmalloc(buf_count - * sizeof(*buflist_entry.data.buffer_list.buffers)), - }, - }, - }; - size_t i = 0; - FOR_ALL_BUFFERS(buf) { - if (IGNORE_BUF(buf)) { - continue; - } - buflist_entry.data.buffer_list.buffers[i] = (struct buffer_list_buffer) { - .pos = buf->b_last_cursor.mark, - .fname = (char *) buf->b_ffname, - .additional_data = buf->additional_data, - }; - i++; - } + ShadaEntry buflist_entry = shada_get_buflist(&removable_bufs); if (shada_pack_entry(packer, buflist_entry, 0) == kSDWriteFailed) { xfree(buflist_entry.data.buffer_list.buffers); ret = kSDWriteFailed; goto shada_write_exit; } xfree(buflist_entry.data.buffer_list.buffers); -#undef IGNORE_BUF } // Write some of the variables @@ -2596,45 +2590,14 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, const bool search_highlighted = !(no_hlsearch || find_shada_parameter('h') != NULL); const bool search_last_used = search_was_last_used(); -#define ADD_SEARCH_PAT(func, wms_attr, hlo, pcae, o, is_sub) \ - do { \ - SearchPattern pat; \ - func(&pat); \ - if (pat.pat != NULL) { \ - wms->wms_attr = (PossiblyFreedShadaEntry) { \ - .can_free_entry = false, \ - .data = { \ - .type = kSDItemSearchPattern, \ - .timestamp = pat.timestamp, \ - .data = { \ - .search_pattern = { \ - .magic = pat.magic, \ - .smartcase = !pat.no_scs, \ - .has_line_offset = hlo, \ - .place_cursor_at_end = pcae, \ - .offset = o, \ - .is_last_used = (is_sub ^ search_last_used), \ - .is_substitute_pattern = is_sub, \ - .highlighted = ((is_sub ^ search_last_used) \ - && search_highlighted), \ - .pat = (char *) pat.pat, \ - .additional_data = pat.additional_data, \ - .search_backward = (!is_sub && pat.off.dir == '?'), \ - } \ - } \ - } \ - }; \ - } \ - } while (0) // Initialize search pattern - ADD_SEARCH_PAT(get_search_pattern, search_pattern, pat.off.line, \ - pat.off.end, pat.off.off, false); + add_search_pattern(&wms->search_pattern, &get_search_pattern, false, + search_last_used, search_highlighted); // Initialize substitute search pattern - ADD_SEARCH_PAT(get_substitute_pattern, sub_search_pattern, false, false, 0, - true); -#undef ADD_SEARCH_PAT + add_search_pattern(&wms->sub_search_pattern, &get_substitute_pattern, true, + search_last_used, search_highlighted); // Initialize substitute replacement string { @@ -2657,10 +2620,12 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, // Initialize jump list const void *jump_iter = NULL; + setpcmark(); + cleanup_jumplist(); do { xfmark_T fm; - cleanup_jumplist(); jump_iter = mark_jumplist_iter(jump_iter, curwin, &fm); + const buf_T *const buf = (fm.fmark.fnum == 0 ? NULL : buflist_findnr(fm.fmark.fnum)); @@ -2745,7 +2710,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, if (name == NUL) { break; } - if (limit_reg_lines && reg.y_size > max_reg_lines) { + if (limit_reg_lines && reg.y_size > (size_t)max_reg_lines) { continue; } wms->registers[op_reg_index(name)] = (PossiblyFreedShadaEntry) { @@ -2968,17 +2933,23 @@ int shada_write_file(const char *const file, bool nomerge) char *const fname = shada_filename(file); char *tempname = NULL; - ShaDaWriteDef sd_writer = (ShaDaWriteDef) { + ShaDaWriteDef sd_writer = { .write = &write_file, .close = &close_sd_writer, .error = NULL, }; - ShaDaReadDef sd_reader; - - intptr_t fd; + ShaDaReadDef sd_reader = { .close = NULL }; if (!nomerge) { - if (open_shada_file_for_reading(fname, &sd_reader) != 0) { + int error; + if ((error = open_shada_file_for_reading(fname, &sd_reader)) != 0) { + if (error != UV_ENOENT) { + emsgf(_(SERR "System error while opening ShaDa file %s for reading " + "to merge before writing it: %s"), + fname, os_strerror(error)); + // Try writing the file even if opening it emerged any issues besides + // file not existing: maybe writing will succeed nevertheless. + } nomerge = true; goto shada_write_file_nomerge; } @@ -2996,15 +2967,11 @@ int shada_write_file(const char *const file, bool nomerge) // 2: Make sure that user can always read and write the result. // 3: If somebody happened to delete the file after it was opened for // reading use u=rw permissions. -shada_write_file_open: - fd = (intptr_t) open_file(tempname, O_CREAT|O_WRONLY|O_NOFOLLOW|O_EXCL, - perm); - if (fd < 0) { - if (fd == UV_EEXIST -#ifdef ELOOP - || fd == UV_ELOOP -#endif - ) { +shada_write_file_open: {} + sd_writer.cookie = file_open_new( + &error, tempname, kFileCreateOnly|kFileNoSymlink, perm); + if (sd_writer.cookie == NULL) { + if (error == UV_EEXIST || error == UV_ELOOP) { // File already exists, try another name char *const wp = tempname + strlen(tempname) - 1; if (*wp == 'z') { @@ -3014,11 +2981,16 @@ shada_write_file_open: fname); xfree(fname); xfree(tempname); + assert(sd_reader.close != NULL); + sd_reader.close(&sd_reader); return FAIL; } else { (*wp)++; goto shada_write_file_open; } + } else { + emsgf(_(SERR "System error while opening temporary ShaDa file %s " + "for writing: %s"), tempname, os_strerror(error)); } } } @@ -3042,23 +3014,29 @@ shada_write_file_nomerge: {} } *tail = tail_save; } - fd = (intptr_t) open_file(fname, O_CREAT|O_WRONLY|O_TRUNC, - 0600); - } - - if (p_verbose > 0) { - verbose_enter(); - smsg(_("Writing ShaDa file \"%s\""), fname); - verbose_leave(); + int error; + sd_writer.cookie = file_open_new(&error, fname, kFileCreate|kFileTruncate, + 0600); + if (sd_writer.cookie == NULL) { + emsgf(_(SERR "System error while opening ShaDa file %s for writing: %s"), + fname, os_strerror(error)); + } } - if (fd < 0) { + if (sd_writer.cookie == NULL) { xfree(fname); xfree(tempname); + if (sd_reader.cookie != NULL) { + sd_reader.close(&sd_reader); + } return FAIL; } - sd_writer.cookie = (void *) fd; + if (p_verbose > 0) { + verbose_enter(); + smsg(_("Writing ShaDa file \"%s\""), fname); + verbose_leave(); + } convert_setup(&sd_writer.sd_conv, p_enc, "utf-8"); @@ -3066,15 +3044,11 @@ shada_write_file_nomerge: {} ? NULL : &sd_reader)); assert(sw_ret != kSDWriteIgnError); -#ifndef UNIX - sd_writer.close(&sd_writer); -#endif if (!nomerge) { sd_reader.close(&sd_reader); bool did_remove = false; if (sw_ret == kSDWriteSuccessfull) { #ifdef UNIX - bool closed = false; // For Unix we check the owner of the file. It's not very nice to // overwrite a user’s viminfo file after a "su root", with a // viminfo file that the user can't read. @@ -3083,16 +3057,15 @@ shada_write_file_nomerge: {} if (getuid() == ROOT_UID) { if (old_info.stat.st_uid != ROOT_UID || old_info.stat.st_gid != getgid()) { - const uv_uid_t old_uid = (uv_uid_t) old_info.stat.st_uid; - const uv_gid_t old_gid = (uv_gid_t) old_info.stat.st_gid; - const int fchown_ret = os_fchown((int) fd, old_uid, old_gid); - sd_writer.close(&sd_writer); + const uv_uid_t old_uid = (uv_uid_t)old_info.stat.st_uid; + const uv_gid_t old_gid = (uv_gid_t)old_info.stat.st_gid; + const int fchown_ret = os_fchown(file_fd(sd_writer.cookie), + old_uid, old_gid); if (fchown_ret != 0) { EMSG3(_(RNERR "Failed setting uid and gid for file %s: %s"), tempname, os_strerror(fchown_ret)); goto shada_write_file_did_not_remove; } - closed = true; } } else if (!(old_info.stat.st_uid == getuid() ? (old_info.stat.st_mode & 0200) @@ -3100,13 +3073,9 @@ shada_write_file_nomerge: {} ? (old_info.stat.st_mode & 0020) : (old_info.stat.st_mode & 0002)))) { EMSG2(_("E137: ShaDa file is not writable: %s"), fname); - sd_writer.close(&sd_writer); goto shada_write_file_did_not_remove; } } - if (!closed) { - sd_writer.close(&sd_writer); - } #endif if (vim_rename(tempname, fname) == -1) { EMSG3(_(RNERR "Can't rename ShaDa file from %s to %s!"), @@ -3133,6 +3102,7 @@ shada_write_file_did_not_remove: } xfree(tempname); } + sd_writer.close(&sd_writer); xfree(fname); return OK; @@ -3262,20 +3232,20 @@ static ShaDaReadResult fread_len(ShaDaReadDef *const sd_reader, FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { const ptrdiff_t read_bytes = sd_reader->read(sd_reader, buffer, length); - (void) read_bytes; - if (sd_reader->error != NULL) { - emsgf(_(SERR "System error while reading ShaDa file: %s"), - sd_reader->error); - return kSDReadStatusReadError; - } else if (sd_reader->eof) { - emsgf(_(RCERR "Error while reading ShaDa file: " - "last entry specified that it occupies %" PRIu64 " bytes, " - "but file ended earlier"), - (uint64_t) length); - return kSDReadStatusNotShaDa; + if (read_bytes != (ptrdiff_t)length) { + if (sd_reader->error != NULL) { + emsgf(_(SERR "System error while reading ShaDa file: %s"), + sd_reader->error); + return kSDReadStatusReadError; + } else { + emsgf(_(RCERR "Error while reading ShaDa file: " + "last entry specified that it occupies %" PRIu64 " bytes, " + "but file ended earlier"), + (uint64_t)length); + return kSDReadStatusNotShaDa; + } } - assert(read_bytes >= 0 && (size_t) read_bytes == length); return kSDReadStatusSuccess; } |