Patch 9.0.1583
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 #12433)
Files:      src/memfile.c, src/memline.c, src/crypt.c, src/proto/crypt.pro,
            src/structs.h, src/buffer.c, src/fileio.c,
            src/testdir/test_crypt.vim


*** ../vim-9.0.1582/src/memfile.c       2023-04-22 21:14:21.585140551 +0100
--- src/memfile.c       2023-05-27 16:28:42.056761913 +0100
***************
*** 150,156 ****
      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_used_count = 0;
      mf_hash_init(&mfp->mf_hash);
      mf_hash_init(&mfp->mf_trans);
--- 150,156 ----
      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 = MF_DIRTY_NO;
      mfp->mf_used_count = 0;
      mf_hash_init(&mfp->mf_hash);
      mf_hash_init(&mfp->mf_trans);
***************
*** 224,230 ****
      if (mfp->mf_fd < 0)
        return FAIL;
  
!     mfp->mf_dirty = TRUE;
      return OK;
  }
  
--- 224,230 ----
      if (mfp->mf_fd < 0)
        return FAIL;
  
!     mfp->mf_dirty = MF_DIRTY_YES;
      return OK;
  }
  
***************
*** 386,392 ****
        }
      }
      hp->bh_flags = BH_LOCKED | BH_DIRTY;      // new block is always dirty
!     mfp->mf_dirty = TRUE;
      hp->bh_page_count = page_count;
      mf_ins_used(mfp, hp);
      mf_ins_hash(mfp, hp);
--- 386,392 ----
        }
      }
      hp->bh_flags = BH_LOCKED | BH_DIRTY;      // new block is always dirty
!     mfp->mf_dirty = MF_DIRTY_YES;
      hp->bh_page_count = page_count;
      mf_ins_used(mfp, hp);
      mf_ins_hash(mfp, hp);
***************
*** 483,489 ****
      if (dirty)
      {
        flags |= BH_DIRTY;
!       mfp->mf_dirty = TRUE;
      }
      hp->bh_flags = flags;
      if (infile)
--- 483,490 ----
      if (dirty)
      {
        flags |= BH_DIRTY;
!       if (mfp->mf_dirty != MF_DIRTY_YES_NOSYNC)
!           mfp->mf_dirty = MF_DIRTY_YES;
      }
      hp->bh_flags = flags;
      if (infile)
***************
*** 528,536 ****
      bhdr_T    *hp;
      int               got_int_save = got_int;
  
!     if (mfp->mf_fd < 0)           // there is no file, nothing to do
      {
!       mfp->mf_dirty = FALSE;
        return FAIL;
      }
  
--- 529,538 ----
      bhdr_T    *hp;
      int               got_int_save = got_int;
  
!     if (mfp->mf_fd < 0)
      {
!       // there is no file, nothing to do
!       mfp->mf_dirty = MF_DIRTY_NO;
        return FAIL;
      }
  
***************
*** 576,582 ****
       * In case of an error this flag is also set, to avoid trying all the 
time.
       */
      if (hp == NULL || status == FAIL)
