vim-patch:8.1.1413: error when the drive of the swap file was disconnected (#30009)

Problem:    Error when the drive of the swap file was disconnected.
Solution:   Try closing and re-opening the swap file. (closes vim/vim#4378)

b58a4b938c

Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
zeertzjq 2024-08-08 16:11:53 +08:00 committed by GitHub
parent 2f1ea1133a
commit a89088b7a0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 41 additions and 16 deletions

View File

@ -566,7 +566,8 @@ static int mf_write(memfile_T *mfp, bhdr_T *hp)
bhdr_T *hp2;
unsigned page_count; // number of pages 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;
}
@ -593,28 +594,48 @@ static int mf_write(memfile_T *mfp, bhdr_T *hp)
// TODO(elmart): Check (page_size * nr) within off_T bounds.
off_T offset = (off_T)(page_size * nr); // offset in the file
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;
}
unsigned size = page_size * page_count; // number of bytes written
void *data = (hp2 == NULL) ? hp->bh_data : hp2->bh_data;
if ((unsigned)write_eintr(mfp->mf_fd, data, size) != size) {
/// 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"));
for (int attempt = 1; attempt <= 2; attempt++) {
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;
}
void *data = (hp2 == NULL) ? hp->bh_data : hp2->bh_data;
if ((unsigned)write_eintr(mfp->mf_fd, data, size) == size) {
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 = os_open(mfp->mf_fname, mfp->mf_flags, S_IREAD | S_IWRITE);
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 = true;
return FAIL;
}
did_swapwrite_msg = false;
if (hp2 != NULL) { // written a non-dummy block
hp2->bh_flags &= ~BH_DIRTY;
@ -751,7 +772,9 @@ static bool mf_do_open(memfile_T *mfp, char *fname, int flags)
emsg(_("E300: Swap file already exists (symlink attack?)"));
} else {
// try to open the file
mfp->mf_fd = os_open(mfp->mf_fname, flags | O_NOFOLLOW, S_IREAD | S_IWRITE);
flags |= O_NOFOLLOW;
mfp->mf_flags = flags;
mfp->mf_fd = os_open(mfp->mf_fname, flags, S_IREAD | S_IWRITE);
}
// If the file cannot be opened, use memory only

View File

@ -46,6 +46,8 @@ typedef struct {
char *mf_fname; ///< name of the file
char *mf_ffname; ///< idem, full path
int mf_fd; ///< file descriptor
int mf_flags; ///< flags used when opening this memfile
bool mf_reopen; ///< mf_fd was closed, retry opening
bhdr_T *mf_free_first; ///< first block header in free list
/// The used blocks are kept in mf_hash.