diff --git a/LICENSE b/LICENSE index 3fff97c..42c3bed 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2016 BitShares Munich IVS +Copyright (c) 2017 BitShares Munich IVS Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/cid/Makefile b/cid/Makefile index bb4c1ee..638d6c9 100644 --- a/cid/Makefile +++ b/cid/Makefile @@ -7,7 +7,7 @@ endif LFLAGS = DEPS = -OBJS = cid.o +OBJS = cid.o set.o %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) diff --git a/cid/set.c b/cid/set.c new file mode 100644 index 0000000..4c2438d --- /dev/null +++ b/cid/set.c @@ -0,0 +1,181 @@ +#include +#include +#include "ipfs/cid/cid.h" +#include "ipfs/util/errs.h" + +struct CidSet *ipfs_cid_set_new () +{ + return calloc(1, sizeof(struct CidSet)); +} + +void ipfs_cid_set_destroy (struct CidSet **set) +{ + struct CidSet *prev; + + if (set) { + while (*set) { + prev = *set; + *set = (*set)->next; + if (prev->cid) { + free (prev->cid); + } + free (prev); + } + } +} + +int ipfs_cid_set_add (struct CidSet *set, struct Cid *cid, int visit) +{ + if (!set || !cid) { + return ErrInvalidParam; + } + if (!set->cid) { // First item. + set->cid = malloc(sizeof (struct Cid)); + if (!set->cid) { + return ErrAllocFailed; + } + memcpy(set->cid, cid, sizeof (struct Cid)); + set->cid->hash = calloc(1, cid->hash_length); + if (!set->cid->hash) { + free (set->cid); + return ErrAllocFailed; + } + memcpy(set->cid->hash, cid->hash, cid->hash_length); + return 0; + } + for (;;) { + if ((set->cid->hash_length == cid->hash_length) && + (memcmp(set->cid->hash, cid->hash, cid->hash_length)==0)) { + // Already added. + if (!visit) { + // update with new cid. + free(set->cid->hash); + memcpy(set->cid, cid, sizeof (struct Cid)); + set->cid->hash = calloc(1, cid->hash_length); + if (!set->cid->hash) { + return ErrAllocFailed; + } + memcpy(set->cid->hash, cid->hash, cid->hash_length); + } + return 0; + } + if (!set->next) { + set->next = ipfs_cid_set_new(); + if (!set->next) { + return ErrAllocFailed; + } + set = set->next; + set->cid = malloc(sizeof (struct Cid)); + if (!set->cid) { + return ErrAllocFailed; + } + memcpy(set->cid, cid, sizeof (struct Cid)); + set->cid->hash = calloc(1, cid->hash_length); + if (!set->cid->hash) { + return ErrAllocFailed; + } + memcpy(set->cid->hash, cid->hash, cid->hash_length); + return 0; + } + set = set->next; + } +} + +int ipfs_cid_set_has (struct CidSet *set, struct Cid *cid) +{ + if (!set || !cid || !set->cid) { + return 0; + } + for (;;) { + if ((set->cid->hash_length == cid->hash_length) && + (memcmp(set->cid->hash, cid->hash, cid->hash_length)==0)) { + return 1; // has + } + if (!set->next) { + return 0; // end without found. + } + set = set->next; + } +} + +int ipfs_cid_set_remove (struct CidSet *set, struct Cid *cid) +{ + struct CidSet *prev = set; + + if (!set || !cid || !set->cid) { + return 0; + } + for (;;) { + if ((set->cid->hash_length == cid->hash_length) && + (memcmp(set->cid->hash, cid->hash, cid->hash_length)==0)) { + free (set->cid); + if (prev == set) { // first item + set = set->next; + if (!set) { + prev->cid = NULL; + return 1; + } + prev->cid = set->cid; + } else { + prev->next = set->next; + } + free (set); + return 1; // removed + } + if (!set->next) { + return 0; // end without found. + } + prev = set; + set = set->next; + } +} + +int ipfs_cid_set_len (struct CidSet *set) +{ + int len; + + if (!set || !set->cid) { + return 0; + } + + for (len = 0 ; set ; len++, set = set->next); + + return len; +} + +unsigned char **ipfs_cid_set_keys (struct CidSet *set) +{ + int i, len=ipfs_cid_set_len(set); + unsigned char **ret; + + ret = calloc(len+1, sizeof(char*)); + if (ret) { + for (i = 0 ; icid && set->cid->hash) { + ret[i] = calloc(1, set->cid->hash_length + 1); + if (ret[i]) { + memcpy(ret[i], set->cid->hash, set->cid->hash_length); + } + } + set = set->next; + } + } + return ret; +} + +int ipfs_cid_set_foreach (struct CidSet *set, int (*func)(struct Cid *)) +{ + int err = 0; + + while (set) { + if (set->cid) { + err = func (set->cid); + if (err) { + return err; + } + } + set = set->next; + } + + return err; +} diff --git a/dnslink/dnslink.c b/dnslink/dnslink.c index c88125f..fbcf3b0 100644 --- a/dnslink/dnslink.c +++ b/dnslink/dnslink.c @@ -46,9 +46,49 @@ Expect these resolutions: #include #include -#include -#include -#include +#ifdef __MINGW32__ + #include + + #define u_char unsigned char + #define u_int16_t uint16_t + #define u_int32_t uint32_t + #define NS_MAXDNAME 1025 /*%< maximum domain name */ + #define ns_c_in 1 + #define ns_t_txt 16 + + typedef enum __ns_sect { + ns_s_qd = 0, /*%< Query: Question. */ + ns_s_zn = 0, /*%< Update: Zone. */ + ns_s_an = 1, /*%< Query: Answer. */ + ns_s_pr = 1, /*%< Update: Prerequisites. */ + ns_s_ns = 2, /*%< Query: Name servers. */ + ns_s_ud = 2, /*%< Update: Update. */ + ns_s_ar = 3, /*%< Query|Update: Additional records. */ + ns_s_max = 4 + } ns_sect; + + typedef struct __ns_msg { + const unsigned char *_msg, *_eom; + u_int16_t _id, _flags, _counts[ns_s_max]; + const unsigned char *_sections[ns_s_max]; + ns_sect _sect; + int _rrnum; + const unsigned char *_msg_ptr; + } ns_msg; + + typedef struct __ns_rr { + char name[NS_MAXDNAME]; + u_int16_t type; + u_int16_t rr_class; + u_int32_t ttl; + u_int16_t rdlength; + const u_char * rdata; + } ns_rr; +#else + #include + #include + #include +#endif #include "ipfs/namesys/namesys.h" #define IPFS_DNSLINK_C #include "ipfs/dnslink/dnslink.h" @@ -57,65 +97,71 @@ Expect these resolutions: int ipfs_dns (int argc, char **argv) { - int err, r=0, i; - char **txt, *path, *param; - - if (argc == 4 && strcmp ("-r", argv[2])==0) { - r = 1; - argc--; argv++; - } - - if (argc != 3) { - fprintf (stderr, "usage: ipfs dns [-r] dns.name.com\n"); +#ifdef __MINGW32__ + fprintf (stderr, "Sorry, dns has not yet been implemented for the Windows version.\n"); return -1; } +#else + int err, r=0, i; + char **txt, *path, *param; - param = malloc (strlen (argv[2]) + 1); - if (!param) { - fprintf (stderr, "memory allocation failed.\n"); - return 1; - } - strcpy (param, argv[2]); - - for (i = 0 ; i < DefaultDepthLimit ; i++) { - if (memcmp(param, "/ipns/", 6) == 0) { - err = ipfs_dnslink_resolv_lookupTXT (&txt, param+6); - } else { - err = ipfs_dnslink_resolv_lookupTXT (&txt, param); - } - if (err) { - fprintf (stderr, "dns lookupTXT: %s\n", Err[err]); - return err; + if (argc == 4 && strcmp ("-r", argv[2])==0) { + r = 1; + argc--; argv++; } - err = ipfs_dnslink_parse_txt(&path, *txt); - if (err) { + if (argc != 3) { + fprintf (stderr, "usage: ipfs dns [-r] dns.name.com\n"); + return -1; + } + + param = malloc (strlen (argv[2]) + 1); + if (!param) { + fprintf (stderr, "memory allocation failed.\n"); + return 1; + } + strcpy (param, argv[2]); + + for (i = 0 ; i < DefaultDepthLimit ; i++) { + if (memcmp(param, "/ipns/", 6) == 0) { + err = ipfs_dnslink_resolv_lookupTXT (&txt, param+6); + } else { + err = ipfs_dnslink_resolv_lookupTXT (&txt, param); + } + free (param); + + if (err) { + fprintf (stderr, "dns lookupTXT: %s\n", Err[err]); + return err; + } + + err = ipfs_dnslink_parse_txt(&path, *txt); + if (err) { + free (*txt); + free (txt); + fprintf (stderr, "dns parse_txt: %s\n", Err[err]); + return err; + } + free (*txt); free (txt); - fprintf (stderr, "dns parse_txt: %s\n", Err[err]); - return err; - } + param = path; - free (*txt); - free (txt); + if (! r) { + // not recursive. + break; + } + + if (memcmp(path, "/ipfs/", 6) == 0) { + break; + } + } while (--r); + fprintf (stdout, "%s\n", param); free (param); - if (! r) { - // not recursive. - break; - } - - if (memcmp(path, "/ipfs/", 6) == 0) { - break; - } - - param = path; - } while (--r); - fprintf (stdout, "%s\n", path); - free (path); - - return 0; -} + return 0; + } +#endif // MINGW // ipfs_dnslink_resolve resolves the dnslink at a particular domain. It will // recursively keep resolving until reaching the defaultDepth of Resolver. If @@ -190,56 +236,58 @@ int ipfs_dnslink_resolve_n (char **p, char *d, int depth) return ErrResolveLimit; } -// lookup using libresolv -lresolv -int ipfs_dnslink_resolv_lookupTXT(char ***txt, char *domain) -{ - char buf[4096], *p; - int responseLength; - int i, l, n = 0; - ns_msg query_parse_msg; - ns_rr query_parse_rr; - u_char responseByte[4096]; +#ifndef __MINGW32__ + // lookup using libresolv -lresolv + int ipfs_dnslink_resolv_lookupTXT(char ***txt, char *domain) + { + char buf[4096], *p; + int responseLength; + int i, l, n = 0; + ns_msg query_parse_msg; + ns_rr query_parse_rr; + u_char responseByte[4096]; - // Use res_query from libresolv to retrieve TXT record from DNS server. - if ((responseLength = res_query(domain,ns_c_in,ns_t_txt,responseByte,sizeof(responseByte))) < 0 || - ns_initparse(responseByte,responseLength,&query_parse_msg) < 0) { - return ErrResolveFailed; - } else { - l = sizeof (buf); - buf[--l] = '\0'; - p = buf; - // save every TXT record to buffer separating with a \0 - for (i=0 ; i < ns_msg_count(query_parse_msg,ns_s_an) ; i++) { - if (ns_parserr(&query_parse_msg,ns_s_an,i,&query_parse_rr)) { - return ErrResolveFailed; - } else { - char *rdata = ns_rr_rdata(query_parse_rr); - memcpy(p, rdata+1, *rdata); // first byte is record length - p += *rdata; // update pointer - *p++ = '\0'; // mark end-of-record and update pointer to next record. - n++; // update record count + // Use res_query from libresolv to retrieve TXT record from DNS server. + if ((responseLength = res_query(domain,ns_c_in,ns_t_txt,responseByte,sizeof(responseByte))) < 0 || + ns_initparse(responseByte,responseLength,&query_parse_msg) < 0) { + return ErrResolveFailed; + } else { + l = sizeof (buf); + buf[--l] = '\0'; + p = buf; + // save every TXT record to buffer separating with a \0 + for (i=0 ; i < ns_msg_count(query_parse_msg,ns_s_an) ; i++) { + if (ns_parserr(&query_parse_msg,ns_s_an,i,&query_parse_rr)) { + return ErrResolveFailed; + } else { + char *rdata = ns_rr_rdata(query_parse_rr); + memcpy(p, rdata+1, *rdata); // first byte is record length + p += *rdata; // update pointer + *p++ = '\0'; // mark end-of-record and update pointer to next record. + n++; // update record count + } + } + // allocate array for all records + NULL pointer terminator. + *txt = calloc(n+1, sizeof(void*)); + if (!*txt) { + return ErrAllocFailed; + } + l = p - buf; // length of all records in buffer. + p = malloc(l); // allocate memory that will be used as string data at *txt array. + if (!p) { + free(*txt); + *txt = NULL; + return ErrAllocFailed; + } + memcpy(p, buf, l); // transfer from buffer to allocated memory. + for (i = 0 ; i < n ; i++) { + *txt[i] = p; // save position of current record at *txt array. + p = memchr(p, '\0', l - (p - *txt[0])) + 1; // find next record position after next \0 } } - // allocate array for all records + NULL pointer terminator. - *txt = calloc(n+1, sizeof(void*)); - if (!*txt) { - return ErrAllocFailed; - } - l = p - buf; // length of all records in buffer. - p = malloc(l); // allocate memory that will be used as string data at *txt array. - if (!p) { - free(*txt); - *txt = NULL; - return ErrAllocFailed; - } - memcpy(p, buf, l); // transfer from buffer to allocated memory. - for (i = 0 ; i < n ; i++) { - *txt[i] = p; // save position of current record at *txt array. - p = memchr(p, '\0', l - (p - *txt[0])) + 1; // find next record position after next \0 - } + return 0; } - return 0; -} +#endif // ipfs_dnslink_resolve_once implements resolver. int ipfs_dnslink_resolve_once (char ***p, char *domain) @@ -257,11 +305,13 @@ int ipfs_dnslink_resolve_once (char ***p, char *domain) return ErrInvalidDomain; } +#ifndef __MINGW32__ if (!ipfs_dnslink_lookup_txt) { // if not set ipfs_dnslink_lookup_txt = ipfs_dnslink_resolv_lookupTXT; // use default libresolv } err = ipfs_dnslink_lookup_txt (&txt, domain); +#endif if (err) { return err; } diff --git a/flatfs/flatfs.c b/flatfs/flatfs.c index fe06dba..0d1101b 100644 --- a/flatfs/flatfs.c +++ b/flatfs/flatfs.c @@ -50,8 +50,11 @@ int ipfs_flatfs_create_directory(const char* full_directory) { return 0; } // it is not there, create it +#ifdef __MINGW32__ + if (mkdir(full_directory) == -1) +#else if (mkdir(full_directory, S_IRWXU) == -1) - return 0; +#endif return 0; return 1; } diff --git a/include/ipfs/cid/cid.h b/include/ipfs/cid/cid.h index a145d7e..dfff375 100644 --- a/include/ipfs/cid/cid.h +++ b/include/ipfs/cid/cid.h @@ -26,6 +26,11 @@ struct Cid { size_t hash_length; }; +struct CidSet { + struct Cid *cid; + struct CidSet *next; +}; + /*** * encode a Cid into a protobuf array of bytes * @param incoming the incoming Cid struct @@ -95,4 +100,13 @@ int ipfs_cid_hash_to_base58(const unsigned char* hash, size_t hash_length, unsig */ int ipfs_cid_cast(const unsigned char* incoming, size_t incoming_size, struct Cid* cid); +struct CidSet *ipfs_cid_set_new (); +void ipfs_cid_set_destroy (struct CidSet **set); +int ipfs_cid_set_add (struct CidSet *set, struct Cid *cid, int visit); +int ipfs_cid_set_has (struct CidSet *set, struct Cid *cid); +int ipfs_cid_set_remove (struct CidSet *set, struct Cid *cid); +int ipfs_cid_set_len (struct CidSet *set); +unsigned char **ipfs_cid_set_keys (struct CidSet *set); +int ipfs_cid_set_foreach (struct CidSet *set, int (*func)(struct Cid *)); + #endif diff --git a/include/ipfs/pin/pin.h b/include/ipfs/pin/pin.h index 9564340..bd6d62c 100644 --- a/include/ipfs/pin/pin.h +++ b/include/ipfs/pin/pin.h @@ -40,4 +40,8 @@ // Return array index or -1 if fail. PinMode ipfs_string_to_pin_mode (char *str); int ipfs_pin_is_pinned (struct Pinned *p); + // Find out if the child is in the hash. + int ipfs_pin_has_child (struct FSRepo *ds, + unsigned char *hash, size_t hash_size, + unsigned char *child, size_t child_size); #endif // IPFS_PIN_H diff --git a/main/main.c b/main/main.c index 1958b34..b0c1a63 100644 --- a/main/main.c +++ b/main/main.c @@ -6,6 +6,33 @@ #include "ipfs/importer/exporter.h" #include "ipfs/dnslink/dnslink.h" +#ifdef __MINGW32__ + void bzero(void *s, size_t n) + { + memset (s, '\0', n); + } + + char *strtok_r(char *str, const char *delim, char **save) + { + char *res, *last; + + if( !save ) + return strtok(str, delim); + if( !str && !(str = *save) ) + return NULL; + last = str + strlen(str); + if( (*save = res = strtok(str, delim)) ) + { + *save += strlen(res); + if( *save < last ) + (*save)++; + else + *save = NULL; + } + return res; + } +#endif // MINGW + void stripit(int argc, char** argv) { char tmp[strlen(argv[argc])]; strcpy(tmp, &argv[argc][1]); diff --git a/os/utils.c b/os/utils.c index 76e162a..4ba8443 100644 --- a/os/utils.c +++ b/os/utils.c @@ -1,9 +1,12 @@ #include "ipfs/os/utils.h" +#include #include #include #include -#include +#ifndef __MINGW32__ + #include +#endif #include #include #include @@ -25,7 +28,11 @@ char* os_utils_getenv(const char* variable) { * @returns true(1) on success */ int os_utils_setenv(const char* variable, const char* value, int overwrite) { - return setenv(variable, value, overwrite); +#ifdef __MINGW32__ + return 0; +#else + setenv(variable, value, overwrite); +#endif } /** @@ -33,8 +40,11 @@ int os_utils_setenv(const char* variable, const char* value, int overwrite) { * @returns the home directory */ char* os_utils_get_homedir() { +#ifndef __MINGW32__ struct passwd *pw = getpwuid(getuid()); return pw->pw_dir; +#endif + return "."; } /** diff --git a/pin/pin.c b/pin/pin.c index f9ac59f..8fe507b 100644 --- a/pin/pin.c +++ b/pin/pin.c @@ -1,11 +1,14 @@ #include #include +#include "ipfs/repo/fsrepo/fs_repo.h" + #define IPFS_PIN_C #include "ipfs/pin/pin.h" #include "ipfs/cid/cid.h" #include "ipfs/datastore/key.h" +#include "ipfs/merkledag/merkledag.h" #include "ipfs/util/errs.h" // package pin implements structures and methods to keep track of @@ -110,3 +113,35 @@ char *ipfs_pin_pinned_msg (struct Pinned *p) } return ret; } + +// Find out if the child is in the hash. +int ipfs_pin_has_child (struct FSRepo *ds, + unsigned char *hash, size_t hash_size, + unsigned char *child, size_t child_size) +{ + struct Node *node; + struct NodeLink *node_link; + + if (ipfs_merkledag_get (hash, hash_size, &node, ds)) { + if (node) { + if ((node->hash_size == child_size) && + (memcmp (node->hash, child, child_size) == 0)) { + return 1; + } + // browse the node links. + for (node_link = node->head_link ; node_link ; node_link = node_link->next) { + if ((node_link->hash_size == child_size) && + (memcmp (node_link->hash, child, child_size) != 0) && + ipfs_pin_has_child (ds, node_link->hash, node_link->hash_size, + child, child_size)) { + return 1; + } + if ((node_link->hash_size == child_size) && + (memcmp (node_link->hash, child, child_size) == 0)) { + return 1; // child is a child of the hash node. + } + } + } + } + return 0; +} diff --git a/repo/fsrepo/fs_repo.c b/repo/fsrepo/fs_repo.c index 57f901a..aa80b54 100644 --- a/repo/fsrepo/fs_repo.c +++ b/repo/fsrepo/fs_repo.c @@ -482,7 +482,11 @@ int ipfs_repo_fsrepo_blockstore_init(const struct FSRepo* fs_repo) { if (retVal == 0) return 0; +#ifdef __MINGW32__ + if (mkdir(full_path) != 0) +#else if (mkdir(full_path, S_IRWXU) != 0) +#endif return 0; return 1; } diff --git a/repo/fsrepo/lmdb_datastore.c b/repo/fsrepo/lmdb_datastore.c index 1bcd5a9..663897e 100644 --- a/repo/fsrepo/lmdb_datastore.c +++ b/repo/fsrepo/lmdb_datastore.c @@ -183,6 +183,10 @@ int repo_fsrepo_lmdb_cast(struct Datastore* datastore) { * @returns true(1) on success */ int repo_fsrepo_lmdb_create_directory(struct Datastore* datastore) { +#ifdef __MINGW32__ + return mkdir(datastore->path) == 0; +#else return mkdir(datastore->path, S_IRWXU) == 0; +#endif } diff --git a/repo/init.c b/repo/init.c index a3c4b34..49db57f 100644 --- a/repo/init.c +++ b/repo/init.c @@ -74,7 +74,11 @@ int ipfs_repo_init(int argc, char** argv) { return 0; } // make the directory +#ifdef __MINGW32__ + if (mkdir(dir) == -1) { +#else if (mkdir(dir, S_IRWXU) == -1) { +#endif printf("Unable to create the directory: %s\n", dir); return 0; }