!       mfp->mf_dirty = FALSE;
  
      if ((flags & MFS_FLUSH) && *p_sws != NUL)
      {
--- 578,584 ----
       * In case of an error this flag is also set, to avoid trying all the 
time.
       */
      if (hp == NULL || status == FAIL)
!       mfp->mf_dirty = MF_DIRTY_NO;
  
      if ((flags & MFS_FLUSH) && *p_sws != NUL)
      {
***************
*** 675,681 ****
      for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
        if (hp->bh_bnum > 0)
            hp->bh_flags |= BH_DIRTY;
!     mfp->mf_dirty = TRUE;
  }
  
  /*
--- 677,683 ----
      for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
        if (hp->bh_bnum > 0)
            hp->bh_flags |= BH_DIRTY;
!     mfp->mf_dirty = MF_DIRTY_YES;
  }
  
  /*
*** ../vim-9.0.1582/src/memline.c       2023-04-27 21:13:09.184215933 +0100
--- src/memline.c       2023-05-27 16:29:35.588799270 +0100
***************
*** 64,70 ****
  #define BLOCK0_ID1_C0  'c'                // block 0 id 1 'cm' 0
  #define BLOCK0_ID1_C1  'C'                // block 0 id 1 'cm' 1
  #define BLOCK0_ID1_C2  'd'                // block 0 id 1 'cm' 2
! // BLOCK0_ID1_C3 and BLOCK0_ID1_C4 are for libsodium enctyption.  However, for
  // these the swapfile is disabled, thus they will not be used.  Added for
  // consistency anyway.
  #define BLOCK0_ID1_C3  'S'                // block 0 id 1 'cm' 3
--- 64,70 ----
  #define BLOCK0_ID1_C0  'c'                // block 0 id 1 'cm' 0
  #define BLOCK0_ID1_C1  'C'                // block 0 id 1 'cm' 1
  #define BLOCK0_ID1_C2  'd'                // block 0 id 1 'cm' 2
! // BLOCK0_ID1_C3 and BLOCK0_ID1_C4 are for libsodium encryption.  However, for
  // these the swapfile is disabled, thus they will not be used.  Added for
  // consistency anyway.
  #define BLOCK0_ID1_C3  'S'                // block 0 id 1 'cm' 3
***************
*** 807,812 ****
--- 807,814 ----
            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;
  #if defined(MSWIN)
            /*
             * set full pathname for swap file now, because a ":!cd dir" may
***************
*** 939,945 ****
                && b0p->b0_id[1] != BLOCK0_ID1_C0
                && b0p->b0_id[1] != BLOCK0_ID1_C1
                && b0p->b0_id[1] != BLOCK0_ID1_C2
!               && b0p->b0_id[1] != BLOCK0_ID1_C3)
            )
        return FAIL;
      return OK;
--- 941,948 ----
                && b0p->b0_id[1] != BLOCK0_ID1_C0
                && b0p->b0_id[1] != BLOCK0_ID1_C1
                && b0p->b0_id[1] != BLOCK0_ID1_C2
!               && b0p->b0_id[1] != BLOCK0_ID1_C3
!               && b0p->b0_id[1] != BLOCK0_ID1_C4)
            )
        return FAIL;
      return OK;
***************
*** 2513,2519 ****
                need_check_timestamps = TRUE;   // give message later
            }
        }
!       if (buf->b_ml.ml_mfp->mf_dirty)
        {
            (void)mf_sync(buf->b_ml.ml_mfp, (check_char ? MFS_STOP : 0)
                                        | (bufIsChanged(buf) ? MFS_FLUSH : 0));
--- 2516,2522 ----
                need_check_timestamps = TRUE;   // give message later
            }
        }
!       if (buf->b_ml.ml_mfp->mf_dirty == MF_DIRTY_YES)
        {
            (void)mf_sync(buf->b_ml.ml_mfp, (check_char ? MFS_STOP : 0)
                                        | (bufIsChanged(buf) ? MFS_FLUSH : 0));
*** ../vim-9.0.1582/src/crypt.c 2023-05-20 16:39:03.337433572 +0100
--- src/crypt.c 2023-05-27 17:48:30.240642842 +0100
***************
*** 525,531 ****
      if (arg.cat_seed_len > 0)
        arg.cat_seed = header + CRYPT_MAGIC_LEN + arg.cat_salt_len;
      if (arg.cat_add_len > 0)
!       arg.cat_add = header + CRYPT_MAGIC_LEN + arg.cat_salt_len + 
arg.cat_seed_len;
  
      return crypt_create(method_nr, key, &arg);
  }
--- 525,532 ----
      if (arg.cat_seed_len > 0)
        arg.cat_seed = header + CRYPT_MAGIC_LEN + arg.cat_salt_len;
      if (arg.cat_add_len > 0)
!       arg.cat_add = header + CRYPT_MAGIC_LEN
!                                        + arg.cat_salt_len + arg.cat_seed_len;
  
      return crypt_create(method_nr, key, &arg);
  }
***************
*** 603,609 ****
        if (arg.cat_seed_len > 0)
            arg.cat_seed = *header + CRYPT_MAGIC_LEN + arg.cat_salt_len;
        if (arg.cat_add_len > 0)
!           arg.cat_add = *header + CRYPT_MAGIC_LEN + arg.cat_salt_len + 
arg.cat_seed_len;
  
        // TODO: Should this be crypt method specific? (Probably not worth
        // it).  sha2_seed is pretty bad for large amounts of entropy, so make
--- 604,611 ----
        if (arg.cat_seed_len > 0)
            arg.cat_seed = *header + CRYPT_MAGIC_LEN + arg.cat_salt_len;
        if (arg.cat_add_len > 0)
!           arg.cat_add = *header + CRYPT_MAGIC_LEN
!                                        + arg.cat_salt_len + arg.cat_seed_len;
  
        // TODO: Should this be crypt method specific? (Probably not worth
        // it).  sha2_seed is pretty bad for large amounts of entropy, so make
***************
*** 795,804 ****
      }
  }
  
! #ifdef FEAT_SODIUM
!     static void
  crypt_check_swapfile_curbuf(void)
  {
      int method = crypt_get_method_nr(curbuf);
      if (crypt_method_is_sodium(method))
      {
--- 797,810 ----
      }
  }
  
! /*
!  * If the crypt method for "curbuf" does not support encrypting the swap file
!  * then disable the swap file.
!  */
!     void
  crypt_check_swapfile_curbuf(void)
  {
+ #ifdef FEAT_SODIUM
      int method = crypt_get_method_nr(curbuf);
      if (crypt_method_is_sodium(method))
      {
***************
*** 809,816 ****
        msg_scroll = TRUE;
        msg(_("Note: Encryption of swapfile not supported, disabling swap 
file"));
      }
- }
  #endif
  
      void
  crypt_check_current_method(void)
--- 815,822 ----
        msg_scroll = TRUE;
        msg(_("Note: Encryption of swapfile not supported, disabling swap 
file"));
      }
  #endif
+ }
  
      void
  crypt_check_current_method(void)
***************
*** 863,871 ****
                set_option_value_give_err((char_u *)"key", 0L, p1, OPT_LOCAL);
                crypt_free_key(p1);
                p1 = curbuf->b_p_key;
- #ifdef FEAT_SODIUM
                crypt_check_swapfile_curbuf();
- #endif
            }
            break;
        }
--- 869,875 ----
***************
*** 959,965 ****
            sodium_free(sd_state);
            return FAIL;
        }
