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