static mongoc_cursor_t * query_collection (mongoc_collection_t *collection, uint32_t last_time) { mongoc_cursor_t *cursor; bson_t query; bson_t gt; bson_t opts; BSON_ASSERT (collection); bson_init (&query); BSON_APPEND_DOCUMENT_BEGIN (&query, "ts", >); BSON_APPEND_TIMESTAMP (>, "$gt", last_time, 0); bson_append_document_end (&query, >); bson_init (&opts); BSON_APPEND_BOOL (&opts, "tailable", true); BSON_APPEND_BOOL (&opts, "awaitData", true); cursor = mongoc_collection_find_with_opts (collection, &query, &opts, NULL); bson_destroy (&query); bson_destroy (&opts); return cursor; }
SEXP R_mongo_collection_find(SEXP ptr_col, SEXP ptr_query, SEXP ptr_opts) { mongoc_collection_t *col = r2col(ptr_col); bson_t *query = r2bson(ptr_query); bson_t *opts = r2bson(ptr_opts); mongoc_cursor_t *c = mongoc_collection_find_with_opts(col, query, opts, NULL); return cursor2r(c, ptr_col); }
static future_t * find (func_ctx_t *ctx, bson_t *cmd) { BSON_APPEND_UTF8 (cmd, "find", "collection"); ctx->cursor = mongoc_collection_find_with_opts ( ctx->collection, tmp_bson ("{}"), ctx->opts, ctx->prefs); /* use ctx->data as the bson_t** out-param to mongoc_cursor_next () */ return future_cursor_next (ctx->cursor, (const bson_t **) &ctx->data); }
/* test that we add readConcern only inside $query, not outside it too */ static void test_mongos_read_concern (void) { mock_server_t *server; mongoc_client_t *client; mongoc_collection_t *collection; mongoc_read_prefs_t *prefs; mongoc_cursor_t *cursor; const bson_t *doc; future_t *future; request_t *request; server = mock_mongos_new (WIRE_VERSION_READ_CONCERN); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); collection = mongoc_client_get_collection (client, "test", "test"); prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY); cursor = mongoc_collection_find_with_opts ( collection, tmp_bson ("{'a': 1}"), tmp_bson ("{'readConcern': {'level': 'foo'}}"), prefs); future = future_cursor_next (cursor, &doc); request = mock_server_receives_command ( server, "test", MONGOC_QUERY_SLAVE_OK, "{" " '$query': {" " 'find': 'test', 'filter': {}, 'readConcern': {'level': 'foo'}" " }," " '$readPreference': {" " 'mode': 'secondary'" " }," " 'readConcern': {'$exists': false}" "}"); mock_server_replies_to_find ( request, MONGOC_QUERY_SLAVE_OK, 0, 1, "db.collection", "{}", true); /* mongoc_cursor_next returned true */ BSON_ASSERT (future_get_bool (future)); request_destroy (request); future_destroy (future); mongoc_cursor_destroy (cursor); mongoc_read_prefs_destroy (prefs); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mock_server_destroy (server); }
int be_mongo_getuser(void *handle, const char *username, const char *password, char **phash, const char *clientid) { struct mongo_backend *conf = (struct mongo_backend *)handle; mongoc_collection_t *collection; mongoc_cursor_t *cursor; bson_error_t error; const bson_t *doc; bson_iter_t iter; bson_t query; char *result = NULL; bson_init (&query); bson_append_utf8 (&query, conf->user_username_prop, -1, username, -1); collection = mongoc_client_get_collection (conf->client, conf->database, conf->user_coll); cursor = mongoc_collection_find_with_opts(collection, &query, NULL, NULL); if (!mongoc_cursor_error (cursor, &error) && mongoc_cursor_next (cursor, &doc)) { bson_iter_init(&iter, doc); if (bson_iter_find(&iter, conf->user_password_prop)) { const char *password_src = bson_iter_utf8(&iter, NULL); size_t password_len = strlen(password_src) + 1; result = (char *) malloc(password_len); memcpy(result, password_src, password_len); } else { _log(LOG_NOTICE, "[mongo] (%s) missing for user (%s)", conf->user_password_prop, username); } } if (mongoc_cursor_error (cursor, &error)) { fprintf (stderr, "Cursor Failure: %s\n", error.message); } bson_destroy (&query); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); *phash = result; return BACKEND_DEFER; }
static void test_exhaust (void) { mock_server_t *server; mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; request_t *request; future_t *future; const bson_t *doc; bson_error_t error; server = mock_server_with_autoismaster (WIRE_VERSION_FIND_CMD); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); collection = mongoc_client_get_collection (client, "db", "collection"); cursor = mongoc_collection_find_with_opts (collection, tmp_bson (NULL), NULL, tmp_bson ("{'exhaust': true}")); future = future_cursor_next (cursor, &doc); /* Find, getMore and killCursors commands spec: "The find command does not * support the exhaust flag from OP_QUERY. Drivers that support exhaust MUST * fallback to existing OP_QUERY wire protocol messages." */ request = mock_server_receives_request (server); mock_server_replies_to_find ( request, MONGOC_QUERY_SLAVE_OK | MONGOC_QUERY_EXHAUST, 0, 0, "db.collection", "{}", false /* is_command */); ASSERT (future_get_bool (future)); ASSERT_OR_PRINT (!mongoc_cursor_error (cursor, &error), error); request_destroy (request); future_destroy (future); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mock_server_destroy (server); }
mongoc_gridfs_file_list_t * _mongoc_gridfs_file_list_new_with_opts (mongoc_gridfs_t *gridfs, const bson_t *filter, const bson_t *opts) { mongoc_gridfs_file_list_t *list; mongoc_cursor_t *cursor; cursor = mongoc_collection_find_with_opts ( gridfs->files, filter, opts, NULL /* read prefs */); BSON_ASSERT (cursor); list = (mongoc_gridfs_file_list_t *) bson_malloc0 (sizeof *list); list->cursor = cursor; list->gridfs = gridfs; return list; }
static void _test_collection_op_query_or_find_command ( test_collection_find_with_opts_t *test_data, check_request_fn_t check_request_fn, const char *reply_json, int32_t max_wire_version) { mock_server_t *server; mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; bson_error_t error; future_t *future; request_t *request; const bson_t *doc; server = mock_server_with_autoismaster (max_wire_version); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); collection = mongoc_client_get_collection (client, "db", "collection"); cursor = mongoc_collection_find_with_opts (collection, test_data->filter_bson, test_data->read_prefs, test_data->opts_bson); ASSERT_OR_PRINT (!mongoc_cursor_error (cursor, &error), error); future = future_cursor_next (cursor, &doc); request = check_request_fn (server, test_data); ASSERT (request); mock_server_replies_simple (request, reply_json); ASSERT (future_get_bool (future)); request_destroy (request); future_destroy (future); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mock_server_destroy (server); }
int be_mongo_superuser(void *conf, const char *username) { struct mongo_backend *handle = (struct mongo_backend *) conf; mongoc_collection_t *collection; mongoc_cursor_t *cursor; bson_error_t error; const bson_t *doc; int result = 0; bson_t query; bson_iter_t iter; bson_init (&query); bson_append_utf8(&query, handle->user_username_prop, -1, username, -1); collection = mongoc_client_get_collection(handle->client, handle->database, handle->user_coll); cursor = mongoc_collection_find_with_opts(collection, &query, NULL, NULL); if (!mongoc_cursor_error (cursor, &error) && mongoc_cursor_next (cursor, &doc)) { bson_iter_init(&iter, doc); if (bson_iter_find(&iter, handle->user_superuser_prop)) { result = bson_iter_as_bool(&iter) ? 1 : 0; } } if (mongoc_cursor_error (cursor, &error)) { fprintf(stderr, "Cursor Failure: %s\n", error.message); } bson_destroy (&query); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); return (result) ? BACKEND_ALLOW : BACKEND_DEFER; }
int main (int argc, char *argv[]) { mongoc_client_t *client = NULL; mongoc_database_t *database = NULL; mongoc_collection_t *collection = NULL; mongoc_cursor_t *cursor = NULL; bson_error_t error; const char *uristr = "mongodb://127.0.0.1/"; const char *authuristr; bson_t roles; bson_t query; const bson_t *doc; if (argc != 2) { printf ("%s - [implicit|scram]\n", argv[0]); return 1; } if (strcmp (argv[1], "implicit") == 0) { authuristr = "mongodb://user,=:[email protected]/test?appname=scram-example"; } else if (strcmp (argv[1], "scram") == 0) { authuristr = "mongodb://user,=:[email protected]/" "test?appname=scram-example&authMechanism=SCRAM-SHA-1"; } else { printf ("%s - [implicit|scram]\n", argv[0]); return 1; } mongoc_init (); client = mongoc_client_new (uristr); if (!client) { fprintf (stderr, "Failed to parse URI.\n"); return EXIT_FAILURE; } mongoc_client_set_error_api (client, 2); database = mongoc_client_get_database (client, "test"); bson_init (&roles); bson_init (&query); BCON_APPEND (&roles, "0", "{", "role", "root", "db", "admin", "}"); mongoc_database_add_user (database, "user,=", "pass", &roles, NULL, &error); mongoc_database_destroy (database); mongoc_client_destroy (client); client = mongoc_client_new (authuristr); if (!client) { fprintf (stderr, "failed to parse SCRAM uri\n"); goto CLEANUP; } mongoc_client_set_error_api (client, 2); collection = mongoc_client_get_collection (client, "test", "test"); cursor = mongoc_collection_find_with_opts (collection, &query, NULL, NULL); mongoc_cursor_next (cursor, &doc); if (mongoc_cursor_error (cursor, &error)) { fprintf (stderr, "Auth error: %s\n", error.message); goto CLEANUP; } CLEANUP: bson_destroy (&roles); bson_destroy (&query); if (collection) { mongoc_collection_destroy (collection); } if (client) { mongoc_client_destroy (client); } if (cursor) { mongoc_cursor_destroy (cursor); } mongoc_cleanup (); return EXIT_SUCCESS; }
static void test_getmore_cmd_await (void) { bson_t *opts; mock_server_t *server; mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; future_t *future; request_t *request; const bson_t *doc; opts = tmp_bson ("{'tailable': true," " 'awaitData': true," " 'maxAwaitTimeMS': {'$numberLong': '9999'}}"); /* * "find" command */ server = mock_server_with_autoismaster (WIRE_VERSION_FIND_CMD); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); collection = mongoc_client_get_collection (client, "db", "collection"); cursor = mongoc_collection_find_with_opts (collection, tmp_bson (NULL), NULL, opts); future = future_cursor_next (cursor, &doc); request = mock_server_receives_command ( server, "db", MONGOC_QUERY_SLAVE_OK, "{'find': 'collection', 'filter': {}}"); ASSERT (request); mock_server_replies_simple (request, "{'ok': 1," " 'cursor': {" " 'id': {'$numberLong': '123'}," " 'ns': 'db.collection'," " 'firstBatch': [{}]}}"); ASSERT (future_get_bool (future)); request_destroy (request); future_destroy (future); /* * "getMore" command */ future = future_cursor_next (cursor, &doc); request = mock_server_receives_command ( server, "db", MONGOC_QUERY_SLAVE_OK, "{'getMore': {'$numberLong': '123'}," " 'collection': 'collection'," " 'maxTimeMS': {'$numberLong': '9999'}}}"); ASSERT (request); mock_server_replies_simple (request, "{'ok': 1," " 'cursor': {" " 'id': {'$numberLong': '0'}," " 'ns': 'db.collection'," " 'nextBatch': [{}]}}"); ASSERT (future_get_bool (future)); request_destroy (request); future_destroy (future); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mock_server_destroy (server); }
bool map_reduce_basic (mongoc_database_t* database) { bson_t reply; bson_t* command; bool res; bson_error_t error; mongoc_cursor_t* cursor; const bson_t* doc; bool map_reduce_done = false; bool query_done = false; const char* out_collection_name = "outCollection"; mongoc_collection_t* out_collection; /* Empty find query */ bson_t find_query = BSON_INITIALIZER; /* Construct the mapReduce command */ /* Other arguments can also be specified here, like "query" or "limit" and so on */ command = BCON_NEW ("mapReduce", BCON_UTF8 (COLLECTION_NAME), "map", BCON_CODE (MAPPER), "reduce", BCON_CODE (REDUCER), "out", BCON_UTF8 (out_collection_name)); res = mongoc_database_command_simple (database, command, NULL, &reply, &error); map_reduce_done = true; if (!res) { fprintf (stderr, "MapReduce failed: %s\n", error.message); goto cleanup; } /* Do something with the reply (it doesn't contain the mapReduce results) */ print_res (&reply); /* Now we'll query outCollection to see what the results are */ out_collection = mongoc_database_get_collection (database, out_collection_name); cursor = mongoc_collection_find_with_opts (out_collection, &find_query, NULL, NULL); query_done = true; /* Do something with the results */ while (mongoc_cursor_next (cursor, &doc)) { print_res (doc); } if (mongoc_cursor_error (cursor, &error)) { fprintf (stderr, "ERROR: %s\n", error.message); res = false; goto cleanup; } cleanup: /* cleanup */ if (query_done) { mongoc_cursor_destroy (cursor); mongoc_collection_destroy (out_collection); } if (map_reduce_done) { bson_destroy (&reply); bson_destroy (command); } return res; }
int main (int argc, char *argv[]) { mongoc_client_t *client; mongoc_collection_t *collection; mongoc_cursor_t *cursor; bson_error_t error; const bson_t *doc; const char *collection_name = "test"; bson_t query; char *str; const char *uri_string = "mongodb://127.0.0.1/?appname=client-example"; mongoc_uri_t *uri; mongoc_init (); if (argc > 1) { uri_string = argv[1]; } if (argc > 2) { collection_name = argv[2]; } uri = mongoc_uri_new_with_error (uri_string, &error); if (!uri) { fprintf (stderr, "failed to parse URI: %s\n" "error message: %s\n", uri_string, error.message); return EXIT_FAILURE; } client = mongoc_client_new_from_uri (uri); if (!client) { return EXIT_FAILURE; } mongoc_client_set_error_api (client, 2); bson_init (&query); #if 0 bson_append_utf8 (&query, "hello", -1, "world", -1); #endif collection = mongoc_client_get_collection (client, "test", collection_name); cursor = mongoc_collection_find_with_opts ( collection, &query, NULL, /* additional options */ NULL); /* read prefs, NULL for default */ while (mongoc_cursor_next (cursor, &doc)) { str = bson_as_canonical_extended_json (doc, NULL); fprintf (stdout, "%s\n", str); bson_free (str); } if (mongoc_cursor_error (cursor, &error)) { fprintf (stderr, "Cursor Failure: %s\n", error.message); return EXIT_FAILURE; } bson_destroy (&query); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); mongoc_uri_destroy (uri); mongoc_client_destroy (client); mongoc_cleanup (); return EXIT_SUCCESS; }
static mongoc_cursor_t * find (mongoc_collection_t *collection, mongoc_read_prefs_t *prefs) { return mongoc_collection_find_with_opts ( collection, tmp_bson ("{}"), NULL /* opts */, prefs); }
int main (int argc, char *argv[]) { int exit_code = EXIT_FAILURE; mongoc_client_t *client; mongoc_client_session_t *client_session = NULL; mongoc_collection_t *collection = NULL; const char *uristr = "mongodb://127.0.0.1/?appname=session-example"; bson_error_t error; bson_t *selector = NULL; bson_t *update = NULL; bson_t *update_opts = NULL; bson_t *find_opts = NULL; mongoc_read_prefs_t *secondary = NULL; mongoc_cursor_t *cursor = NULL; const bson_t *doc; char *str; bool r; mongoc_init (); if (argc > 1) { uristr = argv[1]; } client = mongoc_client_new (uristr); if (!client) { fprintf (stderr, "Failed to parse URI.\n"); goto done; } mongoc_client_set_error_api (client, 2); /* pass NULL for options - by default the session is causally consistent */ client_session = mongoc_client_start_session (client, NULL, &error); if (!client_session) { fprintf (stderr, "Failed to start session: %s\n", error.message); goto done; } collection = mongoc_client_get_collection (client, "test", "collection"); selector = BCON_NEW ("_id", BCON_INT32 (1)); update = BCON_NEW ("$inc", "{", "x", BCON_INT32 (1), "}"); update_opts = bson_new (); if (!mongoc_client_session_append (client_session, update_opts, &error)) { fprintf (stderr, "Could not add session to opts: %s\n", error.message); goto done; } r = mongoc_collection_update_one ( collection, selector, update, update_opts, NULL /* reply */, &error); if (!r) { fprintf (stderr, "Update failed: %s\n", error.message); goto done; } bson_destroy (selector); selector = BCON_NEW ("_id", BCON_INT32 (1)); secondary = mongoc_read_prefs_new (MONGOC_READ_SECONDARY); find_opts = BCON_NEW ("maxTimeMS", BCON_INT32 (2000)); if (!mongoc_client_session_append (client_session, find_opts, &error)) { fprintf (stderr, "Could not add session to opts: %s\n", error.message); goto done; }; /* read from secondary. since we're in a causally consistent session, the * data is guaranteed to reflect the update we did on the primary. the query * blocks waiting for the secondary to catch up, if necessary, or times out * and fails after 2000 ms. */ cursor = mongoc_collection_find_with_opts ( collection, selector, find_opts, secondary); bson_destroy (selector); mongoc_read_prefs_destroy (secondary); bson_destroy (find_opts); while (mongoc_cursor_next (cursor, &doc)) { str = bson_as_json (doc, NULL); fprintf (stdout, "%s\n", str); bson_free (str); } if (mongoc_cursor_error (cursor, &error)) { fprintf (stderr, "Cursor Failure: %s\n", error.message); goto done; } exit_code = EXIT_SUCCESS; done: if (find_opts) { bson_destroy (find_opts); } if (update) { bson_destroy (update); } if (selector) { bson_destroy (selector); } if (update_opts) { bson_destroy (update_opts); } if (secondary) { mongoc_read_prefs_destroy (secondary); } /* destroy cursor, collection, session before the client they came from */ if (cursor) { mongoc_cursor_destroy (cursor); } if (collection) { mongoc_collection_destroy (collection); } if (client_session) { mongoc_client_session_destroy (client_session); } if (client) { mongoc_client_destroy (client); } mongoc_cleanup (); return exit_code; }
int be_mongo_aclcheck(void *conf, const char *clientid, const char *username, const char *topic, int acc) { struct mongo_backend *handle = (struct mongo_backend *) conf; mongoc_collection_t *collection; mongoc_cursor_t *cursor; bson_error_t error; const bson_t *doc; bson_iter_t iter; int match = 0; const bson_oid_t *topic_lookup_oid = NULL; const char *topic_lookup_utf8 = NULL; int64_t topic_lookup_int64 = 0; bson_t query; bson_init(&query); bson_append_utf8(&query, handle->user_username_prop, -1, username, -1); collection = mongoc_client_get_collection(handle->client, handle->database, handle->user_coll); cursor = mongoc_collection_find_with_opts(collection, &query, NULL, NULL); if (!mongoc_cursor_error (cursor, &error) && mongoc_cursor_next (cursor, &doc)) { // First find any user[handle->user_topiclist_fk_prop] if (bson_iter_init_find(&iter, doc, handle->user_topiclist_fk_prop)) { bson_type_t loc_id_type = bson_iter_type(&iter); if (loc_id_type == BSON_TYPE_OID) { topic_lookup_oid = bson_iter_oid(&iter); } else if (loc_id_type == BSON_TYPE_INT32 || loc_id_type == BSON_TYPE_INT64) { topic_lookup_int64 = bson_iter_as_int64(&iter); } else if (loc_id_type == BSON_TYPE_UTF8) { topic_lookup_utf8 = bson_iter_utf8(&iter, NULL); } } // Look through the props from the beginning for user[handle->user_topics_prop] if (bson_iter_init_find(&iter, doc, handle->user_topics_prop)) { bson_type_t embedded_prop_type = bson_iter_type(&iter); if (embedded_prop_type == BSON_TYPE_ARRAY) { match = be_mongo_check_acl_topics_array(&iter, topic, clientid, username); } else if (embedded_prop_type == BSON_TYPE_DOCUMENT) { match = be_mongo_check_acl_topics_map(&iter, topic, acc, clientid, username); } } } if ((mongoc_cursor_error (cursor, &error)) && (match != 1)) { fprintf (stderr, "Cursor Failure: %s\n", error.message); } bson_destroy(&query); mongoc_cursor_destroy (cursor); mongoc_collection_destroy(collection); if (!match && (topic_lookup_oid != NULL || topic_lookup_int64 != 0 || topic_lookup_utf8 != NULL)) { bson_init(&query); if (topic_lookup_oid != NULL) { bson_append_oid(&query, handle->topiclist_key_prop, -1, topic_lookup_oid); } else if (topic_lookup_int64 != 0) { bson_append_int64(&query, handle->topiclist_key_prop, -1, topic_lookup_int64); } else if (topic_lookup_utf8 != NULL) { bson_append_utf8(&query, handle->topiclist_key_prop, -1, topic_lookup_utf8, -1); } collection = mongoc_client_get_collection(handle->client, handle->database, handle->topiclist_coll); cursor = mongoc_collection_find_with_opts(collection, &query, NULL, NULL); if (!mongoc_cursor_error (cursor, &error) && mongoc_cursor_next(cursor, &doc)) { bson_iter_init(&iter, doc); if (bson_iter_find(&iter, handle->topiclist_topics_prop)) { bson_type_t loc_prop_type = bson_iter_type(&iter); if (loc_prop_type == BSON_TYPE_ARRAY) { match = be_mongo_check_acl_topics_array(&iter, topic, clientid, username); } else if (loc_prop_type == BSON_TYPE_DOCUMENT) { match = be_mongo_check_acl_topics_map(&iter, topic, acc, clientid, username); } } else { _log(LOG_NOTICE, "[mongo] ACL check error - no topic list found for user (%s) in collection (%s)", username, handle->topiclist_coll); } } if ((mongoc_cursor_error (cursor, &error)) && (match != 1)) { fprintf (stderr, "Cursor Failure: %s\n", error.message); } bson_destroy(&query); mongoc_cursor_destroy(cursor); mongoc_collection_destroy(collection); } return (match) ? BACKEND_ALLOW : BACKEND_DEFER; }
/** * _mongoc_gridfs_file_refresh_page: * * Refresh a GridFS file's underlying page. This recalculates the current * page number based on the file's stream position, then fetches that page * from the database. * * Note that this fetch is unconditional and the page is queried from the * database even if the current page covers the same theoretical chunk. * * * Side Effects: * * file->page is loaded with the appropriate buffer, fetched from the * database. If the file position is at the end of the file and on a new * chunk boundary, a new page is created. If the position is far past the * end of the file, _mongoc_gridfs_file_extend is responsible for creating * chunks to file the gap. * * file->n is set based on file->pos. file->error is set on error. */ static bool _mongoc_gridfs_file_refresh_page (mongoc_gridfs_file_t *file) { bson_t query; bson_t child; bson_t opts; const bson_t *chunk; const char *key; bson_iter_t iter; int64_t existing_chunks; int64_t required_chunks; const uint8_t *data = NULL; uint32_t len; ENTRY; BSON_ASSERT (file); file->n = (int32_t) (file->pos / file->chunk_size); if (file->page) { _mongoc_gridfs_file_page_destroy (file->page); file->page = NULL; } /* if the file pointer is past the end of the current file (i.e. pointing to * a new chunk), we'll pass the page constructor a new empty page. */ existing_chunks = divide_round_up (file->length, file->chunk_size); required_chunks = divide_round_up (file->pos + 1, file->chunk_size); if (required_chunks > existing_chunks) { data = (uint8_t *) ""; len = 0; } else { /* if we have a cursor, but the cursor doesn't have the chunk we're going * to need, destroy it (we'll grab a new one immediately there after) */ if (file->cursor && !_mongoc_gridfs_file_keep_cursor (file)) { mongoc_cursor_destroy (file->cursor); file->cursor = NULL; } if (!file->cursor) { bson_init (&query); BSON_APPEND_VALUE (&query, "files_id", &file->files_id); BSON_APPEND_DOCUMENT_BEGIN (&query, "n", &child); BSON_APPEND_INT32 (&child, "$gte", file->n); bson_append_document_end (&query, &child); bson_init (&opts); BSON_APPEND_DOCUMENT_BEGIN (&opts, "sort", &child); BSON_APPEND_INT32 (&child, "n", 1); bson_append_document_end (&opts, &child); BSON_APPEND_DOCUMENT_BEGIN (&opts, "projection", &child); BSON_APPEND_INT32 (&child, "n", 1); BSON_APPEND_INT32 (&child, "data", 1); BSON_APPEND_INT32 (&child, "_id", 0); bson_append_document_end (&opts, &child); /* find all chunks greater than or equal to our current file pos */ file->cursor = mongoc_collection_find_with_opts ( file->gridfs->chunks, &query, &opts, NULL); file->cursor_range[0] = file->n; file->cursor_range[1] = (uint32_t) (file->length / file->chunk_size); bson_destroy (&query); bson_destroy (&opts); BSON_ASSERT (file->cursor); } /* we might have had a cursor before, then seeked ahead past a chunk. * iterate until we're on the right chunk */ while (file->cursor_range[0] <= file->n) { if (!mongoc_cursor_next (file->cursor, &chunk)) { /* copy cursor error; if there's none, we're missing a chunk */ if (!mongoc_cursor_error (file->cursor, &file->error)) { missing_chunk (file); } RETURN (0); } file->cursor_range[0]++; } BSON_ASSERT (bson_iter_init (&iter, chunk)); /* grab out what we need from the chunk */ while (bson_iter_next (&iter)) { key = bson_iter_key (&iter); if (strcmp (key, "n") == 0) { if (file->n != bson_iter_int32 (&iter)) { missing_chunk (file); RETURN (0); } } else if (strcmp (key, "data") == 0) { bson_iter_binary (&iter, NULL, &len, &data); } else { /* Unexpected key. This should never happen */ RETURN (0); } } if (file->n != file->pos / file->chunk_size) { return 0; } } if (!data) { bson_set_error (&file->error, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_CHUNK_MISSING, "corrupt chunk number %" PRId32, file->n); RETURN (0); } file->page = _mongoc_gridfs_file_page_new (data, len, file->chunk_size); /* seek in the page towards wherever we're supposed to be */ RETURN ( _mongoc_gridfs_file_page_seek (file->page, file->pos % file->chunk_size)); }