!       if (state->method_nr == CRYPT_M_SOD2)
        {
            memcpy(arg->cat_add, &opslimit, sizeof(opslimit));
            arg->cat_add += sizeof(opslimit);
--- 963,970 ----
            sodium_free(sd_state);
            return FAIL;
        }
!       // "cat_add" should not be NULL, check anyway for safety
!       if (state->method_nr == CRYPT_M_SOD2 && arg->cat_add != NULL)
        {
            memcpy(arg->cat_add, &opslimit, sizeof(opslimit));
            arg->cat_add += sizeof(opslimit);
*** ../vim-9.0.1582/src/proto/crypt.pro 2023-04-23 17:50:14.853935966 +0100
--- src/proto/crypt.pro 2023-05-27 17:41:05.316792383 +0100
***************
*** 22,27 ****
--- 22,28 ----
  void crypt_decode_inplace(cryptstate_T *state, char_u *buf, size_t len, int 
last);
  void crypt_free_key(char_u *key);
  void crypt_check_method(int method);
+ void crypt_check_swapfile_curbuf(void);
  void crypt_check_current_method(void);
  char_u *crypt_get_key(int store, int twice);
  void crypt_append_msg(buf_T *buf);
*** ../vim-9.0.1582/src/structs.h       2023-05-06 22:21:07.247211940 +0100
--- src/structs.h       2023-05-27 17:22:02.661070039 +0100
***************
*** 691,696 ****
--- 691,702 ----
      int               cmod_did_esilent;       // incremented when emsg_silent 
is
  } cmdmod_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;
+ 
  #define MF_SEED_LEN   8
  
  struct memfile
***************
*** 712,718 ****
      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
!     int               mf_dirty;               // TRUE if there are dirty 
blocks
  #ifdef FEAT_CRYPT
      buf_T     *mf_buffer;             // buffer this memfile is for
      char_u    mf_seed[MF_SEED_LEN];   // seed for encryption
--- 718,724 ----
      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;
  #ifdef FEAT_CRYPT
      buf_T     *mf_buffer;             // buffer this memfile is for
      char_u    mf_seed[MF_SEED_LEN];   // seed for encryption
*** ../vim-9.0.1582/src/buffer.c        2023-05-23 18:00:53.947320728 +0100
--- src/buffer.c        2023-05-27 17:15:39.001590554 +0100
***************
*** 218,223 ****
--- 218,227 ----
        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);
