Skip to content

Instantly share code, notes, and snippets.

@mmonaco
Created June 13, 2013 03:29
Show Gist options
  • Save mmonaco/5771047 to your computer and use it in GitHub Desktop.
Save mmonaco/5771047 to your computer and use it in GitHub Desktop.
/**
* AVL hashmap
*
* This is used to map file descriptors from
**/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include "avltree.h"
struct avl_node** avl_init() {
return NULL;
}
int avl_insert(struct avl_node** root, int key, const char* data)
{
struct avl_node* new;
/* build new node */
if ((new = malloc(sizeof(struct avl_node))) == NULL)
return -errno;
new->key = key;
new->data = data;
new->left = NULL;
new->right = NULL;
new->height = 0;
/* insert new node */
if (*root == NULL)
return 0;
while (1) {
root->height += 1;
if (key < root->key) {
if (root->left == NULL) {
root->left = new;
break;
}
root = root->left;
} else if (key > root->key) {
if (root->right == NULL) {
root->right = new;
break;
}
root = root->right;
} else {
return -EINVAL;
}
}
return 0;
}
struct avl_node* avl_lookup_node(struct avl_node* root, int key)
{
while (1) {
if (root == NULL)
return NULL;
else if (key == root->key)
return root;
else if (key < root->key)
root = root->left;
else
root = root->right;
}
}
const char* avl_lookup(struct avl_node* root, int key)
{
root = avl_lookup_node(root, key);
if (root != NULL)
return root->data;
}
const char* avl_delete(struct avl_node* root, int key)
{
return NULL;
}
#ifndef __AVLTREE_H__
#define __AVLTREE_H__
struct avl_node {
int key;
const char* data;
struct avl_node* left;
struct avl_node* right;
int height;
};
struct avl_node* avl_init();
int avl_insert(struct avl_node* root, int key, const char* data);
const char* avl_lookup(struct avl_node* root, int key);
const char* avl_delete(struct avl_node* root, int key);
#endif
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/inotify.h>
#include <linux/fcntl.h>
#include <ftw.h>
#include "avltree.h"
const int AVG_PATH_LEN = 16;
const int IN_EVENT_SIZE = sizeof(struct inotify_event);
#define IN_BUFFER_SIZE (16 * (IN_EVENT_SIZE + AVG_PATH_LEN))
const uint32_t IN_MASK = IN_ALL_EVENTS - IN_ACCESS - IN_CLOSE_NOWRITE - IN_OPEN;
#define ESC "\033[0m"
#define BOLD "\033[1m"
#define YELLOW "\033[1;33m"
#define GREEN "\033[1;34m"
#define GREY "\033[1;35m"
#define RED "\033[1;31m"
static struct avl_node** dirmap;
static int in_fd;
void signal_handler(int sig)
{
fprintf(stderr, "Caught SIGINT, exiting.\n");
exit(EXIT_SUCCESS);
}
void print_event(struct inotify_event* ep)
{
const char* name;
int wd;
if (ep->len != 0)
name = ep->name;
else
name = avl_lookup(*dirmap, ep->wd);
printf(BOLD "%s:" ESC, name);
if (ep->mask & IN_ACCESS) fputs(" access", stdout);
if (ep->mask & IN_ATTRIB) fputs(" attrib", stdout);
if (ep->mask & IN_CLOSE_WRITE) fputs(" close_write", stdout);
if (ep->mask & IN_CLOSE_NOWRITE) fputs(" close_nowrite", stdout);
if (ep->mask & IN_CREATE) fputs(" create", stdout);
if (ep->mask & IN_DELETE) fputs(" delete", stdout);
if (ep->mask & IN_DELETE_SELF) fputs(" delete_self", stdout);
if (ep->mask & IN_MODIFY) fputs(" modify", stdout);
if (ep->mask & IN_MOVE_SELF) fputs(" move_self", stdout);
if (ep->mask & IN_MOVED_FROM) fputs(" moved_from", stdout);
if (ep->mask & IN_MOVED_TO) fputs(" moved_to", stdout);
if (ep->mask & IN_MOVE) printf("(%i)", ep->cookie);
if (ep->mask & IN_OPEN) fputs(" open", stdout);
if (ep->mask & (IN_IGNORED | IN_ISDIR | IN_UNMOUNT))
fputs(" |", stdout);
if (ep->mask & IN_IGNORED) fputs(YELLOW " ignored" ESC, stdout);
if (ep->mask & IN_ISDIR) fputs(" isdir", stdout);
if (ep->mask & IN_UNMOUNT) fputs(YELLOW " unmount" ESC, stdout);
if (ep->mask & IN_Q_OVERFLOW) fputs(YELLOW " !!!q_overflow!!!" ESC, stdout);
puts("");
if (ep->mask & (IN_CREATE | IN_ISDIR)) {
wd = inotify_add_watch(in_fd, name, IN_MASK | IN_EXCL_UNLINK);
if (wd < 0) {
printf(GREY "?%s " ESC "%s\n", name, strerror(errno));
}
if (avl_insert(*dirmap, wd, name) < 0) {
perror("error inserting into the dirmap");
exit(EXIT_FAILURE);
}
printf(GREEN "+%s" ESC "\n", name);
} else if (ep->mask & (IN_DELETE | IN_ISDIR)) {
avl_delete(*dirmap, ep->wd);
printf(RED "-%s\n" ESC, name);
}
fflush(stdout);
}
int ftw_visitor(const char* fpath, const struct stat* sb, int typeflag)
{
int wd;
if ( ! (typeflag & FTW_D))
return 0;
wd = inotify_add_watch(in_fd, fpath, IN_MASK | IN_EXCL_UNLINK);
if (wd < 0) {
printf(GREY "?%s " ESC "%s\n", fpath, strerror(errno));
if (errno == ENOSPC)
return 1;
}
if (avl_insert(*dirmap, wd, fpath) < 0) {
perror("error inserting into the dirmap");
exit(EXIT_FAILURE);
}
printf(GREEN "+%s" ESC "\n", fpath);
return 0;
}
int main(int argc, char* argv[])
{
int i, len;
char buffer[IN_BUFFER_SIZE];
struct inotify_event* event;
if (argc != 2) {
fprintf(stderr, "usage: %s path\n", argv[0]);
return EXIT_FAILURE;
}
if ((in_fd = inotify_init()) < 0) {
perror("inotify_init() has failed");
return EXIT_FAILURE;
}
if (ftw(argv[1], ftw_visitor, 64) < 0) {
perror("error walking subdirs");
return EXIT_FAILURE;
}
if (signal(SIGINT, signal_handler) == SIG_ERR) {
perror("error registering for SIGINT");
return EXIT_FAILURE;
}
while (1) {
i = 0;
if ((len = read(in_fd, buffer, IN_BUFFER_SIZE)) <= 1) {
perror("error reading inotify event");
break;
}
while (i < len) {
event = (struct inotify_event*) &buffer[i];
print_event(event);
i += IN_EVENT_SIZE + event->len;
}
puts("");
}
close(in_fd);
return EXIT_FAILURE;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment