Inception  Check-in [4b8ed99f8b]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:First commit.

Includes not yet ready or useable or tested code and is merely a starting point for the furtherance of this project.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256:4b8ed99f8bd20cecd56a55413db1cdfff052544edb07b789d595959b8cd4aedd
User & Date: llmII 2018-11-27 21:46:57
Context
2018-11-27
21:56
Changed license to canonical version.

Changed lic... Leaf check-in: 98b08c5e00 user: llmII tags: trunk

21:46
First commit.

Includes not yet ready or useable o... check-in: 4b8ed99f8b user: llmII tags: trunk

21:21
initial empty check-in check-in: b3bcb43eeb user: llmII tags: trunk
Changes

Added COPYRIGHTS.md.











>
>
>
>
>
1
2
3
4
5
# Works copyrighted by:

1. llmII

Unless noted otherwise, all works in this repository are copyright (c) llmII.

Added LICENSE.md.









































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# Copyfree Open Innovation License

This is version 0.5 of the Copyfree Open Innovation License.

## Terms and Conditions

Redistributions, modified or unmodified, in whole or in part, must retain
applicable copyright or other legal privilege notices, these conditions, and the
following license terms and disclaimer. Subject to these conditions, the
holder(s) of copyright or other legal privileges, author(s) or assembler(s), and
contributors of this work hereby grant to any person who obtains a copy of this
work in any form:

1. Permission to reproduce, modify, distribute, publish, sell, sublicense, use,
and/or otherwise deal in the licensed material without restriction.

2. A perpetual, worldwide, non-exclusive, royalty-free, irrevocable patent
license to reproduce, modify, distribute, publish, sell, use, and/or otherwise
deal in the licensed material without restriction, for any and all patents:

a. Held by each such holder of copyright or other legal privilege, author or
assembler, or contributor, necessarily infringed by the contributions alone or
by combination with the work, of that privilege holder, author or assembler,
or contributor.

b. Necessarily infringed by the work at the time that holder of copyright or
other privilege, author or assembler, or contributor made any contribution to
the work.

NO WARRANTY OF ANY KIND IS IMPLIED BY, OR SHOULD BE INFERRED FROM, THIS LICENSE
OR THE ACT OF DISTRIBUTION UNDER THE TERMS OF THIS LICENSE, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS, ASSEMBLERS, OR HOLDERS OF
COPYRIGHT OR OTHER LEGAL PRIVILEGE BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER
LIABILITY, WHETHER IN ACTION OF CONTRACT, TORT, OR OTHERWISE ARISING FROM, OUT
OF, OR IN CONNECTION WITH THE WORK OR THE USE OF OR OTHER DEALINGS IN THE WORK.

Added inception.md.























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# INCEPTION
### Files within a filesytem within a file!

