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