mirror of
https://github.com/Fennix-Project/Kernel.git
synced 2025-07-10 23:09:18 +00:00
Restructured and rewritten entire codebase
This commit is contained in:
642
storage/file_descriptor.cpp
Normal file
642
storage/file_descriptor.cpp
Normal file
@ -0,0 +1,642 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem.hpp>
|
||||
|
||||
#include <smart_ptr.hpp>
|
||||
#include <convert.h>
|
||||
#include <stropts.h>
|
||||
#include <task.hpp>
|
||||
#include <printf.h>
|
||||
#include <lock.hpp>
|
||||
#include <cwalk.h>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
// ReadFSFunction(fd_Read)
|
||||
// {
|
||||
// if (Size <= 0)
|
||||
// Size = node->Length;
|
||||
|
||||
// if (RefOffset > node->Length)
|
||||
// return 0;
|
||||
|
||||
// if ((node->Length - RefOffset) == 0)
|
||||
// return 0; /* EOF */
|
||||
|
||||
// if (RefOffset + (off_t)Size > node->Length)
|
||||
// Size = node->Length;
|
||||
|
||||
// memcpy(Buffer, (uint8_t *)(node->Address + RefOffset), Size);
|
||||
// return Size;
|
||||
// }
|
||||
|
||||
// WriteFSFunction(fd_Write)
|
||||
// {
|
||||
// if (Size <= 0)
|
||||
// Size = node->Length;
|
||||
|
||||
// if (RefOffset > node->Length)
|
||||
// return 0;
|
||||
|
||||
// if (RefOffset + (off_t)Size > node->Length)
|
||||
// Size = node->Length;
|
||||
|
||||
// memcpy((uint8_t *)(node->Address + RefOffset), Buffer, Size);
|
||||
// return Size;
|
||||
// }
|
||||
|
||||
// vfs::FileSystemOperations fd_op = {
|
||||
// .Name = "fd",
|
||||
// // .Read = fd_Read,
|
||||
// // .Write = fd_Write,
|
||||
// };
|
||||
|
||||
FileDescriptorTable::Fildes
|
||||
FileDescriptorTable::GetFileDescriptor(int FileDescriptor)
|
||||
{
|
||||
foreach (auto fd in FileDescriptors)
|
||||
{
|
||||
if (fd.Descriptor == FileDescriptor)
|
||||
{
|
||||
// debug("Found file descriptor %d", FileDescriptor);
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
FileDescriptorTable::DupFildes
|
||||
FileDescriptorTable::GetDupFildes(int FileDescriptor)
|
||||
{
|
||||
foreach (auto fd in FildesDuplicates)
|
||||
{
|
||||
if (fd.Descriptor == FileDescriptor)
|
||||
{
|
||||
debug("Found duplicated file descriptor %d", FileDescriptor);
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
int FileDescriptorTable::ProbeMode(mode_t Mode, int Flags)
|
||||
{
|
||||
if (!(Flags & O_CREAT))
|
||||
return 0;
|
||||
|
||||
if (Flags & O_RDONLY)
|
||||
{
|
||||
if (!(Mode & S_IRUSR))
|
||||
{
|
||||
debug("No read permission (%d)", Mode);
|
||||
return -EACCES;
|
||||
}
|
||||
}
|
||||
|
||||
if (Flags & O_WRONLY)
|
||||
{
|
||||
if (!(Mode & S_IWUSR))
|
||||
{
|
||||
debug("No write permission (%d)", Mode);
|
||||
return -EACCES;
|
||||
}
|
||||
}
|
||||
|
||||
if (Flags & O_RDWR)
|
||||
{
|
||||
if (!(Mode & S_IRUSR) ||
|
||||
!(Mode & S_IWUSR))
|
||||
{
|
||||
debug("No read/write permission (%d)", Mode);
|
||||
return -EACCES;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FileDescriptorTable::AddFileDescriptor(const char *AbsolutePath,
|
||||
mode_t Mode, int Flags)
|
||||
{
|
||||
Tasking::PCB *pcb = thisProcess;
|
||||
|
||||
if (ProbeMode(Mode, Flags) < 0)
|
||||
return -EACCES;
|
||||
|
||||
if (Flags & O_CREAT)
|
||||
{
|
||||
int ret;
|
||||
Node *n = new Node(pcb->CurrentWorkingDirectory,
|
||||
AbsolutePath,
|
||||
NodeType::FILE,
|
||||
cwk_path_is_absolute(AbsolutePath),
|
||||
fs,
|
||||
&ret);
|
||||
|
||||
if (ret == -EEXIST)
|
||||
{
|
||||
debug("%s: File already exists, continuing...",
|
||||
AbsolutePath);
|
||||
}
|
||||
else if (ret < 0)
|
||||
{
|
||||
error("Failed to create file %s: %d",
|
||||
AbsolutePath, ret);
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (Flags & O_EXCL)
|
||||
{
|
||||
RefNode *File = fs->Open(AbsolutePath,
|
||||
pcb->CurrentWorkingDirectory);
|
||||
|
||||
if (!File)
|
||||
{
|
||||
error("Failed to open file %s",
|
||||
AbsolutePath);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
if (Flags & O_TRUNC)
|
||||
{
|
||||
fixme("O_TRUNC");
|
||||
}
|
||||
|
||||
if (Flags & O_APPEND)
|
||||
{
|
||||
fixme("O_APPEND");
|
||||
}
|
||||
|
||||
if (Flags & O_CLOEXEC)
|
||||
{
|
||||
fixme("O_CLOEXEC");
|
||||
}
|
||||
|
||||
RefNode *File = fs->Open(AbsolutePath,
|
||||
pcb->CurrentWorkingDirectory);
|
||||
|
||||
if (!File)
|
||||
{
|
||||
error("Failed to open file %s",
|
||||
AbsolutePath);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
Fildes fd = {.Descriptor = GetFreeFileDescriptor()};
|
||||
|
||||
if (fd.Descriptor < 0)
|
||||
return -EMFILE;
|
||||
|
||||
fd.Mode = Mode;
|
||||
fd.Flags = Flags;
|
||||
fd.Handle = File;
|
||||
|
||||
FileDescriptors.push_back(fd);
|
||||
|
||||
char FileName[64];
|
||||
sprintf(FileName, "%d", fd.Descriptor);
|
||||
vfs::Node *n = fs->Create(FileName, vfs::NodeType::FILE, this->fdDir);
|
||||
if (n)
|
||||
{
|
||||
/* FIXME: Implement proper file descriptors */
|
||||
n->Size = File->FileSize;
|
||||
}
|
||||
|
||||
return fd.Descriptor;
|
||||
}
|
||||
|
||||
int FileDescriptorTable::RemoveFileDescriptor(int FileDescriptor)
|
||||
{
|
||||
forItr(itr, FileDescriptors)
|
||||
{
|
||||
if (itr->Descriptor == FileDescriptor)
|
||||
{
|
||||
FileDescriptors.erase(itr);
|
||||
|
||||
char FileName[64];
|
||||
sprintf(FileName, "%d", FileDescriptor);
|
||||
fs->Delete(FileName, false, this->fdDir);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
forItr(itr, FildesDuplicates)
|
||||
{
|
||||
if (itr->Descriptor == FileDescriptor)
|
||||
{
|
||||
FildesDuplicates.erase(itr);
|
||||
|
||||
char FileName[64];
|
||||
sprintf(FileName, "%d", FileDescriptor);
|
||||
fs->Delete(FileName, false, this->fdDir);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
int FileDescriptorTable::GetFreeFileDescriptor()
|
||||
{
|
||||
int i = 0;
|
||||
while (true)
|
||||
{
|
||||
bool Found = false;
|
||||
foreach (auto fd in FileDescriptors)
|
||||
{
|
||||
if (fd.Descriptor == i)
|
||||
{
|
||||
Found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Found)
|
||||
{
|
||||
foreach (auto fd in FildesDuplicates)
|
||||
{
|
||||
if (fd.Descriptor == i)
|
||||
{
|
||||
Found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!Found)
|
||||
return i;
|
||||
i++;
|
||||
}
|
||||
|
||||
return -EMFILE;
|
||||
}
|
||||
|
||||
const char *FileDescriptorTable::GetAbsolutePath(int FileDescriptor)
|
||||
{
|
||||
Fildes fd = this->GetFileDescriptor(FileDescriptor);
|
||||
DupFildes dfd = this->GetDupFildes(FileDescriptor);
|
||||
|
||||
if (fd.Descriptor == -1 &&
|
||||
dfd.Descriptor == -1)
|
||||
return "";
|
||||
|
||||
RefNode *hnd = nullptr;
|
||||
if (fd.Descriptor != -1)
|
||||
hnd = fd.Handle;
|
||||
else
|
||||
hnd = dfd.Handle;
|
||||
|
||||
Node *node = hnd->node;
|
||||
const char *path = new char[strlen(node->FullPath) + 1];
|
||||
strcpy((char *)path, node->FullPath);
|
||||
return path;
|
||||
}
|
||||
|
||||
int FileDescriptorTable::_open(const char *pathname, int flags,
|
||||
mode_t mode)
|
||||
{
|
||||
if (pathname == nullptr)
|
||||
return -EFAULT;
|
||||
|
||||
return AddFileDescriptor(pathname, mode, flags);
|
||||
}
|
||||
|
||||
int FileDescriptorTable::_creat(const char *pathname, mode_t mode)
|
||||
{
|
||||
return _open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode);
|
||||
}
|
||||
|
||||
ssize_t FileDescriptorTable::_read(int fd, void *buf, size_t count)
|
||||
{
|
||||
Fildes fdesc = this->GetFileDescriptor(fd);
|
||||
DupFildes dfdesc = this->GetDupFildes(fd);
|
||||
if (fdesc.Descriptor < 0 &&
|
||||
dfdesc.Descriptor < 0)
|
||||
{
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
RefNode *hnd = nullptr;
|
||||
if (fdesc.Descriptor != -1)
|
||||
hnd = fdesc.Handle;
|
||||
else
|
||||
hnd = dfdesc.Handle;
|
||||
|
||||
return hnd->read((uint8_t *)buf, count);
|
||||
}
|
||||
|
||||
ssize_t FileDescriptorTable::_write(int fd, const void *buf,
|
||||
size_t count)
|
||||
{
|
||||
Fildes fdesc = this->GetFileDescriptor(fd);
|
||||
DupFildes dfdesc = this->GetDupFildes(fd);
|
||||
if (fdesc.Descriptor < 0 &&
|
||||
dfdesc.Descriptor < 0)
|
||||
{
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
RefNode *hnd = nullptr;
|
||||
if (fdesc.Descriptor != -1)
|
||||
hnd = fdesc.Handle;
|
||||
else
|
||||
hnd = dfdesc.Handle;
|
||||
|
||||
return hnd->write((uint8_t *)buf, count);
|
||||
}
|
||||
|
||||
int FileDescriptorTable::_close(int fd)
|
||||
{
|
||||
Fildes fdesc = this->GetFileDescriptor(fd);
|
||||
DupFildes dfdesc = this->GetDupFildes(fd);
|
||||
|
||||
if (fdesc.Descriptor < 0 &&
|
||||
dfdesc.Descriptor < 0)
|
||||
{
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
if (RemoveFileDescriptor(fd) < 0)
|
||||
return -EBADF;
|
||||
|
||||
/* If the file descriptor is a duplicate,
|
||||
we don't need to close the handle,
|
||||
because it's a duplicate of another
|
||||
file descriptor. */
|
||||
|
||||
bool Found = false;
|
||||
RefNode *hnd = nullptr;
|
||||
|
||||
if (fdesc.Descriptor != -1)
|
||||
hnd = fdesc.Handle;
|
||||
else
|
||||
hnd = dfdesc.Handle;
|
||||
|
||||
foreach (auto dfd in FileDescriptors)
|
||||
{
|
||||
if (dfd.Handle == hnd)
|
||||
{
|
||||
Found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (auto dfd in FildesDuplicates)
|
||||
{
|
||||
if (dfd.Handle == hnd)
|
||||
{
|
||||
Found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Found)
|
||||
delete hnd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
off_t FileDescriptorTable::_lseek(int fd, off_t offset, int whence)
|
||||
{
|
||||
Fildes fdesc = this->GetFileDescriptor(fd);
|
||||
DupFildes dfdesc = this->GetDupFildes(fd);
|
||||
|
||||
if (fdesc.Descriptor < 0 &&
|
||||
dfdesc.Descriptor < 0)
|
||||
{
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
RefNode *hnd = nullptr;
|
||||
if (fdesc.Descriptor != -1)
|
||||
hnd = fdesc.Handle;
|
||||
else
|
||||
hnd = dfdesc.Handle;
|
||||
|
||||
return hnd->seek(offset, whence);
|
||||
}
|
||||
|
||||
int FileDescriptorTable::_stat(const char *pathname,
|
||||
struct stat *statbuf)
|
||||
{
|
||||
if (pathname == nullptr)
|
||||
return -EINVAL;
|
||||
|
||||
RefNode *file = fs->Open(pathname,
|
||||
thisProcess->CurrentWorkingDirectory);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
error("Failed to open file %s",
|
||||
pathname);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
Node *node = file->node;
|
||||
statbuf->st_dev = 0; /* FIXME: stub */
|
||||
statbuf->st_ino = node->IndexNode;
|
||||
statbuf->st_mode = node->Type | node->Mode;
|
||||
statbuf->st_nlink = 0; /* FIXME: stub */
|
||||
statbuf->st_uid = node->UserIdentifier;
|
||||
statbuf->st_gid = node->GroupIdentifier;
|
||||
statbuf->st_rdev = 0; /* FIXME: stub */
|
||||
statbuf->st_size = node->Size;
|
||||
statbuf->st_blksize = 0; /* FIXME: stub */
|
||||
statbuf->st_blocks = 0; /* FIXME: stub */
|
||||
statbuf->st_attr = 0; /* FIXME: stub */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FileDescriptorTable::_fstat(int fd, struct stat *statbuf)
|
||||
{
|
||||
Fildes fdesc = this->GetFileDescriptor(fd);
|
||||
DupFildes dfdesc = this->GetDupFildes(fd);
|
||||
|
||||
if (fdesc.Descriptor < 0 &&
|
||||
dfdesc.Descriptor < 0)
|
||||
{
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
RefNode *hnd = nullptr;
|
||||
if (fdesc.Descriptor != -1)
|
||||
hnd = fdesc.Handle;
|
||||
else
|
||||
hnd = dfdesc.Handle;
|
||||
|
||||
Node *node = hnd->node;
|
||||
statbuf->st_dev = 0; /* FIXME: stub */
|
||||
statbuf->st_ino = node->IndexNode;
|
||||
statbuf->st_mode = node->Type | node->Mode;
|
||||
statbuf->st_nlink = 0; /* FIXME: stub */
|
||||
statbuf->st_uid = node->UserIdentifier;
|
||||
statbuf->st_gid = node->GroupIdentifier;
|
||||
statbuf->st_rdev = 0; /* FIXME: stub */
|
||||
statbuf->st_size = node->Size;
|
||||
statbuf->st_blksize = 0; /* FIXME: stub */
|
||||
statbuf->st_blocks = 0; /* FIXME: stub */
|
||||
statbuf->st_attr = 0; /* FIXME: stub */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FileDescriptorTable::_lstat(const char *pathname,
|
||||
struct stat *statbuf)
|
||||
{
|
||||
if (pathname == nullptr)
|
||||
return -EINVAL;
|
||||
|
||||
RefNode *file = fs->Open(pathname,
|
||||
thisProcess->CurrentWorkingDirectory);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
error("Failed to open file %s",
|
||||
pathname);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
Node *node = file->node;
|
||||
statbuf->st_dev = 0; /* FIXME: stub */
|
||||
statbuf->st_ino = node->IndexNode;
|
||||
statbuf->st_mode = node->Type | node->Mode;
|
||||
statbuf->st_nlink = 0; /* FIXME: stub */
|
||||
statbuf->st_uid = node->UserIdentifier;
|
||||
statbuf->st_gid = node->GroupIdentifier;
|
||||
statbuf->st_rdev = 0; /* FIXME: stub */
|
||||
statbuf->st_size = node->Size;
|
||||
statbuf->st_blksize = 0; /* FIXME: stub */
|
||||
statbuf->st_blocks = 0; /* FIXME: stub */
|
||||
statbuf->st_attr = 0; /* FIXME: stub */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FileDescriptorTable::_dup(int oldfd)
|
||||
{
|
||||
Fildes fdesc = this->GetFileDescriptor(oldfd);
|
||||
DupFildes dfdesc = this->GetDupFildes(oldfd);
|
||||
|
||||
if (fdesc.Descriptor < 0 &&
|
||||
dfdesc.Descriptor < 0)
|
||||
{
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
int newfd = this->GetFreeFileDescriptor();
|
||||
if (newfd < 0)
|
||||
return -EMFILE;
|
||||
|
||||
DupFildes new_dfd{};
|
||||
if (fdesc.Descriptor != -1)
|
||||
{
|
||||
new_dfd.Handle = fdesc.Handle;
|
||||
new_dfd.Mode = fdesc.Mode;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_dfd.Handle = dfdesc.Handle;
|
||||
new_dfd.Mode = dfdesc.Mode;
|
||||
}
|
||||
|
||||
new_dfd.Descriptor = newfd;
|
||||
this->FildesDuplicates.push_back(new_dfd);
|
||||
debug("Duplicated file descriptor %d to %d",
|
||||
oldfd, newfd);
|
||||
return newfd;
|
||||
}
|
||||
|
||||
int FileDescriptorTable::_dup2(int oldfd, int newfd)
|
||||
{
|
||||
Fildes fdesc = this->GetFileDescriptor(oldfd);
|
||||
DupFildes dfdesc = this->GetDupFildes(oldfd);
|
||||
|
||||
if (fdesc.Descriptor < 0 &&
|
||||
dfdesc.Descriptor < 0)
|
||||
{
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
if (newfd < 0)
|
||||
return -EBADF;
|
||||
|
||||
if (newfd == oldfd)
|
||||
return newfd;
|
||||
|
||||
/* Even if it's not valid
|
||||
we ignore it. */
|
||||
this->_close(newfd);
|
||||
|
||||
DupFildes new_dfd{};
|
||||
if (fdesc.Descriptor != -1)
|
||||
{
|
||||
new_dfd.Handle = fdesc.Handle;
|
||||
new_dfd.Mode = fdesc.Mode;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_dfd.Handle = dfdesc.Handle;
|
||||
new_dfd.Mode = dfdesc.Mode;
|
||||
}
|
||||
|
||||
new_dfd.Descriptor = newfd;
|
||||
this->FildesDuplicates.push_back(new_dfd);
|
||||
debug("Duplicated file descriptor %d to %d",
|
||||
oldfd, newfd);
|
||||
return newfd;
|
||||
}
|
||||
|
||||
int FileDescriptorTable::_ioctl(int fd, unsigned long request, void *argp)
|
||||
{
|
||||
Fildes fdesc = this->GetFileDescriptor(fd);
|
||||
DupFildes dfdesc = this->GetDupFildes(fd);
|
||||
if (fdesc.Descriptor < 0 &&
|
||||
dfdesc.Descriptor < 0)
|
||||
{
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
RefNode *hnd = nullptr;
|
||||
if (fdesc.Descriptor != -1)
|
||||
hnd = fdesc.Handle;
|
||||
else
|
||||
hnd = dfdesc.Handle;
|
||||
|
||||
return hnd->ioctl(request, argp);
|
||||
}
|
||||
|
||||
FileDescriptorTable::FileDescriptorTable(void *Owner)
|
||||
{
|
||||
debug("+ %#lx", this);
|
||||
this->fdDir = fs->Create("fd", vfs::NodeType::DIRECTORY,
|
||||
((Tasking::PCB *)Owner)->ProcessDirectory);
|
||||
}
|
||||
|
||||
FileDescriptorTable::~FileDescriptorTable()
|
||||
{
|
||||
debug("- %#lx", this);
|
||||
foreach (auto fd in FileDescriptors)
|
||||
{
|
||||
debug("Removing fd: %d(%#lx)",
|
||||
fd.Descriptor, fd);
|
||||
this->RemoveFileDescriptor(fd.Descriptor);
|
||||
delete fd.Handle;
|
||||
}
|
||||
}
|
||||
}
|
402
storage/filesystem.cpp
Normal file
402
storage/filesystem.cpp
Normal file
@ -0,0 +1,402 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem.hpp>
|
||||
|
||||
#include <smart_ptr.hpp>
|
||||
#include <convert.h>
|
||||
#include <printf.h>
|
||||
#include <cwalk.h>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
// show debug messages
|
||||
// #define DEBUG_FILESYSTEM 1
|
||||
|
||||
#ifdef DEBUG_FILESYSTEM
|
||||
#define vfsdbg(m, ...) debug(m, ##__VA_ARGS__)
|
||||
#else
|
||||
#define vfsdbg(m, ...)
|
||||
#endif
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
Node *Virtual::GetNodeFromPath_Unsafe(const char *Path, Node *Parent)
|
||||
{
|
||||
vfsdbg("GetNodeFromPath( Path: \"%s\" Parent: \"%s\" )",
|
||||
Path, Parent ? Parent->Name : "(null)");
|
||||
|
||||
if (strcmp(Path, "/") == 0)
|
||||
return FileSystemRoot->Children[0]; // 0 - filesystem root
|
||||
|
||||
if (strcmp(Path, ".") == 0)
|
||||
return Parent;
|
||||
|
||||
if (strcmp(Path, "..") == 0)
|
||||
{
|
||||
if (Parent)
|
||||
{
|
||||
if (Parent->Parent)
|
||||
return Parent->Parent;
|
||||
else
|
||||
return Parent;
|
||||
}
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Node *ReturnNode = Parent;
|
||||
bool IsAbsolutePath = cwk_path_is_absolute(Path);
|
||||
|
||||
if (!ReturnNode)
|
||||
ReturnNode = FileSystemRoot->Children[0]; // 0 - filesystem root
|
||||
|
||||
if (IsAbsolutePath)
|
||||
ReturnNode = FileSystemRoot->Children[0]; // 0 - filesystem root
|
||||
|
||||
cwk_segment segment;
|
||||
if (unlikely(!cwk_path_get_first_segment(Path, &segment)))
|
||||
{
|
||||
error("Path doesn't have any segments.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
char *SegmentName = new char[segment.end - segment.begin + 1];
|
||||
memcpy(SegmentName, segment.begin, segment.end - segment.begin);
|
||||
vfsdbg("GetNodeFromPath()->SegmentName: \"%s\"", SegmentName);
|
||||
GetNodeFromPathNextParent:
|
||||
foreach (auto Child in ReturnNode->Children)
|
||||
{
|
||||
vfsdbg("comparing \"%s\" with \"%s\"",
|
||||
Child->Name, SegmentName);
|
||||
if (strcmp(Child->Name, SegmentName) == 0)
|
||||
{
|
||||
ReturnNode = Child;
|
||||
goto GetNodeFromPathNextParent;
|
||||
}
|
||||
}
|
||||
delete[] SegmentName;
|
||||
} while (cwk_path_get_next_segment(&segment));
|
||||
|
||||
const char *basename;
|
||||
cwk_path_get_basename(Path, &basename, nullptr);
|
||||
vfsdbg("BaseName: \"%s\" NodeName: \"%s\"",
|
||||
basename, ReturnNode->Name);
|
||||
|
||||
if (strcmp(basename, ReturnNode->Name) == 0)
|
||||
{
|
||||
vfsdbg("GetNodeFromPath()->\"%s\"", ReturnNode->Name);
|
||||
return ReturnNode;
|
||||
}
|
||||
|
||||
vfsdbg("GetNodeFromPath()->\"(null)\"");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Node *Virtual::GetNodeFromPath(const char *Path, Node *Parent)
|
||||
{
|
||||
SmartLock(VirtualLock);
|
||||
return GetNodeFromPath_Unsafe(Path, Parent);
|
||||
}
|
||||
|
||||
bool Virtual::PathIsRelative(const char *Path)
|
||||
{
|
||||
vfsdbg("PathIsRelative( Path: \"%s\" )", Path);
|
||||
bool IsRelative = cwk_path_is_relative(Path);
|
||||
vfsdbg("PathIsRelative()->\"%s\"",
|
||||
IsRelative ? "true" : "false");
|
||||
return IsRelative;
|
||||
}
|
||||
|
||||
Node *Virtual::GetParent(const char *Path, Node *Parent)
|
||||
{
|
||||
vfsdbg("GetParent( Path: \"%s\" Parent: \"%s\" )",
|
||||
Path, Parent ? Parent->Name : "(nil)");
|
||||
|
||||
if (Parent)
|
||||
{
|
||||
vfsdbg("GetParent()->\"%s\"", Parent->Name);
|
||||
return Parent;
|
||||
}
|
||||
|
||||
Parent = FileSystemRoot->Children[0];
|
||||
|
||||
size_t length;
|
||||
cwk_path_get_root(Path, &length);
|
||||
if (length > 0)
|
||||
{
|
||||
foreach (auto Child in FileSystemRoot->Children)
|
||||
{
|
||||
if (strcmp(Child->Name, Path) == 0)
|
||||
{
|
||||
Parent = Child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vfsdbg("GetParent()->\"%s\"", ParentNode->Name);
|
||||
return Parent;
|
||||
}
|
||||
|
||||
const char *Virtual::NormalizePath(const char *Path, Node *Parent)
|
||||
{
|
||||
assert(Parent != nullptr);
|
||||
|
||||
vfsdbg("NormalizePath( Path: \"%s\" Parent: \"%s\" )",
|
||||
Path, Parent->Name);
|
||||
|
||||
size_t PathSize = strlen((char *)Path) + 1;
|
||||
char *NormalizedPath = new char[PathSize];
|
||||
|
||||
{
|
||||
Memory::SmartHeap sh(PathSize);
|
||||
memcpy(sh, (char *)Path, PathSize);
|
||||
cwk_path_normalize(sh, NormalizedPath, PathSize);
|
||||
}
|
||||
|
||||
const char *FinalPath;
|
||||
if (cwk_path_is_relative(NormalizedPath))
|
||||
{
|
||||
size_t PathSize = cwk_path_join(Parent->FullPath,
|
||||
NormalizedPath,
|
||||
nullptr, 0);
|
||||
|
||||
FinalPath = new char[PathSize + 1];
|
||||
cwk_path_join(Parent->FullPath, NormalizedPath,
|
||||
(char *)FinalPath, PathSize + 1);
|
||||
|
||||
delete[] NormalizedPath;
|
||||
}
|
||||
else
|
||||
FinalPath = NormalizedPath;
|
||||
|
||||
vfsdbg("NormalizePath()->\"%s\"", FinalPath);
|
||||
return FinalPath;
|
||||
}
|
||||
|
||||
bool Virtual::PathExists(const char *Path, Node *Parent)
|
||||
{
|
||||
if (isempty((char *)Path))
|
||||
{
|
||||
vfsdbg("PathExists()->PathIsEmpty");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Parent == nullptr)
|
||||
Parent = FileSystemRoot;
|
||||
|
||||
vfsdbg("PathExists( Path: \"%s\" Parent: \"%s\" )",
|
||||
Path, Parent->Name);
|
||||
|
||||
const char *CleanPath = NormalizePath(Path, Parent);
|
||||
bool ret = GetNodeFromPath(CleanPath, Parent) != nullptr;
|
||||
delete[] CleanPath;
|
||||
vfsdbg("PathExists()->\"%s\"",
|
||||
ret ? "true" : "false");
|
||||
return ret;
|
||||
}
|
||||
|
||||
Node *Virtual::Create(const char *Path, NodeType Type, Node *Parent)
|
||||
{
|
||||
if (isempty((char *)Path))
|
||||
return nullptr;
|
||||
|
||||
SmartLock(VirtualLock);
|
||||
Node *RootNode = FileSystemRoot->Children[0];
|
||||
Node *CurrentParent = this->GetParent(Path, Parent);
|
||||
vfsdbg("Virtual::Create( Path: \"%s\" Parent: \"%s\" )",
|
||||
Path, Parent ? Parent->Name : CurrentParent->Name);
|
||||
|
||||
const char *CleanPath = this->NormalizePath(Path, CurrentParent);
|
||||
vfsdbg("CleanPath: \"%s\"", CleanPath);
|
||||
|
||||
VirtualLock.Unlock();
|
||||
if (PathExists(CleanPath, CurrentParent))
|
||||
{
|
||||
error("Path \"%s\" already exists.", CleanPath);
|
||||
goto CreatePathError;
|
||||
}
|
||||
VirtualLock.Lock(__FUNCTION__);
|
||||
|
||||
cwk_segment segment;
|
||||
if (!cwk_path_get_first_segment(CleanPath, &segment))
|
||||
{
|
||||
error("Path doesn't have any segments.");
|
||||
goto CreatePathError;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
char *SegmentName = new char[segment.end - segment.begin + 1];
|
||||
memcpy(SegmentName, segment.begin, segment.end - segment.begin);
|
||||
vfsdbg("SegmentName: \"%s\"", SegmentName);
|
||||
|
||||
auto GetChild = [](const char *Name, Node *Parent)
|
||||
{
|
||||
vfsdbg("GetChild( Name: \"%s\" Parent: \"%s\" )",
|
||||
Name, Parent->Name);
|
||||
|
||||
if (!Parent)
|
||||
{
|
||||
vfsdbg("GetChild()->nullptr");
|
||||
return (Node *)nullptr;
|
||||
}
|
||||
|
||||
foreach (auto Child in Parent->Children)
|
||||
{
|
||||
if (strcmp(Child->Name, Name) == 0)
|
||||
{
|
||||
vfsdbg("GetChild()->\"%s\"", Child->Name);
|
||||
return Child;
|
||||
}
|
||||
}
|
||||
|
||||
vfsdbg("GetChild()->nullptr (not found)");
|
||||
return (Node *)nullptr;
|
||||
};
|
||||
|
||||
if (Parent)
|
||||
{
|
||||
if (GetChild(SegmentName, RootNode) != nullptr)
|
||||
{
|
||||
RootNode = GetChild(SegmentName, RootNode);
|
||||
delete[] SegmentName;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (GetChild(SegmentName, CurrentParent) == nullptr)
|
||||
{
|
||||
Node *NewNode = new Node(CurrentParent,
|
||||
SegmentName,
|
||||
NodeType::DIRECTORY);
|
||||
|
||||
CurrentParent = NewNode;
|
||||
CurrentParent->Type = Type;
|
||||
CurrentParent->FullPath = CleanPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentParent = GetChild(SegmentName, CurrentParent);
|
||||
}
|
||||
|
||||
delete[] SegmentName;
|
||||
} while (cwk_path_get_next_segment(&segment));
|
||||
|
||||
vfsdbg("Virtual::Create()->\"%s\"", CurrentParent->Name);
|
||||
#ifdef DEBUG
|
||||
VirtualLock.Unlock();
|
||||
debug("Path created: \"%s\"",
|
||||
CurrentParent->FullPath);
|
||||
VirtualLock.Lock(__FUNCTION__);
|
||||
#endif
|
||||
return CurrentParent;
|
||||
|
||||
CreatePathError:
|
||||
delete[] CleanPath;
|
||||
vfsdbg("Virtual::Create()->nullptr");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int Virtual::Delete(const char *Path, bool Recursive, Node *Parent)
|
||||
{
|
||||
vfsdbg("Virtual::Delete( Path: \"%s\" Parent: \"%s\" )",
|
||||
Path, Parent ? Parent->Name : "(null)");
|
||||
|
||||
if (isempty((char *)Path))
|
||||
return -EINVAL;
|
||||
|
||||
if (Parent == nullptr)
|
||||
Parent = FileSystemRoot;
|
||||
|
||||
const char *CleanPath = this->NormalizePath(Path, Parent);
|
||||
vfsdbg("CleanPath: \"%s\"", CleanPath);
|
||||
|
||||
if (!PathExists(CleanPath, Parent))
|
||||
{
|
||||
vfsdbg("Path \"%s\" doesn't exist.", CleanPath);
|
||||
delete[] CleanPath;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
Node *NodeToDelete = GetNodeFromPath(CleanPath, Parent);
|
||||
delete[] CleanPath;
|
||||
return NodeToDelete->Delete(Recursive);
|
||||
}
|
||||
|
||||
int Virtual::Delete(Node *Path, bool Recursive, Node *Parent)
|
||||
{
|
||||
return Delete(Path->FullPath, Recursive, Parent);
|
||||
}
|
||||
|
||||
RefNode *Virtual::Open(const char *Path, Node *Parent)
|
||||
{
|
||||
vfsdbg("Opening \"%s\" with parent \"%s\"",
|
||||
Path, Parent ? Parent->Name : "(null)");
|
||||
|
||||
if (strcmp(Path, "/") == 0)
|
||||
return FileSystemRoot->CreateReference();
|
||||
|
||||
if (!Parent)
|
||||
Parent = FileSystemRoot->Children[0];
|
||||
|
||||
if (strcmp(Path, ".") == 0)
|
||||
return Parent->CreateReference();
|
||||
|
||||
if (strcmp(Path, "..") == 0)
|
||||
{
|
||||
if (Parent->Parent)
|
||||
return Parent->Parent->CreateReference();
|
||||
else
|
||||
return Parent->CreateReference();
|
||||
}
|
||||
|
||||
Node *CurrentParent = this->GetParent(Path, Parent);
|
||||
const char *CleanPath = NormalizePath(Path, CurrentParent);
|
||||
|
||||
if (PathExists(CleanPath, CurrentParent))
|
||||
{
|
||||
Node *node = GetNodeFromPath(CleanPath, CurrentParent);
|
||||
if (node)
|
||||
{
|
||||
delete[] CleanPath;
|
||||
/* TODO: Check if dir or file? */
|
||||
return node->CreateReference();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Virtual::Virtual()
|
||||
{
|
||||
SmartLock(VirtualLock);
|
||||
trace("Initializing virtual file system...");
|
||||
FileSystemRoot = new Node(nullptr, "<root>", NodeType::MOUNTPOINT);
|
||||
FileSystemRoot->vFS = this;
|
||||
}
|
||||
|
||||
Virtual::~Virtual()
|
||||
{
|
||||
SmartLock(VirtualLock);
|
||||
stub;
|
||||
/* TODO: sync, cache */
|
||||
}
|
||||
}
|
27
storage/fs/fat32.cpp
Normal file
27
storage/fs/fat32.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem/ustar.hpp>
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <debug.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
}
|
37
storage/fs/null.cpp
Normal file
37
storage/fs/null.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem/mounts.hpp>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
size_t NullDevice::read(uint8_t *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
return Size;
|
||||
}
|
||||
|
||||
size_t NullDevice::write(uint8_t *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
return Size;
|
||||
}
|
||||
|
||||
NullDevice::NullDevice() : Node(DevFS, "null", CHARDEVICE) {}
|
||||
NullDevice::~NullDevice() {}
|
||||
}
|
49
storage/fs/ptmx.cpp
Normal file
49
storage/fs/ptmx.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem/mounts.hpp>
|
||||
#include <filesystem/ioctl.hpp>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
size_t PTMXDevice::read(uint8_t *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
if (Size <= 0)
|
||||
return 0;
|
||||
|
||||
memset(Buffer, 0, Size);
|
||||
return Size;
|
||||
}
|
||||
|
||||
size_t PTMXDevice::write(uint8_t *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
return Size;
|
||||
}
|
||||
|
||||
PTMXDevice::PTMXDevice() : Node(DevFS, "null", CHARDEVICE)
|
||||
{
|
||||
pts = new Node(DevFS, "pts", DIRECTORY);
|
||||
}
|
||||
|
||||
PTMXDevice::~PTMXDevice()
|
||||
{
|
||||
delete pts;
|
||||
}
|
||||
}
|
44
storage/fs/random.cpp
Normal file
44
storage/fs/random.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem/mounts.hpp>
|
||||
#include <rand.hpp>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
size_t RandomDevice::read(uint8_t *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
if (Size <= 0)
|
||||
return 0;
|
||||
|
||||
uint64_t *buf = (uint64_t *)Buffer;
|
||||
for (size_t i = 0; i < Size / sizeof(uint64_t); i++)
|
||||
buf[i] = Random::rand64();
|
||||
return Size;
|
||||
}
|
||||
|
||||
size_t RandomDevice::write(uint8_t *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
return Size;
|
||||
}
|
||||
|
||||
RandomDevice::RandomDevice() : Node(DevFS, "random", CHARDEVICE) {}
|
||||
RandomDevice::~RandomDevice() {}
|
||||
}
|
32
storage/fs/root.cpp
Normal file
32
storage/fs/root.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem/mounts.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
vfsRoot::vfsRoot(const char *Name, Virtual *vfs_ctx)
|
||||
: Node(nullptr,
|
||||
Name,
|
||||
MOUNTPOINT)
|
||||
{
|
||||
this->vFS = fs;
|
||||
vfs_ctx->GetRootNode()->Children.push_back(this);
|
||||
}
|
||||
}
|
61
storage/fs/tty.cpp
Normal file
61
storage/fs/tty.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem/mounts.hpp>
|
||||
#include <filesystem/ioctl.hpp>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
size_t TTYDevice::write(uint8_t *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
for (size_t i = 0; i < Size; i++)
|
||||
putchar(((char *)Buffer)[i]);
|
||||
|
||||
Display->SetBuffer(0); /* FIXME: stub */
|
||||
return Size;
|
||||
}
|
||||
|
||||
int TTYDevice::ioctl(unsigned long Request, void *Argp)
|
||||
{
|
||||
switch (Request)
|
||||
{
|
||||
case TIOCGWINSZ:
|
||||
{
|
||||
struct winsize *ws = (struct winsize *)Argp;
|
||||
Video::ScreenBuffer *sb = Display->GetBuffer(0);
|
||||
Video::FontInfo fi = Display->GetCurrentFont()->GetInfo();
|
||||
|
||||
fixme("TIOCGWINSZ: stub");
|
||||
ws->ws_xpixel = uint16_t(sb->Width);
|
||||
ws->ws_ypixel = uint16_t(sb->Height);
|
||||
ws->ws_col = uint16_t(sb->Width / fi.Width);
|
||||
ws->ws_row = uint16_t(sb->Height / fi.Height);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fixme("Unknown request %#lx", Request);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
TTYDevice::TTYDevice() : Node(DevFS, "tty", CHARDEVICE) {}
|
||||
TTYDevice::~TTYDevice() {}
|
||||
}
|
178
storage/fs/ustar.cpp
Normal file
178
storage/fs/ustar.cpp
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem/ustar.hpp>
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <debug.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
size_t USTARNode::read(uint8_t *Buffer,
|
||||
size_t Size,
|
||||
off_t Offset)
|
||||
{
|
||||
if (Size <= 0)
|
||||
Size = this->Size;
|
||||
|
||||
if (Offset > this->Size)
|
||||
return 0;
|
||||
|
||||
if ((this->Size - Offset) == 0)
|
||||
return 0; /* EOF */
|
||||
|
||||
if (Offset + (off_t)Size > this->Size)
|
||||
Size = this->Size;
|
||||
|
||||
memcpy(Buffer, (uint8_t *)(this->Address + Offset), Size);
|
||||
return Size;
|
||||
}
|
||||
|
||||
USTARNode::USTARNode(uintptr_t Address,
|
||||
const char *Name,
|
||||
NodeType Type,
|
||||
Virtual *vfs_ctx)
|
||||
: Node(nullptr,
|
||||
Name,
|
||||
Type,
|
||||
true,
|
||||
vfs_ctx,
|
||||
nullptr),
|
||||
Address(Address)
|
||||
{
|
||||
}
|
||||
|
||||
USTARNode::~USTARNode() {}
|
||||
|
||||
bool USTAR::TestArchive(uintptr_t Address)
|
||||
{
|
||||
if (!Memory::Virtual().Check((void *)Address))
|
||||
{
|
||||
error("Address %#lx is not mapped!", Address);
|
||||
return false;
|
||||
}
|
||||
|
||||
FileHeader *header = (FileHeader *)Address;
|
||||
if (memcmp(header->signature, "ustar", 5) != 0)
|
||||
{
|
||||
error("ustar signature invalid!");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void USTAR::ReadArchive(uintptr_t Address, Virtual *vfs_ctx)
|
||||
{
|
||||
trace("Initializing USTAR with address %#lx", Address);
|
||||
|
||||
if (!this->TestArchive(Address))
|
||||
return; /* Check whether the archive is deflated */
|
||||
|
||||
FileHeader *header = (FileHeader *)Address;
|
||||
|
||||
debug("USTAR signature valid! Name:%s Signature:%s Mode:%d Size:%lu",
|
||||
header->name, header->signature,
|
||||
string2int(header->mode), header->size);
|
||||
|
||||
for (size_t i = 0;; i++)
|
||||
{
|
||||
if (memcmp(header->signature, "ustar", 5) != 0)
|
||||
break;
|
||||
|
||||
memmove(header->name,
|
||||
header->name + 1,
|
||||
strlen(header->name));
|
||||
|
||||
if (header->name[strlen(header->name) - 1] == '/')
|
||||
{
|
||||
debug("Removing trailing slash from %s", header->name);
|
||||
header->name[strlen(header->name) - 1] = 0;
|
||||
}
|
||||
|
||||
// if (!isempty((char *)header->name))
|
||||
// KPrint("Adding file \e88AACC%s\eCCCCCC (\e88AACC%lu \eCCCCCCbytes)", header->name, size);
|
||||
// else
|
||||
// goto NextFileAddress;
|
||||
|
||||
size_t size = getsize(header->size);
|
||||
Node *node;
|
||||
NodeType type = NODE_TYPE_NONE;
|
||||
if (isempty((char *)header->name))
|
||||
goto NextFileAddress;
|
||||
|
||||
switch (header->typeflag[0])
|
||||
{
|
||||
case REGULAR_FILE:
|
||||
type = NodeType::FILE;
|
||||
break;
|
||||
case SYMLINK:
|
||||
type = NodeType::SYMLINK;
|
||||
break;
|
||||
case DIRECTORY:
|
||||
type = NodeType::DIRECTORY;
|
||||
break;
|
||||
case CHARDEV:
|
||||
type = NodeType::CHARDEVICE;
|
||||
break;
|
||||
case BLOCKDEV:
|
||||
type = NodeType::BLOCKDEVICE;
|
||||
break;
|
||||
default:
|
||||
warn("Unknown type: %d", header->typeflag[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
node = new USTARNode((Address + 512), header->name,
|
||||
type, vfs_ctx);
|
||||
|
||||
debug("%s %d KiB, Type:%c", header->name,
|
||||
TO_KiB(size), header->typeflag[0]);
|
||||
node->Mode = string2int(header->mode);
|
||||
node->Size = size;
|
||||
node->GroupIdentifier = getsize(header->gid);
|
||||
node->UserIdentifier = getsize(header->uid);
|
||||
node->DeviceMajor = getsize(header->dev_maj);
|
||||
node->DeviceMinor = getsize(header->dev_min);
|
||||
|
||||
node->AccessTime = getsize(header->mtime);
|
||||
node->ModifyTime = getsize(header->mtime);
|
||||
node->ChangeTime = getsize(header->mtime);
|
||||
node->IndexNode = i;
|
||||
|
||||
if (type == NodeType::SYMLINK)
|
||||
{
|
||||
node->Symlink = new char[strlen(header->link) + 1];
|
||||
strncpy((char *)node->Symlink,
|
||||
header->link,
|
||||
strlen(header->link));
|
||||
}
|
||||
|
||||
NextFileAddress:
|
||||
Address += ((size / 512) + 1) * 512;
|
||||
if (size % 512)
|
||||
Address += 512;
|
||||
|
||||
header = (FileHeader *)Address;
|
||||
}
|
||||
}
|
||||
|
||||
USTAR::USTAR() {}
|
||||
|
||||
USTAR::~USTAR() {}
|
||||
}
|
43
storage/fs/zero.cpp
Normal file
43
storage/fs/zero.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem/mounts.hpp>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
using namespace vfs;
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
size_t ZeroDevice::read(uint8_t *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
if (Size <= 0)
|
||||
return 0;
|
||||
|
||||
memset(Buffer, 0, Size);
|
||||
return Size;
|
||||
}
|
||||
|
||||
size_t ZeroDevice::write(uint8_t *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
return Size;
|
||||
}
|
||||
|
||||
ZeroDevice::ZeroDevice() : Node(DevFS, "zero", CHARDEVICE) {}
|
||||
ZeroDevice::~ZeroDevice() {}
|
||||
}
|
130
storage/kernel_io.cpp
Normal file
130
storage/kernel_io.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
using Tasking::PCB;
|
||||
using vfs::FileDescriptorTable;
|
||||
|
||||
static bool CheckForScheduler()
|
||||
{
|
||||
if (TaskManager == nullptr)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int fopen(const char *pathname, const char *mode)
|
||||
{
|
||||
if (!CheckForScheduler())
|
||||
return -ENOSYS;
|
||||
|
||||
PCB *pcb = thisProcess;
|
||||
FileDescriptorTable *fdt = pcb->FileDescriptors;
|
||||
int fd = fdt->_open(pathname, ConvertFileFlags(mode), 0666);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int creat(const char *pathname, mode_t mode)
|
||||
{
|
||||
if (!CheckForScheduler())
|
||||
return -ENOSYS;
|
||||
|
||||
PCB *pcb = thisProcess;
|
||||
FileDescriptorTable *fdt = pcb->FileDescriptors;
|
||||
int fd = fdt->_creat(pathname, mode);
|
||||
return fd;
|
||||
}
|
||||
|
||||
ssize_t fread(int fd, void *buf, size_t count)
|
||||
{
|
||||
if (!CheckForScheduler())
|
||||
return -ENOSYS;
|
||||
|
||||
PCB *pcb = thisProcess;
|
||||
FileDescriptorTable *fdt = pcb->FileDescriptors;
|
||||
ssize_t r = fdt->_read(fd, buf, count);
|
||||
return r;
|
||||
}
|
||||
|
||||
ssize_t fwrite(int fd, const void *buf, size_t count)
|
||||
{
|
||||
if (!CheckForScheduler())
|
||||
return -ENOSYS;
|
||||
|
||||
PCB *pcb = thisProcess;
|
||||
FileDescriptorTable *fdt = pcb->FileDescriptors;
|
||||
ssize_t r = fdt->_write(fd, buf, count);
|
||||
return r;
|
||||
}
|
||||
|
||||
int fclose(int fd)
|
||||
{
|
||||
if (!CheckForScheduler())
|
||||
return -ENOSYS;
|
||||
|
||||
PCB *pcb = thisProcess;
|
||||
FileDescriptorTable *fdt = pcb->FileDescriptors;
|
||||
int r = fdt->_close(fd);
|
||||
return r;
|
||||
}
|
||||
|
||||
off_t lseek(int fd, off_t offset, int whence)
|
||||
{
|
||||
if (!CheckForScheduler())
|
||||
return -ENOSYS;
|
||||
|
||||
PCB *pcb = thisProcess;
|
||||
FileDescriptorTable *fdt = pcb->FileDescriptors;
|
||||
off_t r = fdt->_lseek(fd, offset, whence);
|
||||
return r;
|
||||
}
|
||||
|
||||
int stat(const char *pathname, struct stat *statbuf)
|
||||
{
|
||||
if (!CheckForScheduler())
|
||||
return -ENOSYS;
|
||||
|
||||
PCB *pcb = thisProcess;
|
||||
FileDescriptorTable *fdt = pcb->FileDescriptors;
|
||||
int r = fdt->_stat(pathname, statbuf);
|
||||
return r;
|
||||
}
|
||||
|
||||
int fstat(int fd, struct stat *statbuf)
|
||||
{
|
||||
if (!CheckForScheduler())
|
||||
return -ENOSYS;
|
||||
|
||||
PCB *pcb = thisProcess;
|
||||
FileDescriptorTable *fdt = pcb->FileDescriptors;
|
||||
int r = fdt->_fstat(fd, statbuf);
|
||||
return r;
|
||||
}
|
||||
|
||||
int lstat(const char *pathname, struct stat *statbuf)
|
||||
{
|
||||
if (!CheckForScheduler())
|
||||
return -ENOSYS;
|
||||
|
||||
PCB *pcb = thisProcess;
|
||||
FileDescriptorTable *fdt = pcb->FileDescriptors;
|
||||
int r = fdt->_lstat(pathname, statbuf);
|
||||
return r;
|
||||
}
|
263
storage/node.cpp
Normal file
263
storage/node.cpp
Normal file
@ -0,0 +1,263 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <cwalk.h>
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
int Node::open(int Flags, mode_t Mode)
|
||||
{
|
||||
debug("Operation not handled");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
int Node::close()
|
||||
{
|
||||
debug("Operation not handled");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
size_t Node::read(uint8_t *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
debug("Operation not handled");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
size_t Node::write(uint8_t *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
debug("Operation not handled");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
int Node::ioctl(unsigned long Request, void *Argp)
|
||||
{
|
||||
debug("Operation not handled");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
RefNode *Node::CreateReference()
|
||||
{
|
||||
SmartLock(NodeLock);
|
||||
RefNode *ref = new RefNode(this);
|
||||
References.push_back(ref);
|
||||
debug("Created reference %#lx for node %#lx", ref, this);
|
||||
return ref;
|
||||
}
|
||||
|
||||
void Node::RemoveReference(RefNode *Reference)
|
||||
{
|
||||
SmartLock(NodeLock);
|
||||
debug("Removing reference %#lx for node %#lx", Reference, this);
|
||||
References.erase(std::find(References.begin(),
|
||||
References.end(),
|
||||
Reference));
|
||||
}
|
||||
|
||||
Node::Node(Node *Parent, const char *Name, NodeType Type,
|
||||
bool NoParent, Virtual *fs, int *Err)
|
||||
{
|
||||
assert(Name != nullptr);
|
||||
assert(strlen(Name) != 0);
|
||||
assert((NoParent == false &&
|
||||
fs == nullptr) ||
|
||||
(NoParent == true &&
|
||||
fs != nullptr));
|
||||
|
||||
if (Err != nullptr)
|
||||
*Err = 0;
|
||||
|
||||
this->Type = Type;
|
||||
|
||||
auto GetChild = [](const char *Name, Node *Parent)
|
||||
{
|
||||
if (!Parent)
|
||||
return (Node *)nullptr;
|
||||
|
||||
foreach (auto Child in Parent->Children)
|
||||
{
|
||||
if (strcmp(Child->Name, Name) == 0)
|
||||
return Child;
|
||||
}
|
||||
|
||||
return (Node *)nullptr;
|
||||
};
|
||||
|
||||
auto CreateWithParent = [this](const char *Name, Node *Parent)
|
||||
{
|
||||
assert(Parent->vFS != nullptr);
|
||||
assert(Parent->Type == DIRECTORY ||
|
||||
Parent->Type == MOUNTPOINT);
|
||||
|
||||
this->vFS = Parent->vFS;
|
||||
this->Parent = Parent;
|
||||
|
||||
this->Name = new char[strlen(Name) + 1];
|
||||
strcpy((char *)this->Name, Name);
|
||||
|
||||
this->FullPath = new char[strlen(Parent->FullPath) +
|
||||
strlen(this->Name) + 2];
|
||||
strcpy((char *)this->FullPath, Parent->FullPath);
|
||||
if (strcmp(this->FullPath, "/") != 0)
|
||||
strcat((char *)this->FullPath, "/");
|
||||
strcat((char *)this->FullPath, this->Name);
|
||||
|
||||
this->Parent->Children.push_back(this);
|
||||
};
|
||||
|
||||
if (Parent)
|
||||
CreateWithParent(Name, Parent);
|
||||
else if (NoParent)
|
||||
{
|
||||
const char *Path = Name;
|
||||
|
||||
Node *RootNode = fs->FileSystemRoot->Children[0];
|
||||
Node *CurrentParent = fs->GetParent(Path, Parent);
|
||||
|
||||
if (fs->PathExists(Path, CurrentParent))
|
||||
{
|
||||
debug("Path \"%s\" already exists.", Path);
|
||||
delete[] Path;
|
||||
if (Err != nullptr)
|
||||
*Err = -EEXIST;
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
|
||||
const char *CleanPath = fs->NormalizePath(Path, CurrentParent);
|
||||
|
||||
cwk_segment segment;
|
||||
if (!cwk_path_get_first_segment(CleanPath, &segment))
|
||||
{
|
||||
debug("Path doesn't have any segments.");
|
||||
delete[] CleanPath;
|
||||
if (Err != nullptr)
|
||||
*Err = -EINVAL;
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
|
||||
cwk_segment last_segment;
|
||||
cwk_path_get_last_segment(CleanPath, &last_segment);
|
||||
|
||||
do
|
||||
{
|
||||
char *SegmentName = new char[segment.end - segment.begin + 1];
|
||||
memcpy(SegmentName, segment.begin, segment.end - segment.begin);
|
||||
|
||||
if (Parent)
|
||||
{
|
||||
if (GetChild(SegmentName, RootNode) != nullptr)
|
||||
{
|
||||
RootNode = GetChild(SegmentName, RootNode);
|
||||
delete[] SegmentName;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (GetChild(SegmentName, CurrentParent) == nullptr)
|
||||
{
|
||||
if (segment.begin == last_segment.begin)
|
||||
{
|
||||
CreateWithParent(SegmentName, CurrentParent);
|
||||
delete[] SegmentName;
|
||||
break; /* This is the last segment anyway... */
|
||||
}
|
||||
|
||||
CurrentParent = new Node(CurrentParent,
|
||||
SegmentName,
|
||||
Type);
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentParent = GetChild(SegmentName, CurrentParent);
|
||||
}
|
||||
|
||||
delete[] SegmentName;
|
||||
} while (cwk_path_get_next_segment(&segment));
|
||||
}
|
||||
else
|
||||
{
|
||||
this->Name = new char[strlen(Name) + 1];
|
||||
strcpy((char *)this->Name, Name);
|
||||
this->FullPath = Name;
|
||||
|
||||
trace("Node %s(%#lx) has no parent",
|
||||
this->Name, this);
|
||||
}
|
||||
}
|
||||
|
||||
int Node::Delete(bool Recursive)
|
||||
{
|
||||
if (this->References.size() != 0)
|
||||
{
|
||||
debug("Node %s(%#lx) has %ld references",
|
||||
this->FullPath, this,
|
||||
this->References.size());
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (this->Type == MOUNTPOINT ||
|
||||
this->Type == DIRECTORY)
|
||||
{
|
||||
if (this->Children.size() != 0)
|
||||
{
|
||||
if (!Recursive)
|
||||
{
|
||||
debug("Node %s(%#lx) has %ld children",
|
||||
this->FullPath, this,
|
||||
this->Children.size());
|
||||
return -ENOTEMPTY;
|
||||
}
|
||||
|
||||
for (auto Child : this->Children)
|
||||
{
|
||||
int ret = Child->Delete(Recursive);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
debug("Failed to delete child %s(%#lx)",
|
||||
Child->FullPath, Child);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Node::~Node()
|
||||
{
|
||||
debug("Destroyed node %#lx", this);
|
||||
assert(this->Children.size() == 0);
|
||||
|
||||
if (this->Parent)
|
||||
{
|
||||
this->Parent->Children.erase(std::find(this->Parent->Children.begin(),
|
||||
this->Parent->Children.end(),
|
||||
this));
|
||||
}
|
||||
|
||||
delete[] this->Name;
|
||||
if (this->Parent)
|
||||
delete[] this->FullPath;
|
||||
if (this->Symlink)
|
||||
delete[] this->Symlink;
|
||||
}
|
||||
}
|
158
storage/ref_node.cpp
Normal file
158
storage/ref_node.cpp
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem.hpp>
|
||||
|
||||
#ifdef DEBUG
|
||||
const char *SeekStrings[] =
|
||||
{"SEEK_SET",
|
||||
"SEEK_CUR",
|
||||
"SEEK_END"};
|
||||
#endif
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
size_t RefNode::read(uint8_t *Buffer, size_t Size)
|
||||
{
|
||||
if (this->SymlinkTo)
|
||||
return this->SymlinkTo->read(Buffer, Size);
|
||||
|
||||
return this->node->read(Buffer, Size, this->FileOffset.load());
|
||||
}
|
||||
|
||||
size_t RefNode::write(uint8_t *Buffer, size_t Size)
|
||||
{
|
||||
if (this->SymlinkTo)
|
||||
return this->SymlinkTo->write(Buffer, Size);
|
||||
|
||||
return this->node->write(Buffer, Size, this->FileOffset.load());
|
||||
}
|
||||
|
||||
off_t RefNode::seek(off_t Offset, int Whence)
|
||||
{
|
||||
if (this->SymlinkTo)
|
||||
return this->SymlinkTo->seek(Offset, Whence);
|
||||
|
||||
// debug("Current offset is %d", this->Offset.load());
|
||||
switch (Whence)
|
||||
{
|
||||
case SEEK_SET:
|
||||
{
|
||||
if (Offset > this->FileSize)
|
||||
return -EINVAL;
|
||||
|
||||
if (Offset < 0)
|
||||
{
|
||||
fixme("Negative offset %d is not implemented", Offset);
|
||||
Offset = 0;
|
||||
}
|
||||
|
||||
if (Offset > this->FileSize)
|
||||
{
|
||||
fixme("Offset %d is bigger than file size %d",
|
||||
Offset, this->FileSize);
|
||||
Offset = this->FileSize;
|
||||
}
|
||||
|
||||
this->FileOffset.store(Offset);
|
||||
break;
|
||||
}
|
||||
case SEEK_CUR:
|
||||
{
|
||||
off_t NewOffset = off_t(this->FileOffset.load()) + Offset;
|
||||
if (NewOffset > this->FileSize ||
|
||||
NewOffset < 0)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
this->FileOffset.store(NewOffset);
|
||||
break;
|
||||
}
|
||||
case SEEK_END:
|
||||
{
|
||||
off_t NewOffset = this->FileSize + Offset;
|
||||
if (NewOffset > this->FileSize ||
|
||||
NewOffset < 0)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
this->FileOffset.store(NewOffset);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
error("Invalid whence!");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
off_t RetOffset = off_t(this->FileOffset.load());
|
||||
// debug("( %d %ld %s[%d] ) -> %d",
|
||||
// Offset, this->Offset.load(),
|
||||
// SeekStrings[Whence], Whence,
|
||||
// RetOffset);
|
||||
return RetOffset;
|
||||
}
|
||||
|
||||
int RefNode::ioctl(unsigned long Request, void *Argp)
|
||||
{
|
||||
if (this->SymlinkTo)
|
||||
return this->SymlinkTo->ioctl(Request, Argp);
|
||||
|
||||
return this->node->ioctl(Request, Argp);
|
||||
}
|
||||
|
||||
RefNode::RefNode(Node *node)
|
||||
{
|
||||
this->node = node;
|
||||
this->FileSize = node->Size;
|
||||
if (this->node->Type == SYMLINK)
|
||||
{
|
||||
if (!this->node->SymlinkTarget)
|
||||
{
|
||||
this->node->SymlinkTarget =
|
||||
node->vFS->GetNodeFromPath(this->node->Symlink);
|
||||
}
|
||||
|
||||
if (!this->node->SymlinkTarget)
|
||||
{
|
||||
error("Symlink target %s not found!",
|
||||
this->node->Symlink);
|
||||
return;
|
||||
}
|
||||
|
||||
/* not standard but useful in kernel-space */
|
||||
this->node->Size = this->node->SymlinkTarget->Size;
|
||||
this->SymlinkTo = this->node->SymlinkTarget->CreateReference();
|
||||
}
|
||||
|
||||
debug("Created reference node for %s [%#lx]",
|
||||
this->node->FullPath, (uintptr_t)this);
|
||||
}
|
||||
|
||||
RefNode::~RefNode()
|
||||
{
|
||||
if (this->SymlinkTo)
|
||||
this->node->SymlinkTarget->RemoveReference(this);
|
||||
this->node->RemoveReference(this);
|
||||
|
||||
debug("Destroyed reference node for %s [%#lx]",
|
||||
this->node->FullPath, (uintptr_t)this);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user