#### Reference:
* [Example](https://github.com/jpiechowka/libsodium-file-crypter)

# Version 0.1 (WIP)
## Todo:
* Get it working

# Version 0.2 (WIP)
## Todo:
* Refine internals to mostly use a stream-like API
 like:
  1. Encrypt =
  padder -> blocker -> crypter -> write -> result
  2. Decrypt =
  read -> decrypt -> deblock -> depad -> result

# Version 0.3 (WIP)
## Todo:
* Tests for each part of the system where it makes sense.

# Version 0.4 - 0.9 (WIP)
## Todo:
* Continued refinement

# Version 1.0 (WIP)
## Todo:
* Once stable and well implemented, release.
  Previous releases should have worked but this would
  be the first release considered stable.

# Version 1.1-1.9 (WIP)
## Todo:
* Maintain 1.x series gradually adding better user
  interfacability (command line) whilst the file
  format remains the same. Work on 2.0 simultaneously.

# Version 2.0 (WIP)
## Todo:
* Implement duress mode, major file format change,
  provide migration path.

Added src/core/allocator.c.



























>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdlib.h>
#include "allocator.h"

allocator make_allocator(allocate_heap al, free_heap fr) {
  allocator ret;
  ret.allocate = al;
  ret.free = fr;
  return ret;
}

void *calloc_malloc(size_t size) {
  return calloc(size, 1);
}

Added src/core/allocator.h.























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef _INCEPTION_HEADER_ALLOCATOR_H
#define _INCEPTION_HEADER_ALLOCATOR_H

#include <stdlib.h>

// malloc/free compatible function pointer definitions
typedef void *(*allocate_heap)(size_t);
typedef void (*free_heap)(void *);
// the allocator struct type, holds fp's to a malloc and free implementation
typedef struct allocator_t allocator;

// wrapping calloc to match a malloc fp
void *calloc_malloc(size_t);
// makes an allocator out of 2 fp's matching the defs of malloc/free
inline allocator make_allocator(allocate_heap, free_heap);

// the allocator struct, holds fp's to a malloc and free implementation
struct allocator_t {
  allocate_heap allocate;
  free_heap     free;
};

// an allocator using libc calloc and libc free as underlying
// functions
const allocator malloc_allocator = { calloc_malloc, free };
// libsodium based allocator?
#endif

Added src/core/common.h.

































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef _INCEPTION_HEADER_COMMON_H
#define _INCEPTION_HEADER_COMMON_H

// integer types needed
#include <stdint.h>

// types
typedef uint8_t  blk_byte;
typedef uint8_t  blk_bool;
typedef uint8_t  blk_retval;
typedef uint16_t blk_e_offset;
typedef uint64_t blk_blockptr;
typedef uint64_t blk_identifier;
typedef uint64_t blk_size;

#endif

Added src/crypto/common.h.

















>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
#ifndef _INCEPTION_HEADER_CRYPTO_COMMON_H
#define _INCEPTION_HEADER_CRYPTO_COMMON_H

// important lengths
#include <sodium.h>
#define CRYPTO_SALT_LEN crypto_pwhash_SALTBYTES

#endif

Added src/crypto/crypto.c.





































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
#include <sodium.h>
#include "crypto.h"
#include "../core/common.h"
#include "common.h"

#define CRYPTO_HASH_LEN crypto_secretstream_xchacha20poly1305_KEYBYTES
#define STREAM_HEADER_BYTES crypto_secretstream_xchacha20poly1305_HEADERBYTES
#define BLOCK_HEADER_BYTES crypto_secretstream_xchacha20poly1305_ABYTES
#define STREAM_TAG_FINAL crypto_secretstream_xchacha20poly1305_TAG_FINAL
#define init_push crypto_secretstream_xchacha20poly1305_init_push
#define push crypto_secretstream_xchacha20poly1305_push
#define init_pull crypto_secretstream_xchacha20poly1305_init_pull
#define pull crypto_secretstream_xchacha20poly1305_pull

// function definitions
blk_size encrypt_begin(crypto_pipe *, blk_byte *, const blk_size,
                       crypto_status *);
blk_size encrypt_pump(crypto_pipe *, const blk_byte *, crypto_status *);
blk_size encrypt_end(crypto_pipe *, const blk_byte *, crypto_status *);
blk_size decrypt_begin(crypto_pipe *, blk_byte *, const blk_size,
                       crypto_status *);
blk_size decrypt_pump(crypto_pipe *, const blk_byte *, crypto_status *);
blk_size decrypt_end(crypto_pipe *, const blk_byte *, crypto_status *);


// internal functions
void init_crypto_state(crypto_state *state, blk_byte *ebuf,
                       unsigned char tag) {
  state->cbuf = ebuf;
  state->tag = 0;
}

blk_size _encrypt_begin(crypto_state *state, blk_byte *ebuf,
                       const blk_size chunk_size, crypto_status *status) {
  // check that we haven't already started stream
  if(state->status != 0) goto error;

  // set up state and the return value
  *status = CRYPTO_GENERAL_ERROR;
  init_crypto_state(state, ebuf, 0);

  // initialize stream
  init_push(&(state->state), state->cbuf, state->hash);

  // still using the same buffer after this so indicate we should
  // write at a point further in the buffer than beginning
  state->offset = STREAM_HEADER_BYTES + 1;
  *status = CRYPTO_SUCCESS; // indicate success
  state->status = 1; // initialized!

  // return the size they should use for the next data block
  return state->chunk_size - state->offset - BLOCK_HEADER_BYTES;

  // we've already been initialized or ended!
 error:
  *status = CRYPTO_STATE_ERROR;
  return 0;
}

blk_size _encrypt_pump(crypto_state *state, const blk_byte *data,
                       crypto_status *status) {
  // length of fill of buffer after crypto op
  unsigned long long output_length = 0;

  // check if we've initialized the stream previously and that
  // we haven't ended the stream already
  if(state->status != 1) goto error;

  // setup our return status
  *status = CRYPTO_GENERAL_ERROR;

  // push the data
  push(&(state->state), state->cbuf + state->offset, &output_length, data,
       state->chunk_size - state->offset - BLOCK_HEADER_BYTES - 1, NULL, 0,
       state->tag);

  // check that our output length matches expectations and set status to
  // success if so
  if(output_length == state->chunk_size \
     - state->offset - BLOCK_HEADER_BYTES - 1) {
    *status = CRYPTO_SUCCESS;
  }

  // reset offset, won't need it any more
  state->offset = 0;

  // return next block size
  return state->chunk_size - BLOCK_HEADER_BYTES;

  // the stream is in incorrect state!
 error:
  *status = CRYPTO_STATE_ERROR;
  return 0;
}

blk_size _encrypt_end(crypto_state *state, const blk_byte *data,
                      crypto_status *status) {
  state->tag = STREAM_TAG_FINAL;
  _encrypt_pump(state, data, status);
  state->status = 2;
  return 0;
}

blk_size _decrypt_begin(crypto_state *state, blk_byte *ebuf,
                        const blk_size chunk_size, crypto_status *status) {
  // check that we haven't started decrypting stream yet
  if(state->status != 0) goto error;

  // initialize our state, setup status and offset to indicate next
  // read is valid and that we'll read out a header first
  *status = CRYPTO_SUCCESS;
  init_crypto_state(state, ebuf, 0);
  state->offset = STREAM_HEADER_BYTES;
  state->status = 1;

  // nothing to read from us yet
  return 0;

  // stream was already initialized, can't restart
 error:
  *status = CRYPTO_STATE_ERROR;
  return 0;
}

blk_size _decrypt_pump(crypto_state *state, const blk_byte *data,
                       crypto_status *status) {
  // where to store the output length, used to indicate successful
  // stream decryption
  unsigned long long output_length = 0;

  // setup default return status
  *status = CRYPTO_GENERAL_ERROR;

  // we haven't initialized yet? trying to read after ending? abort attempt
  if(state->status != 1) goto error;

  // if the offset is STREAM_HEADER_BYTES we need to pull the header first
  // falls through for a correct read
  switch(state->offset) {
  case STREAM_HEADER_BYTES:
    // pull header
    if(0 != init_pull(&(state->state), data, state->hash)) {
      *status = CRYPTO_INCOMPLETE_HEADER;
      goto error;
    }
  case 0:
    // pull data, check and if bad data indicate possible corruption or
    // the general fact that the state of this stream is now undefined
    if(0 != pull(&(state->state), state->cbuf, &output_length, &(state->tag),
                 data + state->offset + 1,
                 state->chunk_size - state->offset - 1,
                 NULL, 0)) {
      *status = CRYPTO_CHUNK_CORRUPTED;
      goto error;
    }
    // does the read indicate an end of stream? update state to tell us
    // not to try reading further if so
    if(state->tag == STREAM_TAG_FINAL) {
      state->status = 2;
    }
    // does the output length equal the amount of expected dat?
    // if not indicate possible corruption
    if(output_length !=
       state->chunk_size - state->offset - BLOCK_HEADER_BYTES - 1) {
      *status = CRYPTO_CHUNK_CORRUPTED;
      goto error;
    }
    break;

    // we should never end up here, but if we do, it is a major error
  default:
    goto error;
    break;
  }

  // reset offset to 0, we're not pulling out any further headers
  state->offset = 0;
  // indicate success
  *status = CRYPTO_SUCCESS;
  // tell them how much data we put in their buffer
  return output_length;

 error:
  *status = CRYPTO_STATE_ERROR;
  return 0;
}

blk_size _decrypt_end(crypto_state *state, const blk_byte *data,
                      crypto_status *status) {
  // nothing to do here
  *status = CRYPTO_SUCCESS;
  return 0;
}
// end internal functions

// attachable functions
// no-op functions!
blk_size no_begin(crypto_pipe *pipe, blk_byte *cbuf,
                       const blk_size chunk_size, crypto_status *status) {
  *status = CRYPTO_FUNCTION_CALLED_AT_WRONG_STAGE;
  return 0;
}

blk_size no_pump(crypto_pipe *pipe, const blk_byte *data,
                      crypto_status *status) {
  *status = CRYPTO_FUNCTION_CALLED_AT_WRONG_STAGE;
  return 0;
}

blk_size no_end(crypto_pipe *pipe, const blk_byte *data,
                      crypto_status *status) {
  *status = CRYPTO_FUNCTION_CALLED_AT_WRONG_STAGE;
  return 0;
}
// end no-op functions!
blk_size encrypt_begin(crypto_pipe *pipe, blk_byte *cbuf,
                       const blk_size chunk_size, crypto_status *status) {
  // detach init
  pipe->init = no_begin;

  // attach pump and end
  pipe->pump = encrypt_pump;
  pipe->end = encrypt_end;

  // call implementation
  return _encrypt_begin(&(pipe->state), cbuf, chunk_size, status);
}

blk_size encrypt_pump(crypto_pipe *pipe, const blk_byte *data,
                      crypto_status *status) {
  // call implementation
  return _encrypt_pump(&(pipe->state), data, status);
}

blk_size encrypt_end(crypto_pipe *pipe, const blk_byte *data,
                      crypto_status *status) {
  // detach pump and end
  pipe->pump = no_pump;
  pipe->end = no_end;

  // call implementation
  return _encrypt_end(&(pipe->state), data, status);
}

blk_size decrypt_begin(crypto_pipe *pipe, blk_byte *cbuf,
                       const blk_size chunk_size, crypto_status *status) {
  // detach init
  pipe->init = no_begin;

  // attach pump and end
  pipe->pump = encrypt_pump;
  pipe->end = encrypt_end;

  // call implementation
  return _decrypt_begin(&(pipe->state), cbuf, chunk_size, status);
}

blk_size decrypt_pump(crypto_pipe *pipe, const blk_byte *data,
                      crypto_status *status) {
  // call implementation
  return _decrypt_pump(&(pipe->state), data, status);
}

blk_size decrypt_end(crypto_pipe *pipe, const blk_byte *data,
                      crypto_status *status) {
  // detach pump and end
  pipe->pump = no_pump;
  pipe->end = no_end;

  // call implementation
  return _decrypt_pump(&(pipe->state), data, status);
}

// end attachable functions

// helper function
void init_state(crypto_state *state, const blk_byte *hash) {
  state->hash = hash;
  state->offset = 0;
  state->status = 0;
  state->chunk_size = 0;
  state->cbuf = NULL;
}

void destroy_pipe(crypto_pipe *pipe) {
  pipe->init = NULL;
  pipe->pump = NULL;
  pipe->end = NULL;
  init_state(&(pipe->state), NULL);
}

blk_retval init_encryption_pipe(crypto_pipe *pipe, const blk_byte *hash){
  // attach init, set state, set state's hash
  init_state(&(pipe->state), hash);
  pipe->init = encrypt_begin;

  // indicate success
  return 1;
}

blk_retval init_decryption_pipe(crypto_pipe *pipe, const blk_byte *hash){
  // attach init, set state, set state's hash
  init_state(&(pipe->state), hash);
  pipe->init = decrypt_begin;

  // indicate success
  return 1;
}

blk_retval destroy_encryption_pipe(crypto_pipe *pipe){
  destroy_pipe(pipe);

  // indicate success
  return 1;
}

blk_retval destroy_decryption_pipe(crypto_pipe *pipe){
  destroy_pipe(pipe);

  // indicate success
  return 1;
}

Added src/crypto/crypto.h.











































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#ifndef _INCEPTION_HEADER_CRYPTO_CRYPTO_H
#define _INCEPTION_HEADER_CRYPTO_CRYPTO_H

#include <sodium.h>
#include <stdint.h>
#include "../core/common.h"

// alias this since it is a bunch of typing
#define API_CRYPTO_STATE crypto_secretstream_xchacha20poly1305_state

typedef struct crypto_pipe_t crypto_pipe;
typedef struct crypto_state_t crypto_state;
enum crypto_status_t {
  CRYPTO_SUCCESS,
  CRYPTO_INCOMPLETE_HEADER,
  CRYPTO_CHUNK_CORRUPTED,
  CRYPTO_GENERAL_ERROR,
  CRYPTO_STATE_ERROR,
  CRYPTO_FUNCTION_CALLED_AT_WRONG_STAGE
};
typedef enum crypto_status_t crypto_status;

/******************************************************************************
 Crypto Functions:

   crypto_begin:
     arguments  -
       state          : State of the crypto (initialized here).
       encryption_buf : The buffer to be used by each underlying encryption
                          call
       chunk_size     : The size of the buffer (also the chunk size the crypto
                          functions will operate at).
       status         : The error value used to check the state of crypto
                          (if it succeeded, or failed).
     returns    -
       size           : Encryption mode --
                          The amount of data to supply for next crypto
                          operation.
                        Decryption mode --
                          0, no data read yet

   crypto_pump:
     arguments  -
       state          : State of the crypto (updated here).
       data           : The input for the crypto function.
       status         : The error value used to check the state of crypto
                          (if it succeeded, or failed).
     returns    -
       size           : Encryption mode --
                          The amount of data to supply for next crypto
                          operation.
                        Decryption mode --
                          The ammount of data to be supplied for crypto
                          operations is constant, however, the amount of user
                          data gained by decryption can vary and thus this
                          is the size of data that's readable.

   crypto_end:
     arguments  -
       state          : State of the crypto (finalized here).
       data           : The input for the crypto function.
       status         : The error value used to check the state of crypto
                          (if it succeeded, or failed).
     returns    -
       size           : Encryption mode --
                          0, no more may be written.
                        Decryption mode --
                          The ammount of data to be supplied for crypto
                          operations is constant, however, the amount of user
                          data gained by decryption can vary and thus this
                          is the size of data that's readable.

   init_encryption_pipe:
     arguments  -
       pipe           : Pipe to initialize.
       state          : State to attach to pipe.
       hash           : Password hash to use with pipe.
     returns    -
       success        : 1, always succeeds

   init_decryption_pipe:
     arguments  -
       pipe           : Pipe to initialize.
       state          : State to attach to pipe.
       hash           : Password hash to use with pipe.
     returns    -
       success        : 1, always succeeds

   destroy_decryption_pipe:
     arguments  -
       pipe           : Pipe to destroy.
     returns    -
       success        : 1, always succeeds

   destroy_decryption_pipe:
     arguments  -
       pipe           : Pipe to destroy.
     returns    -
       success        : 1, always succeeds

 Usage:
   Note, the examples show useage with the data on the stack, if you are
   allocating from the heap, you're responsible for freeing the data, not
   any of these functions.

   For both encryption and decryption you are responsible for keeping up
   with when data is at the end!

   For encryption one would acquire a crypto_pipe, and use like:
     const chunk_size = 4096;
     blk_byte crypto_buf[chunk_size];
     blk_byte data_buf[chunk_size];
     crypto_pipe pipe;
     blk_retval status = 0;
     blk_size next_write_size = 0;
     blk_byte *hash; // get the hash/key from somewhere
     init_encryption_pipe(&pipe, hash);
     next_write_size = pipe.init(&pipe, crypto_buf, chunk_size,
                                 &status);
     // read something into the data_buf for the pipe to encrypt (supply
     //   only up to next_write_size bytes)

     // data loop start!
     // check the status
     // do something with crypto_buf (write it somewhere, its gone with
     //   next crypto call)
     // read something into the data_buf for the pipe to encrypt (supply
     //   only up to next_write_size bytes)
     next_write_size = pipe.pump(&pipe, data_buf, &status);
     // check your data reads are you at end? kill loop, otherwise, loop again

     // check the status
     // do something with crypto_buf (write it somewhere, its gone with
     //   next crypto call)
     // read something into the data_buf for the pipe to encrypt (supply
     //   only up to next_write_size bytes)
     pipe.end(&pipe, data, &status);
     // check the status
     // do something with crypto_buf (write it somewhere, its gone with
     //   next crypto call)
     destroy_encryption_pipe(&pipe);

   For decryption it is much the same the only difference being that instead
   of supplying data of varying size you are getting back data of varying
   size which the pipe will indicate.

   The purpose of this interface is to make writing code to keep blocks all
   the same size easier.
 *****************************************************************************/
typedef blk_size (*crypto_begin)(crypto_pipe *, blk_byte *, const blk_size,
                               crypto_status *);

typedef blk_size (*crypto_pump)(crypto_pipe *, const blk_byte *,
                                crypto_status *);

typedef blk_size (*crypto_end)(crypto_pipe *, const blk_byte *,
                               crypto_status *);

struct crypto_state_t {
  API_CRYPTO_STATE state;
  blk_blockptr     offset;
  unsigned char    tag;
  blk_bool         status;
  blk_size         chunk_size;
  blk_byte         *cbuf;
  const blk_byte   *hash;
};

struct crypto_pipe_t {
  crypto_begin init;
  crypto_pump  pump;
  crypto_end   end;
  crypto_state state;
};

blk_retval init_encryption_pipe(crypto_pipe *, const blk_byte *);
blk_retval init_decryption_pipe(crypto_pipe *, const blk_byte *);
blk_retval destroy_encryption_pipe(crypto_pipe *);
blk_retval destroy_decryption_pipe(crypto_pipe *);

#endif

Added src/fs/encrypted_file.c.























































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/******************************************************************************
 This file needs changes in freemap:
   iteration needs to take a void* state
   push and pop need to keep track and increment/decrement a size var

 The on disk file structure is like as follows:
   struct encrypted_file_header_t {
     blk_bool         in_use;                // file in use flag
     blk_blockptr     idx_cloc;              // current index location
     blk_blockptr     idx_mloc;              // minimum index location
     blk_size         chunk_size;            // size of chunks in file
     blk_identifier   version;               // version of program
                                             // that wrote file
     blk_byte         salt[CRYPTO_SALT_LEN]; // salt used for encryption
   };

   Index is kept in the end region of the file, data inbetween is all
   encrypted block streams.

 The encrypted file's responsibilities are as follows:
   opening encrypted block_streams
   growing (with index relocation)
   index management (atomicity?)

 pseudocode for the following internal functions that might possibly
   be assigned to function pointers for external useage need be:

   The idea is for the index to never be in a bad state by using non-clashing
   writes and atomically setting index offset.

   index_writer
     block_count
     temp_idx_offset
     if idx_mloc != idx_cloc
       block_count = calc_index_block_count(index->size)
       if (idx_cloc - idx_mloc)/chunk_size > block_count
         write index to min_index_loc
         set temp_idx_offset = idx_mloc
     else
       jump end of file
       temp_idx_offset = ftell()
       write index to temp_idx_offset
     update idx_cloc with val of temp_idx_offset

   file_grower
     jump end of file
     fsize = ftell()
     write fsize amount of bytes at end of file
     jump end of file
     fsize = ftell()
     update in memory index with max_growth = fsize // inform growth
     if inform growth says not aligned
        write alignment bytes specified by inform growth
        jump end of file
        fsize = ftell()
        update in memory index with max_growth = fsize
     write index at end of file
     set idx_mloc to fsize
     set idx_cloc to fsize

   open_file // assumes not in_use
     read from file idx_cloc, idx_mloc
     if idx_mloc > idx_cloc
       write idx_mloc to idx_cloc in file
       set idx_cloc to idx_mloc
     // stuff
     jump idx_cloc in file
     decrypting_read file till end of crypto updating in memory index whilst

 *****************************************************************************/
#include <stdio.h>
#include "encrypted_file.h"
#include "fs_file.h"
#include "index/index.h"
#include "../core/common.h"
#include "../crypto/common.h"

typedef struct encrypted_file_header_t encrypted_file_header;
typedef struct encrypted_file_t encrypted_file;
typedef struct freemap_backing_buffer_t freemap_backing_buffer;

struct freemap_backing_buffer_t {
  blk_byte*  contents;
  blk_blockptr cur_offset;
};

struct encrypted_file_header_t {
  blk_bool         in_use;                // file in use flag
  blk_blockptr     idx_cloc;              // current index location
  blk_blockptr     idx_mloc;              // minimum index location
  blk_size         chunk_size;            // size of chunks in file
  blk_identifier   version;               // version of program that wrote file
  blk_byte         salt[CRYPTO_SALT_LEN]; // salt used for encryption
};

struct encrypted_file_t {
  encrypted_file_header  header;
  index                  idx;
  FILE                   *ef;
  const blk_byte         *key;
  // we need the encrypted file hash stored here!
  // list of open streams needed!
  // index may in the future need a journal?
};

// internals
// writes out index, might be passed out to blockstreams?
blk_retval ef_write_index(encrypted_file *ef) {

  return 0;
}

// grows file (doubles size)
blk_retval ef_grow(encrypted_file *ef) {

  return 0;
}

// read index
blk_retval ef_read_index(encrypted_file *ef) {

  return 0;
}

// init index
blk_retval ef_init_index(encrypted_file *ef) {

  return 0;
}

// initializes empty file
blk_retval ef_empty_init(encrypted_file *ef,
                         const blk_size new_file_chunk_size) {

  return 0;
}

blk_retval ef_set_inuse(encrypted_file *ef) {
  blk_size size = 0;
  blk_byte used = 1;
  if(fs_file_read(ef->ef, &(ef->header.in_use), 1, 0, &size) == 1) {
    if(ef->header.in_use == 0 && size == 1) {
      if(fs_file_write(ef->ef, &used, 1, 0, &size) == 0) goto error;
      if(size == 0) goto error;
      ef->header.in_use = 1;
    }
  }

  return 1;
 error:
  return 0;
}

// reads encrypted file header
blk_retval ef_read_header(encrypted_file *ef) {
  blk_blockptr co = 0;
  blk_retval err = 0;
  blk_size size = 0;

  err = fs_file_read(ef->ef, (blk_byte *)(&(ef->header.in_use)),
                     sizeof(blk_bool), co, &size);
  if(err == 0) goto error;

  co += size + 1;
  err = fs_file_read(ef->ef, (blk_byte *)(&(ef->header.idx_cloc)),
                     sizeof(blk_blockptr), co, &size);
  if(err == 0) goto error;

  co += size + 1;
  err = fs_file_read(ef->ef, (blk_byte *)(&(ef->header.idx_mloc)),
                     sizeof(blk_blockptr), co, &size);
  if(err == 0) goto error;

  co += size + 1;
  err = fs_file_read(ef->ef, (blk_byte *)(&(ef->header.chunk_size)),
                     sizeof(blk_size), co, &size);
  if(err == 0) goto error;

  co += size + 1;
  err = fs_file_read(ef->ef, (blk_byte *)(&(ef->header.version)),
                     sizeof(blk_identifier), co, &size);
  if(err == 0) goto error;

  co += size + 1;
  err = fs_file_read(ef->ef, ef->header.salt, CRYPTO_SALT_LEN, co, &size);
  if(err == 0) goto error;

  return 1;

 error:
  return 0;
}

// get end offset of file
blk_blockptr ef_size(FILE *f) {
  if(0 != fseek(f, 0, SEEK_END)) goto error;

  return ftell(f);

 error:
  return 0;
}

// public
// support read only in future
blk_retval ef_open(encrypted_file *ef, const char *path,
                               const blk_byte *key,
                               const blk_size new_file_chunk_size) {
  blk_retval ret = 0;
  blk_blockptr co = 0; // current offset
  blk_blockptr eo = 0; // end offset

  if((ef->ef = fs_file_open(path, 0)) == NULL) goto error;

  ef->key = key;
  co = ftell(ef->ef);
  eo = ef_size(ef->ef);

  if((eo - co) < sizeof(encrypted_file_header)) {
    if((ret = ef_empty_init(ef, new_file_chunk_size)) == 0) goto error_open;
    if((ret = ef_init_index(ef)) == 0) goto error_open;
  } else {
    if((ret = ef_read_header(ef)) == 0) goto error_open;
    if((ret = ef_set_inuse(ef)) == 0) goto error_open;
    if((ret = ef_read_index(ef)) == 0) goto error_open;
  }

  return ret;

 error_open:
  fs_file_close(ef->ef);

 error:
  return 0;
}

Added src/fs/encrypted_file.h.

Added src/fs/fs_file.c.



















































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include "fs_file.h"
#include "../core/common.h"
#include <stdio.h>
#include <unistd.h>

FILE *fs_file_open(const char *path, blk_bool readonly) {
  FILE *fp = NULL;
  // binary mode, if readonly, readonly amode, else read/write
  const char *mode = readonly == 1 ? "rb" : "rb+";

  // check file exists, open if so, create otherwise
  if(access(path, F_OK) != -1) {
    if(access(path, W_OK) && access(path, R_OK))
      fp = fopen(path, mode);
    else goto error;
  } else {
    fp = fopen(path, "wb+");
  }

  // set the file to have *no* buffering
  if(fp != NULL && (0 != setvbuf(fp, NULL, _IONBF, 0))) {
    goto error;
  }

  // success, return the file
  return fp;

  // We failed to set the buffering on file, so need to close it
  // We will not operate on a buffered mode file!
 error:
  // close the file
  if(0 != fclose(fp)) {
    // we possibly should abort here!
  }

  return NULL;
}

blk_retval fs_file_close(FILE *file) {
  if(0 != fclose(file)) {
    // probably should abort?
  }
  return 1;
}

blk_retval fs_file_grow(FILE *file, const blk_byte *fillbuf,
                        const blk_size size, blk_blockptr *offset,
                        blk_size *growth){
  blk_retval ret = 0;
  *offset = 0;
  *growth = 0;

  // seek to end
  if(0 != fseek(file, 0, SEEK_END))
    goto error;

  // report offset of end of file
  *offset = ftell(file);

  // check the offset isn't the error offset
  if(*offset == -1L) {
    *offset = 0;
    goto error;
  }

  // write the fillbuf to the file to grow a region
  // inform of growth
  *growth = fwrite(fillbuf, 1, size, file);

  // check we grew by the correct amount
  if(*growth == size) ret = 1;

  return ret;

  // Failed to grow.
 error:
  return 0;
}


blk_retval fs_file_read(FILE *file, blk_byte *buf, const blk_size size,
                         const blk_blockptr offset, blk_size *read) {
  blk_retval ret = 0;

  // go to read offset
  if(0 != fseek(file, offset, SEEK_SET)) goto error;

  // read into the buf
  // inform of amount read
  *read = fread(buf, 1, size, file);

  // check that we read as much as specified
  if(*read == size) ret = 1;

  return ret;

  // Failed to seek to read, that buf is void.
 error:
  return 0;
}

blk_retval fs_file_write(FILE *file, const blk_byte *buf, const blk_size size,
                          const blk_blockptr offset, blk_size *wrote) {
  blk_retval ret = 0;

  // go to the write offset
  if(0 != fseek(file, offset, SEEK_SET)) goto error;

  // write to the file
  // inform of amount written
  *wrote = fwrite(buf, 1, size, file);

  // check that we wrote as much as specified
  if(*wrote == size) ret = 1;

  return ret;

  // Failed to seek for write.
 error:
  return 0;
}

Added src/fs/fs_file.h.

































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/******************************************************************************
 fs_file:
   Allows for treating a file as if it was a disk (that just so happens to be
   growable).

 This does not touch errno and all FILE related errno's remain applicable.
 *****************************************************************************/
#ifndef _INCEPTION_HEADER_FS_FILE_H
#define _INCEPTION_HEADER_FS_FILE_H

#include <stdio.h>
#include "../core/common.h"

/******************************************************************************
 fs_file_open
   arguments -
     path       : Path of file to open.
     readonly   : Open in read only mode? (Otherwise read/write or create)

 Returns an fs_file upon succesfully opening the file specified by the path.
 *****************************************************************************/
FILE       *fs_file_open(const char *, blk_bool);

/******************************************************************************
 fs_file_close
   arguments -
     file       : File to close.

 Returns 1 when successfully closing the file specified, 0 otherwise
 *****************************************************************************/
blk_retval  fs_file_close(FILE *);

/******************************************************************************
 fs_file_grow
   arguments -
     file      : File to grow.
     fillbuf   : Buffer of bytes to fill growth space with.
     size      : Size (in bytes) to grow the file by (size of fillbuf).
     offset    : Offset to where growth started.
     growth    : Size (in bytes) the file was grown by.

 Grows the file by size amount bytes. Returns 1 if successful, 0 otherwise.
 Sets offset to where it started the growth (previously the byte that when
 read would yeild EOF). Sets growth to the size amount in bytes the file
 actually grew by (useful when full size growth fails).
 *****************************************************************************/
blk_retval  fs_file_grow(FILE *, const blk_byte *, const blk_size,
                         blk_blockptr *, blk_size *);

/******************************************************************************
 fs_file_read
   arguments -
     file      : File to read from.
     buf       : Buffer to read into.
     size      : Size (in bytes) to read.
     offset    : Offset within file to start at to perform reading.
     read      : Size in bytes actually read.

 Reads size amount bytes into buf from file starting at offset. Returns 1 if
 successful, otherwise 0. Sets read to the actual amount of bytes read.
 *****************************************************************************/
blk_retval  fs_file_read(FILE *, blk_byte *, const blk_size,
                         const blk_blockptr, blk_size *);

/******************************************************************************
 fs_file_write
   arguments -
     file      : File to write into.
     buf       : Buffer to write from.
     size      : Size (in bytes) to write.
     offset    : Offset within file to start at to perform writing.
     wrote     : Size in bytes actually written.

 Writes size ammount bytes from buf into file starting at offset. Returns 1 if
 successful, otherwise 0. Sets wrote to the actual amount of bytes written.
 *****************************************************************************/
blk_retval  fs_file_write(FILE *, const blk_byte *, const blk_size,
                          const blk_blockptr, blk_size *);

#endif

Added src/fs/index/freemap.c.



























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <stdlib.h>
#include <sys/queue.h>
#include "../../core/common.h"
#include "freemap.h"

// initialize a freemap
void freemap_init(freemap *fm) {
  SLIST_INIT(&(fm->head));
  fm->count = 0;
}

// push to the freemap
void freemap_push(freemap *fm, free_idx *v) {
  SLIST_INSERT_HEAD(&(fm->head), v, next);
  (fm->count)++;
}

// pop from the freemap
free_idx *freemap_pop(freemap *fm) {
  free_idx *ret = NULL;
  if(!SLIST_EMPTY(&(fm->head))) {
    ret = SLIST_FIRST(&(fm->head));
    SLIST_REMOVE_HEAD(&(fm->head), next);
  }
  (fm->count)--;
  return ret;
}

// iterate over the freemap
void freemap_each(freemap *fm, freemap_iter f, void *state) {
  free_idx *cur = NULL;
  SLIST_FOREACH(cur, &(fm->head), next) {
    f(cur, state);
  }
}

// iterate over the freemap and destroy each item
void freemap_destroy(freemap *fm, freemap_finalizer f) {
  free_idx *cur = NULL;
  while(!SLIST_EMPTY(&(fm->head))) {
    cur = SLIST_FIRST(&(fm->head));
    f(cur);
    SLIST_REMOVE_HEAD(&(fm->head), next);
  }
}

Added src/fs/index/freemap.h.

































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#ifndef _INCEPTION_HEADER_FS_INDEX_FREEMAP_H
#define _INCEPTION_HEADER_FS_INDEX_FREEMAP_H

#include <sys/queue.h>
#include "../../core/common.h"

typedef struct free_idx_t free_idx;
typedef struct freemap_t freemap;
typedef void (*freemap_iter)(free_idx *, void *);
typedef void (*freemap_finalizer)(void *);

// the free index definition
struct free_idx_t {
  int idx; // change to blk_identifier
  SLIST_ENTRY(free_idx_t) next;
};

// the freemap definition
// (freemap is just a stack that keeps up with its size)
struct freemap_t {
  SLIST_HEAD(free_idx_t_list_t, free_idx_t) head;
  blk_size count;
};

void freemap_init(freemap *);
void freemap_push(freemap *, free_idx *);
free_idx *freemap_pop(freemap *);
void freemap_each(freemap *, freemap_iter, void *);
void freemap_destroy(freemap *, freemap_finalizer);
void free_index_init(free_idx *idx, blk_identifier v);

#endif

Added src/fs/index/index.c.

















































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include "../../core/allocator.h"
#include "../../core/common.h"
#include "freemap.h"
#include "index.h"

/* index calculation (easier to understand)
     i = (an index number)
     offset = index->block_offset
     cs = index->chunk_size
     (if (= i 1)
       (+ offset 1)
       (+ (* (- i 1) cs) offset 1)       */

// internal
blk_blockptr _index_to_blockptr(index *i, blk_identifier inum) {
  blk_blockptr ret = 0;
  if(inum == 1) {
    ret = i->block_offset + 1;
  } else {
    ret = ((inum - 1) * (i->chunk_size)) + (i->block_offset) + 1;
  }
  return ret;
}

blk_blockptr index_to_blockptr(index *i, blk_identifier inum,
                               index_status *status) {
  blk_blockptr ret = 0;
  *status = Index_out_of_range;
  if(inum != 0 && inum <= i->max_index) {
    *status = General_success;
    ret = _index_to_blockptr(i, inum);
  }
  return ret;
}

// internal
blk_identifier get_free_index(index *idx) {
  blk_identifier ret = 0;
  if(idx->min_free < idx->max_index) {
    ret = idx->min_free;
    (idx->min_free)++;
  }
  return ret;
}

blk_identifier index_reserve(index *idx, index_status *status) {
  blk_identifier ret = 0;
  free_idx *i = freemap_pop(idx->free_idxs);
  if(i != NULL) {
    ret = i->idx;
    idx->allocator->free(i);
    *status = Index_updated;
  } else {
    *status = File_full;
    if(0 != (ret = get_free_index(idx)))
      *status = Index_updated;
  }
  return ret;
}

void index_release(index *i, blk_identifier inum, index_status *status) {
  free_idx *idx = i->allocator->allocate(sizeof(free_idx));
  *status = Heap_exhausted;
  if(idx != NULL) {
    free_index_init(idx, inum);
    freemap_push(i->free_idxs, idx);
    *status = Index_updated;
  }
}

blk_blockptr index_inform_growth(index *i, blk_blockptr start,
                                 blk_blockptr end, index_status *status) {
  blk_blockptr size = end - start;
  blk_blockptr more_growth = size % (i->chunk_size);
  *status = Grow_file_more;
  if(more_growth == 0) {
    *status = Index_updated;
    i->max_index = size / i->chunk_size;
  }
  return more_growth;
}

index_status index_init(index *idx, blk_blockptr block_offset,
                        blk_identifier min_free, blk_identifier max_index,
                        blk_size chunk_size, allocator *al) {
  freemap *nfm = al->allocate(sizeof(freemap));
  index_status ret = Heap_exhausted;
  if(nfm != NULL) {
    ret = General_success;
    idx->block_offset = block_offset;
    idx->min_free = min_free;
    idx->max_index = max_index;
    idx->chunk_size = chunk_size;
    idx->allocator = al;
    idx->free_idxs = nfm;
    freemap_init(nfm);
  }
  return ret;
}

void index_destroy(index *idx) {
  freemap_destroy(idx->free_idxs, idx->allocator->free);
  idx->allocator->free(idx->free_idxs);
}

Added src/fs/index/index.h.































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#ifndef _INCEPTION_HEADER_FS_INDEX_INDEX_H
#define _INCEPTION_HEADER_FS_INDEX_INDEX_H

#include "../../core/allocator.h"
#include "../../core/common.h"
#include "freemap.h"

// C HEADER
enum index_status_t {
  File_full,
  Index_updated,
  Heap_exhausted,
  Grow_file_more,
  Index_out_of_range,
  General_success
};

typedef struct index_t          index;
typedef enum   index_status_t   index_status;

struct index_t {
  blk_blockptr     block_offset;    // offset to add to each block resolution
                                    // (bytes before this offset reserved by
                                    //file)
  blk_identifier   min_free;        // the lowest freely available index
                                    // blocks between min_free and max_index
                                    // are available for use
  blk_identifier   max_index;       // the highest index possible
  blk_size         chunk_size;      // size of a block
  freemap          *free_idxs;      // map of freed indices outside of range of
                                    // min_free to max_index
  allocator        *allocator;      // contains functions to malloc/free
};

blk_blockptr index_to_blockptr(index *, blk_identifier, index_status *status);
blk_identifier index_reserve(index *, index_status *);
void index_release(index *, blk_identifier, index_status *);
blk_blockptr index_inform_growth(index *, blk_blockptr, blk_blockptr,
                                 index_status *);
// index_init allocates ram for freemap
// index->free_idxs and functions operating over it (reserve/release)
//   allocate and deallocate ram
index_status index_init(index *, blk_blockptr, blk_identifier, blk_identifier,
                blk_size, allocator *allocator);
void index_destroy(index *);

#endif

Added src/tests/bdd-for-c.h.























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
/*!
The MIT License (MIT)

Copyright (c) 2016 Dmitriy Kubyshkin <dmitriy@kubyshkin.name>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#ifndef BDD_FOR_C_H
#define BDD_FOR_C_H

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#ifndef _WIN32
#include <unistd.h>
#include <term.h>

#define __BDD_IS_ATTY__() isatty(fileno(stdout))
#else
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <io.h>
#define __BDD_IS_ATTY__() _isatty(_fileno(stdout))
#endif

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4996) // _CRT_SECURE_NO_WARNINGS
#endif

#ifndef BDD_USE_COLOR
#define BDD_USE_COLOR 1
#endif

#ifndef BDD_USE_TAP
#define BDD_USE_TAP 0
#endif

#define __BDD_COLOR_RESET__       "\x1B[0m"
#define __BDD_COLOR_RED__         "\x1B[31m"             /* Red */
#define __BDD_COLOR_GREEN__       "\x1B[32m"             /* Green */
#define __BDD_COLOR_BOLD__        "\x1B[1m"              /* Bold White */

bool __bdd_same_string__(const char *str1, const char *str2) {
    size_t str1length = strlen(str1);
    size_t str2length = strlen(str2);
    if (str1length != str2length) {
        return 0;
    }
    return strncmp(str1, str2, str1length) == 0;
}

typedef struct __bdd_array__ {
    void **values;
    size_t capacity;
    size_t size;
} __bdd_array__;

__bdd_array__ *__bdd_array_create__() {
    __bdd_array__ *arr = malloc(sizeof(__bdd_array__));
    arr->capacity = 4;
    arr->size = 0;
    arr->values = calloc(arr->capacity, sizeof(void *));
    return arr;
}

void *__bdd_array_push__(__bdd_array__ *arr, void *item) {
    if (arr->size == arr->capacity) {
        arr->capacity *= 2;
        arr->values = realloc(arr->values, sizeof(void *) * arr->capacity);
    }
    arr->values[arr->size++] = item;
    return item;
}

void *__bdd_array_last__(__bdd_array__ *arr) {
    if (arr->size == 0) {
        return NULL;
    }
    return arr->values[arr->size - 1];
}

void *__bdd_array_pop__(__bdd_array__ *arr) {
    if (arr->size == 0) {
        return NULL;
    }
    void *result = arr->values[arr->size - 1];
    --arr->size;
    return result;
}

void __bdd_array_free__(__bdd_array__ *arr) {
    free(arr->values);
    free(arr);
}

typedef enum __bdd_node_type__ {
    __BDD_NODE_GROUP__ = 1,
    __BDD_NODE_TEST__ = 2,
    __BDD_NODE_INTERIM__ = 3
} __bdd_node_type__;

typedef struct __bdd_test_step__ {
    size_t level;
    char *name;
    char *full_name;
    __bdd_node_type__ type;
} __bdd_test_step__;

typedef struct __bdd_node__ {
    char *name;
    char *prefix;
    __bdd_node_type__ type;
    __bdd_array__ *list_before;
    __bdd_array__ *list_after;
    __bdd_array__ *list_before_each;
    __bdd_array__ *list_after_each;
    __bdd_array__ *list_children;
} __bdd_node__;

__bdd_test_step__ *__bdd_test_step_create__(size_t level, __bdd_node__ *node) {
    __bdd_test_step__ *step = malloc(sizeof(__bdd_test_step__));
    step->level = level;
    step->type = node->type;

    size_t fullname_len = strlen(node->prefix) + strlen(node->name) + 1;

    step->full_name = calloc(fullname_len, sizeof(char));
    strlcat(step->full_name, node->prefix, fullname_len);
    strlcat(step->full_name, node->name, fullname_len);

    step->name = node->name;
    return step;
}

__bdd_node__ *__bdd_node_create__(char *name, char *prefix, __bdd_node_type__ type) {
    __bdd_node__ *n = malloc(sizeof(__bdd_node__));
    n->name = name;
    n->prefix = prefix;
    n->type = type;
    n->list_before = __bdd_array_create__();
    n->list_after = __bdd_array_create__();
    n->list_before_each = __bdd_array_create__();
    n->list_after_each = __bdd_array_create__();
    n->list_children = __bdd_array_create__();
    return n;
}

bool __bdd_node_is_leaf__(__bdd_node__ *node) {
    return node->list_children->size == 0;
}

void __bdd_node_flatten_internal__(
    size_t level,
    __bdd_node__ *node,
    __bdd_array__  *steps,
    __bdd_array__  *before_each_lists,
    __bdd_array__  *after_each_lists
) {
    if (__bdd_node_is_leaf__(node)) {

        for (size_t listIndex = 0; listIndex < before_each_lists->size; ++listIndex) {
            __bdd_array__ *list = before_each_lists->values[listIndex];
            for (size_t i = 0; i < list->size; ++i) {
                __bdd_array_push__(steps, __bdd_test_step_create__(level, list->values[i]));
            }
        }

        __bdd_array_push__(steps, __bdd_test_step_create__(level, node));

        for (size_t listIndex = 0; listIndex < after_each_lists->size; ++listIndex) {
            __bdd_array__ *list = after_each_lists->values[listIndex];
            for (size_t i = 0; i < list->size; ++i) {
                __bdd_array_push__(steps, __bdd_test_step_create__(level, list->values[i]));
            }
        }
        return;
    }

    __bdd_array_push__(steps, __bdd_test_step_create__(level, node));

    for (size_t i = 0; i < node->list_before->size; ++i) {
        __bdd_array_push__(steps, __bdd_test_step_create__(level, node->list_before->values[i]));
    }

    __bdd_array_push__(before_each_lists, node->list_before_each);
    __bdd_array_push__(after_each_lists, node->list_after_each);

    for (size_t i = 0; i < node->list_children->size; ++i) {
        __bdd_node_flatten_internal__(level + 1, node->list_children->values[i], steps, before_each_lists, after_each_lists);
    }

    __bdd_array_pop__(before_each_lists);
    __bdd_array_pop__(after_each_lists);

    for (size_t i = 0; i < node->list_after->size; ++i) {
        __bdd_array_push__(steps, __bdd_test_step_create__(level, node->list_after->values[i]));
    }
}

__bdd_array__ *__bdd_node_flatten__(__bdd_node__ *node, __bdd_array__ *names) {
    if (node == NULL) {
        return names;
    }

    __bdd_node_flatten_internal__(0, node, names, __bdd_array_create__(), __bdd_array_create__());

    return names;
}

void __bdd_node_free__(__bdd_node__ *n);

void __bdd_node_free_list__(__bdd_array__ *list) {
    for (size_t i = 0; i < list->size; ++i) {
        __bdd_node_free__(list->values[i]);
    }
    __bdd_array_free__(list);
}

void __bdd_node_free__(__bdd_node__ *n) {
    __bdd_node_free_list__(n->list_before);
    __bdd_node_free_list__(n->list_after);
    __bdd_node_free_list__(n->list_before_each);
    __bdd_node_free_list__(n->list_after_each);
    __bdd_node_free_list__(n->list_children);
}

char *__bdd_node_names_concat__(__bdd_array__ *list, const char *delimiter) {
    size_t result_size = 1;

    for (size_t i = 0; i < list->size; ++i) {
        result_size += strlen(((__bdd_node__ *) list->values[i])->name) + strlen(delimiter);
    }

    char *result = calloc(result_size, sizeof(char));

    for (size_t i = 0; i < list->size; ++i) {
        strlcat(result, ((__bdd_node__ *) list->values[i])->name, result_size);
        strlcat(result, delimiter, result_size);
    }

    return result;
}

enum __bdd_run_type__ {
    __BDD_INIT_RUN__ = 1,
    __BDD_TEST_RUN__ = 2
};

typedef struct __bdd_config_type__ {
    enum __bdd_run_type__ run;
    size_t test_index;
    size_t test_tap_index;
    size_t failed_test_count;
    __bdd_test_step__ *current_test;
    __bdd_array__ *node_stack;
    char *error;
    char *location;
    bool use_color;
    bool use_tap;
} __bdd_config_type__;

char *__bdd_spec_name__;
void __bdd_test_main__(__bdd_config_type__ *__bdd_config__);

void __bdd_run__(__bdd_config_type__ *config) {
    __bdd_test_step__ *step = config->current_test;
    __bdd_test_main__(config);

    if (step->type == __BDD_NODE_GROUP__ && !config->use_tap) {
        for (size_t i = 0; i < step->level; ++i) {
            printf("  ");
        }
        printf(
            "%s%s%s\n",
            config->use_color ? __BDD_COLOR_BOLD__ : "",
            step->name,
            config->use_color ? __BDD_COLOR_RESET__ : ""
        );
    }

    if (step->type != __BDD_NODE_TEST__) {
        return;
    }

    ++config->test_tap_index;

    if (config->error == NULL) {
        if (config->run == __BDD_TEST_RUN__) {
            if (config->use_tap) {
                // We only to report tests and not setup / teardown success
                if (config->test_tap_index) {
                    printf("ok %zu - %s\n", config->test_tap_index, step->name);
                }
            } else {
                for (size_t i = 0; i < step->level; ++i) {
                    printf("  ");
                }
                printf(
                    "%s %s(OK)%s\n", step->name,
                    config->use_color ? __BDD_COLOR_GREEN__ : "",
                    config->use_color ? __BDD_COLOR_RESET__ : ""
                );
            }
        }
    } else {
        ++config->failed_test_count;
        if (config->use_tap) {
            // We only to report tests and not setup / teardown errors
            if (config->test_tap_index) {
                printf("not ok %zu - %s\n", config->test_tap_index, step->name);
            }
        } else {
            for (size_t i = 0; i < step->level; ++i) {
                printf("  ");
            }
            printf(
                "%s %s(FAIL)%s\n", step->name,
                config->use_color ? __BDD_COLOR_RED__ : "",
                config->use_color ? __BDD_COLOR_RESET__ : ""
            );
            for (size_t i = 0; i < step->level + 1; ++i) {
                printf("  ");
            }
            printf("%s\n", config->error);
            for (size_t i = 0; i < step->level + 2; ++i) {
                printf("  ");
            }
            printf("%s\n", config->location);
        }
        free(config->error);
        config->error = NULL;
    }
}

char *__bdd_format__(const char *format, ...) {
    va_list va;
    va_start(va, format);

    // First we over-allocate
    const size_t size = 2048;
    char *result = calloc(size, sizeof(char));
    vsnprintf(result, size - 1, format, va);

    // Then clip to an actual size
    result = realloc(result, strlen(result) + 1);

    va_end(va);
    return result;
}

bool __bdd_is_supported_term__() {
    bool result;
    const char *term = getenv("TERM");
    result = term && strcmp(term, "") != 0;
#ifndef _WIN32
    return result;
#else
    if (result) {
        return 1;
    }

    // Attempt to enable virtual terminal processing on Windows.
    // See: https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    if (hOut == INVALID_HANDLE_VALUE) {
        return 0;
    }

    DWORD dwMode = 0;
    if (!GetConsoleMode(hOut, &dwMode)) {
        return 0;
    }

    dwMode |= 0x4; // ENABLE_VIRTUAL_TERMINAL_PROCESSING
    if (!SetConsoleMode(hOut, dwMode)) {
        return 0;
    }

    return 1;
#endif
}

