changeset 16823:b1b7c7a31679 v8.1.1413

patch 8.1.1413: error when the drive of the swap file was disconnected commit https://github.com/vim/vim/commit/b58a4b938c4bc7e0499700859bd7abba9acc5b11 Author: Bram Moolenaar <Bram@vim.org> Date: Mon May 27 23:36:21 2019 +0200 patch 8.1.1413: error when the drive of the swap file was disconnected Problem: Error when the drive of the swap file was disconnected. Solution: Try closing and re-opening the swap file. (closes https://github.com/vim/vim/issues/4378)
author Bram Moolenaar <Bram@vim.org>
date Mon, 27 May 2019 23:45:04 +0200
parents 26751afbadf0
children 1f6bb29738d2
files src/memfile.c src/structs.h src/testdir/test_startup.vim src/version.c
diffstat 4 files changed, 74 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- a/src/memfile.c
+++ b/src/memfile.c
@@ -994,7 +994,8 @@ mf_write(memfile_T *mfp, bhdr_T *hp)
     unsigned	page_count; /* number of pages written */
     unsigned	size;	    /* number of bytes written */
 
-    if (mfp->mf_fd < 0)	    /* there is no file, can't write */
+    if (mfp->mf_fd < 0 && !mfp->mf_reopen)
+	// there is no file and there was no file, can't write
 	return FAIL;
 
     if (hp->bh_bnum < 0)	/* must assign file block number */
