mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Added open(2).
Please note that mount points and file systems do not exist yet.
This commit is contained in:
parent
6447783c12
commit
ae423eaeef
9 changed files with 112 additions and 361 deletions
|
@ -46,7 +46,7 @@ __BEGIN_DECLS
|
|||
#define O_RDONLY 00
|
||||
#define O_WRONLY 01
|
||||
#define O_RDWR 02
|
||||
#define O_CREAT 0100
|
||||
#define O_CREAT (1<<5)
|
||||
#define O_EXCL 0200
|
||||
#define O_NOCTTY 0400
|
||||
#define O_TRUNC 01000
|
||||
|
@ -82,10 +82,10 @@ struct _flock
|
|||
typedef struct _flock flock;
|
||||
|
||||
/* TODO: These are not implemented in libmaxsi/sortix yet. */
|
||||
int open(const char* path, int oflag, ...);
|
||||
#ifndef SORTIX_UNIMPLEMENTED
|
||||
int creat(const char* path, mode_t mode);
|
||||
int fcntl(int fd, int cmd, ...);
|
||||
int open(const char* path, int oflag, ...);
|
||||
int openat(int fd, const char* path, int oflag, ...);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ namespace Maxsi
|
|||
DEFN_SYSCALL1(int, SysPipe, 20, int*);
|
||||
DEFN_SYSCALL1(int, SysClose, 21, int);
|
||||
DEFN_SYSCALL1(int, SysDup, 22, int);
|
||||
DEFN_SYSCALL3(int, SysOpen, 23, const char*, int, mode_t);
|
||||
|
||||
size_t Print(const char* Message)
|
||||
{
|
||||
|
@ -89,6 +90,11 @@ namespace Maxsi
|
|||
{
|
||||
return SysDup(fd);
|
||||
}
|
||||
|
||||
extern "C" int open(const char* path, int flags, mode_t mode)
|
||||
{
|
||||
return SysOpen(path, flags, mode);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
|
@ -71,6 +71,8 @@ initrd.o \
|
|||
thread.o \
|
||||
io.o \
|
||||
pipe.o \
|
||||
filesystem.o \
|
||||
mount.o \
|
||||
../libmaxsi/libmaxsi-sortix.a
|
||||
|
||||
JSOBJS:=$(subst .o,-js.o,$(OBJS))
|
||||
|
|
60
sortix/filesystem.cpp
Normal file
60
sortix/filesystem.cpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
/******************************************************************************
|
||||
|
||||
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
Sortix 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.
|
||||
|
||||
Sortix 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 Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
filesystem.cpp
|
||||
Allows access to stored sequences of bytes in an orderly fashion.
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
#include "platform.h"
|
||||
#include "syscall.h"
|
||||
#include "process.h"
|
||||
#include "filesystem.h"
|
||||
#include "mount.h"
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
namespace FileSystem
|
||||
{
|
||||
Device* Open(const char* path, int flags, mode_t mode)
|
||||
{
|
||||
size_t pathoffset = 0;
|
||||
DevFileSystem* fs = Mount::WhichFileSystem(path, &pathoffset);
|
||||
if ( !fs ) { return NULL; }
|
||||
return fs->Open(path + pathoffset, flags, mode);
|
||||
}
|
||||
|
||||
int SysOpen(const char* path, int flags, mode_t mode)
|
||||
{
|
||||
Process* process = CurrentProcess();
|
||||
Device* dev = Open(path, flags, mode);
|
||||
if ( !dev ) { return -1; /* TODO: errno */ }
|
||||
int fd = process->descriptors.Allocate(dev);
|
||||
if ( fd < 0 ) { dev->Unref(); }
|
||||
return fd;
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
Syscall::Register(SYSCALL_OPEN, (void*) SysOpen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
with Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
filesystem.h
|
||||
Abstracts away a file system device.
|
||||
Allows access to stored sequences of bytes in an orderly fashion.
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
|
@ -26,71 +26,41 @@
|
|||
#define SORTIX_FILESYSTEM_H
|
||||
|
||||
#include "device.h"
|
||||
#include "mount.h"
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
class Thread;
|
||||
|
||||
namespace FileSystem
|
||||
{
|
||||
struct SysCallback
|
||||
{
|
||||
Device* device;
|
||||
union { int deviceError; nat deviceType; }
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: These belong in libmaxsi!
|
||||
|
||||
const nat O_RDONLY = 1;
|
||||
const nat O_WRONLY = 2;
|
||||
const nat O_RDWR = 3;
|
||||
const nat O_EXEC = 4;
|
||||
const nat O_SEARCH = 5;
|
||||
const nat O_LOWERFLAGS = 0x7;
|
||||
|
||||
// TODO: Sortix might never support all of these flags if they are stupid.
|
||||
const nat O_APPEND = (1<<3);
|
||||
const nat O_CLOEXEC = (1<<4);
|
||||
const nat O_CREAT = (1<<5);
|
||||
const nat O_DIRECTORY = (1<<6);
|
||||
const nat O_DSYNC = (1<<6);
|
||||
const nat O_EXCL = (1<<7);
|
||||
const nat O_NOCTTY = (1<<8);
|
||||
const nat O_NOFOLLOW = (1<<9);
|
||||
const nat O_RSYNC = (1<<11);
|
||||
const nat O_SYNC = (1<<12);
|
||||
const nat O_TRUNC = (1<<13);
|
||||
const nat O_TTY_INIT = (1<<13);
|
||||
|
||||
// If O_RDONLY, then no one is allowed to write to this, or if O_RDWD then
|
||||
// no one else is allowed to use this besides me.
|
||||
const nat O_EXCLUSIVELY = (1<<14);
|
||||
const nat O_USERSPACEABLE = ((1<<15)-1);
|
||||
|
||||
const nat O_MOUNT = (1<<31);
|
||||
const int O_RDONLY = 1;
|
||||
const int O_WRONLY = 2;
|
||||
const int O_RDWR = 3;
|
||||
const int O_EXEC = 4;
|
||||
const int O_SEARCH = 5;
|
||||
const int O_LOWERFLAGS = 0x7;
|
||||
const int O_APPEND = (1<<3);
|
||||
const int O_CLOEXEC = (1<<4);
|
||||
const int O_CREAT = (1<<5);
|
||||
const int O_DIRECTORY = (1<<6);
|
||||
const int O_DSYNC = (1<<6);
|
||||
const int O_EXCL = (1<<7);
|
||||
const int O_NOCTTY = (1<<8);
|
||||
const int O_NOFOLLOW = (1<<9);
|
||||
const int O_RSYNC = (1<<11);
|
||||
const int O_SYNC = (1<<12);
|
||||
const int O_TRUNC = (1<<13);
|
||||
const int O_TTY_INIT = (1<<13);
|
||||
|
||||
class DevFileSystem : public Device
|
||||
{
|
||||
public:
|
||||
DevFileSystem() { };
|
||||
virtual ~DevFileSystem() { }
|
||||
|
||||
public:
|
||||
bool LegalNodeName(const char* name);
|
||||
|
||||
public:
|
||||
virtual int Initialize(MountPoint* mountPoint, const char* commandLine) = 0;
|
||||
|
||||
public:
|
||||
virtual bool Open(const char* path, nat openFlags, nat mode, FileSystem::SysCallback* callbackInfo, Thread* thread);
|
||||
virtual Device* Open(const char* path, int flags, mode_t mode) = 0;
|
||||
|
||||
};
|
||||
|
||||
namespace FileSystem
|
||||
{
|
||||
DevFileSystem* CreateDriver(const char* fsType);
|
||||
void Init();
|
||||
Device* Open(const char* path, int flags, mode_t mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,8 @@
|
|||
#include "sound.h"
|
||||
#include "io.h"
|
||||
#include "pipe.h"
|
||||
#include "filesystem.h"
|
||||
#include "mount.h"
|
||||
|
||||
using namespace Maxsi;
|
||||
|
||||
|
@ -244,6 +246,12 @@ namespace Sortix
|
|||
// Initialize the pipe system.
|
||||
Pipe::Init();
|
||||
|
||||
// Initialize the filesystem system.
|
||||
FileSystem::Init();
|
||||
|
||||
// Initialize the mount system.
|
||||
Mount::Init();
|
||||
|
||||
// Initialize the scheduler.
|
||||
Scheduler::Init();
|
||||
|
||||
|
|
279
sortix/mount.cpp
279
sortix/mount.cpp
|
@ -23,283 +23,22 @@
|
|||
******************************************************************************/
|
||||
|
||||
#include "platform.h"
|
||||
#include <libmaxsi/string.h>
|
||||
#include "device.h"
|
||||
#include "filesystem.h"
|
||||
#include "thread.h"
|
||||
#include "process.h"
|
||||
#include "memorymanagement.h"
|
||||
#include "mount.h"
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
namespace Syscall
|
||||
{
|
||||
void SysOpen(Thread* thread)
|
||||
{
|
||||
struct Parameters
|
||||
{
|
||||
struct
|
||||
{
|
||||
const char* USER userPath SYSPARAM;
|
||||
nat openFlags SYSPARAM;
|
||||
nat mode SYSPARAM;
|
||||
};
|
||||
struct
|
||||
{
|
||||
int handle;
|
||||
bool pending;
|
||||
FileSystem::SysCallback callbackInfo;
|
||||
const char* safePath;
|
||||
};
|
||||
};
|
||||
|
||||
// We store our parameters and data inside the thread object, and we
|
||||
// are passed parameters in a special way, so make sure it works.
|
||||
STATIC_ASSERT(0 * sizeof(size_t) == offsetof(Parameters, userPath));
|
||||
STATIC_ASSERT(1 * sizeof(size_t) == offsetof(Parameters, openflags));
|
||||
STATIC_ASSERT(2 * sizeof(size_t) == offsetof(Parameters, mode));
|
||||
STATIC_ASSERT(sizeof(Parameters) <= sizeof(thread->sysParams));
|
||||
Parameters* params = (Parameters*) thread->sysParams;
|
||||
|
||||
int handle;
|
||||
const char* path;
|
||||
|
||||
// Initialize our variables and validate parameters.
|
||||
if ( !thread->sysParamsInited )
|
||||
{
|
||||
thread->sysParamsInited = true;
|
||||
params->handle = handle = -1;
|
||||
params->pending = false;
|
||||
|
||||
// Make sure the path is a valid string in userspace.
|
||||
params->safePath = path = ValidateUserString(params->userPath)
|
||||
if ( path == NULL ) { thread->SysReturnError(-1); return; }
|
||||
|
||||
params->openFlags &= O_USERSPACEABLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
path = params->safePath;
|
||||
handle = param->handle;
|
||||
}
|
||||
|
||||
// Get a descriptor for our device.
|
||||
if ( handle == -1 )
|
||||
{
|
||||
param->handle = handle = thread->GetProcess()->_descs.Reserve();
|
||||
if ( handle < 0 ) { thread->SysReturnError(handle); return; }
|
||||
}
|
||||
|
||||
// Attempt to open the path. If the operation is blocking, this
|
||||
// function will re-called when it completes, successful or not.
|
||||
if ( !params->pending )
|
||||
{
|
||||
params->pending = true;
|
||||
|
||||
MountPoint* mount = Mount::GetMountPoint(path);
|
||||
if ( mount == NULL ) { Error::Set(Error::BADINPUT); thread->SysReturnError(-1); return; }
|
||||
|
||||
if ( !mount->fs->Open(path, params->openFlags, params->mode, ¶ms->callbackInfo, thread) ) { return; }
|
||||
}
|
||||
|
||||
// Return an error if the open failed.
|
||||
if ( unlikely(params->callbackInfo.device == NULL) )
|
||||
{
|
||||
handle = thread->GetProcess()->_descs.Free(handle);
|
||||
Error::Set(params->callbackInfo.deviceError);
|
||||
thread->SysReturnError(-1); return;
|
||||
}
|
||||
|
||||
// Bind the device to the descriptor and return it.
|
||||
handle = thread->GetProcess()->_descs.UseReservation(handle, params->callbackInfo.device);
|
||||
thread->SysReturn(handle); return;
|
||||
}
|
||||
|
||||
void SysMount(Thread* thread)
|
||||
{
|
||||
struct Parameters
|
||||
{
|
||||
struct
|
||||
{
|
||||
const char* USER userDevicePath SYSPARAM;
|
||||
const char* USER userTargetPath SYSPARAM;
|
||||
const char* USER userDriverName SYSPARAM;
|
||||
nat mode SYSPARAM;
|
||||
};
|
||||
struct
|
||||
{
|
||||
int stage;
|
||||
DevBuffer* storage;
|
||||
DevFileSystem* fsDriver;
|
||||
DevDirectory* directory;
|
||||
FileSystem::SysCallback callbackInfo;
|
||||
};
|
||||
};
|
||||
|
||||
// We store our parameters and data inside the thread object, and we
|
||||
// are passed parameters in a special way, so make sure it works.
|
||||
STATIC_ASSERT(0 * sizeof(size_t) == offsetof(Parameters, userDevicePath));
|
||||
STATIC_ASSERT(1 * sizeof(size_t) == offsetof(Parameters, userTargetPath));
|
||||
STATIC_ASSERT(2 * sizeof(size_t) == offsetof(Parameters, userDriverName));
|
||||
STATIC_ASSERT(3 * sizeof(size_t) == offsetof(Parameters, mode));
|
||||
STATIC_ASSERT(sizeof(Parameters) <= sizeof(thread->sysParams));
|
||||
Parameters* params = (Parameters*) thread->sysParams;
|
||||
|
||||
// Initialize our variables and validate parameters.
|
||||
if ( !thread->sysParamsInited )
|
||||
{
|
||||
thread->sysParamsInited = true;
|
||||
if ( ValidateUserString(params->userDevicePath) == NULL ||
|
||||
ValidateUserString(params->userTargetPath) == NULL ||
|
||||
( params->userDriverName != NULL &&
|
||||
ValidateUserString(params->userDriverName) == NULL ) )
|
||||
{
|
||||
thread->SysReturnError(-1); return;
|
||||
}
|
||||
|
||||
params->mode &= O_USERSPACEABLE;
|
||||
nat baseMode = params->mode & O_LOWERFLAGS;
|
||||
nat extMode = params->mode & (~O_LOWERFLAGS);
|
||||
|
||||
// Deny unsupported open modes.
|
||||
if ( (baseMode != O_RDWR && baseMode != O_RDONLY) ||
|
||||
(extMode != 0 && extMode != O_EXCLUSIVELY && extMode != O_SYNC) )
|
||||
{
|
||||
Error::Set(Error::BADINPUT);
|
||||
thread->SysReturnError(-1); return;
|
||||
}
|
||||
|
||||
params->stage = 0;
|
||||
params->storage = NULL;
|
||||
params->fsDriver = NULL;
|
||||
params->directory = NULL;
|
||||
}
|
||||
|
||||
MountPoint* mount;
|
||||
Device* device = NULL;
|
||||
|
||||
switch ( params->stage )
|
||||
{
|
||||
// Get a handle to the storage device.
|
||||
case 0: params->stage++;
|
||||
|
||||
mount = Mount::GetMountPoint(¶ms->userDevicePath);
|
||||
if ( mount == NULL ) { Error::Set(Error::BADINPUT); break; }
|
||||
|
||||
ASSERT(params->mode & O_USERSPACEABLE == 0);
|
||||
if ( !mount->fs->Open(params->userDevicePath, params->mode | O_EXCLUSIVELY, 0, ¶ms->callbackInfo, thread) ) { return; }
|
||||
|
||||
// Validate the properness of the storage device.
|
||||
case 1: params->stage++;
|
||||
device = params->callbackInfo.device;
|
||||
|
||||
// Did it exist/could we open it/did we have permission?
|
||||
if ( unlikely(device == NULL) ) { Error::Set(params->callbackInfo.deviceError); break; }
|
||||
|
||||
// Is it a buffer?
|
||||
if ( unlikely(!device->IsType(Device::BUFFER)) ) { Error::Set(Error::ENOTBLK); break; }
|
||||
|
||||
params->storage = (DevBuffer*) device; device = NULL;
|
||||
|
||||
// Get a handle to the destination directory.
|
||||
case 2: params->stage++;
|
||||
|
||||
mount = Mount::GetMountPoint(¶ms->userTargetPath);
|
||||
if ( mount == NULL ) { Error::Set(Error::BADINPUT); break; }
|
||||
|
||||
// TODO: Figure out some good mode flags here!
|
||||
// TODO: Make sure the FS driver forces the dest dir to be empty!
|
||||
if ( !mount->fs->Open(params->userTargetPath, O_RDWR | O_DIRECTORY | O_MOUNT, 0, ¶ms->callbackInfo, thread) ) { return; }
|
||||
|
||||
// Validate the properness of the destination directory.
|
||||
case 2: params->stage++;
|
||||
device = params->callbackInfo.device;
|
||||
|
||||
// Did it exist/could we open it?
|
||||
if ( unlikely(device == NULL) ) { Error::Set(params->callbackInfo.deviceError); break; }
|
||||
|
||||
// Is it a directory?
|
||||
if ( unlikely(!device->IsType(Device::DIRECTORY)) ) { Error::Set(Error::ENOTDIR); break; }
|
||||
|
||||
params->directory = (DevDirectory*) device; device = NULL;
|
||||
|
||||
// Validate that the user owns the directory.
|
||||
if ( !params->directory->IsOwner(thread->GetProcess()->GetUser()) ) { Error::Set(Error::EPERM); break; }
|
||||
|
||||
// TODO: Add a run-time assertion that the dir is empty!
|
||||
|
||||
// Load the proper driver for this file system type.
|
||||
case 3: params->stage++;
|
||||
|
||||
// TODO: Make an async interface that can scan a device!
|
||||
params->fsDriver = FileSystem::CreateDriver(params->userDriverName);
|
||||
if ( params->fsDriver == NULL ) { Error::Set(Error::ENODEV); break; }
|
||||
|
||||
// Now bind the file system driver to the device and directory.
|
||||
case 4: params->stage++;
|
||||
MountPoint* newMount = new MountPoint();
|
||||
|
||||
newMount->device = params->storage;
|
||||
newMount->fs = params->fsDriver;
|
||||
|
||||
// TODO: Actually do the mounting!
|
||||
|
||||
// Check if everything went well.
|
||||
case 4:
|
||||
// TODO: Check if everything went well!
|
||||
thread->SysReturn(0); return;
|
||||
}
|
||||
|
||||
if ( device != NULL ) { device->close(); }
|
||||
if ( params->storage != NULL ) { params->storage->close(); }
|
||||
if ( params->directory != NULL ) { params->directory->close(); }
|
||||
if ( params->fsDriver != NULL ) { params->fsDriver->close(); }
|
||||
|
||||
thread->SysReturnError(-1); return;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Mount
|
||||
{
|
||||
MountPoint* GetMountPoint(const char** path, Thread* thread)
|
||||
DevFileSystem* WhichFileSystem(const char* path, size_t* pathoffset)
|
||||
{
|
||||
ASSERT(path != NULL);
|
||||
ASSERT(*path != NULL);
|
||||
ASSERT(thread != NULL);
|
||||
// TODO: Support some file systems!
|
||||
*pathoffset = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( unlikely(**path != '/') ) { return NULL; } (*path)++;
|
||||
MountPoint* currentFS = thread->GetProcess->GetRootFS();
|
||||
|
||||
ASSERT(currentFS != NULL);
|
||||
|
||||
// Simply check if path belongs to a child mount point.
|
||||
for ( MountPoint* considering = currentFS->child; considering != NULL; considering = considering->nextSibling )
|
||||
{
|
||||
ASSERT(considering->IsSane());
|
||||
|
||||
size_t consideringPathLen = String::Length(considering->path);
|
||||
if ( String::CompareN(*path, considering->path, consideringPathLen) == 0 )
|
||||
{
|
||||
// Check if this is the right dir!
|
||||
char lastChar = (*path)[consideringPathLen];
|
||||
|
||||
if ( lastChar == '/' ) { (*path) += consideringPathLen + 1; }
|
||||
else if ( lastChar == '\0' ) { (*path) += consideringPathLen + 0; }
|
||||
else { continue; }
|
||||
|
||||
// Check if the mountpoint isn't ready.
|
||||
if ( considering->waiting != NULL ) { Error::Set(Error::EBUSY); return NULL; }
|
||||
|
||||
currentFS = considering;
|
||||
considering = currentFS->child;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(currentFS->fs != NULL);
|
||||
|
||||
return currentFS;
|
||||
void Init()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -27,47 +27,12 @@
|
|||
|
||||
namespace Sortix
|
||||
{
|
||||
class Device;
|
||||
class DevFileSystem;
|
||||
class DevBuffer;
|
||||
class Process;
|
||||
|
||||
class MountPoint
|
||||
{
|
||||
public:
|
||||
MountPoint();
|
||||
~MountPoint();
|
||||
|
||||
public:
|
||||
const char* path;
|
||||
DevFileSystem* fs;
|
||||
DevBuffer* device;
|
||||
nat flags;
|
||||
|
||||
public:
|
||||
Thread* waiting;
|
||||
int* waitingResult;
|
||||
|
||||
public:
|
||||
bool Mount();
|
||||
|
||||
public:
|
||||
bool IsSane() { return path != NULL && fs != NULL && device != NULL; }
|
||||
|
||||
};
|
||||
|
||||
namespace Mount
|
||||
{
|
||||
void Init();
|
||||
MountPoint* GetMountPoint(const char*& path, Thread* thread);
|
||||
void OnMountFailure(MountPoint* mountPoint, int cause);
|
||||
void OnMountSuccess(MountPoint* mountPoint);
|
||||
}
|
||||
|
||||
namespace Syscall
|
||||
{
|
||||
void SysOpen(Thread* thread);
|
||||
void SysMount(Thread* thread);
|
||||
DevFileSystem* WhichFileSystem(const char* path, size_t* pathoffset);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,8 @@
|
|||
#define SYSCALL_PIPE 20
|
||||
#define SYSCALL_CLOSE 21
|
||||
#define SYSCALL_DUP 22
|
||||
#define SYSCALL_MAX_NUM 23 /* index of highest constant + 1 */
|
||||
#define SYSCALL_OPEN 23
|
||||
#define SYSCALL_MAX_NUM 24 /* index of highest constant + 1 */
|
||||
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in a new issue