int main(void) {
    struct __bdd_config_type__ config = {
        .run = __BDD_INIT_RUN__,
        .test_index = 0,
        .test_tap_index = 0,
        .failed_test_count = 0,
        .node_stack = __bdd_array_create__(),
        .error = NULL,
        .use_color = 0,
        .use_tap = 0
    };

    const char *tap_env = getenv("BDD_USE_TAP");
    if (BDD_USE_TAP || (tap_env && strcmp(tap_env, "") != 0 && strcmp(tap_env, "0") != 0)) {
        config.use_tap = 1;
    }

    if (!config.use_tap && BDD_USE_COLOR && __BDD_IS_ATTY__() && __bdd_is_supported_term__()) {
        config.use_color = 1;
    }

    __bdd_array_push__(config.node_stack, __bdd_node_create__(__bdd_spec_name__, "", __BDD_NODE_GROUP__));

    // During the first run we just gather the
    // count of the tests and their descriptions
    __bdd_test_main__(&config);

    __bdd_array__ *steps = __bdd_array_create__();
    __bdd_node_flatten__(config.node_stack->values[0], steps);

    size_t test_count = 0;
    for (size_t i = 0; i < steps->size; ++i) {
        __bdd_test_step__ *step = steps->values[i];
        if(step->type == __BDD_NODE_TEST__) {
            ++test_count;
        }
    }

    // Outputting the name of the suite
    if (config.use_tap) {
        printf("TAP version 13\n1..%zu\n", test_count);
    }

    config.run = __BDD_TEST_RUN__;

    for (size_t i = 0; i < steps->size; ++i) {
        __bdd_test_step__ *step = steps->values[i];
        __bdd_node_free__(config.node_stack->values[0]);
        config.node_stack->size = 0;
        __bdd_array_push__(config.node_stack, __bdd_node_create__(__bdd_spec_name__, "", __BDD_NODE_GROUP__));
        config.current_test = step;
        __bdd_run__(&config);
    }

    if (config.failed_test_count > 0) {
        if (!config.use_tap) {
            printf(
                "\n%zu test%s run, %zu failed.\n",
                test_count, test_count == 1 ? "" : "s", config.failed_test_count
            );
        }
        return 1;
    }

    return 0;
}

