static void parse_join(const char *bytes, size_t len, struct user *user, int kq) { struct channel *c; struct list *lp; if (*bytes != '#') { cmderr(user, CHSHARP, kq); return; } if (illegal_name(bytes, len, user, kq, CHEMTPY, CHILLEGAL)) return; if ((c = table_get(channels, bytes, len)) == NULL) { c = chancpy(bytes, len); table_put(channels, c->name, c->len, c); } else for (short i = 0; i < user->nchans; i++) if (user->joined_chans[i] == c) { cmderr(user, CHJOINED, kq); return; } if (user->nchans == NELEMS(user->joined_chans)) { cmderr(user, CHTOOMANY, kq); return; } user->joined_chans[user->nchans++] = c; lp = list(user); SLIST_INSERT_HEAD(&c->users, lp, next); ok(user, kq); }
static void rm_watch(int wd, bool update_parent) { watch_node* node = table_get(watches, wd); if (node == NULL) { return; } userlog(LOG_DEBUG, "unwatching %s: %d (%p)", node->path, node->wd, node); if (inotify_rm_watch(inotify_fd, node->wd) < 0) { userlog(LOG_DEBUG, "inotify_rm_watch(%d:%s): %s", node->wd, node->path, strerror(errno)); } 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); } } if (update_parent && node->parent != NULL) { for (int i=0; i<array_size(node->parent->kids); i++) { if (array_get(node->parent->kids, i) == node) { array_put(node->parent->kids, i, NULL); break; } } } array_delete(node->kids); free(node); table_put(watches, wd, NULL); }
int test_remove( void ) { ASSERT_TRUE(table_put(&test_table, L"test2", value, NULL)); ASSERT_TRUE(table_has(&test_table, L"test2")); table_remove(&test_table, L"test2", NULL); ASSERT_FALSE(table_has(&test_table, L"test2")); return 0; }
/* * constructs a default set for configuration variables * * conf_preset() cannot be implemented with conf_set() since they differ in handling an omitted * section name. conf_section() cannot affect conf_preset() because the former is not callable * before the latter. Thus, conf_preset() can safely assume that a section name is given properly * whenever necessary. On the other hand, because conf_set() is affected by conf_section(), a * variable name without a section name and a period should be recognized as referring to the * current section, not to the global section. * * TODO: * - some adjustment on arguments to table_new() is necessary; * - considering changes to the format of a configuration file as a program to accept it is * upgraded, making it a recoverable error to encounter a non-preset section or variable name * would be useful; this enables an old version of the program to accept a new configuration * file with diagnostics. */ int (conf_preset)(const conf_t *tab, int ctrl) { size_t len; char *pbuf, *sec, *var; const char *hkey; table_t *t; struct valnode_t *pnode; assert(!section); assert(tab); control = ctrl; section = table_new(0, NULL, NULL); errcode = CONF_ERR_OK; for (; tab->var; tab++) { assert(tab->defval); assert(tab->type == CONF_TYPE_BOOL || tab->type == CONF_TYPE_INT || tab->type == CONF_TYPE_UINT || tab->type == CONF_TYPE_REAL || tab->type == CONF_TYPE_STR); len = strlen(tab->var); pbuf = strcpy(MEM_ALLOC(len+1 + strlen(tab->defval)+1), tab->var); if (sep(pbuf, &sec, &var) != CONF_ERR_OK) { MEM_FREE(pbuf); break; /* sep sets errcode */ } if (!sec) /* means global section in this case */ sec = ""; /* lower modifies sec only when necessary */ hkey = hash_string((control & CONF_OPT_CASE)? sec: lower(sec)); t = table_get(section, hkey); if (!t) { /* new section */ t = table_new(0, NULL, NULL); table_put(section, hkey, t); } MEM_NEW(pnode); pnode->type = tab->type; pnode->freep = pbuf; pnode->val = strcpy(pbuf + len+1, tab->defval); table_put(t, hash_string((control & CONF_OPT_CASE)? var: lower(var)), pnode); } preset = 1; return errcode; }
static int add_watch(const char* path, watch_node* parent) { int wd = inotify_add_watch(inotify_fd, path, IN_MODIFY | IN_ATTRIB | IN_CREATE | IN_DELETE | IN_MOVE | IN_DELETE_SELF); if (wd < 0) { if (errno == ENOSPC) { limit_reached = true; } userlog(LOG_ERR, "inotify_add_watch(%s): %s", path, strerror(errno)); return ERR_CONTINUE; } else { userlog(LOG_DEBUG, "watching %s: %d", path, wd); } watch_node* node = table_get(watches, wd); if (node != NULL) { if (node->wd != wd || strcmp(node->name, path) != 0) { char buf1[PATH_MAX], buf2[PATH_MAX]; const char* normalized1 = realpath(node->name, buf1); const char* normalized2 = realpath(path, buf2); if (normalized1 == NULL || normalized2 == NULL || strcmp(normalized1, normalized2) != 0) { userlog(LOG_ERR, "table error: collision at %d (new %s, existing %s)", wd, path, node->name); return ERR_ABORT; } else { userlog(LOG_WARNING, "intersection at %d: (new %s, existing %s, real %s)", wd, path, node->name, normalized1); return ERR_IGNORE; } } return wd; } node = malloc(sizeof(watch_node)); CHECK_NULL(node); node->name = strdup(path); CHECK_NULL(node->name); node->wd = wd; node->parent = parent; node->kids = NULL; if (parent != NULL) { if (parent->kids == NULL) { parent->kids = array_create(DEFAULT_SUBDIR_COUNT); CHECK_NULL(parent->kids); } CHECK_NULL(array_push(parent->kids, node)); } if (table_put(watches, wd, node) == NULL) { userlog(LOG_ERR, "table error: unable to put (%d:%s)", wd, path); return ERR_ABORT; } return wd; }
int init_tests( void ) { ASSERT_TRUE(table_create(&test_table, HASH_DEFAULT_SIZE)); value = (int*) malloc(sizeof(int)); ASSERT_NOT_NULL(value); *value = 0; ASSERT_TRUE(table_put(&test_table, L"test", value, NULL)); return 0; }
/* * This function implements the "object[key] = value" syntax in the language. * The semantics depend on the type of object, but the idea is that @value is set to the * sub-value with specified @key in @object. */ kj_internal void vm_set_property(vm_t *vm, value_t *object, value_t const *key, value_t const *value) { switch (object->type) { case KJ_TYPE_TABLE: table_put(&object->table->table, vm->allocator, key, value); break; default: vm_throw(vm, "invalid set operation performed on value of type %s.", VALUE_TYPE_STRING[object->type]); } }
void _update_bind_desc(_controls_menu *data) { Uint32 normal = COLOR_MENU_TEXT; for (int i = 0; i < 5; i++) { table_put(data->m_bindingsMenu->m_aColors, i, &normal); } table_put(data->m_cmdMenu->m_aColors, 2, &normal); data->m_bindingsConflict = false; // check for conflicts for (int i = 0; i < 4; i++) { for (int j = i+1; j < 5; j++) { if (! input_bindings_conflict(&(data->m_aControls[i]), &(data->m_aControls[j]))) { continue; } Uint32 red = 0xff0000ff, disabled = COLOR_MENU_DISABLED; table_put(data->m_bindingsMenu->m_aColors, i, &red); table_put(data->m_bindingsMenu->m_aColors, j, &red); table_put(data->m_cmdMenu->m_aColors, 2, &disabled); data->m_bindingsConflict = true; } } for (int i = 0; i < 5; i++) { char *desc; table_get(data->m_bindingsMenu->m_aValues, i, &desc); free(desc); desc = _bind_desc(&(data->m_aControls[i])); table_put(data->m_bindingsMenu->m_aValues, i, &desc); } }
void menu_set_value(menu *pMenu, const char *fmt, ...) { char* cText = (char*) malloc(512); if (! cText) { debug_print("Out of memory.\n"); sys_abort(); } va_list vArgs; va_start(vArgs, fmt); vsnprintf(cText, 512, fmt, vArgs); va_end(vArgs); table_put(pMenu->m_aValues, pMenu->m_aValues->m_len-1, &cText); }
void pass1(char *filename) { printf("============== pass1 ===============\n"); FILE *file = fopen(filename, "rt"); char line[MAX_LEN], label[MAX_LEN], op[MAX_LEN], param[MAX_LEN]; UINT16 address = 0; while (fgets(line, MAX_LEN, file)) { printf("%04x %s", address, line); parse(line, label, op, param); if (!strcmp(label, "")==0) { if (!table_put(symTable, &symTop, label, address)) { printf("Error: symbol %s duplicate\n", label); exit(1); } } address += 2; } fclose(file); }
void ws(char *name, FILE *fp) { table_t table ; char buf[128]; char *word; int *count; void **ar; int i; table = NULL; word = NULL; ar = NULL; memset(buf, 0, sizeof(buf)); table = table_new(4096, cmpstring, hashcode); while(getword(fp, buf, sizeof(buf))) { word = (char *) mem_calloc(1, strlen(buf) + 1); assert(word); strcpy(word, buf); count = table_get(table, word); if(count) { (*count)++; }else { count = (int *) mem_calloc(1, sizeof(*count)); assert(count); *count = 1; table_put(table, word, count); } }/*while*/ if(name) printf("%s:\n",name); printf("table has keys:%d\n", table_length(table)); ar = table_to_array(table, NULL); qsort(ar, table_length(table), 2 * sizeof(*ar), cmp); for(i = 0; ar[i]; i += 2) { printf("%d\t%s\n", *(int *)ar[i+1], (char *)ar[i]); } }
/* Função para adicionar um par chave valor na tabela. * Devolve 0 (ok) ou -1 (problemas). */ int ptable_put(struct ptable_t *ptable, char *key, struct data_t *value) { uint16_t result,size; result = -1; if(ptable->isOpen) { struct message_t *msg; char *msg_buffer, *buffer; result = table_put(ptable->table,key,value); if(result==0) { msg = (struct message_t*) malloc(sizeof(struct message_t)); msg->opcode = OC_PUT; msg->c_type = CT_ENTRY; msg->content.entry = entry_create(key,value); // size = message_to_buffer(msg,&msg_buffer); //Alocar memoria buffer = (char *) malloc(size+sizeof(uint16_t)); if(buffer == NULL) { perror("Out of memory"); return -1; } //Copiar o tamanho da mensagem memcpy(buffer,&size,sizeof(uint16_t)); //Copiar a mensagem memcpy(buffer+sizeof(uint16_t),msg_buffer,size); //Escrever mensagem if(pmanager_log(ptable->pmanager,buffer)==-1) { printf("Falha na escrita\n"); } //Free(s) free(buffer); free(msg_buffer); free_message(msg); } } return result; }
static void parse_login(const char *bytes, size_t len, struct user *user, int kq) { if (user->name != NULL) { cmderr(user, ULOGGED, kq); return; } if (*bytes == '#') { cmderr(user, USHARP, kq); return; } if (illegal_name(bytes, len, user, kq, UEMPTY, UILLEGAL)) return; if (table_get(users, bytes, len)) { cmderr(user, UUSED, kq); return; } user->name = malloc_or_die(len); bcopy(bytes, user->name, len); user->namelen = len; table_put(users, user->name, user->namelen, user); ok(user, kq); }
void wf(const char *name, FILE *fp) { table_t table = table_new(0, NULL, NULL); char buf[BUFSIZ]; while (getword(fp, buf, sizeof(buf), first, rest)) { const char *word; int i, *count; for (i=0; buf[i] != '\0'; i++) buf[i] = tolower(buf[i]); word = atom_string(buf); count = table_get(table, word); if (count) { (*count) ++; } else { count = (int *)zalloc(sizeof (*count)); *count = 1; table_put(table, word, count); } } if (name) { printf("%s:\n", name); } /* print the words */ int i; void **array = table_to_array(table, NULL); qsort(array, table_length(table), 2*sizeof(*array), cmp); for (i = 0; array[i]; i+=2) { printf("%d\t%s\n", *(int *)array[i+1], (char *)array[i]); } zfree(array); /* destroy the table */ table_free(&table, vfree); }
void menu_set_color(menu *pMenu, Uint32 color) { table_put(pMenu->m_aColors, pMenu->m_aColors->m_len-1, &color); }
int main(int argc, char **argv) { int r, op = 'p', method = 'c'; const char *path; if (argc < 2) { fprintf(stderr, "usage: kv dbpath [put|get] [col|table|hash|pat|ql] [value_size]\n"); return -1; } path = *argv[1] ? argv[1] : NULL; if (argc > 2) { op = *argv[2]; } if (argc > 3) { method = *argv[3]; } if (argc > 4) { value_size = atoi(argv[4]); } if (argc > 5) { nloops = atoi(argv[5]); } if (grn_init()) { fprintf(stderr, "grn_init() failed\n"); return -1; } if (grn_ctx_init(&ctx, (method == 'q' ? GRN_CTX_USE_QL|GRN_CTX_BATCH_MODE : 0))) { fprintf(stderr, "grn_ctx_init() failed\n"); return -1; } srand(0); if (method == 'h' || method == 'p') { switch (method) { case 'h' : r = (op == 'p') ? hash_put(path) : hash_get(path); break; case 'p' : r = (op == 'p') ? pat_put(path) : pat_get(path); break; default : r = -1; fprintf(stderr, "invalid method\n"); break; } } else { if (path) { db = grn_db_open(&ctx, path); } if (!db) { db = grn_db_create(&ctx, path, NULL); } if (!db) { fprintf(stderr, "db initialize failed\n"); return -1; } value_type = grn_type_create(&ctx, "<value_type>", 12, 0, value_size); switch (method) { case 'q' : r = (op == 'p') ? ql_put() : ql_get(); break; case 'c' : r = (op == 'p') ? column_put() : column_get(); break; case 't' : r = (op == 'p') ? table_put() : table_get(); //r = (op == 'p') ? table_put_allocate() : table_get(); //r = (op == 'p') ? table_put2() : table_get(); break; default : r = -1; fprintf(stderr, "invalid method\n"); break; } if (grn_obj_close(&ctx, db)) { fprintf(stderr, "grn_obj_close() failed\n"); return -1; } } if (grn_ctx_fin(&ctx)) { fprintf(stderr, "grn_ctx_fin() failed\n"); return -1; } if (grn_fin()) { fprintf(stderr, "grn_fin() failed\n"); return -1; } return r; }
/* * reads a configuration file and constructs the configuration data * * A tricky construct using do-while for reading lines from a file is to allow for a configuration * file that does not end with a newline. Asserting that BUFLEN is greater than 1 is necessary to * prevent fgets() from returning an empty string even if there are still characters unread. * TODO: * - some adjustment on arguments to table_new() is necessary */ size_t (conf_init)(FILE *fp, int ctrl) { char *p; size_t buflen, len; size_t lineno, nlineno; const char *hkey; table_t *tab; struct valnode_t *pnode; assert(fp); assert(preset || !section); assert(!current); assert(BUFLEN > 1); if (!preset) { control = ctrl; /* if preset, ctrl ignored */ section = table_new(0, NULL, NULL); } tab = NULL; errcode = CONF_ERR_OK; lineno = nlineno = 0; len = 0; p = MEM_ALLOC(buflen=BUFLEN); *p = '\0'; do { assert(buflen - len > 1); fgets(p+len, buflen-len, fp); if (ferror(fp)) { errcode = CONF_ERR_IO; break; } len += strlen(p+len); if (len == 0) /* EOF and no remaining data */ break; if (len > 2 && p[len-2] == '\\' && p[len-1] == '\n') { /* line splicing */ int c; nlineno++; len -= 2; if (len > 0 && isspace(p[len-1])) { while (--len > 0 && isspace(p[len-1])) continue; p[len++] = ' '; } if ((c = getc(fp)) != EOF && c != '\n' && isspace(c)) { if (p[len-1] != ' ') p[len++] = ' '; while ((c = getc(fp)) != EOF && c != '\n' && isspace(c)) continue; } else if (c == EOF) { /* no following line for slicing */ lineno += nlineno; errcode = CONF_ERR_BSLASH; goto retcode; } ungetc(c, fp); p[len] = '\0'; /* at worst, backslash is replaced with space and newline with null, thus room for two characters, which guarantees buflen-len greater than 1 */ } else if (p[len-1] == '\n' || feof(fp)) { /* line completed */ int type; char *s, *t, *var, *val; lineno++; if (p[len-1] == '\n') p[--len] = '\0'; /* in fact, no need to adjust len */ var = triml(p); switch(*var) { case '[': /* section specification */ cmtrem(++var); s = strchr(var, ']'); if (!s) { errcode = CONF_ERR_LINE; goto retcode; } *s = '\0'; if (sepunit(var, &var) != CONF_ERR_OK) goto retcode; /* sepunit sets errcode */ hkey = hash_string((control & CONF_OPT_CASE)? var: lower(var)); tab = table_get(section, hkey); if (!tab) { if (preset) { errcode = CONF_ERR_SEC; goto retcode; } tab = table_new(0, NULL, NULL); } table_put(section, hkey, tab); /* no break */ case '\0': /* empty line */ case '#': /* comment-only line */ case ';': break; /* reuses existing buffer */ default: /* variable = value */ val = p + strcspn(p, "#;"); s = strchr(var, '='); if (!s || val < s) { errcode = CONF_ERR_LINE; goto retcode; } *s = '\0'; if (sepunit(var, &var) != CONF_ERR_OK) goto retcode; /* sepunit() sets errcode */ if (*(unsigned char *)var == '\0') { /* empty variable name */ errcode = CONF_ERR_VAR; goto retcode; } val = triml(++s); if (*val == '"' || *val == '\'') { /* quoted */ char end = *val; /* remembers for match */ t = s = ++val; /* starts copying from s to t */ do { switch(*s) { case '\\': /* escape sequence */ if (control & CONF_OPT_ESC) *(unsigned char *)t++ = escseq(*(unsigned char *)++s); else { *t++ = '\\'; *(unsigned char *)t++ = *(unsigned char *)++s; } break; case '\0': /* unclosed ' or " */ errcode = CONF_ERR_LINE; goto retcode; case '\'': case '\"': if (*s == end) { *t = '\0'; break; } /* no break */ default: /* literal copy */ *(unsigned char *)t++ = *(unsigned char *)s; break; } s++; } while(*(unsigned char *)t != '\0'); /* checks if any trailing invalid char */ cmtrem(s); trimt(s); if (*(unsigned char *)s != '\0') { errcode = CONF_ERR_LINE; goto retcode; } } else { /* unquoted */ cmtrem(val); trimt(val); } if (!tab) { /* global section */ hkey = hash_string(""); tab = table_get(section, hkey); if (!tab) { if (preset) { errcode = CONF_ERR_SEC; goto retcode; } tab = table_new(0, NULL, NULL); } table_put(section, hkey, tab); } hkey = hash_string((control & CONF_OPT_CASE)? var: lower(var)); if (preset) { pnode = table_get(tab, hkey); if (!pnode) { errcode = CONF_ERR_VAR; goto retcode; } type = pnode->type; } else type = CONF_TYPE_STR; MEM_NEW(pnode); pnode->freep = p; pnode->type = type; pnode->val = val; pnode = table_put(tab, hkey, pnode); if (pnode) { /* value overwritten, thus free */ MEM_FREE(pnode->freep); MEM_FREE(pnode); } p = MEM_ALLOC(buflen=BUFLEN); /* uses new buffer */ break; } len = 0; *p = '\0'; lineno += nlineno; /* adjusts line number */ nlineno = 0; } else /* expands buffer */ MEM_RESIZE(p, buflen+=BUFLEN); } while(!feof(fp)); retcode: MEM_FREE(p); return (errcode != CONF_ERR_OK)? lineno: 0; }
/* * inserts or replaces a value associated with a variable * * TODO: * - some adjustment on arguments to table_new() is necessary */ int (conf_set)(const char *secvar, const char *value) { size_t len; char buf[30], *pbuf; char *sec, *var; table_t *tab; const char *hkey; struct valnode_t *pnode; assert(secvar); assert(value); /* sep() always clears errcode */ len = strlen(secvar); pbuf = strcpy((len > sizeof(buf)-1)? MEM_ALLOC(len+1): buf, secvar); if (sep(pbuf, &sec, &var) != CONF_ERR_OK) { if (pbuf != buf) MEM_FREE(pbuf); return errcode; /* sep sets errcode */ } if (!sec) { /* current selected */ if (!current) { /* no current section, thus global */ hkey = hash_string(""); /* in case table for global not yet allocated */ tab = table_get(section, hkey); } else tab = current; } else { /* section name given */ hkey = hash_string((control & CONF_OPT_CASE)? sec: lower(sec)); tab = table_get(section, hkey); } if (!tab) { /* new section */ if (preset) { if (pbuf != buf) MEM_FREE(pbuf); return (errcode = CONF_ERR_SEC); } else { /* adds it */ tab = table_new(0, NULL, NULL); table_put(section, hkey, tab); } } assert(tab); hkey = hash_string((control & CONF_OPT_CASE)? var: lower(var)); if (pbuf != buf) MEM_FREE(pbuf); pnode = table_get(tab, hkey); if (!pnode) { /* new variable */ if (preset) return (errcode = CONF_ERR_VAR); else { /* inserts */ MEM_NEW(pnode); pnode->type = CONF_TYPE_STR; table_put(tab, hkey, pnode); } } else /* replaces, thus reuses pnode */ MEM_FREE(pnode->freep); pnode->val = pnode->freep = strcpy(MEM_ALLOC(strlen(value)+1), value); return errcode; }
int main() { table_t tab = table_new(1024, cmp, dictGenHashFunction); table_put(tab, "append", "cmd_append"); table_put(tab, "bitcount", "cmd_bitcount"); table_put(tab, "brpop", "cmd_brpop"); table_put(tab, "brpoplpush", "cmd_brpoplpush"); table_put(tab, "decr", "cmd_decr"); table_put(tab, "decrby", "cmd_decrby"); table_put(tab, "del", "cmd_del"); table_put(tab, "exists", "cmd_exists"); table_put(tab, "get", "cmd_get"); table_put(tab, "getbit", "cmd_getbit"); table_put(tab, "getrange", "cmd_getrange"); table_put(tab, "incr", "cmd_incr"); table_put(tab, "incrby", "cmd_incrby"); table_put(tab, "keys", "cmd_keys"); table_put(tab, "lindex", "cmd_lindex"); table_put(tab, "linsert", "cmd_linsert"); table_put(tab, "llen", "cmd_llen"); table_put(tab, "lpop", "cmd_lpop"); table_put(tab, "lpush", "cmd_lpush"); table_put(tab, "lpushx", "cmd_lpushx"); table_put(tab, "lrange", "cmd_lrange"); table_put(tab, "lrem", "cmd_lrem"); table_put(tab, "lset", "cmd_lset"); table_put(tab, "ltrim", "cmd_ltrim"); table_put(tab, "mget", "cmd_mget"); table_put(tab, "msetnx", "cmd_msetnx"); table_put(tab, "randomkey", "cmd_randomkey"); table_put(tab, "rename", "cmd_rename"); table_put(tab, "rpop", "cmd_rpop"); table_put(tab, "rpoplpush", "cmd_rpoplpush"); table_put(tab, "rpush", "cmd_rpush"); table_put(tab, "rpushx", "cmd_rpushx"); table_put(tab, "set", "cmd_set"); table_put(tab, "setbit", "cmd_setbit"); table_put(tab, "setrange", "cmd_setrange"); table_put(tab, "strlen", "cmd_strlen"); table_put(tab, "type", "cmd_type"); table_map(tab, apply); printf("len = %d\n", table_length(tab)); char key[32]; scanf("%s", key); printf("%s\n", (char *)table_get(tab, key)); printf("remove set\n"); table_remove(tab, "set"); table_map(tab, apply); printf("len = %d\n", table_length(tab)); scanf("%s", key); printf("%s\n", (char *)table_get(tab, key)); table_free(&tab); return 0; }
static int add_watch(int path_len, watch_node* parent) { int wd = inotify_add_watch(inotify_fd, path_buf, EVENT_MASK); if (wd < 0) { if (errno == EACCES || errno == ENOENT) { userlog(LOG_DEBUG, "inotify_add_watch(%s): %s", path_buf, strerror(errno)); return ERR_IGNORE; } else if (errno == ENOSPC) { userlog(LOG_WARNING, "inotify_add_watch(%s): %s", path_buf, strerror(errno)); watch_limit_reached(); return ERR_CONTINUE; } else { userlog(LOG_ERR, "inotify_add_watch(%s): %s", path_buf, strerror(errno)); return ERR_ABORT; } } else { userlog(LOG_DEBUG, "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)", wd, path_buf, node->wd, node->path); 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); 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; if (parent != NULL) { if (parent->kids == NULL) { parent->kids = array_create(DEFAULT_SUBDIR_COUNT); CHECK_NULL(parent->kids, ERR_ABORT); } CHECK_NULL(array_push(parent->kids, node), ERR_ABORT); } if (table_put(watches, wd, node) == NULL) { userlog(LOG_ERR, "table error: unable to put (%d:%s)", wd, path_buf); return ERR_ABORT; } return wd; }