diff options
Diffstat (limited to 'src/nvim/fileio.c')
-rw-r--r-- | src/nvim/fileio.c | 301 |
1 files changed, 164 insertions, 137 deletions
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 873c15ff4a..c1b8203ed1 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -200,18 +200,14 @@ void filemess(buf_T *buf, char_u *name, char_u *s, int attr) { int msg_scroll_save; - if (msg_silent != 0) + if (msg_silent != 0) { return; - msg_add_fname(buf, name); /* put file name in IObuff with quotes */ - /* If it's extremely long, truncate it. */ - if (STRLEN(IObuff) > IOSIZE - 80) - IObuff[IOSIZE - 80] = NUL; - STRCAT(IObuff, s); - /* - * For the first message may have to start a new line. - * For further ones overwrite the previous one, reset msg_scroll before - * calling filemess(). - */ + } + add_quoted_fname((char *)IObuff, IOSIZE - 80, buf, (const char *)name); + xstrlcat((char *)IObuff, (const char *)s, IOSIZE); + // For the first message may have to start a new line. + // For further ones overwrite the previous one, reset msg_scroll before + // calling filemess(). msg_scroll_save = msg_scroll; if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0) msg_scroll = FALSE; @@ -428,7 +424,7 @@ readfile ( } if (!read_buffer && !read_stdin) { - perm = os_getperm(fname); + perm = os_getperm((const char *)fname); #ifdef UNIX // On Unix it is possible to read a directory, so we have to // check for it before os_open(). @@ -614,10 +610,12 @@ readfile ( return FAIL; } #ifdef UNIX - /* Set swap file protection bits after creating it. */ + // Set swap file protection bits after creating it. if (swap_mode > 0 && curbuf->b_ml.ml_mfp != NULL - && curbuf->b_ml.ml_mfp->mf_fname != NULL) - (void)os_setperm(curbuf->b_ml.ml_mfp->mf_fname, (long)swap_mode); + && curbuf->b_ml.ml_mfp->mf_fname != NULL) { + (void)os_setperm((const char *)curbuf->b_ml.ml_mfp->mf_fname, + (long)swap_mode); + } #endif } @@ -1798,8 +1796,8 @@ failed: } if (!filtering && !(flags & READ_DUMMY)) { - msg_add_fname(curbuf, sfname); /* fname in IObuff with quotes */ - c = FALSE; + add_quoted_fname((char *)IObuff, IOSIZE, curbuf, (const char *)sfname); + c = false; #ifdef UNIX # ifdef S_ISFIFO @@ -2256,9 +2254,16 @@ buf_write ( int len; linenr_T lnum; long nchars; - char_u *errmsg = NULL; - int errmsg_allocated = FALSE; - char_u *errnum = NULL; +#define SET_ERRMSG_NUM(num, msg) \ + errnum = num, errmsg = msg, errmsgarg = 0 +#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 smallbuf[SMBUFSIZE]; char_u *backup_ext; @@ -2280,7 +2285,6 @@ buf_write ( /* writing everything */ int whole = (start == 1 && end == buf->b_ml.ml_line_count); linenr_T old_line_count = buf->b_ml.ml_line_count; - int attr; int fileformat; int write_bin; struct bw_info write_info; /* info for buf_write_bytes() */ @@ -2575,13 +2579,11 @@ buf_write ( perm = file_info_old.stat.st_mode; if (!S_ISREG(file_info_old.stat.st_mode)) { /* not a file */ if (S_ISDIR(file_info_old.stat.st_mode)) { - errnum = (char_u *)"E502: "; - errmsg = (char_u *)_("is a directory"); + SET_ERRMSG_NUM("E502", _("is a directory")); goto fail; } if (os_nodetype((char *)fname) != NODE_WRITABLE) { - errnum = (char_u *)"E503: "; - errmsg = (char_u *)_("is not a file or writable device"); + SET_ERRMSG_NUM("E503", _("is not a file or writable device")); goto fail; } /* It's a device of some kind (or a fifo) which we can write to @@ -2597,8 +2599,7 @@ buf_write ( */ c = os_nodetype((char *)fname); if (c == NODE_OTHER) { - errnum = (char_u *)"E503: "; - errmsg = (char_u *)_("is not a file or writable device"); + SET_ERRMSG_NUM("E503", _("is not a file or writable device")); goto fail; } if (c == NODE_WRITABLE) { @@ -2606,12 +2607,11 @@ buf_write ( newfile = TRUE; perm = -1; } else { - perm = os_getperm(fname); - if (perm < 0) - newfile = TRUE; - else if (os_isdir(fname)) { - errnum = (char_u *)"E502: "; - errmsg = (char_u *)_("is a directory"); + perm = os_getperm((const char *)fname); + if (perm < 0) { + newfile = true; + } else if (os_isdir(fname)) { + SET_ERRMSG_NUM("E502", _("is a directory")); goto fail; } if (overwriting) { @@ -2630,11 +2630,9 @@ buf_write ( if (!forceit && file_readonly) { if (vim_strchr(p_cpo, CPO_FWRITE) != NULL) { - errnum = (char_u *)"E504: "; - errmsg = (char_u *)_(err_readonly); + SET_ERRMSG_NUM("E504", _(err_readonly)); } else { - errnum = (char_u *)"E505: "; - errmsg = (char_u *)_("is read-only (add ! to override)"); + SET_ERRMSG_NUM("E505", _("is read-only (add ! to override)")); } goto fail; } @@ -2870,9 +2868,9 @@ buf_write ( xfree(backup); backup = NULL; } else { - /* set file protection same as original file, but - * strip s-bit */ - (void)os_setperm(backup, perm & 0777); + // set file protection same as original file, but + // strip s-bit. + (void)os_setperm((const char *)backup, perm & 0777); #ifdef UNIX /* @@ -2883,7 +2881,8 @@ buf_write ( */ if (file_info_new.stat.st_gid != file_info_old.stat.st_gid && os_fchown(bfd, -1, file_info_old.stat.st_gid) != 0) { - os_setperm(backup, (perm & 0707) | ((perm & 07) << 3)); + os_setperm((const char *)backup, + (perm & 0707) | ((perm & 07) << 3)); } # ifdef HAVE_SELINUX mch_copy_sec(fname, backup); @@ -2901,23 +2900,27 @@ buf_write ( while ((write_info.bw_len = read_eintr(fd, copybuf, BUFSIZE)) > 0) { if (buf_write_bytes(&write_info) == FAIL) { - errmsg = (char_u *)_( - "E506: Can't write to backup file (add ! to override)"); + SET_ERRMSG(_( + "E506: Can't write to backup file (add ! to override)")); break; } os_breakcheck(); if (got_int) { - errmsg = (char_u *)_(e_interr); + SET_ERRMSG(_(e_interr)); break; } } - if (close(bfd) < 0 && errmsg == NULL) - errmsg = (char_u *)_( - "E507: Close error for backup file (add ! to override)"); - if (write_info.bw_len < 0) - errmsg = (char_u *)_( - "E508: Can't read file for backup (add ! to override)"); + int error; + if ((error = os_close(bfd)) != 0 && errmsg == NULL) { + SET_ERRMSG_ARG(_("E507: Close error for backup file " + "(add ! to override): %s"), + error); + } + if (write_info.bw_len < 0) { + SET_ERRMSG(_( + "E508: Can't read file for backup (add ! to override)")); + } #ifdef UNIX set_file_time(backup, file_info_old.stat.st_atim.tv_sec, @@ -2934,18 +2937,19 @@ buf_write ( } } nobackup: - close(fd); /* ignore errors for closing read file */ + os_close(fd); // Ignore errors for closing read file. xfree(copybuf); - if (backup == NULL && errmsg == NULL) - errmsg = (char_u *)_( - "E509: Cannot create backup file (add ! to override)"); - /* ignore errors when forceit is TRUE */ + if (backup == NULL && errmsg == NULL) { + SET_ERRMSG(_( + "E509: Cannot create backup file (add ! to override)")); + } + // Ignore errors when forceit is TRUE. if ((some_error || errmsg != NULL) && !forceit) { retval = FAIL; goto fail; } - errmsg = NULL; + SET_ERRMSG(NULL); } else { char_u *dirp; char_u *p; @@ -2960,8 +2964,7 @@ nobackup: * anyway, thus we need an extra check here. */ if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL) { - errnum = (char_u *)"E504: "; - errmsg = (char_u *)_(err_readonly); + SET_ERRMSG_NUM("E504", _(err_readonly)); goto fail; } @@ -3025,7 +3028,7 @@ nobackup: } } 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; } } @@ -3037,8 +3040,8 @@ nobackup: && file_info_old.stat.st_uid == getuid() && vim_strchr(p_cpo, CPO_FWRITE) == NULL) { perm |= 0200; - (void)os_setperm(fname, perm); - made_writable = TRUE; + (void)os_setperm((const char *)fname, perm); + made_writable = true; } #endif @@ -3066,7 +3069,7 @@ nobackup: && !(exiting && backup != NULL)) { ml_preserve(buf, FALSE); if (got_int) { - errmsg = (char_u *)_(e_interr); + SET_ERRMSG(_(e_interr)); goto restore_backup; } } @@ -3137,8 +3140,8 @@ nobackup: */ if (*p_ccv != NUL) { wfname = vim_tempname(); - if (wfname == NULL) { /* Can't write without a tempfile! */ - errmsg = (char_u *)_("E214: Can't find temp file for writing"); + if (wfname == NULL) { // Can't write without a tempfile! + SET_ERRMSG(_("E214: Can't find temp file for writing")); goto restore_backup; } } @@ -3150,8 +3153,8 @@ nobackup: && wfname == fname ) { if (!forceit) { - errmsg = (char_u *)_( - "E213: Cannot convert (add ! to write without conversion)"); + SET_ERRMSG(_( + "E213: Cannot convert (add ! to write without conversion)")); goto restore_backup; } notconverted = TRUE; @@ -3186,11 +3189,10 @@ nobackup: if ((!newfile && os_fileinfo_hardlinks(&file_info) > 1) || (os_fileinfo_link((char *)fname, &file_info) && !os_fileinfo_id_equal(&file_info, &file_info_old))) { - errmsg = (char_u *)_("E166: Can't open linked file for writing"); - } else + SET_ERRMSG(_("E166: Can't open linked file for writing")); + } else { #endif - { - errmsg = (char_u *)_("E212: Can't open file for writing"); + SET_ERRMSG_ARG(_("E212: Can't open file for writing: %s"), fd); if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL && perm >= 0) { #ifdef UNIX @@ -3208,7 +3210,9 @@ nobackup: os_remove((char *)wfname); continue; } +#ifdef UNIX } +#endif } restore_backup: @@ -3250,7 +3254,7 @@ restore_backup: xfree(wfname); goto fail; } - errmsg = NULL; + SET_ERRMSG(NULL); write_info.bw_fd = fd; @@ -3370,7 +3374,6 @@ restore_backup: nchars += len; } -#if defined(UNIX) // 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 @@ -3379,11 +3382,11 @@ restore_backup: // 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 && os_fsync(fd) != 0 && !device) { - errmsg = (char_u *)_("E667: Fsync failed"); + int error; + if (p_fs && (error = os_fsync(fd)) != 0 && !device) { + SET_ERRMSG_ARG(_("E667: Fsync failed: %s"), error); end = 0; } -#endif #ifdef HAVE_SELINUX /* Probably need to set the security context. */ @@ -3402,8 +3405,9 @@ restore_backup: || file_info.stat.st_uid != file_info_old.stat.st_uid || file_info.stat.st_gid != file_info_old.stat.st_gid) { os_fchown(fd, file_info_old.stat.st_uid, file_info_old.stat.st_gid); - if (perm >= 0) /* set permission again, may have changed */ - (void)os_setperm(wfname, perm); + if (perm >= 0) { // Set permission again, may have changed. + (void)os_setperm((const char *)wfname, perm); + } } buf_set_file_id(buf); } else if (!buf->file_id_valid) { @@ -3412,8 +3416,8 @@ restore_backup: } #endif - if (close(fd) != 0) { - errmsg = (char_u *)_("E512: Close failed"); + if ((error = os_close(fd)) != 0) { + SET_ERRMSG_ARG(_("E512: Close failed: %s"), error); end = 0; } @@ -3421,8 +3425,9 @@ restore_backup: 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)os_setperm(wfname, perm); + if (perm >= 0) { // Set perm. of new file same as old file. + (void)os_setperm((const char *)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). */ @@ -3449,21 +3454,24 @@ restore_backup: if (end == 0) { if (errmsg == NULL) { if (write_info.bw_conv_error) { - if (write_info.bw_conv_error_lnum == 0) - errmsg = (char_u *)_( - "E513: write error, conversion failed (make 'fenc' empty to override)"); - else { - errmsg_allocated = TRUE; - errmsg = xmalloc(300); - vim_snprintf((char *)errmsg, 300, - _("E513: write error, conversion failed in line %" PRId64 + if (write_info.bw_conv_error_lnum == 0) { + SET_ERRMSG(_( + "E513: write error, conversion failed " + "(make 'fenc' empty to override)")); + } else { + errmsg_allocated = true; + SET_ERRMSG(xmalloc(300)); + vim_snprintf( + errmsg, 300, + _("E513: write error, conversion failed in line %" PRIdLINENR " (make 'fenc' empty to override)"), - (int64_t)write_info.bw_conv_error_lnum); + write_info.bw_conv_error_lnum); } - } else if (got_int) - errmsg = (char_u *)_(e_interr); - else - errmsg = (char_u *)_("E514: write error (file system full?)"); + } else if (got_int) { + SET_ERRMSG(_(e_interr)); + } else { + SET_ERRMSG(_("E514: write error (file system full?)")); + } } /* @@ -3518,8 +3526,8 @@ restore_backup: fname = sfname; /* use shortname now, for the messages */ #endif if (!filtering) { - msg_add_fname(buf, fname); /* put fname in IObuff with quotes */ - c = FALSE; + add_quoted_fname((char *)IObuff, IOSIZE, buf, (const char *)fname); + c = false; if (write_info.bw_conv_error) { STRCAT(IObuff, _(" CONVERSION ERROR")); c = TRUE; @@ -3628,7 +3636,7 @@ restore_backup: close(empty_fd); } if (org != NULL) { - os_setperm((char_u *)org, os_getperm(fname) & 0777); + os_setperm(org, os_getperm((const char *)fname) & 0777); xfree(org); } } @@ -3668,33 +3676,32 @@ nofail: #endif if (errmsg != NULL) { - int numlen = errnum != NULL ? (int)STRLEN(errnum) : 0; - - attr = hl_attr(HLF_E); /* set highlight for error messages */ - msg_add_fname(buf, + // - 100 to save some space for further error message #ifndef UNIX - sfname + add_quoted_fname((char *)IObuff, IOSIZE - 100, buf, (const char *)sfname); #else - fname + add_quoted_fname((char *)IObuff, IOSIZE - 100, buf, (const char *)fname); #endif - ); /* put file name in IObuff with quotes */ - if (STRLEN(IObuff) + STRLEN(errmsg) + numlen >= IOSIZE) - IObuff[IOSIZE - STRLEN(errmsg) - numlen - 1] = NUL; - /* If the error message has the form "is ...", put the error number in - * front of the file name. */ if (errnum != NULL) { - STRMOVE(IObuff + numlen, IObuff); - memmove(IObuff, errnum, (size_t)numlen); + if (errmsgarg != 0) { + emsgf("%s: %s%s: %s", errnum, IObuff, errmsg, os_strerror(errmsgarg)); + } else { + emsgf("%s: %s%s", errnum, IObuff, errmsg); + } + } else if (errmsgarg != 0) { + emsgf(errmsg, os_strerror(errmsgarg)); + } else { + emsgf(errmsg); } - STRCAT(IObuff, errmsg); - emsg(IObuff); - if (errmsg_allocated) + if (errmsg_allocated) { xfree(errmsg); + } retval = FAIL; 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"), - attr | MSG_HIST); + attr | MSG_HIST); MSG_PUTS_ATTR(_( "don't quit the editor until the file is successfully written!"), attr | MSG_HIST); @@ -3754,6 +3761,9 @@ nofail: got_int |= prev_got_int; return retval; +#undef SET_ERRMSG +#undef SET_ERRMSG_ARG +#undef SET_ERRMSG_NUM } /* @@ -3797,16 +3807,25 @@ static int set_rw_fname(char_u *fname, char_u *sfname) return OK; } -/* - * Put file name into IObuff with quotes. - */ -void msg_add_fname(buf_T *buf, char_u *fname) +/// Put file name into the specified buffer with quotes +/// +/// Replaces home directory at the start with `~`. +/// +/// @param[out] ret_buf Buffer to save results to. +/// @param[in] buf_len ret_buf length. +/// @param[in] buf buf_T file name is coming from. +/// @param[in] fname File name to write. +static void add_quoted_fname(char *const ret_buf, const size_t buf_len, + const buf_T *const buf, const char *fname) + FUNC_ATTR_NONNULL_ARG(1) { - if (fname == NULL) - fname = (char_u *)"-stdin-"; - home_replace(buf, fname, IObuff + 1, IOSIZE - 4, TRUE); - IObuff[0] = '"'; - STRCAT(IObuff, "\" "); + if (fname == NULL) { + fname = "-stdin-"; + } + ret_buf[0] = '"'; + home_replace(buf, (const char_u *)fname, (char_u *)ret_buf + 1, + (int)buf_len - 4, true); + xstrlcat(ret_buf, "\" ", buf_len); } /// Append message for text mode to IObuff. @@ -4548,9 +4567,9 @@ int put_time(FILE *fd, time_t time_) /// os_rename() only works if both files are on the same file system, this /// function will (attempts to?) copy the file across if rename fails -- webb -// +/// /// @return -1 for failure, 0 for success -int vim_rename(char_u *from, char_u *to) +int vim_rename(const char_u *from, const char_u *to) { int fd_in; int fd_out; @@ -4569,10 +4588,12 @@ int vim_rename(char_u *from, char_u *to) * the file name differs we need to go through a temp file. */ if (fnamecmp(from, to) == 0) { - if (p_fic && STRCMP(path_tail(from), path_tail(to)) != 0) + if (p_fic && (STRCMP(path_tail((char_u *)from), path_tail((char_u *)to)) + != 0)) { use_tmp_file = true; - else + } else { return 0; + } } // Fail if the "from" file doesn't exist. Avoids that "to" is deleted. @@ -4638,9 +4659,9 @@ int vim_rename(char_u *from, char_u *to) /* * Rename() failed, try copying the file. */ - perm = os_getperm(from); + perm = os_getperm((const char *)from); #ifdef HAVE_ACL - /* For systems that support ACL: get the ACL from the original file. */ + // For systems that support ACL: get the ACL from the original file. acl = mch_get_acl(from); #endif fd_in = os_open((char *)from, O_RDONLY, 0); @@ -4688,8 +4709,8 @@ int vim_rename(char_u *from, char_u *to) errmsg = _("E210: Error reading \"%s\""); to = from; } -#ifndef UNIX /* for Unix os_open() already set the permission */ - os_setperm(to, perm); +#ifndef UNIX // For Unix os_open() already set the permission. + os_setperm((const char *)to, perm); #endif #ifdef HAVE_ACL mch_set_acl(to, acl); @@ -5200,7 +5221,7 @@ void forward_slash(char_u *fname) { char_u *p; - if (path_with_url(fname)) { + if (path_with_url((const char *)fname)) { return; } for (p = fname; *p != NUL; p++) { @@ -5261,7 +5282,7 @@ static void vim_maketempdir(void) /// Delete "name" and everything in it, recursively. /// @param name The path which should be deleted. /// @return 0 for success, -1 if some file was not deleted. -int delete_recursive(char_u *name) +int delete_recursive(const char *name) { int result = 0; @@ -5275,7 +5296,7 @@ int delete_recursive(char_u *name) EW_DIR | EW_FILE | EW_SILENT | EW_ALLLINKS | EW_DODOT | EW_EMPTYOK) == OK) { for (int i = 0; i < file_count; i++) { - if (delete_recursive(files[i]) != 0) { + if (delete_recursive((const char *)files[i]) != 0) { result = -1; } } @@ -5285,9 +5306,9 @@ int delete_recursive(char_u *name) } xfree(exp); - os_rmdir((char *)name); + os_rmdir(name); } else { - result = os_remove((char *)name) == 0 ? 0 : -1; + result = os_remove(name) == 0 ? 0 : -1; } return result; @@ -5299,7 +5320,7 @@ void vim_deltempdir(void) if (vim_tempdir != NULL) { // remove the trailing path separator path_tail(vim_tempdir)[-1] = NUL; - delete_recursive(vim_tempdir); + delete_recursive((const char *)vim_tempdir); xfree(vim_tempdir); vim_tempdir = NULL; } @@ -6464,6 +6485,12 @@ win_found: win_remove(curwin, NULL); aucmd_win_used = false; last_status(false); // may need to remove last status line + + if (!valid_tabpage_win(curtab)) { + // no valid window in current tabpage + close_tabpage(curtab); + } + restore_snapshot(SNAP_AUCMD_IDX, false); (void)win_comp_pos(); // recompute window positions unblock_autocmds(); |