aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/buffer.c172
-rw-r--r--src/buffer_defs.h6
-rw-r--r--src/diff.c6
-rw-r--r--src/eval.c69
-rw-r--r--src/ex_cmds.c35
-rw-r--r--src/ex_cmds2.c45
-rw-r--r--src/file_search.c47
-rw-r--r--src/fileio.c259
-rw-r--r--src/fileio.h3
-rw-r--r--src/if_cscope.c91
-rw-r--r--src/if_cscope_defs.h5
-rw-r--r--src/macros.h15
-rw-r--r--src/main.c13
-rw-r--r--src/memfile.c48
-rw-r--r--src/memline.c92
-rw-r--r--src/misc2.c18
-rw-r--r--src/os/fs.c48
-rw-r--r--src/os/os.h38
-rw-r--r--src/os_unix_defs.h2
-rw-r--r--src/path.c30
-rw-r--r--src/quickfix.c14
-rw-r--r--src/spell.c5
-rw-r--r--src/tag.c8
-rw-r--r--src/undo.c45
-rw-r--r--test/unit/os/fs.moon105
25 files changed, 578 insertions, 641 deletions
diff --git a/src/buffer.c b/src/buffer.c
index d2379f4afa..7cd773b55c 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -65,6 +65,10 @@
#include "ui.h"
#include "undo.h"
#include "window.h"
+#include "os/os.h"
+
+// Todo(stefan991): remove this macro
+#define INVALID_DEVICE_ID UINT64_MAX
static char_u *buflist_match(regprog_T *prog, buf_T *buf);
# define HAVE_BUFLIST_MATCH
@@ -72,25 +76,15 @@ static char_u *fname_match(regprog_T *prog, char_u *name);
static void buflist_setfpos(buf_T *buf, win_T *win, linenr_T lnum,
colnr_T col, int copy_options);
static wininfo_T *find_wininfo(buf_T *buf, int skip_diff_buffer);
-#ifdef UNIX
-static buf_T *buflist_findname_stat(char_u *ffname, struct stat *st);
-static int otherfile_buf(buf_T *buf, char_u *ffname, struct stat *stp);
-static int buf_same_ino(buf_T *buf, struct stat *stp);
-#else
-static int otherfile_buf(buf_T *buf, char_u *ffname);
-#endif
+static buf_T *buflist_findname_file_info(char_u *ffname, FileInfo *file_info);
+static int otherfile_buf(buf_T *buf, char_u *ffname, FileInfo *file_info);
+static int buf_same_ino(buf_T *buf, FileInfo *file_info);
static int ti_change(char_u *str, char_u **last);
static int append_arg_number(win_T *wp, char_u *buf, int buflen, int add_file);
static void free_buffer(buf_T *);
static void free_buffer_stuff(buf_T *buf, int free_options);
static void clear_wininfo(buf_T *buf);
-#ifdef UNIX
-# define dev_T dev_t
-#else
-# define dev_T unsigned
-#endif
-
static void insert_sign(buf_T *buf, signlist_T *prev, signlist_T *next, int id, linenr_T lnum, int typenr);
static char *msg_loclist = N_("[Location List]");
@@ -1304,29 +1298,20 @@ buflist_new (
)
{
buf_T *buf;
-#ifdef UNIX
- struct stat st;
-#endif
fname_expand(curbuf, &ffname, &sfname); /* will allocate ffname */
/*
* If file name already exists in the list, update the entry.
*/
-#ifdef UNIX
- /* On Unix we can use inode numbers when the file exists. Works better
+ /* We can use inode numbers when the file exists. Works better
* for hard links. */
- if (sfname == NULL || mch_stat((char *)sfname, &st) < 0)
- st.st_dev = (dev_T)-1;
-#endif
- if (ffname != NULL && !(flags & BLN_DUMMY) && (buf =
-#ifdef UNIX
- buflist_findname_stat(ffname,
- &st)
-#else
- buflist_findname(ffname)
-#endif
- ) != NULL) {
+ FileInfo file_info;
+ if (sfname == NULL || !os_get_file_info((char *)sfname, &file_info)) {
+ file_info.stat.st_dev = INVALID_DEVICE_ID;
+ }
+ if (ffname != NULL && !(flags & BLN_DUMMY)
+ && (buf = buflist_findname_file_info(ffname, &file_info)) != NULL) {
free(ffname);
if (lnum != 0)
buflist_setfpos(buf, curwin, lnum, (colnr_T)0, FALSE);
@@ -1452,15 +1437,13 @@ buflist_new (
hash_init(&buf->b_s.b_keywtab_ic);
buf->b_fname = buf->b_sfname;
-#ifdef UNIX
- if (st.st_dev == (dev_T)-1)
+ if (file_info.stat.st_dev == INVALID_DEVICE_ID)
buf->b_dev_valid = FALSE;
else {
buf->b_dev_valid = TRUE;
- buf->b_dev = st.st_dev;
- buf->b_ino = st.st_ino;
+ buf->b_dev = file_info.stat.st_dev;
+ buf->b_ino = file_info.stat.st_ino;
}
-#endif
buf->b_u_synced = TRUE;
buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED;
if (flags & BLN_DUMMY)
@@ -1682,31 +1665,28 @@ buf_T *buflist_findname_exp(char_u *fname)
*/
buf_T *buflist_findname(char_u *ffname)
{
-#ifdef UNIX
- struct stat st;
-
- if (mch_stat((char *)ffname, &st) < 0)
- st.st_dev = (dev_T)-1;
- return buflist_findname_stat(ffname, &st);
+ FileInfo file_info;
+ if (!os_get_file_info((char *)ffname, &file_info)) {
+ file_info.stat.st_dev = INVALID_DEVICE_ID;
+ }
+ return buflist_findname_file_info(ffname, &file_info);
}
/*
- * Same as buflist_findname(), but pass the stat structure to avoid getting it
- * twice for the same file.
+ * Same as buflist_findname(), but pass the FileInfo structure to avoid
+ * getting it twice for the same file.
* Returns NULL if not found.
*/
-static buf_T *buflist_findname_stat(char_u *ffname, struct stat *stp)
+static buf_T *buflist_findname_file_info(char_u *ffname, FileInfo *file_info)
{
-#endif
buf_T *buf;
- for (buf = firstbuf; buf != NULL; buf = buf->b_next)
- if ((buf->b_flags & BF_DUMMY) == 0 && !otherfile_buf(buf, ffname
-#ifdef UNIX
- , stp
-#endif
- ))
+ for (buf = firstbuf; buf != NULL; buf = buf->b_next) {
+ if ((buf->b_flags & BF_DUMMY) == 0
+ && !otherfile_buf(buf, ffname, file_info)) {
return buf;
+ }
+ }
return NULL;
}
@@ -2220,9 +2200,7 @@ setfname (
)
{
buf_T *obuf = NULL;
-#ifdef UNIX
- struct stat st;
-#endif
+ FileInfo file_info;
if (ffname == NULL || *ffname == NUL) {
/* Removing the name. */
@@ -2230,9 +2208,7 @@ setfname (
free(buf->b_sfname);
buf->b_ffname = NULL;
buf->b_sfname = NULL;
-#ifdef UNIX
- st.st_dev = (dev_T)-1;
-#endif
+ file_info.stat.st_dev = INVALID_DEVICE_ID;
} else {
fname_expand(buf, &ffname, &sfname); /* will allocate ffname */
if (ffname == NULL) /* out of memory */
@@ -2243,16 +2219,12 @@ setfname (
* - if the buffer is loaded, fail
* - if the buffer is not loaded, delete it from the list
*/
-#ifdef UNIX
- if (mch_stat((char *)ffname, &st) < 0)
- st.st_dev = (dev_T)-1;
-#endif
- if (!(buf->b_flags & BF_DUMMY))
-#ifdef UNIX
- obuf = buflist_findname_stat(ffname, &st);
-#else
- obuf = buflist_findname(ffname);
-#endif
+ if (!os_get_file_info((char *)ffname, &file_info)) {
+ file_info.stat.st_dev = INVALID_DEVICE_ID;
+ }
+ if (!(buf->b_flags & BF_DUMMY)) {
+ obuf = buflist_findname_file_info(ffname, &file_info);
+ }
if (obuf != NULL && obuf != buf) {
if (obuf->b_ml.ml_mfp != NULL) { /* it's loaded, fail */
if (message)
@@ -2278,15 +2250,13 @@ setfname (
buf->b_sfname = sfname;
}
buf->b_fname = buf->b_sfname;
-#ifdef UNIX
- if (st.st_dev == (dev_T)-1)
+ if (file_info.stat.st_dev == INVALID_DEVICE_ID) {
buf->b_dev_valid = FALSE;
- else {
+ } else {
buf->b_dev_valid = TRUE;
- buf->b_dev = st.st_dev;
- buf->b_ino = st.st_ino;
+ buf->b_dev = file_info.stat.st_dev;
+ buf->b_ino = file_info.stat.st_ino;
}
-#endif
buf_name_changed(buf);
return OK;
@@ -2419,80 +2389,72 @@ void buflist_altfpos(win_T *win)
*/
int otherfile(char_u *ffname)
{
- return otherfile_buf(curbuf, ffname
-#ifdef UNIX
- , NULL
-#endif
- );
+ return otherfile_buf(curbuf, ffname, NULL);
}
-static int otherfile_buf(buf_T *buf, char_u *ffname
-#ifdef UNIX
- , struct stat *stp
-#endif
-)
+static int otherfile_buf(buf_T *buf, char_u *ffname, FileInfo *file_info_p)
{
/* no name is different */
- if (ffname == NULL || *ffname == NUL || buf->b_ffname == NULL)
+ if (ffname == NULL || *ffname == NUL || buf->b_ffname == NULL) {
return TRUE;
- if (fnamecmp(ffname, buf->b_ffname) == 0)
+ }
+ if (fnamecmp(ffname, buf->b_ffname) == 0) {
return FALSE;
-#ifdef UNIX
+ }
{
- struct stat st;
+ FileInfo file_info;
/* If no struct stat given, get it now */
- if (stp == NULL) {
- if (!buf->b_dev_valid || mch_stat((char *)ffname, &st) < 0)
- st.st_dev = (dev_T)-1;
- stp = &st;
+ if (file_info_p == NULL) {
+ if (!buf->b_dev_valid || !os_get_file_info((char *)ffname, &file_info)) {
+ file_info.stat.st_dev = INVALID_DEVICE_ID;
+ }
+ file_info_p = &file_info;
}
/* Use dev/ino to check if the files are the same, even when the names
* are different (possible with links). Still need to compare the
* name above, for when the file doesn't exist yet.
* Problem: The dev/ino changes when a file is deleted (and created
* again) and remains the same when renamed/moved. We don't want to
- * mch_stat() each buffer each time, that would be too slow. Get the
+ * stat() each buffer each time, that would be too slow. Get the
* dev/ino again when they appear to match, but not when they appear
* to be different: Could skip a buffer when it's actually the same
* file. */
- if (buf_same_ino(buf, stp)) {
+ if (buf_same_ino(buf, file_info_p)) {
buf_setino(buf);
- if (buf_same_ino(buf, stp))
+ if (buf_same_ino(buf, file_info_p))
return FALSE;
}
}
-#endif
return TRUE;
}
-#if defined(UNIX) || defined(PROTO)
/*
* Set inode and device number for a buffer.
* Must always be called when b_fname is changed!.
*/
void buf_setino(buf_T *buf)
{
- struct stat st;
-
- if (buf->b_fname != NULL && mch_stat((char *)buf->b_fname, &st) >= 0) {
+ FileInfo file_info;
+ if (buf->b_fname != NULL
+ && os_get_file_info((char *)buf->b_fname, &file_info)) {
buf->b_dev_valid = TRUE;
- buf->b_dev = st.st_dev;
- buf->b_ino = st.st_ino;
- } else
+ buf->b_dev = file_info.stat.st_dev;
+ buf->b_ino = file_info.stat.st_ino;
+ } else {
buf->b_dev_valid = FALSE;
+ }
}
/*
* Return TRUE if dev/ino in buffer "buf" matches with "stp".
*/
-static int buf_same_ino(buf_T *buf, struct stat *stp)
+static int buf_same_ino(buf_T *buf, FileInfo *file_info)
{
return buf->b_dev_valid
- && stp->st_dev == buf->b_dev
- && stp->st_ino == buf->b_ino;
+ && file_info->stat.st_dev == buf->b_dev
+ && file_info->stat.st_ino == buf->b_ino;
}
-#endif
/*
* Print info about the current buffer.
diff --git a/src/buffer_defs.h b/src/buffer_defs.h
index 5c55173022..d78cf0651f 100644
--- a/src/buffer_defs.h
+++ b/src/buffer_defs.h
@@ -423,11 +423,9 @@ struct file_buffer {
char_u *b_sfname; /* short file name */
char_u *b_fname; /* current file name */
-#ifdef UNIX
int b_dev_valid; /* TRUE when b_dev has a valid number */
- dev_t b_dev; /* device number */
- ino_t b_ino; /* inode number */
-#endif
+ uint64_t b_dev; /* device number */
+ uint64_t b_ino; /* inode number */
int b_fnum; /* buffer number for this file. */
diff --git a/src/diff.c b/src/diff.c
index a93f1324fe..e360edc665 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -863,8 +863,6 @@ void ex_diffpatch(exarg_T *eap)
char_u dirbuf[MAXPATHL];
char_u *fullname = NULL;
#endif // ifdef UNIX
- struct stat st;
-
// We need two temp file names.
// Name of original temp file.
char_u *tmp_orig = vim_tempname('o');
@@ -965,7 +963,9 @@ void ex_diffpatch(exarg_T *eap)
os_remove((char *)buf);
// Only continue if the output file was created.
- if ((mch_stat((char *)tmp_new, &st) < 0) || (st.st_size == 0)) {
+ off_t file_size;
+ bool file_size_success = os_get_file_size((char *)tmp_new, &file_size);
+ if (!file_size_success || file_size == 0) {
EMSG(_("E816: Cannot read patch output"));
} else {
if (curbuf->b_fname != NULL) {
diff --git a/src/eval.c b/src/eval.c
index ed246c363b..9300b9a77b 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -9664,24 +9664,21 @@ static void f_getfontname(typval_T *argvars, typval_T *rettv)
*/
static void f_getfperm(typval_T *argvars, typval_T *rettv)
{
- char_u *fname;
- struct stat st;
- char_u *perm = NULL;
+ char_u *perm = NULL;
char_u flags[] = "rwx";
- int i;
- fname = get_tv_string(&argvars[0]);
-
- rettv->v_type = VAR_STRING;
- if (mch_stat((char *)fname, &st) >= 0) {
+ char_u *filename = get_tv_string(&argvars[0]);
+ int32_t file_perm = os_getperm(filename);
+ if (file_perm >= 0) {
perm = vim_strsave((char_u *)"---------");
if (perm != NULL) {
- for (i = 0; i < 9; i++) {
- if (st.st_mode & (1 << (8 - i)))
+ for (int i = 0; i < 9; i++) {
+ if (file_perm & (1 << (8 - i)))
perm[i] = flags[i % 3];
}
}
}
+ rettv->v_type = VAR_STRING;
rettv->vval.v_string = perm;
}
@@ -9690,25 +9687,25 @@ static void f_getfperm(typval_T *argvars, typval_T *rettv)
*/
static void f_getfsize(typval_T *argvars, typval_T *rettv)
{
- char_u *fname;
- struct stat st;
-
- fname = get_tv_string(&argvars[0]);
+ char *fname = (char *)get_tv_string(&argvars[0]);
rettv->v_type = VAR_NUMBER;
- if (mch_stat((char *)fname, &st) >= 0) {
- if (os_isdir(fname))
+ off_t file_size;
+ if (os_get_file_size(fname, &file_size)) {
+ if (os_isdir((char_u *)fname))
rettv->vval.v_number = 0;
else {
- rettv->vval.v_number = (varnumber_T)st.st_size;
+ rettv->vval.v_number = (varnumber_T)file_size;
/* non-perfect check for overflow */
- if ((off_t)rettv->vval.v_number != (off_t)st.st_size)
+ if ((off_t)rettv->vval.v_number != file_size) {
rettv->vval.v_number = -2;
+ }
}
- } else
+ } else {
rettv->vval.v_number = -1;
+ }
}
/*
@@ -9716,15 +9713,14 @@ static void f_getfsize(typval_T *argvars, typval_T *rettv)
*/
static void f_getftime(typval_T *argvars, typval_T *rettv)
{
- char_u *fname;
- struct stat st;
+ char *fname = (char *)get_tv_string(&argvars[0]);
- fname = get_tv_string(&argvars[0]);
-
- if (mch_stat((char *)fname, &st) >= 0)
- rettv->vval.v_number = (varnumber_T)st.st_mtime;
- else
+ FileInfo file_info;
+ if (os_get_file_info(fname, &file_info)) {
+ rettv->vval.v_number = (varnumber_T)file_info.stat.st_mtim.tv_sec;
+ } else {
rettv->vval.v_number = -1;
+ }
}
/*
@@ -9733,44 +9729,45 @@ static void f_getftime(typval_T *argvars, typval_T *rettv)
static void f_getftype(typval_T *argvars, typval_T *rettv)
{
char_u *fname;
- struct stat st;
char_u *type = NULL;
char *t;
fname = get_tv_string(&argvars[0]);
rettv->v_type = VAR_STRING;
- if (mch_lstat((char *)fname, &st) >= 0) {
+ FileInfo file_info;
+ if (os_get_file_info_link((char *)fname, &file_info)) {
+ uint64_t mode = file_info.stat.st_mode;
#ifdef S_ISREG
- if (S_ISREG(st.st_mode))
+ if (S_ISREG(mode))
t = "file";
- else if (S_ISDIR(st.st_mode))
+ else if (S_ISDIR(mode))
t = "dir";
# ifdef S_ISLNK
- else if (S_ISLNK(st.st_mode))
+ else if (S_ISLNK(mode))
t = "link";
# endif
# ifdef S_ISBLK
- else if (S_ISBLK(st.st_mode))
+ else if (S_ISBLK(mode))
t = "bdev";
# endif
# ifdef S_ISCHR
- else if (S_ISCHR(st.st_mode))
+ else if (S_ISCHR(mode))
t = "cdev";
# endif
# ifdef S_ISFIFO
- else if (S_ISFIFO(st.st_mode))
+ else if (S_ISFIFO(mode))
t = "fifo";
# endif
# ifdef S_ISSOCK
- else if (S_ISSOCK(st.st_mode))
+ else if (S_ISSOCK(mode))
t = "fifo";
# endif
else
t = "other";
#else
# ifdef S_IFMT
- switch (st.st_mode & S_IFMT) {
+ switch (mode & S_IFMT) {
case S_IFREG: t = "file"; break;
case S_IFDIR: t = "dir"; break;
# ifdef S_IFLNK
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
index eb42acd93f..3613a02cb3 100644
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -1492,14 +1492,10 @@ void write_viminfo(char_u *file, int forceit)
FILE *fp_in = NULL; /* input viminfo file, if any */
FILE *fp_out = NULL; /* output viminfo file */
char_u *tempname = NULL; /* name of temp viminfo file */
- struct stat st_new; /* mch_stat() of potential new file */
char_u *wp;
#if defined(UNIX)
mode_t umask_save;
#endif
-#ifdef UNIX
- struct stat st_old; /* mch_stat() of existing viminfo file */
-#endif
if (no_viminfo())
return;
@@ -1511,7 +1507,7 @@ void write_viminfo(char_u *file, int forceit)
fp_in = mch_fopen((char *)fname, READBIN);
if (fp_in == NULL) {
/* if it does exist, but we can't read it, don't try writing */
- if (mch_stat((char *)fname, &st_new) == 0)
+ if (os_file_exists(fname))
goto end;
#if defined(UNIX)
/*
@@ -1536,16 +1532,15 @@ void write_viminfo(char_u *file, int forceit)
* overwrite a user's viminfo file after a "su root", with a
* viminfo file that the user can't read.
*/
- st_old.st_dev = (dev_t)0;
- st_old.st_ino = 0;
- st_old.st_mode = 0600;
- if (mch_stat((char *)fname, &st_old) == 0
+
+ FileInfo old_info; // FileInfo of existing viminfo file
+ if (os_get_file_info((char *)fname, &old_info)
&& getuid() != ROOT_UID
- && !(st_old.st_uid == getuid()
- ? (st_old.st_mode & 0200)
- : (st_old.st_gid == getgid()
- ? (st_old.st_mode & 0020)
- : (st_old.st_mode & 0002)))) {
+ && !(old_info.stat.st_uid == getuid()
+ ? (old_info.stat.st_mode & 0200)
+ : (old_info.stat.st_gid == getgid()
+ ? (old_info.stat.st_mode & 0020)
+ : (old_info.stat.st_mode & 0002)))) {
int tt = msg_didany;
/* avoid a wait_return for this message, it's annoying */
@@ -1563,7 +1558,7 @@ void write_viminfo(char_u *file, int forceit)
* Check if tempfile already exists. Never overwrite an
* existing file!
*/
- if (mch_stat((char *)tempname, &st_new) == 0) {
+ if (os_file_exists(tempname)) {
/*
* Try another name. Change one character, just before
* the extension.
@@ -1571,8 +1566,7 @@ void write_viminfo(char_u *file, int forceit)
wp = tempname + STRLEN(tempname) - 5;
if (wp < path_tail(tempname)) /* empty file name? */
wp = path_tail(tempname);
- for (*wp = 'z'; mch_stat((char *)tempname, &st_new) == 0;
- --*wp) {
+ for (*wp = 'z'; os_file_exists(tempname); --*wp) {
/*
* They all exist? Must be something wrong! Don't
* write the viminfo file then.
@@ -1598,7 +1592,7 @@ void write_viminfo(char_u *file, int forceit)
umask_save = umask(0);
fd = mch_open((char *)tempname,
O_CREAT|O_EXCL|O_WRONLY|O_NOFOLLOW,
- (int)((st_old.st_mode & 0777) | 0600));
+ (int)((old_info.stat.st_mode & 0777) | 0600));
(void)umask(umask_save);
# else
fd = mch_open((char *)tempname,
@@ -1624,8 +1618,9 @@ void write_viminfo(char_u *file, int forceit)
* Make sure the owner can read/write it. This only works for
* root.
*/
- if (fp_out != NULL)
- ignored = fchown(fileno(fp_out), st_old.st_uid, st_old.st_gid);
+ if (fp_out != NULL) {
+ fchown(fileno(fp_out), old_info.stat.st_uid, old_info.stat.st_gid);
+ }
#endif
}
}
diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c
index aecd9995ba..0837e5386e 100644
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -48,15 +48,13 @@
static void cmd_source(char_u *fname, exarg_T *eap);
/* Growarray to store info about already sourced scripts.
- * For Unix also store the dev/ino, so that we don't have to stat() each
+ * Also store the dev/ino, so that we don't have to stat() each
* script when going through the list. */
typedef struct scriptitem_S {
char_u *sn_name;
-# ifdef UNIX
int sn_dev_valid;
- dev_t sn_dev;
- ino_t sn_ino;
-# endif
+ uint64_t sn_dev;
+ uint64_t sn_ino;
int sn_prof_on; /* TRUE when script is/was profiled */
int sn_pr_force; /* forceit: profile functions in this script */
proftime_T sn_pr_child; /* time set when going into first child */
@@ -2458,10 +2456,6 @@ do_source (
void *save_funccalp;
int save_debug_break_level = debug_break_level;
scriptitem_T *si = NULL;
-# ifdef UNIX
- struct stat st;
- int stat_ok;
-# endif
#ifdef STARTUPTIME
struct timeval tv_rel;
struct timeval tv_start;
@@ -2622,23 +2616,19 @@ do_source (
* If it's new, generate a new SID.
*/
save_current_SID = current_SID;
-# ifdef UNIX
- stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
-# endif
+ FileInfo file_info;
+ bool file_info_ok = os_get_file_info((char *)fname_exp, &file_info);
for (current_SID = script_items.ga_len; current_SID > 0; --current_SID) {
si = &SCRIPT_ITEM(current_SID);
+ // Compare dev/ino when possible, it catches symbolic links.
+ // Also compare file names, the inode may change when the file was edited.
+ bool file_id_equal = file_info_ok && si->sn_dev_valid
+ && si->sn_dev == file_info.stat.st_dev
+ && si->sn_ino == file_info.stat.st_ino;
if (si->sn_name != NULL
- && (
-# ifdef UNIX
- /* Compare dev/ino when possible, it catches symbolic
- * links. Also compare file names, the inode may change
- * when the file was edited. */
- ((stat_ok && si->sn_dev_valid)
- && (si->sn_dev == st.st_dev
- && si->sn_ino == st.st_ino)) ||
-# endif
- fnamecmp(si->sn_name, fname_exp) == 0))
+ && (file_id_equal || fnamecmp(si->sn_name, fname_exp) == 0)) {
break;
+ }
}
if (current_SID == 0) {
current_SID = ++last_current_SID;
@@ -2651,14 +2641,13 @@ do_source (
si = &SCRIPT_ITEM(current_SID);
si->sn_name = fname_exp;
fname_exp = NULL;
-# ifdef UNIX
- if (stat_ok) {
+ if (file_info_ok) {
si->sn_dev_valid = TRUE;
- si->sn_dev = st.st_dev;
- si->sn_ino = st.st_ino;
- } else
+ si->sn_dev = file_info.stat.st_dev;
+ si->sn_ino = file_info.stat.st_ino;
+ } else {
si->sn_dev_valid = FALSE;
-# endif
+ }
/* Allocate the local script variables to use for this script. */
new_script_vars(current_SID);
diff --git a/src/file_search.c b/src/file_search.c
index 82b9689e09..96f0b71b73 100644
--- a/src/file_search.c
+++ b/src/file_search.c
@@ -110,11 +110,9 @@ typedef struct ff_visited {
/* for unix use inode etc for comparison (needed because of links), else
* use filename.
*/
-#ifdef UNIX
int ffv_dev_valid; /* ffv_dev and ffv_ino were set */
- dev_t ffv_dev; /* device number */
- ino_t ffv_ino; /* inode number */
-#endif
+ uint64_t ffv_dev; /* device number */
+ uint64_t ffv_ino; /* inode number */
/* The memory for this struct is allocated according to the length of
* ffv_fname.
*/
@@ -1126,38 +1124,27 @@ static int ff_wc_equal(char_u *s1, char_u *s2)
static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u *wc_path)
{
ff_visited_T *vp;
-#ifdef UNIX
- struct stat st;
- int url = FALSE;
-#endif
+ bool url = false;
- /* For an URL we only compare the name, otherwise we compare the
- * device/inode (unix) or the full path name (not Unix). */
+ FileInfo file_info;
+ // For an URL we only compare the name, otherwise we compare the
+ // device/inode.
if (path_with_url(fname)) {
vim_strncpy(ff_expand_buffer, fname, MAXPATHL - 1);
-#ifdef UNIX
- url = TRUE;
-#endif
+ url = true;
} else {
ff_expand_buffer[0] = NUL;
-#ifdef UNIX
- if (mch_stat((char *)fname, &st) < 0)
-#else
- if (vim_FullName(fname, ff_expand_buffer, MAXPATHL, TRUE) == FAIL)
-#endif
+ if (!os_get_file_info((char *)fname, &file_info)) {
return FAIL;
+ }
}
/* check against list of already visited files */
for (vp = *visited_list; vp != NULL; vp = vp->ffv_next) {
- if (
-#ifdef UNIX
- !url ? (vp->ffv_dev_valid && vp->ffv_dev == st.st_dev
- && vp->ffv_ino == st.st_ino)
- :
-#endif
- fnamecmp(vp->ffv_fname, ff_expand_buffer) == 0
- ) {
+ if ((url && fnamecmp(vp->ffv_fname, ff_expand_buffer) == 0)
+ || (!url && vp->ffv_dev_valid
+ && vp->ffv_dev == file_info.stat.st_dev
+ && vp->ffv_ino == file_info.stat.st_ino)) {
/* are the wildcard parts equal */
if (ff_wc_equal(vp->ffv_wc_path, wc_path) == TRUE)
/* already visited */
@@ -1171,19 +1158,15 @@ static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u *
vp = (ff_visited_T *)alloc((unsigned)(sizeof(ff_visited_T)
+ STRLEN(ff_expand_buffer)));
-#ifdef UNIX
if (!url) {
vp->ffv_dev_valid = TRUE;
- vp->ffv_ino = st.st_ino;
- vp->ffv_dev = st.st_dev;
+ vp->ffv_ino = file_info.stat.st_ino;
+ vp->ffv_dev = file_info.stat.st_dev;
vp->ffv_fname[0] = NUL;
} else {
vp->ffv_dev_valid = FALSE;
STRCPY(vp->ffv_fname, ff_expand_buffer);
}
-#else
- STRCPY(vp->ffv_fname, ff_expand_buffer);
-#endif
if (wc_path != NULL)
vp->ffv_wc_path = vim_strsave(wc_path);
diff --git a/src/fileio.c b/src/fileio.c
index 8f2639064a..fc23d3765c 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -86,7 +86,7 @@ static void set_file_time(char_u *fname, time_t atime, time_t mtime);
static int set_rw_fname(char_u *fname, char_u *sfname);
static int msg_add_fileformat(int eol_type);
static void msg_add_eol(void);
-static int check_mtime(buf_T *buf, struct stat *s);
+static int check_mtime(buf_T *buf, FileInfo *file_info);
static int time_differs(long t1, long t2);
static int apply_autocmds_exarg(event_T event, char_u *fname, char_u *fname_io,
int force, buf_T *buf,
@@ -262,7 +262,6 @@ readfile (
#endif
int fileformat = 0; /* end-of-line format */
int keep_fileformat = FALSE;
- struct stat st;
int file_readonly;
linenr_T skip_count = 0;
linenr_T read_count = 0;
@@ -441,8 +440,9 @@ readfile (
if (newfile && !read_stdin && !read_buffer) {
/* Remember time of file. */
- if (mch_stat((char *)fname, &st) >= 0) {
- buf_store_time(curbuf, &st, fname);
+ FileInfo file_info;
+ if (os_get_file_info((char *)fname, &file_info)) {
+ buf_store_file_info(curbuf, &file_info, fname);
curbuf->b_mtime_read = curbuf->b_mtime;
#ifdef UNIX
/*
@@ -456,7 +456,7 @@ readfile (
* not be able to write to the file ourselves.
* Setting the bits is done below, after creating the swap file.
*/
- swap_mode = (st.st_mode & 0644) | 0600;
+ swap_mode = (file_info.stat.st_mode & 0644) | 0600;
#endif
} else {
curbuf->b_mtime = 0;
@@ -2473,7 +2473,6 @@ buf_write (
int overwriting; /* TRUE if writing over original */
int no_eol = FALSE; /* no end-of-line written */
int device = FALSE; /* writing to a device */
- struct stat st_old;
int prev_got_int = got_int;
bool file_readonly = false; /* overwritten file is read-only */
static char *err_readonly =
@@ -2774,15 +2773,14 @@ buf_write (
* Get information about original file (if there is one).
*/
#if defined(UNIX)
- st_old.st_dev = 0;
- st_old.st_ino = 0;
perm = -1;
- if (mch_stat((char *)fname, &st_old) < 0)
+ FileInfo file_info_old;
+ if (!os_get_file_info((char *)fname, &file_info_old)) {
newfile = TRUE;
- else {
- perm = st_old.st_mode;
- if (!S_ISREG(st_old.st_mode)) { /* not a file */
- if (S_ISDIR(st_old.st_mode)) {
+ } else {
+ 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");
goto fail;
@@ -2822,8 +2820,10 @@ buf_write (
errmsg = (char_u *)_("is a directory");
goto fail;
}
- if (overwriting)
- (void)mch_stat((char *)fname, &st_old);
+ if (overwriting) {
+ os_get_file_info((char *)fname, &file_info_old);
+ }
+
}
#endif /* !UNIX */
@@ -2849,7 +2849,7 @@ buf_write (
* Check if the timestamp hasn't changed since reading the file.
*/
if (overwriting) {
- retval = check_mtime(buf, &st_old);
+ retval = check_mtime(buf, &file_info_old);
if (retval == FAIL)
goto fail;
}
@@ -2890,14 +2890,11 @@ buf_write (
* off. This helps when editing large files on almost-full disks.
*/
if (!(append && *p_pm == NUL) && !filtering && perm >= 0 && dobackup) {
-#if defined(UNIX) || defined(WIN32)
- struct stat st;
-#endif
+ FileInfo file_info;
- if ((bkc_flags & BKC_YES) || append) /* "yes" */
+ if ((bkc_flags & BKC_YES) || append) { /* "yes" */
backup_copy = TRUE;
-#if defined(UNIX) || defined(WIN32)
- else if ((bkc_flags & BKC_AUTO)) { /* "auto" */
+ } else if ((bkc_flags & BKC_AUTO)) { /* "auto" */
int i;
# ifdef UNIX
@@ -2908,18 +2905,16 @@ buf_write (
* - we don't have write permission in the directory
* - we can't set the owner/group of the new file
*/
- if (st_old.st_nlink > 1
- || mch_lstat((char *)fname, &st) < 0
- || st.st_dev != st_old.st_dev
- || st.st_ino != st_old.st_ino
+ if (file_info_old.stat.st_nlink > 1
+ || !os_get_file_info_link((char *)fname, &file_info)
+ || !os_file_info_id_equal(&file_info, &file_info_old)
# ifndef HAVE_FCHOWN
- || st.st_uid != st_old.st_uid
- || st.st_gid != st_old.st_gid
+ || file_info.stat.st_uid != file_info_old.stat.st_uid
+ || file_info.stat.st_gid != file_info_old.stat.st_gid
# endif
- )
+ ) {
backup_copy = TRUE;
- else
-# else
+ } else
# endif
{
/*
@@ -2931,8 +2926,9 @@ buf_write (
STRCPY(IObuff, fname);
for (i = 4913;; i += 123) {
sprintf((char *)path_tail(IObuff), "%d", i);
- if (mch_lstat((char *)IObuff, &st) < 0)
+ if (!os_get_file_info_link((char *)IObuff, &file_info)) {
break;
+ }
}
fd = mch_open((char *)IObuff,
O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, perm);
@@ -2941,13 +2937,14 @@ buf_write (
else {
# ifdef UNIX
# ifdef HAVE_FCHOWN
- ignored = fchown(fd, st_old.st_uid, st_old.st_gid);
+ fchown(fd, file_info_old.stat.st_uid, file_info_old.stat.st_gid);
# endif
- if (mch_stat((char *)IObuff, &st) < 0
- || st.st_uid != st_old.st_uid
- || st.st_gid != st_old.st_gid
- || (long)st.st_mode != perm)
+ if (!os_get_file_info((char *)IObuff, &file_info)
+ || file_info.stat.st_uid != file_info_old.stat.st_uid
+ || file_info.stat.st_gid != file_info_old.stat.st_gid
+ || (long)file_info.stat.st_mode != perm) {
backup_copy = TRUE;
+ }
# endif
/* Close the file before removing it, on MS-Windows we
* can't delete an open file. */
@@ -2962,27 +2959,25 @@ buf_write (
*/
if ((bkc_flags & BKC_BREAKSYMLINK) || (bkc_flags & BKC_BREAKHARDLINK)) {
# ifdef UNIX
- int lstat_res;
-
- lstat_res = mch_lstat((char *)fname, &st);
+ bool file_info_link_ok = os_get_file_info_link((char *)fname, &file_info);
/* Symlinks. */
if ((bkc_flags & BKC_BREAKSYMLINK)
- && lstat_res == 0
- && st.st_ino != st_old.st_ino)
+ && file_info_link_ok
+ && !os_file_info_id_equal(&file_info, &file_info_old)) {
backup_copy = FALSE;
+ }
/* Hardlinks. */
if ((bkc_flags & BKC_BREAKHARDLINK)
- && st_old.st_nlink > 1
- && (lstat_res != 0 || st.st_ino == st_old.st_ino))
+ && file_info_old.stat.st_nlink > 1
+ && (!file_info_link_ok
+ || os_file_info_id_equal(&file_info, &file_info_old))) {
backup_copy = FALSE;
-# else
+ }
# endif
}
-#endif
-
/* make sure we have a valid backup extension to use */
if (*p_bex == NUL)
backup_ext = (char_u *)".bak";
@@ -2994,7 +2989,6 @@ buf_write (
int bfd;
char_u *copybuf, *wp;
int some_error = FALSE;
- struct stat st_new;
char_u *dirp;
char_u *rootname;
@@ -3019,12 +3013,6 @@ buf_write (
*/
dirp = p_bdir;
while (*dirp) {
-#ifdef UNIX
- st_new.st_ino = 0;
- st_new.st_dev = 0;
- st_new.st_gid = 0;
-#endif
-
/*
* Isolate one directory name, using an entry in 'bdir'.
*/
@@ -3035,6 +3023,7 @@ buf_write (
goto nobackup;
}
+ FileInfo file_info_new;
{
/*
* Make backup file name.
@@ -3049,20 +3038,17 @@ buf_write (
/*
* Check if backup file already exists.
*/
- if (mch_stat((char *)backup, &st_new) >= 0) {
-#ifdef UNIX
+ if (os_get_file_info((char *)backup, &file_info_new)) {
/*
* Check if backup file is same as original file.
* May happen when modname() gave the same file back (e.g. silly
* link). If we don't check here, we either ruin the file when
* copying or erase it after writing.
*/
- if (st_new.st_dev == st_old.st_dev
- && st_new.st_ino == st_old.st_ino) {
+ if (os_file_info_id_equal(&file_info_new, &file_info_old)) {
free(backup);
backup = NULL; /* no backup file to delete */
}
-#endif
/*
* If we are not going to keep the backup file, don't
@@ -3076,8 +3062,9 @@ buf_write (
wp = backup;
*wp = 'z';
while (*wp > 'a'
- && mch_stat((char *)backup, &st_new) >= 0)
+ && os_get_file_info((char *)backup, &file_info_new)) {
--*wp;
+ }
/* They all exist??? Must be something wrong. */
if (*wp == 'a') {
free(backup);
@@ -3114,13 +3101,13 @@ buf_write (
* bits for the group same as the protection bits for
* others.
*/
- if (st_new.st_gid != st_old.st_gid
+ if (file_info_new.stat.st_gid != file_info_old.stat.st_gid
# ifdef HAVE_FCHOWN /* sequent-ptx lacks fchown() */
- && fchown(bfd, (uid_t)-1, st_old.st_gid) != 0
+ && fchown(bfd, (uid_t)-1, file_info_old.stat.st_gid) != 0
# endif
- )
- os_setperm(backup,
- (perm & 0707) | ((perm & 07) << 3));
+ ) {
+ os_setperm(backup, (perm & 0707) | ((perm & 07) << 3));
+ }
# ifdef HAVE_SELINUX
mch_copy_sec(fname, backup);
# endif
@@ -3155,7 +3142,9 @@ buf_write (
errmsg = (char_u *)_(
"E508: Can't read file for backup (add ! to override)");
#ifdef UNIX
- set_file_time(backup, st_old.st_atime, st_old.st_mtime);
+ set_file_time(backup,
+ file_info_old.stat.st_atim.tv_sec,
+ file_info_old.stat.st_mtim.tv_sec);
#endif
#ifdef HAVE_ACL
mch_set_acl(backup, acl);
@@ -3266,7 +3255,8 @@ nobackup:
#if defined(UNIX)
/* When using ":w!" and the file was read-only: make it writable */
- if (forceit && perm >= 0 && !(perm & 0200) && st_old.st_uid == getuid()
+ if (forceit && perm >= 0 && !(perm & 0200)
+ && file_info_old.stat.st_uid == getuid()
&& vim_strchr(p_cpo, CPO_FWRITE) == NULL) {
perm |= 0200;
(void)os_setperm(fname, perm);
@@ -3412,15 +3402,14 @@ nobackup:
*/
if (errmsg == NULL) {
#ifdef UNIX
- struct stat st;
+ FileInfo file_info;
/* Don't delete the file when it's a hard or symbolic link. */
- if ((!newfile && st_old.st_nlink > 1)
- || (mch_lstat((char *)fname, &st) == 0
- && (st.st_dev != st_old.st_dev
- || st.st_ino != st_old.st_ino)))
+ if ((!newfile && file_info_old.stat.st_nlink > 1)
+ || (os_get_file_info_link((char *)fname, &file_info)
+ && !os_file_info_id_equal(&file_info, &file_info_old))) {
errmsg = (char_u *)_("E166: Can't open linked file for writing");
- else
+ } else
#endif
{
errmsg = (char_u *)_("E212: Can't open file for writing");
@@ -3432,8 +3421,10 @@ nobackup:
if (!(perm & 0200))
made_writable = TRUE;
perm |= 0200;
- if (st_old.st_uid != getuid() || st_old.st_gid != getgid())
+ if (file_info_old.stat.st_uid != getuid()
+ || file_info_old.stat.st_gid != getgid()) {
perm &= 0777;
+ }
#endif
if (!append) /* don't remove when appending */
os_remove((char *)wfname);
@@ -3444,8 +3435,6 @@ nobackup:
restore_backup:
{
- struct stat st;
-
/*
* If we failed to open the file, we don't need a backup. Throw it
* away. If we moved or removed the original file try to put the
@@ -3460,11 +3449,13 @@ restore_backup:
* In that case we leave the copy around.
*/
/* If file does not exist, put the copy in its place */
- if (mch_stat((char *)fname, &st) < 0)
+ if (!os_file_exists(fname)) {
vim_rename(backup, fname);
+ }
/* if original file does exist throw away the copy */
- if (mch_stat((char *)fname, &st) >= 0)
+ if (os_file_exists(fname)) {
os_remove((char *)backup);
+ }
} else {
/* try to put the original file back */
vim_rename(backup, fname);
@@ -3472,8 +3463,9 @@ restore_backup:
}
/* if original file no longer exists give an extra warning */
- if (!newfile && mch_stat((char *)fname, &st) < 0)
+ if (!newfile && !os_file_exists(fname)) {
end = 0;
+ }
}
if (wfname != fname)
@@ -3649,14 +3641,14 @@ restore_backup:
* file. Get the new device and inode number. */
if (backup != NULL && !backup_copy) {
# ifdef HAVE_FCHOWN
- struct stat st;
/* don't change the owner when it's already OK, some systems remove
* permission or ACL stuff */
- if (mch_stat((char *)wfname, &st) < 0
- || st.st_uid != st_old.st_uid
- || st.st_gid != st_old.st_gid) {
- ignored = fchown(fd, st_old.st_uid, st_old.st_gid);
+ FileInfo file_info;
+ if (!os_get_file_info((char *)wfname, &file_info)
+ || file_info.stat.st_uid != file_info_old.stat.st_uid
+ || file_info.stat.st_gid != file_info_old.stat.st_gid) {
+ 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);
}
@@ -3855,20 +3847,20 @@ restore_backup:
char *org = (char *)modname(fname, p_pm, FALSE);
if (backup != NULL) {
- struct stat st;
-
/*
* If the original file does not exist yet
* the current backup file becomes the original file
*/
if (org == NULL)
EMSG(_("E205: Patchmode: can't save original file"));
- else if (mch_stat(org, &st) < 0) {
+ else if (!os_file_exists((char_u *)org)) {
vim_rename(backup, (char_u *)org);
free(backup); /* don't delete the file */
backup = NULL;
#ifdef UNIX
- set_file_time((char_u *)org, st_old.st_atime, st_old.st_mtime);
+ set_file_time((char_u *)org,
+ file_info_old.stat.st_atim.tv_sec,
+ file_info_old.stat.st_mtim.tv_sec);
#endif
}
}
@@ -3961,8 +3953,8 @@ nofail:
/* Update the timestamp to avoid an "overwrite changed file"
* prompt when writing again. */
- if (mch_stat((char *)fname, &st_old) >= 0) {
- buf_store_time(buf, &st_old, fname);
+ if (os_get_file_info((char *)fname, &file_info_old)) {
+ buf_store_file_info(buf, &file_info_old, fname);
buf->b_mtime_read = buf->b_mtime;
}
}
@@ -4138,10 +4130,11 @@ static void msg_add_eol(void)
* The size isn't checked, because using a tool like "gzip" takes care of
* using the same timestamp but can't set the size.
*/
-static int check_mtime(buf_T *buf, struct stat *st)
+static int check_mtime(buf_T *buf, FileInfo *file_info)
{
if (buf->b_mtime_read != 0
- && time_differs((long)st->st_mtime, buf->b_mtime_read)) {
+ && time_differs((long)file_info->stat.st_mtim.tv_sec,
+ buf->b_mtime_read)) {
msg_scroll = TRUE; /* don't overwrite messages here */
msg_silent = 0; /* must give this prompt */
/* don't use emsg() here, don't want to flush the buffers */
@@ -4814,12 +4807,11 @@ int vim_rename(char_u *from, char_u *to)
int n;
char *errmsg = NULL;
char *buffer;
- struct stat st;
long perm;
#ifdef HAVE_ACL
vim_acl_T acl; /* ACL from original file */
#endif
- int use_tmp_file = FALSE;
+ bool use_tmp_file = false;
/*
* When the names are identical, there is nothing to do. When they refer
@@ -4828,30 +4820,25 @@ int vim_rename(char_u *from, char_u *to)
*/
if (fnamecmp(from, to) == 0) {
if (p_fic && STRCMP(path_tail(from), path_tail(to)) != 0)
- use_tmp_file = TRUE;
+ use_tmp_file = true;
else
return 0;
}
- /*
- * Fail if the "from" file doesn't exist. Avoids that "to" is deleted.
- */
- if (mch_stat((char *)from, &st) < 0)
+ // Fail if the "from" file doesn't exist. Avoids that "to" is deleted.
+ FileInfo from_info;
+ if (!os_get_file_info((char *)from, &from_info)) {
return -1;
+ }
-#ifdef UNIX
- {
- struct stat st_to;
-
- /* It's possible for the source and destination to be the same file.
- * This happens when "from" and "to" differ in case and are on a FAT32
- * filesystem. In that case go through a temp file name. */
- if (mch_stat((char *)to, &st_to) >= 0
- && st.st_dev == st_to.st_dev
- && st.st_ino == st_to.st_ino)
- use_tmp_file = TRUE;
+ // It's possible for the source and destination to be the same file.
+ // This happens when "from" and "to" differ in case and are on a FAT32
+ // filesystem. In that case go through a temp file name.
+ FileInfo to_info;
+ if (os_get_file_info((char *)to, &to_info)
+ && os_file_info_id_equal(&from_info, &to_info)) {
+ use_tmp_file = true;
}
-#endif
if (use_tmp_file) {
char_u tempname[MAXPATHL + 1];
@@ -5086,8 +5073,6 @@ buf_check_timestamp (
int focus /* called for GUI focus event */
)
{
- struct stat st;
- int stat_res;
int retval = 0;
char_u *path;
char_u *tbuf;
@@ -5114,27 +5099,25 @@ buf_check_timestamp (
)
return 0;
- if ( !(buf->b_flags & BF_NOTEDITED)
- && buf->b_mtime != 0
- && ((stat_res = mch_stat((char *)buf->b_ffname, &st)) < 0
- || time_differs((long)st.st_mtime, buf->b_mtime)
- || st.st_size != buf->b_orig_size
-#ifdef HAVE_ST_MODE
- || (int)st.st_mode != buf->b_orig_mode
-#else
- || os_getperm(buf->b_ffname) != buf->b_orig_mode
-#endif
- )) {
+ FileInfo file_info;
+ bool file_info_ok;
+ if (!(buf->b_flags & BF_NOTEDITED)
+ && buf->b_mtime != 0
+ && (!(file_info_ok = os_get_file_info((char *)buf->b_ffname, &file_info))
+ || time_differs((long)file_info.stat.st_mtim.tv_sec, buf->b_mtime)
+ || (int)file_info.stat.st_mode != buf->b_orig_mode
+ )) {
retval = 1;
/* set b_mtime to stop further warnings (e.g., when executing
* FileChangedShell autocmd) */
- if (stat_res < 0) {
+ if (!file_info_ok) {
buf->b_mtime = 0;
buf->b_orig_size = 0;
buf->b_orig_mode = 0;
- } else
- buf_store_time(buf, &st, buf->b_ffname);
+ } else {
+ buf_store_file_info(buf, &file_info, buf->b_ffname);
+ }
/* Don't do anything for a directory. Might contain the file
* explorer. */
@@ -5147,10 +5130,10 @@ buf_check_timestamp (
* was set, the global option value otherwise.
*/
else if ((buf->b_p_ar >= 0 ? buf->b_p_ar : p_ar)
- && !bufIsChanged(buf) && stat_res >= 0)
+ && !bufIsChanged(buf) && file_info_ok)
reload = TRUE;
else {
- if (stat_res < 0)
+ if (!file_info_ok)
reason = "deleted";
else if (bufIsChanged(buf))
reason = "conflict";
@@ -5435,15 +5418,12 @@ void buf_reload(buf_T *buf, int orig_mode)
/* Careful: autocommands may have made "buf" invalid! */
}
-void buf_store_time(buf_T *buf, struct stat *st, char_u *fname)
+// TODO(stefan991): remove unused parameter fname
+void buf_store_file_info(buf_T *buf, FileInfo *file_info, char_u *fname)
{
- buf->b_mtime = (long)st->st_mtime;
- buf->b_orig_size = st->st_size;
-#ifdef HAVE_ST_MODE
- buf->b_orig_mode = (int)st->st_mode;
-#else
- buf->b_orig_mode = os_getperm(fname);
-#endif
+ buf->b_mtime = (long)file_info->stat.st_mtim.tv_sec;
+ buf->b_orig_size = file_info->stat.st_size;
+ buf->b_orig_mode = (int)file_info->stat.st_mode;
}
/*
@@ -5527,9 +5507,6 @@ vim_tempname (
#ifdef TEMPDIRNAMES
static char *(tempdirs[]) = {TEMPDIRNAMES};
int i;
-# ifndef EEXIST
- struct stat st;
-# endif
/*
* This will create a directory for private use by this instance of Vim.
@@ -5580,7 +5557,7 @@ vim_tempname (
/* If mkdir() does not set errno to EEXIST, check for
* existing file here. There is a race condition then,
* although it's fail-safe. */
- if (mch_stat((char *)itmp, &st) >= 0)
+ if (os_file_exists(itmp))
continue;
# endif
# if defined(UNIX)
diff --git a/src/fileio.h b/src/fileio.h
index 8b743aab0d..5f67449382 100644
--- a/src/fileio.h
+++ b/src/fileio.h
@@ -2,6 +2,7 @@
#define NEOVIM_FILEIO_H
#include "buffer_defs.h"
+#include "os/os.h"
/*
* Struct to save values in before executing autocommands for a buffer that is
@@ -40,7 +41,7 @@ int vim_rename(char_u *from, char_u *to);
int check_timestamps(int focus);
int buf_check_timestamp(buf_T *buf, int focus);
void buf_reload(buf_T *buf, int orig_mode);
-void buf_store_time(buf_T *buf, struct stat *st, char_u *fname);
+void buf_store_file_info(buf_T *buf, FileInfo *file_info, char_u *fname);
void write_lnum_adjust(linenr_T offset);
void vim_deltempdir(void);
char_u *vim_tempname(int extra_char);
diff --git a/src/if_cscope.c b/src/if_cscope.c
index eadd1e5b1a..b000b03444 100644
--- a/src/if_cscope.c
+++ b/src/if_cscope.c
@@ -52,8 +52,7 @@ static int cs_find_common(char *opt, char *pat, int, int, int,
char_u *cmdline);
static int cs_help(exarg_T *eap);
static void clear_csinfo(int i);
-static int cs_insert_filelist(char *, char *, char *,
- struct stat *);
+static int cs_insert_filelist(char *, char *, char *, FileInfo *file_info);
static int cs_kill(exarg_T *eap);
static void cs_kill_execute(int, char *);
static cscmd_T * cs_lookup_cmd(exarg_T *eap);
@@ -481,8 +480,6 @@ cs_add_common (
char *flags
)
{
- struct stat statbuf;
- int ret;
char *fname = NULL;
char *fname2 = NULL;
char *ppath = NULL;
@@ -503,28 +500,25 @@ cs_add_common (
goto add_err;
fname = (char *)vim_strnsave((char_u *)fname, len);
free(fbuf);
- ret = stat(fname, &statbuf);
- if (ret < 0) {
+ FileInfo file_info;
+ bool file_info_ok = os_get_file_info(fname, &file_info);
+ if (!file_info_ok) {
staterr:
if (p_csverbose)
cs_stat_emsg(fname);
goto add_err;
}
- /* get the prepend path (arg2), expand it, and try to stat it */
+ // get the prepend path (arg2), expand it, and see if it exists
if (arg2 != NULL) {
- struct stat statbuf2;
-
ppath = (char *)alloc(MAXPATHL + 1);
-
expand_env((char_u *)arg2, (char_u *)ppath, MAXPATHL);
- ret = stat(ppath, &statbuf2);
- if (ret < 0)
+ if (!os_file_exists((char_u *)ppath))
goto staterr;
}
/* if filename is a directory, append the cscope database name to it */
- if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
+ if ((file_info.stat.st_mode & S_IFMT) == S_IFDIR) {
fname2 = (char *)alloc((unsigned)(strlen(CSCOPE_DBFILE) + strlen(fname) + 2));
while (fname[strlen(fname)-1] == '/'
@@ -538,23 +532,18 @@ staterr:
else
(void)sprintf(fname2, "%s/%s", fname, CSCOPE_DBFILE);
- ret = stat(fname2, &statbuf);
- if (ret < 0) {
+ file_info_ok = os_get_file_info(fname2, &file_info);
+ if (!file_info_ok) {
if (p_csverbose)
cs_stat_emsg(fname2);
goto add_err;
}
- i = cs_insert_filelist(fname2, ppath, flags, &statbuf);
+ i = cs_insert_filelist(fname2, ppath, flags, &file_info);
}
-#if defined(UNIX)
- else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode))
-#else
- /* WIN32 - substitute define S_ISREG from os_unix_defs.h */
- else if (((statbuf.st_mode) & S_IFMT) == S_IFREG)
-#endif
+ else if (S_ISREG(file_info.stat.st_mode) || S_ISLNK(file_info.stat.st_mode))
{
- i = cs_insert_filelist(fname, ppath, flags, &statbuf);
+ i = cs_insert_filelist(fname, ppath, flags, &file_info);
} else {
if (p_csverbose)
(void)EMSG2(
@@ -1223,53 +1212,16 @@ static char *GetWin32Error(void)
*
* insert a new cscope database filename into the filelist
*/
-static int cs_insert_filelist(char *fname, char *ppath, char *flags, struct stat *sb)
+static int cs_insert_filelist(char *fname, char *ppath, char *flags,
+ FileInfo *file_info)
{
short i, j;
-#ifndef UNIX
- BY_HANDLE_FILE_INFORMATION bhfi;
-
- /* On windows 9x GetFileInformationByHandle doesn't work, so skip it */
- if (!mch_windows95()) {
- switch (win32_fileinfo(fname, &bhfi)) {
- case FILEINFO_ENC_FAIL: /* enc_to_utf16() failed */
- case FILEINFO_READ_FAIL: /* CreateFile() failed */
- if (p_csverbose) {
- char *cant_msg = _("E625: cannot open cscope database: %s");
- char *winmsg = GetWin32Error();
-
- if (winmsg != NULL) {
- (void)EMSG2(cant_msg, winmsg);
- LocalFree(winmsg);
- } else
- /* subst filename if can't get error text */
- (void)EMSG2(cant_msg, fname);
- }
- return -1;
-
- case FILEINFO_INFO_FAIL: /* GetFileInformationByHandle() failed */
- if (p_csverbose)
- (void)EMSG(_("E626: cannot get cscope database information"));
- return -1;
- }
- }
-#endif
i = -1; /* can be set to the index of an empty item in csinfo */
for (j = 0; j < csinfo_size; j++) {
if (csinfo[j].fname != NULL
-#if defined(UNIX)
- && csinfo[j].st_dev == sb->st_dev && csinfo[j].st_ino == sb->st_ino
-#else
- /* compare pathnames first */
- && ((path_full_compare(csinfo[j].fname, fname, FALSE) & kEqualFiles)
- /* if not Windows 9x, test index file attributes too */
- || (!mch_windows95()
- && csinfo[j].nVolume == bhfi.dwVolumeSerialNumber
- && csinfo[j].nIndexHigh == bhfi.nFileIndexHigh
- && csinfo[j].nIndexLow == bhfi.nFileIndexLow))
-#endif
- ) {
+ && csinfo[j].st_dev == file_info->stat.st_dev
+ && csinfo[j].st_ino == file_info->stat.st_ino) {
if (p_csverbose)
(void)EMSG(_("E568: duplicate cscope database not added"));
return -1;
@@ -1312,15 +1264,8 @@ static int cs_insert_filelist(char *fname, char *ppath, char *flags, struct stat
} else
csinfo[i].flags = NULL;
-#if defined(UNIX)
- csinfo[i].st_dev = sb->st_dev;
- csinfo[i].st_ino = sb->st_ino;
-
-#else
- csinfo[i].nVolume = bhfi.dwVolumeSerialNumber;
- csinfo[i].nIndexLow = bhfi.nFileIndexLow;
- csinfo[i].nIndexHigh = bhfi.nFileIndexHigh;
-#endif
+ csinfo[i].st_dev = file_info->stat.st_dev;
+ csinfo[i].st_ino = file_info->stat.st_ino;
return i;
} /* cs_insert_filelist */
diff --git a/src/if_cscope_defs.h b/src/if_cscope_defs.h
index 7a60da20dd..3c64067795 100644
--- a/src/if_cscope_defs.h
+++ b/src/if_cscope_defs.h
@@ -51,10 +51,9 @@ typedef struct csi {
char * flags; /* additional cscope flags/options (e.g, -p2) */
#if defined(UNIX)
pid_t pid; /* PID of the connected cscope process. */
- dev_t st_dev; /* ID of dev containing cscope db */
- ino_t st_ino; /* inode number of cscope db */
-#else
#endif
+ uint64_t st_dev; /* ID of dev containing cscope db */
+ uint64_t st_ino; /* inode number of cscope db */
FILE * fr_fp; /* from cscope: FILE. */
FILE * to_fp; /* to cscope: FILE. */
diff --git a/src/macros.h b/src/macros.h
index 5f7147be23..9bfe3d054b 100644
--- a/src/macros.h
+++ b/src/macros.h
@@ -98,21 +98,6 @@
#define vim_isbreak(c) (breakat_flags[(char_u)(c)])
# define mch_fopen(n, p) fopen((n), (p))
-# define mch_fstat(n, p) fstat((n), (p))
-# ifdef STAT_IGNORES_SLASH
-/* On Solaris stat() accepts "file/" as if it was "file". Return -1 if
- * the name ends in "/" and it's not a directory. */
-# define mch_stat(n, p) (illegal_slash(n) ? -1 : stat((n), (p)))
-# else
-# define mch_stat(n, p) stat((n), (p))
-# endif
-
-#ifdef HAVE_LSTAT
-# define mch_lstat(n, p) lstat((n), (p))
-#else
-# define mch_lstat(n, p) mch_stat((n), (p))
-#endif
-
# define mch_open(n, m, p) open((n), (m), (p))
/* mch_open_rw(): invoke mch_open() with third argument for user R/W. */
diff --git a/src/main.c b/src/main.c
index 9fd97b23a5..828a6d5200 100644
--- a/src/main.c
+++ b/src/main.c
@@ -2130,14 +2130,13 @@ process_env (
*/
static int file_owned(char *fname)
{
- struct stat s;
uid_t uid = getuid();
-
- return !(mch_stat(fname, &s) != 0 || s.st_uid != uid
-# ifdef HAVE_LSTAT
- || mch_lstat(fname, &s) != 0 || s.st_uid != uid
-# endif
- );
+ FileInfo file_info;
+ bool file_owned = os_get_file_info(fname, &file_info)
+ && file_info.stat.st_uid == uid;
+ bool link_owned = os_get_file_info_link(fname, &file_info)
+ && file_info.stat.st_uid == uid;
+ return file_owned && link_owned;
}
#endif
diff --git a/src/memfile.c b/src/memfile.c
index 5330fb7fc5..9431101d8d 100644
--- a/src/memfile.c
+++ b/src/memfile.c
@@ -46,25 +46,6 @@
#include "ui.h"
#include "os/os.h"
-/*
- * Some systems have the page size in statfs.f_bsize, some in stat.st_blksize
- */
-#ifdef HAVE_ST_BLKSIZE
-# define STATFS stat
-# define F_BSIZE st_blksize
-# define fstatfs(fd, buf, len, nul) mch_fstat((fd), (buf))
-#else
-# ifdef HAVE_SYS_STATFS_H
-# include <sys/statfs.h>
-# define STATFS statfs
-# define F_BSIZE f_bsize
-# endif
-#endif
-
-/*
- * for Amiga Dos 2.0x we use Flush
- */
-
#define MEMFILE_PAGE_SIZE 4096 /* default page size */
static long_u total_mem_used = 0; /* total memory used for memfiles */
@@ -125,10 +106,6 @@ memfile_T *mf_open(char_u *fname, int flags)
{
memfile_T *mfp;
off_t size;
-#if defined(STATFS) && defined(UNIX) && !defined(__QNX__) && !defined(__minix)
-# define USE_FSTATFS
- struct STATFS stf;
-#endif
if ((mfp = (memfile_T *)alloc((unsigned)sizeof(memfile_T))) == NULL)
return NULL;
@@ -157,7 +134,6 @@ memfile_T *mf_open(char_u *fname, int flags)
mfp->mf_page_size = MEMFILE_PAGE_SIZE;
mfp->mf_old_key = NULL;
-#ifdef USE_FSTATFS
/*
* Try to set the page size equal to the block size of the device.
* Speeds up I/O a lot.
@@ -165,12 +141,13 @@ memfile_T *mf_open(char_u *fname, int flags)
* in ml_recover(). The size used here may be wrong, therefore
* mf_blocknr_max must be rounded up.
*/
+ FileInfo file_info;
if (mfp->mf_fd >= 0
- && fstatfs(mfp->mf_fd, &stf, sizeof(struct statfs), 0) == 0
- && stf.F_BSIZE >= MIN_SWAP_PAGE_SIZE
- && stf.F_BSIZE <= MAX_SWAP_PAGE_SIZE)
- mfp->mf_page_size = stf.F_BSIZE;
-#endif
+ && os_get_file_info_fd(mfp->mf_fd, &file_info)
+ && file_info.stat.st_blksize >= MIN_SWAP_PAGE_SIZE
+ && file_info.stat.st_blksize <= MAX_SWAP_PAGE_SIZE) {
+ mfp->mf_page_size = file_info.stat.st_blksize;
+ }
if (mfp->mf_fd < 0 || (flags & (O_TRUNC|O_EXCL))
|| (size = lseek(mfp->mf_fd, (off_t)0L, SEEK_END)) <= 0)
@@ -1064,10 +1041,6 @@ mf_do_open (
int flags /* flags for open() */
)
{
-#ifdef HAVE_LSTAT
- struct stat sb;
-#endif
-
mfp->mf_fname = fname;
/*
@@ -1077,17 +1050,16 @@ mf_do_open (
*/
mf_set_ffname(mfp);
-#ifdef HAVE_LSTAT
/*
* Extra security check: When creating a swap file it really shouldn't
* exist yet. If there is a symbolic link, this is most likely an attack.
*/
- if ((flags & O_CREAT) && mch_lstat((char *)mfp->mf_fname, &sb) >= 0) {
+ FileInfo file_info;
+ if ((flags & O_CREAT)
+ && os_get_file_info_link((char *)mfp->mf_fname, &file_info)) {
mfp->mf_fd = -1;
EMSG(_("E300: Swap file already exists (symlink attack?)"));
- } else
-#endif
- {
+ } else {
/*
* try to open the file
*/
diff --git a/src/memline.c b/src/memline.c
index 53864e6b5d..bf2743fe1d 100644
--- a/src/memline.c
+++ b/src/memline.c
@@ -832,8 +832,6 @@ static void ml_upd_block0(buf_T *buf, upd_block0_T what)
*/
static void set_b0_fname(ZERO_BL *b0p, buf_T *buf)
{
- struct stat st;
-
if (buf->b_ffname == NULL)
b0p->b0_fname[0] = NUL;
else {
@@ -861,12 +859,13 @@ static void set_b0_fname(ZERO_BL *b0p, buf_T *buf)
memmove(b0p->b0_fname + 1, uname, ulen);
}
}
- if (mch_stat((char *)buf->b_ffname, &st) >= 0) {
- long_to_char((long)st.st_mtime, b0p->b0_mtime);
+ FileInfo file_info;
+ if (os_get_file_info((char *)buf->b_ffname, &file_info)) {
+ long_to_char((long)file_info.stat.st_mtim.tv_sec, b0p->b0_mtime);
#ifdef CHECK_INODE
- long_to_char((long)st.st_ino, b0p->b0_ino);
+ long_to_char((long)file_info.stat.st_ino, b0p->b0_ino);
#endif
- buf_store_time(buf, &st, buf->b_ffname);
+ buf_store_file_info(buf, &file_info, buf->b_ffname);
buf->b_mtime_read = buf->b_mtime;
} else {
long_to_char(0L, b0p->b0_mtime);
@@ -943,7 +942,6 @@ void ml_recover(void)
infoptr_T *ip;
blocknr_T bnum;
int page_count;
- struct stat org_stat, swp_stat;
int len;
int directly;
linenr_T lnum;
@@ -1155,12 +1153,15 @@ void ml_recover(void)
/*
* check date of swap file and original file
*/
+ FileInfo org_file_info;
+ FileInfo swp_file_info;
mtime = char_to_long(b0p->b0_mtime);
if (curbuf->b_ffname != NULL
- && mch_stat((char *)curbuf->b_ffname, &org_stat) != -1
- && ((mch_stat((char *)mfp->mf_fname, &swp_stat) != -1
- && org_stat.st_mtime > swp_stat.st_mtime)
- || org_stat.st_mtime != mtime)) {
+ && os_get_file_info((char *)curbuf->b_ffname, &org_file_info)
+ && ((os_get_file_info((char *)mfp->mf_fname, &swp_file_info)
+ && org_file_info.stat.st_mtim.tv_sec
+ > swp_file_info.stat.st_mtim.tv_sec)
+ || org_file_info.stat.st_mtim.tv_sec != mtime)) {
EMSG(_("E308: Warning: Original file may have been changed"));
}
out_flush();
@@ -1607,12 +1608,9 @@ recover_names (
* Try finding a swap file by simply adding ".swp" to the file name.
*/
if (*dirp == NUL && file_count + num_files == 0 && fname != NULL) {
- struct stat st;
- char_u *swapname;
-
- swapname = modname(fname_res, (char_u *)".swp", TRUE);
+ char_u *swapname = modname(fname_res, (char_u *)".swp", TRUE);
if (swapname != NULL) {
- if (mch_stat((char *)swapname, &st) != -1) { /* It exists! */
+ if (os_file_exists(swapname)) {
files = (char_u **)alloc((unsigned)sizeof(char_u *));
files[0] = swapname;
swapname = NULL;
@@ -1717,7 +1715,6 @@ static int process_still_running;
*/
static time_t swapfile_info(char_u *fname)
{
- struct stat st;
int fd;
struct block0 b0;
time_t x = (time_t)0;
@@ -1727,18 +1724,19 @@ static time_t swapfile_info(char_u *fname)
#endif
/* print the swap file date */
- if (mch_stat((char *)fname, &st) != -1) {
+ FileInfo file_info;
+ if (os_get_file_info((char *)fname, &file_info)) {
#ifdef UNIX
/* print name of owner of the file */
- if (os_get_uname(st.st_uid, uname, B0_UNAME_SIZE) == OK) {
+ if (os_get_uname(file_info.stat.st_uid, uname, B0_UNAME_SIZE) == OK) {
MSG_PUTS(_(" owned by: "));
msg_outtrans((char_u *)uname);
MSG_PUTS(_(" dated: "));
} else
#endif
MSG_PUTS(_(" dated: "));
- x = st.st_mtime; /* Manx C can't do &st.st_mtime */
- p = ctime(&x); /* includes '\n' */
+ x = file_info.stat.st_mtim.tv_sec;
+ p = ctime(&x); // includes '\n'
if (p == NULL)
MSG_PUTS("(invalid)\n");
else
@@ -1850,7 +1848,6 @@ static int recov_file_names(char_u **names, char_u *path, int prepend_dot)
void ml_sync_all(int check_file, int check_char)
{
buf_T *buf;
- struct stat st;
for (buf = firstbuf; buf != NULL; buf = buf->b_next) {
if (buf->b_ml.ml_mfp == NULL || buf->b_ml.ml_mfp->mf_fname == NULL)
@@ -1865,9 +1862,10 @@ void ml_sync_all(int check_file, int check_char)
* If the original file does not exist anymore or has been changed
* call ml_preserve() to get rid of all negative numbered blocks.
*/
- if (mch_stat((char *)buf->b_ffname, &st) == -1
- || st.st_mtime != buf->b_mtime_read
- || st.st_size != buf->b_orig_size) {
+ FileInfo file_info;
+ if (!os_get_file_info((char *)buf->b_ffname, &file_info)
+ || file_info.stat.st_mtim.tv_sec != buf->b_mtime_read
+ || (off_t)file_info.stat.st_size != buf->b_orig_size) {
ml_preserve(buf, FALSE);
did_check_timestamps = FALSE;
need_check_timestamps = TRUE; /* give message later */
@@ -3435,7 +3433,6 @@ attention_message (
char_u *fname /* swap file name */
)
{
- struct stat st;
time_t x, sx;
char *p;
@@ -3448,10 +3445,11 @@ attention_message (
MSG_PUTS(_("While opening file \""));
msg_outtrans(buf->b_fname);
MSG_PUTS("\"\n");
- if (mch_stat((char *)buf->b_fname, &st) != -1) {
+ FileInfo file_info;
+ if (os_get_file_info((char *)buf->b_fname, &file_info)) {
MSG_PUTS(_(" dated: "));
- x = st.st_mtime; /* Manx C can't do &st.st_mtime */
- p = ctime(&x); /* includes '\n' */
+ x = file_info.stat.st_mtim.tv_sec;
+ p = ctime(&x); // includes '\n'
if (p == NULL)
MSG_PUTS("(invalid)\n");
else
@@ -3559,21 +3557,13 @@ findswapname (
fname = NULL;
break;
}
- /*
- * check if the swapfile already exists
- */
- if (!os_file_exists(fname)) { /* it does not exist */
-#ifdef HAVE_LSTAT
- struct stat sb;
-
- /*
- * Extra security check: When a swap file is a symbolic link, this
- * is most likely a symlink attack.
- */
- if (mch_lstat((char *)fname, &sb) < 0)
-#else
-#endif
- break;
+ // check if the swapfile already exists
+ // Extra security check: When a swap file is a symbolic link, this
+ // is most likely a symlink attack.
+ FileInfo file_info;
+ bool file_or_link_found = os_get_file_info_link((char *)fname, &file_info);
+ if (!file_or_link_found) {
+ break;
}
/*
@@ -3834,7 +3824,6 @@ fnamecmp_ino (
long ino_block0
)
{
- struct stat st;
ino_t ino_c = 0; /* ino of current file */
ino_t ino_s; /* ino of file from swap file */
char_u buf_c[MAXPATHL]; /* full path of fname_c */
@@ -3842,18 +3831,21 @@ fnamecmp_ino (
int retval_c; /* flag: buf_c valid */
int retval_s; /* flag: buf_s valid */
- if (mch_stat((char *)fname_c, &st) == 0)
- ino_c = (ino_t)st.st_ino;
+ FileInfo file_info;
+ if (os_get_file_info((char *)fname_c, &file_info)) {
+ ino_c = (ino_t)file_info.stat.st_ino;
+ }
/*
* First we try to get the inode from the file name, because the inode in
* the swap file may be outdated. If that fails (e.g. this path is not
* valid on this machine), use the inode from block 0.
*/
- if (mch_stat((char *)fname_s, &st) == 0)
- ino_s = (ino_t)st.st_ino;
- else
+ if (os_get_file_info((char *)fname_s, &file_info)) {
+ ino_s = (ino_t)file_info.stat.st_ino;
+ } else {
ino_s = (ino_t)ino_block0;
+ }
if (ino_c && ino_s)
return ino_c != ino_s;
diff --git a/src/misc2.c b/src/misc2.c
index c424dd8709..8d556db347 100644
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -826,24 +826,6 @@ int vim_chdirfile(char_u *fname)
}
#endif
-#if defined(STAT_IGNORES_SLASH) || defined(PROTO)
-/*
- * Check if "name" ends in a slash and is not a directory.
- * Used for systems where stat() ignores a trailing slash on a file name.
- * The Vim code assumes a trailing slash is only ignored for a directory.
- */
-int illegal_slash(char *name)
-{
- if (name[0] == NUL)
- return FALSE; /* no file name is not illegal */
- if (name[strlen(name) - 1] != '/')
- return FALSE; /* no trailing slash */
- if (os_isdir((char_u *)name))
- return FALSE; /* trailing slash for a directory */
- return TRUE;
-}
-#endif
-
/*
* Change directory to "new_dir". If FEAT_SEARCHPATH is defined, search
* 'cdpath' for relative directory names, otherwise just os_chdir().
diff --git a/src/os/fs.c b/src/os/fs.c
index e03d06669d..89eb4c8691 100644
--- a/src/os/fs.c
+++ b/src/os/fs.c
@@ -189,6 +189,16 @@ int os_file_is_writable(const char *name)
return 0;
}
+bool os_get_file_size(const char *name, off_t *size)
+{
+ uv_stat_t statbuf;
+ if (os_stat((char_u *)name, &statbuf) == OK) {
+ *size = statbuf.st_size;
+ return true;
+ }
+ return false;
+}
+
int os_rename(const char_u *path, const char_u *new_path)
{
uv_fs_t request;
@@ -227,3 +237,41 @@ int os_remove(const char *path)
return result;
}
+bool os_get_file_info(const char *path, FileInfo *file_info)
+{
+ if (os_stat((char_u *)path, &(file_info->stat)) == OK) {
+ return true;
+ }
+ return false;
+}
+
+bool os_get_file_info_link(const char *path, FileInfo *file_info)
+{
+ uv_fs_t request;
+ int result = uv_fs_lstat(uv_default_loop(), &request, path, NULL);
+ file_info->stat = request.statbuf;
+ uv_fs_req_cleanup(&request);
+ if (result == kLibuvSuccess) {
+ return true;
+ }
+ return false;
+}
+
+bool os_get_file_info_fd(int file_descriptor, FileInfo *file_info)
+{
+ uv_fs_t request;
+ int result = uv_fs_fstat(uv_default_loop(), &request, file_descriptor, NULL);
+ file_info->stat = request.statbuf;
+ uv_fs_req_cleanup(&request);
+ if (result == kLibuvSuccess) {
+ return true;
+ }
+ return false;
+}
+
+bool os_file_info_id_equal(FileInfo *file_info_1, FileInfo *file_info_2)
+{
+ return file_info_1->stat.st_ino == file_info_2->stat.st_ino
+ && file_info_1->stat.st_dev == file_info_2->stat.st_dev;
+}
+
diff --git a/src/os/os.h b/src/os/os.h
index 67cda28348..b30872f06d 100644
--- a/src/os/os.h
+++ b/src/os/os.h
@@ -58,6 +58,12 @@ bool os_file_is_readonly(const char *name);
/// @return `2` for a directory which we have rights to write into.
int os_file_is_writable(const char *name);
+/// Get the size of a file in bytes.
+///
+/// @param[out] size pointer to an off_t to put the size into.
+/// @return `true` for success, `false` for failure.
+bool os_get_file_size(const char *name, off_t *size);
+
/// Rename a file or directory.
///
/// @return `OK` for success, `FAIL` for failure.
@@ -105,4 +111,36 @@ char *os_get_user_directory(const char *name);
/// @return OK on success, FAIL if an failure occured.
int os_stat(const char_u *name, uv_stat_t *statbuf);
+/// Struct which encapsulates stat information.
+typedef struct {
+ // TODO(stefan991): make stat private
+ uv_stat_t stat;
+} FileInfo;
+
+/// Get the file information for a given path
+///
+/// @param file_descriptor File descriptor of the file.
+/// @param[out] file_info Pointer to a FileInfo to put the information in.
+/// @return `true` on sucess, `false` for failure.
+bool os_get_file_info(const char *path, FileInfo *file_info);
+
+/// Get the file information for a given path without following links
+///
+/// @param path Path to the file.
+/// @param[out] file_info Pointer to a FileInfo to put the information in.
+/// @return `true` on sucess, `false` for failure.
+bool os_get_file_info_link(const char *path, FileInfo *file_info);
+
+/// Get the file information for a given file descriptor
+///
+/// @param file_descriptor File descriptor of the file.
+/// @param[out] file_info Pointer to a FileInfo to put the information in.
+/// @return `true` on sucess, `false` for failure.
+bool os_get_file_info_fd(int file_descriptor, FileInfo *file_info);
+
+/// Compare the inodes of two FileInfos
+///
+/// @return `true` if the two FileInfos represent the same file.
+bool os_file_info_id_equal(FileInfo *file_info_1, FileInfo *file_info_2);
+
#endif // NEOVIM_OS_OS_H
diff --git a/src/os_unix_defs.h b/src/os_unix_defs.h
index 5ca09a7584..96fc7ff32e 100644
--- a/src/os_unix_defs.h
+++ b/src/os_unix_defs.h
@@ -229,6 +229,7 @@
# define MAXPATHL 1024
#endif
+// TODO(stefan991): remove macro
#define CHECK_INODE /* used when checking if a swap file already
exists for a file */
# ifndef DFLT_MAXMEM
@@ -276,7 +277,6 @@
#endif
#define HAVE_DUP /* have dup() */
-#define HAVE_ST_MODE /* have stat.st_mode */
/* We have three kinds of ACL support. */
#define HAVE_ACL (HAVE_POSIX_ACL || HAVE_SOLARIS_ACL || HAVE_AIX_ACL)
diff --git a/src/path.c b/src/path.c
index 93366c93ab..541e1e1724 100644
--- a/src/path.c
+++ b/src/path.c
@@ -1285,7 +1285,6 @@ void simplify_filename(char_u *filename)
if (components > 0) { /* strip one preceding component */
int do_strip = FALSE;
char_u saved_char;
- struct stat st;
/* Don't strip for an erroneous file name. */
if (!stripping_disabled) {
@@ -1294,12 +1293,10 @@ void simplify_filename(char_u *filename)
* link that refers to a non-existent file. */
saved_char = p[-1];
p[-1] = NUL;
-#ifdef UNIX
- if (mch_lstat((char *)filename, &st) < 0)
-#else
- if (mch_stat((char *)filename, &st) < 0)
-#endif
+ FileInfo file_info;
+ if (!os_get_file_info_link((char *)filename, &file_info)) {
do_strip = TRUE;
+ }
p[-1] = saved_char;
--p;
@@ -1320,40 +1317,37 @@ void simplify_filename(char_u *filename)
* components. */
saved_char = *tail;
*tail = NUL;
- if (mch_stat((char *)filename, &st) >= 0)
+ if (os_get_file_info((char *)filename, &file_info)) {
do_strip = TRUE;
+ }
else
stripping_disabled = TRUE;
*tail = saved_char;
-#ifdef UNIX
if (do_strip) {
- struct stat new_st;
-
- /* On Unix, the check for the unstripped file name
+ /* The check for the unstripped file name
* above works also for a symbolic link pointing to
* a searchable directory. But then the parent of
* the directory pointed to by the link must be the
* same as the stripped file name. (The latter
* exists in the file system since it is the
* component's parent directory.) */
- if (p == start && relative)
- (void)mch_stat(".", &new_st);
- else {
+ FileInfo new_file_info;
+ if (p == start && relative) {
+ os_get_file_info(".", &new_file_info);
+ } else {
saved_char = *p;
*p = NUL;
- (void)mch_stat((char *)filename, &new_st);
+ os_get_file_info((char *)filename, &new_file_info);
*p = saved_char;
}
- if (new_st.st_ino != st.st_ino ||
- new_st.st_dev != st.st_dev) {
+ if (!os_file_info_id_equal(&file_info, &new_file_info)) {
do_strip = FALSE;
/* We don't disable stripping of later
* components since the unstripped path name is
* still valid. */
}
}
-#endif
}
}
diff --git a/src/quickfix.c b/src/quickfix.c
index 91ebe9795b..94b2b05501 100644
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -2573,9 +2573,6 @@ static char_u *get_mef_name(void)
char_u *name;
static int start = -1;
static int off = 0;
-#ifdef HAVE_LSTAT
- struct stat sb;
-#endif
if (*p_mef == NUL) {
name = vim_tempname('e');
@@ -2602,13 +2599,12 @@ static char_u *get_mef_name(void)
STRCPY(name, p_mef);
sprintf((char *)name + (p - p_mef), "%d%d", start, off);
STRCAT(name, p + 2);
- if (!os_file_exists(name)
-#ifdef HAVE_LSTAT
- /* Don't accept a symbolic link, its a security risk. */
- && mch_lstat((char *)name, &sb) < 0
-#endif
- )
+ // Don't accept a symbolic link, its a security risk.
+ FileInfo file_info;
+ bool file_or_link_found = os_get_file_info_link((char *)name, &file_info);
+ if (!file_or_link_found) {
break;
+ }
free(name);
}
return name;
diff --git a/src/spell.c b/src/spell.c
index 5ee799ebf1..5392fe4a70 100644
--- a/src/spell.c
+++ b/src/spell.c
@@ -7768,7 +7768,6 @@ mkspell (
afffile_T *(afile[8]);
int i;
int len;
- struct stat st;
int error = FALSE;
spellinfo_T spin;
@@ -7832,7 +7831,7 @@ mkspell (
else {
// Check for overwriting before doing things that may take a lot of
// time.
- if (!over_write && mch_stat((char *)wfname, &st) >= 0) {
+ if (!over_write && os_file_exists(wfname)) {
EMSG(_(e_exists));
goto theend;
}
@@ -7888,7 +7887,7 @@ mkspell (
spin.si_region = 1 << i;
vim_snprintf((char *)fname, MAXPATHL, "%s.aff", innames[i]);
- if (mch_stat((char *)fname, &st) >= 0) {
+ if (os_file_exists(fname)) {
// Read the .aff file. Will init "spin->si_conv" based on the
// "SET" line.
afile[i] = spell_read_aff(&spin, fname);
diff --git a/src/tag.c b/src/tag.c
index d97eb61ab4..bfef5366d9 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -1511,12 +1511,10 @@ line_read_in:
* compute the first offset.
*/
if (state == TS_BINARY) {
- /* Get the tag file size (don't use mch_fstat(), it's not
- * portable). */
- if ((filesize = lseek(fileno(fp),
- (off_t)0L, SEEK_END)) <= 0)
+ // Get the tag file size.
+ if ((filesize = lseek(fileno(fp), (off_t)0L, SEEK_END)) <= 0) {
state = TS_LINEAR;
- else {
+ } else {
lseek(fileno(fp), (off_t)0L, SEEK_SET);
/* Calculate the first read offset in the file. Start
diff --git a/src/undo.c b/src/undo.c
index a17ba50255..47ce8ee8da 100644
--- a/src/undo.c
+++ b/src/undo.c
@@ -675,7 +675,6 @@ char_u *u_get_undo_file_name(char_u *buf_ffname, int reading)
char_u *undo_file_name = NULL;
int dir_len;
char_u *p;
- struct stat st;
char_u *ffname = buf_ffname;
#ifdef HAVE_READLINK
char_u fname_buf[MAXPATHL];
@@ -723,7 +722,7 @@ char_u *u_get_undo_file_name(char_u *buf_ffname, int reading)
// When reading check if the file exists.
if (undo_file_name != NULL &&
- (!reading || mch_stat((char *)undo_file_name, &st) >= 0)) {
+ (!reading || os_file_exists(undo_file_name))) {
break;
}
free(undo_file_name);
@@ -1107,11 +1106,6 @@ void u_write_undo(char_u *name, int forceit, buf_T *buf, char_u *hash)
FILE *fp = NULL;
int perm;
int write_ok = FALSE;
-#ifdef UNIX
- int st_old_valid = FALSE;
- struct stat st_old;
- struct stat st_new;
-#endif
int do_crypt = FALSE;
if (name == NULL) {
@@ -1135,16 +1129,10 @@ void u_write_undo(char_u *name, int forceit, buf_T *buf, char_u *hash)
*/
perm = 0600;
if (buf->b_ffname != NULL) {
-#ifdef UNIX
- if (mch_stat((char *)buf->b_ffname, &st_old) >= 0) {
- perm = st_old.st_mode;
- st_old_valid = TRUE;
- }
-#else
perm = os_getperm(buf->b_ffname);
- if (perm < 0)
+ if (perm < 0) {
perm = 0600;
-#endif
+ }
}
/* strip any s-bit */
@@ -1223,14 +1211,17 @@ void u_write_undo(char_u *name, int forceit, buf_T *buf, char_u *hash)
* this fails, set the protection bits for the group same as the
* protection bits for others.
*/
- if (st_old_valid
- && mch_stat((char *)file_name, &st_new) >= 0
- && st_new.st_gid != st_old.st_gid
+ FileInfo file_info_old;
+ FileInfo file_info_new;
+ if (os_get_file_info((char *)buf->b_ffname, &file_info_old)
+ && os_get_file_info((char *)file_name, &file_info_new)
+ && file_info_old.stat.st_gid != file_info_new.stat.st_gid
# ifdef HAVE_FCHOWN /* sequent-ptx lacks fchown() */
- && fchown(fd, (uid_t)-1, st_old.st_gid) != 0
+ && fchown(fd, (uid_t)-1, file_info_old.stat.st_gid) != 0
# endif
- )
+ ) {
os_setperm(file_name, (perm & 0707) | ((perm & 07) << 3));
+ }
# ifdef HAVE_SELINUX
if (buf->b_ffname != NULL)
mch_copy_sec(buf->b_ffname, file_name);
@@ -1351,10 +1342,6 @@ void u_read_undo(char_u *name, char_u *hash, char_u *orig_name)
#ifdef U_DEBUG
int *uhp_table_used;
#endif
-#ifdef UNIX
- struct stat st_orig;
- struct stat st_undo;
-#endif
int do_decrypt = FALSE;
if (name == NULL) {
@@ -1365,10 +1352,12 @@ void u_read_undo(char_u *name, char_u *hash, char_u *orig_name)
#ifdef UNIX
/* For safety we only read an undo file if the owner is equal to the
* owner of the text file or equal to the current user. */
- if (mch_stat((char *)orig_name, &st_orig) >= 0
- && mch_stat((char *)file_name, &st_undo) >= 0
- && st_orig.st_uid != st_undo.st_uid
- && st_undo.st_uid != getuid()) {
+ FileInfo file_info_orig;
+ FileInfo file_info_undo;
+ if (os_get_file_info((char *)orig_name, &file_info_orig)
+ && os_get_file_info((char *)file_name, &file_info_undo)
+ && file_info_orig.stat.st_uid != file_info_undo.stat.st_uid
+ && file_info_undo.stat.st_uid != getuid()) {
if (p_verbose > 0) {
verbose_enter();
smsg((char_u *)_("Not reading undo file, owner differs: %s"),
diff --git a/test/unit/os/fs.moon b/test/unit/os/fs.moon
index c1ab4bd78a..b11e2515bd 100644
--- a/test/unit/os/fs.moon
+++ b/test/unit/os/fs.moon
@@ -14,6 +14,8 @@ describe 'fs function', ->
setup ->
lfs.mkdir 'unit-test-directory'
(io.open 'unit-test-directory/test.file', 'w').close!
+ (io.open 'unit-test-directory/test_2.file', 'w').close!
+ lfs.link 'test.file', 'unit-test-directory/test_link.file', true
-- Since the tests are executed, they are called by an executable. We use
-- that executable for several asserts.
@@ -25,6 +27,8 @@ describe 'fs function', ->
teardown ->
os.remove 'unit-test-directory/test.file'
+ os.remove 'unit-test-directory/test_2.file'
+ os.remove 'unit-test-directory/test_link.file'
lfs.rmdir 'unit-test-directory'
describe 'os_dirname', ->
@@ -213,6 +217,12 @@ describe 'fs function', ->
eq 2, os_file_is_writable 'unit-test-directory'
describe 'file operations', ->
+ setup ->
+ (io.open 'unit-test-directory/test_remove.file', 'w').close!
+
+ teardown ->
+ os.remove 'unit-test-directory/test_remove.file'
+
os_file_exists = (filename) ->
fs.os_file_exists (to_cstr filename)
@@ -261,9 +271,9 @@ describe 'fs function', ->
neq 0, (os_remove 'non-existing-file')
it 'removes the given file and returns 0', ->
- eq true, (os_file_exists 'unit-test-directory/test.file')
- eq 0, (os_remove 'unit-test-directory/test.file')
- eq false, (os_file_exists 'unit-test-directory/test.file')
+ eq true, (os_file_exists 'unit-test-directory/test_remove.file')
+ eq 0, (os_remove 'unit-test-directory/test_remove.file')
+ eq false, (os_file_exists 'unit-test-directory/test_remove.file')
describe 'folder operations', ->
os_mkdir = (path, mode) ->
@@ -293,3 +303,92 @@ describe 'fs function', ->
eq 0, (os_rmdir 'unit-test-directory/new-dir', mode)
eq false, (os_isdir 'unit-test-directory/new-dir')
+ describe 'FileInfo', ->
+
+ file_info_new = () ->
+ file_info = ffi.new 'FileInfo[1]'
+ file_info[0].stat.st_ino = 0
+ file_info[0].stat.st_dev = 0
+ file_info
+
+ is_file_info_filled = (file_info) ->
+ file_info[0].stat.st_ino > 0 and file_info[0].stat.st_dev > 0
+
+ describe 'os_get_file_info', ->
+ it 'returns false if given an non-existing file', ->
+ file_info = file_info_new!
+ assert.is_false (fs.os_get_file_info '/non-existent', file_info)
+
+ it 'returns true if given an existing file and fills file_info', ->
+ file_info = file_info_new!
+ path = 'unit-test-directory/test.file'
+ assert.is_true (fs.os_get_file_info path, file_info)
+ assert.is_true (is_file_info_filled file_info)
+
+ it 'returns the file info of the linked file, not the link', ->
+ file_info = file_info_new!
+ path = 'unit-test-directory/test_link.file'
+ assert.is_true (fs.os_get_file_info path, file_info)
+ assert.is_true (is_file_info_filled file_info)
+ mode = tonumber file_info[0].stat.st_mode
+ eq ffi.C.kS_IFREG, (bit.band mode, ffi.C.kS_IFMT)
+
+ describe 'os_get_file_info_link', ->
+ it 'returns false if given an non-existing file', ->
+ file_info = file_info_new!
+ assert.is_false (fs.os_get_file_info_link '/non-existent', file_info)
+
+ it 'returns true if given an existing file and fills file_info', ->
+ file_info = file_info_new!
+ path = 'unit-test-directory/test.file'
+ assert.is_true (fs.os_get_file_info_link path, file_info)
+ assert.is_true (is_file_info_filled file_info)
+
+ it 'returns the file info of the link, not the linked file', ->
+ file_info = file_info_new!
+ path = 'unit-test-directory/test_link.file'
+ assert.is_true (fs.os_get_file_info_link path, file_info)
+ assert.is_true (is_file_info_filled file_info)
+ mode = tonumber file_info[0].stat.st_mode
+ eq ffi.C.kS_IFLNK, (bit.band mode, ffi.C.kS_IFMT)
+
+ describe 'os_get_file_info_fd', ->
+ it 'returns false if given an invalid file descriptor', ->
+ file_info = file_info_new!
+ assert.is_false (fs.os_get_file_info_fd -1, file_info)
+
+ it 'returns true if given an file descriptor and fills file_info', ->
+ file_info = file_info_new!
+ path = 'unit-test-directory/test.file'
+ fd = ffi.C.open path, 0
+ assert.is_true (fs.os_get_file_info_fd fd, file_info)
+ assert.is_true (is_file_info_filled file_info)
+ ffi.C.close fd
+
+ describe 'os_file_info_id_equal', ->
+ it 'returns false if file infos represent different files', ->
+ file_info_1 = file_info_new!
+ file_info_2 = file_info_new!
+ path_1 = 'unit-test-directory/test.file'
+ path_2 = 'unit-test-directory/test_2.file'
+ assert.is_true (fs.os_get_file_info path_1, file_info_1)
+ assert.is_true (fs.os_get_file_info path_2, file_info_2)
+ assert.is_false (fs.os_file_info_id_equal file_info_1, file_info_2)
+
+ it 'returns true if file infos represent the same file', ->
+ file_info_1 = file_info_new!
+ file_info_2 = file_info_new!
+ path = 'unit-test-directory/test.file'
+ assert.is_true (fs.os_get_file_info path, file_info_1)
+ assert.is_true (fs.os_get_file_info path, file_info_2)
+ assert.is_true (fs.os_file_info_id_equal file_info_1, file_info_2)
+
+ it 'returns true if file infos represent the same file (symlink)', ->
+ file_info_1 = file_info_new!
+ file_info_2 = file_info_new!
+ path_1 = 'unit-test-directory/test.file'
+ path_2 = 'unit-test-directory/test_link.file'
+ assert.is_true (fs.os_get_file_info path_1, file_info_1)
+ assert.is_true (fs.os_get_file_info path_2, file_info_2)
+ assert.is_true (fs.os_file_info_id_equal file_info_1, file_info_2)
+