ufs2: Reading inodes of ufs2.

Now file system can be mounted sucessfully.

Adding documentation for using the code.

Change-Id: I2bd1b72e06ffc3b5f6306aaa69c59becf4cb882b
Reviewed-on: https://review.haiku-os.org/c/haiku/+/2696
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
Suhel Mehta
2020-05-18 12:16:32 +00:00
committed by Adrien Destugues
parent 9883929b9c
commit ac754f75e9
8 changed files with 296 additions and 7 deletions
+46
View File
@@ -0,0 +1,46 @@
Implementation of UFS2 on Haiku
===============================
While making a device for testing I have used a usb drive and formatted it to
UFS2 by using the following commands in FreeBSD. Here da0 is usb.
gpart destroy -F /dev/da0
gpart create -s gpt /dev/da0
gpart add -t freebsd-ufs /dev/da0
newfs /dev/da0p1
By running the following commands you can run the implemented code of UFS2.
Commands
--------
# Building the ufs2 shell
jam -q "<build>ufs2_shell"
To run it, use
jam run objects/linux/x86_64/release/tests/add-ons/kernel/file_systems/ufs2/ufs2_shell/ufs2_shell <path_to_the_image>
If you are using a usb drive then you may not be able to open it so, you just
need to add sudo in the beginning of above command and make sure that you have
not mounted the usb drive.
Alternatively you can start from an existing freebsd image, so it has some files in it:
Download FreeBSD-12.1-RELEASE-amd64-mini-memstick.img
diskimage register FreeBSD-12.1-RELEASE-amd64-mini-memstick.img to access the MBR style partitions inside it (on Linux probably using mount -o loop or something like that)
dd if=/dev/disk/virtual/files/8/1 bs=8K skip=1 of=fbsd_ufstest.img to extract the filesystem from the partition (skipping the freebsd disklabel)
Check the result: file fbsd_ufstest.img
fbsd_ufstest.img: Unix Fast File system [v2] (little-endian)
During the implementation of the project the following links were found useful.
https://github.com/freebsd/freebsd/blob/master/sys/ufs/ffs/fs.h
https://flylib.com/books/en/2.48.1/ufs2_inodes.html
@@ -0,0 +1,76 @@
/*
* Copyright 2020 Suhel Mehta, [email protected]
* Copyright 2008-2010, Axel Dörfler, [email protected].
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "Inode.h"
#ifdef TRACE_ufs2
#define TRACE(x...) dprintf("\33[34mufs2:\33[0m " x)
#else
#define TRACE(x...) ;
#endif
#define ERROR(x...) dprintf("\33[34mufs2:\33[0m " x)
Inode::Inode(Volume* volume, ino_t id)
:
fVolume(volume),
fID(id),
fCache(NULL),
fMap(NULL)
{
rw_lock_init(&fLock, "ufs2 inode");
fInitStatus = B_OK;//UpdateNodeFromDisk();
if (fInitStatus == B_OK) {
if (!IsDirectory() && !IsSymLink()) {
fCache = file_cache_create(fVolume->ID(), ID(), Size());
fMap = file_map_create(fVolume->ID(), ID(), Size());
}
}
}
Inode::Inode(Volume* volume, ino_t id, const ufs2_inode& item)
:
fVolume(volume),
fID(id),
fCache(NULL),
fMap(NULL),
fInitStatus(B_OK),
fNode(item)
{
if (!IsDirectory() && !IsSymLink()) {
fCache = file_cache_create(fVolume->ID(), ID(), Size());
fMap = file_map_create(fVolume->ID(), ID(), Size());
}
}
Inode::Inode(Volume* volume)
:
fVolume(volume),
fID(0),
fCache(NULL),
fMap(NULL),
fInitStatus(B_NO_INIT)
{
rw_lock_init(&fLock, "ufs2 inode");
}
Inode::~Inode()
{
TRACE("Inode destructor\n");
file_cache_delete(FileCache());
file_map_delete(Map());
TRACE("Inode destructor: Done\n");
}
status_t
Inode::InitCheck()
{
return fInitStatus;
}
@@ -0,0 +1,127 @@
/*
* Copyright 2020 Suhel Mehta, [email protected]
* Copyright 2008-2010, Axel Dörfler, [email protected].
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef INODE_H
#define INODE_H
#include "ufs2.h"
#include "Volume.h"
#define UFS2_ROOT ((ino_t)2)
struct ufs2_inode {
u_int16_t fileMode;
int16_t linkCount;
int32_t userId;
int32_t groupId;
int32_t inodeBlockSize;
int64_t size;
int64_t byteHeld;
int64_t accessTime;
int64_t modifiedTime;
int64_t changeTime;
int64_t createTime;
/* time in nano seconds */
int32_t nsModifiedTime;
int32_t nsAccessTime;
int32_t nsChangeTime;
int32_t nsCreateTime;
int32_t generationNumber;
int32_t kernelFlags;
int32_t statusFlags;
int32_t extendedAttSize; /* Extended attribute size */
/* 2 Direct extended attribute block pointers */
int64_t extendedBklPtr1;
int64_t extendedBklPtr2;
/* 12 direct block pointers */
int64_t directBlkPtr1;
int64_t directBlkPtr2;
int64_t directBlkPtr3;
int64_t directBlkPtr4;
int64_t directBlkPtr5;
int64_t directBlkPtr6;
int64_t directBlkPtr7;
int64_t directBlkPtr8;
int64_t directBlkPtr9;
int64_t directBlkPtr10;
int64_t directBlkPtr11;
int64_t directBlkPtr12;
int64_t indirectBlkPtr; /* 1 Indirect block pointer */
int64_t doubleIndriectBlkPtr; // 1 Double Indirect block pointer
int64_t tripleIndriectBlkPtr; // 1 Triple Indirect block pointer
/* Unused but need to figure out what are they */
int64_t unused1;
int64_t unused2;
int64_t unused3;
};
class Inode {
public:
Inode(Volume* volume, ino_t id);
Inode(Volume* volume, ino_t id,
const ufs2_inode& item);
~Inode();
status_t InitCheck();
ino_t ID() const { return fID; }
//
rw_lock* Lock() { return& fLock; }
//
// status_t UpdateNodeFromDisk();
bool IsDirectory() const
{ return S_ISDIR(Mode()); }
bool IsFile() const
{ return S_ISREG(Mode()); }
bool IsSymLink() const
{ return S_ISLNK(Mode()); }
// status_t CheckPermissions(int accessMode) const;
mode_t Mode() const { return fNode.fileMode; }
off_t Size() const { return fNode.size; }
uid_t UserID() const { return fNode.userId; }
gid_t GroupID() const { return fNode.groupId; }
/*void GetChangeTime(struct timespec& timespec) const
{ fNode.GetChangeTime(timespec); }
void GetModificationTime(struct timespec& timespec) const
{ fNode.GetModificationTime(timespec); }
void GetCreationTime(struct timespec& timespec) const
{ fNode.GetCreationTime(timespec); }
void GetAccessTime(struct timespec& timespec) const
{ fNode.GetCreationTime(timespec); }*/
Volume* GetVolume() const { return fVolume; }
// status_t FindBlock(off_t logical, off_t& physical,
// off_t* _length = NULL);
// status_t ReadAt(off_t pos, uint8* buffer, size_t* length);
// status_t FillGapWithZeros(off_t start, off_t end);
void* FileCache() const { return fCache; }
void* Map() const { return fMap; }
// status_t FindParent(ino_t* id);
//static Inode* Create(Transaction& transaction, ino_t id, Inode* parent, int32 mode, uint64 size = 0, uint64 flags = 0);
private:
Inode(Volume* volume);
Inode(const Inode&);
Inode& operator=(const Inode&);
// uint64 _NumBlocks();
private:
rw_lock fLock;
::Volume* fVolume;
ino_t fID;
void* fCache;
void* fMap;
status_t fInitStatus;
ufs2_inode fNode;
};
#endif // INODE_H
@@ -19,6 +19,7 @@ DEFINES += DEBUG_APP="\\\"ufs2\\\"" ;
local ufs2Sources = local ufs2Sources =
DeviceOpener.cpp DeviceOpener.cpp
Inode.cpp
Volume.cpp Volume.cpp
kernel_interface.cpp kernel_interface.cpp
; ;
@@ -5,6 +5,8 @@
#include "Volume.h" #include "Volume.h"
#include "DeviceOpener.h" #include "DeviceOpener.h"
#include "Inode.h"
#define TRACE_UFS2 #define TRACE_UFS2
#ifdef TRACE_UFS2 #ifdef TRACE_UFS2
@@ -33,7 +35,8 @@ Volume::IsValidSuperBlock()
Volume::Volume(fs_volume *volume) Volume::Volume(fs_volume *volume)
: fFSVolume(volume) : fFSVolume(volume),
fRootNode(NULL)
{ {
fFlags = 0; fFlags = 0;
mutex_init(&fLock, "ufs2 volume"); mutex_init(&fLock, "ufs2 volume");
@@ -98,6 +101,14 @@ Volume::Mount(const char *deviceName, uint32 flags)
TRACE("Valid super block\n"); TRACE("Valid super block\n");
status = get_vnode(fFSVolume, UFS2_ROOT, (void**) &fRootNode);
if (status != B_OK) {
ERROR("could not create root node: get_vnode() failed! %d\n",status);
return status;
}
fRootNode = new(std::nothrow) Inode(this, UFS2_ROOT);
status = publish_vnode(fFSVolume, UFS2_ROOT, (void*)fRootNode,
&gufs2VnodeOps, fRootNode->Mode(), 0);
opener.Keep(); opener.Keep();
return B_OK; return B_OK;
@@ -7,10 +7,15 @@
#include "ufs2.h" #include "ufs2.h"
extern fs_volume_ops gUfs2VolumeOps;
extern fs_vnode_ops gufs2VnodeOps;
enum volume_flags { enum volume_flags {
VOLUME_READ_ONLY = 0x0001 VOLUME_READ_ONLY = 0x0001
}; };
class Inode;
class Volume { class Volume {
public: public:
Volume(fs_volume* volume); Volume(fs_volume* volume);
@@ -25,6 +30,8 @@ class Volume {
bool IsValidInodeBlock(off_t block) const; bool IsValidInodeBlock(off_t block) const;
bool IsReadOnly() const; bool IsReadOnly() const;
fs_volume* FSVolume() const { return fFSVolume; } fs_volume* FSVolume() const { return fFSVolume; }
dev_t ID() const
{ return fFSVolume ? fFSVolume->id : -1; }
ufs2_super_block& SuperBlock() { return fSuperBlock; } ufs2_super_block& SuperBlock() { return fSuperBlock; }
status_t LoadSuperBlock(); status_t LoadSuperBlock();
static status_t Identify(int fd, ufs2_super_block* superBlock); static status_t Identify(int fd, ufs2_super_block* superBlock);
@@ -35,6 +42,7 @@ class Volume {
ufs2_super_block fSuperBlock; ufs2_super_block fSuperBlock;
mutex fLock; mutex fLock;
uint32 fFlags; uint32 fFlags;
Inode* fRootNode;
}; };
#endif // VOLUME_H #endif // VOLUME_H
@@ -7,6 +7,7 @@
#include "system_dependencies.h" #include "system_dependencies.h"
#include "ufs2.h" #include "ufs2.h"
#include "Volume.h" #include "Volume.h"
#include "Inode.h"
#ifdef TRACE_ufs2 #ifdef TRACE_ufs2
#define TRACE(x...) dprintf("\33[34mufs2:\33[0m " x) #define TRACE(x...) dprintf("\33[34mufs2:\33[0m " x)
@@ -78,14 +79,14 @@ static status_t
ufs2_mount(fs_volume *_volume, const char *device, uint32 flags, ufs2_mount(fs_volume *_volume, const char *device, uint32 flags,
const char *args, ino_t *_rootID) const char *args, ino_t *_rootID)
{ {
TRACE("Tracing mount()"); TRACE("Tracing mount()\n");
Volume* volume = new(std::nothrow) Volume(_volume); Volume* volume = new(std::nothrow) Volume(_volume);
if (volume == NULL) if (volume == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
_volume->private_volume = volume; _volume->private_volume = volume;
//_volume->ops = &gufs2VolumeOps; _volume->ops = &gUfs2VolumeOps;
*_rootID = UFS2_ROOT;
status_t status = volume->Mount(device, flags); status_t status = volume->Mount(device, flags);
if (status != B_OK){ if (status != B_OK){
ERROR("Failed mounting the volume. Error: %s\n", strerror(status)); ERROR("Failed mounting the volume. Error: %s\n", strerror(status));
@@ -116,7 +117,25 @@ static status_t
ufs2_get_vnode(fs_volume *_volume, ino_t id, fs_vnode *_node, int *_type, ufs2_get_vnode(fs_volume *_volume, ino_t id, fs_vnode *_node, int *_type,
uint32 *_flags, bool reenter) uint32 *_flags, bool reenter)
{ {
return B_NOT_SUPPORTED; 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 != B_OK) {
delete inode;
ERROR("get_vnode: InitCheck() failed. Error: %s\n", strerror(status));
return status;
}
_node->private_node = inode;
_node->ops = &gufs2VnodeOps;
*_type = inode->Mode();
*_flags = 0;
return B_OK;
} }
@@ -453,10 +472,10 @@ ufs2_std_ops(int32 op, ...)
} }
} }
fs_volume_ops gufs2VolumeOps = { fs_volume_ops gUfs2VolumeOps = {
&ufs2_unmount, &ufs2_unmount,
&ufs2_read_fs_info, &ufs2_read_fs_info,
NULL, // write_fs_info() NULL, //write_fs_info()
NULL, // fs_sync, NULL, // fs_sync,
&ufs2_get_vnode, &ufs2_get_vnode,
}; };
@@ -40,6 +40,7 @@ UseHeaders [ FDirName $(HAIKU_TOP) src tools fs_shell ] ;
local ufs2Source = local ufs2Source =
DeviceOpener.cpp DeviceOpener.cpp
Inode.cpp
Volume.cpp Volume.cpp
kernel_interface.cpp kernel_interface.cpp
; ;