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:
committed by
Adrien Destugues
parent
9883929b9c
commit
ac754f75e9
@@ -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
|
||||||
;
|
;
|
||||||
|
|||||||
Reference in New Issue
Block a user