From a4b6a14ea524689556e9f9cf927a3519c64c0e24 Mon Sep 17 00:00:00 2001 From: Jose Marcial Vieira Bisneto Date: Thu, 1 Dec 2016 06:48:16 -0300 Subject: [PATCH] Initial implementation of path/resolver --- include/ipfs/path/path.h | 9 +++ path/resolver.c | 128 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 path/resolver.c diff --git a/include/ipfs/path/path.h b/include/ipfs/path/path.h index f2a97c1..2b3fdbb 100644 --- a/include/ipfs/path/path.h +++ b/include/ipfs/path/path.h @@ -35,4 +35,13 @@ int ParseCidToPath (char *dst, char *txt); int ParsePath (char *dst, char *txt); int PathIsValid (char *p); + + // Resolver provides path resolution to IPFS + // It has a pointer to a DAGService, which is uses to resolve nodes. + // TODO: now that this is more modular, try to unify this code with the + // the resolvers in namesys + typedef struct s_resolver { + DAGService DAG; + int (*ResolveOnce)(NodeLink **lnk, Context ctx, DAGService *ds, Node **nd, char *name); + } Resolver; #endif // IPFS_PATH_H diff --git a/path/resolver.c b/path/resolver.c new file mode 100644 index 0000000..15e9e70 --- /dev/null +++ b/path/resolver.c @@ -0,0 +1,128 @@ +#include "ipfs/cid/cid.h" +#include "ipfs/path/path.h" + +Resolver* NewBasicResolver (DAGService *ds) +{ + Resolver *ret = malloc(sizeof(Resolver)); + if (!ret) return NULL; + ret->DAG = ds; + ret->ResolveOnce = ResolveSingle; + return ret; +} + +// SplitAbsPath clean up and split fpath. It extracts the first component (which +// must be a Multihash) and return it separately. +int SplitAbsPath (struct Cid* cid, char ***parts, char *fpath) +{ + *parts = Segments(fpath); + + if (strcmp (**parts, "ipfs") == 0) *parts++; + + // if nothing, bail. + if (!**parts) return ErrNoComponents; + + // first element in the path is a cid + cid_decode_from_string(**parts, strlen(**parts), cid); + return 0; +} + +// ResolvePath fetches the node for given path. It returns the last item +// returned by ResolvePathComponents. +int ResolvePath(Node **nd, Context ctx, Resolver *s, char *fpath) +{ + int err = IsValid(fpath); + Node **ndd; + + if (err) { + return err; + } + err = ResolvePathComponents(&ndd, ctx, s, fpath); + if (err) { + return err; + } + if (ndd == NULL) { + return ErrBadPath; + } + while(*ndd) { + *nd = *ndd; + ndd++; + } + return 0; +} + +int ResolveSingle(NodeLink **lnk, Context ctx, DAGService *ds, Node **nd, char *name) +{ + return ResolveLink(lnk, name); +} + +// ResolvePathComponents fetches the nodes for each segment of the given path. +// It uses the first path component as a hash (key) of the first node, then +// resolves all other components walking the links, with ResolveLinks. +int ResolvePathComponents(Node ***nd, Context ctx, Resolver *s, char *fpath) +{ + int err; + struct Cid h; + char **parts; + + err = SplitAbsPath(&h, &parts, fpath); + if (err) { + return err; + } + + //log.Debug("resolve dag get"); + //*nd = s->DAG.Get(ctx, h); + //if (nd == DAG_ERR_VAL) { + // return DAG_ERR_VAL; + //} + + return ResolveLinks(ctx, *nd, parts); +} + +// ResolveLinks iteratively resolves names by walking the link hierarchy. +// Every node is fetched from the DAGService, resolving the next name. +// Returns the list of nodes forming the path, starting with ndd. This list is +// guaranteed never to be empty. +// +// ResolveLinks(nd, []string{"foo", "bar", "baz"}) +// would retrieve "baz" in ("bar" in ("foo" in nd.Links).Links).Links +int ResolveLinks(Node ***result, Context ctx, Node *ndd, char **names) +{ + int err, idx = 0; + NodeLink *lnk; + Node *nd; + + *result = calloc (sizeof(Node*), SegmentsLength(names) + 1); + if (!*result) { + return -1; + } + memset (*result, NULL, sizeof(Node*) * (SegmentsLength(names)+1)); + + *result[idx++] = ndd; + nd = ndd; // dup arg workaround + + while (*names) { + //TODO + //var cancel context.CancelFunc + //ctx, cancel = context.WithTimeout(ctx, time.Minute) + //defer cancel() + + // for each of the path components + err = ResolveLink(&lnk, *names); + if (err) { + char msg[51]; + *result[idx] = NULL; + snprintf(msg, sizeof(msg), ErrPath[ErrNoLinkFmt], *names, nd->Cid); + if (ErrPath[ErrNoLink]) { + free(ErrPath[ErrNoLink]); + } + ErrPath[ErrNoLink] = malloc(strlen(msg) + 1); + if (ErrPath[ErrNoLink]) { + strcpy(ErrPath[ErrNoLink], msg); + } + free (*result); + return ErrNoLink; + } + names++; + } + return 0; +}