List *find_with_hash(Map map, void *needle, int h) { int n = map->buckets->count; int index = ((unsigned int)h) % n; List *bucket = (List *)array__item_ptr(map->buckets, index); return bucket_find(bucket, needle, map->eq); }
int test_file(FILE *fp, int argc, char **argv) { char buf[65535 + 1]; char *pos; unsigned int strategy = 0; /* what bucketing strategy we're using */ void *ptr = NULL; unsigned int bucketsize = 0; struct params params = {0}; struct chash *hash = NULL; char name[256]; if (!parse_params(argc, argv, ¶ms)) { fprintf(stderr, "failed to parse params\n"); return 0; } while (fgets((char *) buf, 65535, fp)) { str_rtrim(buf); pos = (char *) str_ltrim(buf); if (!str_casecmp(pos, "new")) { /* creating a new bucket */ unsigned int size = -1; if (ptr) { chash_delete(hash); free(ptr); } /* read parameters */ if ((fscanf(fp, "%255s %u %u", name, &strategy, &size) == 3) && (size <= 65535) && (bucketsize = size) && (ptr = malloc(size)) && (hash = chash_ptr_new(1, 2.0, /* some fn pointer casting dodginess */ (unsigned int (*)(const void *)) str_len, (int (*)(const void *, const void *)) str_cmp)) && (bucket_new(ptr, bucketsize, strategy))) { /* succeeded, do nothing */ if (params.verbose) { printf("%s: new bucket with size %u strategy %u\n", name, size, strategy); } } else { fprintf(stderr, "%s: failed to create bucket\n", name); return 0; } } else if (!str_casecmp(pos, "add")) { /* adding a term to the bucket */ void *ret; unsigned int veclen, succeed, len; int toobig; if (!ptr) { return 0; } /* read parameters */ if ((fscanf(fp, "%65535s %u %u", buf, &veclen, &succeed) == 3) && (veclen <= 65535)) { len = str_len(buf); if ((((ret = bucket_alloc(ptr, bucketsize, strategy, buf, len, veclen, &toobig, NULL)) && succeed) || (!ret && !succeed))) { /* do nothing */ if (params.verbose) { printf("%s: added term '%s'\n", name, buf); } } else if (succeed) { fprintf(stderr, "%s: failed to add '%s' to bucket\n", name, buf); return 0; } else if (!succeed) { fprintf(stderr, "%s: add '%s' succeeded but shouldn't " "have\n", name, buf); return 0; } } else { fprintf(stderr, "%s: failed to add\n", name); return 0; } } else if (!str_casecmp(pos, "ls")) { /* matching stuff in the bucket */ unsigned int numterms, i, len, veclen, veclen2, state; void *addr; struct chash *tmphash; const char *term; void **tmpptr, *tmp; if (!ptr) { return 0; } if (!(tmphash = chash_ptr_new(1, 2.0, /* some fn pointer casting dodginess */ (unsigned int (*)(const void *)) str_len, (int (*)(const void *, const void *)) str_cmp))) { fprintf(stderr, "%s: failed to init hashtable\n", name); return 0; } /* first, fill hashtable with all terms from bucket */ state = 0; while ((term = bucket_next_term(ptr, bucketsize, strategy, &state, &len, &addr, &veclen))) { if (!((term = str_ndup(term, len)) && (chash_ptr_ptr_insert(tmphash, term, (void*) term) == CHASH_OK))) { fprintf(stderr, "%s: failed to init hashtable\n", name); return 0; } } /* now, take terms from file, comparing them with hashtable * entries */ if (fscanf(fp, "%u", &numterms)) { for (i = 0; i < numterms; i++) { if (fscanf(fp, "%65535s %u ", buf, &veclen)) { if (params.verbose) { printf("%s: ls checking %s\n", name, buf); } if ((addr = bucket_find(ptr, bucketsize, strategy, buf, str_len(buf), &veclen2, NULL)) /* remove it from hashtable */ && chash_ptr_ptr_find(tmphash, buf, &tmpptr) == CHASH_OK && chash_ptr_ptr_remove(tmphash, *tmpptr, &tmp) == CHASH_OK && (free(tmp), 1) && (veclen <= 65535) && (veclen2 == veclen) && fread(buf, veclen, 1, fp) && ((buf[veclen] = '\0'), 1) && (!params.verbose || printf("%s: ls check read '%s'\n", name, buf)) && !memcmp(buf, addr, veclen)) { /* do nothing */ } else { unsigned int j; fprintf(stderr, "%s: ls failed cmp '%s' with '", name, buf); for (j = 0; j < veclen; j++) { putc(((char *) addr)[j], stderr); } fprintf(stderr, "'\n"); return 0; } } else { fprintf(stderr, "%s: ls failed\n", name); return 0; } } if (chash_size(tmphash)) { fprintf(stderr, "%s: ls failed\n", name); return 0; } } else { fprintf(stderr, "%s: ls failed\n", name); return 0; } chash_delete(tmphash); if (params.verbose) { printf("%s: matched all (%u) entries\n", name, numterms); } } else if (!str_casecmp(pos, "set")) { /* setting the vector for a term in the bucket */ unsigned int veclen, reallen; void *addr; if (!ptr) { return 0; } /* read parameters */ if ((fscanf(fp, "%65535s %u ", buf, &veclen) == 2) && (veclen <= 65535)) { addr = bucket_find(ptr, bucketsize, strategy, buf, str_len(buf), &reallen, NULL); if (addr && (reallen == veclen) && fread(addr, 1, veclen, fp)) { /* do nothing */ if (params.verbose) { unsigned int j; printf("%s: set term '%s' to '", name, buf); for (j = 0; j < reallen; j++) { putc(((char *) addr)[j], stdout); } printf("'\n"); } } else { fprintf(stderr, "%s: failed to set!\n", name); return 0; } } else { fprintf(stderr, "%s: failed to set\n", name); return 0; } } else if (!str_casecmp(pos, "realloc")) { /* reallocating a term in the bucket */ unsigned int veclen, succeed; int toobig; if (!ptr) { return 0; } /* read parameters */ if ((fscanf(fp, "%65535s %u %u", buf, &veclen, &succeed) == 3) && (veclen <= 65535)) { if (!bucket_realloc(ptr, bucketsize, strategy, buf, str_len(buf), veclen, &toobig)) { fprintf(stderr, "%s: failed to realloc!\n", name); return 0; } } else { fprintf(stderr, "%s: failed to realloc\n", name); return 0; } if (params.verbose) { printf("%s: realloc'd term '%s'\n", name, buf); } } else if (!str_casecmp(pos, "rm")) { /* removing something from the bucket */ unsigned int succeed; if (!ptr) { return 0; } if (fscanf(fp, "%65535s %u", buf, &succeed) == 2) { if (succeed) { if (!(bucket_remove(ptr, bucketsize, strategy, buf, str_len(buf)))) { fprintf(stderr, "%s: failed to rm '%s'\n", name, buf); return 0; } else if (params.verbose) { printf("%s: rm term '%s'\n", name, buf); } } else if (succeed) { fprintf(stderr, "%s: failed to rm\n", name); return 0; } } else { fprintf(stderr, "%s: failed to rm\n", name); return 0; } } else if (!str_casecmp(pos, "print")) { /* printing out the bucket contents */ unsigned int state = 0, len, veclen; const char *term; char format[100]; void *addr; if (!ptr) { printf("can't print, no bucket\n"); } else { do { term = bucket_next_term(ptr, bucketsize, strategy, &state, &len, &addr, &veclen); } while (term && memcpy(buf, term, len) && ((buf[len] = '\0') || 1) && snprintf(format, 100, "%%.%us (%%u): '%%.%us' (%%u) " "(off %%u)\n", len, veclen) && printf(format, term, len, (char*) addr, veclen, ((char *) addr) - (char *) ptr)); if (!state) { printf("(empty)\n"); } printf("%u entries, %u data, %u string, %u overhead, %u free\n", bucket_entries(ptr, bucketsize, strategy), bucket_utilised(ptr, bucketsize, strategy), bucket_string(ptr, bucketsize, strategy), bucket_overhead(ptr, bucketsize, strategy), bucket_unused(ptr, bucketsize, strategy)); } } else if (!str_casecmp(pos, "match")) { unsigned int veclen, veclen2; void *addr; if (fscanf(fp, "%65535s %u ", buf, &veclen)) { if ((addr = bucket_find(ptr, bucketsize, strategy, buf, str_len(buf), &veclen2, NULL)) && (veclen <= 65535) && (veclen2 >= veclen) && (!params.verbose || printf("%s: match on '%s' ", name, buf)) && fread(buf, veclen, 1, fp) && !memcmp(buf, addr, veclen)) { if (params.verbose) { printf("content succeeded\n"); } } else { fprintf(stderr, "%s: match failed (%s vs %s)\n", name, buf, (char *) addr); return 0; } } else { fprintf(stderr, "%s: match failed\n", name); return 0; } } else if ((*pos != '#') && str_len(pos)) { fprintf(stderr, "%s: unknown command '%s'\n", name, pos); return 0; } } if (ptr) { chash_delete(hash); free(ptr); } return 1; }
bool access_list(struct client *cli, const char *bucket, const char *key, const char *user) { struct macl { char perm[128]; /* perm(s) granted */ char grantee[64]; /* grantee user */ }; GHashTable *param; enum errcode err = InternalError; DB_ENV *dbenv = tdbrep.tdb.env; DB *acls = tdbrep.tdb.acls; int alloc_len; char owner[64]; GList *res; struct db_acl_key *acl_key; struct db_acl_ent *acl; DB_TXN *txn = NULL; DBC *cur = NULL; GList *content; DBT pkey, pval; struct macl *mp; char guser[64]; GList *p; char *s; int str_len; int rc; bool rcb; /* verify READ access for ACL */ if (!user || !has_access(user, bucket, key, "READ_ACP")) { err = AccessDenied; goto err_out; } /* parse URI query string */ param = hreq_query(&cli->req); if (!param) goto err_out; res = NULL; alloc_len = sizeof(struct db_acl_key) + strlen(key) + 1; acl_key = alloca(alloc_len); memset(acl_key, 0, alloc_len); strncpy(acl_key->bucket, bucket, sizeof(acl_key->bucket)); strcpy(acl_key->key, key); /* open transaction, search cursor */ rc = dbenv->txn_begin(dbenv, NULL, &txn, 0); if (rc) { dbenv->err(dbenv, rc, "DB_ENV->txn_begin"); goto err_out_param; } rc = bucket_find(txn, bucket, &owner[0], sizeof(owner)); if (rc) { if (rc == DB_NOTFOUND) err = InvalidBucketName; else dbenv->err(dbenv, rc, "bucket_find"); goto err_out_rb; } rc = acls->cursor(acls, txn, &cur, 0); if (rc) { acls->err(acls, rc, "acls->cursor"); goto err_out_rb; } memset(&pkey, 0, sizeof(pkey)); pkey.data = acl_key; pkey.size = alloc_len; for (;; free(acl)) { memset(&pval, 0, sizeof(pval)); pval.flags = DB_DBT_MALLOC; rc = cur->get(cur, &pkey, &pval, DB_NEXT); if (rc) break; acl = pval.data; /* This is a workaround, see FIXME about DB_NEXT. */ if (strncmp(acl->bucket, bucket, sizeof(acl->bucket))) continue; if (strcmp(acl->key, key)) continue; if ((mp = malloc(sizeof(struct macl))) == NULL) { free(acl); cur->close(cur); goto err_out_rb; } memcpy(mp->grantee, acl->grantee, sizeof(mp->grantee)); mp->grantee[sizeof(mp->grantee)-1] = 0; memcpy(mp->perm, acl->perm, sizeof(mp->perm)); /* lop off the trailing comma */ mp->perm[sizeof(mp->perm)-1] = 0; str_len = strlen(mp->perm); if (str_len && mp->perm[str_len-1] == ',') mp->perm[--str_len] = 0; res = g_list_append(res, mp); } if (rc != DB_NOTFOUND) acls->err(acls, rc, "access_list iteration"); /* close cursor, transaction */ rc = cur->close(cur); if (rc) acls->err(acls, rc, "acls->cursor close"); rc = txn->commit(txn, 0); if (rc) dbenv->err(dbenv, rc, "DB_ENV->txn_commit"); /* dump collected acls -- no more exception handling */ s = g_markup_printf_escaped( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" "<AccessControlPolicy " "xmlns=\"http://indy.yyz.us/doc/2006-03-01/\">\r\n" " <Owner>\r\n" " <ID>%s</ID>\r\n" " <DisplayName>%s</DisplayName>\r\n" " </Owner>\r\n", owner, owner); content = g_list_append(NULL, s); s = g_markup_printf_escaped( " <AccessControlList>\r\n"); content = g_list_append(content, s); for (p = res; p != NULL; p = p->next) { mp = p->data; if (!strcmp(DB_ACL_ANON, mp->grantee)) { strcpy(guser, "anonymous"); } else { strncpy(guser, mp->grantee, sizeof(guser)); guser[sizeof(guser)-1] = 0; } s = g_markup_printf_escaped( " <Grant>\r\n" " <Grantee xmlns:xsi=\"http://www.w3.org/2001/" "XMLSchema-instance\" xsi:type=\"CanonicalUser\">\r\n" " <ID>%s</ID>\r\n" " <DisplayName>%s</DisplayName>\r\n" " </Grantee>\r\n", guser, guser); content = g_list_append(content, s); /* * FIXME This parsing is totally lame, we should replace * strings with a bit mask once we make sure this works. */ if (!strcmp(mp->perm, "READ,WRITE,READ_ACP,WRITE_ACP")) { s = g_markup_printf_escaped( " <Permission>FULL_CONTROL</Permission>\r\n"); } else { s = g_markup_printf_escaped( " <Permission>%s</Permission>\r\n", mp->perm); } content = g_list_append(content, s); s = g_markup_printf_escaped(" </Grant>\r\n"); content = g_list_append(content, s); free(mp); } s = g_markup_printf_escaped(" </AccessControlList>\r\n"); content = g_list_append(content, s); s = g_markup_printf_escaped("</AccessControlPolicy>\r\n"); content = g_list_append(content, s); g_list_free(res); rcb = cli_resp_xml(cli, 200, content); g_list_free(content); return rcb; err_out_rb: rc = txn->abort(txn); if (rc) dbenv->err(dbenv, rc, "DB_ENV->txn_abort"); for (p = res; p != NULL; p = p->next) free(p->data); g_list_free(res); err_out_param: g_hash_table_destroy(param); err_out: return cli_err(cli, err); }
bool bucket_add(struct client *cli, const char *user, const char *bucket) { char *hdr, timestr[64]; enum errcode err = InternalError; int rc; struct db_bucket_ent ent; bool setacl; /* is ok to put pre-existing bucket */ enum ReqACLC canacl; DB *buckets = tdbrep.tdb.buckets; DB *acls = tdbrep.tdb.acls; DB_ENV *dbenv = tdbrep.tdb.env; DB_TXN *txn = NULL; DBT key, val; if (!user) return cli_err(cli, AccessDenied); /* prepare parameters */ setacl = false; if (cli->req.uri.query_len) { switch (hreq_is_query(&cli->req)) { case URIQ_ACL: setacl = true; break; default: err = InvalidURI; goto err_par; } } if ((rc = hreq_acl_canned(&cli->req)) == ACLCNUM) { err = InvalidArgument; goto err_par; } canacl = (rc == -1)? ACLC_PRIV: rc; /* begin trans */ rc = dbenv->txn_begin(dbenv, NULL, &txn, 0); if (rc) { dbenv->err(dbenv, rc, "DB_ENV->txn_begin"); goto err_db; } memset(&key, 0, sizeof(key)); memset(&val, 0, sizeof(val)); memset(&ent, 0, sizeof(ent)); strncpy(ent.name, bucket, sizeof(ent.name)); strncpy(ent.owner, user, sizeof(ent.owner)); ent.time_create = GUINT64_TO_LE(time(NULL)); key.data = &ent.name; key.size = strlen(ent.name) + 1; val.data = &ent; val.size = sizeof(ent); if (setacl) { /* check if the bucket exists, else insert it */ rc = bucket_find(txn, bucket, NULL, 0); if (rc) { if (rc != DB_NOTFOUND) { buckets->err(buckets, rc, "buckets->find"); goto err_out; } rc = buckets->put(buckets, txn, &key, &val, DB_NOOVERWRITE); if (rc) { buckets->err(buckets, rc, "buckets->put"); goto err_out; } } else { if (!has_access(user, bucket, NULL, "WRITE_ACP")) { err = AccessDenied; goto err_out; } if (!object_del_acls(txn, bucket, "")) goto err_out; } } else { /* attempt to insert new bucket */ rc = buckets->put(buckets, txn, &key, &val, DB_NOOVERWRITE); if (rc) { if (rc == DB_KEYEXIST) err = BucketAlreadyExists; else buckets->err(buckets, rc, "buckets->put"); goto err_out; } } /* insert bucket ACL */ rc = add_access_canned(txn, bucket, "", user, canacl); if (rc) { acls->err(acls, rc, "acls->put"); goto err_out; } /* commit -- no more exception emulation with goto. */ rc = txn->commit(txn, 0); if (rc) { dbenv->err(dbenv, rc, "DB_ENV->txn_commit"); return cli_err(cli, InternalError); } if (asprintf(&hdr, "HTTP/%d.%d 200 x\r\n" "Content-Length: 0\r\n" "Date: %s\r\n" "Location: /%s\r\n" "Server: " PACKAGE_STRING "\r\n" "\r\n", cli->req.major, cli->req.minor, hutil_time2str(timestr, sizeof(timestr), time(NULL)), bucket) < 0) return cli_err(cli, InternalError); rc = atcp_writeq(&cli->wst, hdr, strlen(hdr), atcp_cb_free, hdr); if (rc) { free(hdr); return true; } return atcp_write_start(&cli->wst); err_out: rc = txn->abort(txn); if (rc) dbenv->err(dbenv, rc, "DB_ENV->txn_abort"); err_db: err_par: return cli_err(cli, err); }
unsigned int hashmap_find( hashmap_t *hashmap, hashmap_key_t key, hashmap_value_t * const value ) { bucket_t *bucket = hashmap_bucket_get( hashmap, key ); return bucket_find( bucket, key, value ); }