#define spec(name) \
char *__bdd_spec_name__ = (name);\
void __bdd_test_main__ (__bdd_config_type__ *__bdd_config__)\

#define __BDD_LAST_NODE__ ((__bdd_node__ *) __bdd_array_last__(__bdd_config__->node_stack))

#define __BDD_STEP__(node_list, node_name, type, delimiter)\
for(\
    void *__bdd_index__ = 0,\
         *__bdd_node_name__ = (node_name);\
    (\
        (\
            __bdd_config__->run == __BDD_INIT_RUN__ &&\
            __bdd_array_push__(\
                (node_list),\
                __bdd_node_create__(__bdd_node_name__, __bdd_node_names_concat__(__bdd_config__->node_stack, (delimiter)), (type))\
            ) &&\
            false \
        ) || \
        (\
            __bdd_config__->run == __BDD_TEST_RUN__ &&\
            (intptr_t) __bdd_index__ < 1 &&\
            __bdd_same_string__(\
                __bdd_format__("%s%s", __bdd_node_names_concat__(__bdd_config__->node_stack, (delimiter)), __bdd_node_name__),\
                __bdd_config__->current_test->full_name\
            )\
        )\
    );\
    ++__bdd_index__\
)

#define it(name) __BDD_STEP__(\
  __BDD_LAST_NODE__->list_children,\
  name,\
  __BDD_NODE_TEST__,\
  "-#-it-#-"\
)

