vim-patch:9.0.1583: get E304 when using 'cryptmethod' "xchacha20v2" (#23790)

Problem:    Get E304 when using 'cryptmethod' "xchacha20v2". (Steve Mynott)
Solution:   Add 4th crypt method to block zero ID check.  Avoid syncing a swap
            file before reading the file. (closes vim/vim#12433)

3a2a60ce4a

Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
zeertzjq 2023-05-28 08:06:30 +08:00 committed by GitHub
parent b46f61ac05
commit 7a8402ac31
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 100 additions and 65 deletions

View File

@ -248,6 +248,11 @@ int open_buffer(int read_stdin, exarg_T *eap, int flags_arg)
return FAIL;
}
// Do not sync this buffer yet, may first want to read the file.
if (curbuf->b_ml.ml_mfp != NULL) {
curbuf->b_ml.ml_mfp->mf_dirty = MF_DIRTY_YES_NOSYNC;
}
// The autocommands in readfile() may change the buffer, but only AFTER
// reading the file.
set_bufref(&old_curbuf, curbuf);
@ -316,6 +321,12 @@ int open_buffer(int read_stdin, exarg_T *eap, int flags_arg)
}
}
// Can now sync this buffer in ml_sync_all().
if (curbuf->b_ml.ml_mfp != NULL
&& curbuf->b_ml.ml_mfp->mf_dirty == MF_DIRTY_YES_NOSYNC) {
curbuf->b_ml.ml_mfp->mf_dirty = MF_DIRTY_YES;
}
// if first time loading this buffer, init b_chartab[]
if (curbuf->b_flags & BF_NEVERLOADED) {
(void)buf_init_chartab(curbuf, false);

View File

@ -153,6 +153,7 @@ void filemess(buf_T *buf, char *name, char *s, int attr)
int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
linenr_T lines_to_read, exarg_T *eap, int flags, bool silent)
{
int retval = FAIL; // jump to "theend" instead of returning
int fd = stdin_fd >= 0 ? stdin_fd : 0;
int newfile = (flags & READ_NEW);
int check_readonly;
@ -240,7 +241,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
&& vim_strchr(p_cpo, CPO_FNAMER) != NULL
&& !(flags & READ_DUMMY)) {
if (set_rw_fname(fname, sfname) == FAIL) {
return FAIL;
goto theend;
}
}
@ -284,10 +285,9 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
if (newfile) {
if (apply_autocmds_exarg(EVENT_BUFREADCMD, NULL, sfname,
false, curbuf, eap)) {
int status = OK;
retval = OK;
if (aborting()) {
status = FAIL;
retval = FAIL;
}
// The BufReadCmd code usually uses ":read" to get the text and
@ -295,14 +295,15 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
// consider this to work like ":edit", thus reset the
// BF_NOTEDITED flag. Then ":write" will work to overwrite the
// same file.
if (status == OK) {
if (retval == OK) {
curbuf->b_flags &= ~BF_NOTEDITED;
}
return status;
goto theend;
}
} else if (apply_autocmds_exarg(EVENT_FILEREADCMD, sfname, sfname,
false, NULL, eap)) {
return aborting() ? FAIL : OK;
retval = aborting() ? FAIL : OK;
goto theend;
}
curbuf->b_op_start = orig_start;
@ -310,7 +311,8 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
if (flags & READ_NOFILE) {
// Return NOTDONE instead of FAIL so that BufEnter can be triggered
// and other operations don't fail.
return NOTDONE;
retval = NOTDONE;
goto theend;
}
}
@ -328,7 +330,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
filemess(curbuf, fname, _("Illegal file name"), 0);
msg_end();
msg_scroll = msg_save;
return FAIL;
goto theend;
}
// If the name ends in a path separator, we can't open it. Check here,
@ -340,7 +342,8 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
}
msg_end();
msg_scroll = msg_save;
return NOTDONE;
retval = NOTDONE;
goto theend;
}
}
@ -365,12 +368,13 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
if (!silent) {
filemess(curbuf, fname, _(msg_is_a_directory), 0);
}
retval = NOTDONE;
} else {
filemess(curbuf, fname, _("is not a file"), 0);
}
msg_end();
msg_scroll = msg_save;
return S_ISDIR(perm) ? NOTDONE : FAIL;
goto theend;
}
}
@ -431,7 +435,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
if (fd < 0) { // cannot open at all
msg_scroll = msg_save;
if (!newfile) {
return FAIL;
goto theend;
}
if (perm == UV_ENOENT) { // check if the file exists
// Set the 'new-file' flag, so that when the file has
@ -450,7 +454,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
|| (using_b_fname
&& (old_b_fname != curbuf->b_fname))) {
emsg(_(e_auchangedbuf));
return FAIL;
goto theend;
}
}
if (!silent) {
@ -472,10 +476,10 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
// remember the current fileformat
save_file_ff(curbuf);
if (aborting()) { // autocmds may abort script processing
return FAIL;
if (!aborting()) { // autocmds may abort script processing
retval = OK; // a new file is not an error
}
return OK; // a new file is not an error
goto theend;
}
#if defined(UNIX) && defined(EOVERFLOW)
filemess(curbuf, sfname, ((fd == UV_EFBIG) ? _("[File too big]") :
@ -491,7 +495,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
#endif
curbuf->b_p_ro = true; // must use "w!" now
return FAIL;
goto theend;
}
// Only set the 'ro' flag for readonly files the first time they are
@ -526,7 +530,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
if (!read_buffer) {
close(fd);
}
return FAIL;
goto theend;
}
#ifdef UNIX
// Set swap file protection bits after creating it.
@ -561,7 +565,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
if (!read_buffer && !read_stdin) {
close(fd);
}
return FAIL;
goto theend;
}
no_wait_return++; // don't wait for return yet
@ -617,7 +621,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
no_wait_return--;
msg_scroll = msg_save;
curbuf->b_p_ro = true; // must use "w!" now
return FAIL;
goto theend;
}
// Don't allow the autocommands to change the current buffer.
// Try to re-open the file.
@ -636,7 +640,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
emsg(_("E201: *ReadPre autocommands must not change current buffer"));
}
curbuf->b_p_ro = true; // must use "w!" now
return FAIL;
goto theend;
}
}
@ -1684,7 +1688,8 @@ failed:
}
msg_scroll = msg_save;
check_marks_read();
return OK; // an interrupt isn't really an error
retval = OK; // an interrupt isn't really an error
goto theend;
}
if (!filtering && !(flags & READ_DUMMY) && !silent) {
@ -1860,10 +1865,18 @@ failed:
}
}
if (recoverymode && error) {
return FAIL;
if (!(recoverymode && error)) {
retval = OK;
}
return OK;
theend:
if (curbuf->b_ml.ml_mfp != NULL
&& curbuf->b_ml.ml_mfp->mf_dirty == MF_DIRTY_YES_NOSYNC) {
// OK to sync the swap file now
curbuf->b_ml.ml_mfp->mf_dirty = MF_DIRTY_YES;
}
return retval;
}
#ifdef OPEN_CHR_FILES

