Skip to content

Commit

Permalink
Line editing through li. 170
Browse files Browse the repository at this point in the history
  • Loading branch information
christinerose authored Aug 21, 2023
1 parent 27da43d commit 3bf8e35
Showing 1 changed file with 25 additions and 24 deletions.
49 changes: 25 additions & 24 deletions data/planet/-hosted_on_ocamlorg/building-the-ocaml-gpt-library.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ source:
---

## Introduction
In the world today, software development often demands efficient management of storage devices. One of the key players in this arena is the GUID Partitioning Table (GPT). In this tutorial, we'll go over the steps of how the [`ocaml-gpt`](https://github.com/PizieDust/ocaml-gpt) library was developed and what this means for the OCaml ecosystem, especially in the context of the Mirage operating system which is lacking in persistent storage capabilities. Through this `ocaml-gpt` library, developers will be able to seamlessly manage partitions in their block devices and disk images enabling enhanced control and reliability in storage management.
In the world today, software development often demands efficient management of storage devices. One of the key players in this arena is the GUID Partitioning Table (GPT). In this tutorial, we'll go over the steps of how the [`ocaml-gpt`](https://github.com/PizieDust/ocaml-gpt) library was developed and what this means for the OCaml ecosystem, especially in the context of the Mirage operating system, which is lacking in persistent storage capabilities. Through this `ocaml-gpt` library, developers will be able to seamlessly manage partitions in their block devices and disk images enabling enhanced control and reliability in storage management.

## Background Research
Before diving into the technical details, let's understand the significance of GPT. The GUID Partitioning Table is a modern replacement for the older Master Boot Record (MBR) partitioning scheme. GPT offers advantages like support for larger disk sizes (up to 10 Billion TB), better data integrity, and the flexibility to accommodate more partitions (up to 128). Understanding the principles of GPT sets the stage for comprehending how the `ocaml-gpt` library simplifies its usage. Most of the information and the specifications on GPT were gotten from this Wikipedia article [GUID Partition Table](https://en.wikipedia.org/wiki/GUID_Partition_Table). This article contains a lot of information specifically
Before diving into the technical details, let's understand the significance of GPT. The GUID Partitioning Table is a modern replacement for the older Master Boot Record (MBR) partitioning scheme. GPT offers advantages like support for larger disk sizes (up to 10 Billion TB), better data integrity, and the flexibility to accommodate more partitions (up to 128). Understanding the principles of GPT sets the stage for comprehending how the `ocaml-gpt` library simplifies its usage. Most of the information and the specifications on GPT were obtained from this Wikipedia article: [GUID Partition Table](https://en.wikipedia.org/wiki/GUID_Partition_Table). This article contains a lot of information specifically.

## Welcome to the World of Dune
[Dune](dune.build) is a build system for OCaml projects. In other words, `dune` helps us setup a skeleton project we can use to build our library. It can be used to build executables, libraries, run tests, and much more which is just perfect for our use case. `Dune` is absolutely awesome.
[Dune](dune.build) is a build system for OCaml projects. In other words, Dune helps us setup a skeleton project we can use to build our library. It can be used to build executables, libraries, run tests, and much more, which is just perfect for our use case. Dune is absolutely awesome!

So let's dive in by installing `dune` using the OCaml Package Manager, [opam](https://opam.ocaml.org/) which is like OCaml's version of `pip` for Python or `Composer` for PHP:
So let's dive in by installing Dune using the OCaml Package Manager, [opam](https://opam.ocaml.org/), which is like OCaml's version of Pip for Python or Composer for PHP:

