Merge #775 'Implement FileID struct'

This commit is contained in:
Justin M. Keyes
2014-06-28 03:24:35 -04:00
15 changed files with 280 additions and 201 deletions

View File

@@ -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;
} }
/* /*

View File

@@ -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. */

View 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. */

View File

@@ -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);
} }

View File

@@ -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) {

View File

@@ -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 */

View File

@@ -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. */

View 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.

View File

@@ -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
View 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

View File

@@ -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"

View File

@@ -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;
} }

View File

@@ -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

View File

@@ -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;

View File

@@ -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)