***************
*** 298,303 ****
--- 302,312 ----
            retval = read_buffer(TRUE, eap, flags);
      }
  
+     // 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)
      {
*** ../vim-9.0.1582/src/fileio.c        2023-04-23 17:50:14.853935966 +0100
--- src/fileio.c        2023-05-27 17:41:25.320790220 +0100
***************
*** 125,130 ****
--- 125,131 ----
      exarg_T   *eap,                   // can be NULL!
      int               flags)
  {
+     int               retval = FAIL;  // jump to "theend" instead of returning
      int               fd = 0;
      int               newfile = (flags & READ_NEW);
      int               check_readonly;
***************
*** 239,245 ****
            && !(flags & READ_DUMMY))
      {
        if (set_rw_fname(fname, sfname) == FAIL)
!           return FAIL;
      }
  
      // Remember the initial values of curbuf, curbuf->b_ffname and
--- 240,246 ----
            && !(flags & READ_DUMMY))
      {
        if (set_rw_fname(fname, sfname) == FAIL)
!           goto theend;
      }
  
      // Remember the initial values of curbuf, curbuf->b_ffname and
***************
*** 289,323 ****
            if (apply_autocmds_exarg(EVENT_BUFREADCMD, NULL, sfname,
                                                          FALSE, curbuf, eap))
            {
!               int status = OK;
  #ifdef FEAT_EVAL
                if (aborting())
!                   status = FAIL;
  #endif
                // The BufReadCmd code usually uses ":read" to get the text and
                // perhaps ":file" to change the buffer name. But we should
                // consider this to work like ":edit", thus reset the
                // BF_NOTEDITED flag.  Then ":write" will work to overwrite the
                // same file.
!               if (status == OK)
                    curbuf->b_flags &= ~BF_NOTEDITED;
!               return status;
            }
        }
        else if (apply_autocmds_exarg(EVENT_FILEREADCMD, sfname, sfname,
                                                            FALSE, NULL, eap))
  #ifdef FEAT_EVAL
!           return aborting() ? FAIL : OK;
  #else
!           return OK;
  #endif
  
        curbuf->b_op_start = orig_start;
  
        if (flags & READ_NOFILE)
            // Return NOTDONE instead of FAIL so that BufEnter can be triggered
            // and other operations don't fail.
!           return NOTDONE;
      }
  
      if ((shortmess(SHM_OVER) || curbuf->b_help) && p_verbose == 0)
--- 290,330 ----
            if (apply_autocmds_exarg(EVENT_BUFREADCMD, NULL, sfname,
                                                          FALSE, curbuf, eap))
            {
!               retval = OK;
  #ifdef FEAT_EVAL
                if (aborting())
!                   retval = FAIL;
  #endif
                // The BufReadCmd code usually uses ":read" to get the text and
                // perhaps ":file" to change the buffer name. But we should
                // consider this to work like ":edit", thus reset the
                // BF_NOTEDITED flag.  Then ":write" will work to overwrite the
                // same file.
!               if (retval == OK)
                    curbuf->b_flags &= ~BF_NOTEDITED;
!               goto theend;
            }
        }
        else if (apply_autocmds_exarg(EVENT_FILEREADCMD, sfname, sfname,
                                                            FALSE, NULL, eap))
+       {
  #ifdef FEAT_EVAL
!           retval = aborting() ? FAIL : OK;
  #else
!           retval = OK;
  #endif
+           goto theend;
+       }
  
        curbuf->b_op_start = orig_start;
  
        if (flags & READ_NOFILE)
+       {
            // Return NOTDONE instead of FAIL so that BufEnter can be triggered
            // and other operations don't fail.
!           retval = NOTDONE;
!           goto theend;
!       }
      }
  
      if ((shortmess(SHM_OVER) || curbuf->b_help) && p_verbose == 0)
***************
*** 335,341 ****
            filemess(curbuf, fname, (char_u *)_("Illegal file name"), 0);
            msg_end();
            msg_scroll = msg_save;
!           return FAIL;
        }
  
        // If the name ends in a path separator, we can't open it.  Check here,
--- 342,348 ----
            filemess(curbuf, fname, (char_u *)_("Illegal file name"), 0);
            msg_end();
            msg_scroll = msg_save;
!           goto theend;
        }
  
        // If the name ends in a path separator, we can't open it.  Check here,
