Archived
1
0
Fork 0

mongodb support

This commit is contained in:
Henrik Hautakoski 2010-10-27 17:18:39 +02:00
parent 97bdfd94f1
commit a908cf92af
12 changed files with 2884 additions and 4 deletions

View file

@ -3,9 +3,9 @@
#
CC = gcc
CFLAGS = -O2 -Werror `mysql_config --cflags` -Ilib
CFLAGS = -O2 -Werror -Ilib
LD = $(CC)
LDFLAGS = -L/usr/lib/mysql -lmysqlclient
LDFLAGS =
FINDOBJ = find . -name "*.o" -type f -printf "%P\n"
@ -30,7 +30,18 @@ obj =
obj += lib/ini/iniparser.o
obj += lib/ini/dictionary.o
obj += src/database/mysql.o
ifeq ($(database), mongo)
CFLAGS += -DMONGO_HAVE_STDINT
obj += lib/mongodb/md5.o
obj += lib/mongodb/bson.o
obj += lib/mongodb/numbers.o
obj += lib/mongodb/mongo.o
obj += src/database/mongo.o
else
CFLAGS += $(shell mysql_config --cflags)
LDFLAGS += $(shell mysql_config --libs)
obj += src/database/mysql.o
endif
obj += src/rbtree.o
obj += src/path.o
@ -50,7 +61,7 @@ obj += src/archived.o
all : $(PROGRAM)
$(PROGRAM) : $(obj)
$(QUIET_LD)$(LD) $(LDFLAGS) $^ -o $@
$(QUIET_LD)$(LD) $^ -o $@ $(LDFLAGS)
clean :
@for obj in `$(FINDOBJ)`; do \

View file

@ -4,3 +4,7 @@
# Verbose output
# VERBOSE = 1
# database adapter, mysql is default
# database = mysql
# database = mongo

648
lib/mongodb/bson.c Normal file
View file

