c-ipfs/merkledag/merkledag.c

139 lines
4.1 KiB
C

/**
* A basic storage building block of the IPFS system
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libp2p/crypto/sha256.h"
#include "mh/multihash.h"
#include "mh/hashes.h"
#include "ipfs/merkledag/merkledag.h"
#include "ipfs/unixfs/unixfs.h"
/***
* Convert a HashtableNode into a Block
* @param node the node to convert
* @param blockResult where to put the results
* @returns true(1) on success, false(0) otherwise
*/
int ipfs_merkledag_convert_node_to_block(struct HashtableNode* node, struct Block** blockResult) {
*blockResult = ipfs_block_new();
if (*blockResult == NULL)
return 0;
struct Block* block = *blockResult;
block->cid = ipfs_cid_new(1, node->hash, node->hash_size, CID_DAG_PROTOBUF);
if (block->cid == NULL) {
ipfs_block_free(block);
*blockResult = NULL;
return 0;
}
block->data_length = ipfs_hashtable_node_protobuf_encode_size(node);
block->data = malloc(block->data_length);
if (block->data == NULL) {
ipfs_block_free(block);
*blockResult = NULL;
return 0;
}
if (!ipfs_hashtable_node_protobuf_encode(node, block->data, block->data_length, &block->data_length)) {
ipfs_block_free(block);
*blockResult = NULL;
return 0;
}
return 1;
}
/***
* Convert the data within a block to a HashtableNode
* @param block the block
* @param node_ptr where to put the results
* @returns true(1) on success, false(0) otherwise
*/
int ipfs_merkledag_convert_block_to_node(struct Block* block, struct HashtableNode** node_ptr) {
return ipfs_hashtable_node_protobuf_decode(block->data, block->data_length, node_ptr);
}
/***
* Adds a node to the dagService and blockService
* @param node the node to add
* @param fs_repo the repo to add to
* @param bytes_written the number of bytes written
* @returns true(1) on success
*/
int ipfs_merkledag_add(struct HashtableNode* node, struct FSRepo* fs_repo, size_t* bytes_written) {
// taken from merkledag.go line 59
int retVal = 0;
// compute the hash if necessary
if (node->hash == NULL) {
size_t protobuf_size = ipfs_hashtable_node_protobuf_encode_size(node);
unsigned char protobuf[protobuf_size];
size_t bytes_encoded;
retVal = ipfs_hashtable_node_protobuf_encode(node, protobuf, protobuf_size, &bytes_encoded);
node->hash_size = 32;
node->hash = (unsigned char*)malloc(node->hash_size);
if (node->hash == NULL) {
return 0;
}
if (libp2p_crypto_hashing_sha256(protobuf, bytes_encoded, &node->hash[0]) == 0) {
free(node->hash);
return 0;
}
}
// write to block store & datastore
struct Block* block = NULL;
if (!ipfs_merkledag_convert_node_to_block(node, &block)) {
return 0;
}
retVal = ipfs_repo_fsrepo_block_write(block, fs_repo, bytes_written);
if (retVal == 0) {
ipfs_block_free(block);
return 0;
}
ipfs_block_free(block);
// TODO: call HasBlock (unsure why as yet)
return 1;
}
/***
* Retrieves a node from the datastore based on the hash
* @param hash the key to look for
* @param hash_size the length of the key
* @param node the node to be created
* @param fs_repo the repository
* @returns true(1) on success
*/
int ipfs_merkledag_get(const unsigned char* hash, size_t hash_size, struct HashtableNode** node, const struct FSRepo* fs_repo) {
int retVal = 1;
struct DatastoreRecord* datastore_record = NULL;
// look for the node in the datastore. If it is not there, it is not a node.
// If it exists, it is only a block.
retVal = fs_repo->config->datastore->datastore_get(hash, hash_size, &datastore_record, fs_repo->config->datastore);
if (retVal == 0)
return 0;
libp2p_datastore_record_free(datastore_record);
// we have the record from the db. Go get the node from the blockstore
if (!ipfs_repo_fsrepo_node_read(hash, hash_size, node, fs_repo))
return 0;
// set the hash
ipfs_hashtable_node_set_hash(*node, hash, hash_size);
return 1;
}
int ipfs_merkledag_get_by_multihash(const unsigned char* multihash, size_t multihash_length, struct HashtableNode** node, const struct FSRepo* fs_repo) {
// convert to hash
size_t hash_size = 0;
unsigned char* hash = NULL;
if (mh_multihash_digest(multihash, multihash_length, &hash, &hash_size) < 0) {
return 0;
}
return ipfs_merkledag_get(hash, hash_size, node, fs_repo);
}