mirror of
https://github.com/NixOS/nixpkgs.git
synced 2024-11-17 19:21:04 +00:00
Merge pull request #318358 from shyim/add-fsnotifier-package
fsnotifier: init at 2024.2.0
This commit is contained in:
commit
f5129fb42b
288
pkgs/by-name/fs/fsnotifier/fsnotifier.patch
Normal file
288
pkgs/by-name/fs/fsnotifier/fsnotifier.patch
Normal file
|
@ -0,0 +1,288 @@
|
|||
diff --git a/fsnotifier.h b/fsnotifier.h
|
||||
index e7b2a42456bc..9dfb61d8d5d0 100644
|
||||
--- a/fsnotifier.h
|
||||
+++ b/fsnotifier.h
|
||||
@@ -61,7 +61,7 @@ bool init_inotify(void);
|
||||
void set_inotify_callback(void (*callback)(const char *, uint32_t));
|
||||
int get_inotify_fd(void);
|
||||
int watch(const char* root, array* mounts);
|
||||
-void unwatch(int id);
|
||||
+void unwatch(int id, char* path, unsigned int path_len);
|
||||
bool process_inotify_input(void);
|
||||
void close_inotify(void);
|
||||
|
||||
diff --git a/inotify.c b/inotify.c
|
||||
index a42846379476..0a33eded78bf 100644
|
||||
--- a/inotify.c
|
||||
+++ b/inotify.c
|
||||
@@ -22,6 +22,8 @@ typedef struct watch_node_str {
|
||||
struct watch_node_str* parent;
|
||||
array* kids;
|
||||
unsigned int path_len;
|
||||
+ struct watch_node_str* prev;
|
||||
+ struct watch_node_str* next;
|
||||
char path[];
|
||||
} watch_node;
|
||||
|
||||
@@ -102,7 +104,7 @@ int get_inotify_fd(void) {
|
||||
|
||||
#define EVENT_MASK (IN_MODIFY | IN_ATTRIB | IN_CREATE | IN_DELETE | IN_MOVE | IN_DELETE_SELF | IN_MOVE_SELF)
|
||||
|
||||
-static int add_watch(unsigned int path_len, watch_node* parent) {
|
||||
+static int add_watch(unsigned int path_len, watch_node* parent, watch_node** out) {
|
||||
int wd = inotify_add_watch(inotify_fd, path_buf, EVENT_MASK);
|
||||
if (wd < 0) {
|
||||
if (errno == EACCES || errno == ENOENT) {
|
||||
@@ -123,36 +125,39 @@ static int add_watch(unsigned int path_len, watch_node* parent) {
|
||||
userlog(LOG_INFO, "watching %s: %d", path_buf, wd);
|
||||
}
|
||||
|
||||
- watch_node* node = table_get(watches, wd);
|
||||
- if (node != NULL) {
|
||||
- if (node->wd != wd) {
|
||||
- userlog(LOG_ERR, "table error: corruption at %d:%s / %d:%s / %d", wd, path_buf, node->wd, node->path, watch_count);
|
||||
- return ERR_ABORT;
|
||||
- }
|
||||
- else if (strcmp(node->path, path_buf) != 0) {
|
||||
- char buf1[PATH_MAX], buf2[PATH_MAX];
|
||||
- const char* normalized1 = realpath(node->path, buf1);
|
||||
- const char* normalized2 = realpath(path_buf, buf2);
|
||||
- if (normalized1 == NULL || normalized2 == NULL || strcmp(normalized1, normalized2) != 0) {
|
||||
- userlog(LOG_ERR, "table error: collision at %d (new %s, existing %s)", wd, path_buf, node->path);
|
||||
- return ERR_ABORT;
|
||||
- }
|
||||
- else {
|
||||
- userlog(LOG_INFO, "intersection at %d: (new %s, existing %s, real %s)", wd, path_buf, node->path, normalized1);
|
||||
- return ERR_IGNORE;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return wd;
|
||||
- }
|
||||
-
|
||||
- node = malloc(sizeof(watch_node) + path_len + 1);
|
||||
+ watch_node* existing = table_get(watches, wd);
|
||||
+ if (existing != NULL) {
|
||||
+ for (;;) {
|
||||
+ if (existing->wd != wd) {
|
||||
+ userlog(LOG_ERR, "table error: corruption at %d:%s / %d:%s / %d", wd, path_buf, existing->wd, existing->path, watch_count);
|
||||
+ return ERR_ABORT;
|
||||
+ }
|
||||
+ if (existing->path_len == path_len && strncmp(existing->path, path_buf, path_len) == 0) {
|
||||
+ return wd;
|
||||
+ }
|
||||
+ char buf1[PATH_MAX], buf2[PATH_MAX];
|
||||
+ const char* normalized1 = realpath(existing->path, buf1);
|
||||
+ const char* normalized2 = realpath(path_buf, buf2);
|
||||
+ if (normalized1 != NULL && normalized2 != NULL && strcmp(normalized1, normalized2) == 0) {
|
||||
+ userlog(LOG_INFO, "intersection at %d: (new %s, existing %s, real %s)", wd, path_buf, existing->path, normalized1);
|
||||
+ return ERR_IGNORE;
|
||||
+ }
|
||||
+ if (existing->next == NULL) {
|
||||
+ break;
|
||||
+ }
|
||||
+ existing = existing->next;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ watch_node* node = malloc(sizeof(watch_node) + path_len + 1);
|
||||
CHECK_NULL(node, ERR_ABORT)
|
||||
memcpy(node->path, path_buf, path_len + 1);
|
||||
node->path_len = path_len;
|
||||
node->wd = wd;
|
||||
node->parent = parent;
|
||||
node->kids = NULL;
|
||||
+ node->prev = existing;
|
||||
+ node->next = NULL;
|
||||
|
||||
if (parent != NULL) {
|
||||
if (parent->kids == NULL) {
|
||||
@@ -162,11 +167,15 @@ static int add_watch(unsigned int path_len, watch_node* parent) {
|
||||
CHECK_NULL(array_push(parent->kids, node), ERR_ABORT)
|
||||
}
|
||||
|
||||
- if (table_put(watches, wd, node) == NULL) {
|
||||
+ if (existing != NULL) {
|
||||
+ existing->next = node;
|
||||
+ }
|
||||
+ else if (table_put(watches, wd, node) == NULL) {
|
||||
userlog(LOG_ERR, "table error: unable to put (%d:%s)", wd, path_buf);
|
||||
return ERR_ABORT;
|
||||
}
|
||||
|
||||
+ *out = node;
|
||||
return wd;
|
||||
}
|
||||
|
||||
@@ -177,22 +186,27 @@ static void watch_limit_reached(void) {
|
||||
}
|
||||
}
|
||||
|
||||
-static void rm_watch(int wd, bool update_parent) {
|
||||
- watch_node* node = table_get(watches, wd);
|
||||
- if (node == NULL) {
|
||||
- return;
|
||||
+static void rm_watch(watch_node* node, bool update_parent) {
|
||||
+ if (node->prev != NULL) {
|
||||
+ node->prev->next = node->next;
|
||||
+ node->next->prev = node->prev;
|
||||
}
|
||||
-
|
||||
- userlog(LOG_INFO, "unwatching %s: %d (%p)", node->path, node->wd, node);
|
||||
-
|
||||
- if (inotify_rm_watch(inotify_fd, node->wd) < 0) {
|
||||
- userlog(LOG_INFO, "inotify_rm_watch(%d:%s): %s", node->wd, node->path, strerror(errno));
|
||||
+ else if (node->next != NULL) {
|
||||
+ table_put(watches, node->wd, node->next);
|
||||
+ node->next->prev = NULL;
|
||||
+ }
|
||||
+ else {
|
||||
+ userlog(LOG_INFO, "unwatching %s: %d (%p)", node->path, node->wd, node);
|
||||
+ if (inotify_rm_watch(inotify_fd, node->wd) < 0) {
|
||||
+ userlog(LOG_INFO, "inotify_rm_watch(%d:%s): %s", node->wd, node->path, strerror(errno));
|
||||
+ }
|
||||
+ table_put(watches, node->wd, NULL);
|
||||
}
|
||||
|
||||
for (int i = 0; i < array_size(node->kids); i++) {
|
||||
watch_node* kid = array_get(node->kids, i);
|
||||
if (kid != NULL) {
|
||||
- rm_watch(kid->wd, false);
|
||||
+ rm_watch(kid, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,7 +221,6 @@ static void rm_watch(int wd, bool update_parent) {
|
||||
|
||||
array_delete(node->kids);
|
||||
free(node);
|
||||
- table_put(watches, wd, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -234,7 +247,9 @@ static int walk_tree(unsigned int path_len, watch_node* parent, bool recursive,
|
||||
}
|
||||
}
|
||||
|
||||
- int id = add_watch(path_len, parent);
|
||||
+
|
||||
+ watch_node* node;
|
||||
+ int id = add_watch(path_len, parent, &node);
|
||||
|
||||
if (dir == NULL) {
|
||||
return id;
|
||||
@@ -271,7 +286,7 @@ static int walk_tree(unsigned int path_len, watch_node* parent, bool recursive,
|
||||
|
||||
int subdir_id = walk_tree(path_len + 1 + name_len, table_get(watches, id), recursive, mounts);
|
||||
if (subdir_id < 0 && subdir_id != ERR_IGNORE) {
|
||||
- rm_watch(id, true);
|
||||
+ rm_watch(node, true);
|
||||
id = subdir_id;
|
||||
break;
|
||||
}
|
||||
@@ -323,47 +338,49 @@ int watch(const char* root, array* mounts) {
|
||||
}
|
||||
|
||||
|
||||
-void unwatch(int id) {
|
||||
- rm_watch(id, true);
|
||||
+void unwatch(int wd, char* path, unsigned int path_len) {
|
||||
+ for (watch_node* node = table_get(watches, wd); node != NULL; node = node->next) {
|
||||
+ if (node->path_len == path_len && strncmp(node->path, path, path_len) == 0) {
|
||||
+ rm_watch(node, true);
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
|
||||
static bool process_inotify_event(struct inotify_event* event) {
|
||||
- watch_node* node = table_get(watches, event->wd);
|
||||
- if (node == NULL) {
|
||||
- return true;
|
||||
- }
|
||||
-
|
||||
- bool is_dir = (event->mask & IN_ISDIR) == IN_ISDIR;
|
||||
- userlog(LOG_INFO, "inotify: wd=%d mask=%d dir=%d name=%s", event->wd, event->mask & (~IN_ISDIR), is_dir, node->path);
|
||||
-
|
||||
- unsigned int path_len = node->path_len;
|
||||
- memcpy(path_buf, node->path, path_len + 1);
|
||||
- if (event->len > 0) {
|
||||
- path_buf[path_len] = '/';
|
||||
- unsigned int name_len = strlen(event->name);
|
||||
- memcpy(path_buf + path_len + 1, event->name, name_len + 1);
|
||||
- path_len += name_len + 1;
|
||||
- }
|
||||
+ for (watch_node* node = table_get(watches, event->wd); node != NULL; node = node->next) {
|
||||
+ bool is_dir = (event->mask & IN_ISDIR) == IN_ISDIR;
|
||||
+ userlog(LOG_INFO, "inotify: wd=%d mask=%d dir=%d name=%s", event->wd, event->mask & (~IN_ISDIR), is_dir, node->path);
|
||||
+
|
||||
+ unsigned int path_len = node->path_len;
|
||||
+ memcpy(path_buf, node->path, path_len + 1);
|
||||
+ if (event->len > 0) {
|
||||
+ path_buf[path_len] = '/';
|
||||
+ unsigned int name_len = strlen(event->name);
|
||||
+ memcpy(path_buf + path_len + 1, event->name, name_len + 1);
|
||||
+ path_len += name_len + 1;
|
||||
+ }
|
||||
|
||||
- if (callback != NULL) {
|
||||
- (*callback)(path_buf, event->mask);
|
||||
- }
|
||||
+ if (callback != NULL) {
|
||||
+ (*callback)(path_buf, event->mask);
|
||||
+ }
|
||||
|
||||
- if (is_dir && event->mask & (IN_CREATE | IN_MOVED_TO)) {
|
||||
- int result = walk_tree(path_len, node, true, NULL);
|
||||
- if (result < 0 && result != ERR_IGNORE && result != ERR_CONTINUE) {
|
||||
- return false;
|
||||
+ if (is_dir && event->mask & (IN_CREATE | IN_MOVED_TO)) {
|
||||
+ int result = walk_tree(path_len, node, true, NULL);
|
||||
+ if (result < 0 && result != ERR_IGNORE && result != ERR_CONTINUE) {
|
||||
+ return false;
|
||||
+ }
|
||||
}
|
||||
- }
|
||||
|
||||
- if (is_dir && event->mask & (IN_DELETE | IN_MOVED_FROM)) {
|
||||
- for (int i = 0; i < array_size(node->kids); i++) {
|
||||
- watch_node* kid = array_get(node->kids, i);
|
||||
- if (kid != NULL && strncmp(path_buf, kid->path, kid->path_len) == 0) {
|
||||
- rm_watch(kid->wd, false);
|
||||
- array_put(node->kids, i, NULL);
|
||||
- break;
|
||||
+ if (is_dir && event->mask & (IN_DELETE | IN_MOVED_FROM)) {
|
||||
+ for (int i = 0; i < array_size(node->kids); i++) {
|
||||
+ watch_node* kid = array_get(node->kids, i);
|
||||
+ if (kid != NULL && strncmp(path_buf, kid->path, kid->path_len) == 0) {
|
||||
+ rm_watch(kid, false);
|
||||
+ array_put(node->kids, i, NULL);
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/main.c b/main.c
|
||||
index b6b2e6fdb5b0..32cc8efe7856 100644
|
||||
--- a/main.c
|
||||
+++ b/main.c
|
||||
@@ -246,7 +246,7 @@ static void unregister_roots(void) {
|
||||
watch_root* root;
|
||||
while ((root = array_pop(roots)) != NULL) {
|
||||
userlog(LOG_INFO, "unregistering root: %s", root->path);
|
||||
- unwatch(root->id);
|
||||
+ unwatch(root->id, root->path, strlen(root->path));
|
||||
free(root->path);
|
||||
free(root);
|
||||
}
|
||||
@@ -422,7 +422,7 @@ static void check_root_removal(const char* path) {
|
||||
for (int i = 0; i < array_size(roots); i++) {
|
||||
watch_root* root = array_get(roots, i);
|
||||
if (root->id >= 0 && strcmp(path, UNFLATTEN(root->path)) == 0) {
|
||||
- unwatch(root->id);
|
||||
+ unwatch(root->id, root->path, strlen(root->path));
|
||||
root->id = -1;
|
||||
userlog(LOG_INFO, "root deleted: %s\n", root->path);
|
||||
report_event("DELETE", path);
|
||||
|
39
pkgs/by-name/fs/fsnotifier/package.nix
Normal file
39
pkgs/by-name/fs/fsnotifier/package.nix
Normal file
|
@ -0,0 +1,39 @@
|
|||
{ lib
|
||||
, stdenv
|
||||
, fetchFromGitHub
|
||||
}:
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
version = "2024.2.0";
|
||||
pname = "fsnotifier";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "JetBrains";
|
||||
repo = "intellij-community";
|
||||
rev = "0f6d9ccb67b8fcad0d802cd76209d503c4ed66a6";
|
||||
sha256 = "3TAiVvKi50JQRrVG6J7LUJKTiuOTDyKt4DhoA1QmbrM=";
|
||||
sparseCheckout = [ "native/fsNotifier/linux" ];
|
||||
};
|
||||
|
||||
# fix for hard-links in nix-store, https://github.com/JetBrains/intellij-community/pull/2171
|
||||
patches = [ ./fsnotifier.patch ];
|
||||
|
||||
sourceRoot = "${src.name}/native/fsNotifier/linux";
|
||||
|
||||
buildPhase = ''
|
||||
mkdir -p $out/bin
|
||||
|
||||
$CC -O2 -Wall -Wextra -Wpedantic -D "VERSION=\"${version}\"" -std=c11 main.c inotify.c util.c -o fsnotifier
|
||||
|
||||
cp fsnotifier $out/bin/fsnotifier
|
||||
'';
|
||||
|
||||
meta = {
|
||||
homepage = "https://github.com/JetBrains/intellij-community/tree/master/native/fsNotifier/linux";
|
||||
description = "IntelliJ Platform companion program for watching and reporting file and directory structure modification";
|
||||
license = lib.licenses.asl20;
|
||||
mainProgram = "fsnotifier";
|
||||
maintainers = with lib.maintainers; [ shyim ];
|
||||
platforms = lib.platforms.linux;
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue