ruby-libstorj 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +1 -0
  5. data/Gemfile +23 -0
  6. data/Gemfile.lock +111 -0
  7. data/Guardfile +21 -0
  8. data/LICENSE +502 -0
  9. data/README.md +262 -0
  10. data/Rakefile +76 -0
  11. data/ext/libstorj/.gitignore +47 -0
  12. data/ext/libstorj/.travis.yml +27 -0
  13. data/ext/libstorj/Doxyfile +2427 -0
  14. data/ext/libstorj/LICENSE +502 -0
  15. data/ext/libstorj/Makefile.am +6 -0
  16. data/ext/libstorj/README.md +198 -0
  17. data/ext/libstorj/autogen.sh +3 -0
  18. data/ext/libstorj/configure.ac +64 -0
  19. data/ext/libstorj/depends/Makefile +153 -0
  20. data/ext/libstorj/depends/config.guess +1462 -0
  21. data/ext/libstorj/depends/config.sub +1823 -0
  22. data/ext/libstorj/depends/extract-osx-sdk.sh +33 -0
  23. data/ext/libstorj/depends/packages/cctools.mk +7 -0
  24. data/ext/libstorj/depends/packages/clang.mk +7 -0
  25. data/ext/libstorj/depends/packages/gmp.mk +23 -0
  26. data/ext/libstorj/depends/packages/gnutls.mk +25 -0
  27. data/ext/libstorj/depends/packages/json-c.mk +7 -0
  28. data/ext/libstorj/depends/packages/libcurl.mk +39 -0
  29. data/ext/libstorj/depends/packages/libmicrohttpd.mk +7 -0
  30. data/ext/libstorj/depends/packages/libuv.mk +7 -0
  31. data/ext/libstorj/depends/packages/nettle.mk +30 -0
  32. data/ext/libstorj/libstorj.pc.in +11 -0
  33. data/ext/libstorj/src/Makefile.am +23 -0
  34. data/ext/libstorj/src/bip39.c +233 -0
  35. data/ext/libstorj/src/bip39.h +64 -0
  36. data/ext/libstorj/src/bip39_english.h +2074 -0
  37. data/ext/libstorj/src/cli.c +1494 -0
  38. data/ext/libstorj/src/crypto.c +525 -0
  39. data/ext/libstorj/src/crypto.h +178 -0
  40. data/ext/libstorj/src/downloader.c +1923 -0
  41. data/ext/libstorj/src/downloader.h +163 -0
  42. data/ext/libstorj/src/http.c +688 -0
  43. data/ext/libstorj/src/http.h +175 -0
  44. data/ext/libstorj/src/rs.c +962 -0
  45. data/ext/libstorj/src/rs.h +99 -0
  46. data/ext/libstorj/src/storj.c +1523 -0
  47. data/ext/libstorj/src/storj.h +1014 -0
  48. data/ext/libstorj/src/uploader.c +2736 -0
  49. data/ext/libstorj/src/uploader.h +181 -0
  50. data/ext/libstorj/src/utils.c +336 -0
  51. data/ext/libstorj/src/utils.h +65 -0
  52. data/ext/libstorj/test/Makefile.am +27 -0
  53. data/ext/libstorj/test/mockbridge.c +260 -0
  54. data/ext/libstorj/test/mockbridge.json +687 -0
  55. data/ext/libstorj/test/mockbridgeinfo.json +1836 -0
  56. data/ext/libstorj/test/mockfarmer.c +358 -0
  57. data/ext/libstorj/test/storjtests.h +41 -0
  58. data/ext/libstorj/test/tests.c +1617 -0
  59. data/ext/libstorj/test/tests_rs.c +869 -0
  60. data/ext/ruby-libstorj/extconf.rb +8 -0
  61. data/ext/ruby-libstorj/ruby-libstorj.cc +17 -0
  62. data/lib/ruby-libstorj.rb +1 -0
  63. data/lib/ruby-libstorj/arg_forwarding_task.rb +58 -0
  64. data/lib/ruby-libstorj/env.rb +178 -0
  65. data/lib/ruby-libstorj/ext/bucket.rb +71 -0
  66. data/lib/ruby-libstorj/ext/create_bucket_request.rb +53 -0
  67. data/lib/ruby-libstorj/ext/curl_code.rb +139 -0
  68. data/lib/ruby-libstorj/ext/ext.rb +71 -0
  69. data/lib/ruby-libstorj/ext/file.rb +84 -0
  70. data/lib/ruby-libstorj/ext/get_bucket_request.rb +45 -0
  71. data/lib/ruby-libstorj/ext/json_request.rb +51 -0
  72. data/lib/ruby-libstorj/ext/list_files_request.rb +63 -0
  73. data/lib/ruby-libstorj/ext/types.rb +226 -0
  74. data/lib/ruby-libstorj/ext/upload_options.rb +38 -0
  75. data/lib/ruby-libstorj/libstorj.rb +22 -0
  76. data/lib/ruby-libstorj/mixins/storj.rb +27 -0
  77. data/lib/ruby-libstorj/struct.rb +42 -0
  78. data/ruby-libstorj.gemspec +57 -0
  79. data/spec/helpers/options.yml.example +22 -0
  80. data/spec/helpers/shared_rake_examples.rb +132 -0
  81. data/spec/helpers/storj_options.rb +96 -0
  82. data/spec/helpers/upload.data +3 -0
  83. data/spec/helpers/upload.data.sha256 +1 -0
  84. data/spec/libstorj_spec.rb +0 -0
  85. data/spec/ruby-libstorj/arg_forwarding_task_spec.rb +311 -0
  86. data/spec/ruby-libstorj/env_spec.rb +353 -0
  87. data/spec/ruby-libstorj/ext_spec.rb +75 -0
  88. data/spec/ruby-libstorj/json_request_spec.rb +13 -0
  89. data/spec/ruby-libstorj/libstorj_spec.rb +81 -0
  90. data/spec/ruby-libstorj/struct_spec.rb +64 -0
  91. data/spec/spec_helper.rb +113 -0
  92. metadata +136 -0
