Python API¶
For most use cases, the Configuration Files should suffice. If you need more fine-grained control over your scenarios you can use the Python API. For instance, the API lets you define the exact fragmentation points of your files, exact sizes of filler fragments, and so forth.
Here is a simple script illustrating the basic usage of the API:
#!/usr/bin/env python3
import pathlib
import sys
from woodblock.file import File, draw_files
from woodblock.fragments import RandomDataFragment, ZeroesFragment
from woodblock.image import Image
from woodblock.scenario import Scenario
HERE = pathlib.Path(__file__).absolute().parent
def main():
woodblock.file.corpus(HERE / '..' / 'data' / 'corpus')
files = draw_files(number_of_files=2)
f_a = files[0].fragment_randomly(num_fragments=3)
f_b = files[1].fragment_evenly(num_fragments=2)
s = Scenario('First API Scenario')
s.add(f_a[1])
s.add(ZeroesFragment(1024))
s.add(f_b[0])
s.add(f_a[2])
s.add(RandomDataFragment(512))
s.add(f_a[0])
s.add(f_b[1])
image = Image(block_size=512)
image.add(s)
image.write(HERE / 'api-demo.dd')
if __name__ == '__main__':
sys.exit(main())
This script randomly chooses two files from the file corpus. The first one is split into three fragments at random fragmentation points, the second one is split into two fragments of equal size. After that the scenario with the name “First API Scenario” is created and the file fragments as well as two filler fragments are added to the scenario. Finally, the scenario is added to an image object which is then written to disk.
Let’s go through this example step by step. The first lines are just some imports.
from woodblock.file import File, draw_files
from woodblock.fragments import RandomDataFragment, ZeroesFragment
from woodblock.image import Image
from woodblock.scenario import Scenario
After we define the file corpus and randomly draw two files:
woodblock.file.corpus(HERE / '..' / 'data' / 'corpus')
files = draw_files(number_of_files=2)
These files are then split into fragments. The first file is split into three fragments. The fragmentation points are chosen randomly. The second file is split into two fragments. The fragmentation point is chosen so that both fragments are of equal size:
f_a = files[0].fragment_randomly(num_fragments=3)
f_b = files[1].fragment_evenly(num_fragments=2)
After that, a Scenario
object is created. Its argument is the name
of the scenario:
s = Scenario('First API Scenario')
A Scenario
object has a method to add
fragments to it.
A call to add
appends a fragment to any previously added fragments,
so that the order of the add
calls defines the order of the
fragments in the scenario:
s.add(f_a[1])
s.add(ZeroesFragment(1024))
s.add(f_b[0])
s.add(f_a[2])
s.add(RandomDataFragment(512))
s.add(f_a[0])
s.add(f_b[1])
We did not only added the fragments of our files but also two filler
fragments: a ZeroesFragment
of 1024 bytes of size and a
RandomDataFragment
of 512 bytes of size. As you can see, you
can specify the exact size of the filler fragments using the API.
After that, our scenario is complete and we create an Image
object with a block size of 512 bytes. Image
objects represent
test image files to be written to disk. Just like we could add fragments
to a scenario, we can add scenarios to an Image
. If we added all
of the scenarios, we can finally write the image using the write
method.
Those are already the basic blocks you need to create your own test images using the API: you select files from the test file corpus, fragments them in some way, add the fragments to a scenario, add the scenario to an image, and finally write the image to disk.
The following sections describe the available API functions and objects in a more detailed way.
Files and Fragments¶
Files are always selected from a file corpus. Therefore, you have to specify
the path to your file corpus before you can select any files. This is done
using the woodblock.files.corpus
function. This function takes the path
to your file corpus as its only argument. An example call would look like this:
# You can provide the path using a string...
woodblock.file.corpus('path/to/your/corpus/')
# ... or via a pathlib.Path object
path = pathlib.Path('path/to/your/corpus/')
woodblock.file.corpus(path)
Once you have defined your corpus, you can start using its files. If you do
not care which exact files to use from your corpus, you can use the
draw_files
function, which randomly chooses the given number of files
from your corpus. The function lets you not only specify the number of files
but also the minimal size of each files. Moreover, you can specify if duplicate
files are allowed or not. Duplicate files are basically two different objects
pointing to the same original file. Finally, you can indicate that you want
the files to be drawn only from a special subdirectory of your corpus. The
following examples show how to use this function:
# This will give you one randomly chosen file:
single_file = woodblock.file.draw_files()
# Here is an example with four randomly chosen files:
files = woodblock.file.draw_files(number_of_files=4)
# Now we want three files, but only from the jpeg/ subdirectory:
files = woodblock.file.draw_files(path='jpeg', number_of_files=3)
# The same but only files with a minimal size of 2 MB:
files = woodblock.file.draw_files(path='jpeg', number_of_files=3, min_size=2*1024**2)
# Finally, choose ten files without duplicates:
files = woodblock.file.draw_files(number_of_files=10, unique=True)
Note that draw_files
always returns a list of File
objects,
that is, even single_file
is a list (with only one item).
File
objects represent files from your corpus. If you don’t want to use
draw_files
to get your File
objects, you can create them manually.
This allows you to choose specific files from your corpus. To create a File
object, simply pass the path of the file you want (relative to the corpus)
to the constructor:
some_file = woodblock.file.File('some/path/relative/to/the/corpus.jpg')
File
objects provide some methods returning metadata about the file they
represent. For example, there are the methods size
, path
,
id
, and hash
which return just what you would expect from the names.
More interesting are the methods used to split a file into fragments. Here, we
have as_fragment
, fragment
, fragment_evenly
, and
fragment_randomly
. The first one simply converts the file into a single
fragment. This is can be used, when you want to add a contiguous file to your
scenario (Scenario
objects can only be used with fragments; see below).
fragment
can be used to fragment a file at specific fragmentation points.
fragment_evenly
and fragment_randomly
are convenience methods, which
split a file into a given number of evenly sized fragments or into a given number of
randomly sized fragments. The following snippet provides some usage examples for the
methods to fragment a file:
# some_file as a single fragment:
contiguous = some_file.as_fragment()
# some_file spit at specific fragmentation points. Fragmentation points are
# defined with respect to the block_size, i.e. the following example splits
# the file at bytes 1024, 1536, and 3584:
fragments = some_file.fragment(fragmentation_points=(2, 3, 7), block_size=512)
# Split some_file into three evenly sized fragments:
evenly_fragmented = some_file.fragment_evenly(num_fragments=3, block_size=512)
# or shorter:
evenly_fragmented = some_file.fragment_evenly(3)
# Split some_file into three fragments at random fragmentation points:
randomly_fragmented: some_file.fragment_randomly(num_fragments=3, block_size=512)
# or shorter:
randomly_fragmented: some_file.fragment_randomly(3)
These methods give you a high level of control to create very specific
fragmentation scenarios. However, if you just want some fragmented files,
Woodblock has some convenience functions for you. draw_fragmented_files
basically combines draw_files
and File.fragment_randomly
and gives you a list of fragment lists.
from woodblock.file import draw_fragmented_files
# Three fragmented files:
fragments = draw_fragmented_files(number_of_files=3)
# Three fragmented files from the png/large subdirectory:
fragments = draw_fragmented_files(path='png/large', number_of_files=3)
# Three fragmented files each split into at least three and at most six fragments:
fragments = draw_fragmented_files(number_of_files=3, min_fragments=3, max_fragments=6)
Since scenarios with intertwined files (or braided files as they are sometimes
called) are quite common, Woodblock provides a helper function for this, too.
intertwine_randomly
chooses a given number of files from your corpus, splits
them into fragments, and orders the fragments for you. Again, there are
various arguments that you can pass to the function:
from woodblock.file import intertwine_randomly
# Intertwine three files:
intertwined = intertwine_randomly(number_of_files=3)
# Intertwine three files from the png/large subdirectory:
intertwined = intertwine_randomly(path='png/large', number_of_files=3)
# Intertwine two files and make sure that each file has
# at least three and at most six fragments:
intertwined = intertwine_randomly(number_of_files=3, min_fragments=3, max_fragments=6)
Note that intertwine_randomly
makes sure that fragments of the
same file are never next to each other.
All of the different fragmentation functions and methods described above
create FileFragment
objects. A FileFragment
represents a
fragment of a file from your corpus. Additionally, Woodblock provides special
fragment types for synthetic data. For instance, you can create a region of
zero bytes using the ZeroesFragment
. This is useful, if you want to
simulate unused or wiped disk areas. Here’s how to create a fragment filled
with 0x00
of 4096 bytes of size:
zeroes = woodblock.fragments.ZeroesFragment(size=4096)
Creating a fragment of 4096 bytes of size filled with random data is equally simple:
random_data = woodblock.fragments.RandomDataFragment(size=4096)
ll of the different fragment types have various methods to provide
information about themselves: you can query the size
and the
SHA-256 hash
as well as a dictionary containing all of the
metadata
of the fragment.
Now that we know how to create fragments, let’s find out how to create a carving test scenario out of them.
Scenarios¶
A Scenario
object represents a test scenario for a file carver.
That is, it consists of a certain number of file fragments arranged in a
certain order. Moreover, a scenario can contain filler fragments such as
the ones described above (e.g. ZeroesFragment
or
RandomDataFragment
).
To create such a scenario using the Woodblock API, simply create an instance
of the Scenario
class:
scenario = woodblock.scenario.Scenario('A simple scenario')
The parameter provided to Scenario
is the name of the scenario. This
name appears in the ground truth files generated and should be as descriptive as
possible. Have a look at the descriptions used in the
DFRWS 2007 File Image Layout page for inspiration.
After you created a Scenario
instance, you can add fragments to it:
import woodblock
from woodblock.file import File
from woodblock.fragments import RandomDataFragment, ZeroesFragment
scenario = woodblock.scenario.Scenario('contiguous file with filler before and after')
scenario.add(ZeroesFragment(size=4096))
scenario.add(File('some/path/relative/to/the/corpus.jpg').as_fragment())
scenario.add(RandomDataFragment(size=4096))
The example above creates the scenario “contiguous file with filler before and after” consisting of 4096 zero bytes, then the contiguously stored file “some/path/relative/to/the/corpus.jpg”, and finally 4096 bytes of random data. The order in which fragments are added to the scenario is the order in which these fragments will be written to disk later on.
The add
method does not only take single fragments, but also lists of
fragments. This is convenient if you are, well, working with lists of
fragments:
import woodblock
from woodblock.file import File
scenario = woodblock.scenario.Scenario('single file with reversed fragments')
fragments = File('some/file.txt').fragment_randomly(5)
fragments.reverse()
scenario.add(fragments)
This is already everything you need to create a scenario. The next step is to add your scenario to an image file which is written to disk.
Images¶
Image
objects represent actual test files that you can provide as input
to the carvers you want to evaluate. An image contains one or more scenarios and
can be written to disk as an actual file. Moreover, when being written an
additional log file is written containing the ground truth about this image.
That is, it specifies which files are contained in the image and at which
offsets their fragments are.
Creating an Image
instance is as easy as:
import woodblock
# By default an image has a block size of 512 bytes:
image = woodblock.image.Image()
# But you can change the block size:
image4k = woodblock.image.Image(block_size=4096)
As you can see from the examples above, an image has a fixed block size. This means that any fragment in this image is padded to this block size. Consider for instance the image and the fragments shown below. The image has a fixed block size but the size of the fragments B and A.2 are no multiples of this block size.
The padding introduced by the Image
instance will align the fragments
to the block size specified in the constructor. That is, padding data will be
appended to B and A.2. This is indicated by the dark gray areas labeled with
“p”.
By default, random data is used where padding is required. However, you can
provide your own data generator when creating your Image
instance.
For example you can use 0x00
as padding like this:
zeroes_padding = woodblock.datagen.Zeroes()
image = woodblock.image.Image(padding_generator=zeroes_padding)
The object that you provide as padding_generator
has to fulfill the
data generator interface described in section “Data Generators”.
After creating an Image
instance, you can add scenarios to it.
This works in the same way as you added fragments to a scenario:
s1 = woodblock.scenario.Scenario("first scenario")
s2 = woodblock.scenario.Scenario("second scenario")
# add some fragments to the scenarios
image = woodblock.image.Image()
image.add(s1)
image.add(s2)
The order of the scenarios in the resulting image corresponds to the order in which you added them. Just as before with fragments and scenarios.
The last step to do is to write the image to disk:
image.write(pathlib.Path('test-image.dd'))
This will not only write all of the scenarios to the image file
test-image.dd
, but it will also write a JSON file containing the ground
truth of the image. This file will be placed next to the image and will have the
same same with .json
appended. In the example above, you would find your
ground truth in the file test-image.dd.json
.
Data Generators¶
Data generators are objects implementing a certain interface. They are used in
Woodblock to generate the block padding that is used in an image or within
some FillerFragments
for example. The interface is quite simple, so it’s
easy to write your own data generators. Here is the Zeroes
data generator
class that is already included in Woodblock:
# You can find this in the module woodblock.datagen
class Zeroes:
"""Generates zero bytes."""
def __call__(self, size):
return b'\x00' * size
def __str__(self):
return 'zeroes'
As you can see, a data generator has to be callable. For classes this means
that you have to implement the __call__
magic method. While this would
be sufficient to make your data generator work, we highly recommend to implement
the __str__
magic method, too. When your data generator is used within
one of the fragment classes for example, its string representation will be written
to the ground truth file. So, returning something meaningful from __str__
helps you and others reading and understanding what is within your image.
When data is needed from your data generator, it will be called with a
size
argument indicating how many bytes to return. Of course, your data
generator should return the correct number here. Woodblock expects the data
generators to always return as many bytes as requested and doesn’t do any checking
on the returned bytes. If your data generator fails to generate the expected
number of bytes for some reason, you should raise an exception and not return
any bytes.
You might have noticed, that the interface would also allow you to use a “normal” function as data generator. While technically this would work, we argue against doing so because your data generator function would not have a descriptive string representation. While there are ways to implement a custom string representation for your functions, using a class is just simpler.
Here is one more simple implementation of a data generator which generates a repeated sequence of bytes:
class Pattern:
"""Generate a repeated sequence of bytes."""
def __init__(self, pattern=b'AB'):
self._pattern = pattern
# a data generator has to be callable => implement the __call__ method
def __call__(self, size):
it = itertools.cycle(self._pattern)
return b''.join(bytes([next(it)]) for _ in range(size))
# a data generator should have a descriptive __str__ implementation
def __str__(self):
return 'pattern'
# this is how you would use the Pattern data generator to pad an image
image = woodblock.image.Image(padding_generator=Pattern(b'XO'))
API Reference¶
The following sections provide a brief documentation of the API.
woodblock.file¶
-
woodblock.file.
corpus
(path)¶ Specifies the path to the test file corpus to use.
- Parameters
path – The path to the corpus
path
can either be a string or apathlib.Path
object. In any way, it has to be an existing directory. All paths used forFile
objects are relative to the file corpus path.
-
woodblock.file.
get_corpus
()¶ Return the specified file corpus path.
- Returns
The corpus path
- Return type
pathlib.Path
-
woodblock.file.
draw_files
(path=None, number_of_files=1, unique=False, min_size=0)¶ Chooses random files from the file corpus.
- Parameters
path – Subdirectory of the corpus
number_of_files (int) – Number of files to draw
unique (bool) – Forbid a file to be drawn multiple times
min_size (int) – Minimal file size
- Returns
a list of
File
objects- Return type
list
If
path
isNone
, the complete corpus will be considered. If it set to a path relative to the corpus, then only files in this directory (and its subdirectories) are considered.If
unique
is set toTrue
, then the resulting list will not contain file objects pointing to the same path in the corpus.min_size
can be set to define a minimal file size of the files to be chosen.
-
woodblock.files.
draw_fragmented_files
(path=None, number_of_files=1, block_size=512, min_fragments=1, max_fragments=4)¶ Choose
number_of_files
random files frompath
and fragment them randomly.- Parameters
path – Subdirectory of the corpus
number_of_files (int) – Number of files to draw
block_size (int) – Block size to be used when splitting files
min_fragments (int) – Min. number of fragments per file
max_fragments (int) – Max. number of fragments per file
- Returns
a list of fragment lists
- Return type
list
This function chooses
number_of_files
files from the givenpath
(relative to the corpus) and fragments them at random fragmentation points. The number of fragments per file will be betweenmin_fragments
andmax_fragments
(both numbers included, i.e.min_fragments
≤ number of fragments ≤max_fragments
).The result is a list of fragment lists, e.g.
[ [f1.1, f1.2, f1.3], [f2.1, ], [f3.1, f3.2] ]
.If
path
isNone
, the complete corpus will be considered. If it set to a path relative to the corpus, then only files in this directory (and its subdirectories) are considered.Note that there is no guarantee that a file is not chosen more than once.
-
woodblock.files.
intertwine_randomly
(path=None, number_of_files=2, block_size=512, min_fragments=1, max_fragments=4)¶ Choose
number_of_files
random files frompath
and intertwine them randomly.- Parameters
path – Subdirectory of the corpus
number_of_files (int) – Number of files to intertwine
block_size (int) – Block size to used when splitting files
min_fragments (int) – Min. number of fragments per file
max_fragments (int) – Max. number of fragments per file
- Returns
a list of intertwined fragments
- Return type
list
This function chooses
number_of_files
files from the givenpath
(relative to the corpus), fragments them at random fragmentation points, and intertwines them randomly. The number of fragments per file will be betweenmin_fragments
andmax_fragments
(both numbers included, i.e.min_fragments
≤ number of fragments ≤ :code`max_fragments`).The result is a list of fragments, e.g.
[f3.1, f1.1, f3.2, f2.1, f1.2, f2.2, f1.3]
.The function ensures that there will in fact be unique
number_of_files
files. Moreover, the function guarantees that two fragments of the same file will not be at consecutive list positions. The fragments of each file will be stored in order.
-
class
woodblock.file.
File
(path)¶ This class represents an actual file of the test file corpus.
- Parameters
path (pathlib.Path) – a path relative to the specified corpus
-
property
woodblock.file.File.
hash
¶ Return the SHA-256 hash of the file contents as hexadecimal string.
- Return type
str
-
property
woodblock.file.File.
id
¶ Returns the ID of the file.
- Return type
str
The ID is a UUID generated when the
File
object is instantiated. EachFile
object has a unique ID—even if it references the same file of the corpus. This is useful, if you want to add the same file twice to the same scenario.
-
property
woodblock.file.File.
path
¶ Returns the path of the file relative to the corpus path.
- Return type
pathlib.Path
-
property
woodblock.file.File.
size
¶ Returns the size of the file.
- Return type
int
-
woodblock.file.File.
as_fragment
()¶ Convert the
File
to a singleFileFragment
. This is useful, if you want to add a contiguous, non-fragmented file to a scenario.- Return type
-
woodblock.file.File.
max_fragments
(block_size)¶ Returns the maximal number of fragments which can be created for a given
block_size
.- Return type
int
-
woodblock.file.File.
fragment
(fragmentation_points, block_size=512)¶ Fragments the file at the given
fragmentation_points
with respect to the givenblock_size
.- Parameters
fragmentation_points (typing.Sequence) – a sequence of fragmentation points relative to the block size
block_size (int) – block size to use when splitting the file
- Returns
a list of
woodblock.fragments.FileFragment
objects- Return type
list
This method fragments the current file at the specified
fragmentation_points
. The fragmentation points are multiplied with the givenblock_size
in order to compute the actual fragmentation offsets.fragmentation_points
has to be a sequence of integers,block_size
has to be an integer and defaults to 512 if it is not specified.
-
woodblock.file.File.
fragment_evenly
(num_fragments, block_size=512)¶ This method fragments the current file into
num_fragments
fragments.- Parameters
num_fragments (int) – number of fragments to create
block_size (int) – block size to use when splitting the file
- Returns
a list of
wwodblock.fragments.FileFragment
objects- Return type
list
The fragmentation points are chosen so that each fragment will be of the same size (if possible). If the file cannot be fragmented evenly, then all but the last fragment will have the same size and the last one will be smaller than the other ones.
The block size to be used when splitting the file can be specified using the
block_size
argument, which defaults to 512.
-
woodblock.file.File.
fragment_randomly
(num_fragments, block_size=512)¶ This method fragments the current file into
num_fragments
fragments. The- Parameters
num_fragments (int) – number of fragments to create
block_size (int) – block size to use when splitting the file
- Returns
a list of
woodblock.fragments.FileFragment
objects- Return type
list
The fragmentation points are chosen randomly. If
num_fragments
isNone
, then the number of fragments is chosen randomly between 1 and the maximum number of fragments for the givenblock_size
.
woodblock.fragments¶
-
class
woodblock.fragments.
FileFragment
(file, fragment_number, start_offset, end_offset, chunk_size=8192)¶ This class represents a fragments of an actual file from the file corpus.
- Parameters
file (woodblock.file.File) – the file the fragment is part of
fragment_number (int) – the fragment number of this fragment
start_offset (int) – start offset of the fragment within the original file
end_offset (int) – end offset of the fragment within the original file
file
is theFile
object representing the original file andfragment_number
is the number of the fragment (i.e. is it the first fragment, is the second one and so on).start_offset
andend_offset
define the offsets where the fragment starts and ends (relative to the original file).
-
property
woodblock.fragments.FileFragment.
hash
¶ Return the SHA-256 digest as hexadecimal string.
- Return type
str
-
property
woodblock.fragments.FileFragment.
metadata
¶ Return the fragment metadata.
- Return type
dict
The fragment metadata is a
dict
containing information about the file the fragments originates from (e.g. the hash, the size, and the path) as well as information about the current fragment (e.g. the hash, the size, and the fragment number with respect to the original file).
-
property
woodblock.fragments.FileFragment.
size
¶ Return the size of the fragment.
- Return type
int
-
class
woodblock.fragments.
FillerFragment
(size, data_generator=None, chunk_size=8192)¶ A filler fragment is a fragment containing synthetic data. It can be used to simulate wiped areas or areas with random data.
- Parameters
size (int) – size of the fragment
data_generator – data generator producing the fragment data
data_generator
has to be an object compatible with the data generator interface.
-
property
woodblock.fragments.FillerFragment.
hash
¶ Return the SHA-256 digest as hexadecimal string.
- Return type
str
-
property
woodblock.fragments.FillerFragment.
metadata
¶ Return the fragment metadata.
- Return type
dict
The fragment metadata is a
dict
containing information about the file the fragments originates from (e.g. the hash, the size, and the type) as well as information about the current fragment (e.g. the hash, the size, and the fragment number with respect to the original file).Note that
FillerFragments
do not point to any “real” files. Therefore, the values of the original file and the fragment will be mostly identical. The file metadata is included only for consistency with theFileFragment
.
-
property
woodblock.fragments.FillerFragment.
size
¶ Return the size of the fragment.
- Return type
int
-
class
woodblock.fragments.
RandomDataFragment
(size, chunk_size=8192)¶ A fragment filled with random bytes.
- Parameters
size (int) – the size of the fragment
-
property
woodblock.fragments.RandomDataFragment.
hash
¶ Return the SHA-256 digest as hexadecimal string.
- Return type
str
-
property
woodblock.fragments.FileFragment.
metadata
Return the fragment metadata.
- Return type
dict
The fragment metadata is a
dict
containing information about the file the fragments originates from (e.g. the hash, the size, and the type) as well as information about the current fragment (e.g. the hash, the size, and the fragment number with respect to the original file).Note that
FillerFragments
do not point to any “real” files. Therefore, the values of the original file and the fragment will be mostly identical. The file metadata is included only for consistency with theFileFragment
.
-
property
woodblock.fragments.RandomDataFragment.
size
¶ Return the size of the fragment.
- Return type
int
-
class
woodblock.fragments.
ZeroesFragment
(size, chunk_size=8192)¶ A fragment filled with random bytes.
- Parameters
size (int) – the size of the fragment
-
property
woodblock.fragments.ZeroesFragment.
hash
¶ Return the SHA-256 digest as hexadecimal string.
- Return type
str
-
property
woodblock.fragments.FileFragment.
metadata
Return the fragment metadata.
- Return type
dict
The fragment metadata is a
dict
containing information about the file the fragments originates from (e.g. the hash, the size, and the type) as well as information about the current fragment (e.g. the hash, the size, and the fragment number with respect to the original file).Note that
FillerFragments
do not point to any “real” files. Therefore, the values of the original file and the fragment will be mostly identical. The file metadata is included only for consistency with theFileFragment
.
-
property
woodblock.fragments.ZeroesFragment.
size
¶ Return the size of the fragment.
- Return type
int
woodblock.scenario¶
-
class
woodblock.scenario.
Scenario
(name)¶ This class represents a file carving scenario.
- Parameters
name (str) – the name of the scenario
A scenario contains fragments in a certain order.
name
defines the name of the scenario which identifies the scenario in the ground truth files.
-
woodblock.scenario.Scenario.
add
(fragment)¶ Add a fragment to the scenario.
- Parameters
fragment – the fragment to add to the scenario
-
woodblock.scenario.Scenario.
add
(fragments) The same as
add(scenario)
but this timescenarios
is a list or tuple of fragments to be added to the scenario.- Parameters
fragments – a list fragments to add to the scenario
-
property
woodblock.scenario.Scenario.
metadata
¶ Return a dict containing metadata about the scenario.
- Return type
dict
woodblock.image¶
-
class
woodblock.image.
Image
(block_size=512, padding_generator=woodblock.datagen.Random())¶ The
Image
class represents a carving test image.- Parameters
block_size (int) – The block size to be used in the image
padding_generator – The data generator to use
An image contains a sequence of
Scenario
instances. An image has a fixed block size and all blocks smaller than the block size will be padded with data generated by a configurable data generator. If nopadding_generator
is specified, random data will be used as padding.
-
woodblock.scenario.Image.
add
(scenario)¶ Add a
Scenario
to the image.- Parameters
scenario (woodblock.scenario.Scenario) – The scenario to add
-
static
woodblock.scenario.Image.
from_config
(path)¶ Create an
Image
instance based on a configuration file.- Parameters
path (pathlib.Path) – Path to the configuration file
-
woodblock.scenario.Image.
write
(path)¶ Write the image to disk.
- Parameters
path (pathlib.Path) – The image output path
This method write the image to the specified
path
. Moreover, it also writes the image metadata to disk. The metadata file will bepath
with the “.json” extension. E.g. ifpath
is “test-image.dd” then the actual image will be in “test-image.dd” and the metadata will be in “test-image.dd.json”.