*
* Initial version by Axel DΓΆrfler, axeld@pinc-software.de
* Parts of this code is based on work previously done by Marcus Overhagen
*
* Copyright 2001-2025 pinc Software. All Rights Reserved.
* This file may be used under the terms of the MIT License.
*/
#ifndef BFS_H
#define BFS_H
#include <SupportDefs.h>
#define BFS_S_ATTR_DIR 01000000000 /* attribute directory */
#define BFS_S_ATTR 02000000000 /* attribute */
#define BFS_S_INDEX_DIR 04000000000 /* index (or index directory) */
#define BFS_S_STR_INDEX 00100000000 /* string index */
#define BFS_S_INT_INDEX 00200000000 /* int32 index */
#define BFS_S_UINT_INDEX 00400000000 /* uint32 index */
#define BFS_S_LONG_LONG_INDEX 00010000000 /* int64 index */
#define BFS_S_ULONG_LONG_INDEX 00020000000 /* uint64 index */
#define BFS_S_FLOAT_INDEX 00040000000 /* float index */
#define BFS_S_DOUBLE_INDEX 00001000000 /* double index */
#define BFS_S_IFMT 00000170000 /* type of file */
#define BFS_S_IFLNK 00000120000 /* symbolic link */
#define BFS_S_IFREG 00000100000 /* regular */
#define BFS_S_IFDIR 00000040000 /* directory */
#define BFS_S_ISREG(mode) (((mode) & BFS_S_IFMT) == BFS_S_IFREG)
#define BFS_S_ISLNK(mode) (((mode) & BFS_S_IFMT) == BFS_S_IFLNK)
#define BFS_S_ISDIR(mode) (((mode) & BFS_S_IFMT) == BFS_S_IFDIR)
#define BFS_S_ISINDEX(mode) (((mode) & BFS_S_INDEX_DIR) == BFS_S_INDEX_DIR)
struct __attribute__((packed)) block_run {
int32 allocation_group;
uint16 start;
uint16 length;
inline bool operator==(const block_run &run) const;
inline bool operator!=(const block_run &run) const;
inline bool IsZero() const;
inline void SetTo(int32 group, uint16 start, uint16 length = 1);
inline static block_run Run(int32 group, uint16 start, uint16 length = 1);
};
typedef block_run inode_addr;
#define BFS_DISK_NAME_LENGTH 32
struct __attribute__((packed)) disk_super_block
{
char name[BFS_DISK_NAME_LENGTH];
int32 magic1;
int32 fs_byte_order;
uint32 block_size;
uint32 block_shift;
int64 num_blocks;
int64 used_blocks;
int32 inode_size;
int32 magic2;
int32 blocks_per_ag;
int32 ag_shift;
int32 num_ags;
int32 flags;
block_run log_blocks;
int64 log_start;
int64 log_end;
int32 magic3;
inode_addr root_dir;
inode_addr indices;
int32 pad[8];
};
#define SUPER_BLOCK_FS_LENDIAN 'BIGE' /* BIGE */
#define SUPER_BLOCK_MAGIC1 'BFS1' /* BFS1 */
#define SUPER_BLOCK_MAGIC2 0xdd121031
#define SUPER_BLOCK_MAGIC3 0x15b6830e
#define SUPER_BLOCK_CLEAN 'CLEN' /* CLEN */
#define SUPER_BLOCK_DIRTY 'DIRT' /* DIRT */
#define NUM_DIRECT_BLOCKS 12
struct __attribute__((packed)) data_stream
{
block_run direct[NUM_DIRECT_BLOCKS];
int64 max_direct_range;
block_run indirect;
int64 max_indirect_range;
block_run double_indirect;
int64 max_double_indirect_range;
int64 size;
};
struct bfs_inode;
struct __attribute__((packed)) small_data
{
uint32 type;
uint16 name_size;
uint16 data_size;
char name[0];
inline char *Name();
inline uint8 *Data();
inline small_data *Next();
inline bool IsLast(bfs_inode *inode);
};
#define FILE_NAME_TYPE 'CSTR'
#define FILE_NAME_NAME 0x13
#define FILE_NAME_NAME_LENGTH 1
#define SHORT_SYMLINK_NAME_LENGTH 144 // length incl. terminating '\0'
struct __attribute__((packed)) bfs_inode
{
int32 magic1;
inode_addr inode_num;
int32 uid;
int32 gid;
int32 mode;
int32 flags;
int64 create_time;
int64 last_modified_time;
inode_addr parent;
inode_addr attributes;
uint32 type;
int32 inode_size;
uint32 etc;
union __attribute__((packed)) {
data_stream data;
char short_symlink[SHORT_SYMLINK_NAME_LENGTH];
};
int32 pad[4];
small_data small_data_start[0];
};
#define INODE_MAGIC1 0x3bbe0ad9
#define INODE_TIME_SHIFT 16
#define INODE_FILE_NAME_LENGTH 256
enum inode_flags
{
INODE_IN_USE = 0x00000001,
INODE_ATTR_INODE = 0x00000004,
INODE_LOGGED = 0x00000008,
INODE_DELETED = 0x00000010,
INODE_EMPTY = 0x00000020,
INODE_LONG_SYMLINK = 0x00000040,
INODE_PERMANENT_FLAGS = 0x0000ffff,
INODE_NO_CACHE = 0x00010000,
INODE_WAS_WRITTEN = 0x00020000,
INODE_NO_TRANSACTION = 0x00040000
};
inline int32
divide_roundup(int32 num,int32 divisor)
{
return (num + divisor - 1) / divisor;
}
inline int64
divide_roundup(int64 num,int32 divisor)
{
return (num + divisor - 1) / divisor;
}
inline int
get_shift(uint64 i)
{
int c;
c = 0;
while (i > 1) {
i >>= 1;
c++;
}
return c;
}
inline int32
round_up(uint32 data)
{
return (data + sizeof(off_t) - 1) & ~(sizeof(off_t) - 1);
}
inline bool block_run::operator==(const block_run &run) const
{
return allocation_group == run.allocation_group
&& start == run.start
&& length == run.length;
}
inline bool block_run::operator!=(const block_run &run) const
{
return allocation_group != run.allocation_group
|| start != run.start
|| length != run.length;
}
inline bool block_run::IsZero() const
{
return allocation_group == 0 && start == 0 && length == 0;
}
inline void block_run::SetTo(int32 _group,uint16 _start,uint16 _length)
{
allocation_group = _group;
start = _start;
length = _length;
}
inline block_run block_run::Run(int32 group, uint16 start, uint16 length)
{
block_run run;
run.allocation_group = group;
run.start = start;
run.length = length;
return run;
}
inline char *small_data::Name()
{
return name;
}
inline uint8 *small_data::Data()
{
return (uint8 *)name + name_size + 3;
}
inline small_data *small_data::Next()
{
return (small_data *)((uint8 *)(this + 1) + name_size + 3 + data_size + 1);
}
inline bool small_data::IsLast(bfs_inode *inode)
{
return (addr_t)this > (addr_t)inode + inode->inode_size - sizeof(small_data)
|| name_size == 0;
}
#endif