Patch 8.0.0685
Problem: When making backups is disabled and conversion with iconv fails
the written file is truncated. (Luo Chen)
Solution: First try converting the file and write the file only when it did
not fail. (partly by Christian Brabandt)
Files: src/fileio.c, src/testdir/test_writefile.vim
*** ../vim-8.0.0684/src/fileio.c 2017-04-07 19:50:08.691049319 +0200
--- src/fileio.c 2017-06-27 21:23:26.649445699 +0200
***************
*** 3166,3171 ****
--- 3166,3172 ----
int device = FALSE; /* writing to a device */
stat_T st_old;
int prev_got_int = got_int;
+ int checking_conversion;
int file_readonly = FALSE; /* overwritten file is
read-only */
static char *err_readonly = "is read-only (cannot override:
\"W\" in 'cpoptions')";
#if defined(UNIX) /*XXX fix me sometime? */
***************
*** 4344,4776 ****
#endif
/*
! * Open the file "wfname" for writing.
! * We may try to open the file twice: If we can't write to the
! * file and forceit is TRUE we delete the existing file and try to create
! * a new one. If this still fails we may have lost the original file!
! * (this may happen when the user reached his quotum for number of files).
! * Appending will fail if the file does not exist and forceit is FALSE.
! */
! while ((fd = mch_open((char *)wfname, O_WRONLY | O_EXTRA | (append
! ? (forceit ? (O_APPEND | O_CREAT) : O_APPEND)
! : (O_CREAT | O_TRUNC))
! , perm < 0 ? 0666 : (perm & 0777))) < 0)
{
/*
! * A forced write will try to create a new file if the old one is
! * still readonly. This may also happen when the directory is
! * read-only. In that case the mch_remove() will fail.
*/
! if (errmsg == NULL)
! {
! #ifdef UNIX
! stat_T st;
!
! /* Don't delete the file when it's a hard or symbolic link. */
! if ((!newfile && st_old.st_nlink > 1)
! || (mch_lstat((char *)fname, &st) == 0
! && (st.st_dev != st_old.st_dev
! || st.st_ino != st_old.st_ino)))
! errmsg = (char_u *)_("E166: Can't open linked file for
writing");
! else
#endif
{
! errmsg = (char_u *)_("E212: Can't open file for writing");
! if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL
! && perm >= 0)
{
#ifdef UNIX
! /* we write to the file, thus it should be marked
! writable after all */
! if (!(perm & 0200))
! made_writable = TRUE;
! perm |= 0200;
! if (st_old.st_uid != getuid() || st_old.st_gid != getgid())
! perm &= 0777;
#endif
! if (!append) /* don't remove when appending */
! mch_remove(wfname);
! continue;
}
- }
- }
restore_backup:
- {
- stat_T st;
-
- /*
- * If we failed to open the file, we don't need a backup. Throw it
- * away. If we moved or removed the original file try to put the
- * backup in its place.
- */
- if (backup != NULL && wfname == fname)
- {
- if (backup_copy)
{
/*
! * There is a small chance that we removed the original,
! * try to move the copy in its place.
! * This may not work if the vim_rename() fails.
! * In that case we leave the copy around.
*/
! /* If file does not exist, put the copy in its place */
! if (mch_stat((char *)fname, &st) < 0)
! vim_rename(backup, fname);
! /* if original file does exist throw away the copy */
! if (mch_stat((char *)fname, &st) >= 0)
! mch_remove(backup);
! }
! else
! {
! /* try to put the original file back */
! vim_rename(backup, fname);
! }
! }
! /* if original file no longer exists give an extra warning */
! if (!newfile && mch_stat((char *)fname, &st) < 0)
! end = 0;
! }
#ifdef FEAT_MBYTE
! if (wfname != fname)
! vim_free(wfname);
#endif
! goto fail;
! }
! errmsg = NULL;
#if defined(MACOS_CLASSIC) || defined(WIN3264)
! /* TODO: Is it need for MACOS_X? (Dany) */
! /*
! * On macintosh copy the original files attributes (i.e. the backup)
! * This is done in order to preserve the resource fork and the
! * Finder attribute (label, comments, custom icons, file creator)
! */
! if (backup != NULL && overwriting && !append)
! {
! if (backup_copy)
! (void)mch_copy_file_attribute(wfname, backup);
! else
! (void)mch_copy_file_attribute(backup, wfname);
! }
! if (!overwriting && !append)
! {
! if (buf->b_ffname != NULL)
! (void)mch_copy_file_attribute(buf->b_ffname, wfname);
! /* Should copy resource fork */
! }
#endif
- write_info.bw_fd = fd;
-
#ifdef FEAT_CRYPT
! if (*buf->b_p_key != NUL && !filtering)
! {
! char_u *header;
! int header_len;
! buf->b_cryptstate = crypt_create_for_writing(crypt_get_method_nr(buf),
! buf->b_p_key, &header, &header_len);
! if (buf->b_cryptstate == NULL || header == NULL)
! end = 0;
! else
! {
! /* Write magic number, so that Vim knows how this file is
! * encrypted when reading it back. */
! write_info.bw_buf = header;
! write_info.bw_len = header_len;
! write_info.bw_flags = FIO_NOCONVERT;
! if (buf_write_bytes(&write_info) == FAIL)
! end = 0;
! wb_flags |= FIO_ENCRYPTED;
! vim_free(header);
! }
! }
#endif
! write_info.bw_buf = buffer;
! nchars = 0;
! /* use "++bin", "++nobin" or 'binary' */
! if (eap != NULL && eap->force_bin != 0)
! write_bin = (eap->force_bin == FORCE_BIN);
! else
! write_bin = buf->b_p_bin;
#ifdef FEAT_MBYTE
! /*
! * The BOM is written just after the encryption magic number.
! * Skip it when appending and the file already existed, the BOM only makes
! * sense at the start of the file.
! */
! if (buf->b_p_bomb && !write_bin && (!append || perm < 0))
! {
! write_info.bw_len = make_bom(buffer, fenc);
! if (write_info.bw_len > 0)
{
! /* don't convert, do encryption */
! write_info.bw_flags = FIO_NOCONVERT | wb_flags;
! if (buf_write_bytes(&write_info) == FAIL)
! end = 0;
! else
! nchars += write_info.bw_len;
}
! }
! write_info.bw_start_lnum = start;
#endif
#ifdef FEAT_PERSISTENT_UNDO
! write_undo_file = (buf->b_p_udf && overwriting && !append
! && !filtering && reset_changed);
! if (write_undo_file)
! /* Prepare for computing the hash value of the text. */
! sha256_start(&sha_ctx);
#endif
! write_info.bw_len = bufsize;
#ifdef HAS_BW_FLAGS
! write_info.bw_flags = wb_flags;
#endif
! fileformat = get_fileformat_force(buf, eap);
! s = buffer;
! len = 0;
! for (lnum = start; lnum <= end; ++lnum)
! {
! /*
! * The next while loop is done once for each character written.
! * Keep it fast!
! */
! ptr = ml_get_buf(buf, lnum, FALSE) - 1;
#ifdef FEAT_PERSISTENT_UNDO
! if (write_undo_file)
! sha256_update(&sha_ctx, ptr + 1, (UINT32_T)(STRLEN(ptr + 1) + 1));
#endif
! while ((c = *++ptr) != NUL)
! {
! if (c == NL)
! *s = NUL; /* replace newlines with NULs */
! else if (c == CAR && fileformat == EOL_MAC)
! *s = NL; /* Mac: replace CRs with NLs */
! else
! *s = c;
! ++s;
! if (++len != bufsize)
! continue;
! if (buf_write_bytes(&write_info) == FAIL)
{
! end = 0; /* write error: break loop */
! break;
! }
! nchars += bufsize;
! s = buffer;
! len = 0;
#ifdef FEAT_MBYTE
! write_info.bw_start_lnum = lnum;
#endif
! }
! /* write failed or last line has no EOL: stop here */
! if (end == 0
! || (lnum == end
! && (write_bin || !buf->b_p_fixeol)
! && (lnum == buf->b_no_eol_lnum
! || (lnum == buf->b_ml.ml_line_count && !buf->b_p_eol))))
! {
! ++lnum; /* written the line, count it */
! no_eol = TRUE;
! break;
! }
! if (fileformat == EOL_UNIX)
! *s++ = NL;
! else
! {
! *s++ = CAR; /* EOL_MAC or EOL_DOS: write CR */
! if (fileformat == EOL_DOS) /* write CR-NL */
{
! if (++len == bufsize)
{
! if (buf_write_bytes(&write_info) == FAIL)
{
! end = 0; /* write error: break loop */
! break;
}
! nchars += bufsize;
! s = buffer;
! len = 0;
}
- *s++ = NL;
}
! }
! if (++len == bufsize && end)
! {
! if (buf_write_bytes(&write_info) == FAIL)
{
! end = 0; /* write error: break loop */
! break;
! }
! nchars += bufsize;
! s = buffer;
! len = 0;
! ui_breakcheck();
! if (got_int)
! {
! end = 0; /* Interrupted, break loop */
! break;
}
- }
#ifdef VMS
! /*
! * On VMS there is a problem: newlines get added when writing blocks
! * at a time. Fix it by writing a line at a time.
! * This is much slower!
! * Explanation: VAX/DECC RTL insists that records in some RMS
! * structures end with a newline (carriage return) character, and if
! * they don't it adds one.
! * With other RMS structures it works perfect without this fix.
! */
! if (buf->b_fab_rfm == FAB$C_VFC
! || ((buf->b_fab_rat & (FAB$M_FTN | FAB$M_CR)) != 0))
! {
! int b2write;
! buf->b_fab_mrs = (buf->b_fab_mrs == 0
! ? MIN(4096, bufsize)
! : MIN(buf->b_fab_mrs, bufsize));
! b2write = len;
! while (b2write > 0)
! {
! write_info.bw_len = MIN(b2write, buf->b_fab_mrs);
! if (buf_write_bytes(&write_info) == FAIL)
{
! end = 0;
! break;
}
! b2write -= MIN(b2write, buf->b_fab_mrs);
}
! write_info.bw_len = bufsize;
nchars += len;
- s = buffer;
- len = 0;
}
! #endif
! }
! if (len > 0 && end > 0)
! {
! write_info.bw_len = len;
! if (buf_write_bytes(&write_info) == FAIL)
! end = 0; /* write error */
! nchars += len;
}
! #if defined(UNIX) && defined(HAVE_FSYNC)
! /* On many journalling file systems there is a bug that causes both the
! * original and the backup file to be lost when halting the system right
! * after writing the file. That's because only the meta-data is
! * journalled. Syncing the file slows down the system, but assures it has
! * been written to disk and we don't lose it.
! * For a device do try the fsync() but don't complain if it does not work
! * (could be a pipe).
! * If the 'fsync' option is FALSE, don't fsync(). Useful for laptops. */
! if (p_fs && fsync(fd) != 0 && !device)
{
! errmsg = (char_u *)_("E667: Fsync failed");
! end = 0;
! }
#endif
#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
! /* Probably need to set the security context. */
! if (!backup_copy)
! mch_copy_sec(backup, wfname);
#endif
#ifdef UNIX
! /* When creating a new file, set its owner/group to that of the original
! * file. Get the new device and inode number. */
! if (backup != NULL && !backup_copy)
! {
# ifdef HAVE_FCHOWN
! stat_T st;
! /* don't change the owner when it's already OK, some systems remove
! * permission or ACL stuff */
! if (mch_stat((char *)wfname, &st) < 0
! || st.st_uid != st_old.st_uid
! || st.st_gid != st_old.st_gid)
! {
! ignored = fchown(fd, st_old.st_uid, st_old.st_gid);
! if (perm >= 0) /* set permission again, may have changed */
! (void)mch_setperm(wfname, perm);
! }
# endif
! buf_setino(buf);
! }
! else if (!buf->b_dev_valid)
! /* Set the inode when creating a new file. */
! buf_setino(buf);
#endif
! if (close(fd) != 0)
! {
! errmsg = (char_u *)_("E512: Close failed");
! end = 0;
! }
#ifdef UNIX
! if (made_writable)
! perm &= ~0200; /* reset 'w' bit for security reasons */
#endif
! if (perm >= 0) /* set perm. of new file same as old file */
! (void)mch_setperm(wfname, perm);
#ifdef HAVE_ACL
! /*
! * Probably need to set the ACL before changing the user (can't set the
! * ACL on a file the user doesn't own).
! * On Solaris, with ZFS and the aclmode property set to "discard" (the
! * default), chmod() discards all part of a file's ACL that don't
represent
! * the mode of the file. It's non-trivial for us to discover whether
we're
! * in that situation, so we simply always re-set the ACL.
! */
# ifndef HAVE_SOLARIS_ZFS_ACL
! if (!backup_copy)
# endif
! mch_set_acl(wfname, acl);
#endif
#ifdef FEAT_CRYPT
! if (buf->b_cryptstate != NULL)
! {
! crypt_free_state(buf->b_cryptstate);
! buf->b_cryptstate = NULL;
! }
#endif
#if defined(FEAT_MBYTE) && defined(FEAT_EVAL)
! if (wfname != fname)
! {
! /*
! * The file was written to a temp file, now it needs to be converted
! * with 'charconvert' to (overwrite) the output file.
! */
! if (end != 0)
{
! if (eval_charconvert(enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc,
! wfname, fname) == FAIL)
{
! write_info.bw_conv_error = TRUE;
! end = 0;
}
}
- mch_remove(wfname);
- vim_free(wfname);
- }
#endif
if (end == 0)
{
if (errmsg == NULL)
{
#ifdef FEAT_MBYTE
--- 4345,4835 ----
#endif
/*
! * If conversion is taking place, we may first pretend to write and check
! * for conversion errors. Then loop again to write for real.
! * When not doing conversion this writes for real right away.
! */
! for (checking_conversion = TRUE; ; checking_conversion = FALSE)
{
/*
! * There is no need to check conversion when:
! * - there is no conversion
! * - we make a backup file, that can be restored in case of conversion
! * failure.
*/
! #ifdef FEAT_MBYTE
! if (!converted || dobackup)
#endif
+ checking_conversion = FALSE;
+
+ if (checking_conversion)
+ {
+ /* Make sure we don't write anything. */
+ fd = -1;
+ write_info.bw_fd = fd;
+ }
+ else
+ {
+ /*
+ * Open the file "wfname" for writing.
+ * We may try to open the file twice: If we can't write to the file
+ * and forceit is TRUE we delete the existing file and try to
+ * create a new one. If this still fails we may have lost the
+ * original file! (this may happen when the user reached his
+ * quotum for number of files).
+ * Appending will fail if the file does not exist and forceit is
+ * FALSE.
+ */
+ while ((fd = mch_open((char *)wfname, O_WRONLY | O_EXTRA | (append
+ ? (forceit ? (O_APPEND | O_CREAT) : O_APPEND)
+ : (O_CREAT | O_TRUNC))
+ , perm < 0 ? 0666 : (perm & 0777))) < 0)
{
! /*
! * A forced write will try to create a new file if the old one
! * is still readonly. This may also happen when the directory
! * is read-only. In that case the mch_remove() will fail.
! */
! if (errmsg == NULL)
{
#ifdef UNIX
! stat_T st;
!
! /* Don't delete the file when it's a hard or symbolic link.
! */
! if ((!newfile && st_old.st_nlink > 1)
! || (mch_lstat((char *)fname, &st) == 0
! && (st.st_dev != st_old.st_dev
! || st.st_ino != st_old.st_ino)))
! errmsg = (char_u *)_("E166: Can't open linked file for
writing");
! else
#endif
! {
! errmsg = (char_u *)_("E212: Can't open file for
writing");
! if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL
! && perm >= 0)
! {
! #ifdef UNIX
! /* we write to the file, thus it should be marked
! writable after all */
! if (!(perm & 0200))
! made_writable = TRUE;
! perm |= 0200;
! if (st_old.st_uid != getuid()
! || st_old.st_gid != getgid())
! perm &= 0777;
! #endif
! if (!append) /* don't remove when appending */
! mch_remove(wfname);
! continue;
! }
! }
}
restore_backup:
{
+ stat_T st;
+
/*
! * If we failed to open the file, we don't need a backup.
! * Throw it away. If we moved or removed the original file
! * try to put the backup in its place.
*/
! if (backup != NULL && wfname == fname)
! {
! if (backup_copy)
! {
! /*
! * There is a small chance that we removed the
! * original, try to move the copy in its place.
! * This may not work if the vim_rename() fails.
! * In that case we leave the copy around.
! */
! /* If file does not exist, put the copy in its
! * place */
! if (mch_stat((char *)fname, &st) < 0)
! vim_rename(backup, fname);
! /* if original file does exist throw away the copy
! */
! if (mch_stat((char *)fname, &st) >= 0)
! mch_remove(backup);
! }
! else
! {
! /* try to put the original file back */
! vim_rename(backup, fname);
! }
! }
! /* if original file no longer exists give an extra warning
! */
! if (!newfile && mch_stat((char *)fname, &st) < 0)
! end = 0;
! }
#ifdef FEAT_MBYTE
! if (wfname != fname)
! vim_free(wfname);
#endif
! goto fail;
! }
! write_info.bw_fd = fd;
#if defined(MACOS_CLASSIC) || defined(WIN3264)
! /* TODO: Is it need for MACOS_X? (Dany) */
! /*
! * On macintosh copy the original files attributes (i.e. the backup)
! * This is done in order to preserve the resource fork and the
! * Finder attribute (label, comments, custom icons, file creator)
! */
! if (backup != NULL && overwriting && !append)
! {
! if (backup_copy)
! (void)mch_copy_file_attribute(wfname, backup);
! else
! (void)mch_copy_file_attribute(backup, wfname);
! }
! if (!overwriting && !append)
! {
! if (buf->b_ffname != NULL)
! (void)mch_copy_file_attribute(buf->b_ffname, wfname);
! /* Should copy resource fork */
! }
#endif
#ifdef FEAT_CRYPT
! if (*buf->b_p_key != NUL && !filtering)
! {
! char_u *header;
! int header_len;
! buf->b_cryptstate = crypt_create_for_writing(
! crypt_get_method_nr(buf),
! buf->b_p_key, &header, &header_len);
! if (buf->b_cryptstate == NULL || header == NULL)
! end = 0;
! else
! {
! /* Write magic number, so that Vim knows how this file is
! * encrypted when reading it back. */
! write_info.bw_buf = header;
! write_info.bw_len = header_len;
! write_info.bw_flags = FIO_NOCONVERT;
! if (buf_write_bytes(&write_info) == FAIL)
! end = 0;
! wb_flags |= FIO_ENCRYPTED;
! vim_free(header);
! }
! }
#endif
+ }
+ errmsg = NULL;
! write_info.bw_buf = buffer;
! nchars = 0;
! /* use "++bin", "++nobin" or 'binary' */
! if (eap != NULL && eap->force_bin != 0)
! write_bin = (eap->force_bin == FORCE_BIN);
! else
! write_bin = buf->b_p_bin;
#ifdef FEAT_MBYTE
! /*
! * The BOM is written just after the encryption magic number.
! * Skip it when appending and the file already existed, the BOM only
! * makes sense at the start of the file.
! */
! if (buf->b_p_bomb && !write_bin && (!append || perm < 0))
{
! write_info.bw_len = make_bom(buffer, fenc);
! if (write_info.bw_len > 0)
! {
! /* don't convert, do encryption */
! write_info.bw_flags = FIO_NOCONVERT | wb_flags;
! if (buf_write_bytes(&write_info) == FAIL)
! end = 0;
! else
! nchars += write_info.bw_len;
! }
}
! write_info.bw_start_lnum = start;
#endif
#ifdef FEAT_PERSISTENT_UNDO
! write_undo_file = (buf->b_p_udf
! && overwriting
! && !append
! && !filtering
! && reset_changed
! && !checking_conversion);
! if (write_undo_file)
! /* Prepare for computing the hash value of the text. */
! sha256_start(&sha_ctx);
#endif
! write_info.bw_len = bufsize;
#ifdef HAS_BW_FLAGS
! write_info.bw_flags = wb_flags;
#endif
! fileformat = get_fileformat_force(buf, eap);
! s = buffer;
! len = 0;
! for (lnum = start; lnum <= end; ++lnum)
! {
! /*
! * The next while loop is done once for each character written.
! * Keep it fast!
! */
! ptr = ml_get_buf(buf, lnum, FALSE) - 1;
#ifdef FEAT_PERSISTENT_UNDO
! if (write_undo_file)
! sha256_update(&sha_ctx, ptr + 1,
! (UINT32_T)(STRLEN(ptr + 1) + 1));
#endif
! while ((c = *++ptr) != NUL)
{
! if (c == NL)
! *s = NUL; /* replace newlines with NULs */
! else if (c == CAR && fileformat == EOL_MAC)
! *s = NL; /* Mac: replace CRs with NLs */
! else
! *s = c;
! ++s;
! if (++len != bufsize)
! continue;
! if (buf_write_bytes(&write_info) == FAIL)
! {
! end = 0; /* write error: break loop */
! break;
! }
! nchars += bufsize;
! s = buffer;
! len = 0;
#ifdef FEAT_MBYTE
! write_info.bw_start_lnum = lnum;
#endif
! }
! /* write failed or last line has no EOL: stop here */
! if (end == 0
! || (lnum == end
! && (write_bin || !buf->b_p_fixeol)
! && (lnum == buf->b_no_eol_lnum
! || (lnum == buf->b_ml.ml_line_count
! && !buf->b_p_eol))))
! {
! ++lnum; /* written the line, count it */
! no_eol = TRUE;
! break;
! }
! if (fileformat == EOL_UNIX)
! *s++ = NL;
! else
{
! *s++ = CAR; /* EOL_MAC or EOL_DOS: write CR */
! if (fileformat == EOL_DOS) /* write CR-NL */
{
! if (++len == bufsize)
{
! if (buf_write_bytes(&write_info) == FAIL)
! {
! end = 0; /* write error: break loop */
! break;
! }
! nchars += bufsize;
! s = buffer;
! len = 0;
}
! *s++ = NL;
}
}
! if (++len == bufsize && end)
{
! if (buf_write_bytes(&write_info) == FAIL)
! {
! end = 0; /* write error: break loop */
! break;
! }
! nchars += bufsize;
! s = buffer;
! len = 0;
! ui_breakcheck();
! if (got_int)
! {
! end = 0; /* Interrupted, break loop */
! break;
! }
}
#ifdef VMS
! /*
! * On VMS there is a problem: newlines get added when writing
! * blocks at a time. Fix it by writing a line at a time.
! * This is much slower!
! * Explanation: VAX/DECC RTL insists that records in some RMS
! * structures end with a newline (carriage return) character, and
! * if they don't it adds one.
! * With other RMS structures it works perfect without this fix.
! */
! if (buf->b_fab_rfm == FAB$C_VFC
! || ((buf->b_fab_rat & (FAB$M_FTN | FAB$M_CR)) != 0))
! {
! int b2write;
! buf->b_fab_mrs = (buf->b_fab_mrs == 0
! ? MIN(4096, bufsize)
! : MIN(buf->b_fab_mrs, bufsize));
! b2write = len;
! while (b2write > 0)
{
! write_info.bw_len = MIN(b2write, buf->b_fab_mrs);
! if (buf_write_bytes(&write_info) == FAIL)
! {
! end = 0;
! break;
! }
! b2write -= MIN(b2write, buf->b_fab_mrs);
}
! write_info.bw_len = bufsize;
! nchars += len;
! s = buffer;
! len = 0;
}
! #endif
! }
! if (len > 0 && end > 0)
! {
! write_info.bw_len = len;
! if (buf_write_bytes(&write_info) == FAIL)
! end = 0; /* write error */
nchars += len;
}
!
! /* Stop when writing done or an error was encountered. */
! if (!checking_conversion || end == 0)
! break;
!
! /* If no error happened until now, writing should be ok, so loop to
! * really write the buffer. */
}
! /* If we started writing, finish writing. Also when an error was
! * encountered. */
! if (!checking_conversion)
{
! #if defined(UNIX) && defined(HAVE_FSYNC)
! /*
! * On many journalling file systems there is a bug that causes both the
! * original and the backup file to be lost when halting the system
! * right after writing the file. That's because only the meta-data is
! * journalled. Syncing the file slows down the system, but assures it
! * has been written to disk and we don't lose it.
! * For a device do try the fsync() but don't complain if it does not
! * work (could be a pipe).
! * If the 'fsync' option is FALSE, don't fsync(). Useful for laptops.
! */
! if (p_fs && fsync(fd) != 0 && !device)
! {
! errmsg = (char_u *)_("E667: Fsync failed");
! end = 0;
! }
#endif
#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
! /* Probably need to set the security context. */
! if (!backup_copy)
! mch_copy_sec(backup, wfname);
#endif
#ifdef UNIX
! /* When creating a new file, set its owner/group to that of the
! * original file. Get the new device and inode number. */
! if (backup != NULL && !backup_copy)
! {
# ifdef HAVE_FCHOWN
! stat_T st;
! /* don't change the owner when it's already OK, some systems remove
! * permission or ACL stuff */
! if (mch_stat((char *)wfname, &st) < 0
! || st.st_uid != st_old.st_uid
! || st.st_gid != st_old.st_gid)
! {
! ignored = fchown(fd, st_old.st_uid, st_old.st_gid);
! if (perm >= 0) /* set permission again, may have changed */
! (void)mch_setperm(wfname, perm);
! }
# endif
! buf_setino(buf);
! }
! else if (!buf->b_dev_valid)
! /* Set the inode when creating a new file. */
! buf_setino(buf);
#endif
! if (close(fd) != 0)
! {
! errmsg = (char_u *)_("E512: Close failed");
! end = 0;
! }
#ifdef UNIX
! if (made_writable)
! perm &= ~0200; /* reset 'w' bit for security reasons */
#endif
! if (perm >= 0) /* set perm. of new file same as old file */
! (void)mch_setperm(wfname, perm);
#ifdef HAVE_ACL
! /*
! * Probably need to set the ACL before changing the user (can't set the
! * ACL on a file the user doesn't own).
! * On Solaris, with ZFS and the aclmode property set to "discard" (the
! * default), chmod() discards all part of a file's ACL that don't
! * represent the mode of the file. It's non-trivial for us to discover
! * whether we're in that situation, so we simply always re-set the ACL.
! */
# ifndef HAVE_SOLARIS_ZFS_ACL
! if (!backup_copy)
# endif
! mch_set_acl(wfname, acl);
#endif
#ifdef FEAT_CRYPT
! if (buf->b_cryptstate != NULL)
! {
! crypt_free_state(buf->b_cryptstate);
! buf->b_cryptstate = NULL;
! }
#endif
#if defined(FEAT_MBYTE) && defined(FEAT_EVAL)
! if (wfname != fname)
{
! /*
! * The file was written to a temp file, now it needs to be
! * converted with 'charconvert' to (overwrite) the output file.
! */
! if (end != 0)
{
! if (eval_charconvert(enc_utf8 ? (char_u *)"utf-8" : p_enc,
! fenc, wfname, fname) == FAIL)
! {
! write_info.bw_conv_error = TRUE;
! end = 0;
! }
}
+ mch_remove(wfname);
+ vim_free(wfname);
}
#endif
+ }
if (end == 0)
{
+ /*
+ * Error encountered.
+ */
if (errmsg == NULL)
{
#ifdef FEAT_MBYTE
***************
*** 5690,5695 ****
--- 5749,5758 ----
}
#endif /* FEAT_MBYTE */
+ if (ip->bw_fd < 0)
+ /* Only checking conversion, which is OK if we get here. */
+ return OK;
+
#ifdef FEAT_CRYPT
if (flags & FIO_ENCRYPTED)
{
*** ../vim-8.0.0684/src/testdir/test_writefile.vim 2017-06-13
19:38:33.301791799 +0200
--- src/testdir/test_writefile.vim 2017-06-27 21:22:55.749684062 +0200
***************
*** 31,33 ****
--- 31,51 ----
call assert_fails('call writefile([], [])', 'E730:')
endfunc
+
+ func Test_writefile_fails_conversion()
+ if !has('multi_byte') || !has('iconv')
+ return
+ endif
+ set nobackup nowritebackup
+ new
+ let contents = ["line one", "line two"]
+ call writefile(contents, 'Xfile')
+ edit Xfile
+ call setline(1, ["first line", "cannot convert \u010b", "third line"])
+ call assert_fails('write ++enc=cp932')
+ call assert_equal(contents, readfile('Xfile'))
+
+ call delete('Xfile')
+ bwipe!
+ set backup& writebackup&
+ endfunc
*** ../vim-8.0.0684/src/version.c 2017-06-27 18:28:52.558196805 +0200
--- src/version.c 2017-06-27 22:11:05.711318535 +0200
***************
*** 766,767 ****
--- 766,769 ----
{ /* Add new patch number below this line */
+ /**/
+ 685,
/**/
--
>From "know your smileys":
=):-) Uncle Sam
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ 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].
For more options, visit https://groups.google.com/d/optout.