Created
May 15, 2012 18:34
-
-
Save chrisbra/2704019 to your computer and use it in GitHub Desktop.
Fix conversion error
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/fileio.c b/src/fileio.c | |
--- a/src/fileio.c | |
+++ b/src/fileio.c | |
@@ -113,6 +113,7 @@ | |
int bw_fd; /* file descriptor */ | |
char_u *bw_buf; /* buffer with data to be written */ | |
int bw_len; /* length of data */ | |
+ int do_write; /* really write */ | |
#ifdef HAS_BW_FLAGS | |
int bw_flags; /* FIO_ flags */ | |
#endif | |
@@ -3163,6 +3164,7 @@ | |
int prev_got_int = got_int; | |
int file_readonly = FALSE; /* overwritten file is read-only */ | |
static char *err_readonly = "is read-only (cannot override: \"W\" in 'cpoptions')"; | |
+ int no_check_conv; /* nr of loops */ | |
#if defined(UNIX) || defined(__EMX__XX) /*XXX fix me sometime? */ | |
int made_writable = FALSE; /* 'w' bit has been set */ | |
#endif | |
@@ -4336,423 +4338,457 @@ | |
notconverted = TRUE; | |
} | |
#endif | |
- | |
+#ifdef FEAT_MBYTE | |
+ no_check_conv = !converted; | |
+#else | |
+ no_check_conv = TRUE; | |
+#endif | |
+ /* in case we are creating a backup file, it shouldn't be necessary to | |
+ * check whether converting from 'enc' to 'fenc' is successfull */ | |
+ if (dobackup) | |
+ no_check_conv = TRUE; | |
/* | |
- * 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. | |
+ * Loop twice, first time check, that conversion can be done successfully | |
+ * so in case of an error one does not truncate the file. | |
*/ | |
- 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 | |
- struct stat 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: | |
- { | |
- struct stat st; | |
- | |
+ for (; no_check_conv < 2 && end > 0; no_check_conv++) | |
+ { | |
+ if (no_check_conv) | |
+ write_info.do_write = TRUE; | |
+ else | |
+ write_info.do_write = FALSE; | |
+ | |
+ if (no_check_conv) | |
+ { | |
/* | |
- * 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) | |
+ * 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) | |
{ | |
/* | |
- * 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); | |
+ * 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 | |
+ struct stat 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: | |
+ { | |
+ struct stat 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; | |
} | |
- 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; | |
+ } | |
+ 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; | |
+ /* 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; | |
- | |
- header = prepare_crypt_write(buf, &header_len); | |
- if (header == NULL) | |
- end = 0; | |
- else | |
- { | |
- /* Write magic number, so that Vim knows that this file is | |
- * encrypted when reading it again. This also undergoes utf-8 to | |
- * ucs-2/4 conversion when needed. */ | |
- 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) | |
+ if (*buf->b_p_key != NUL && !filtering) | |
+ { | |
+ char_u *header; | |
+ int header_len; | |
+ | |
+ header = prepare_crypt_write(buf, &header_len); | |
+ if (header == NULL) | |
end = 0; | |
else | |
- nchars += write_info.bw_len; | |
- } | |
- } | |
- write_info.bw_start_lnum = start; | |
+ { | |
+ /* Write magic number, so that Vim knows that this file is | |
+ * encrypted when reading it again. This also undergoes utf-8 to | |
+ * ucs-2/4 conversion when needed. */ | |
+ 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; | |
+ 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; | |
+ 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 */ | |
+ 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 | |
+ && (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 = 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 | |
- && (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) | |
+ { | |
+ *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; /* write error: break loop */ | |
+ end = 0; | |
break; | |
} | |
- nchars += bufsize; | |
- s = buffer; | |
- len = 0; | |
+ b2write -= MIN(b2write, buf->b_fab_mrs); | |
} | |
- *s++ = NL; | |
- } | |
- } | |
- if (++len == bufsize && end) | |
- { | |
+ 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: 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; /* write error */ | |
+ nchars += len; | |
+ } | |
+ | |
+ /* conversion error */ | |
+ if (!end) | |
+ break; | |
+ | |
+ /* If no error happened until now, writing should be ok, | |
+ * so start outer for loop over again, this time really | |
+ * writing the buffer */ | |
+ if (!no_check_conv) | |
+ continue; | |
+ | |
+ | |
+#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 | |
+ | |
+#ifdef HAVE_SELINUX | |
+ /* 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 | |
+ struct stat 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 (end > 0 && 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). */ | |
+ if (!backup_copy) | |
+ mch_set_acl(wfname, acl); | |
+#endif | |
+#ifdef FEAT_CRYPT | |
+ crypt_method_used = use_crypt_method; | |
+ if (wb_flags & FIO_ENCRYPTED) | |
+ crypt_pop_state(); | |
+#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; | |
- 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 | |
- | |
-#ifdef HAVE_SELINUX | |
- /* 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 | |
- struct stat 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). */ | |
- if (!backup_copy) | |
- mch_set_acl(wfname, acl); | |
-#endif | |
-#ifdef FEAT_CRYPT | |
- crypt_method_used = use_crypt_method; | |
- if (wb_flags & FIO_ENCRYPTED) | |
- crypt_pop_state(); | |
-#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 | |
+ } | |
+ mch_remove(wfname); | |
+ vim_free(wfname); | |
+ } | |
+#endif | |
+ } | |
if (end == 0) | |
{ | |
@@ -4779,6 +4815,10 @@ | |
errmsg = (char_u *)_("E514: write error (file system full?)"); | |
} | |
+ if (end == 0) /* write error */ | |
+ goto fail; | |
+ | |
+ | |
/* | |
* If we have a backup file, try to put it in place of the new file, | |
* because the new file is probably corrupt. This avoids losing the | |
@@ -5702,8 +5742,13 @@ | |
crypt_encode(buf, len, buf); | |
#endif | |
- wlen = write_eintr(ip->bw_fd, buf, len); | |
- return (wlen < len) ? FAIL : OK; | |
+ if (ip->do_write) | |
+ { | |
+ wlen = write_eintr(ip->bw_fd, buf, len); | |
+ return (wlen < len) ? FAIL : OK; | |
+ } | |
+ /* no error, writing and converting file should work ok */ | |
+ return OK; | |
} | |
#ifdef FEAT_MBYTE |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment