]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.1.1413: error when the drive of the swap file was disconnected v8.1.1413
authorBram Moolenaar <Bram@vim.org>
Mon, 27 May 2019 21:36:21 +0000 (23:36 +0200)
committerBram Moolenaar <Bram@vim.org>
Mon, 27 May 2019 21:36:21 +0000 (23:36 +0200)
Problem:    Error when the drive of the swap file was disconnected.
Solution:   Try closing and re-opening the swap file. (closes #4378)

src/memfile.c
src/structs.h
src/testdir/test_startup.vim
src/version.c

index 9a1b4cb1c641e035d5bc71312975d5ecf7eb3b43..5bc587c1f6ed1c042ffb481bd830730f87cd50fc 100644 (file)
@@ -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);
     }
 
index 07dc7e3befe807a2a6753a269e2971e575ab59ab..79681cc2a83fb4c0b0c86972449ff8e46d022f13 100644 (file)
@@ -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 */
+    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. */
+    // 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];
index 33257f79f4b546b6cb3c744ee74ba2b62adeee20..0ce8c81e6d31daac123343eab922e5d108452e18 100644 (file)
@@ -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
 
index d5221414ff07f2e5106d7557732c198730585e2b..240aa702c6ef4cf10e9f93db3568719594bcb115 100644 (file)
@@ -767,6 +767,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1413,
 /**/
     1412,
 /**/