View File

@ -103,7 +103,7 @@ memfile_T *mf_open(char *fname, int flags)
mfp->mf_free_first = NULL; // free list is empty
mfp->mf_used_first = NULL; // used list is empty
mfp->mf_used_last = NULL;
mfp->mf_dirty = false;
mfp->mf_dirty = MF_DIRTY_NO;
mf_hash_init(&mfp->mf_hash);
mf_hash_init(&mfp->mf_trans);
mfp->mf_page_size = MEMFILE_PAGE_SIZE;
@ -159,7 +159,7 @@ memfile_T *mf_open(char *fname, int flags)
int mf_open_file(memfile_T *mfp, char *fname)
{
if (mf_do_open(mfp, fname, O_RDWR | O_CREAT | O_EXCL)) {
mfp->mf_dirty = true;
mfp->mf_dirty = MF_DIRTY_YES;
return OK;
}
@ -269,7 +269,7 @@ bhdr_T *mf_new(memfile_T *mfp, bool negative, unsigned page_count)
}
}
hp->bh_flags = BH_LOCKED | BH_DIRTY; // new block is always dirty
mfp->mf_dirty = true;
mfp->mf_dirty = MF_DIRTY_YES;
hp->bh_page_count = page_count;
mf_ins_used(mfp, hp);
mf_ins_hash(mfp, hp);
@ -342,7 +342,9 @@ void mf_put(memfile_T *mfp, bhdr_T *hp, bool dirty, bool infile)
flags &= ~BH_LOCKED;
if (dirty) {
flags |= BH_DIRTY;
mfp->mf_dirty = true;
if (mfp->mf_dirty != MF_DIRTY_YES_NOSYNC) {
mfp->mf_dirty = MF_DIRTY_YES;
}
}
hp->bh_flags = flags;
if (infile) {
@ -382,8 +384,9 @@ int mf_sync(memfile_T *mfp, int flags)
{
int got_int_save = got_int;
if (mfp->mf_fd < 0) { // there is no file, nothing to do
mfp->mf_dirty = false;
if (mfp->mf_fd < 0) {
// there is no file, nothing to do
mfp->mf_dirty = MF_DIRTY_NO;
return FAIL;
}
@ -426,7 +429,7 @@ int mf_sync(memfile_T *mfp, int flags)
// If the whole list is flushed, the memfile is not dirty anymore.
// In case of an error, dirty flag is also set, to avoid trying all the time.
if (hp == NULL || status == FAIL) {
mfp->mf_dirty = false;
mfp->mf_dirty = MF_DIRTY_NO;
}
if (flags & MFS_FLUSH) {
@ -449,7 +452,7 @@ void mf_set_dirty(memfile_T *mfp)
hp->bh_flags |= BH_DIRTY;
}
}
mfp->mf_dirty = true;
mfp->mf_dirty = MF_DIRTY_YES;
}
/// Insert block in front of memfile's hash list.

View File

@ -38,13 +38,13 @@ typedef struct mf_hashitem {
/// mf_hashitem_T which contains the key and linked list pointers. List of items
/// in each bucket is doubly-linked.
typedef struct mf_hashtab {
size_t mht_mask; /// mask used to mod hash value to array index
/// (nr of items in array is 'mht_mask + 1')
size_t mht_count; /// number of items inserted
mf_hashitem_T **mht_buckets; /// points to the array of buckets (can be
/// mht_small_buckets or a newly allocated array
/// when mht_small_buckets becomes too small)
mf_hashitem_T *mht_small_buckets[MHT_INIT_SIZE]; /// initial buckets
size_t mht_mask; ///< mask used to mod hash value to array index
///< (nr of items in array is 'mht_mask + 1')
size_t mht_count; ///< number of items inserted
mf_hashitem_T **mht_buckets; ///< points to the array of buckets (can be
///< mht_small_buckets or a newly allocated array
///< when mht_small_buckets becomes too small)
mf_hashitem_T *mht_small_buckets[MHT_INIT_SIZE]; ///< initial buckets
} mf_hashtab_T;
/// A block header.
@ -61,17 +61,17 @@ typedef struct mf_hashtab {
/// The blocks in the free list have no block of memory allocated and
/// the contents of the block in the file (if any) is irrelevant.
typedef struct bhdr {
mf_hashitem_T bh_hashitem; /// header for hash table and key
#define bh_bnum bh_hashitem.mhi_key /// block number, part of bh_hashitem
mf_hashitem_T bh_hashitem; ///< header for hash table and key
#define bh_bnum bh_hashitem.mhi_key ///< block number, part of bh_hashitem
struct bhdr *bh_next; /// next block header in free or used list
struct bhdr *bh_prev; /// previous block header in used list
void *bh_data; /// pointer to memory (for used block)
unsigned bh_page_count; /// number of pages in this block
struct bhdr *bh_next; ///< next block header in free or used list
struct bhdr *bh_prev; ///< previous block header in used list
void *bh_data; ///< pointer to memory (for used block)
unsigned bh_page_count; ///< number of pages in this block
#define BH_DIRTY 1U
#define BH_LOCKED 2U
unsigned bh_flags; // BH_DIRTY or BH_LOCKED
unsigned bh_flags; ///< BH_DIRTY or BH_LOCKED
} bhdr_T;
/// A block number translation list item.
@ -81,27 +81,33 @@ typedef struct bhdr {
/// number, we remember the translation to the new positive number in the
/// double linked trans lists. The structure is the same as the hash lists.
typedef struct mf_blocknr_trans_item {
mf_hashitem_T nt_hashitem; /// header for hash table and key
#define nt_old_bnum nt_hashitem.mhi_key /// old, negative, number
blocknr_T nt_new_bnum; /// new, positive, number
mf_hashitem_T nt_hashitem; ///< header for hash table and key
#define nt_old_bnum nt_hashitem.mhi_key ///< old, negative, number
blocknr_T nt_new_bnum; ///< new, positive, number
} mf_blocknr_trans_item_T;
typedef enum {
MF_DIRTY_NO = 0, ///< no dirty blocks
MF_DIRTY_YES, ///< there are dirty blocks
MF_DIRTY_YES_NOSYNC, ///< there are dirty blocks, do not sync yet
} mfdirty_T;
/// A memory file.
typedef struct memfile {
char *mf_fname; /// name of the file
char *mf_ffname; /// idem, full path
int mf_fd; /// file descriptor
bhdr_T *mf_free_first; /// first block header in free list
bhdr_T *mf_used_first; /// mru block header in used list
bhdr_T *mf_used_last; /// lru block header in used list
mf_hashtab_T mf_hash; /// hash lists
mf_hashtab_T mf_trans; /// trans lists
blocknr_T mf_blocknr_max; /// highest positive block number + 1
blocknr_T mf_blocknr_min; /// lowest negative block number - 1
blocknr_T mf_neg_count; /// number of negative blocks numbers
blocknr_T mf_infile_count; /// number of pages in the file
unsigned mf_page_size; /// number of bytes in a page
bool mf_dirty; /// true if there are dirty blocks
char *mf_fname; ///< name of the file
char *mf_ffname; ///< idem, full path
int mf_fd; ///< file descriptor
bhdr_T *mf_free_first; ///< first block header in free list
bhdr_T *mf_used_first; ///< mru block header in used list
bhdr_T *mf_used_last; ///< lru block header in used list
mf_hashtab_T mf_hash; ///< hash lists
mf_hashtab_T mf_trans; ///< trans lists
blocknr_T mf_blocknr_max; ///< highest positive block number + 1
blocknr_T mf_blocknr_min; ///< lowest negative block number - 1
blocknr_T mf_neg_count; ///< number of negative blocks numbers
blocknr_T mf_infile_count; ///< number of pages in the file
unsigned mf_page_size; ///< number of bytes in a page
mfdirty_T mf_dirty;
} memfile_T;
#endif // NVIM_MEMFILE_DEFS_H

View File

@ -510,6 +510,8 @@ void ml_open_file(buf_T *buf)
continue;
}
if (mf_open_file(mfp, fname) == OK) { // consumes fname!
// don't sync yet in ml_sync_all()
mfp->mf_dirty = MF_DIRTY_YES_NOSYNC;
ml_upd_block0(buf, UB_SAME_DIR);
// Flush block zero, so others can read it
@ -1714,7 +1716,7 @@ void ml_sync_all(int check_file, int check_char, bool do_fsync)
need_check_timestamps = true; // give message later
}
}
if (buf->b_ml.ml_mfp->mf_dirty) {
if (buf->b_ml.ml_mfp->mf_dirty == MF_DIRTY_YES) {
(void)mf_sync(buf->b_ml.ml_mfp, (check_char ? MFS_STOP : 0)
| (do_fsync && bufIsChanged(buf) ? MFS_FLUSH : 0));
if (check_char && os_char_avail()) { // character available now