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.
yamux
jmjatlanta 2016-12-29 19:05:44 -05:00
parent 396dfc6abc
commit c2fe60949e
11 changed files with 233 additions and 5 deletions

View File

@ -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
View 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, &current_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, &current_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;
}

View 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);

View File

@ -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

View File

@ -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

View File

@ -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 \

View File

@ -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);
}

View File

@ -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

View File

@ -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
View 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;
}

View File

@ -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
};