neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

bufwrite.c (60699B)


      1 // bufwrite.c: functions for writing a buffer
      2 
      3 #include <fcntl.h>
      4 #include <iconv.h>
      5 #include <inttypes.h>
      6 #include <stdbool.h>
      7 #include <stdio.h>
      8 #include <string.h>
      9 #include <sys/stat.h>
     10 #include <uv.h>
     11 
     12 #include "auto/config.h"
     13 #include "nvim/ascii_defs.h"
     14 #include "nvim/autocmd.h"
     15 #include "nvim/autocmd_defs.h"
     16 #include "nvim/buffer.h"
     17 #include "nvim/buffer_defs.h"
     18 #include "nvim/bufwrite.h"
     19 #include "nvim/change.h"
     20 #include "nvim/drawscreen.h"
     21 #include "nvim/errors.h"
     22 #include "nvim/eval/typval_defs.h"
     23 #include "nvim/eval/vars.h"
     24 #include "nvim/ex_cmds.h"
     25 #include "nvim/ex_cmds_defs.h"
     26 #include "nvim/ex_eval.h"
     27 #include "nvim/fileio.h"
     28 #include "nvim/gettext_defs.h"
     29 #include "nvim/globals.h"
     30 #include "nvim/highlight_defs.h"
     31 #include "nvim/iconv_defs.h"
     32 #include "nvim/input.h"
     33 #include "nvim/macros_defs.h"
     34 #include "nvim/mbyte.h"
     35 #include "nvim/memline.h"
     36 #include "nvim/memline_defs.h"
     37 #include "nvim/memory.h"
     38 #include "nvim/message.h"
     39 #include "nvim/option.h"
     40 #include "nvim/option_vars.h"
     41 #include "nvim/os/fs.h"
     42 #include "nvim/os/fs_defs.h"
     43 #include "nvim/os/input.h"
     44 #include "nvim/os/os_defs.h"
     45 #include "nvim/path.h"
     46 #include "nvim/pos_defs.h"
     47 #include "nvim/sha256.h"
     48 #include "nvim/strings.h"
     49 #include "nvim/types_defs.h"
     50 #include "nvim/ui.h"
     51 #include "nvim/undo.h"
     52 #include "nvim/undo_defs.h"
     53 #include "nvim/vim_defs.h"
     54 
     55 static const char *err_readonly = "is read-only (cannot override: \"W\" in 'cpoptions')";
     56 static const char e_patchmode_cant_touch_empty_original_file[]
     57  = N_("E206: Patchmode: can't touch empty original file");
     58 static const char e_write_error_conversion_failed_make_fenc_empty_to_override[]
     59  = N_("E513: Write error, conversion failed (make 'fenc' empty to override)");
     60 static const char e_write_error_conversion_failed_in_line_nr_make_fenc_empty_to_override[]
     61  = N_("E513: Write error, conversion failed in line %" PRIdLINENR
     62       " (make 'fenc' empty to override)");
     63 static const char e_write_error_file_system_full[]
     64  = N_("E514: Write error (file system full?)");
     65 static const char e_no_matching_autocommands_for_buftype_str_buffer[]
     66  = N_("E676: No matching autocommands for buftype=%s buffer");
     67 
     68 typedef struct {
     69  const char *num;
     70  char *msg;
     71  int arg;
     72  bool alloc;
     73 } Error_T;
     74 
     75 #define SMALLBUFSIZE 256     // size of emergency write buffer
     76 
     77 // Structure to pass arguments from buf_write() to buf_write_bytes().
     78 struct bw_info {
     79  int bw_fd;                      // file descriptor
     80  char *bw_buf;                   // buffer with data to be written
     81  int bw_len;                     // length of data
     82  int bw_flags;                   // FIO_ flags
     83  int bw_first;                   // first write call
     84  char *bw_conv_buf;              // buffer for writing converted chars
     85  size_t bw_conv_buflen;          // size of bw_conv_buf
     86  int bw_conv_error;              // set for conversion error
     87  linenr_T bw_conv_error_lnum;    // first line with error or zero
     88  linenr_T bw_start_lnum;         // line number at start of buffer
     89  iconv_t bw_iconv_fd;            // descriptor for iconv() or -1
     90 };
     91 
     92 #include "bufwrite.c.generated.h"
     93 
     94 /// Convert a Unicode character to bytes.
     95 ///
     96 /// @param c character to convert
     97 /// @param[in,out] pp pointer to store the result at
     98 /// @param flags FIO_ flags that specify which encoding to use
     99 ///
    100 /// @return true for an error, false when it's OK.
    101 static bool ucs2bytes(unsigned c, char **pp, int flags)
    102  FUNC_ATTR_NONNULL_ALL
    103 {
    104  uint8_t *p = (uint8_t *)(*pp);
    105  bool error = false;
    106 
    107  if (flags & FIO_UCS4) {
    108    if (flags & FIO_ENDIAN_L) {
    109      *p++ = (uint8_t)c;
    110      *p++ = (uint8_t)(c >> 8);
    111      *p++ = (uint8_t)(c >> 16);
    112      *p++ = (uint8_t)(c >> 24);
    113    } else {
    114      *p++ = (uint8_t)(c >> 24);
    115      *p++ = (uint8_t)(c >> 16);
    116      *p++ = (uint8_t)(c >> 8);
    117      *p++ = (uint8_t)c;
    118    }
    119  } else if (flags & (FIO_UCS2 | FIO_UTF16)) {
    120    if (c >= 0x10000) {
    121      if (flags & FIO_UTF16) {
    122        // Make two words, ten bits of the character in each.  First
    123        // word is 0xd800 - 0xdbff, second one 0xdc00 - 0xdfff
    124        c -= 0x10000;
    125        if (c >= 0x100000) {
    126          error = true;
    127        }
    128        int cc = (int)(((c >> 10) & 0x3ff) + 0xd800);
    129        if (flags & FIO_ENDIAN_L) {
    130          *p++ = (uint8_t)cc;
    131          *p++ = (uint8_t)(cc >> 8);
    132        } else {
    133          *p++ = (uint8_t)(cc >> 8);
    134          *p++ = (uint8_t)cc;
    135        }
    136        c = (c & 0x3ff) + 0xdc00;
    137      } else {
    138        error = true;
    139      }
    140    }
    141    if (flags & FIO_ENDIAN_L) {
    142      *p++ = (uint8_t)c;
    143      *p++ = (uint8_t)(c >> 8);
    144    } else {
    145      *p++ = (uint8_t)(c >> 8);
    146      *p++ = (uint8_t)c;
    147    }
    148  } else {  // Latin1
    149    if (c >= 0x100) {
    150      error = true;
    151      *p++ = 0xBF;
    152    } else {
    153      *p++ = (uint8_t)c;
    154    }
    155  }
    156 
    157  *pp = (char *)p;
    158  return error;
    159 }
    160 
    161 /// Converts a buffer encoding based on values in ip using iconv.
    162 ///
    163 /// See buf_write_convert for parameters and return value details.
    164 static int buf_write_convert_with_iconv(struct bw_info *ip, char **bufp, int *lenp)
    165 {
    166  int len = *lenp;
    167 
    168  // Convert with iconv().
    169  const char *from = *bufp;
    170  size_t fromlen = (size_t)len;
    171  size_t tolen = ip->bw_conv_buflen;
    172  char *to = ip->bw_conv_buf;
    173 
    174  if (ip->bw_first) {
    175    size_t save_len = tolen;
    176 
    177    // output the initial shift state sequence
    178    iconv(ip->bw_iconv_fd, NULL, NULL, &to, &tolen);
    179 
    180    // There is a bug in iconv() on Linux (which appears to be
    181    // wide-spread) which sets "to" to NULL and messes up "tolen".
    182    if (to == NULL) {
    183      to = ip->bw_conv_buf;
    184      tolen = save_len;
    185    }
    186    ip->bw_first = false;
    187  }
    188 
    189  // If iconv() has an error, fail.
    190  if (iconv(ip->bw_iconv_fd, (void *)&from, &fromlen, &to, &tolen)
    191      == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL) {
    192    ip->bw_conv_error = true;
    193    return -1;
    194  }
    195 
    196  *bufp = ip->bw_conv_buf;
    197  *lenp = (int)(to - ip->bw_conv_buf);
    198 
    199  return len - (int)fromlen;
    200 }
    201 
    202 /// Converts a buffer encoding based on values in ip.
    203 ///
    204 /// @param ip buf_write_bytes context
    205 /// @param[in,out] bufp Pointer to the input buffer. On return, pointer to the output buffer.
    206 /// @param[in,out] lenp Pointer to the input buffer length. On return the referenced value is set to
    207 ///                     the length of the output buffer.
    208 ///
    209 /// @return The number of input buffer bytes consumed for the conversion, which may be less than the
    210 ///         initial input buffer size when the buffer ends with an incomplete character sequence.
    211 static int buf_write_convert(struct bw_info *ip, char **bufp, int *lenp)
    212 {
    213  int flags = ip->bw_flags;  // extra flags
    214 
    215  int wlen = *lenp;
    216  if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1)) {
    217    unsigned c;
    218    int n = 0;
    219    // Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or
    220    // Latin1 chars in the file.
    221    // translate in-place (can only get shorter) or to buffer
    222    char *p = flags & FIO_LATIN1 ? *bufp : ip->bw_conv_buf;
    223    for (wlen = 0; wlen < *lenp; wlen += n) {
    224      n = utf_ptr2len_len(*bufp + wlen, *lenp - wlen);
    225      if (n > *lenp - wlen) {
    226        // We have an incomplete byte sequence at the end to
    227        // be written.  We can't convert it without the
    228        // remaining bytes.  Keep them for the next call.
    229        break;
    230      }
    231      c = n > 1 ? (unsigned)utf_ptr2char(*bufp + wlen)
    232                : (uint8_t)(*bufp)[wlen];
    233      // Check that there is enough space
    234      if (!(flags & FIO_LATIN1)) {
    235        size_t need = (flags & FIO_UCS4) ? 4 : 2;
    236        if ((flags & FIO_UTF16) && c >= 0x10000) {
    237          need = 4;
    238        }
    239 
    240        if ((size_t)(p - ip->bw_conv_buf) + need > ip->bw_conv_buflen) {
    241          return FAIL;
    242        }
    243      }
    244 
    245      if (ucs2bytes(c, &p, flags) && !ip->bw_conv_error) {
    246        ip->bw_conv_error = true;
    247        ip->bw_conv_error_lnum = ip->bw_start_lnum;
    248      }
    249      if (c == NL) {
    250        ip->bw_start_lnum++;
    251      }
    252    }
    253    if (flags & FIO_LATIN1) {
    254      *lenp = (int)(p - *bufp);
    255    } else {
    256      *bufp = ip->bw_conv_buf;
    257      *lenp = (int)(p - ip->bw_conv_buf);
    258    }
    259  }
    260 
    261  if (ip->bw_iconv_fd != (iconv_t)-1) {
    262    return buf_write_convert_with_iconv(ip, bufp, lenp);
    263  }
    264 
    265  return wlen;
    266 }
    267 
    268 /// Call write() to write a number of bytes to the file.
    269 /// Handles 'encoding' conversion.
    270 ///
    271 /// @return  FAIL for failure, OK otherwise.
    272 static int buf_write_bytes(struct bw_info *ip)
    273 {
    274  char *buf = ip->bw_buf;    // data to write
    275  int len = ip->bw_len;      // length of data
    276  int flags = ip->bw_flags;  // extra flags
    277 
    278  int converted = len;
    279  int remaining = 0;
    280 
    281  // Skip conversion when writing the BOM.
    282  if (!(flags & FIO_NOCONVERT)) {
    283    if ((converted = buf_write_convert(ip, &buf, &len)) < 0) {
    284      return FAIL;
    285    }
    286 
    287    remaining = ip->bw_len - converted;
    288  }
    289 
    290  ip->bw_len = remaining;
    291 
    292  // Skip writing while checking conversion
    293  if (ip->bw_fd >= 0) {
    294    int wlen = (int)write_eintr(ip->bw_fd, buf, (size_t)len);
    295    if (wlen < len) {
    296      return FAIL;
    297    }
    298  }
    299 
    300  if (remaining > 0) {
    301    memmove(ip->bw_buf, ip->bw_buf + converted, (size_t)remaining);
    302  }
    303 
    304  return OK;
    305 }
    306 
    307 /// Check modification time of file, before writing to it.
    308 /// The size isn't checked, because using a tool like "gzip" takes care of
    309 /// using the same timestamp but can't set the size.
    310 static int check_mtime(buf_T *buf, FileInfo *file_info)
    311 {
    312  if (buf->b_mtime_read != 0
    313      && time_differs(file_info, buf->b_mtime_read, buf->b_mtime_read_ns)) {
    314    msg_scroll = true;  // Don't overwrite messages here.
    315    msg_silent = 0;     // Must give this prompt.
    316    // Don't use emsg() here, don't want to flush the buffers.
    317    msg(_("WARNING: The file has been changed since reading it!!!"), HLF_E);
    318    if (ask_yesno(_("Do you really want to write to it")) == 'n') {
    319      return FAIL;
    320    }
    321    msg_scroll = false;  // Always overwrite the file message now.
    322  }
    323  return OK;
    324 }
    325 
    326 /// Generate a BOM in "buf[4]" for encoding "name".
    327 ///
    328 /// @return  the length of the BOM (zero when no BOM).
    329 static int make_bom(char *buf_in, char *name)
    330 {
    331  uint8_t *buf = (uint8_t *)buf_in;
    332  int flags = get_fio_flags(name);
    333 
    334  // Can't put a BOM in a non-Unicode file.
    335  if (flags == FIO_LATIN1 || flags == 0) {
    336    return 0;
    337  }
    338 
    339  if (flags == FIO_UTF8) {      // UTF-8
    340    buf[0] = 0xef;
    341    buf[1] = 0xbb;
    342    buf[2] = 0xbf;
    343    return 3;
    344  }
    345  char *p = (char *)buf;
    346  ucs2bytes(0xfeff, &p, flags);
    347  return (int)((uint8_t *)p - buf);
    348 }
    349 
    350 static int buf_write_do_autocmds(buf_T *buf, char **fnamep, char **sfnamep, char **ffnamep,
    351                                 linenr_T start, linenr_T *endp, exarg_T *eap, bool append,
    352                                 bool filtering, bool reset_changed, bool overwriting, bool whole,
    353                                 const pos_T orig_start, const pos_T orig_end)
    354 {
    355  linenr_T old_line_count = buf->b_ml.ml_line_count;
    356  int msg_save = msg_scroll;
    357 
    358  aco_save_T aco;
    359  bool did_cmd = false;
    360  bool nofile_err = false;
    361  bool empty_memline = buf->b_ml.ml_mfp == NULL;
    362  bufref_T bufref;
    363 
    364  char *sfname = *sfnamep;
    365 
    366  // Apply PRE autocommands.
    367  // Set curbuf to the buffer to be written.
    368  // Careful: The autocommands may call buf_write() recursively!
    369  bool buf_ffname = *ffnamep == buf->b_ffname;
    370  bool buf_sfname = sfname == buf->b_sfname;
    371  bool buf_fname_f = *fnamep == buf->b_ffname;
    372  bool buf_fname_s = *fnamep == buf->b_sfname;
    373 
    374  // Set curwin/curbuf to buf and save a few things.
    375  aucmd_prepbuf(&aco, buf);
    376  set_bufref(&bufref, buf);
    377 
    378  if (append) {
    379    did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD, sfname, sfname, false, curbuf, eap);
    380    if (!did_cmd) {
    381      if (overwriting && bt_nofilename(curbuf)) {
    382        nofile_err = true;
    383      } else {
    384        apply_autocmds_exarg(EVENT_FILEAPPENDPRE,
    385                             sfname, sfname, false, curbuf, eap);
    386      }
    387    }
    388  } else if (filtering) {
    389    apply_autocmds_exarg(EVENT_FILTERWRITEPRE,
    390                         NULL, sfname, false, curbuf, eap);
    391  } else if (reset_changed && whole) {
    392    bool was_changed = curbufIsChanged();
    393 
    394    did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD, sfname, sfname, false, curbuf, eap);
    395    if (did_cmd) {
    396      if (was_changed && !curbufIsChanged()) {
    397        // Written everything correctly and BufWriteCmd has reset
    398        // 'modified': Correct the undo information so that an
    399        // undo now sets 'modified'.
    400        u_unchanged(curbuf);
    401        u_update_save_nr(curbuf);
    402      }
    403    } else {
    404      if (overwriting && bt_nofilename(curbuf)) {
    405        nofile_err = true;
    406      } else {
    407        apply_autocmds_exarg(EVENT_BUFWRITEPRE,
    408                             sfname, sfname, false, curbuf, eap);
    409      }
    410    }
    411  } else {
    412    did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD, sfname, sfname, false, curbuf, eap);
    413    if (!did_cmd) {
    414      if (overwriting && bt_nofilename(curbuf)) {
    415        nofile_err = true;
    416      } else {
    417        apply_autocmds_exarg(EVENT_FILEWRITEPRE,
    418                             sfname, sfname, false, curbuf, eap);
    419      }
    420    }
    421  }
    422 
    423  // restore curwin/curbuf and a few other things
    424  aucmd_restbuf(&aco);
    425 
    426  // In three situations we return here and don't write the file:
    427  // 1. the autocommands deleted or unloaded the buffer.
    428  // 2. The autocommands abort script processing.
    429  // 3. If one of the "Cmd" autocommands was executed.
    430  if (!bufref_valid(&bufref)) {
    431    buf = NULL;
    432  }
    433  if (buf == NULL || (buf->b_ml.ml_mfp == NULL && !empty_memline)
    434      || did_cmd || nofile_err
    435      || aborting()) {
    436    if (buf != NULL && (cmdmod.cmod_flags & CMOD_LOCKMARKS)) {
    437      // restore the original '[ and '] positions
    438      buf->b_op_start = orig_start;
    439      buf->b_op_end = orig_end;
    440    }
    441 
    442    no_wait_return--;
    443    msg_scroll = msg_save;
    444    if (nofile_err) {
    445      semsg(_(e_no_matching_autocommands_for_buftype_str_buffer), curbuf->b_p_bt);
    446    }
    447 
    448    if (nofile_err || aborting()) {
    449      // An aborting error, interrupt or exception in the
    450      // autocommands.
    451      return FAIL;
    452    }
    453    if (did_cmd) {
    454      if (buf == NULL) {
    455        // The buffer was deleted.  We assume it was written
    456        // (can't retry anyway).
    457        return OK;
    458      }
    459      if (overwriting) {
    460        // Assume the buffer was written, update the timestamp.
    461        ml_timestamp(buf);
    462        if (append) {
    463          buf->b_flags &= ~BF_NEW;
    464        } else {
    465          buf->b_flags &= ~BF_WRITE_MASK;
    466        }
    467      }
    468      if (reset_changed && buf->b_changed && !append
    469          && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)) {
    470        // Buffer still changed, the autocommands didn't work properly.
    471        return FAIL;
    472      }
    473      return OK;
    474    }
    475    if (!aborting()) {
    476      emsg(_("E203: Autocommands deleted or unloaded buffer to be written"));
    477    }
    478    return FAIL;
    479  }
    480 
    481  // The autocommands may have changed the number of lines in the file.
    482  // When writing the whole file, adjust the end.
    483  // When writing part of the file, assume that the autocommands only
    484  // changed the number of lines that are to be written (tricky!).
    485  if (buf->b_ml.ml_line_count != old_line_count) {
    486    if (whole) {                                              // write all
    487      *endp = buf->b_ml.ml_line_count;
    488    } else if (buf->b_ml.ml_line_count > old_line_count) {           // more lines
    489      *endp += buf->b_ml.ml_line_count - old_line_count;
    490    } else {                                                    // less lines
    491      *endp -= old_line_count - buf->b_ml.ml_line_count;
    492      if (*endp < start) {
    493        no_wait_return--;
    494        msg_scroll = msg_save;
    495        emsg(_("E204: Autocommand changed number of lines in unexpected way"));
    496        return FAIL;
    497      }
    498    }
    499  }
    500 
    501  // The autocommands may have changed the name of the buffer, which may
    502  // be kept in fname, ffname and sfname.
    503  if (buf_ffname) {
    504    *ffnamep = buf->b_ffname;
    505  }
    506  if (buf_sfname) {
    507    *sfnamep = buf->b_sfname;
    508  }
    509  if (buf_fname_f) {
    510    *fnamep = buf->b_ffname;
    511  }
    512  if (buf_fname_s) {
    513    *fnamep = buf->b_sfname;
    514  }
    515  return NOTDONE;
    516 }
    517 
    518 static void buf_write_do_post_autocmds(buf_T *buf, char *fname, exarg_T *eap, bool append,
    519                                       bool filtering, bool reset_changed, bool whole)
    520 {
    521  aco_save_T aco;
    522 
    523  curbuf->b_no_eol_lnum = 0;      // in case it was set by the previous read
    524 
    525  // Apply POST autocommands.
    526  // Careful: The autocommands may call buf_write() recursively!
    527  aucmd_prepbuf(&aco, buf);
    528 
    529  if (append) {
    530    apply_autocmds_exarg(EVENT_FILEAPPENDPOST, fname, fname,
    531                         false, curbuf, eap);
    532  } else if (filtering) {
    533    apply_autocmds_exarg(EVENT_FILTERWRITEPOST, NULL, fname,
    534                         false, curbuf, eap);
    535  } else if (reset_changed && whole) {
    536    apply_autocmds_exarg(EVENT_BUFWRITEPOST, fname, fname,
    537                         false, curbuf, eap);
    538  } else {
    539    apply_autocmds_exarg(EVENT_FILEWRITEPOST, fname, fname,
    540                         false, curbuf, eap);
    541  }
    542 
    543  // restore curwin/curbuf and a few other things
    544  aucmd_restbuf(&aco);
    545 }
    546 
    547 static inline Error_T set_err_num(const char *num, const char *msg)
    548 {
    549  return (Error_T){ .num = num, .msg = (char *)msg, .arg = 0 };
    550 }
    551 
    552 static inline Error_T set_err(const char *msg)
    553 {
    554  return (Error_T){ .num = NULL, .msg = (char *)msg, .arg = 0 };
    555 }
    556 
    557 static inline Error_T set_err_arg(const char *msg, int arg)
    558 {
    559  return (Error_T){ .num = NULL, .msg = (char *)msg, .arg = arg };
    560 }
    561 
    562 static void emit_err(Error_T *e)
    563 {
    564  if (e->num != NULL) {
    565    if (e->arg != 0) {
    566      semsg("%s: %s%s: %s", e->num, IObuff, e->msg, os_strerror(e->arg));
    567    } else {
    568      semsg("%s: %s%s", e->num, IObuff, e->msg);
    569    }
    570  } else if (e->arg != 0) {
    571    semsg(e->msg, os_strerror(e->arg));
    572  } else {
    573    emsg(e->msg);
    574  }
    575  if (e->alloc) {
    576    xfree(e->msg);
    577  }
    578 }
    579 
    580 #if defined(UNIX)
    581 
    582 static int get_fileinfo_os(char *fname, FileInfo *file_info_old, bool overwriting, int *perm,
    583                           bool *device, bool *newfile, Error_T *err)
    584 {
    585  *perm = -1;
    586  if (!os_fileinfo(fname, file_info_old)) {
    587    *newfile = true;
    588  } else {
    589    *perm = (int)file_info_old->stat.st_mode;
    590    if (!S_ISREG(file_info_old->stat.st_mode)) {             // not a file
    591      if (S_ISDIR(file_info_old->stat.st_mode)) {
    592        *err = set_err_num("E502", _("is a directory"));
    593        return FAIL;
    594      }
    595      if (os_nodetype(fname) != NODE_WRITABLE) {
    596        *err = set_err_num("E503", _("is not a file or writable device"));
    597        return FAIL;
    598      }
    599      // It's a device of some kind (or a fifo) which we can write to
    600      // but for which we can't make a backup.
    601      *device = true;
    602      *newfile = true;
    603      *perm = -1;
    604    }
    605  }
    606  return OK;
    607 }
    608 
    609 #else
    610 
    611 static int get_fileinfo_os(char *fname, FileInfo *file_info_old, bool overwriting, int *perm,
    612                           bool *device, bool *newfile, Error_T *err)
    613 {
    614  // Check for a writable device name.
    615  char nodetype = fname == NULL ? NODE_OTHER : (char)os_nodetype(fname);
    616  if (nodetype == NODE_OTHER) {
    617    *err = set_err_num("E503", _("is not a file or writable device"));
    618    return FAIL;
    619  }
    620  if (nodetype == NODE_WRITABLE) {
    621    *device = true;
    622    *newfile = true;
    623    *perm = -1;
    624  } else {
    625    *perm = os_getperm(fname);
    626    if (*perm < 0) {
    627      *newfile = true;
    628    } else if (os_isdir(fname)) {
    629      *err = set_err_num("E502", _("is a directory"));
    630      return FAIL;
    631    }
    632    if (overwriting) {
    633      os_fileinfo(fname, file_info_old);
    634    }
    635  }
    636  return OK;
    637 }
    638 
    639 #endif
    640 
    641 /// @param buf
    642 /// @param fname          File name
    643 /// @param overwriting
    644 /// @param forceit
    645 /// @param[out] file_info_old
    646 /// @param[out] perm
    647 /// @param[out] device
    648 /// @param[out] newfile
    649 /// @param[out] readonly
    650 static int get_fileinfo(buf_T *buf, char *fname, bool overwriting, bool forceit,
    651                        FileInfo *file_info_old, int *perm, bool *device, bool *newfile,
    652                        bool *readonly, Error_T *err)
    653 {
    654  if (get_fileinfo_os(fname, file_info_old, overwriting, perm, device, newfile, err) == FAIL) {
    655    return FAIL;
    656  }
    657 
    658  *readonly = false;  // overwritten file is read-only
    659 
    660  if (!*device && !*newfile) {
    661    // Check if the file is really writable (when renaming the file to
    662    // make a backup we won't discover it later).
    663    *readonly = !os_file_is_writable(fname);
    664 
    665    if (!forceit && *readonly) {
    666      if (vim_strchr(p_cpo, CPO_FWRITE) != NULL) {
    667        *err = set_err_num("E504", _(err_readonly));
    668      } else {
    669        *err = set_err_num("E505", _("is read-only (add ! to override)"));
    670      }
    671      return FAIL;
    672    }
    673 
    674    // If 'forceit' is false, check if the timestamp hasn't changed since reading the file.
    675    if (overwriting && !forceit) {
    676      int retval = check_mtime(buf, file_info_old);
    677      if (retval == FAIL) {
    678        return FAIL;
    679      }
    680    }
    681  }
    682  return OK;
    683 }
    684 
    685 /// @return The backup file name
    686 char *buf_get_backup_name(char *fname, char **dirp, bool no_prepend_dot, char *backup_ext)
    687 {
    688  char *backup = NULL;
    689  // Isolate one directory name, using an entry in 'bdir'.
    690  size_t dir_len = copy_option_part(dirp, IObuff, IOSIZE, ",");
    691  char *p = IObuff + dir_len;
    692  if (**dirp == NUL && !os_isdir(IObuff)) {
    693    int ret;
    694    char *failed_dir;
    695    if ((ret = os_mkdir_recurse(IObuff, 0755, &failed_dir, NULL)) != 0) {
    696      semsg(_("E303: Unable to create directory \"%s\" for backup file: %s"),
    697            failed_dir, os_strerror(ret));
    698      xfree(failed_dir);
    699    }
    700  }
    701  if (after_pathsep(IObuff, p) && p[-1] == p[-2]) {
    702    // path ends with '//', use full path
    703    if ((p = make_percent_swname(IObuff, p, fname))
    704        != NULL) {
    705      backup = modname(p, backup_ext, no_prepend_dot);
    706      xfree(p);
    707    }
    708  }
    709  if (backup == NULL) {
    710    char *rootname = get_file_in_dir(fname, IObuff);
    711    if (rootname != NULL) {
    712      backup = modname(rootname, backup_ext, no_prepend_dot);
    713      xfree(rootname);
    714    }
    715  }
    716  return backup;
    717 }
    718 
    719 static int buf_write_make_backup(char *fname, bool append, FileInfo *file_info_old, vim_acl_T acl,
    720                                 int perm, unsigned bkc, bool file_readonly, bool forceit,
    721                                 bool *backup_copyp, char **backupp, Error_T *err)
    722 {
    723  FileInfo file_info;
    724  const bool no_prepend_dot = false;
    725 
    726  if ((bkc & kOptBkcFlagYes) || append) {       // "yes"
    727    *backup_copyp = true;
    728  } else if ((bkc & kOptBkcFlagAuto)) {          // "auto"
    729    // Don't rename the file when:
    730    // - it's a hard link
    731    // - it's a symbolic link
    732    // - we don't have write permission in the directory
    733    if (os_fileinfo_hardlinks(file_info_old) > 1
    734        || !os_fileinfo_link(fname, &file_info)
    735        || !os_fileinfo_id_equal(&file_info, file_info_old)) {
    736      *backup_copyp = true;
    737    } else {
    738      // Check if we can create a file and set the owner/group to
    739      // the ones from the original file.
    740      // First find a file name that doesn't exist yet (use some
    741      // arbitrary numbers).
    742      size_t dirlen = (size_t)(path_tail(fname) - fname);
    743      assert(dirlen < MAXPATHL);
    744      char tmp_fname[MAXPATHL];
    745      xmemcpyz(tmp_fname, fname, dirlen);
    746      for (int i = 4913;; i += 123) {
    747        snprintf(tmp_fname + dirlen, sizeof(tmp_fname) - dirlen, "%d", i);
    748        if (!os_fileinfo_link(tmp_fname, &file_info)) {
    749          break;
    750        }
    751      }
    752      int fd = os_open(tmp_fname,
    753                       O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, perm);
    754      if (fd < 0) {           // can't write in directory
    755        *backup_copyp = true;
    756      } else {
    757 #ifdef UNIX
    758        os_fchown(fd, (uv_uid_t)file_info_old->stat.st_uid, (uv_gid_t)file_info_old->stat.st_gid);
    759        if (!os_fileinfo(tmp_fname, &file_info)
    760            || file_info.stat.st_uid != file_info_old->stat.st_uid
    761            || file_info.stat.st_gid != file_info_old->stat.st_gid
    762            || (int)file_info.stat.st_mode != perm) {
    763          *backup_copyp = true;
    764        }
    765 #endif
    766        // Close the file before removing it, on MS-Windows we
    767        // can't delete an open file.
    768        close(fd);
    769        os_remove(tmp_fname);
    770      }
    771    }
    772  }
    773 
    774  // Break symlinks and/or hardlinks if we've been asked to.
    775  if ((bkc & kOptBkcFlagBreaksymlink) || (bkc & kOptBkcFlagBreakhardlink)) {
    776 #ifdef UNIX
    777    bool file_info_link_ok = os_fileinfo_link(fname, &file_info);
    778 
    779    // Symlinks.
    780    if ((bkc & kOptBkcFlagBreaksymlink)
    781        && file_info_link_ok
    782        && !os_fileinfo_id_equal(&file_info, file_info_old)) {
    783      *backup_copyp = false;
    784    }
    785 
    786    // Hardlinks.
    787    if ((bkc & kOptBkcFlagBreakhardlink)
    788        && os_fileinfo_hardlinks(file_info_old) > 1
    789        && (!file_info_link_ok
    790            || os_fileinfo_id_equal(&file_info, file_info_old))) {
    791      *backup_copyp = false;
    792    }
    793 #endif
    794  }
    795 
    796  // make sure we have a valid backup extension to use
    797  char *backup_ext = *p_bex == NUL ? ".bak" : p_bex;
    798 
    799  if (*backup_copyp) {
    800    bool some_error = false;
    801 
    802    // Try to make the backup in each directory in the 'bdir' option.
    803    //
    804    // Unix semantics has it, that we may have a writable file,
    805    // that cannot be recreated with a simple open(..., O_CREAT, ) e.g:
    806    //  - the directory is not writable,
    807    //  - the file may be a symbolic link,
    808    //  - the file may belong to another user/group, etc.
    809    //
    810    // For these reasons, the existing writable file must be truncated
    811    // and reused. Creation of a backup COPY will be attempted.
    812    char *dirp = p_bdir;
    813    while (*dirp) {
    814      *backupp = buf_get_backup_name(fname, &dirp, no_prepend_dot, backup_ext);
    815      if (*backupp == NULL) {
    816        some_error = true;                // out of memory
    817        goto nobackup;
    818      }
    819 
    820      FileInfo file_info_new;
    821      {
    822        // Check if backup file already exists.
    823        if (os_fileinfo(*backupp, &file_info_new)) {
    824          if (os_fileinfo_id_equal(&file_info_new, file_info_old)) {
    825            //
    826            // Backup file is same as original file.
    827            // May happen when modname() gave the same file back (e.g. silly
    828            // link). If we don't check here, we either ruin the file when
    829            // copying or erase it after writing.
    830            //
    831            XFREE_CLEAR(*backupp);              // no backup file to delete
    832          } else if (!p_bk) {
    833            // We are not going to keep the backup file, so don't
    834            // delete an existing one, and try to use another name instead.
    835            // Change one character, just before the extension.
    836            //
    837            char *wp = *backupp + strlen(*backupp) - 1 - strlen(backup_ext);
    838            wp = MAX(wp, *backupp);  // empty file name ???
    839            *wp = 'z';
    840            while (*wp > 'a' && os_fileinfo(*backupp, &file_info_new)) {
    841              (*wp)--;
    842            }
    843            // They all exist??? Must be something wrong.
    844            if (*wp == 'a') {
    845              XFREE_CLEAR(*backupp);
    846            }
    847          }
    848        }
    849      }
    850 
    851      // Try to create the backup file
    852      if (*backupp != NULL) {
    853        // remove old backup, if present
    854        os_remove(*backupp);
    855 
    856        // copy the file
    857        if (os_copy(fname, *backupp, UV_FS_COPYFILE_FICLONE) != 0) {
    858          *err = set_err(_("E509: Cannot create backup file (add ! to override)"));
    859          XFREE_CLEAR(*backupp);
    860          *backupp = NULL;
    861          continue;
    862        }
    863 
    864        // set file protection same as original file, but
    865        // strip s-bit.
    866        os_setperm(*backupp, perm & 0777);
    867 
    868 #ifdef UNIX
    869        // Try to set the group of the backup same as the original file. If
    870        // this fails, set the protection bits for the group same as the
    871        // protection bits for others.
    872        if (file_info_new.stat.st_gid != file_info_old->stat.st_gid
    873            && os_chown(*backupp, (uv_uid_t)-1, (uv_gid_t)file_info_old->stat.st_gid) != 0) {
    874          os_setperm(*backupp, (perm & 0707) | ((perm & 07) << 3));
    875        }
    876        os_file_settime(*backupp,
    877                        (double)file_info_old->stat.st_atim.tv_sec,
    878                        (double)file_info_old->stat.st_mtim.tv_sec);
    879 #endif
    880 
    881        os_set_acl(*backupp, acl);
    882 #ifdef HAVE_XATTR
    883        os_copy_xattr(fname, *backupp);
    884 #endif
    885        *err = set_err(NULL);
    886        break;
    887      }
    888    }
    889 
    890 nobackup:
    891    if (*backupp == NULL && err->msg == NULL) {
    892      *err = set_err(_("E509: Cannot create backup file (add ! to override)"));
    893    }
    894    // Ignore errors when forceit is true.
    895    if ((some_error || err->msg != NULL) && !forceit) {
    896      return FAIL;
    897    }
    898    *err = set_err(NULL);
    899  } else {
    900    // Make a backup by renaming the original file.
    901 
    902    // If 'cpoptions' includes the "W" flag, we don't want to
    903    // overwrite a read-only file.  But rename may be possible
    904    // anyway, thus we need an extra check here.
    905    if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL) {
    906      *err = set_err_num("E504", _(err_readonly));
    907      return FAIL;
    908    }
    909 
    910    // Form the backup file name - change path/fo.o.h to
    911    // path/fo.o.h.bak Try all directories in 'backupdir', first one
    912    // that works is used.
    913    char *dirp = p_bdir;
    914    while (*dirp) {
    915      *backupp = buf_get_backup_name(fname, &dirp, no_prepend_dot, backup_ext);
    916      if (*backupp != NULL) {
    917        // If we are not going to keep the backup file, don't
    918        // delete an existing one, try to use another name.
    919        // Change one character, just before the extension.
    920        if (!p_bk && os_path_exists(*backupp)) {
    921          char *p = *backupp + strlen(*backupp) - 1 - strlen(backup_ext);
    922          p = MAX(p, *backupp);  // empty file name ???
    923          *p = 'z';
    924          while (*p > 'a' && os_path_exists(*backupp)) {
    925            (*p)--;
    926          }
    927          // They all exist??? Must be something wrong!
    928          if (*p == 'a') {
    929            XFREE_CLEAR(*backupp);
    930          }
    931        }
    932      }
    933      if (*backupp != NULL) {
    934        // Delete any existing backup and move the current version
    935        // to the backup. For safety, we don't remove the backup
    936        // until the write has finished successfully. And if the
    937        // 'backup' option is set, leave it around.
    938 
    939        // If the renaming of the original file to the backup file
    940        // works, quit here.
    941        ///
    942        if (vim_rename(fname, *backupp) == 0) {
    943          break;
    944        }
    945 
    946        XFREE_CLEAR(*backupp);             // don't do the rename below
    947      }
    948    }
    949    if (*backupp == NULL && !forceit) {
    950      *err = set_err(_("E510: Can't make backup file (add ! to override)"));
    951      return FAIL;
    952    }
    953  }
    954  return OK;
    955 }
    956 
    957 /// buf_write() - write to file "fname" lines "start" through "end"
    958 ///
    959 /// We do our own buffering here because fwrite() is so slow.
    960 ///
    961 /// If "forceit" is true, we don't care for errors when attempting backups.
    962 /// In case of an error everything possible is done to restore the original
    963 /// file.  But when "forceit" is true, we risk losing it.
    964 ///
    965 /// When "reset_changed" is true and "append" == false and "start" == 1 and
    966 /// "end" == curbuf->b_ml.ml_line_count, reset curbuf->b_changed.
    967 ///
    968 /// This function must NOT use NameBuff (because it's called by autowrite()).
    969 ///
    970 ///
    971 /// @param eap     for forced 'ff' and 'fenc', can be NULL!
    972 /// @param append  append to the file
    973 ///
    974 /// @return        FAIL for failure, OK otherwise
    975 int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T end, exarg_T *eap,
    976              bool append, bool forceit, bool reset_changed, bool filtering)
    977 {
    978  int retval = OK;
    979  int msg_save = msg_scroll;
    980  bool prev_got_int = got_int;
    981  // writing everything
    982  bool whole = (start == 1 && end == buf->b_ml.ml_line_count);
    983  bool write_undo_file = false;
    984  context_sha256_T sha_ctx;
    985  unsigned bkc = get_bkc_flags(buf);
    986 
    987  if (fname == NULL || *fname == NUL) {  // safety check
    988    return FAIL;
    989  }
    990  if (buf->b_ml.ml_mfp == NULL) {
    991    // This can happen during startup when there is a stray "w" in the
    992    // vimrc file.
    993    emsg(_(e_empty_buffer));
    994    return FAIL;
    995  }
    996 
    997  // Disallow writing in secure mode.
    998  if (check_secure()) {
    999    return FAIL;
   1000  }
   1001 
   1002  // Avoid a crash for a long name.
   1003  if (strlen(fname) >= MAXPATHL) {
   1004    emsg(_(e_longname));
   1005    return FAIL;
   1006  }
   1007 
   1008  // must init bw_conv_buf and bw_iconv_fd before jumping to "fail"
   1009  struct bw_info write_info;            // info for buf_write_bytes()
   1010  write_info.bw_conv_buf = NULL;
   1011  write_info.bw_conv_error = false;
   1012  write_info.bw_conv_error_lnum = 0;
   1013  write_info.bw_iconv_fd = (iconv_t)-1;
   1014 
   1015  // After writing a file changedtick changes but we don't want to display
   1016  // the line.
   1017  ex_no_reprint = true;
   1018 
   1019  // If there is no file name yet, use the one for the written file.
   1020  // BF_NOTEDITED is set to reflect this (in case the write fails).
   1021  // Don't do this when the write is for a filter command.
   1022  // Don't do this when appending.
   1023  // Only do this when 'cpoptions' contains the 'F' flag.
   1024  if (buf->b_ffname == NULL
   1025      && reset_changed
   1026      && whole
   1027      && buf == curbuf
   1028      && !bt_nofilename(buf)
   1029      && !filtering
   1030      && (!append || vim_strchr(p_cpo, CPO_FNAMEAPP) != NULL)
   1031      && vim_strchr(p_cpo, CPO_FNAMEW) != NULL) {
   1032    if (set_rw_fname(fname, sfname) == FAIL) {
   1033      return FAIL;
   1034    }
   1035    buf = curbuf;           // just in case autocmds made "buf" invalid
   1036  }
   1037 
   1038  if (sfname == NULL) {
   1039    sfname = fname;
   1040  }
   1041 
   1042  // For Unix: Use the short file name whenever possible.
   1043  // Avoids problems with networks and when directory names are changed.
   1044  // Don't do this for Windows, a "cd" in a sub-shell may have moved us to
   1045  // another directory, which we don't detect.
   1046  char *ffname = fname;                           // remember full fname
   1047 #ifdef UNIX
   1048  fname = sfname;
   1049 #endif
   1050 
   1051  // true if writing over original
   1052  bool overwriting = buf->b_ffname != NULL && path_fnamecmp(ffname, buf->b_ffname) == 0;
   1053 
   1054  no_wait_return++;                 // don't wait for return yet
   1055 
   1056  const pos_T orig_start = buf->b_op_start;
   1057  const pos_T orig_end = buf->b_op_end;
   1058 
   1059  // Set '[ and '] marks to the lines to be written.
   1060  buf->b_op_start.lnum = start;
   1061  buf->b_op_start.col = 0;
   1062  buf->b_op_end.lnum = end;
   1063  buf->b_op_end.col = 0;
   1064 
   1065  int res = buf_write_do_autocmds(buf, &fname, &sfname, &ffname, start, &end, eap, append,
   1066                                  filtering, reset_changed, overwriting, whole, orig_start,
   1067                                  orig_end);
   1068  if (res != NOTDONE) {
   1069    return res;
   1070  }
   1071 
   1072  if (cmdmod.cmod_flags & CMOD_LOCKMARKS) {
   1073    // restore the original '[ and '] positions
   1074    buf->b_op_start = orig_start;
   1075    buf->b_op_end = orig_end;
   1076  }
   1077 
   1078  if (shortmess(SHM_OVER) && !exiting) {
   1079    msg_scroll = false;             // overwrite previous file message
   1080  } else {
   1081    msg_scroll = true;              // don't overwrite previous file message
   1082  }
   1083  if (!filtering) {
   1084    msg_ext_set_kind("bufwrite");
   1085    // show that we are busy
   1086 #ifndef UNIX
   1087    filemess(buf, sfname, "");
   1088 #else
   1089    filemess(buf, fname, "");
   1090 #endif
   1091  }
   1092  msg_scroll = false;               // always overwrite the file message now
   1093 
   1094  char *buffer = verbose_try_malloc(WRITEBUFSIZE);
   1095  int bufsize;
   1096  char smallbuf[SMALLBUFSIZE];
   1097  // can't allocate big buffer, use small one (to be able to write when out of
   1098  // memory)
   1099  if (buffer == NULL) {
   1100    buffer = smallbuf;
   1101    bufsize = SMALLBUFSIZE;
   1102  } else {
   1103    bufsize = WRITEBUFSIZE;
   1104  }
   1105 
   1106  Error_T err = { 0 };
   1107  int perm;              // file permissions
   1108  bool newfile = false;  // true if file doesn't exist yet
   1109  bool device = false;   // writing to a device
   1110  bool file_readonly = false;  // overwritten file is read-only
   1111  char *backup = NULL;
   1112  char *fenc_tofree = NULL;   // allocated "fenc"
   1113 
   1114  // Get information about original file (if there is one).
   1115  FileInfo file_info_old;
   1116 
   1117  vim_acl_T acl = NULL;                 // ACL copied from original file to
   1118                                        // backup or new file
   1119 
   1120  if (get_fileinfo(buf, fname, overwriting, forceit, &file_info_old, &perm, &device, &newfile,
   1121                   &file_readonly, &err) == FAIL) {
   1122    goto fail;
   1123  }
   1124 
   1125  // For systems that support ACL: get the ACL from the original file.
   1126  if (!newfile) {
   1127    acl = os_get_acl(fname);
   1128  }
   1129 
   1130  // If 'backupskip' is not empty, don't make a backup for some files.
   1131  bool dobackup = (p_wb || p_bk || *p_pm != NUL);
   1132  if (dobackup && *p_bsk != NUL && match_file_list(p_bsk, sfname, ffname)) {
   1133    dobackup = false;
   1134  }
   1135 
   1136  bool backup_copy = false;  // copy the original file?
   1137 
   1138  // Save the value of got_int and reset it.  We don't want a previous
   1139  // interruption cancel writing, only hitting CTRL-C while writing should
   1140  // abort it.
   1141  prev_got_int = got_int;
   1142  got_int = false;
   1143 
   1144  // Mark the buffer as 'being saved' to prevent changed buffer warnings
   1145  buf->b_saving = true;
   1146 
   1147  // If we are not appending or filtering, the file exists, and the
   1148  // 'writebackup', 'backup' or 'patchmode' option is set, need a backup.
   1149  // When 'patchmode' is set also make a backup when appending.
   1150  //
   1151  // Do not make any backup, if 'writebackup' and 'backup' are both switched
   1152  // off.  This helps when editing large files on almost-full disks.
   1153  if (!(append && *p_pm == NUL) && !filtering && perm >= 0 && dobackup) {
   1154    if (buf_write_make_backup(fname, append, &file_info_old, acl, perm, bkc, file_readonly, forceit,
   1155                              &backup_copy, &backup, &err) == FAIL) {
   1156      retval = FAIL;
   1157      goto fail;
   1158    }
   1159  }
   1160 
   1161 #if defined(UNIX)
   1162  bool made_writable = false;  // 'w' bit has been set
   1163 
   1164  // When using ":w!" and the file was read-only: make it writable
   1165  if (forceit && perm >= 0 && !(perm & 0200)
   1166      && file_info_old.stat.st_uid == getuid()
   1167      && vim_strchr(p_cpo, CPO_FWRITE) == NULL) {
   1168    perm |= 0200;
   1169    os_setperm(fname, perm);
   1170    made_writable = true;
   1171  }
   1172 #endif
   1173 
   1174  // When using ":w!" and writing to the current file, 'readonly' makes no
   1175  // sense, reset it, unless 'Z' appears in 'cpoptions'.
   1176  if (forceit && overwriting && vim_strchr(p_cpo, CPO_KEEPRO) == NULL) {
   1177    buf->b_p_ro = false;
   1178    need_maketitle = true;          // set window title later
   1179    status_redraw_all();            // redraw status lines later
   1180  }
   1181 
   1182  end = MIN(end, buf->b_ml.ml_line_count);
   1183  if (buf->b_ml.ml_flags & ML_EMPTY) {
   1184    start = end + 1;
   1185  }
   1186 
   1187  char *wfname = NULL;       // name of file to write to
   1188 
   1189  // If the original file is being overwritten, there is a small chance that
   1190  // we crash in the middle of writing. Therefore the file is preserved now.
   1191  // This makes all block numbers positive so that recovery does not need
   1192  // the original file.
   1193  // Don't do this if there is a backup file and we are exiting.
   1194  if (reset_changed && !newfile && overwriting && !(exiting && backup != NULL)) {
   1195    ml_preserve(buf, false, !!(buf->b_p_fs >= 0 ? buf->b_p_fs : p_fs));
   1196    if (got_int) {
   1197      err = set_err(_(e_interr));
   1198      goto restore_backup;
   1199    }
   1200  }
   1201 
   1202  // Default: write the file directly.  May write to a temp file for
   1203  // multi-byte conversion.
   1204  wfname = fname;
   1205 
   1206  char *fenc;  // effective 'fileencoding'
   1207 
   1208  // Check for forced 'fileencoding' from "++opt=val" argument.
   1209  if (eap != NULL && eap->force_enc != 0) {
   1210    fenc = eap->cmd + eap->force_enc;
   1211    fenc = enc_canonize(fenc);
   1212    fenc_tofree = fenc;
   1213  } else {
   1214    fenc = buf->b_p_fenc;
   1215  }
   1216 
   1217  // Check if the file needs to be converted.
   1218  bool converted = need_conversion(fenc);
   1219  int wb_flags = 0;
   1220 
   1221  // Check if UTF-8 to UCS-2/4 or Latin1 conversion needs to be done.  Or
   1222  // Latin1 to Unicode conversion.  This is handled in buf_write_bytes().
   1223  // Prepare the flags for it and allocate bw_conv_buf when needed.
   1224  if (converted) {
   1225    wb_flags = get_fio_flags(fenc);
   1226    if (wb_flags & (FIO_UCS2 | FIO_UCS4 | FIO_UTF16 | FIO_UTF8)) {
   1227      // Need to allocate a buffer to translate into.
   1228      if (wb_flags & (FIO_UCS2 | FIO_UTF16 | FIO_UTF8)) {
   1229        write_info.bw_conv_buflen = (size_t)bufsize * 2;
   1230      } else {       // FIO_UCS4
   1231        write_info.bw_conv_buflen = (size_t)bufsize * 4;
   1232      }
   1233      write_info.bw_conv_buf = verbose_try_malloc(write_info.bw_conv_buflen);
   1234      if (!write_info.bw_conv_buf) {
   1235        end = 0;
   1236      }
   1237    }
   1238  }
   1239 
   1240  if (converted && wb_flags == 0) {
   1241    // Use iconv() conversion when conversion is needed and it's not done
   1242    // internally.
   1243    write_info.bw_iconv_fd = (iconv_t)my_iconv_open(fenc, "utf-8");
   1244    if (write_info.bw_iconv_fd != (iconv_t)-1) {
   1245      // We're going to use iconv(), allocate a buffer to convert in.
   1246      write_info.bw_conv_buflen = (size_t)bufsize * ICONV_MULT;
   1247      write_info.bw_conv_buf = verbose_try_malloc(write_info.bw_conv_buflen);
   1248      if (!write_info.bw_conv_buf) {
   1249        end = 0;
   1250      }
   1251      write_info.bw_first = true;
   1252    } else {
   1253      // When the file needs to be converted with 'charconvert' after
   1254      // writing, write to a temp file instead and let the conversion
   1255      // overwrite the original file.
   1256      if (*p_ccv != NUL) {
   1257        wfname = vim_tempname();
   1258        if (wfname == NULL) {  // Can't write without a tempfile!
   1259          err = set_err(_("E214: Can't find temp file for writing"));
   1260          goto restore_backup;
   1261        }
   1262      }
   1263    }
   1264  }
   1265 
   1266  bool notconverted = false;
   1267 
   1268  if (converted && wb_flags == 0
   1269      && write_info.bw_iconv_fd == (iconv_t)-1
   1270      && wfname == fname) {
   1271    if (!forceit) {
   1272      err = set_err(_("E213: Cannot convert (add ! to write without conversion)"));
   1273      goto restore_backup;
   1274    }
   1275    notconverted = true;
   1276  }
   1277 
   1278  bool no_eol = false;  // no end-of-line written
   1279  int nchars;
   1280  linenr_T lnum;
   1281  int fileformat;
   1282  bool checking_conversion;
   1283 
   1284  int fd;
   1285 
   1286  // If conversion is taking place, we may first pretend to write and check
   1287  // for conversion errors.  Then loop again to write for real.
   1288  // When not doing conversion this writes for real right away.
   1289  for (checking_conversion = true;; checking_conversion = false) {
   1290    // There is no need to check conversion when:
   1291    // - there is no conversion
   1292    // - we make a backup file, that can be restored in case of conversion
   1293    // failure.
   1294    if (!converted || dobackup) {
   1295      checking_conversion = false;
   1296    }
   1297 
   1298    if (checking_conversion) {
   1299      // Make sure we don't write anything.
   1300      fd = -1;
   1301      write_info.bw_fd = fd;
   1302    } else {
   1303      // Open the file "wfname" for writing.
   1304      // We may try to open the file twice: If we can't write to the file
   1305      // and forceit is true we delete the existing file and try to
   1306      // create a new one. If this still fails we may have lost the
   1307      // original file!  (this may happen when the user reached his
   1308      // quotum for number of files).
   1309      // Appending will fail if the file does not exist and forceit is
   1310      // false.
   1311      const int fflags = O_WRONLY | (append
   1312                                     ? (forceit ? (O_APPEND | O_CREAT) : O_APPEND)
   1313                                     : (O_CREAT | O_TRUNC));
   1314      const int mode = perm < 0 ? 0666 : (perm & 0777);
   1315 
   1316      while ((fd = os_open(wfname, fflags, mode)) < 0) {
   1317        // A forced write will try to create a new file if the old one
   1318        // is still readonly. This may also happen when the directory
   1319        // is read-only. In that case the os_remove() will fail.
   1320        if (err.msg == NULL) {
   1321 #ifdef UNIX
   1322          FileInfo file_info;
   1323 
   1324          // Don't delete the file when it's a hard or symbolic link.
   1325          if ((!newfile && os_fileinfo_hardlinks(&file_info_old) > 1)
   1326              || (os_fileinfo_link(fname, &file_info)
   1327                  && !os_fileinfo_id_equal(&file_info, &file_info_old))) {
   1328            err = set_err(_("E166: Can't open linked file for writing"));
   1329          } else {
   1330            err = set_err_arg(_("E212: Can't open file for writing: %s"), fd);
   1331            if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL && perm >= 0) {
   1332              // we write to the file, thus it should be marked
   1333              // writable after all
   1334              if (!(perm & 0200)) {
   1335                made_writable = true;
   1336              }
   1337              perm |= 0200;
   1338              if (file_info_old.stat.st_uid != getuid()
   1339                  || file_info_old.stat.st_gid != getgid()) {
   1340                perm &= 0777;
   1341              }
   1342              if (!append) {                    // don't remove when appending
   1343                os_remove(wfname);
   1344              }
   1345              continue;
   1346            }
   1347          }
   1348 #else
   1349          err = set_err_arg(_("E212: Can't open file for writing: %s"), fd);
   1350          if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL && perm >= 0) {
   1351            if (!append) {                    // don't remove when appending
   1352              os_remove(wfname);
   1353            }
   1354            continue;
   1355          }
   1356 #endif
   1357        }
   1358 
   1359 restore_backup:
   1360        {
   1361          // If we failed to open the file, we don't need a backup. Throw it
   1362          // away.  If we moved or removed the original file try to put the
   1363          // backup in its place.
   1364          if (backup != NULL && wfname == fname) {
   1365            if (backup_copy) {
   1366              // There is a small chance that we removed the original,
   1367              // try to move the copy in its place.
   1368              // This may not work if the vim_rename() fails.
   1369              // In that case we leave the copy around.
   1370              // If file does not exist, put the copy in its place
   1371              if (!os_path_exists(fname)) {
   1372                vim_rename(backup, fname);
   1373              }
   1374              // if original file does exist throw away the copy
   1375              if (os_path_exists(fname)) {
   1376                os_remove(backup);
   1377              }
   1378            } else {
   1379              // try to put the original file back
   1380              vim_rename(backup, fname);
   1381            }
   1382          }
   1383 
   1384          // if original file no longer exists give an extra warning
   1385          if (!newfile && !os_path_exists(fname)) {
   1386            end = 0;
   1387          }
   1388        }
   1389 
   1390        if (wfname != fname) {
   1391          xfree(wfname);
   1392        }
   1393        goto fail;
   1394      }
   1395      write_info.bw_fd = fd;
   1396    }
   1397    err = set_err(NULL);
   1398 
   1399    write_info.bw_buf = buffer;
   1400    nchars = 0;
   1401 
   1402    // use "++bin", "++nobin" or 'binary'
   1403    int write_bin;
   1404    if (eap != NULL && eap->force_bin != 0) {
   1405      write_bin = (eap->force_bin == FORCE_BIN);
   1406    } else {
   1407      write_bin = buf->b_p_bin;
   1408    }
   1409 
   1410    // Skip the BOM when appending and the file already existed, the BOM
   1411    // only makes sense at the start of the file.
   1412    if (buf->b_p_bomb && !write_bin && (!append || perm < 0)) {
   1413      write_info.bw_len = make_bom(buffer, fenc);
   1414      if (write_info.bw_len > 0) {
   1415        // don't convert
   1416        write_info.bw_flags = FIO_NOCONVERT | wb_flags;
   1417        if (buf_write_bytes(&write_info) == FAIL) {
   1418          end = 0;
   1419        } else {
   1420          nchars += write_info.bw_len;
   1421        }
   1422      }
   1423    }
   1424    write_info.bw_start_lnum = start;
   1425 
   1426    write_undo_file = (buf->b_p_udf && overwriting && !append
   1427                       && !filtering && reset_changed && !checking_conversion);
   1428    if (write_undo_file) {
   1429      // Prepare for computing the hash value of the text.
   1430      sha256_start(&sha_ctx);
   1431    }
   1432 
   1433    write_info.bw_len = 0;
   1434    write_info.bw_flags = wb_flags;
   1435    fileformat = get_fileformat_force(buf, eap);
   1436    char *s = buffer;
   1437    for (lnum = start; lnum <= end; lnum++) {
   1438      // The next while loop is done once for each character written.
   1439      // Keep it fast!
   1440      char *ptr = ml_get_buf(buf, lnum) - 1;
   1441      if (write_undo_file) {
   1442        sha256_update(&sha_ctx, (uint8_t *)ptr + 1, (uint32_t)(strlen(ptr + 1) + 1));
   1443      }
   1444      char c;
   1445      while ((c = *++ptr) != NUL) {
   1446        if (c == NL) {
   1447          *s = NUL;                       // replace newlines with NULs
   1448        } else if (c == CAR && fileformat == EOL_MAC) {
   1449          *s = NL;                        // Mac: replace CRs with NLs
   1450        } else {
   1451          *s = c;
   1452        }
   1453        s++;
   1454        if (++write_info.bw_len != bufsize) {
   1455          continue;
   1456        }
   1457        if (buf_write_bytes(&write_info) == FAIL) {
   1458          end = 0;                        // write error: break loop
   1459          break;
   1460        }
   1461        nchars += bufsize - write_info.bw_len;
   1462        s = buffer + write_info.bw_len;
   1463        write_info.bw_start_lnum = lnum;
   1464      }
   1465      // write failed or last line has no EOL: stop here
   1466      if (end == 0
   1467          || (lnum == end
   1468              && (write_bin || !buf->b_p_fixeol)
   1469              && ((write_bin && lnum == buf->b_no_eol_lnum)
   1470                  || (lnum == buf->b_ml.ml_line_count && !buf->b_p_eol)))) {
   1471        lnum++;                           // written the line, count it
   1472        no_eol = true;
   1473        break;
   1474      }
   1475      if (fileformat == EOL_UNIX) {
   1476        *s++ = NL;
   1477      } else {
   1478        *s++ = CAR;                       // EOL_MAC or EOL_DOS: write CR
   1479        if (fileformat == EOL_DOS) {      // write CR-NL
   1480          if (++write_info.bw_len == bufsize) {
   1481            if (buf_write_bytes(&write_info) == FAIL) {
   1482              end = 0;                    // write error: break loop
   1483              break;
   1484            }
   1485            nchars += bufsize - write_info.bw_len;
   1486            s = buffer + write_info.bw_len;
   1487          }
   1488          *s++ = NL;
   1489        }
   1490      }
   1491      if (++write_info.bw_len == bufsize) {
   1492        if (buf_write_bytes(&write_info) == FAIL) {
   1493          end = 0;  // Write error: break loop.
   1494          break;
   1495        }
   1496        nchars += bufsize - write_info.bw_len;
   1497        s = buffer + write_info.bw_len;
   1498 
   1499        os_breakcheck();
   1500        if (got_int) {
   1501          end = 0;  // Interrupted, break loop.
   1502          break;
   1503        }
   1504      }
   1505    }
   1506    if (write_info.bw_len > 0 && end > 0) {
   1507      int remaining = write_info.bw_len;
   1508      if (buf_write_bytes(&write_info) == FAIL) {
   1509        end = 0;                      // write error
   1510      }
   1511      nchars += remaining - write_info.bw_len;
   1512    }
   1513 
   1514    // Did we convert & write everything?
   1515    if (end != 0 && write_info.bw_len > 0) {
   1516      write_info.bw_conv_error = true;
   1517      write_info.bw_conv_error_lnum = end;
   1518      end = 0;
   1519    }
   1520 
   1521    if (!buf->b_p_fixeol && buf->b_p_eof) {
   1522      // write trailing CTRL-Z
   1523      write_eintr(write_info.bw_fd, "\x1a", 1);
   1524    }
   1525 
   1526    // Stop when writing done or an error was encountered.
   1527    if (!checking_conversion || end == 0) {
   1528      break;
   1529    }
   1530 
   1531    // If no error happened until now, writing should be ok, so loop to
   1532    // really write the buffer.
   1533  }
   1534 
   1535  // If we started writing, finish writing. Also when an error was
   1536  // encountered.
   1537  if (!checking_conversion) {
   1538    // On many journalling file systems there is a bug that causes both the
   1539    // original and the backup file to be lost when halting the system right
   1540    // after writing the file.  That's because only the meta-data is
   1541    // journalled.  Syncing the file slows down the system, but assures it has
   1542    // been written to disk and we don't lose it.
   1543    // For a device do try the fsync() but don't complain if it does not work
   1544    // (could be a pipe).
   1545    // If the 'fsync' option is false, don't fsync().  Useful for laptops.
   1546    int error;
   1547    if ((buf->b_p_fs >= 0 ? buf->b_p_fs : p_fs) && (error = os_fsync(fd)) != 0
   1548        // fsync not supported on this storage.
   1549        && error != UV_ENOTSUP && !device) {
   1550      err = set_err_arg(e_fsync, error);
   1551      end = 0;
   1552    }
   1553 
   1554    if (!backup_copy) {
   1555 #ifdef HAVE_XATTR
   1556      os_copy_xattr(backup, wfname);
   1557 #endif
   1558    }
   1559 
   1560 #ifdef UNIX
   1561    // When creating a new file, set its owner/group to that of the original
   1562    // file.  Get the new device and inode number.
   1563    if (backup != NULL && !backup_copy) {
   1564      // don't change the owner when it's already OK, some systems remove
   1565      // permission or ACL stuff
   1566      FileInfo file_info;
   1567      if (!os_fileinfo(wfname, &file_info)
   1568          || file_info.stat.st_uid != file_info_old.stat.st_uid
   1569          || file_info.stat.st_gid != file_info_old.stat.st_gid) {
   1570        os_fchown(fd, (uv_uid_t)file_info_old.stat.st_uid, (uv_gid_t)file_info_old.stat.st_gid);
   1571        if (perm >= 0) {  // Set permission again, may have changed.
   1572          os_setperm(wfname, perm);
   1573        }
   1574      }
   1575      buf_set_file_id(buf);
   1576    } else if (!buf->file_id_valid) {
   1577      // Set the file_id when creating a new file.
   1578      buf_set_file_id(buf);
   1579    }
   1580 #endif
   1581 
   1582    if ((error = os_close(fd)) != 0) {
   1583      err = set_err_arg(_("E512: Close failed: %s"), error);
   1584      end = 0;
   1585    }
   1586 
   1587 #ifdef UNIX
   1588    if (made_writable) {
   1589      perm &= ~0200;              // reset 'w' bit for security reasons
   1590    }
   1591 #endif
   1592    if (perm >= 0) {  // Set perm. of new file same as old file.
   1593      os_setperm(wfname, perm);
   1594    }
   1595    // Probably need to set the ACL before changing the user (can't set the
   1596    // ACL on a file the user doesn't own).
   1597    if (!backup_copy) {
   1598      os_set_acl(wfname, acl);
   1599    }
   1600 
   1601    if (wfname != fname) {
   1602      // The file was written to a temp file, now it needs to be converted
   1603      // with 'charconvert' to (overwrite) the output file.
   1604      if (end != 0) {
   1605        if (eval_charconvert("utf-8", fenc, wfname, fname) == FAIL) {
   1606          write_info.bw_conv_error = true;
   1607          end = 0;
   1608        }
   1609      }
   1610      os_remove(wfname);
   1611      xfree(wfname);
   1612    }
   1613  }
   1614 
   1615  if (end == 0) {
   1616    // Error encountered.
   1617    if (err.msg == NULL) {
   1618      if (write_info.bw_conv_error) {
   1619        if (write_info.bw_conv_error_lnum == 0) {
   1620          err = set_err(_(e_write_error_conversion_failed_make_fenc_empty_to_override));
   1621        } else {
   1622          err = set_err(xmalloc(300));
   1623          err.alloc = true;
   1624          vim_snprintf(err.msg, 300,  // NOLINT(runtime/printf)
   1625                       _(e_write_error_conversion_failed_in_line_nr_make_fenc_empty_to_override),
   1626                       write_info.bw_conv_error_lnum);
   1627        }
   1628      } else if (got_int) {
   1629        err = set_err(_(e_interr));
   1630      } else {
   1631        err = set_err(_(e_write_error_file_system_full));
   1632      }
   1633    }
   1634 
   1635    // If we have a backup file, try to put it in place of the new file,
   1636    // because the new file is probably corrupt.  This avoids losing the
   1637    // original file when trying to make a backup when writing the file a
   1638    // second time.
   1639    // When "backup_copy" is set we need to copy the backup over the new
   1640    // file.  Otherwise rename the backup file.
   1641    // If this is OK, don't give the extra warning message.
   1642    if (backup != NULL) {
   1643      if (backup_copy) {
   1644        // This may take a while, if we were interrupted let the user
   1645        // know we got the message.
   1646        if (got_int) {
   1647          msg(_(e_interr), 0);
   1648          ui_flush();
   1649        }
   1650 
   1651        // copy the file.
   1652        if (os_copy(backup, fname, UV_FS_COPYFILE_FICLONE)
   1653            == 0) {
   1654          end = 1;  // success
   1655        }
   1656      } else {
   1657        if (vim_rename(backup, fname) == 0) {
   1658          end = 1;
   1659        }
   1660      }
   1661    }
   1662    goto fail;
   1663  }
   1664 
   1665  lnum -= start;            // compute number of written lines
   1666  no_wait_return--;         // may wait for return now
   1667 
   1668 #if !defined(UNIX)
   1669  fname = sfname;           // use shortname now, for the messages
   1670 #endif
   1671  if (!filtering) {
   1672    add_quoted_fname(IObuff, IOSIZE, buf, fname);
   1673    bool insert_space = false;
   1674    if (write_info.bw_conv_error) {
   1675      xstrlcat(IObuff, _(" CONVERSION ERROR"), IOSIZE);
   1676      insert_space = true;
   1677      if (write_info.bw_conv_error_lnum != 0) {
   1678        vim_snprintf_add(IObuff, IOSIZE, _(" in line %" PRId64 ";"),
   1679                         (int64_t)write_info.bw_conv_error_lnum);
   1680      }
   1681    } else if (notconverted) {
   1682      xstrlcat(IObuff, _("[NOT converted]"), IOSIZE);
   1683      insert_space = true;
   1684    } else if (converted) {
   1685      xstrlcat(IObuff, _("[converted]"), IOSIZE);
   1686      insert_space = true;
   1687    }
   1688    if (device) {
   1689      xstrlcat(IObuff, _("[Device]"), IOSIZE);
   1690      insert_space = true;
   1691    } else if (newfile) {
   1692      xstrlcat(IObuff, _("[New]"), IOSIZE);
   1693      insert_space = true;
   1694    }
   1695    if (no_eol) {
   1696      xstrlcat(IObuff, _("[noeol]"), IOSIZE);
   1697      insert_space = true;
   1698    }
   1699    // may add [unix/dos/mac]
   1700    if (msg_add_fileformat(fileformat)) {
   1701      insert_space = true;
   1702    }
   1703    msg_add_lines(insert_space, lnum, nchars);       // add line/char count
   1704    if (!shortmess(SHM_WRITE)) {
   1705      if (append) {
   1706        xstrlcat(IObuff, shortmess(SHM_WRI) ? _(" [a]") : _(" appended"), IOSIZE);
   1707      } else {
   1708        xstrlcat(IObuff, shortmess(SHM_WRI) ? _(" [w]") : _(" written"), IOSIZE);
   1709      }
   1710    }
   1711 
   1712    msg_ext_set_kind("bufwrite");
   1713    msg_ext_overwrite = true;
   1714    set_keep_msg(msg_trunc(IObuff, false, 0), 0);
   1715  }
   1716 
   1717  // When written everything correctly: reset 'modified'.  Unless not
   1718  // writing to the original file and '+' is not in 'cpoptions'.
   1719  if (reset_changed && whole && !append
   1720      && !write_info.bw_conv_error
   1721      && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)) {
   1722    unchanged(buf, true, false);
   1723    const varnumber_T changedtick = buf_get_changedtick(buf);
   1724    if (buf->b_last_changedtick + 1 == changedtick) {
   1725      // b:changedtick may be incremented in unchanged() but that should not
   1726      // trigger a TextChanged event.
   1727      buf->b_last_changedtick = changedtick;
   1728    }
   1729    u_unchanged(buf);
   1730    u_update_save_nr(buf);
   1731  }
   1732 
   1733  // If written to the current file, update the timestamp of the swap file
   1734  // and reset the BF_WRITE_MASK flags. Also sets buf->b_mtime.
   1735  if (overwriting) {
   1736    ml_timestamp(buf);
   1737    if (append) {
   1738      buf->b_flags &= ~BF_NEW;
   1739    } else {
   1740      buf->b_flags &= ~BF_WRITE_MASK;
   1741    }
   1742  }
   1743 
   1744  // If we kept a backup until now, and we are in patch mode, then we make
   1745  // the backup file our 'original' file.
   1746  if (*p_pm && dobackup) {
   1747    char *const org = modname(fname, p_pm, false);
   1748 
   1749    if (backup != NULL) {
   1750      // If the original file does not exist yet
   1751      // the current backup file becomes the original file
   1752      if (org == NULL) {
   1753        emsg(_("E205: Patchmode: can't save original file"));
   1754      } else if (!os_path_exists(org)) {
   1755        vim_rename(backup, org);
   1756        XFREE_CLEAR(backup);                   // don't delete the file
   1757 #ifdef UNIX
   1758        os_file_settime(org,
   1759                        (double)file_info_old.stat.st_atim.tv_sec,
   1760                        (double)file_info_old.stat.st_mtim.tv_sec);
   1761 #endif
   1762      }
   1763    } else {
   1764      // If there is no backup file, remember that a (new) file was
   1765      // created.
   1766      int empty_fd;
   1767 
   1768      if (org == NULL
   1769          || (empty_fd = os_open(org,
   1770                                 O_CREAT | O_EXCL | O_NOFOLLOW,
   1771                                 perm < 0 ? 0666 : (perm & 0777))) < 0) {
   1772        emsg(_(e_patchmode_cant_touch_empty_original_file));
   1773      } else {
   1774        close(empty_fd);
   1775      }
   1776    }
   1777    if (org != NULL) {
   1778      os_setperm(org, os_getperm(fname) & 0777);
   1779      xfree(org);
   1780    }
   1781  }
   1782 
   1783  // Remove the backup unless 'backup' option is set
   1784  if (!p_bk && backup != NULL
   1785      && !write_info.bw_conv_error
   1786      && os_remove(backup) != 0) {
   1787    emsg(_("E207: Can't delete backup file"));
   1788  }
   1789 
   1790  goto nofail;
   1791 
   1792  // Finish up.  We get here either after failure or success.
   1793 fail:
   1794  no_wait_return--;             // may wait for return now
   1795 nofail:
   1796 
   1797  // Done saving, we accept changed buffer warnings again
   1798  buf->b_saving = false;
   1799 
   1800  xfree(backup);
   1801  if (buffer != smallbuf) {
   1802    xfree(buffer);
   1803  }
   1804  xfree(fenc_tofree);
   1805  xfree(write_info.bw_conv_buf);
   1806  if (write_info.bw_iconv_fd != (iconv_t)-1) {
   1807    iconv_close(write_info.bw_iconv_fd);
   1808    write_info.bw_iconv_fd = (iconv_t)-1;
   1809  }
   1810  os_free_acl(acl);
   1811 
   1812  if (err.msg != NULL) {
   1813    // - 100 to save some space for further error message
   1814 #ifndef UNIX
   1815    add_quoted_fname(IObuff, IOSIZE - 100, buf, sfname);
   1816 #else
   1817    add_quoted_fname(IObuff, IOSIZE - 100, buf, fname);
   1818 #endif
   1819    emit_err(&err);
   1820 
   1821    retval = FAIL;
   1822    if (end == 0) {
   1823      const int hl_id = HLF_E;  // Set highlight for error messages.
   1824      msg_puts_hl(_("\nWARNING: Original file may be lost or damaged\n"), hl_id, true);
   1825      msg_puts_hl(_("don't quit the editor until the file is successfully written!"), hl_id, true);
   1826 
   1827      // Update the timestamp to avoid an "overwrite changed file"
   1828      // prompt when writing again.
   1829      if (os_fileinfo(fname, &file_info_old)) {
   1830        buf_store_file_info(buf, &file_info_old);
   1831        buf->b_mtime_read = buf->b_mtime;
   1832        buf->b_mtime_read_ns = buf->b_mtime_ns;
   1833      }
   1834    }
   1835  }
   1836  msg_scroll = msg_save;
   1837 
   1838  // When writing the whole file and 'undofile' is set, also write the undo
   1839  // file.
   1840  if (retval == OK && write_undo_file) {
   1841    uint8_t hash[UNDO_HASH_SIZE];
   1842 
   1843    sha256_finish(&sha_ctx, hash);
   1844    u_write_undo(NULL, false, buf, hash);
   1845  }
   1846 
   1847  if (!should_abort(retval)) {
   1848    buf_write_do_post_autocmds(buf, fname, eap, append, filtering, reset_changed, whole);
   1849    if (aborting()) {       // autocmds may abort script processing
   1850      retval = false;
   1851    }
   1852  }
   1853 
   1854  got_int |= prev_got_int;
   1855 
   1856  return retval;
   1857 }