The beginnings of datastore

A lot of code cleanup, plus beginning the implementation of a datastore.
This commit is contained in:
John Jones 2016-11-17 15:07:59 -05:00
parent 0b765481da
commit c64a700223
28 changed files with 1169 additions and 132 deletions

40
blocks/block.c Normal file
View file

@ -0,0 +1,40 @@
/**
* The implementation of methods around IPFS blocks
*/
#include <stdlib.h>
#include "ipfs/blocks/block.h"
#include "ipfs/cid/cid.h"
/***
* Create a new block based on the incoming data
* @param data the data to base the block on
* @param data_size the length of the data array
* @param block a pointer to the struct Block that will be created
* @returns true(1) on success
*/
int ipfs_blocks_block_new(unsigned char* data, size_t data_size, struct Block* block) {
char hash[32];
ipfs_crypto_hashing_sha256(data, hash, 32);
ipfs_cid_new(0, hash, 32, CID_PROTOBUF, block->cid);
block->data = malloc(sizeof(unsigned char) * data_size);
if (block->data == NULL)
return 0;
memcpy(block->data, data, data_size);
return 1;
}
/***
* Free resources used by the creation of a block
* @param block the block to free
* @returns true(1) on success
*/
int ipfs_blocks_block_free(struct Block* block) {
ipfs_cid_free(block->cid);
if (block->data != NULL)
free(block->data);
return 1;
}

41
blocks/blockstore.c Normal file
View file

@ -0,0 +1,41 @@
/***
* a thin wrapper over a datastore for getting and putting block objects
*/
/**
* Delete a block based on its Cid
* @param cid the Cid to look for
* @param returns true(1) on success
*/
int ipfs_blockstore_delete(struct Cid* cid) {
return 0;
}
/***
* Determine if the Cid can be found
* @param cid the Cid to look for
* @returns true(1) if found
*/
int ipfs_blockstore_has(struct Cid* cid) {
return 0;
}
/***
* Find a block based on its Cid
* @param cid the Cid to look for
* @param block where to put the data to be returned
* @returns true(1) on success
*/
int ipfs_blockstore_get(struct Cid* cid, struct Block* block) {
return 0;
}
/***
* Put a block in the blockstore
* @param block the block to store
* @returns true(1) on success
*/
int ipfs_blockstore_put(struct Block* block) {
return 0;
}

View file