@ -0,0 +1,648 @@
/* bson.c */
/* Copyright 2009, 2010 10gen Inc.
*
* 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 "bson.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
const int initialBufferSize = 128;
/* only need one of these */
static const int zero = 0;
/* ----------------------------
READING
------------------------------ */
bson * bson_empty(bson * obj){
static char * data = "\005\0\0\0\0";
return bson_init(obj, data, 0);
}
void bson_copy(bson* out, const bson* in){
if (!out) return;
out->data = bson_malloc(bson_size(in));
out->owned = 1;
memcpy(out->data, in->data, bson_size(in));
}
bson * bson_from_buffer(bson * b, bson_buffer * buf){
return bson_init(b, bson_buffer_finish(buf), 1);
}
bson * bson_init( bson * b , char * data , bson_bool_t mine ){
b->data = data;
b->owned = mine;
return b;
}
int bson_size(const bson * b ){
int i;
if ( ! b || ! b->data )
return 0;
bson_little_endian32(&i, b->data);
return i;
}
void bson_destroy( bson * b ){
if ( b->owned && b->data )
free( b->data );
b->data = 0;
b->owned = 0;
}
static char hexbyte(char hex){
switch (hex){
case '0': return 0x0;
case '1': return 0x1;
case '2': return 0x2;
case '3': return 0x3;
case '4': return 0x4;
case '5': return 0x5;
case '6': return 0x6;
case '7': return 0x7;
case '8': return 0x8;
case '9': return 0x9;
case 'a':
case 'A': return 0xa;
case 'b':
case 'B': return 0xb;
case 'c':
case 'C': return 0xc;
case 'd':
case 'D': return 0xd;
case 'e':
case 'E': return 0xe;
case 'f':
case 'F': return 0xf;
default: return 0x0; /* something smarter? */
}
}
void bson_oid_from_string(bson_oid_t* oid, const char* str){
int i;
for (i=0; i<12; i++){
oid->bytes[i] = (hexbyte(str[2*i]) << 4) | hexbyte(str[2*i + 1]);
}
}
void bson_oid_to_string(const bson_oid_t* oid, char* str){
static const char hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
int i;
for (i=0; i<12; i++){
str[2*i] = hex[(oid->bytes[i] & 0xf0) >> 4];
str[2*i + 1] = hex[ oid->bytes[i] & 0x0f ];
}
str[24] = '\0';
}
void bson_oid_gen(bson_oid_t* oid){
static int incr = 0;
static int fuzz = 0;
int i = incr++; /*TODO make atomic*/
int t = time(NULL);
/* TODO rand sucks. find something better */
if (!fuzz){
srand(t);
fuzz = rand();
}
bson_big_endian32(&oid->ints[0], &t);
oid->ints[1] = fuzz;
bson_big_endian32(&oid->ints[2], &i);
}
time_t bson_oid_generated_time(bson_oid_t* oid){
time_t out;
bson_big_endian32(&out, &oid->ints[0]);
return out;
}
void bson_print( bson * b ){
bson_print_raw( b->data , 0 );
}
void bson_print_raw( const char * data , int depth ){
bson_iterator i;
const char * key;
int temp;
char oidhex[25];
bson_iterator_init( &i , data );
while ( bson_iterator_next( &i ) ){
bson_type t = bson_iterator_type( &i );
if ( t == 0 )
break;
key = bson_iterator_key( &i );
for ( temp=0; temp<=depth; temp++ )
printf( "\t" );
printf( "%s : %d \t " , key , t );
switch ( t ){
case bson_int: printf( "%d" , bson_iterator_int( &i ) ); break;
case bson_double: printf( "%f" , bson_iterator_double( &i ) ); break;
case bson_bool: printf( "%s" , bson_iterator_bool( &i ) ? "true" : "false" ); break;
case bson_string: printf( "%s" , bson_iterator_string( &i ) ); break;
case bson_null: printf( "null" ); break;
case bson_oid: bson_oid_to_string(bson_iterator_oid(&i), oidhex); printf( "%s" , oidhex ); break;
case bson_object:
case bson_array:
printf( "\n" );
bson_print_raw( bson_iterator_value( &i ) , depth + 1 );
break;
default:
fprintf( stderr , "can't print type : %d\n" , t );
}
printf( "\n" );
}
}
/* ----------------------------
ITERATOR
------------------------------ */
void bson_iterator_init( bson_iterator * i , const char * bson ){
i->cur = bson + 4;
i->first = 1;
}
bson_type bson_find(bson_iterator* it, const bson* obj, const char* name){
bson_iterator_init(it, obj->data);
while(bson_iterator_next(it)){
if (strcmp(name, bson_iterator_key(it)) == 0)
break;
}
return bson_iterator_type(it);
}
bson_bool_t bson_iterator_more( const bson_iterator * i ){
return *(i->cur);
}
bson_type bson_iterator_next( bson_iterator * i ){
int ds;
if ( i->first ){
i->first = 0;
return (bson_type)(*i->cur);
}
switch ( bson_iterator_type(i) ){
case bson_eoo: return bson_eoo; /* don't advance */
case bson_undefined:
case bson_null: ds = 0; break;
case bson_bool: ds = 1; break;
case bson_int: ds = 4; break;
case bson_long:
case bson_double:
case bson_timestamp:
case bson_date: ds = 8; break;
case bson_oid: ds = 12; break;
case bson_string:
case bson_symbol:
case bson_code: ds = 4 + bson_iterator_int_raw(i); break;
case bson_bindata: ds = 5 + bson_iterator_int_raw(i); break;
case bson_object:
case bson_array:
case bson_codewscope: ds = bson_iterator_int_raw(i); break;
case bson_dbref: ds = 4+12 + bson_iterator_int_raw(i); break;
case bson_regex:
{
const char * s = bson_iterator_value(i);
const char * p = s;
p += strlen(p)+1;
p += strlen(p)+1;
ds = p-s;
break;
}
default:
{
char msg[] = "unknown type: 000000000000";
bson_numstr(msg+14, (unsigned)(i->cur[0]));
bson_fatal_msg(0, msg);
return 0;
}
}
i->cur += 1 + strlen( i->cur + 1 ) + 1 + ds;
return (bson_type)(*i->cur);
}
bson_type bson_iterator_type( const bson_iterator * i ){
return (bson_type)i->cur[0];
}
const char * bson_iterator_key( const bson_iterator * i ){
return i->cur + 1;
}
const char * bson_iterator_value( const bson_iterator * i ){
const char * t = i->cur + 1;
t += strlen( t ) + 1;
return t;
}
/* types */
int bson_iterator_int_raw( const bson_iterator * i ){
int out;
bson_little_endian32(&out, bson_iterator_value( i ));
return out;
}
double bson_iterator_double_raw( const bson_iterator * i ){
double out;
bson_little_endian64(&out, bson_iterator_value( i ));
return out;
}
int64_t bson_iterator_long_raw( const bson_iterator * i ){
int64_t out;
bson_little_endian64(&out, bson_iterator_value( i ));
return out;
}
bson_bool_t bson_iterator_bool_raw( const bson_iterator * i ){
return bson_iterator_value( i )[0];
}
bson_oid_t * bson_iterator_oid( const bson_iterator * i ){
return (bson_oid_t*)bson_iterator_value(i);
}
int bson_iterator_int( const bson_iterator * i ){
switch (bson_iterator_type(i)){
case bson_int: return bson_iterator_int_raw(i);
case bson_long: return bson_iterator_long_raw(i);
case bson_double: return bson_iterator_double_raw(i);
default: return 0;
}
}
double bson_iterator_double( const bson_iterator * i ){
switch (bson_iterator_type(i)){
case bson_int: return bson_iterator_int_raw(i);
case bson_long: return bson_iterator_long_raw(i);
case bson_double: return bson_iterator_double_raw(i);
default: return 0;
}
}
int64_t bson_iterator_long( const bson_iterator * i ){
switch (bson_iterator_type(i)){
case bson_int: return bson_iterator_int_raw(i);
case bson_long: return bson_iterator_long_raw(i);
case bson_double: return bson_iterator_double_raw(i);
default: return 0;
}
}
bson_bool_t bson_iterator_bool( const bson_iterator * i ){
switch (bson_iterator_type(i)){
case bson_bool: return bson_iterator_bool_raw(i);
case bson_int: return bson_iterator_int_raw(i) != 0;
case bson_long: return bson_iterator_long_raw(i) != 0;
case bson_double: return bson_iterator_double_raw(i) != 0;
case bson_eoo:
case bson_null: return 0;
default: return 1;
}
}
const char * bson_iterator_string( const bson_iterator * i ){
return bson_iterator_value( i ) + 4;
}
int bson_iterator_string_len( const bson_iterator * i ){
return bson_iterator_int_raw( i );
}
const char * bson_iterator_code( const bson_iterator * i ){
switch (bson_iterator_type(i)){
case bson_string:
case bson_code: return bson_iterator_value(i) + 4;
case bson_codewscope: return bson_iterator_value(i) + 8;
default: return NULL;
}
}
void bson_iterator_code_scope(const bson_iterator * i, bson * scope){
if (bson_iterator_type(i) == bson_codewscope){
int code_len;
bson_little_endian32(&code_len, bson_iterator_value(i)+4);
bson_init(scope, (void*)(bson_iterator_value(i)+8+code_len), 0);
}else{
bson_empty(scope);
}
}
bson_date_t bson_iterator_date(const bson_iterator * i){
return bson_iterator_long_raw(i);
}
time_t bson_iterator_time_t(const bson_iterator * i){
return bson_iterator_date(i) / 1000;
}
int bson_iterator_bin_len( const bson_iterator * i ){
return bson_iterator_int_raw( i );
}
char bson_iterator_bin_type( const bson_iterator * i ){
return bson_iterator_value(i)[4];
}
const char * bson_iterator_bin_data( const bson_iterator * i ){
return bson_iterator_value( i ) + 5;
}
const char * bson_iterator_regex( const bson_iterator * i ){
return bson_iterator_value( i );
}
const char * bson_iterator_regex_opts( const bson_iterator * i ){
const char* p = bson_iterator_value( i );
return p + strlen(p) + 1;
}
void bson_iterator_subobject(const bson_iterator * i, bson * sub){
bson_init(sub, (char*)bson_iterator_value(i), 0);
}
void bson_iterator_subiterator(const bson_iterator * i, bson_iterator * sub){
bson_iterator_init(sub, bson_iterator_value(i));
}
/* ----------------------------
BUILDING
------------------------------ */
bson_buffer * bson_buffer_init( bson_buffer * b ){
b->buf = (char*)bson_malloc( initialBufferSize );
b->bufSize = initialBufferSize;
b->cur = b->buf + 4;
b->finished = 0;
b->stackPos = 0;
return b;
}
void bson_append_byte( bson_buffer * b , char c ){
b->cur[0] = c;
b->cur++;
}
void bson_append( bson_buffer * b , const void * data , int len ){
memcpy( b->cur , data , len );
b->cur += len;
}
void bson_append32(bson_buffer * b, const void * data){
bson_little_endian32(b->cur, data);
b->cur += 4;
}
void bson_append64(bson_buffer * b, const void * data){
bson_little_endian64(b->cur, data);
b->cur += 8;
}
bson_buffer * bson_ensure_space( bson_buffer * b , const int bytesNeeded ){
int pos = b->cur - b->buf;
char * orig = b->buf;
int new_size;
if (b->finished)
bson_fatal_msg(!!b->buf, "trying to append to finished buffer");
if (pos + bytesNeeded <= b->bufSize)
return b;
new_size = 1.5 * (b->bufSize + bytesNeeded);
b->buf = realloc(b->buf, new_size);
if (!b->buf)
bson_fatal_msg(!!b->buf, "realloc() failed");
b->bufSize = new_size;
b->cur += b->buf - orig;
return b;
}
char * bson_buffer_finish( bson_buffer * b ){
int i;
if ( ! b->finished ){
if ( ! bson_ensure_space( b , 1 ) ) return 0;
bson_append_byte( b , 0 );
i = b->cur - b->buf;
bson_little_endian32(b->buf, &i);
b->finished = 1;
}
return b->buf;
}
void bson_buffer_destroy( bson_buffer * b ){
free( b->buf );
b->buf = 0;
b->cur = 0;
b->finished = 1;
}
static bson_buffer * bson_append_estart( bson_buffer * b , int type , const char * name , const int dataSize ){
const int sl = strlen(name) + 1;
if ( ! bson_ensure_space( b , 1 + sl + dataSize ) )
return 0;
bson_append_byte( b , (char)type );
bson_append( b , name , sl );
return b;
}
/* ----------------------------
BUILDING TYPES
------------------------------ */
bson_buffer * bson_append_int( bson_buffer * b , const char * name , const int i ){
if ( ! bson_append_estart( b , bson_int , name , 4 ) ) return 0;
bson_append32( b , &i );
return b;
}
bson_buffer * bson_append_long( bson_buffer * b , const char * name , const int64_t i ){
if ( ! bson_append_estart( b , bson_long , name , 8 ) ) return 0;
bson_append64( b , &i );
return b;
}
bson_buffer * bson_append_double( bson_buffer * b , const char * name , const double d ){
if ( ! bson_append_estart( b , bson_double , name , 8 ) ) return 0;
bson_append64( b , &d );
return b;
}
bson_buffer * bson_append_bool( bson_buffer * b , const char * name , const bson_bool_t i ){
if ( ! bson_append_estart( b , bson_bool , name , 1 ) ) return 0;
bson_append_byte( b , i != 0 );
return b;
}
bson_buffer * bson_append_null( bson_buffer * b , const char * name ){
if ( ! bson_append_estart( b , bson_null , name , 0 ) ) return 0;
return b;
}
bson_buffer * bson_append_undefined( bson_buffer * b , const char * name ){
if ( ! bson_append_estart( b , bson_undefined , name , 0 ) ) return 0;
return b;
}
bson_buffer * bson_append_string_base( bson_buffer * b , const char * name , const char * value , bson_type type){
int sl = strlen( value ) + 1;
if ( ! bson_append_estart( b , type , name , 4 + sl ) ) return 0;
bson_append32( b , &sl);
bson_append( b , value , sl );
return b;
}
bson_buffer * bson_append_string( bson_buffer * b , const char * name , const char * value ){
return bson_append_string_base(b, name, value, bson_string);
}
bson_buffer * bson_append_symbol( bson_buffer * b , const char * name , const char * value ){
return bson_append_string_base(b, name, value, bson_symbol);
}
bson_buffer * bson_append_code( bson_buffer * b , const char * name , const char * value ){
return bson_append_string_base(b, name, value, bson_code);
}
bson_buffer * bson_append_code_w_scope( bson_buffer * b , const char * name , const char * code , const bson * scope){
int sl = strlen(code) + 1;
int size = 4 + 4 + sl + bson_size(scope);
if (!bson_append_estart(b, bson_codewscope, name, size)) return 0;
bson_append32(b, &size);
bson_append32(b, &sl);
bson_append(b, code, sl);
bson_append(b, scope->data, bson_size(scope));
return b;
}
bson_buffer * bson_append_binary( bson_buffer * b, const char * name, char type, const char * str, int len ){
if ( ! bson_append_estart( b , bson_bindata , name , 4+1+len ) ) return 0;
bson_append32(b, &len);
bson_append_byte(b, type);
bson_append(b, str, len);
return b;
}
bson_buffer * bson_append_oid( bson_buffer * b , const char * name , const bson_oid_t * oid ){
if ( ! bson_append_estart( b , bson_oid , name , 12 ) ) return 0;
bson_append( b , oid , 12 );
return b;
}
bson_buffer * bson_append_new_oid( bson_buffer * b , const char * name ){
bson_oid_t oid;
bson_oid_gen(&oid);
return bson_append_oid(b, name, &oid);
}
bson_buffer * bson_append_regex( bson_buffer * b , const char * name , const char * pattern, const char * opts ){
const int plen = strlen(pattern)+1;
const int olen = strlen(opts)+1;
if ( ! bson_append_estart( b , bson_regex , name , plen + olen ) ) return 0;
bson_append( b , pattern , plen );
bson_append( b , opts , olen );
return b;
}
bson_buffer * bson_append_bson( bson_buffer * b , const char * name , const bson* bson){
if ( ! bson_append_estart( b , bson_object , name , bson_size(bson) ) ) return 0;
bson_append( b , bson->data , bson_size(bson) );
return b;
}
bson_buffer * bson_append_element( bson_buffer * b, const char * name_or_null, const bson_iterator* elem){
bson_iterator next = *elem;
int size;
bson_iterator_next(&next);
size = next.cur - elem->cur;
if (name_or_null == NULL){
bson_ensure_space(b, size);
bson_append(b, elem->cur, size);
}else{
int data_size = size - 1 - strlen(bson_iterator_key(elem));
bson_append_estart(b, elem->cur[0], name_or_null, data_size);
bson_append(b, name_or_null, strlen(name_or_null));
bson_append(b, bson_iterator_value(elem), data_size);
}
return b;
}
bson_buffer * bson_append_date( bson_buffer * b , const char * name , bson_date_t millis ){
if ( ! bson_append_estart( b , bson_date , name , 8 ) ) return 0;
bson_append64( b , &millis );
return b;
}
bson_buffer * bson_append_time_t( bson_buffer * b , const char * name , time_t secs){
return bson_append_date(b, name, (bson_date_t)secs * 1000);
}
bson_buffer * bson_append_start_object( bson_buffer * b , const char * name ){
if ( ! bson_append_estart( b , bson_object , name , 5 ) ) return 0;
b->stack[ b->stackPos++ ] = b->cur - b->buf;
bson_append32( b , &zero );
return b;
}
bson_buffer * bson_append_start_array( bson_buffer * b , const char * name ){
if ( ! bson_append_estart( b , bson_array , name , 5 ) ) return 0;
b->stack[ b->stackPos++ ] = b->cur - b->buf;
bson_append32( b , &zero );
return b;
}
bson_buffer * bson_append_finish_object( bson_buffer * b ){
char * start;
int i;
if ( ! bson_ensure_space( b , 1 ) ) return 0;
bson_append_byte( b , 0 );
start = b->buf + b->stack[ --b->stackPos ];
i = b->cur - start;
bson_little_endian32(start, &i);
return b;
}
void* bson_malloc(int size){
void* p = malloc(size);
bson_fatal_msg(!!p, "malloc() failed");
return p;
}
static bson_err_handler err_handler = NULL;
bson_err_handler set_bson_err_handler(bson_err_handler func){
bson_err_handler old = err_handler;
err_handler = func;
return old;
}
void bson_fatal( int ok ){
bson_fatal_msg(ok, "");
}
void bson_fatal_msg( int ok , const char* msg){
if (ok)
return;
if (err_handler){
err_handler(msg);
}
fprintf( stderr , "error: %s\n" , msg );
exit(-5);
}
extern const char bson_numstrs[1000][4];
void bson_numstr(char* str, int i){
if(i < 1000)
memcpy(str, bson_numstrs[i], 4);
else
sprintf(str,"%d", i);
}

218
lib/mongodb/bson.h Normal file
View file

