forked from agorise/c-ipfs
Added the ability to retrieve the file using directories
Files can be refered to directly using their hash, or the hash of their directory and the file name.
This commit is contained in:
parent
396dfc6abc
commit
c2fe60949e
11 changed files with 233 additions and 5 deletions
|
@ -7,7 +7,7 @@ endif
|
|||
|
||||
LFLAGS =
|
||||
DEPS =
|
||||
OBJS = importer.o exporter.o
|
||||
OBJS = importer.o exporter.o resolver.o
|
||||
|
||||
%.o: %.c $(DEPS)
|
||||
$(CC) -c -o $@ $< $(CFLAGS)
|
||||
|
|
142
importer/resolver.c
Normal file
142
importer/resolver.c
Normal file
|
@ -0,0 +1,142 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "libp2p/crypto/encoding/base58.h"
|
||||
#include "ipfs/merkledag/node.h"
|
||||
#include "ipfs/merkledag/merkledag.h"
|
||||
#include "ipfs/repo/fsrepo/fs_repo.h"
|
||||
|
||||
/**
|
||||
* return the next chunk of a path
|
||||
* @param path the path
|
||||
* @param next_part a pointer to a string NOTE: don't forget to free
|
||||
* @returns true(1) on success, false(0) on error, or no more parts
|
||||
*/
|
||||
int ipfs_resolver_next_path(const char* path, char** next_part) {
|
||||
for (int i = 0; i < strlen(path); i++) {
|
||||
if (path[i] != '/') { // we have the next section
|
||||
char* pos = strchr(&path[i+1], '/');
|
||||
if (pos == NULL) {
|
||||
*next_part = (char*)malloc(strlen(path) + 1);
|
||||
strcpy(*next_part, path);
|
||||
} else {
|
||||
*next_part = (char*)malloc(pos - &path[i] + 1);
|
||||
strncpy(*next_part, &path[i], pos-&path[i]);
|
||||
(*next_part)[pos-&path[i]] = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove preceding slash and "/ipfs/" or "/ipns/"
|
||||
* @param path
|
||||
*/
|
||||
const char* ipfs_resolver_remove_path_prefix(const char* path) {
|
||||
int pos = 0;
|
||||
int first_non_slash = -1;
|
||||
while(&path[pos] != NULL) {
|
||||
if (path[pos] == '/') {
|
||||
pos++;
|
||||
continue;
|
||||
} else {
|
||||
if (first_non_slash == -1)
|
||||
first_non_slash = pos;
|
||||
if (pos == first_non_slash && (strncmp(&path[pos], "ipfs", 4) == 0 || strncmp(&path[pos], "ipns", 4) == 0) ) {
|
||||
// ipfs or ipns should be up front. Otherwise, it could be part of the path
|
||||
pos += 4;
|
||||
} else {
|
||||
return &path[pos];
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interogate the path and the current node, looking
|
||||
* for the desired node.
|
||||
* @param path the current path
|
||||
* @param from the current node (or NULL if it is the first call)
|
||||
* @returns what we are looking for, or NULL if it wasn't found
|
||||
*/
|
||||
struct Node* ipfs_resolver_get(const char* path, struct Node* from, const struct FSRepo* fs_repo) {
|
||||
// remove unnecessary stuff
|
||||
if (from == NULL)
|
||||
path = ipfs_resolver_remove_path_prefix(path);
|
||||
// grab the portion of the path to work with
|
||||
char* path_section;
|
||||
if (ipfs_resolver_next_path(path, &path_section) == 0)
|
||||
return NULL;
|
||||
struct Node* current_node = NULL;
|
||||
if (from == NULL) {
|
||||
// this is the first time around. Grab the root node
|
||||
if (path_section[0] == 'Q' && path_section[1] == 'm') {
|
||||
// we have a hash. Convert to a real hash, and find the node
|
||||
size_t hash_length = libp2p_crypto_encoding_base58_decode_size(strlen(path_section));
|
||||
unsigned char hash[hash_length];
|
||||
unsigned char* ptr = &hash[0];
|
||||
if (libp2p_crypto_encoding_base58_decode((unsigned char*)path_section, strlen(path_section), &ptr, &hash_length) == 0) {
|
||||
free(path_section);
|
||||
return NULL;
|
||||
}
|
||||
if (ipfs_merkledag_get_by_multihash(hash, hash_length, ¤t_node, fs_repo) == 0) {
|
||||
free(path_section);
|
||||
return NULL;
|
||||
}
|
||||
// we have the root node, now see if we want this or something further down
|
||||
int pos = strlen(path_section);
|
||||
if (pos == strlen(path)) {
|
||||
return current_node;
|
||||
} else {
|
||||
// look on...
|
||||
return ipfs_resolver_get(&path[pos+1], current_node, fs_repo); // the +1 is the slash
|
||||
}
|
||||
} else {
|
||||
// we don't have a current node, and we don't have a hash. Something is wrong
|
||||
free(path_section);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
// we were passed a node. If it is a directory, see if what we're looking for is in it
|
||||
if (ipfs_node_is_directory(from)) {
|
||||
struct NodeLink* curr_link = from->head_link;
|
||||
while (curr_link != NULL) {
|
||||
// if it matches the name, we found what we're looking for.
|
||||
// If so, load up the node by its hash
|
||||
if (strcmp(curr_link->name, path_section) == 0) {
|
||||
if (ipfs_merkledag_get(curr_link->hash, curr_link->hash_size, ¤t_node, fs_repo) == 0) {
|
||||
free(path_section);
|
||||
return NULL;
|
||||
}
|
||||
if (strlen(path_section) == strlen(path)) {
|
||||
// we are at the end of our search
|
||||
ipfs_node_free(from);
|
||||
return current_node;
|
||||
} else {
|
||||
char* next_path_section;
|
||||
ipfs_resolver_next_path(&path[strlen(path_section)], &next_path_section);
|
||||
free(path_section);
|
||||
// if we're at the end of the path, return the node
|
||||
// continue looking for the next part of the path
|
||||
ipfs_node_free(from);
|
||||
return ipfs_resolver_get(next_path_section, current_node, fs_repo);
|
||||
}
|
||||
}
|
||||
curr_link = curr_link->next;
|
||||
}
|
||||
} else {
|
||||
// we're asking for a file from an object that is not a directory. Bail.
|
||||
free(path_section);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
// it should never get here
|
||||
free(path_section);
|
||||
if (from != NULL)
|
||||
ipfs_node_free(from);
|
||||
return NULL;
|
||||
}
|
12
include/ipfs/importer/resolver.h
Normal file
12
include/ipfs/importer/resolver.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "ipfs/merkledag/node.h"
|
||||
|
||||
/**
|
||||
* Interogate the path and the current node, looking
|
||||
* for the desired node.
|
||||
* @param path the current path
|
||||
* @param from the current node (or NULL if it is the first call)
|
||||
* @returns what we are looking for, or NULL if it wasn't found
|
||||
*/
|
||||
struct Node* ipfs_resolver_get(const char* path, struct Node* from, const struct FSRepo* fs_repo);
|
|
@ -25,4 +25,13 @@ int ipfs_merkledag_add(struct Node* node, struct FSRepo* fs_repo, size_t* bytes_
|
|||
*/
|
||||
int ipfs_merkledag_get(const unsigned char* hash, size_t hash_size, struct Node** node, const struct FSRepo* fs_repo);
|
||||
|
||||
/***
|
||||
* Retrieves a node from the datastore based on the multihash
|
||||
* @param multihash the base58 encoded multihash (should start with Qm) as a null terminated string
|
||||
* @param node the node to be created
|
||||
* @param fs_repo the repository
|
||||
* @returns true(1) on success
|
||||
*/
|
||||
int ipfs_merkledag_get_by_multihash(const unsigned char* multihash, size_t multihash_length, struct Node** node, const struct FSRepo* fs_repo);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -142,6 +142,13 @@ int ipfs_node_new(struct Node** node);
|
|||
*/
|
||||
int ipfs_node_create_directory(struct Node** node);
|
||||
|
||||
/***
|
||||
* Determine if this node is actually a directory
|
||||
* @param node the node to examine
|
||||
* @returns true(1) if this node is a directory. Otherwise, false(0)
|
||||
*/
|
||||
int ipfs_node_is_directory(struct Node* node);
|
||||
|
||||
/**
|
||||
* sets the Cid into the struct element titled cached
|
||||
* @param node the node to work with
|
||||
|
|
|
@ -11,8 +11,7 @@ OBJS = main.o \
|
|||
../datastore/ds_helper.o \
|
||||
../dnslink/dnslink.o \
|
||||
../flatfs/flatfs.o \
|
||||
../importer/importer.o \
|
||||
../importer/exporter.o \
|
||||
../importer/importer.o ../importer/exporter.o ../importer/resolver.o \
|
||||
../path/path.o \
|
||||
../merkledag/merkledag.o ../merkledag/node.o \
|
||||
../multibase/multibase.o \
|
||||
|
|
|
@ -78,3 +78,13 @@ int ipfs_merkledag_get(const unsigned char* hash, size_t hash_size, struct Node*
|
|||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ipfs_merkledag_get_by_multihash(const unsigned char* multihash, size_t multihash_length, struct Node** 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);
|
||||
}
|
||||
|
|
|
@ -385,6 +385,19 @@ int ipfs_node_create_directory(struct Node** node) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cached struct element
|
||||
* @param node the node to be modified
|
||||
|
|
|
@ -10,8 +10,7 @@ OBJS = testit.o test_helper.o \
|
|||
../core/builder.o \
|
||||
../datastore/ds_helper.o \
|
||||
../flatfs/flatfs.o \
|
||||
../importer/importer.o \
|
||||
../importer/exporter.o \
|
||||
../importer/importer.o ../importer/exporter.o ../importer/resolver.o \
|
||||
../merkledag/merkledag.o ../merkledag/node.o \
|
||||
../multibase/multibase.o \
|
||||
../os/utils.o \
|
||||
|
|
34
test/node/test_resolver.h
Normal file
34
test/node/test_resolver.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#include "ipfs/importer/resolver.h"
|
||||
|
||||
int test_resolver_get() {
|
||||
// clean out repository
|
||||
drop_and_build_repository("/Users/JohnJones/.ipfs");
|
||||
|
||||
int argc = 3;
|
||||
char* argv[argc];
|
||||
argv[0] = "ipfs";
|
||||
argv[1] = "add";
|
||||
argv[2] = "/Users/JohnJones/ipfstest";
|
||||
|
||||
ipfs_import_files(argc, (char**)argv);
|
||||
|
||||
struct FSRepo* fs_repo;
|
||||
ipfs_repo_fsrepo_new("/Users/JohnJones/.ipfs", NULL, &fs_repo);
|
||||
ipfs_repo_fsrepo_open(fs_repo);
|
||||
|
||||
// find something that is already in the repository
|
||||
struct Node* result = ipfs_resolver_get("/ipfs/QmbMecmXESf96ZNry7hRuzaRkEBhjqXpoYfPCwgFzVGDzB", NULL, fs_repo);
|
||||
if (result == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ipfs_node_free(result);
|
||||
|
||||
// find something by path
|
||||
result = ipfs_resolver_get("/ipfs/QmWKtXwRg4oL2KaXhvJ3KyGjFE2PVKREwu7qb65V7ficui/hello_world.txt", NULL, fs_repo);
|
||||
if (result == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
#include "merkledag/test_merkledag.h"
|
||||
#include "node/test_node.h"
|
||||
#include "node/test_importer.h"
|
||||
#include "node/test_resolver.h"
|
||||
#include "repo/test_repo_bootstrap_peers.h"
|
||||
#include "repo/test_repo_config.h"
|
||||
#include "repo/test_repo_fsrepo.h"
|
||||
|
@ -52,6 +53,7 @@ const char* names[] = {
|
|||
"test_merkledag_get_data",
|
||||
"test_merkledag_add_node",
|
||||
"test_merkledag_add_node_with_links",
|
||||
"test_resolver_get",
|
||||
"test_unixfs_encode_decode",
|
||||
"test_unixfs_encode_smallfile"
|
||||
};
|
||||
|
@ -85,6 +87,7 @@ int (*funcs[])(void) = {
|
|||
test_merkledag_get_data,
|
||||
test_merkledag_add_node,
|
||||
test_merkledag_add_node_with_links,
|
||||
test_resolver_get,
|
||||
test_unixfs_encode_decode,
|
||||
test_unixfs_encode_smallfile
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue