Added open(2).

Please note that mount points and file systems do not exist yet.
This commit is contained in:
Jonas 'Sortie' Termansen 2011-11-17 23:31:41 +01:00
parent 6447783c12
commit ae423eaeef
9 changed files with 112 additions and 361 deletions

View File

@ -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

View File

@ -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
}

View File

@ -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
View 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);
}
}
}

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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, &params->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(&params->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, &params->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(&params->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, &params->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()
{
}
}
}

View File

@ -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);
}
}

View File

@ -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