2016-11-13 21:01:51 -05:00
|
|
|
/**
|
|
|
|
* An implementation of an IPFS node
|
|
|
|
* Copying the go-ipfs-node project
|
|
|
|
*/
|
2016-12-05 10:50:17 -05:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2017-03-21 12:11:41 -05:00
|
|
|
#include <strings.h>
|
2016-12-05 10:50:17 -05:00
|
|
|
#include "inttypes.h"
|
2016-12-07 11:07:36 -05:00
|
|
|
|
2016-12-23 17:21:04 -05:00
|
|
|
#include "mh/multihash.h"
|
|
|
|
#include "mh/hashes.h"
|
|
|
|
#include "ipfs/cid/cid.h"
|
2016-12-19 09:03:28 -05:00
|
|
|
#include "ipfs/merkledag/node.h"
|
2016-12-23 17:21:04 -05:00
|
|
|
#include "ipfs/unixfs/unixfs.h"
|
2017-03-21 12:58:39 -05:00
|
|
|
#include "ipfs/util/string_tokenizer.h"
|
2016-12-23 17:21:04 -05:00
|
|
|
|
2016-11-13 21:01:51 -05:00
|
|
|
|
2016-12-23 09:37:43 -05:00
|
|
|
// for protobuf Node (all fields optional) data (optional bytes) links (repeated node_link)
|
2016-12-21 06:40:19 -05:00
|
|
|
enum WireType ipfs_node_message_fields[] = { WIRETYPE_LENGTH_DELIMITED, WIRETYPE_LENGTH_DELIMITED };
|
|
|
|
// for protobuf NodeLink (all fields optional) hash name tsize
|
|
|
|
enum WireType ipfs_node_link_message_fields[] = { WIRETYPE_LENGTH_DELIMITED, WIRETYPE_LENGTH_DELIMITED, WIRETYPE_VARINT };
|
2016-12-12 15:06:17 -05:00
|
|
|
|
2016-12-07 11:07:36 -05:00
|
|
|
/*====================================================================================
|
|
|
|
* Link Functions
|
|
|
|
*===================================================================================*/
|
|
|
|
|
2016-12-12 15:06:17 -05:00
|
|
|
/* ipfs_node_link_new
|
2016-12-05 10:50:17 -05:00
|
|
|
* @Param name: The name of the link (char *)
|
|
|
|
* @Param size: Size of the link (size_t)
|
|
|
|
* @Param ahash: An Qmhash
|
|
|
|
*/
|
2016-12-21 06:40:19 -05:00
|
|
|
int ipfs_node_link_create(char * name, unsigned char * ahash, size_t hash_size, struct NodeLink** node_link)
|
2016-12-05 10:50:17 -05:00
|
|
|
{
|
2016-12-23 20:12:51 -05:00
|
|
|
ipfs_node_link_new(node_link);
|
2016-12-12 15:06:17 -05:00
|
|
|
if (*node_link == NULL)
|
|
|
|
return 0;
|
2016-12-21 06:40:19 -05:00
|
|
|
|
|
|
|
struct NodeLink* link = *node_link;
|
|
|
|
// hash
|
|
|
|
link->hash_size = hash_size;
|
|
|
|
link->hash = (unsigned char*)malloc(hash_size);
|
|
|
|
memcpy(link->hash, ahash, hash_size);
|
|
|
|
// name
|
2016-12-23 20:12:51 -05:00
|
|
|
if (name != NULL && strlen(name) > 0) {
|
|
|
|
link->name = malloc(strlen(name) + 1);
|
|
|
|
if ( link->name == NULL) {
|
|
|
|
free(link);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
strcpy(link->name, name);
|
2016-12-14 06:25:09 -05:00
|
|
|
}
|
2016-12-21 06:40:19 -05:00
|
|
|
// t_size
|
|
|
|
link->t_size = 0;
|
|
|
|
// other, non-protobuffed data
|
|
|
|
link->next = NULL;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ipfs_node_link_new(struct NodeLink** node_link) {
|
|
|
|
*node_link = malloc(sizeof(struct NodeLink));
|
|
|
|
if (*node_link == NULL)
|
2016-12-12 15:06:17 -05:00
|
|
|
return 0;
|
2016-12-21 06:40:19 -05:00
|
|
|
|
|
|
|
struct NodeLink* link = *node_link;
|
|
|
|
link->hash = NULL;
|
|
|
|
link->hash_size = 0;
|
|
|
|
link->name = NULL;
|
|
|
|
link->next = NULL;
|
|
|
|
link->t_size = 0;
|
2016-12-12 15:06:17 -05:00
|
|
|
return 1;
|
2016-12-05 10:50:17 -05:00
|
|
|
}
|
|
|
|
|
2016-12-12 15:06:17 -05:00
|
|
|
/* ipfs_node_link_free
|
|
|
|
* @param node_link: Free the link you have allocated.
|
2016-12-05 10:50:17 -05:00
|
|
|
*/
|
2016-12-12 15:06:17 -05:00
|
|
|
int ipfs_node_link_free(struct NodeLink * node_link)
|
2016-12-05 10:50:17 -05:00
|
|
|
{
|
2016-12-12 18:27:46 -05:00
|
|
|
if (node_link != NULL) {
|
2016-12-21 06:40:19 -05:00
|
|
|
if (node_link->hash != NULL)
|
|
|
|
free(node_link->hash);
|
2016-12-12 18:27:46 -05:00
|
|
|
if (node_link->name != NULL)
|
|
|
|
free(node_link->name);
|
|
|
|
free(node_link);
|
|
|
|
}
|
2016-12-12 15:06:17 -05:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-12-21 06:40:19 -05:00
|
|
|
/***
|
|
|
|
* Find length of encoded version of NodeLink
|
|
|
|
* @param link the link to examine
|
|
|
|
* @returns the maximum length of the encoded NodeLink
|
|
|
|
*/
|
2016-12-23 09:37:43 -05:00
|
|
|
size_t ipfs_node_link_protobuf_encode_size(const struct NodeLink* link) {
|
2016-12-12 15:06:17 -05:00
|
|
|
if (link == NULL)
|
|
|
|
return 0;
|
2016-12-21 06:40:19 -05:00
|
|
|
// hash, name, tsize
|
2016-12-12 15:06:17 -05:00
|
|
|
size_t size = 0;
|
2016-12-21 06:40:19 -05:00
|
|
|
if (link->hash_size > 0) {
|
|
|
|
size += 11 + link->hash_size;
|
|
|
|
}
|
|
|
|
if (link->name != NULL && strlen(link->name) > 0) {
|
|
|
|
size += 11 + strlen(link->name);
|
|
|
|
}
|
|
|
|
if (link->t_size > 0) {
|
|
|
|
size += 22;
|
|
|
|
}
|
2016-12-12 15:06:17 -05:00
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-12-21 06:40:19 -05:00
|
|
|
/**
|
|
|
|
* Encode a NodeLink in protobuf format
|
|
|
|
* @param link the link to work with
|
|
|
|
* @param buffer the buffer to fill
|
|
|
|
* @param max_buffer_length the length of the buffer
|
|
|
|
* @param bytes_written the number of bytes written to buffer
|
|
|
|
* @returns true(1) on success
|
|
|
|
*/
|
2016-12-23 09:37:43 -05:00
|
|
|
int ipfs_node_link_protobuf_encode(const struct NodeLink* link, unsigned char* buffer, size_t max_buffer_length, size_t* bytes_written) {
|
2016-12-21 06:40:19 -05:00
|
|
|
// 3 fields, hash (length delimited), name (length delimited), tsize (varint)
|
2016-12-12 15:06:17 -05:00
|
|
|
size_t bytes_used = 0;
|
|
|
|
int retVal = 0;
|
|
|
|
*bytes_written = 0;
|
2016-12-21 06:40:19 -05:00
|
|
|
// hash
|
|
|
|
if (link->hash_size > 0) {
|
2016-12-23 17:21:04 -05:00
|
|
|
size_t hash_length = mh_new_length(MH_H_SHA2_256, link->hash_size);
|
|
|
|
unsigned char hash[hash_length];
|
|
|
|
mh_new(hash, MH_H_SHA2_256, link->hash, link->hash_size);
|
|
|
|
retVal = protobuf_encode_length_delimited(1, ipfs_node_link_message_fields[0], (char*)hash, hash_length, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used);
|
|
|
|
if (retVal == 0) {
|
2016-12-21 06:40:19 -05:00
|
|
|
return 0;
|
2016-12-23 17:21:04 -05:00
|
|
|
}
|
2016-12-21 06:40:19 -05:00
|
|
|
*bytes_written += bytes_used;
|
|
|
|
}
|
2016-12-23 17:21:04 -05:00
|
|
|
// name is optional, but they encode it anyways
|
2016-12-21 06:40:19 -05:00
|
|
|
if (link->name != NULL && strlen(link->name) > 0) {
|
|
|
|
retVal = protobuf_encode_string(2, ipfs_node_link_message_fields[1], link->name, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used);
|
|
|
|
if (retVal == 0)
|
|
|
|
return 0;
|
|
|
|
*bytes_written += bytes_used;
|
2016-12-23 17:21:04 -05:00
|
|
|
} else {
|
|
|
|
retVal = protobuf_encode_string(2, ipfs_node_link_message_fields[1], "", &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used);
|
|
|
|
if (retVal == 0)
|
|
|
|
return 0;
|
|
|
|
*bytes_written += bytes_used;
|
2016-12-21 06:40:19 -05:00
|
|
|
}
|
|
|
|
// tsize
|
|
|
|
if (link->t_size > 0) {
|
|
|
|
retVal = protobuf_encode_varint(3, ipfs_node_link_message_fields[2], link->t_size, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used);
|
|
|
|
if (retVal == 0)
|
|
|
|
return 0;
|
|
|
|
*bytes_written += bytes_used;
|
|
|
|
}
|
2016-12-12 15:06:17 -05:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-12-21 06:40:19 -05:00
|
|
|
/**
|
|
|
|
* Turn a protobuf encoded byte array into a NodeLink object
|
|
|
|
* @param buffer the buffer to look in
|
|
|
|
* @param buffer_length the length of the buffer
|
|
|
|
* @param link the link to fill
|
|
|
|
* @returns true(1) on success
|
|
|
|
*/
|
|
|
|
int ipfs_node_link_protobuf_decode(unsigned char* buffer, size_t buffer_length, struct NodeLink** node_link) {
|
2016-12-12 15:06:17 -05:00
|
|
|
size_t pos = 0;
|
|
|
|
int retVal = 0;
|
2016-12-21 06:40:19 -05:00
|
|
|
struct NodeLink* link = NULL;
|
2016-12-12 15:06:17 -05:00
|
|
|
|
2016-12-21 06:40:19 -05:00
|
|
|
// allocate memory for object
|
|
|
|
if (ipfs_node_link_new(node_link) == 0)
|
2016-12-12 15:06:17 -05:00
|
|
|
goto exit;
|
2016-12-21 06:40:19 -05:00
|
|
|
|
|
|
|
link = *node_link;
|
|
|
|
|
2016-12-12 15:06:17 -05:00
|
|
|
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) {
|
2016-12-21 06:40:19 -05:00
|
|
|
case (1): { // hash
|
2016-12-23 17:21:04 -05:00
|
|
|
size_t hash_size = 0;
|
|
|
|
unsigned char* hash;
|
|
|
|
if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&hash, &hash_size, &bytes_read) == 0)
|
2016-12-12 15:06:17 -05:00
|
|
|
goto exit;
|
2016-12-23 17:21:04 -05:00
|
|
|
link->hash_size = hash_size - 2;
|
2016-12-23 19:08:41 -05:00
|
|
|
link->hash = (unsigned char*)malloc(link->hash_size);
|
2016-12-23 20:12:51 -05:00
|
|
|
memcpy((char*)link->hash, (char*)&hash[2], link->hash_size);
|
2016-12-23 17:21:04 -05:00
|
|
|
free(hash);
|
2016-12-12 15:06:17 -05:00
|
|
|
pos += bytes_read;
|
|
|
|
break;
|
2016-12-21 06:40:19 -05:00
|
|
|
}
|
|
|
|
case (2): { // name
|
|
|
|
if (protobuf_decode_string(&buffer[pos], buffer_length - pos, &link->name, &bytes_read) == 0)
|
|
|
|
goto exit;
|
|
|
|
pos += bytes_read;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case (3): { // t_size
|
|
|
|
if (protobuf_decode_varint(&buffer[pos], buffer_length - pos, (unsigned long long*)&link->t_size, &bytes_read) == 0)
|
2016-12-12 15:06:17 -05:00
|
|
|
goto exit;
|
|
|
|
pos += bytes_read;
|
|
|
|
break;
|
2016-12-21 06:40:19 -05:00
|
|
|
}
|
2016-12-12 15:06:17 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
retVal = 1;
|
|
|
|
|
|
|
|
exit:
|
|
|
|
if (retVal == 0) {
|
|
|
|
if (link != NULL)
|
2016-12-21 06:40:19 -05:00
|
|
|
ipfs_node_link_free(link);
|
2016-12-12 15:06:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return retVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* return an approximate size of the encoded node
|
|
|
|
*/
|
2016-12-23 09:37:43 -05:00
|
|
|
size_t ipfs_node_protobuf_encode_size(const struct Node* node) {
|
2016-12-12 15:06:17 -05:00
|
|
|
size_t size = 0;
|
|
|
|
// links
|
2016-12-12 16:58:27 -05:00
|
|
|
struct NodeLink* current = node->head_link;
|
|
|
|
while(current != NULL) {
|
2016-12-21 06:40:19 -05:00
|
|
|
size += 11 + ipfs_node_link_protobuf_encode_size(current);
|
2016-12-12 16:58:27 -05:00
|
|
|
current = current->next;
|
2016-12-12 15:06:17 -05:00
|
|
|
}
|
2016-12-21 06:40:19 -05:00
|
|
|
// data
|
|
|
|
if (node->data_size > 0) {
|
|
|
|
size += 11 + node->data_size;
|
|
|
|
}
|
2016-12-12 15:06:17 -05: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
|
|
|
|
*/
|
2016-12-23 09:37:43 -05:00
|
|
|
int ipfs_node_protobuf_encode(const struct Node* node, unsigned char* buffer, size_t max_buffer_length, size_t* bytes_written) {
|
2016-12-12 15:06:17 -05:00
|
|
|
size_t bytes_used = 0;
|
|
|
|
*bytes_written = 0;
|
|
|
|
int retVal = 0;
|
|
|
|
// links
|
2016-12-12 16:58:27 -05:00
|
|
|
struct NodeLink* current = node->head_link;
|
2016-12-21 06:40:19 -05:00
|
|
|
while (current != NULL) {
|
|
|
|
size_t temp_size = ipfs_node_link_protobuf_encode_size(current);
|
|
|
|
unsigned char temp[temp_size];
|
|
|
|
retVal = ipfs_node_link_protobuf_encode(current, temp, temp_size, &bytes_used);
|
|
|
|
if (retVal == 0)
|
|
|
|
return 0;
|
2016-12-23 09:37:43 -05:00
|
|
|
retVal = protobuf_encode_length_delimited(2, ipfs_node_message_fields[1], (char*)temp, bytes_used, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used);
|
2016-12-14 12:24:44 -05:00
|
|
|
if (retVal == 0)
|
|
|
|
return 0;
|
2016-12-12 15:06:17 -05:00
|
|
|
*bytes_written += bytes_used;
|
2016-12-12 16:58:27 -05:00
|
|
|
current = current->next;
|
2016-12-12 15:06:17 -05:00
|
|
|
}
|
2016-12-23 17:21:04 -05:00
|
|
|
// data
|
|
|
|
if (node->data_size > 0) {
|
|
|
|
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);
|
|
|
|
if (retVal == 0)
|
|
|
|
return 0;
|
|
|
|
*bytes_written += bytes_used;
|
|
|
|
}
|
2016-12-12 15:06:17 -05: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) {
|
|
|
|
/*
|
2016-12-21 06:40:19 -05:00
|
|
|
* Field 1: data
|
2016-12-23 09:37:43 -05:00
|
|
|
* Field 2: link
|
2016-12-12 15:06:17 -05:00
|
|
|
*/
|
|
|
|
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) {
|
2016-12-23 09:37:43 -05:00
|
|
|
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): {// links
|
2016-12-12 15:06:17 -05:00
|
|
|
if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&temp_buffer, &temp_size, &bytes_read) == 0)
|
|
|
|
goto exit;
|
|
|
|
pos += bytes_read;
|
2016-12-21 06:40:19 -05:00
|
|
|
if (ipfs_node_link_protobuf_decode(temp_buffer, temp_size, &temp_link) == 0)
|
2016-12-12 15:06:17 -05:00
|
|
|
goto exit;
|
|
|
|
free(temp_buffer);
|
|
|
|
temp_buffer = NULL;
|
2016-12-21 06:40:19 -05:00
|
|
|
ipfs_node_add_link(*node, temp_link);
|
2016-12-12 15:06:17 -05:00
|
|
|
break;
|
2016-12-21 06:40:19 -05:00
|
|
|
}
|
2016-12-12 15:06:17 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
retVal = 1;
|
|
|
|
|
|
|
|
exit:
|
|
|
|
if (retVal == 0) {
|
|
|
|
ipfs_node_free(*node);
|
|
|
|
}
|
|
|
|
if (temp_buffer != NULL)
|
|
|
|
free(temp_buffer);
|
|
|
|
|
|
|
|
return retVal;
|
2016-12-05 10:50:17 -05:00
|
|
|
}
|
2016-12-12 15:06:17 -05:00
|
|
|
|
2016-12-05 10:50:17 -05:00
|
|
|
/*====================================================================================
|
|
|
|
* Node Functions
|
|
|
|
*===================================================================================*/
|
2016-12-12 15:06:17 -05:00
|
|
|
/*ipfs_node_new
|
2016-12-05 10:50:17 -05:00
|
|
|
* Creates an empty node, allocates the required memory
|
|
|
|
* Returns a fresh new node with no data set in it.
|
|
|
|
*/
|
2016-12-12 15:06:17 -05:00
|
|
|
int ipfs_node_new(struct Node** node)
|
2016-12-05 10:50:17 -05:00
|
|
|
{
|
2016-12-12 15:06:17 -05:00
|
|
|
*node = (struct Node *)malloc(sizeof(struct Node));
|
|
|
|
if (*node == NULL)
|
|
|
|
return 0;
|
2016-12-21 06:40:19 -05:00
|
|
|
(*node)->hash = NULL;
|
|
|
|
(*node)->hash_size = 0;
|
2016-12-12 15:06:17 -05:00
|
|
|
(*node)->data = NULL;
|
2016-12-14 12:07:43 -05:00
|
|
|
(*node)->data_size = 0;
|
2016-12-12 15:06:17 -05:00
|
|
|
(*node)->encoded = NULL;
|
2016-12-12 16:58:27 -05:00
|
|
|
(*node)->head_link = NULL;
|
2016-12-12 15:06:17 -05:00
|
|
|
return 1;
|
2016-12-05 10:50:17 -05:00
|
|
|
}
|
|
|
|
|
2016-12-28 22:45:35 -05:00
|
|
|
/***
|
|
|
|
* Allocates memory for a node, and sets the data section to indicate
|
|
|
|
* that this node is a directory
|
|
|
|
* @param node the node to initialize
|
|
|
|
* @returns true(1) on success, otherwise false(0)
|
|
|
|
*/
|
|
|
|
int ipfs_node_create_directory(struct Node** node) {
|
|
|
|
// initialize parent_node
|
|
|
|
if (ipfs_node_new(node) == 0)
|
|
|
|
return 0;
|
|
|
|
// put a UnixFS protobuf in the data section
|
|
|
|
struct UnixFS* unix_fs;
|
|
|
|
if (ipfs_unixfs_new(&unix_fs) == 0) {
|
|
|
|
ipfs_node_free(*node);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
unix_fs->data_type = UNIXFS_DIRECTORY;
|
|
|
|
size_t protobuf_len = ipfs_unixfs_protobuf_encode_size(unix_fs);
|
|
|
|
unsigned char protobuf[protobuf_len];
|
|
|
|
if (ipfs_unixfs_protobuf_encode(unix_fs, protobuf, protobuf_len, &protobuf_len) == 0) {
|
|
|
|
ipfs_node_free(*node);
|
|
|
|
ipfs_unixfs_free(unix_fs);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ipfs_unixfs_free(unix_fs);
|
|
|
|
ipfs_node_set_data(*node, protobuf, protobuf_len);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-12-29 19:05:44 -05:00
|
|
|
int ipfs_node_is_directory(struct Node* node) {
|
|
|
|
if (node->data_size < 2) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
struct UnixFS* unix_fs;
|
|
|
|
if (ipfs_unixfs_protobuf_decode(node->data, node->data_size, &unix_fs) == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
int retVal = (unix_fs->data_type == UNIXFS_DIRECTORY);
|
|
|
|
ipfs_unixfs_free(unix_fs);
|
|
|
|
return retVal;
|
|
|
|
}
|
|
|
|
|
2016-12-07 11:07:36 -05:00
|
|
|
/**
|
|
|
|
* Set the cached struct element
|
2016-12-12 15:06:17 -05:00
|
|
|
* @param node the node to be modified
|
|
|
|
* @param cid the Cid to be copied into the Node->cached element
|
2016-12-07 11:07:36 -05:00
|
|
|
* @returns true(1) on success
|
|
|
|
*/
|
2016-12-21 06:40:19 -05:00
|
|
|
int ipfs_node_set_hash(struct Node* node, const unsigned char* hash, size_t hash_size)
|
2016-12-07 11:07:36 -05:00
|
|
|
{
|
2016-12-21 06:40:19 -05:00
|
|
|
// don't reallocate if it is the same size
|
|
|
|
if (node->hash != NULL && hash_size != node->hash_size) {
|
|
|
|
free(node->hash);
|
|
|
|
node->hash = NULL;
|
|
|
|
node->hash_size = 0;
|
|
|
|
}
|
|
|
|
// we must reallocate
|
|
|
|
if (node->hash == NULL && hash_size > 0) {
|
|
|
|
node->hash = (unsigned char*)malloc(hash_size);
|
|
|
|
if (node->hash == NULL)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (hash_size > 0) { // don't bother if there is nothing to copy
|
|
|
|
memcpy(node->hash, hash, hash_size);
|
|
|
|
node->hash_size = hash_size;
|
|
|
|
}
|
|
|
|
return 1;
|
2016-12-07 11:07:36 -05:00
|
|
|
}
|
|
|
|
|
2016-12-12 15:06:17 -05:00
|
|
|
/*ipfs_node_set_data
|
2016-12-05 10:50:17 -05: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 11:07:36 -05:00
|
|
|
* Sets pointers of encoded & cached to NULL /following go method
|
2016-12-05 10:50:17 -05:00
|
|
|
* returns 1 on success 0 on failure
|
|
|
|
*/
|
2016-12-23 17:21:04 -05:00
|
|
|
int ipfs_node_set_data(struct Node* node, unsigned char * Data, size_t data_size)
|
2016-12-05 10:50:17 -05:00
|
|
|
{
|
2016-12-23 17:21:04 -05:00
|
|
|
if(!node || !Data)
|
2016-12-05 10:50:17 -05:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2016-12-23 17:21:04 -05:00
|
|
|
if (node->data != NULL) {
|
|
|
|
free(node->data);
|
|
|
|
}
|
|
|
|
node->data = malloc(sizeof(unsigned char) * data_size);
|
|
|
|
if (node->data == NULL)
|
2016-12-12 06:27:06 -05:00
|
|
|
return 0;
|
|
|
|
|
2016-12-23 17:21:04 -05:00
|
|
|
memcpy(node->data, Data, data_size);
|
|
|
|
node->data_size = data_size;
|
2016-12-05 10:50:17 -05:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-12-12 15:06:17 -05:00
|
|
|
/*ipfs_node_set_encoded
|
2016-12-07 11:07:36 -05: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 10:50:17 -05:00
|
|
|
*/
|
2016-12-12 15:06:17 -05:00
|
|
|
int ipfs_node_set_encoded(struct Node * N, unsigned char * Data)
|
2016-12-05 10:50:17 -05:00
|
|
|
{
|
2016-12-07 11:07:36 -05: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 10:50:17 -05:00
|
|
|
}
|
2016-12-12 15:06:17 -05:00
|
|
|
/*ipfs_node_get_data
|
2016-12-07 11:07:36 -05: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 10:50:17 -05:00
|
|
|
*/
|
2016-12-12 15:06:17 -05:00
|
|
|
unsigned char * ipfs_node_get_data(struct Node * N)
|
2016-12-07 11:07:36 -05:00
|
|
|
{
|
|
|
|
unsigned char * DATA;
|
|
|
|
DATA = N->data;
|
|
|
|
return DATA;
|
2016-12-05 10:50:17 -05:00
|
|
|
}
|
|
|
|
|
2016-12-12 16:58:27 -05: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 10:50:17 -05:00
|
|
|
}
|
2016-12-12 16:58:27 -05:00
|
|
|
return 1;
|
2016-12-05 10:50:17 -05:00
|
|
|
}
|
2016-12-12 16:58:27 -05:00
|
|
|
return 0;
|
2016-12-05 10:50:17 -05:00
|
|
|
}
|
2016-12-12 16:58:27 -05:00
|
|
|
|
2016-12-12 15:06:17 -05:00
|
|
|
/*ipfs_node_free
|
2016-12-05 10:50:17 -05: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 18:27:46 -05:00
|
|
|
int ipfs_node_free(struct Node * N)
|
2016-12-05 10:50:17 -05:00
|
|
|
{
|
2016-12-12 16:58:27 -05:00
|
|
|
if(N != NULL)
|
2016-12-05 10:50:17 -05:00
|
|
|
{
|
2016-12-12 18:27:46 -05:00
|
|
|
// remove links
|
|
|
|
struct NodeLink* current = N->head_link;
|
2016-12-12 16:58:27 -05:00
|
|
|
while (current != NULL) {
|
|
|
|
struct NodeLink* toDelete = current;
|
|
|
|
current = current->next;
|
|
|
|
ipfs_node_remove_link(N, toDelete);
|
2016-12-07 11:07:36 -05:00
|
|
|
}
|
2016-12-21 06:40:19 -05:00
|
|
|
if(N->hash != NULL)
|
2016-12-07 11:07:36 -05:00
|
|
|
{
|
2016-12-21 06:40:19 -05:00
|
|
|
free(N->hash);
|
|
|
|
N->hash = NULL;
|
|
|
|
N->hash_size = 0;
|
2016-12-07 11:53:17 -05:00
|
|
|
}
|
|
|
|
if (N->data) {
|
|
|
|
free(N->data);
|
2016-12-05 10:50:17 -05:00
|
|
|
}
|
2016-12-12 18:27:46 -05:00
|
|
|
if (N->encoded != NULL) {
|
|
|
|
free(N->encoded);
|
|
|
|
}
|
|
|
|
free(N);
|
2016-12-07 11:07:36 -05:00
|
|
|
}
|
2016-12-12 18:27:46 -05:00
|
|
|
return 1;
|
2016-12-05 10:50:17 -05:00
|
|
|
}
|
2016-12-12 16:58:27 -05:00
|
|
|
|
2016-12-12 15:06:17 -05:00
|
|
|
/*ipfs_node_get_link_by_name
|
2016-12-05 10:50:17 -05: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 15:06:17 -05:00
|
|
|
struct NodeLink * ipfs_node_get_link_by_name(struct Node * N, char * Name)
|
2016-12-05 10:50:17 -05:00
|
|
|
{
|
2016-12-12 16:58:27 -05:00
|
|
|
struct NodeLink* current = N->head_link;
|
|
|
|
while(current != NULL && strcmp(Name, current->name) != 0) {
|
|
|
|
current = current->next;
|
2016-12-05 10:50:17 -05:00
|
|
|
}
|
2016-12-12 16:58:27 -05:00
|
|
|
return current;
|
2016-12-05 10:50:17 -05:00
|
|
|
}
|
2016-12-12 16:58:27 -05:00
|
|
|
|
2016-12-12 15:06:17 -05:00
|
|
|
/*ipfs_node_remove_link_by_name
|
2016-12-05 10:50:17 -05: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 15:06:17 -05:00
|
|
|
int ipfs_node_remove_link_by_name(char * Name, struct Node * mynode)
|
2016-12-05 10:50:17 -05:00
|
|
|
{
|
2016-12-12 16:58:27 -05: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 10:50:17 -05:00
|
|
|
}
|
2016-12-12 16:58:27 -05:00
|
|
|
|
|
|
|
return 1;
|
2016-12-05 10:50:17 -05:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2016-12-12 16:58:27 -05:00
|
|
|
|
2016-12-12 15:06:17 -05:00
|
|
|
/* ipfs_node_add_link
|
2016-12-23 17:21:04 -05:00
|
|
|
* Adds a link to your node
|
|
|
|
* @param node the node to add to
|
|
|
|
* @param mylink: the link to add
|
|
|
|
* @returns true(1) on success
|
2016-12-05 10:50:17 -05:00
|
|
|
*/
|
2016-12-23 17:21:04 -05:00
|
|
|
int ipfs_node_add_link(struct Node* node, struct NodeLink * mylink)
|
2016-12-05 10:50:17 -05:00
|
|
|
{
|
2016-12-23 17:21:04 -05:00
|
|
|
if(node->head_link != NULL) {
|
2016-12-12 16:58:27 -05:00
|
|
|
// add to existing by finding last one
|
2016-12-23 17:21:04 -05:00
|
|
|
struct NodeLink* current_end = node->head_link;
|
2016-12-12 16:58:27 -05:00
|
|
|
while(current_end->next != NULL) {
|
|
|
|
current_end = current_end->next;
|
2016-12-05 10:50:17 -05:00
|
|
|
}
|
2016-12-12 16:58:27 -05:00
|
|
|
// now we have the last one, add to it
|
|
|
|
current_end->next = mylink;
|
2016-12-05 10:50:17 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-12-23 17:21:04 -05:00
|
|
|
node->head_link = mylink;
|
2016-12-05 10:50:17 -05:00
|
|
|
}
|
2016-12-12 16:58:27 -05:00
|
|
|
return 1;
|
2016-12-05 10:50:17 -05:00
|
|
|
}
|
|
|
|
|
2016-12-12 15:06:17 -05:00
|
|
|
/*ipfs_node_new_from_link
|
2016-12-05 10:50:17 -05: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 15:06:17 -05:00
|
|
|
int ipfs_node_new_from_link(struct NodeLink * mylink, struct Node** node)
|
2016-12-05 10:50:17 -05:00
|
|
|
{
|
2016-12-12 16:58:27 -05:00
|
|
|
*node = (struct Node *) malloc(sizeof(struct Node));
|
2016-12-12 15:06:17 -05:00
|
|
|
if (*node == NULL)
|
|
|
|
return 0;
|
2016-12-12 16:58:27 -05:00
|
|
|
(*node)->head_link = NULL;
|
|
|
|
ipfs_node_add_link(*node, mylink);
|
2016-12-21 06:40:19 -05:00
|
|
|
(*node)->hash = NULL;
|
|
|
|
(*node)->hash_size = 0;
|
2016-12-12 15:06:17 -05:00
|
|
|
(*node)->data = NULL;
|
2016-12-15 05:40:24 -05:00
|
|
|
(*node)->data_size = 0;
|
2016-12-12 15:06:17 -05:00
|
|
|
(*node)->encoded = NULL;
|
|
|
|
return 1;
|
2016-12-05 10:50:17 -05:00
|
|
|
}
|
2016-12-12 15:06:17 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* create a new Node struct with data
|
2016-12-07 11:07:36 -05:00
|
|
|
* @param data: bytes buffer you want to create the node from
|
2016-12-12 15:06:17 -05:00
|
|
|
* @param data_size the size of the data buffer
|
|
|
|
* @param node a pointer to the node to be created
|
2016-12-05 10:50:17 -05:00
|
|
|
* returns a node with the data you inputted.
|
|
|
|
*/
|
2016-12-12 15:06:17 -05:00
|
|
|
int ipfs_node_new_from_data(unsigned char * data, size_t data_size, struct Node** node)
|
2016-12-05 10:50:17 -05:00
|
|
|
{
|
2016-12-07 11:07:36 -05:00
|
|
|
if(data)
|
|
|
|
{
|
2016-12-12 15:06:17 -05:00
|
|
|
if (ipfs_node_new(node) == 0)
|
|
|
|
return 0;
|
|
|
|
return ipfs_node_set_data(*node, data, data_size);
|
2016-12-07 11:07:36 -05:00
|
|
|
}
|
2016-12-12 15:06:17 -05:00
|
|
|
return 0;
|
2016-12-07 11:07:36 -05:00
|
|
|
}
|
2016-12-12 15:06:17 -05: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 11:07:36 -05:00
|
|
|
*/
|
2016-12-12 15:06:17 -05:00
|
|
|
int ipfs_node_new_from_encoded(unsigned char * data, struct Node** node)
|
2016-12-07 11:07:36 -05:00
|
|
|
{
|
|
|
|
if(data)
|
|
|
|
{
|
2016-12-12 15:06:17 -05:00
|
|
|
if (ipfs_node_new(node) == 0)
|
|
|
|
return 0;
|
|
|
|
(*node)->encoded = data;
|
|
|
|
return 1;
|
2016-12-07 11:07:36 -05:00
|
|
|
}
|
2016-12-12 15:06:17 -05:00
|
|
|
return 0;
|
2016-12-05 10:50:17 -05: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.
|
|
|
|
}
|
2017-03-21 12:11:41 -05:00
|
|
|
char input[strlen(input1)+1];
|
2016-12-05 10:50:17 -05:00
|
|
|
bzero(input, strlen(input1));
|
|
|
|
strcpy(input, input1);
|
|
|
|
int num = 0;
|
|
|
|
char * tr;
|
|
|
|
char * end;
|
|