@@ -0,0 +1,178 @@
1
+ /**
2
+ * @file crypto.h
3
+ * @brief Storj crypto utilities.
4
+ *
5
+ * Helper crypto utilities
6
+ */
7
+ #ifndef STORJ_CRYPTO_H
8
+ #define STORJ_CRYPTO_H
9
+
10
+ #include <nettle/aes.h>
11
+ #include <nettle/ripemd160.h>
12
+ #include <nettle/hmac.h>
13
+ #include <nettle/pbkdf2.h>
14
+ #include <nettle/sha.h>
15
+ #include <nettle/ctr.h>
16
+ #include <nettle/gcm.h>
17
+ #include <nettle/base64.h>
18
+
19
+ #include "bip39.h"
20
+ #include "utils.h"
21
+
22
+ #define DETERMINISTIC_KEY_SIZE 64
23
+ #define DETERMINISTIC_KEY_HEX_SIZE 32
24
+ #define BUCKET_NAME_MAGIC "398734aab3c4c30c9f22590e83a95f7e43556a45fc2b3060e0c39fde31f50272"
25
+
26
+ static const uint8_t BUCKET_META_MAGIC[32] = {66,150,71,16,50,114,88,160,163,35,154,65,162,213,226,215,70,138,57,61,52,19,210,170,38,164,162,200,86,201,2,81};
27
+
28
+ int sha256_of_str(const uint8_t *str, int str_len, uint8_t *digest);
29
+
30
+ int sha512_of_str(const uint8_t *str, int str_len, uint8_t *digest);
31
+
32
+ int ripemd160_of_str(const uint8_t *str, int str_len, uint8_t *digest);
33
+
34
+ int ripemd160sha256(uint8_t *data, uint64_t data_size, uint8_t *digest);
35
+
36
+ int ripemd160sha256_as_string(uint8_t *data, uint64_t data_size, char *digest);
37
+
38
+ int double_ripemd160sha256(uint8_t *data, uint64_t data_size, uint8_t *digest);
39
+
40
+ int double_ripemd160sha256_as_string(uint8_t *data, uint64_t data_size,
41
+ char **digest);
42
+
43
+ void pbkdf2_hmac_sha512(unsigned key_length,
44
+ const uint8_t *key,
45
+ unsigned iterations,
46
+ unsigned salt_length, const uint8_t *salt,
47
+ unsigned length, uint8_t *dst);
48
+
49
+ /**
50
+ * @brief Generate a bucket's key
51
+ *
52
+ * @param[in] Character array of the mnemonic
53
+ * @param[in] bucket_id Character array of bucket id
54
+ * @param[out] bucket_key 64 byte character array that is the bucket's key
55
+ * @return A non-zero error value on failure and 0 on success.
56
+ */
57
+ int generate_bucket_key(const char *mnemonic, const char *bucket_id,
58
+ char **bucket_key);
59
+
60
+ /**
61
+ * @brief Generate a file's key
62
+ *
63
+ * @param[in] Character array of the mnemonic
64
+ * @param[in] bucket_id Character array of bucket id
65
+ * @param[in] index Character array of index
66
+ * @param[out] file_key 64 byte character array that is the bucket's key
67
+ * @return A non-zero error value on failure and 0 on success.
68
+ */
69
+ int generate_file_key(const char *mnemonic,
70
+ const char *bucket_id,
71
+ const char *index,
72
+ char **file_key);
73
+
74
+ /**
75
+ * @brief Calculate deterministic key by getting sha512 of key + id
76
+ *
77
+ * @param[in] Character array of the key
78
+ * @param[in] key_len Integer value of length of key
79
+ * @param[in] id Character array id
80
+ * @param[out] buffer 64 byte character array of the deterministic key
81
+ * @return A non-zero error value on failure and 0 on success.
82
+ */
83
+ int get_deterministic_key(const char *key, int key_len,
84
+ const char *id, char **buffer);
85
+
86
+ /**
87
+ * @brief Increment the iv for ctr decryption/encryption
88
+ *
89
+ * This function will modify iv and increment the counter based
90
+ * on the bytes position and the AES block size, useful for decrypting
91
+ * shards asynchronously.
92
+ *
93
+ * The iv must be 16 bytes, the AES block size, and the bytes_position
94
+ * must a multiple of 16.
95
+ *
96
+ * @param[out] iv The ctr/iv to be incremented
97
+ * @return A non-zero value on failure
98
+ */
99
+ int increment_ctr_aes_iv(uint8_t *iv, uint64_t bytes_position);
100
+
101
+ /**
102
+ * @brief Will derive an encryption key from passhrase
103
+ *
104
+ * Will use PBKDF2 to generate an encryption key from the passphrase.
105
+ *
106
+ * @param[in] passphrase - The passhrase
107
+ * @param[in] salt - The salt used in the key derivation function
108
+ * @return A key or NULL on failure.
109
+ */
110
+ uint8_t *key_from_passphrase(const char *passphrase, const char *salt);
111
+
112
+ /**
113
+ * @brief Will encrypt data with passphrase
114
+ *
115
+ * Data is encrypted using AES-256-CTR with a key generated from a key
116
+ * derivation function with the passphrase.
117
+ *
118
+ * @param[in] passphrase - The passhrase used to encrypt the data
119
+ * @param[in] salt - The salt used in the key derivation function
120
+ * @param[in] data - The data to be encrypted
121
+ * @param[out] result - The encrypted data encoded as hex string
122
+ * @return A non-zero error value on failure and 0 on success.
123
+ */
124
+ int encrypt_data(const char *passphrase,
125
+ const char *salt,
126
+ const char *data,
127
+ char **result);
128
+
129
+ /**
130
+ * @brief Will decrypt data with passphrase
131
+ *
132
+ * Data is decrypted using AES-256-CTR with a key generated from a key
133
+ * derivation function with the passphrase.
134
+ *
135
+ * @param[in] passphrase - The passhrase used to encrypt the data
136
+ * @param[in] salt - The salt used in the key derivation function
137
+ * @param[in] data - The hex string of encoded data
138
+ * @param[out] result - The decrypted data
139
+ */
140
+ int decrypt_data(const char *passphrase,
141
+ const char *salt,
142
+ const char *data,
143
+ char **result);
144
+
145
+ /**
146
+ * @brief Will encrypt file meta
147
+ *
148
+ * This will encrypt file meta information using AES-256-GCM. The
149
+ * resulting buffer will concat digest, iv and cipher text as base54
150
+ * null terminated string.
151
+ *
152
+ * @param[in] filemeta - The null terminated filename
153
+ * @param[in] encrypt_key - The key used to encrypt the file meta (32 bytes)
154
+ * @param[in] encrypt_iv - The iv to use for encryption (32 bytes)
155
+ * @param[out] buffer_base64 - The base64 encoded encrypted data including
156
+ * digest, iv and cipher text
157
+ * @return A non-zero value on error, zero on success.
158
+ */
159
+ int encrypt_meta(const char *filemeta,
160
+ uint8_t *encrypt_key,
161
+ uint8_t *encrypt_iv,
162
+ char **buffer_base64);
163
+
164
+ /**
165
+ * @brief Will decrypt file meta
166
+ *
167
+ * This will decrypt file meta information.
168
+ *
169
+ * @param[in] buffer_base64 - The base64 encrypted data
170
+ * @param[in] decrypt_key - The key used to decrypt the file (32 bytes)
171
+ * @param[out] filemeta - The null terminated filename
172
+ * @return A non-zero value on error, zero on success.
173
+ */
174
+ int decrypt_meta(const char *buffer_base64,
175
+ uint8_t *decrypt_key,
176
+ char **filemeta);
177
+
178
+ #endif /* STORJ_CRYPTO_H */
@@ -0,0 +1,1923 @@
1
+ #include "downloader.h"
2
+
3
+ static void free_exchange_report(storj_exchange_report_t *report)
4
+ {
5
+ free(report->data_hash);
6
+ free(report->reporter_id);
7
+ free(report->farmer_id);
8
+ free(report->client_id);
9
+ free(report);
10
+ }
11
+
12
+ static void free_download_state(storj_download_state_t *state)
13
+ {
14
+ for (int i = 0; i < state->total_pointers; i++) {
15
+ storj_pointer_t *pointer = &state->pointers[i];
16
+
17
+ free(pointer->token);
18
+ free(pointer->shard_hash);
19
+ free(pointer->farmer_id);
20
+ free(pointer->farmer_address);
21
+
22
+ free_exchange_report(pointer->report);
23
+ }
24
+
25
+ if (state->excluded_farmer_ids) {
26
+ free(state->excluded_farmer_ids);
27
+ }
28
+
29
+ if (state->decrypt_key) {
30
+ memset_zero(state->decrypt_key, SHA256_DIGEST_SIZE);
31
+ free(state->decrypt_key);
32
+ }
33
+
34
+ if (state->decrypt_ctr) {
35
+ memset_zero(state->decrypt_ctr, AES_BLOCK_SIZE);
36
+ free(state->decrypt_ctr);
37
+ }
38
+
39
+ if (state->info) {
40
+ if (state->info->erasure) {
41
+ free((char *)state->info->erasure);
42
+ }
43
+ free((char *)state->info->hmac);
44
+ free(state->info);
45
+ }
46
+
47
+ if (state->hmac) {
48
+ free((char *)state->hmac);
49
+ }
50
+
51
+ free(state->pointers);
52
+ free(state);
53
+ }
54
+
55
+ static void request_pointers(uv_work_t *work)
56
+ {
57
+ json_request_download_t *req = work->data;
58
+ storj_download_state_t *state = req->state;
59
+
60
+ int status_code = 0;
61
+ int request_status = fetch_json(req->http_options, req->options, req->method,
62
+ req->path, req->body, req->auth,
63
+ &req->response, &status_code);
64
+
65
+
66
+ if (request_status) {
67
+ state->log->warn(state->env->log_options, state->handle,
68
+ "Request pointers error: %i", request_status);
69
+ }
70
+
71
+ req->status_code = status_code;
72
+
73
+ if (!req->response) {
74
+ req->status_code = -1;
75
+ }
76
+
77
+ }
78
+
79
+ static void request_replace_pointer(uv_work_t *work)
80
+ {
81
+ json_request_replace_pointer_t *req = work->data;
82
+ storj_download_state_t *state = req->state;
83
+
84
+ int status_code = 0;
85
+
86
+ int excluded_farmer_ids_len = (req->excluded_farmer_ids) ? strlen(req->excluded_farmer_ids) : 0;
87
+ char query_args[BUFSIZ];
88
+ memset(query_args, '\0', BUFSIZ);
89
+ snprintf(query_args, BUFSIZ,
90
+ "?limit=1&skip=%i&exclude=%s",
91
+ req->pointer_index,
92
+ req->excluded_farmer_ids);
93
+
94
+ int path_len = 9 + strlen(req->bucket_id) + 7 +
95
+ strlen(req->file_id) + strlen(query_args);
96
+ char *path = calloc(path_len + 1, sizeof(char));
97
+ if (!path) {
98
+ req->error_status = STORJ_MEMORY_ERROR;
99
+ return;
100
+ }
101
+
102
+ strcat(path, "/buckets/");
103
+ strcat(path, req->bucket_id);
104
+ strcat(path, "/files/");
105
+ strcat(path, req->file_id);
106
+ strcat(path, query_args);
107
+
108
+ int request_status = fetch_json(req->http_options, req->options, "GET",
109
+ path, NULL, true,
110
+ &req->response, &status_code);
111
+
112
+ if (request_status) {
113
+ state->log->warn(state->env->log_options, state->handle,
114
+ "Request replace pointer error: %i", request_status);
115
+ }
116
+
117
+ req->status_code = status_code;
118
+
119
+ if (!req->response) {
120
+ req->status_code = -1;
121
+ }
122
+
123
+ free(path);
124
+
125
+ }
126
+
127
+ static void set_pointer_from_json(storj_download_state_t *state,
128
+ storj_pointer_t *p,
129
+ struct json_object *json,
130
+ bool is_replaced)
131
+ {
132
+ if (!json_object_is_type(json, json_type_object)) {
133
+ state->error_status = STORJ_BRIDGE_JSON_ERROR;
134
+ return;
135
+ }
136
+
137
+ struct json_object *token_value;
138
+ char *token = NULL;
139
+ if (json_object_object_get_ex(json, "token", &token_value)) {
140
+ token = (char *)json_object_get_string(token_value);
141
+ }
142
+
143
+ struct json_object *hash_value;
144
+ if (!json_object_object_get_ex(json, "hash", &hash_value)) {
145
+ state->error_status = STORJ_BRIDGE_JSON_ERROR;
146
+ return;
147
+ }
148
+ char *hash = (char *)json_object_get_string(hash_value);
149
+
150
+ struct json_object *size_value;
151
+ if (!json_object_object_get_ex(json, "size", &size_value)) {
152
+ state->error_status = STORJ_BRIDGE_JSON_ERROR;
153
+ return;
154
+ }
155
+ uint64_t size = json_object_get_int64(size_value);
156
+
157
+ struct json_object *parity_value;
158
+ bool parity = false;
159
+ if (json_object_object_get_ex(json, "parity", &parity_value)) {
160
+ parity = json_object_get_boolean(parity_value);
161
+ }
162
+
163
+ struct json_object *index_value;
164
+ if (!json_object_object_get_ex(json, "index", &index_value)) {
165
+ state->error_status = STORJ_BRIDGE_JSON_ERROR;
166
+ return;
167
+ }
168
+ uint32_t index = json_object_get_int(index_value);
169
+
170
+ struct json_object *farmer_value;
171
+ char *address = NULL;
172
+ uint32_t port = 0;
173
+ char *farmer_id = NULL;
174
+ if (json_object_object_get_ex(json, "farmer", &farmer_value) &&
175
+ json_object_is_type(farmer_value, json_type_object)) {
176
+
177
+ struct json_object *address_value;
178
+ if (!json_object_object_get_ex(farmer_value, "address",
179
+ &address_value)) {
180
+ state->error_status = STORJ_BRIDGE_JSON_ERROR;
181
+ return;
182
+ }
183
+ address = (char *)json_object_get_string(address_value);
184
+
185
+ struct json_object *port_value;
186
+ if (!json_object_object_get_ex(farmer_value, "port", &port_value)) {
187
+ state->error_status = STORJ_BRIDGE_JSON_ERROR;
188
+ return;
189
+ }
190
+ port = json_object_get_int(port_value);
191
+
192
+ struct json_object *farmer_id_value;
193
+ if (!json_object_object_get_ex(farmer_value, "nodeID",
194
+ &farmer_id_value)) {
195
+ state->error_status = STORJ_BRIDGE_JSON_ERROR;
196
+ return;
197
+ }
198
+ farmer_id = (char *)json_object_get_string(farmer_id_value);
199
+ }
200
+
201
+ if (is_replaced) {
202
+ p->replace_count += 1;
203
+ } else {
204
+ p->replace_count = 0;
205
+ }
206
+
207
+ // Check to see if we have a token for this shard, otherwise
208
+ // we will immediatly move this shard to POINTER_MISSING
209
+ // so that it can be retried and possibly recovered.
210
+ if (address && token) {
211
+ // reset the status
212
+ p->status = POINTER_CREATED;
213
+ } else {
214
+ state->log->warn(state->env->log_options,
215
+ state->handle,
216
+ "Missing shard %s at index %i",
217
+ hash,
218
+ index);
219
+ p->status = POINTER_MISSING;
220
+ }
221
+
222
+ p->size = size;
223
+ p->parity = parity;
224
+ p->downloaded_size = 0;
225
+ p->index = index;
226
+ p->farmer_port = port;
227
+
228
+ if (is_replaced) {
229
+ free(p->token);
230
+ free(p->shard_hash);
231
+ free(p->farmer_address);
232
+ free(p->farmer_id);
233
+ }
234
+ if (token) {
235
+ p->token = strdup(token);
236
+ } else {
237
+ p->token = NULL;
238
+ }
239
+ p->shard_hash = strdup(hash);
240
+ if (address) {
241
+ p->farmer_address = strdup(address);
242
+ } else {
243
+ p->farmer_address = NULL;
244
+ }
245
+ if (farmer_id) {
246
+ p->farmer_id = strdup(farmer_id);
247
+ } else {
248
+ p->farmer_id = NULL;
249
+ }
250
+
251
+ // setup exchange report values
252
+ if (is_replaced) {
253
+ free_exchange_report(p->report);
254
+ }
255
+ p->report = malloc(
256
+ sizeof(storj_exchange_report_t));
257
+
258
+ if (!p->report) {
259
+ state->error_status = STORJ_MEMORY_ERROR;
260
+ return;
261
+ }
262
+
263
+ const char *client_id = state->env->bridge_options->user;
264
+ p->report->reporter_id = strdup(client_id);
265
+ p->report->client_id = strdup(client_id);
266
+ p->report->data_hash = strdup(hash);
267
+ if (farmer_id) {
268
+ p->report->farmer_id = strdup(farmer_id);
269
+ } else {
270
+ p->report->farmer_id = NULL;
271
+ }
272
+ p->report->send_status = 0; // not sent
273
+ p->report->send_count = 0;
274
+
275
+ // these values will be changed in after_request_shard
276
+ p->report->start = 0;
277
+ p->report->end = 0;
278
+ p->report->code = STORJ_REPORT_FAILURE;
279
+ p->report->message = STORJ_REPORT_DOWNLOAD_ERROR;
280
+
281
+ p->work = NULL;
282
+
283
+ if (!state->shard_size) {
284
+ // TODO make sure all except last shard is the same size
285
+ state->shard_size = size;
286
+ state->log->debug(state->env->log_options,
287
+ state->handle,
288
+ "Shard size set to %" PRIu64,
289
+ state->shard_size);
290
+ };
291
+ }
292
+
293
+ static void append_pointers_to_state(storj_download_state_t *state,
294
+ struct json_object *res)
295
+ {
296
+ int length = json_object_array_length(res);
297
+
298
+ if (length == 0) {
299
+ state->log->debug(state->env->log_options,
300
+ state->handle,
301
+ "Finished requesting pointers");
302
+ state->pointers_completed = true;
303
+ } else if (length > 0) {
304
+
305
+ int prev_total_pointers = state->total_pointers;
306
+ int total_pointers = state->total_pointers + length;
307
+
308
+ if (state->total_pointers > 0) {
309
+ state->pointers = realloc(state->pointers,
310
+ total_pointers * sizeof(storj_pointer_t));
311
+ } else {
312
+ state->pointers = malloc(length * sizeof(storj_pointer_t) * 100);
313
+ }
314
+ if (!state->pointers) {
315
+ state->error_status = STORJ_MEMORY_ERROR;
316
+ return;
317
+ }
318
+
319
+ state->total_pointers = total_pointers;
320
+ state->total_shards = total_pointers;
321
+
322
+ for (int i = 0; i < length; i++) {
323
+
324
+ // get the relative index
325
+ int j = i + prev_total_pointers;
326
+
327
+ struct json_object *json = json_object_array_get_idx(res, i);
328
+
329
+ set_pointer_from_json(state, &state->pointers[j], json, false);
330
+
331
+ // Keep track of the number of data and parity pointers
332
+ storj_pointer_t *pointer = &state->pointers[j];
333
+ if (pointer->parity) {
334
+ state->total_parity_pointers += 1;
335
+ }
336
+ }
337
+ }
338
+
339
+ }
340
+
341
+ static void after_request_pointers(uv_work_t *work, int status)
342
+ {
343
+ json_request_download_t *req = work->data;
344
+ storj_download_state_t *state = req->state;
345
+
346
+ state->pending_work_count--;
347
+ state->requesting_pointers = false;
348
+
349
+ if (req->response) {
350
+ state->log->debug(state->env->log_options, state->handle,
351
+ "Finished request pointers - JSON Response %s",
352
+ json_object_to_json_string(req->response));
353
+ }
354
+
355
+ if (status != 0) {
356
+
357
+ state->error_status = STORJ_BRIDGE_POINTER_ERROR;
358
+
359
+ } else if (req->status_code == 429 || req->status_code == 420) {
360
+
361
+ state->error_status = STORJ_BRIDGE_RATE_ERROR;
362
+
363
+ } else if (req->status_code != 200) {
364
+ if (req->status_code > 0 && req->status_code < 500) {
365
+ state->error_status = STORJ_BRIDGE_POINTER_ERROR;
366
+ } else {
367
+ state->pointer_fail_count += 1;
368
+ }
369
+
370
+ state->log->debug(state->env->log_options, state->handle,
371
+ "Request pointers fail count: %i",
372
+ state->pointer_fail_count);
373
+
374
+ if (state->pointer_fail_count >= STORJ_MAX_POINTER_TRIES) {
375
+ state->pointer_fail_count = 0;
376
+ state->error_status = STORJ_BRIDGE_POINTER_ERROR;
377
+ }
378
+
379
+ } else if (!json_object_is_type(req->response, json_type_array)) {
380
+ state->error_status = STORJ_BRIDGE_JSON_ERROR;
381
+ } else {
382
+ append_pointers_to_state(state, req->response);
383
+ }
384
+
385
+ queue_next_work(state);
386
+
387
+ if (req->response) {
388
+ json_object_put(req->response);
389
+ }
390
+ free(req->path);
391
+ free(req);
392
+ free(work);
393
+ }
394
+
395
+ static void after_request_replace_pointer(uv_work_t *work, int status)
396
+ {
397
+ json_request_replace_pointer_t *req = work->data;
398
+ storj_download_state_t *state = req->state;
399
+
400
+ state->pending_work_count--;
401
+ state->requesting_pointers = false;
402
+
403
+ state->log->debug(state->env->log_options, state->handle,
404
+ "Finished request replace pointer %i - JSON Response: %s",
405
+ req->pointer_index,
406
+ json_object_to_json_string(req->response));
407
+
408
+ if (status != 0) {
409
+
410
+ state->error_status = STORJ_BRIDGE_REPOINTER_ERROR;
411
+
412
+ } else if (req->error_status) {
413
+
414
+ state->error_status = req->error_status;
415
+
416
+ } else if (req->status_code == 429 || req->status_code == 420) {
417
+
418
+ state->error_status = STORJ_BRIDGE_RATE_ERROR;
419
+
420
+ } else if (req->status_code != 200) {
421
+
422
+ if (req->status_code > 0 && req->status_code < 500) {
423
+ state->pointers[req->pointer_index].status = POINTER_MISSING;
424
+ } else {
425
+ // Update status so that it will be retried
426
+ state->pointers[req->pointer_index].status = POINTER_ERROR_REPORTED;
427
+ state->pointer_fail_count += 1;
428
+ }
429
+
430
+ state->log->debug(state->env->log_options, state->handle,
431
+ "Request replace pointer fail count: %i",
432
+ state->pointer_fail_count);
433
+
434
+ if (state->pointer_fail_count >= STORJ_MAX_POINTER_TRIES) {
435
+ // Skip retrying mark as missing
436
+ state->pointer_fail_count = 0;
437
+ state->pointers[req->pointer_index].status = POINTER_MISSING;
438
+ }
439
+
440
+ } else if (!json_object_is_type(req->response, json_type_array)) {
441
+ state->error_status = STORJ_BRIDGE_JSON_ERROR;
442
+ } else {
443
+ struct json_object *json = json_object_array_get_idx(req->response, 0);
444
+
445
+ set_pointer_from_json(state,
446
+ &state->pointers[req->pointer_index],
447
+ json,
448
+ true);
449
+
450
+ if (state->pointers[req->pointer_index].index != req->pointer_index) {
451
+
452
+ state->log->error(state->env->log_options,
453
+ state->handle,
454
+ "Replacement shard index %i does not match %i",
455
+ state->pointers[req->pointer_index].index,
456
+ req->pointer_index);
457
+
458
+ state->error_status = STORJ_BRIDGE_JSON_ERROR;
459
+ }
460
+ }
461
+
462
+ queue_next_work(state);
463
+
464
+ json_object_put(req->response);
465
+ free(work->data);
466
+ free(work);
467
+ }
468
+
469
+ static void queue_request_pointers(storj_download_state_t *state)
470
+ {
471
+ if (state->requesting_pointers || state->canceled) {
472
+ return;
473
+ }
474
+
475
+ // queue request to replace pointer if any pointers have failure
476
+ for (int i = 0; i < state->total_pointers; i++) {
477
+
478
+ storj_pointer_t *pointer = &state->pointers[i];
479
+
480
+ if (pointer->replace_count >= STORJ_DEFAULT_MIRRORS) {
481
+ state->log->warn(state->env->log_options,
482
+ state->handle,
483
+ "Unable to download shard %s at index %i",
484
+ pointer->shard_hash,
485
+ pointer->index);
486
+ pointer->replace_count = 0;
487
+ pointer->status = POINTER_MISSING;
488
+ return;
489
+ }
490
+
491
+ if (pointer->status == POINTER_ERROR_REPORTED) {
492
+
493
+ // exclude this farmer id from future requests
494
+ state->log->debug(state->env->log_options,
495
+ state->handle,
496
+ "Adding farmer_id %s to excluded list",
497
+ pointer->report->farmer_id);
498
+
499
+ if (!state->excluded_farmer_ids) {
500
+ state->excluded_farmer_ids = calloc(42, sizeof(char));
501
+ if (!state->excluded_farmer_ids) {
502
+ state->error_status = STORJ_MEMORY_ERROR;
503
+ return;
504
+ }
505
+ strcat(state->excluded_farmer_ids, pointer->report->farmer_id);
506
+ } else {
507
+ state->excluded_farmer_ids =
508
+ realloc(state->excluded_farmer_ids,
509
+ strlen(state->excluded_farmer_ids) + 42);
510
+ if (!state->excluded_farmer_ids) {
511
+ state->error_status = STORJ_MEMORY_ERROR;
512
+ return;
513
+ }
514
+ strcat(state->excluded_farmer_ids, ",");
515
+ strcat(state->excluded_farmer_ids, pointer->report->farmer_id);
516
+ }
517
+
518
+ json_request_replace_pointer_t *req =
519
+ malloc(sizeof(json_request_replace_pointer_t));
520
+ if (!req) {
521
+ state->error_status = STORJ_MEMORY_ERROR;
522
+ return;
523
+ }
524
+
525
+ req->pointer_index = i;
526
+
527
+ req->http_options = state->env->http_options;
528
+ req->options = state->env->bridge_options;
529
+ req->bucket_id = state->bucket_id;
530
+ req->file_id = state->file_id;
531
+ req->state = state;
532
+ req->excluded_farmer_ids = state->excluded_farmer_ids;
533
+ req->error_status = 0;
534
+ req->response = NULL;
535
+ req->status_code = 0;
536
+
537
+ uv_work_t *work = malloc(sizeof(uv_work_t));
538
+ if (!work) {
539
+ state->error_status = STORJ_MEMORY_ERROR;
540
+ return;
541
+ }
542
+ work->data = req;
543
+
544
+ state->log->info(state->env->log_options,
545
+ state->handle,
546
+ "Requesting replacement pointer at index: %i",
547
+ req->pointer_index);
548
+
549
+ state->pending_work_count++;
550
+ int status = uv_queue_work(state->env->loop,
551
+ (uv_work_t*) work,
552
+ request_replace_pointer,
553
+ after_request_replace_pointer);
554
+
555
+ if (status) {
556
+ state->error_status = STORJ_QUEUE_ERROR;
557
+ return;
558
+ }
559
+
560
+ pointer->status = POINTER_BEING_REPLACED;
561
+
562
+ // we're done until the next pass
563
+ state->requesting_pointers = true;
564
+ return;
565
+ }
566
+
567
+ }
568
+
569
+ // only request the next set of pointers if we're not finished
570
+ if (state->pointers_completed) {
571
+ return;
572
+ }
573
+
574
+ json_request_download_t *req = malloc(sizeof(json_request_download_t));
575
+ if (!req) {
576
+ state->error_status = STORJ_MEMORY_ERROR;
577
+ return;
578
+ }
579
+
580
+ char query_args[BUFSIZ];
581
+ memset(query_args, '\0', BUFSIZ);
582
+ snprintf(query_args, BUFSIZ, "?limit=3&skip=%d", state->total_pointers);
583
+
584
+ int path_len = 9 + strlen(state->bucket_id) + 7 +
585
+ strlen(state->file_id) + strlen(query_args);
586
+
587
+ char *path = calloc(path_len + 1, sizeof(char));
588
+ if (!path) {
589
+ state->error_status = STORJ_MEMORY_ERROR;
590
+ return;
591
+ }
592
+ strcat(path, "/buckets/");
593
+ strcat(path, state->bucket_id);
594
+ strcat(path, "/files/");
595
+ strcat(path, state->file_id);
596
+ strcat(path, query_args);
597
+
598
+ req->http_options = state->env->http_options;
599
+ req->options = state->env->bridge_options;
600
+ req->method = "GET";
601
+ req->path = path;
602
+ req->body = NULL;
603
+ req->auth = true;
604
+
605
+ req->state = state;
606
+
607
+ uv_work_t *work = malloc(sizeof(uv_work_t));
608
+ if (!work) {
609
+ state->error_status = STORJ_MEMORY_ERROR;
610
+ return;
611
+ }
612
+ work->data = req;
613
+
614
+ state->log->info(state->env->log_options,
615
+ state->handle,
616
+ "Requesting next set of pointers, total pointers: %i",
617
+ state->total_pointers);
618
+
619
+ state->pending_work_count++;
620
+ int status = uv_queue_work(state->env->loop, (uv_work_t*) work,
621
+ request_pointers, after_request_pointers);
622
+
623
+ if (status) {
624
+ state->error_status = STORJ_QUEUE_ERROR;
625
+ return;
626
+ }
627
+
628
+ state->requesting_pointers = true;
629
+ }
630
+
631
+ static void request_shard(uv_work_t *work)
632
+ {
633
+ shard_request_download_t *req = work->data;
634
+
635
+ int status_code;
636
+ int write_code = 0;
637
+
638
+ req->start = get_time_milliseconds();
639
+
640
+ uint64_t file_position = req->pointer_index * req->state->shard_size;
641
+
642
+ int error_status = fetch_shard(req->http_options,
643
+ req->farmer_id,
644
+ req->farmer_proto,
645
+ req->farmer_host,
646
+ req->farmer_port,
647
+ req->shard_hash,
648
+ req->shard_total_bytes,
649
+ req->token,
650
+ req->state->destination,
651
+ file_position,
652
+ &status_code,
653
+ &write_code,
654
+ &req->progress_handle,
655
+ req->canceled);
656
+
657
+ req->end = get_time_milliseconds();
658
+
659
+ if (write_code != 0) {
660
+ req->state->log->error(req->state->env->log_options, req->state->handle,
661
+ "Put shard read error: %i", write_code);
662
+ }
663
+
664
+ if (error_status) {
665
+ req->error_status = error_status;
666
+ } else if (status_code != 200) {
667
+ switch(status_code) {
668
+ case 401:
669
+ case 403:
670
+ req->error_status = STORJ_FARMER_AUTH_ERROR;
671
+ break;
672
+ case 504:
673
+ req->error_status = STORJ_FARMER_TIMEOUT_ERROR;
674
+ break;
675
+ default:
676
+ req->error_status = STORJ_FARMER_REQUEST_ERROR;
677
+ }
678
+ } else {
679
+ req->error_status = 0;
680
+ }
681
+ }
682
+
683
+ static void free_request_shard_work(uv_handle_t *progress_handle)
684
+ {
685
+ uv_work_t *work = progress_handle->data;
686
+ shard_request_download_t *req = work->data;
687
+
688
+ free(req);
689
+ free(work);
690
+ }
691
+
692
+ static uint64_t calculate_data_filesize(storj_download_state_t *state)
693
+ {
694
+ uint64_t total_bytes = 0;
695
+
696
+ for (int i = 0; i < state->total_pointers; i++) {
697
+ storj_pointer_t *pointer = &state->pointers[i];
698
+ if (pointer->parity) {
699
+ continue;
700
+ }
701
+ total_bytes += pointer->size;
702
+ }
703
+
704
+ return total_bytes;
705
+ }
706
+
707
+ static void report_progress(storj_download_state_t *state)
708
+ {
709
+ uint64_t downloaded_bytes = 0;
710
+ uint64_t total_bytes = 0;
711
+
712
+ for (int i = 0; i < state->total_pointers; i++) {
713
+
714
+ storj_pointer_t *pointer = &state->pointers[i];
715
+
716
+ downloaded_bytes += pointer->downloaded_size;
717
+ total_bytes += pointer->size;
718
+ }
719
+
720
+ double total_progress = (double)downloaded_bytes / (double)total_bytes;
721
+
722
+ state->progress_cb(total_progress,
723
+ downloaded_bytes,
724
+ total_bytes,
725
+ state->handle);
726
+ }
727
+
728
+ static void after_request_shard(uv_work_t *work, int status)
729
+ {
730
+ shard_request_download_t *req = work->data;
731
+
732
+ req->state->pending_work_count--;
733
+ req->state->resolving_shards -= 1;
734
+
735
+ uv_handle_t *progress_handle = (uv_handle_t *) &req->progress_handle;
736
+
737
+ // free the download progress
738
+ free(progress_handle->data);
739
+
740
+ // assign work so that we can free after progress_handle is closed
741
+ progress_handle->data = work;
742
+
743
+ // update the pointer status
744
+ storj_pointer_t *pointer = &req->state->pointers[req->pointer_index];
745
+
746
+ pointer->report->start = req->start;
747
+ pointer->report->end = req->end;
748
+
749
+ if (req->error_status) {
750
+
751
+ req->state->log->warn(req->state->env->log_options,
752
+ req->state->handle,
753
+ "Error downloading shard: %s, reason: %s",
754
+ req->shard_hash,
755
+ storj_strerror(req->error_status));
756
+
757
+ pointer->status = POINTER_ERROR;
758
+
759
+ switch(req->error_status) {
760
+ case STORJ_FARMER_INTEGRITY_ERROR:
761
+ pointer->report->code = STORJ_REPORT_FAILURE;
762
+ pointer->report->message = STORJ_REPORT_FAILED_INTEGRITY;
763
+ default:
764
+ pointer->report->code = STORJ_REPORT_FAILURE;
765
+ pointer->report->message = STORJ_REPORT_DOWNLOAD_ERROR;
766
+ }
767
+
768
+ } else {
769
+
770
+ req->state->log->info(req->state->env->log_options,
771
+ req->state->handle,
772
+ "Finished downloading shard: %s",
773
+ req->shard_hash);
774
+
775
+ pointer->report->code = STORJ_REPORT_SUCCESS;
776
+ pointer->report->message = STORJ_REPORT_SHARD_DOWNLOADED;
777
+ pointer->status = POINTER_DOWNLOADED;
778
+
779
+ // Make sure the downloaded size is updated
780
+ pointer->downloaded_size = pointer->size;
781
+
782
+ report_progress(req->state);
783
+
784
+ }
785
+
786
+ queue_next_work(req->state);
787
+
788
+ // close the async progress handle
789
+ uv_close(progress_handle, free_request_shard_work);
790
+ }
791
+
792
+ static void progress_request_shard(uv_async_t* async)
793
+ {
794
+ shard_download_progress_t *progress = async->data;
795
+
796
+ storj_download_state_t *state = progress->state;
797
+
798
+ state->pointers[progress->pointer_index].downloaded_size = progress->bytes;
799
+
800
+ report_progress(state);
801
+ }
802
+
803
+ static void queue_request_shards(storj_download_state_t *state)
804
+ {
805
+ if (state->canceled) {
806
+ return;
807
+ }
808
+
809
+ int i = 0;
810
+
811
+ while (state->resolving_shards < state->download_max_concurrency &&
812
+ i < state->total_pointers) {
813
+
814
+ storj_pointer_t *pointer = &state->pointers[i];
815
+
816
+ if (pointer->status == POINTER_CREATED) {
817
+ shard_request_download_t *req = malloc(sizeof(shard_request_download_t));
818
+ if (!req) {
819
+ state->error_status = STORJ_MEMORY_ERROR;
820
+ return;
821
+ }
822
+
823
+ req->http_options = state->env->http_options;
824
+ req->farmer_id = pointer->farmer_id;
825
+ req->farmer_proto = "http";
826
+ req->farmer_host = pointer->farmer_address;
827
+ req->farmer_port = pointer->farmer_port;
828
+ req->shard_hash = pointer->shard_hash;
829
+ req->shard_total_bytes = pointer->size;
830
+ req->byte_position = state->shard_size * i;
831
+ req->token = pointer->token;
832
+ req->error_status = 0;
833
+
834
+ req->pointer_index = pointer->index;
835
+
836
+ req->state = state;
837
+ req->canceled = &state->canceled;
838
+
839
+ uv_work_t *work = malloc(sizeof(uv_work_t));
840
+ if (!work) {
841
+ state->error_status = STORJ_MEMORY_ERROR;
842
+ return;
843
+ }
844
+
845
+ work->data = req;
846
+
847
+ state->resolving_shards += 1;
848
+ pointer->status = POINTER_BEING_DOWNLOADED;
849
+ pointer->work = work;
850
+
851
+ state->log->info(state->env->log_options,
852
+ state->handle,
853
+ "Queue request shard: %s",
854
+ req->shard_hash);
855
+
856
+ // setup download progress reporting
857
+ shard_download_progress_t *progress =
858
+ malloc(sizeof(shard_download_progress_t));
859
+ if (!progress) {
860
+ state->error_status = STORJ_MEMORY_ERROR;
861
+ return;
862
+ }
863
+
864
+ progress->pointer_index = pointer->index;
865
+ progress->bytes = 0;
866
+ progress->state = state;
867
+
868
+ req->progress_handle.data = progress;
869
+
870
+ uv_async_init(state->env->loop, &req->progress_handle,
871
+ progress_request_shard);
872
+
873
+ // queue download
874
+ state->pending_work_count++;
875
+ int status = uv_queue_work(state->env->loop, (uv_work_t*) work,
876
+ request_shard, after_request_shard);
877
+ if (status) {
878
+ state->error_status = STORJ_QUEUE_ERROR;
879
+ return;
880
+ }
881
+ }
882
+
883
+ i++;
884
+ }
885
+ }
886
+
887
+ static void send_exchange_report(uv_work_t *work)
888
+ {
889
+ shard_send_report_t *req = work->data;
890
+ storj_download_state_t *state = req->state;
891
+
892
+ struct json_object *body = json_object_new_object();
893
+
894
+ json_object_object_add(body, "dataHash",
895
+ json_object_new_string(req->report->data_hash));
896
+
897
+ json_object_object_add(body, "reporterId",
898
+ json_object_new_string(req->report->reporter_id));
899
+
900
+ json_object_object_add(body, "farmerId",
901
+ json_object_new_string(req->report->farmer_id));
902
+
903
+ json_object_object_add(body, "clientId",
904
+ json_object_new_string(req->report->client_id));
905
+
906
+ json_object_object_add(body, "exchangeStart",
907
+ json_object_new_int64(req->report->start));
908
+
909
+ json_object_object_add(body, "exchangeEnd",
910
+ json_object_new_int64(req->report->end));
911
+
912
+ json_object_object_add(body, "exchangeResultCode",
913
+ json_object_new_int(req->report->code));
914
+
915
+ json_object_object_add(body, "exchangeResultMessage",
916
+ json_object_new_string(req->report->message));
917
+
918
+ int status_code = 0;
919
+
920
+ // there should be an empty object in response
921
+ struct json_object *response = NULL;
922
+ int request_status = fetch_json(req->http_options,
923
+ req->options, "POST",
924
+ "/reports/exchanges", body,
925
+ true, &response, &status_code);
926
+
927
+
928
+ if (request_status) {
929
+ state->log->warn(state->env->log_options, state->handle,
930
+ "Send exchange report error: %i", request_status);
931
+ }
932
+
933
+ req->status_code = status_code;
934
+
935
+ // free all memory for body and response
936
+ if (response) {
937
+ json_object_put(response);
938
+ }
939
+ json_object_put(body);
940
+ }
941
+
942
+ static void after_send_exchange_report(uv_work_t *work, int status)
943
+ {
944
+ shard_send_report_t *req = work->data;
945
+
946
+ req->state->pending_work_count--;
947
+
948
+ // set status so that this pointer can be replaced
949
+ if (req->report->send_count >= STORJ_MAX_REPORT_TRIES ||
950
+ req->status_code == 201) {
951
+
952
+ storj_pointer_t *pointer = &req->state->pointers[req->pointer_index];
953
+
954
+ if (pointer->status == POINTER_ERROR) {
955
+ pointer->status = POINTER_ERROR_REPORTED;
956
+ }
957
+ }
958
+
959
+ if (req->status_code == 201) {
960
+ // set the status so that this pointer can be replaced
961
+ req->report->send_status = 2; // report has been sent
962
+ } else {
963
+ req->report->send_status = 0; // reset report back to unsent
964
+ }
965
+
966
+ queue_next_work(req->state);
967
+
968
+ free(work->data);
969
+ free(work);
970
+
971
+ }
972
+
973
+ static void queue_send_exchange_reports(storj_download_state_t *state)
974
+ {
975
+
976
+ if (state->canceled) {
977
+ return;
978
+ }
979
+
980
+ for (int i = 0; i < state->total_pointers; i++) {
981
+
982
+ storj_pointer_t *pointer = &state->pointers[i];
983
+
984
+ if (pointer->report->send_status < 1 &&
985
+ pointer->report->send_count < STORJ_MAX_REPORT_TRIES &&
986
+ pointer->report->start > 0 &&
987
+ pointer->report->end > 0) {
988
+
989
+ uv_work_t *work = malloc(sizeof(uv_work_t));
990
+ if (!work) {
991
+ state->error_status = STORJ_MEMORY_ERROR;
992
+ return;
993
+ }
994
+
995
+ shard_send_report_t *req = malloc(sizeof(shard_send_report_t));
996
+ if (!req) {
997
+ state->error_status = STORJ_MEMORY_ERROR;
998
+ return;
999
+ }
1000
+
1001
+ req->http_options = state->env->http_options;
1002
+ req->options = state->env->bridge_options;
1003
+ req->status_code = 0;
1004
+ req->report = pointer->report;
1005
+ req->report->send_status = 1; // being reported
1006
+ req->report->send_count += 1;
1007
+ req->state = state;
1008
+ req->pointer_index = i;
1009
+
1010
+ work->data = req;
1011
+
1012
+ state->pending_work_count++;
1013
+ int status = uv_queue_work(state->env->loop, (uv_work_t*) work,
1014
+ send_exchange_report,
1015
+ after_send_exchange_report);
1016
+ if (status) {
1017
+ state->error_status = STORJ_QUEUE_ERROR;
1018
+ return;
1019
+ }
1020
+ }
1021
+ }
1022
+ }
1023
+
1024
+ static void determine_decryption_key_v1(storj_download_state_t *state)
1025
+ {
1026
+ uint8_t *index = NULL;
1027
+ char *file_key_as_str = NULL;
1028
+
1029
+ file_key_as_str = calloc(DETERMINISTIC_KEY_SIZE + 1, sizeof(char));
1030
+ if (!file_key_as_str) {
1031
+ state->error_status = STORJ_MEMORY_ERROR;
1032
+ goto cleanup;
1033
+ }
1034
+
1035
+ if (generate_file_key(state->env->encrypt_options->mnemonic,
1036
+ state->bucket_id,
1037
+ state->info->index, &file_key_as_str)) {
1038
+ state->error_status = STORJ_MEMORY_ERROR;
1039
+ goto cleanup;
1040
+ }
1041
+ file_key_as_str[DETERMINISTIC_KEY_SIZE] = '\0';
1042
+
1043
+ uint8_t *decrypt_key = str2hex(strlen(file_key_as_str), file_key_as_str);
1044
+ if (!decrypt_key) {
1045
+ state->error_status = STORJ_MEMORY_ERROR;
1046
+ goto cleanup;
1047
+ }
1048
+
1049
+ state->decrypt_key = decrypt_key;
1050
+
1051
+ index = str2hex(strlen(state->info->index), (char *)state->info->index);
1052
+ if (!index) {
1053
+ state->error_status = STORJ_MEMORY_ERROR;
1054
+ goto cleanup;
1055
+ }
1056
+
1057
+ uint8_t *decrypt_ctr = calloc(AES_BLOCK_SIZE, sizeof(uint8_t));
1058
+ if (!decrypt_ctr) {
1059
+ state->error_status = STORJ_MEMORY_ERROR;
1060
+ goto cleanup;
1061
+ }
1062
+
1063
+ memcpy(decrypt_ctr, index, AES_BLOCK_SIZE);
1064
+ state->decrypt_ctr = decrypt_ctr;
1065
+
1066
+ cleanup:
1067
+ if (file_key_as_str) {
1068
+ free(file_key_as_str);
1069
+ }
1070
+ if (index) {
1071
+ free(index);
1072
+ }
1073
+ }
1074
+
1075
+ static void determine_decryption_key_v0(storj_download_state_t *state)
1076
+ {
1077
+ char *file_key = calloc(DETERMINISTIC_KEY_SIZE + 1, sizeof(char));
1078
+ if (!file_key) {
1079
+ state->error_status = STORJ_MEMORY_ERROR;
1080
+ return;
1081
+ }
1082
+
1083
+ if (generate_file_key(state->env->encrypt_options->mnemonic,
1084
+ state->bucket_id,
1085
+ state->file_id, &file_key)) {
1086
+ state->error_status = STORJ_MEMORY_ERROR;
1087
+ return;
1088
+ }
1089
+ file_key[DETERMINISTIC_KEY_SIZE] = '\0';
1090
+
1091
+ uint8_t *decrypt_key = calloc(SHA256_DIGEST_SIZE + 1, sizeof(uint8_t));
1092
+ if (!decrypt_key) {
1093
+ state->error_status = STORJ_MEMORY_ERROR;
1094
+ return;
1095
+ }
1096
+
1097
+ sha256_of_str((uint8_t *)file_key, DETERMINISTIC_KEY_SIZE, decrypt_key);
1098
+ decrypt_key[SHA256_DIGEST_SIZE] = '\0';
1099
+
1100
+ memset_zero(file_key, DETERMINISTIC_KEY_SIZE + 1);
1101
+ free(file_key);
1102
+
1103
+ state->decrypt_key = decrypt_key;
1104
+
1105
+ uint8_t *file_id_hash = calloc(RIPEMD160_DIGEST_SIZE + 1, sizeof(uint8_t));
1106
+ if (!file_id_hash) {
1107
+ state->error_status = STORJ_MEMORY_ERROR;
1108
+ return;
1109
+ }
1110
+ ripemd160_of_str((uint8_t *)state->file_id,
1111
+ strlen(state->file_id), file_id_hash);
1112
+ file_id_hash[RIPEMD160_DIGEST_SIZE] = '\0';
1113
+
1114
+ uint8_t *decrypt_ctr = calloc(AES_BLOCK_SIZE, sizeof(uint8_t));
1115
+ if (!decrypt_ctr) {
1116
+ state->error_status = STORJ_MEMORY_ERROR;
1117
+ return;
1118
+ }
1119
+ memcpy(decrypt_ctr, file_id_hash, AES_BLOCK_SIZE);
1120
+
1121
+ free(file_id_hash);
1122
+
1123
+ state->decrypt_ctr = decrypt_ctr;
1124
+ }
1125
+
1126
+ static void determine_decryption_key(storj_download_state_t *state)
1127
+ {
1128
+ if (!state->env->encrypt_options ||
1129
+ !state->env->encrypt_options->mnemonic) {
1130
+
1131
+ state->decrypt_key = NULL;
1132
+ state->decrypt_ctr = NULL;
1133
+ } else {
1134
+ if (state->info->index) {
1135
+ // calculate decryption key based on the index
1136
+ determine_decryption_key_v1(state);
1137
+ } else {
1138
+ // calculate decryption key based on the file_id
1139
+ determine_decryption_key_v0(state);
1140
+ }
1141
+ };
1142
+ }
1143
+
1144
+ static void after_request_info(uv_work_t *work, int status)
1145
+ {
1146
+ file_info_request_t *req = work->data;
1147
+
1148
+ req->state->pending_work_count--;
1149
+ req->state->requesting_info = false;
1150
+
1151
+ if (status != 0) {
1152
+ req->state->error_status = STORJ_BRIDGE_FILEINFO_ERROR;
1153
+ } else if (req->status_code == 200 || req->status_code == 304) {
1154
+ req->state->info = req->info;
1155
+ if (req->info->erasure) {
1156
+ if (strcmp(req->info->erasure, "reedsolomon") == 0) {
1157
+ req->state->rs = true;
1158
+ req->state->truncated = false;
1159
+ } else {
1160
+ req->state->error_status = STORJ_FILE_UNSUPPORTED_ERASURE;
1161
+ }
1162
+ }
1163
+
1164
+ // Now that we have info we can calculate the decryption key
1165
+ determine_decryption_key(req->state);
1166
+
1167
+ } else if (req->error_status) {
1168
+ switch(req->error_status) {
1169
+ case STORJ_BRIDGE_REQUEST_ERROR:
1170
+ case STORJ_BRIDGE_INTERNAL_ERROR:
1171
+ req->state->info_fail_count += 1;
1172
+ break;
1173
+ default:
1174
+ req->state->error_status = req->error_status;
1175
+ break;
1176
+ }
1177
+ if (req->state->info_fail_count >= STORJ_MAX_INFO_TRIES) {
1178
+ req->state->info_fail_count = 0;
1179
+ req->state->error_status = req->error_status;
1180
+ }
1181
+ } else {
1182
+ req->state->error_status = STORJ_BRIDGE_FILEINFO_ERROR;
1183
+ }
1184
+
1185
+ queue_next_work(req->state);
1186
+
1187
+ free(req);
1188
+ free(work);
1189
+
1190
+ }
1191
+
1192
+ static void request_info(uv_work_t *work)
1193
+ {
1194
+ file_info_request_t *req = work->data;
1195
+ storj_download_state_t *state = req->state;
1196
+
1197
+ int path_len = 9 + strlen(req->bucket_id) + 7 + strlen(req->file_id) + 5;
1198
+ char *path = calloc(path_len + 1, sizeof(char));
1199
+ if (!path) {
1200
+ req->error_status = STORJ_MEMORY_ERROR;
1201
+ return;
1202
+ }
1203
+
1204
+ strcat(path, "/buckets/");
1205
+ strcat(path, req->bucket_id);
1206
+ strcat(path, "/files/");
1207
+ strcat(path, req->file_id);
1208
+ strcat(path, "/info");
1209
+
1210
+ int status_code = 0;
1211
+ struct json_object *response = NULL;
1212
+ int request_status = fetch_json(req->http_options,
1213
+ req->options,
1214
+ "GET",
1215
+ path,
1216
+ NULL,
1217
+ true,
1218
+ &response,
1219
+ &status_code);
1220
+
1221
+ req->status_code = status_code;
1222
+
1223
+ state->log->debug(state->env->log_options,
1224
+ state->handle,
1225
+ "fn[request_info] - JSON Response: %s",
1226
+ json_object_to_json_string(response));
1227
+
1228
+ if (request_status) {
1229
+ req->error_status = STORJ_BRIDGE_REQUEST_ERROR;
1230
+ state->log->warn(state->env->log_options, state->handle,
1231
+ "Request file info error: %i", request_status);
1232
+
1233
+ } else if (status_code == 200 || status_code == 304) {
1234
+
1235
+ req->info = malloc(sizeof(storj_file_meta_t));
1236
+ req->info->created = NULL;
1237
+ req->info->filename = NULL;
1238
+ req->info->mimetype = NULL;
1239
+ req->info->erasure = NULL;
1240
+ req->info->size = 0;
1241
+ req->info->hmac = NULL;
1242
+ req->info->id = NULL;
1243
+ req->info->decrypted = false;
1244
+ req->info->index = NULL;
1245
+
1246
+ struct json_object *erasure_obj;
1247
+ struct json_object *erasure_value;
1248
+ char *erasure = NULL;
1249
+ if (json_object_object_get_ex(response, "erasure", &erasure_obj)) {
1250
+ if (json_object_object_get_ex(erasure_obj, "type", &erasure_value)) {
1251
+ erasure = (char *)json_object_get_string(erasure_value);
1252
+ } else {
1253
+ state->log->warn(state->env->log_options, state->handle,
1254
+ "value missing from erasure response");
1255
+ }
1256
+ }
1257
+
1258
+ if (erasure) {
1259
+ req->info->erasure = strdup(erasure);
1260
+ }
1261
+
1262
+ struct json_object *index_value;
1263
+ char *index = NULL;
1264
+ if (json_object_object_get_ex(response, "index", &index_value)) {
1265
+ index = (char *)json_object_get_string(index_value);
1266
+ }
1267
+
1268
+ if (index) {
1269
+ req->info->index = strdup(index);
1270
+ }
1271
+
1272
+ struct json_object *hmac_obj;
1273
+ if (!json_object_object_get_ex(response, "hmac", &hmac_obj)) {
1274
+ state->log->warn(state->env->log_options, state->handle,
1275
+ "hmac missing from response");
1276
+ goto clean_up;
1277
+ }
1278
+ if (!json_object_is_type(hmac_obj, json_type_object)) {
1279
+ state->log->warn(state->env->log_options, state->handle,
1280
+ "hmac not an object");
1281
+ goto clean_up;
1282
+ }
1283
+
1284
+ // check the type of hmac
1285
+ struct json_object *hmac_type;
1286
+ if (!json_object_object_get_ex(hmac_obj, "type", &hmac_type)) {
1287
+ state->log->warn(state->env->log_options, state->handle,
1288
+ "hmac.type missing from response");
1289
+ goto clean_up;
1290
+ }
1291
+ if (!json_object_is_type(hmac_type, json_type_string)) {
1292
+ state->log->warn(state->env->log_options, state->handle,
1293
+ "hmac.type not a string");
1294
+ goto clean_up;
1295
+ }
1296
+ char *hmac_type_str = (char *)json_object_get_string(hmac_type);
1297
+ if (0 != strcmp(hmac_type_str, "sha512")) {
1298
+ state->log->warn(state->env->log_options, state->handle,
1299
+ "hmac.type is unknown");
1300
+ goto clean_up;
1301
+ }
1302
+
1303
+ // get the hmac value
1304
+ struct json_object *hmac_value;
1305
+ if (!json_object_object_get_ex(hmac_obj, "value", &hmac_value)) {
1306
+ state->log->warn(state->env->log_options, state->handle,
1307
+ "hmac.value missing from response");
1308
+ goto clean_up;
1309
+ }
1310
+ if (!json_object_is_type(hmac_value, json_type_string)) {
1311
+ state->log->warn(state->env->log_options, state->handle,
1312
+ "hmac.value not a string");
1313
+ goto clean_up;
1314
+ }
1315
+ char *hmac = (char *)json_object_get_string(hmac_value);
1316
+ req->info->hmac = strdup(hmac);
1317
+
1318
+ } else if (status_code == 403 || status_code == 401) {
1319
+ req->error_status = STORJ_BRIDGE_AUTH_ERROR;
1320
+ } else if (status_code == 404 || status_code == 400) {
1321
+ req->error_status = STORJ_BRIDGE_FILE_NOTFOUND_ERROR;
1322
+ } else if (status_code == 500) {
1323
+ req->error_status = STORJ_BRIDGE_INTERNAL_ERROR;
1324
+ } else {
1325
+ req->error_status = STORJ_BRIDGE_REQUEST_ERROR;
1326
+ }
1327
+
1328
+ clean_up:
1329
+ if (response) {
1330
+ json_object_put(response);
1331
+ }
1332
+ free(path);
1333
+ }
1334
+
1335
+ static void queue_request_info(storj_download_state_t *state)
1336
+ {
1337
+ if (state->requesting_info || state->canceled) {
1338
+ return;
1339
+ }
1340
+
1341
+ uv_work_t *work = malloc(sizeof(uv_work_t));
1342
+ if (!work) {
1343
+ state->error_status = STORJ_MEMORY_ERROR;
1344
+ return;
1345
+ }
1346
+
1347
+ state->requesting_info = true;
1348
+
1349
+ file_info_request_t *req = malloc(sizeof(file_info_request_t));
1350
+ req->http_options = state->env->http_options;
1351
+ req->options = state->env->bridge_options;
1352
+ req->status_code = 0;
1353
+ req->bucket_id = state->bucket_id;
1354
+ req->file_id = state->file_id;
1355
+ req->error_status = 0;
1356
+ req->info = NULL;
1357
+ req->state = state;
1358
+
1359
+ work->data = req;
1360
+
1361
+ state->pending_work_count++;
1362
+ int status = uv_queue_work(state->env->loop, (uv_work_t*) work,
1363
+ request_info,
1364
+ after_request_info);
1365
+ if (status) {
1366
+ state->error_status = STORJ_QUEUE_ERROR;
1367
+ return;
1368
+ }
1369
+
1370
+ }
1371
+
1372
+ static int prepare_file_hmac(storj_download_state_t *state)
1373
+ {
1374
+ // initialize the hmac with the decrypt key
1375
+ struct hmac_sha512_ctx hmac_ctx;
1376
+ hmac_sha512_set_key(&hmac_ctx, SHA256_DIGEST_SIZE, state->decrypt_key);
1377
+
1378
+ for (int i = 0; i < state->total_pointers; i++) {
1379
+
1380
+ storj_pointer_t *pointer = &state->pointers[i];
1381
+
1382
+ if (!pointer->shard_hash ||
1383
+ strlen(pointer->shard_hash) != RIPEMD160_DIGEST_SIZE * 2) {
1384
+ return 1;
1385
+ }
1386
+
1387
+ struct base16_decode_ctx base16_ctx;
1388
+ base16_decode_init(&base16_ctx);
1389
+
1390
+ size_t decode_len = 0;
1391
+ uint8_t hash[RIPEMD160_DIGEST_SIZE];
1392
+ if (!base16_decode_update(&base16_ctx,
1393
+ &decode_len,
1394
+ hash,
1395
+ RIPEMD160_DIGEST_SIZE * 2,
1396
+ (uint8_t *)pointer->shard_hash)) {
1397
+ return 1;
1398
+
1399
+ }
1400
+ if (!base16_decode_final(&base16_ctx) ||
1401
+ decode_len != RIPEMD160_DIGEST_SIZE) {
1402
+ return 1;
1403
+ }
1404
+ hmac_sha512_update(&hmac_ctx, RIPEMD160_DIGEST_SIZE, hash);
1405
+ }
1406
+
1407
+ uint8_t digest_raw[SHA512_DIGEST_SIZE];
1408
+ hmac_sha512_digest(&hmac_ctx, SHA512_DIGEST_SIZE, digest_raw);
1409
+
1410
+ size_t digest_len = BASE16_ENCODE_LENGTH(SHA512_DIGEST_SIZE);
1411
+ state->hmac = calloc(digest_len + 1, sizeof(char));
1412
+ if (!state->hmac) {
1413
+ return 1;
1414
+ }
1415
+
1416
+ base16_encode_update((uint8_t *)state->hmac, SHA512_DIGEST_SIZE, digest_raw);
1417
+
1418
+ return 0;
1419
+ }
1420
+
1421
+ static bool has_missing_shard(storj_download_state_t *state)
1422
+ {
1423
+ bool missing = false;
1424
+ for (int i = 0; i < state->total_pointers; i++) {
1425
+ storj_pointer_t *pointer = &state->pointers[i];
1426
+ if (pointer->status == POINTER_MISSING) {
1427
+ missing = true;
1428
+ }
1429
+ }
1430
+ return missing;
1431
+ }
1432
+
1433
+ static bool can_recover_shards(storj_download_state_t *state)
1434
+ {
1435
+ if (state->pointers_completed) {
1436
+ uint32_t missing_pointers = 0;
1437
+
1438
+ for (int i = 0; i < state->total_pointers; i++) {
1439
+ storj_pointer_t *pointer = &state->pointers[i];
1440
+ if (pointer->status == POINTER_MISSING) {
1441
+ missing_pointers += 1;
1442
+ }
1443
+ }
1444
+
1445
+ if (missing_pointers > state->total_parity_pointers) {
1446
+ return false;
1447
+ }
1448
+ }
1449
+
1450
+ return true;
1451
+ }
1452
+
1453
+ static void after_recover_shards(uv_work_t *work, int status)
1454
+ {
1455
+ file_request_recover_t *req = work->data;
1456
+ storj_download_state_t *state = req->state;
1457
+
1458
+ state->pending_work_count--;
1459
+ state->recovering_shards = false;
1460
+ state->truncated = true;
1461
+
1462
+ if (status != 0) {
1463
+ req->state->error_status = STORJ_QUEUE_ERROR;
1464
+ } else if (req->error_status) {
1465
+ req->state->error_status = req->error_status;
1466
+ } else {
1467
+ // Recovery was successful and the pointers have been finished
1468
+ for (int i = 0; i < state->total_pointers; i++) {
1469
+ state->pointers[i].status = POINTER_FINISHED;
1470
+ state->completed_shards += 1;
1471
+ }
1472
+ }
1473
+
1474
+ queue_next_work(state);
1475
+
1476
+ memset_zero(req->decrypt_key, SHA256_DIGEST_SIZE);
1477
+ free(req->decrypt_key);
1478
+
1479
+ memset_zero(req->decrypt_ctr, AES_BLOCK_SIZE);
1480
+ free(req->decrypt_ctr);
1481
+
1482
+ free(req->zilch);
1483
+ free(req);
1484
+ free(work);
1485
+ }
1486
+
1487
+ static void recover_shards(uv_work_t *work)
1488
+ {
1489
+ file_request_recover_t *req = work->data;
1490
+ storj_download_state_t *state = req->state;
1491
+ reed_solomon* rs = NULL;
1492
+ uint8_t *data_map = NULL;
1493
+ uint8_t **data_blocks = NULL;
1494
+ uint8_t **fec_blocks = NULL;
1495
+
1496
+ int error = 0;
1497
+
1498
+ struct aes256_ctx ctx;
1499
+ uint64_t bytes_decrypted = 0;
1500
+ size_t len = AES_BLOCK_SIZE * 8;
1501
+
1502
+ // Make sure that the file is the correct size before recovering
1503
+ // shards in case that the last shard is the one being recovered.
1504
+ #ifdef _WIN32
1505
+
1506
+ HANDLE prefile = (HANDLE)_get_osfhandle(req->fd);
1507
+ if (prefile == INVALID_HANDLE_VALUE) {
1508
+ req->error_status = STORJ_FILE_RESIZE_ERROR;
1509
+ return;
1510
+ }
1511
+
1512
+ LARGE_INTEGER presize;
1513
+ presize.HighPart = (uint32_t)((req->filesize & 0xFFFFFFFF00000000LL) >> 32);
1514
+ presize.LowPart = (uint32_t)(req->filesize & 0xFFFFFFFFLL);
1515
+
1516
+ if (!SetFilePointerEx(prefile, presize, 0, FILE_BEGIN)) {
1517
+ req->error_status = STORJ_FILE_RESIZE_ERROR;
1518
+ return;
1519
+ }
1520
+
1521
+ if (!SetEndOfFile(prefile)) {
1522
+ req->error_status = STORJ_FILE_RESIZE_ERROR;
1523
+ return;
1524
+ }
1525
+
1526
+ #else
1527
+ if (ftruncate(req->fd, req->filesize)) {
1528
+ // errno for more details
1529
+ req->error_status = STORJ_FILE_RESIZE_ERROR;
1530
+ }
1531
+ #endif
1532
+
1533
+ error = map_file(req->fd, req->filesize, &data_map, false);
1534
+ if (error) {
1535
+ req->error_status = STORJ_MAPPING_ERROR;
1536
+ goto finish;
1537
+ }
1538
+
1539
+ if (!req->has_missing) {
1540
+ goto decrypt;
1541
+ }
1542
+
1543
+ fec_init();
1544
+
1545
+ rs = reed_solomon_new(req->data_shards, req->parity_shards);
1546
+ if (!rs) {
1547
+ req->error_status = STORJ_MEMORY_ERROR;
1548
+ goto finish;
1549
+ }
1550
+
1551
+ data_blocks = (uint8_t**)malloc(req->data_shards * sizeof(uint8_t *));
1552
+ if (!data_blocks) {
1553
+ req->error_status = STORJ_MEMORY_ERROR;
1554
+ goto finish;
1555
+ }
1556
+
1557
+ fec_blocks = (uint8_t**)malloc(req->parity_shards * sizeof(uint8_t *));
1558
+ if (!fec_blocks) {
1559
+ req->error_status = STORJ_MEMORY_ERROR;
1560
+ goto finish;
1561
+ }
1562
+
1563
+ for (int i = 0; i < req->data_shards; i++) {
1564
+ data_blocks[i] = data_map + i * req->shard_size;
1565
+ }
1566
+
1567
+ for (int i = 0; i < req->parity_shards; i++) {
1568
+ fec_blocks[i] = data_map + (req->data_shards + i) * req->shard_size;
1569
+ }
1570
+
1571
+ uint32_t total_shards = req->data_shards + req->parity_shards;
1572
+
1573
+ state->log->debug(state->env->log_options, state->handle,
1574
+ "Recovering shards, data_shards: %i, " \
1575
+ "parity_shards: %i, shard_size: %" PRIu64 ", " \
1576
+ "file_size: %" PRIu64,
1577
+ req->data_shards,
1578
+ req->parity_shards,
1579
+ req->shard_size,
1580
+ req->data_filesize);
1581
+
1582
+ error = reed_solomon_reconstruct(rs, data_blocks, fec_blocks,
1583
+ req->zilch, total_shards,
1584
+ req->shard_size, req->data_filesize);
1585
+
1586
+ if (error) {
1587
+ req->error_status = STORJ_FILE_RECOVER_ERROR;
1588
+ goto finish;
1589
+ }
1590
+
1591
+
1592
+ decrypt:
1593
+
1594
+ aes256_set_encrypt_key(&ctx, req->decrypt_key);
1595
+
1596
+ while (bytes_decrypted < req->data_filesize) {
1597
+
1598
+ if (bytes_decrypted + len > req->data_filesize) {
1599
+ len = req->data_filesize - bytes_decrypted;
1600
+ }
1601
+
1602
+ ctr_crypt(&ctx, (nettle_cipher_func *)aes256_encrypt,
1603
+ AES_BLOCK_SIZE, req->decrypt_ctr,
1604
+ len,
1605
+ (uint8_t *)data_map + bytes_decrypted,
1606
+ (uint8_t *)data_map + bytes_decrypted);
1607
+
1608
+ bytes_decrypted += len;
1609
+ }
1610
+
1611
+ finish:
1612
+ if (data_map) {
1613
+ error = unmap_file(data_map, req->filesize);
1614
+ if (error) {
1615
+ req->error_status = STORJ_UNMAPPING_ERROR;
1616
+ }
1617
+ }
1618
+
1619
+ if (data_blocks) {
1620
+ free(data_blocks);
1621
+ }
1622
+
1623
+ if (fec_blocks) {
1624
+ free(fec_blocks);
1625
+ }
1626
+
1627
+ if (rs) {
1628
+ reed_solomon_release(rs);
1629
+ }
1630
+
1631
+ #ifdef _WIN32
1632
+
1633
+ HANDLE file = (HANDLE)_get_osfhandle(req->fd);
1634
+ if (file == INVALID_HANDLE_VALUE) {
1635
+ req->error_status = STORJ_FILE_RESIZE_ERROR;
1636
+ return;
1637
+ }
1638
+
1639
+ LARGE_INTEGER size;
1640
+ size.HighPart = (uint32_t)((req->data_filesize & 0xFFFFFFFF00000000LL) >> 32);
1641
+ size.LowPart = (uint32_t)(req->data_filesize & 0xFFFFFFFFLL);
1642
+
1643
+ if (!SetFilePointerEx(file, size, 0, FILE_BEGIN)) {
1644
+ req->error_status = STORJ_FILE_RESIZE_ERROR;
1645
+ return;
1646
+ }
1647
+
1648
+ if (!SetEndOfFile(file)) {
1649
+ req->error_status = STORJ_FILE_RESIZE_ERROR;
1650
+ return;
1651
+ }
1652
+
1653
+ #else
1654
+ if (ftruncate(req->fd, req->data_filesize)) {
1655
+ // errno for more details
1656
+ req->error_status = STORJ_FILE_RESIZE_ERROR;
1657
+ }
1658
+ #endif
1659
+
1660
+ }
1661
+
1662
+ static void queue_recover_shards(storj_download_state_t *state)
1663
+ {
1664
+ if (!state->recovering_shards && state->pointers_completed) {
1665
+
1666
+ int total_missing = 0;
1667
+ bool has_missing = false;
1668
+ bool is_ready = true;
1669
+
1670
+ uint8_t *zilch = (uint8_t *)calloc(1, state->total_pointers);
1671
+
1672
+ for (int i = 0; i < state->total_pointers; i++) {
1673
+ storj_pointer_t *pointer = &state->pointers[i];
1674
+ if (pointer->status == POINTER_MISSING) {
1675
+ total_missing += 1;
1676
+ has_missing = true;
1677
+ zilch[i] = 1;
1678
+ }
1679
+
1680
+ if (pointer->status != POINTER_MISSING &&
1681
+ pointer->status != POINTER_DOWNLOADED) {
1682
+ is_ready = false;
1683
+ state->log->debug(state->env->log_options,
1684
+ state->handle,
1685
+ "Pointer %i not ready with status: %i",
1686
+ i, pointer->status);
1687
+
1688
+ }
1689
+ }
1690
+
1691
+ if (!is_ready) {
1692
+ free(zilch);
1693
+ return;
1694
+ }
1695
+
1696
+ state->log->info(state->env->log_options,
1697
+ state->handle,
1698
+ "Queuing recovery of %i of %i shards",
1699
+ total_missing, state->total_shards);
1700
+
1701
+ file_request_recover_t *req = malloc(sizeof(file_request_recover_t));
1702
+ if (!req) {
1703
+ state->error_status = STORJ_MEMORY_ERROR;
1704
+ return;
1705
+ }
1706
+
1707
+ uv_work_t *work = malloc(sizeof(uv_work_t));
1708
+ if (!work) {
1709
+ state->error_status = STORJ_MEMORY_ERROR;
1710
+ return;
1711
+ }
1712
+
1713
+ req->fd = fileno(state->destination);
1714
+ req->filesize = state->shard_size * state->total_pointers;
1715
+ req->data_filesize = calculate_data_filesize(state);
1716
+ req->data_shards = state->total_pointers - state->total_parity_pointers;
1717
+ req->parity_shards = state->total_parity_pointers;
1718
+ req->shard_size = state->shard_size;
1719
+ req->zilch = zilch;
1720
+ req->has_missing = has_missing;
1721
+
1722
+ if (state->decrypt_key && state->decrypt_ctr) {
1723
+ req->decrypt_key = calloc(SHA256_DIGEST_SIZE, sizeof(uint8_t));
1724
+ if (!req->decrypt_key) {
1725
+ state->error_status = STORJ_MEMORY_ERROR;
1726
+ return;
1727
+ }
1728
+ req->decrypt_ctr = calloc(AES_BLOCK_SIZE, sizeof(uint8_t));
1729
+ if (!req->decrypt_ctr) {
1730
+ state->error_status = STORJ_MEMORY_ERROR;
1731
+ return;
1732
+ }
1733
+ memcpy(req->decrypt_key, state->decrypt_key, SHA256_DIGEST_SIZE);
1734
+ memcpy(req->decrypt_ctr, state->decrypt_ctr, AES_BLOCK_SIZE);
1735
+
1736
+ increment_ctr_aes_iv(req->decrypt_ctr, 0);
1737
+ } else {
1738
+ req->decrypt_key = NULL;
1739
+ req->decrypt_ctr = NULL;
1740
+ }
1741
+
1742
+ req->state = state;
1743
+ req->error_status = 0;
1744
+
1745
+ work->data = req;
1746
+
1747
+ state->pending_work_count++;
1748
+ int status = uv_queue_work(state->env->loop, (uv_work_t*) work,
1749
+ recover_shards, after_recover_shards);
1750
+
1751
+ if (status) {
1752
+ state->error_status = STORJ_QUEUE_ERROR;
1753
+ return;
1754
+ }
1755
+
1756
+ state->recovering_shards = true;
1757
+ }
1758
+ }
1759
+
1760
+ static void queue_next_work(storj_download_state_t *state)
1761
+ {
1762
+ // report any errors
1763
+ if (state->error_status != 0) {
1764
+ if (!state->finished && state->pending_work_count == 0) {
1765
+
1766
+ state->finished = true;
1767
+ state->finished_cb(state->error_status,
1768
+ state->destination,
1769
+ state->handle);
1770
+
1771
+ free_download_state(state);
1772
+ }
1773
+
1774
+ return;
1775
+ }
1776
+
1777
+ // report download complete
1778
+ if (state->pointers_completed &&
1779
+ state->completed_shards == state->total_shards &&
1780
+ state->truncated) {
1781
+
1782
+ if (!state->finished && state->pending_work_count == 0) {
1783
+
1784
+ // calculate the hmac of all shard hashes
1785
+ if (prepare_file_hmac(state)) {
1786
+ state->error_status = STORJ_FILE_GENERATE_HMAC_ERROR;
1787
+ }
1788
+
1789
+ if (state->info && state->info->hmac) {
1790
+ if (0 != strcmp(state->info->hmac, state->hmac)) {
1791
+ state->error_status = STORJ_FILE_DECRYPTION_ERROR;
1792
+ }
1793
+ } else {
1794
+ state->log->warn(state->env->log_options,
1795
+ state->handle,
1796
+ "Unable to verify decryption integrity" \
1797
+ ", missing hmac from file info.");
1798
+ }
1799
+
1800
+ state->finished = true;
1801
+ state->finished_cb(state->error_status, state->destination, state->handle);
1802
+
1803
+ free_download_state(state);
1804
+ return;
1805
+ }
1806
+
1807
+ goto finish_up;
1808
+ }
1809
+
1810
+ queue_request_pointers(state);
1811
+
1812
+ if (!state->info) {
1813
+ queue_request_info(state);
1814
+ }
1815
+
1816
+ if (state->info) {
1817
+ queue_request_shards(state);
1818
+
1819
+ if (state->rs) {
1820
+ if (can_recover_shards(state)) {
1821
+ queue_recover_shards(state);
1822
+ } else {
1823
+ state->error_status = STORJ_FILE_SHARD_MISSING_ERROR;
1824
+ queue_next_work(state);
1825
+ return;
1826
+ }
1827
+ } else {
1828
+ if (!has_missing_shard(state)) {
1829
+ queue_recover_shards(state);
1830
+ } else {
1831
+ state->error_status = STORJ_FILE_SHARD_MISSING_ERROR;
1832
+ queue_next_work(state);
1833
+ return;
1834
+ }
1835
+ }
1836
+ }
1837
+
1838
+ queue_send_exchange_reports(state);
1839
+
1840
+ finish_up:
1841
+
1842
+ state->log->debug(state->env->log_options, state->handle,
1843
+ "Pending work count: %d", state->pending_work_count);
1844
+
1845
+ }
1846
+
1847
+ STORJ_API int storj_bridge_resolve_file_cancel(storj_download_state_t *state)
1848
+ {
1849
+ if (state->canceled) {
1850
+ return 0;
1851
+ }
1852
+
1853
+ state->canceled = true;
1854
+ state->error_status = STORJ_TRANSFER_CANCELED;
1855
+
1856
+ // loop over all pointers, and cancel any that are queued to be downloaded
1857
+ // any downloads that are in-progress will monitor the state->canceled
1858
+ // status and exit when set to true
1859
+ for (int i = 0; i < state->total_pointers; i++) {
1860
+ storj_pointer_t *pointer = &state->pointers[i];
1861
+ if (pointer->status == POINTER_BEING_DOWNLOADED) {
1862
+ uv_cancel((uv_req_t *)pointer->work);
1863
+ }
1864
+ }
1865
+
1866
+ return 0;
1867
+ }
1868
+
1869
+ STORJ_API storj_download_state_t *storj_bridge_resolve_file(storj_env_t *env,
1870
+ const char *bucket_id,
1871
+ const char *file_id,
1872
+ FILE *destination,
1873
+ void *handle,
1874
+ storj_progress_cb progress_cb,
1875
+ storj_finished_download_cb finished_cb)
1876
+ {
1877
+ storj_download_state_t *state = malloc(sizeof(storj_download_state_t));
1878
+ if (!state) {
1879
+ return NULL;
1880
+ }
1881
+
1882
+ // setup download state
1883
+ state->total_bytes = 0;
1884
+ state->info = NULL;
1885
+ state->requesting_info = false;
1886
+ state->info_fail_count = 0;
1887
+ state->env = env;
1888
+ state->file_id = file_id;
1889
+ state->bucket_id = bucket_id;
1890
+ state->destination = destination;
1891
+ state->progress_cb = progress_cb;
1892
+ state->finished_cb = finished_cb;
1893
+ state->finished = false;
1894
+ state->total_shards = 0;
1895
+ state->download_max_concurrency = STORJ_DOWNLOAD_CONCURRENCY;
1896
+ state->completed_shards = 0;
1897
+ state->resolving_shards = 0;
1898
+ state->total_pointers = 0;
1899
+ state->total_parity_pointers = 0;
1900
+ state->rs = false;
1901
+ state->recovering_shards = false;
1902
+ state->truncated = true;
1903
+ state->pointers = NULL;
1904
+ state->pointers_completed = false;
1905
+ state->pointer_fail_count = 0;
1906
+ state->requesting_pointers = false;
1907
+ state->error_status = STORJ_TRANSFER_OK;
1908
+ state->writing = false;
1909
+ state->shard_size = 0;
1910
+ state->excluded_farmer_ids = NULL;
1911
+ state->hmac = NULL;
1912
+ state->pending_work_count = 0;
1913
+ state->canceled = false;
1914
+ state->log = env->log;
1915
+ state->handle = handle;
1916
+ state->decrypt_key = NULL;
1917
+ state->decrypt_ctr = NULL;
1918
+
1919
+ // start download
1920
+ queue_next_work(state);
1921
+
1922
+ return state;
1923
+ }