@@ -1011,6 +1012,8 @@ mf_write(memfile_T *mfp, bhdr_T *hp)
      */
     for (;;)
     {
+	int attempt;
+
 	nr = hp->bh_bnum;
 	if (nr > mfp->mf_infile_count)		/* beyond end of file */
 	{
@@ -1021,29 +1024,49 @@ mf_write(memfile_T *mfp, bhdr_T *hp)
 	    hp2 = hp;
 
 	offset = (off_T)page_size * nr;
-	if (vim_lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
-	{
-	    PERROR(_("E296: Seek error in swap file write"));
-	    return FAIL;
-	}
 	if (hp2 == NULL)	    /* freed block, fill with dummy data */
 	    page_count = 1;
 	else
 	    page_count = hp2->bh_page_count;
 	size = page_size * page_count;
-	if (mf_write_block(mfp, hp2 == NULL ? hp : hp2, offset, size) == FAIL)
+
+	for (attempt = 1; attempt <= 2; ++attempt)
 	{
-	    /*
-	     * Avoid repeating the error message, this mostly happens when the
-	     * disk is full. We give the message again only after a successful
-	     * write or when hitting a key. We keep on trying, in case some
-	     * space becomes available.
-	     */
-	    if (!did_swapwrite_msg)
-		emsg(_("E297: Write error in swap file"));
-	    did_swapwrite_msg = TRUE;
-	    return FAIL;
+	    if (mfp->mf_fd >= 0)
+	    {
+		if (vim_lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
+		{
+		    PERROR(_("E296: Seek error in swap file write"));
+		    return FAIL;
+		}
+		if (mf_write_block(mfp,
+				   hp2 == NULL ? hp : hp2, offset, size) == OK)
+		    break;
+	    }
+
+	    if (attempt == 1)
+	    {
+		// If the swap file is on a network drive, and the network
+		// gets disconnected and then re-connected, we can maybe fix it
+		// by closing and then re-opening the file.
+		if (mfp->mf_fd >= 0)
+		    close(mfp->mf_fd);
+		mfp->mf_fd = mch_open_rw((char *)mfp->mf_fname, mfp->mf_flags);
+		mfp->mf_reopen = (mfp->mf_fd < 0);
+	    }
+	    if (attempt == 2 || mfp->mf_fd < 0)
+	    {
+		// Avoid repeating the error message, this mostly happens when
+		// the disk is full. We give the message again only after a
+		// successful write or when hitting a key. We keep on trying,
+		// in case some space becomes available.
+		if (!did_swapwrite_msg)
+		    emsg(_("E297: Write error in swap file"));
+		did_swapwrite_msg = TRUE;
+		return FAIL;
+	    }
 	}
+
 	did_swapwrite_msg = FALSE;
 	if (hp2 != NULL)		    /* written a non-dummy block */
 	    hp2->bh_flags &= ~BH_DIRTY;
@@ -1271,6 +1294,7 @@ mf_do_open(
 	 * the file) */
 	flags |= O_NOINHERIT;
 #endif
+	mfp->mf_flags = flags;
 	mfp->mf_fd = mch_open_rw((char *)mfp->mf_fname, flags);
     }
 
--- a/src/structs.h
+++ b/src/structs.h
@@ -604,28 +604,30 @@ typedef struct
 
 struct memfile
 {
-    char_u	*mf_fname;		/* name of the file */
-    char_u	*mf_ffname;		/* idem, full path */
-    int		mf_fd;			/* file descriptor */
-    bhdr_T	*mf_free_first;		/* first block_hdr in free list */
-    bhdr_T	*mf_used_first;		/* mru block_hdr in used list */
-    bhdr_T	*mf_used_last;		/* lru block_hdr in used list */
-    unsigned	mf_used_count;		/* number of pages in used list */
-    unsigned	mf_used_count_max;	/* maximum number of pages in memory */
-    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 */
-    int		mf_dirty;		/* TRUE if there are dirty blocks */
+    char_u	*mf_fname;		// name of the file
+    char_u	*mf_ffname;		// idem, full path
+    int		mf_fd;			// file descriptor
+    int		mf_flags;		// flags used when opening this memfile
+    int		mf_reopen;		// mf_fd was closed, retry opening
+    bhdr_T	*mf_free_first;		// first block_hdr in free list
+    bhdr_T	*mf_used_first;		// mru block_hdr in used list
+    bhdr_T	*mf_used_last;		// lru block_hdr in used list
+    unsigned	mf_used_count;		// number of pages in used list
+    unsigned	mf_used_count_max;	// maximum number of pages in memory
+    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
+    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 */
-
-    /* Values for key, method and seed used for reading data blocks when
-     * updating for a newly set key or method. Only when mf_old_key != NULL. */
+    buf_T	*mf_buffer;		// buffer this memfile is for
+    char_u	mf_seed[MF_SEED_LEN];	// seed for encryption
+
+    // Values for key, method and seed used for reading data blocks when
+    // updating for a newly set key or method. Only when mf_old_key != NULL.
     char_u	*mf_old_key;
     int		mf_old_cm;
     char_u	mf_old_seed[MF_SEED_LEN];
--- a/src/testdir/test_startup.vim
+++ b/src/testdir/test_startup.vim
@@ -288,24 +288,24 @@ func Test_q_arg()
 
   " Test with default argument '-q'.
   call assert_equal('errors.err', &errorfile)
-  call writefile(["../memfile.c:1482:5: error: expected ';' before '}' token"], 'errors.err')
+  call writefile(["../memfile.c:208:5: error: expected ';' before '}' token"], 'errors.err')
   if RunVim([], after, '-q')
     let lines = readfile('Xtestout')
     call assert_equal(['errors.err',
-	\              '[0, 1482, 5, 0]',
-	\              source_file . "|1482 col 5| error: expected ';' before '}' token"],
+	\              '[0, 208, 5, 0]',
+	\              source_file . "|208 col 5| error: expected ';' before '}' token"],
 	\             lines)
   endif
   call delete('Xtestout')
   call delete('errors.err')
 
   " Test with explicit argument '-q Xerrors' (with space).
-  call writefile(["../memfile.c:1482:5: error: expected ';' before '}' token"], 'Xerrors')
+  call writefile(["../memfile.c:208:5: error: expected ';' before '}' token"], 'Xerrors')
   if RunVim([], after, '-q Xerrors')
     let lines = readfile('Xtestout')
     call assert_equal(['Xerrors',
-	\              '[0, 1482, 5, 0]',
-	\              source_file . "|1482 col 5| error: expected ';' before '}' token"],
+	\              '[0, 208, 5, 0]',
+	\              source_file . "|208 col 5| error: expected ';' before '}' token"],
 	\             lines)
   endif
   call delete('Xtestout')
@@ -314,8 +314,8 @@ func Test_q_arg()
   if RunVim([], after, '-qXerrors')
     let lines = readfile('Xtestout')
     call assert_equal(['Xerrors',
-	\              '[0, 1482, 5, 0]',
-	\              source_file . "|1482 col 5| error: expected ';' before '}' token"],
+	\              '[0, 208, 5, 0]',
+	\              source_file . "|208 col 5| error: expected ';' before '}' token"],
 	\             lines)
   endif
 
--- a/src/version.c
+++ b/src/version.c
@@ -768,6 +768,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1413,
+/**/
     1412,
 /**/
     1411,