@ -0,0 +1,218 @@
/* bson.h */
/* Copyright 2009, 2010 10gen Inc.
*
* 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.
*/
#ifndef _BSON_H_
#define _BSON_H_
#include "platform_hacks.h"
#include <time.h>
MONGO_EXTERN_C_START
typedef enum {
bson_eoo=0 ,
bson_double=1,
bson_string=2,
bson_object=3,
bson_array=4,
bson_bindata=5,
bson_undefined=6,
bson_oid=7,
bson_bool=8,
bson_date=9,
bson_null=10,
bson_regex=11,
bson_dbref=12, /* deprecated */
bson_code=13,
bson_symbol=14,
bson_codewscope=15,
bson_int = 16,
bson_timestamp = 17,
bson_long = 18
} bson_type;
typedef int bson_bool_t;
typedef struct {
char * data;
bson_bool_t owned;
} bson;
typedef struct {
const char * cur;
bson_bool_t first;
} bson_iterator;
typedef struct {
char * buf;
char * cur;
int bufSize;
bson_bool_t finished;
int stack[32];
int stackPos;
} bson_buffer;
#pragma pack(1)
typedef union{
char bytes[12];
int ints[3];
} bson_oid_t;
#pragma pack()
typedef int64_t bson_date_t; /* milliseconds since epoch UTC */
/* ----------------------------
READING
------------------------------ */
bson * bson_empty(bson * obj); /* returns pointer to static empty bson object */
void bson_copy(bson* out, const bson* in); /* puts data in new buffer. NOOP if out==NULL */
bson * bson_from_buffer(bson * b, bson_buffer * buf);
bson * bson_init( bson * b , char * data , bson_bool_t mine );
int bson_size(const bson * b );
void bson_destroy( bson * b );
void bson_print( bson * b );
void bson_print_raw( const char * bson , int depth );
/* advances iterator to named field */
/* returns bson_eoo (which is false) if field not found */
bson_type bson_find(bson_iterator* it, const bson* obj, const char* name);
void bson_iterator_init( bson_iterator * i , const char * bson );
/* more returns true for eoo. best to loop with bson_iterator_next(&it) */
bson_bool_t bson_iterator_more( const bson_iterator * i );
bson_type bson_iterator_next( bson_iterator * i );
bson_type bson_iterator_type( const bson_iterator * i );
const char * bson_iterator_key( const bson_iterator * i );
const char * bson_iterator_value( const bson_iterator * i );
/* these convert to the right type (return 0 if non-numeric) */
double bson_iterator_double( const bson_iterator * i );
int bson_iterator_int( const bson_iterator * i );
int64_t bson_iterator_long( const bson_iterator * i );
/* false: boolean false, 0 in any type, or null */
/* true: anything else (even empty strings and objects) */
bson_bool_t bson_iterator_bool( const bson_iterator * i );
/* these assume you are using the right type */
double bson_iterator_double_raw( const bson_iterator * i );
int bson_iterator_int_raw( const bson_iterator * i );
int64_t bson_iterator_long_raw( const bson_iterator * i );
bson_bool_t bson_iterator_bool_raw( const bson_iterator * i );
bson_oid_t* bson_iterator_oid( const bson_iterator * i );
/* these can also be used with bson_code and bson_symbol*/
const char * bson_iterator_string( const bson_iterator * i );
int bson_iterator_string_len( const bson_iterator * i );
/* works with bson_code, bson_codewscope, and bson_string */
/* returns NULL for everything else */
const char * bson_iterator_code(const bson_iterator * i);
/* calls bson_empty on scope if not a bson_codewscope */
void bson_iterator_code_scope(const bson_iterator * i, bson * scope);
/* both of these only work with bson_date */
bson_date_t bson_iterator_date(const bson_iterator * i);
time_t bson_iterator_time_t(const bson_iterator * i);
int bson_iterator_bin_len( const bson_iterator * i );
char bson_iterator_bin_type( const bson_iterator * i );
const char * bson_iterator_bin_data( const bson_iterator * i );
const char * bson_iterator_regex( const bson_iterator * i );
const char * bson_iterator_regex_opts( const bson_iterator * i );
/* these work with bson_object and bson_array */
void bson_iterator_subobject(const bson_iterator * i, bson * sub);
void bson_iterator_subiterator(const bson_iterator * i, bson_iterator * sub);
/* str must be at least 24 hex chars + null byte */
void bson_oid_from_string(bson_oid_t* oid, const char* str);
void bson_oid_to_string(const bson_oid_t* oid, char* str);
void bson_oid_gen(bson_oid_t* oid);
time_t bson_oid_generated_time(bson_oid_t* oid); /* Gives the time the OID was created */
/* ----------------------------
BUILDING
------------------------------ */
bson_buffer * bson_buffer_init( bson_buffer * b );
bson_buffer * bson_ensure_space( bson_buffer * b , const int bytesNeeded );
/**
* @return the raw data. you either should free this OR call bson_destroy not both
*/
char * bson_buffer_finish( bson_buffer * b );
void bson_buffer_destroy( bson_buffer * b );
bson_buffer * bson_append_oid( bson_buffer * b , const char * name , const bson_oid_t* oid );
bson_buffer * bson_append_new_oid( bson_buffer * b , const char * name );
bson_buffer * bson_append_int( bson_buffer * b , const char * name , const int i );
bson_buffer * bson_append_long( bson_buffer * b , const char * name , const int64_t i );
bson_buffer * bson_append_double( bson_buffer * b , const char * name , const double d );
bson_buffer * bson_append_string( bson_buffer * b , const char * name , const char * str );
bson_buffer * bson_append_symbol( bson_buffer * b , const char * name , const char * str );
bson_buffer * bson_append_code( bson_buffer * b , const char * name , const char * str );
bson_buffer * bson_append_code_w_scope( bson_buffer * b , const char * name , const char * code , const bson * scope);
bson_buffer * bson_append_binary( bson_buffer * b, const char * name, char type, const char * str, int len );
bson_buffer * bson_append_bool( bson_buffer * b , const char * name , const bson_bool_t v );
bson_buffer * bson_append_null( bson_buffer * b , const char * name );
bson_buffer * bson_append_undefined( bson_buffer * b , const char * name );
bson_buffer * bson_append_regex( bson_buffer * b , const char * name , const char * pattern, const char * opts );
bson_buffer * bson_append_bson( bson_buffer * b , const char * name , const bson* bson);
bson_buffer * bson_append_element( bson_buffer * b, const char * name_or_null, const bson_iterator* elem);
/* these both append a bson_date */
bson_buffer * bson_append_date(bson_buffer * b, const char * name, bson_date_t millis);
bson_buffer * bson_append_time_t(bson_buffer * b, const char * name, time_t secs);
bson_buffer * bson_append_start_object( bson_buffer * b , const char * name );
bson_buffer * bson_append_start_array( bson_buffer * b , const char * name );
bson_buffer * bson_append_finish_object( bson_buffer * b );
void bson_numstr(char* str, int i);
void bson_incnumstr(char* str);
/* ------------------------------
ERROR HANDLING - also used in mongo code
------------------------------ */
void * bson_malloc(int size); /* checks return value */
/* bson_err_handlers shouldn't return!!! */
typedef void(*bson_err_handler)(const char* errmsg);
/* returns old handler or NULL */
/* default handler prints error then exits with failure*/
bson_err_handler set_bson_err_handler(bson_err_handler func);
/* does nothing is ok != 0 */
void bson_fatal( int ok );
void bson_fatal_msg( int ok, const char* msg );
MONGO_EXTERN_C_END
#endif

381
lib/mongodb/md5.c Normal file
View file