@ -24,14 +24,14 @@ int init_pre_run(struct Request* request) {
/**
* This actually opens the repo and gets things set up
* @param repo_root the root of the repository
* @param repo the repo information
* @returns true(1) on success
*/
int initialize_ipns_keyspace(char* repo_root) {
//TODO: open fs repo
struct FSRepo repo;
// get the path
int retVal = fs_repo_open(repo_root, &repo);
int initialize_ipns_keyspace(struct FSRepo* repo) {
//open fs repo
int retVal = ipfs_repo_fsrepo_open(repo);
if (retVal == 0)
return 0;
//TODO: make a new node, then close it
//TODO: setup offline routing on new node
struct IpfsNode* ipfs_node;
@ -66,11 +66,16 @@ int do_init(FILE* out_file, char* repo_root, int empty, int num_bits_for_keypair
return 0;
}
// initialize the fs repo
int retVal = fs_repo_init(repo_root, conf);
struct FSRepo* repo;
int retVal = ipfs_repo_fsrepo_new(repo_root, conf, &repo);
if (retVal == 0)
return 0;
retVal = ipfs_repo_fsrepo_init(repo);
if (retVal == 0)
return 0;
//TODO: add default assets
return initialize_ipns_keyspace(repo_root);
return initialize_ipns_keyspace(repo);
}
/***

View file

@ -0,0 +1,29 @@
/***
* IPFS has the notion of storage blocks.
*/
#ifndef __IPFS_BLOCKS_BLOCK_H__
#define __IPFS_BLOCKS_BLOCK_H__
struct Block {
struct Cid* cid;
unsigned char* data;
};
/***
* Create a new block based on the incoming data.
* @param data the data to base the block on
* @param data_size the length of the data array
* @param block a pointer to the struct Block that will be created
* @returns true(1) on success
*/
int ipfs_blocks_block_new(unsigned char* data, size_t data_size, struct Block* block);
/***
* Free resources used by the creation of a block
* @param block the block to free
* @returns true(1) on success
*/
int ipfs_blocks_block_free(struct Block* block);
#endif

View file

@ -0,0 +1,38 @@
/***
* a thin wrapper over a datastore for getting and putting block objects
*/
#ifndef __IPFS_BLOCKS_BLOCKSTORE_H__
#ifndef __IPFS_BLOCKS_BLOCKSTORE_H__
/**
* Delete a block based on its Cid
* @param cid the Cid to look for
* @param returns true(1) on success
*/
int ipfs_blockstore_delete(struct Cid* cid);
/***
* Determine if the Cid can be found
* @param cid the Cid to look for
* @returns true(1) if found
*/
int ipfs_blockstore_has(struct Cid* cid);
/***
* Find a block based on its Cid
* @param cid the Cid to look for
* @param block where to put the data to be returned
* @returns true(1) on success
*/
int ipfs_blockstore_get(struct Cid* cid, struct Block* block);
/***
* Put a block in the blockstore
* @param block the block to store
* @returns true(1) on success
*/
int ipfs_blockstore_put(struct Block* block);
#endif

View file

@ -13,7 +13,7 @@
* @param variable the variable to look for
* @returns the results
*/
char* os_utils_getenv(char* variable);
char* os_utils_getenv(const char* variable);
/**
* get the user's home directory
@ -28,10 +28,12 @@ char* os_utils_get_homedir();
* @param results where to put the results
* @param max_len throw an error if the total is longer than max_len
*/
int os_utils_filepath_join(char* root, char* extension, char* results, unsigned long max_len);
int os_utils_filepath_join(const char* root, const char* extension, char* results, unsigned long max_len);
int os_utils_file_exists(char* file_name);
int os_utils_file_exists(const char* file_name);
int os_utils_directory_writeable(char* path);
int os_utils_file_size(const char* file_name);
int os_utils_directory_writeable(const char* path);
#endif /* utils_h */

View file

@ -74,11 +74,18 @@ int config_path(char* config_root, char* extension, char* result, int max_len);
*/
int repo_config_init(struct RepoConfig* config, unsigned int num_bits_for_keypair, char* repo_path);
/***
* Initialize memory for a RepoConfig struct
* @param config the structure to initialize
* @returns true(1) on success
*/
int ipfs_repo_config_new(struct RepoConfig** config);
/***
* free all resources that were allocated to store config information
* @param config the config
* @returns true(1)
*/
int repo_config_free(struct RepoConfig* config);
int ipfs_repo_config_free(struct RepoConfig* config);
#endif

View file

@ -11,27 +11,41 @@ struct Datastore {
char* storage_max;
int storage_gc_watermark;
char* gc_period;
char* params;
int no_sync;
int hash_on_read;
int bloom_filter_size;
// function pointers for datastore operations
int (*datastore_open)(int argc, char** argv, struct Datastore* datastore);
int (*datastore_close)(int argc, char** argv, struct Datastore* datastore);
// a handle to the datastore "context" used by the datastore
void* handle;
};
/***
* initialize the structure of the datastore
* Initialize the structure of the datastore to default settings. Used for
* creating a new datastore on the disk.
* @param datastore the struct to initialize
* @param config_root the path to the root of IPFS
* @returns true(1) on success
*/
int repo_config_datastore_init(struct Datastore* datastore, char* config_root);
int ipfs_repo_config_datastore_init(struct Datastore* datastore, char* config_root);
/***
* initialize the structure of the datastore
* @param datastore the struct to initialize
* @returns true(1) on success
*/
int ipfs_repo_config_datastore_new(struct Datastore** datastore);
/***
* deallocate the memory and clear resources from a datastore_init
* @param datastore the struct to deallocate
* @returns true(1)
*/
int repo_config_datastore_free(struct Datastore* datastore);
int ipfs_repo_config_datastore_free(struct Datastore* datastore);
#endif

View file

@ -19,7 +19,15 @@ struct Identity {
/***
* initializes a new keypair, and puts it in the Identity struct
*/
int repo_config_identity_new(struct Identity* identity, unsigned long num_bits_for_keypair);
int repo_config_identity_init(struct Identity* identity, unsigned long num_bits_for_keypair);
/***
* Build a RsaPrivateKey struct from a base64 string of the private key
* @param identity where to put the new struct
* @param base64 the base 64 encoded private key in DER format
* @returns true(1) on success
*/
int repo_config_identity_build_private_key(struct Identity* identity, const char* base64);
/***
* Frees resources held by Identity
@ -28,4 +36,11 @@ int repo_config_identity_new(struct Identity* identity, unsigned long num_bits_f
*/
int repo_config_identity_free(struct Identity* identity);
/***
* Initializes a new identity struct that will need to be identity_free'd
* @param identity the identity to allocate memory for
* @returns true(1) on success
*/
int repo_config_identity_new(struct Identity** identity);
#endif /* identity_h */

View file

@ -15,7 +15,7 @@ struct FSRepo {
int closed;
char* path;
struct IOCloser* lock_file;
struct Config* config;
struct RepoConfig* config;
struct Datastore* data_store;
};
@ -25,7 +25,7 @@ struct FSRepo {
* @param repo where to store the repo info
* @return 0 if there was a problem, otherwise 1
*/
int fs_repo_open(char* repo_path, struct FSRepo* repo);
int ipfs_repo_fsrepo_open(struct FSRepo* repo);
/***
* checks to see if the repo is initialized
@ -48,7 +48,20 @@ int fs_repo_write_config_file(char* path, struct RepoConfig* config);
* @param config the information for the config file
* @returns true(1) on success
*/
int fs_repo_init(char* repo_path, struct RepoConfig* config);
int ipfs_repo_fsrepo_new(char* repo_path, struct RepoConfig* config, struct FSRepo** fs_repo);
/***
* Free all resources used by this struct
* @param repo the repo to clean up
* @returns true(1) on success
*/
int ipfs_repo_fsrepo_free(struct FSRepo* config);
/***
* Initialize a new repo with the specified configuration
* @param config the information in order to build the repo
* @returns true(1) on success
*/
int ipfs_repo_fsrepo_init(struct FSRepo* config);
#endif /* fs_repo_h */

View file

@ -0,0 +1,30 @@
#ifndef __FS_REPO_LMDB_DATASTORE_H__
#define __FS_REPO_LMDB_DATASTORE_H__
#include "ipfs/repo/config/datastore.h"
/***
* Places the LMDB methods into the datastore's function pointers
* @param datastore the datastore to fill
* @returns true(1) on success;
*/
int repo_fsrepo_lmdb_cast(struct Datastore* datastore);
/**
* Open an lmdb database with the given parameters.
* Note: for now, the parameters are not used
* @param argc number of parameters in the following array
* @param argv an array of parameters
*/
int repo_fsrepro_lmdb_open(int argc, char** argv, struct Datastore* datastore);
/***
* Close an LMDB database
* NOTE: for now, argc and argv are not used
* @param argc number of parameters in the argv array
* @param argv parameters to be passed in
* @param datastore the datastore struct that contains information about the opened database
*/
int repo_fsrepo_lmdb_close(int argc, char** argv, struct Datastore* datastore);
#endif

View file

@ -4,13 +4,14 @@
#include <sys/types.h>
#include <pwd.h>
#include <unistd.h>
#include <stdio.h>
/**
* get an environment varible from the os
* @param variable the variable to look for
* @returns the results
*/
char* os_utils_getenv(char* variable) {
char* os_utils_getenv(const char* variable) {
return getenv(variable);
}
@ -30,22 +31,36 @@ char* os_utils_get_homedir() {
* @param results where to put the results
* @param max_len throw an error if the total is longer than max_len
*/
int os_utils_filepath_join(char* root, char* extension, char* results, unsigned long max_len) {
//TODO: implement slash checks
int os_utils_filepath_join(const char* root, const char* extension, char* results, unsigned long max_len) {
if (strlen(root) + strlen(extension) + 1 > max_len)
return 0;
strncpy(results, root, strlen(root) + 1);
// one of these should have a slash. If not, add one
if (root[strlen(root)-1] != '/' && extension[0] != '/') {
results[strlen(root)] = '/';
results[strlen(root)+1] = 0;
}
strncat(results, extension, strlen(extension)+1);
return 1;
}
int os_utils_file_exists(char* file_name) {
int os_utils_file_exists(const char* file_name) {
if (access(file_name, F_OK) != -1)
return 1;
return 0;
}
int os_utils_directory_writeable(char* path) {
int os_utils_directory_writeable(const char* path) {
int result = access(path, W_OK);
return result == 0;
}
int os_utils_file_size(const char* path) {
// open file
FILE* in_file = fopen(path, "r");
// determine size
fseek(in_file, 0L, SEEK_END);
size_t file_size = ftell(in_file);
fclose(in_file);
return file_size;
}

View file

@ -1,5 +1,5 @@
CC = gcc
CFLAGS = -O0 -I../../include -I../../../c-libp2p/include
CFLAGS = -O0 -I../../include -I../../../c-libp2p/include -I../../../c-multihash/include
ifdef DEBUG
CFLAGS += -g3

View file

@ -78,7 +78,7 @@ int repo_config_get_file_name(char* path, char** result) {
if (result == NULL)
return 0;
return os_utils_filepath_join(path, "/config", *result, max_len);
return os_utils_filepath_join(path, "config", *result, max_len);
}
/***
@ -88,9 +88,8 @@ int repo_config_get_file_name(char* path, char** result) {
* @returns true(1) on success, otherwise 0
*/
int repo_config_init(struct RepoConfig* config, unsigned int num_bits_for_keypair, char* repo_path) {
// identity
int retVal = repo_config_identity_new(&(config->identity), num_bits_for_keypair);
int retVal = repo_config_identity_init(&(config->identity), num_bits_for_keypair);
if (retVal == 0)
return 0;
@ -100,7 +99,7 @@ int repo_config_init(struct RepoConfig* config, unsigned int num_bits_for_keypai
return 0;
// datastore
retVal = repo_config_datastore_init(&(config->datastore), repo_path);
retVal = ipfs_repo_config_datastore_init(&(config->datastore), repo_path);
if (retVal == 0)
return 0;
@ -139,10 +138,30 @@ int repo_config_init(struct RepoConfig* config, unsigned int num_bits_for_keypai
return 1;
}
int repo_config_free(struct RepoConfig* config) {
repo_config_bootstrap_peers_free(&(config->peer_addresses));
repo_config_datastore_free(&(config->datastore));
repo_config_addresses_free(&(config->addresses));
/***
* Initialize memory for a RepoConfig struct
* @param config the structure to initialize
* @returns true(1) on success
*/
int ipfs_repo_config_new(struct RepoConfig** config) {
*config = (struct RepoConfig*)malloc(sizeof(struct RepoConfig));
if (*config == NULL)
return 0;
return 1;
}
/**
* Free resources
* @param config the struct to be freed
* @returns true(1) on success
*/
int ipfs_repo_config_free(struct RepoConfig* config) {
if (config != NULL) {
repo_config_bootstrap_peers_free(&(config->peer_addresses));
//ipfs_repo_config_datastore_free(&(config->datastore));
repo_config_addresses_free(&(config->addresses));
free(config);
}
return 1;
}

View file

@ -17,11 +17,11 @@
* @param datastore the struct to initialize
* @returns true(1) on success
*/
int repo_config_datastore_init(struct Datastore* datastore, char* config_root) {
int ipfs_repo_config_datastore_init(struct Datastore* datastore, char* config_root) {
unsigned long stringLength = strlen(config_root) + 12;
datastore->path = malloc(sizeof(char) * stringLength);
os_utils_filepath_join(config_root, "/datastore", datastore->path, stringLength);
datastore->type = "leveldb";
os_utils_filepath_join(config_root, "datastore", datastore->path, stringLength);
datastore->type = "lmdb";
datastore->storage_max = "10GB";
datastore->storage_gc_watermark = 90;
datastore->gc_period = "1h";
@ -30,12 +30,30 @@ int repo_config_datastore_init(struct Datastore* datastore, char* config_root) {
return 1;
}
/***
* initialize the structure of the datastore
* @param datastore the struct to initialize
* @returns true(1) on success
*/
int ipfs_repo_config_datastore_new(struct Datastore** datastore) {
*datastore = malloc(sizeof(struct Datastore));
if (*datastore == NULL)
return 0;
(*datastore)->path = NULL;
return 1;
}
/***
* deallocate the memory and clear resources from a datastore_init
* @param datastore the struct to deallocate
* @returns true(1)
*/
int repo_config_datastore_free(struct Datastore* datastore) {
//free(datastore);
int ipfs_repo_config_datastore_free(struct Datastore* datastore) {
if (datastore != NULL)
{
if (datastore->path != NULL)
free(datastore->path);
free(datastore);
}
return 1;
}

View file

@ -8,36 +8,104 @@
#include "ipfs/repo/config/identity.h"
#include "libp2p/crypto/rsa.h"
#include "libp2p/peerutils.h"
#include "libp2p/crypto/encoding/base64.h"
#include "libp2p/crypto/encoding/x509.h"
/**
* Builds the Peer ID using the private key, and places it in the identity->peer_id
* @param identity Where to get the DER of the private key
* @returns true(1) on success
*/
int repo_config_identity_build_peer_id(struct Identity* identity) {
// ic key and PeerID
char hash[32];
ID_FromPK_non_null_terminated(hash, identity->private_key.der, identity->private_key.der_length);
// peer id is multihashed
size_t sz = 255;
char results[sz];
if (PrettyID(results, &sz, hash, 32) == 0)
return 0;
// copy it into the structure
identity->peer_id = (char*)malloc(sz + 1);
if (identity->peer_id == NULL)
return 0;
strncpy(identity->peer_id, results, sz);
identity->peer_id[sz] = 0;
return 1;
}
/***
* public methods
*/
/***
* initializes a new Identity
* Initializes a new Identity. NOTE: This builds a new private/public key pair
* @param identity the identity to fill
* @param num_bits_for_keypair the number of bits for the keypair
* @returns true(1) on success, false(0) otherwise
*/
int repo_config_identity_new(struct Identity* identity, unsigned long num_bits_for_keypair) {
int repo_config_identity_init(struct Identity* identity, unsigned long num_bits_for_keypair) {
if (num_bits_for_keypair < 1024)
return 0;
// generate the private key (& public)
if (!libp2p_crypto_rsa_generate_keypair( &(identity->private_key), num_bits_for_keypair))
return 0;
// now the private key (in DER format) is in identity->private_key->der;
// and the public key (also in DER format) is in identity->private_key->public_key_der;
//TODO: the public key needs to be "pretty printed" and put in a multihash
repo_config_identity_build_peer_id(identity);
return 1;
}
int repo_config_identity_free(struct Identity* identity) {
if (identity->private_key.public_key_der != NULL)
free(identity->private_key.public_key_der);
if (identity->private_key.der != NULL)
free(identity->private_key.der);
return 0;
int repo_config_identity_new(struct Identity** identity) {
*identity = (struct Identity*)malloc(sizeof(struct Identity));
if (*identity == NULL)
return 0;
memset(*identity, 0, sizeof(struct Identity));
return 1;
}
int repo_config_identity_free(struct Identity* identity) {
if (identity != NULL) {
if (identity->private_key.public_key_der != NULL)
free(identity->private_key.public_key_der);
if (identity->private_key.der != NULL)
free(identity->private_key.der);
free(identity);
}
return 1;
}
/***
* Build a RsaPrivateKey struct from a base64 string of the private key
* @param identity where to put the new struct
* @param base64 the null terminated base 64 encoded private key in DER format
* @returns true(1) on success
*/
int repo_config_identity_build_private_key(struct Identity* identity, const char* base64) {
size_t decoded_size = libp2p_crypto_encoding_base64_decode_size(strlen(base64));
unsigned char decoded[decoded_size];
int retVal = libp2p_crypto_encoding_base64_decode(base64, strlen(base64), decoded, decoded_size, &decoded_size);
if (retVal == 0)
return 0;
// now convert DER to RsaPrivateKey
retVal = libp2p_crypto_encoding_x509_der_to_private_key(decoded, decoded_size, &identity->private_key);
if (retVal == 0)
return 0;
// now build the private key DER
retVal = libp2p_crypto_rsa_private_key_fill_public_key(&identity->private_key);
if (retVal == 0)
return 0;
// now build PeerID
retVal = repo_config_identity_build_peer_id(identity);
return retVal;
}

View file

@ -1,5 +1,5 @@
CC = gcc
CFLAGS = -O0 -I../../include -I../../../c-libp2p/include
CFLAGS = -O0 -I../../include -I../../../c-libp2p/include -I../../../lmdb/libraries/liblmdb
ifdef DEBUG
CFLAGS += -g3
@ -7,7 +7,7 @@ endif
LFLAGS =
DEPS =
OBJS = fs_repo.o
OBJS = fs_repo.o jsmn.o lmdb_datastore.o
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)

View file

@ -8,8 +8,12 @@
#include "libp2p/crypto/encoding/base64.h"
#include "ipfs/repo/config/datastore.h"
#include "ipfs/repo/fsrepo/fs_repo.h"
#include "ipfs/os/utils.h"
#include "ipfs/repo/fsrepo/lmdb_datastore.h"
#include "jsmn.h"
/**
* private methods
*/
@ -28,7 +32,7 @@ int repo_config_write_config_file(char* full_filename, struct RepoConfig* config
fprintf(out_file, "{\n");
fprintf(out_file, " \"Identity\": {\n");
fprintf(out_file, " \"PeerID\": \"%s\",\n", config->identity.peer_id);
// TODO: print correct format of private key
// print correct format of private key
// first base 64 it
size_t encoded_size = libp2p_crypto_encoding_base64_encode_size(config->identity.private_key.der_length);
unsigned char encoded_buffer[encoded_size + 1];
@ -60,7 +64,7 @@ int repo_config_write_config_file(char* full_filename, struct RepoConfig* config
fprintf(out_file, " ],\n");
fprintf(out_file, " \"API\": \"%s\",\n", config->addresses.api);
fprintf(out_file, " \"Gateway\": \"%s\"\n", config->addresses.gateway);
fprintf(out_file, " }\n \"Mounts\": {\n");
fprintf(out_file, " },\n \"Mounts\": {\n");
fprintf(out_file, " \"IPFS\": \"%s\",\n", config->mounts.ipfs);
fprintf(out_file, " \"IPNS\": \"%s\",\n", config->mounts.ipns);
fprintf(out_file, " \"FuseAllowOther\": %s\n", "false");
@ -87,7 +91,7 @@ int repo_config_write_config_file(char* full_filename, struct RepoConfig* config
if (i < config->gateway.http_headers.num_elements - 1)
fprintf(out_file, ",\n");
else
fprintf(out_file, "\n");
fprintf(out_file, "\n },\n");
}
fprintf(out_file, " \"RootRedirect\": \"%s\"\n", config->gateway.root_redirect);
fprintf(out_file, " \"Writable\": %s\n", config->gateway.writable ? "true" : "false");
@ -101,13 +105,16 @@ int repo_config_write_config_file(char* full_filename, struct RepoConfig* config
}
/**
* constructs the FSRepo struct. Basically fills in the FSRepo.path
* Remember: the path must be freed
* constructs the FSRepo struct.
* Remember: ipfs_repo_fsrepo_free must be called
* @param repo_path the path to the repo
* @param config the optional config file. NOTE: if passed, fsrepo_free will free resources of the RepoConfig.
* @param repo the struct to fill in
* @returns false(0) if something bad happened, otherwise true(1)
*/
int fs_repo_new_fs_repo(char* repo_path, struct FSRepo* repo) {
int ipfs_repo_fsrepo_new(char* repo_path, struct RepoConfig* config, struct FSRepo** repo) {
*repo = (struct FSRepo*)malloc(sizeof(struct FSRepo));
if (repo_path == NULL) {
// get the user's home directory
char* home_dir = os_utils_get_homedir();
@ -115,11 +122,25 @@ int fs_repo_new_fs_repo(char* repo_path, struct FSRepo* repo) {
unsigned long newPathLen = strlen(home_dir) + strlen(default_subdir) + 2; // 1 for slash and 1 for end
char* newPath = malloc(sizeof(char) * newPathLen);
os_utils_filepath_join(os_utils_get_homedir(), default_subdir, newPath, newPathLen);
repo->path = newPath;
(*repo)->path = newPath;
} else {
int len = strlen(repo_path) + 1;
repo->path = (char*)malloc(len);
strncpy(repo->path, repo_path, len);
(*repo)->path = (char*)malloc(len);
strncpy((*repo)->path, repo_path, len);
}
// allocate other structures
if (config != NULL)
(*repo)->config = config;
else {
if (ipfs_repo_config_new(&((*repo)->config)) == 0) {
free(repo_path);
return 0;
}
}
if (ipfs_repo_config_datastore_new(&((*repo)->data_store)) == 0) {
free(repo_path);
ipfs_repo_config_free((*repo)->config);
return 0;
}
return 1;
}
@ -129,8 +150,13 @@ int fs_repo_new_fs_repo(char* repo_path, struct FSRepo* repo) {
* @param repo the struct to clean up
* @returns true(1) on success
*/
int fs_repo_free(struct FSRepo* repo) {
free(repo->path);
int ipfs_repo_fsrepo_free(struct FSRepo* repo) {
if (repo != NULL) {
free(repo->path);
ipfs_repo_config_free(repo->config);
ipfs_repo_config_datastore_free(repo->data_store);
free(repo);
}
return 1;
}
@ -175,24 +201,218 @@ int repo_check_initialized(char* full_path) {
}
/***
* opens the datastore and puts it in the FSRepo struct
* Reads the file, placing its contents in buffer
* NOTE: this allocates memory for buffer, and should be freed
* @param path the path to the config file
* @param buffer where to put the contents
* @returns true(1) on success
*/
int _read_file(const char* path, char** buffer) {
int file_size = os_utils_file_size(path);
if (file_size <= 0)
return 0;
// allocate memory
*buffer = malloc(file_size + 1);
if (*buffer == NULL) {
return 0;
}
memset(*buffer, 0, file_size + 1);
// open file
FILE* in_file = fopen(path, "r");
// read data
fread(*buffer, file_size, 1, in_file);
// cleanup
fclose(in_file);
return 1;
}
/**
* Find the position of a key
* @param data the string that contains the json
* @param tokens the tokens of the parsed string
* @param tok_length the number of tokens there are
* @param tag what we're looking for
* @returns the position of the requested token in the array, or -1
*/
int _find_token(const char* data, const jsmntok_t* tokens, int tok_length, int start_from, const char* tag) {
for(int i = start_from; i < tok_length; i++) {
jsmntok_t curr_token = tokens[i];
if ( curr_token.type == JSMN_STRING) {
// convert to string
int str_len = curr_token.end - curr_token.start;
char str[str_len + 1];
strncpy(str, &data[curr_token.start], str_len );
str[str_len] = 0;
if (strcmp(str, tag) == 0)
return i;
}
}
return -1;
}
/**
* Retrieves the value of a key / value pair from the JSON data
* @param data the full JSON string
* @param tokens the array of tokens
* @param tok_length the number of tokens
* @param search_from start search from this token onward
* @param tag what to search for
* @param result where to put the result. NOTE: allocates memory that must be freed
* @returns true(1) on success
*/
int _get_json_string_value(char* data, const jsmntok_t* tokens, int tok_length, int search_from, const char* tag, char** result) {
int pos = _find_token(data, tokens, tok_length, search_from, tag);
if (pos < 0)
return 0;
jsmntok_t curr_token = tokens[pos+1];
if (curr_token.type == JSMN_PRIMITIVE) {
// a null
*result = NULL;
}
if (curr_token.type != JSMN_STRING)
return 0;
// allocate memory
int str_len = curr_token.end - curr_token.start;
*result = malloc(sizeof(char) * str_len + 1);
// copy in the string
strncpy(*result, &data[curr_token.start], str_len);
(*result)[str_len] = 0;
return 1;
}
/**
* Retrieves the value of a key / value pair from the JSON data
* @param data the full JSON string
* @param tokens the array of tokens
* @param tok_length the number of tokens
* @param search_from start search from this token onward
* @param tag what to search for
* @param result where to put the result
* @returns true(1) on success
*/
int _get_json_int_value(char* data, const jsmntok_t* tokens, int tok_length, int search_from, const char* tag, int* result) {
int pos = _find_token(data, tokens, tok_length, search_from, tag);
if (pos < 0)
return 0;
jsmntok_t curr_token = tokens[pos+1];
if (curr_token.type != JSMN_PRIMITIVE)
return 0;
// allocate memory
int str_len = curr_token.end - curr_token.start;
char str[str_len + 1];
// copy in the string
strncpy(str, &data[curr_token.start], str_len);
str[str_len] = 0;
if (strcmp(str, "true") == 0)
*result = 1;
else if (strcmp(str, "false") == 0)
*result = 0;
else if (strcmp(str, "null") == 0) // what should we do here?
*result = 0;
else // its a real number
*result = atoi(str);
return 1;
}
/***
* Opens the config file and puts the data into the FSRepo struct
* @param repo the FSRepo struct
* @returns 0 on failure, otherwise 1
*/
int fs_repo_open_config(struct FSRepo* repo) {
//TODO: open config file
//TODO: read into the FSRepo struct
int retVal;
char* data;
size_t full_filename_length = strlen(repo->path) + 8;
char full_filename[full_filename_length];
retVal = os_utils_filepath_join(repo->path, "config", full_filename, full_filename_length);
if (retVal == 0)
return 0;
retVal = _read_file(full_filename, &data);
// parse the data
jsmn_parser parser;
jsmn_init(&parser);
int num_tokens = 256;
jsmntok_t tokens[num_tokens];
num_tokens = jsmn_parse(&parser, data, strlen(data), tokens, 256);
if (num_tokens <= 0) {
free(data);
return 0;
}
// fill FSRepo struct
repo->config = malloc(sizeof(struct RepoConfig));
// Identity
int curr_pos = _find_token(data, tokens, num_tokens, 0, "Identity");
if (curr_pos < 0) {
free(data);
return 0;
}
// the next should be the array, then string "PeerID"
_get_json_string_value(data, tokens, num_tokens, curr_pos, "PeerID", &repo->config->identity.peer_id);
char* priv_key_base64;
// then PrivKey
_get_json_string_value(data, tokens, num_tokens, curr_pos, "PrivKey", &priv_key_base64);
retVal = repo_config_identity_build_private_key(&repo->config->identity, priv_key_base64);
if (retVal == 0) {
free(data);
free(priv_key_base64);
return 0;
}
// now the datastore
int datastore_position = _find_token(data, tokens, num_tokens, 0, "Datastore");
_get_json_string_value(data, tokens, num_tokens, curr_pos, "Type", &repo->config->datastore.type);
_get_json_string_value(data, tokens, num_tokens, curr_pos, "Path", &repo->config->datastore.path);
_get_json_string_value(data, tokens, num_tokens, curr_pos, "StorageMax", &repo->config->datastore.storage_max);
_get_json_int_value(data, tokens, num_tokens, curr_pos, "StorageGCWatermark", &repo->config->datastore.storage_gc_watermark);
_get_json_string_value(data, tokens, num_tokens, curr_pos, "GCPeriod", &repo->config->datastore.gc_period);
_get_json_string_value(data, tokens, num_tokens, curr_pos, "Params", &repo->config->datastore.params);
_get_json_int_value(data, tokens, num_tokens, curr_pos, "NoSync", &repo->config->datastore.no_sync);
_get_json_int_value(data, tokens, num_tokens, curr_pos, "HashOnRead", &repo->config->datastore.hash_on_read);
_get_json_int_value(data, tokens, num_tokens, curr_pos, "BloomFilterSize", &repo->config->datastore.bloom_filter_size);
// free the memory used reading the json file
free(data);
free(priv_key_base64);
return 1;
}
/***
* set function pointers in the datastore struct to lmdb
* @param repo contains the information
* @returns true(1) on success
*/
int fs_repo_setup_lmdb_datastore(struct FSRepo* repo) {
return repo_fsrepo_lmdb_cast(repo->data_store);
}
/***
* opens the repo's datastore, and puts a reference to it in the FSRepo struct
* @param repo the FSRepo struct
* @returns 0 on failure, otherwise 1
*/
int fs_repo_open_datastore(struct FSRepo* repo) {
//TODO: this
return 1;
int argc = 0;
char** argv = NULL;
// copy struct from config area to this area
repo->data_store = &repo->config->datastore;
if (strncmp(repo->data_store->type, "lmdb", 4) == 0) {
// this is a LightningDB. Open it.
int retVal = fs_repo_setup_lmdb_datastore(repo);
if (retVal == 0)
return 0;
} else {
// add new datastore types here
return 0;
}
int retVal = repo->data_store->datastore_open(argc, argv, repo->data_store);
// do specific datastore cleanup here if needed
return retVal;
}
/**
@ -201,22 +421,13 @@ int fs_repo_open_datastore(struct FSRepo* repo) {
/**
* opens a fsrepo
* @param repo_path the path to the repo
* @param repo where to store the repo info
* @param repo the repo struct. Should contain the path. This method will do the rest
* @return 0 if there was a problem, otherwise 1
*/
int fs_repo_open(char* repo_path, struct FSRepo* repo) {
int ipfs_repo_fsrepo_open(struct FSRepo* repo) {
//TODO: lock
// get the path set in the repo struct
int retVal = fs_repo_new_fs_repo(repo_path, repo);
if (retVal == 0) {
fs_repo_free(repo);
return 0;
}
// check if initialized
if (!repo_check_initialized(repo->path)) {
fs_repo_free(repo);
return 0;
}
//TODO: lock the file (remember to unlock)
@ -224,12 +435,11 @@ int fs_repo_open(char* repo_path, struct FSRepo* repo) {
//TODO: make sure the directory is writable
//TODO: open the config
if (!fs_repo_open_config(repo)) {
fs_repo_free(repo);
return 0;
}
//TODO: open the datastore. Note: the config file has the datastore type
// open the datastore
if (!fs_repo_open_datastore(repo)) {
fs_repo_free(repo);
return 0;
}
@ -253,14 +463,14 @@ int fs_repo_is_initialized(char* repo_path) {
* @param config the information for the config file
* @returns true(1) on success
*/
int fs_repo_init(char* path, struct RepoConfig* config) {
int ipfs_repo_fsrepo_init(struct FSRepo* repo) {
// TODO: Do a lock so 2 don't do this at the same time
// return error if this has already been done
if (fs_repo_is_initialized_unsynced(path))
if (fs_repo_is_initialized_unsynced(repo->path))
return 0;
int retVal = fs_repo_write_config_file(path, config);
int retVal = fs_repo_write_config_file(repo->path, repo->config);
if (retVal == 0)
return 0;

313
repo/fsrepo/jsmn.c Normal file
View file

@ -0,0 +1,313 @@
#include "jsmn.h"
/**
* Allocates a fresh unused token from the token pull.
*/
static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
jsmntok_t *tokens, size_t num_tokens) {
jsmntok_t *tok;
if (parser->toknext >= num_tokens) {
return NULL;
}
tok = &tokens[parser->toknext++];
tok->start = tok->end = -1;
tok->size = 0;
#ifdef JSMN_PARENT_LINKS
tok->parent = -1;
#endif
return tok;
}
/**
* Fills token type and boundaries.
*/
static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
int start, int end) {
token->type = type;
token->start = start;
token->end = end;
token->size = 0;
}
/**
* Fills next available token with JSON primitive.
*/
static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
size_t len, jsmntok_t *tokens, size_t num_tokens) {
jsmntok_t *token;
int start;
start = parser->pos;
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
switch (js[parser->pos]) {
#ifndef JSMN_STRICT
/* In strict mode primitive must be followed by "," or "}" or "]" */
case ':':
#endif
case '\t' : case '\r' : case '\n' : case ' ' :
case ',' : case ']' : case '}' :
goto found;
}
if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
parser->pos = start;
return JSMN_ERROR_INVAL;
}
}
#ifdef JSMN_STRICT
/* In strict mode primitive must be followed by a comma/object/array */
parser->pos = start;
return JSMN_ERROR_PART;
#endif
found:
if (tokens == NULL) {
parser->pos--;
return 0;
}
token = jsmn_alloc_token(parser, tokens, num_tokens);
if (token == NULL) {
parser->pos = start;
return JSMN_ERROR_NOMEM;
}
jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
#ifdef JSMN_PARENT_LINKS
token->parent = parser->toksuper;
#endif
parser->pos--;
return 0;
}
/**
* Fills next token with JSON string.
*/
static int jsmn_parse_string(jsmn_parser *parser, const char *js,
size_t len, jsmntok_t *tokens, size_t num_tokens) {
jsmntok_t *token;
int start = parser->pos;
parser->pos++;
/* Skip starting quote */
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
char c = js[parser->pos];
/* Quote: end of string */
if (c == '\"') {
if (tokens == NULL) {
return 0;
}
token = jsmn_alloc_token(parser, tokens, num_tokens);
if (token == NULL) {
parser->pos = start;
return JSMN_ERROR_NOMEM;
}
jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
#ifdef JSMN_PARENT_LINKS
token->parent = parser->toksuper;
#endif
return 0;
}
/* Backslash: Quoted symbol expected */
if (c == '\\' && parser->pos + 1 < len) {
int i;
parser->pos++;
switch (js[parser->pos]) {
/* Allowed escaped symbols */
case '\"': case '/' : case '\\' : case 'b' :
case 'f' : case 'r' : case 'n' : case 't' :
break;
/* Allows escaped symbol \uXXXX */
case 'u':
parser->pos++;
for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
/* If it isn't a hex character we have an error */
if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
(js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
(js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
parser->pos = start;
return JSMN_ERROR_INVAL;
}
parser->pos++;
}
parser->pos--;
break;
/* Unexpected symbol */
default:
parser->pos = start;
return JSMN_ERROR_INVAL;
}
}
}
parser->pos = start;
return JSMN_ERROR_PART;
}
/**
* Parse JSON string and fill tokens.
*/
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
jsmntok_t *tokens, unsigned int num_tokens) {
int r;
int i;
jsmntok_t *token;
int count = parser->toknext;
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
char c;
jsmntype_t type;
c = js[parser->pos];
switch (c) {
case '{': case '[':
count++;
if (tokens == NULL) {
break;
}
token = jsmn_alloc_token(parser, tokens, num_tokens);
if (token == NULL)
return JSMN_ERROR_NOMEM;
if (parser->toksuper != -1) {
tokens[parser->toksuper].size++;
#ifdef JSMN_PARENT_LINKS
token->parent = parser->toksuper;
#endif
}
token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
token->start = parser->pos;
parser->toksuper = parser->toknext - 1;
break;
case '}': case ']':
if (tokens == NULL)
break;
type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
#ifdef JSMN_PARENT_LINKS
if (parser->toknext < 1) {
return JSMN_ERROR_INVAL;
}
token = &tokens[parser->toknext - 1];
for (;;) {
if (token->start != -1 && token->end == -1) {
if (token->type != type) {
return JSMN_ERROR_INVAL;
}
token->end = parser->pos + 1;
parser->toksuper = token->parent;
break;
}
if (token->parent == -1) {
if(token->type != type || parser->toksuper == -1) {
return JSMN_ERROR_INVAL;
}
break;
}
token = &tokens[token->parent];
}
#else
for (i = parser->toknext - 1; i >= 0; i--) {
token = &tokens[i];
if (token->start != -1 && token->end == -1) {
if (token->type != type) {
return JSMN_ERROR_INVAL;
}
parser->toksuper = -1;
token->end = parser->pos + 1;
break;
}
}
/* Error if unmatched closing bracket */
if (i == -1) return JSMN_ERROR_INVAL;
for (; i >= 0; i--) {
token = &tokens[i];
if (token->start != -1 && token->end == -1) {
parser->toksuper = i;
break;
}
}
#endif
break;
case '\"':
r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
if (r < 0) return r;
count++;
if (parser->toksuper != -1 && tokens != NULL)
tokens[parser->toksuper].size++;
break;
case '\t' : case '\r' : case '\n' : case ' ':
break;
case ':':
parser->toksuper = parser->toknext - 1;
break;
case ',':
if (tokens != NULL && parser->toksuper != -1 &&
tokens[parser->toksuper].type != JSMN_ARRAY &&
tokens[parser->toksuper].type != JSMN_OBJECT) {
#ifdef JSMN_PARENT_LINKS
parser->toksuper = tokens[parser->toksuper].parent;
#else
for (i = parser->toknext - 1; i >= 0; i--) {
if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
if (tokens[i].start != -1 && tokens[i].end == -1) {
parser->toksuper = i;
break;
}
}
}
#endif
}
break;
#ifdef JSMN_STRICT
/* In strict mode primitives are: numbers and booleans */
case '-': case '0': case '1' : case '2': case '3' : case '4':
case '5': case '6': case '7' : case '8': case '9':
case 't': case 'f': case 'n' :
/* And they must not be keys of the object */
if (tokens != NULL && parser->toksuper != -1) {
jsmntok_t *t = &tokens[parser->toksuper];
if (t->type == JSMN_OBJECT ||
(t->type == JSMN_STRING && t->size != 0)) {
return JSMN_ERROR_INVAL;
}
}
#else
/* In non-strict mode every unquoted value is a primitive */
default:
#endif
r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
if (r < 0) return r;
count++;
if (parser->toksuper != -1 && tokens != NULL)
tokens[parser->toksuper].size++;
break;
#ifdef JSMN_STRICT
/* Unexpected char in strict mode */
default:
return JSMN_ERROR_INVAL;
#endif
}
}
if (tokens != NULL) {
for (i = parser->toknext - 1; i >= 0; i--) {
/* Unmatched opened object or array */
if (tokens[i].start != -1 && tokens[i].end == -1) {
return JSMN_ERROR_PART;
}
}
}
return count;
}
/**
* Creates a new parser based over a given buffer with an array of tokens
* available.
*/
void jsmn_init(jsmn_parser *parser) {
parser->pos = 0;
parser->toknext = 0;
parser->toksuper = -1;
}

76
repo/fsrepo/jsmn.h Normal file
View file

@ -0,0 +1,76 @@
#ifndef __JSMN_H_
#define __JSMN_H_
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* JSON type identifier. Basic types are:
* o Object
* o Array
* o String
* o Other primitive: number, boolean (true/false) or null
*/
typedef enum {
JSMN_UNDEFINED = 0,
JSMN_OBJECT = 1,
JSMN_ARRAY = 2,
JSMN_STRING = 3,
JSMN_PRIMITIVE = 4
} jsmntype_t;
enum jsmnerr {
/* Not enough tokens were provided */
JSMN_ERROR_NOMEM = -1,
/* Invalid character inside JSON string */
JSMN_ERROR_INVAL = -2,
/* The string is not a full JSON packet, more bytes expected */
JSMN_ERROR_PART = -3
};
/**
* JSON token description.
* type type (object, array, string etc.)
* start start position in JSON data string
* end end position in JSON data string
*/
typedef struct {
jsmntype_t type;
int start;
int end;
int size;
#ifdef JSMN_PARENT_LINKS
int parent;
#endif
} jsmntok_t;
/**
* JSON parser. Contains an array of token blocks available. Also stores
* the string being parsed now and current position in that string
*/
typedef struct {
unsigned int pos; /* offset in the JSON string */
unsigned int toknext; /* next token to allocate */
int toksuper; /* superior token node, e.g parent object or array */
} jsmn_parser;
/**
* Create JSON parser over an array of tokens
*/
void jsmn_init(jsmn_parser *parser);
/**
* Run JSON parser. It parses a JSON data string into and array of tokens, each describing
* a single JSON object.
*/
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
jsmntok_t *tokens, unsigned int num_tokens);
#ifdef __cplusplus
}
#endif
#endif /* __JSMN_H_ */

View file

@ -0,0 +1,60 @@
/***
* Here are the wrappers for the lightning database
*/
#include <stdlib.h>
#include "lmdb.h"
#include "ipfs/repo/fsrepo/lmdb_datastore.h"
/**
* Open an lmdb database with the given parameters.
* Note: for now, the parameters are not used
* @param argc number of parameters in the following array
* @param argv an array of parameters
*/
int repo_fsrepro_lmdb_open(int argc, char** argv, struct Datastore* datastore) {
// create environment
struct MDB_env* mdb_env;
int retVal = mdb_env_create(&mdb_env);
if (retVal < 0) {
mdb_env_close(mdb_env);
return 0;
}
// open the environment
retVal = mdb_env_open(mdb_env, datastore->path, 0, 755);
if (retVal < 0) {
mdb_env_close(mdb_env);
return 0;
}
datastore->handle = (void*)mdb_env;
return 1;
}
/***
* Close an LMDB database
* NOTE: for now, argc and argv are not used
* @param argc number of parameters in the argv array
* @param argv parameters to be passed in
* @param datastore the datastore struct that contains information about the opened database
*/
int repo_fsrepo_lmdb_close(int argc, char** argv, struct Datastore* datastore) {
struct MDB_env* mdb_env = (struct MDB_env*)datastore->handle;
mdb_env_close(mdb_env);
free(mdb_env);
return 1;
}
/***
* Places the LMDB methods into the datastore's function pointers
* @param datastore the datastore to fill
* @returns true(1) on success;
*/
int repo_fsrepo_lmdb_cast(struct Datastore* datastore) {
datastore->datastore_open = &repo_fsrepro_lmdb_open;
datastore->datastore_close = &repo_fsrepo_lmdb_close;
return 1;
}

View file

@ -1,10 +1,10 @@
CC = gcc
CFLAGS = -O0 -I../include -I../../c-libp2p/include -I../../c-multihash/include -I../../c-multiaddr/ -g3
LFLAGS = -L../../c-libp2p -L../../c-multihash -L../../c-multiaddr -lp2p -lm -lmultihash -lmultiaddr
LFLAGS = -L../../c-libp2p -L../../c-multihash -L../../c-multiaddr -lp2p -lm -lmultihash -lmultiaddr -lpthread
DEPS = cmd/ipfs/test_init.h repo/test_repo_bootstrap_peers.h repo/test_repo_config.h repo/test_repo_identity.h cid/test_cid.h
OBJS = testit.o ../cmd/ipfs/init.o ../commands/argument.o ../commands/command_option.o \
../commands/command.o ../commands/cli/parse.o ../core/builder.o ../repo/fsrepo/fs_repo.o \
../repo/fsrepo/fs_repo.o ../repo//config/config.o ../os/utils.o ../repo/config/identity.o \
../repo/fsrepo/jsmn.o ../repo/fsrepo/lmdb_datastore.o ../repo/config/config.o ../os/utils.o ../repo/config/identity.o \
../repo/config/bootstrap_peers.o ../repo/config/datastore.o ../repo/config/gateway.o \
../repo/config/addresses.o ../repo/config/swarm.o ../repo/config/peer.o \
../thirdparty/ipfsaddr/ipfs_addr.o ../cid/cid.o ../multibase/multibase.o
@ -13,7 +13,7 @@ OBJS = testit.o ../cmd/ipfs/init.o ../commands/argument.o ../commands/command_op
$(CC) -c -o $@ $< $(CFLAGS)
test_ipfs: $(OBJS)
$(CC) -o $@ $^ $(LFLAGS)
$(CC) -o $@ $^ $(LFLAGS) ../../lmdb/libraries/liblmdb/liblmdb.a
all: test_ipfs

View file

@ -6,7 +6,7 @@
#include "ipfs/cid/cid.h"
#include "ipfs/multibase/multibase.h"
#include "libp2p/crypto/hashing/sha256.h"
#include "libp2p/crypto/sha256.h"
int test_cid_new_free() {

View file

@ -13,6 +13,7 @@
//#include <string.h>
int test_init_new_installation() {
unlink("/tmp/.ipfs/config");
// do the minimum to get the .ipfs directory structure and config file built
struct Request request;
int retVal = ipfs_cmd_ipfs_init_command_new( &request.cmd );

View file

@ -14,38 +14,42 @@
#include "ipfs/os/utils.h"
int test_repo_config_init() {
struct RepoConfig repoConfig;
int retVal = repo_config_init(&repoConfig, 2048, "/Users/JohnJones/.ipfs");
struct RepoConfig* repoConfig;
int retVal = ipfs_repo_config_new(&repoConfig);
if (retVal == 0)
return 0;
retVal = repo_config_init(repoConfig, 2048, "/Users/JohnJones/.ipfs");
if (retVal == 0)
return 0;
// now tear it apart to check for anything broken
// addresses
retVal = strncmp(repoConfig.addresses.api, "/ip4/127.0.0.1/tcp/5001", 23);
retVal = strncmp(repoConfig->addresses.api, "/ip4/127.0.0.1/tcp/5001", 23);
if (retVal != 0)
return 0;
retVal = strncmp(repoConfig.addresses.gateway, "/ip4/127.0.0.1/tcp/8080", 23);
retVal = strncmp(repoConfig->addresses.gateway, "/ip4/127.0.0.1/tcp/8080", 23);
if (retVal != 0)
return 0;
if (repoConfig.addresses.swarm.num_addresses != 2)
if (repoConfig->addresses.swarm.num_addresses != 2)
return 0;
retVal = strncmp(repoConfig.addresses.swarm.addresses[0], "/ip4/0.0.0.0/tcp/4001", 21);
retVal = strncmp(repoConfig->addresses.swarm.addresses[0], "/ip4/0.0.0.0/tcp/4001", 21);
if (retVal != 0)
return 0;
retVal = strncmp(repoConfig.addresses.swarm.addresses[1], "/ip6/::/tcp/4001", 16);
retVal = strncmp(repoConfig->addresses.swarm.addresses[1], "/ip6/::/tcp/4001", 16);
if (retVal != 0)
return 0;
// datastore
retVal = strncmp(repoConfig.datastore.path, "/Users/JohnJones/.ipfs/datastore", 32);
retVal = strncmp(repoConfig->datastore.path, "/Users/JohnJones/.ipfs/datastore", 32);
if (retVal != 0)
return 0;
repo_config_free(&repoConfig);
ipfs_repo_config_free(repoConfig);
return 1;
}
@ -55,24 +59,25 @@ int test_repo_config_init() {
*/
int test_repo_config_write() {
// first delete the existing one
unlink("/tmp/config");
unlink("/tmp/.ipfs/config");
// now build a new one
struct RepoConfig repoConfig;
if (!repo_config_init(&repoConfig, 2048, "/tmp")) {
repo_config_free(&repoConfig);
struct RepoConfig* repoConfig;
ipfs_repo_config_new(&repoConfig);
if (!repo_config_init(repoConfig, 2048, "/tmp/.ipfs")) {
ipfs_repo_config_free(repoConfig);
return 0;
}
if (!fs_repo_write_config_file("/tmp", &repoConfig)) {
repo_config_free(&repoConfig);
if (!fs_repo_write_config_file("/tmp/.ipfs", repoConfig)) {
ipfs_repo_config_free(repoConfig);
return 0;
}
repo_config_free(&repoConfig);
ipfs_repo_config_free(repoConfig);
// check to see if the file exists
return os_utils_file_exists("/tmp/config");
return os_utils_file_exists("/tmp/.ipfs/config");
}
#endif /* test_repo_config_h */

View file

@ -0,0 +1,20 @@
#include "ipfs/repo/fsrepo/fs_repo.h"
int test_repo_fsrepo_open_config() {
struct FSRepo* fs_repo;
struct RepoConfig* repo_config;
const char* path = "/tmp/.ipfs";
// create the struct
int retVal = ipfs_repo_fsrepo_new((char*)path, repo_config, &fs_repo);
if (retVal == 0)
return 0;
// open the repository and read the file
retVal = ipfs_repo_fsrepo_open(fs_repo);
if (retVal == 0)
return 0;
return 1;
}

View file

@ -16,11 +16,11 @@
int test_repo_config_identity_new() {
struct Identity identity;
int retVal = repo_config_identity_new(&identity, 2046);
int retVal = repo_config_identity_init(&identity, 2046);
// now examine it
int privateKeySize = sizeof(identity.private_key);
if (privateKeySize != 72) {
printf("Private key structure size should be 72");
if (privateKeySize < 0) {
printf("Private key structure size should be greater than 0\n");
retVal = 0;
}
return retVal;
@ -34,17 +34,8 @@ int test_repo_config_identity_private_key() {
libp2p_crypto_encoding_base64_decode(priv_b64, strlen(priv_b64), out_buff, decoded_len, &decoded_len);
char str[decoded_len];
int j = 0;
for (int i = 0; i < decoded_len; i++) {
if (out_buff[i] >= 32 && out_buff[i] <= 127) {
str[j] = out_buff[i];
j++;
}
printf("%hhX-%c ", out_buff[i], out_buff[i]);
}
out_buff[j] = 0;
printf("String: %s", str);
// now test
return 0;
return 1;
}

View file

@ -1,6 +1,7 @@
#include "repo/test_repo_config.h"
#include "repo/test_repo_identity.h"
#include "repo/test_repo_bootstrap_peers.h"
#include "repo/test_repo_fsrepo.h"
#include "cmd/ipfs/test_init.h"
#include "cid/test_cid.h"
@ -11,20 +12,26 @@ int testit(const char* name, int (*func)(void)) {
printf("%s success!\n", name);
else
printf("** Uh oh! %s failed.**\n", name);
return retVal;
return retVal == 0;
}
int main(int argc, char** argv) {
testit("test_cid_new_free", test_cid_new_free);
testit("test_cid_cast_multihash", test_cid_cast_multihash);
testit("test_cid_cast_non_multihash", test_cid_cast_non_multihash);
testit("test_init_new_installation", test_init_new_installation);
testit("test_repo_config_init", test_repo_config_init);
testit("test_repo_config_write", test_repo_config_write);
testit("test_repo_config_identity_new", test_repo_config_identity_new);
testit("test_repo_config_identity_private_key", test_repo_config_identity_private_key);
testit("test_reop_bootstrap_peers_init", test_repo_bootstrap_peers_init);
testit("get_init_command", test_get_init_command);
int counter = 0;
counter += testit("test_cid_new_free", test_cid_new_free);
counter += testit("test_cid_cast_multihash", test_cid_cast_multihash);
counter += testit("test_cid_cast_non_multihash", test_cid_cast_non_multihash);
counter += testit("test_init_new_installation", test_init_new_installation);
counter += testit("test_repo_config_init", test_repo_config_init);
counter += testit("test_repo_config_write", test_repo_config_write);
counter += testit("test_repo_config_identity_new", test_repo_config_identity_new);
counter += testit("test_repo_config_identity_private_key", test_repo_config_identity_private_key);
counter += testit("test_reop_bootstrap_peers_init", test_repo_bootstrap_peers_init);
counter += testit("get_init_command", test_get_init_command);
counter += testit("test_fs_repo_open", test_repo_fsrepo_open_config);
if (counter > 0) {
printf("***** There were %d failed test(s) *****\n", counter);
} else {
printf("All tests passed\n");
}
return 1;
}