summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2014-12-02 10:06:21 +0100
committerJörg Frings-Fürst <debian@jff-webhosting.net>2014-12-02 10:06:21 +0100
commitfd841e416881cc0392e61ec312c1870f3a0004bd (patch)
tree8357ba56e79d614ba57f722e7878b853591dc339 /examples
Initial import of libmongo-client version 0.1.8-2
Diffstat (limited to 'examples')
-rw-r--r--examples/Makefile.am8
-rw-r--r--examples/bson-inspect.c341
-rw-r--r--examples/gridfs.c413
-rw-r--r--examples/mongo-dump.c224
4 files changed, 986 insertions, 0 deletions
diff --git a/examples/Makefile.am b/examples/Makefile.am
new file mode 100644
index 0000000..0cff31f
--- /dev/null
+++ b/examples/Makefile.am
@@ -0,0 +1,8 @@
+noinst_PROGRAMS = mongo-dump bson-inspect gridfs
+
+AM_CFLAGS = -I$(top_srcdir)/src/ @GLIB_CFLAGS@
+LDADD = $(top_builddir)/src/libmongo-client.la @GLIB_LIBS@
+
+mongo_dump_SOURCES = mongo-dump.c
+bson_inspect_SOURCES = bson-inspect.c
+gridfs_SOURCES = gridfs.c
diff --git a/examples/bson-inspect.c b/examples/bson-inspect.c
new file mode 100644
index 0000000..841dc45
--- /dev/null
+++ b/examples/bson-inspect.c
@@ -0,0 +1,341 @@
+/* bson-inspect.c - BSON inspector, example application.
+ * Copyright 2011, 2012 Gergely Nagy <algernon@balabit.hu>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <glib.h>
+#include <bson.h>
+
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static void
+_indent (gint level, gboolean verbose)
+{
+ gint i;
+
+ if (!verbose)
+ return;
+
+ for (i = 1; i <= level; i++)
+ printf (" ");
+}
+
+static void
+bson_dump (bson *b, gint ilevel, gboolean verbose, gboolean as_array)
+{
+ bson_cursor *c;
+ gboolean first = TRUE;
+
+ c = bson_cursor_new (b);
+ while (bson_cursor_next (c))
+ {
+ if (!first)
+ {
+ printf (", ");
+ if (verbose)
+ printf ("\n");
+ }
+ first = FALSE;
+ if (verbose)
+ {
+ _indent (ilevel, verbose);
+ printf ("/* type='%s'; */\n",
+ bson_cursor_type_as_string (c) + 10);
+ }
+ _indent (ilevel, verbose);
+ if (!as_array)
+ {
+ printf ("\"%s\" : ", bson_cursor_key (c));
+ }
+ switch (bson_cursor_type (c))
+ {
+ case BSON_TYPE_DOUBLE:
+ {
+ gdouble d;
+ bson_cursor_get_double (c, &d);
+ printf ("%f", d);
+ break;
+ }
+ case BSON_TYPE_STRING:
+ {
+ const gchar *s;
+ gchar *s2;
+ bson_cursor_get_string (c, &s);
+ s2 = g_strescape (s, NULL);
+ printf ("\"%s\"", s2);
+ g_free (s2);
+ break;
+ }
+ case BSON_TYPE_OID:
+ {
+ const guint8 *oid;
+ gint j;
+ bson_cursor_get_oid (c, &oid);
+ printf ("ObjectId( \"");
+ for (j = 0; j < 12; j++)
+ printf ("%02x", oid[j]);
+ printf ("\" )");
+ break;
+ }
+ case BSON_TYPE_BOOLEAN:
+ {
+ gboolean b;
+ bson_cursor_get_boolean (c, &b);
+ printf ((b) ? "true" : "false");
+ break;
+ }
+ case BSON_TYPE_REGEXP:
+ {
+ const gchar *r, *o;
+ gchar *r2, *o2;
+ bson_cursor_get_regex (c, &r, &o);
+ r2 = g_strescape (r, NULL);
+ o2 = g_strescape (o, NULL);
+ printf ("Regex(\"/%s/%s\")", r2, o2);
+ g_free (r2);
+ g_free (o2);
+ break;
+ }
+ case BSON_TYPE_NULL:
+ {
+ printf ("null");
+ break;
+ }
+ case BSON_TYPE_JS_CODE:
+ {
+ const gchar *js;
+ gchar *js2;
+ bson_cursor_get_javascript (c, &js);
+ js2 = g_strescape (js, NULL);
+ printf ("%s", js2);
+ g_free (js2);
+ break;
+ }
+ case BSON_TYPE_SYMBOL:
+ {
+ const gchar *s;
+ gchar *s2;
+ bson_cursor_get_symbol (c, &s);
+ s2 = g_strescape (s, NULL);
+ printf ("%s", s2);
+ g_free (s2);
+ break;
+ }
+ case BSON_TYPE_INT32:
+ {
+ gint32 l32;
+ bson_cursor_get_int32 (c, &l32);
+ printf ("%d", l32);
+ break;
+ }
+ case BSON_TYPE_INT64:
+ {
+ gint64 l64;
+ bson_cursor_get_int64 (c, &l64);
+ printf ("%" G_GINT64_FORMAT, l64);
+ break;
+ }
+ case BSON_TYPE_DOCUMENT:
+ {
+ bson *sd;
+ bson_cursor_get_document (c, &sd);
+ printf ("{ ");
+ if (verbose)
+ printf ("/* size='%d' */\n", bson_size (sd));
+ bson_dump (sd, ilevel + 1, verbose, FALSE);
+ if (verbose)
+ {
+ printf ("\n");
+ _indent (ilevel, verbose);
+ printf ("}");
+ }
+ else
+ printf (" }");
+ bson_free (sd);
+ break;
+ }
+ case BSON_TYPE_ARRAY:
+ {
+ bson *sa;
+
+ bson_cursor_get_array (c, &sa);
+ printf ("[ ");
+ if (verbose)
+ printf ("/* size='%d' */\n", bson_size (sa));
+ bson_dump (sa, ilevel + 1, verbose, TRUE);
+ if (verbose)
+ {
+ printf ("\n");
+ _indent (ilevel, verbose);
+ printf ("]");
+ }
+ else
+ printf (" ]");
+ bson_free (sa);
+ break;
+ }
+ case BSON_TYPE_BINARY:
+ {
+ const guint8 *data;
+ gint32 size;
+ bson_binary_subtype t;
+ gchar *b64;
+
+ bson_cursor_get_binary (c, &t, &data, &size);
+ b64 = g_base64_encode (data, size);
+ printf ("{ ");
+ if (verbose)
+ {
+ printf ("/* size='%d' */\n", size);
+ _indent (ilevel + 1, verbose);
+ }
+ printf ("\"$binary\" : \"%s\",", b64);
+ if (verbose)
+ {
+ printf ("\n");
+ _indent (ilevel + 1, verbose);
+ }
+ else
+ printf (" ");
+ printf ("\"$type\" : \"%02d\"", t);
+ if (verbose)
+ {
+ printf ("\n");
+ _indent (ilevel, verbose);
+ }
+ else
+ printf (" ");
+ printf ("}");
+ g_free (b64);
+ break;
+ }
+ case BSON_TYPE_JS_CODE_W_SCOPE:
+ case BSON_TYPE_UNDEFINED:
+ case BSON_TYPE_UTC_DATETIME:
+ case BSON_TYPE_DBPOINTER:
+ case BSON_TYPE_TIMESTAMP:
+ case BSON_TYPE_MIN:
+ case BSON_TYPE_MAX:
+ default:
+ printf ("\"<unimplemented>\"");
+ break;
+ }
+ }
+ bson_cursor_free (c);
+}
+
+int
+main (int argc, char *argv[])
+{
+ int fd;
+ off_t offs = 0;
+ bson *b;
+ guint8 *data;
+ struct stat st;
+ gint64 i = 1;
+ GOptionContext *context;
+ gboolean verbose = FALSE;
+ GError *error = NULL;
+
+ GOptionEntry entries[] =
+ {
+ { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
+ "Be verbose", NULL },
+ { NULL, 0, 0, 0, NULL, NULL, NULL }
+ };
+
+ context = g_option_context_new ("- inspect a BSON dump");
+ g_option_context_add_main_entries (context, entries, "bson-inspect");
+ if (!g_option_context_parse (context, &argc, &argv, &error))
+ {
+ g_print ("option parsing failed: %s\n", error->message);
+ exit (1);
+ }
+
+ if (argc < 2)
+ {
+ gchar **nargv;
+ argc = 2;
+
+ nargv = g_new (gchar *, 3);
+ nargv[0] = argv[0];
+ nargv[1] = "--help";
+ nargv[2] = NULL;
+
+ g_option_context_parse (context, &argc, (gchar ***)&nargv, &error);
+
+ exit (1);
+ }
+
+ fd = open (argv[1], O_RDONLY);
+ if (fd == -1)
+ {
+ fprintf (stderr, "Error opening file '%s': %s\n",
+ argv[1], strerror (errno));
+ exit (1);
+ }
+ if (fstat (fd, &st) != 0)
+ {
+ fprintf (stderr, "Error fstat()ing file '%s': %s\n",
+ argv[1], strerror (errno));
+ close (fd);
+ exit (1);
+ }
+
+ data = mmap (NULL, (size_t)st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (data == MAP_FAILED)
+ {
+ fprintf (stderr, "Error mmap()ing file '%s': %s\n",
+ argv[1], strerror (errno));
+ close (fd);
+ exit (1);
+ }
+
+ while (offs < st.st_size)
+ {
+ b = bson_new_from_data ((const guint8 *)(data + offs),
+ bson_stream_doc_size (data, offs) - 1);
+ bson_finish (b);
+ offs += bson_size (b);
+
+ if (verbose)
+ printf ("/* Document #%" G_GUINT64_FORMAT "; size='%d' */\n", i,
+ bson_size (b));
+ printf ("{ ");
+ if (verbose)
+ printf ("\n");
+ bson_dump (b, 1, verbose, FALSE);
+ if (verbose)
+ printf ("\n}\n");
+ else
+ printf (" }\n");
+ if (verbose)
+ printf ("\n");
+
+ bson_free (b);
+ i++;
+ }
+ munmap (data, st.st_size);
+ close (fd);
+
+ return 0;
+}
diff --git a/examples/gridfs.c b/examples/gridfs.c
new file mode 100644
index 0000000..2d19aee
--- /dev/null
+++ b/examples/gridfs.c
@@ -0,0 +1,413 @@
+/* gridfs.c - A GridFS utility; example application
+ * Copyright 2011, 2012 Gergely Nagy <algernon@balabit.hu>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <mongo.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+typedef struct
+{
+ gchar *host;
+ gint port;
+ gchar *db;
+ gchar *coll;
+ gchar *ns;
+ gboolean verbose;
+ gboolean slaveok;
+ gboolean master_sync;
+} config_t;
+
+#define VLOG(...) { if (config->verbose) fprintf (stderr, __VA_ARGS__); }
+
+void
+mongo_gridfs_error (int e)
+{
+ fprintf (stderr, "Error encountered: %s\n", strerror (e));
+ exit (1);
+}
+
+mongo_sync_gridfs *
+mongo_gridfs_connect (config_t *config)
+{
+ mongo_sync_connection *conn;
+ mongo_sync_gridfs *gfs;
+
+ VLOG ("Connecting to %s:%d/%s.%s...\n", config->host, config->port,
+ config->db, config->coll);
+
+ conn = mongo_sync_connect (config->host, config->port, config->slaveok);
+ if (!conn)
+ mongo_gridfs_error (errno);
+
+ if (config->master_sync)
+ {
+ VLOG ("Syncing to master...\n");
+ conn = mongo_sync_reconnect (conn, TRUE);
+ if (!conn)
+ mongo_gridfs_error (errno);
+ }
+
+ gfs = mongo_sync_gridfs_new (conn, config->ns);
+ if (!gfs)
+ mongo_gridfs_error (errno);
+
+ return gfs;
+}
+
+void
+mongo_gridfs_get (config_t *config, gint argc, gchar *argv[])
+{
+ mongo_sync_gridfs *gfs;
+ mongo_sync_gridfs_chunked_file *gfile;
+ mongo_sync_cursor *cursor;
+ gint64 n = 0;
+ bson *query;
+ int fd;
+
+ gchar *gfn, *ofn;
+
+ if (argc < 4)
+ {
+ fprintf (stderr, "Usage: %s get GRIDFS_FILENAME OUTPUT_FILENAME\n",
+ argv[0]);
+ exit (1);
+ }
+ gfn = argv[2];
+ ofn = argv[3];
+
+ gfs = mongo_gridfs_connect (config);
+
+ VLOG ("Trying to find '%s'...\n", gfn);
+
+ query = bson_build (BSON_TYPE_STRING, "filename", gfn, -1,
+ BSON_TYPE_NONE);
+ bson_finish (query);
+ gfile = mongo_sync_gridfs_chunked_find (gfs, query);
+ if (!gfile)
+ mongo_gridfs_error (errno);
+ bson_free (query);
+
+ VLOG ("Opening output file '%s'...\n", ofn);
+ fd = open (ofn, O_RDWR | O_CREAT | O_TRUNC, 0600);
+ if (fd == -1)
+ {
+ fprintf (stderr, "Error opening output file '%s': %s\n",
+ ofn, strerror (errno));
+ exit (1);
+ }
+
+ VLOG ("Writing '%s' -> '%s' (%" G_GINT64_FORMAT " bytes in %" G_GINT64_FORMAT
+ " chunks)\n", gfn, ofn,
+ mongo_sync_gridfs_file_get_length (gfile),
+ mongo_sync_gridfs_file_get_chunks (gfile));
+
+ cursor = mongo_sync_gridfs_chunked_file_cursor_new (gfile, 0, 0);
+ if (!cursor)
+ mongo_gridfs_error (errno);
+
+ while (mongo_sync_cursor_next (cursor))
+ {
+ gint32 size;
+ guint8 *data;
+
+ VLOG ("\rWriting chunk %" G_GINT64_FORMAT "...", n++);
+
+ data = mongo_sync_gridfs_chunked_file_cursor_get_chunk (cursor, &size);
+ if (!data)
+ mongo_gridfs_error (errno);
+
+ if (write (fd, data, size) != size)
+ {
+ perror ("write()");
+ exit (1);
+ }
+ g_free (data);
+ }
+ mongo_sync_cursor_free (cursor);
+ mongo_sync_gridfs_chunked_file_free (gfile);
+
+ close (fd);
+
+ mongo_sync_gridfs_free (gfs, TRUE);
+
+ VLOG("\n");
+}
+
+void
+mongo_gridfs_put (config_t *config, gint argc, gchar *argv[])
+{
+ mongo_sync_gridfs *gfs;
+ mongo_sync_gridfs_chunked_file *gfile;
+ bson *meta;
+ int fd;
+ guint8 *data;
+ struct stat st;
+
+ gchar *gfn, *ifn, *oid_s;
+
+ if (argc < 4)
+ {
+ fprintf (stderr, "Usage: %s put INPUT_FILENAME GRIDFS_FILENAME\n",
+ argv[0]);
+ exit (1);
+ }
+ ifn = argv[2];
+ gfn = argv[3];
+
+ mongo_util_oid_init (0);
+
+ gfs = mongo_gridfs_connect (config);
+
+ VLOG ("Opening input file: '%s'...\n", ifn);
+ fd = open (ifn, O_RDONLY);
+ if (!fd)
+ {
+ fprintf (stderr, "Error opening input file: %s\n",
+ strerror (errno));
+ exit (1);
+ }
+ if (fstat (fd, &st) != 0)
+ {
+ fprintf (stderr, "Error stat'ing the input file: %s\n",
+ strerror (errno));
+ exit (1);
+ }
+
+ data = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (data == MAP_FAILED)
+ {
+ fprintf (stderr, "Error mmapping the input file: %s\n",
+ strerror (errno));
+ }
+
+ meta = bson_build (BSON_TYPE_STRING, "filename", gfn, -1,
+ BSON_TYPE_NONE);
+ bson_finish (meta);
+
+ VLOG ("Uploading '%s' -> '%s'...\n", ifn, gfn);
+
+ gfile = mongo_sync_gridfs_chunked_file_new_from_buffer (gfs, meta,
+ data, st.st_size);
+ if (!gfile)
+ mongo_gridfs_error (errno);
+ bson_free (meta);
+ munmap (data, st.st_size);
+
+ oid_s = mongo_util_oid_as_string (mongo_sync_gridfs_file_get_id (gfile));
+ printf ("Uploaded file: %s (_id: %s; md5 = %s)\n", gfn,
+ oid_s,
+ mongo_sync_gridfs_file_get_md5 (gfile));
+
+ g_free (oid_s);
+ mongo_sync_gridfs_chunked_file_free (gfile);
+ mongo_sync_gridfs_free (gfs, TRUE);
+}
+
+void
+mongo_gridfs_list (config_t *config)
+{
+ mongo_sync_cursor *cursor;
+ mongo_sync_gridfs *gfs;
+
+ gfs = mongo_gridfs_connect (config);
+
+ cursor = mongo_sync_gridfs_list (gfs, NULL);
+
+ while (mongo_sync_cursor_next (cursor))
+ {
+ bson *meta = mongo_sync_cursor_get_data (cursor);
+ bson_cursor *c;
+ const guint8 oid[12];
+ gint32 i32, chunk_size;
+ gint64 length, date;
+ const gchar *md5, *filename = NULL;
+ gchar *oid_s;
+
+ c = bson_find (meta, "_id");
+ if (!bson_cursor_get_oid (c, (const guint8 **)&oid))
+ mongo_gridfs_error (errno);
+
+ bson_cursor_find (c, "length");
+ if (!bson_cursor_get_int32 (c, &i32))
+ {
+ if (!bson_cursor_get_int64 (c, &length))
+ mongo_gridfs_error (errno);
+ }
+ else
+ length = i32;
+
+ bson_cursor_find (c, "chunkSize");
+ if (!bson_cursor_get_int32 (c, &chunk_size))
+ mongo_gridfs_error (errno);
+
+ bson_cursor_find (c, "uploadDate");
+ if (!bson_cursor_get_utc_datetime (c, &date))
+ mongo_gridfs_error (errno);
+
+ bson_cursor_find (c, "md5");
+ if (!bson_cursor_get_string (c, &md5))
+ mongo_gridfs_error (errno);
+
+ bson_cursor_find (c, "filename");
+ bson_cursor_get_string (c, &filename);
+
+ bson_cursor_free (c);
+
+ oid_s = mongo_util_oid_as_string (oid);
+ printf ("{ _id: ObjectID(\"%s\"), length: %" G_GINT64_FORMAT
+ ", chunkSize: %i, uploadDate: %"
+ G_GINT64_FORMAT ", md5: \"%s\"",
+
+ oid_s, length, chunk_size, date, md5);
+ g_free (oid_s);
+
+ if (filename)
+ printf (", filename: \"%s\"", filename);
+ printf (" }\n");
+
+ if (config->verbose)
+ {
+ c = bson_cursor_new (meta);
+ printf ("\tExtra metadata: [ ");
+ while (bson_cursor_next (c))
+ {
+ if (strcmp (bson_cursor_key (c), "_id") &&
+ strcmp (bson_cursor_key (c), "length") &&
+ strcmp (bson_cursor_key (c), "chunkSize") &&
+ strcmp (bson_cursor_key (c), "uploadDate") &&
+ strcmp (bson_cursor_key (c), "md5") &&
+ strcmp (bson_cursor_key (c), "filename"))
+ {
+ printf ("%s (%s), ", bson_cursor_key (c),
+ bson_cursor_type_as_string (c));
+ }
+ }
+ bson_cursor_free (c);
+ printf ("]\n");
+ }
+ }
+
+ mongo_sync_gridfs_free (gfs, TRUE);
+}
+
+void
+mongo_gridfs_remove (config_t *config, gint argc, gchar *argv[])
+{
+ mongo_sync_gridfs *gfs;
+ bson *query;
+ gchar *fn;
+
+ if (argc < 3)
+ {
+ fprintf (stderr, "Usage: %s remove GRIDFS_FILENAME\n", argv[0]);
+ exit (1);
+ }
+ fn = argv[2];
+
+ gfs = mongo_gridfs_connect (config);
+
+ VLOG ("Deleting file: '%s'...\n", fn);
+
+ query = bson_build (BSON_TYPE_STRING, "filename", fn, -1,
+ BSON_TYPE_NONE);
+ bson_finish (query);
+
+ if (mongo_sync_gridfs_remove (gfs, query))
+ {
+ VLOG ("\tDeleted\n");
+ }
+ else
+ {
+ VLOG ("\tFailed: %s\n", strerror (errno));
+ }
+ bson_free (query);
+
+ mongo_sync_gridfs_free (gfs, TRUE);
+}
+
+int
+main (int argc, char *argv[])
+{
+ GError *error = NULL;
+ GOptionContext *context;
+ config_t config = {
+ NULL, 27017, NULL, NULL, NULL, FALSE, FALSE, FALSE
+ };
+
+ GOptionEntry entries[] =
+ {
+ { "host", 'h', 0, G_OPTION_ARG_STRING, &config.host,
+ "Host to connect to", "HOST" },
+ { "port", 'p', 0, G_OPTION_ARG_INT, &config.port, "Port", "PORT" },
+ { "db", 'd', 0, G_OPTION_ARG_STRING, &config.db, "Database", "DB" },
+ { "collection", 'c', 0, G_OPTION_ARG_STRING, &config.coll, "Collection",
+ "COLL" },
+ { "verbose", 'v', 0, G_OPTION_ARG_NONE, &config.verbose,
+ "Be verbose", NULL },
+ { "slave-ok", 's', 0, G_OPTION_ARG_NONE, &config.slaveok,
+ "Connecting to slaves is ok", NULL },
+ { "master-sync", 'm', 0, G_OPTION_ARG_NONE, &config.master_sync,
+ "Reconnect to the replica master", NULL },
+ { NULL, 0, 0, 0, NULL, NULL, NULL }
+ };
+
+ context = g_option_context_new ("- GridFS utility");
+ g_option_context_add_main_entries (context, entries, "mongo-dump");
+ if (!g_option_context_parse (context, &argc, &argv, &error))
+ {
+ g_print ("option parsing failed: %s\n", error->message);
+ exit (1);
+ }
+
+ if (!config.host || !config.port || !config.db ||
+ !config.coll || argc < 2)
+ {
+ gchar **nargv;
+ argc = 2;
+
+ nargv = g_new (gchar *, 3);
+ nargv[0] = argv[0];
+ nargv[1] = "--help";
+ nargv[2] = NULL;
+
+ g_option_context_parse (context, &argc, (gchar ***)&nargv, &error);
+
+ exit (1);
+ }
+ config.ns = g_strdup_printf ("%s.%s", config.db, config.coll);
+
+ if (g_ascii_strcasecmp (argv[1], "get") == 0)
+ mongo_gridfs_get (&config, argc, argv);
+ else if (g_ascii_strcasecmp (argv[1], "put") == 0)
+ mongo_gridfs_put (&config, argc, argv);
+ else if (g_ascii_strcasecmp (argv[1], "list") == 0)
+ mongo_gridfs_list (&config);
+ else if (g_ascii_strcasecmp (argv[1], "remove") == 0)
+ mongo_gridfs_remove (&config, argc, argv);
+
+ g_free (config.ns);
+ g_option_context_free (context);
+
+ return 0;
+}
diff --git a/examples/mongo-dump.c b/examples/mongo-dump.c
new file mode 100644
index 0000000..7e6419f
--- /dev/null
+++ b/examples/mongo-dump.c
@@ -0,0 +1,224 @@
+/* mongo-dump.c - MongoDB database dumper; example application.
+ * Copyright 2011, 2012 Gergely Nagy <algernon@balabit.hu>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <mongo.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+typedef struct
+{
+ gchar *addr;
+ gint port;
+ gchar *db;
+ gchar *coll;
+ gchar *output;
+ gchar *ns;
+ gboolean verbose;
+ gboolean slaveok;
+ gboolean master_sync;
+} config_t;
+
+#define VLOG(...) { if (config->verbose) fprintf (stderr, __VA_ARGS__); }
+
+void
+mongo_dump (config_t *config)
+{
+ mongo_sync_connection *conn;
+ mongo_sync_cursor *cursor;
+ bson *b;
+ int fd;
+
+ glong cnt, pos = 0;
+
+ gchar *error = NULL;
+ int e;
+
+ if (config->port == MONGO_CONN_LOCAL)
+ {
+ VLOG ("Connecting to %s/%s.%s...\n", config->addr, config->db,
+ config->coll);
+ }
+ else
+ {
+ VLOG ("Connecting to %s:%d/%s.%s...\n", config->addr, config->port,
+ config->db, config->coll);
+ }
+ conn = mongo_sync_connect (config->addr, config->port, config->slaveok);
+
+ if (!conn)
+ {
+ e = errno;
+
+ mongo_sync_cmd_get_last_error (conn, config->db, &error);
+ fprintf (stderr, "Error connecting to %s:%d: %s\n", config->addr,
+ config->port, (error) ? error : strerror (e));
+ g_free (error);
+ exit (1);
+ }
+
+ if (config->master_sync)
+ {
+ VLOG ("Syncing to master...\n");
+ conn = mongo_sync_reconnect (conn, TRUE);
+ if (!conn)
+ {
+ e = errno;
+
+ mongo_sync_cmd_get_last_error (conn, config->db, &error);
+ fprintf (stderr, "Error reconnecting to the master of %s:%d: %s\n",
+ config->addr, config->port, (error) ? error : strerror (e));
+ exit (1);
+ }
+ }
+
+ VLOG ("Counting documents...\n");
+ cnt = mongo_sync_cmd_count (conn, config->db, config->coll, NULL);
+ if (cnt < 0)
+ {
+ e = errno;
+
+ mongo_sync_cmd_get_last_error (conn, config->db, &error);
+ fprintf (stderr, "Error counting documents in %s.%s: %s\n",
+ config->db, config->coll, (error) ? error : strerror (e));
+ mongo_sync_disconnect (conn);
+ exit (1);
+ }
+
+ VLOG ("Opening output file '%s'...\n", config->output);
+ if (strcmp (config->output, "-") == 0)
+ fd = 1;
+ else
+ {
+ fd = open (config->output, O_RDWR | O_CREAT | O_TRUNC, 0600);
+ if (fd == -1)
+ {
+ fprintf (stderr, "Error opening output file '%s': %s\n",
+ config->output, strerror (errno));
+ mongo_sync_disconnect (conn);
+ exit (1);
+ }
+ }
+
+ VLOG ("Launching initial query...\n");
+ b = bson_new ();
+ bson_finish (b);
+ cursor = mongo_sync_cursor_new (conn, config->ns,
+ mongo_sync_cmd_query (conn, config->ns,
+ MONGO_WIRE_FLAG_QUERY_NO_CURSOR_TIMEOUT,
+ 0, 10, b, NULL));
+ bson_free (b);
+
+ while ((pos < cnt) && mongo_sync_cursor_next (cursor))
+ {
+ bson *b = mongo_sync_cursor_get_data (cursor);
+ pos++;
+
+ if (!b)
+ {
+ e = errno;
+
+ mongo_sync_cmd_get_last_error (conn, config->db, &error);
+ fprintf (stderr, "Error advancing the cursor: %s\n",
+ (error) ? error : strerror (e));
+ mongo_sync_disconnect (conn);
+ exit (1);
+ }
+
+ if (pos % 10 == 0)
+ VLOG ("\rDumping... %03.2f%%", (pos * 1.0) / (cnt * 1.0) * 100);
+
+ if (write (fd, bson_data (b), bson_size (b)) != bson_size (b))
+ {
+ perror ("write()");
+ exit (1);
+ }
+ bson_free (b);
+ }
+ VLOG ("\rDumping... %03.2f%%\n", (double)((pos / cnt) * 100));
+
+ mongo_sync_cursor_free (cursor);
+
+ close (fd);
+ mongo_sync_disconnect (conn);
+}
+
+int
+main (int argc, char *argv[])
+{
+ GError *error = NULL;
+ GOptionContext *context;
+ config_t config = {
+ NULL, 27017, NULL, NULL, NULL, NULL, FALSE, FALSE, FALSE
+ };
+
+ GOptionEntry entries[] =
+ {
+ { "addr", 'a', 0, G_OPTION_ARG_STRING, &config.addr,
+ "Address to connect to", "ADDRESS" },
+ { "port", 'p', 0, G_OPTION_ARG_INT, &config.port, "Port", "PORT" },
+ { "db", 'd', 0, G_OPTION_ARG_STRING, &config.db, "Database", "DB" },
+ { "collection", 'c', 0, G_OPTION_ARG_STRING, &config.coll, "Collection",
+ "COLL" },
+ { "verbose", 'v', 0, G_OPTION_ARG_NONE, &config.verbose,
+ "Be verbose", NULL },
+ { "output", 'o', 0, G_OPTION_ARG_STRING, &config.output,
+ "Output", "FILENAME" },
+ { "slave-ok", 's', 0, G_OPTION_ARG_NONE, &config.slaveok,
+ "Connecting to slaves is ok", NULL },
+ { "master-sync", 'm', 0, G_OPTION_ARG_NONE, &config.master_sync,
+ "Reconnect to the replica master", NULL },
+ { NULL, 0, 0, 0, NULL, NULL, NULL }
+ };
+
+ context = g_option_context_new ("- dump a complete mongo collection");
+ g_option_context_add_main_entries (context, entries, "mongo-dump");
+ if (!g_option_context_parse (context, &argc, &argv, &error))
+ {
+ g_print ("option parsing failed: %s\n", error->message);
+ exit (1);
+ }
+
+ if (!((config.addr && config.port)) || !config.db ||
+ !config.coll || !config.output)
+ {
+ gchar **nargv;
+ argc = 2;
+
+ nargv = g_new (gchar *, 3);
+ nargv[0] = argv[0];
+ nargv[1] = "--help";
+ nargv[2] = NULL;
+
+ g_option_context_parse (context, &argc, (gchar ***)&nargv, &error);
+
+ exit (1);
+ }
+
+ config.ns = g_strdup_printf ("%s.%s", config.db, config.coll);
+ mongo_dump (&config);
+
+ g_free (config.ns);
+ g_option_context_free (context);
+
+ return 0;
+}