Here is a patch that creates a daemon that tracks file
state with inotify, writes it out to a file upon request,
and changes most of the calls to stat to use said cache.
It has bugs, but I figured it would be smarter to see
if the approach was acceptable at all before spending the
time to root the bugs out.
I've implemented the communication with a file, and not a socket,
because I think implementing a socket is going to create
security issues on multiuser systems. For example, would a
socket allow stat information to cross user boundaries?
Most stat calls are redirected to a cache that is maintained by a
daemon that maintains file system state via inotify.
Signed-off-by: Robert Zeh <robert.allan.zeh@xxxxxxxxx>
---
abspath.c | 9 ++-
bisect.c | 3 +-
check-racy.c | 2 +-
combine-diff.c | 3 +-
command-list.txt | 1 +
config.c | 3 +-
copy.c | 3 +-
diff-lib.c | 3 +-
diff-no-index.c | 3 +-
diff.c | 9 ++-
diffcore-order.c | 3 +-
dir.c | 4 +-
filechange-cache.c | 203
+++++++++++++++++++++++++++++++++++++++++++++++++++
filechange-cache.h | 20 +++++
filechange-daemon.c | 164 +++++++++++++++++++++++++++++++++++++++++
filechange-printer.c | 13 ++++
git.c | 27 +++++++
ll-merge.c | 3 +-
merge-recursive.c | 5 +-
name-hash.c | 3 +-
name-hash.h | 1 +
notes-merge.c | 3 +-
path.c | 5 +-
read-cache.c | 11 +--
rerere.c | 7 +-
setup.c | 5 +-
test-chmtime.c | 2 +-
test-wildmatch.c | 2 +-
unpack-trees.c | 6 +-
29 files changed, 486 insertions(+), 40 deletions(-)
create mode 100644 filechange-cache.c
create mode 100644 filechange-cache.h
create mode 100644 filechange-daemon.c
create mode 100644 filechange-printer.c
create mode 100644 name-hash.h
diff --git a/abspath.c b/abspath.c
index 40cdc46..798c005 100644
--- a/abspath.c
+++ b/abspath.c
@@ -1,3 +1,4 @@
+#include "filechange-cache.h"
#include "cache.h"
/*
@@ -8,7 +9,7 @@
int is_directory(const char *path)
{
struct stat st;
- return (!stat(path, &st) && S_ISDIR(st.st_mode));
+ return (!cached_stat(path, &st) && S_ISDIR(st.st_mode));
}
/* We allow "recursive" symbolic links. Only within reason, though. */
@@ -117,7 +118,7 @@ static const char *real_path_internal(const char
*path, int die_on_error)
last_elem = NULL;
}
- if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
+ if (!cached_lstat(buf, &st) && S_ISLNK(st.st_mode)) {
ssize_t len = readlink(buf, next_buf, PATH_MAX);
if (len < 0) {
if (die_on_error)
@@ -167,9 +168,9 @@ static const char *get_pwd_cwd(void)
return NULL;
pwd = getenv("PWD");
if (pwd && strcmp(pwd, cwd)) {
- stat(cwd, &cwd_stat);
+ cached_stat(cwd, &cwd_stat);
if ((cwd_stat.st_dev || cwd_stat.st_ino) &&
- !stat(pwd, &pwd_stat) &&
+ !cached_stat(pwd, &pwd_stat) &&
pwd_stat.st_dev == cwd_stat.st_dev &&
pwd_stat.st_ino == cwd_stat.st_ino) {
strlcpy(cwd, pwd, PATH_MAX);
diff --git a/bisect.c b/bisect.c
index bd1b7b5..d4b1af7 100644
--- a/bisect.c
+++ b/bisect.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "commit.h"
#include "diff.h"
+#include "filechange-cache.h"
#include "revision.h"
#include "refs.h"
#include "list-objects.h"
@@ -649,7 +650,7 @@ static int is_expected_rev(const unsigned char *sha1)
FILE *fp;
int res = 0;
- if (stat(filename, &st) || !S_ISREG(st.st_mode))
+ if (cached_stat(filename, &st) || !S_ISREG(st.st_mode))
return 0;
fp = fopen(filename, "r");
diff --git a/check-racy.c b/check-racy.c
index 00d92a1..c54be01 100644
--- a/check-racy.c
+++ b/check-racy.c
@@ -11,7 +11,7 @@ int main(int ac, char **av)
struct cache_entry *ce = active_cache[i];
struct stat st;
- if (lstat(ce->name, &st)) {
+ if (cached_lstat(ce->name, &st)) {
error("lstat(%s): %s", ce->name, strerror(errno));
continue;
}
diff --git a/combine-diff.c b/combine-diff.c
index 35d41cd..b6a09a5 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -3,6 +3,7 @@
#include "blob.h"
#include "diff.h"
#include "diffcore.h"
+#include "filechange-cache.h"
#include "quote.h"
#include "xdiff-interface.h"
#include "log-tree.h"
@@ -806,7 +807,7 @@ static void show_patch_diff(struct combine_diff_path
*elem, int num_parent,
struct stat st;
int fd = -1;
- if (lstat(elem->path, &st) < 0)
+ if (cached_lstat(elem->path, &st) < 0)
goto deleted_file;
if (S_ISLNK(st.st_mode)) {
diff --git a/command-list.txt b/command-list.txt
index bf83303..9dec5e1 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -29,6 +29,7 @@ git-count-objects
ancillaryinterrogators
git-credential purehelpers
git-credential-cache purehelpers
git-credential-store purehelpers
+git-filechange-daemon purehelpers
git-cvsexportcommit foreignscminterface
git-cvsimport foreignscminterface
git-cvsserver foreignscminterface
diff --git a/config.c b/config.c
index aefd80b..99749fe 100644
--- a/config.c
+++ b/config.c
@@ -7,6 +7,7 @@
*/
#include "cache.h"
#include "exec_cmd.h"
+#include "filechange-cache.h"
#include "strbuf.h"
#include "quote.h"
@@ -1436,7 +1437,7 @@ int git_config_set_multivar_in_file(const char
*config_filename,
goto out_free;
}
- fstat(in_fd, &st);
+ cached_fstat(in_fd, &st);
contents_sz = xsize_t(st.st_size);
contents = xmmap(NULL, contents_sz, PROT_READ,
MAP_PRIVATE, in_fd, 0);
diff --git a/copy.c b/copy.c
index a7f58fd..972fabe 100644
--- a/copy.c
+++ b/copy.c
@@ -1,3 +1,4 @@
+#include "filechange-cache.h"
#include "cache.h"
int copy_fd(int ifd, int ofd)
@@ -39,7 +40,7 @@ static int copy_times(const char *dst, const char *src)
{
struct stat st;
struct utimbuf times;
- if (stat(src, &st) < 0)
+ if (cached_stat(src, &st) < 0)
return -1;
times.actime = st.st_atime;
times.modtime = st.st_mtime;
diff --git a/diff-lib.c b/diff-lib.c
index f35de0f..8d5a005 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -2,6 +2,7 @@
* Copyright (C) 2005 Junio C Hamano
*/
#include "cache.h"
+#include "filechange-cache.h"
#include "quote.h"
#include "commit.h"
#include "diff.h"
@@ -27,7 +28,7 @@
*/
static int check_removed(const struct cache_entry *ce, struct stat *st)
{
- if (lstat(ce->name, st) < 0) {
+ if (cached_lstat(ce->name, st) < 0) {
if (errno != ENOENT && errno != ENOTDIR)
return -1;
return 1;
diff --git a/diff-no-index.c b/diff-no-index.c
index 74da659..d3fb354 100644
--- a/diff-no-index.c
+++ b/diff-no-index.c
@@ -7,6 +7,7 @@
#include "cache.h"
#include "color.h"
#include "commit.h"
+#include "filechange-cache.h"
#include "blob.h"
#include "tag.h"
#include "diff.h"
@@ -51,7 +52,7 @@ static int get_mode(const char *path, int *mode)
#endif
else if (path == file_from_standard_input)
*mode = create_ce_mode(0666);
- else if (lstat(path, &st))
+ else if (cached_lstat(path, &st))
return error("Could not access '%s'", path);
else
*mode = st.st_mode;
diff --git a/diff.c b/diff.c
index 156fec4..a5be122 100644
--- a/diff.c
+++ b/diff.c
@@ -5,6 +5,7 @@
#include "quote.h"
#include "diff.h"
#include "diffcore.h"
+#include "filechange-cache.h"
#include "delta.h"
#include "xdiff-interface.h"
#include "color.h"
@@ -2629,7 +2630,7 @@ static int reuse_worktree_file(const char *name,
const unsigned char *sha1, int
* If ce matches the file in the work tree, we can reuse it.
*/
if (ce_uptodate(ce) ||
- (!lstat(name, &st) && !ce_match_stat(ce, &st, 0)))
+ (!cached_lstat(name, &st) && !ce_match_stat(ce, &st, 0)))
return 1;
return 0;
@@ -2684,7 +2685,7 @@ int diff_populate_filespec(struct diff_filespec
*s, int size_only)
struct stat st;
int fd;
- if (lstat(s->path, &st) < 0) {
+ if (cached_lstat(s->path, &st) < 0) {
if (errno == ENOENT) {
err_empty:
err = -1;
@@ -2826,7 +2827,7 @@ static struct diff_tempfile
*prepare_temp_file(const char *name,
if (!one->sha1_valid ||
reuse_worktree_file(name, one->sha1, 1)) {
struct stat st;
- if (lstat(name, &st) < 0) {
+ if (cached_lstat(name, &st) < 0) {
if (errno == ENOENT)
goto not_a_valid_file;
die_errno("stat(%s)", name);
@@ -3043,7 +3044,7 @@ static void diff_fill_sha1_info(struct
diff_filespec *one)
hashcpy(one->sha1, null_sha1);
return;
}
- if (lstat(one->path, &st) < 0)
+ if (cached_lstat(one->path, &st) < 0)
die_errno("stat '%s'", one->path);
if (index_path(one->sha1, one->path, &st, 0))
die("cannot hash %s", one->path);
diff --git a/diffcore-order.c b/diffcore-order.c
index 23e9385..636be01 100644
--- a/diffcore-order.c
+++ b/diffcore-order.c
@@ -4,6 +4,7 @@
#include "cache.h"
#include "diff.h"
#include "diffcore.h"
+#include "filechange-cache.h"
static char **order;
static int order_cnt;
@@ -22,7 +23,7 @@ static void prepare_order(const char *orderfile)
fd = open(orderfile, O_RDONLY);
if (fd < 0)
return;
- if (fstat(fd, &st)) {
+ if (cached_fstat(fd, &st)) {
close(fd);
return;
}
diff --git a/dir.c b/dir.c
index 57394e4..a67a592 100644
--- a/dir.c
+++ b/dir.c
@@ -476,7 +476,7 @@ int add_excludes_from_file_to_list(const char *fname,
char *buf, *entry;
fd = open(fname, O_RDONLY);
- if (fd < 0 || fstat(fd, &st) < 0) {
+ if (fd < 0 || cached_fstat(fd, &st) < 0) {
if (errno != ENOENT)
warn_on_inaccessible(fname);
if (0 <= fd)
@@ -1551,7 +1551,7 @@ static int remove_dir_recurse(struct strbuf *path,
int flag, int *kept_up)
strbuf_setlen(path, len);
strbuf_addstr(path, e->d_name);
- if (lstat(path->buf, &st))
+ if (cached_lstat(path->buf, &st))
; /* fall thru */
else if (S_ISDIR(st.st_mode)) {
if (!remove_dir_recurse(path, flag, &kept_down))
diff --git a/filechange-cache.c b/filechange-cache.c
new file mode 100644
index 0000000..80c698f
--- /dev/null
+++ b/filechange-cache.c
@@ -0,0 +1,203 @@
+#include <unistd.h>
+#include <stdio.h>
+#include "builtin.h"
+#include "hash.h"
+#include "name-hash.h"
+#include "strbuf.h"
+#include "filechange-cache.h"
+
+
+static struct hash_table stat_cache;
+static const int CACHE_ENTRY_FILE_SIZE =
+ sizeof(struct stat) + /* sizeof(stat_cache_entry.st) */
+ sizeof(int); /* sizeof(stat_cache_entry.stat_return) */
+
+static void insert_stat_cache_entry(const char *path,
+ struct stat_cache_entry *new_entry);
+
+void setup_stat_cache()
+{
+ init_hash(&stat_cache);
+}
+
+static int write_stat_cache_entry(void *void_stat_cache_entry, void
*void_fp)
+{
+ FILE *fp = (FILE*)(void_fp);
+ const struct stat_cache_entry *entry =
+ (struct stat_cache_entry*)(void_stat_cache_entry);
+
+ for (; entry; entry = entry->next) {
+ if (fprintf(fp, "%s\n", entry->path) < 0)
+ die_errno("Unable to write to %s",
+ git_path("WT_STATUS_TMP"));
+ if (fwrite(&entry->stat_return,
+ CACHE_ENTRY_FILE_SIZE, 1, fp) < 0)
+ die_errno("Unable to write to %s",
+ git_path("WT_STATUS_TMP"));
+ }
+ return 0;
+}
+
+void write_stat_cache()
+{
+ const char *status_tmp = git_path("WT_STATUS_TMP");
+ const char *status_output = git_path("WT_STATUS");
+ FILE *fp = fopen(status_tmp, "w");
+ if (!fp)
+ die_errno("Unable to create %s", status_tmp);
+ if (fprintf(fp, "version_format=1\n") < 0)
+ die_errno("Unable to write to %s", status_tmp);
+ for_each_hash(&stat_cache, write_stat_cache_entry, fp);
+ if (fclose(fp) < 0)
+ die_errno("Unable to close %s", status_tmp);
+ if (rename(status_tmp, status_output) < 0)
+ die_errno("Unable to rename %s to %s", status_tmp,
+ status_output);
+}
+
+static void read_stat_cache_file()
+{
+ struct strbuf line = STRBUF_INIT;
+ const char *status_output = git_path("WT_STATUS");
+ int read_version = 0;
+
+ FILE *fp = fopen(status_output, "r");
+ if (!fp)
+ die_errno("Unable to read %s", status_output);
+
+ if (strbuf_getline(&line, fp, '\n') != EOF) {
+ sscanf(line.buf, "version_format=%d\n", &read_version);
+ if (read_version != 1) {
+ die("Expected version 1 of stat_cache file");
+ }
+ }
+
+ while (strbuf_getline(&line, fp, '\n') != EOF) {
+ struct stat_cache_entry *entry =
+ (struct stat_cache_entry*)(xcalloc(1, sizeof(*entry)));
+ entry->path = xstrdup(line.buf);
+ if (fread(&entry->stat_return,
+ CACHE_ENTRY_FILE_SIZE, 1, fp) != 1) {
+ die_errno("Unable to read stat_cache file");
+ }
+ insert_stat_cache_entry(entry->path, entry);
+ }
+
+ strbuf_release(&line);
+}
+
+static int request_stat_cache_file()
+{
+ int count = 0;
+ int stat_return_code = 0;
+ const char *request_path = git_path("REQUEST_WT_STATUS");
+ const char *status_output = git_path("WT_STATUS");
+ struct stat stat_buf;
+
+ char buffer[1] = { 0 };
+ FILE *fp = NULL;
+
+ if (0 != stat(request_path, &stat_buf))
+ return 0;
+
+ if (unlink(status_output) != 0 && (errno != ENOENT))
+ die_errno("Unable to remove %s", status_output);
+
+ fp = fopen(request_path, "w");
+ if (!fp) {
+ die_errno("Unable to open %s", request_path);
+ }
+
+ if (fwrite(&buffer, 0, 0, fp) != 0)
+ die_errno("Unable to write to %s", request_path);
+
+ for (count = 0;
+ (count < 10) &&
+ ((stat_return_code = stat(status_output, &stat_buf)) != 0) &&
+ (errno == ENOENT);
+ count++) {
+ usleep(1000);
+ }
+
+ return stat_return_code == 0;
+}
+
+void read_stat_cache()
+{
+ static int read_cache = 1;
+ if (read_cache && request_stat_cache_file()) {
+ read_stat_cache_file();
+ read_cache = 0;
+ }
+ read_cache = 0;
+}
+
+struct stat_cache_entry *get_stat_cache_entry(const char *path)
+{
+ const unsigned int hash = hash_name(path, strlen(path));
+ struct stat_cache_entry *entry = NULL;
+ for(entry = lookup_hash(hash, &stat_cache); entry;
+ entry = entry->next) {
+ if (!strcmp(path, entry->path)) return entry;
+ }
+ return NULL;
+}
+
+static void insert_stat_cache_entry(const char *path,
+ struct stat_cache_entry *new_entry)
+{
+ assert(get_stat_cache_entry(path) == NULL);
+
+ void **insert_result =
+ insert_hash(hash_name(path, strlen(path)), (void*)new_entry,
+ &stat_cache);
+ if (!insert_result) return;
+ struct stat_cache_entry *existing_entry =
+ (struct stat_cache_entry*)(*insert_result);
+ while(existing_entry->next) {
+ existing_entry = existing_entry->next;
+ }
+ assert(!existing_entry->next);
+ existing_entry->next = new_entry;
+}
+
+void update_stat_cache(const char *path)
+{
+ struct stat_cache_entry *entry = get_stat_cache_entry(path);
+ if (!entry) {
+ entry = (struct stat_cache_entry*)(xcalloc(1, sizeof(*entry)));
+ entry->path = xstrdup(path);
+ insert_stat_cache_entry(path, entry);
+ }
+
+ entry->stat_return = lstat(path, &entry->st);
+}
+
+int cached_stat(const char *path, struct stat *buf)
+{
+ return stat(path, buf);
+}
+
+int cached_fstat(int fd, struct stat *buf)
+{
+ return fstat(fd, buf);
+}
+
+int cached_lstat(const char *path, struct stat *buf)
+{
+ int stat_return_value = 0;
+ struct stat_cache_entry *entry = 0;
+
+ read_stat_cache();
+
+ entry = get_stat_cache_entry(path);
+
+ stat_return_value = lstat(path, buf);
+
+ if (entry && (stat_return_value != entry->stat_return) &&
+ (memcpy(&entry->st, buf, sizeof(*buf)))) {
+ abort();
+ }
+
+ return stat_return_value;
+}
diff --git a/filechange-cache.h b/filechange-cache.h
new file mode 100644
index 0000000..75a9f79
--- /dev/null
+++ b/filechange-cache.h
@@ -0,0 +1,20 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+struct stat_cache_entry {
+ const char *path;
+ struct stat_cache_entry *next;
+ int stat_return;
+ struct stat st;
+};
+
+extern void write_stat_cache();
+extern void read_stat_cache();
+extern void setup_stat_cache();
+extern struct stat_cache_entry *get_stat_cache_entry(const char *path);
+extern void update_stat_cache(const char *path);
+
+extern int cached_stat(const char *path, struct stat *buf);
+extern int cached_fstat(int fd, struct stat *buf);
+extern int cached_lstat(const char *path, struct stat *buf);
diff --git a/filechange-daemon.c b/filechange-daemon.c
new file mode 100644
index 0000000..df6f0d3
--- /dev/null
+++ b/filechange-daemon.c
@@ -0,0 +1,164 @@
+#include <stdio.h>
+#include <libgen.h>
+#include <x86_64-linux-gnu/sys/inotify.h>
+
+#include "filechange-cache.h"
+#include "builtin.h"
+#include "dir.h"
+#include "hash.h"
+
+static int request_watch_descriptor = -1;
+static int root_directory_watch_descriptor = -1;
+
+static void setup_environment()
+{
+ setup_stat_cache();
+}
+
+static int setup_inotify()
+{
+ int inotify_fd = inotify_init();
+ if (inotify_fd < 0) {
+ die_errno("Unable to create inotify watch");
+ }
+ return inotify_fd;
+}
+
+static void restart()
+{
+
+}
+
+
+static void watch_control(int inotify_fd)
+{
+ struct stat stat_buf;
+ const char *request_path = git_path("REQUEST_WT_STATUS");
+
+ if ((stat(request_path, &stat_buf) == -1) && (errno == ENOENT)) {
+ FILE *out = fopen(request_path, "w");
+ if (out == NULL)
+ die_errno("Unable to create %s", request_path);
+ }
+
+ request_watch_descriptor = inotify_add_watch(inotify_fd,
+ request_path, IN_MODIFY);
+
+ if (request_watch_descriptor < 0)
+ die_errno("Unable to watch %s", get_git_dir());
+}
+
+static void watch_file(int inotify_fd, const char *path)
+{
+ int watch_descriptor = 0;
+ char *path_copy = xstrdup(path);
+ char *dir = dirname(path_copy);
+ const int interest_set =
+ IN_MODIFY | IN_DELETE | IN_CREATE |
+ IN_DELETE_SELF | IN_MOVE_SELF |
+ IN_MOVED_TO;
+
+ watch_descriptor = inotify_add_watch(inotify_fd, dir, interest_set);
+ if (watch_descriptor < 0)
+ die_errno("Unable to create inotify watch for %s", dir);
+
+ watch_descriptor = inotify_add_watch(inotify_fd, path, interest_set);
+ if (watch_descriptor < 0)
+ die_errno("Unable to create inotify watch for %s", dir);
+ update_stat_cache(path);
+
+ free(path_copy);
+}
+
+static void watch_directory(int inotify_fd)
+{
+ char buf[PATH_MAX];
+
+ if (!getcwd(buf, sizeof(buf)))
+ die_errno("Unable to get current directory");
+
+ int i = 0;
+ struct dir_struct dir;
+ const char *pathspec[1] = { buf, NULL };
+
+ memset(&dir, 0, sizeof(dir));
+ setup_standard_excludes(&dir);
+
+ fill_directory(&dir, pathspec);
+ for(i = 0; i < dir.nr; i++) {
+ struct dir_entry *ent = dir.entries[i];
+ watch_file(inotify_fd, ent->name);
+ free(ent);
+ }
+
+ free(dir.entries);
+ free(dir.ignored);
+}
+
+static void watch_root_directory(int inotify_fd)
+{
+ char buf[PATH_MAX];
+
+ if (!getcwd(buf, sizeof(buf)))
+ die_errno("Unable to get current directory");
+
+ root_directory_watch_descriptor =
+ inotify_add_watch(inotify_fd, buf, IN_DELETE);
+ if (root_directory_watch_descriptor < 0)
+ die_errno("Unable to watch %s directory", buf);
+}
+
+#define INOTIFY_EVENT_SIZE (sizeof (struct inotify_event) + PATH_MAX + 1)
+
+static void remove_request_file(void)
+{
+ const char *request_path = git_path("REQUEST_WT_STATUS");
+ if (unlink(request_path)) {
+ die_errno("Unable to remove %s on exit",
+ request_path);
+ }
+}
+
+static void loop(int inotify_fd)
+{
+ char buffer[INOTIFY_EVENT_SIZE * 10];
+ int length = 0;
+
+ while (1) {
+ int i = 0;
+ length = read(inotify_fd, buffer, sizeof(buffer));
+ for(i = 0; i < length; ) {
+ struct inotify_event *event =
+ (struct inotify_event*)(buffer+i);
+ /* printf("event: %d %x %d %s\n", event->wd, event->mask,
+ event->len, event->name); */
+ if (request_watch_descriptor == event->wd) {
+ write_stat_cache();
+ } else if (root_directory_watch_descriptor
+ == event->wd) {
+ printf("root directory died!\n");
+ exit(0);
+ } else if (event->mask & IN_Q_OVERFLOW) {
+ restart();
+ } else if (event->mask & IN_MODIFY) {
+ if (event->len)
+ update_stat_cache(event->name);
+ }
+
+ i += sizeof(struct inotify_event) + event->len;
+ }
+ }
+}
+
+int main(int argc, const char **argv)
+{
+ const int inotify_fd = setup_inotify();
+
+ atexit(remove_request_file);
+ setup_environment();
+ watch_control(inotify_fd);
+ watch_root_directory(inotify_fd);
+ watch_directory(inotify_fd);
+ loop(inotify_fd);
+ return 0;
+}
diff --git a/filechange-printer.c b/filechange-printer.c
new file mode 100644
index 0000000..fe43d80
--- /dev/null
+++ b/filechange-printer.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+#include "filechange-cache.h"
+
+int main()
+{
+ struct stat_cache_entry *entry = NULL;
+ const char *missing = "t/t7201-co.sh";
+ read_stat_cache();
+
+ entry = get_stat_cache_entry(missing);
+ printf("%p\n", entry);
+ return 0;
+}
diff --git a/git.c b/git.c
index b10c18b..ea92a65 100644
--- a/git.c
+++ b/git.c
@@ -504,6 +504,31 @@ static int run_argv(int *argcp, const char ***argv)
}
+static void fork_filechange_daemon()
+{
+ struct stat stat_buf;
+ FILE *log = fopen("/tmp/foo.txt", "a");
+ fprintf(log, "cwd = %s\n", get_current_dir_name());
+
+ if (stat(git_path("REQUEST_WT_STATUS"), &stat_buf) == -1) {
+ pid_t child = 0;
+
+ child = fork();
+ fprintf(log, "starting %d\n", (int)child);
+ if (!child) {
+ fclose(log);
+ execl("/home/razeh/src/git/git-filechange-daemon",
+ "/home/razeh/src/git/git-filechange-daemon",
+ get_current_dir_name(),
+ (char*) NULL);
+ die_errno("Unable to launch file change daemon");
+ }
+ } else {
+ fprintf(log, "already running\n");
+ }
+
+}
+
int main(int argc, const char **argv)
{
const char *cmd;
@@ -558,6 +583,8 @@ int main(int argc, const char **argv)
*/
setup_path();
+ fork_filechange_daemon();
+
while (1) {
static int done_help = 0;
static int was_alias = 0;
diff --git a/ll-merge.c b/ll-merge.c
index fb61ea6..7ced2bb 100644
--- a/ll-merge.c
+++ b/ll-merge.c
@@ -6,6 +6,7 @@
#include "cache.h"
#include "attr.h"
+#include "filechange-cache.h"
#include "xdiff-interface.h"
#include "run-command.h"
#include "ll-merge.h"
@@ -195,7 +196,7 @@ static int ll_ext_merge(const struct ll_merge_driver
*fn,
fd = open(temp[1], O_RDONLY);
if (fd < 0)
goto bad;
- if (fstat(fd, &st))
+ if (cached_fstat(fd, &st))
goto close_bad;
result->size = st.st_size;
result->ptr = xmalloc(result->size + 1);
diff --git a/merge-recursive.c b/merge-recursive.c
index ea9dbd3..7d371d6 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -12,6 +12,7 @@
#include "tree-walk.h"
#include "diff.h"
#include "diffcore.h"
+#include "filechange-cache.h"
#include "tag.h"
#include "unpack-trees.h"
#include "string-list.h"
@@ -606,7 +607,7 @@ static char *unique_path(struct merge_options *o,
const char *path, const char *
*p = '_';
while (string_list_has_string(&o->current_file_set, newpath) ||
string_list_has_string(&o->current_directory_set, newpath) ||
- lstat(newpath, &st) == 0)
+ cached_lstat(newpath, &st) == 0)
sprintf(p, "_%d", suffix++);
string_list_insert(&o->current_file_set, newpath);
@@ -634,7 +635,7 @@ static int dir_in_way(const char *path, int
check_working_copy)
}
free(dirpath);
- return check_working_copy && !lstat(path, &st) && S_ISDIR(st.st_mode);
+ return check_working_copy && !cached_lstat(path, &st) &&
S_ISDIR(st.st_mode);
}
static int was_tracked(const char *path)
diff --git a/name-hash.c b/name-hash.c
index d8d25c2..d88185f 100644
--- a/name-hash.c
+++ b/name-hash.c
@@ -7,6 +7,7 @@
*/
#define NO_THE_INDEX_COMPATIBILITY_MACROS
#include "cache.h"
+#include "name-hash.h"
/*
* This removes bit 5 if bit 6 is set.
@@ -20,7 +21,7 @@ static inline unsigned char icase_hash(unsigned char c)
return c & ~((c & 0x40) >> 1);
}
-static unsigned int hash_name(const char *name, int namelen)
+unsigned int hash_name(const char *name, int namelen)
{
unsigned int hash = 0x123;
diff --git a/name-hash.h b/name-hash.h
new file mode 100644
index 0000000..3355d94
--- /dev/null
+++ b/name-hash.h
@@ -0,0 +1 @@
+extern unsigned int hash_name(const char *name, int namelen);
diff --git a/notes-merge.c b/notes-merge.c
index 0f67bd3..f792f83 100644
--- a/notes-merge.c
+++ b/notes-merge.c
@@ -3,6 +3,7 @@
#include "refs.h"
#include "diff.h"
#include "diffcore.h"
+#include "filechange-cache.h"
#include "xdiff-interface.h"
#include "ll-merge.h"
#include "dir.h"
@@ -731,7 +732,7 @@ int notes_merge_commit(struct notes_merge_options *o,
strbuf_addstr(&path, e->d_name);
/* write file as blob, and add to partial_tree */
- if (stat(path.buf, &st))
+ if (cached_stat(path.buf, &st))
die_errno("Failed to stat '%s'", path.buf);
if (index_path(blob_sha1, path.buf, &st, HASH_WRITE_OBJECT))
die("Failed to write blob object from '%s'", path.buf);
diff --git a/path.c b/path.c
index d3d3f8b..6844d2d 100644
--- a/path.c
+++ b/path.c
@@ -11,6 +11,7 @@
* which is what it's designed for.
*/
#include "cache.h"
+#include "filechange-cache.h"
#include "strbuf.h"
#include "string-list.h"
@@ -360,7 +361,7 @@ const char *enter_repo(const char *path, int strict)
for (i = 0; suffix[i]; i++) {
struct stat st;
strcpy(used_path + len, suffix[i]);
- if (!stat(used_path, &st) &&
+ if (!cached_stat(used_path, &st) &&
(S_ISREG(st.st_mode) ||
(S_ISDIR(st.st_mode) && is_git_directory(used_path)))) {
strcat(validated_path, suffix[i]);
@@ -400,7 +401,7 @@ int set_shared_perm(const char *path, int mode)
return 0;
}
if (!mode) {
- if (lstat(path, &st) < 0)
+ if (cached_lstat(path, &st) < 0)
return -1;
mode = st.st_mode;
orig_mode = mode;
diff --git a/read-cache.c b/read-cache.c
index 827ae55..508ddc1 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -8,6 +8,7 @@
#include "cache-tree.h"
#include "refs.h"
#include "dir.h"
+#include "filechange-cache.h"
#include "tree.h"
#include "commit.h"
#include "blob.h"
@@ -672,7 +673,7 @@ int add_to_index(struct index_state *istate, const
char *path, struct stat *st,
int add_file_to_index(struct index_state *istate, const char *path,
int flags)
{
struct stat st;
- if (lstat(path, &st))
+ if (cached_lstat(path, &st))
die_errno("unable to stat '%s'", path);
return add_to_index(istate, path, &st, flags);
}
@@ -1032,7 +1033,7 @@ static struct cache_entry
*refresh_cache_ent(struct index_state *istate,
return ce;
}
- if (lstat(ce->name, &st) < 0) {
+ if (cached_lstat(ce->name, &st) < 0) {
if (err)
*err = errno;
return NULL;
@@ -1430,7 +1431,7 @@ int read_index_from(struct index_state *istate,
const char *path)
die_errno("index file open failed");
}
- if (fstat(fd, &st))
+ if (cached_fstat(fd, &st))
die_errno("cannot stat the open index");
mmap_size = xsize_t(st.st_size);
@@ -1618,7 +1619,7 @@ static void ce_smudge_racily_clean_entry(struct
cache_entry *ce)
*/
struct stat st;
- if (lstat(ce->name, &st) < 0)
+ if (cached_lstat(ce->name, &st) < 0)
return;
if (ce_match_stat_basic(ce, &st))
return;
@@ -1830,7 +1831,7 @@ int write_index(struct index_state *istate, int newfd)
return -1;
}
- if (ce_flush(&c, newfd) || fstat(newfd, &st))
+ if (ce_flush(&c, newfd) || cached_fstat(newfd, &st))
return -1;
istate->timestamp.sec = (unsigned int)st.st_mtime;
istate->timestamp.nsec = ST_MTIME_NSEC(st);
diff --git a/rerere.c b/rerere.c
index a6a5cd5..5115d0e 100644
--- a/rerere.c
+++ b/rerere.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "filechange-cache.h"
#include "string-list.h"
#include "rerere.h"
#include "xdiff-interface.h"
@@ -28,7 +29,7 @@ const char *rerere_path(const char *hex, const char *file)
static int has_rerere_resolution(const char *hex)
{
struct stat st;
- return !stat(rerere_path(hex, "postimage"), &st);
+ return !cached_stat(rerere_path(hex, "postimage"), &st);
}
static void read_rr(struct string_list *rr)
@@ -681,13 +682,13 @@ int rerere_forget(const char **pathspec)
static time_t rerere_created_at(const char *name)
{
struct stat st;
- return stat(rerere_path(name, "preimage"), &st) ? (time_t) 0 :
st.st_mtime;
+ return cached_stat(rerere_path(name, "preimage"), &st) ? (time_t) 0 :
st.st_mtime;
}
static time_t rerere_last_used_at(const char *name)
{
struct stat st;
- return stat(rerere_path(name, "postimage"), &st) ? (time_t) 0 :
st.st_mtime;
+ return cached_stat(rerere_path(name, "postimage"), &st) ? (time_t) 0 :
st.st_mtime;
}
static void unlink_rr_item(const char *name)
diff --git a/setup.c b/setup.c
index 2e1521b..690987a 100644
--- a/setup.c
+++ b/setup.c
@@ -1,5 +1,6 @@
#include "cache.h"
#include "dir.h"
+#include "filechange-cache.h"
#include "string-list.h"
static int inside_git_dir = -1;
@@ -74,7 +75,7 @@ int check_filename(const char *prefix, const char *arg)
name = prefix_filename(prefix, strlen(prefix), arg);
else
name = arg;
- if (!lstat(name, &st))
+ if (!cached_lstat(name, &st))
return 1; /* file exists */
if (errno == ENOENT || errno == ENOTDIR)
return 0; /* file does not exist */
@@ -638,7 +639,7 @@ static const char *setup_nongit(const char *cwd, int
*nongit_ok)
static dev_t get_device_or_die(const char *path, const char *prefix,
int prefix_len)
{
struct stat buf;
- if (stat(path, &buf)) {
+ if (cached_stat(path, &buf)) {
die_errno("failed to stat '%*s%s%s'",
prefix_len,
prefix ? prefix : "",
diff --git a/test-chmtime.c b/test-chmtime.c
index 92713d1..bb5f22a 100644
--- a/test-chmtime.c
+++ b/test-chmtime.c
@@ -81,7 +81,7 @@ int main(int argc, const char *argv[])
struct stat sb;
struct utimbuf utb;
- if (stat(argv[i], &sb) < 0) {
+ if (cached_stat(argv[i], &sb) < 0) {
fprintf(stderr, "Failed to stat %s: %s\n",
argv[i], strerror(errno));
return -1;
diff --git a/test-wildmatch.c b/test-wildmatch.c
index a3e2643..838ff69 100644
--- a/test-wildmatch.c
+++ b/test-wildmatch.c
@@ -19,7 +19,7 @@ static int perf(int ac, char **av)
if (lang && strcmp(lang, "C"))
die("Please test it on C locale.");
- if ((fd = open(file, O_RDONLY)) == -1 || fstat(fd, &st))
+ if ((fd = open(file, O_RDONLY)) == -1 || cached_fstat(fd, &st))
die_errno("file open");
buffer = xmalloc(st.st_size + 2);
diff --git a/unpack-trees.c b/unpack-trees.c
index 09e53df..fc20be4 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -1430,13 +1430,13 @@ static int verify_absent_1(struct cache_entry *ce,
char path[PATH_MAX + 1];
memcpy(path, ce->name, len);
path[len] = 0;
- if (lstat(path, &st))
+ if (cached_lstat(path, &st))
return error("cannot stat '%s': %s", path,
strerror(errno));
return check_ok_to_remove(path, len, DT_UNKNOWN, NULL, &st,
error_type, o);
- } else if (lstat(ce->name, &st)) {
+ } else if (cached_lstat(ce->name, &st)) {
if (errno != ENOENT)
return error("cannot stat '%s': %s", ce->name,
strerror(errno));
@@ -1838,7 +1838,7 @@ int oneway_merge(struct cache_entry **src, struct
unpack_trees_options *o)
int update = 0;
if (o->reset && o->update && !ce_uptodate(old) &&
!ce_skip_worktree(old)) {
struct stat st;
- if (lstat(old->name, &st) ||
+ if (cached_lstat(old->name, &st) ||
ie_match_stat(o->src_index, old, &st,
CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE))
update |= CE_UPDATE;
}
--
1.8.2.rc0.29.g3a0aba8.dirty
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html