mirror of
https://github.com/neovim/neovim.git
synced 2025-12-09 16:12:48 +00:00
Merge #775 'Implement FileID struct'
This commit is contained in:
@@ -70,21 +70,12 @@
|
||||
#include "nvim/window.h"
|
||||
#include "nvim/os/os.h"
|
||||
|
||||
// Todo(stefan991): remove this macro
|
||||
#define INVALID_DEVICE_ID UINT64_MAX
|
||||
|
||||
#define HAVE_BUFLIST_MATCH
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "buffer.c.generated.h"
|
||||
#endif
|
||||
|
||||
#ifdef UNIX
|
||||
# define dev_T dev_t
|
||||
#else
|
||||
# define dev_T unsigned
|
||||
#endif
|
||||
|
||||
static char *msg_loclist = N_("[Location List]");
|
||||
static char *msg_qflist = N_("[Quickfix List]");
|
||||
static char *e_auabort = N_("E855: Autocommands caused command to abort");
|
||||
@@ -1300,12 +1291,12 @@ buflist_new (
|
||||
*/
|
||||
/* We can use inode numbers when the file exists. Works better
|
||||
* for hard links. */
|
||||
FileInfo file_info;
|
||||
if (sfname == NULL || !os_get_file_info((char *)sfname, &file_info)) {
|
||||
file_info.stat.st_dev = INVALID_DEVICE_ID;
|
||||
}
|
||||
FileID file_id;
|
||||
bool file_id_valid = (sfname != NULL &&
|
||||
os_get_file_id((char *)sfname, &file_id));
|
||||
if (ffname != NULL && !(flags & BLN_DUMMY)
|
||||
&& (buf = buflist_findname_file_info(ffname, &file_info)) != NULL) {
|
||||
&& (buf = buflist_findname_file_id(ffname, &file_id,
|
||||
file_id_valid)) != NULL) {
|
||||
free(ffname);
|
||||
if (lnum != 0)
|
||||
buflist_setfpos(buf, curwin, lnum, (colnr_T)0, FALSE);
|
||||
@@ -1432,12 +1423,11 @@ buflist_new (
|
||||
hash_init(&buf->b_s.b_keywtab_ic);
|
||||
|
||||
buf->b_fname = buf->b_sfname;
|
||||
if (file_info.stat.st_dev == INVALID_DEVICE_ID)
|
||||
buf->b_dev_valid = FALSE;
|
||||
else {
|
||||
buf->b_dev_valid = TRUE;
|
||||
buf->b_dev = file_info.stat.st_dev;
|
||||
buf->b_ino = file_info.stat.st_ino;
|
||||
if (!file_id_valid) {
|
||||
buf->file_id_valid = false;
|
||||
} else {
|
||||
buf->file_id_valid = true;
|
||||
buf->file_id = file_id;
|
||||
}
|
||||
buf->b_u_synced = TRUE;
|
||||
buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED;
|
||||
@@ -1658,25 +1648,24 @@ buf_T *buflist_findname_exp(char_u *fname)
|
||||
*/
|
||||
buf_T *buflist_findname(char_u *ffname)
|
||||
{
|
||||
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);
|
||||
FileID file_id;
|
||||
bool file_id_valid = os_get_file_id((char *)ffname, &file_id);
|
||||
return buflist_findname_file_id(ffname, &file_id, file_id_valid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Same as buflist_findname(), but pass the FileInfo structure to avoid
|
||||
* Same as buflist_findname(), but pass the FileID structure to avoid
|
||||
* getting it twice for the same file.
|
||||
* Returns NULL if not found.
|
||||
*/
|
||||
static buf_T *buflist_findname_file_info(char_u *ffname, FileInfo *file_info)
|
||||
static buf_T *buflist_findname_file_id(char_u *ffname, FileID *file_id,
|
||||
bool file_id_valid)
|
||||
{
|
||||
buf_T *buf;
|
||||
|
||||
for (buf = firstbuf; buf != NULL; buf = buf->b_next) {
|
||||
if ((buf->b_flags & BF_DUMMY) == 0
|
||||
&& !otherfile_buf(buf, ffname, file_info)) {
|
||||
&& !otherfile_buf(buf, ffname, file_id, file_id_valid)) {
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
@@ -2192,7 +2181,8 @@ setfname (
|
||||
)
|
||||
{
|
||||
buf_T *obuf = NULL;
|
||||
FileInfo file_info;
|
||||
FileID file_id;
|
||||
bool file_id_valid = false;
|
||||
|
||||
if (ffname == NULL || *ffname == NUL) {
|
||||
/* Removing the name. */
|
||||
@@ -2200,7 +2190,6 @@ setfname (
|
||||
free(buf->b_sfname);
|
||||
buf->b_ffname = NULL;
|
||||
buf->b_sfname = NULL;
|
||||
file_info.stat.st_dev = INVALID_DEVICE_ID;
|
||||
} else {
|
||||
fname_expand(buf, &ffname, &sfname); /* will allocate ffname */
|
||||
if (ffname == NULL) /* out of memory */
|
||||
@@ -2211,11 +2200,9 @@ setfname (
|
||||
* - if the buffer is loaded, fail
|
||||
* - if the buffer is not loaded, delete it from the list
|
||||
*/
|
||||
if (!os_get_file_info((char *)ffname, &file_info)) {
|
||||
file_info.stat.st_dev = INVALID_DEVICE_ID;
|
||||
}
|
||||
file_id_valid = os_get_file_id((char *)ffname, &file_id);
|
||||
if (!(buf->b_flags & BF_DUMMY)) {
|
||||
obuf = buflist_findname_file_info(ffname, &file_info);
|
||||
obuf = buflist_findname_file_id(ffname, &file_id, file_id_valid);
|
||||
}
|
||||
if (obuf != NULL && obuf != buf) {
|
||||
if (obuf->b_ml.ml_mfp != NULL) { /* it's loaded, fail */
|
||||
@@ -2241,12 +2228,11 @@ setfname (
|
||||
buf->b_sfname = sfname;
|
||||
}
|
||||
buf->b_fname = buf->b_sfname;
|
||||
if (file_info.stat.st_dev == INVALID_DEVICE_ID) {
|
||||
buf->b_dev_valid = FALSE;
|
||||
if (!file_id_valid) {
|
||||
buf->file_id_valid = false;
|
||||
} else {
|
||||
buf->b_dev_valid = TRUE;
|
||||
buf->b_dev = file_info.stat.st_dev;
|
||||
buf->b_ino = file_info.stat.st_ino;
|
||||
buf->file_id_valid = true;
|
||||
buf->file_id = file_id;
|
||||
}
|
||||
|
||||
buf_name_changed(buf);
|
||||
@@ -2380,10 +2366,11 @@ void buflist_altfpos(win_T *win)
|
||||
*/
|
||||
int otherfile(char_u *ffname)
|
||||
{
|
||||
return otherfile_buf(curbuf, ffname, NULL);
|
||||
return otherfile_buf(curbuf, ffname, NULL, false);
|
||||
}
|
||||
|
||||
static int otherfile_buf(buf_T *buf, char_u *ffname, FileInfo *file_info_p)
|
||||
static int otherfile_buf(buf_T *buf, char_u *ffname,
|
||||
FileID *file_id_p, bool file_id_valid)
|
||||
{
|
||||
/* no name is different */
|
||||
if (ffname == NULL || *ffname == NUL || buf->b_ffname == NULL) {
|
||||
@@ -2393,14 +2380,15 @@ static int otherfile_buf(buf_T *buf, char_u *ffname, FileInfo *file_info_p)
|
||||
return FALSE;
|
||||
}
|
||||
{
|
||||
FileInfo file_info;
|
||||
|
||||
FileID file_id;
|
||||
/* If no struct stat given, get it now */
|
||||
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;
|
||||
if (file_id_p == NULL) {
|
||||
file_id_p = &file_id;
|
||||
file_id_valid = os_get_file_id((char *)ffname, file_id_p);
|
||||
}
|
||||
if (!file_id_valid) {
|
||||
// file_id not valid, assume files are different.
|
||||
return TRUE;
|
||||
}
|
||||
/* 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
|
||||
@@ -2411,40 +2399,34 @@ static int otherfile_buf(buf_T *buf, char_u *ffname, FileInfo *file_info_p)
|
||||
* 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, file_info_p)) {
|
||||
buf_setino(buf);
|
||||
if (buf_same_ino(buf, file_info_p))
|
||||
if (buf_same_file_id(buf, file_id_p)) {
|
||||
buf_set_file_id(buf);
|
||||
if (buf_same_file_id(buf, file_id_p))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set inode and device number for a buffer.
|
||||
* Must always be called when b_fname is changed!.
|
||||
*/
|
||||
void buf_setino(buf_T *buf)
|
||||
// Set file_id for a buffer.
|
||||
// Must always be called when b_fname is changed!
|
||||
void buf_set_file_id(buf_T *buf)
|
||||
{
|
||||
FileInfo file_info;
|
||||
FileID file_id;
|
||||
if (buf->b_fname != NULL
|
||||
&& os_get_file_info((char *)buf->b_fname, &file_info)) {
|
||||
buf->b_dev_valid = TRUE;
|
||||
buf->b_dev = file_info.stat.st_dev;
|
||||
buf->b_ino = file_info.stat.st_ino;
|
||||
&& os_get_file_id((char *)buf->b_fname, &file_id)) {
|
||||
buf->file_id_valid = true;
|
||||
buf->file_id = file_id;
|
||||
} else {
|
||||
buf->b_dev_valid = FALSE;
|
||||
buf->file_id_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if dev/ino in buffer "buf" matches with "stp".
|
||||
*/
|
||||
static int buf_same_ino(buf_T *buf, FileInfo *file_info)
|
||||
// return TRUE if file_id in buffer "buf" matches with "file_id".
|
||||
static bool buf_same_file_id(buf_T *buf, FileID *file_id)
|
||||
{
|
||||
return buf->b_dev_valid
|
||||
&& file_info->stat.st_dev == buf->b_dev
|
||||
&& file_info->stat.st_ino == buf->b_ino;
|
||||
return buf->file_id_valid
|
||||
&& os_file_id_equal(&(buf->file_id), file_id);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -88,6 +88,9 @@ typedef struct memfile memfile_T;
|
||||
// for signlist_T
|
||||
#include "nvim/sign_defs.h"
|
||||
|
||||
// for FileID
|
||||
#include "nvim/os/fs_defs.h"
|
||||
|
||||
/*
|
||||
* The taggy struct is used to store the information about a :tag command.
|
||||
*/
|
||||
@@ -471,9 +474,8 @@ struct file_buffer {
|
||||
char_u *b_sfname; /* short file name */
|
||||
char_u *b_fname; /* current file name */
|
||||
|
||||
int b_dev_valid; /* TRUE when b_dev has a valid number */
|
||||
uint64_t b_dev; /* device number */
|
||||
uint64_t b_ino; /* inode number */
|
||||
bool file_id_valid;
|
||||
FileID file_id;
|
||||
|
||||
int b_fnum; /* buffer number for this file. */
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include "nvim/window.h"
|
||||
#include "nvim/os/os.h"
|
||||
#include "nvim/os/shell.h"
|
||||
#include "nvim/os/fs_defs.h"
|
||||
|
||||
|
||||
/* Growarray to store info about already sourced scripts.
|
||||
@@ -52,9 +53,8 @@
|
||||
* script when going through the list. */
|
||||
typedef struct scriptitem_S {
|
||||
char_u *sn_name;
|
||||
int sn_dev_valid;
|
||||
uint64_t sn_dev;
|
||||
uint64_t sn_ino;
|
||||
bool file_id_valid;
|
||||
FileID file_id;
|
||||
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 */
|
||||
@@ -2559,15 +2559,14 @@ do_source (
|
||||
* If it's new, generate a new SID.
|
||||
*/
|
||||
save_current_SID = current_SID;
|
||||
FileInfo file_info;
|
||||
bool file_info_ok = os_get_file_info((char *)fname_exp, &file_info);
|
||||
FileID file_id;
|
||||
bool file_id_ok = os_get_file_id((char *)fname_exp, &file_id);
|
||||
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;
|
||||
bool file_id_equal = file_id_ok && si->file_id_valid
|
||||
&& os_file_id_equal(&(si->file_id), &file_id);
|
||||
if (si->sn_name != NULL
|
||||
&& (file_id_equal || fnamecmp(si->sn_name, fname_exp) == 0)) {
|
||||
break;
|
||||
@@ -2584,12 +2583,11 @@ do_source (
|
||||
si = &SCRIPT_ITEM(current_SID);
|
||||
si->sn_name = fname_exp;
|
||||
fname_exp = NULL;
|
||||
if (file_info_ok) {
|
||||
si->sn_dev_valid = TRUE;
|
||||
si->sn_dev = file_info.stat.st_dev;
|
||||
si->sn_ino = file_info.stat.st_ino;
|
||||
if (file_id_ok) {
|
||||
si->file_id_valid = true;
|
||||
si->file_id = file_id;
|
||||
} else {
|
||||
si->sn_dev_valid = FALSE;
|
||||
si->file_id_valid = false;
|
||||
}
|
||||
|
||||
/* Allocate the local script variables to use for this script. */
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
#include "nvim/ui.h"
|
||||
#include "nvim/window.h"
|
||||
#include "nvim/os/os.h"
|
||||
#include "nvim/os/fs_defs.h"
|
||||
|
||||
static char_u *ff_expand_buffer = NULL; /* used for expanding filenames */
|
||||
|
||||
@@ -108,12 +109,9 @@ typedef struct ff_visited {
|
||||
* different. So we have to save it.
|
||||
*/
|
||||
char_u *ffv_wc_path;
|
||||
/* for unix use inode etc for comparison (needed because of links), else
|
||||
* use filename.
|
||||
*/
|
||||
int ffv_dev_valid; /* ffv_dev and ffv_ino were set */
|
||||
uint64_t ffv_dev; /* device number */
|
||||
uint64_t ffv_ino; /* inode number */
|
||||
// use FileID for comparison (needed because of links), else use filename.
|
||||
bool file_id_valid;
|
||||
FileID file_id;
|
||||
/* The memory for this struct is allocated according to the length of
|
||||
* ffv_fname.
|
||||
*/
|
||||
@@ -1088,15 +1086,15 @@ static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u *
|
||||
ff_visited_T *vp;
|
||||
bool url = false;
|
||||
|
||||
FileInfo file_info;
|
||||
// For a URL we only compare the name, otherwise we compare the
|
||||
FileID file_id;
|
||||
// For an URL we only compare the name, otherwise we compare the
|
||||
// device/inode.
|
||||
if (path_with_url(fname)) {
|
||||
STRLCPY(ff_expand_buffer, fname, MAXPATHL);
|
||||
url = true;
|
||||
} else {
|
||||
ff_expand_buffer[0] = NUL;
|
||||
if (!os_get_file_info((char *)fname, &file_info)) {
|
||||
if (!os_get_file_id((char *)fname, &file_id)) {
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
@@ -1104,9 +1102,8 @@ static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u *
|
||||
/* check against list of already visited files */
|
||||
for (vp = *visited_list; vp != NULL; vp = vp->ffv_next) {
|
||||
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)) {
|
||||
|| (!url && vp->file_id_valid
|
||||
&& os_file_id_equal(&(vp->file_id), &file_id))) {
|
||||
/* are the wildcard parts equal */
|
||||
if (ff_wc_equal(vp->ffv_wc_path, wc_path) == TRUE)
|
||||
/* already visited */
|
||||
@@ -1120,12 +1117,11 @@ static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u *
|
||||
vp = xmalloc(sizeof(ff_visited_T) + STRLEN(ff_expand_buffer));
|
||||
|
||||
if (!url) {
|
||||
vp->ffv_dev_valid = TRUE;
|
||||
vp->ffv_ino = file_info.stat.st_ino;
|
||||
vp->ffv_dev = file_info.stat.st_dev;
|
||||
vp->file_id_valid = true;
|
||||
vp->file_id = file_id;
|
||||
vp->ffv_fname[0] = NUL;
|
||||
} else {
|
||||
vp->ffv_dev_valid = FALSE;
|
||||
vp->file_id_valid = false;
|
||||
STRCPY(vp->ffv_fname, ff_expand_buffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -3433,10 +3433,11 @@ restore_backup:
|
||||
(void)os_setperm(wfname, perm);
|
||||
}
|
||||
# endif
|
||||
buf_setino(buf);
|
||||
} else if (!buf->b_dev_valid)
|
||||
/* Set the inode when creating a new file. */
|
||||
buf_setino(buf);
|
||||
buf_set_file_id(buf);
|
||||
} else if (!buf->file_id_valid) {
|
||||
// Set the file_id when creating a new file.
|
||||
buf_set_file_id(buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (close(fd) != 0) {
|
||||
|
||||
@@ -1139,14 +1139,7 @@ static void clear_csinfo(int i)
|
||||
csinfo[i].fname = NULL;
|
||||
csinfo[i].ppath = NULL;
|
||||
csinfo[i].flags = NULL;
|
||||
#if defined(UNIX)
|
||||
csinfo[i].st_dev = (dev_t)0;
|
||||
csinfo[i].st_ino = (ino_t)0;
|
||||
#else
|
||||
csinfo[i].nVolume = 0;
|
||||
csinfo[i].nIndexHigh = 0;
|
||||
csinfo[i].nIndexLow = 0;
|
||||
#endif
|
||||
csinfo[i].file_id = FILE_ID_EMPTY;
|
||||
csinfo[i].pid = 0;
|
||||
csinfo[i].fr_fp = NULL;
|
||||
csinfo[i].to_fp = NULL;
|
||||
@@ -1181,8 +1174,7 @@ static int cs_insert_filelist(char *fname, char *ppath, char *flags,
|
||||
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
|
||||
&& csinfo[j].st_dev == file_info->stat.st_dev
|
||||
&& csinfo[j].st_ino == file_info->stat.st_ino) {
|
||||
&& os_file_id_equal_file_info(&(csinfo[j].file_id), file_info)) {
|
||||
if (p_csverbose)
|
||||
(void)EMSG(_("E568: duplicate cscope database not added"));
|
||||
return -1;
|
||||
@@ -1225,8 +1217,7 @@ static int cs_insert_filelist(char *fname, char *ppath, char *flags,
|
||||
} else
|
||||
csinfo[i].flags = NULL;
|
||||
|
||||
csinfo[i].st_dev = file_info->stat.st_dev;
|
||||
csinfo[i].st_ino = file_info->stat.st_ino;
|
||||
os_file_info_get_id(file_info, &(csinfo[i].file_id));
|
||||
return i;
|
||||
} /* cs_insert_filelist */
|
||||
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
|
||||
#if defined(UNIX)
|
||||
# include <sys/types.h> /* pid_t */
|
||||
# include <sys/stat.h> /* dev_t, ino_t */
|
||||
#else
|
||||
#endif
|
||||
|
||||
#include "nvim/os/fs_defs.h"
|
||||
|
||||
#define CSCOPE_SUCCESS 0
|
||||
#define CSCOPE_FAILURE -1
|
||||
|
||||
@@ -52,8 +52,7 @@ typedef struct csi {
|
||||
#if defined(UNIX)
|
||||
pid_t pid; /* PID of the connected cscope process. */
|
||||
#endif
|
||||
uint64_t st_dev; /* ID of dev containing cscope db */
|
||||
uint64_t st_ino; /* inode number of cscope db */
|
||||
FileID file_id;
|
||||
|
||||
FILE * fr_fp; /* from cscope: FILE. */
|
||||
FILE * to_fp; /* to cscope: FILE. */
|
||||
|
||||
@@ -686,16 +686,12 @@ static void set_b0_fname(ZERO_BL *b0p, buf_T *buf)
|
||||
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)file_info.stat.st_ino, b0p->b0_ino);
|
||||
#endif
|
||||
long_to_char((long)os_file_info_get_inode(&file_info), b0p->b0_ino);
|
||||
buf_store_file_info(buf, &file_info);
|
||||
buf->b_mtime_read = buf->b_mtime;
|
||||
} else {
|
||||
long_to_char(0L, b0p->b0_mtime);
|
||||
#ifdef CHECK_INODE
|
||||
long_to_char(0L, b0p->b0_ino);
|
||||
#endif
|
||||
buf->b_mtime = 0;
|
||||
buf->b_mtime_read = 0;
|
||||
buf->b_orig_size = 0;
|
||||
@@ -3339,17 +3335,16 @@ findswapname (
|
||||
*/
|
||||
if (b0.b0_flags & B0_SAME_DIR) {
|
||||
if (fnamecmp(path_tail(buf->b_ffname),
|
||||
path_tail(b0.b0_fname)) != 0
|
||||
path_tail(b0.b0_fname)) != 0
|
||||
|| !same_directory(fname, buf->b_ffname)) {
|
||||
#ifdef CHECK_INODE
|
||||
/* Symlinks may point to the same file even
|
||||
* when the name differs, need to check the
|
||||
* inode too. */
|
||||
expand_env(b0.b0_fname, NameBuff, MAXPATHL);
|
||||
if (fnamecmp_ino(buf->b_ffname, NameBuff,
|
||||
char_to_long(b0.b0_ino)))
|
||||
#endif
|
||||
differ = TRUE;
|
||||
char_to_long(b0.b0_ino))) {
|
||||
differ = TRUE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
@@ -3357,14 +3352,10 @@ findswapname (
|
||||
* "~user/path/file". Expand it first.
|
||||
*/
|
||||
expand_env(b0.b0_fname, NameBuff, MAXPATHL);
|
||||
#ifdef CHECK_INODE
|
||||
if (fnamecmp_ino(buf->b_ffname, NameBuff,
|
||||
char_to_long(b0.b0_ino)))
|
||||
char_to_long(b0.b0_ino))) {
|
||||
differ = TRUE;
|
||||
#else
|
||||
if (fnamecmp(NameBuff, buf->b_ffname) != 0)
|
||||
differ = TRUE;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
@@ -3504,7 +3495,6 @@ static int b0_magic_wrong(ZERO_BL *b0p)
|
||||
|| b0p->b0_magic_char != B0_MAGIC_CHAR;
|
||||
}
|
||||
|
||||
#ifdef CHECK_INODE
|
||||
/*
|
||||
* Compare current file name with file name from swap file.
|
||||
* Try to use inode numbers when possible.
|
||||
@@ -3549,20 +3539,19 @@ static int b0_magic_wrong(ZERO_BL *b0p)
|
||||
* available -> probably same file
|
||||
* == 0 == 0 FAIL FAIL FALSE
|
||||
*
|
||||
* Note that when the ino_t is 64 bits, only the last 32 will be used. This
|
||||
* can't be changed without making the block 0 incompatible with 32 bit
|
||||
* versions.
|
||||
* Only the last 32 bits of the inode will be used. This can't be changed
|
||||
* without making the block 0 incompatible with 32 bit versions.
|
||||
*/
|
||||
|
||||
static int
|
||||
static int
|
||||
fnamecmp_ino (
|
||||
char_u *fname_c, /* current file name */
|
||||
char_u *fname_s, /* file name from swap file */
|
||||
long ino_block0
|
||||
)
|
||||
{
|
||||
ino_t ino_c = 0; /* ino of current file */
|
||||
ino_t ino_s; /* ino of file from swap file */
|
||||
uint64_t ino_c = 0; /* ino of current file */
|
||||
uint64_t ino_s; /* ino of file from swap file */
|
||||
char_u buf_c[MAXPATHL]; /* full path of fname_c */
|
||||
char_u buf_s[MAXPATHL]; /* full path of fname_s */
|
||||
int retval_c; /* flag: buf_c valid */
|
||||
@@ -3570,7 +3559,7 @@ fnamecmp_ino (
|
||||
|
||||
FileInfo file_info;
|
||||
if (os_get_file_info((char *)fname_c, &file_info)) {
|
||||
ino_c = (ino_t)file_info.stat.st_ino;
|
||||
ino_c = os_file_info_get_inode(&file_info);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3579,9 +3568,9 @@ fnamecmp_ino (
|
||||
* valid on this machine), use the inode from block 0.
|
||||
*/
|
||||
if (os_get_file_info((char *)fname_s, &file_info)) {
|
||||
ino_s = (ino_t)file_info.stat.st_ino;
|
||||
ino_s = os_file_info_get_inode(&file_info);
|
||||
} else {
|
||||
ino_s = (ino_t)ino_block0;
|
||||
ino_s = (uint64_t)ino_block0;
|
||||
}
|
||||
|
||||
if (ino_c && ino_s)
|
||||
@@ -3604,7 +3593,6 @@ fnamecmp_ino (
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
#endif /* CHECK_INODE */
|
||||
|
||||
/*
|
||||
* Move a long integer into a four byte character array.
|
||||
|
||||
104
src/nvim/os/fs.c
104
src/nvim/os/fs.c
@@ -149,19 +149,13 @@ static bool is_executable_in_path(const char_u *name)
|
||||
/// Get stat information for a file.
|
||||
///
|
||||
/// @return OK on success, FAIL if a failure occurred.
|
||||
int os_stat(const char_u *name, uv_stat_t *statbuf)
|
||||
static bool os_stat(const char *name, uv_stat_t *statbuf)
|
||||
{
|
||||
uv_fs_t request;
|
||||
int result = uv_fs_stat(uv_default_loop(), &request,
|
||||
(const char *)name, NULL);
|
||||
int result = uv_fs_stat(uv_default_loop(), &request, name, NULL);
|
||||
*statbuf = request.statbuf;
|
||||
uv_fs_req_cleanup(&request);
|
||||
|
||||
if (result == kLibuvSuccess) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
return FAIL;
|
||||
return (result == kLibuvSuccess);
|
||||
}
|
||||
|
||||
/// Get the file permissions for a given file.
|
||||
@@ -170,10 +164,10 @@ int os_stat(const char_u *name, uv_stat_t *statbuf)
|
||||
int32_t os_getperm(const char_u *name)
|
||||
{
|
||||
uv_stat_t statbuf;
|
||||
if (os_stat(name, &statbuf) == FAIL) {
|
||||
return -1;
|
||||
} else {
|
||||
if (os_stat((char *)name, &statbuf)) {
|
||||
return (int32_t)statbuf.st_mode;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,11 +194,7 @@ int os_setperm(const char_u *name, int perm)
|
||||
bool os_file_exists(const char_u *name)
|
||||
{
|
||||
uv_stat_t statbuf;
|
||||
if (os_stat(name, &statbuf) == OK) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return os_stat((char *)name, &statbuf);
|
||||
}
|
||||
|
||||
/// Check if a file is readonly.
|
||||
@@ -238,7 +228,7 @@ int os_file_is_writable(const char *name)
|
||||
bool os_get_file_size(const char *name, off_t *size)
|
||||
{
|
||||
uv_stat_t statbuf;
|
||||
if (os_stat((char_u *)name, &statbuf) == OK) {
|
||||
if (os_stat(name, &statbuf)) {
|
||||
*size = statbuf.st_size;
|
||||
return true;
|
||||
}
|
||||
@@ -302,10 +292,7 @@ int os_remove(const char *path)
|
||||
/// @return `true` on success, `false` for failure.
|
||||
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;
|
||||
return os_stat(path, &(file_info->stat));
|
||||
}
|
||||
|
||||
/// Get the file information for a given path without following links
|
||||
@@ -319,10 +306,7 @@ bool os_get_file_info_link(const char *path, FileInfo *file_info)
|
||||
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;
|
||||
return (result == kLibuvSuccess);
|
||||
}
|
||||
|
||||
/// Get the file information for a given file descriptor
|
||||
@@ -336,17 +320,75 @@ bool os_get_file_info_fd(int file_descriptor, FileInfo *file_info)
|
||||
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;
|
||||
return (result == kLibuvSuccess);
|
||||
}
|
||||
|
||||
/// 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)
|
||||
bool os_file_info_id_equal(const FileInfo *file_info_1,
|
||||
const 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;
|
||||
}
|
||||
|
||||
/// Get the `FileID` of a `FileInfo`
|
||||
///
|
||||
/// @param file_info Pointer to the `FileInfo`
|
||||
/// @param[out] file_id Pointer to a `FileID`
|
||||
void os_file_info_get_id(const FileInfo *file_info, FileID *file_id)
|
||||
{
|
||||
file_id->inode = file_info->stat.st_ino;
|
||||
file_id->device_id = file_info->stat.st_dev;
|
||||
}
|
||||
|
||||
/// Get the inode of a `FileInfo`
|
||||
///
|
||||
/// @deprecated Use `FileID` instead, this function is only needed in memline.c
|
||||
/// @param file_info Pointer to the `FileInfo`
|
||||
/// @return the inode number
|
||||
uint64_t os_file_info_get_inode(const FileInfo *file_info)
|
||||
{
|
||||
return file_info->stat.st_ino;
|
||||
}
|
||||
|
||||
/// Get the `FileID` for a given path
|
||||
///
|
||||
/// @param path Path to the file.
|
||||
/// @param[out] file_info Pointer to a `FileID` to fill in.
|
||||
/// @return `true` on sucess, `false` for failure.
|
||||
bool os_get_file_id(const char *path, FileID *file_id)
|
||||
{
|
||||
uv_stat_t statbuf;
|
||||
if (os_stat(path, &statbuf)) {
|
||||
file_id->inode = statbuf.st_ino;
|
||||
file_id->device_id = statbuf.st_dev;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Check if two `FileID`s are equal
|
||||
///
|
||||
/// @param file_id_1 Pointer to first `FileID`
|
||||
/// @param file_id_2 Pointer to second `FileID`
|
||||
/// @return `true` if the two `FileID`s represent te same file.
|
||||
bool os_file_id_equal(const FileID *file_id_1, const FileID *file_id_2)
|
||||
{
|
||||
return file_id_1->inode == file_id_2->inode
|
||||
&& file_id_1->device_id == file_id_2->device_id;
|
||||
}
|
||||
|
||||
/// Check if a `FileID` is equal to a `FileInfo`
|
||||
///
|
||||
/// @param file_id Pointer to a `FileID`
|
||||
/// @param file_info Pointer to a `FileInfo`
|
||||
/// @return `true` if the `FileID` and the `FileInfo` represent te same file.
|
||||
bool os_file_id_equal_file_info(const FileID *file_id,
|
||||
const FileInfo *file_info)
|
||||
{
|
||||
return file_id->inode == file_info->stat.st_ino
|
||||
&& file_id->device_id == file_info->stat.st_dev;
|
||||
}
|
||||
|
||||
|
||||
19
src/nvim/os/fs_defs.h
Normal file
19
src/nvim/os/fs_defs.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef NVIM_OS_FS_DEFS_H
|
||||
#define NVIM_OS_FS_DEFS_H
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
/// Struct which encapsulates stat information.
|
||||
typedef struct {
|
||||
uv_stat_t stat; ///< @private
|
||||
} FileInfo;
|
||||
|
||||
/// Struct which encapsulates inode/dev_id information.
|
||||
typedef struct {
|
||||
uint64_t inode; ///< @private The inode of the file
|
||||
uint64_t device_id; ///< @private The id of the device containing the file
|
||||
} FileID;
|
||||
|
||||
#define FILE_ID_EMPTY (FileID){.inode = 0, .device_id = 0}
|
||||
|
||||
#endif // NVIM_OS_FS_DEFS_H
|
||||
@@ -2,14 +2,9 @@
|
||||
#define NVIM_OS_OS_H
|
||||
#include <uv.h>
|
||||
|
||||
#include "nvim/os/fs_defs.h"
|
||||
#include "nvim/vim.h"
|
||||
|
||||
/// Struct which encapsulates stat information.
|
||||
typedef struct {
|
||||
// TODO(stefan991): make stat private
|
||||
uv_stat_t stat;
|
||||
} FileInfo;
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "os/fs.h.generated.h"
|
||||
# include "os/mem.h.generated.h"
|
||||
|
||||
@@ -381,12 +381,12 @@ char_u *name,
|
||||
int len /* buffer size, only used when name gets longer */
|
||||
)
|
||||
{
|
||||
struct stat st;
|
||||
char_u *slash, *tail;
|
||||
DIR *dirp;
|
||||
struct dirent *dp;
|
||||
|
||||
if (lstat((char *)name, &st) >= 0) {
|
||||
FileInfo file_info;
|
||||
if (os_get_file_info_link((char *)name, &file_info)) {
|
||||
/* Open the directory where the file is located. */
|
||||
slash = vim_strrchr(name, '/');
|
||||
if (slash == NULL) {
|
||||
@@ -406,15 +406,14 @@ int len /* buffer size, only used when name gets longer */
|
||||
if (STRICMP(tail, dp->d_name) == 0
|
||||
&& STRLEN(tail) == STRLEN(dp->d_name)) {
|
||||
char_u newname[MAXPATHL + 1];
|
||||
struct stat st2;
|
||||
|
||||
/* Verify the inode is equal. */
|
||||
STRLCPY(newname, name, MAXPATHL + 1);
|
||||
STRLCPY(newname + (tail - name), dp->d_name,
|
||||
MAXPATHL - (tail - name) + 1);
|
||||
if (lstat((char *)newname, &st2) >= 0
|
||||
&& st.st_ino == st2.st_ino
|
||||
&& st.st_dev == st2.st_dev) {
|
||||
FileInfo file_info_new;
|
||||
if (os_get_file_info_link((char *)newname, &file_info_new)
|
||||
&& os_file_info_id_equal(&file_info, &file_info_new)) {
|
||||
STRCPY(tail, dp->d_name);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -229,9 +229,6 @@
|
||||
# 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
|
||||
# define DFLT_MAXMEM (5*1024) /* use up to 5 Mbyte for a buffer */
|
||||
# endif
|
||||
|
||||
@@ -52,13 +52,13 @@ FileComparison path_full_compare(char_u *s1, char_u *s2, int checkname)
|
||||
char_u exp1[MAXPATHL];
|
||||
char_u full1[MAXPATHL];
|
||||
char_u full2[MAXPATHL];
|
||||
uv_stat_t st1, st2;
|
||||
FileID file_id_1, file_id_2;
|
||||
|
||||
expand_env(s1, exp1, MAXPATHL);
|
||||
int r1 = os_stat(exp1, &st1);
|
||||
int r2 = os_stat(s2, &st2);
|
||||
if (r1 != OK && r2 != OK) {
|
||||
// If os_stat() doesn't work, may compare the names.
|
||||
bool id_ok_1 = os_get_file_id((char *)exp1, &file_id_1);
|
||||
bool id_ok_2 = os_get_file_id((char *)s2, &file_id_2);
|
||||
if (!id_ok_1 && !id_ok_2) {
|
||||
// If os_get_file_id() doesn't work, may compare the names.
|
||||
if (checkname) {
|
||||
vim_FullName(exp1, full1, MAXPATHL, FALSE);
|
||||
vim_FullName(s2, full2, MAXPATHL, FALSE);
|
||||
@@ -68,10 +68,10 @@ FileComparison path_full_compare(char_u *s1, char_u *s2, int checkname)
|
||||
}
|
||||
return kBothFilesMissing;
|
||||
}
|
||||
if (r1 != OK || r2 != OK) {
|
||||
if (!id_ok_1 || !id_ok_2) {
|
||||
return kOneFileMissing;
|
||||
}
|
||||
if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino) {
|
||||
if (os_file_id_equal(&file_id_1, &file_id_2)) {
|
||||
return kEqualFiles;
|
||||
}
|
||||
return kDifferentFiles;
|
||||
|
||||
@@ -314,6 +314,12 @@ describe 'fs function', ->
|
||||
is_file_info_filled = (file_info) ->
|
||||
file_info[0].stat.st_ino > 0 and file_info[0].stat.st_dev > 0
|
||||
|
||||
file_id_new = () ->
|
||||
file_info = ffi.new 'FileID[1]'
|
||||
file_info[0].inode = 0
|
||||
file_info[0].device_id = 0
|
||||
file_info
|
||||
|
||||
describe 'os_get_file_info', ->
|
||||
it 'returns false if given a non-existing file', ->
|
||||
file_info = file_info_new!
|
||||
@@ -392,3 +398,67 @@ describe 'fs function', ->
|
||||
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)
|
||||
|
||||
describe 'os_file_info_get_id', ->
|
||||
it 'extracts ino/dev from file_info into file_id', ->
|
||||
file_info = file_info_new!
|
||||
file_id = file_id_new!
|
||||
path = 'unit-test-directory/test.file'
|
||||
assert.is_true (fs.os_get_file_info path, file_info)
|
||||
fs.os_file_info_get_id(file_info, file_id)
|
||||
eq file_info[0].stat.st_ino, file_id[0].inode
|
||||
eq file_info[0].stat.st_dev, file_id[0].device_id
|
||||
|
||||
describe 'os_file_info_get_inode', ->
|
||||
it 'returns the inode from file_info', ->
|
||||
file_info = file_info_new!
|
||||
path = 'unit-test-directory/test.file'
|
||||
assert.is_true (fs.os_get_file_info path, file_info)
|
||||
inode = fs.os_file_info_get_inode(file_info)
|
||||
eq file_info[0].stat.st_ino, inode
|
||||
|
||||
describe 'os_get_file_id', ->
|
||||
it 'returns false if given an non-existing file', ->
|
||||
file_id = file_id_new!
|
||||
assert.is_false (fs.os_get_file_id '/non-existent', file_id)
|
||||
|
||||
it 'returns true if given an existing file and fills file_id', ->
|
||||
file_id = file_id_new!
|
||||
path = 'unit-test-directory/test.file'
|
||||
assert.is_true (fs.os_get_file_id path, file_id)
|
||||
assert.is_true 0 < file_id[0].inode
|
||||
assert.is_true 0 < file_id[0].device_id
|
||||
|
||||
describe 'os_file_id_equal', ->
|
||||
it 'returns true if two FileIDs are equal', ->
|
||||
file_id = file_id_new!
|
||||
path = 'unit-test-directory/test.file'
|
||||
assert.is_true (fs.os_get_file_id path, file_id)
|
||||
assert.is_true (fs.os_file_id_equal file_id, file_id)
|
||||
|
||||
it 'returns false if two FileIDs are not equal', ->
|
||||
file_id_1 = file_id_new!
|
||||
file_id_2 = file_id_new!
|
||||
path_1 = 'unit-test-directory/test.file'
|
||||
path_2 = 'unit-test-directory/test_2.file'
|
||||
assert.is_true (fs.os_get_file_id path_1, file_id_1)
|
||||
assert.is_true (fs.os_get_file_id path_2, file_id_2)
|
||||
assert.is_false (fs.os_file_id_equal file_id_1, file_id_2)
|
||||
|
||||
describe 'os_file_id_equal_file_info', ->
|
||||
it 'returns true if file_id and file_info represent the same file', ->
|
||||
file_id = file_id_new!
|
||||
file_info = file_info_new!
|
||||
path = 'unit-test-directory/test.file'
|
||||
assert.is_true (fs.os_get_file_id path, file_id)
|
||||
assert.is_true (fs.os_get_file_info path, file_info)
|
||||
assert.is_true (fs.os_file_id_equal_file_info file_id, file_info)
|
||||
|
||||
it 'returns false if file_id and file_info represent different files',->
|
||||
file_id = file_id_new!
|
||||
file_info = 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_id path_1, file_id)
|
||||
assert.is_true (fs.os_get_file_info path_2, file_info)
|
||||
assert.is_false (fs.os_file_id_equal_file_info file_id, file_info)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user