{"id":29303697,"url":"https://github.com/mateusznowakdev/minifs","last_synced_at":"2025-09-07T03:37:30.257Z","repository":{"id":300739588,"uuid":"1006502877","full_name":"mateusznowakdev/minifs","owner":"mateusznowakdev","description":"Absurdly small filesystem for microcontrollers running TinyGo","archived":false,"fork":false,"pushed_at":"2025-06-22T13:24:00.000Z","size":5,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-07-07T01:49:23.710Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mateusznowakdev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-22T12:20:03.000Z","updated_at":"2025-06-22T19:50:42.000Z","dependencies_parsed_at":null,"dependency_job_id":"a724c973-d650-4868-aa6f-00abd98673f2","html_url":"https://github.com/mateusznowakdev/minifs","commit_stats":null,"previous_names":["mateusznowakdev/minifs"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/mateusznowakdev/minifs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mateusznowakdev%2Fminifs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mateusznowakdev%2Fminifs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mateusznowakdev%2Fminifs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mateusznowakdev%2Fminifs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mateusznowakdev","download_url":"https://codeload.github.com/mateusznowakdev/minifs/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mateusznowakdev%2Fminifs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273993022,"owners_count":25203792,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-07T02:00:09.463Z","response_time":67,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-07-07T01:40:55.587Z","updated_at":"2025-09-07T03:37:30.245Z","avatar_url":"https://github.com/mateusznowakdev.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# minifs\n\nDead simple filesystem for very low-power microcontrollers running TinyGo. Requires Go 1.23+.\n\n* Good performance (10x faster than littlefs on average, tested with SAMD21 at 8 MHz)\n* Atomic file updates\n* Basic wear leveling\n* Only essential features\n  * no long filenames\n  * no directories\n  * no timestamps\n  * no access control\n  * ...\n\nIt can be useful if there are few small files to be frequently read or written, but may not be a good choice for other purposes.\n\n## Installing\n\n```\n$ go get github.com/mateusznowakdev/minifs\n```\n\n## API\n\nThis library is a wrapper around the TinyGo's `machine.Flash`\n\nInstead of the standard Go file API, there's a custom one which is simpler and faster:\n\n* `Format()`\n* `fs.Delete(name)`\n* `fs.Exists(name)`\n* `fs.List()` \n* `fs.Read(name)`\n* `fs.Rename(old, new)`\n* `fs.Write(name, data)`\n\nEach function returns an error object, either from `machine.Flash` (due to hardware failures) or from `Filesystem` implementation.\n\nSome checks are not implemented (for example if flash memory is too small to store all files created so far).\n\n## Metadata\n\nMetadata block is split into 16-byte-long sections.\n\n| Section # | Bytes  | Explanation                  |\n|:---------:|:------:|------------------------------|\n|   **0**   | 0..12  | `SfsMetadataBk` magic number |\n|           |   13   | Version number               |\n|           | 14..15 | File count (up to 2^16)      |\n| **1..n**  | 0..11  | File name (0xFF-terminated)  |\n|           | 12..13 | File size (up to 2^16)       |\n|           | 14..15 | Block number (up to 2^16)    |\n\nFor example, up to 15 files can be stored if the block size is 256 bytes. The larger the block, the more file slots are available.\n\nMetadata block is not guaranteed to be found at the very beginning. It is necessary to scan the entire flash memory to find it. It may be beneficial to reserve less space to improve the startup speed.\n\nIf there are multiple \"valid\" metadata blocks, only the first one is considered actually valid. If there are no valid blocks or there is some suspicious data (such as invalid version number), then the filesystem is considered damaged and must be formatted.\n\nThe file size is also limited to the size of a single block, which makes fragmentation impossible, but may be a significant limitation.\n\n## Wear leveling\n\nFile data is always written next to the current position of metadata block.\n\n### Example\n\n| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |\n|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:--:|:--:|:--:|:--:|:--:|:--:|\n|   |   | M | 1 | 5 |   | 3 | 4 |   | 2 | 8  | 11 | 6  | 7  | 10 | 9  |\n\nLet's rename file 1. This will cause metadata to be copied.\n\n| 0 | 1 |   2   | 3 | 4 |    5    | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |\n|:-:|:-:|:-----:|:-:|:-:|:-------:|:-:|:-:|:-:|:-:|:--:|:--:|:--:|:--:|:--:|:--:|\n|   |   | ~~M~~ | 1 | 5 | _**M**_ | 3 | 4 |   | 2 | 8  | 11 | 6  | 7  | 10 | 9  |\n\nIf this successful, then the old metadata block gets erased.\n\n| 0 | 1 | 2 | 3 | 4 |    5    | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |\n|:-:|:-:|:-:|:-:|:-:|:-------:|:-:|:-:|:-:|:-:|:--:|:--:|:--:|:--:|:--:|:--:|\n|   |   |   | 1 | 5 | _**M**_ | 3 | 4 |   | 2 | 8  | 11 | 6  | 7  | 10 | 9  |\n\n### Example 2\n\nNow let's overwrite file 10. First, the new file data is written to the first available block, next to the metadata block:\n\n| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |    8     | 9 | 10 | 11 | 12 | 13 |   14   | 15 |\n|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:--------:|:-:|:--:|:--:|:--:|:--:|:------:|:--:|\n|   |   |   | 1 | 5 | M | 3 | 4 | _**10**_ | 2 | 8  | 11 | 6  | 7  | ~~10~~ | 9  |\n\nThen the metadata needs to be updated. Since there is no more space to the right (block #14 is still being used!), we wrap around and find the first available block:\n\n|    0    | 1 | 2 | 3 | 4 |   5   | 6 | 7 |    8     | 9 | 10 | 11 | 12 | 13 |   14   | 15 |\n|:-------:|:-:|:-:|:-:|:-:|:-----:|:-:|:-:|:--------:|:-:|:--:|:--:|:--:|:--:|:------:|:--:|\n| _**M**_ |   |   | 1 | 5 | ~~M~~ | 3 | 4 | _**10**_ | 2 | 8  | 11 | 6  | 7  | ~~10~~ | 9  |\n\nIf this is successful, then the old metadata block gets erased and old data block will be repurposed later (data is NOT erased).\n\n|    0    | 1 | 2 | 3 | 4 | 5 | 6 | 7 |    8     | 9 | 10 | 11 | 12 | 13 |   14   | 15 |\n|:-------:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:--------:|:-:|:--:|:--:|:--:|:--:|:------:|:--:|\n| _**M**_ |   |   | 1 | 5 |   | 3 | 4 | _**10**_ | 2 | 8  | 11 | 6  | 7  | ~~10~~ | 9  |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmateusznowakdev%2Fminifs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmateusznowakdev%2Fminifs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmateusznowakdev%2Fminifs/lists"}