fileio: Refactor errmsg handling

Adds os_strerror() result to a number of places. Also since I could not track 
where err\* variables are NULL and where they are not, using macros to make sure 
that all three variables are set at once.

Removes #ifdef UNIX around the use of os_fsync, makes it use os_close in place 
of close in some places.
This commit is contained in:
ZyX
2017-04-03 00:35:29 +03:00
parent b10880dadc
commit 364709bedb
2 changed files with 99 additions and 79 deletions

View File

@@ -2740,6 +2740,9 @@ A jump table for the options with a short description can be found at |Q_op|.
mode, so it may be undesirable in some situations. Be warned that mode, so it may be undesirable in some situations. Be warned that
turning this off increases the chances of data loss after a crash. turning this off increases the chances of data loss after a crash.
Currently applies only to writing the buffer with e.g. |:w| and
|writefile()|.
*'gdefault'* *'gd'* *'nogdefault'* *'nogd'* *'gdefault'* *'gd'* *'nogdefault'* *'nogd'*
'gdefault' 'gd' boolean (default off) 'gdefault' 'gd' boolean (default off)
global global

View File

@@ -2258,9 +2258,16 @@ buf_write (
int len; int len;
linenr_T lnum; linenr_T lnum;
long nchars; long nchars;
char_u *errmsg = NULL; #define SET_ERRMSG_NUM(num, msg) \
int errmsg_allocated = FALSE; errnum = num ": ", errmsg = msg, errmsgarg = 0
char_u *errnum = NULL; #define SET_ERRMSG_ARG(msg, error) \
errnum = NULL, errmsg = msg, errmsgarg = error
#define SET_ERRMSG(msg) \
errnum = NULL, errmsg = msg, errmsgarg = 0
const char *errnum = NULL;
char *errmsg = NULL;
int errmsgarg = 0;
bool errmsg_allocated = false;
char_u *buffer; char_u *buffer;
char_u smallbuf[SMBUFSIZE]; char_u smallbuf[SMBUFSIZE];
char_u *backup_ext; char_u *backup_ext;
@@ -2282,7 +2289,6 @@ buf_write (
/* writing everything */ /* writing everything */
int whole = (start == 1 && end == buf->b_ml.ml_line_count); int whole = (start == 1 && end == buf->b_ml.ml_line_count);
linenr_T old_line_count = buf->b_ml.ml_line_count; linenr_T old_line_count = buf->b_ml.ml_line_count;
int attr;
int fileformat; int fileformat;
int write_bin; int write_bin;
struct bw_info write_info; /* info for buf_write_bytes() */ struct bw_info write_info; /* info for buf_write_bytes() */
@@ -2577,13 +2583,11 @@ buf_write (
perm = file_info_old.stat.st_mode; perm = file_info_old.stat.st_mode;
if (!S_ISREG(file_info_old.stat.st_mode)) { /* not a file */ if (!S_ISREG(file_info_old.stat.st_mode)) { /* not a file */
if (S_ISDIR(file_info_old.stat.st_mode)) { if (S_ISDIR(file_info_old.stat.st_mode)) {
errnum = (char_u *)"E502: "; SET_ERRMSG_NUM("E502", _("is a directory"));
errmsg = (char_u *)_("is a directory");
goto fail; goto fail;
} }
if (os_nodetype((char *)fname) != NODE_WRITABLE) { if (os_nodetype((char *)fname) != NODE_WRITABLE) {
errnum = (char_u *)"E503: "; SET_ERRMSG_NUM("E503", _("is not a file or writable device"));
errmsg = (char_u *)_("is not a file or writable device");
goto fail; goto fail;
} }
/* It's a device of some kind (or a fifo) which we can write to /* It's a device of some kind (or a fifo) which we can write to
@@ -2599,8 +2603,7 @@ buf_write (
*/ */
c = os_nodetype((char *)fname); c = os_nodetype((char *)fname);
if (c == NODE_OTHER) { if (c == NODE_OTHER) {
errnum = (char_u *)"E503: "; SET_ERRMSG_NUM("E503", _("is not a file or writable device"));
errmsg = (char_u *)_("is not a file or writable device");
goto fail; goto fail;
} }
if (c == NODE_WRITABLE) { if (c == NODE_WRITABLE) {
@@ -2612,8 +2615,7 @@ buf_write (
if (perm < 0) { if (perm < 0) {
newfile = true; newfile = true;
} else if (os_isdir(fname)) { } else if (os_isdir(fname)) {
errnum = (char_u *)"E502: "; SET_ERRMSG_NUM("E502", _("is a directory"));
errmsg = (char_u *)_("is a directory");
goto fail; goto fail;
} }
if (overwriting) { if (overwriting) {
@@ -2632,11 +2634,9 @@ buf_write (
if (!forceit && file_readonly) { if (!forceit && file_readonly) {
if (vim_strchr(p_cpo, CPO_FWRITE) != NULL) { if (vim_strchr(p_cpo, CPO_FWRITE) != NULL) {
errnum = (char_u *)"E504: "; SET_ERRMSG_NUM("E504", _(err_readonly));
errmsg = (char_u *)_(err_readonly);
} else { } else {
errnum = (char_u *)"E505: "; SET_ERRMSG_NUM("E505", _("is read-only (add ! to override)"));
errmsg = (char_u *)_("is read-only (add ! to override)");
} }
goto fail; goto fail;
} }
@@ -2904,23 +2904,27 @@ buf_write (
while ((write_info.bw_len = read_eintr(fd, copybuf, while ((write_info.bw_len = read_eintr(fd, copybuf,
BUFSIZE)) > 0) { BUFSIZE)) > 0) {
if (buf_write_bytes(&write_info) == FAIL) { if (buf_write_bytes(&write_info) == FAIL) {
errmsg = (char_u *)_( SET_ERRMSG(_(
"E506: Can't write to backup file (add ! to override)"); "E506: Can't write to backup file (add ! to override)"));
break; break;
} }
os_breakcheck(); os_breakcheck();
if (got_int) { if (got_int) {
errmsg = (char_u *)_(e_interr); SET_ERRMSG(_(e_interr));
break; break;
} }
} }
if (close(bfd) < 0 && errmsg == NULL) int error;
errmsg = (char_u *)_( if ((error = os_close(bfd)) != 0 && errmsg == NULL) {
"E507: Close error for backup file (add ! to override)"); SET_ERRMSG_ARG(_(
if (write_info.bw_len < 0) "E507: Close error for backup file (add ! to override): %s"),
errmsg = (char_u *)_( error);
"E508: Can't read file for backup (add ! to override)"); }
if (write_info.bw_len < 0) {
SET_ERRMSG(_(
"E508: Can't read file for backup (add ! to override)"));
}
#ifdef UNIX #ifdef UNIX
set_file_time(backup, set_file_time(backup,
file_info_old.stat.st_atim.tv_sec, file_info_old.stat.st_atim.tv_sec,
@@ -2937,18 +2941,19 @@ buf_write (
} }
} }
nobackup: nobackup:
close(fd); /* ignore errors for closing read file */ os_close(fd); /* ignore errors for closing read file */
xfree(copybuf); xfree(copybuf);
if (backup == NULL && errmsg == NULL) if (backup == NULL && errmsg == NULL) {
errmsg = (char_u *)_( SET_ERRMSG(_(
"E509: Cannot create backup file (add ! to override)"); "E509: Cannot create backup file (add ! to override)"));
/* ignore errors when forceit is TRUE */ }
// Ignore errors when forceit is TRUE.
if ((some_error || errmsg != NULL) && !forceit) { if ((some_error || errmsg != NULL) && !forceit) {
retval = FAIL; retval = FAIL;
goto fail; goto fail;
} }
errmsg = NULL; SET_ERRMSG(NULL);
} else { } else {
char_u *dirp; char_u *dirp;
char_u *p; char_u *p;
@@ -2963,8 +2968,7 @@ nobackup:
* anyway, thus we need an extra check here. * anyway, thus we need an extra check here.
*/ */
if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL) { if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL) {
errnum = (char_u *)"E504: "; SET_ERRMSG_NUM("E504", _(err_readonly));
errmsg = (char_u *)_(err_readonly);
goto fail; goto fail;
} }
@@ -3028,7 +3032,7 @@ nobackup:
} }
} }
if (backup == NULL && !forceit) { if (backup == NULL && !forceit) {
errmsg = (char_u *)_("E510: Can't make backup file (add ! to override)"); SET_ERRMSG(_("E510: Can't make backup file (add ! to override)"));
goto fail; goto fail;
} }
} }
@@ -3069,7 +3073,7 @@ nobackup:
&& !(exiting && backup != NULL)) { && !(exiting && backup != NULL)) {
ml_preserve(buf, FALSE); ml_preserve(buf, FALSE);
if (got_int) { if (got_int) {
errmsg = (char_u *)_(e_interr); SET_ERRMSG(_(e_interr));
goto restore_backup; goto restore_backup;
} }
} }
@@ -3140,8 +3144,8 @@ nobackup:
*/ */
if (*p_ccv != NUL) { if (*p_ccv != NUL) {
wfname = vim_tempname(); wfname = vim_tempname();
if (wfname == NULL) { /* Can't write without a tempfile! */ if (wfname == NULL) { // Can't write without a tempfile!
errmsg = (char_u *)_("E214: Can't find temp file for writing"); SET_ERRMSG(_("E214: Can't find temp file for writing"));
goto restore_backup; goto restore_backup;
} }
} }
@@ -3153,8 +3157,8 @@ nobackup:
&& wfname == fname && wfname == fname
) { ) {
if (!forceit) { if (!forceit) {
errmsg = (char_u *)_( SET_ERRMSG(_(
"E213: Cannot convert (add ! to write without conversion)"); "E213: Cannot convert (add ! to write without conversion)"));
goto restore_backup; goto restore_backup;
} }
notconverted = TRUE; notconverted = TRUE;
@@ -3189,11 +3193,10 @@ nobackup:
if ((!newfile && os_fileinfo_hardlinks(&file_info) > 1) if ((!newfile && os_fileinfo_hardlinks(&file_info) > 1)
|| (os_fileinfo_link((char *)fname, &file_info) || (os_fileinfo_link((char *)fname, &file_info)
&& !os_fileinfo_id_equal(&file_info, &file_info_old))) { && !os_fileinfo_id_equal(&file_info, &file_info_old))) {
errmsg = (char_u *)_("E166: Can't open linked file for writing"); SET_ERRMSG(_("E166: Can't open linked file for writing"));
} else } else {
#endif #endif
{ SET_ERRMSG(_("E212: Can't open file for writing"));
errmsg = (char_u *)_("E212: Can't open file for writing");
if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL
&& perm >= 0) { && perm >= 0) {
#ifdef UNIX #ifdef UNIX
@@ -3211,7 +3214,9 @@ nobackup:
os_remove((char *)wfname); os_remove((char *)wfname);
continue; continue;
} }
#ifdef UNIX
} }
#endif
} }
restore_backup: restore_backup:
@@ -3253,7 +3258,7 @@ restore_backup:
xfree(wfname); xfree(wfname);
goto fail; goto fail;
} }
errmsg = NULL; SET_ERRMSG(NULL);
write_info.bw_fd = fd; write_info.bw_fd = fd;
@@ -3373,7 +3378,6 @@ restore_backup:
nchars += len; nchars += len;
} }
#if defined(UNIX)
// On many journalling file systems there is a bug that causes both the // 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 // 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 // after writing the file. That's because only the meta-data is
@@ -3382,11 +3386,11 @@ restore_backup:
// For a device do try the fsync() but don't complain if it does not work // For a device do try the fsync() but don't complain if it does not work
// (could be a pipe). // (could be a pipe).
// If the 'fsync' option is FALSE, don't fsync(). Useful for laptops. // If the 'fsync' option is FALSE, don't fsync(). Useful for laptops.
if (p_fs && os_fsync(fd) != 0 && !device) { int error;
errmsg = (char_u *)_("E667: Fsync failed"); if (p_fs && (error = os_fsync(fd)) != 0 && !device) {
SET_ERRMSG_ARG(_("E667: Fsync failed: %s"), error);
end = 0; end = 0;
} }
#endif
#ifdef HAVE_SELINUX #ifdef HAVE_SELINUX
/* Probably need to set the security context. */ /* Probably need to set the security context. */
@@ -3416,8 +3420,8 @@ restore_backup:
} }
#endif #endif
if (close(fd) != 0) { if ((error = os_close(fd)) != 0) {
errmsg = (char_u *)_("E512: Close failed"); SET_ERRMSG_ARG(_("E512: Close failed: %s"), error);
end = 0; end = 0;
} }
@@ -3454,21 +3458,25 @@ restore_backup:
if (end == 0) { if (end == 0) {
if (errmsg == NULL) { if (errmsg == NULL) {
if (write_info.bw_conv_error) { if (write_info.bw_conv_error) {
if (write_info.bw_conv_error_lnum == 0) if (write_info.bw_conv_error_lnum == 0) {
errmsg = (char_u *)_( SET_ERRMSG(_(
"E513: write error, conversion failed (make 'fenc' empty to override)"); "E513: write error, conversion failed "
else { "(make 'fenc' empty to override)"));
errmsg_allocated = TRUE; }
errmsg = xmalloc(300); else {
vim_snprintf((char *)errmsg, 300, errmsg_allocated = true;
_("E513: write error, conversion failed in line %" PRId64 SET_ERRMSG(xmalloc(300));
" (make 'fenc' empty to override)"), vim_snprintf(
(int64_t)write_info.bw_conv_error_lnum); errmsg, 300,
_("E513: write error, conversion failed in line %" PRIdLINENR
" (make 'fenc' empty to override)"),
write_info.bw_conv_error_lnum);
}
} else if (got_int) {
SET_ERRMSG(_(e_interr));
} else {
SET_ERRMSG(_("E514: write error (file system full?)"));
} }
} else if (got_int)
errmsg = (char_u *)_(e_interr);
else
errmsg = (char_u *)_("E514: write error (file system full?)");
} }
/* /*
@@ -3673,31 +3681,37 @@ nofail:
#endif #endif
if (errmsg != NULL) { if (errmsg != NULL) {
int numlen = errnum != NULL ? (int)STRLEN(errnum) : 0; const size_t numlen = (errnum != NULL ? strlen(errnum) : 0);
attr = hl_attr(HLF_E); /* set highlight for error messages */ // Put file name in IObuff with quotes.
msg_add_fname(buf,
#ifndef UNIX #ifndef UNIX
sfname msg_add_fname(buf, sfname);
#else #else
fname msg_add_fname(buf, fname);
#endif #endif
); /* put file name in IObuff with quotes */ const size_t errmsglen = strlen(errmsg);
if (STRLEN(IObuff) + STRLEN(errmsg) + numlen >= IOSIZE) if (STRLEN(IObuff) + errmsglen + numlen >= IOSIZE) {
IObuff[IOSIZE - STRLEN(errmsg) - numlen - 1] = NUL; IObuff[IOSIZE - errmsglen - numlen - 1] = NUL;
/* If the error message has the form "is ...", put the error number in }
* front of the file name. */ // If the error message has the form "is ...", put the error number in
// front of the file name.
if (errnum != NULL) { if (errnum != NULL) {
STRMOVE(IObuff + numlen, IObuff); STRMOVE(IObuff + numlen, IObuff);
memmove(IObuff, errnum, (size_t)numlen); memmove(IObuff, errnum, numlen);
} }
STRCAT(IObuff, errmsg); xstrlcat((char *)IObuff, errmsg, IOSIZE);
emsg(IObuff); if (errmsgarg != 0) {
if (errmsg_allocated) emsgf((const char *)IObuff, os_strerror(errmsgarg));
} else {
emsgf((const char *)IObuff);
}
if (errmsg_allocated) {
xfree(errmsg); xfree(errmsg);
}
retval = FAIL; retval = FAIL;
if (end == 0) { if (end == 0) {
const int attr = hl_attr(HLF_E); // Set highlight for error messages.
MSG_PUTS_ATTR(_("\nWARNING: Original file may be lost or damaged\n"), MSG_PUTS_ATTR(_("\nWARNING: Original file may be lost or damaged\n"),
attr | MSG_HIST); attr | MSG_HIST);
MSG_PUTS_ATTR(_( MSG_PUTS_ATTR(_(
@@ -3759,6 +3773,9 @@ nofail:
got_int |= prev_got_int; got_int |= prev_got_int;
return retval; return retval;
#undef SET_ERRMSG
#undef SET_ERRMSG_ARG
#undef SET_ERRMSG_NUM
} }
/* /*