libmongo-client 0.1.4
src/sync-gridfs.c
Go to the documentation of this file.
00001 /* sync-gridfs.c - libmongo-client GridFS implementation
00002  * Copyright 2011 Gergely Nagy <algernon@balabit.hu>
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00021 #include "sync-gridfs.h"
00022 #include "libmongo-private.h"
00023 
00024 #include <errno.h>
00025 
00026 mongo_sync_gridfs *
00027 mongo_sync_gridfs_new (mongo_sync_connection *conn,
00028                        const gchar *ns_prefix)
00029 {
00030   mongo_sync_gridfs *gfs;
00031   bson *index;
00032   gchar *db;
00033 
00034   if (!conn)
00035     {
00036       errno = ENOTCONN;
00037       return NULL;
00038     }
00039   if (!ns_prefix)
00040     {
00041       errno = EINVAL;
00042       return NULL;
00043     }
00044   db = strchr (ns_prefix, '.');
00045   if (!db)
00046     {
00047       errno = EINVAL;
00048       return NULL;
00049     }
00050 
00051   gfs = g_new (mongo_sync_gridfs, 1);
00052   gfs->conn = conn;
00053 
00054   gfs->ns.prefix = g_strdup (ns_prefix);
00055   gfs->ns.files = g_strconcat (gfs->ns.prefix, ".files", NULL);
00056   gfs->ns.chunks = g_strconcat (gfs->ns.prefix, ".chunks", NULL);
00057   gfs->ns.db = g_strndup (ns_prefix, db - ns_prefix);
00058 
00059   gfs->chunk_size = 256 * 1024;
00060 
00061   index = bson_new_sized (256);
00062   bson_append_int32 (index, "files_id", 1);
00063   bson_append_int32 (index, "n", 1);
00064   bson_finish (index);
00065 
00066   if (!mongo_sync_cmd_index_create (conn, gfs->ns.chunks, index,
00067                                     MONGO_INDEX_UNIQUE))
00068     {
00069       bson_free (index);
00070       mongo_sync_gridfs_free (gfs, FALSE);
00071 
00072       errno = EPROTO;
00073       return NULL;
00074     }
00075   bson_free (index);
00076 
00077   return gfs;
00078 }
00079 
00080 void
00081 mongo_sync_gridfs_free (mongo_sync_gridfs *gfs, gboolean disconnect)
00082 {
00083   if (!gfs)
00084     {
00085       errno = ENOTCONN;
00086       return;
00087     }
00088 
00089   g_free (gfs->ns.prefix);
00090   g_free (gfs->ns.files);
00091   g_free (gfs->ns.chunks);
00092   g_free (gfs->ns.db);
00093 
00094   if (disconnect)
00095     mongo_sync_disconnect (gfs->conn);
00096 
00097   g_free (gfs);
00098   errno = 0;
00099 }
00100 
00101 gint32
00102 mongo_sync_gridfs_get_chunk_size (mongo_sync_gridfs *gfs)
00103 {
00104   if (!gfs)
00105     {
00106       errno = ENOTCONN;
00107       return -1;
00108     }
00109   return gfs->chunk_size;
00110 }
00111 
00112 gboolean
00113 mongo_sync_gridfs_set_chunk_size (mongo_sync_gridfs *gfs,
00114                                   gint32 chunk_size)
00115 {
00116   if (!gfs)
00117     {
00118       errno = ENOTCONN;
00119       return FALSE;
00120     }
00121   if (chunk_size < 1)
00122     {
00123       errno = EINVAL;
00124       return FALSE;
00125     }
00126 
00127   gfs->chunk_size = chunk_size;
00128   return TRUE;
00129 }
00130 
00131 mongo_sync_cursor *
00132 mongo_sync_gridfs_list (mongo_sync_gridfs *gfs,
00133                         const bson *query)
00134 {
00135   mongo_sync_cursor *cursor;
00136   bson *q = NULL;
00137 
00138   if (!gfs)
00139     {
00140       errno = ENOTCONN;
00141       return NULL;
00142     }
00143 
00144   if (!query)
00145     {
00146       q = bson_new ();
00147       bson_finish (q);
00148     }
00149 
00150   cursor = mongo_sync_cursor_new
00151     (gfs->conn, gfs->ns.files,
00152      mongo_sync_cmd_query (gfs->conn, gfs->ns.files, 0, 0, 0,
00153                            (q) ? q : query, NULL));
00154   if (!cursor)
00155     {
00156       int e = errno;
00157 
00158       bson_free (q);
00159       errno = e;
00160       return NULL;
00161     }
00162   bson_free (q);
00163   return cursor;
00164 }
00165 
00166 const guint8 *
00167 mongo_sync_gridfs_file_get_id (gpointer gfile)
00168 {
00169   mongo_sync_gridfs_chunked_file *c = (mongo_sync_gridfs_chunked_file *)gfile;
00170   mongo_sync_gridfs_stream *s = (mongo_sync_gridfs_stream *)gfile;
00171 
00172   if (!gfile)
00173     {
00174       errno = ENOTCONN;
00175       return NULL;
00176     }
00177   if (c->meta.type == LMC_GRIDFS_FILE_CHUNKED)
00178     return c->meta.oid;
00179   else
00180     return s->file.id;
00181 }
00182 
00183 gint64
00184 mongo_sync_gridfs_file_get_length (gpointer gfile)
00185 {
00186   mongo_sync_gridfs_file_common *f = (mongo_sync_gridfs_file_common *)gfile;
00187 
00188   if (!gfile)
00189     {
00190       errno = ENOTCONN;
00191       return -1;
00192     }
00193   return f->length;
00194 }
00195 
00196 gint32
00197 mongo_sync_gridfs_file_get_chunk_size (gpointer gfile)
00198 {
00199   mongo_sync_gridfs_file_common *f = (mongo_sync_gridfs_file_common *)gfile;
00200 
00201   if (!gfile)
00202     {
00203       errno = ENOTCONN;
00204       return -1;
00205     }
00206   return f->chunk_size;
00207 }
00208 
00209 const gchar *
00210 mongo_sync_gridfs_file_get_md5 (gpointer gfile)
00211 {
00212   mongo_sync_gridfs_chunked_file *f = (mongo_sync_gridfs_chunked_file *)gfile;
00213 
00214   if (!gfile)
00215     {
00216       errno = ENOTCONN;
00217       return NULL;
00218     }
00219   if (f->meta.type != LMC_GRIDFS_FILE_CHUNKED)
00220     {
00221       errno = EOPNOTSUPP;
00222       return NULL;
00223     }
00224 
00225   return f->meta.md5;
00226 }
00227 
00228 gint64
00229 mongo_sync_gridfs_file_get_date (gpointer gfile)
00230 {
00231   mongo_sync_gridfs_chunked_file *f = (mongo_sync_gridfs_chunked_file *)gfile;
00232 
00233   if (!gfile)
00234     {
00235       errno = ENOTCONN;
00236       return -1;
00237     }
00238   if (f->meta.type != LMC_GRIDFS_FILE_CHUNKED)
00239     {
00240       errno = EOPNOTSUPP;
00241       return -1;
00242     }
00243 
00244   return f->meta.date;
00245 }
00246 
00247 const bson *
00248 mongo_sync_gridfs_file_get_metadata (gpointer gfile)
00249 {
00250   mongo_sync_gridfs_chunked_file *f = (mongo_sync_gridfs_chunked_file *)gfile;
00251 
00252   if (!gfile)
00253     {
00254       errno = ENOTCONN;
00255       return NULL;
00256     }
00257   if (f->meta.type != LMC_GRIDFS_FILE_CHUNKED)
00258     {
00259       errno = EOPNOTSUPP;
00260       return NULL;
00261     }
00262 
00263   return f->meta.metadata;
00264 }
00265 
00266 gint64
00267 mongo_sync_gridfs_file_get_chunks (gpointer gfile)
00268 {
00269   mongo_sync_gridfs_file_common *f = (mongo_sync_gridfs_file_common *)gfile;
00270   double chunk_count;
00271 
00272   if (!gfile)
00273     {
00274       errno = ENOTCONN;
00275       return -1;
00276     }
00277 
00278   chunk_count = (double)f->length / (double)f->chunk_size;
00279   return (chunk_count - (gint64)chunk_count > 0) ?
00280     (gint64)(chunk_count + 1) : (gint64)(chunk_count);
00281 }
00282 
00283 gboolean
00284 mongo_sync_gridfs_remove (mongo_sync_gridfs *gfs,
00285                           const bson *query)
00286 {
00287   mongo_sync_cursor *fc;
00288 
00289   fc = mongo_sync_gridfs_list (gfs, query);
00290   if (!fc)
00291     {
00292       if (errno != ENOTCONN)
00293         errno = ENOENT;
00294       return FALSE;
00295     }
00296 
00297   while (mongo_sync_cursor_next (fc))
00298     {
00299       bson *meta = mongo_sync_cursor_get_data (fc), *q;
00300       bson_cursor *c;
00301       const guint8 *ooid;
00302       guint8 oid[12];
00303 
00304       c = bson_find (meta, "_id");
00305       if (!bson_cursor_get_oid (c, &ooid))
00306         {
00307           bson_free (meta);
00308           bson_cursor_free (c);
00309           mongo_sync_cursor_free (fc);
00310 
00311           errno = EPROTO;
00312           return FALSE;
00313         }
00314       bson_cursor_free (c);
00315       memcpy (oid, ooid, 12);
00316       bson_free (meta);
00317 
00318       /* Delete metadata */
00319       q = bson_build (BSON_TYPE_OID, "_id", oid,
00320                       BSON_TYPE_NONE);
00321       bson_finish (q);
00322 
00323       if (!mongo_sync_cmd_delete (gfs->conn, gfs->ns.files, 0, q))
00324         {
00325           bson_free (q);
00326           mongo_sync_cursor_free (fc);
00327           return FALSE;
00328         }
00329       bson_free (q);
00330 
00331       /* Delete chunks */
00332       q = bson_build (BSON_TYPE_OID, "files_id", oid,
00333                       BSON_TYPE_NONE);
00334       bson_finish (q);
00335 
00336       /* Chunks may or may not exist, an error in this case is
00337          non-fatal. */
00338       mongo_sync_cmd_delete (gfs->conn, gfs->ns.chunks, 0, q);
00339       bson_free (q);
00340     }
00341 
00342   mongo_sync_cursor_free (fc);
00343 
00344   return TRUE;
00345 }
 All Data Structures Files Functions Variables Enumerations Enumerator Defines