***************
*** 346,352 ****
            filemess(curbuf, fname, (char_u *)_(msg_is_a_directory), 0);
            msg_end();
            msg_scroll = msg_save;
!           return NOTDONE;
        }
      }
  
--- 353,360 ----
            filemess(curbuf, fname, (char_u *)_(msg_is_a_directory), 0);
            msg_end();
            msg_scroll = msg_save;
!           retval = NOTDONE;
!           goto theend;
        }
      }
  
***************
*** 367,374 ****
  # endif
                                                )
        {
-           int retval = FAIL;
- 
            if (S_ISDIR(perm))
            {
                filemess(curbuf, fname, (char_u *)_(msg_is_a_directory), 0);
--- 375,380 ----
***************
*** 378,384 ****
                filemess(curbuf, fname, (char_u *)_("is not a file"), 0);
            msg_end();
            msg_scroll = msg_save;
!           return retval;
        }
  #endif
  #if defined(MSWIN)
--- 384,390 ----
                filemess(curbuf, fname, (char_u *)_("is not a file"), 0);
            msg_end();
            msg_scroll = msg_save;
!           goto theend;
        }
  #endif
  #if defined(MSWIN)
***************
*** 391,397 ****
            filemess(curbuf, fname, (char_u *)_("is a device (disabled with 
'opendevice' option)"), 0);
            msg_end();
            msg_scroll = msg_save;
!           return FAIL;
        }
  #endif
      }
--- 397,403 ----
            filemess(curbuf, fname, (char_u *)_("is a device (disabled with 
'opendevice' option)"), 0);
            msg_end();
            msg_scroll = msg_save;
!           goto theend;
        }
  #endif
      }
***************
*** 534,540 ****
                                         && (old_b_fname != curbuf->b_fname)))
                        {
                            
emsg(_(e_autocommands_changed_buffer_or_buffer_name));
!                           return FAIL;
                        }
                    }
                    if (dir_of_file_exists(fname))
--- 540,546 ----
                                         && (old_b_fname != curbuf->b_fname)))
                        {
                            
emsg(_(e_autocommands_changed_buffer_or_buffer_name));
!                           goto theend;
                        }
                    }
                    if (dir_of_file_exists(fname))
***************
*** 557,566 ****
                    save_file_ff(curbuf);
  
  #if defined(FEAT_EVAL)
!                   if (aborting())   // autocmds may abort script processing
!                       return FAIL;
  #endif
!                   return OK;      // a new file is not an error
                }
                else
                {
--- 563,572 ----
                    save_file_ff(curbuf);
  
  #if defined(FEAT_EVAL)
!                   if (!aborting())   // autocmds may abort script processing
  #endif
!                       retval = OK;        // a new file is not an error
!                   goto theend;
                }
                else
                {
***************
*** 576,582 ****
                }
            }
  