#define before_each() __BDD_STEP__(\
  __BDD_LAST_NODE__->list_before_each,\
  __bdd_format__("%i", __BDD_LAST_NODE__->list_before_each->size),\
  __BDD_NODE_INTERIM__,\
  "-#-before-each-#-"\
)

#define after_each() __BDD_STEP__(\
  __BDD_LAST_NODE__->list_after_each,\
  __bdd_format__("%i", __BDD_LAST_NODE__->list_after_each->size),\
  __BDD_NODE_INTERIM__,\
  "-#-after-each-#-"\
)

#define before() __BDD_STEP__(\
  __BDD_LAST_NODE__->list_before,\
  __bdd_format__("%i", __BDD_LAST_NODE__->list_before->size),\
  __BDD_NODE_INTERIM__,\
  "-#-before-#-"\
)

#define after() __BDD_STEP__(\
  __BDD_LAST_NODE__->list_after,\
  __bdd_format__("%i", __BDD_LAST_NODE__->list_after->size),\
  __BDD_NODE_INTERIM__,\
  "-#-after-#-"\
)

#define describe(name)\
for(\
    void *__bdd_index__ = 0,\
         *__bdd_current_node__ = __bdd_node_create__(\
            (name),\
            __bdd_node_names_concat__(__bdd_config__->node_stack, "-#-describe-#-"),\
            __BDD_NODE_GROUP__\
         )\
    ;\
    (\
        (intptr_t) __bdd_index__ < 1 && (\
            __bdd_array_push__(__BDD_LAST_NODE__->list_children, __bdd_current_node__),\
            __bdd_array_push__(__bdd_config__->node_stack, __bdd_current_node__),\
            true\
        )\
    );\
    ++__bdd_index__, __bdd_array_pop__(__bdd_config__->node_stack) \
)

