xfs: An attempt at reading shortform dir

This patch gets read_dir, lookup and few others to work. Entries cannot
be listed yet except the root.

Change-Id: Ic4b7b61a794a1b75849e45777a383b3315b15aa8
Reviewed-on: https://review.haiku-os.org/c/haiku/+/2915
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
CruxBox
2020-07-03 08:13:27 +00:00
committed by Adrien Destugues
parent 66f0993a1b
commit 7e1b5cf809
16 changed files with 760 additions and 314 deletions
@@ -1,7 +1,8 @@
/*
* Copyright 2020, Shubham Bhagat, [email protected]
* All rights reserved. Distributed under the terms of the MIT License.
*/
* Copyright 2020, Shubham Bhagat, [email protected]
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "BPlusTree.h"
+18 -21
View File
@@ -1,30 +1,28 @@
/*
* Copyright 2020, Shubham Bhagat, [email protected]
* All rights reserved. Distributed under the terms of the MIT License.
*/
* Copyright 2020, Shubham Bhagat, [email protected]
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef _BPLUS_TREE_H_
#define _BPLUS_TREE_H_
#include "system_dependencies.h"
/* Allocation B+ Tree Format */
#define XFS_ABTB_MAGICNUM 0x41425442 // For block offset B+Tree
#define XFS_ABTC_MAGICNUM 0x41425443 // For block count B+ Tree
/* Header for Short Format btree */
#define XFS_ABTB_MAGICNUM 0x41425442
// For block offset B+Tree
#define XFS_ABTC_MAGICNUM 0x41425443
// For block count B+ Tree
#define XFS_BTREE_SBLOCK_SIZE 18
/* Header for Long Format btree */
// Header for Short Format btree
#define XFS_BTREE_LBLOCK_SIZE 24
// Header for Long Format btree
/*
* Headers are the "nodes" really and are called "blocks". The records, keys and
* pts are calculated using helpers
*/
* Headers are the "nodes" really and are called "blocks". The records, keys
* and ptrs are calculated using helpers
*/
struct bplustree_short_block {
void SwapEndian();
@@ -93,11 +91,11 @@ typedef struct xfs_alloc_rec {
} xfs_alloc_rec_t, xfs_alloc_key_t;
// Swap Endians while returning itself
typedef uint32 xfs_alloc_ptr_t; // Node pointers, AG relative block pointer
typedef uint32 xfs_alloc_ptr_t;
// Node pointers, AG relative block pointer
#define ALLOC_FLAG 0x1
#define LONG_BLOCK_FLAG 0x1
#define SHORT_BLOCK_FLAG 0x2
@@ -118,7 +116,7 @@ union btree_rec {
class BPlusTree {
public:
public:
uint32 BlockSize();
int RecordSize();
int MaxRecords(bool leaf);
@@ -129,7 +127,7 @@ class BPlusTree {
int KeyOffset(int pos); // get the pos'th key
int PtrOffset(int pos); // get the pos'th ptr
private:
private:
Volume* fVolume;
xfs_agnumber_t fAgnumber;
btree_ptr* fRoot;
@@ -140,4 +138,3 @@ class BPlusTree {
#endif
+1 -1
View File
@@ -5,7 +5,7 @@
#ifndef _DEBUG_H_
#define _DEBUG_H_
#define TRACE_XFS
// #define TRACE_XFS
#ifdef TRACE_XFS
#define TRACE(x...) dprintf("\n\33[34mxfs:\33[0m " x)
#else
@@ -0,0 +1,99 @@
/*
* Copyright 2020, Shubham Bhagat, [email protected]
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "Directory.h"
DirectoryIterator::DirectoryIterator(Inode* inode)
{
fInode = inode;
fShortDir = NULL;
}
DirectoryIterator::~DirectoryIterator()
{
delete fShortDir;
}
status_t
DirectoryIterator::Init()
{
if (fInode->Format() == XFS_DINODE_FMT_LOCAL)
{
fShortDir = new(std::nothrow) ShortDirectory(fInode);
if (fShortDir == NULL)
return B_NO_MEMORY;
return B_OK;
}
/* Return B_OK so even if the shortform directory has an extent directory
* we can atleast still list the shortform directory
*/
//TODO: Reading from extent based directories
if (fInode->Format() == XFS_DINODE_FMT_EXTENTS) {
TRACE("Iterator:GetNext: EXTENTS");
return B_OK;
}
//TODO: Reading from B+Trees based directories
if (fInode->Format() == XFS_DINODE_FMT_BTREE) {
TRACE("Iterator:GetNext: B+TREE");
return B_OK;
}
return B_BAD_VALUE;
}
status_t
DirectoryIterator::GetNext(char* name, size_t* length, xfs_ino_t* ino)
{
if (fInode->Format() == XFS_DINODE_FMT_LOCAL) {
status_t status = fShortDir->GetNext(name, length, ino);
return status;
}
//TODO: Reading from extent based directories
if (fInode->Format() == XFS_DINODE_FMT_EXTENTS) {
TRACE("Iterator:GetNext: EXTENTS");
return B_NOT_SUPPORTED;
}
//TODO: Reading from B+Trees based directories
if (fInode->Format() == XFS_DINODE_FMT_BTREE) {
TRACE("Iterator:GetNext: B+TREE");
return B_NOT_SUPPORTED;
}
// Only reaches here if Inode is a device or is corrupt.
return B_BAD_VALUE;
}
status_t
DirectoryIterator::Lookup(const char* name, size_t length, xfs_ino_t* ino)
{
if (fInode->Format() == XFS_DINODE_FMT_LOCAL) {
status_t status = fShortDir->Lookup(name, length, ino);
return status;
}
//TODO: Reading from extent based dirs
if (fInode->Format() == XFS_DINODE_FMT_EXTENTS) {
TRACE("Iterator:Lookup: EXTENTS");
return B_NOT_SUPPORTED;
}
//TODO: Reading from B+Tree based dirs
if (fInode->Format() == XFS_DINODE_FMT_BTREE) {
TRACE("Iterator:Lookup: B+TREE");
return B_NOT_SUPPORTED;
}
return B_BAD_VALUE;
}
@@ -0,0 +1,35 @@
/*
* Copyright 2020, Shubham Bhagat, [email protected]
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef _DIRECTORY_H_
#define _DIRECTORY_H_
#include "Inode.h"
#include "ShortDirectory.h"
/*
* This class should act as a layer between any kind of directory
* and the kernel interface
*/
class DirectoryIterator {
public:
DirectoryIterator(Inode* inode);
~DirectoryIterator();
status_t Init();
bool IsLocalDir() { return fInode->IsLocal(); }
status_t GetNext(char* name, size_t* length,
xfs_ino_t* ino);
status_t Lookup(const char* name, size_t length,
xfs_ino_t* id);
private:
Inode* fInode;
ShortDirectory* fShortDir;
// Short form Directory type
};
#endif
+49 -41
View File
@@ -1,13 +1,14 @@
/*
* Copyright 2020, Shubham Bhagat, [email protected]
* All rights reserved. Distributed under the terms of the MIT License.
*/
* Copyright 2020, Shubham Bhagat, [email protected]
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "Inode.h"
void
xfs_inode::SwapEndian()
xfs_inode_t::SwapEndian()
{
di_magic = B_BENDIAN_TO_HOST_INT16(di_magic);
di_mode = B_BENDIAN_TO_HOST_INT16(di_mode);
@@ -37,42 +38,42 @@ xfs_inode::SwapEndian()
xfs_rfsblock_t
xfs_inode::NoOfBlocks() const
xfs_inode_t::NoOfBlocks() const
{
return di_nblocks;
}
xfs_fsize_t
xfs_inode::Size() const
xfs_inode_t::Size() const
{
return di_size;
}
mode_t
xfs_inode::Mode()
xfs_inode_t::Mode() const
{
return di_mode;
}
uint32
xfs_inode::UserId()
xfs_inode_t::UserId() const
{
return di_uid;
}
uint32
xfs_inode::GroupId()
xfs_inode_t::GroupId() const
{
return di_gid;
}
void
xfs_inode::GetModificationTime(struct timespec& stamp)
xfs_inode_t::GetModificationTime(struct timespec& stamp)
{
stamp.tv_sec = di_mtime.t_sec;
stamp.tv_nsec = di_mtime.t_nsec;
@@ -80,7 +81,7 @@ xfs_inode::GetModificationTime(struct timespec& stamp)
void
xfs_inode::GetAccessTime(struct timespec& stamp)
xfs_inode_t::GetAccessTime(struct timespec& stamp)
{
stamp.tv_sec = di_atime.t_sec;
stamp.tv_nsec = di_atime.t_nsec;
@@ -88,7 +89,7 @@ xfs_inode::GetAccessTime(struct timespec& stamp)
void
xfs_inode::GetChangeTime(struct timespec& stamp)
xfs_inode_t::GetChangeTime(struct timespec& stamp)
{
stamp.tv_sec = di_ctime.t_sec;
stamp.tv_nsec = di_ctime.t_nsec;
@@ -96,51 +97,66 @@ xfs_inode::GetChangeTime(struct timespec& stamp)
uint32
xfs_inode::NLink()
xfs_inode_t::NLink() const
{
return di_nlink;
}
int8
xfs_inode::Version()
xfs_inode_t::Version() const
{
return di_version;
}
uint16
xfs_inode::Flags()
xfs_inode_t::Flags() const
{
return di_flags;
}
int8
xfs_inode::Format()
xfs_inode_t::Format() const
{
return di_format;
}
Inode::Inode(Volume* volume, xfs_ino_t id)
:
fVolume(volume),
fId(id)
{
fVolume = volume;
fId = id;
fNode = new(std::nothrow) xfs_inode_t;
uint16 inodeSize = volume->InodeSize();
}
status_t
Inode::Init()
{
fNode = new(std::nothrow) xfs_inode_t;
if (fNode == NULL)
return B_NO_MEMORY;
uint16 inodeSize = fVolume->InodeSize();
fBuffer = new(std::nothrow) char[inodeSize];
if (fBuffer == NULL)
return B_NO_MEMORY;
status_t status = GetFromDisk();
if (status == B_OK) {
status = InitCheck();
if (status) {
TRACE("Inode successfully read!");
if (fNode->di_magic == INODE_MAGIC) {
TRACE("Init(): Inode successfully read.\n");
status = B_OK;
} else {
TRACE("Inode wasn't read successfully!");
TRACE("Init(): Inode wasn't read successfully!\n");
status = B_BAD_VALUE;
}
}
return status;
}
@@ -149,29 +165,28 @@ Inode::GetFromDisk()
{
xfs_agnumber_t agNo = INO_TO_AGNO(fId, fVolume);
// Get the AG number from the inode
uint32 agInodeNo = INO_TO_AGINO(fId, fVolume->AgInodeBits());
uint32 agRelativeInodeNo = INO_TO_AGINO(fId, fVolume->AgInodeBits());
// AG relative ino #
xfs_agblock_t agBlock = INO_TO_AGBLOCK(agInodeNo, fVolume);
xfs_agblock_t agBlock = INO_TO_AGBLOCK(agRelativeInodeNo, fVolume);
// AG relative block number
xfs_off_t offset = INO_TO_OFFSET(fId, fVolume);
// Offset into the block
xfs_off_t offset = INO_TO_BLOCKOFFSET(fId, fVolume);
// Offset into the block1
uint32 len = fVolume->InodeSize();
// Inode len to read (size of inode)
int fd = fVolume->Device();
if (agNo > fVolume->AgCount()) {
ERROR("Inode::GetFromDisk : AG Number more than number of AGs");
return B_ENTRY_NOT_FOUND;
}
xfs_agblock_t agBlocks = fVolume->AgBlocks();
xfs_agblock_t numberOfBlocksInAg = fVolume->AgBlocks();
xfs_fsblock_t blockToRead =
FSB_TO_BB(fVolume->BlockLog(), ((uint64)(agNo * agBlocks) + agBlock));
xfs_fsblock_t blockToRead = FSBLOCKS_TO_BASICBLOCKS(fVolume->BlockLog(),
((uint64)(agNo * numberOfBlocksInAg) + agBlock));
xfs_daddr_t readPos = blockToRead*(BBLOCKSIZE) + offset;
xfs_daddr_t readPos = blockToRead*(BASICBLOCKSIZE) + offset;
if (read_pos(fd, readPos, fBuffer, len) != len) {
if (read_pos(fVolume->Device(), readPos, fBuffer, len) != len) {
ERROR("Inode::Inode(): IO Error");
return B_IO_ERROR;
}
@@ -183,13 +198,6 @@ Inode::GetFromDisk()
}
bool
Inode::InitCheck()
{
return fNode->di_magic == INODE_MAGIC;
}
Inode::~Inode()
{
delete fBuffer;
+128 -103
View File
@@ -1,22 +1,23 @@
/*
* Copyright 2020, Shubham Bhagat, [email protected]
* All rights reserved. Distributed under the terms of the MIT License.
*/
* Copyright 2020, Shubham Bhagat, [email protected]
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef _INODE_H_
#define _INODE_H_
#include "system_dependencies.h"
#include "Volume.h"
#include "xfs_types.h"
#define INODE_MAGIC 0x494e
#define INODE_CORE_SIZE 96 // For v4 FS
#define INODE_CORE_UNLINKED_SIZE 100 //For v4 FS
#define INODE_MINSIZE_LOG 8
#define INODE_MAXSIZE_LOG 11
#define INODE_CORE_SIZE 96
#define INODE_CORE_UNLINKED_SIZE 100
// Inode core but with unlinked pointer
#define DATA_FORK_OFFSET 0x64
// For v4 FS
#define INO_MASK(x) ((1ULL << (x)) - 1)
// Gets 2^x - 1
#define INO_TO_AGNO(id, volume) (xfs_agnumber_t)id >> (volume->AgInodeBits())
@@ -27,132 +28,156 @@
(id >> (volume->InodesPerBlkLog())) \
& (INO_MASK(volume->AgBlocksLog()))
// Gets the AG relative block number that contains inode
#define INO_TO_OFFSET(id, volume) (id & INO_MASK(volume->InodesPerBlkLog()))
#define INO_TO_BLOCKOFFSET(id, volume) (id & INO_MASK(volume->InodesPerBlkLog()))
// Gets the offset into the block from the inode number
#define DIR_DFORK_PTR(dir_ino_ptr) (char*) dir_ino_ptr + DATA_FORK_OFFSET
#define DIR_AFORK_PTR(dir_ino_ptr) \
(XFS_DFORK_PTR + \
((uint32)dir_ino_ptr->di_forkoff<<3))
#define DIR_AFORK_EXIST(dir_ino_ptr) dir_ino_ptr->di_forkoff!=0
typedef struct xfs_timestamp
{
struct xfs_timestamp_t {
int32 t_sec;
int32 t_nsec;
} xfs_timestamp_t;
};
typedef enum xfs_dinode_fmt
{
XFS_DINODE_FMT_DEV, // For devices
XFS_DINODE_FMT_LOCAL, // For Directories and links
XFS_DINODE_FMT_EXTENTS, // For large number of extents
XFS_DINODE_FMT_BTREE, // Extents and Directories
XFS_DINODE_FMT_UUID, // Not used
} xfs_dinode_fmt_t;
enum xfs_dinode_fmt_t {
XFS_DINODE_FMT_DEV,
// For devices
XFS_DINODE_FMT_LOCAL,
// For Directories and links
XFS_DINODE_FMT_EXTENTS,
// For large number of extents
XFS_DINODE_FMT_BTREE,
// Extents and Directories
XFS_DINODE_FMT_UUID,
// Not used
};
/*
The xfs_ino_t is the same for all types of inodes, the data and attribute
fork might be different and that is to be handled accordingly.
*/
typedef struct xfs_inode
{
void SwapEndian();
int8 Version(); //TODO
mode_t Mode();
void GetModificationTime(struct timespec& timestamp);
void GetChangeTime(struct timespec& timestamp);
void GetAccessTime(struct timespec& timestamp);
int8 Format(); // The format of the inode
xfs_fsize_t Size() const; // TODO
xfs_rfsblock_t NoOfBlocks() const;
uint32 NLink();
uint16 Flags();
uint32 UserId();
uint32 GroupId();
* The xfs_ino_t is the same for all types of inodes, the data and attribute
* fork might be different and that is to be handled accordingly.
*/
struct xfs_inode_t {
void SwapEndian();
int8 Version() const;
//TODO: Check
mode_t Mode() const;
void GetModificationTime(struct timespec&
timestamp);
void GetChangeTime(struct timespec& timestamp);
void GetAccessTime(struct timespec& timestamp);
int8 Format() const;
// The format of the inode
xfs_fsize_t Size() const;
xfs_rfsblock_t NoOfBlocks() const;
uint32 NLink() const;
uint16 Flags() const;
uint32 UserId() const;
uint32 GroupId() const;
uint16 di_magic;
uint16 di_mode; // uses standard S_Ixxx
int8 di_version; // 1 or 2
int8 di_format;
uint16 di_onlink;
uint32 di_uid;
uint32 di_gid;
uint32 di_nlink;
uint16 di_projid;
uint8 di_pad[8];
uint16 di_flushiter;
xfs_timestamp_t di_atime;
xfs_timestamp_t di_mtime;
xfs_timestamp_t di_ctime;
xfs_fsize_t di_size; // size in bytes or length if link
xfs_rfsblock_t di_nblocks; // blocks used including metadata
// extended attributes not included
xfs_extlen_t di_extsize; // extent size
xfs_extnum_t di_nextents; // number of data extents
xfs_aextnum_t di_anextents; // number of EA extents
uint8 di_forkoff; // decides where di_a starts
int8 di_aformat; // similar to di_format
uint32 di_dmevmask;
uint16 di_dmstate;
uint16 di_flags;
uint32 di_gen;
uint16 di_magic;
uint16 di_mode;
// uses standard S_Ixxx
int8 di_version;
//This either would be 1 or 2
int8 di_format;
uint16 di_onlink;
uint32 di_uid;
uint32 di_gid;
uint32 di_nlink;
uint16 di_projid;
uint8 di_pad[8];
uint16 di_flushiter;
xfs_timestamp_t di_atime;
xfs_timestamp_t di_mtime;
xfs_timestamp_t di_ctime;
xfs_fsize_t di_size;
// size in bytes or length if link
xfs_rfsblock_t di_nblocks;
// blocks used including metadata
// extended attributes not included
xfs_extlen_t di_extsize;
// extent size
xfs_extnum_t di_nextents;
// number of data extents
xfs_aextnum_t di_anextents;
// number of EA extents
uint8 di_forkoff;
// decides where di_a starts
int8 di_aformat;
// similar to di_format
uint32 di_dmevmask;
uint16 di_dmstate;
uint16 di_flags;
uint32 di_gen;
uint32 di_next_unlinked;
} xfs_inode_t;
uint32 di_next_unlinked;
};
class Inode
{
public:
Inode(Volume* volume, xfs_ino_t id);
~Inode();
bool InitCheck();
class Inode {
public:
Inode(Volume* volume, xfs_ino_t id);
~Inode();
status_t Init();
xfs_ino_t ID() const { return fId; }
xfs_ino_t ID() const { return fId; }
bool IsDirectory() const
{ return S_ISDIR(Mode()); }
bool IsDirectory() const
{ return S_ISDIR(Mode()); }
bool IsFile() const
{ return S_ISREG(Mode()); }
bool IsFile() const
{ return S_ISREG(Mode()); }
bool IsSymLink() const
{ return S_ISLNK(Mode()); }
bool IsSymLink() const
{ return S_ISLNK(Mode()); }
mode_t Mode() const { return fNode->Mode(); }
mode_t Mode() const { return fNode->Mode(); }
Volume* GetVolume() { return fVolume;}
Volume* GetVolume() { return fVolume;}
int8 Format() { return fNode->Format(); }
int8 Format() const { return fNode->Format(); }
bool IsLocal() { return Format() == XFS_DINODE_FMT_LOCAL; }
bool IsLocal() const
{ return
Format() == XFS_DINODE_FMT_LOCAL; }
uint32 NLink() { return fNode->NLink(); }
uint32 NLink() const { return fNode->NLink(); }
int8 Version() { return fNode->Version(); }
int8 Version() const { return fNode->Version(); }
xfs_fsize_t Size() const { return fNode->Size(); }
xfs_rfsblock_t NoOfBlocks() const
{ return fNode->NoOfBlocks(); }
xfs_rfsblock_t NoOfBlocks() const { return fNode->NoOfBlocks(); }
char* Buffer() { return fBuffer; }
int16 Flags() const { return fNode->Flags(); }
int16 Flags() const { return fNode->Flags(); }
void GetChangeTime(struct timespec& timestamp) const
{ fNode->GetChangeTime(timestamp); }
xfs_fsize_t Size() const { return fNode->Size(); }
void GetModificationTime(struct timespec& timestamp) const
{ fNode->GetModificationTime(timestamp); }
void GetChangeTime(struct timespec& timestamp) const
{ fNode->GetChangeTime(timestamp); }
void GetAccessTime(struct timespec& timestamp) const
{ fNode->GetAccessTime(timestamp); }
void GetModificationTime(struct timespec& timestamp)
const
{ fNode->GetModificationTime(timestamp); }
private:
uint32 UserId() { return fNode->UserId(); }
uint32 GroupId() { return fNode->GroupId(); }
void GetAccessTime(struct timespec& timestamp) const
{ fNode->GetAccessTime(timestamp); }
status_t GetFromDisk();
xfs_inode_t* fNode;
xfs_ino_t fId;
Volume* fVolume;
char* fBuffer; // Contains the disk inode in BE format
uint32 UserId() const { return fNode->UserId(); }
uint32 GroupId() const { return fNode->GroupId(); }
private:
status_t GetFromDisk();
xfs_inode_t* fNode;
xfs_ino_t fId;
Volume* fVolume;
char* fBuffer;
// Contains the disk inode in BE format
};
#endif
@@ -20,9 +20,12 @@ DEFINES += DEBUG_APP="\\\"xfs\\\"" ;
UseHeaders [ FDirName $(HAIKU_TOP) src libs uuid ] : true ;
local xfsSources =
DeviceOpener.cpp
Directory.cpp
Inode.cpp
kernel_cpp.cpp
kernel_interface.cpp
ShortDirectory.cpp
Volume.cpp
xfs.cpp
;
@@ -0,0 +1,84 @@
/*
* Copyright 2020, Shubham Bhagat, [email protected]
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "ShortDirectory.h"
ShortDirectory::ShortDirectory(Inode* inode)
:
fInode(inode),
fTrack(0)
{
memcpy(&fHeader,
DIR_DFORK_PTR(fInode->Buffer()), sizeof(xfs_dir2_sf_hdr_t));
}
ShortDirectory::~ShortDirectory()
{
}
xfs_ino_t
ShortDirectory::GetParentIno()
{
TRACE("GetParentIno: \n");
if (fHeader.i8count > 0)
return B_BENDIAN_TO_HOST_INT64(fHeader.parent.i8);
else
return B_BENDIAN_TO_HOST_INT32(fHeader.parent.i4);
}
status_t
ShortDirectory::Lookup(const char* name, size_t length, xfs_ino_t* ino)
{
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
xfs_ino_t rootIno = fInode->GetVolume()->Root();
if (strcmp(name, ".") == 0 || (rootIno == fInode->ID())) {
*ino = fInode->ID();
TRACE("ShortDirectory:Lookup: name: \".\" ino: (%d)\n", *ino);
return B_OK;
}
*ino = GetParentIno();
TRACE("Parent: (%d)\n", *ino);
return B_OK;
}
//TODO: Other entries
return B_NOT_SUPPORTED;
}
status_t
ShortDirectory::GetNext(char* name, size_t* length, xfs_ino_t* ino)
{
if (fTrack == 0) {
// Return '.'
if (*length < 2)
return B_BUFFER_OVERFLOW;
*length = 2;
strlcpy(name, ".", *length + 1);
*ino = fInode->ID();
fTrack = 1;
TRACE("ShortDirectory:GetNext: name: \".\" ino: (%d)\n", *ino);
return B_OK;
}
if (fTrack == 1) {
// Return '..'
if (*length < 3)
return B_BUFFER_OVERFLOW;
*length = 3;
strlcpy(name, "..", *length + 1);
*ino = GetParentIno();
fTrack = 2;
TRACE("ShortDirectory:GetNext: name: \"..\" ino: (%d)\n", *ino);
return B_OK;
}
// TODO: Now iterate through sf entries
return B_NOT_SUPPORTED;
}
@@ -0,0 +1,78 @@
/*
* Copyright 2020, Shubham Bhagat, [email protected]
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef __SHORT_DIR_H__
#define __SHORT_DIR_H__
#include "Inode.h"
struct xfs_dir2_sf_off_t { uint8 i[2]; };
//offset into the literal area
union xfs_dir2_inou_t {
uint64 i8;
uint32 i4;
};
// Short form directory header
struct xfs_dir2_sf_hdr_t {
uint8 count;
// number of entries
uint8 i8count;
// # of 64bit inode entries
xfs_dir2_inou_t parent;
// absolute inode # of parent
};
/*
*The xfs_dir2_sf_entry is split into
* two parts because the entries size is variable
*/
struct xfs_dir2_sf_entry_t {
uint8 namelen;
// length of the name, in bytes
xfs_dir2_sf_off_t offset;
// offset tag, for directory iteration
uint8 name[];
// name of directory entry
};
union xfs_dir2_sf_entry_inum_t {
struct xfs_ftype_inum{
uint8 ftype;
xfs_dir2_inou_t inumber;
};
struct xfs_inum{
xfs_dir2_inou_t inumber;
};
};
class ShortDirectory
{
public:
ShortDirectory(Inode* inode);
~ShortDirectory();
status_t GetNext(char* name, size_t* length,
xfs_ino_t* ino);
xfs_ino_t GetParentIno();
status_t Lookup(const char* name, size_t length,
xfs_ino_t* id);
private:
Inode* fInode;
xfs_dir2_sf_hdr_t fHeader;
xfs_dir2_sf_off_t fLastEntryOffset;
// offset into the literal area
uint8 fTrack;
// Takes the values 0, 1 or 2 only
};
#endif
+22 -4
View File
@@ -3,12 +3,15 @@
* Copyright 2020, Shubham Bhagat, [email protected]
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "Volume.h"
#include "DeviceOpener.h"
#include "Inode.h"
Volume::Volume(fs_volume *volume)
: fFSVolume(volume)
: fFSVolume(volume)
{
fFlags = 0;
mutex_init(&fLock, "xfs volume");
@@ -24,7 +27,7 @@ Volume::~Volume()
bool
Volume::IsValidSuperBlock()
Volume::IsValidSuperBlock() const
{
return fSuperBlock.IsValid();
}
@@ -65,7 +68,7 @@ Volume::Mount(const char *deviceName, uint32 flags)
DeviceOpener opener(deviceName, (flags & B_MOUNT_READ_ONLY) != 0
? O_RDONLY
: O_RDWR);
: O_RDWR);
fDevice = opener.Device();
if (fDevice < B_OK) {
ERROR("Volume::Mount(): couldn't open device\n");
@@ -92,6 +95,21 @@ Volume::Mount(const char *deviceName, uint32 flags)
}
opener.Keep();
//publish the root inode
Inode* rootInode = new(std::nothrow) Inode(this, Root());
if (rootInode == NULL)
return B_NO_MEMORY;
status = rootInode->Init();
if (status != B_OK)
return status;
status = publish_vnode(FSVolume(), Root(),
(void*)rootInode, &gxfsVnodeOps, rootInode->Mode(), 0);
if (status != B_OK)
return B_BAD_VALUE;
return B_OK;
}
+32 -20
View File
@@ -1,17 +1,19 @@
/*
* Copyright 2020, Shubham Bhagat, [email protected]
* All rights reserved. Distributed under the terms of the MIT License.
*/
* Copyright 2020, Shubham Bhagat, [email protected]
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef _VOLUME_H_
#define _VOLUME_H_
#include <DeviceOpener.h>
#include "xfs.h"
/* Converting the FS Blocks to Basic Blocks */
#define FSBSHIFT(fsBlockLog) (fsBlockLog - BBLOCKLOG);
#define FSB_TO_BB(fsBlockLog, x) x << FSBSHIFT(fsBlockLog);
#define FSBLOCK_SHIFT(fsBlockLog) (fsBlockLog - BASICBLOCKLOG);
#define FSBLOCKS_TO_BASICBLOCKS(fsBlockLog, x) x << FSBLOCK_SHIFT(fsBlockLog);
// Converting the FS Blocks to Basic Blocks
enum volume_flags {
VOLUME_READ_ONLY = 0x0001
@@ -28,15 +30,16 @@ public:
status_t Initialize(int fd, const char *label,
uint32 blockSize, uint32 sectorSize);
bool IsValidSuperBlock();
bool IsValidSuperBlock() const;
bool IsReadOnly() const
{ return (fFlags & VOLUME_READ_ONLY) != 0; }
{ return
(fFlags & VOLUME_READ_ONLY) != 0; }
dev_t ID() const
{ return fFSVolume ? fFSVolume->id : -1; }
fs_volume* FSVolume() const
{ return fFSVolume; }
char* Name()
const char* Name() const
{ return fSuperBlock.Name(); }
XfsSuperBlock& SuperBlock() { return fSuperBlock; }
@@ -44,29 +47,37 @@ public:
static status_t Identify(int fd, XfsSuperBlock *superBlock);
uint32 BlockSize() { return fSuperBlock.BlockSize(); }
uint32 BlockSize() const
{ return fSuperBlock.BlockSize(); }
uint8 BlockLog() { return fSuperBlock.BlockLog(); }
uint8 BlockLog() const
{ return fSuperBlock.BlockLog(); }
uint32 DirBlockSize()
uint32 DirBlockSize() const
{ return fSuperBlock.DirBlockSize(); }
uint8 AgInodeBits()
uint8 AgInodeBits() const
{ return fSuperBlock.AgInodeBits(); }
uint8 AgBlocksLog()
uint8 AgBlocksLog() const
{ return fSuperBlock.AgBlocksLog(); }
uint8 InodesPerBlkLog()
uint8 InodesPerBlkLog() const
{ return fSuperBlock.InodesPerBlkLog(); }
off_t Root() const { return fSuperBlock.Root(); }
uint16 InodeSize() { return fSuperBlock.InodeSize(); }
uint16 InodeSize() const
{ return fSuperBlock.InodeSize(); }
xfs_agnumber_t AgCount() { return fSuperBlock.AgCount(); }
xfs_agnumber_t AgCount() const
{ return fSuperBlock.AgCount(); }
xfs_agblock_t AgBlocks() { return fSuperBlock.AgBlocks(); }
xfs_agblock_t AgBlocks() const
{ return fSuperBlock.AgBlocks(); }
uint8 SuperBlockFlags() const
{ return fSuperBlock.Flags(); }
#if 0
off_t NumBlocks() const
@@ -77,7 +88,8 @@ protected:
fs_volume* fFSVolume;
int fDevice;
XfsSuperBlock fSuperBlock;
char fName[32]; /* filesystem name */
char fName[32];
// Filesystem name
uint32 fDeviceBlockSize;
mutex fLock;
@@ -1,9 +1,12 @@
/*
* Copyright 2001-2017, Axel Dörfler, [email protected].
* Copyright 2020, Shubham Bhagat, [email protected]
* All rights reserved. Distributed under the terms of the MIT License.
*/
* Copyright 2001-2017, Axel Dörfler, [email protected].
* Copyright 2020, Shubham Bhagat, [email protected]
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "system_dependencies.h"
#include "Directory.h"
#include "Inode.h"
#include "Volume.h"
@@ -86,16 +89,6 @@ xfs_mount(fs_volume *_volume, const char *device, uint32 flags,
return status;
}
//publish the root inode
Inode* rootInode = new(std::nothrow) Inode(volume, volume->Root());
if (rootInode != NULL) {
status = publish_vnode(volume->FSVolume(), volume->Root(),
(void*)rootInode, &gxfsVnodeOps, rootInode->Mode(), 0);
if (status!=B_OK)
return B_BAD_VALUE;
}
*_rootID = volume->Root();
return B_OK;
}
@@ -116,6 +109,7 @@ xfs_unmount(fs_volume *_volume)
static status_t
xfs_read_fs_info(fs_volume *_volume, struct fs_info *info)
{
TRACE("XFS_READ_FS_INFO:\n");
Volume* volume = (Volume*)_volume->private_volume;
info->flags = B_FS_IS_READONLY
@@ -140,15 +134,15 @@ static status_t
xfs_get_vnode(fs_volume *_volume, ino_t id, fs_vnode *_node, int *_type,
uint32 *_flags, bool reenter)
{
TRACE("XFS_GET_VNODE:\n");
Volume* volume = (Volume*)_volume->private_volume;
Inode* inode = new(std::nothrow) Inode(volume, id);
if (inode == NULL)
return B_NO_MEMORY;
status_t status = inode->InitCheck();
if (status == false) {
status_t status = inode->Init();
if (status != B_OK) {
delete inode;
ERROR("get_vnode: InitCheck() failed. Error: %s\n", strerror(status));
return B_NO_INIT;
@@ -158,7 +152,7 @@ xfs_get_vnode(fs_volume *_volume, ino_t id, fs_vnode *_node, int *_type,
_node->ops = &gxfsVnodeOps;
*_type = inode->Mode();
*_flags = 0;
TRACE("(%d)\n", inode->ID());
return B_OK;
}
@@ -166,7 +160,9 @@ xfs_get_vnode(fs_volume *_volume, ino_t id, fs_vnode *_node, int *_type,
static status_t
xfs_put_vnode(fs_volume *_volume, fs_vnode *_node, bool reenter)
{
return B_NOT_SUPPORTED;
TRACE("XFS_PUT_VNODE:\n");
delete (Inode*)_node->private_node;
return B_OK;
}
@@ -208,7 +204,36 @@ static status_t
xfs_lookup(fs_volume *_volume, fs_vnode *_directory, const char *name,
ino_t *_vnodeID)
{
return B_NOT_SUPPORTED;
TRACE("XFS_LOOKUP: %p (%s)\n", name, name);
Volume* volume = (Volume*)_volume->private_volume;
Inode* directory = (Inode*)_directory->private_node;
if (!directory->IsDirectory())
return B_NOT_A_DIRECTORY;
//TODO: pretend everything is accessible. We should actually checking
//for permission here.
DirectoryIterator* iterator =
new(std::nothrow) DirectoryIterator(directory);
if (iterator == NULL)
return B_NO_MEMORY;
status_t status = iterator->Init();
if (status != B_OK) {
delete iterator;
return status;
}
status = iterator->Lookup(name, strlen(name), (xfs_ino_t*)_vnodeID);
if (status != B_OK) {
delete iterator;
return status;
}
TRACE("XFS_LOOKUP: ID: (%d)\n", *_vnodeID);
status = get_vnode(volume->FSVolume(), *_vnodeID, NULL);
TRACE("get_vnode status: (%d)\n", status);
return status;
}
@@ -224,6 +249,7 @@ static status_t
xfs_read_stat(fs_volume *_volume, fs_vnode *_node, struct stat *stat)
{
Inode* inode = (Inode*)_node->private_node;
TRACE("XFS_READ_STAT: root_id: (%d)\n", inode->ID());
stat->st_dev = inode->GetVolume()->ID();
stat->st_ino = inode->ID();
stat->st_nlink = 1;
@@ -234,7 +260,7 @@ xfs_read_stat(fs_volume *_volume, fs_vnode *_node, struct stat *stat)
stat->st_mode = inode->Mode();
stat->st_type = 0; // TODO
stat->st_size = inode->GetVolume()->InodeSize();
stat->st_size = inode->Size();
stat->st_blocks = inode->NoOfBlocks();
inode->GetAccessTime(stat->st_atim);
@@ -282,7 +308,9 @@ xfs_free_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie)
static status_t
xfs_access(fs_volume *_volume, fs_vnode *_node, int accessMode)
{
return B_NOT_SUPPORTED;
//TODO: pretend everything is accessible. We should actually checking
//for permission here.
return B_OK;
}
@@ -322,7 +350,20 @@ xfs_remove_dir(fs_volume *_volume, fs_vnode *_directory, const char *name)
static status_t
xfs_open_dir(fs_volume * /*_volume*/, fs_vnode *_node, void **_cookie)
{
return B_NOT_SUPPORTED;
Inode* inode = (Inode*)_node->private_node;
TRACE("XFS_OPEN_DIR: (%d)\n", inode->ID());
if (!inode->IsDirectory())
return B_NOT_A_DIRECTORY;
DirectoryIterator* iterator = new(std::nothrow) DirectoryIterator(inode);
if (iterator == NULL) {
delete iterator;
return B_NO_MEMORY;
}
status_t status = iterator->Init();
*_cookie = iterator;
return status;
}
@@ -330,7 +371,39 @@ static status_t
xfs_read_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie,
struct dirent *dirent, size_t bufferSize, uint32 *_num)
{
return B_NOT_SUPPORTED;
TRACE("XFS_READ_DIR\n");
DirectoryIterator* iterator = (DirectoryIterator*)_cookie;
Volume* volume = (Volume*)_volume->private_volume;
uint32 maxCount = *_num;
uint32 count = 0;
while (count < maxCount and (bufferSize > sizeof(struct dirent))) {
size_t length = bufferSize - sizeof(struct dirent) + 1;
xfs_ino_t ino;
status_t status = iterator->GetNext(dirent->d_name, &length, &ino);
if (status == B_ENTRY_NOT_FOUND)
break;
if (status == B_BUFFER_OVERFLOW) {
if (count == 0)
return status;
break;
}
if (status != B_OK)
return status;
dirent->d_dev = volume->ID();
dirent->d_ino = ino;
dirent->d_reclen = sizeof(dirent) + length;
bufferSize -= dirent->d_reclen;
dirent = (struct dirent*)((uint8*)dirent + dirent->d_reclen);
count++;
}
*_num = count;
TRACE("Count: (%d)\n", count);
return B_OK;
}
+25 -18
View File
@@ -6,13 +6,20 @@
#include "xfs.h"
uint8
XfsSuperBlock::Flags() const
{
return sb_flags;
}
bool
XfsSuperBlock::IsValid()
XfsSuperBlock::IsValid() const
{
if (sb_magicnum != XFS_SB_MAGIC)
return false;
if (BBLOCKSIZE > sb_blocksize) {
if (BASICBLOCKSIZE > sb_blocksize) {
ERROR("Basic block is less than 512 bytes!");
return false;
}
@@ -22,91 +29,91 @@ XfsSuperBlock::IsValid()
uint32
XfsSuperBlock::BlockSize()
XfsSuperBlock::BlockSize() const
{
return sb_blocksize;
}
uint8
XfsSuperBlock::BlockLog()
XfsSuperBlock::BlockLog() const
{
return sb_blocklog;
}
uint32
XfsSuperBlock::DirBlockSize()
XfsSuperBlock::DirBlockSize() const
{
return BlockSize() * (1 << sb_dirblklog);
}
uint8
XfsSuperBlock::AgInodeBits()
XfsSuperBlock::AgInodeBits() const
{
return AgBlocksLog() + InodesPerBlkLog();
}
uint8
XfsSuperBlock::InodesPerBlkLog()
XfsSuperBlock::InodesPerBlkLog() const
{
return sb_inopblog;
}
uint8
XfsSuperBlock::AgBlocksLog()
XfsSuperBlock::AgBlocksLog() const
{
return sb_agblklog;
}
uint32
XfsSuperBlock::Size()
XfsSuperBlock::Size() const
{
return XFS_SB_MAXSIZE;
}
uint16
XfsSuperBlock::InodeSize()
XfsSuperBlock::InodeSize() const
{
return sb_inodesize;
}
xfs_rfsblock_t
XfsSuperBlock::TotalBlocks()
XfsSuperBlock::TotalBlocks() const
{
return sb_dblocks;
}
xfs_rfsblock_t
XfsSuperBlock::TotalBlocksWithLog()
XfsSuperBlock::TotalBlocksWithLog() const
{
return TotalBlocks() + sb_logblocks;
}
uint64
XfsSuperBlock::FreeBlocks()
XfsSuperBlock::FreeBlocks() const
{
return sb_fdblocks;
}
uint64
XfsSuperBlock::UsedBlocks()
XfsSuperBlock::UsedBlocks() const
{
return TotalBlocks() - FreeBlocks();
}
char*
XfsSuperBlock::Name()
const char*
XfsSuperBlock::Name() const
{
return sb_fname;
}
@@ -120,14 +127,14 @@ XfsSuperBlock::Root() const
xfs_agnumber_t
XfsSuperBlock::AgCount()
XfsSuperBlock::AgCount() const
{
return sb_agcount;
}
xfs_agblock_t
XfsSuperBlock::AgBlocks()
XfsSuperBlock::AgBlocks() const
{
return sb_agblocks;
}
+82 -79
View File
@@ -1,19 +1,19 @@
/*
* Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
* Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
/*
*Important:
*All fields in XFS metadata structures are in big-endian byte order
*except for log items which are formatted in host order.
*
*This file contains all global structure definitions.
*/
*Important:
*All fields in XFS metadata structures are in big-endian byte order
*except for log items which are formatted in host order.
*
*This file contains all global structure definitions.
*/
#ifndef _XFS_SB_H_
#define _XFS_SB_H_
#include "system_dependencies.h"
#include "xfs_types.h"
@@ -22,83 +22,86 @@ extern fs_vnode_ops gxfsVnodeOps;
extern fs_volume_ops gxfsVolumeOps;
#define XFS_SB_MAGIC 0x58465342 /* Identifies XFS. "XFSB" */
#define XFS_SB_MAGIC 0x58465342
// Identifies XFS. "XFSB"
#define XFS_SB_MAXSIZE 512
#define BBLOCKLOG 9 /* Log of block size should be 9 */
#define BBLOCKSIZE 1 << BBLOCKLOG /* The size of a basic block should be 512 */
#define BASICBLOCKLOG 9
// Log of block size should be 9
#define BASICBLOCKSIZE 1 << BASICBLOCKLOG
// The size of a basic block should be 512
/* Version 4 superblock definition */
class XfsSuperBlock
{
class XfsSuperBlock {
public:
bool IsValid();
char* Name();
uint32 BlockSize();
uint8 BlockLog();
uint32 DirBlockSize(); // maximum 65536
uint8 AgInodeBits();
uint8 InodesPerBlkLog();
uint8 AgBlocksLog();
xfs_rfsblock_t TotalBlocks();
xfs_rfsblock_t TotalBlocksWithLog();
uint64 FreeBlocks();
uint64 UsedBlocks();
uint32 Size();
uint16 InodeSize();
void SwapEndian();
xfs_ino_t Root() const;
xfs_agnumber_t AgCount();
xfs_agblock_t AgBlocks();
bool IsValid() const;
const char* Name() const;
uint32 BlockSize() const;
uint8 BlockLog() const;
uint32 DirBlockSize() const;
// maximum 65536
uint8 AgInodeBits() const;
uint8 InodesPerBlkLog() const;
uint8 AgBlocksLog() const;
xfs_rfsblock_t TotalBlocks() const;
xfs_rfsblock_t TotalBlocksWithLog() const;
uint64 FreeBlocks() const;
uint64 UsedBlocks() const;
uint32 Size() const;
uint16 InodeSize() const;
void SwapEndian();
xfs_ino_t Root() const;
xfs_agnumber_t AgCount() const;
xfs_agblock_t AgBlocks() const;
uint8 Flags() const;
private:
uint32 sb_magicnum;
uint32 sb_blocksize;
xfs_rfsblock_t sb_dblocks;
xfs_rfsblock_t sb_rblocks;
xfs_rtblock_t sb_rextents;
uuid_t sb_uuid;
xfs_fsblock_t sb_logstart;
xfs_ino_t sb_rootino;
xfs_ino_t sb_rbmino;
xfs_ino_t sb_rsumino;
xfs_agblock_t sb_rextsize;
xfs_agblock_t sb_agblocks;
xfs_agnumber_t sb_agcount;
xfs_extlen_t sb_rbmblocks;
xfs_extlen_t sb_logblocks;
uint16 sb_versionnum;
uint16 sb_sectsize;
uint16 sb_inodesize;
uint16 sb_inopblock;
char sb_fname[12];
uint8 sb_blocklog;
uint8 sb_sectlog;
uint8 sb_inodelog;
uint8 sb_inopblog;
uint8 sb_agblklog;
uint8 sb_rextslog;
uint8 sb_inprogress;
uint8 sb_imax_pct;
uint64 sb_icount;
uint64 sb_ifree;
uint64 sb_fdblocks;
uint64 sb_frextents;
xfs_ino_t sb_uquotino;
xfs_ino_t sb_gquotino;
uint16 sb_qflags;
uint8 sb_flags;
uint8 sb_shared_vn;
xfs_extlen_t sb_inoalignmt;
uint32 sb_unit;
uint32 sb_width;
uint8 sb_dirblklog;
uint8 sb_logsectlog;
uint16 sb_logsectsize;
uint32 sb_logsunit;
uint32 sb_features2;
uint32 sb_magicnum;
uint32 sb_blocksize;
xfs_rfsblock_t sb_dblocks;
xfs_rfsblock_t sb_rblocks;
xfs_rtblock_t sb_rextents;
uuid_t sb_uuid;
xfs_fsblock_t sb_logstart;
xfs_ino_t sb_rootino;
xfs_ino_t sb_rbmino;
xfs_ino_t sb_rsumino;
xfs_agblock_t sb_rextsize;
xfs_agblock_t sb_agblocks;
xfs_agnumber_t sb_agcount;
xfs_extlen_t sb_rbmblocks;
xfs_extlen_t sb_logblocks;
uint16 sb_versionnum;
uint16 sb_sectsize;
uint16 sb_inodesize;
uint16 sb_inopblock;
char sb_fname[12];
uint8 sb_blocklog;
uint8 sb_sectlog;
uint8 sb_inodelog;
uint8 sb_inopblog;
uint8 sb_agblklog;
uint8 sb_rextslog;
uint8 sb_inprogress;
uint8 sb_imax_pct;
uint64 sb_icount;
uint64 sb_ifree;
uint64 sb_fdblocks;
uint64 sb_frextents;
xfs_ino_t sb_uquotino;
xfs_ino_t sb_gquotino;
uint16 sb_qflags;
uint8 sb_flags;
uint8 sb_shared_vn;
xfs_extlen_t sb_inoalignmt;
uint32 sb_unit;
uint32 sb_width;
uint8 sb_dirblklog;
uint8 sb_logsectlog;
uint16 sb_logsectsize;
uint32 sb_logsunit;
uint32 sb_features2;
};
@@ -39,8 +39,11 @@ UseHeaders [ FDirName $(HAIKU_TOP) headers private ] : true ;
UseHeaders [ FDirName $(HAIKU_TOP) src tools fs_shell ] ;
local xfsSource =
DeviceOpener.cpp
Directory.cpp
Inode.cpp
kernel_interface.cpp
ShortDirectory.cpp
Volume.cpp
xfs.cpp
;