2016-11-14 02:01:51 +00:00
|
|
|
/**
|
|
|
|
* An implementation of an IPFS node
|
|
|
|
* Copying the go-ipfs-node project
|
|
|
|
*/
|
2016-12-05 15:50:17 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "inttypes.h"
|
|
|
|
#include "ipfs/cid/cid.h"
|
2016-12-07 16:07:36 +00:00
|
|
|
|
2016-11-14 02:01:51 +00:00
|
|
|
#include "ipfs/node/node.h"
|
|
|
|
|
2016-12-12 20:06:17 +00:00
|
|
|
// for protobuf Node data & data_size encoded cid link_amount & links
|
|
|
|
enum WireType ipfs_node_message_fields[] = { WIRETYPE_LENGTH_DELIMITED, WIRETYPE_LENGTH_DELIMITED, WIRETYPE_LENGTH_DELIMITED, WIRETYPE_LENGTH_DELIMITED };
|
|
|
|
// for protobuf NodeLink name cid
|
|
|
|
enum WireType ipfs_node_link_message_fields[] = { WIRETYPE_LENGTH_DELIMITED, WIRETYPE_LENGTH_DELIMITED };
|
|
|
|
|
2016-12-07 16:07:36 +00:00
|
|
|
/*====================================================================================
|
|
|
|
* Link Functions
|
|
|
|
*===================================================================================*/
|
|
|
|
|
2016-12-12 20:06:17 +00:00
|
|
|
/* ipfs_node_link_new
|
2016-12-05 15:50:17 +00:00
|
|
|
* @Param name: The name of the link (char *)
|
|
|
|
* @Param size: Size of the link (size_t)
|
|
|
|
* @Param ahash: An Qmhash
|
|
|
|
*/
|
2016-12-12 20:06:17 +00:00
|
|
|
int ipfs_node_link_new(char * name, unsigned char * ahash, struct NodeLink** node_link)
|
2016-12-05 15:50:17 +00:00
|
|
|
{
|
2016-12-12 20:06:17 +00:00
|
|
|
*node_link = malloc(sizeof(struct NodeLink));
|
|
|
|
if (*node_link == NULL)
|
|
|
|
return 0;
|
2016-12-14 11:25:09 +00:00
|
|
|
(*node_link)->name = malloc(strlen(name) + 1);
|
|
|
|
if ( (*node_link)->name == NULL) {
|
|
|
|
free(*node_link);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
strcpy((*node_link)->name, name);
|
2016-12-12 21:58:27 +00:00
|
|
|
(*node_link)->next = NULL;
|
2016-12-05 15:50:17 +00:00
|
|
|
int ver = 0;
|
2016-12-12 20:06:17 +00:00
|
|
|
size_t lenhash = strlen((char*)ahash);
|
|
|
|
if (ipfs_cid_new(ver, ahash, lenhash, CID_PROTOBUF, &(*node_link)->cid) == 0) {
|
|
|
|
free(*node_link);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
2016-12-05 15:50:17 +00:00
|
|
|
}
|
|
|
|
|
2016-12-12 20:06:17 +00:00
|
|
|
/* ipfs_node_link_free
|
|
|
|
* @param node_link: Free the link you have allocated.
|
2016-12-05 15:50:17 +00:00
|
|
|
*/
|
2016-12-12 20:06:17 +00:00
|
|
|
int ipfs_node_link_free(struct NodeLink * node_link)
|
2016-12-05 15:50:17 +00:00
|
|
|
{
|
2016-12-12 23:27:46 +00:00
|
|
|
if (node_link != NULL) {
|
|
|
|
if (node_link->cid != NULL)
|
|
|
|
ipfs_cid_free(node_link->cid);
|
|
|
|
if (node_link->name != NULL)
|
|
|
|
free(node_link->name);
|
|
|
|
free(node_link);
|
|
|
|
}
|
2016-12-12 20:06:17 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-12-14 11:25:09 +00:00
|
|
|
size_t ipfs_node_link_protobuf_encode_size(struct NodeLink* link) {
|
2016-12-12 20:06:17 +00:00
|
|
|
if (link == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
size_t size = 0;
|
|
|
|
size += 11 + strlen(link->name);
|
|
|
|
size += ipfs_cid_protobuf_encode_size(link->cid);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ipfs_node_link_protobuf_encode(struct NodeLink* link, unsigned char* buffer, size_t max_buffer_length, size_t* bytes_written) {
|
|
|
|
size_t bytes_used = 0;
|
|
|
|
int retVal = 0;
|
|
|
|
*bytes_written = 0;
|
|
|
|
retVal = protobuf_encode_length_delimited(1, ipfs_node_link_message_fields[0], link->name, strlen(link->name), &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used);
|
2016-12-14 11:39:06 +00:00
|
|
|
if (retVal == 0)
|
|
|
|
return 0;
|
2016-12-12 20:06:17 +00:00
|
|
|
*bytes_written += bytes_used;
|
|
|
|
// cid
|
|
|
|
size_t cid_size = ipfs_cid_protobuf_encode_size(link->cid);
|
|
|
|
unsigned char cid_buffer[cid_size];
|
|
|
|
retVal = ipfs_cid_protobuf_encode(link->cid, cid_buffer, cid_size, &bytes_used);
|
2016-12-14 11:39:06 +00:00
|
|
|
if (retVal == 0)
|
|
|
|
return 0;
|
2016-12-14 11:25:09 +00:00
|
|
|
retVal = protobuf_encode_length_delimited(2, ipfs_node_link_message_fields[1], (char*)&cid_buffer[0], bytes_used, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used);
|
2016-12-14 11:39:06 +00:00
|
|
|
if (retVal == 0)
|
|
|
|
return 0;
|
2016-12-12 20:06:17 +00:00
|
|
|
*bytes_written += bytes_used;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ipfs_node_link_protobuf_decode(unsigned char* buffer, size_t buffer_length, struct NodeLink** link, size_t* bytes_read) {
|
|
|
|
size_t pos = 0;
|
|
|
|
int retVal = 0;
|
|
|
|
*link = (struct NodeLink*)malloc(sizeof(struct NodeLink));
|
|
|
|
(*link)->cid = NULL;
|
|
|
|
(*link)->name = NULL;
|
2016-12-12 21:58:27 +00:00
|
|
|
(*link)->next = NULL;
|
2016-12-12 20:06:17 +00:00
|
|
|
unsigned char* temp_buffer = NULL;
|
|
|
|
size_t temp_size;
|
|
|
|
|
|
|
|
if (*link == NULL)
|
|
|
|
goto exit;
|
|
|
|
while(pos < buffer_length) {
|
|
|
|
size_t bytes_read = 0;
|
|
|
|
int field_no;
|
|
|
|
enum WireType field_type;
|
|
|
|
if (protobuf_decode_field_and_type(&buffer[pos], buffer_length, &field_no, &field_type, &bytes_read) == 0) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
pos += bytes_read;
|
|
|
|
switch(field_no) {
|
|
|
|
case (1):
|
|
|
|
if (protobuf_decode_string(&buffer[pos], buffer_length - pos, &((*link)->name), &bytes_read) == 0)
|
|
|
|
goto exit;
|
|
|
|
pos += bytes_read;
|
|
|
|
break;
|
|
|
|
case (2):
|
|
|
|
if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&temp_buffer, &temp_size, &bytes_read) == 0)
|
|
|
|
goto exit;
|
|
|
|
ipfs_cid_protobuf_decode(temp_buffer, temp_size, &((*link)->cid));
|
|
|
|
pos += bytes_read;
|
|
|
|
free(temp_buffer);
|
|
|
|
temp_buffer = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
retVal = 1;
|
|
|
|
|
|
|
|
exit:
|
|
|
|
if (retVal == 0) {
|
|
|
|
if (link != NULL)
|
|
|
|
ipfs_node_link_free(*link);
|
|
|
|
}
|
|
|
|
if (temp_buffer != NULL)
|
|
|
|
free(temp_buffer);
|
|
|
|
|
|
|
|
return retVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* return an approximate size of the encoded node
|
|
|
|
*/
|
|
|
|
size_t ipfs_node_protobuf_encode_size(struct Node* node) {
|
|
|
|
size_t size = 0;
|
|
|
|
// data
|
|
|
|
size += 11 + node->data_size;
|
|
|
|
// encoded
|
|
|
|
size += 11;
|
|
|
|
if (node->encoded != NULL)
|
|
|
|
size += strlen((const char*)node->encoded);
|
|
|
|
// cid (a.k.a. cached)
|
|
|
|
size += 11 + ipfs_cid_protobuf_encode_size(node->cached);
|
|
|
|
// links
|
|
|
|
size += 11;
|
2016-12-12 21:58:27 +00:00
|
|
|
struct NodeLink* current = node->head_link;
|
|
|
|
while(current != NULL) {
|
|
|
|
size += 11 + strlen(current->name) + ipfs_cid_protobuf_encode_size(current->cid);
|
|
|
|
current = current->next;
|
2016-12-12 20:06:17 +00:00
|
|
|
}
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* Encode a node into a protobuf byte stream
|
|
|
|
* @param node the node to encode
|
|
|
|
* @param buffer where to put it
|
|
|
|
* @param max_buffer_length the length of buffer
|
|
|
|
* @param bytes_written how much of buffer was used
|
|
|
|
* @returns true(1) on success
|
|
|
|
*/
|
|
|
|
int ipfs_node_protobuf_encode(struct Node* node, unsigned char* buffer, size_t max_buffer_length, size_t* bytes_written) {
|
|
|
|
// data & data_size
|
|
|
|
size_t bytes_used = 0;
|
|
|
|
*bytes_written = 0;
|
|
|
|
int retVal = 0;
|
2016-12-14 11:25:09 +00:00
|
|
|
retVal = protobuf_encode_length_delimited(1, ipfs_node_message_fields[0], (char*)node->data, node->data_size, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used);
|
2016-12-12 20:06:17 +00:00
|
|
|
*bytes_written += bytes_used;
|
|
|
|
int sz = 0;
|
|
|
|
if (node->encoded != NULL)
|
2016-12-14 11:25:09 +00:00
|
|
|
sz = strlen((char*)node->encoded);
|
|
|
|
retVal = protobuf_encode_length_delimited(2, ipfs_node_message_fields[1], (char*)node->encoded, sz, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used);
|
2016-12-12 20:06:17 +00:00
|
|
|
*bytes_written += bytes_used;
|
|
|
|
// cid
|
|
|
|
size_t cid_size = ipfs_cid_protobuf_encode_size(node->cached);
|
|
|
|
unsigned char cid[cid_size];
|
|
|
|
retVal = ipfs_cid_protobuf_encode(node->cached, cid, cid_size, &cid_size);
|
2016-12-14 11:25:09 +00:00
|
|
|
retVal = protobuf_encode_length_delimited(3, ipfs_node_message_fields[2], (char*)cid, cid_size, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used);
|
2016-12-12 20:06:17 +00:00
|
|
|
*bytes_written += bytes_used;
|
|
|
|
// links
|
2016-12-12 21:58:27 +00:00
|
|
|
struct NodeLink* current = node->head_link;
|
|
|
|
while(current != NULL) {
|
2016-12-12 20:06:17 +00:00
|
|
|
// size + name + cid
|
2016-12-12 21:58:27 +00:00
|
|
|
size_t link_buffer_size = 11 + ipfs_node_link_protobuf_encode_size(current);
|
2016-12-12 20:06:17 +00:00
|
|
|
unsigned char link_buffer[link_buffer_size];
|
2016-12-12 21:58:27 +00:00
|
|
|
retVal = ipfs_node_link_protobuf_encode(current, link_buffer, link_buffer_size, &link_buffer_size);
|
2016-12-14 11:25:09 +00:00
|
|
|
protobuf_encode_length_delimited(4, ipfs_node_message_fields[3], (char*)link_buffer, link_buffer_size, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used);
|
2016-12-12 20:06:17 +00:00
|
|
|
*bytes_written += bytes_used;
|
2016-12-12 21:58:27 +00:00
|
|
|
current = current->next;
|
2016-12-12 20:06:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* Decode a stream of bytes into a Node structure
|
|
|
|
* @param buffer where to get the bytes from
|
|
|
|
* @param buffer_length the length of buffer
|
|
|
|
* @param node pointer to the Node to be created
|
|
|
|
* @returns true(1) on success
|
|
|
|
*/
|
|
|
|
int ipfs_node_protobuf_decode(unsigned char* buffer, size_t buffer_length, struct Node** node) {
|
|
|
|
/*
|
|
|
|
* Field 0: data
|
|
|
|
* Field 1: encoded
|
|
|
|
* Field 3: cid
|
|
|
|
* Field 4: links array
|
|
|
|
*/
|
|
|
|
size_t pos = 0;
|
|
|
|
int retVal = 0;
|
|
|
|
unsigned char* temp_buffer = NULL;
|
|
|
|
size_t temp_size;
|
|
|
|
struct NodeLink* temp_link = NULL;
|
|
|
|
|
|
|
|
if (ipfs_node_new(node) == 0)
|
|
|
|
goto exit;
|
|
|
|
|
|
|
|
while(pos < buffer_length) {
|
|
|
|
size_t bytes_read = 0;
|
|
|
|
int field_no;
|
|
|
|
enum WireType field_type;
|
|
|
|
if (protobuf_decode_field_and_type(&buffer[pos], buffer_length, &field_no, &field_type, &bytes_read) == 0) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
pos += bytes_read;
|
|
|
|
switch(field_no) {
|
|
|
|
case (1): // data
|
|
|
|
if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&((*node)->data), &((*node)->data_size), &bytes_read) == 0)
|
|
|
|
goto exit;
|
|
|
|
pos += bytes_read;
|
|
|
|
break;
|
|
|
|
case (2): // encoded
|
|
|
|
if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&((*node)->encoded), &temp_size, &bytes_read) == 0)
|
|
|
|
goto exit;
|
|
|
|
pos += bytes_read;
|
|
|
|
break;
|
|
|
|
case (3): // cid
|
|
|
|
if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&temp_buffer, &temp_size, &bytes_read) == 0)
|
|
|
|
goto exit;
|
|
|
|
pos += bytes_read;
|
|
|
|
if (ipfs_cid_protobuf_decode(temp_buffer, temp_size, &((*node)->cached)) == 0)
|
|
|
|
goto exit;
|
|
|
|
free(temp_buffer);
|
|
|
|
temp_buffer = NULL;
|
|
|
|
break;
|
|
|
|
case (4): // links
|
|
|
|
if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&temp_buffer, &temp_size, &bytes_read) == 0)
|
|
|
|
goto exit;
|
|
|
|
pos += bytes_read;
|
|
|
|
if (ipfs_node_link_protobuf_decode(temp_buffer, temp_size, &temp_link, &bytes_read) == 0)
|
|
|
|
goto exit;
|
|
|
|
free(temp_buffer);
|
|
|
|
temp_buffer = NULL;
|
2016-12-12 21:58:27 +00:00
|
|
|
ipfs_node_add_link(*node, temp_link);
|
2016-12-12 20:06:17 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
retVal = 1;
|
|
|
|
|
|
|
|
exit:
|
|
|
|
if (retVal == 0) {
|
|
|
|
ipfs_node_free(*node);
|
|
|
|
}
|
|
|
|
if (temp_buffer != NULL)
|
|
|
|
free(temp_buffer);
|
|
|
|
|
|
|
|
return retVal;
|
2016-12-05 15:50:17 +00:00
|
|
|
}
|
2016-12-12 20:06:17 +00:00
|
|
|
|
2016-12-05 15:50:17 +00:00
|
|
|
/*====================================================================================
|
|
|
|
* Node Functions
|
|
|
|
*===================================================================================*/
|
2016-12-12 20:06:17 +00:00
|
|
|
/*ipfs_node_new
|
2016-12-05 15:50:17 +00:00
|
|
|
* Creates an empty node, allocates the required memory
|
|
|
|
* Returns a fresh new node with no data set in it.
|
|
|
|
*/
|
2016-12-12 20:06:17 +00:00
|
|
|
int ipfs_node_new(struct Node** node)
|
2016-12-05 15:50:17 +00:00
|
|
|
{
|
2016-12-12 20:06:17 +00:00
|
|
|
*node = (struct Node *)malloc(sizeof(struct Node));
|
|
|
|
if (*node == NULL)
|
|
|
|
return 0;
|
|
|
|
(*node)->cached = NULL;
|
|
|
|
(*node)->data = NULL;
|
2016-12-14 17:07:43 +00:00
|
|
|
(*node)->data_size = 0;
|
2016-12-12 20:06:17 +00:00
|
|
|
(*node)->encoded = NULL;
|
2016-12-12 21:58:27 +00:00
|
|
|
(*node)->head_link = NULL;
|
2016-12-12 20:06:17 +00:00
|
|
|
return 1;
|
2016-12-05 15:50:17 +00:00
|
|
|
}
|
|
|
|
|
2016-12-07 16:07:36 +00:00
|
|
|
/**
|
|
|
|
* Set the cached struct element
|
2016-12-12 20:06:17 +00:00
|
|
|
* @param node the node to be modified
|
|
|
|
* @param cid the Cid to be copied into the Node->cached element
|
2016-12-07 16:07:36 +00:00
|
|
|
* @returns true(1) on success
|
|
|
|
*/
|
2016-12-14 11:25:09 +00:00
|
|
|
int ipfs_node_set_cached(struct Node* node, const struct Cid* cid)
|
2016-12-07 16:07:36 +00:00
|
|
|
{
|
2016-12-12 20:06:17 +00:00
|
|
|
if (node->cached != NULL)
|
|
|
|
ipfs_cid_free(node->cached);
|
|
|
|
return ipfs_cid_new(cid->version, cid->hash, cid->hash_length, cid->codec, &(node->cached));
|
2016-12-07 16:07:36 +00:00
|
|
|
}
|
|
|
|
|
2016-12-12 20:06:17 +00:00
|
|
|
/*ipfs_node_set_data
|
2016-12-05 15:50:17 +00:00
|
|
|
* Sets the data of a node
|
|
|
|
* @param Node: The node which you want to set data in.
|
|
|
|
* @param Data, the data you want to assign to the node
|
2016-12-07 16:07:36 +00:00
|
|
|
* Sets pointers of encoded & cached to NULL /following go method
|
2016-12-05 15:50:17 +00:00
|
|
|
* returns 1 on success 0 on failure
|
|
|
|
*/
|
2016-12-12 20:06:17 +00:00
|
|
|
int ipfs_node_set_data(struct Node * N, unsigned char * Data, size_t data_size)
|
2016-12-05 15:50:17 +00:00
|
|
|
{
|
|
|
|
if(!N || !Data)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
N->encoded = NULL;
|
|
|
|
N->cached = NULL;
|
2016-12-12 11:27:06 +00:00
|
|
|
N->data = malloc(sizeof(unsigned char) * data_size);
|
|
|
|
if (N->data == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
memcpy(N->data, Data, data_size);
|
|
|
|
N->data_size = data_size;
|
2016-12-05 15:50:17 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-12-12 20:06:17 +00:00
|
|
|
/*ipfs_node_set_encoded
|
2016-12-07 16:07:36 +00:00
|
|
|
* @param NODE: the node you wish to alter (struct Node *)
|
|
|
|
* @param Data: The data you wish to set in encoded.(unsigned char *)
|
|
|
|
* returns 1 on success 0 on failure
|
2016-12-05 15:50:17 +00:00
|
|
|
*/
|
2016-12-12 20:06:17 +00:00
|
|
|
int ipfs_node_set_encoded(struct Node * N, unsigned char * Data)
|
2016-12-05 15:50:17 +00:00
|
|
|
{
|
2016-12-07 16:07:36 +00:00
|
|
|
if(!N || !Data)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
N->encoded = Data;
|
|
|
|
//I don't know if these will be needed, enable them if you need them.
|
|
|
|
//N->cached = NULL;
|
|
|
|
//N->data = NULL;
|
|
|
|
return 1;
|
2016-12-05 15:50:17 +00:00
|
|
|
}
|
2016-12-12 20:06:17 +00:00
|
|
|
/*ipfs_node_get_data
|
2016-12-07 16:07:36 +00:00
|
|
|
* Gets data from a node
|
|
|
|
* @param Node: = The node you want to get data from. (unsigned char *)
|
|
|
|
* Returns data of node.
|
2016-12-05 15:50:17 +00:00
|
|
|
*/
|
2016-12-12 20:06:17 +00:00
|
|
|
unsigned char * ipfs_node_get_data(struct Node * N)
|
2016-12-07 16:07:36 +00:00
|
|
|
{
|
|
|
|
unsigned char * DATA;
|
|
|
|
DATA = N->data;
|
|
|
|
return DATA;
|
2016-12-05 15:50:17 +00:00
|
|
|
}
|
|
|
|
|
2016-12-12 21:58:27 +00:00
|
|
|
struct NodeLink* ipfs_node_link_last(struct Node* node) {
|
|
|
|
struct NodeLink* current = node->head_link;
|
|
|
|
while(current != NULL) {
|
|
|
|
if (current->next == NULL)
|
|
|
|
break;
|
|
|
|
current = current->next;
|
|
|
|
}
|
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ipfs_node_remove_link(struct Node* node, struct NodeLink* toRemove) {
|
|
|
|
struct NodeLink* current = node->head_link;
|
|
|
|
struct NodeLink* previous = NULL;
|
|
|
|
while(current != NULL && current != toRemove) {
|
|
|
|
previous = current;
|
|
|
|
current = current->next;
|
|
|
|
}
|
|
|
|
if (current != NULL) {
|
|
|
|
if (previous == NULL) {
|
|
|
|
// we're trying to delete the head
|
|
|
|
previous = current->next;
|
|
|
|
ipfs_node_link_free(current);
|
|
|
|
node->head_link = previous;
|
|
|
|
} else {
|
|
|
|
// we're in the middle or end
|
|
|
|
previous = current->next;
|
|
|
|
ipfs_node_link_free(current);
|
2016-12-05 15:50:17 +00:00
|
|
|
}
|
2016-12-12 21:58:27 +00:00
|
|
|
return 1;
|
2016-12-05 15:50:17 +00:00
|
|
|
}
|
2016-12-12 21:58:27 +00:00
|
|
|
return 0;
|
2016-12-05 15:50:17 +00:00
|
|
|
}
|
2016-12-12 21:58:27 +00:00
|
|
|
|
2016-12-12 20:06:17 +00:00
|
|
|
/*ipfs_node_free
|
2016-12-05 15:50:17 +00:00
|
|
|
* Once you are finished using a node, always delete it using this.
|
|
|
|
* It will take care of the links inside it.
|
|
|
|
* @param N: the node you want to free. (struct Node *)
|
|
|
|
*/
|
2016-12-12 23:27:46 +00:00
|
|
|
int ipfs_node_free(struct Node * N)
|
2016-12-05 15:50:17 +00:00
|
|
|
{
|
2016-12-12 21:58:27 +00:00
|
|
|
if(N != NULL)
|
2016-12-05 15:50:17 +00:00
|
|
|
{
|
2016-12-12 23:27:46 +00:00
|
|
|
// remove links
|
|
|
|
struct NodeLink* current = N->head_link;
|
2016-12-12 21:58:27 +00:00
|
|
|
while (current != NULL) {
|
|
|
|
struct NodeLink* toDelete = current;
|
|
|
|
current = current->next;
|
|
|
|
ipfs_node_remove_link(N, toDelete);
|
2016-12-07 16:07:36 +00:00
|
|
|
}
|
|
|
|
if(N->cached)
|
|
|
|
{
|
2016-12-07 16:53:17 +00:00
|
|
|
ipfs_cid_free(N->cached);
|
|
|
|
}
|
|
|
|
if (N->data) {
|
|
|
|
free(N->data);
|
2016-12-05 15:50:17 +00:00
|
|
|
}
|
2016-12-12 23:27:46 +00:00
|
|
|
if (N->encoded != NULL) {
|
|
|
|
free(N->encoded);
|
|
|
|
}
|
|
|
|
free(N);
|
2016-12-07 16:07:36 +00:00
|
|
|
}
|
2016-12-12 23:27:46 +00:00
|
|
|
return 1;
|
2016-12-05 15:50:17 +00:00
|
|
|
}
|
2016-12-12 21:58:27 +00:00
|
|
|
|
2016-12-12 20:06:17 +00:00
|
|
|
/*ipfs_node_get_link_by_name
|
2016-12-05 15:50:17 +00:00
|
|
|
* Returns a copy of the link with given name
|
|
|
|
* @param Name: (char * name) searches for link with this name
|
|
|
|
* Returns the link struct if it's found otherwise returns NULL
|
|
|
|
*/
|
2016-12-12 20:06:17 +00:00
|
|
|
struct NodeLink * ipfs_node_get_link_by_name(struct Node * N, char * Name)
|
2016-12-05 15:50:17 +00:00
|
|
|
{
|
2016-12-12 21:58:27 +00:00
|
|
|
struct NodeLink* current = N->head_link;
|
|
|
|
while(current != NULL && strcmp(Name, current->name) != 0) {
|
|
|
|
current = current->next;
|
2016-12-05 15:50:17 +00:00
|
|
|
}
|
2016-12-12 21:58:27 +00:00
|
|
|
return current;
|
2016-12-05 15:50:17 +00:00
|
|
|
}
|
2016-12-12 21:58:27 +00:00
|
|
|
|
2016-12-12 20:06:17 +00:00
|
|
|
/*ipfs_node_remove_link_by_name
|
2016-12-05 15:50:17 +00:00
|
|
|
* Removes a link from node if found by name.
|
|
|
|
* @param name: Name of link (char * name)
|
|
|
|
* returns 1 on success, 0 on failure.
|
|
|
|
*/
|
2016-12-12 20:06:17 +00:00
|
|
|
int ipfs_node_remove_link_by_name(char * Name, struct Node * mynode)
|
2016-12-05 15:50:17 +00:00
|
|
|
{
|
2016-12-12 21:58:27 +00:00
|
|
|
struct NodeLink* current = mynode->head_link;
|
|
|
|
struct NodeLink* previous = NULL;
|
|
|
|
while( (current != NULL)
|
|
|
|
&& (( Name == NULL && current->name != NULL )
|
|
|
|
|| ( Name != NULL && current->name == NULL )
|
|
|
|
|| ( Name != NULL && current->name != NULL && strcmp(Name, current->name) != 0) ) ) {
|
|
|
|
previous = current;
|
|
|
|
current = current->next;
|
|
|
|
}
|
|
|
|
if (current != NULL) {
|
|
|
|
// we found it
|
|
|
|
if (previous == NULL) {
|
|
|
|
// we're first, use the next one (if there is one)
|
|
|
|
if (current->next != NULL)
|
|
|
|
mynode->head_link = current->next;
|
|
|
|
} else {
|
|
|
|
// we're somewhere in the middle, remove me from the list
|
|
|
|
previous->next = current->next;
|
|
|
|
ipfs_node_link_free(current);
|
2016-12-05 15:50:17 +00:00
|
|
|
}
|
2016-12-12 21:58:27 +00:00
|
|
|
|
|
|
|
return 1;
|
2016-12-05 15:50:17 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2016-12-12 21:58:27 +00:00
|
|
|
|
2016-12-12 20:06:17 +00:00
|
|
|
/* ipfs_node_add_link
|
2016-12-12 11:27:06 +00:00
|
|
|
* Adds a link to your nodse
|
2016-12-05 15:50:17 +00:00
|
|
|
* @param mynode: &yournode
|
|
|
|
* @param mylink: the CID you want to create a node from
|
|
|
|
* @param linksz: sizeof(your cid here)
|
|
|
|
* Returns your node with the newly added link
|
|
|
|
*/
|
2016-12-12 21:58:27 +00:00
|
|
|
int ipfs_node_add_link(struct Node* Nl, struct NodeLink * mylink)
|
2016-12-05 15:50:17 +00:00
|
|
|
{
|
2016-12-12 21:58:27 +00:00
|
|
|
if(Nl->head_link != NULL) {
|
|
|
|
// add to existing by finding last one
|
|
|
|
struct NodeLink* current_end = Nl->head_link;
|
|
|
|
while(current_end->next != NULL) {
|
|
|
|
current_end = current_end->next;
|
2016-12-05 15:50:17 +00:00
|
|
|
}
|
2016-12-12 21:58:27 +00:00
|
|
|
// now we have the last one, add to it
|
|
|
|
current_end->next = mylink;
|
2016-12-05 15:50:17 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-12-12 21:58:27 +00:00
|
|
|
Nl->head_link = mylink;
|
2016-12-05 15:50:17 +00:00
|
|
|
}
|
2016-12-12 21:58:27 +00:00
|
|
|
return 1;
|
2016-12-05 15:50:17 +00:00
|
|
|
}
|
|
|
|
|
2016-12-12 20:06:17 +00:00
|
|
|
/*ipfs_node_new_from_link
|
2016-12-05 15:50:17 +00:00
|
|
|
* Create a node from a link
|
|
|
|
* @param mylink: the link you want to create it from. (struct Cid *)
|
|
|
|
* @param linksize: sizeof(the link in mylink) (size_T)
|
|
|
|
* Returns a fresh new node with the link you specified. Has to be freed with Node_Free preferably.
|
|
|
|
*/
|
2016-12-12 20:06:17 +00:00
|
|
|
int ipfs_node_new_from_link(struct NodeLink * mylink, struct Node** node)
|
2016-12-05 15:50:17 +00:00
|
|
|
{
|
2016-12-12 21:58:27 +00:00
|
|
|
*node = (struct Node *) malloc(sizeof(struct Node));
|
2016-12-12 20:06:17 +00:00
|
|
|
if (*node == NULL)
|
|
|
|
return 0;
|
2016-12-12 21:58:27 +00:00
|
|
|
(*node)->head_link = NULL;
|
|
|
|
ipfs_node_add_link(*node, mylink);
|
2016-12-12 20:06:17 +00:00
|
|
|
(*node)->cached = NULL;
|
|
|
|
(*node)->data = NULL;
|
|
|
|
(*node)->encoded = NULL;
|
|
|
|
return 1;
|
2016-12-05 15:50:17 +00:00
|
|
|
}
|
2016-12-12 20:06:17 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* create a new Node struct with data
|
2016-12-07 16:07:36 +00:00
|
|
|
* @param data: bytes buffer you want to create the node from
|
2016-12-12 20:06:17 +00:00
|
|
|
* @param data_size the size of the data buffer
|
|
|
|
* @param node a pointer to the node to be created
|
2016-12-05 15:50:17 +00:00
|
|
|
* returns a node with the data you inputted.
|
|
|
|
*/
|
2016-12-12 20:06:17 +00:00
|
|
|
int ipfs_node_new_from_data(unsigned char * data, size_t data_size, struct Node** node)
|
2016-12-05 15:50:17 +00:00
|
|
|
{
|
2016-12-07 16:07:36 +00:00
|
|
|
if(data)
|
|
|
|
{
|
2016-12-12 20:06:17 +00:00
|
|
|
if (ipfs_node_new(node) == 0)
|
|
|
|
return 0;
|
|
|
|
return ipfs_node_set_data(*node, data, data_size);
|
2016-12-07 16:07:36 +00:00
|
|
|
}
|
2016-12-12 20:06:17 +00:00
|
|
|
return 0;
|
2016-12-07 16:07:36 +00:00
|
|
|
}
|
2016-12-12 20:06:17 +00:00
|
|
|
|
|
|
|
/***
|
|
|
|
* create a Node struct from encoded data
|
|
|
|
* @param data: encoded bytes buffer you want to create the node from. Note: this copies the pointer, not a memcpy
|
|
|
|
* @param node a pointer to the node that will be created
|
|
|
|
* @returns true(1) on success
|
2016-12-07 16:07:36 +00:00
|
|
|
*/
|
2016-12-12 20:06:17 +00:00
|
|
|
int ipfs_node_new_from_encoded(unsigned char * data, struct Node** node)
|
2016-12-07 16:07:36 +00:00
|
|
|
{
|
|
|
|
if(data)
|
|
|
|
{
|
2016-12-12 20:06:17 +00:00
|
|
|
if (ipfs_node_new(node) == 0)
|
|
|
|
return 0;
|
|
|
|
(*node)->encoded = data;
|
|
|
|
return 1;
|
2016-12-07 16:07:36 +00:00
|
|
|
}
|
2016-12-12 20:06:17 +00:00
|
|
|
return 0;
|
2016-12-05 15:50:17 +00:00
|
|
|
}
|
|
|
|
/*Node_Resolve_Max_Size
|
|
|
|
* !!!This shouldn't concern you!
|
|
|
|
*Gets the ammount of words that will be returned by Node_Resolve
|
|
|
|
*@Param1: The string that will be processed (eg: char * sentence = "foo/bar/bin")
|
|
|
|
*Returns either -1 if something went wrong or the ammount of words that would be processed.
|
|
|
|
*/
|
|
|
|
int Node_Resolve_Max_Size(char * input1)
|
|
|
|
{
|
|
|
|
if(!input1)
|
|
|
|
{
|
|
|
|
return -1; // Input is null, therefor nothing can be processed.
|
|
|
|
}
|
|
|
|
char input[strlen(input1)];
|
|
|
|
bzero(input, strlen(input1));
|
|
|
|
strcpy(input, input1);
|
|
|
|
int num = 0;
|
|
|
|
char * tr;
|
|
|
|
char * end;
|
|
|
|
tr=strtok_r(input,"/",&end);
|
|
|
|
for(int i = 0;tr;i++)
|
|
|
|
{
|
|
|
|
tr=strtok_r(NULL,"/",&end);
|
|
|
|
num++;
|
|
|
|
}
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Node_Resolve Basically stores everything in a pointer array eg: char * bla[Max_Words_]
|
|
|
|
* !!!This shouldn't concern you!!!
|
|
|
|
*@param1: Pointer array(char * foo[x], X=Whatever ammount there is. should be used with the helper function Node_Resolve_Max_Size)
|
|
|
|
*@param2: Sentence to gather words/paths from (Eg: char * meh = "foo/bar/bin")
|
|
|
|
*@Returns 1 or 0, 0 if something went wrong, 1 if everything went smoothly.
|
|
|
|
*/
|
2016-12-07 16:07:36 +00:00
|
|
|
|
2016-12-05 15:50:17 +00:00
|
|
|
int Node_Resolve(char ** result, char * input1)
|
|
|
|
{
|
|
|
|
if(!input1)
|
|
|
|
{
|
|
|
|
return 0; // Input is null, therefor nothing can be processed.
|
|
|
|
}
|
|
|
|
char input[strlen(input1)];
|
|
|
|
bzero(input, strlen(input1));
|
|
|
|
strcpy(input, input1);
|
|
|
|
char * tr;
|
|
|
|
char * end;
|
|
|
|
tr=strtok_r(input,"/",&end);
|
|
|
|
for(int i = 0;tr;i++)
|
|
|
|
{
|
|
|
|
result[i] = (char *) malloc(strlen(tr)+1);
|
|
|
|
strcpy(result[i], tr);
|
|
|
|
tr=strtok_r(NULL,"/",&end);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Node_Resolve_Links
|
|
|
|
* Processes a path returning all links.
|
|
|
|
* @param N: The node you want to get links from
|
|
|
|
* @param path: The "foo/bar/bin" path
|
|
|
|
*/
|
|
|
|
struct Link_Proc * Node_Resolve_Links(struct Node * N, char * path)
|
|
|
|
{
|
|
|
|
if(!N || !path)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
int expected_link_ammount = Node_Resolve_Max_Size(path);
|
2016-12-12 20:06:17 +00:00
|
|
|
struct Link_Proc * LProc = (struct Link_Proc *) malloc(sizeof(struct Link_Proc) + sizeof(struct NodeLink) * expected_link_ammount);
|
2016-12-05 15:50:17 +00:00
|
|
|
LProc->ammount = 0;
|
|
|
|
char * linknames[expected_link_ammount];
|
|
|
|
Node_Resolve(linknames, path);
|
|
|
|
for(int i=0;i<expected_link_ammount; i++)
|
|
|
|
{
|
2016-12-12 20:06:17 +00:00
|
|
|
struct NodeLink * proclink;
|
|
|
|
proclink = ipfs_node_get_link_by_name(N, linknames[i]);
|
2016-12-05 15:50:17 +00:00
|
|
|
if(proclink)
|
|
|
|
{
|
2016-12-12 20:06:17 +00:00
|
|
|
LProc->links[i] = (struct NodeLink *)malloc(sizeof(struct NodeLink));
|
|
|
|
memcpy(LProc->links[i], proclink, sizeof(struct NodeLink));
|
2016-12-05 15:50:17 +00:00
|
|
|
LProc->ammount++;
|
|
|
|
free(proclink);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//Freeing pointer array
|
|
|
|
for(int i=0;i<expected_link_ammount; i++)
|
|
|
|
{
|
|
|
|
free(linknames[i]);
|
|
|
|
}
|
|
|
|
return LProc;
|
|
|
|
}
|
|
|
|
/*Free_link_Proc
|
|
|
|
* frees the Link_Proc struct you created.
|
|
|
|
* @param1: Link_Proc struct (struct Link_Proc *)
|
|
|
|
*/
|
|
|
|
void Free_Link_Proc(struct Link_Proc * LPRC)
|
|
|
|
{
|
|
|
|
if(LPRC->ammount != 0)
|
|
|
|
{
|
|
|
|
for(int i=0;i<LPRC->ammount;i++)
|
|
|
|
{
|
2016-12-12 20:06:17 +00:00
|
|
|
ipfs_node_link_free(LPRC->links[i]);
|
2016-12-05 15:50:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
free(LPRC);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Node_Tree() Basically a unix-like ls
|
|
|
|
*@Param1: Result char * foo[strlen(sentence)]
|
|
|
|
*@Param2: char sentence[] = foo/bar/bin/whatever
|
|
|
|
*Return: 0 if failure, 1 if success
|
|
|
|
*/
|
|
|
|
int Node_Tree(char * result, char * input1) //I don't know where you use this but here it is.
|
|
|
|
{
|
|
|
|
if(!input1)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
char input[strlen(input1)];
|
|
|
|
bzero(input, strlen(input1));
|
|
|
|
strcpy(input, input1);
|
|
|
|
for(int i=0; i<strlen(input); i++)
|
|
|
|
{
|
|
|
|
if(input[i] == '/')
|
|
|
|
{
|
|
|
|
input[i] = ' ';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
strcpy(result, input);
|
|
|
|
return 1;
|
|
|
|
}
|