static void test_hash_random_pool(pool_t pool) { #define KEYMAX 100000 HASH_TABLE(void *, void *) hash; unsigned int *keys; unsigned int i, key, keyidx, delidx; keys = i_new(unsigned int, KEYMAX); keyidx = 0; hash_table_create_direct(&hash, pool, 0); for (i = 0; i < KEYMAX; i++) { key = (rand() % KEYMAX) + 1; if (rand() % 5 > 0) { if (hash_table_lookup(hash, POINTER_CAST(key)) == NULL) { hash_table_insert(hash, POINTER_CAST(key), POINTER_CAST(1)); keys[keyidx++] = key; } } else if (keyidx > 0) { delidx = rand() % keyidx; hash_table_remove(hash, POINTER_CAST(keys[delidx])); memmove(&keys[delidx], &keys[delidx+1], (keyidx-delidx-1) * sizeof(*keys)); keyidx--; } } for (i = 0; i < keyidx; i++) hash_table_remove(hash, POINTER_CAST(keys[i])); hash_table_destroy(&hash); i_free(keys); }
static struct log_client *log_client_get(struct log_connection *log, pid_t pid) { struct log_client *client; client = hash_table_lookup(log->clients, POINTER_CAST(pid)); if (client == NULL) { client = i_new(struct log_client, 1); hash_table_insert(log->clients, POINTER_CAST(pid), client); }
static struct dsync_mail_change * export_save_change_get(struct dsync_mailbox_exporter *exporter, uint32_t uid) { struct dsync_mail_change *change; change = hash_table_lookup(exporter->changes, POINTER_CAST(uid)); if (change == NULL) { change = p_new(exporter->pool, struct dsync_mail_change, 1); change->uid = uid; hash_table_insert(exporter->changes, POINTER_CAST(uid), change); } else {
unsigned int auth_server_connection_add_request(struct auth_server_connection *conn, struct auth_client_request *request) { unsigned int id; id = ++conn->client->request_id_counter; if (id == 0) { /* wrapped - ID 0 not allowed */ id = ++conn->client->request_id_counter; } i_assert(hash_table_lookup(conn->requests, POINTER_CAST(id)) == NULL); hash_table_insert(conn->requests, POINTER_CAST(id), request); return id; }
static void checkpassword_request_finish(struct chkpw_auth_request *request, enum userdb_result result) { struct userdb_module *_module = request->request->userdb->userdb; struct checkpassword_userdb_module *module = (struct checkpassword_userdb_module *)_module; userdb_callback_t *callback = (userdb_callback_t *)request->callback; hash_table_remove(module->clients, POINTER_CAST(request->pid)); if (result == USERDB_RESULT_OK) { if (strchr(str_c(request->input_buf), '\n') != NULL) { auth_request_log_error(request->request, "userdb-checkpassword", "LF characters in checkpassword reply"); result = USERDB_RESULT_INTERNAL_FAILURE; } else { auth_request_init_userdb_reply(request->request); auth_request_set_fields(request->request, t_strsplit(str_c(request->input_buf), "\t"), NULL); } } callback(result, request->request); auth_request_unref(&request->request); checkpassword_request_free(request); }
void service_process_destroy(struct service_process *process) { struct service *service = process->service; struct service_list *service_list = service->list; DLLIST_REMOVE(&service->processes, process); hash_table_remove(service_pids, POINTER_CAST(process->pid)); if (process->available_count > 0) service->process_avail--; service->process_count--; i_assert(service->process_avail <= service->process_count); if (process->to_status != NULL) timeout_remove(&process->to_status); if (process->to_idle != NULL) timeout_remove(&process->to_idle); if (service->list->log_byes != NULL) service_process_notify_add(service->list->log_byes, process); process->destroyed = TRUE; service_process_unref(process); if (service->process_count < service->process_limit && service->type == SERVICE_TYPE_LOGIN) service_login_notify(service, FALSE); service_list_unref(service_list); }
void master_login_auth_request(struct master_login_auth *auth, const struct master_auth_request *req, master_login_auth_request_callback_t *callback, void *context) { struct master_login_auth_request *login_req; unsigned int id; if (auth->fd == -1) { if (master_login_auth_connect(auth) < 0) { /* we couldn't connect to auth now, so we probably can't in future either. */ master_service_stop_new_connections(master_service); callback(NULL, MASTER_AUTH_ERRMSG_INTERNAL_FAILURE, context); return; } o_stream_nsend_str(auth->output, t_strdup_printf("VERSION\t%u\t%u\n", AUTH_MASTER_PROTOCOL_MAJOR_VERSION, AUTH_MASTER_PROTOCOL_MINOR_VERSION)); } id = ++auth->id_counter; if (id == 0) id++; login_req = i_new(struct master_login_auth_request, 1); login_req->create_stamp = ioloop_time; login_req->id = id; login_req->auth_pid = req->auth_pid; login_req->client_pid = req->client_pid; login_req->auth_id = req->auth_id; memcpy(login_req->cookie, req->cookie, sizeof(login_req->cookie)); login_req->callback = callback; login_req->context = context; i_assert(hash_table_lookup(auth->requests, POINTER_CAST(id)) == NULL); hash_table_insert(auth->requests, POINTER_CAST(id), login_req); DLLIST2_APPEND(&auth->request_head, &auth->request_tail, login_req); if (auth->to == NULL) master_login_auth_set_timeout(auth); master_login_auth_send_request(auth, login_req); }
void auth_request_handler_cancel_request(struct auth_request_handler *handler, unsigned int client_id) { struct auth_request *request; request = hash_table_lookup(handler->requests, POINTER_CAST(client_id)); if (request != NULL) auth_request_handler_remove(handler, request); }
static int search_update_flag_change_guid(struct dsync_mailbox_exporter *exporter, struct mail *mail) { struct dsync_mail_change *change, *log_change; const char *guid, *hdr_hash; int ret; change = hash_table_lookup(exporter->changes, POINTER_CAST(mail->uid)); if (change != NULL) { i_assert(change->type == DSYNC_MAIL_CHANGE_TYPE_FLAG_CHANGE); } else { i_assert(exporter->return_all_mails); change = p_new(exporter->pool, struct dsync_mail_change, 1); change->uid = mail->uid; change->type = DSYNC_MAIL_CHANGE_TYPE_FLAG_CHANGE; hash_table_insert(exporter->changes, POINTER_CAST(mail->uid), change); } if ((ret = exporter_get_guids(exporter, mail, &guid, &hdr_hash)) < 0) return -1; if (ret == 0) { /* the message was expunged during export */ memset(change, 0, sizeof(*change)); change->type = DSYNC_MAIL_CHANGE_TYPE_EXPUNGE; change->uid = mail->uid; /* find its GUID from log if possible */ log_change = dsync_transaction_log_scan_find_new_expunge( exporter->log_scan, mail->uid); if (log_change != NULL) change->guid = log_change->guid; } else { change->guid = *guid == '\0' ? "" : p_strdup(exporter->pool, guid); change->hdr_hash = p_strdup(exporter->pool, hdr_hash); search_update_flag_changes(exporter, mail, change); } return 0; }
static int replicator_input_line(struct replicator_connection *conn, const char *line) { void *context; unsigned int id; /* <+|-> \t <id> */ if ((line[0] != '+' && line[0] != '-') || line[1] != '\t' || str_to_uint(line+2, &id) < 0 || id == 0) { i_error("Replicator sent invalid input: %s", line); return -1; } context = hash_table_lookup(conn->requests, POINTER_CAST(id)); if (context == NULL) { i_error("Replicator sent invalid ID: %u", id); return -1; } hash_table_remove(conn->requests, POINTER_CAST(id)); conn->callback(line[0] == '+', context); return 0; }
static int auth_server_lookup_request(struct auth_server_connection *conn, const char *id_arg, bool remove, struct auth_client_request **request_r) { struct auth_client_request *request; unsigned int id; if (id_arg == NULL || str_to_uint(id_arg, &id) < 0) { i_error("BUG: Authentication server input missing ID"); return -1; } request = hash_table_lookup(conn->requests, POINTER_CAST(id)); if (request == NULL) { i_error("BUG: Authentication server sent unknown id %u", id); return -1; } if (remove || auth_client_request_is_aborted(request)) hash_table_remove(conn->requests, POINTER_CAST(id)); *request_r = request; return 0; }
static bool ATTR_NOWARN_UNUSED_RESULT export_change_get(struct dsync_transaction_log_scan *ctx, uint32_t uid, enum dsync_mail_change_type type, struct dsync_mail_change **change_r) { struct dsync_mail_change *change; const char *orig_guid; i_assert(uid > 0); i_assert(type != DSYNC_MAIL_CHANGE_TYPE_SAVE); *change_r = NULL; if (uid > ctx->highest_wanted_uid) return FALSE; change = hash_table_lookup(ctx->changes, POINTER_CAST(uid)); if (change == NULL) { /* first change for this UID */ change = p_new(ctx->pool, struct dsync_mail_change, 1); change->uid = uid; change->type = type; hash_table_insert(ctx->changes, POINTER_CAST(uid), change); } else if (type == DSYNC_MAIL_CHANGE_TYPE_EXPUNGE) {
void replicator_connection_notify_sync(struct replicator_connection *conn, const char *username, void *context) { unsigned int id; replicator_connection_connect(conn); id = ++conn->request_id_counter; if (id == 0) id++; hash_table_insert(conn->requests, POINTER_CAST(id), context); T_BEGIN { replicator_send(conn, REPLICATION_PRIORITY_SYNC, t_strdup_printf( "U\t%s\tsync\t%u\n", str_tabescape(username), id)); } T_END; }
static void master_login_auth_request_remove(struct master_login_auth *auth, struct master_login_auth_request *request) { bool update_timeout; update_timeout = request->prev == NULL; hash_table_remove(auth->requests, POINTER_CAST(request->id)); DLLIST2_REMOVE(&auth->request_head, &auth->request_tail, request); if (update_timeout) { timeout_remove(&auth->to); master_login_auth_set_timeout(auth); } }
bool auth_request_handler_auth_continue(struct auth_request_handler *handler, const char *args) { struct auth_request *request; const char *data; size_t data_len; buffer_t *buf; unsigned int id; data = strchr(args, '\t'); if (data == NULL || str_to_uint(t_strdup_until(args, data), &id) < 0) { i_error("BUG: Authentication client sent broken CONT request"); return FALSE; } data++; request = hash_table_lookup(handler->requests, POINTER_CAST(id)); if (request == NULL) { const char *reply = t_strdup_printf( "FAIL\t%u\treason=Authentication request timed out", id); handler->callback(reply, handler->context); return TRUE; } /* accept input only once after mechanism has sent a CONT reply */ if (!request->accept_cont_input) { auth_request_handler_auth_fail(handler, request, "Unexpected continuation"); return TRUE; } request->accept_cont_input = FALSE; data_len = strlen(data); buf = buffer_create_dynamic(pool_datastack_create(), MAX_BASE64_DECODED_SIZE(data_len)); if (base64_decode(data, data_len, NULL, buf) < 0) { auth_request_handler_auth_fail(handler, request, "Invalid base64 data in continued response"); return TRUE; } /* handler is referenced until auth_request_handler_reply() is called. */ handler->refcount++; auth_request_continue(request, buf->data, buf->used); return TRUE; }
static void mailbox_list_index_generate_name(struct mailbox_list_index *ilist, struct mailbox_list_index_node *node) { guid_128_t guid; char *name; guid_128_generate(guid); name = p_strdup_printf(ilist->mailbox_pool, "unknown-%s", guid_128_to_string(guid)); node->name = name; hash_table_insert(ilist->mailbox_names, POINTER_CAST(node->name_id), name); if (ilist->highest_name_id < node->name_id) ilist->highest_name_id = node->name_id; }
static void maildir_keywords_create(struct maildir_keywords *mk, const char *name, unsigned int chridx) { const char **strp; char *new_name; i_assert(chridx < MAILDIR_MAX_KEYWORDS); new_name = p_strdup(mk->pool, name); hash_table_insert(mk->hash, new_name, POINTER_CAST(chridx + 1)); strp = array_idx_modifiable(&mk->list, chridx); *strp = new_name; mk->changed = TRUE; }
const char *str_table_ref(struct str_table *table, const char *str) { char *key; void *value; unsigned int ref; if (!hash_table_lookup_full(table->hash, str, &key, &value)) { key = i_strdup(str); ref = 1; } else { ref = POINTER_CAST_TO(value, unsigned int); i_assert(ref > 0); ref++; } hash_table_update(table->hash, key, POINTER_CAST(ref)); return key; }
static void auth_request_handler_remove(struct auth_request_handler *handler, struct auth_request *request) { i_assert(request->handler == handler); if (request->removed_from_handler) { /* already removed it */ return; } request->removed_from_handler = TRUE; /* if db lookup is stuck, this call doesn't actually free the auth request, so make sure we don't get back here. */ timeout_remove(&request->to_abort); hash_table_remove(handler->requests, POINTER_CAST(request->id)); auth_request_unref(&request); }
void str_table_unref(struct str_table *table, const char **str) { char *key; void *value; unsigned int ref; if (!hash_table_lookup_full(table->hash, *str, &key, &value)) i_unreached(); ref = POINTER_CAST_TO(value, unsigned int); i_assert(ref > 0); if (--ref > 0) hash_table_update(table->hash, key, POINTER_CAST(ref)); else { hash_table_remove(table->hash, key); i_free(key); } *str = NULL; }
static int mailbox_list_index_parse_header(struct mailbox_list_index *ilist, struct mail_index_view *view) { const void *data, *p; size_t i, len, size; uint32_t id, prev_id = 0; char *name; mail_index_map_get_header_ext(view, view->map, ilist->ext_id, &data, &size); if (size == 0) return 0; for (i = sizeof(struct mailbox_list_index_header); i < size; ) { /* get id */ if (i + sizeof(id) > size) return -1; memcpy(&id, CONST_PTR_OFFSET(data, i), sizeof(id)); i += sizeof(id); if (id <= prev_id) { /* allow extra space in the end as long as last id=0 */ return id == 0 ? 0 : -1; } /* get name */ p = memchr(CONST_PTR_OFFSET(data, i), '\0', size-i); if (p == NULL) return -1; len = (const char *)p - (const char *)(CONST_PTR_OFFSET(data, i)); name = p_strndup(ilist->mailbox_pool, CONST_PTR_OFFSET(data, i), len); i += len + 1; /* add id => name to hash table */ hash_table_insert(ilist->mailbox_names, POINTER_CAST(id), name); ilist->highest_name_id = id; } i_assert(i == size); return 0; }
static void sigchld_handler(const struct child_wait_status *status, struct checkpassword_userdb_module *module) { struct chkpw_auth_request *request = hash_table_lookup(module->clients, POINTER_CAST(status->pid)); switch (checkpassword_sigchld_handler(status, request)) { case SIGCHLD_RESULT_UNKNOWN_CHILD: case SIGCHLD_RESULT_DEAD_CHILD: break; case SIGCHLD_RESULT_UNKNOWN_ERROR: checkpassword_request_finish(request, USERDB_RESULT_INTERNAL_FAILURE); break; case SIGCHLD_RESULT_OK: checkpassword_request_half_finish(request); request = NULL; break; } }
static struct master_login_auth_request * master_login_auth_lookup_request(struct master_login_auth *auth, unsigned int id) { struct master_login_auth_request *request; request = hash_table_lookup(auth->requests, POINTER_CAST(id)); if (request == NULL) { i_error("Auth server sent reply with unknown ID %u", id); return NULL; } master_login_auth_request_remove(auth, request); if (request->aborted) { request->callback(NULL, MASTER_AUTH_ERRMSG_INTERNAL_FAILURE, request->context); i_free(request); return NULL; } return request; }
static void master_login_auth_timeout(struct master_login_auth *auth) { struct master_login_auth_request *request; const char *reason; while (auth->request_head != NULL && auth_get_next_timeout_secs(auth) == 0) { request = auth->request_head; DLLIST2_REMOVE(&auth->request_head, &auth->request_tail, request); hash_table_remove(auth->requests, POINTER_CAST(request->id)); reason = t_strdup_printf( "Auth server request timed out after %u secs", (unsigned int)(ioloop_time - request->create_stamp)); request_internal_failure(request, reason); i_free(request); } timeout_remove(&auth->to); master_login_auth_set_timeout(auth); }
} director_disconnect(ctx); } static void user_list_add(const char *username, pool_t pool, HASH_TABLE_TYPE(user_list) users) { struct user_list *user, *old_user; unsigned int user_hash; user = p_new(pool, struct user_list, 1); user->name = p_strdup(pool, username); user_hash = mail_user_hash(username, doveadm_settings->director_username_hash); old_user = hash_table_lookup(users, POINTER_CAST(user_hash)); if (old_user != NULL) user->next = old_user; hash_table_insert(users, POINTER_CAST(user_hash), user); } static void ATTR_NULL(1) userdb_get_user_list(const char *auth_socket_path, pool_t pool, HASH_TABLE_TYPE(user_list) users) { struct auth_master_user_list_ctx *ctx; struct auth_master_connection *conn; const char *username; if (auth_socket_path == NULL) { auth_socket_path = t_strconcat(doveadm_settings->base_dir,
static int maildir_keywords_sync(struct maildir_keywords *mk) { struct istream *input; struct stat st; char *line, *p, *new_name; const char **strp; unsigned int idx; int fd; /* Remember that we rely on uidlist file locking in here. That's why we rely on stat()'s timestamp and don't bother handling ESTALE errors. */ if (mk->storage->set->mail_nfs_storage) { /* file is updated only by replacing it, no need to flush attribute cache */ nfs_flush_file_handle_cache(mk->path); } if (nfs_safe_stat(mk->path, &st) < 0) { if (errno == ENOENT) { maildir_keywords_clear(mk); mk->synced = TRUE; return 0; } mail_storage_set_critical(mk->storage, "stat(%s) failed: %m", mk->path); return -1; } if (st.st_mtime == mk->synced_mtime) { /* hasn't changed */ mk->synced = TRUE; return 0; } mk->synced_mtime = st.st_mtime; fd = open(mk->path, O_RDONLY); if (fd == -1) { if (errno == ENOENT) { maildir_keywords_clear(mk); mk->synced = TRUE; return 0; } mail_storage_set_critical(mk->storage, "open(%s) failed: %m", mk->path); return -1; } maildir_keywords_clear(mk); input = i_stream_create_fd(fd, 1024, FALSE); while ((line = i_stream_read_next_line(input)) != NULL) { p = strchr(line, ' '); if (p == NULL) { /* note that when converting .customflags file this case happens in the first line. */ continue; } *p++ = '\0'; if (str_to_uint(line, &idx) < 0 || idx >= MAILDIR_MAX_KEYWORDS || *p == '\0') { /* shouldn't happen */ continue; } /* save it */ new_name = p_strdup(mk->pool, p); hash_table_insert(mk->hash, new_name, POINTER_CAST(idx + 1)); strp = array_idx_modifiable(&mk->list, idx); *strp = new_name; } i_stream_destroy(&input); if (close(fd) < 0) { mail_storage_set_critical(mk->storage, "close(%s) failed: %m", mk->path); return -1; } mk->synced = TRUE; return 0; }
static void checkpassword_lookup(struct auth_request *request, userdb_callback_t *callback) { struct userdb_module *_module = request->userdb->userdb; struct checkpassword_userdb_module *module = (struct checkpassword_userdb_module *)_module; struct chkpw_auth_request *chkpw_auth_request; int fd_in[2], fd_out[2]; pid_t pid; fd_in[0] = -1; if (pipe(fd_in) < 0 || pipe(fd_out) < 0) { auth_request_log_error(request, "userdb-checkpassword", "pipe() failed: %m"); callback(USERDB_RESULT_INTERNAL_FAILURE, request); if (fd_in[0] != -1) { (void)close(fd_in[0]); (void)close(fd_in[1]); } return; } pid = fork(); if (pid == -1) { auth_request_log_error(request, "userdb-checkpassword", "fork() failed: %m"); callback(USERDB_RESULT_INTERNAL_FAILURE, request); (void)close(fd_in[0]); (void)close(fd_in[1]); (void)close(fd_out[0]); (void)close(fd_out[1]); return; } if (pid == 0) { (void)close(fd_in[0]); (void)close(fd_out[1]); checkpassword_lookup_child(request, module, fd_in[1], fd_out[0]); /* not reached */ } if (close(fd_in[1]) < 0) { auth_request_log_error(request, "userdb-checkpassword", "close(fd_in[1]) failed: %m"); } if (close(fd_out[0]) < 0) { auth_request_log_error(request, "userdb-checkpassword", "close(fd_out[0]) failed: %m"); } auth_request_ref(request); chkpw_auth_request = i_new(struct chkpw_auth_request, 1); chkpw_auth_request->fd_in = fd_in[0]; chkpw_auth_request->fd_out = fd_out[1]; chkpw_auth_request->pid = pid; chkpw_auth_request->request = request; chkpw_auth_request->callback = callback; chkpw_auth_request->half_finish_callback = checkpassword_request_half_finish; chkpw_auth_request->finish_callback = checkpassword_request_finish; chkpw_auth_request->internal_failure_code = USERDB_RESULT_INTERNAL_FAILURE; chkpw_auth_request->io_in = io_add(fd_in[0], IO_READ, checkpassword_child_input, chkpw_auth_request); chkpw_auth_request->io_out = io_add(fd_out[1], IO_WRITE, checkpassword_child_output, chkpw_auth_request); hash_table_insert(module->clients, POINTER_CAST(pid), chkpw_auth_request); if (checkpassword_userdb_children != NULL) child_wait_add_pid(checkpassword_userdb_children, pid); else { checkpassword_userdb_children = child_wait_new_with_pid(pid, sigchld_handler, module); } }
struct service_process *service_process_create(struct service *service) { static unsigned int uid_counter = 0; struct service_process *process; unsigned int uid = ++uid_counter; const char *hostdomain; pid_t pid; bool process_forked; i_assert(service->status_fd[0] != -1); if (service->to_throttle != NULL) { /* throttling service, don't create new processes */ return NULL; } if (service->list->destroying) { /* these services are being destroyed, no point in creating new processes now */ return NULL; } /* look this up before fork()ing so that it gets cached for all the future lookups. */ hostdomain = my_hostdomain(); if (service->type == SERVICE_TYPE_ANVIL && service_anvil_global->pid != 0) { pid = service_anvil_global->pid; uid = service_anvil_global->uid; process_forked = FALSE; } else { pid = fork(); process_forked = TRUE; service->list->fork_counter++; } if (pid < 0) { service_error(service, "fork() failed: %m"); return NULL; } if (pid == 0) { /* child */ service_process_setup_environment(service, uid, hostdomain); service_reopen_inet_listeners(service); service_dup_fds(service); drop_privileges(service); process_exec(service->executable, NULL); } i_assert(hash_table_lookup(service_pids, POINTER_CAST(pid)) == NULL); process = i_new(struct service_process, 1); process->service = service; process->refcount = 1; process->pid = pid; process->uid = uid; if (process_forked) { process->to_status = timeout_add(SERVICE_FIRST_STATUS_TIMEOUT_SECS * 1000, service_process_status_timeout, process); } process->available_count = service->client_limit; service->process_count++; service->process_avail++; DLLIST_PREPEND(&service->processes, process); service_list_ref(service->list); hash_table_insert(service_pids, POINTER_CAST(process->pid), process); if (service->type == SERVICE_TYPE_ANVIL && process_forked) service_anvil_process_created(process); return process; }
static int mailbox_list_index_parse_records(struct mailbox_list_index *ilist, struct mail_index_view *view, const char **error_r) { struct mailbox_list_index_node *node; const struct mail_index_record *rec; const struct mailbox_list_index_record *irec; const void *data; bool expunged; uint32_t seq, uid, count; *error_r = NULL; count = mail_index_view_get_messages_count(view); for (seq = 1; seq <= count; seq++) { node = p_new(ilist->mailbox_pool, struct mailbox_list_index_node, 1); rec = mail_index_lookup(view, seq); node->uid = rec->uid; node->flags = rec->flags; mail_index_lookup_ext(view, seq, ilist->ext_id, &data, &expunged); if (data == NULL) { *error_r = "Missing list extension data"; return -1; } irec = data; node->name_id = irec->name_id; node->name = hash_table_lookup(ilist->mailbox_names, POINTER_CAST(irec->name_id)); if (node->name == NULL) { *error_r = "name_id not in index header"; if (ilist->has_backing_store) return -1; /* generate a new name and use it */ mailbox_list_index_generate_name(ilist, node); } hash_table_insert(ilist->mailbox_hash, POINTER_CAST(node->uid), node); } /* do a second scan to create the actual mailbox tree hierarchy. this is needed because the parent_uid may be smaller or higher than the current node's uid */ for (seq = 1; seq <= count; seq++) { mail_index_lookup_uid(view, seq, &uid); mail_index_lookup_ext(view, seq, ilist->ext_id, &data, &expunged); irec = data; node = mailbox_list_index_lookup_uid(ilist, uid); i_assert(node != NULL); if (irec->parent_uid != 0) { /* node should have a parent */ node->parent = mailbox_list_index_lookup_uid(ilist, irec->parent_uid); if (node->parent != NULL) { node->next = node->parent->children; node->parent->children = node; continue; } *error_r = "parent_uid points to nonexistent record"; if (ilist->has_backing_store) return -1; /* just place it under the root */ } node->next = ilist->mailbox_tree; ilist->mailbox_tree = node; } return *error_r == NULL ? 0 : -1; }
struct mailbox_list_index_node * mailbox_list_index_lookup_uid(struct mailbox_list_index *ilist, uint32_t uid) { return hash_table_lookup(ilist->mailbox_hash, POINTER_CAST(uid)); }