libmongo-client 0.1.4
|
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 }