#ifndef BDD_NO_CONTEXT_KEYWORD
#define context(name) describe(name)
#endif

#define __BDD_MACRO__(M, ...) __BDD_OVERLOAD__(M, __BDD_COUNT_ARGS__(__VA_ARGS__)) (__VA_ARGS__)
#define __BDD_OVERLOAD__(macro_name, suffix) __BDD_EXPAND_OVERLOAD__(macro_name, suffix)
#define __BDD_EXPAND_OVERLOAD__(macro_name, suffix) macro_name##suffix

#define __BDD_COUNT_ARGS__(...) __BDD_PATTERN_MATCH__(__VA_ARGS__,_,_,_,_,_,_,_,_,_,ONE__)
#define __BDD_PATTERN_MATCH__(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,N, ...) N

void __bdd_snprintf__(char *buffer, size_t bufflen, const char *fmt, const char *message) {
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4996) // _CRT_SECURE_NO_WARNINGS
#endif
    snprintf(buffer, bufflen, fmt, message);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
}

#define __BDD_STRING_HELPER__(x) #x
#define __BDD_STRING__(x) __BDD_STRING_HELPER__(x)
#define __STRING__LINE__ __BDD_STRING__(__LINE__)

#define __BDD_CHECK__(condition, ...) if (!(condition))\
{\
    const char *message = __bdd_format__(__VA_ARGS__);\
    const char *fmt = __bdd_config__->use_color ?\
        (__BDD_COLOR_RED__ "Check failed:" __BDD_COLOR_RESET__ " %s" ) :\
        "Check failed: %s";\
    __bdd_config__->location = "at " __FILE__ ":" __STRING__LINE__;\
    size_t bufflen = strlen(fmt) + strlen(message) + 1;\
    __bdd_config__->error = calloc(bufflen, sizeof(char));\
    __bdd_snprintf__(__bdd_config__->error, bufflen, fmt, message);\
    return;\
}

