Merge pull request #619 from stefan991/mch_stat-cleanup

Replace `struct stat` with `FileInfo`
This commit is contained in:
Justin M. Keyes 2014-05-09 15:33:00 -04:00
commit 1a3ee71de2
25 changed files with 579 additions and 642 deletions

View File

@ -65,6 +65,10 @@
#include "ui.h" #include "ui.h"
#include "undo.h" #include "undo.h"
#include "window.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); static char_u *buflist_match(regprog_T *prog, buf_T *buf);
# define HAVE_BUFLIST_MATCH # 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, static void buflist_setfpos(buf_T *buf, win_T *win, linenr_T lnum,
colnr_T col, int copy_options); colnr_T col, int copy_options);
static wininfo_T *find_wininfo(buf_T *buf, int skip_diff_buffer); static wininfo_T *find_wininfo(buf_T *buf, int skip_diff_buffer);
#ifdef UNIX static buf_T *buflist_findname_file_info(char_u *ffname, FileInfo *file_info);
static buf_T *buflist_findname_stat(char_u *ffname, struct stat *st); static int otherfile_buf(buf_T *buf, char_u *ffname, FileInfo *file_info);
static int otherfile_buf(buf_T *buf, char_u *ffname, struct stat *stp); static int buf_same_ino(buf_T *buf, FileInfo *file_info);
static int buf_same_ino(buf_T *buf, struct stat *stp);
#else
static int otherfile_buf(buf_T *buf, char_u *ffname);
#endif
static int ti_change(char_u *str, char_u **last); 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 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(buf_T *);
static void free_buffer_stuff(buf_T *buf, int free_options); static void free_buffer_stuff(buf_T *buf, int free_options);
static void clear_wininfo(buf_T *buf); 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 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]"); static char *msg_loclist = N_("[Location List]");
@ -1304,29 +1298,20 @@ buflist_new (
) )
{ {
buf_T *buf; buf_T *buf;
#ifdef UNIX
struct stat st;
#endif
fname_expand(curbuf, &ffname, &sfname); /* will allocate ffname */ fname_expand(curbuf, &ffname, &sfname); /* will allocate ffname */
/* /*
* If file name already exists in the list, update the entry. * If file name already exists in the list, update the entry.
*/ */
#ifdef UNIX /* We can use inode numbers when the file exists. Works better
/* On Unix we can use inode numbers when the file exists. Works better
* for hard links. */ * for hard links. */
if (sfname == NULL || mch_stat((char *)sfname, &st) < 0) FileInfo file_info;
st.st_dev = (dev_T)-1; if (sfname == NULL || !os_get_file_info((char *)sfname, &file_info)) {
#endif file_info.stat.st_dev = INVALID_DEVICE_ID;
if (ffname != NULL && !(flags & BLN_DUMMY) && (buf = }
#ifdef UNIX if (ffname != NULL && !(flags & BLN_DUMMY)
buflist_findname_stat(ffname, && (buf = buflist_findname_file_info(ffname, &file_info)) != NULL) {
&st)
#else
buflist_findname(ffname)
#endif
) != NULL) {
free(ffname); free(ffname);
if (lnum != 0) if (lnum != 0)
buflist_setfpos(buf, curwin, lnum, (colnr_T)0, FALSE); buflist_setfpos(buf, curwin, lnum, (colnr_T)0, FALSE);
@ -1452,15 +1437,13 @@ buflist_new (
hash_init(&buf->b_s.b_keywtab_ic); hash_init(&buf->b_s.b_keywtab_ic);
buf->b_fname = buf->b_sfname; buf->b_fname = buf->b_sfname;
#ifdef UNIX if (file_info.stat.st_dev == INVALID_DEVICE_ID)
if (st.st_dev == (dev_T)-1)
buf->b_dev_valid = FALSE; buf->b_dev_valid = FALSE;
else { else {
buf->b_dev_valid = TRUE; buf->b_dev_valid = TRUE;
buf->b_dev = st.st_dev; buf->b_dev = file_info.stat.st_dev;
buf->b_ino = st.st_ino; buf->b_ino = file_info.stat.st_ino;
} }
#endif
buf->b_u_synced = TRUE; buf->b_u_synced = TRUE;
buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED; buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED;
if (flags & BLN_DUMMY) if (flags & BLN_DUMMY)
@ -1682,31 +1665,28 @@ buf_T *buflist_findname_exp(char_u *fname)
*/ */
buf_T *buflist_findname(char_u *ffname) buf_T *buflist_findname(char_u *ffname)
{ {
#ifdef UNIX FileInfo file_info;
struct stat st; if (!os_get_file_info((char *)ffname, &file_info)) {
file_info.stat.st_dev = INVALID_DEVICE_ID;
if (mch_stat((char *)ffname, &st) < 0) }
st.st_dev = (dev_T)-1; return buflist_findname_file_info(ffname, &file_info);
return buflist_findname_stat(ffname, &st);
} }
/* /*
* Same as buflist_findname(), but pass the stat structure to avoid getting it * Same as buflist_findname(), but pass the FileInfo structure to avoid
* twice for the same file. * getting it twice for the same file.
* Returns NULL if not found. * 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; buf_T *buf;
for (buf = firstbuf; buf != NULL; buf = buf->b_next) for (buf = firstbuf; buf != NULL; buf = buf->b_next) {
if ((buf->b_flags & BF_DUMMY) == 0 && !otherfile_buf(buf, ffname if ((buf->b_flags & BF_DUMMY) == 0
#ifdef UNIX && !otherfile_buf(buf, ffname, file_info)) {
, stp
#endif
))
return buf; return buf;
}
}
return NULL; return NULL;
} }
@ -2220,9 +2200,7 @@ setfname (
) )
{ {
buf_T *obuf = NULL; buf_T *obuf = NULL;
#ifdef UNIX FileInfo file_info;
struct stat st;
#endif
if (ffname == NULL || *ffname == NUL) { if (ffname == NULL || *ffname == NUL) {
/* Removing the name. */ /* Removing the name. */
@ -2230,9 +2208,7 @@ setfname (
free(buf->b_sfname); free(buf->b_sfname);
buf->b_ffname = NULL; buf->b_ffname = NULL;
buf->b_sfname = NULL; buf->b_sfname = NULL;
#ifdef UNIX file_info.stat.st_dev = INVALID_DEVICE_ID;
st.st_dev = (dev_T)-1;
#endif
} else { } else {
fname_expand(buf, &ffname, &sfname); /* will allocate ffname */ fname_expand(buf, &ffname, &sfname); /* will allocate ffname */
if (ffname == NULL) /* out of memory */ if (ffname == NULL) /* out of memory */
@ -2243,16 +2219,12 @@ setfname (
* - if the buffer is loaded, fail * - if the buffer is loaded, fail
* - if the buffer is not loaded, delete it from the list * - if the buffer is not loaded, delete it from the list
*/ */
#ifdef UNIX if (!os_get_file_info((char *)ffname, &file_info)) {
if (mch_stat((char *)ffname, &st) < 0) file_info.stat.st_dev = INVALID_DEVICE_ID;
st.st_dev = (dev_T)-1; }
#endif if (!(buf->b_flags & BF_DUMMY)) {
if (!(buf->b_flags & BF_DUMMY)) obuf = buflist_findname_file_info(ffname, &file_info);
#ifdef UNIX }
obuf = buflist_findname_stat(ffname, &st);
#else
obuf = buflist_findname(ffname);
#endif
if (obuf != NULL && obuf != buf) { if (obuf != NULL && obuf != buf) {
if (obuf->b_ml.ml_mfp != NULL) { /* it's loaded, fail */ if (obuf->b_ml.ml_mfp != NULL) { /* it's loaded, fail */
if (message) if (message)
@ -2278,15 +2250,13 @@ setfname (
buf->b_sfname = sfname; buf->b_sfname = sfname;
} }
buf->b_fname = buf->b_sfname; buf->b_fname = buf->b_sfname;
#ifdef UNIX if (file_info.stat.st_dev == INVALID_DEVICE_ID) {
if (st.st_dev == (dev_T)-1)
buf->b_dev_valid = FALSE; buf->b_dev_valid = FALSE;
else { } else {
buf->b_dev_valid = TRUE; buf->b_dev_valid = TRUE;
buf->b_dev = st.st_dev; buf->b_dev = file_info.stat.st_dev;
buf->b_ino = st.st_ino; buf->b_ino = file_info.stat.st_ino;
} }
#endif
buf_name_changed(buf); buf_name_changed(buf);
return OK; return OK;
@ -2419,80 +2389,72 @@ void buflist_altfpos(win_T *win)
*/ */
int otherfile(char_u *ffname) int otherfile(char_u *ffname)
{ {
return otherfile_buf(curbuf, ffname return otherfile_buf(curbuf, ffname, NULL);
#ifdef UNIX
, NULL
#endif
);
} }
static int otherfile_buf(buf_T *buf, char_u *ffname static int otherfile_buf(buf_T *buf, char_u *ffname, FileInfo *file_info_p)
#ifdef UNIX
, struct stat *stp
#endif
)
{ {
/* no name is different */ /* no name is different */
if (ffname == NULL || *ffname == NUL || buf->b_ffname == NULL) if (ffname == NULL || *ffname == NUL || buf->b_ffname == NULL) {
return TRUE; return TRUE;
if (fnamecmp(ffname, buf->b_ffname) == 0) }
if (fnamecmp(ffname, buf->b_ffname) == 0) {
return FALSE; return FALSE;
#ifdef UNIX }
{ {
struct stat st; FileInfo file_info;
/* If no struct stat given, get it now */ /* If no struct stat given, get it now */
if (stp == NULL) { if (file_info_p == NULL) {
if (!buf->b_dev_valid || mch_stat((char *)ffname, &st) < 0) if (!buf->b_dev_valid || !os_get_file_info((char *)ffname, &file_info)) {
st.st_dev = (dev_T)-1; file_info.stat.st_dev = INVALID_DEVICE_ID;
stp = &st; }
file_info_p = &file_info;
} }
/* Use dev/ino to check if the files are the same, even when the names /* 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 * are different (possible with links). Still need to compare the
* name above, for when the file doesn't exist yet. * name above, for when the file doesn't exist yet.
* Problem: The dev/ino changes when a file is deleted (and created * 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 * 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 * 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 * to be different: Could skip a buffer when it's actually the same
* file. */ * file. */
if (buf_same_ino(buf, stp)) { if (buf_same_ino(buf, file_info_p)) {
buf_setino(buf); buf_setino(buf);
if (buf_same_ino(buf, stp)) if (buf_same_ino(buf, file_info_p))
return FALSE; return FALSE;
} }
} }
#endif
return TRUE; return TRUE;
} }
#if defined(UNIX) || defined(PROTO)
/* /*
* Set inode and device number for a buffer. * Set inode and device number for a buffer.
* Must always be called when b_fname is changed!. * Must always be called when b_fname is changed!.
*/ */
void buf_setino(buf_T *buf) void buf_setino(buf_T *buf)
{ {
struct stat st; FileInfo file_info;
if (buf->b_fname != NULL
if (buf->b_fname != NULL && mch_stat((char *)buf->b_fname, &st) >= 0) { && os_get_file_info((char *)buf->b_fname, &file_info)) {
buf->b_dev_valid = TRUE; buf->b_dev_valid = TRUE;
buf->b_dev = st.st_dev; buf->b_dev = file_info.stat.st_dev;
buf->b_ino = st.st_ino; buf->b_ino = file_info.stat.st_ino;
} else } else {
buf->b_dev_valid = FALSE; buf->b_dev_valid = FALSE;
}
} }
/* /*
* Return TRUE if dev/ino in buffer "buf" matches with "stp". * 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 return buf->b_dev_valid
&& stp->st_dev == buf->b_dev && file_info->stat.st_dev == buf->b_dev
&& stp->st_ino == buf->b_ino; && file_info->stat.st_ino == buf->b_ino;
} }
#endif
/* /*
* Print info about the current buffer. * Print info about the current buffer.

View File

@ -423,11 +423,9 @@ struct file_buffer {
char_u *b_sfname; /* short file name */ char_u *b_sfname; /* short file name */
char_u *b_fname; /* current file name */ char_u *b_fname; /* current file name */
#ifdef UNIX
int b_dev_valid; /* TRUE when b_dev has a valid number */ int b_dev_valid; /* TRUE when b_dev has a valid number */
dev_t b_dev; /* device number */ uint64_t b_dev; /* device number */
ino_t b_ino; /* inode number */ uint64_t b_ino; /* inode number */
#endif
int b_fnum; /* buffer number for this file. */ int b_fnum; /* buffer number for this file. */

View File

@ -863,8 +863,6 @@ void ex_diffpatch(exarg_T *eap)
char_u dirbuf[MAXPATHL]; char_u dirbuf[MAXPATHL];
char_u *fullname = NULL; char_u *fullname = NULL;
#endif // ifdef UNIX #endif // ifdef UNIX
struct stat st;
// We need two temp file names. // We need two temp file names.
// Name of original temp file. // Name of original temp file.
char_u *tmp_orig = vim_tempname('o'); char_u *tmp_orig = vim_tempname('o');
@ -965,7 +963,9 @@ void ex_diffpatch(exarg_T *eap)
os_remove((char *)buf); os_remove((char *)buf);
// Only continue if the output file was created. // 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")); EMSG(_("E816: Cannot read patch output"));
} else { } else {
if (curbuf->b_fname != NULL) { if (curbuf->b_fname != NULL) {

View File

@ -9664,24 +9664,21 @@ static void f_getfontname(typval_T *argvars, typval_T *rettv)
*/ */
static void f_getfperm(typval_T *argvars, typval_T *rettv) static void f_getfperm(typval_T *argvars, typval_T *rettv)
{ {
char_u *fname; char_u *perm = NULL;
struct stat st;
char_u *perm = NULL;
char_u flags[] = "rwx"; char_u flags[] = "rwx";
int i;
fname = get_tv_string(&argvars[0]); char_u *filename = get_tv_string(&argvars[0]);
int32_t file_perm = os_getperm(filename);
rettv->v_type = VAR_STRING; if (file_perm >= 0) {
if (mch_stat((char *)fname, &st) >= 0) {
perm = vim_strsave((char_u *)"---------"); perm = vim_strsave((char_u *)"---------");
if (perm != NULL) { if (perm != NULL) {
for (i = 0; i < 9; i++) { for (int i = 0; i < 9; i++) {
if (st.st_mode & (1 << (8 - i))) if (file_perm & (1 << (8 - i)))
perm[i] = flags[i % 3]; perm[i] = flags[i % 3];
} }
} }
} }
rettv->v_type = VAR_STRING;
rettv->vval.v_string = perm; 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) static void f_getfsize(typval_T *argvars, typval_T *rettv)
{ {
char_u *fname; char *fname = (char *)get_tv_string(&argvars[0]);
struct stat st;
fname = get_tv_string(&argvars[0]);
rettv->v_type = VAR_NUMBER; rettv->v_type = VAR_NUMBER;
if (mch_stat((char *)fname, &st) >= 0) { off_t file_size;
if (os_isdir(fname)) if (os_get_file_size(fname, &file_size)) {
if (os_isdir((char_u *)fname))
rettv->vval.v_number = 0; rettv->vval.v_number = 0;
else { else {
rettv->vval.v_number = (varnumber_T)st.st_size; rettv->vval.v_number = (varnumber_T)file_size;
/* non-perfect check for overflow */ /* 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; rettv->vval.v_number = -2;
}
} }
} else } else {
rettv->vval.v_number = -1; 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) static void f_getftime(typval_T *argvars, typval_T *rettv)
{ {
char_u *fname; char *fname = (char *)get_tv_string(&argvars[0]);
struct stat st;
fname = get_tv_string(&argvars[0]); FileInfo file_info;
if (os_get_file_info(fname, &file_info)) {
if (mch_stat((char *)fname, &st) >= 0) rettv->vval.v_number = (varnumber_T)file_info.stat.st_mtim.tv_sec;
rettv->vval.v_number = (varnumber_T)st.st_mtime; } else {
else
rettv->vval.v_number = -1; 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) static void f_getftype(typval_T *argvars, typval_T *rettv)
{ {
char_u *fname; char_u *fname;
struct stat st;
char_u *type = NULL; char_u *type = NULL;
char *t; char *t;
fname = get_tv_string(&argvars[0]); fname = get_tv_string(&argvars[0]);
rettv->v_type = VAR_STRING; 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 #ifdef S_ISREG
if (S_ISREG(st.st_mode)) if (S_ISREG(mode))
t = "file"; t = "file";
else if (S_ISDIR(st.st_mode)) else if (S_ISDIR(mode))
t = "dir"; t = "dir";
# ifdef S_ISLNK # ifdef S_ISLNK
else if (S_ISLNK(st.st_mode)) else if (S_ISLNK(mode))
t = "link"; t = "link";
# endif # endif
# ifdef S_ISBLK # ifdef S_ISBLK
else if (S_ISBLK(st.st_mode)) else if (S_ISBLK(mode))
t = "bdev"; t = "bdev";
# endif # endif
# ifdef S_ISCHR # ifdef S_ISCHR
else if (S_ISCHR(st.st_mode)) else if (S_ISCHR(mode))
t = "cdev"; t = "cdev";
# endif # endif
# ifdef S_ISFIFO # ifdef S_ISFIFO
else if (S_ISFIFO(st.st_mode)) else if (S_ISFIFO(mode))
t = "fifo"; t = "fifo";
# endif # endif
# ifdef S_ISSOCK # ifdef S_ISSOCK
else if (S_ISSOCK(st.st_mode)) else if (S_ISSOCK(mode))
t = "fifo"; t = "fifo";
# endif # endif
else else
t = "other"; t = "other";
#else #else
# ifdef S_IFMT # ifdef S_IFMT
switch (st.st_mode & S_IFMT) { switch (mode & S_IFMT) {
case S_IFREG: t = "file"; break; case S_IFREG: t = "file"; break;
case S_IFDIR: t = "dir"; break; case S_IFDIR: t = "dir"; break;
# ifdef S_IFLNK # ifdef S_IFLNK

View File

@ -1492,14 +1492,10 @@ void write_viminfo(char_u *file, int forceit)
FILE *fp_in = NULL; /* input viminfo file, if any */ FILE *fp_in = NULL; /* input viminfo file, if any */
FILE *fp_out = NULL; /* output viminfo file */ FILE *fp_out = NULL; /* output viminfo file */
char_u *tempname = NULL; /* name of temp viminfo file */ char_u *tempname = NULL; /* name of temp viminfo file */
struct stat st_new; /* mch_stat() of potential new file */
char_u *wp; char_u *wp;
#if defined(UNIX) #if defined(UNIX)
mode_t umask_save; mode_t umask_save;
#endif #endif
#ifdef UNIX
struct stat st_old; /* mch_stat() of existing viminfo file */
#endif
if (no_viminfo()) if (no_viminfo())
return; return;
@ -1511,7 +1507,7 @@ void write_viminfo(char_u *file, int forceit)
fp_in = mch_fopen((char *)fname, READBIN); fp_in = mch_fopen((char *)fname, READBIN);
if (fp_in == NULL) { if (fp_in == NULL) {
/* if it does exist, but we can't read it, don't try writing */ /* 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; goto end;
#if defined(UNIX) #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 * overwrite a user's viminfo file after a "su root", with a
* viminfo file that the user can't read. * viminfo file that the user can't read.
*/ */
st_old.st_dev = (dev_t)0;
st_old.st_ino = 0; FileInfo old_info; // FileInfo of existing viminfo file
st_old.st_mode = 0600; if (os_get_file_info((char *)fname, &old_info)
if (mch_stat((char *)fname, &st_old) == 0
&& getuid() != ROOT_UID && getuid() != ROOT_UID
&& !(st_old.st_uid == getuid() && !(old_info.stat.st_uid == getuid()
? (st_old.st_mode & 0200) ? (old_info.stat.st_mode & 0200)
: (st_old.st_gid == getgid() : (old_info.stat.st_gid == getgid()
? (st_old.st_mode & 0020) ? (old_info.stat.st_mode & 0020)
: (st_old.st_mode & 0002)))) { : (old_info.stat.st_mode & 0002)))) {
int tt = msg_didany; int tt = msg_didany;
/* avoid a wait_return for this message, it's annoying */ /* 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 * Check if tempfile already exists. Never overwrite an
* existing file! * existing file!
*/ */
if (mch_stat((char *)tempname, &st_new) == 0) { if (os_file_exists(tempname)) {
/* /*
* Try another name. Change one character, just before * Try another name. Change one character, just before
* the extension. * the extension.
@ -1571,8 +1566,7 @@ void write_viminfo(char_u *file, int forceit)
wp = tempname + STRLEN(tempname) - 5; wp = tempname + STRLEN(tempname) - 5;
if (wp < path_tail(tempname)) /* empty file name? */ if (wp < path_tail(tempname)) /* empty file name? */
wp = path_tail(tempname); wp = path_tail(tempname);
for (*wp = 'z'; mch_stat((char *)tempname, &st_new) == 0; for (*wp = 'z'; os_file_exists(tempname); --*wp) {
--*wp) {
/* /*
* They all exist? Must be something wrong! Don't * They all exist? Must be something wrong! Don't
* write the viminfo file then. * write the viminfo file then.
@ -1598,7 +1592,7 @@ void write_viminfo(char_u *file, int forceit)
umask_save = umask(0); umask_save = umask(0);
fd = mch_open((char *)tempname, fd = mch_open((char *)tempname,
O_CREAT|O_EXCL|O_WRONLY|O_NOFOLLOW, 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); (void)umask(umask_save);
# else # else
fd = mch_open((char *)tempname, 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 * Make sure the owner can read/write it. This only works for
* root. * root.
*/ */
if (fp_out != NULL) if (fp_out != NULL) {
ignored = fchown(fileno(fp_out), st_old.st_uid, st_old.st_gid); fchown(fileno(fp_out), old_info.stat.st_uid, old_info.stat.st_gid);
}
#endif #endif
} }
} }

View File

@ -48,15 +48,13 @@
static void cmd_source(char_u *fname, exarg_T *eap); static void cmd_source(char_u *fname, exarg_T *eap);
/* Growarray to store info about already sourced scripts. /* 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. */ * script when going through the list. */
typedef struct scriptitem_S { typedef struct scriptitem_S {
char_u *sn_name; char_u *sn_name;
# ifdef UNIX
int sn_dev_valid; int sn_dev_valid;
dev_t sn_dev; uint64_t sn_dev;
ino_t sn_ino; uint64_t sn_ino;
# endif
int sn_prof_on; /* TRUE when script is/was profiled */ int sn_prof_on; /* TRUE when script is/was profiled */
int sn_pr_force; /* forceit: profile functions in this script */ int sn_pr_force; /* forceit: profile functions in this script */
proftime_T sn_pr_child; /* time set when going into first child */ proftime_T sn_pr_child; /* time set when going into first child */
@ -2458,10 +2456,6 @@ do_source (
void *save_funccalp; void *save_funccalp;
int save_debug_break_level = debug_break_level; int save_debug_break_level = debug_break_level;
scriptitem_T *si = NULL; scriptitem_T *si = NULL;
# ifdef UNIX
struct stat st;
int stat_ok;
# endif
#ifdef STARTUPTIME #ifdef STARTUPTIME
struct timeval tv_rel; struct timeval tv_rel;
struct timeval tv_start; struct timeval tv_start;
@ -2622,23 +2616,19 @@ do_source (
* If it's new, generate a new SID. * If it's new, generate a new SID.
*/ */
save_current_SID = current_SID; save_current_SID = current_SID;
# ifdef UNIX FileInfo file_info;
stat_ok = (mch_stat((char *)fname_exp, &st) >= 0); bool file_info_ok = os_get_file_info((char *)fname_exp, &file_info);
# endif
for (current_SID = script_items.ga_len; current_SID > 0; --current_SID) { for (current_SID = script_items.ga_len; current_SID > 0; --current_SID) {
si = &SCRIPT_ITEM(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 if (si->sn_name != NULL
&& ( && (file_id_equal || fnamecmp(si->sn_name, fname_exp) == 0)) {
# 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))
break; break;
}
} }
if (current_SID == 0) { if (current_SID == 0) {
current_SID = ++last_current_SID; current_SID = ++last_current_SID;
@ -2651,14 +2641,13 @@ do_source (
si = &SCRIPT_ITEM(current_SID); si = &SCRIPT_ITEM(current_SID);
si->sn_name = fname_exp; si->sn_name = fname_exp;
fname_exp = NULL; fname_exp = NULL;
# ifdef UNIX if (file_info_ok) {
if (stat_ok) {
si->sn_dev_valid = TRUE; si->sn_dev_valid = TRUE;
si->sn_dev = st.st_dev; si->sn_dev = file_info.stat.st_dev;
si->sn_ino = st.st_ino; si->sn_ino = file_info.stat.st_ino;
} else } else {
si->sn_dev_valid = FALSE; si->sn_dev_valid = FALSE;
# endif }
/* Allocate the local script variables to use for this script. */ /* Allocate the local script variables to use for this script. */
new_script_vars(current_SID); new_script_vars(current_SID);

View File

@ -110,11 +110,9 @@ typedef struct ff_visited {
/* for unix use inode etc for comparison (needed because of links), else /* for unix use inode etc for comparison (needed because of links), else
* use filename. * use filename.
*/ */
#ifdef UNIX
int ffv_dev_valid; /* ffv_dev and ffv_ino were set */ int ffv_dev_valid; /* ffv_dev and ffv_ino were set */
dev_t ffv_dev; /* device number */ uint64_t ffv_dev; /* device number */
ino_t ffv_ino; /* inode number */ uint64_t ffv_ino; /* inode number */
#endif
/* The memory for this struct is allocated according to the length of /* The memory for this struct is allocated according to the length of
* ffv_fname. * 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) static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u *wc_path)
{ {
ff_visited_T *vp; ff_visited_T *vp;
#ifdef UNIX bool url = false;
struct stat st;
int url = FALSE;
#endif
/* For an URL we only compare the name, otherwise we compare the FileInfo file_info;
* device/inode (unix) or the full path name (not Unix). */ // For an URL we only compare the name, otherwise we compare the
// device/inode.
if (path_with_url(fname)) { if (path_with_url(fname)) {
vim_strncpy(ff_expand_buffer, fname, MAXPATHL - 1); vim_strncpy(ff_expand_buffer, fname, MAXPATHL - 1);
#ifdef UNIX url = true;
url = TRUE;
#endif
} else { } else {
ff_expand_buffer[0] = NUL; ff_expand_buffer[0] = NUL;
#ifdef UNIX if (!os_get_file_info((char *)fname, &file_info)) {
if (mch_stat((char *)fname, &st) < 0)
#else
if (vim_FullName(fname, ff_expand_buffer, MAXPATHL, TRUE) == FAIL)
#endif
return FAIL; return FAIL;
}
} }
/* check against list of already visited files */ /* check against list of already visited files */
for (vp = *visited_list; vp != NULL; vp = vp->ffv_next) { for (vp = *visited_list; vp != NULL; vp = vp->ffv_next) {
if ( if ((url && fnamecmp(vp->ffv_fname, ff_expand_buffer) == 0)
#ifdef UNIX || (!url && vp->ffv_dev_valid
!url ? (vp->ffv_dev_valid && vp->ffv_dev == st.st_dev && vp->ffv_dev == file_info.stat.st_dev
&& vp->ffv_ino == st.st_ino) && vp->ffv_ino == file_info.stat.st_ino)) {
:
#endif
fnamecmp(vp->ffv_fname, ff_expand_buffer) == 0
) {
/* are the wildcard parts equal */ /* are the wildcard parts equal */
if (ff_wc_equal(vp->ffv_wc_path, wc_path) == TRUE) if (ff_wc_equal(vp->ffv_wc_path, wc_path) == TRUE)
/* already visited */ /* 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) vp = (ff_visited_T *)alloc((unsigned)(sizeof(ff_visited_T)
+ STRLEN(ff_expand_buffer))); + STRLEN(ff_expand_buffer)));
#ifdef UNIX
if (!url) { if (!url) {
vp->ffv_dev_valid = TRUE; vp->ffv_dev_valid = TRUE;
vp->ffv_ino = st.st_ino; vp->ffv_ino = file_info.stat.st_ino;
vp->ffv_dev = st.st_dev; vp->ffv_dev = file_info.stat.st_dev;
vp->ffv_fname[0] = NUL; vp->ffv_fname[0] = NUL;
} else { } else {
vp->ffv_dev_valid = FALSE; vp->ffv_dev_valid = FALSE;
STRCPY(vp->ffv_fname, ff_expand_buffer); STRCPY(vp->ffv_fname, ff_expand_buffer);
} }
#else
STRCPY(vp->ffv_fname, ff_expand_buffer);
#endif
if (wc_path != NULL) if (wc_path != NULL)
vp->ffv_wc_path = vim_strsave(wc_path); vp->ffv_wc_path = vim_strsave(wc_path);

View File

@ -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 set_rw_fname(char_u *fname, char_u *sfname);
static int msg_add_fileformat(int eol_type); static int msg_add_fileformat(int eol_type);
static void msg_add_eol(void); 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 time_differs(long t1, long t2);
static int apply_autocmds_exarg(event_T event, char_u *fname, char_u *fname_io, static int apply_autocmds_exarg(event_T event, char_u *fname, char_u *fname_io,
int force, buf_T *buf, int force, buf_T *buf,
@ -262,7 +262,6 @@ readfile (
#endif #endif
int fileformat = 0; /* end-of-line format */ int fileformat = 0; /* end-of-line format */
int keep_fileformat = FALSE; int keep_fileformat = FALSE;
struct stat st;
int file_readonly; int file_readonly;
linenr_T skip_count = 0; linenr_T skip_count = 0;
linenr_T read_count = 0; linenr_T read_count = 0;
@ -441,8 +440,9 @@ readfile (
if (newfile && !read_stdin && !read_buffer) { if (newfile && !read_stdin && !read_buffer) {
/* Remember time of file. */ /* Remember time of file. */
if (mch_stat((char *)fname, &st) >= 0) { FileInfo file_info;
buf_store_time(curbuf, &st, fname); if (os_get_file_info((char *)fname, &file_info)) {
buf_store_file_info(curbuf, &file_info, fname);
curbuf->b_mtime_read = curbuf->b_mtime; curbuf->b_mtime_read = curbuf->b_mtime;
#ifdef UNIX #ifdef UNIX
/* /*
@ -456,7 +456,7 @@ readfile (
* not be able to write to the file ourselves. * not be able to write to the file ourselves.
* Setting the bits is done below, after creating the swap file. * 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 #endif
} else { } else {
curbuf->b_mtime = 0; curbuf->b_mtime = 0;
@ -2473,7 +2473,6 @@ buf_write (
int overwriting; /* TRUE if writing over original */ int overwriting; /* TRUE if writing over original */
int no_eol = FALSE; /* no end-of-line written */ int no_eol = FALSE; /* no end-of-line written */
int device = FALSE; /* writing to a device */ int device = FALSE; /* writing to a device */
struct stat st_old;
int prev_got_int = got_int; int prev_got_int = got_int;
bool file_readonly = false; /* overwritten file is read-only */ bool file_readonly = false; /* overwritten file is read-only */
static char *err_readonly = static char *err_readonly =
@ -2774,15 +2773,14 @@ buf_write (
* Get information about original file (if there is one). * Get information about original file (if there is one).
*/ */
#if defined(UNIX) #if defined(UNIX)
st_old.st_dev = 0;
st_old.st_ino = 0;
perm = -1; 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; newfile = TRUE;
else { } else {
perm = st_old.st_mode; perm = file_info_old.stat.st_mode;
if (!S_ISREG(st_old.st_mode)) { /* not a file */ if (!S_ISREG(file_info_old.stat.st_mode)) { /* not a file */
if (S_ISDIR(st_old.st_mode)) { if (S_ISDIR(file_info_old.stat.st_mode)) {
errnum = (char_u *)"E502: "; errnum = (char_u *)"E502: ";
errmsg = (char_u *)_("is a directory"); errmsg = (char_u *)_("is a directory");
goto fail; goto fail;
@ -2822,8 +2820,10 @@ buf_write (
errmsg = (char_u *)_("is a directory"); errmsg = (char_u *)_("is a directory");
goto fail; goto fail;
} }
if (overwriting) if (overwriting) {
(void)mch_stat((char *)fname, &st_old); os_get_file_info((char *)fname, &file_info_old);
}
} }
#endif /* !UNIX */ #endif /* !UNIX */
@ -2849,7 +2849,7 @@ buf_write (
* Check if the timestamp hasn't changed since reading the file. * Check if the timestamp hasn't changed since reading the file.
*/ */
if (overwriting) { if (overwriting) {
retval = check_mtime(buf, &st_old); retval = check_mtime(buf, &file_info_old);
if (retval == FAIL) if (retval == FAIL)
goto fail; goto fail;
} }
@ -2890,14 +2890,11 @@ buf_write (
* off. This helps when editing large files on almost-full disks. * off. This helps when editing large files on almost-full disks.
*/ */
if (!(append && *p_pm == NUL) && !filtering && perm >= 0 && dobackup) { if (!(append && *p_pm == NUL) && !filtering && perm >= 0 && dobackup) {
#if defined(UNIX) || defined(WIN32) FileInfo file_info;
struct stat st;
#endif
if ((bkc_flags & BKC_YES) || append) /* "yes" */ if ((bkc_flags & BKC_YES) || append) { /* "yes" */
backup_copy = TRUE; backup_copy = TRUE;
#if defined(UNIX) || defined(WIN32) } else if ((bkc_flags & BKC_AUTO)) { /* "auto" */
else if ((bkc_flags & BKC_AUTO)) { /* "auto" */
int i; int i;
# ifdef UNIX # ifdef UNIX
@ -2908,18 +2905,16 @@ buf_write (
* - we don't have write permission in the directory * - we don't have write permission in the directory
* - we can't set the owner/group of the new file * - we can't set the owner/group of the new file
*/ */
if (st_old.st_nlink > 1 if (file_info_old.stat.st_nlink > 1
|| mch_lstat((char *)fname, &st) < 0 || !os_get_file_info_link((char *)fname, &file_info)
|| st.st_dev != st_old.st_dev || !os_file_info_id_equal(&file_info, &file_info_old)
|| st.st_ino != st_old.st_ino
# ifndef HAVE_FCHOWN # ifndef HAVE_FCHOWN
|| st.st_uid != st_old.st_uid || file_info.stat.st_uid != file_info_old.stat.st_uid
|| st.st_gid != st_old.st_gid || file_info.stat.st_gid != file_info_old.stat.st_gid
# endif # endif
) ) {
backup_copy = TRUE; backup_copy = TRUE;
else } else
# else
# endif # endif
{ {
/* /*
@ -2931,8 +2926,9 @@ buf_write (
STRCPY(IObuff, fname); STRCPY(IObuff, fname);
for (i = 4913;; i += 123) { for (i = 4913;; i += 123) {
sprintf((char *)path_tail(IObuff), "%d", i); 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; break;
}
} }
fd = mch_open((char *)IObuff, fd = mch_open((char *)IObuff,
O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, perm); O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, perm);
@ -2941,13 +2937,14 @@ buf_write (
else { else {
# ifdef UNIX # ifdef UNIX
# ifdef HAVE_FCHOWN # 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 # endif
if (mch_stat((char *)IObuff, &st) < 0 if (!os_get_file_info((char *)IObuff, &file_info)
|| st.st_uid != st_old.st_uid || file_info.stat.st_uid != file_info_old.stat.st_uid
|| st.st_gid != st_old.st_gid || file_info.stat.st_gid != file_info_old.stat.st_gid
|| (long)st.st_mode != perm) || (long)file_info.stat.st_mode != perm) {
backup_copy = TRUE; backup_copy = TRUE;
}
# endif # endif
/* Close the file before removing it, on MS-Windows we /* Close the file before removing it, on MS-Windows we
* can't delete an open file. */ * can't delete an open file. */
@ -2962,27 +2959,25 @@ buf_write (
*/ */
if ((bkc_flags & BKC_BREAKSYMLINK) || (bkc_flags & BKC_BREAKHARDLINK)) { if ((bkc_flags & BKC_BREAKSYMLINK) || (bkc_flags & BKC_BREAKHARDLINK)) {
# ifdef UNIX # ifdef UNIX
int lstat_res; bool file_info_link_ok = os_get_file_info_link((char *)fname, &file_info);
lstat_res = mch_lstat((char *)fname, &st);
/* Symlinks. */ /* Symlinks. */
if ((bkc_flags & BKC_BREAKSYMLINK) if ((bkc_flags & BKC_BREAKSYMLINK)
&& lstat_res == 0 && file_info_link_ok
&& st.st_ino != st_old.st_ino) && !os_file_info_id_equal(&file_info, &file_info_old)) {
backup_copy = FALSE; backup_copy = FALSE;
}
/* Hardlinks. */ /* Hardlinks. */
if ((bkc_flags & BKC_BREAKHARDLINK) if ((bkc_flags & BKC_BREAKHARDLINK)
&& st_old.st_nlink > 1 && file_info_old.stat.st_nlink > 1
&& (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; backup_copy = FALSE;
# else }
# endif # endif
} }
#endif
/* make sure we have a valid backup extension to use */ /* make sure we have a valid backup extension to use */
if (*p_bex == NUL) if (*p_bex == NUL)
backup_ext = (char_u *)".bak"; backup_ext = (char_u *)".bak";
@ -2994,7 +2989,6 @@ buf_write (
int bfd; int bfd;
char_u *copybuf, *wp; char_u *copybuf, *wp;
int some_error = FALSE; int some_error = FALSE;
struct stat st_new;
char_u *dirp; char_u *dirp;
char_u *rootname; char_u *rootname;
@ -3019,12 +3013,6 @@ buf_write (
*/ */
dirp = p_bdir; dirp = p_bdir;
while (*dirp) { 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'. * Isolate one directory name, using an entry in 'bdir'.
*/ */
@ -3035,6 +3023,7 @@ buf_write (
goto nobackup; goto nobackup;
} }
FileInfo file_info_new;
{ {
/* /*
* Make backup file name. * Make backup file name.
@ -3049,20 +3038,17 @@ buf_write (
/* /*
* Check if backup file already exists. * Check if backup file already exists.
*/ */
if (mch_stat((char *)backup, &st_new) >= 0) { if (os_get_file_info((char *)backup, &file_info_new)) {
#ifdef UNIX
/* /*
* Check if backup file is same as original file. * Check if backup file is same as original file.
* May happen when modname() gave the same file back (e.g. silly * 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 * link). If we don't check here, we either ruin the file when
* copying or erase it after writing. * copying or erase it after writing.
*/ */
if (st_new.st_dev == st_old.st_dev if (os_file_info_id_equal(&file_info_new, &file_info_old)) {
&& st_new.st_ino == st_old.st_ino) {
free(backup); free(backup);
backup = NULL; /* no backup file to delete */ backup = NULL; /* no backup file to delete */
} }
#endif
/* /*
* If we are not going to keep the backup file, don't * If we are not going to keep the backup file, don't
@ -3076,8 +3062,9 @@ buf_write (
wp = backup; wp = backup;
*wp = 'z'; *wp = 'z';
while (*wp > 'a' while (*wp > 'a'
&& mch_stat((char *)backup, &st_new) >= 0) && os_get_file_info((char *)backup, &file_info_new)) {
--*wp; --*wp;
}
/* They all exist??? Must be something wrong. */ /* They all exist??? Must be something wrong. */
if (*wp == 'a') { if (*wp == 'a') {
free(backup); free(backup);
@ -3114,13 +3101,13 @@ buf_write (
* bits for the group same as the protection bits for * bits for the group same as the protection bits for
* others. * 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() */ # 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 # endif
) ) {
os_setperm(backup, os_setperm(backup, (perm & 0707) | ((perm & 07) << 3));
(perm & 0707) | ((perm & 07) << 3)); }
# ifdef HAVE_SELINUX # ifdef HAVE_SELINUX
mch_copy_sec(fname, backup); mch_copy_sec(fname, backup);
# endif # endif
@ -3155,7 +3142,9 @@ buf_write (
errmsg = (char_u *)_( errmsg = (char_u *)_(
"E508: Can't read file for backup (add ! to override)"); "E508: Can't read file for backup (add ! to override)");
#ifdef UNIX #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 #endif
#ifdef HAVE_ACL #ifdef HAVE_ACL
mch_set_acl(backup, acl); mch_set_acl(backup, acl);
@ -3266,7 +3255,8 @@ nobackup:
#if defined(UNIX) #if defined(UNIX)
/* When using ":w!" and the file was read-only: make it writable */ /* 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) { && vim_strchr(p_cpo, CPO_FWRITE) == NULL) {
perm |= 0200; perm |= 0200;
(void)os_setperm(fname, perm); (void)os_setperm(fname, perm);
@ -3412,15 +3402,14 @@ nobackup:
*/ */
if (errmsg == NULL) { if (errmsg == NULL) {
#ifdef UNIX #ifdef UNIX
struct stat st; FileInfo file_info;
/* Don't delete the file when it's a hard or symbolic link. */ /* Don't delete the file when it's a hard or symbolic link. */
if ((!newfile && st_old.st_nlink > 1) if ((!newfile && file_info_old.stat.st_nlink > 1)
|| (mch_lstat((char *)fname, &st) == 0 || (os_get_file_info_link((char *)fname, &file_info)
&& (st.st_dev != st_old.st_dev && !os_file_info_id_equal(&file_info, &file_info_old))) {
|| st.st_ino != st_old.st_ino)))
errmsg = (char_u *)_("E166: Can't open linked file for writing"); errmsg = (char_u *)_("E166: Can't open linked file for writing");
else } else
#endif #endif
{ {
errmsg = (char_u *)_("E212: Can't open file for writing"); errmsg = (char_u *)_("E212: Can't open file for writing");
@ -3432,8 +3421,10 @@ nobackup:
if (!(perm & 0200)) if (!(perm & 0200))
made_writable = TRUE; made_writable = TRUE;
perm |= 0200; 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; perm &= 0777;
}
#endif #endif
if (!append) /* don't remove when appending */ if (!append) /* don't remove when appending */
os_remove((char *)wfname); os_remove((char *)wfname);
@ -3444,8 +3435,6 @@ nobackup:
restore_backup: restore_backup:
{ {
struct stat st;
/* /*
* If we failed to open the file, we don't need a backup. Throw it * 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 * 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. * In that case we leave the copy around.
*/ */
/* If file does not exist, put the copy in its place */ /* 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); vim_rename(backup, fname);
}
/* if original file does exist throw away the copy */ /* 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); os_remove((char *)backup);
}
} else { } else {
/* try to put the original file back */ /* try to put the original file back */
vim_rename(backup, fname); vim_rename(backup, fname);
@ -3472,8 +3463,9 @@ restore_backup:
} }
/* if original file no longer exists give an extra warning */ /* 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; end = 0;
}
} }
if (wfname != fname) if (wfname != fname)
@ -3649,14 +3641,14 @@ restore_backup:
* file. Get the new device and inode number. */ * file. Get the new device and inode number. */
if (backup != NULL && !backup_copy) { if (backup != NULL && !backup_copy) {
# ifdef HAVE_FCHOWN # ifdef HAVE_FCHOWN
struct stat st;
/* don't change the owner when it's already OK, some systems remove /* don't change the owner when it's already OK, some systems remove
* permission or ACL stuff */ * permission or ACL stuff */
if (mch_stat((char *)wfname, &st) < 0 FileInfo file_info;
|| st.st_uid != st_old.st_uid if (!os_get_file_info((char *)wfname, &file_info)
|| st.st_gid != st_old.st_gid) { || file_info.stat.st_uid != file_info_old.stat.st_uid
ignored = fchown(fd, st_old.st_uid, st_old.st_gid); || 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 */ if (perm >= 0) /* set permission again, may have changed */
(void)os_setperm(wfname, perm); (void)os_setperm(wfname, perm);
} }
@ -3855,20 +3847,20 @@ restore_backup:
char *org = (char *)modname(fname, p_pm, FALSE); char *org = (char *)modname(fname, p_pm, FALSE);
if (backup != NULL) { if (backup != NULL) {
struct stat st;
/* /*
* If the original file does not exist yet * If the original file does not exist yet
* the current backup file becomes the original file * the current backup file becomes the original file
*/ */
if (org == NULL) if (org == NULL)
EMSG(_("E205: Patchmode: can't save original file")); 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); vim_rename(backup, (char_u *)org);
free(backup); /* don't delete the file */ free(backup); /* don't delete the file */
backup = NULL; backup = NULL;
#ifdef UNIX #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 #endif
} }
} }
@ -3961,8 +3953,8 @@ nofail:
/* Update the timestamp to avoid an "overwrite changed file" /* Update the timestamp to avoid an "overwrite changed file"
* prompt when writing again. */ * prompt when writing again. */
if (mch_stat((char *)fname, &st_old) >= 0) { if (os_get_file_info((char *)fname, &file_info_old)) {
buf_store_time(buf, &st_old, fname); buf_store_file_info(buf, &file_info_old, fname);
buf->b_mtime_read = buf->b_mtime; 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 * The size isn't checked, because using a tool like "gzip" takes care of
* using the same timestamp but can't set the size. * 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 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_scroll = TRUE; /* don't overwrite messages here */
msg_silent = 0; /* must give this prompt */ msg_silent = 0; /* must give this prompt */
/* don't use emsg() here, don't want to flush the buffers */ /* 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; int n;
char *errmsg = NULL; char *errmsg = NULL;
char *buffer; char *buffer;
struct stat st;
long perm; long perm;
#ifdef HAVE_ACL #ifdef HAVE_ACL
vim_acl_T acl; /* ACL from original file */ vim_acl_T acl; /* ACL from original file */
#endif #endif
int use_tmp_file = FALSE; bool use_tmp_file = false;
/* /*
* When the names are identical, there is nothing to do. When they refer * 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 (fnamecmp(from, to) == 0) {
if (p_fic && STRCMP(path_tail(from), path_tail(to)) != 0) if (p_fic && STRCMP(path_tail(from), path_tail(to)) != 0)
use_tmp_file = TRUE; use_tmp_file = true;
else else
return 0; return 0;
} }
/* // Fail if the "from" file doesn't exist. Avoids that "to" is deleted.
* 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)) {
if (mch_stat((char *)from, &st) < 0)
return -1; 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;
} }
#endif
// 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;
}
if (use_tmp_file) { if (use_tmp_file) {
char_u tempname[MAXPATHL + 1]; char_u tempname[MAXPATHL + 1];
@ -5086,8 +5073,6 @@ buf_check_timestamp (
int focus /* called for GUI focus event */ int focus /* called for GUI focus event */
) )
{ {
struct stat st;
int stat_res;
int retval = 0; int retval = 0;
char_u *path; char_u *path;
char_u *tbuf; char_u *tbuf;
@ -5114,27 +5099,25 @@ buf_check_timestamp (
) )
return 0; return 0;
if ( !(buf->b_flags & BF_NOTEDITED) FileInfo file_info;
&& buf->b_mtime != 0 bool file_info_ok;
&& ((stat_res = mch_stat((char *)buf->b_ffname, &st)) < 0 if (!(buf->b_flags & BF_NOTEDITED)
|| time_differs((long)st.st_mtime, buf->b_mtime) && buf->b_mtime != 0
|| st.st_size != buf->b_orig_size && (!(file_info_ok = os_get_file_info((char *)buf->b_ffname, &file_info))
#ifdef HAVE_ST_MODE || time_differs((long)file_info.stat.st_mtim.tv_sec, buf->b_mtime)
|| (int)st.st_mode != buf->b_orig_mode || (int)file_info.stat.st_mode != buf->b_orig_mode
#else )) {
|| os_getperm(buf->b_ffname) != buf->b_orig_mode
#endif
)) {
retval = 1; retval = 1;
/* set b_mtime to stop further warnings (e.g., when executing /* set b_mtime to stop further warnings (e.g., when executing
* FileChangedShell autocmd) */ * FileChangedShell autocmd) */
if (stat_res < 0) { if (!file_info_ok) {
buf->b_mtime = 0; buf->b_mtime = 0;
buf->b_orig_size = 0; buf->b_orig_size = 0;
buf->b_orig_mode = 0; buf->b_orig_mode = 0;
} else } else {
buf_store_time(buf, &st, buf->b_ffname); buf_store_file_info(buf, &file_info, buf->b_ffname);
}
/* Don't do anything for a directory. Might contain the file /* Don't do anything for a directory. Might contain the file
* explorer. */ * explorer. */
@ -5147,10 +5130,10 @@ buf_check_timestamp (
* was set, the global option value otherwise. * was set, the global option value otherwise.
*/ */
else if ((buf->b_p_ar >= 0 ? buf->b_p_ar : p_ar) 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; reload = TRUE;
else { else {
if (stat_res < 0) if (!file_info_ok)
reason = "deleted"; reason = "deleted";
else if (bufIsChanged(buf)) else if (bufIsChanged(buf))
reason = "conflict"; reason = "conflict";
@ -5435,15 +5418,12 @@ void buf_reload(buf_T *buf, int orig_mode)
/* Careful: autocommands may have made "buf" invalid! */ /* 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_mtime = (long)file_info->stat.st_mtim.tv_sec;
buf->b_orig_size = st->st_size; buf->b_orig_size = file_info->stat.st_size;
#ifdef HAVE_ST_MODE buf->b_orig_mode = (int)file_info->stat.st_mode;
buf->b_orig_mode = (int)st->st_mode;
#else
buf->b_orig_mode = os_getperm(fname);
#endif
} }
/* /*
@ -5527,9 +5507,6 @@ vim_tempname (
#ifdef TEMPDIRNAMES #ifdef TEMPDIRNAMES
static char *(tempdirs[]) = {TEMPDIRNAMES}; static char *(tempdirs[]) = {TEMPDIRNAMES};
int i; int i;
# ifndef EEXIST
struct stat st;
# endif
/* /*
* This will create a directory for private use by this instance of Vim. * 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 /* If mkdir() does not set errno to EEXIST, check for
* existing file here. There is a race condition then, * existing file here. There is a race condition then,
* although it's fail-safe. */ * although it's fail-safe. */
if (mch_stat((char *)itmp, &st) >= 0) if (os_file_exists(itmp))
continue; continue;
# endif # endif
# if defined(UNIX) # if defined(UNIX)

View File

@ -2,6 +2,7 @@
#define NEOVIM_FILEIO_H #define NEOVIM_FILEIO_H
#include "buffer_defs.h" #include "buffer_defs.h"
#include "os/os.h"
/* /*
* Struct to save values in before executing autocommands for a buffer that is * 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 check_timestamps(int focus);
int buf_check_timestamp(buf_T *buf, int focus); int buf_check_timestamp(buf_T *buf, int focus);
void buf_reload(buf_T *buf, int orig_mode); 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 write_lnum_adjust(linenr_T offset);
void vim_deltempdir(void); void vim_deltempdir(void);
char_u *vim_tempname(int extra_char); char_u *vim_tempname(int extra_char);

View File

@ -52,8 +52,7 @@ static int cs_find_common(char *opt, char *pat, int, int, int,
char_u *cmdline); char_u *cmdline);
static int cs_help(exarg_T *eap); static int cs_help(exarg_T *eap);
static void clear_csinfo(int i); static void clear_csinfo(int i);
static int cs_insert_filelist(char *, char *, char *, static int cs_insert_filelist(char *, char *, char *, FileInfo *file_info);
struct stat *);
static int cs_kill(exarg_T *eap); static int cs_kill(exarg_T *eap);
static void cs_kill_execute(int, char *); static void cs_kill_execute(int, char *);
static cscmd_T * cs_lookup_cmd(exarg_T *eap); static cscmd_T * cs_lookup_cmd(exarg_T *eap);
@ -481,8 +480,6 @@ cs_add_common (
char *flags char *flags
) )
{ {
struct stat statbuf;
int ret;
char *fname = NULL; char *fname = NULL;
char *fname2 = NULL; char *fname2 = NULL;
char *ppath = NULL; char *ppath = NULL;
@ -503,28 +500,25 @@ cs_add_common (
goto add_err; goto add_err;
fname = (char *)vim_strnsave((char_u *)fname, len); fname = (char *)vim_strnsave((char_u *)fname, len);
free(fbuf); free(fbuf);
ret = stat(fname, &statbuf); FileInfo file_info;
if (ret < 0) { bool file_info_ok = os_get_file_info(fname, &file_info);
if (!file_info_ok) {
staterr: staterr:
if (p_csverbose) if (p_csverbose)
cs_stat_emsg(fname); cs_stat_emsg(fname);
goto add_err; 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) { if (arg2 != NULL) {
struct stat statbuf2;
ppath = (char *)alloc(MAXPATHL + 1); ppath = (char *)alloc(MAXPATHL + 1);
expand_env((char_u *)arg2, (char_u *)ppath, MAXPATHL); expand_env((char_u *)arg2, (char_u *)ppath, MAXPATHL);
ret = stat(ppath, &statbuf2); if (!os_file_exists((char_u *)ppath))
if (ret < 0)
goto staterr; goto staterr;
} }
/* if filename is a directory, append the cscope database name to it */ /* 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)); fname2 = (char *)alloc((unsigned)(strlen(CSCOPE_DBFILE) + strlen(fname) + 2));
while (fname[strlen(fname)-1] == '/' while (fname[strlen(fname)-1] == '/'
@ -538,23 +532,18 @@ staterr:
else else
(void)sprintf(fname2, "%s/%s", fname, CSCOPE_DBFILE); (void)sprintf(fname2, "%s/%s", fname, CSCOPE_DBFILE);
ret = stat(fname2, &statbuf); file_info_ok = os_get_file_info(fname2, &file_info);
if (ret < 0) { if (!file_info_ok) {
if (p_csverbose) if (p_csverbose)
cs_stat_emsg(fname2); cs_stat_emsg(fname2);
goto add_err; 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(file_info.stat.st_mode) || S_ISLNK(file_info.stat.st_mode))
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
{ {
i = cs_insert_filelist(fname, ppath, flags, &statbuf); i = cs_insert_filelist(fname, ppath, flags, &file_info);
} else { } else {
if (p_csverbose) if (p_csverbose)
(void)EMSG2( (void)EMSG2(
@ -1223,53 +1212,16 @@ static char *GetWin32Error(void)
* *
* insert a new cscope database filename into the filelist * 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; 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 */ i = -1; /* can be set to the index of an empty item in csinfo */
for (j = 0; j < csinfo_size; j++) { for (j = 0; j < csinfo_size; j++) {
if (csinfo[j].fname != NULL if (csinfo[j].fname != NULL
#if defined(UNIX) && csinfo[j].st_dev == file_info->stat.st_dev
&& csinfo[j].st_dev == sb->st_dev && csinfo[j].st_ino == sb->st_ino && csinfo[j].st_ino == file_info->stat.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
) {
if (p_csverbose) if (p_csverbose)
(void)EMSG(_("E568: duplicate cscope database not added")); (void)EMSG(_("E568: duplicate cscope database not added"));
return -1; return -1;
@ -1312,15 +1264,8 @@ static int cs_insert_filelist(char *fname, char *ppath, char *flags, struct stat
} else } else
csinfo[i].flags = NULL; csinfo[i].flags = NULL;
#if defined(UNIX) csinfo[i].st_dev = file_info->stat.st_dev;
csinfo[i].st_dev = sb->st_dev; csinfo[i].st_ino = file_info->stat.st_ino;
csinfo[i].st_ino = sb->st_ino;
#else
csinfo[i].nVolume = bhfi.dwVolumeSerialNumber;
csinfo[i].nIndexLow = bhfi.nFileIndexLow;
csinfo[i].nIndexHigh = bhfi.nFileIndexHigh;
#endif
return i; return i;
} /* cs_insert_filelist */ } /* cs_insert_filelist */

View File

@ -51,10 +51,9 @@ typedef struct csi {
char * flags; /* additional cscope flags/options (e.g, -p2) */ char * flags; /* additional cscope flags/options (e.g, -p2) */
#if defined(UNIX) #if defined(UNIX)
pid_t pid; /* PID of the connected cscope process. */ 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 #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 * fr_fp; /* from cscope: FILE. */
FILE * to_fp; /* to cscope: FILE. */ FILE * to_fp; /* to cscope: FILE. */

View File

@ -98,21 +98,6 @@
#define vim_isbreak(c) (breakat_flags[(char_u)(c)]) #define vim_isbreak(c) (breakat_flags[(char_u)(c)])
# define mch_fopen(n, p) fopen((n), (p)) # 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)) # define mch_open(n, m, p) open((n), (m), (p))
/* mch_open_rw(): invoke mch_open() with third argument for user R/W. */ /* mch_open_rw(): invoke mch_open() with third argument for user R/W. */

View File

@ -2130,14 +2130,13 @@ process_env (
*/ */
static int file_owned(char *fname) static int file_owned(char *fname)
{ {
struct stat s;
uid_t uid = getuid(); uid_t uid = getuid();
FileInfo file_info;
return !(mch_stat(fname, &s) != 0 || s.st_uid != uid bool file_owned = os_get_file_info(fname, &file_info)
# ifdef HAVE_LSTAT && file_info.stat.st_uid == uid;
|| mch_lstat(fname, &s) != 0 || s.st_uid != uid bool link_owned = os_get_file_info_link(fname, &file_info)
# endif && file_info.stat.st_uid == uid;
); return file_owned && link_owned;
} }
#endif #endif

View File

@ -46,25 +46,6 @@
#include "ui.h" #include "ui.h"
#include "os/os.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 */ #define MEMFILE_PAGE_SIZE 4096 /* default page size */
static long_u total_mem_used = 0; /* total memory used for memfiles */ 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; memfile_T *mfp;
off_t size; 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) if ((mfp = (memfile_T *)alloc((unsigned)sizeof(memfile_T))) == NULL)
return 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_page_size = MEMFILE_PAGE_SIZE;
mfp->mf_old_key = NULL; mfp->mf_old_key = NULL;
#ifdef USE_FSTATFS
/* /*
* Try to set the page size equal to the block size of the device. * Try to set the page size equal to the block size of the device.
* Speeds up I/O a lot. * 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 * in ml_recover(). The size used here may be wrong, therefore
* mf_blocknr_max must be rounded up. * mf_blocknr_max must be rounded up.
*/ */
FileInfo file_info;
if (mfp->mf_fd >= 0 if (mfp->mf_fd >= 0
&& fstatfs(mfp->mf_fd, &stf, sizeof(struct statfs), 0) == 0 && os_get_file_info_fd(mfp->mf_fd, &file_info)
&& stf.F_BSIZE >= MIN_SWAP_PAGE_SIZE && file_info.stat.st_blksize >= MIN_SWAP_PAGE_SIZE
&& stf.F_BSIZE <= MAX_SWAP_PAGE_SIZE) && file_info.stat.st_blksize <= MAX_SWAP_PAGE_SIZE) {
mfp->mf_page_size = stf.F_BSIZE; mfp->mf_page_size = file_info.stat.st_blksize;
#endif }
if (mfp->mf_fd < 0 || (flags & (O_TRUNC|O_EXCL)) if (mfp->mf_fd < 0 || (flags & (O_TRUNC|O_EXCL))
|| (size = lseek(mfp->mf_fd, (off_t)0L, SEEK_END)) <= 0) || (size = lseek(mfp->mf_fd, (off_t)0L, SEEK_END)) <= 0)
@ -1064,10 +1041,6 @@ mf_do_open (
int flags /* flags for open() */ int flags /* flags for open() */
) )
{ {
#ifdef HAVE_LSTAT
struct stat sb;
#endif
mfp->mf_fname = fname; mfp->mf_fname = fname;
/* /*
@ -1077,17 +1050,16 @@ mf_do_open (
*/ */
mf_set_ffname(mfp); mf_set_ffname(mfp);
#ifdef HAVE_LSTAT
/* /*
* Extra security check: When creating a swap file it really shouldn't * 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. * 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; mfp->mf_fd = -1;
EMSG(_("E300: Swap file already exists (symlink attack?)")); EMSG(_("E300: Swap file already exists (symlink attack?)"));
} else } else {
#endif
{
/* /*
* try to open the file * try to open the file
*/ */

View File

@ -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) static void set_b0_fname(ZERO_BL *b0p, buf_T *buf)
{ {
struct stat st;
if (buf->b_ffname == NULL) if (buf->b_ffname == NULL)
b0p->b0_fname[0] = NUL; b0p->b0_fname[0] = NUL;
else { else {
@ -861,12 +859,13 @@ static void set_b0_fname(ZERO_BL *b0p, buf_T *buf)
memmove(b0p->b0_fname + 1, uname, ulen); memmove(b0p->b0_fname + 1, uname, ulen);
} }
} }
if (mch_stat((char *)buf->b_ffname, &st) >= 0) { FileInfo file_info;
long_to_char((long)st.st_mtime, b0p->b0_mtime); 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 #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 #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; buf->b_mtime_read = buf->b_mtime;
} else { } else {
long_to_char(0L, b0p->b0_mtime); long_to_char(0L, b0p->b0_mtime);
@ -943,7 +942,6 @@ void ml_recover(void)
infoptr_T *ip; infoptr_T *ip;
blocknr_T bnum; blocknr_T bnum;
int page_count; int page_count;
struct stat org_stat, swp_stat;
int len; int len;
int directly; int directly;
linenr_T lnum; linenr_T lnum;
@ -1155,12 +1153,15 @@ void ml_recover(void)
/* /*
* check date of swap file and original file * check date of swap file and original file
*/ */
FileInfo org_file_info;
FileInfo swp_file_info;
mtime = char_to_long(b0p->b0_mtime); mtime = char_to_long(b0p->b0_mtime);
if (curbuf->b_ffname != NULL if (curbuf->b_ffname != NULL
&& mch_stat((char *)curbuf->b_ffname, &org_stat) != -1 && os_get_file_info((char *)curbuf->b_ffname, &org_file_info)
&& ((mch_stat((char *)mfp->mf_fname, &swp_stat) != -1 && ((os_get_file_info((char *)mfp->mf_fname, &swp_file_info)
&& org_stat.st_mtime > swp_stat.st_mtime) && org_file_info.stat.st_mtim.tv_sec
|| org_stat.st_mtime != mtime)) { > 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")); EMSG(_("E308: Warning: Original file may have been changed"));
} }
out_flush(); out_flush();
@ -1607,12 +1608,9 @@ recover_names (
* Try finding a swap file by simply adding ".swp" to the file name. * Try finding a swap file by simply adding ".swp" to the file name.
*/ */
if (*dirp == NUL && file_count + num_files == 0 && fname != NULL) { if (*dirp == NUL && file_count + num_files == 0 && fname != NULL) {
struct stat st; char_u *swapname = modname(fname_res, (char_u *)".swp", TRUE);
char_u *swapname;
swapname = modname(fname_res, (char_u *)".swp", TRUE);
if (swapname != NULL) { 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 = (char_u **)alloc((unsigned)sizeof(char_u *));
files[0] = swapname; files[0] = swapname;
swapname = NULL; swapname = NULL;
@ -1717,7 +1715,6 @@ static int process_still_running;
*/ */
static time_t swapfile_info(char_u *fname) static time_t swapfile_info(char_u *fname)
{ {
struct stat st;
int fd; int fd;
struct block0 b0; struct block0 b0;
time_t x = (time_t)0; time_t x = (time_t)0;
@ -1727,18 +1724,19 @@ static time_t swapfile_info(char_u *fname)
#endif #endif
/* print the swap file date */ /* 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 #ifdef UNIX
/* print name of owner of the file */ /* 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_PUTS(_(" owned by: "));
msg_outtrans((char_u *)uname); msg_outtrans((char_u *)uname);
MSG_PUTS(_(" dated: ")); MSG_PUTS(_(" dated: "));
} else } else
#endif #endif
MSG_PUTS(_(" dated: ")); MSG_PUTS(_(" dated: "));
x = st.st_mtime; /* Manx C can't do &st.st_mtime */ x = file_info.stat.st_mtim.tv_sec;
p = ctime(&x); /* includes '\n' */ p = ctime(&x); // includes '\n'
if (p == NULL) if (p == NULL)
MSG_PUTS("(invalid)\n"); MSG_PUTS("(invalid)\n");
else 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) void ml_sync_all(int check_file, int check_char)
{ {
buf_T *buf; buf_T *buf;
struct stat st;
for (buf = firstbuf; buf != NULL; buf = buf->b_next) { for (buf = firstbuf; buf != NULL; buf = buf->b_next) {
if (buf->b_ml.ml_mfp == NULL || buf->b_ml.ml_mfp->mf_fname == NULL) 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 * If the original file does not exist anymore or has been changed
* call ml_preserve() to get rid of all negative numbered blocks. * call ml_preserve() to get rid of all negative numbered blocks.
*/ */
if (mch_stat((char *)buf->b_ffname, &st) == -1 FileInfo file_info;
|| st.st_mtime != buf->b_mtime_read if (!os_get_file_info((char *)buf->b_ffname, &file_info)
|| st.st_size != buf->b_orig_size) { || 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); ml_preserve(buf, FALSE);
did_check_timestamps = FALSE; did_check_timestamps = FALSE;
need_check_timestamps = TRUE; /* give message later */ need_check_timestamps = TRUE; /* give message later */
@ -3435,7 +3433,6 @@ attention_message (
char_u *fname /* swap file name */ char_u *fname /* swap file name */
) )
{ {
struct stat st;
time_t x, sx; time_t x, sx;
char *p; char *p;
@ -3448,10 +3445,11 @@ attention_message (
MSG_PUTS(_("While opening file \"")); MSG_PUTS(_("While opening file \""));
msg_outtrans(buf->b_fname); msg_outtrans(buf->b_fname);
MSG_PUTS("\"\n"); 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: ")); MSG_PUTS(_(" dated: "));
x = st.st_mtime; /* Manx C can't do &st.st_mtime */ x = file_info.stat.st_mtim.tv_sec;
p = ctime(&x); /* includes '\n' */ p = ctime(&x); // includes '\n'
if (p == NULL) if (p == NULL)
MSG_PUTS("(invalid)\n"); MSG_PUTS("(invalid)\n");
else else
@ -3559,21 +3557,13 @@ findswapname (
fname = NULL; fname = NULL;
break; break;
} }
/* // check if the swapfile already exists
* check if the swapfile already exists // Extra security check: When a swap file is a symbolic link, this
*/ // is most likely a symlink attack.
if (!os_file_exists(fname)) { /* it does not exist */ FileInfo file_info;
#ifdef HAVE_LSTAT bool file_or_link_found = os_get_file_info_link((char *)fname, &file_info);
struct stat sb; if (!file_or_link_found) {
break;
/*
* 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;
} }
/* /*
@ -3834,7 +3824,6 @@ fnamecmp_ino (
long ino_block0 long ino_block0
) )
{ {
struct stat st;
ino_t ino_c = 0; /* ino of current file */ ino_t ino_c = 0; /* ino of current file */
ino_t ino_s; /* ino of file from swap file */ ino_t ino_s; /* ino of file from swap file */
char_u buf_c[MAXPATHL]; /* full path of fname_c */ 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_c; /* flag: buf_c valid */
int retval_s; /* flag: buf_s valid */ int retval_s; /* flag: buf_s valid */
if (mch_stat((char *)fname_c, &st) == 0) FileInfo file_info;
ino_c = (ino_t)st.st_ino; 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 * 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 * 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. * valid on this machine), use the inode from block 0.
*/ */
if (mch_stat((char *)fname_s, &st) == 0) if (os_get_file_info((char *)fname_s, &file_info)) {
ino_s = (ino_t)st.st_ino; ino_s = (ino_t)file_info.stat.st_ino;
else } else {
ino_s = (ino_t)ino_block0; ino_s = (ino_t)ino_block0;
}
if (ino_c && ino_s) if (ino_c && ino_s)
return ino_c != ino_s; return ino_c != ino_s;

View File

@ -826,24 +826,6 @@ int vim_chdirfile(char_u *fname)
} }
#endif #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 * Change directory to "new_dir". If FEAT_SEARCHPATH is defined, search
* 'cdpath' for relative directory names, otherwise just os_chdir(). * 'cdpath' for relative directory names, otherwise just os_chdir().

View File

@ -189,6 +189,16 @@ int os_file_is_writable(const char *name)
return 0; 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) int os_rename(const char_u *path, const char_u *new_path)
{ {
uv_fs_t request; uv_fs_t request;
@ -227,3 +237,41 @@ int os_remove(const char *path)
return result; 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;
}

View File

@ -58,6 +58,12 @@ bool os_file_is_readonly(const char *name);
/// @return `2` for a directory which we have rights to write into. /// @return `2` for a directory which we have rights to write into.
int os_file_is_writable(const char *name); 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. /// Rename a file or directory.
/// ///
/// @return `OK` for success, `FAIL` for failure. /// @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. /// @return OK on success, FAIL if an failure occured.
int os_stat(const char_u *name, uv_stat_t *statbuf); 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 #endif // NEOVIM_OS_OS_H

View File

@ -229,6 +229,7 @@
# define MAXPATHL 1024 # define MAXPATHL 1024
#endif #endif
// TODO(stefan991): remove macro
#define CHECK_INODE /* used when checking if a swap file already #define CHECK_INODE /* used when checking if a swap file already
exists for a file */ exists for a file */
# ifndef DFLT_MAXMEM # ifndef DFLT_MAXMEM
@ -276,7 +277,6 @@
#endif #endif
#define HAVE_DUP /* have dup() */ #define HAVE_DUP /* have dup() */
#define HAVE_ST_MODE /* have stat.st_mode */
/* We have three kinds of ACL support. */ /* We have three kinds of ACL support. */
#define HAVE_ACL (HAVE_POSIX_ACL || HAVE_SOLARIS_ACL || HAVE_AIX_ACL) #define HAVE_ACL (HAVE_POSIX_ACL || HAVE_SOLARIS_ACL || HAVE_AIX_ACL)

View File

@ -1285,7 +1285,6 @@ void simplify_filename(char_u *filename)
if (components > 0) { /* strip one preceding component */ if (components > 0) { /* strip one preceding component */
int do_strip = FALSE; int do_strip = FALSE;
char_u saved_char; char_u saved_char;
struct stat st;
/* Don't strip for an erroneous file name. */ /* Don't strip for an erroneous file name. */
if (!stripping_disabled) { if (!stripping_disabled) {
@ -1294,12 +1293,10 @@ void simplify_filename(char_u *filename)
* link that refers to a non-existent file. */ * link that refers to a non-existent file. */
saved_char = p[-1]; saved_char = p[-1];
p[-1] = NUL; p[-1] = NUL;
#ifdef UNIX FileInfo file_info;
if (mch_lstat((char *)filename, &st) < 0) if (!os_get_file_info_link((char *)filename, &file_info)) {
#else
if (mch_stat((char *)filename, &st) < 0)
#endif
do_strip = TRUE; do_strip = TRUE;
}
p[-1] = saved_char; p[-1] = saved_char;
--p; --p;
@ -1320,40 +1317,37 @@ void simplify_filename(char_u *filename)
* components. */ * components. */
saved_char = *tail; saved_char = *tail;
*tail = NUL; *tail = NUL;
if (mch_stat((char *)filename, &st) >= 0) if (os_get_file_info((char *)filename, &file_info)) {
do_strip = TRUE; do_strip = TRUE;
}
else else
stripping_disabled = TRUE; stripping_disabled = TRUE;
*tail = saved_char; *tail = saved_char;
#ifdef UNIX
if (do_strip) { if (do_strip) {
struct stat new_st; /* The check for the unstripped file name
/* On Unix, the check for the unstripped file name
* above works also for a symbolic link pointing to * above works also for a symbolic link pointing to
* a searchable directory. But then the parent of * a searchable directory. But then the parent of
* the directory pointed to by the link must be the * the directory pointed to by the link must be the
* same as the stripped file name. (The latter * same as the stripped file name. (The latter
* exists in the file system since it is the * exists in the file system since it is the
* component's parent directory.) */ * component's parent directory.) */
if (p == start && relative) FileInfo new_file_info;
(void)mch_stat(".", &new_st); if (p == start && relative) {
else { os_get_file_info(".", &new_file_info);
} else {
saved_char = *p; saved_char = *p;
*p = NUL; *p = NUL;
(void)mch_stat((char *)filename, &new_st); os_get_file_info((char *)filename, &new_file_info);
*p = saved_char; *p = saved_char;
} }
if (new_st.st_ino != st.st_ino || if (!os_file_info_id_equal(&file_info, &new_file_info)) {
new_st.st_dev != st.st_dev) {
do_strip = FALSE; do_strip = FALSE;
/* We don't disable stripping of later /* We don't disable stripping of later
* components since the unstripped path name is * components since the unstripped path name is
* still valid. */ * still valid. */
} }
} }
#endif
} }
} }

View File

@ -2573,9 +2573,6 @@ static char_u *get_mef_name(void)
char_u *name; char_u *name;
static int start = -1; static int start = -1;
static int off = 0; static int off = 0;
#ifdef HAVE_LSTAT
struct stat sb;
#endif
if (*p_mef == NUL) { if (*p_mef == NUL) {
name = vim_tempname('e'); name = vim_tempname('e');
@ -2602,13 +2599,12 @@ static char_u *get_mef_name(void)
STRCPY(name, p_mef); STRCPY(name, p_mef);
sprintf((char *)name + (p - p_mef), "%d%d", start, off); sprintf((char *)name + (p - p_mef), "%d%d", start, off);
STRCAT(name, p + 2); STRCAT(name, p + 2);
if (!os_file_exists(name) // Don't accept a symbolic link, its a security risk.
#ifdef HAVE_LSTAT FileInfo file_info;
/* Don't accept a symbolic link, its a security risk. */ bool file_or_link_found = os_get_file_info_link((char *)name, &file_info);
&& mch_lstat((char *)name, &sb) < 0 if (!file_or_link_found) {
#endif
)
break; break;
}
free(name); free(name);
} }
return name; return name;

View File

@ -7768,7 +7768,6 @@ mkspell (
afffile_T *(afile[8]); afffile_T *(afile[8]);
int i; int i;
int len; int len;
struct stat st;
int error = FALSE; int error = FALSE;
spellinfo_T spin; spellinfo_T spin;
@ -7832,7 +7831,7 @@ mkspell (
else { else {
// Check for overwriting before doing things that may take a lot of // Check for overwriting before doing things that may take a lot of
// time. // time.
if (!over_write && mch_stat((char *)wfname, &st) >= 0) { if (!over_write && os_file_exists(wfname)) {
EMSG(_(e_exists)); EMSG(_(e_exists));
goto theend; goto theend;
} }
@ -7888,7 +7887,7 @@ mkspell (
spin.si_region = 1 << i; spin.si_region = 1 << i;
vim_snprintf((char *)fname, MAXPATHL, "%s.aff", innames[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 // Read the .aff file. Will init "spin->si_conv" based on the
// "SET" line. // "SET" line.
afile[i] = spell_read_aff(&spin, fname); afile[i] = spell_read_aff(&spin, fname);

View File

@ -1511,12 +1511,10 @@ line_read_in:
* compute the first offset. * compute the first offset.
*/ */
if (state == TS_BINARY) { if (state == TS_BINARY) {
/* Get the tag file size (don't use mch_fstat(), it's not // Get the tag file size.
* portable). */ if ((filesize = lseek(fileno(fp), (off_t)0L, SEEK_END)) <= 0) {
if ((filesize = lseek(fileno(fp),
(off_t)0L, SEEK_END)) <= 0)
state = TS_LINEAR; state = TS_LINEAR;
else { } else {
lseek(fileno(fp), (off_t)0L, SEEK_SET); lseek(fileno(fp), (off_t)0L, SEEK_SET);
/* Calculate the first read offset in the file. Start /* Calculate the first read offset in the file. Start

View File

@ -675,7 +675,6 @@ char_u *u_get_undo_file_name(char_u *buf_ffname, int reading)
char_u *undo_file_name = NULL; char_u *undo_file_name = NULL;
int dir_len; int dir_len;
char_u *p; char_u *p;
struct stat st;
char_u *ffname = buf_ffname; char_u *ffname = buf_ffname;
#ifdef HAVE_READLINK #ifdef HAVE_READLINK
char_u fname_buf[MAXPATHL]; 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. // When reading check if the file exists.
if (undo_file_name != NULL && if (undo_file_name != NULL &&
(!reading || mch_stat((char *)undo_file_name, &st) >= 0)) { (!reading || os_file_exists(undo_file_name))) {
break; break;
} }
free(undo_file_name); 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; FILE *fp = NULL;
int perm; int perm;
int write_ok = FALSE; int write_ok = FALSE;
#ifdef UNIX
int st_old_valid = FALSE;
struct stat st_old;
struct stat st_new;
#endif
int do_crypt = FALSE; int do_crypt = FALSE;
if (name == NULL) { if (name == NULL) {
@ -1135,16 +1129,10 @@ void u_write_undo(char_u *name, int forceit, buf_T *buf, char_u *hash)
*/ */
perm = 0600; perm = 0600;
if (buf->b_ffname != NULL) { 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); perm = os_getperm(buf->b_ffname);
if (perm < 0) if (perm < 0) {
perm = 0600; perm = 0600;
#endif }
} }
/* strip any s-bit */ /* 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 * this fails, set the protection bits for the group same as the
* protection bits for others. * protection bits for others.
*/ */
if (st_old_valid FileInfo file_info_old;
&& mch_stat((char *)file_name, &st_new) >= 0 FileInfo file_info_new;
&& st_new.st_gid != st_old.st_gid 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() */ # 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 # endif
) ) {
os_setperm(file_name, (perm & 0707) | ((perm & 07) << 3)); os_setperm(file_name, (perm & 0707) | ((perm & 07) << 3));
}
# ifdef HAVE_SELINUX # ifdef HAVE_SELINUX
if (buf->b_ffname != NULL) if (buf->b_ffname != NULL)
mch_copy_sec(buf->b_ffname, file_name); mch_copy_sec(buf->b_ffname, file_name);
@ -1350,10 +1341,6 @@ void u_read_undo(char_u *name, char_u *hash, char_u *orig_name)
char_u magic_buf[UF_START_MAGIC_LEN]; char_u magic_buf[UF_START_MAGIC_LEN];
#ifdef U_DEBUG #ifdef U_DEBUG
int *uhp_table_used; int *uhp_table_used;
#endif
#ifdef UNIX
struct stat st_orig;
struct stat st_undo;
#endif #endif
int do_decrypt = FALSE; int do_decrypt = FALSE;
@ -1365,10 +1352,12 @@ void u_read_undo(char_u *name, char_u *hash, char_u *orig_name)
#ifdef UNIX #ifdef UNIX
/* For safety we only read an undo file if the owner is equal to the /* 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. */ * owner of the text file or equal to the current user. */
if (mch_stat((char *)orig_name, &st_orig) >= 0 FileInfo file_info_orig;
&& mch_stat((char *)file_name, &st_undo) >= 0 FileInfo file_info_undo;
&& st_orig.st_uid != st_undo.st_uid if (os_get_file_info((char *)orig_name, &file_info_orig)
&& st_undo.st_uid != getuid()) { && 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) { if (p_verbose > 0) {
verbose_enter(); verbose_enter();
smsg((char_u *)_("Not reading undo file, owner differs: %s"), smsg((char_u *)_("Not reading undo file, owner differs: %s"),

View File

@ -14,6 +14,8 @@ describe 'fs function', ->
setup -> setup ->
lfs.mkdir 'unit-test-directory' lfs.mkdir 'unit-test-directory'
(io.open 'unit-test-directory/test.file', 'w').close! (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 -- Since the tests are executed, they are called by an executable. We use
-- that executable for several asserts. -- that executable for several asserts.
@ -25,6 +27,8 @@ describe 'fs function', ->
teardown -> teardown ->
os.remove 'unit-test-directory/test.file' 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' lfs.rmdir 'unit-test-directory'
describe 'os_dirname', -> describe 'os_dirname', ->
@ -213,6 +217,12 @@ describe 'fs function', ->
eq 2, os_file_is_writable 'unit-test-directory' eq 2, os_file_is_writable 'unit-test-directory'
describe 'file operations', -> 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) -> os_file_exists = (filename) ->
fs.os_file_exists (to_cstr filename) fs.os_file_exists (to_cstr filename)
@ -261,9 +271,9 @@ describe 'fs function', ->
neq 0, (os_remove 'non-existing-file') neq 0, (os_remove 'non-existing-file')
it 'removes the given file and returns 0', -> it 'removes the given file and returns 0', ->
eq true, (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.file') eq 0, (os_remove 'unit-test-directory/test_remove.file')
eq false, (os_file_exists 'unit-test-directory/test.file') eq false, (os_file_exists 'unit-test-directory/test_remove.file')
describe 'folder operations', -> describe 'folder operations', ->
os_mkdir = (path, mode) -> os_mkdir = (path, mode) ->
@ -293,3 +303,92 @@ describe 'fs function', ->
eq 0, (os_rmdir 'unit-test-directory/new-dir', mode) eq 0, (os_rmdir 'unit-test-directory/new-dir', mode)
eq false, (os_isdir 'unit-test-directory/new-dir') 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)