mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 19:38:20 +00:00
refactor(fileio.c): factor out file info calc
This commit is contained in:
@@ -125,6 +125,8 @@ typedef struct {
|
|||||||
bool alloc;
|
bool alloc;
|
||||||
} Error_T;
|
} Error_T;
|
||||||
|
|
||||||
|
static char *err_readonly = "is read-only (cannot override: \"W\" in 'cpoptions')";
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "fileio.c.generated.h"
|
# include "fileio.c.generated.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -2314,6 +2316,111 @@ static void emit_err(Error_T *e)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(UNIX)
|
||||||
|
|
||||||
|
static int get_fileinfo_os(char *fname, FileInfo *file_info_old, bool overwriting, long *perm,
|
||||||
|
bool *device, bool *newfile, Error_T *err)
|
||||||
|
{
|
||||||
|
*perm = -1;
|
||||||
|
if (!os_fileinfo(fname, file_info_old)) {
|
||||||
|
*newfile = true;
|
||||||
|
} else {
|
||||||
|
*perm = (long)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)) {
|
||||||
|
*err = set_err_num("E502", _("is a directory"));
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
if (os_nodetype(fname) != NODE_WRITABLE) {
|
||||||
|
*err = set_err_num("E503", _("is not a file or writable device"));
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
// It's a device of some kind (or a fifo) which we can write to
|
||||||
|
// but for which we can't make a backup.
|
||||||
|
*device = true;
|
||||||
|
*newfile = true;
|
||||||
|
*perm = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static int get_fileinfo_os(char *fname, FileInfo *file_info_old, bool overwriting, long *perm,
|
||||||
|
bool *device, bool *newfile, Error_T *err)
|
||||||
|
{
|
||||||
|
// Check for a writable device name.
|
||||||
|
char nodetype = fname == NULL ? NODE_OTHER : (char)os_nodetype(fname);
|
||||||
|
if (nodetype == NODE_OTHER) {
|
||||||
|
*err = set_err_num("E503", _("is not a file or writable device"));
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
if (nodetype == NODE_WRITABLE) {
|
||||||
|
*device = true;
|
||||||
|
*newfile = true;
|
||||||
|
*perm = -1;
|
||||||
|
} else {
|
||||||
|
*perm = os_getperm((const char *)fname);
|
||||||
|
if (*perm < 0) {
|
||||||
|
*newfile = true;
|
||||||
|
} else if (os_isdir(fname)) {
|
||||||
|
*err = set_err_num("E502", _("is a directory"));
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
if (overwriting) {
|
||||||
|
os_fileinfo(fname, file_info_old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// @param buf
|
||||||
|
/// @param fname File name
|
||||||
|
/// @param overwriting
|
||||||
|
/// @param forceit
|
||||||
|
/// @param[out] file_info_old
|
||||||
|
/// @param[out] perm
|
||||||
|
/// @param[out] device
|
||||||
|
/// @param[out] newfile
|
||||||
|
/// @param[out] readonly
|
||||||
|
static int get_fileinfo(buf_T *buf, char *fname, bool overwriting, bool forceit,
|
||||||
|
FileInfo *file_info_old, long *perm, bool *device, bool *newfile,
|
||||||
|
bool *readonly, Error_T *err)
|
||||||
|
{
|
||||||
|
if (get_fileinfo_os(fname, file_info_old, overwriting, perm, device, newfile, err) == FAIL) {
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*readonly = false; // overwritten file is read-only
|
||||||
|
|
||||||
|
if (!*device && !*newfile) {
|
||||||
|
// Check if the file is really writable (when renaming the file to
|
||||||
|
// make a backup we won't discover it later).
|
||||||
|
*readonly = !os_file_is_writable(fname);
|
||||||
|
|
||||||
|
if (!forceit && *readonly) {
|
||||||
|
if (vim_strchr(p_cpo, CPO_FWRITE) != NULL) {
|
||||||
|
*err = set_err_num("E504", _(err_readonly));
|
||||||
|
} else {
|
||||||
|
*err = set_err_num("E505", _("is read-only (add ! to override)"));
|
||||||
|
}
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If 'forceit' is false, check if the timestamp hasn't changed since reading the file.
|
||||||
|
if (overwriting && !forceit) {
|
||||||
|
int retval = check_mtime(buf, file_info_old);
|
||||||
|
if (retval == FAIL) {
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/// buf_write() - write to file "fname" lines "start" through "end"
|
/// buf_write() - write to file "fname" lines "start" through "end"
|
||||||
///
|
///
|
||||||
/// We do our own buffering here because fwrite() is so slow.
|
/// We do our own buffering here because fwrite() is so slow.
|
||||||
@@ -2338,8 +2445,6 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
|
|||||||
int retval = OK;
|
int retval = OK;
|
||||||
int msg_save = msg_scroll;
|
int msg_save = msg_scroll;
|
||||||
int prev_got_int = got_int;
|
int prev_got_int = got_int;
|
||||||
static char *err_readonly =
|
|
||||||
"is read-only (cannot override: \"W\" in 'cpoptions')";
|
|
||||||
// writing everything
|
// writing everything
|
||||||
int whole = (start == 1 && end == buf->b_ml.ml_line_count);
|
int whole = (start == 1 && end == buf->b_ml.ml_line_count);
|
||||||
int write_undo_file = false;
|
int write_undo_file = false;
|
||||||
@@ -2467,8 +2572,10 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
|
|||||||
}
|
}
|
||||||
|
|
||||||
Error_T err = { 0 };
|
Error_T err = { 0 };
|
||||||
int newfile = false; // true if file doesn't exist yet
|
long perm; // file permissions
|
||||||
int device = false; // writing to a device
|
bool newfile = false; // true if file doesn't exist yet
|
||||||
|
bool device = false; // writing to a device
|
||||||
|
bool file_readonly = false; // overwritten file is read-only
|
||||||
char *backup = NULL;
|
char *backup = NULL;
|
||||||
char *fenc_tofree = NULL; // allocated "fenc"
|
char *fenc_tofree = NULL; // allocated "fenc"
|
||||||
|
|
||||||
@@ -2480,78 +2587,10 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
|
|||||||
// backup or new file
|
// backup or new file
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
long perm; // file permissions
|
if (get_fileinfo(buf, fname, overwriting, forceit, &file_info_old, &perm, &device, &newfile,
|
||||||
#if defined(UNIX)
|
&file_readonly, &err) == FAIL) {
|
||||||
perm = -1;
|
|
||||||
if (!os_fileinfo(fname, &file_info_old)) {
|
|
||||||
newfile = true;
|
|
||||||
} else {
|
|
||||||
perm = (long)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)) {
|
|
||||||
err = set_err_num("E502", _("is a directory"));
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (os_nodetype(fname) != NODE_WRITABLE) {
|
|
||||||
err = set_err_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
|
|
||||||
// but for which we can't make a backup.
|
|
||||||
device = true;
|
|
||||||
newfile = true;
|
|
||||||
perm = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else // win32
|
|
||||||
// Check for a writable device name.
|
|
||||||
char nodetype = fname == NULL ? NODE_OTHER : os_nodetype(fname);
|
|
||||||
if (nodetype == NODE_OTHER) {
|
|
||||||
err = set_err_num("E503", _("is not a file or writable device"));
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
if (nodetype == NODE_WRITABLE) {
|
|
||||||
device = true;
|
|
||||||
newfile = true;
|
|
||||||
perm = -1;
|
|
||||||
} else {
|
|
||||||
perm = os_getperm((const char *)fname);
|
|
||||||
if (perm < 0) {
|
|
||||||
newfile = true;
|
|
||||||
} else if (os_isdir(fname)) {
|
|
||||||
err = set_err_num("E502", _("is a directory"));
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
if (overwriting) {
|
|
||||||
os_fileinfo(fname, &file_info_old);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // !UNIX
|
|
||||||
|
|
||||||
bool file_readonly = false; // overwritten file is read-only
|
|
||||||
|
|
||||||
if (!device && !newfile) {
|
|
||||||
// Check if the file is really writable (when renaming the file to
|
|
||||||
// make a backup we won't discover it later).
|
|
||||||
file_readonly = !os_file_is_writable(fname);
|
|
||||||
|
|
||||||
if (!forceit && file_readonly) {
|
|
||||||
if (vim_strchr(p_cpo, CPO_FWRITE) != NULL) {
|
|
||||||
err = set_err_num("E504", _(err_readonly));
|
|
||||||
} else {
|
|
||||||
err = set_err_num("E505", _("is read-only (add ! to override)"));
|
|
||||||
}
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If 'forceit' is false, check if the timestamp hasn't changed since reading the file.
|
|
||||||
if (overwriting && !forceit) {
|
|
||||||
retval = check_mtime(buf, &file_info_old);
|
|
||||||
if (retval == FAIL) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_ACL
|
#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.
|
||||||
@@ -3407,37 +3446,37 @@ restore_backup:
|
|||||||
#endif
|
#endif
|
||||||
if (!filtering) {
|
if (!filtering) {
|
||||||
add_quoted_fname(IObuff, IOSIZE, buf, (const char *)fname);
|
add_quoted_fname(IObuff, IOSIZE, buf, (const char *)fname);
|
||||||
char c = false;
|
bool insert_space = false;
|
||||||
if (write_info.bw_conv_error) {
|
if (write_info.bw_conv_error) {
|
||||||
STRCAT(IObuff, _(" CONVERSION ERROR"));
|
STRCAT(IObuff, _(" CONVERSION ERROR"));
|
||||||
c = true;
|
insert_space = true;
|
||||||
if (write_info.bw_conv_error_lnum != 0) {
|
if (write_info.bw_conv_error_lnum != 0) {
|
||||||
vim_snprintf_add(IObuff, IOSIZE, _(" in line %" PRId64 ";"),
|
vim_snprintf_add(IObuff, IOSIZE, _(" in line %" PRId64 ";"),
|
||||||
(int64_t)write_info.bw_conv_error_lnum);
|
(int64_t)write_info.bw_conv_error_lnum);
|
||||||
}
|
}
|
||||||
} else if (notconverted) {
|
} else if (notconverted) {
|
||||||
STRCAT(IObuff, _("[NOT converted]"));
|
STRCAT(IObuff, _("[NOT converted]"));
|
||||||
c = true;
|
insert_space = true;
|
||||||
} else if (converted) {
|
} else if (converted) {
|
||||||
STRCAT(IObuff, _("[converted]"));
|
STRCAT(IObuff, _("[converted]"));
|
||||||
c = true;
|
insert_space = true;
|
||||||
}
|
}
|
||||||
if (device) {
|
if (device) {
|
||||||
STRCAT(IObuff, _("[Device]"));
|
STRCAT(IObuff, _("[Device]"));
|
||||||
c = true;
|
insert_space = true;
|
||||||
} else if (newfile) {
|
} else if (newfile) {
|
||||||
STRCAT(IObuff, new_file_message());
|
STRCAT(IObuff, new_file_message());
|
||||||
c = true;
|
insert_space = true;
|
||||||
}
|
}
|
||||||
if (no_eol) {
|
if (no_eol) {
|
||||||
msg_add_eol();
|
msg_add_eol();
|
||||||
c = true;
|
insert_space = true;
|
||||||
}
|
}
|
||||||
// may add [unix/dos/mac]
|
// may add [unix/dos/mac]
|
||||||
if (msg_add_fileformat(fileformat)) {
|
if (msg_add_fileformat(fileformat)) {
|
||||||
c = true;
|
insert_space = true;
|
||||||
}
|
}
|
||||||
msg_add_lines(c, (long)lnum, nchars); // add line/char count
|
msg_add_lines(insert_space, (long)lnum, nchars); // add line/char count
|
||||||
if (!shortmess(SHM_WRITE)) {
|
if (!shortmess(SHM_WRITE)) {
|
||||||
if (append) {
|
if (append) {
|
||||||
STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [a]") : _(" appended"));
|
STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [a]") : _(" appended"));
|
||||||
|
Reference in New Issue
Block a user