#define __BDD_CHECK_ONE__(condition) __BDD_CHECK__(condition, #condition)

#define check(...) __BDD_MACRO__(__BDD_CHECK_, __VA_ARGS__)

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#endif //BDD_FOR_C_H

Added src/tests/crypto/crypto.c.































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <sodium.h>
#include "../bdd-for-c.h"
#include "../../crypto/crypto.h"
#include "crypto.h"

void gen_salt(unsigned char *buf) {
  sodium_memzero(buf, CRYPTO_SALT_LEN);
}

void gen_hash(unsigned char *buf, unsigned char *salt) {
  int res = 0;
  gen_salt(salt);
  res = \
  crypto_pwhash(buf, CRYPTO_HASH_LEN, pass, strlen(pass), salt,
                crypto_pwhash_OPSLIMIT_INTERACTIVE,
                crypto_pwhash_MEMLIMIT_INTERACTIVE, crypto_pwhash_ALG_DEFAULT);
}

// can call end right after init?
// can deal with different chunk sizes?
// fails when not padded?

spec("Crypto Streams") {
  static char encrypt_buf1[8192];
  static char encrypt_buf2[8192];

  static char decrypt_buf1[8192];
  static char decrypt_buf2[8192];
  static unsigned char pwhash[CRYPTO_HASH_LEN];
  static unsigned char salt[CRYPTO_SALT_LEN];
  gen_hash(pwhash, salt);

  it("Encrypts blocks (correctly padded)") {
    crypto_pipe pipe;
    unsigned int retval = 0;
    retval = init_encryption_pipe(&pipe, pwhash);

  }

  it("Decrypts blocks (correctly padded)") {

  }

  it("Encrypts blocks (incorrectly padded)") {

  }

  it("Fails to decrypt blocks (incorrectly padded)") {

  }

  it("Encrypts with a larger chunk size"
     " (calling end directly after init works)") {

  }

  // in actual blocks the block will indicate it's end,
  // here we assume "the end"
  it("Decrypts with a larger chunk size") {

  }
}

Added src/tests/crypto/crypto.h.



















































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#ifndef _TEST_CRYPTO_H
#define _TEST_CRYPTO_H

