From ac754f75e96edbc3f49c6a16272650dd789633de Mon Sep 17 00:00:00 2001 From: Suhel Mehta Date: Thu, 14 May 2020 19:20:14 +0530 Subject: [PATCH] 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 --- docs/develop/file_systems/ufs2.txt | 46 +++++++ .../kernel/file_systems/ufs2/Inode.cpp | 76 +++++++++++ src/add-ons/kernel/file_systems/ufs2/Inode.h | 127 ++++++++++++++++++ src/add-ons/kernel/file_systems/ufs2/Jamfile | 1 + .../kernel/file_systems/ufs2/Volume.cpp | 13 +- src/add-ons/kernel/file_systems/ufs2/Volume.h | 8 ++ .../file_systems/ufs2/kernel_interface.cpp | 31 ++++- .../file_systems/ufs2/ufs2_shell/Jamfile | 1 + 8 files changed, 296 insertions(+), 7 deletions(-) create mode 100644 docs/develop/file_systems/ufs2.txt create mode 100644 src/add-ons/kernel/file_systems/ufs2/Inode.cpp create mode 100644 src/add-ons/kernel/file_systems/ufs2/Inode.h diff --git a/docs/develop/file_systems/ufs2.txt b/docs/develop/file_systems/ufs2.txt new file mode 100644 index 0000000000..e09e22ec3d --- /dev/null +++ b/docs/develop/file_systems/ufs2.txt @@ -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 "ufs2_shell" + +To run it, use + + jam run objects/linux/x86_64/release/tests/add-ons/kernel/file_systems/ufs2/ufs2_shell/ufs2_shell + +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 diff --git a/src/add-ons/kernel/file_systems/ufs2/Inode.cpp b/src/add-ons/kernel/file_systems/ufs2/Inode.cpp new file mode 100644 index 0000000000..7a73cbdc19 --- /dev/null +++ b/src/add-ons/kernel/file_systems/ufs2/Inode.cpp @@ -0,0 +1,76 @@ +/* + * Copyright 2020 Suhel Mehta, mehtasuhel@gmail.com + * Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de. + * 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; +} diff --git a/src/add-ons/kernel/file_systems/ufs2/Inode.h b/src/add-ons/kernel/file_systems/ufs2/Inode.h new file mode 100644 index 0000000000..6fe1b77842 --- /dev/null +++ b/src/add-ons/kernel/file_systems/ufs2/Inode.h @@ -0,0 +1,127 @@ +/* + * Copyright 2020 Suhel Mehta, mehtasuhel@gmail.com + * Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de. + * 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 diff --git a/src/add-ons/kernel/file_systems/ufs2/Jamfile b/src/add-ons/kernel/file_systems/ufs2/Jamfile index c9336ce597..b50e8ed08e 100644 --- a/src/add-ons/kernel/file_systems/ufs2/Jamfile +++ b/src/add-ons/kernel/file_systems/ufs2/Jamfile @@ -19,6 +19,7 @@ DEFINES += DEBUG_APP="\\\"ufs2\\\"" ; local ufs2Sources = DeviceOpener.cpp + Inode.cpp Volume.cpp kernel_interface.cpp ; diff --git a/src/add-ons/kernel/file_systems/ufs2/Volume.cpp b/src/add-ons/kernel/file_systems/ufs2/Volume.cpp index c5af304df6..6c1d657008 100644 --- a/src/add-ons/kernel/file_systems/ufs2/Volume.cpp +++ b/src/add-ons/kernel/file_systems/ufs2/Volume.cpp @@ -5,6 +5,8 @@ #include "Volume.h" #include "DeviceOpener.h" +#include "Inode.h" + #define TRACE_UFS2 #ifdef TRACE_UFS2 @@ -33,7 +35,8 @@ Volume::IsValidSuperBlock() Volume::Volume(fs_volume *volume) - : fFSVolume(volume) + : fFSVolume(volume), + fRootNode(NULL) { fFlags = 0; mutex_init(&fLock, "ufs2 volume"); @@ -98,6 +101,14 @@ Volume::Mount(const char *deviceName, uint32 flags) 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(); return B_OK; diff --git a/src/add-ons/kernel/file_systems/ufs2/Volume.h b/src/add-ons/kernel/file_systems/ufs2/Volume.h index faf421e61f..66ad0272ff 100644 --- a/src/add-ons/kernel/file_systems/ufs2/Volume.h +++ b/src/add-ons/kernel/file_systems/ufs2/Volume.h @@ -7,10 +7,15 @@ #include "ufs2.h" +extern fs_volume_ops gUfs2VolumeOps; +extern fs_vnode_ops gufs2VnodeOps; + enum volume_flags { VOLUME_READ_ONLY = 0x0001 }; +class Inode; + class Volume { public: Volume(fs_volume* volume); @@ -25,6 +30,8 @@ class Volume { bool IsValidInodeBlock(off_t block) const; bool IsReadOnly() const; fs_volume* FSVolume() const { return fFSVolume; } + dev_t ID() const + { return fFSVolume ? fFSVolume->id : -1; } ufs2_super_block& SuperBlock() { return fSuperBlock; } status_t LoadSuperBlock(); static status_t Identify(int fd, ufs2_super_block* superBlock); @@ -35,6 +42,7 @@ class Volume { ufs2_super_block fSuperBlock; mutex fLock; uint32 fFlags; + Inode* fRootNode; }; #endif // VOLUME_H diff --git a/src/add-ons/kernel/file_systems/ufs2/kernel_interface.cpp b/src/add-ons/kernel/file_systems/ufs2/kernel_interface.cpp index 18b81aca39..cc8738f8d2 100644 --- a/src/add-ons/kernel/file_systems/ufs2/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/ufs2/kernel_interface.cpp @@ -7,6 +7,7 @@ #include "system_dependencies.h" #include "ufs2.h" #include "Volume.h" +#include "Inode.h" #ifdef TRACE_ufs2 #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, const char *args, ino_t *_rootID) { - TRACE("Tracing mount()"); + TRACE("Tracing mount()\n"); Volume* volume = new(std::nothrow) Volume(_volume); if (volume == NULL) return B_NO_MEMORY; _volume->private_volume = volume; - //_volume->ops = &gufs2VolumeOps; - + _volume->ops = &gUfs2VolumeOps; + *_rootID = UFS2_ROOT; status_t status = volume->Mount(device, flags); if (status != B_OK){ 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, 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_read_fs_info, - NULL, // write_fs_info() + NULL, //write_fs_info() NULL, // fs_sync, &ufs2_get_vnode, }; diff --git a/src/tests/add-ons/kernel/file_systems/ufs2/ufs2_shell/Jamfile b/src/tests/add-ons/kernel/file_systems/ufs2/ufs2_shell/Jamfile index 107f755384..ebc59e0703 100644 --- a/src/tests/add-ons/kernel/file_systems/ufs2/ufs2_shell/Jamfile +++ b/src/tests/add-ons/kernel/file_systems/ufs2/ufs2_shell/Jamfile @@ -40,6 +40,7 @@ UseHeaders [ FDirName $(HAIKU_TOP) src tools fs_shell ] ; local ufs2Source = DeviceOpener.cpp + Inode.cpp Volume.cpp kernel_interface.cpp ;