!       return FAIL;
      }
  
      /*
--- 582,588 ----
                }
            }
  
!       goto theend;
      }
  
      /*
***************
*** 614,620 ****
            emsg(_(e_autocommands_changed_buffer_or_buffer_name));
            if (!read_buffer)
                close(fd);
!           return FAIL;
        }
  #ifdef UNIX
        // Set swap file protection bits after creating it.
--- 620,626 ----
            emsg(_(e_autocommands_changed_buffer_or_buffer_name));
            if (!read_buffer)
                close(fd);
!           goto theend;
        }
  #ifdef UNIX
        // Set swap file protection bits after creating it.
***************
*** 654,660 ****
      {
        if (!read_buffer && !read_stdin)
            close(fd);
!       return FAIL;
      }
  
      ++no_wait_return;     // don't wait for return yet
--- 660,666 ----
      {
        if (!read_buffer && !read_stdin)
            close(fd);
!       goto theend;
      }
  
      ++no_wait_return;     // don't wait for return yet
***************
*** 715,721 ****
            --no_wait_return;
            msg_scroll = msg_save;
            curbuf->b_p_ro = TRUE;      // must use "w!" now
!           return FAIL;
        }
  #endif
        /*
--- 721,727 ----
            --no_wait_return;
            msg_scroll = msg_save;
            curbuf->b_p_ro = TRUE;      // must use "w!" now
!           goto theend;
        }
  #endif
        /*
***************
*** 737,743 ****
            else
                emsg(_(e_readpre_autocommands_must_not_change_current_buffer));
            curbuf->b_p_ro = TRUE;      // must use "w!" now
!           return FAIL;
        }
      }
  
--- 743,749 ----
            else
                emsg(_(e_readpre_autocommands_must_not_change_current_buffer));
            curbuf->b_p_ro = TRUE;      // must use "w!" now
!           goto theend;
        }
      }
  
***************
*** 2461,2467 ****
  #ifdef FEAT_VIMINFO
            check_marks_read();
  #endif
!           return OK;          // an interrupt isn't really an error
        }
  
        if (!filtering && !(flags & READ_DUMMY))
--- 2467,2474 ----
  #ifdef FEAT_VIMINFO
            check_marks_read();
  #endif
!           retval = OK;        // an interrupt isn't really an error
!           goto theend;
        }
  
        if (!filtering && !(flags & READ_DUMMY))
***************
*** 2696,2708 ****
            msg_scroll = m;
  # ifdef FEAT_EVAL
        if (aborting())     // autocmds may abort script processing
!           return FAIL;
  # endif
      }
  
!     if (recoverymode && error)
!       return FAIL;
!     return OK;
  }
  
  #if defined(OPEN_CHR_FILES) || defined(PROTO)
--- 2703,2722 ----
            msg_scroll = m;
  # ifdef FEAT_EVAL
        if (aborting())     // autocmds may abort script processing
!           goto theend;
  # endif
      }
  
!     if (!(recoverymode && error))
!       retval = 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;
  }
  
  #if defined(OPEN_CHR_FILES) || defined(PROTO)
***************
*** 2941,2947 ****
--- 2955,2964 ----
        if (cryptkey == NULL && !*did_ask)
        {
            if (*curbuf->b_p_key)
+           {
                cryptkey = curbuf->b_p_key;
+               crypt_check_swapfile_curbuf();
+           }
            else
            {
                // When newfile is TRUE, store the typed key in the 'key'
*** ../vim-9.0.1582/src/testdir/test_crypt.vim  2023-04-25 15:27:23.355582228 
+0100
--- src/testdir/test_crypt.vim  2023-05-27 17:47:35.220670356 +0100
***************
*** 1,5 ****
--- 1,6 ----
  " Tests for encryption.
  
+ source shared.vim
  source check.vim
  CheckFeature cryptv
  
***************
*** 88,93 ****
--- 89,117 ----
    call Crypt_uncrypt('xchacha20v2')
  endfunc
  
+ func Test_crypt_sodium_v2_startup()
+   CheckFeature sodium
+   CheckRunVimInTerminal
+ 
+   let buf = RunVimInTerminal('--cmd "set cm=xchacha20v2" -x Xfoo', 
#{wait_for_ruler: 0, rows: 6})
+   call g:TermWait(buf, g:RunningWithValgrind() ? 1000 : 50)
+   call term_sendkeys(buf, "foo\<CR>foo\<CR>")
+   call term_sendkeys(buf, "ifoo\<Esc>")
+   call term_sendkeys(buf, "ZZ")
+   call TermWait(buf)
+ 
+   " Wait for Vim to write the file and exit.  Then wipe out the terminal 
buffer.
+   call WaitForAssert({-> assert_equal("finished", term_getstatus(buf))})
+   exe buf .. 'bwipe!'
+   call assert_true(filereadable('Xfoo'))
+ 
+   let buf = RunVimInTerminal('--cmd "set ch=3 cm=xchacha20v2 key=foo" Xfoo', 
#{rows: 10})
+   call g:TermWait(buf, g:RunningWithValgrind() ? 1000 : 50)
+   call StopVimInTerminal(buf)
+ 
+   call delete('Xfoo')
+ endfunc
+ 
  func Uncrypt_stable(method, crypted_text, key, uncrypted_text)
    split Xtest.txt
    set bin noeol key= fenc=latin1
*** ../vim-9.0.1582/src/version.c       2023-05-27 14:10:04.319182880 +0100
--- src/version.c       2023-05-27 17:44:31.116746546 +0100
***************
*** 697,698 ****
--- 697,700 ----
  {   /* Add new patch number below this line */
+ /**/
+     1583,
  /**/

-- 
>From "know your smileys":
 y:-)   Bad toupee

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20230527170328.DCD091C0B0E%40moolenaar.net.

Raspunde prin e-mail lui