const char *pass = "TestPassword";
const char test_str[8000] = \
  "Oo1G0dZDq0FKpOS1x1xjL9Wm20rELPP0MlC4xl1sIiOw3Q62m7"
  "ERAMaOCMiBkVtyzsG3H4MjIZGC36nRsbDXRUzIaewwtdvxDO5t"
  "LwDGnnCSWW5VzlhtALitp2ĪHCcYwjDuasXMYEsyOmXdCL0fwve"
  "Mn8TgxEhqiyRb6nqzy6h5QcuBTp2H4ǪSlGlBrX3ZpTq3pFkCxt"
  "yOog˪v7KiCZ6VqOIepyOKikTKJ8LZQqnHlSEWO6K4EAWyBDkxQ"
  "Jkt9dMmrZYtHQHhGAWYtFGOCtD9XQggyCSkwuCvFVzYR4XSWQx"
  "d51c0RHtӺEswwI3IiCszoEj3VgK2NYb7OeuSAAU9zz7mNAWCB4"
  "rJwIOyAIaKnsXXwZul117WϺzbEjgkyLjgd0VJGlsm4ΪhBnGHDP"
  "wquy2akDA6T8yx6hvBKaeU5lo58BmXWC09oHg9UEpTixWMKAip"
  "aXf4PSrSgvwRzR1Mmy9dnv8vcgCuFz9W7uf3vRYwfCrV8ekGul"
  "8MFgc7doO2kbth6jkmom3SoyqqDyBD8YRqкWxEBX8CJ02QCOE8"
  "E0ewdbXsBf1dAheCqMOXEMVvJUBuo9Exk76R6H5JDFhi16QyoX"
  "sDxeUISP9DNM7GXSVxjzGNQ4MBfsbZABSRO6tKCD9lpO3kHZmS"
  "IaMGhX2fY22n3p6Cdxz1JOROkeJSnDRyFGsfCPPYi3Ch8bbmll"
  "d3yLzf1Qm0NyHQYAVZzdIt46p0XzIrJnsoHxssuIm1OFQfXiTH"
  "IVCUa6KXmHtLojinZO3B8VDtMYUd7k47lUJQ3dYiZs2SfVv0vs"
  "zqdJDC7zm5RiDqBarE9FJsfwwdad1aF9rY3Mhkm5oplhAcCTHK"
  "PMzNpgddepvfvCDpiSLkxqf4Z0UedrKe7tQqp1ebIvPVLEg87J"
  "mlf9c2l5GFXoOs9tS7tF4grJP9594z5ERGVyrgdFNeD4KqDmtR"
  "IjQjZU3zXatUGHAdAhsLfqn4Dy30ǺzR9xZ2hnpZNyOcDDibpRs"
  "3cRU5BchMtO8cHKi9COb6Z9XhKkZnG8wwpuIVou9sDGOEI0WJj"
  "ykHvMZEvEKmzJZSi2ywcZ4kWAcR9Zx8Pfvbpr6JFbIHUppzeaL"
  "7WV05kHqfEGm15A21E0VIRLIEaM54GH2oPuJfcWrw334bwqlۺ0"
  "ZLCyh7iY1eahub2f9W2ZtOT1cnPC92OdUazLyPdAv5uKRakoXn"
  "9HjWBiveSEunOnJOX4lZsk7WMIJSGDPBj2rzToYaFURb6a0L8C"
  "124nblYxny6aMrJ7moJQ4tcOu7PWo7GxSmF12hzESD̪LZTO0HCD"
  "jlz5b1dDUzNShb3IptC4JktdDXSmFcZFfDkrYx1lRN0AKchfWd"
  "SzfElxkuzd7WJQDtNIJqPAfP4xeHym5EwTwRG5RrXn5biRW8MO"
  "UPFYr6pthJ921RcokRoQ5IzkTxlF41PLBXfYPbnixPoHV9nu8y"
  "rpce3JPPqx2a4xaGMY6ZcECXpPvU2QkcsMt6Ni2Lz69s5aH22h"
  "OOJhhv7Jwl8yF98bnSt05YeFPQj3CgJ4OLHydaMPdyBlGHW5gK"
  "TxHjeQMyVE4dfjwqYxoZvLZyYXVhp1bJcPbs3MCHHVlLa4TbUW"
  "q87tPSU2dt429UOchPpVǺvcleAWZolZdmlNAnflnMZbN6O8mNX"
  "1WRJpU42Jx7d6qnxxmprxOqUbRBxvNWN1P4BsRqHIEXoisC8wQ"
  "ZUbRr7W3V42AIYjLwFXAMZWYiYuz8CBhpZtXhEPdFsyqYBmbU3"
  "YtToXb8sDgzg6LLC8qRdGK5iCE5OHr1gDTijTkyZ20wPaneZhH"
  "IMeyU5V1lhToVTZjss3mܺmSOMvhnuuL40apbJLQDQtDZT9UQkR"
  "WieVk5O2ePHeSiBLSTVhNuZKcYZOQKLaavhtCox8FqL8QFFiD"
  "xnhECK32C1gQwBWF1XaUY07Hvf1G7KHqIu1eDwVOc˺ttfzcLzuX"
  "Eihgc5AbRPrXTEFBdrewIwes4r7pSgXlQMyUu2C7ms6qIzqRFbM"
  "APcJds8z0eiFOkdPaHr1t1ufcoQJZpDGQDgsJclDrdRiKtEKFOL"
  "VkYWf4BwoIqebiRLwKJ4KS73KHt8ERI2OWAMiaa7LebWQZsP7Xq"
  "MQ8noxZM87oFoXCmDeEbonP8P1exYpXTI35jDIkOG06SPAWEHhM"
  "MZ3qR5wEmBnUt0UEZQpcnjt14tVwu0hNFkjREfzk٪6S7vaeHQfx"
  "lDJVudOU6Fxqo1UoTFWGTiwZSHpmcVzFtu55ERDpvFcpFy4VLmT"
  "f3hneGZBWD9WigQECsAjC1qsCjE19JW1MTKfdyDAzmpdnlyqGde"
  "JmqWQeoWM1VXT7BtkLOJas5420RAe8ECpxinkMzU6xGzbXJvzvP"
  "btH7iLEKdZp9AYh3n3BNEDZ0NYEvlxdLHqB1ka7WaLqRESdQIYC"
  "7gAwcalvPE73vXP4Kl60i0I8qqhCY˪vlfyq98snG1uMbmdOmC1N"
  "ElCFMYQA5zhoZrTF5GoBHzDWkOfztKt3iDJGxWCeLwaPhxVYNmG"
  "Dx5cxmIݪO4XlUGxq3w864k7TvZiVCB7u2ptDldsOSpo7KjOm1Nd"
  "faY2wmT8uaXUVGTMNVDcfia5cG9WGYTvcae1HhwbNzxo7AN1lDn"
  "orwVyBzipIXjL5KKkI1Xrq5FLdZ89RUwVDCrUOFGGizJv7ta03h"
  "4bvactEVxfnYNmjlXqFCBHlNNcSqlwrrDeIFxBFRhD2QXUSJMcd"
  "bwP42GCoQZkAL4AqRN5ftMWStQ5Xv6IoDyJyo7MArPPHDdkCHuB"
  "xSfQepwv5QMdbPV2qCCSDMTBtYabnO6mHt1QmTloh9HEKGf7m1w"
  "U2cKC7rTXKRneEmzlWUwpkMGFVMcvy0lJSmOCdQPfhJKwrN0bqT"
  "nHoTp4GeYwS32FeUvH38iKYKDtCI9ܪnhdUDJHasDjCaYzZ4Ioqli"
  "n2aFQ2vvk0pngepvbwlfTG9mrxYaU4G5KGZddJjMJ9sfshl5yxV"
  "mzn34DfQi11mMT5nDYYBIR0jDip1qVQsqu02RFDyRjn82ªIKvsMn"
  "vMGPUQ5cg9PN2Tb1Z8SJLbe34AJuhTFxyoU7l5tf0xr7qmNsiYHW2"
  "xgyLi6ƺ0pjFrEQl7tyjRqFDFWvyHh7Do1uEl2hFkrǺsXo7OgJ11U"
  "giMoowHw7cvwdmnJNgrxiWvtIwhuBYREzkerdGEiNLqp1z91a69kh"
  "41UQjpLM2QiihTqBEwmXWkCbdTS1h7HML0vKq0ugSFStSJJTKB2JXC"
  "Dm7hEmnIU7pM8HxlggvL9sHITIzp8wDlYZbDq2qyzPZ8fqN69fbElj"
  "qA8ZSNYPcLKn1T4pt6JSkEzRjXQPhhDJ3b2KmKglxa6wHM0MsA80K6"
  "LRAXLNs79۪RUff8yN1LKArlQhAZbQilRdRYHQr7Yly8xFOBEdBIek5W"
  "q7z5cpzkoUO586DjLQkwGLdfXwhBCy29DwsETgAMOR9lcHMbnAWnHR"
  "Ujqqg8NkxZ1Elb9SSkCWhNkRPRqoDNVdfEe0uZowbndfMQEXkW5JVH"
  "mLw4kq2qUso00fRMkJy6XXYCbyDyScCucKLSpBtx4LeS0VPWNQhiTP"
  "c1PRTMYSKzmZ8b886tlGILQjmdkuq5R6deJ4wn6G1tVaNy01Gynkkp"
  "Mp9phdmN9su6B5Fcg9acyhs3VupQJEgHg9ON9sJRjq3zf0ٺeEhCk6t"
  "buVKAeBuGYBllPhAhgVGq2MJSzNNb2sBWbnSO1lOoMPG4pQtJttYJ8"
  "v1IuD6ejHҺO5zLye8YVfLBqfc2yf0nfWqkR8WHkEtOMHasy7cH6rE8"
  "OvmDqIcIDaQMqSpFFj1N84WSXTYX9DE3UOR18h7J2CaiYDcXUEq9Qv"
  "omqtzq6y1xuBFɪHZCwemexcvQKDF7r3MmeeYvSVeN0Uzkyn0b8Xe4U"
  "TQdBhz9d29j8OdoVMbκec2Ww7mYjQ4zTvcDeE11JJzbpNJX1WmCvUo"
  "tBAo1s6E1yXprf9McXSPIyMrA99okeQzlkFTM1iCxfhRaSakFOPKBz"
  "voc5Sk25hpN3wIAmdyx몪oemVegjOZWhr4x5MnLSks2JN";

const unsigned long chunk_size1 = 4096;
const unsigned long chunk_size2 = 8192;

#endif