```sh
opam install dune
Expand All @@ -28,7 +28,7 @@ After installation is complete, we can update our shell environment by running:
```sh
eval $(opam env)
```
At this point, we can initialize our project:
At this point, we can initialise our project:

```sh
dune init proj ocaml-gpt
Expand All @@ -43,12 +43,12 @@ dune: NAME argument: invalid component name `ocaml-gpt'
Usage: dune init project [OPTION]… NAME [PATH]
Try 'dune init project --help' or 'dune --help' for more information.
```
This is because `dune` uses `snake_case` and not `kebab-case`. A quick workaround (suggested by my mentor [Reynir](https://github.com/reynir)) is to generate the files and manually editing the dune files to use our `kebab-case` name. So we run the command again:
This is because Dune uses `snake_case` and not `kebab-case`. A quick workaround (suggested by my mentor [Reynir](https://github.com/reynir)) is to generate the files and manually edit the `dune` files to use our `kebab-case` name. So we run the command again:
```sh
dune init proj ocaml_gpt
```
Running the command above will create a directory `ocaml_gpt` in our current working directory. We have to enter this directory to see which files have been generated:
Running the command above will create the directory `ocaml_gpt` in our current working directory. We have to enter this directory to see which files have been generated:
```sh
cd ocaml_gpt
Expand All @@ -70,24 +70,25 @@ Our project folder should look like this:
4 directories, 8 files
```
Here, we can edit the `dune-project` file to specify some information about our project such as the Author's name, package name, license, dependencies etc. Ironically, `dune-project` is `kebab-case`.
Here, we can edit the `dune-project` file to specify some information about our project such as the author's name, package name, license, dependencies, etc. Ironically, `dune-project` is `kebab-case`.
So a quick breakdown of the different directories:
- The `bin` directory is where we can keep our executables and binaries.
- The `lib` directory is where we can keep our library files and main code.
- The `test` directory is where we can write our unit test.
For our project, we are using the following dependencies:
- `OCaml` (version 4.02 or later)
- `dune` (build system)
- OCaml (version 4.02 or later)
- Dune (build system)
- `uuidm` (library for UUID manipulation)
- `checkseum` (library for checksum calculations)
- `OCaml-cstruct` (library for working with C-like structures)
- `cmdliner` (librrary for )
## Breaking down the Modules
If you read the `GPT` specification in the Wikipedia article, you will notice that the GPT header has a certain format to be followed.
#### GPT header format
Below is a snippet from the Wikipedia article detailing the different components that make up the GPT header along with the various offsets, lengths and content.
## Breaking Down the Modules
If you read the GPT specification in the Wikipedia article, you will notice that the GPT header has a certain format to be followed.
#### GPT Header Format
Below is a snippet from the Wikipedia article detailing the different components that make up the GPT header along with the various offsets, lengths, and content.
```
| Offset | Length | Contents |
|:---------: |:--------: |:---------------------------------------------------------------------------------------------------------------------------------------: |
Expand All @@ -107,24 +108,24 @@ Below is a snippet from the Wikipedia article detailing the different components
| 88 (0x58) | 4 bytes | CRC32 of partition entries array in little endian |
| 92 (0x5C) | * | Reserved; must be zeroes for the rest of the block (420 bytes for a sector size of 512 bytes; but can be more with larger sector sizes) |
```
Using this, we can abstract our library into different modules, one module for our partitions and the other module for the header itself.
Using this, we can abstract our library into different modules: one module for our partitions and the other module for the header itself.

#### Partition Module:
Partitions in the GPT header contain fields that we can organize as an OCaml record. This record encapsulates essential attributes of a partition entry. The fields we will be working with are:
Partitions in the GPT header contain fields that we can organise as an OCaml record. This record encapsulates essential attributes of a partition entry. The fields we will be working with are:

- `type_guid`: This field stores the UUID (Universally Unique Identifier) that indicates the type of the partition. It provides information about the purpose and format of the partition.
- `partition_guid`: This field holds the UUID that uniquely identifies the partition. This identifier is unique within the context of the entire GPT table and helps distinguish one partition from another.
- `starting_lba`: This field is of type `int64` and represents the starting logical block address (LBA) of the partition. LBAs are used to locate data blocks on the storage device.
- `ending_lba`: This field is also of type `int64` and signifies the ending LBA of the partition. It marks the last block address occupied by the partition. Using the `starting_lba` and the `ending_lba` we can determine the size of the partition.
- `attributes`: This field is an `int64` that stores partition-specific attributes. These attributes provide additional information about the partition, such as whether it's bootable or whether it's required by the system.
- `name`: The name of the partition, represented as a `string`. This field stores a descriptive label for the partition, making it more user-friendly.
- `name`: The name of the partition, represented as a `string`. This field stores a descriptive label for the partition, making it more user friendly.

When combined, these fields represent a partition entry in our GPT table. At this point, we now have to think of the methods in our module, namely for creating and parsing our partition entries. In our module we have functions for this:
- `make`: This function is used to create our partition entry. The output is a record of the different fields that make up a partition entry.
- `marshal`: We take a Cstruct record of our partition and convert it into a binary before, which can then be written unto a disk.
- `unmarshal`: The reverse of marshaling where we take a binary buffer and extract a Cstruct record of it's representation.
- `marshal`: We take a `Cstruct` record of our partition and convert it into a binary before, which can then be written unto a disk.
- `unmarshal`: The reverse of marshaling, where we take a binary buffer and extract a `Cstruct` record of it's representation.

#### GPT module
#### GPT Module
This module defines a record type that represents the structure of the GPT header itself. Below is an explanation of the different fields and methods in this module:

- `signature`: A string that represents the GPT header signature, which is basically just `"EFI PART"`.
Expand All @@ -150,13 +151,13 @@ With our fields, we can now define the different methods to compute our GPT head
- `unmarshal`: Parses the binary buffer to create a GPT header record.
- `marshal`: Fills a binary buffer with the values from the GPT header record.

At this point, all that's left to do is code our modules, types and methods.
At this point, all that's left to do is code our modules, types, and methods.

## Writing Test
Tests are a great way to verify our code is working as we expect it to. It also helps maintain a standard as we continue updating our code. Writing Unit tests is definitely important.
In our project, we are using the [`Alcotest`](https://ocaml.org/p/alcotest/latest) library to conduct our tests. This is an awesome library and many thanks to [Craig Ferguson](https://www.craigfe.io/) for creating this beautiful package and the whole OCaml Opensource community for maintaining it.
Tests are a great way to verify that our code is working as we expect it to. It also helps maintain a standard as we continue updating our code. Writing Unit tests are definitely important.
In our project, we are using the [`Alcotest`](https://ocaml.org/p/alcotest/latest) library to conduct our tests. This is an awesome library, and many thanks to [Craig Ferguson](https://www.craigfe.io/) for creating this beautiful package and the whole OCaml open-source community for maintaining it.

Using Alcotest, we can test different parts of our code and even the different functions we have in our code. For our library, we wrote the following test:
Using `Alcotest`, we can test different parts of our code and even the different functions we have in our code. For our library, we wrote the following test:

- `test_make_partition`: Tests the creation of a partition using the `Partition.make` function.
- `test_make_partition_wrong_type_guid`: Tests the scenario where an invalid GUID type is provided to create a partition.
Expand Down

0 comments on commit 3bf8e35

Please sign in to comment.