<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Jonas Plum</title><link>https://blog.jonasplum.de/</link><description></description><generator>Gozer</generator><lastBuildDate>Sun, 05 Jul 2026 06:04:43 +0000</lastBuildDate><item><title>Apple container</title><link>https://blog.jonasplum.de/apple-container.html</link><description>&lt;p&gt;I tried &lt;a href=&#34;https://github.com/apple/container&#34;&gt;https://github.com/apple/container&lt;/a&gt; today.&#xA;It&#39;s a pretty nice docker replacement and works well on macOS 15.5, even though officially only macOS 26 is supported.&#xA;The only thing I&#39;m missing currently is file mounts.&lt;/p&gt;&#xA;</description><pubDate>Sun, 28 Jun 2026 00:00:00 +0000</pubDate><guid>https://blog.jonasplum.de/apple-container.html</guid></item><item><title>Use markdown as config</title><link>https://blog.jonasplum.de/markdown-as-config.html</link><description>&lt;p&gt;Most of the time we use json or yaml files for configuration. But these lack the ability to display styled text or syntax-highlighted code samples. Markdown has these capabilities, but cannot be easily parsed to be used as a configuration file.&lt;/p&gt;&#xA;&lt;p&gt;I created &lt;a href=&#34;https://github.com/cugu/md&#34;&gt;https://github.com/cugu/md&lt;/a&gt; to parse markdown into Go structs, similar to how &lt;code&gt;encoding/json.Unmarshal&lt;/code&gt; works for json files.&lt;/p&gt;&#xA;&lt;p&gt;The following example shows how to use the package.&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 1&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;main&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 2&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 3&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 4&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#x9;&lt;span class=&#34;s&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 5&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 6&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#x9;&lt;span class=&#34;s&#34;&gt;&amp;#34;github.com/cugu/md&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 7&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 8&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 9&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Text&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;Title&lt;/span&gt;       &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;`md:&amp;#34;heading&amp;#34;`&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;11&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;Description&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;`md:&amp;#34;paragraph&amp;#34;`&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;13&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;14&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;example&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;`&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;# Title&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;16&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;A short description.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;17&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;`&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;18&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;19&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#x9;&lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;text&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Text&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;21&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#x9;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;md&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Unmarshal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([]&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;example&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;22&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#x9;&#x9;&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;23&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#x9;&#x9;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;24&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#x9;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;25&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;26&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;27&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Description&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;28&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#x9;&lt;span class=&#34;c1&#34;&gt;// Output:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;29&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&#x9;&lt;span class=&#34;c1&#34;&gt;// Title&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;30&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&#x9;&lt;span class=&#34;c1&#34;&gt;// A short description.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;31&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;use-case-1-package-definitions&#34;&gt;Use case 1: Package definitions &lt;a class=&#34;anchor&#34; href=&#34;#use-case-1-package-definitions&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;I started to create a simple package manager which uses markdown files for package definitions.&#xA;Sections are used for the install and uninstall commands.&#xA;GitHub renders these files as markdown, so headings and description paragraphs render nicely for humans, and the embedded code is syntax-highlighted as well.&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 1&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gh&#34;&gt;# Starship prompt&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 2&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gh&#34;&gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 3&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;Starship is a minimal, blazing-fast, and infinitely customizable prompt for any shell!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 4&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 5&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;## Install&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 6&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 7&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;```bash&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 8&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 9&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# download starship and install it&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;11&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;curl -fsSL https://starship.rs/install.sh -o install-starship.sh&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;chmod +x install-starship.sh&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;13&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;./install-starship.sh --bin-dir ~/bin --yes&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;14&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# more steps...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;16&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;```&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;17&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;18&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;## Uninstall&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;19&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;```bash&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;21&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;use-case-2-end-to-end-tests&#34;&gt;Use case 2: End-to-end tests &lt;a class=&#34;anchor&#34; href=&#34;#use-case-2-end-to-end-tests&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Another project I am working on processes received json events.&#xA;This project uses markdown files for end-to-end testing.&#xA;The input json and the expected output logs are defined in different markdown sections.&#xA;Titles and paragraphs are used for description.&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 1&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gh&#34;&gt;# Test 1: Reply to Slack message&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 2&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gh&#34;&gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 3&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;Reply to a received Slack [&lt;span class=&#34;nt&#34;&gt;message event&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;https://api.slack.com/events/message&lt;/span&gt;).&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 4&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 5&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;## Event&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 6&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 7&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;```json&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 8&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 9&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;channel&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;C123ABC456&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;11&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;user&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;U123ABC456&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;text&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello Bob&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;13&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;ts&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;1355517523.000005&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;14&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;```&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;16&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;17&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;## Output&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;18&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;19&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;```log&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;&lt;/span&gt;INFO &amp;#34;received message&amp;#34; type=&amp;#34;message&amp;#34; text=&amp;#34;Hello Bob&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;21&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;INFO &amp;#34;reply sent&amp;#34; msg=&amp;#34;Hello Alice&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;22&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;```&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion &lt;a class=&#34;anchor&#34; href=&#34;#conclusion&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;I&#39;m happy if &lt;a href=&#34;https://github.com/cugu/md&#34;&gt;https://github.com/cugu/md&lt;/a&gt; is useful for your projects and for your feedback.&#xA;I also consider adding features, e.g. marshalling if needed, but want to keep the package as simple as possible.&lt;/p&gt;&#xA;</description><pubDate>Sun, 26 May 2024 00:00:00 +0000</pubDate><guid>https://blog.jonasplum.de/markdown-as-config.html</guid></item><item><title>A take on supply chain security in Go</title><link>https://blog.jonasplum.de/a-take-on-supply-chain-security-in-go.html</link><description>&lt;p&gt;List your dependencies capabilities and monitor if dependency updates require more capabilities.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-problem&#34;&gt;The Problem &lt;a class=&#34;anchor&#34; href=&#34;#the-problem&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Recently different &lt;a href=&#34;https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610&#34;&gt;attacks&lt;/a&gt; and&#xA;&lt;a href=&#34;https://www.bleepingcomputer.com/news/security/dev-corrupts-npm-libs-colors-and-faker-breaking-thousands-of-apps/&#34;&gt;other&lt;/a&gt;&#xA;&lt;a href=&#34;https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44228&#34;&gt;issues&lt;/a&gt;&#xA;related to open-source dependencies highlighted a quite severe problem with dependencies:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Every imported package gives that package&#39;s author basically remote code&#xA;execution for your software.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h2 id=&#34;the-idea&#34;&gt;The Idea &lt;a class=&#34;anchor&#34; href=&#34;#the-idea&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;A &lt;a href=&#34;https://www.youtube.com/watch?v=fh9WXPu0hw8&#34;&gt;video on WASI&lt;/a&gt; by&#xA;&lt;a href=&#34;https://twitter.com/linclark&#34;&gt;linclark&lt;/a&gt; brought me to the idea how cool it would be if we could pass permissions to our&#xA;dependencies.&lt;/p&gt;&#xA;&lt;p&gt;In Go this could look something like this:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;module github.com/cugu/gocap&#xA;&#xA;go 1.20&#xA;&#xA;require (&#xA;&#x9;github.com/go-chi/chi       v5.0.7   (network:read)&#xA;&#x9;github.com/mattn/go-sqlite3 v1.14.10 (file:read, file:write)&#xA;&#x9;github.com/sirupsen/logrus  v1.8.1   (os:stdout)&#xA;&#x9;github.com/yuin/goldmark    v1.4.4   ()&#xA;)&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;code&gt;chi&lt;/code&gt; would be able to receive network requests, &lt;code&gt;go-sqlite3&lt;/code&gt; would be able to read and write files and &lt;code&gt;logrus&lt;/code&gt; could&#xA;write to stdout. But also all those modules would be limited to those capabilities and, for example, the logging&#xA;library &lt;code&gt;logrus&lt;/code&gt; would not be able to interact with files, the network or execute code.&lt;/p&gt;&#xA;&lt;p&gt;Changes of dependencies would be much less critical in many cases, as a potential attacker would have only limited&#xA;attack surface besides stealing your CPU cycles.&lt;/p&gt;&#xA;&lt;h2 id=&#34;a-simpler-but-working-approach-gocap&#34;&gt;A simpler but working approach: GoCap &lt;a class=&#34;anchor&#34; href=&#34;#a-simpler-but-working-approach-gocap&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Implementing the approach above would require changes to Go itself. So I came up with another, simpler approach: GoCap.&#xA;GoCap can check and validate the source code of dependencies for their capabilities and is ment to be included into the&#xA;testing phase of the build process. This way GoCap can at least pin the capabilities of dependencies.&lt;/p&gt;&#xA;&lt;p&gt;GoCap provides simple capability checking for Go using a &lt;code&gt;go.cap&lt;/code&gt; file. The&#xA;&lt;code&gt;go.cap&lt;/code&gt; files lists all package dependencies that require critical permissions like file access, execution rights or&#xA;network access. Unlike the idea above GoCap works on packages not modules and capabilities are based on the imported&#xA;packages of the standard library.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;go.cap&lt;/code&gt; file for GoCap itself looks like this:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;github.com/cugu/gocap (execute, file)&#xA;&#xA;github.com/alecthomas/kong (file, syscall)&#xA;github.com/pkg/errors (runtime)&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h3 id=&#34;install-gocap&#34;&gt;Install GoCap &lt;a class=&#34;anchor&#34; href=&#34;#install-gocap&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;You can &lt;a href=&#34;https://github.com/cugu/gocap/releases&#34;&gt;download a release&lt;/a&gt; or run&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;go install github.com/cugu/gocap@v0.1.0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;gocap-generate&#34;&gt;gocap generate &lt;a class=&#34;anchor&#34; href=&#34;#gocap-generate&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;&lt;code&gt;gocap generate &amp;lt;path&amp;gt;&lt;/code&gt; prints a valid &lt;code&gt;go.cap&lt;/code&gt; file. It lists all dependency packages that require critical permissions&#xA;like file access, execution rights or network access.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;! &lt;code&gt;gocap generate&lt;/code&gt; runs on package basis and the path argument must point to a Go package (there must be .go files)&#xA;not a Go Module. Also &lt;code&gt;gocap generate&lt;/code&gt; needs the dependencies downloaded before, e.g. run &lt;code&gt;go mod download&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;Example&lt;/em&gt;&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; ~/myProjects/gocap&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;go mod download&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;gocap generate . &amp;gt; go.cap&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;em&gt;go.cap&lt;/em&gt;&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;github.com/cugu/gocap (execute, file)&#xA;&#xA;github.com/alecthomas/kong (file, syscall)&#xA;github.com/pkg/errors (runtime)&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h3 id=&#34;gocap-check&#34;&gt;gocap check &lt;a class=&#34;anchor&#34; href=&#34;#gocap-check&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;&lt;code&gt;gocap check &amp;lt;path&amp;gt;&lt;/code&gt; compares a local &lt;code&gt;go.cap&lt;/code&gt; file with the actual required capabilities by dependency packages. Any&#xA;mismatch results in a non-zero exit code, so you can use GoCap check in your CI pipelines.&#xA;See &lt;a href=&#34;https://github.com/cugu/gocap/blob/main/.github/workflows/ci.yml#L28&#34;&gt;ci.yml&lt;/a&gt; for a working example.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;Example&lt;/em&gt;&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;gocap check .&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;em&gt;Output&lt;/em&gt;&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;github.com/alecthomas/kong&#xA;&#x9;capability &#39;syscall&#39; not provided by go.cap file, add to go.cap file if you want to grant the capability&#xA;github.com/pkg/errors&#xA;&#x9;unnecessary capability &#39;network&#39;, please remove from go.cap file&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h2 id=&#34;capabilities&#34;&gt;Capabilities &lt;a class=&#34;anchor&#34; href=&#34;#capabilities&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Name&lt;/th&gt;&#xA;&lt;th&gt;Description&lt;/th&gt;&#xA;&lt;th&gt;Packages&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;file&lt;/td&gt;&#xA;&lt;td&gt;Read and write access to files&lt;/td&gt;&#xA;&lt;td&gt;os io/ioutil&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;network&lt;/td&gt;&#xA;&lt;td&gt;Read and write to the network&lt;/td&gt;&#xA;&lt;td&gt;net net/http&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;execute&lt;/td&gt;&#xA;&lt;td&gt;Execute other binaries&lt;/td&gt;&#xA;&lt;td&gt;os/exec&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;syscall&lt;/td&gt;&#xA;&lt;td&gt;Perform any system call in context of the software&lt;/td&gt;&#xA;&lt;td&gt;syscall, C&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;unsafe&lt;/td&gt;&#xA;&lt;td&gt;Usage of the unsafe package in combination with a //go:linkname compiler directive can be used to load external C or assembler code&lt;/td&gt;&#xA;&lt;td&gt;unsafe&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;reflect&lt;/td&gt;&#xA;&lt;td&gt;reflect.NewAt in combination with reflect#Value.Call might be used call arbitrary functions&lt;/td&gt;&#xA;&lt;td&gt;reflect&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;</description><pubDate>Wed, 12 Jan 2022 00:00:00 +0000</pubDate><guid>https://blog.jonasplum.de/a-take-on-supply-chain-security-in-go.html</guid></item><item><title>APFS filesystem format</title><link>https://blog.jonasplum.de/apfs.html</link><description>&lt;p&gt;I started to reverse engineer APFS and want to share what I found out so far. You can send me feedback and ideas on this post via &lt;a href=&#34;https://twitter.com/intent/tweet?text=@cugu_pio%20&amp;amp;related=cugu_pio&amp;amp;url=https://blog.cugu.eu/post/apfs/&#34;&gt;Twitter&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Notice&lt;/strong&gt;: I created a test image with macOS Sierra 10.12.3 (16D32). All results are guesses and the reverse engineering is work in progress. Also newer versions of APFS might change structures. The information below is neither complete nor proven to be correct.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Update 2017-04-30&lt;/strong&gt;: Added a section for the checksum&#xA;&lt;strong&gt;Update 2017-06-16&lt;/strong&gt;: Add apfs.ksy respository&lt;/p&gt;&#xA;&lt;h2 id=&#34;contents&#34;&gt;Contents &lt;a class=&#34;anchor&#34; href=&#34;#contents&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;#overview&#34;&gt;Overview&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;#general&#34;&gt;General information&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;#structures&#34;&gt;Structures&lt;/a&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;#block_header&#34;&gt;Block header&lt;/a&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;#checksum&#34;&gt;Checksum&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;#container_superblock&#34;&gt;Container Superblock&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;#node&#34;&gt;Node&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;#spacemanager&#34;&gt;Spacemanager&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;#allocation_info_file&#34;&gt;Allocation Info File&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;#0x11&#34;&gt;Unknown&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;#btree&#34;&gt;B-Tree&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;#checkpoint&#34;&gt;Checkpoint&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;#volume_superblock&#34;&gt;Volume Superblock&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;#allocation_file&#34;&gt;Allocation File&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;a-nameoverviewa-overview&#34;&gt;&lt;a name=&#34;overview&#34;&gt;&lt;/a&gt; Overview &lt;a class=&#34;anchor&#34; href=&#34;#a-nameoverviewa-overview&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;APFS is structured in a single container that can contain multiple APFS volumes. A container needs to be &amp;gt;512 MB to contain more than one volume, &amp;gt;1024MB to contain more than two volumes and so on. The following image shows an overview of the APFs structure.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;/files/apfs_overview.png&#34; alt=&#34;APFS Overview&#34; /&gt;&lt;/p&gt;&#xA;&lt;p&gt;Each element of this structure (except for the allocation file) starts with a 32 byte &lt;strong&gt;block header&lt;/strong&gt;, which contains some general information about the block. Afterwards the body of the structure is following. The following types exist:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;0x01&lt;/strong&gt;: Container Superblock&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;0x02&lt;/strong&gt;: Node&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;0x05&lt;/strong&gt;: Spacemanager&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;0x07&lt;/strong&gt;: Allocation Info File&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;0x11&lt;/strong&gt;: &lt;em&gt;Unknown&lt;/em&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;0x0B&lt;/strong&gt;: B-Tree&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;0x0C&lt;/strong&gt;: Checkpoint&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;0x0D&lt;/strong&gt;: Volume Superblock&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Each of this structures is described in detail below. A more detailed version of the APFS structure is available as a Kaitai struct file: &lt;a href=&#34;https://github.com/cugu/apfs.ksy&#34;&gt;apfs.ksy&lt;/a&gt;. You can use it to examine APFS dumps in the &lt;a href=&#34;https://ide.kaitai.io/#&#34;&gt;Kaitai IDE&lt;/a&gt; or &lt;a href=&#34;http://kaitai.io/repl/&#34;&gt;create parsers&lt;/a&gt; for various languages. This .ksy file must considered experimental.&lt;/p&gt;&#xA;&lt;h2 id=&#34;a-namegenerala-general-information&#34;&gt;&lt;a name=&#34;general&#34;&gt;&lt;/a&gt; General information: &lt;a class=&#34;anchor&#34; href=&#34;#a-namegenerala-general-information&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The filesystem uses &lt;strong&gt;litte-endian&lt;/strong&gt; values for storing information&lt;/li&gt;&#xA;&lt;li&gt;Timestamps are &lt;strong&gt;64bit nanoseconds&lt;/strong&gt; (1 / 1,000,000,000 seconds!) starting from 1.1.1970 UTC (unix epoch). The current timestamp is around &lt;code&gt;0x14b11800f375e000&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Standard block size seems to be 4096 byte per block.&lt;/li&gt;&#xA;&lt;li&gt;APFS is a &lt;strong&gt;copy-on-write&lt;/strong&gt; filesystem so each block is copied before changes are applied so a history of all unoverwritten files and filesystem structures exists. This might result in a huge amount of forensic artefacts.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;a-namestructuresa-structures&#34;&gt;&lt;a name=&#34;structures&#34;&gt;&lt;/a&gt; Structures &lt;a class=&#34;anchor&#34; href=&#34;#a-namestructuresa-structures&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;h3 id=&#34;a-nameblock-headera-block-header&#34;&gt;&lt;a name=&#34;block_header&#34;&gt;&lt;/a&gt; Block header &lt;a class=&#34;anchor&#34; href=&#34;#a-nameblock-headera-block-header&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;Each filesystem structure in APFS starts with a block header. This header starts with a checksum for the whole block. Other informations in the header include the copy-on-write version of the block, the block id and the block type.&lt;/p&gt;&#xA;&lt;TABLE BORDER=&#34;0&#34; CELLBORDER=&#34;1&#34; CELLSPACING=&#34;0&#34;&gt;&#xA;        &lt;TR&gt;&lt;TD &gt;pos&lt;/TD&gt;&lt;TD &gt;size&lt;/TD&gt;&lt;TD &gt;type&lt;/TD&gt;&lt;TD &gt;id&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;checksum_pos&#34;&gt;0&lt;/TD&gt;&lt;TD PORT=&#34;checksum_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;uint64&lt;/TD&gt;&lt;TD PORT=&#34;checksum_type&#34;&gt;checksum&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;block_id_pos&#34;&gt;8&lt;/TD&gt;&lt;TD PORT=&#34;block_id_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;uint64&lt;/TD&gt;&lt;TD PORT=&#34;block_id_type&#34;&gt;block_id&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;version_pos&#34;&gt;16&lt;/TD&gt;&lt;TD PORT=&#34;version_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;uint64&lt;/TD&gt;&lt;TD PORT=&#34;version_type&#34;&gt;version&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;block_type_pos&#34;&gt;24&lt;/TD&gt;&lt;TD PORT=&#34;block_type_size&#34;&gt;2&lt;/TD&gt;&lt;TD&gt;uint16&lt;/TD&gt;&lt;TD PORT=&#34;block_type_type&#34;&gt;block_type&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;flags_pos&#34;&gt;26&lt;/TD&gt;&lt;TD PORT=&#34;flags_size&#34;&gt;2&lt;/TD&gt;&lt;TD&gt;uint16&lt;/TD&gt;&lt;TD PORT=&#34;flags_type&#34;&gt;flags&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;padding_pos&#34;&gt;28&lt;/TD&gt;&lt;TD PORT=&#34;padding_size&#34;&gt;4&lt;/TD&gt;&lt;TD&gt;uint32&lt;/TD&gt;&lt;TD PORT=&#34;padding_type&#34;&gt;padding&lt;/TD&gt;&lt;/TR&gt;&#xA;      &lt;/TABLE&gt;&#xA;&lt;h4 id=&#34;a-namechecksuma-checksum&#34;&gt;&lt;a name=&#34;checksum&#34;&gt;&lt;/a&gt; Checksum &lt;a class=&#34;anchor&#34; href=&#34;#a-namechecksuma-checksum&#34;&gt;#&lt;/a&gt;&lt;/h4&gt;&#xA;&lt;p&gt;According to the &lt;a href=&#34;https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/APFS_Guide/FAQ/FAQ.html&#34;&gt;apple docs&lt;/a&gt; the Fletcher&#39;s checksum algorithm is used. Apple uses a variant of the algorithm described in a &lt;a href=&#34;http://collaboration.cmc.ec.gc.ca/science/rpn/biblio/ddj/Website/articles/DDJ/1992/9205/9205b/9205b.htm&#34;&gt;paper by John Kodis&lt;/a&gt;. The following algorithm shows this procedure. The input is the block without the first 8 byte.&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 1&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;createChecksum&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 2&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sum1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sum2&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;uint64&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 3&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 4&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;modValue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;uint64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;31&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 5&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 6&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 7&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;d&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;binary&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;LittleEndian&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Uint32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 8&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;sum1&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sum1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;uint64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;d&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;modValue&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 9&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;sum2&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sum2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sum1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;modValue&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;11&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;check1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;modValue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sum1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sum2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;modValue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;13&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;check2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;modValue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sum1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;check1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;modValue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;14&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;check2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;check1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;16&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The nice feature of the algorithm is, that when you check a block in APFS with the following algorithm you should get null as a result. Note that the input in this case is the whole block, including the checksum.&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 1&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;checkChecksum&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 2&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sum1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sum2&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;uint64&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 3&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 4&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;modValue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;uint64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;31&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 5&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 6&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 7&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;d&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;binary&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;LittleEndian&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Uint32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 8&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;sum1&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sum1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;uint64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;d&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;modValue&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt; 9&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;sum2&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sum2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sum1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;modValue&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;11&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sum2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sum1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;ln&#34;&gt;13&lt;/span&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;a-namecontainer-superblocka-container-superblock&#34;&gt;&lt;a name=&#34;container_superblock&#34;&gt;&lt;/a&gt; Container Superblock &lt;a class=&#34;anchor&#34; href=&#34;#a-namecontainer-superblocka-container-superblock&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;The container superblock is the entry point to the filesystem. Because of the structure with containers and flexible volumes, allocation needs to handled on a container level. The container superblock contains information on the blocksize, the number of blocks and pointers to the spacemanager for this task. Additionally the block IDs of all volumes are stored in the superblock. To map block IDs to block offsets a pointer to a block map b-tree is stored. This b-tree contains entries for each volume with its ID and offset.&lt;/p&gt;&#xA;&lt;TABLE BORDER=&#34;0&#34; CELLBORDER=&#34;1&#34; CELLSPACING=&#34;0&#34;&gt;&#xA;        &lt;TR&gt;&lt;TD &gt;pos&lt;/TD&gt;&lt;TD &gt;size&lt;/TD&gt;&lt;TD &gt;type&lt;/TD&gt;&lt;TD &gt;id&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;magic_pos&#34;&gt;0&lt;/TD&gt;&lt;TD PORT=&#34;magic_size&#34;&gt;4&lt;/TD&gt;&lt;TD&gt;byte&lt;/TD&gt;&lt;TD PORT=&#34;magic_type&#34;&gt;magic &#34;NXSB&#34;&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;blocksize_pos&#34;&gt;4&lt;/TD&gt;&lt;TD PORT=&#34;blocksize_size&#34;&gt;4&lt;/TD&gt;&lt;TD&gt;uint32&lt;/TD&gt;&lt;TD PORT=&#34;blocksize_type&#34;&gt;blocksize&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;totalblocks_pos&#34;&gt;8&lt;/TD&gt;&lt;TD PORT=&#34;totalblocks_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;uint64&lt;/TD&gt;&lt;TD PORT=&#34;totalblocks_type&#34;&gt;totalblocks&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;guid_pos&#34;&gt;40&lt;/TD&gt;&lt;TD PORT=&#34;guid_size&#34;&gt;16&lt;/TD&gt;&lt;TD&gt;byte&lt;/TD&gt;&lt;TD PORT=&#34;guid_type&#34;&gt;guid&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;next_free_block_id_pos&#34;&gt;56&lt;/TD&gt;&lt;TD PORT=&#34;next_free_block_id_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;uint64&lt;/TD&gt;&lt;TD PORT=&#34;next_free_block_id_type&#34;&gt;next_free_block_id&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;next_version_pos&#34;&gt;64&lt;/TD&gt;&lt;TD PORT=&#34;next_version_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;uint64&lt;/TD&gt;&lt;TD PORT=&#34;next_version_type&#34;&gt;next_version&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;previous_containersuperblock_block_pos&#34;&gt;104&lt;/TD&gt;&lt;TD PORT=&#34;previous_containersuperblock_block_size&#34;&gt;4&lt;/TD&gt;&lt;TD&gt;uint32&lt;/TD&gt;&lt;TD PORT=&#34;previous_containersuperblock_block_type&#34;&gt;previous_containersuperblock_block&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;spaceman_id_pos&#34;&gt;120&lt;/TD&gt;&lt;TD PORT=&#34;spaceman_id_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;uint64&lt;/TD&gt;&lt;TD PORT=&#34;spaceman_id_type&#34;&gt;spaceman_id&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;block_map_block_pos&#34;&gt;128&lt;/TD&gt;&lt;TD PORT=&#34;block_map_block_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;uint64&lt;/TD&gt;&lt;TD PORT=&#34;block_map_block_type&#34;&gt;block_map_block&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;unknown_id_pos&#34;&gt;136&lt;/TD&gt;&lt;TD PORT=&#34;unknown_id_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;uint64&lt;/TD&gt;&lt;TD PORT=&#34;unknown_id_type&#34;&gt;unknown_id&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;padding2_pos&#34;&gt;144&lt;/TD&gt;&lt;TD PORT=&#34;padding2_size&#34;&gt;4&lt;/TD&gt;&lt;TD&gt;uint32&lt;/TD&gt;&lt;TD PORT=&#34;padding2_type&#34;&gt;padding2&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;apfs_count_pos&#34;&gt;148&lt;/TD&gt;&lt;TD PORT=&#34;apfs_count_size&#34;&gt;4&lt;/TD&gt;&lt;TD&gt;uint32&lt;/TD&gt;&lt;TD PORT=&#34;apfs_count_type&#34;&gt;apfs_count&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;offset_apfs_pos&#34;&gt;152&lt;/TD&gt;&lt;TD PORT=&#34;offset_apfs_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;uint64&lt;/TD&gt;&lt;TD PORT=&#34;offset_apfs_type&#34;&gt;offset_apfs (repeat apfs_count times)&lt;/TD&gt;&lt;/TR&gt;&#xA;      &lt;/TABLE&gt;&#xA;&lt;h3 id=&#34;a-namenodea-node&#34;&gt;&lt;a name=&#34;node&#34;&gt;&lt;/a&gt; Node &lt;a class=&#34;anchor&#34; href=&#34;#a-namenodea-node&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;Nodes are flexible containers that are used for storing different kinds entries. They can be part of a B-tree or exist on their own. Nodes can either contain flexible or fixed sized entries. A node starts with a list of pointers to the entry keys and entry records. This way for each entry the node contains an entry header at the beginning of the node, an entry key in the middle of the node and an entry record at the end of the node.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;/files/node.png&#34; alt=&#34;Node&#34; /&gt;&lt;/p&gt;&#xA;&lt;TABLE BORDER=&#34;0&#34; CELLBORDER=&#34;1&#34; CELLSPACING=&#34;0&#34;&gt;&#xA;        &lt;TR&gt;&lt;TD &gt;pos&lt;/TD&gt;&lt;TD &gt;size&lt;/TD&gt;&lt;TD &gt;type&lt;/TD&gt;&lt;TD &gt;id&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;alignment_pos&#34;&gt;0&lt;/TD&gt;&lt;TD PORT=&#34;alignment_size&#34;&gt;4&lt;/TD&gt;&lt;TD&gt;uint32&lt;/TD&gt;&lt;TD PORT=&#34;alignment_type&#34;&gt;alignment&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;entry_count_pos&#34;&gt;4&lt;/TD&gt;&lt;TD PORT=&#34;entry_count_size&#34;&gt;4&lt;/TD&gt;&lt;TD&gt;uint32&lt;/TD&gt;&lt;TD PORT=&#34;entry_count_type&#34;&gt;entry_count&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;head_size_pos&#34;&gt;10&lt;/TD&gt;&lt;TD PORT=&#34;head_size_size&#34;&gt;2&lt;/TD&gt;&lt;TD&gt;uint16&lt;/TD&gt;&lt;TD PORT=&#34;head_size_type&#34;&gt;head_size&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;meta_entry_pos&#34;&gt;16&lt;/TD&gt;&lt;TD PORT=&#34;meta_entry_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;entry&lt;/TD&gt;&lt;TD PORT=&#34;meta_entry_type&#34;&gt;meta_entry&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;entries_pos&#34;&gt;24&lt;/TD&gt;&lt;TD PORT=&#34;entries_size&#34;&gt;...&lt;/TD&gt;&lt;TD&gt;entry&lt;/TD&gt;&lt;TD PORT=&#34;entries_type&#34;&gt;entries (repeat entry_count times)&lt;/TD&gt;&lt;/TR&gt;&#xA;      &lt;/TABLE&gt;&#xA;&lt;h3 id=&#34;a-namespacemanagera-spacemanager&#34;&gt;&lt;a name=&#34;spacemanager&#34;&gt;&lt;/a&gt; Spacemanager &lt;a class=&#34;anchor&#34; href=&#34;#a-namespacemanagera-spacemanager&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;The spacemanager (sometimes called spaceman) is used to manage allocated blocks in the APFS container. The number of free blocks and a pointer to the allocation info file(s?) are stored here.&lt;/p&gt;&#xA;&lt;TABLE BORDER=&#34;0&#34; CELLBORDER=&#34;1&#34; CELLSPACING=&#34;0&#34;&gt;&#xA;        &lt;TR&gt;&lt;TD &gt;pos&lt;/TD&gt;&lt;TD &gt;size&lt;/TD&gt;&lt;TD &gt;type&lt;/TD&gt;&lt;TD &gt;id&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;blocksize_pos&#34;&gt;0&lt;/TD&gt;&lt;TD PORT=&#34;blocksize_size&#34;&gt;4&lt;/TD&gt;&lt;TD&gt;uint32&lt;/TD&gt;&lt;TD PORT=&#34;blocksize_type&#34;&gt;blocksize&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;totalblocks_pos&#34;&gt;16&lt;/TD&gt;&lt;TD PORT=&#34;totalblocks_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;uint64&lt;/TD&gt;&lt;TD PORT=&#34;totalblocks_type&#34;&gt;totalblocks&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;freeblocks_pos&#34;&gt;40&lt;/TD&gt;&lt;TD PORT=&#34;freeblocks_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;uint64&lt;/TD&gt;&lt;TD PORT=&#34;freeblocks_type&#34;&gt;freeblocks&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;prev_allocationinfofile_block_pos&#34;&gt;144&lt;/TD&gt;&lt;TD PORT=&#34;prev_allocationinfofile_block_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;uint64&lt;/TD&gt;&lt;TD PORT=&#34;prev_allocationinfofile_block_type&#34;&gt;prev_allocationinfofile_block&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;allocationinfofile_block_pos&#34;&gt;352&lt;/TD&gt;&lt;TD PORT=&#34;allocationinfofile_block_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;uint64&lt;/TD&gt;&lt;TD PORT=&#34;allocationinfofile_block_type&#34;&gt;allocationinfofile_block&lt;/TD&gt;&lt;/TR&gt;&#xA;      &lt;/TABLE&gt;&#xA;&lt;h3 id=&#34;a-nameallocation-info-filea-allocation-info-file&#34;&gt;&lt;a name=&#34;allocation_info_file&#34;&gt;&lt;/a&gt; Allocation Info File &lt;a class=&#34;anchor&#34; href=&#34;#a-nameallocation-info-filea-allocation-info-file&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;The allocation info file works as a missing header for the allocation file. The allocation files length, version and the offset of the allocation file are stored here.&lt;/p&gt;&#xA;&lt;TABLE BORDER=&#34;0&#34; CELLBORDER=&#34;1&#34; CELLSPACING=&#34;0&#34;&gt;&#xA;        &lt;TR&gt;&lt;TD &gt;pos&lt;/TD&gt;&lt;TD &gt;size&lt;/TD&gt;&lt;TD &gt;type&lt;/TD&gt;&lt;TD &gt;id&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;alloc_file_length_pos&#34;&gt;4&lt;/TD&gt;&lt;TD PORT=&#34;alloc_file_length_size&#34;&gt;4&lt;/TD&gt;&lt;TD&gt;uint32&lt;/TD&gt;&lt;TD PORT=&#34;alloc_file_length_type&#34;&gt;alloc_file_length&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;alloc_file_version_pos&#34;&gt;8&lt;/TD&gt;&lt;TD PORT=&#34;alloc_file_version_size&#34;&gt;4&lt;/TD&gt;&lt;TD&gt;uint32&lt;/TD&gt;&lt;TD PORT=&#34;alloc_file_version_type&#34;&gt;alloc_file_version&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;total_blocks_pos&#34;&gt;24&lt;/TD&gt;&lt;TD PORT=&#34;total_blocks_size&#34;&gt;4&lt;/TD&gt;&lt;TD&gt;uint32&lt;/TD&gt;&lt;TD PORT=&#34;total_blocks_type&#34;&gt;total_blocks&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;free_blocks_pos&#34;&gt;28&lt;/TD&gt;&lt;TD PORT=&#34;free_blocks_size&#34;&gt;4&lt;/TD&gt;&lt;TD&gt;uint32&lt;/TD&gt;&lt;TD PORT=&#34;free_blocks_type&#34;&gt;free_blocks&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;allocationfile_block_pos&#34;&gt;32&lt;/TD&gt;&lt;TD PORT=&#34;allocationfile_block_size&#34;&gt;4&lt;/TD&gt;&lt;TD&gt;uint32&lt;/TD&gt;&lt;TD PORT=&#34;allocationfile_block_type&#34;&gt;allocationfile_block&lt;/TD&gt;&lt;/TR&gt;&#xA;      &lt;/TABLE&gt;&#xA;&lt;h3 id=&#34;a-name0x11a-unknown&#34;&gt;&lt;a name=&#34;0x11&#34;&gt;&lt;/a&gt; Unknown &lt;a class=&#34;anchor&#34; href=&#34;#a-name0x11a-unknown&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;The structure with type 0x11 is quite empty and seems to be related to the spacemanager as it occurs adjacent to it. Its purpose it unknown.&lt;/p&gt;&#xA;&lt;h3 id=&#34;a-namebtreea-b-tree&#34;&gt;&lt;a name=&#34;btree&#34;&gt;&lt;/a&gt; B-Tree &lt;a class=&#34;anchor&#34; href=&#34;#a-namebtreea-b-tree&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;B-trees manage multiple nodes. They contain the offset of the root node.&lt;/p&gt;&#xA;&lt;TABLE BORDER=&#34;0&#34; CELLBORDER=&#34;1&#34; CELLSPACING=&#34;0&#34;&gt;&#xA;        &lt;TR&gt;&lt;TD &gt;pos&lt;/TD&gt;&lt;TD &gt;size&lt;/TD&gt;&lt;TD &gt;type&lt;/TD&gt;&lt;TD &gt;id&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;root_pos&#34;&gt;16&lt;/TD&gt;&lt;TD PORT=&#34;root_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;uint64&lt;/TD&gt;&lt;TD PORT=&#34;root_type&#34;&gt;root&lt;/TD&gt;&lt;/TR&gt;&#xA;      &lt;/TABLE&gt;&#xA;&lt;h3 id=&#34;a-namecheckpointa-checkpoint&#34;&gt;&lt;a name=&#34;checkpoint&#34;&gt;&lt;/a&gt; Checkpoint &lt;a class=&#34;anchor&#34; href=&#34;#a-namecheckpointa-checkpoint&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;A checkpoint structure exists for every container superblock. But I have no clue what it is good for.&lt;/p&gt;&#xA;&lt;h3 id=&#34;a-namevolume-superblocka-volume-superblock&#34;&gt;&lt;a name=&#34;volume_superblock&#34;&gt;&lt;/a&gt; Volume Superblock &lt;a class=&#34;anchor&#34; href=&#34;#a-namevolume-superblocka-volume-superblock&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;A volume superblock exists for each volume in the filesystem. It contains the name of the volume, an ID and a timestamp. Similarly to the container superblock it contains a pointer to a block map which maps block IDs to bock offsets. Additionally a pointer to the root directory, which is stored as a node, is stored in the volume superblock.&lt;/p&gt;&#xA;&lt;TABLE BORDER=&#34;0&#34; CELLBORDER=&#34;1&#34; CELLSPACING=&#34;0&#34;&gt;&#xA;        &lt;TR&gt;&lt;TD &gt;pos&lt;/TD&gt;&lt;TD &gt;size&lt;/TD&gt;&lt;TD &gt;type&lt;/TD&gt;&lt;TD &gt;id&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;magic_pos&#34;&gt;0&lt;/TD&gt;&lt;TD PORT=&#34;magic_size&#34;&gt;4&lt;/TD&gt;&lt;TD&gt;byte&lt;/TD&gt;&lt;TD PORT=&#34;magic_type&#34;&gt;magic &#34;APSB&#34;&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;block_map_pos&#34;&gt;96&lt;/TD&gt;&lt;TD PORT=&#34;block_map_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;uint64&lt;/TD&gt;&lt;TD PORT=&#34;block_map_type&#34;&gt;block_map&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;root_dir_id_pos&#34;&gt;104&lt;/TD&gt;&lt;TD PORT=&#34;root_dir_id_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;uint64&lt;/TD&gt;&lt;TD PORT=&#34;root_dir_id_type&#34;&gt;root_dir_id&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;pointer3_pos&#34;&gt;112&lt;/TD&gt;&lt;TD PORT=&#34;pointer3_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;uint64&lt;/TD&gt;&lt;TD PORT=&#34;pointer3_type&#34;&gt;pointer3&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;pointer4_pos&#34;&gt;120&lt;/TD&gt;&lt;TD PORT=&#34;pointer4_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;uint64&lt;/TD&gt;&lt;TD PORT=&#34;pointer4_type&#34;&gt;pointer4&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;bin_pos&#34;&gt;208&lt;/TD&gt;&lt;TD PORT=&#34;bin_size&#34;&gt;16&lt;/TD&gt;&lt;TD&gt;byte&lt;/TD&gt;&lt;TD PORT=&#34;bin_type&#34;&gt;guid&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;time1_pos&#34;&gt;224&lt;/TD&gt;&lt;TD PORT=&#34;time1_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;uint64&lt;/TD&gt;&lt;TD PORT=&#34;time1_type&#34;&gt;time1&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;time2_pos&#34;&gt;272&lt;/TD&gt;&lt;TD PORT=&#34;time2_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;uint64&lt;/TD&gt;&lt;TD PORT=&#34;time2_type&#34;&gt;time2&lt;/TD&gt;&lt;/TR&gt;&#xA;        &lt;TR&gt;&lt;TD PORT=&#34;name_pos&#34;&gt;672&lt;/TD&gt;&lt;TD PORT=&#34;name_size&#34;&gt;8&lt;/TD&gt;&lt;TD&gt;str(ASCII)&lt;/TD&gt;&lt;TD PORT=&#34;name_type&#34;&gt;name&lt;/TD&gt;&lt;/TR&gt;&#xA;      &lt;/TABLE&gt;&#xA;&lt;h3 id=&#34;a-nameallocation-filea-allocation-file&#34;&gt;&lt;a name=&#34;allocation_file&#34;&gt;&lt;/a&gt; Allocation File &lt;a class=&#34;anchor&#34; href=&#34;#a-nameallocation-filea-allocation-file&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;Allocation files are simple bitmaps. They do not have a block header and therefore no type id.&lt;/p&gt;&#xA;</description><pubDate>Sat, 22 Apr 2017 00:00:00 +0000</pubDate><guid>https://blog.jonasplum.de/apfs.html</guid></item><item><title>Structure of gpg keys</title><link>https://blog.jonasplum.de/structure-of-pgp-keys.html</link><description>&lt;p&gt;Creating a new nice pgp key I first needed to examine the exact structure of a pgp key.&lt;/p&gt;&#xA;&lt;p&gt;I used the batch mode of gpg (&lt;code&gt;gpg --status-fd 1 --no-tty --batch --gen-key&lt;/code&gt;) to create the key &lt;a href=&#34;/files/4B9E3333.gpg&#34;&gt;0x4B9E3333&lt;/a&gt; with the settings:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;Key-Type: default&#xA;Subkey-Type: default&#xA;Name-Real: Cugu&#xA;Name-Email: cugu@cugu.eu&#xA;Expire-Date: 2020-05-04&#xA;Passphrase: password&#xA;%pubring foo.pub&#xA;%secring foo.sec&#xA;%commit&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;A nice feature here, is that the short name &lt;em&gt;Cugu&lt;/em&gt; is allowed, while in command line mode at least five letters are mandatory.&lt;/p&gt;&#xA;&lt;p&gt;The created public gpg key consists of five single packets.&lt;/p&gt;&#xA;&lt;h2 id=&#34;public-key-packet&#34;&gt;Public Key Packet &lt;a class=&#34;anchor&#34; href=&#34;#public-key-packet&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;The first packet contains the public key information as well as creation date. The created key is an RSA key so the public key is the &lt;strong&gt;e&lt;/strong&gt; which is 0x10001 (=65537) in this case. The 2048 bit (256 byte) long &lt;strong&gt;n&lt;/strong&gt; is the modulus for the RSA operation.&lt;/p&gt;&#xA;&lt;p&gt;The owner of the secret key has the secret RSA exponent &lt;strong&gt;d&lt;/strong&gt;. To sign a message the owner can calculate m&lt;sup&gt;d&lt;/sup&gt; &lt;em&gt;mod&lt;/em&gt; n = c. Using this public key everyone can afterwards calculate c&lt;sup&gt;e&lt;/sup&gt; &lt;em&gt;mod&lt;/em&gt; n = m&lt;sub&gt;1&lt;/sub&gt; and validate that m&lt;sub&gt;1&lt;/sub&gt; = m.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;99&#xA;=======&#xA;  01 0D       269 length&#xA;  04          Version 4&#xA;  53946f6e    Creation Date Timestamp&#xA;  01          RSA&#xA;  0800        2048&#xA;  bfde487046d4d5b5460a4682a21ea8b874675a67ffe5a3a9685d45f02a8ad420&#xA;  b08389f200c6e3cae3b113ef81150ef4bacd15f7c496ee5aca41b18d440d8449&#xA;  bb791131b3c25ee54c9b10394b4740d70402a9d9316f5ddb9aa741b512b81099&#xA;  837b46a7f04d11feaa5b69ed630e8c7a94f6c7754f62634ec1663b00aac3c957&#xA;  23798c69abb619be691e0c990d93e83da2c4d2269ebe1fdece5a517c83c0b567&#xA;  1e9c4da6010d3b74baada0289b64f24bd6398a6ae652d4b4745ab908955ff04d&#xA;  a3f87c5ee087bacef35f6f4507f9becdb16425e4d94ae633168ace98e0eb3110&#xA;  ebd9ce358bc07eb20f411b52cb4334cfdd46ee6d6da8f0f10f83e4ff329a4a41&#xA;              RSA n&#xA;  0011        Padding?&#xA;  010001      RSA e&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h2 id=&#34;user-id-packet&#34;&gt;User ID Packet &lt;a class=&#34;anchor&#34; href=&#34;#user-id-packet&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;This second packet contains the data that should be bound to the public key from above.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;b4&#xA;=======&#xA;  13          Length 19&#xA;  43756775203c6375677540637567752e65 Cugu &amp;lt;cugu@cugu.eu&amp;gt;&#xA;  753e&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h2 id=&#34;signature-packet&#34;&gt;Signature Packet &lt;a class=&#34;anchor&#34; href=&#34;#signature-packet&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;This packet binds the User ID Packet to the public key. The content of all the subpackets can be gathered by using &lt;a href=&#34;http://www.pgpdump.net/&#34;&gt;pgpdump&lt;/a&gt; or reading &lt;a href=&#34;http://www.ietf.org/rfc/rfc4880.txt&#34;&gt;RFC4880&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The key flags sub packet indicates, that this key can just be used for signing and certification. openpgp shows &lt;em&gt;sc&lt;/em&gt; in this case. A capital letter shows, that a sub key is capable of other functions (e.g. capital E -&amp;gt; sub key can be used for encryption)&lt;/p&gt;&#xA;&lt;p&gt;The most interesting part here is sig(i).&#xA;i is build by a combination of a lot of information:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;The complete Public Key Packet (e.g. 0x99010D...010001)&lt;/li&gt;&#xA;&lt;li&gt;The user ID Packet, where the length is encoded in 4 byte. (e.g. in our case: 0xb4&lt;strong&gt;000000&lt;/strong&gt;1343756775203c6375677540637567752e65753e)&lt;/li&gt;&#xA;&lt;li&gt;Data from this Signature Packet starting including version till the end of the hashed subpackets (e.g. 0x0413010a...021780)&lt;/li&gt;&#xA;&lt;li&gt;A trailer starting with 0x04FF and a 4 byte length of the data from the Signature Packet&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;All this information is concatenated and hashed. This hash is afterwards appended to a combination of 0x1f followed by many 0xff a single 0x00 and a specification of the used hash (e.g. &lt;strong&gt;i&lt;/strong&gt;=0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003051300d060960864801650304020305000440 + hash)&lt;/p&gt;&#xA;&lt;p&gt;The value 0x3051300d060960864801650304020305000440 for our hash is specified in &lt;a href=&#34;http://www.ietf.org/rfc/rfc4880.txt&#34;&gt;RFC4880&lt;/a&gt; 5.2.2.&lt;/p&gt;&#xA;&lt;p&gt;All this values (&lt;strong&gt;i&lt;/strong&gt;=0x1f...) is signed: i&lt;sup&gt;d&lt;/sup&gt; &lt;em&gt;mod&lt;/em&gt; n = sig(i)&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;89&#xA;=======&#xA;  013d        Length 317&#xA;  04          Version&#xA;  13          Positive certification of a User ID and Public-Key packet.&#xA;  01          RSA&#xA;  0a          SHA512&#xA;&#xA;  00 27         Length hashed Subpackets 15&#xA;&#xA;    05          Length 5&#xA;    02          Subpacket Type (2 = Signature Creation Time)&#xA;    53946f6e    Timestamp&#xA;&#xA;    02          Length 2&#xA;    1b          Subpacket Type (27 = Key Flags)&#xA;    03&#xA;&#xA;    05          Length 5&#xA;    09          Subpacket (Type 9 = Key Expiration Time)&#xA;    0b1b7832    Timestamp Offset (186349618 + Creation Time)&#xA;&#xA;    05          Length 5&#xA;    0b          Subpacket (Type 11 = Preferred Symmetric Algorithms)&#xA;    09080703&#xA;&#xA;    05          Length 5&#xA;    15          Subpacket (Type 21 = Preferred Hash Algorithms)&#xA;    0a09080b&#xA;&#xA;    05          Length 5&#xA;    16          Subpacket (Type 22 = Preferred Compression Algorithms)&#xA;    02030100&#xA;&#xA;    02          Length 2&#xA;    1e          Subpacket (Type 30 = Features)&#xA;    01          Modification Detection&#xA;&#xA;    02          Length 2&#xA;    17          Subpacket (Type 23 = Key Server Preferences)&#xA;    80          0x80 = No-modify&#xA;&#xA;  00 0a         Length unhased Subpackets 10&#xA;&#xA;    09          Length 9&#xA;    10          Subpacket (Type 16 = Issuer)&#xA;    48c1 f448 4b9e 3333&#xA;                last 4 blocks of the fingerprint&#xA;&#xA;  c678        last 2 byte of the hash over m&#xA;&#xA;  0800        2048&#xA;  816a53faf1135895ad8890c165a32a1d1166e5df41fa43713f02fafdbc55f4f1&#xA;  848038f55f778550acb76ebab3d6323604342445f7224406edab06c93f46c246&#xA;  b109b4b18a1ccc71fda28e3f1059d866c2e389f9ab589e76be11e5ef737e1178&#xA;  f5675425d5f5c4246a04e76d5dc9dc6b93550f0766a57298ed463a9fc6e8bba8&#xA;  3287f3b5c33eebefbf358e32936e0a316be86d56ac96391e796b8eac7091e215&#xA;  6a7eae9082369775901c86fcb1ca6c74d8c345d9db6c299923a86d97287209f9&#xA;  9bedf83b599e561fff370877dd1a7c6fecd632b2d984e7b1c27fbfc80e3a59e2&#xA;  217b0708b161192e194c204506aed50b20485da514dc29df2128f8ac42fe2458&#xA;              sig(i)&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h2 id=&#34;public-subkey-packet&#34;&gt;Public Subkey Packet &lt;a class=&#34;anchor&#34; href=&#34;#public-subkey-packet&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;This subkey can be used for encryption. Otherwise this and the following signature packet are built the same way as above.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;b9&#xA;=======&#xA;  010d        269 length&#xA;  04          Version 4&#xA;  53946f6e    Timestamp&#xA;  01          RSA&#xA;  0800        2048&#xA;  aa19801ed96301caaef25633b87eedcecfb31a7363fd798264b1f9fa307728ed&#xA;  b50f086404930ecbf03f13d807e181ade29268589eba63c459b6e90388d40169&#xA;  29a63d6e06c4f87289aef3269cd5ba9d31bce6f364ea97513611a84e97a85f32&#xA;  6b77114e0c4ec3c5249f91fd48783713d0825ef99db56e846562189844454722&#xA;  67cd4e64d43fa2a305267c0482b968ec00e8cea00b6464ef6e4117095036779a&#xA;  4b713ec1ad04580b4fcebb66ed8afc3a0e6c315f6790a0c6f2277ae8a017fe9e&#xA;  67b036cc786d85718cc1d0670dc1c7d688369eb10934e1b3245a183ab70e3068&#xA;  80cb3f91c8fd389c5e7f46bfd1e3fb70def93900bfbe2cb59faaa1df311d253f&#xA;              512 bit&#xA;  0011        Padding?&#xA;  010001      RSA e&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h2 id=&#34;signature-packet-1&#34;&gt;Signature Packet &lt;a class=&#34;anchor&#34; href=&#34;#signature-packet-1&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;pre&gt;&lt;code&gt;89&#xA;=======&#xA;  0125        293 Length&#xA;  04          Version 4&#xA;  18          Subkey Binding Signature&#xA;  01          RSA&#xA;  0a          SHA512&#xA;&#xA;  00 0f         Length hashed Subpackets 15&#xA;&#xA;    05          Length 5&#xA;    02          Subpacket Type 2 = Signature Creation Time&#xA;    53946f6e    Timestamp&#xA;&#xA;    02          Length 2&#xA;    1b          Subpacket Type 27 = Key Flags&#xA;    0c          1100&#xA;&#xA;    05          Length 5&#xA;    09          Subpacket (Type 9 = Key Expiration Time)&#xA;    0b1b7832    Timestamp Offset (186349618 + Creation Time)&#xA;&#xA;  00 0a         Length unhased Subpackets 10&#xA;&#xA;    09          Length 9&#xA;    10          Subpacket (Type 16 = Issuer)&#xA;    48c1f4484b9e3333&#xA;                Last 4 Blocks FP&#xA;&#xA;  c16e        diff&#xA;&#xA;  0800        2048&#xA;  a9b0401874d80f839c407b50e5dcb5ee51e5aafc95933fee013631620a61e69d&#xA;  63be81e79f35b57cb4cf372ea7bdaa23e9593e18a747101229849cd59517bd75&#xA;  e8d2965ccf517420906fb649e6f885f927bcabd9f925b80a31d165b12776260f&#xA;  711ed37d10262d1c103b42fd0baead95529d6c2f10cae24d353dc1e9aa2336ce&#xA;  9457c4d484eed4416ec1a23a734ca41d146fc79229757a5b7a61f2ac5600cd4c&#xA;  f800aa118e77dbd32d20c774021dd70f2efb90f00218593e3b00fe97ecbdfc05&#xA;  633fee7c75bb27aa44d76d9c8c047e7bb1c1d07212c668639bbab1ed9c1288f9&#xA;  b914da5f600baaa22e911338205c58b2bc1d3282ff54e7801eb8889284686eb3&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;</description><pubDate>Tue, 24 Jun 2014 00:00:00 +0000</pubDate><guid>https://blog.jonasplum.de/structure-of-pgp-keys.html</guid></item><item><title>Recover broken docx</title><link>https://blog.jonasplum.de/recover-broken-docx.html</link><description>&lt;p&gt;Today a friend of me asked me to recover a docx document. MS Word called this document broken.&lt;/p&gt;&#xA;&lt;p&gt;docx is essentially a zip file. The command &lt;code&gt;zip -F broken.docx --out restore.zip&lt;/code&gt; tries to restore the file.&#xA;Well no success. &lt;code&gt;zip -FF broken.docx --out restore.zip&lt;/code&gt; tries harder!&#xA;Afterwards &lt;code&gt;unzip restore.zip&lt;/code&gt; unzips the file.&#xA;The file document.xml in the folder word contains the actual text data from the word document.&#xA;Unfortunately in my case the document.xml was half empty :(&#xA;Zip commands are taken from: &lt;a href=&#34;http://computers.tutsplus.com/tutorials/how-to-repair-damaged-zip-files-with-terminal--mac-49294&#34;&gt;http://computers.tutsplus.com/tutorials/how-to-repair-damaged-zip-files-with-terminal--mac-49294&lt;/a&gt;&lt;/p&gt;&#xA;</description><pubDate>Tue, 13 May 2014 00:00:00 +0000</pubDate><guid>https://blog.jonasplum.de/recover-broken-docx.html</guid></item></channel></rss>