diff --git a/src/add-ons/kernel/file_systems/ufs2/DirectoryIterator.cpp b/src/add-ons/kernel/file_systems/ufs2/DirectoryIterator.cpp new file mode 100644 index 0000000000..36dd4d3d82 --- /dev/null +++ b/src/add-ons/kernel/file_systems/ufs2/DirectoryIterator.cpp @@ -0,0 +1,130 @@ +/* + * Copyright 2020 Suhel Mehta, mehtasuhel@gmail.com + * All rights reserved. Distributed under the terms of the MIT License. + */ + + +#include "DirectoryIterator.h" + +#include + +#include "Inode.h" + +#define TRACE_UFS2 +#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) + + +DirectoryIterator::DirectoryIterator(Inode* inode) + : + fInode(inode) +{ + TRACE("DirectoryIterator::DirectoryIterator() \n"); +} + + +int DirectoryIterator::countDir = 0; + +DirectoryIterator::~DirectoryIterator() +{ +} + + +status_t +DirectoryIterator::InitCheck() +{ + return B_OK; +} + + +status_t +DirectoryIterator::Lookup(const char* name, size_t length, ino_t* _id) +{ + int count = 0; + if (strcmp(name, ".") == 0) { + *_id = fInode->ID(); + return B_OK; + } else if (strcmp(name, "..") == 0) { + if (fInode->ID() == 1) + *_id = fInode->ID(); + + /* else + *_id = fInode->Parent();*/ + + } + while(_GetNext(name, &length, _id, count) != B_OK) { + count++; + } + return B_OK; +} + + +status_t +DirectoryIterator::GetNext(char* name, size_t* _nameLength, ino_t* _id) +{ + TRACE("In GetNext function\n"); + int64_t offset = fInode->GetBlockPointer() * MINBSIZE; + dir direct; + dir_info direct_info; + int fd = fInode->GetVolume()->Device(); + if (read_pos(fd, offset, &direct_info, + sizeof(dir_info)) != sizeof(dir_info)) { + return B_BAD_DATA; + } + + offset = offset + sizeof(dir_info) + 16 * countDir; + if (read_pos(fd, offset, &direct, sizeof(dir)) != sizeof(dir)) { + return B_BAD_DATA; + } + + if (direct.next_ino != 0) { + strlcpy(name, direct.name, sizeof(name)); + *_id = direct.next_ino; + *_nameLength = direct.namlen; + countDir++; + return B_OK; + } + countDir = 0; + return B_ENTRY_NOT_FOUND; +} + + +status_t +DirectoryIterator::_GetNext(const char* name, size_t* _nameLength, + ino_t* _id, int count) +{ + TRACE("In GetNext function\n"); + int64_t offset = fInode->GetBlockPointer() * MINBSIZE; + dir direct; + dir_info direct_info; + int fd = fInode->GetVolume()->Device(); + if (read_pos(fd, offset, &direct_info, + sizeof(dir_info)) != sizeof(dir_info)) { + return B_BAD_DATA; + } + if(strcmp(name, "..") == 0) + { + *_id = direct_info.dotdot_ino; + return B_OK; + } + + offset = offset + sizeof(dir_info) + (16 * count); + if (read_pos(fd, offset, &direct, sizeof(dir)) != sizeof(dir)) { + return B_BAD_DATA; + } + + char getname; + strlcpy(&getname, direct.name, sizeof(name)); + if(strcmp(name, &getname) == 0) { + *_id = direct.next_ino; + return B_OK; + } + else { + return B_ENTRY_NOT_FOUND; + } +} diff --git a/src/add-ons/kernel/file_systems/ufs2/DirectoryIterator.h b/src/add-ons/kernel/file_systems/ufs2/DirectoryIterator.h new file mode 100644 index 0000000000..5da9f9fa0c --- /dev/null +++ b/src/add-ons/kernel/file_systems/ufs2/DirectoryIterator.h @@ -0,0 +1,66 @@ +/* + * Copyright 2020 Suhel Mehta, mehtasuhel@gmail.com + * All rights reserved. Distributed under the terms of the MIT License. + */ + + +#ifndef DIRECTORYITERATOR_H +#define DIRECTORYITERATOR_H + + +#include "ufs2.h" + + +class Inode; + +#define MAXNAMELEN 255 + +struct dir { + u_int32_t next_ino; + u_int16_t reclen; + u_int8_t type; + u_int8_t namlen; + char name[MAXNAMELEN + 1]; +}; + +struct dir_info { + u_int32_t dot_ino; + int16_t dot_reclen; + u_int8_t dot_type; + u_int8_t dot_namelen; + char dot_name[4]; + u_int32_t dotdot_ino; + int16_t dotdot_reclen; + u_int8_t dotdot_type; + u_int8_t dotdot_namelen; + char dotdot_name[4]; +}; + +class DirectoryIterator { +public: + DirectoryIterator(Inode* inode); + ~DirectoryIterator(); + + status_t InitCheck(); + status_t Lookup(const char* name, size_t length, + ino_t* id); + status_t GetNext(char* name, size_t* _nameLength, + ino_t* _id); + status_t _GetNext(const char* name, size_t* _nameLength, + ino_t* _id, int count); + dir* DirectContent() { return direct; } + dir_info* DirectInfo() { return direct_info; } + static int countDir; + +private: + + int64 fOffset; + cluster_t fCluster; + Inode* fInode; + dir* direct; + dir_info* direct_info; + +}; + + +#endif // DIRECTORYITERATOR_H diff --git a/src/add-ons/kernel/file_systems/ufs2/Inode.cpp b/src/add-ons/kernel/file_systems/ufs2/Inode.cpp index 7a73cbdc19..455e753d62 100644 --- a/src/add-ons/kernel/file_systems/ufs2/Inode.cpp +++ b/src/add-ons/kernel/file_systems/ufs2/Inode.cpp @@ -13,6 +13,7 @@ #endif #define ERROR(x...) dprintf("\33[34mufs2:\33[0m " x) + Inode::Inode(Volume* volume, ino_t id) : fVolume(volume), @@ -29,6 +30,16 @@ Inode::Inode(Volume* volume, ino_t id) fMap = file_map_create(fVolume->ID(), ID(), Size()); } } + int fd = fVolume->Device(); + ufs2_super_block* superblock = (ufs2_super_block* )&fVolume->SuperBlock(); + int64_t fs_block = ino_to_fsba(superblock, id); + int64_t offset_in_block = ino_to_fsbo(superblock, id); + int64_t offset = fs_block * MINBSIZE + offset_in_block * 256; + + if (read_pos(fd, offset, (void*)&fNode, sizeof(fNode)) != sizeof(fNode)) + ERROR("Inode::Inode(): IO Error\n"); + + } diff --git a/src/add-ons/kernel/file_systems/ufs2/Inode.h b/src/add-ons/kernel/file_systems/ufs2/Inode.h index e1499f1f72..f76cd1a0f5 100644 --- a/src/add-ons/kernel/file_systems/ufs2/Inode.h +++ b/src/add-ons/kernel/file_systems/ufs2/Inode.h @@ -118,6 +118,9 @@ class Inode { Volume* GetVolume() const { return fVolume; } + int64_t GetBlockPointer() { return fNode.directBlkPtr1; } + ino_t Parent(); + // status_t FindBlock(off_t logical, off_t& physical, // off_t* _length = NULL); // status_t ReadAt(off_t pos, uint8* buffer, size_t* length); @@ -140,7 +143,6 @@ private: ::Volume* fVolume; ino_t fID; void* fCache; - bool fHasNanoTime; void* fMap; status_t fInitStatus; ufs2_inode fNode; diff --git a/src/add-ons/kernel/file_systems/ufs2/Jamfile b/src/add-ons/kernel/file_systems/ufs2/Jamfile index b50e8ed08e..5b601de2bf 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 + DirectoryIterator.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 1dae4b25b5..73971d4cb1 100644 --- a/src/add-ons/kernel/file_systems/ufs2/Volume.cpp +++ b/src/add-ons/kernel/file_systems/ufs2/Volume.cpp @@ -111,14 +111,10 @@ 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, + status = publish_vnode(this->FSVolume(), 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 8bae234709..9defae27dd 100644 --- a/src/add-ons/kernel/file_systems/ufs2/Volume.h +++ b/src/add-ons/kernel/file_systems/ufs2/Volume.h @@ -32,6 +32,7 @@ class Volume { { return (fFlags & VOLUME_READ_ONLY) != 0; } const char* Name() const; fs_volume* FSVolume() const { return fFSVolume; } + int Device() const { return fDevice; } dev_t ID() const { return fFSVolume ? fFSVolume->id : -1; } ufs2_super_block& SuperBlock() { return fSuperBlock; } 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 b2f6b25331..c97855353f 100644 --- a/src/add-ons/kernel/file_systems/ufs2/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/ufs2/kernel_interface.cpp @@ -4,11 +4,11 @@ */ +#include "DirectoryIterator.h" +#include "Inode.h" #include "system_dependencies.h" #include "ufs2.h" #include "Volume.h" -#include "Inode.h" - #define TRACE_UFS2 #ifdef TRACE_UFS2 @@ -196,7 +196,19 @@ static status_t ufs2_lookup(fs_volume *_volume, fs_vnode *_directory, const char *name, ino_t *_vnodeID) { - return B_NOT_SUPPORTED; + TRACE("UFS2_LOOKUP: %p (%s)\n", name, name); + Volume* volume = (Volume*)_volume->private_volume; + Inode* directory = (Inode*)_directory->private_node; + + status_t status = DirectoryIterator(directory).Lookup(name, strlen(name), + (ino_t*)_vnodeID); + + if (status != B_OK) + return status; + + status = get_vnode(volume->FSVolume(), *_vnodeID, NULL); + TRACE("get_vnode status: %s\n", strerror(status)); + return status; } @@ -215,6 +227,7 @@ ufs2_read_stat(fs_volume *_volume, fs_vnode *_node, struct stat *stat) Inode* inode = (Inode*)_node->private_node; stat->st_dev = inode->GetVolume()->ID(); stat->st_ino = inode->ID(); + TRACE("stat->st_ino %ld\n",stat->st_ino); // TODO handle hardlinks which will have nlink > 1. Maybe linkCount in inode // structure may help? stat->st_nlink = 1; @@ -226,7 +239,7 @@ ufs2_read_stat(fs_volume *_volume, fs_vnode *_node, struct stat *stat) stat->st_type = 0; inode->GetAccessTime(stat->st_atim); -/* inode->GetModificationTime(stat->st_mtim);*/ + inode->GetModificationTime(stat->st_mtim); inode->GetChangeTime(stat->st_ctim); inode->GetCreationTime(stat->st_crtim); @@ -269,7 +282,8 @@ ufs2_free_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie) static status_t ufs2_access(fs_volume *_volume, fs_vnode *_node, int accessMode) { - return B_NOT_SUPPORTED; + TRACE("In access\n"); + return B_OK; } @@ -308,7 +322,17 @@ ufs2_remove_dir(fs_volume *_volume, fs_vnode *_directory, const char *name) static status_t ufs2_open_dir(fs_volume * /*_volume*/, fs_vnode *_node, void **_cookie) { - return B_NOT_SUPPORTED; + Inode* inode = (Inode*)_node->private_node; + + if (!inode->IsDirectory()) + return B_NOT_A_DIRECTORY; + + DirectoryIterator* iterator = new(std::nothrow) DirectoryIterator(inode); + if (iterator == NULL) + return B_NO_MEMORY; + + *_cookie = iterator; + return B_OK; } @@ -316,7 +340,40 @@ static status_t ufs2_read_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie, struct dirent *dirent, size_t bufferSize, uint32 *_num) { - return B_NOT_SUPPORTED; + TRACE("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; + ino_t iNodeNo; + + status_t status = iterator->GetNext(dirent->d_name, &length, &iNodeNo); + 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 = iNodeNo; + dirent->d_reclen = sizeof(dirent) + length; + bufferSize -= dirent->d_reclen; + dirent = (struct dirent*)((uint8*)dirent + dirent->d_reclen); + count++; + } + + *_num = count; + TRACE("count is %d\n", count); + return B_OK; + } diff --git a/src/add-ons/kernel/file_systems/ufs2/ufs2.h b/src/add-ons/kernel/file_systems/ufs2/ufs2.h index 36f46411cf..00366f99b2 100644 --- a/src/add-ons/kernel/file_systems/ufs2/ufs2.h +++ b/src/add-ons/kernel/file_systems/ufs2/ufs2.h @@ -37,6 +37,9 @@ #include "system_dependencies.h" +typedef uint32 cluster_t; +typedef uint64_t ufs2_daddr_t; + #define SBLOCK_FLOPPY 0 #define SBLOCK_UFS1 8192 #define SBLOCK_UFS2 65536 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 ebc59e0703..8bf460e4f5 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 + DirectoryIterator.cpp Inode.cpp Volume.cpp kernel_interface.cpp