PureFS: Difference between revisions
[unchecked revision] | [unchecked revision] |
(Added some information) |
(→Example Of Disk Space Allocation: Fixed a small error) |
||
(22 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
{{In Progress}} |
|||
{{Filesystems}} |
{{Filesystems}} |
||
'''Note: if you find a grammatical error in the article, please correct it (the author does not know English well, so there may be errors).'''<br/> |
|||
PureFS is a simple disk file system designed to quickly read information and data from files and directories.<br> |
|||
PureFS is a disk file system designed to simplify the interaction between the operating system and disks. |
|||
Due to its structure, it is possible to use a second file system on the disk, you just need to create a 3rd or 4th entry for PureFS in the MBR partition table('''SystemID = 0x15'''). |
|||
== PureFS |
== PureFS V1.2.0 == |
||
Better than the [https://wiki.osdev.org/index.php?title=PureFS&oldid=28856 previous version] in terms of speed, but a bit more complicated.<br/> |
|||
There are only 4 structures: |
|||
PureFS V1.2.0 has a total of 6 main structures: |
|||
* PureFsHeader |
|||
#PureFsHeader |
|||
* PureFsPartitionHeader |
|||
#PureFsVolumeHeader |
|||
* PureFsFile |
|||
#PureFsFileMap |
|||
* PureFsData |
|||
#PureFsDataMap |
|||
'''Note: all values must be written in Little-Endian format!''' |
|||
#PureFsFileTable |
|||
#PureFsDataTable |
|||
Advantages(+): |
|||
#Easy to implement. |
|||
#Easy to understand. |
|||
#Supports nested directories. |
|||
#Maximum available 2^64 - 1 sectors. |
|||
Disadvantages(-): |
|||
#It can be journalable, provided that the OS takes care of this task itself. |
|||
#The maximum length of the file name is 255 characters. |
|||
#The maximum number of volumes is 40. |
|||
#Does not support Unicode names. |
|||
#Takes up a lot of space. |
|||
== Example Of Disk Space Allocation == |
|||
Note: sector #1 is not the first sector on the disk, but the first sector of PureFS.<br/> |
|||
Partition with a single volume: |
|||
{| class="wikitable" |
|||
|- |
|||
! Sector # |
|||
! Structure |
|||
|- |
|||
| 1 |
|||
| PureFS header |
|||
|- |
|||
| 2 |
|||
| PureFS volume header |
|||
|- |
|||
| 3 |
|||
| PureFS file map |
|||
|- |
|||
| 3+blocks/map |
|||
| PureFS data map |
|||
|- |
|||
| 3+blocks/map*2 |
|||
| PureFS file table |
|||
|- |
|||
| 3+blocks/map*2+32*blocks/map |
|||
| PureFS data table |
|||
|} |
|||
== Structures == |
|||
=== PureFsHeader === |
=== PureFsHeader === |
||
Contains information about file system. |
Contains information about the file system.<br/> |
||
{| |
{| class="wikitable" |
||
|- |
|- |
||
! Offset |
! Offset |
||
! Size |
! Size |
||
! Type |
|||
! Name |
! Name |
||
! Value |
! Value |
||
|- |
|- |
||
| 0x00 |
| 0x00 |
||
| 0x08 |
| 0x08 |
||
| char[8] |
|||
| Signature |
| Signature |
||
| ` |
| `->PureFS` |
||
|- |
|- |
||
| 0x08 |
| 0x08 |
||
| 0x04 |
| 0x04 |
||
| u32 |
|||
| Version |
| Version |
||
| |
| PureFS version number(1.2.0 = 0x010200) |
||
|- |
|- |
||
| 0x0C |
| 0x0C |
||
| 0x08 |
| 0x08 |
||
| u64 |
|||
| FirstPartition |
|||
| NumVolumes |
|||
| Offset to first partition (in sectors) |
|||
| Number of PureFS volumes |
|||
|- |
|- |
||
| 0x14 |
| 0x14 |
||
| |
| 0x01 |
||
| u8 |
|||
| NumPartitions |
|||
| Number of PureFS partitions |
|||
|- |
|||
| 0x1C |
|||
| 0x08 |
|||
| Checksum |
| Checksum |
||
| |
| Complements byte sum of fields above to 0 |
||
|- |
|- |
||
| |
| 0x15 |
||
| |
| 0x0B |
||
| u8[11] |
|||
| Reserved |
| Reserved |
||
| Reserved for future use |
| Reserved for future use |
||
|- |
|- |
||
| 0x20 |
|||
| 0x28*0x0C |
|||
| PureFsVolumePtr[40] |
|||
| Volumes |
|||
| Pointers to PureFS volumes |
|||
|} |
|} |
||
PureFsVolumePtr: |
|||
=== PureFsPartitionHeader === |
|||
{| class="wikitable" |
|||
Contains information about partition. |
|||
{| {{wikitable}} |
|||
|- |
|- |
||
! Offset |
! Offset |
||
! Size |
! Size |
||
! Type |
|||
! Name |
! Name |
||
! Value |
! Value |
||
|- |
|- |
||
| 0x00 |
| 0x00 |
||
| |
| 0x08 |
||
| u64 |
|||
| Offset |
|||
| Offset to PureFS volume (in sectors) |
|||
|- |
|||
| 0x08 |
|||
| 0x04 |
|||
| u32 |
|||
| NameHash |
|||
| Murmur v3 32-bit volume name hash<br /> |
|||
|} |
|||
=== PureFsVolumeHeader === |
|||
Contains information about the PureFS volume.<br/> |
|||
{| class="wikitable" |
|||
|- |
|||
! Offset |
|||
! Size |
|||
! Type |
|||
! Name |
|||
! Value |
|||
|- |
|||
| 0x00 |
|||
| 0x37+0x01 |
|||
| char[55+1] |
|||
| Name |
| Name |
||
| PureFS volume name (zero-terminated) |
|||
| Name of the partition |
|||
|- |
|- |
||
| |
| 0x38 |
||
| 0x08 |
| 0x08 |
||
| u64 |
|||
| Attributes |
| Attributes |
||
| |
| PureFS volume attributes |
||
|- |
|||
| 0x40 |
|||
| 0x08 |
|||
| u64 |
|||
| BlocksPerMap |
|||
| Maximum number of blocks(sectors) per map(FileMap/DataMap) |
|||
|- |
|- |
||
| 0x48 |
| 0x48 |
||
| 0x08 |
| 0x08 |
||
| u64 |
|||
| NumBlocks |
|||
| NumFiles |
|||
| Maximum number of blocks(sectors) in partition |
|||
| Current number of files |
|||
|- |
|- |
||
| 0x50 |
| 0x50 |
||
| 0x08 |
| 0x08 |
||
| u64 |
|||
| NumFiles |
|||
| NumData |
|||
| Current number of files in partition |
|||
| Current number of data blocks(sectors) |
|||
|- |
|- |
||
| 0x58 |
| 0x58 |
||
| |
| 0x1A8 |
||
| u8[424] |
|||
| FirstFile |
|||
| Reserved |
|||
| Offset to first file block (in sectors) |
|||
| Reserved for future use |
|||
|} |
|||
Attributes: |
|||
*'''BOOTABLE'''(0x01) - marks that there is a program (OS kernel, for example) on the partition that bootloader should load. |
|||
*'''READABLE'''(0x02) |
|||
*'''WRITEABLE'''(0x04) |
|||
=== PureFsFileMap === |
|||
Consists of PureFsVolumeHeader::BlocksPerMap sectors. There are 32 PureFsFileMapEntry entries in each sector.<br/> |
|||
PureFsFileMapEntry: |
|||
{| class="wikitable" |
|||
|- |
|- |
||
! Offset |
|||
| 0x60 |
|||
! Size |
|||
| 0x08 |
|||
! Type |
|||
| LastFile |
|||
! Name |
|||
| Offset to last file block (in sectors) |
|||
! Value |
|||
|- |
|- |
||
| |
| 0x00 |
||
| 0x08 |
| 0x08 |
||
| u64 |
|||
| FirstData |
|||
| FileIndex |
|||
| Offset to first data block (in sectors) |
|||
| PureFsFile block(sector) index in the file table |
|||
|- |
|- |
||
| 0x70 |
|||
| 0x08 |
| 0x08 |
||
| 0x04 |
|||
| LastData |
|||
| u32 |
|||
| Offset to last data block (in sectors) |
|||
| PathHash<br /> |
|||
| Murmur v3 32-bit hash of file path on partition ('''without partition name!''') |
|||
|- |
|- |
||
| |
| 0x0C |
||
| 0x04 |
|||
| u32 |
|||
| ParentHash |
|||
| Murmur v3 32-bit hash of the path to the parent directory on the partition ('''without partition name!''') |
|||
|} |
|||
=== PureFsDataMap === |
|||
Consists of PureFsVolumeHeader::BlocksPerMap sectors. There are 32 PureFsDataMapEntry entries in each sector.<br/> |
|||
PureFsDataMapEntry: |
|||
{| class="wikitable" |
|||
|- |
|||
! Offset |
|||
! Size |
|||
! Type |
|||
! Name |
|||
! Value |
|||
|- |
|||
| 0x00 |
|||
| 0x08 |
| 0x08 |
||
| u64 |
|||
| NextPartition |
|||
| FileIndex |
|||
| Offset to next partition (in sectors) |
|||
| PureFsData block(sector) index in the data table |
|||
|- |
|- |
||
| |
| 0x08 |
||
| |
| 0x08 |
||
| u8[8] |
|||
| Reserved |
| Reserved |
||
| Reserved for future use |
| Reserved for future use |
||
|- |
|||
|} |
|} |
||
'''Attributes:''' |
|||
=== PureFsFileTable === |
|||
* '''SYSTEM'''(0x01) - partition required for the file system to function |
|||
Contains PureFsFile blocks.<br/> |
|||
* '''BOOTABLE'''(0x02) - the partition contains a program that can be loaded by the bootloader |
|||
PureFsFile: |
|||
* '''HIDDEN'''(0x04) |
|||
{| class="wikitable" |
|||
* '''READONLY'''(0x08) |
|||
* '''WRITEONLY'''(0x10) |
|||
'''NextPartition:''' if this is the last partition, this field is 0 |
|||
=== PureFsFile === |
|||
Contains information about file. |
|||
{| {{wikitable}} |
|||
|- |
|- |
||
! Offset |
! Offset |
||
! Size |
! Size |
||
! Type |
|||
! Name |
! Name |
||
! Value |
! Value |
||
|- |
|- |
||
| 0x00 |
| 0x00 |
||
| 0x100 |
| 0x100 |
||
| char[255+1] |
|||
| Name |
| Name |
||
| File name (ASCII) |
| File name (ASCII) (zero-terminated) |
||
|- |
|- |
||
| 0x100 |
| 0x100 |
||
| 0x08 |
| 0x08 |
||
| u64 |
|||
| Size |
|||
| Original file size |
|||
|- |
|||
| 0x108 |
|||
| 0x04 |
|||
| u32 |
|||
| Attributes |
| Attributes |
||
| File attributes |
| File attributes |
||
|- |
|- |
||
| |
| 0x10C |
||
| 0x08 |
| 0x08 |
||
| u64 |
|||
| NumBlocks |
|||
| ParentIndex |
|||
| Number of data blocks(`PureFsData`) of the file |
|||
| Index of the PureFsFile block(sector) of the parent directory in the file table |
|||
|- |
|- |
||
| |
| 0x114 |
||
| 0x08 |
| 0x08 |
||
| u64 |
|||
| OriginalSize |
|||
| DataIndex |
|||
| Original file data size |
|||
| Index of the PureFsData block(sector) in the data table |
|||
|- |
|||
| 0x118 |
|||
| 0x08 |
|||
| FirstBlock |
|||
| Offset to first data block(`PureFsData`) (in sectors) |
|||
|- |
|||
| 0x120 |
|||
| 0x04 |
|||
| PathHash |
|||
| Murmur3 32-bit hash of the file path on the partition |
|||
|- |
|||
| 0x124 |
|||
| 0x04 |
|||
| ParentHash |
|||
| Murmur3 32-bit hash of the path to the file's parent directory |
|||
|- |
|- |
||
| |
| 0x11C |
||
| |
| 0xE4 |
||
| u8[228] |
|||
| Reserved |
| Reserved |
||
| Reserved for future use |
| Reserved for future use |
||
|- |
|||
|} |
|} |
||
'''Attributes:''' |
|||
* '''SYSTEM'''(0x01) - file required for the file system to function |
|||
* '''EXECUTABLE'''(0x02) - it is possible to run the file as a program |
|||
* '''HIDDEN'''(0x04) |
|||
* '''READONLY'''(0x08) |
|||
* '''WRITEONLY'''(0x10) |
|||
* '''DIRECTORY'''(0x20) - marks that it is a directory and not a file |
|||
'''OriginalSize:''' if the file is empty or it is a directory, it is equal to 0<br> |
|||
'''FirstBlock:''' if the file is empty or it is a directory, it is equal to 0 |
|||
Attributes: |
|||
=== PureFsData === |
|||
*'''EXECUTABLE'''(0x01) - marks the file as a program that can be executed by the OS. |
|||
Contains one of the file's data parts. |
|||
*'''READABLE'''(0x02) |
|||
{| {{wikitable}} |
|||
*'''WRITEABLE'''(0x04) |
|||
=== PureFsDataTable === |
|||
Contains PureFsData blocks.<br/> |
|||
PureFsData: |
|||
{| class="wikitable" |
|||
|- |
|- |
||
! Offset |
! Offset |
||
! Size |
! Size |
||
! Type |
|||
! Name |
! Name |
||
! Value |
! Value |
||
|- |
|- |
||
| 0x00 |
| 0x00 |
||
| 0x1F8 |
| 0x1F8 |
||
| u8[504] |
|||
| Data |
| Data |
||
| |
| Part of the file data |
||
|- |
|- |
||
| 0x1F8 |
| 0x1F8 |
||
| 0x08 |
| 0x08 |
||
| u64 |
|||
| NextData |
|||
| NextIndex |
|||
| Offset to next data block(`PureFsData`) (in sectors) |
|||
| Index of the next data block(sector) (0 if last) |
|||
|- |
|||
|} |
|} |
||
'''NextData:''' if this is the last block of data, this field is 0 |
|||
== Implementation of some functions == |
|||
purefs.h: |
|||
<source lang="c">#pragma once |
|||
#ifndef PUREFS_H |
|||
#define PUREFS_H |
|||
#include <stdint.h> |
|||
#include <string.h> |
|||
typedef int8_t i8; |
|||
typedef int16_t i16; |
|||
typedef int32_t i32; |
|||
typedef int64_t i64; |
|||
typedef uint8_t u8; |
|||
typedef uint16_t u16; |
|||
typedef uint32_t u32; |
|||
typedef uint64_t u64; |
|||
#pragma pack(push, 1) |
|||
#define PUREFS_SIGNATURE "->PureFS" |
|||
#define PUREFS_V1_1_0 0x010100 |
|||
#define PUREFS_SYSID 0x15 |
|||
#define PUREFS_MURMUR3_SEED 0x4E53544B |
|||
typedef struct _PureFsHeader { |
|||
i8 Signature[8]; |
|||
u32 Version; |
|||
u64 FirstPartition; |
|||
u64 NumPartitions; |
|||
u8 Checksum; |
|||
u8 Reserved[0x1E3]; |
|||
} PureFsHeader; |
|||
#define PUREFS_PARTITION_ATR_SYSTEM 0x01 |
|||
#define PUREFS_PARTITION_ATR_BOOTABLE 0x02 |
|||
#define PUREFS_PARTITION_ATR_HIDDEN 0x04 |
|||
#define PUREFS_PARTITION_ATR_READONLY 0x08 |
|||
#define PUREFS_PARTITION_ATR_WRITEONLY 0x10 |
|||
typedef struct _PureFsPartitionHeader { |
|||
i8 Name[64]; |
|||
u64 Attributes; |
|||
u64 NumBlocks; |
|||
u64 NumFiles; |
|||
u64 FirstFile; |
|||
u64 LastFile; |
|||
u64 FirstData; |
|||
u64 LastData; |
|||
u64 NextPartition; |
|||
u8 Reserved[0x180]; |
|||
} PureFsPartitionHeader; |
|||
#define PUREFS_FILE_ATR_SYSTEM 0x01 |
|||
#define PUREFS_FILE_ATR_EXECUTABLE 0x02 |
|||
#define PUREFS_FILE_ATR_HIDDEN 0x04 |
|||
#define PUREFS_FILE_ATR_READONLY 0x08 |
|||
#define PUREFS_FILE_ATR_WRITEONLY 0x10 |
|||
#define PUREFS_FILE_ATR_DIRECTORY 0x20 |
|||
typedef struct _PureFsFile { |
|||
i8 Name[256]; |
|||
u64 Attributes; |
|||
u64 NumBlocks; |
|||
u64 OriginalSize; |
|||
u64 FirstBlock; |
|||
u32 PathHash; |
|||
u32 ParentHash; |
|||
u8 Reserved[0xD8]; |
|||
} PureFsFile; |
|||
typedef struct _PureFsData { |
|||
u8 Data[504]; |
|||
u64 NextData; |
|||
} PureFsData; |
|||
#pragma pack(pop) |
|||
extern size_t ReadSector(void *disk, u64 lba, u8 *buf); |
|||
extern u32 murmur3_32(u8 *key, size_t len, u32 seed); |
|||
size_t PureFsCheckHeader(PureFsHeader *h); |
|||
size_t PureFsReadHeader(void *disk, PureFsHeader *h); |
|||
size_t PureFsReadPartitionHeader(void *disk, const char *name, PureFsHeader *fsh, PureFsPartitionHeader *ph); |
|||
size_t PureFsReadFile(void *disk, const char *path, PureFsHeader *h, PureFsFile *buf1, u8 *buf2); |
|||
#endif |
|||
</source> |
|||
purefs.c: |
|||
<source lang="c"> |
|||
#include <purefs.h> |
|||
// Returns: 0 - invalid PureFS header, 1 - valid |
|||
size_t PureFsCheckHeader(PureFsHeader *h) { |
|||
u8 csum; |
|||
u8 i; |
|||
if (!strcmp(h->Signature, PUREFS_SIGNATURE) || h->Version != PUREFS_V1_1_0) return 0; |
|||
csum = 0; |
|||
for (i = 0; i < 0x1D; ++i) csum == ((u8*)h)[i]; |
|||
return !csum; |
|||
} |
|||
// Returns LBA of the sector with PureFsHeader or 0 |
|||
size_t PureFsReadHeader(void *disk, PureFsHeader *h) { |
|||
u8 MBR[512]; |
|||
size_t off; |
|||
size_t i; |
|||
u64 lba; |
|||
if (!h || !ReadSector(disk, 0, &MBR[0])) return 0; |
|||
// Finding a PureFS entry in the MBR partition table |
|||
lba = 0; |
|||
off = 440 + 4 + 2; |
|||
for (i = 0; i < 4; ++i) { |
|||
// We check that the partition is active and its ID is PureFS(0x15) |
|||
if (*((u8*)off) & 0x80 && *((u8*)(off + 4)) == PUREFS_SYSID) { |
|||
lba = (u64)*((u32*)(off + 8)); |
|||
if (lba) break; |
|||
} |
|||
} |
|||
if (!lba || !ReadSector(disk, lba, h) || !PureFsCheckHeader(h)) return 0; |
|||
return lba; |
|||
} |
|||
// Returns LBA of the sector with PureFsPartitionHeader or 0 |
|||
size_t PureFsReadPartitionHeader(void *disk, const char *name, PureFsHeader *fsh, PureFsPartitionHeader *ph) { |
|||
u64 lba; |
|||
if (!fsh->FirstPartition || !fsh->NumPartitions) return 0; |
|||
lba = (u64)fsh->FirstPartition; |
|||
do { |
|||
if (!ReadSector(disk, lba, ph)) continue; |
|||
if (!strcmp(ph->Name, name)) return lba; |
|||
lba = ph->NextPartition; |
|||
} while (ph->NextPartition); |
|||
return 0; |
|||
} |
|||
// Returns LBA of the sector with PureFsFile or 0 |
|||
size_t PureFsReadFile(void *disk, const char *path, PureFsHeader *h, PureFsFile *buf1, u8 *buf2) { |
|||
PureFsPartitionHeader ph; |
|||
char *separator; |
|||
char tmp[512]; |
|||
PureFsFile f; |
|||
size_t found; |
|||
size_t len; |
|||
u32 hash; |
|||
u64 lba; |
|||
u64 i; |
|||
u64 j; |
|||
if (!h || !h->FirstPartition || !h->NumPartitions) return 0; |
|||
// Get file path hash |
|||
hash = murmur3_32(path, strlen(path), PUREFS_MURMUR3_SEED); |
|||
while (*path == '/') ++path; |
|||
separator = strchr(path, '/'); |
|||
if (!separator) return 0; |
|||
len = (size_t)separator - (size_t)path; |
|||
memcpy(tmp, path, len); |
|||
tmp[len] = 0; |
|||
// Looking for a partition by name |
|||
found = 0; |
|||
lba = (u64)h->FirstPartition; |
|||
do { |
|||
if (!ReadSector(disk, lba, &ph)) continue; |
|||
if (!strcmp(ph.Name, tmp)) { |
|||
found = 1; |
|||
break; |
|||
} |
|||
lba = ph.NextPartition; |
|||
} while (ph.NextPartition); |
|||
if (!found || !ph.NumBlocks || !ph.NumFiles || !ph.FirstFile) return 0; |
|||
// Looking for file |
|||
found = 0; |
|||
lba += ph.FirstFile; |
|||
for (i = 0; i < ph.NumFiles; ++i) { |
|||
if (!ReadSector(disk, lba, &f)) continue; |
|||
if (f.PathHash == hash) { |
|||
found = 1; |
|||
break; |
|||
} |
|||
++lba; |
|||
} |
|||
if (!found) return 0; |
|||
// Copy PureFsFile and read data as needed |
|||
if (buf1) memcpy(buf1, &f, sizeof(PureFsFile)); |
|||
if (f.FirstBlock && buf2) { |
|||
len = f.OriginalSize; |
|||
j = lba + f.FirstBlock; |
|||
for (i = 0; i < f.NumBlocks - 1; ++i) { |
|||
if (!ReadSector(disk, j, tmp) || !((PureFsData*)tmp)->NextData) return 0; |
|||
== FAQ == |
|||
memcpy(buf2, tmp, 504); |
|||
*How are directories stored? - Directories are the same as files, except that the PUREFS_FILE_ATR_DIRECTORY bit is set in PureFsFile::Attributes, and the data blocks(sectors) (PureFsData) contain the indexes of the files they contain. |
|||
buf2 = (u8*)((size_t)buf2 + 504); |
|||
*How are symbolic links stored? - Symbolic links differ from regular files only in that they have no data blocks, and the PureFsFile::DataIndex field contains the index of the file/directory in the PureFsFileTable table. |
|||
len -= 504; |
|||
*How are hash collisions handled? - For this purpose, the PathHash and ParentHash fields are provided in the PureFsFileMapEntry structure to minimize the risk of finding the wrong file. When the OS reads the PureFsFile structure, it must check that the file name matches the file being searched for. |
|||
++j; |
|||
} |
|||
== See Also == |
|||
if (!ReadSector(disk, j, tmp)) return 0; |
|||
[https://wiki.osdev.org/index.php?title=PureFS&oldid=28856 PureFS V1.1.0]<br/> |
|||
memcpy(buf2, tmp, len); |
|||
[https://en.wikipedia.org/wiki/MurmurHash#Algorithm Murmur v3 32-bit hash] |
|||
} |
|||
return lba; |
|||
} |
|||
</source> |
|||
== See also == |
|||
[https://en.wikipedia.org/wiki/MurmurHash#Algorithm murmur hash v3] |
|||
[[Category:Filesystems]] |
[[Category:Filesystems]] |
Latest revision as of 15:13, 29 May 2024
Filesystems |
---|
Virtual Filesystems |
Disk Filesystems |
CD/DVD Filesystems |
Network Filesystems |
Flash Filesystems |
Note: if you find a grammatical error in the article, please correct it (the author does not know English well, so there may be errors).
PureFS is a disk file system designed to simplify the interaction between the operating system and disks.
PureFS V1.2.0
Better than the previous version in terms of speed, but a bit more complicated.
PureFS V1.2.0 has a total of 6 main structures:
- PureFsHeader
- PureFsVolumeHeader
- PureFsFileMap
- PureFsDataMap
- PureFsFileTable
- PureFsDataTable
Advantages(+):
- Easy to implement.
- Easy to understand.
- Supports nested directories.
- Maximum available 2^64 - 1 sectors.
Disadvantages(-):
- It can be journalable, provided that the OS takes care of this task itself.
- The maximum length of the file name is 255 characters.
- The maximum number of volumes is 40.
- Does not support Unicode names.
- Takes up a lot of space.
Example Of Disk Space Allocation
Note: sector #1 is not the first sector on the disk, but the first sector of PureFS.
Partition with a single volume:
Sector # | Structure |
---|---|
1 | PureFS header |
2 | PureFS volume header |
3 | PureFS file map |
3+blocks/map | PureFS data map |
3+blocks/map*2 | PureFS file table |
3+blocks/map*2+32*blocks/map | PureFS data table |
Structures
PureFsHeader
Contains information about the file system.
Offset | Size | Type | Name | Value |
---|---|---|---|---|
0x00 | 0x08 | char[8] | Signature | `->PureFS` |
0x08 | 0x04 | u32 | Version | PureFS version number(1.2.0 = 0x010200) |
0x0C | 0x08 | u64 | NumVolumes | Number of PureFS volumes |
0x14 | 0x01 | u8 | Checksum | Complements byte sum of fields above to 0 |
0x15 | 0x0B | u8[11] | Reserved | Reserved for future use |
0x20 | 0x28*0x0C | PureFsVolumePtr[40] | Volumes | Pointers to PureFS volumes |
PureFsVolumePtr:
Offset | Size | Type | Name | Value |
---|---|---|---|---|
0x00 | 0x08 | u64 | Offset | Offset to PureFS volume (in sectors) |
0x08 | 0x04 | u32 | NameHash | Murmur v3 32-bit volume name hash |
PureFsVolumeHeader
Contains information about the PureFS volume.
Offset | Size | Type | Name | Value |
---|---|---|---|---|
0x00 | 0x37+0x01 | char[55+1] | Name | PureFS volume name (zero-terminated) |
0x38 | 0x08 | u64 | Attributes | PureFS volume attributes |
0x40 | 0x08 | u64 | BlocksPerMap | Maximum number of blocks(sectors) per map(FileMap/DataMap) |
0x48 | 0x08 | u64 | NumFiles | Current number of files |
0x50 | 0x08 | u64 | NumData | Current number of data blocks(sectors) |
0x58 | 0x1A8 | u8[424] | Reserved | Reserved for future use |
Attributes:
- BOOTABLE(0x01) - marks that there is a program (OS kernel, for example) on the partition that bootloader should load.
- READABLE(0x02)
- WRITEABLE(0x04)
PureFsFileMap
Consists of PureFsVolumeHeader::BlocksPerMap sectors. There are 32 PureFsFileMapEntry entries in each sector.
PureFsFileMapEntry:
Offset | Size | Type | Name | Value |
---|---|---|---|---|
0x00 | 0x08 | u64 | FileIndex | PureFsFile block(sector) index in the file table |
0x08 | 0x04 | u32 | PathHash |
Murmur v3 32-bit hash of file path on partition (without partition name!) |
0x0C | 0x04 | u32 | ParentHash | Murmur v3 32-bit hash of the path to the parent directory on the partition (without partition name!) |
PureFsDataMap
Consists of PureFsVolumeHeader::BlocksPerMap sectors. There are 32 PureFsDataMapEntry entries in each sector.
PureFsDataMapEntry:
Offset | Size | Type | Name | Value |
---|---|---|---|---|
0x00 | 0x08 | u64 | FileIndex | PureFsData block(sector) index in the data table |
0x08 | 0x08 | u8[8] | Reserved | Reserved for future use |
PureFsFileTable
Contains PureFsFile blocks.
PureFsFile:
Offset | Size | Type | Name | Value |
---|---|---|---|---|
0x00 | 0x100 | char[255+1] | Name | File name (ASCII) (zero-terminated) |
0x100 | 0x08 | u64 | Size | Original file size |
0x108 | 0x04 | u32 | Attributes | File attributes |
0x10C | 0x08 | u64 | ParentIndex | Index of the PureFsFile block(sector) of the parent directory in the file table |
0x114 | 0x08 | u64 | DataIndex | Index of the PureFsData block(sector) in the data table |
0x11C | 0xE4 | u8[228] | Reserved | Reserved for future use |
Attributes:
- EXECUTABLE(0x01) - marks the file as a program that can be executed by the OS.
- READABLE(0x02)
- WRITEABLE(0x04)
PureFsDataTable
Contains PureFsData blocks.
PureFsData:
Offset | Size | Type | Name | Value |
---|---|---|---|---|
0x00 | 0x1F8 | u8[504] | Data | Part of the file data |
0x1F8 | 0x08 | u64 | NextIndex | Index of the next data block(sector) (0 if last) |
FAQ
- How are directories stored? - Directories are the same as files, except that the PUREFS_FILE_ATR_DIRECTORY bit is set in PureFsFile::Attributes, and the data blocks(sectors) (PureFsData) contain the indexes of the files they contain.
- How are symbolic links stored? - Symbolic links differ from regular files only in that they have no data blocks, and the PureFsFile::DataIndex field contains the index of the file/directory in the PureFsFileTable table.
- How are hash collisions handled? - For this purpose, the PathHash and ParentHash fields are provided in the PureFsFileMapEntry structure to minimize the risk of finding the wrong file. When the OS reads the PureFsFile structure, it must check that the file name matches the file being searched for.