#ifndef BFS_H
#define BFS_H
#include "bfs_endian.h"
#include "system_dependencies.h"
#ifdef _BOOT_MODE
namespace BFS {
#endif
#ifndef _BOOT_MODE
extern fs_volume_ops gBFSVolumeOps;
extern fs_vnode_ops gBFSVnodeOps;
#endif
struct block_run {
int32 allocation_group;
uint16 start;
uint16 length;
int32 AllocationGroup() const
{ return BFS_ENDIAN_TO_HOST_INT32(allocation_group); }
uint16 Start() const { return BFS_ENDIAN_TO_HOST_INT16(start); }
uint16 Length() const { return BFS_ENDIAN_TO_HOST_INT16(length); }
inline bool operator==(const block_run &run) const;
inline bool operator!=(const block_run &run) const;
inline bool IsZero() const;
inline bool MergeableWith(block_run run) const;
inline void SetTo(int32 group, uint16 start, uint16 length = 1);
inline static block_run Run(int32 group, uint16 start, uint16 length = 1);
} _PACKED;
typedef block_run inode_addr;
#define MAX_BLOCK_RUN_LENGTH 65535
#define BFS_DISK_NAME_LENGTH 32
struct 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 _reserved[8];
int32 pad_to_block[87];
int32 Magic1() const { return BFS_ENDIAN_TO_HOST_INT32(magic1); }
int32 Magic2() const { return BFS_ENDIAN_TO_HOST_INT32(magic2); }
int32 Magic3() const { return BFS_ENDIAN_TO_HOST_INT32(magic3); }
int32 ByteOrder() const { return BFS_ENDIAN_TO_HOST_INT32(fs_byte_order); }
uint32 BlockSize() const { return BFS_ENDIAN_TO_HOST_INT32(block_size); }
uint32 BlockShift() const { return BFS_ENDIAN_TO_HOST_INT32(block_shift); }
off_t NumBlocks() const { return BFS_ENDIAN_TO_HOST_INT64(num_blocks); }
off_t UsedBlocks() const { return BFS_ENDIAN_TO_HOST_INT64(used_blocks); }
int32 InodeSize() const { return BFS_ENDIAN_TO_HOST_INT32(inode_size); }
int32 BlocksPerAllocationGroup() const
{ return BFS_ENDIAN_TO_HOST_INT32(blocks_per_ag); }
int32 AllocationGroups() const { return BFS_ENDIAN_TO_HOST_INT32(num_ags); }
int32 AllocationGroupShift() const
{ return BFS_ENDIAN_TO_HOST_INT32(ag_shift); }
int32 Flags() const { return BFS_ENDIAN_TO_HOST_INT32(flags); }
off_t LogStart() const { return BFS_ENDIAN_TO_HOST_INT64(log_start); }
off_t LogEnd() const { return BFS_ENDIAN_TO_HOST_INT64(log_end); }
bool IsMagicValid() const;
bool IsValid() const;
void Initialize(const char *name, off_t numBlocks, uint32 blockSize);
} _PACKED;
#define SUPER_BLOCK_FS_LENDIAN 'BIGE'
#define SUPER_BLOCK_MAGIC1 'BFS1'
#define SUPER_BLOCK_MAGIC2 0xdd121031
#define SUPER_BLOCK_MAGIC3 0x15b6830e
#define SUPER_BLOCK_DISK_CLEAN 'CLEN'
#define SUPER_BLOCK_DISK_DIRTY 'DIRT'
#define NUM_DIRECT_BLOCKS 12
struct 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;
off_t MaxDirectRange() const
{ return BFS_ENDIAN_TO_HOST_INT64(max_direct_range); }
off_t MaxIndirectRange() const
{ return BFS_ENDIAN_TO_HOST_INT64(max_indirect_range); }
off_t MaxDoubleIndirectRange() const
{ return BFS_ENDIAN_TO_HOST_INT64(max_double_indirect_range); }
off_t Size() const
{ return BFS_ENDIAN_TO_HOST_INT64(size); }
} _PACKED;
#define NUM_ARRAY_BLOCKS 4
#define DOUBLE_INDIRECT_ARRAY_SIZE 4096
struct bfs_inode;
struct small_data {
uint32 type;
uint16 name_size;
uint16 data_size;
char name[0];
uint32 Type() const
{ return BFS_ENDIAN_TO_HOST_INT32(type); }
uint16 NameSize() const
{ return BFS_ENDIAN_TO_HOST_INT16(
name_size); }
uint16 DataSize() const
{ return BFS_ENDIAN_TO_HOST_INT16(
data_size); }
inline char* Name() const;
inline uint8* Data() const;
inline uint32 Size() const;
inline small_data* Next() const;
inline bool IsLast(const bfs_inode* inode) const;
} _PACKED;
#define FILE_NAME_TYPE 'CSTR'
#define FILE_NAME_NAME 0x13
#define FILE_NAME_NAME_LENGTH 1
#define MAX_INDEX_KEY_LENGTH 255
class Volume;
#define SHORT_SYMLINK_NAME_LENGTH 144
#define INODE_MAGIC1 0x3bbe0ad9
#define INODE_FILE_NAME_LENGTH 256
#define INODE_TIME_SHIFT 16
#define INODE_TIME_MASK 0xfff0
inline uint32 unique_from_nsec(uint32 time);
struct 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 {
data_stream data;
char short_symlink[SHORT_SYMLINK_NAME_LENGTH];
};
bigtime_t status_change_time;
int32 pad[2];
small_data small_data_start[0];
int32 Magic1() const { return BFS_ENDIAN_TO_HOST_INT32(magic1); }
int32 UserID() const { return BFS_ENDIAN_TO_HOST_INT32(uid); }
int32 GroupID() const { return BFS_ENDIAN_TO_HOST_INT32(gid); }
int32 Mode() const { return BFS_ENDIAN_TO_HOST_INT32(mode); }
int32 Flags() const { return BFS_ENDIAN_TO_HOST_INT32(flags); }
int32 Type() const { return BFS_ENDIAN_TO_HOST_INT32(type); }
int32 InodeSize() const { return BFS_ENDIAN_TO_HOST_INT32(inode_size); }
int64 LastModifiedTime() const
{ return BFS_ENDIAN_TO_HOST_INT64(last_modified_time); }
int64 CreateTime() const
{ return BFS_ENDIAN_TO_HOST_INT64(create_time); }
int64 StatusChangeTime() const
{ return BFS_ENDIAN_TO_HOST_INT64(status_change_time); }
small_data* SmallDataStart() { return small_data_start; }
status_t InitCheck(Volume* volume) const;
static int64 ToInode(bigtime_t time)
{ return ((time / 1000000) << INODE_TIME_SHIFT)
+ unique_from_nsec((time % 1000000) * 1000); }
static int64 ToInode(const timespec& tv)
{ return ((int64)tv.tv_sec << INODE_TIME_SHIFT)
+ unique_from_nsec(tv.tv_nsec); }
static time_t ToSecs(int64 time)
{ return time >> INODE_TIME_SHIFT; }
static uint32 ToNsecs(int64 time) {
if ((time & 0xF000) == 0xF000)
return 0;
return (time & INODE_TIME_MASK) << 14;
}
} _PACKED;
enum inode_flags {
INODE_IN_USE = 0x00000001,
INODE_ATTR_INODE = 0x00000004,
INODE_LOGGED = 0x00000008,
INODE_DELETED = 0x00000010,
INODE_NOT_READY = 0x00000020,
INODE_LONG_SYMLINK = 0x00000040,
INODE_PERMANENT_FLAGS = 0x0000ffff,
INODE_WAS_WRITTEN = 0x00020000,
INODE_IN_TRANSACTION = 0x00040000,
INODE_DONT_FREE_SPACE = 0x00080000
};
struct file_cookie {
bigtime_t last_notification;
off_t last_size;
int open_mode;
};
#define BFS_OPEN_MODE_USER_MASK 0x7fffffff
#define BFS_OPEN_MODE_CHECKING 0x80000000
#define INODE_NOTIFICATION_INTERVAL 1000000LL
inline uint32
unique_from_nsec(uint32 time)
{
static vint32 number;
if (time != 0)
return (((time + 16383) >> 14) & INODE_TIME_MASK) | (++number & 0xf);
return (++number & 0xfff) | 0xf000;
}
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 bool
block_run::MergeableWith(block_run run) const
{
return allocation_group == run.allocation_group
&& Start() + Length() == run.Start()
&& (uint32)Length() + run.Length() <= MAX_BLOCK_RUN_LENGTH;
}
inline void
block_run::SetTo(int32 _group,uint16 _start,uint16 _length)
{
allocation_group = HOST_ENDIAN_TO_BFS_INT32(_group);
start = HOST_ENDIAN_TO_BFS_INT16(_start);
length = HOST_ENDIAN_TO_BFS_INT16(_length);
}
inline block_run
block_run::Run(int32 group, uint16 start, uint16 length)
{
block_run run;
run.allocation_group = HOST_ENDIAN_TO_BFS_INT32(group);
run.start = HOST_ENDIAN_TO_BFS_INT16(start);
run.length = HOST_ENDIAN_TO_BFS_INT16(length);
return run;
}
inline char*
small_data::Name() const
{
return const_cast<char*>(name);
}
inline uint8*
small_data::Data() const
{
return (uint8*)Name() + NameSize() + 3;
}
inline uint32
small_data::Size() const
{
return sizeof(small_data) + NameSize() + 3 + DataSize() + 1;
}
inline small_data*
small_data::Next() const
{
return (small_data*)((uint8*)this + Size());
}
inline bool
small_data::IsLast(const bfs_inode* inode) const
{
return (addr_t)this > (addr_t)inode
+ inode->InodeSize() - sizeof(small_data) || name_size == 0;
}
#ifdef _BOOT_MODE
}
#endif
#endif