821 lines
22 KiB
C++
821 lines
22 KiB
C++
/*
|
|
* Copyright 2015 - 2017 gtalent2@gmail.com
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <ox/std/std.hpp>
|
|
|
|
namespace ox {
|
|
namespace fs {
|
|
|
|
template<typename FsT, typename InodeId>
|
|
struct __attribute__((packed)) FileStoreHeader {
|
|
public:
|
|
typedef InodeId InodeId_t;
|
|
typedef FsT FsSize_t;
|
|
const static auto VERSION = 5;
|
|
|
|
private:
|
|
uint16_t m_version;
|
|
uint16_t m_fsType;
|
|
FsSize_t m_size;
|
|
FsSize_t m_memUsed;
|
|
FsSize_t m_rootInode;
|
|
|
|
public:
|
|
void setVersion(uint16_t);
|
|
uint16_t getVersion();
|
|
|
|
void setFsType(uint16_t);
|
|
uint16_t getFsType();
|
|
|
|
void setSize(FsSize_t);
|
|
FsSize_t getSize();
|
|
|
|
void setMemUsed(FsSize_t);
|
|
FsSize_t getMemUsed();
|
|
|
|
void setRootInode(FsSize_t);
|
|
FsSize_t getRootInode();
|
|
};
|
|
|
|
template<typename FsSize_t, typename InodeId_t>
|
|
void FileStoreHeader<FsSize_t, InodeId_t>::setVersion(uint16_t version) {
|
|
m_version = std::bigEndianAdapt(version);
|
|
}
|
|
|
|
template<typename FsSize_t, typename InodeId_t>
|
|
uint16_t FileStoreHeader<FsSize_t, InodeId_t>::getVersion() {
|
|
return std::bigEndianAdapt(m_version);
|
|
}
|
|
|
|
template<typename FsSize_t, typename InodeId_t>
|
|
void FileStoreHeader<FsSize_t, InodeId_t>::setFsType(uint16_t fsType) {
|
|
m_fsType = std::bigEndianAdapt(fsType);
|
|
}
|
|
|
|
template<typename FsSize_t, typename InodeId_t>
|
|
uint16_t FileStoreHeader<FsSize_t, InodeId_t>::getFsType() {
|
|
return std::bigEndianAdapt(m_fsType);
|
|
}
|
|
|
|
template<typename FsSize_t, typename InodeId_t>
|
|
void FileStoreHeader<FsSize_t, InodeId_t>::setSize(FsSize_t size) {
|
|
m_size = std::bigEndianAdapt(size);
|
|
}
|
|
|
|
template<typename FsSize_t, typename InodeId_t>
|
|
FsSize_t FileStoreHeader<FsSize_t, InodeId_t>::getSize() {
|
|
return std::bigEndianAdapt(m_size);
|
|
}
|
|
|
|
template<typename FsSize_t, typename InodeId_t>
|
|
void FileStoreHeader<FsSize_t, InodeId_t>::setMemUsed(FsSize_t memUsed) {
|
|
m_memUsed = std::bigEndianAdapt(memUsed);
|
|
}
|
|
|
|
template<typename FsSize_t, typename InodeId_t>
|
|
FsSize_t FileStoreHeader<FsSize_t, InodeId_t>::getMemUsed() {
|
|
return std::bigEndianAdapt(m_memUsed);
|
|
}
|
|
|
|
template<typename FsSize_t, typename InodeId_t>
|
|
void FileStoreHeader<FsSize_t, InodeId_t>::setRootInode(FsSize_t rootInode) {
|
|
m_rootInode = std::bigEndianAdapt(rootInode);
|
|
}
|
|
|
|
template<typename FsSize_t, typename InodeId_t>
|
|
FsSize_t FileStoreHeader<FsSize_t, InodeId_t>::getRootInode() {
|
|
return std::bigEndianAdapt(m_rootInode);
|
|
}
|
|
|
|
template<typename Header>
|
|
class FileStore {
|
|
|
|
public:
|
|
typedef typename Header::InodeId_t InodeId_t;
|
|
typedef typename Header::FsSize_t FsSize_t;
|
|
const static auto VERSION = Header::VERSION;
|
|
|
|
struct StatInfo {
|
|
InodeId_t inodeId;
|
|
typename Header::FsSize_t size;
|
|
uint8_t fileType;
|
|
};
|
|
|
|
private:
|
|
struct __attribute__((packed)) Inode {
|
|
private:
|
|
// the next Inode in memory
|
|
typename Header::FsSize_t m_prev;
|
|
typename Header::FsSize_t m_next;
|
|
typename Header::FsSize_t m_dataLen;
|
|
|
|
InodeId_t m_id;
|
|
uint8_t m_fileType;
|
|
typename Header::FsSize_t m_left;
|
|
typename Header::FsSize_t m_right;
|
|
|
|
public:
|
|
typename Header::FsSize_t size();
|
|
|
|
void setDataLen(typename Header::FsSize_t);
|
|
typename Header::FsSize_t getDataLen();
|
|
|
|
void setPrev(typename Header::FsSize_t);
|
|
typename Header::FsSize_t getPrev();
|
|
|
|
void setNext(typename Header::FsSize_t);
|
|
typename Header::FsSize_t getNext();
|
|
|
|
void setId(InodeId_t);
|
|
InodeId_t getId();
|
|
|
|
void setFileType(uint8_t);
|
|
uint8_t getFileType();
|
|
|
|
void setLeft(typename Header::FsSize_t);
|
|
typename Header::FsSize_t getLeft();
|
|
|
|
void setRight(typename Header::FsSize_t);
|
|
typename Header::FsSize_t getRight();
|
|
|
|
void setData(void *data, typename Header::FsSize_t size);
|
|
uint8_t *getData();
|
|
};
|
|
|
|
Header m_header;
|
|
|
|
public:
|
|
/**
|
|
* Dumps this file store's inodes to the given file store.
|
|
*/
|
|
int dumpTo(FileStore<Header> *dest);
|
|
|
|
/**
|
|
* Compacts and resizes the file store to the minimum possible size for
|
|
* the contents.
|
|
*
|
|
* NOTE: This does NOT resize the buffer that this file store refers to!
|
|
*/
|
|
void resize(typename Header::FsSize_t size = 0);
|
|
|
|
/**
|
|
* Writes the given data to a "file" with the given id.
|
|
* @param id the id of the file
|
|
* @param data the contents of the file
|
|
* @param dataLen the number of bytes data points to
|
|
*/
|
|
int write(InodeId_t id, void *data, typename Header::FsSize_t dataLen, uint8_t fileType = 0);
|
|
|
|
/**
|
|
* Removes the inode of the given ID.
|
|
* @param id the id of the file
|
|
*/
|
|
int remove(InodeId_t id);
|
|
|
|
/**
|
|
* Reads the "file" at the given id. You are responsible for freeing
|
|
* the data when done with it.
|
|
* @param id id of the "file"
|
|
* @param data pointer to the pointer where the data is stored
|
|
* @param size pointer to a value that will be assigned the size of data
|
|
* @return 0 if read is a success
|
|
*/
|
|
int read(InodeId_t id, void *data, typename Header::FsSize_t *size);
|
|
|
|
/**
|
|
* Reads the "file" at the given id. You are responsible for freeing
|
|
* the data when done with it.
|
|
* @param id id of the "file"
|
|
* @param readStart where in the data to start reading
|
|
* @param readSize how much data to read
|
|
* @param data pointer to the pointer where the data is stored
|
|
* @param size pointer to a value that will be assigned the size of data
|
|
* @return 0 if read is a success
|
|
*/
|
|
int read(InodeId_t id, typename Header::FsSize_t readStart,
|
|
typename Header::FsSize_t readSize, void *data,
|
|
typename Header::FsSize_t *size);
|
|
|
|
/**
|
|
* Reads the "file" at the given id. You are responsible for freeing
|
|
* the data when done with it.
|
|
* @param id id of the "file"
|
|
* @param readStart where in the data to start reading
|
|
* @param readSize how much data to read
|
|
* @param data pointer to the pointer where the data is stored
|
|
* @param size pointer to a value that will be assigned the size of data
|
|
* @return 0 if read is a success
|
|
*/
|
|
template<typename T>
|
|
int read(InodeId_t id, typename Header::FsSize_t readStart,
|
|
typename Header::FsSize_t readSize, T *data,
|
|
typename Header::FsSize_t *size);
|
|
|
|
/**
|
|
* Reads the stat information of the inode of the given inode id.
|
|
* If the returned inode id is 0, then the requested inode was not found.
|
|
* @param id id of the inode to stat
|
|
* @return the stat information of the inode of the given inode id
|
|
*/
|
|
StatInfo stat(InodeId_t id);
|
|
|
|
/**
|
|
* Returns the space needed for this data at the given inode address.
|
|
* @param id the target inode id
|
|
* @param size the size of the data to insert
|
|
* @return the space currently available in this file store.
|
|
*/
|
|
typename Header::FsSize_t spaceNeeded(typename Header::FsSize_t size);
|
|
|
|
/**
|
|
* Returns the size of the file store.
|
|
* @return the size of the file store.
|
|
*/
|
|
typename Header::FsSize_t size();
|
|
|
|
/**
|
|
* Returns the space currently available in this file store.
|
|
* @return the space currently available in this file store.
|
|
*/
|
|
typename Header::FsSize_t available();
|
|
|
|
uint16_t fsType();
|
|
|
|
uint16_t version();
|
|
|
|
static uint8_t *format(uint8_t *buffer, typename Header::FsSize_t size, uint16_t fsType = 0);
|
|
|
|
private:
|
|
/**
|
|
* Gets the inode at the given id.
|
|
* @param root the root node to start comparing on
|
|
* @param id id of the "file"
|
|
* @param pathLen number of characters in pathLen
|
|
* @return the requested Inode, if available
|
|
*/
|
|
Inode *getInode(Inode *root, InodeId_t id);
|
|
|
|
/**
|
|
* Gets the inode at the given id.
|
|
* @param root the root node to start comparing on
|
|
* @param id id of the "file"
|
|
* @param pathLen number of characters in pathLen
|
|
* @param targetAddr the address of the target inode
|
|
* @return the requested Inode, if available
|
|
*/
|
|
Inode *getInodeParent(Inode *root, InodeId_t id, typename Header::FsSize_t targetAddr);
|
|
|
|
/**
|
|
* Reads the "file" at the given id. You are responsible for freeing
|
|
* the data when done with it.
|
|
* @param inode inode of the "file"
|
|
* @param readStart where in the data to start reading
|
|
* @param readSize how much data to read
|
|
* @param data pointer to the pointer where the data is stored
|
|
* @param size pointer to a value that will be assigned the size of data
|
|
* @return 0 if read is a success
|
|
*/
|
|
template<typename T>
|
|
int read(Inode *inode, typename Header::FsSize_t readStart,
|
|
typename Header::FsSize_t readSize, T *data,
|
|
typename Header::FsSize_t *size);
|
|
|
|
/**
|
|
* Removes the inode of the given ID.
|
|
* @param id the id of the file
|
|
*/
|
|
int remove(Inode *root, InodeId_t id);
|
|
|
|
/**
|
|
* Removes the given node from the linked list.
|
|
* @param node node to remove
|
|
*/
|
|
void dealloc(Inode *node);
|
|
|
|
/**
|
|
* Gets the address of the next available inode, assuming there is a next
|
|
* available inode.
|
|
*/
|
|
typename Header::FsSize_t nextInodeAddr();
|
|
|
|
/**
|
|
* Gets an address for a new Inode.
|
|
* @param size the size of the Inode
|
|
*/
|
|
void *alloc(typename Header::FsSize_t size);
|
|
|
|
/**
|
|
* Compacts all of the inodes into a contiguous space, starting at the first inode.
|
|
*/
|
|
void compact();
|
|
|
|
/**
|
|
* Inserts the given insertValue into the tree of the given root.
|
|
* If the inode already exists, it replaces the old on deletes it.
|
|
* @return true if the inode was inserted
|
|
*/
|
|
bool insert(Inode *root, Inode *insertValue);
|
|
|
|
typename Header::FsSize_t firstInode();
|
|
|
|
typename Header::FsSize_t lastInode();
|
|
|
|
/**
|
|
* Updates the address of the inode in the tree.
|
|
*/
|
|
void updateInodeAddress(InodeId_t id, typename Header::FsSize_t oldAddr, typename Header::FsSize_t newAddr);
|
|
|
|
uint8_t *begin() {
|
|
return (uint8_t*) this;
|
|
}
|
|
|
|
uint8_t *end() {
|
|
return begin() + this->m_header.getSize();
|
|
}
|
|
|
|
/**
|
|
* Converts an actual pointer to a FsSize_t.
|
|
*/
|
|
typename Header::FsSize_t ptr(void *ptr);
|
|
|
|
/**
|
|
* Converts a FsSize_t to an actual pointer.
|
|
*/
|
|
template<typename T>
|
|
T ptr(typename Header::FsSize_t ptr) {
|
|
return (T) (begin() + ptr);
|
|
};
|
|
|
|
};
|
|
|
|
template<typename Header>
|
|
typename Header::FsSize_t FileStore<Header>::Inode::size() {
|
|
return sizeof(Inode) + getDataLen();
|
|
}
|
|
|
|
template<typename Header>
|
|
void FileStore<Header>::Inode::setDataLen(typename Header::FsSize_t dataLen) {
|
|
this->m_dataLen = std::bigEndianAdapt(dataLen);
|
|
}
|
|
|
|
template<typename Header>
|
|
typename Header::FsSize_t FileStore<Header>::Inode::getDataLen() {
|
|
return std::bigEndianAdapt(m_dataLen);
|
|
}
|
|
|
|
template<typename Header>
|
|
void FileStore<Header>::Inode::setPrev(typename Header::FsSize_t prev) {
|
|
this->m_prev = std::bigEndianAdapt(prev);
|
|
}
|
|
|
|
template<typename Header>
|
|
typename Header::FsSize_t FileStore<Header>::Inode::getPrev() {
|
|
return std::bigEndianAdapt(m_prev);
|
|
}
|
|
|
|
template<typename Header>
|
|
void FileStore<Header>::Inode::setNext(typename Header::FsSize_t next) {
|
|
this->m_next = std::bigEndianAdapt(next);
|
|
}
|
|
|
|
template<typename Header>
|
|
typename Header::FsSize_t FileStore<Header>::Inode::getNext() {
|
|
return std::bigEndianAdapt(m_next);
|
|
}
|
|
|
|
template<typename Header>
|
|
void FileStore<Header>::Inode::setId(InodeId_t id) {
|
|
this->m_id = std::bigEndianAdapt(id);
|
|
}
|
|
|
|
template<typename Header>
|
|
typename Header::InodeId_t FileStore<Header>::Inode::getId() {
|
|
return std::bigEndianAdapt(m_id);
|
|
}
|
|
|
|
template<typename Header>
|
|
void FileStore<Header>::Inode::setFileType(uint8_t fileType) {
|
|
this->m_fileType = std::bigEndianAdapt(fileType);
|
|
}
|
|
|
|
template<typename Header>
|
|
uint8_t FileStore<Header>::Inode::getFileType() {
|
|
return std::bigEndianAdapt(m_fileType);
|
|
}
|
|
|
|
template<typename Header>
|
|
void FileStore<Header>::Inode::setLeft(typename Header::FsSize_t left) {
|
|
this->m_left = std::bigEndianAdapt(left);
|
|
}
|
|
|
|
template<typename Header>
|
|
typename Header::FsSize_t FileStore<Header>::Inode::getLeft() {
|
|
return std::bigEndianAdapt(m_left);
|
|
}
|
|
|
|
template<typename Header>
|
|
void FileStore<Header>::Inode::setRight(typename Header::FsSize_t right) {
|
|
this->m_right = std::bigEndianAdapt(right);
|
|
}
|
|
|
|
template<typename Header>
|
|
typename Header::FsSize_t FileStore<Header>::Inode::getRight() {
|
|
return std::bigEndianAdapt(m_right);
|
|
}
|
|
|
|
template<typename Header>
|
|
void FileStore<Header>::Inode::setData(void *data, typename Header::FsSize_t size) {
|
|
ox_memcpy(getData(), data, size);
|
|
setDataLen(size);
|
|
}
|
|
|
|
|
|
template<typename Header>
|
|
uint8_t *FileStore<Header>::Inode::getData() {
|
|
return (uint8_t*) (this + 1);
|
|
}
|
|
|
|
|
|
// FileStore
|
|
|
|
template<typename Header>
|
|
int FileStore<Header>::dumpTo(FileStore<Header> *dest) {
|
|
if (dest->size() >= size()) {
|
|
auto i = ptr<Inode*>(firstInode());
|
|
do {
|
|
dest->write(i->getId(), i->getData(), i->getDataLen(), i->getFileType());
|
|
i = ptr<Inode*>(i->getNext());
|
|
} while (ptr(i) != firstInode());
|
|
return 0;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
template<typename Header>
|
|
void FileStore<Header>::resize(typename Header::FsSize_t size) {
|
|
if (size < m_header.getSize()) {
|
|
// shrink file store
|
|
if (m_header.getMemUsed() > size) {
|
|
size = m_header.getMemUsed();
|
|
}
|
|
compact();
|
|
m_header.setSize(size);
|
|
} else if (size > m_header.getSize()) {
|
|
// grow file store
|
|
m_header.setSize(size);
|
|
}
|
|
}
|
|
|
|
template<typename Header>
|
|
int FileStore<Header>::write(InodeId_t id, void *data, typename Header::FsSize_t dataLen, uint8_t fileType) {
|
|
auto retval = 1;
|
|
const typename Header::FsSize_t size = sizeof(Inode) + dataLen;
|
|
if (size <= (m_header.getSize() - m_header.getMemUsed())) {
|
|
auto inode = (Inode*) alloc(size);
|
|
if (inode) {
|
|
remove(id);
|
|
inode->setId(id);
|
|
inode->setFileType(fileType);
|
|
inode->setData(data, dataLen);
|
|
auto root = ptr<Inode*>(m_header.getRootInode());
|
|
if (insert(root, inode) || root == inode) {
|
|
retval = 0;
|
|
} else {
|
|
dealloc(inode);
|
|
retval = 2;
|
|
}
|
|
} else {
|
|
retval = 3;
|
|
}
|
|
} else {
|
|
retval = 4;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
template<typename Header>
|
|
int FileStore<Header>::remove(InodeId_t id) {
|
|
return remove(ptr<Inode*>(m_header.getRootInode()), id);
|
|
}
|
|
|
|
template<typename Header>
|
|
int FileStore<Header>::remove(Inode *root, InodeId_t id) {
|
|
auto err = 1;
|
|
|
|
if (root->getId() > id) {
|
|
if (root->getLeft()) {
|
|
auto left = ptr<Inode*>(root->getLeft());
|
|
if (left->getId() != id) {
|
|
err = remove(left, id);
|
|
} else {
|
|
root->setLeft(0);
|
|
// pass children to parent
|
|
if (left->getRight()) {
|
|
insert(root, ptr<Inode*>(left->getRight()));
|
|
}
|
|
if (left->getLeft()) {
|
|
insert(root, ptr<Inode*>(left->getLeft()));
|
|
}
|
|
dealloc(left);
|
|
err = 0;
|
|
}
|
|
}
|
|
} else if (root->getId() < id) {
|
|
if (root->getRight()) {
|
|
auto right = ptr<Inode*>(root->getRight());
|
|
if (right->getId() != id) {
|
|
err = remove(right, id);
|
|
} else {
|
|
root->setRight(0);
|
|
// pass children to parent
|
|
if (right->getRight()) {
|
|
insert(root, ptr<Inode*>(right->getRight()));
|
|
}
|
|
if (right->getLeft()) {
|
|
insert(root, ptr<Inode*>(right->getLeft()));
|
|
}
|
|
dealloc(right);
|
|
err = 0;
|
|
}
|
|
}
|
|
} else if (ptr<Inode*>(m_header.getRootInode())->getId() == id) {
|
|
m_header.setRootInode(root->getRight());
|
|
if (root->getLeft()) {
|
|
insert(ptr<Inode*>(m_header.getRootInode()), ptr<Inode*>(root->getLeft()));
|
|
}
|
|
dealloc(root);
|
|
err = 0;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
template<typename Header>
|
|
void FileStore<Header>::dealloc(Inode *inode) {
|
|
auto next = ptr<Inode*>(inode->getNext());
|
|
auto prev = ptr<Inode*>(inode->getPrev());
|
|
prev->setNext(ptr(next));
|
|
next->setPrev(ptr(prev));
|
|
|
|
m_header.setMemUsed(m_header.getMemUsed() - inode->size());
|
|
|
|
ox_memset(inode, 0, inode->size());
|
|
}
|
|
|
|
template<typename Header>
|
|
void FileStore<Header>::updateInodeAddress(InodeId_t id, typename Header::FsSize_t oldAddr, typename Header::FsSize_t newAddr) {
|
|
auto parent = getInodeParent(ptr<Inode*>(m_header.getRootInode()), id, oldAddr);
|
|
if (parent) {
|
|
if (parent->getLeft() == oldAddr) {
|
|
parent->setLeft(newAddr);
|
|
} else if (parent->getRight() == oldAddr) {
|
|
parent->setRight(newAddr);
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename Header>
|
|
int FileStore<Header>::read(InodeId_t id, void *data, typename Header::FsSize_t *size) {
|
|
auto inode = getInode(ptr<Inode*>(m_header.getRootInode()), id);
|
|
return inode ? read(inode, 0, inode->getDataLen(), (uint8_t*) data, size) : 1;
|
|
}
|
|
|
|
template<typename Header>
|
|
int FileStore<Header>::read(InodeId_t id, typename Header::FsSize_t readStart,
|
|
typename Header::FsSize_t readSize, void *data, typename Header::FsSize_t *size) {
|
|
auto inode = getInode(ptr<Inode*>(m_header.getRootInode()), id);
|
|
return inode ? read<uint8_t>(inode, readStart, readSize, (uint8_t*) data, size) : 1;
|
|
}
|
|
|
|
template<typename Header>
|
|
template<typename T>
|
|
int FileStore<Header>::read(InodeId_t id, typename Header::FsSize_t readStart,
|
|
typename Header::FsSize_t readSize, T *data, typename Header::FsSize_t *size) {
|
|
auto inode = getInode(ptr<Inode*>(m_header.getRootInode()), id);
|
|
return inode ? read(inode, readStart, readSize, data, size) : 1;
|
|
}
|
|
|
|
template<typename Header>
|
|
template<typename T>
|
|
int FileStore<Header>::read(Inode *inode, typename Header::FsSize_t readStart,
|
|
typename Header::FsSize_t readSize, T *data, typename Header::FsSize_t *size) {
|
|
// be sure read size is not greater than what is available to read
|
|
if (inode->getDataLen() - readStart < readSize) {
|
|
readSize = inode->getDataLen() - readStart;
|
|
}
|
|
if (size) {
|
|
*size = readSize;
|
|
}
|
|
|
|
readSize /= sizeof(T);
|
|
T *it = (T*) &(inode->getData()[readStart]);
|
|
for (typename Header::FsSize_t i = 0; i < readSize; i++) {
|
|
*(data++) = *(it++);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
template<typename Header>
|
|
typename FileStore<Header>::StatInfo FileStore<Header>::stat(InodeId_t id) {
|
|
auto inode = getInode(ptr<Inode*>(m_header.getRootInode()), id);
|
|
StatInfo stat;
|
|
if (inode) {
|
|
stat.size = inode->getDataLen();
|
|
stat.fileType = inode->getFileType();
|
|
stat.inodeId = id;
|
|
} else {
|
|
stat.inodeId = 0;
|
|
}
|
|
return stat;
|
|
}
|
|
|
|
template<typename Header>
|
|
typename Header::FsSize_t FileStore<Header>::spaceNeeded(typename Header::FsSize_t size) {
|
|
return sizeof(Inode) + size;
|
|
}
|
|
|
|
template<typename Header>
|
|
typename Header::FsSize_t FileStore<Header>::size() {
|
|
return m_header.getSize();
|
|
}
|
|
|
|
template<typename Header>
|
|
typename Header::FsSize_t FileStore<Header>::available() {
|
|
return m_header.getSize() - m_header.getMemUsed();
|
|
}
|
|
|
|
template<typename Header>
|
|
typename FileStore<Header>::Inode *FileStore<Header>::getInode(Inode *root, InodeId_t id) {
|
|
Inode *retval = nullptr;
|
|
|
|
if (root->getId() > id) {
|
|
if (root->getLeft()) {
|
|
retval = getInode(ptr<Inode*>(root->getLeft()), id);
|
|
}
|
|
} else if (root->getId() < id) {
|
|
if (root->getRight()) {
|
|
retval = getInode(ptr<Inode*>(root->getRight()), id);
|
|
}
|
|
} else if (root->getId() == id) {
|
|
retval = root;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
template<typename Header>
|
|
typename FileStore<Header>::Inode *FileStore<Header>::getInodeParent(Inode *root, InodeId_t id, typename Header::FsSize_t targetAddr) {
|
|
Inode *retval = nullptr;
|
|
|
|
if (root->getId() > id) {
|
|
if (root->getLeft()) {
|
|
if (root->getLeft() == targetAddr) {
|
|
retval = root;
|
|
} else {
|
|
retval = getInodeParent(ptr<Inode*>(root->getLeft()), id, targetAddr);
|
|
}
|
|
}
|
|
} else if (root->getId() < id) {
|
|
if (root->getRight()) {
|
|
if (root->getRight() == targetAddr) {
|
|
retval = root;
|
|
} else {
|
|
retval = getInodeParent(ptr<Inode*>(root->getRight()), id, targetAddr);
|
|
}
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
template<typename Header>
|
|
typename Header::FsSize_t FileStore<Header>::nextInodeAddr() {
|
|
return lastInode() + ptr<Inode*>(lastInode())->size();
|
|
}
|
|
|
|
template<typename Header>
|
|
void *FileStore<Header>::alloc(typename Header::FsSize_t size) {
|
|
auto next = nextInodeAddr();
|
|
if ((next + size) > ptr(end())) {
|
|
compact();
|
|
next = nextInodeAddr();
|
|
if ((next + size) > ptr(end())) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
const auto retval = next;
|
|
const auto inode = ptr<Inode*>(retval);
|
|
ox_memset(inode, 0, size);
|
|
inode->setPrev(ptr<Inode*>(firstInode())->getPrev());
|
|
inode->setNext(firstInode());
|
|
m_header.setMemUsed(m_header.getMemUsed() + size);
|
|
ptr<Inode*>(lastInode())->setNext(retval);
|
|
ptr<Inode*>(firstInode())->setPrev(retval);
|
|
return inode;
|
|
}
|
|
|
|
template<typename Header>
|
|
void FileStore<Header>::compact() {
|
|
auto dest = ptr<Inode*>(firstInode());
|
|
auto current = ptr<Inode*>(firstInode());
|
|
while (current->getNext() > firstInode() && current->getNext() < ptr(end())) {
|
|
ox_memcpy(dest, current, current->size());
|
|
if (dest->getNext() != firstInode()) {
|
|
dest->setNext(ptr(dest) + dest->size());
|
|
}
|
|
ptr<Inode*>(dest->getNext())->setPrev(ptr(dest));
|
|
updateInodeAddress(dest->getId(), ptr(current), ptr(dest));
|
|
current = ptr<Inode*>(dest->getNext());
|
|
dest = ptr<Inode*>(ptr(dest) + dest->size());
|
|
}
|
|
}
|
|
|
|
template<typename Header>
|
|
bool FileStore<Header>::insert(Inode *root, Inode *insertValue) {
|
|
auto retval = false;
|
|
|
|
if (root->getId() > insertValue->getId()) {
|
|
if (root->getLeft()) {
|
|
retval = insert(ptr<Inode*>(root->getLeft()), insertValue);
|
|
} else {
|
|
root->setLeft(ptr(insertValue));
|
|
retval = true;
|
|
}
|
|
} else if (root->getId() < insertValue->getId()) {
|
|
if (root->getRight()) {
|
|
retval = insert(ptr<Inode*>(root->getRight()), insertValue);
|
|
} else {
|
|
root->setRight(ptr(insertValue));
|
|
retval = true;
|
|
}
|
|
} else if (m_header.getRootInode() == 0) {
|
|
m_header.setRootInode(ptr(insertValue));
|
|
retval = true;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
template<typename Header>
|
|
typename Header::FsSize_t FileStore<Header>::ptr(void *ptr) {
|
|
#ifdef _MSC_VER
|
|
#pragma warning(disable:4244)
|
|
#endif
|
|
return ((uint8_t*) ptr) - begin();
|
|
#ifdef _MSC_VER
|
|
#pragma warning(default:4244)
|
|
#endif
|
|
}
|
|
|
|
template<typename Header>
|
|
typename Header::FsSize_t FileStore<Header>::firstInode() {
|
|
return sizeof(FileStore<Header>);
|
|
}
|
|
|
|
template<typename Header>
|
|
typename Header::FsSize_t FileStore<Header>::lastInode() {
|
|
return ptr<Inode*>(firstInode())->getPrev();
|
|
}
|
|
|
|
template<typename Header>
|
|
uint16_t FileStore<Header>::fsType() {
|
|
return m_header.getFsType();
|
|
};
|
|
|
|
template<typename Header>
|
|
uint16_t FileStore<Header>::version() {
|
|
return m_header.getVersion();
|
|
};
|
|
|
|
template<typename Header>
|
|
uint8_t *FileStore<Header>::format(uint8_t *buffer, typename Header::FsSize_t size, uint16_t fsType) {
|
|
ox_memset(buffer, 0, size);
|
|
|
|
auto *fs = (FileStore*) buffer;
|
|
fs->m_header.setFsType(fsType);
|
|
fs->m_header.setVersion(Header::VERSION);
|
|
fs->m_header.setSize(size);
|
|
fs->m_header.setMemUsed(sizeof(FileStore<Header>) + sizeof(Inode));
|
|
fs->m_header.setRootInode(sizeof(FileStore<Header>));
|
|
((Inode*) (fs + 1))->setPrev(sizeof(FileStore<Header>));
|
|
((Inode*) (fs + 1))->setNext(sizeof(FileStore<Header>));
|
|
|
|
return (uint8_t*) buffer;
|
|
}
|
|
|
|
typedef FileStore<FileStoreHeader<uint16_t, uint16_t>> FileStore16;
|
|
typedef FileStore<FileStoreHeader<uint32_t, uint64_t>> FileStore32;
|
|
typedef FileStore<FileStoreHeader<uint64_t, uint64_t>> FileStore64;
|
|
|
|
}
|
|
}
|