@ -0,0 +1,381 @@
/*
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
L. Peter Deutsch
ghost@aladdin.com
*/
/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
/*
Independent implementation of MD5 (RFC 1321).
This code implements the MD5 Algorithm defined in RFC 1321, whose
text is available at
http://www.ietf.org/rfc/rfc1321.txt
The code is derived from the text of the RFC, including the test suite
(section A.5) but excluding the rest of Appendix A. It does not include
any code or documentation that is identified in the RFC as being
copyrighted.
The original and principal author of md5.c is L. Peter Deutsch
<ghost@aladdin.com>. Other authors are noted in the change history
that follows (in reverse chronological order):
2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
either statically or dynamically; added missing #include <string.h>
in library.
2002-03-11 lpd Corrected argument list for main(), and added int return
type, in test program and T value program.
2002-02-21 lpd Added missing #include <stdio.h> in test program.
2000-07-03 lpd Patched to eliminate warnings about "constant is
unsigned in ANSI C, signed in traditional"; made test program
self-checking.
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
1999-05-03 lpd Original version.
*/
#include "md5.h"
#include <string.h>
#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
#ifdef MONGO_BIG_ENDIAN
# define BYTE_ORDER 1
#else
# define BYTE_ORDER -1
#endif
#define T_MASK ((mongo_md5_word_t)~0)
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
#define T3 0x242070db
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
#define T6 0x4787c62a
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
#define T9 0x698098d8
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
#define T13 0x6b901122
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
#define T16 0x49b40821
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
#define T19 0x265e5a51
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
#define T22 0x02441453
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
#define T25 0x21e1cde6
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
#define T28 0x455a14ed
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
#define T31 0x676f02d9
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
#define T35 0x6d9d6122
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
#define T38 0x4bdecfa9
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
#define T41 0x289b7ec6
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
#define T44 0x04881d05
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
#define T47 0x1fa27cf8
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
#define T50 0x432aff97
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
#define T53 0x655b59c3
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
#define T57 0x6fa87e4f
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
#define T60 0x4e0811a1
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
#define T63 0x2ad7d2bb
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
static void
mongo_md5_process(mongo_md5_state_t *pms, const mongo_md5_byte_t *data /*[64]*/)
{
mongo_md5_word_t
a = pms->abcd[0], b = pms->abcd[1],
c = pms->abcd[2], d = pms->abcd[3];
mongo_md5_word_t t;
#if BYTE_ORDER > 0
/* Define storage only for big-endian CPUs. */
mongo_md5_word_t X[16];
#else
/* Define storage for little-endian or both types of CPUs. */
mongo_md5_word_t xbuf[16];
const mongo_md5_word_t *X;
#endif
{
#if BYTE_ORDER == 0
/*
* Determine dynamically whether this is a big-endian or
* little-endian machine, since we can use a more efficient
* algorithm on the latter.
*/
static const int w = 1;
if (*((const mongo_md5_byte_t *)&w)) /* dynamic little-endian */
#endif
#if BYTE_ORDER <= 0 /* little-endian */
{
/*
* On little-endian machines, we can process properly aligned
* data without copying it.
*/
if (!((data - (const mongo_md5_byte_t *)0) & 3)) {
/* data are properly aligned */
X = (const mongo_md5_word_t *)data;
} else {
/* not aligned */
memcpy(xbuf, data, 64);
X = xbuf;
}
}
#endif
#if BYTE_ORDER == 0
else /* dynamic big-endian */
#endif
#if BYTE_ORDER >= 0 /* big-endian */
{
/*
* On big-endian machines, we must arrange the bytes in the
* right order.
*/
const mongo_md5_byte_t *xp = data;
int i;
# if BYTE_ORDER == 0
X = xbuf; /* (dynamic only) */
# else
# define xbuf X /* (static only) */
# endif
for (i = 0; i < 16; ++i, xp += 4)
xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
}
#endif
}
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
/* Round 1. */
/* Let [abcd k s i] denote the operation
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + F(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 7, T1);
SET(d, a, b, c, 1, 12, T2);
SET(c, d, a, b, 2, 17, T3);
SET(b, c, d, a, 3, 22, T4);
SET(a, b, c, d, 4, 7, T5);
SET(d, a, b, c, 5, 12, T6);
SET(c, d, a, b, 6, 17, T7);
SET(b, c, d, a, 7, 22, T8);
SET(a, b, c, d, 8, 7, T9);
SET(d, a, b, c, 9, 12, T10);
SET(c, d, a, b, 10, 17, T11);
SET(b, c, d, a, 11, 22, T12);
SET(a, b, c, d, 12, 7, T13);
SET(d, a, b, c, 13, 12, T14);
SET(c, d, a, b, 14, 17, T15);
SET(b, c, d, a, 15, 22, T16);
#undef SET
/* Round 2. */
/* Let [abcd k s i] denote the operation
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + G(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 1, 5, T17);
SET(d, a, b, c, 6, 9, T18);
SET(c, d, a, b, 11, 14, T19);
SET(b, c, d, a, 0, 20, T20);
SET(a, b, c, d, 5, 5, T21);
SET(d, a, b, c, 10, 9, T22);
SET(c, d, a, b, 15, 14, T23);
SET(b, c, d, a, 4, 20, T24);
SET(a, b, c, d, 9, 5, T25);
SET(d, a, b, c, 14, 9, T26);
SET(c, d, a, b, 3, 14, T27);
SET(b, c, d, a, 8, 20, T28);
SET(a, b, c, d, 13, 5, T29);
SET(d, a, b, c, 2, 9, T30);
SET(c, d, a, b, 7, 14, T31);
SET(b, c, d, a, 12, 20, T32);
#undef SET
/* Round 3. */
/* Let [abcd k s t] denote the operation
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define SET(a, b, c, d, k, s, Ti)\
t = a + H(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 5, 4, T33);
SET(d, a, b, c, 8, 11, T34);
SET(c, d, a, b, 11, 16, T35);
SET(b, c, d, a, 14, 23, T36);
SET(a, b, c, d, 1, 4, T37);
SET(d, a, b, c, 4, 11, T38);
SET(c, d, a, b, 7, 16, T39);
SET(b, c, d, a, 10, 23, T40);
SET(a, b, c, d, 13, 4, T41);
SET(d, a, b, c, 0, 11, T42);
SET(c, d, a, b, 3, 16, T43);
SET(b, c, d, a, 6, 23, T44);
SET(a, b, c, d, 9, 4, T45);
SET(d, a, b, c, 12, 11, T46);
SET(c, d, a, b, 15, 16, T47);
SET(b, c, d, a, 2, 23, T48);
#undef SET
/* Round 4. */
/* Let [abcd k s t] denote the operation
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + I(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 6, T49);
SET(d, a, b, c, 7, 10, T50);
SET(c, d, a, b, 14, 15, T51);
SET(b, c, d, a, 5, 21, T52);
SET(a, b, c, d, 12, 6, T53);
SET(d, a, b, c, 3, 10, T54);
SET(c, d, a, b, 10, 15, T55);
SET(b, c, d, a, 1, 21, T56);
SET(a, b, c, d, 8, 6, T57);
SET(d, a, b, c, 15, 10, T58);
SET(c, d, a, b, 6, 15, T59);
SET(b, c, d, a, 13, 21, T60);
SET(a, b, c, d, 4, 6, T61);
SET(d, a, b, c, 11, 10, T62);
SET(c, d, a, b, 2, 15, T63);
SET(b, c, d, a, 9, 21, T64);
#undef SET
/* Then perform the following additions. (That is increment each
of the four registers by the value it had before this block
was started.) */
pms->abcd[0] += a;
pms->abcd[1] += b;
pms->abcd[2] += c;
pms->abcd[3] += d;
}
void
mongo_md5_init(mongo_md5_state_t *pms)
{
pms->count[0] = pms->count[1] = 0;
pms->abcd[0] = 0x67452301;
pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
pms->abcd[3] = 0x10325476;
}
void
mongo_md5_append(mongo_md5_state_t *pms, const mongo_md5_byte_t *data, int nbytes)
{
const mongo_md5_byte_t *p = data;
int left = nbytes;
int offset = (pms->count[0] >> 3) & 63;
mongo_md5_word_t nbits = (mongo_md5_word_t)(nbytes << 3);
if (nbytes <= 0)
return;
/* Update the message length. */
pms->count[1] += nbytes >> 29;
pms->count[0] += nbits;
if (pms->count[0] < nbits)
pms->count[1]++;
/* Process an initial partial block. */
if (offset) {
int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
memcpy(pms->buf + offset, p, copy);
if (offset + copy < 64)
return;
p += copy;
left -= copy;
mongo_md5_process(pms, pms->buf);
}
/* Process full blocks. */
for (; left >= 64; p += 64, left -= 64)
mongo_md5_process(pms, p);
/* Process a final partial block. */
if (left)
memcpy(pms->buf, p, left);
}
void
mongo_md5_finish(mongo_md5_state_t *pms, mongo_md5_byte_t digest[16])
{
static const mongo_md5_byte_t pad[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
mongo_md5_byte_t data[8];
int i;
/* Save the length before padding. */
for (i = 0; i < 8; ++i)
data[i] = (mongo_md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
/* Pad to 56 bytes mod 64. */
mongo_md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
/* Append the length. */
mongo_md5_append(pms, data, 8);
for (i = 0; i < 16; ++i)
digest[i] = (mongo_md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
}

91
lib/mongodb/md5.h Normal file
View file

@ -0,0 +1,91 @@
/*
Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
L. Peter Deutsch
ghost@aladdin.com
*/
/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
/*
Independent implementation of MD5 (RFC 1321).
This code implements the MD5 Algorithm defined in RFC 1321, whose
text is available at
http://www.ietf.org/rfc/rfc1321.txt
The code is derived from the text of the RFC, including the test suite
(section A.5) but excluding the rest of Appendix A. It does not include
any code or documentation that is identified in the RFC as being
copyrighted.
The original and principal author of md5.h is L. Peter Deutsch
<ghost@aladdin.com>. Other authors are noted in the change history
that follows (in reverse chronological order):
2002-04-13 lpd Removed support for non-ANSI compilers; removed
references to Ghostscript; clarified derivation from RFC 1321;
now handles byte order either statically or dynamically.
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
added conditionalization for C++ compilation from Martin
Purschke <purschke@bnl.gov>.
1999-05-03 lpd Original version.
*/
#ifndef md5_INCLUDED
# define md5_INCLUDED
/*
* This package supports both compile-time and run-time determination of CPU
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
* compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
* defined as non-zero, the code will be compiled to run only on big-endian
* CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
* run on either big- or little-endian CPUs, but will run slightly less
* efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
*/
typedef unsigned char mongo_md5_byte_t; /* 8-bit byte */
typedef unsigned int mongo_md5_word_t; /* 32-bit word */
/* Define the state of the MD5 Algorithm. */
typedef struct mongo_md5_state_s {
mongo_md5_word_t count[2]; /* message length in bits, lsw first */
mongo_md5_word_t abcd[4]; /* digest buffer */
mongo_md5_byte_t buf[64]; /* accumulate block */
} mongo_md5_state_t;
#ifdef __cplusplus
extern "C"
{
#endif
/* Initialize the algorithm. */
void mongo_md5_init(mongo_md5_state_t *pms);
/* Append a string to the message. */
void mongo_md5_append(mongo_md5_state_t *pms, const mongo_md5_byte_t *data, int nbytes);
/* Finish the message and return the digest. */
void mongo_md5_finish(mongo_md5_state_t *pms, mongo_md5_byte_t digest[16]);
#ifdef __cplusplus
} /* end extern "C" */
#endif
#endif /* md5_INCLUDED */

803
lib/mongodb/mongo.c Normal file
View file

@ -0,0 +1,803 @@
/* mongo.c */
/* Copyright 2009, 2010 10gen Inc.
*
* 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 "md5.h"
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#endif
/* only need one of these */
static const int zero = 0;
static const int one = 1;
/* ----------------------------
message stuff
------------------------------ */
static void looping_write(mongo_connection * conn, const void* buf, int len){
const char* cbuf = buf;
while (len){
int sent = send(conn->sock, cbuf, len, 0);
if (sent == -1) MONGO_THROW(MONGO_EXCEPT_NETWORK);
cbuf += sent;
len -= sent;
}
}
static void looping_read(mongo_connection * conn, void* buf, int len){
char* cbuf = buf;
while (len){
int sent = recv(conn->sock, cbuf, len, 0);
if (sent == 0 || sent == -1) MONGO_THROW(MONGO_EXCEPT_NETWORK);
cbuf += sent;
len -= sent;
}
}
/* Always calls free(mm) */
void mongo_message_send(mongo_connection * conn, mongo_message* mm){
mongo_header head; /* little endian */
bson_little_endian32(&head.len, &mm->head.len);
bson_little_endian32(&head.id, &mm->head.id);
bson_little_endian32(&head.responseTo, &mm->head.responseTo);
bson_little_endian32(&head.op, &mm->head.op);
MONGO_TRY{
looping_write(conn, &head, sizeof(head));
looping_write(conn, &mm->data, mm->head.len - sizeof(head));
}MONGO_CATCH{
free(mm);
MONGO_RETHROW();
}
free(mm);
}
char * mongo_data_append( char * start , const void * data , int len ){
memcpy( start , data , len );
return start + len;
}
char * mongo_data_append32( char * start , const void * data){
bson_little_endian32( start , data );
return start + 4;
}
char * mongo_data_append64( char * start , const void * data){
bson_little_endian64( start , data );
return start + 8;
}
mongo_message * mongo_message_create( int len , int id , int responseTo , int op ){
mongo_message * mm = (mongo_message*)bson_malloc( len );
if (!id)
id = rand();
/* native endian (converted on send) */
mm->head.len = len;
mm->head.id = id;
mm->head.responseTo = responseTo;
mm->head.op = op;
return mm;
}
/* ----------------------------
connection stuff
------------------------------ */
static int mongo_connect_helper( mongo_connection * conn ){
/* setup */
conn->sock = 0;
conn->connected = 0;
memset( conn->sa.sin_zero , 0 , sizeof(conn->sa.sin_zero) );
conn->sa.sin_family = AF_INET;
conn->sa.sin_port = htons(conn->left_opts->port);
conn->sa.sin_addr.s_addr = inet_addr( conn->left_opts->host );
conn->addressSize = sizeof(conn->sa);
/* connect */
conn->sock = socket( AF_INET, SOCK_STREAM, 0 );
if ( conn->sock <= 0 ){
return mongo_conn_no_socket;
}
if ( connect( conn->sock , (struct sockaddr*)&conn->sa , conn->addressSize ) ){
return mongo_conn_fail;
}
/* nagle */
setsockopt( conn->sock, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one) );
/* TODO signals */
conn->connected = 1;
return 0;
}
mongo_conn_return mongo_connect( mongo_connection * conn , mongo_connection_options * options ){
MONGO_INIT_EXCEPTION(&conn->exception);
conn->left_opts = bson_malloc(sizeof(mongo_connection_options));
conn->right_opts = NULL;
if ( options ){
memcpy( conn->left_opts , options , sizeof( mongo_connection_options ) );
} else {
strcpy( conn->left_opts->host , "127.0.0.1" );
conn->left_opts->port = 27017;
}
return mongo_connect_helper(conn);
}
static void swap_repl_pair(mongo_connection * conn){
mongo_connection_options * tmp = conn->left_opts;
conn->left_opts = conn->right_opts;
conn->right_opts = tmp;
}
mongo_conn_return mongo_connect_pair( mongo_connection * conn , mongo_connection_options * left, mongo_connection_options * right ){
conn->connected = 0;
MONGO_INIT_EXCEPTION(&conn->exception);
conn->left_opts = NULL;
conn->right_opts = NULL;
if ( !left || !right )
return mongo_conn_bad_arg;
conn->left_opts = bson_malloc(sizeof(mongo_connection_options));
conn->right_opts = bson_malloc(sizeof(mongo_connection_options));
memcpy( conn->left_opts, left, sizeof( mongo_connection_options ) );
memcpy( conn->right_opts, right, sizeof( mongo_connection_options ) );
return mongo_reconnect(conn);
}
mongo_conn_return mongo_reconnect( mongo_connection * conn ){
mongo_conn_return ret;
mongo_disconnect(conn);
/* single server */
if(conn->right_opts == NULL)
return mongo_connect_helper(conn);
/* repl pair */
ret = mongo_connect_helper(conn);
if (ret == mongo_conn_success && mongo_cmd_ismaster(conn, NULL)){
return mongo_conn_success;
}
swap_repl_pair(conn);
ret = mongo_connect_helper(conn);
if (ret == mongo_conn_success){
if(mongo_cmd_ismaster(conn, NULL))
return mongo_conn_success;
else
return mongo_conn_not_master;
}
/* failed to connect to both servers */
return ret;
}
void mongo_insert_batch( mongo_connection * conn , const char * ns , bson ** bsons, int count){
int size = 16 + 4 + strlen( ns ) + 1;
int i;
mongo_message * mm;
char* data;
for(i=0; i<count; i++){
size += bson_size(bsons[i]);
}
mm = mongo_message_create( size , 0 , 0 , mongo_op_insert );
data = &mm->data;
data = mongo_data_append32(data, &zero);
data = mongo_data_append(data, ns, strlen(ns) + 1);
for(i=0; i<count; i++){
data = mongo_data_append(data, bsons[i]->data, bson_size( bsons[i] ) );
}
mongo_message_send(conn, mm);
}
void mongo_insert( mongo_connection * conn , const char * ns , bson * bson ){
char * data;
mongo_message * mm = mongo_message_create( 16 /* header */
+ 4 /* ZERO */
+ strlen(ns)
+ 1 + bson_size(bson)
, 0, 0, mongo_op_insert);
data = &mm->data;
data = mongo_data_append32(data, &zero);
data = mongo_data_append(data, ns, strlen(ns) + 1);
data = mongo_data_append(data, bson->data, bson_size(bson));
mongo_message_send(conn, mm);
}
void mongo_update(mongo_connection* conn, const char* ns, const bson* cond, const bson* op, int flags){
char * data;
mongo_message * mm = mongo_message_create( 16 /* header */
+ 4 /* ZERO */
+ strlen(ns) + 1
+ 4 /* flags */
+ bson_size(cond)
+ bson_size(op)
, 0 , 0 , mongo_op_update );
data = &mm->data;
data = mongo_data_append32(data, &zero);
data = mongo_data_append(data, ns, strlen(ns) + 1);
data = mongo_data_append32(data, &flags);
data = mongo_data_append(data, cond->data, bson_size(cond));
data = mongo_data_append(data, op->data, bson_size(op));
mongo_message_send(conn, mm);
}
void mongo_remove(mongo_connection* conn, const char* ns, const bson* cond){
char * data;
mongo_message * mm = mongo_message_create( 16 /* header */
+ 4 /* ZERO */
+ strlen(ns) + 1
+ 4 /* ZERO */
+ bson_size(cond)
, 0 , 0 , mongo_op_delete );
data = &mm->data;
data = mongo_data_append32(data, &zero);
data = mongo_data_append(data, ns, strlen(ns) + 1);
data = mongo_data_append32(data, &zero);
data = mongo_data_append(data, cond->data, bson_size(cond));
mongo_message_send(conn, mm);
}
mongo_reply * mongo_read_response( mongo_connection * conn ){
mongo_header head; /* header from network */
mongo_reply_fields fields; /* header from network */
mongo_reply * out; /* native endian */
int len;
looping_read(conn, &head, sizeof(head));
looping_read(conn, &fields, sizeof(fields));
bson_little_endian32(&len, &head.len);
if (len < sizeof(head)+sizeof(fields) || len > 64*1024*1024)
MONGO_THROW(MONGO_EXCEPT_NETWORK); /* most likely corruption */
out = (mongo_reply*)bson_malloc(len);
out->head.len = len;
bson_little_endian32(&out->head.id, &head.id);
bson_little_endian32(&out->head.responseTo, &head.responseTo);
bson_little_endian32(&out->head.op, &head.op);
bson_little_endian32(&out->fields.flag, &fields.flag);
bson_little_endian64(&out->fields.cursorID, &fields.cursorID);
bson_little_endian32(&out->fields.start, &fields.start);
bson_little_endian32(&out->fields.num, &fields.num);
MONGO_TRY{
looping_read(conn, &out->objs, len-sizeof(head)-sizeof(fields));
}MONGO_CATCH{
free(out);
MONGO_RETHROW();
}
return out;
}
mongo_cursor* mongo_find(mongo_connection* conn, const char* ns, bson* query, bson* fields, int nToReturn, int nToSkip, int options){
int sl;
mongo_cursor * cursor;
char * data;
mongo_message * mm = mongo_message_create( 16 + /* header */
4 + /* options */
strlen( ns ) + 1 + /* ns */
4 + 4 + /* skip,return */
bson_size( query ) +
bson_size( fields ) ,
0 , 0 , mongo_op_query );
data = &mm->data;
data = mongo_data_append32( data , &options );
data = mongo_data_append( data , ns , strlen( ns ) + 1 );
data = mongo_data_append32( data , &nToSkip );
data = mongo_data_append32( data , &nToReturn );
data = mongo_data_append( data , query->data , bson_size( query ) );
if ( fields )
data = mongo_data_append( data , fields->data , bson_size( fields ) );
bson_fatal_msg( (data == ((char*)mm) + mm->head.len), "query building fail!" );
mongo_message_send( conn , mm );
cursor = (mongo_cursor*)bson_malloc(sizeof(mongo_cursor));
MONGO_TRY{
cursor->mm = mongo_read_response(conn);
}MONGO_CATCH{
free(cursor);
MONGO_RETHROW();
}
sl = strlen(ns)+1;
cursor->ns = bson_malloc(sl);
if (!cursor->ns){
free(cursor->mm);
free(cursor);
return 0;
}
memcpy((void*)cursor->ns, ns, sl); /* cast needed to silence GCC warning */
cursor->conn = conn;
cursor->current.data = NULL;
return cursor;
}
bson_bool_t mongo_find_one(mongo_connection* conn, const char* ns, bson* query, bson* fields, bson* out){
mongo_cursor* cursor = mongo_find(conn, ns, query, fields, 1, 0, 0);
if (cursor && mongo_cursor_next(cursor)){
bson_copy(out, &cursor->current);
mongo_cursor_destroy(cursor);
return 1;
}else{
mongo_cursor_destroy(cursor);
return 0;
}
}
int64_t mongo_count(mongo_connection* conn, const char* db, const char* ns, bson* query){
bson_buffer bb;
bson cmd;
bson out;
int64_t count = -1;
bson_buffer_init(&bb);
bson_append_string(&bb, "count", ns);
if (query && bson_size(query) > 5) /* not empty */
bson_append_bson(&bb, "query", query);
bson_from_buffer(&cmd, &bb);
MONGO_TRY{
if(mongo_run_command(conn, db, &cmd, &out)){
bson_iterator it;
if(bson_find(&it, &out, "n"))
count = bson_iterator_long(&it);
}
}MONGO_CATCH{
bson_destroy(&cmd);
MONGO_RETHROW();
}
bson_destroy(&cmd);
bson_destroy(&out);
return count;
}
bson_bool_t mongo_disconnect( mongo_connection * conn ){
if ( ! conn->connected )
return 1;
#ifdef _WIN32
closesocket( conn->sock );
#else
close( conn->sock );
#endif
conn->sock = 0;
conn->connected = 0;
return 0;
}
bson_bool_t mongo_destroy( mongo_connection * conn ){
free(conn->left_opts);
free(conn->right_opts);
conn->left_opts = NULL;
conn->right_opts = NULL;
return mongo_disconnect( conn );
}
bson_bool_t mongo_cursor_get_more(mongo_cursor* cursor){
if (cursor->mm && cursor->mm->fields.cursorID){
mongo_connection* conn = cursor->conn;
char* data;
int sl = strlen(cursor->ns)+1;
mongo_message * mm = mongo_message_create(16 /*header*/
+4 /*ZERO*/
+sl
+4 /*numToReturn*/
+8 /*cursorID*/
, 0, 0, mongo_op_get_more);
data = &mm->data;
data = mongo_data_append32(data, &zero);
data = mongo_data_append(data, cursor->ns, sl);
data = mongo_data_append32(data, &zero);
data = mongo_data_append64(data, &cursor->mm->fields.cursorID);
mongo_message_send(conn, mm);
free(cursor->mm);
MONGO_TRY{
cursor->mm = mongo_read_response(cursor->conn);
}MONGO_CATCH{
cursor->mm = NULL;
mongo_cursor_destroy(cursor);
MONGO_RETHROW();
}
return cursor->mm && cursor->mm->fields.num;
} else{
return 0;
}
}
bson_bool_t mongo_cursor_next(mongo_cursor* cursor){
char* bson_addr;
/* no data */
if (!cursor->mm || cursor->mm->fields.num == 0)
return 0;
/* first */
if (cursor->current.data == NULL){
bson_init(&cursor->current, &cursor->mm->objs, 0);
return 1;
}
bson_addr = cursor->current.data + bson_size(&cursor->current);
if (bson_addr >= ((char*)cursor->mm + cursor->mm->head.len)){
if (!mongo_cursor_get_more(cursor))
return 0;
bson_init(&cursor->current, &cursor->mm->objs, 0);
} else {
bson_init(&cursor->current, bson_addr, 0);
}
return 1;
}
void mongo_cursor_destroy(mongo_cursor* cursor){
if (!cursor) return;
if (cursor->mm && cursor->mm->fields.cursorID){
mongo_connection* conn = cursor->conn;
mongo_message * mm = mongo_message_create(16 /*header*/
+4 /*ZERO*/
+4 /*numCursors*/
+8 /*cursorID*/
, 0, 0, mongo_op_kill_cursors);
char* data = &mm->data;
data = mongo_data_append32(data, &zero);
data = mongo_data_append32(data, &one);
data = mongo_data_append64(data, &cursor->mm->fields.cursorID);
MONGO_TRY{
mongo_message_send(conn, mm);
}MONGO_CATCH{
free(cursor->mm);
free((void*)cursor->ns);
free(cursor);
MONGO_RETHROW();
}
}
free(cursor->mm);
free((void*)cursor->ns);
free(cursor);
}
bson_bool_t mongo_create_index(mongo_connection * conn, const char * ns, bson * key, int options, bson * out){
bson_buffer bb;
bson b;
bson_iterator it;
char name[255] = {'_'};
int i = 1;
char idxns[1024];
bson_iterator_init(&it, key->data);
while(i < 255 && bson_iterator_next(&it)){
strncpy(name + i, bson_iterator_key(&it), 255 - i);
i += strlen(bson_iterator_key(&it));
}
name[254] = '\0';
bson_buffer_init(&bb);
bson_append_bson(&bb, "key", key);
bson_append_string(&bb, "ns", ns);
bson_append_string(&bb, "name", name);
if (options & MONGO_INDEX_UNIQUE)
bson_append_bool(&bb, "unique", 1);
if (options & MONGO_INDEX_DROP_DUPS)
bson_append_bool(&bb, "dropDups", 1);
bson_from_buffer(&b, &bb);
strncpy(idxns, ns, 1024-16);
strcpy(strchr(idxns, '.'), ".system.indexes");
mongo_insert(conn, idxns, &b);
bson_destroy(&b);
*strchr(idxns, '.') = '\0'; /* just db not ns */
return !mongo_cmd_get_last_error(conn, idxns, out);
}
bson_bool_t mongo_create_simple_index(mongo_connection * conn, const char * ns, const char* field, int options, bson * out){
bson_buffer bb;
bson b;
bson_bool_t success;
bson_buffer_init(&bb);
bson_append_int(&bb, field, 1);
bson_from_buffer(&b, &bb);
success = mongo_create_index(conn, ns, &b, options, out);
bson_destroy(&b);
return success;
}
bson_bool_t mongo_run_command(mongo_connection * conn, const char * db, bson * command, bson * out){
bson fields;
int sl = strlen(db);
char* ns = bson_malloc(sl + 5 + 1); /* ".$cmd" + nul */
bson_bool_t success;
strcpy(ns, db);
strcpy(ns+sl, ".$cmd");
success = mongo_find_one(conn, ns, command, bson_empty(&fields), out);
free(ns);
return success;
}
bson_bool_t mongo_simple_int_command(mongo_connection * conn, const char * db, const char* cmdstr, int arg, bson * realout){
bson out;
bson cmd;
bson_buffer bb;
bson_bool_t success = 0;
bson_buffer_init(&bb);
bson_append_int(&bb, cmdstr, arg);
bson_from_buffer(&cmd, &bb);
if(mongo_run_command(conn, db, &cmd, &out)){
bson_iterator it;
if(bson_find(&it, &out, "ok"))
success = bson_iterator_bool(&it);
}
bson_destroy(&cmd);
if (realout)
*realout = out;
else
bson_destroy(&out);
return success;
}
bson_bool_t mongo_simple_str_command(mongo_connection * conn, const char * db, const char* cmdstr, const char* arg, bson * realout){
bson out;
bson cmd;
bson_buffer bb;
bson_bool_t success = 0;
bson_buffer_init(&bb);
bson_append_string(&bb, cmdstr, arg);
bson_from_buffer(&cmd, &bb);
if(mongo_run_command(conn, db, &cmd, &out)){
bson_iterator it;
if(bson_find(&it, &out, "ok"))
success = bson_iterator_bool(&it);
}
bson_destroy(&cmd);
if (realout)
*realout = out;
else
bson_destroy(&out);
return success;
}
bson_bool_t mongo_cmd_drop_db(mongo_connection * conn, const char * db){
return mongo_simple_int_command(conn, db, "dropDatabase", 1, NULL);
}
bson_bool_t mongo_cmd_drop_collection(mongo_connection * conn, const char * db, const char * collection, bson * out){
return mongo_simple_str_command(conn, db, "drop", collection, out);
}
void mongo_cmd_reset_error(mongo_connection * conn, const char * db){
mongo_simple_int_command(conn, db, "reseterror", 1, NULL);
}
static bson_bool_t mongo_cmd_get_error_helper(mongo_connection * conn, const char * db, bson * realout, const char * cmdtype){
bson out = {NULL,0};
bson_bool_t haserror = 1;
if(mongo_simple_int_command(conn, db, cmdtype, 1, &out)){
bson_iterator it;
haserror = (bson_find(&it, &out, "err") != bson_null);
}
if(realout)
*realout = out; /* transfer of ownership */
else
bson_destroy(&out);
return haserror;
}
bson_bool_t mongo_cmd_get_prev_error(mongo_connection * conn, const char * db, bson * out){
return mongo_cmd_get_error_helper(conn, db, out, "getpreverror");
}
bson_bool_t mongo_cmd_get_last_error(mongo_connection * conn, const char * db, bson * out){
return mongo_cmd_get_error_helper(conn, db, out, "getlasterror");
}
bson_bool_t mongo_cmd_ismaster(mongo_connection * conn, bson * realout){
bson out = {NULL,0};
bson_bool_t ismaster = 0;
if (mongo_simple_int_command(conn, "admin", "ismaster", 1, &out)){
bson_iterator it;
bson_find(&it, &out, "ismaster");
ismaster = bson_iterator_bool(&it);
}
if(realout)
*realout = out; /* transfer of ownership */
else
bson_destroy(&out);
return ismaster;
}
static void digest2hex(mongo_md5_byte_t digest[16], char hex_digest[33]){
static const char hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
int i;
for (i=0; i<16; i++){
hex_digest[2*i] = hex[(digest[i] & 0xf0) >> 4];
hex_digest[2*i + 1] = hex[ digest[i] & 0x0f ];
}
hex_digest[32] = '\0';
}
static void mongo_pass_digest(const char* user, const char* pass, char hex_digest[33]){
mongo_md5_state_t st;
mongo_md5_byte_t digest[16];
mongo_md5_init(&st);
mongo_md5_append(&st, (const mongo_md5_byte_t*)user, strlen(user));
mongo_md5_append(&st, (const mongo_md5_byte_t*)":mongo:", 7);
mongo_md5_append(&st, (const mongo_md5_byte_t*)pass, strlen(pass));
mongo_md5_finish(&st, digest);
digest2hex(digest, hex_digest);
}
void mongo_cmd_add_user(mongo_connection* conn, const char* db, const char* user, const char* pass){
bson_buffer bb;
bson user_obj;
bson pass_obj;
char hex_digest[33];
char* ns = malloc(strlen(db) + strlen(".system.users") + 1);
strcpy(ns, db);
strcpy(ns+strlen(db), ".system.users");
mongo_pass_digest(user, pass, hex_digest);
bson_buffer_init(&bb);
bson_append_string(&bb, "user", user);
bson_from_buffer(&user_obj, &bb);
bson_buffer_init(&bb);
bson_append_start_object(&bb, "$set");
bson_append_string(&bb, "pwd", hex_digest);
bson_append_finish_object(&bb);
bson_from_buffer(&pass_obj, &bb);
MONGO_TRY{
mongo_update(conn, ns, &user_obj, &pass_obj, MONGO_UPDATE_UPSERT);
}MONGO_CATCH{
free(ns);
bson_destroy(&user_obj);
bson_destroy(&pass_obj);
MONGO_RETHROW();
}
free(ns);
bson_destroy(&user_obj);
bson_destroy(&pass_obj);
}
bson_bool_t mongo_cmd_authenticate(mongo_connection* conn, const char* db, const char* user, const char* pass){
bson_buffer bb;
bson from_db, auth_cmd;
const char* nonce;
bson_bool_t success = 0;
mongo_md5_state_t st;
mongo_md5_byte_t digest[16];
char hex_digest[33];
if (mongo_simple_int_command(conn, db, "getnonce", 1, &from_db)){
bson_iterator it;
bson_find(&it, &from_db, "nonce");
nonce = bson_iterator_string(&it);
}else{
return 0;
}
mongo_pass_digest(user, pass, hex_digest);
mongo_md5_init(&st);
mongo_md5_append(&st, (const mongo_md5_byte_t*)nonce, strlen(nonce));
mongo_md5_append(&st, (const mongo_md5_byte_t*)user, strlen(user));
mongo_md5_append(&st, (const mongo_md5_byte_t*)hex_digest, 32);
mongo_md5_finish(&st, digest);
digest2hex(digest, hex_digest);
bson_buffer_init(&bb);
bson_append_int(&bb, "authenticate", 1);
bson_append_string(&bb, "user", user);
bson_append_string(&bb, "nonce", nonce);
bson_append_string(&bb, "key", hex_digest);
bson_from_buffer(&auth_cmd, &bb);
bson_destroy(&from_db);
MONGO_TRY{
if(mongo_run_command(conn, db, &auth_cmd, &from_db)){
bson_iterator it;
if(bson_find(&it, &from_db, "ok"))
success = bson_iterator_bool(&it);
}
}MONGO_CATCH{
bson_destroy(&auth_cmd);
MONGO_RETHROW();
}
bson_destroy(&from_db);
bson_destroy(&auth_cmd);
return success;
}

186
lib/mongodb/mongo.h Normal file
View file

@ -0,0 +1,186 @@
/* mongo.h */
/* Copyright 2009, 2010 10gen Inc.
*
* 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.
*/
#ifndef _MONGO_H_
#define _MONGO_H_
#include "mongo_except.h"
#include "bson.h"
#ifdef _WIN32
#include <windows.h>
#include <winsock.h>
typedef int socklen_t;
#else
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#endif
MONGO_EXTERN_C_START
typedef struct mongo_connection_options {
char host[255];
int port;
} mongo_connection_options;
typedef struct {
mongo_connection_options* left_opts; /* always current server */
mongo_connection_options* right_opts; /* unused with single server */
struct sockaddr_in sa;
socklen_t addressSize;
int sock;
bson_bool_t connected;
mongo_exception_context exception;
} mongo_connection;
#pragma pack(1)
typedef struct {
int len;
int id;
int responseTo;
int op;
} mongo_header;
typedef struct {
mongo_header head;
char data;
} mongo_message;
typedef struct {
int flag; /* non-zero on failure */
int64_t cursorID;
int start;
int num;
} mongo_reply_fields;
typedef struct {
mongo_header head;
mongo_reply_fields fields;
char objs;
} mongo_reply;
#pragma pack()
typedef struct {
mongo_reply * mm; /* message is owned by cursor */
mongo_connection * conn; /* connection is *not* owned by cursor */
const char* ns; /* owned by cursor */
bson current;
} mongo_cursor;
enum mongo_operations {
mongo_op_msg = 1000, /* generic msg command followed by a string */
mongo_op_update = 2001, /* update object */
mongo_op_insert = 2002,
mongo_op_query = 2004,
mongo_op_get_more = 2005,
mongo_op_delete = 2006,
mongo_op_kill_cursors = 2007
};
/* ----------------------------
CONNECTION STUFF
------------------------------ */
typedef enum {
mongo_conn_success = 0,
mongo_conn_bad_arg,
mongo_conn_no_socket,
mongo_conn_fail,
mongo_conn_not_master /* leaves conn connected to slave */
} mongo_conn_return;
/**
* @param options can be null
*/
mongo_conn_return mongo_connect( mongo_connection * conn , mongo_connection_options * options );
mongo_conn_return mongo_connect_pair( mongo_connection * conn , mongo_connection_options * left, mongo_connection_options * right );
mongo_conn_return mongo_reconnect( mongo_connection * conn ); /* you will need to reauthenticate after calling */
bson_bool_t mongo_disconnect( mongo_connection * conn ); /* use this if you want to be able to reconnect */
bson_bool_t mongo_destroy( mongo_connection * conn ); /* you must call this even if connection failed */
/* ----------------------------
CORE METHODS - insert update remove query getmore
------------------------------ */
void mongo_insert( mongo_connection * conn , const char * ns , bson * data );
void mongo_insert_batch( mongo_connection * conn , const char * ns , bson ** data , int num );
static const int MONGO_UPDATE_UPSERT = 0x1;
static const int MONGO_UPDATE_MULTI = 0x2;
void mongo_update(mongo_connection* conn, const char* ns, const bson* cond, const bson* op, int flags);
void mongo_remove(mongo_connection* conn, const char* ns, const bson* cond);
mongo_cursor* mongo_find(mongo_connection* conn, const char* ns, bson* query, bson* fields ,int nToReturn ,int nToSkip, int options);
bson_bool_t mongo_cursor_next(mongo_cursor* cursor);
void mongo_cursor_destroy(mongo_cursor* cursor);
/* out can be NULL if you don't care about results. useful for commands */
bson_bool_t mongo_find_one(mongo_connection* conn, const char* ns, bson* query, bson* fields, bson* out);
int64_t mongo_count(mongo_connection* conn, const char* db, const char* coll, bson* query);
/* ----------------------------
HIGHER LEVEL - indexes - command helpers eval
------------------------------ */
/* Returns true on success */
/* WARNING: Unlike other drivers these do not cache results */
static const int MONGO_INDEX_UNIQUE = 0x1;
static const int MONGO_INDEX_DROP_DUPS = 0x2;
bson_bool_t mongo_create_index(mongo_connection * conn, const char * ns, bson * key, int options, bson * out);
bson_bool_t mongo_create_simple_index(mongo_connection * conn, const char * ns, const char* field, int options, bson * out);
/* ----------------------------
COMMANDS
------------------------------ */
bson_bool_t mongo_run_command(mongo_connection * conn, const char * db, bson * command, bson * out);
/* for simple commands with a single k-v pair */
bson_bool_t mongo_simple_int_command(mongo_connection * conn, const char * db, const char* cmd, int arg, bson * out);
bson_bool_t mongo_simple_str_command(mongo_connection * conn, const char * db, const char* cmd, const char* arg, bson * out);
bson_bool_t mongo_cmd_drop_db(mongo_connection * conn, const char * db);
bson_bool_t mongo_cmd_drop_collection(mongo_connection * conn, const char * db, const char * collection, bson * out);
void mongo_cmd_add_user(mongo_connection* conn, const char* db, const char* user, const char* pass);
bson_bool_t mongo_cmd_authenticate(mongo_connection* conn, const char* db, const char* user, const char* pass);
/* return value is master status */
bson_bool_t mongo_cmd_ismaster(mongo_connection * conn, bson * out);
/* true return indicates error */
bson_bool_t mongo_cmd_get_last_error(mongo_connection * conn, const char * db, bson * out);
bson_bool_t mongo_cmd_get_prev_error(mongo_connection * conn, const char * db, bson * out);
void mongo_cmd_reset_error(mongo_connection * conn, const char * db);
/* ----------------------------
UTILS
------------------------------ */
MONGO_EXTERN_C_END
#endif

143
lib/mongodb/mongo_except.h Normal file
View file

@ -0,0 +1,143 @@
/* mongo_except.h */
/* Copyright 2009 10gen Inc.
*
* 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.
*/
/* This file is based loosely on cexcept (http://www.nicemice.net/cexcept/). I
* have modified it to work better with mongo's API.
*
* The MONGO_TRY, MONGO_CATCH, and MONGO_TROW macros assume that a pointer to
* the current connection is available as 'conn'. If you would like to use a
* different name, use the _GENERIC version of these macros.
*
* WARNING: do not return or otherwise jump (excluding MONGO_TRHOW()) out of a
* MONGO_TRY block as the nessesary clean-up code will not be called. Jumping
* out of the MONGO_CATCH block is OK.
*/
#ifdef MONGO_CODE_EXAMPLE
mongo_connection conn[1]; /* makes conn a ptr to the connection */
MONGO_TRY{
mongo_find_one(...);
MONGO_THROW(conn, MONGO_EXCEPT_NETWORK);
}MONGO_CATCH{
switch(conn->exception->type){
case MONGO_EXCEPT_NETWORK:
do_something();
case MONGO_EXCEPT_FIND_ERR:
do_something();
default:
MONGO_RETHROW();
}
}
#endif
/* ORIGINAL CEXEPT COPYRIGHT:
cexcept: README 2.0.1 (2008-Jul-23-Wed)
http://www.nicemice.net/cexcept/
Adam M. Costello
http://www.nicemice.net/amc/
The package is both free-as-in-speech and free-as-in-beer:
Copyright (c) 2000-2008 Adam M. Costello and Cosmin Truta.
This package may be modified only if its author and version
information is updated accurately, and may be redistributed
only if accompanied by this unaltered notice. Subject to those
restrictions, permission is granted to anyone to do anything with
this package. The copyright holders make no guarantees regarding
this package, and are not responsible for any damage resulting from
its use.
*/
#ifndef _MONGO_EXCEPT_H_
#define _MONGO_EXCEPT_H_
#include <setjmp.h>
/* always non-zero */
typedef enum{
MONGO_EXCEPT_NETWORK=1,
MONGO_EXCEPT_FIND_ERR
}mongo_exception_type;
typedef struct {
jmp_buf base_handler;
jmp_buf *penv;
int caught;
volatile mongo_exception_type type;
}mongo_exception_context;
#define MONGO_TRY MONGO_TRY_GENERIC(conn)
#define MONGO_CATCH MONGO_CATCH_GENERIC(conn)
#define MONGO_THROW(e) MONGO_THROW_GENERIC(conn, e)
#define MONGO_RETHROW() MONGO_RETHROW_GENERIC(conn)
/* the rest of this file is implementation details */
/* this is done in mongo_connect */
#define MONGO_INIT_EXCEPTION(exception_ptr) \
do{ \
mongo_exception_type t; /* exception_ptr won't be available */\
(exception_ptr)->penv = &(exception_ptr)->base_handler; \
if ((t = setjmp((exception_ptr)->base_handler))) { /* yes, '=' is correct */ \
switch(t){ \
case MONGO_EXCEPT_NETWORK: bson_fatal_msg(0, "network error"); \
case MONGO_EXCEPT_FIND_ERR: bson_fatal_msg(0, "error in find"); \
default: bson_fatal_msg(0, "unknown exception"); \
} \
} \
}while(0)
#define MONGO_TRY_GENERIC(connection) \
{ \
jmp_buf *exception__prev, exception__env; \
exception__prev = (connection)->exception.penv; \
(connection)->exception.penv = &exception__env; \
if (setjmp(exception__env) == 0) { \
do
#define MONGO_CATCH_GENERIC(connection) \
while ((connection)->exception.caught = 0, \
(connection)->exception.caught); \
} \
else { \
(connection)->exception.caught = 1; \
} \
(connection)->exception.penv = exception__prev; \
} \
if (!(connection)->exception.caught ) { } \
else
/* Try ends with do, and Catch begins with while(0) and ends with */
/* else, to ensure that Try/Catch syntax is similar to if/else */
/* syntax. */
/* */
/* The 0 in while(0) is expressed as x=0,x in order to appease */
/* compilers that warn about constant expressions inside while(). */
/* Most compilers should still recognize that the condition is always */
/* false and avoid generating code for it. */
#define MONGO_THROW_GENERIC(connection, type_in) \
for (;; longjmp(*(connection)->exception.penv, type_in)) \
(connection)->exception.type = type_in
#define MONGO_RETHROW_GENERIC(connection) \
MONGO_THROW_GENERIC(connection, (connection)->exception.type)
#endif

127
lib/mongodb/numbers.c Normal file
View file

@ -0,0 +1,127 @@
/* Copyright 2009 10gen Inc.
*
* 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.
*/
/* all the numbers that fit in a 4 byte string */
const char bson_numstrs[1000][4] = {
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
"100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
"110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
"120", "121", "122", "123", "124", "125", "126", "127", "128", "129",
"130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
"140", "141", "142", "143", "144", "145", "146", "147", "148", "149",
"150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
"160", "161", "162", "163", "164", "165", "166", "167", "168", "169",
"170", "171", "172", "173", "174", "175", "176", "177", "178", "179",
"180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
"190", "191", "192", "193", "194", "195", "196", "197", "198", "199",
"200", "201", "202", "203", "204", "205", "206", "207", "208", "209",
"210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
"220", "221", "222", "223", "224", "225", "226", "227", "228", "229",
"230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
"240", "241", "242", "243", "244", "245", "246", "247", "248", "249",
"250", "251", "252", "253", "254", "255", "256", "257", "258", "259",
"260", "261", "262", "263", "264", "265", "266", "267", "268", "269",
"270", "271", "272", "273", "274", "275", "276", "277", "278", "279",
"280", "281", "282", "283", "284", "285", "286", "287", "288", "289",
"290", "291", "292", "293", "294", "295", "296", "297", "298", "299",
"300", "301", "302", "303", "304", "305", "306", "307", "308", "309",
"310", "311", "312", "313", "314", "315", "316", "317", "318", "319",
"320", "321", "322", "323", "324", "325", "326", "327", "328", "329",
"330", "331", "332", "333", "334", "335", "336", "337", "338", "339",
"340", "341", "342", "343", "344", "345", "346", "347", "348", "349",
"350", "351", "352", "353", "354", "355", "356", "357", "358", "359",
"360", "361", "362", "363", "364", "365", "366", "367", "368", "369",
"370", "371", "372", "373", "374", "375", "376", "377", "378", "379",
"380", "381", "382", "383", "384", "385", "386", "387", "388", "389",
"390", "391", "392", "393", "394", "395", "396", "397", "398", "399",
"400", "401", "402", "403", "404", "405", "406", "407", "408", "409",
"410", "411", "412", "413", "414", "415", "416", "417", "418", "419",
"420", "421", "422", "423", "424", "425", "426", "427", "428", "429",
"430", "431", "432", "433", "434", "435", "436", "437", "438", "439",
"440", "441", "442", "443", "444", "445", "446", "447", "448", "449",
"450", "451", "452", "453", "454", "455", "456", "457", "458", "459",
"460", "461", "462", "463", "464", "465", "466", "467", "468", "469",
"470", "471", "472", "473", "474", "475", "476", "477", "478", "479",
"480", "481", "482", "483", "484", "485", "486", "487", "488", "489",
"490", "491", "492", "493", "494", "495", "496", "497", "498", "499",
"500", "501", "502", "503", "504", "505", "506", "507", "508", "509",
"510", "511", "512", "513", "514", "515", "516", "517", "518", "519",
"520", "521", "522", "523", "524", "525", "526", "527", "528", "529",
"530", "531", "532", "533", "534", "535", "536", "537", "538", "539",
"540", "541", "542", "543", "544", "545", "546", "547", "548", "549",
"550", "551", "552", "553", "554", "555", "556", "557", "558", "559",
"560", "561", "562", "563", "564", "565", "566", "567", "568", "569",
"570", "571", "572", "573", "574", "575", "576", "577", "578", "579",
"580", "581", "582", "583", "584", "585", "586", "587", "588", "589",
"590", "591", "592", "593", "594", "595", "596", "597", "598", "599",
"600", "601", "602", "603", "604", "605", "606", "607", "608", "609",
"610", "611", "612", "613", "614", "615", "616", "617", "618", "619",
"620", "621", "622", "623", "624", "625", "626", "627", "628", "629",
"630", "631", "632", "633", "634", "635", "636", "637", "638", "639",
"640", "641", "642", "643", "644", "645", "646", "647", "648", "649",
"650", "651", "652", "653", "654", "655", "656", "657", "658", "659",
"660", "661", "662", "663", "664", "665", "666", "667", "668", "669",
"670", "671", "672", "673", "674", "675", "676", "677", "678", "679",
"680", "681", "682", "683", "684", "685", "686", "687", "688", "689",
"690", "691", "692", "693", "694", "695", "696", "697", "698", "699",
"700", "701", "702", "703", "704", "705", "706", "707", "708", "709",
"710", "711", "712", "713", "714", "715", "716", "717", "718", "719",
"720", "721", "722", "723", "724", "725", "726", "727", "728", "729",
"730", "731", "732", "733", "734", "735", "736", "737", "738", "739",
"740", "741", "742", "743", "744", "745", "746", "747", "748", "749",
"750", "751", "752", "753", "754", "755", "756", "757", "758", "759",
"760", "761", "762", "763", "764", "765", "766", "767", "768", "769",
"770", "771", "772", "773", "774", "775", "776", "777", "778", "779",
"780", "781", "782", "783", "784", "785", "786", "787", "788", "789",
"790", "791", "792", "793", "794", "795", "796", "797", "798", "799",
"800", "801", "802", "803", "804", "805", "806", "807", "808", "809",
"810", "811", "812", "813", "814", "815", "816", "817", "818", "819",
"820", "821", "822", "823", "824", "825", "826", "827", "828", "829",
"830", "831", "832", "833", "834", "835", "836", "837", "838", "839",
"840", "841", "842", "843", "844", "845", "846", "847", "848", "849",
"850", "851", "852", "853", "854", "855", "856", "857", "858", "859",
"860", "861", "862", "863", "864", "865", "866", "867", "868", "869",
"870", "871", "872", "873", "874", "875", "876", "877", "878", "879",
"880", "881", "882", "883", "884", "885", "886", "887", "888", "889",
"890", "891", "892", "893", "894", "895", "896", "897", "898", "899",
"900", "901", "902", "903", "904", "905", "906", "907", "908", "909",
"910", "911", "912", "913", "914", "915", "916", "917", "918", "919",
"920", "921", "922", "923", "924", "925", "926", "927", "928", "929",
"930", "931", "932", "933", "934", "935", "936", "937", "938", "939",
"940", "941", "942", "943", "944", "945", "946", "947", "948", "949",
"950", "951", "952", "953", "954", "955", "956", "957", "958", "959",
"960", "961", "962", "963", "964", "965", "966", "967", "968", "969",
"970", "971", "972", "973", "974", "975", "976", "977", "978", "979",
"980", "981", "982", "983", "984", "985", "986", "987", "988", "989",
"990", "991", "992", "993", "994", "995", "996", "997", "998", "999",
};

View file

@ -0,0 +1,91 @@
/* platform_hacks.h */
/* Copyright 2009, 2010 10gen Inc.
*
* 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.
*/
/* all platform-specific ifdefs should go here */
#ifndef _PLATFORM_HACKS_H_
#define _PLATFORM_HACKS_H_
#ifdef __GNUC__
#define MONGO_INLINE static __inline__
#else
#define MONGO_INLINE static
#endif
#ifdef __cplusplus
#define MONGO_EXTERN_C_START extern "C" {
#define MONGO_EXTERN_C_END }
#else
#define MONGO_EXTERN_C_START
#define MONGO_EXTERN_C_END
#endif
#if defined(MONGO_HAVE_STDINT) || __STDC_VERSION__ >= 199901L
#include <stdint.h>
#elif defined(MONGO_HAVE_UNISTD)
#include <unistd.h>
#elif defined(MONGO_USE__INT64)
typedef __int64 int64_t;
#elif defined(MONGO_USE_LONG_LONG_INT)
typedef long long int int64_t;
#else
#error must have a 64bit int type
#endif
/* big endian is only used for OID generation. little is used everywhere else */
#ifdef MONGO_BIG_ENDIAN
#define bson_little_endian64(out, in) ( bson_swap_endian64(out, in) )
#define bson_little_endian32(out, in) ( bson_swap_endian32(out, in) )
#define bson_big_endian64(out, in) ( memcpy(out, in, 8) )
#define bson_big_endian32(out, in) ( memcpy(out, in, 4) )
#else
#define bson_little_endian64(out, in) ( memcpy(out, in, 8) )
#define bson_little_endian32(out, in) ( memcpy(out, in, 4) )
#define bson_big_endian64(out, in) ( bson_swap_endian64(out, in) )
#define bson_big_endian32(out, in) ( bson_swap_endian32(out, in) )
#endif
MONGO_EXTERN_C_START
MONGO_INLINE void bson_swap_endian64(void* outp, const void* inp){
const char *in = (const char*)inp;
char *out = (char*)outp;
out[0] = in[7];
out[1] = in[6];
out[2] = in[5];
out[3] = in[4];
out[4] = in[3];
out[5] = in[2];
out[6] = in[1];
out[7] = in[0];
}
MONGO_INLINE void bson_swap_endian32(void* outp, const void* inp){
const char *in = (const char*)inp;
char *out = (char*)outp;
out[0] = in[3];
out[1] = in[2];
out[2] = in[1];
out[3] = in[0];
}
MONGO_EXTERN_C_END
#endif

177
src/database/mongo.c Normal file
View file

@ -0,0 +1,177 @@
/* database/mongo.c - mongodb driver
*
* Copyright (C) 2010 Henrik Hautakoski <henrik@fiktivkod.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This driver uses the official mongodb C driver API.
* however error handling is somewhat weak, looks like this is a design
* choice of mongodb and not much can be done about that.
*/
#include <string.h>
#include <time.h>
#include <mongodb/mongo.h>
#include <ini/iniparser.h>
#include "../debug.h"
#include "../path.h"
#include "../database.h"
static struct {
mongo_connection conn;
mongo_connection_options opts;
char ns[255];
} db;
static void coll_create_index() {
bson b;
bson_buffer buf;
bson_buffer_init(&buf);
bson_append_int(&buf, "Path", 1);
bson_append_int(&buf, "File", 1);
bson_from_buffer(&b, &buf);
mongo_create_index(&db.conn, db.ns, &b, 0, NULL);
bson_destroy(&b);
}
static void coll_clear() {
bson cond;
bson_empty(&cond);
mongo_remove(&db.conn, db.ns, &cond);
bson_destroy(&cond);
}
int database_init(dictionary *conf) {
char *confdb = iniparser_getstring(conf, "mongo:database", NULL);
char *confcoll = iniparser_getstring(conf, "mongo:collection", NULL);
if (!confcoll) {
fprintf(stderr, "mongo: missing 'collection' in configuration\n");
return -1;
}
if (!confcoll) {
fprintf(stderr, "mongo: missing 'database' in configuration\n");
return -1;
}
strncpy(db.opts.host, iniparser_getstring(conf, "mongo:host", "127.0.0.1"), sizeof(db.opts.host));
db.opts.port = iniparser_getint(conf, "mongo:port", 27017);
mongo_conn_return status = mongo_connect(&db.conn, &db.opts);
if (status != mongo_conn_success) {
char *err;
switch (status) {
case mongo_conn_bad_arg :
err = "Bad arguments";
break;
case mongo_conn_no_socket :
err = "No socket";
break;
case mongo_conn_fail:
err = "Connection failed";
break;
case mongo_conn_not_master:
err = "Not master\n";
break;
default:
err = "Unkown error";
}
fprintf(stderr, "mongo: %s (%s:%i)\n", err, db.opts.host, db.opts.port);
return -1;
}
/* do auth if these values are precent */
char *user = iniparser_getstring(conf, "mongo:username", NULL);
char *pass = iniparser_getstring(conf, "mongo:password", NULL);
if (user && pass) {
bson_bool_t rc = mongo_cmd_authenticate(&db.conn, confdb, user, pass);
if (!rc) {
fprintf(stderr, "mongo: can't authenticate\n");
return -1;
}
}
/* create the namespace string */
snprintf(db.ns, sizeof(db.ns), "%s.%s", confdb, confcoll);
/* prepare collection */
coll_clear();
coll_create_index();
return 0;
}
int database_insert(const char *path, const char *filename, const int isdir) {
bson b;
bson_buffer buf;
bson_buffer_init(&buf);
bson_append_new_oid(&buf, "_id");
bson_append_string(&buf, "Path", path);
bson_append_string(&buf, "File", filename);
bson_append_int(&buf, "Type", isdir != 0);
bson_append_time_t(&buf, "Date", time(NULL));
bson_from_buffer(&b, &buf);
mongo_insert(&db.conn, db.ns, &b);
bson_destroy(&b);
return 0;
}
int database_delete(const char *path, const char *filename) {
bson cond;
bson_buffer buf;
char *fpath = path_normalize(path, filename, 1);
if (!fpath)
return -1;
bson_buffer_init(&buf);
bson_append_string(&buf, "Path", path);
bson_append_string(&buf, "File", filename);
bson_from_buffer(&cond, &buf);
mongo_remove(&db.conn, db.ns, &cond);
bson_destroy(&cond);
bson_buffer_init(&buf);
bson_append_regex(&buf, "Path", fpath, "");
bson_from_buffer(&cond, &buf);
mongo_remove(&db.conn, db.ns, &cond);
bson_destroy(&cond);
free(fpath);
return 0;
}
int database_close() {
mongo_destroy(&db.conn);
return 0;
}