c2fe60949e
Files can be refered to directly using their hash, or the hash of their directory and the file name.
142 lines
4.4 KiB
C
142 lines
4.4 KiB
C
#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;
|
|
}
|