mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Refactor kernel VFS.
Note: This is an incompatible ABI change.
This commit is contained in:
parent
9634a0c3d2
commit
1444683ea8
92 changed files with 4494 additions and 4472 deletions
11
Makefile
11
Makefile
|
@ -162,8 +162,17 @@ release-all-archs:
|
|||
$(INITRD): sysroot
|
||||
mkdir -p `dirname $(INITRD)`
|
||||
echo -n > $(INITRD).filter
|
||||
echo "exclude /boot" >> $(INITRD).filter
|
||||
echo "exclude /dev" >> $(INITRD).filter
|
||||
echo "exclude /next" >> $(INITRD).filter
|
||||
echo "exclude /tmp" >> $(INITRD).filter
|
||||
for OTHER_PLATFORM in $(OTHER_PLATFORMS); do \
|
||||
echo "exclude /$$OTHER_PLATFORM" >> $(INITRD).filter; \
|
||||
echo "exclude /etc/$$OTHER_PLATFORM" >> $(INITRD).filter; \
|
||||
echo "exclude /include/$$OTHER_PLATFORM" >> $(INITRD).filter; \
|
||||
done;
|
||||
if ! which mkinitrd; then echo You need to install mkinitrd; fi
|
||||
mkinitrd --filter $(INITRD).filter "$(SYSROOT)/$(HOST)/bin" -o $(INITRD)
|
||||
mkinitrd --filter $(INITRD).filter "$(SYSROOT)" -o $(INITRD)
|
||||
rm -f $(INITRD).filter
|
||||
|
||||
.PHONY: initrd
|
||||
|
|
|
@ -144,6 +144,7 @@ fdio.o \
|
|||
fileno.o \
|
||||
fork.o \
|
||||
fpipe.o \
|
||||
fstatat.o \
|
||||
fstat.o \
|
||||
ftruncate.o \
|
||||
getc.o \
|
||||
|
@ -165,8 +166,8 @@ memstat.o \
|
|||
mkdir.o \
|
||||
mktemp.o \
|
||||
on_exit.o \
|
||||
open.o \
|
||||
openat.o \
|
||||
open.o \
|
||||
pipe.o \
|
||||
print.o \
|
||||
putc.o \
|
||||
|
|
|
@ -26,6 +26,14 @@
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if defined(PLATFORM_X86)
|
||||
#define CPUTYPE_STR "i486-sortix"
|
||||
#elif defined(PLATFORM_X64)
|
||||
#define CPUTYPE_STR "x86_64-sortix"
|
||||
#else
|
||||
#error No cputype environmental variable provided here.
|
||||
#endif
|
||||
|
||||
// Note that the only PATH variable in Sortix is the one used here.
|
||||
extern "C" int execvpe(const char* filename, char* const* argv,
|
||||
char* const* envp)
|
||||
|
@ -33,7 +41,7 @@ extern "C" int execvpe(const char* filename, char* const* argv,
|
|||
if ( strchr(filename, '/') )
|
||||
return execve(filename, argv, envp);
|
||||
size_t filenamelen = strlen(filename);
|
||||
const char* PATH = "/bin";
|
||||
const char* PATH = "/" CPUTYPE_STR "/bin";
|
||||
size_t pathlen = strlen(PATH);
|
||||
char* pathname = (char*) malloc(filenamelen + 1 + pathlen + 1);
|
||||
if ( !pathname ) { return -1; }
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
|
@ -34,8 +35,8 @@
|
|||
|
||||
typedef struct fddir_sortix_struct
|
||||
{
|
||||
struct sortix_dirent* dirent;
|
||||
struct sortix_dirent* current;
|
||||
struct kernel_dirent* dirent;
|
||||
struct kernel_dirent* current;
|
||||
size_t direntsize;
|
||||
int fd;
|
||||
} fddir_sortix_t;
|
||||
|
@ -44,18 +45,23 @@ int fddir_sortix_readents(fddir_sortix_t* info)
|
|||
{
|
||||
if ( !info->dirent )
|
||||
{
|
||||
// Allocate a buffer of at least sizeof(sortix_dirent).
|
||||
info->direntsize = sizeof(struct sortix_dirent) + 4UL;
|
||||
// Allocate a buffer of at least sizeof(kernel_dirent).
|
||||
info->direntsize = sizeof(struct kernel_dirent) + 4UL;
|
||||
info->dirent = malloc(info->direntsize);
|
||||
if ( !info->dirent ) { return -1; }
|
||||
if ( !info->dirent )
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( readdirents(info->fd, info->dirent, info->direntsize) )
|
||||
if ( readdirents(info->fd, info->dirent, info->direntsize) < 0 )
|
||||
{
|
||||
if ( errno != ERANGE ) { return -1; }
|
||||
size_t newdirentsize = info->dirent->d_namelen;
|
||||
struct sortix_dirent* newdirent = malloc(newdirentsize);
|
||||
if ( !newdirent ) { return -1; }
|
||||
if ( errno != ERANGE )
|
||||
return -1;
|
||||
size_t newdirentsize = sizeof(struct kernel_dirent) + info->dirent->d_namelen + 1;
|
||||
if ( newdirentsize < info->direntsize )
|
||||
newdirentsize *= 2;
|
||||
struct kernel_dirent* newdirent = malloc(newdirentsize);
|
||||
if ( !newdirent )
|
||||
return -1;
|
||||
free(info->dirent);
|
||||
info->dirent = newdirent;
|
||||
info->direntsize = newdirentsize;
|
||||
|
@ -70,7 +76,8 @@ int fddir_sortix_read(void* user, struct dirent* dirent, size_t* size)
|
|||
fddir_sortix_t* info = (fddir_sortix_t*) user;
|
||||
if ( !info->current )
|
||||
{
|
||||
if ( fddir_sortix_readents(info) ) { return -1; }
|
||||
if ( fddir_sortix_readents(info) )
|
||||
return -1;
|
||||
info->current = info->dirent;
|
||||
}
|
||||
|
||||
|
@ -82,7 +89,7 @@ int fddir_sortix_read(void* user, struct dirent* dirent, size_t* size)
|
|||
dirent->d_reclen = needed;
|
||||
strcpy(dirent->d_name, info->current->d_name);
|
||||
|
||||
info->current = info->current->d_next;
|
||||
info->current = kernel_dirent_next(info->current);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -90,7 +97,7 @@ int fddir_sortix_read(void* user, struct dirent* dirent, size_t* size)
|
|||
int fddir_sortix_rewind(void* user)
|
||||
{
|
||||
fddir_sortix_t* info = (fddir_sortix_t*) user;
|
||||
return lseek(info->fd, SEEK_SET, 0);
|
||||
return lseek(info->fd, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
int fddir_sortix_fd(void* user)
|
||||
|
@ -116,7 +123,9 @@ DIR* fdopendir(int fd)
|
|||
DIR* dir = dnewdir();
|
||||
if ( !dir ) { free(info); return NULL; }
|
||||
|
||||
// TODO: Possibly set O_CLOEXEC on fd, as that's what GNU/Linux does.
|
||||
int old_dflags = fcntl(fd, F_GETFD);
|
||||
if ( 0 <= old_dflags )
|
||||
fcntl(fd, F_SETFD, old_dflags | O_CLOEXEC);
|
||||
|
||||
info->fd = fd;
|
||||
|
||||
|
@ -131,7 +140,7 @@ DIR* fdopendir(int fd)
|
|||
|
||||
DIR* opendir(const char* path)
|
||||
{
|
||||
int fd = open(path, O_SEARCH | O_DIRECTORY | O_CLOEXEC);
|
||||
int fd = open(path, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
|
||||
if ( fd < 0 ) { return NULL; }
|
||||
DIR* dir = fdopendir(fd);
|
||||
if ( !dir ) { close(fd); return NULL; }
|
||||
|
|
33
libc/fstatat.cpp
Normal file
33
libc/fstatat.cpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
The Sortix C Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The Sortix C Library 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
fstatat.cpp
|
||||
Retrieves status of an open file.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
DEFN_SYSCALL4(int, sys_fstatat, SYSCALL_FSTATAT, int, const char*, struct stat*, int);
|
||||
|
||||
extern "C" int fstatat(int dirfd, const char* path, struct stat* buf, int flags)
|
||||
{
|
||||
return sys_fstatat(dirfd, path, buf, flags);
|
||||
}
|
110
libc/getcwd.cpp
110
libc/getcwd.cpp
|
@ -22,12 +22,116 @@
|
|||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
DEFN_SYSCALL2(char*, SysGetCWD, SYSCALL_GETCWD, char*, size_t);
|
||||
static int dup_handles_cwd(int fd)
|
||||
{
|
||||
if ( fd == AT_FDCWD )
|
||||
return open(".", O_RDONLY | O_DIRECTORY);
|
||||
return dup(fd);
|
||||
}
|
||||
|
||||
static char* FindDirectoryEntryAt(int dirfd, ino_t inode, dev_t dev)
|
||||
{
|
||||
int dupdirfd = dup_handles_cwd(dirfd);
|
||||
if ( dupdirfd < 0 )
|
||||
return NULL;
|
||||
DIR* dir = fdopendir(dupdirfd);
|
||||
if ( !dir ) { close(dupdirfd); return NULL; }
|
||||
struct dirent* entry;
|
||||
while ( (entry = readdir(dir)) )
|
||||
{
|
||||
if ( !strcmp(entry->d_name, "..") )
|
||||
continue;
|
||||
struct stat st;
|
||||
if ( fstatat(dupdirfd, entry->d_name, &st, 0) )
|
||||
continue; // Not ideal, but missing permissions, broken symlinks..
|
||||
if ( st.st_ino == inode && st.st_dev == dev )
|
||||
{
|
||||
char* result = strdup(entry->d_name);
|
||||
closedir(dir);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
extern "C" char* get_current_dir_name(void)
|
||||
{
|
||||
int fd;
|
||||
int parent;
|
||||
struct stat fdst;
|
||||
struct stat parentst;
|
||||
size_t retlen = 0;
|
||||
size_t newretlen;
|
||||
char* ret = NULL;
|
||||
char* newret;
|
||||
char* elem;
|
||||
|
||||
fd = open(".", O_RDONLY | O_DIRECTORY);
|
||||
if ( fd < 0 )
|
||||
goto cleanup_done;
|
||||
if ( fstat(fd, &fdst) )
|
||||
goto cleanup_fd;
|
||||
next_parent:
|
||||
parent = openat(fd, "..", O_RDONLY | O_DIRECTORY);
|
||||
if ( parent < 0 )
|
||||
goto cleanup_fd;
|
||||
if ( fstat(parent, &parentst) )
|
||||
goto cleanup_parent;
|
||||
if ( fdst.st_ino == parentst.st_ino &&
|
||||
fdst.st_dev == parentst.st_dev )
|
||||
{
|
||||
close(fd);
|
||||
close(parent);
|
||||
return ret ? ret : strdup("/");
|
||||
}
|
||||
elem = FindDirectoryEntryAt(parent, fdst.st_ino, fdst.st_dev);
|
||||
if ( !elem )
|
||||
goto cleanup_parent;
|
||||
newretlen = 1 + strlen(elem) + retlen;
|
||||
newret = (char*) malloc(sizeof(char) * (newretlen + 1));
|
||||
if ( !newret )
|
||||
goto cleanup_elem;
|
||||
stpcpy(stpcpy(stpcpy(newret, "/"), elem), ret ? ret : "");
|
||||
free(elem);
|
||||
free(ret);
|
||||
ret = newret;
|
||||
retlen = newretlen;
|
||||
close(fd);
|
||||
fd = parent;
|
||||
fdst = parentst;
|
||||
goto next_parent;
|
||||
|
||||
cleanup_elem:
|
||||
free(elem);
|
||||
cleanup_parent:
|
||||
close(parent);
|
||||
cleanup_fd:
|
||||
close(fd);
|
||||
cleanup_done:
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
extern "C" char* getcwd(char* buf, size_t size)
|
||||
{
|
||||
return SysGetCWD(buf, size);
|
||||
char* cwd = get_current_dir_name();
|
||||
if ( !buf )
|
||||
return cwd;
|
||||
if ( !cwd )
|
||||
return NULL;
|
||||
if ( size < strlen(cwd)+1 ) { free(cwd); errno = ERANGE; return NULL; }
|
||||
strcpy(buf, cwd);
|
||||
free(cwd);
|
||||
return buf;
|
||||
}
|
||||
|
|
|
@ -59,9 +59,9 @@ struct flock
|
|||
|
||||
int fcntl(int fd, int cmd, ...);
|
||||
int open(const char* path, int oflag, ...);
|
||||
int openat(int fd, const char* path, int oflag, ...);
|
||||
#if defined(__SORTIX_SHOW_UNIMPLEMENTED)
|
||||
int creat(const char* path, mode_t mode);
|
||||
int openat(int fd, const char* path, int oflag, ...);
|
||||
#endif
|
||||
|
||||
__END_DECLS
|
||||
|
|
|
@ -26,21 +26,16 @@
|
|||
#define _SYS_READDIRENTS_H 1
|
||||
|
||||
#include <features.h>
|
||||
#include <sys/types.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sortix/dirent.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
@include(size_t.h)
|
||||
|
||||
// Keep this up to date with <sortix/directory.h>
|
||||
struct sortix_dirent
|
||||
{
|
||||
struct sortix_dirent* d_next;
|
||||
unsigned char d_type;
|
||||
size_t d_namelen;
|
||||
char d_name[];
|
||||
};
|
||||
|
||||
int readdirents(int fd, struct sortix_dirent* dirent, size_t size);
|
||||
ssize_t readdirents(int fd, struct kernel_dirent* dirent, size_t size);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -45,13 +45,16 @@ __END_DECLS
|
|||
#include <sortix/stat.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
int chmod(const char* path, mode_t mode);
|
||||
int fchmod(int fd, mode_t mode);
|
||||
int fstat(int fd, struct stat* st);
|
||||
int fstatat(int dirfd, const char* path, struct stat* buf, int flags);
|
||||
int lstat(const char* restrict path, struct stat* restrict st);
|
||||
int mkdir(const char *path, mode_t mode);
|
||||
int mkdir(const char* path, mode_t mode);
|
||||
int stat(const char* restrict path, struct stat* restrict st);
|
||||
mode_t umask(mode_t mask);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
|
@ -165,6 +165,7 @@ int execvp(const char*, char* const []);
|
|||
pid_t fork(void);
|
||||
int ftruncate(int, off_t);
|
||||
char* getcwd(char*, size_t);
|
||||
char* get_current_dir_name(void);
|
||||
pid_t getpid(void);
|
||||
pid_t getppid(void);
|
||||
int isatty(int);
|
||||
|
|
|
@ -25,10 +25,9 @@
|
|||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
DEFN_SYSCALL3(int, SysSeek, SYSCALL_SEEK, int, off_t*, int);
|
||||
DEFN_SYSCALL3(off_t, sys_seek, SYSCALL_SEEK, int, off_t, int);
|
||||
|
||||
extern "C" off_t lseek(int fd, off_t offset, int whence)
|
||||
{
|
||||
SysSeek(fd, &offset, whence);
|
||||
return offset;
|
||||
return sys_seek(fd, offset, whence);
|
||||
}
|
||||
|
|
|
@ -26,14 +26,11 @@
|
|||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
DEFN_SYSCALL3(ssize_t, SysRead, SYSCALL_READ, int, void*, size_t);
|
||||
DEFN_SYSCALL3(ssize_t, sys_read, SYSCALL_READ, int, void*, size_t);
|
||||
|
||||
extern "C" ssize_t read(int fd, void* buf, size_t count)
|
||||
{
|
||||
retry:
|
||||
ssize_t result = SysRead(fd, buf, count);
|
||||
if ( result < 0 && errno == EAGAIN ) { goto retry; }
|
||||
return result;
|
||||
return sys_read(fd, buf, count);
|
||||
}
|
||||
|
||||
DEFN_SYSCALL4(ssize_t, sys_pread, SYSCALL_PREAD, int, void*, size_t, off_t);
|
||||
|
|
|
@ -25,9 +25,9 @@
|
|||
#include <sys/readdirents.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
DEFN_SYSCALL3(int, SysReadDirEnts, SYSCALL_READDIRENTS, int, struct sortix_dirent*, size_t);
|
||||
DEFN_SYSCALL4(ssize_t, SysReadDirEnts, SYSCALL_READDIRENTS, int, struct kernel_dirent*, size_t, size_t);
|
||||
|
||||
extern "C" int readdirents(int fd, struct sortix_dirent* dirent, size_t size)
|
||||
extern "C" ssize_t readdirents(int fd, struct kernel_dirent* dirent, size_t size)
|
||||
{
|
||||
return SysReadDirEnts(fd, dirent, size);
|
||||
return SysReadDirEnts(fd, dirent, size, 1);
|
||||
}
|
||||
|
|
|
@ -26,14 +26,11 @@
|
|||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
DEFN_SYSCALL3(ssize_t, SysWrite, SYSCALL_WRITE, int, const void*, size_t);
|
||||
DEFN_SYSCALL3(ssize_t, sys_write, SYSCALL_WRITE, int, const void*, size_t);
|
||||
|
||||
extern "C" ssize_t write(int fd, const void* buf, size_t count)
|
||||
{
|
||||
retry:
|
||||
ssize_t result = SysWrite(fd, buf, count);
|
||||
if ( result < 0 && errno == EAGAIN ) { goto retry; }
|
||||
return result;
|
||||
return sys_write(fd, buf, count);
|
||||
}
|
||||
|
||||
DEFN_SYSCALL4(ssize_t, sys_pwrite, SYSCALL_PWRITE, int, const void*, size_t, off_t);
|
||||
|
|
|
@ -74,36 +74,34 @@ ata.o \
|
|||
bga.o \
|
||||
calltrace.o \
|
||||
com.o \
|
||||
copy.o \
|
||||
$(CPU)/calltrace.o \
|
||||
$(CPU)/kthread.o \
|
||||
crc32.o \
|
||||
descriptors.o \
|
||||
device.o \
|
||||
directory.o \
|
||||
descriptor.o \
|
||||
dispmsg.o \
|
||||
dtable.o \
|
||||
elf.o \
|
||||
filesystem.o \
|
||||
fs/devfs.o \
|
||||
fs/initfs.o \
|
||||
fs/ramfs.o \
|
||||
fsfunc.o \
|
||||
fs/kram.o \
|
||||
fs/util.o \
|
||||
fs/videofs.o \
|
||||
initrd.o \
|
||||
inode.o \
|
||||
interlock.o \
|
||||
interrupt.o \
|
||||
ioctx.o \
|
||||
io.o \
|
||||
kb/layout/us.o \
|
||||
kb/ps2.o \
|
||||
kernelinfo.o \
|
||||
kernel.o \
|
||||
keyboard.o \
|
||||
kthread.o \
|
||||
lfbtextbuffer.o \
|
||||
linebuffer.o \
|
||||
log.o \
|
||||
logterminal.o \
|
||||
memorymanagement.o \
|
||||
mount.o \
|
||||
mtable.o \
|
||||
panic.o \
|
||||
pci.o \
|
||||
pipe.o \
|
||||
|
@ -115,7 +113,6 @@ signal.o \
|
|||
sound.o \
|
||||
string.o \
|
||||
syscall.o \
|
||||
terminal.o \
|
||||
textbuffer.o \
|
||||
textterminal.o \
|
||||
thread.o \
|
||||
|
@ -125,6 +122,7 @@ utf8.o \
|
|||
vga.o \
|
||||
vgatextbuffer.o \
|
||||
video.o \
|
||||
vnode.o \
|
||||
worker.o \
|
||||
|
||||
ALLOBJS=\
|
||||
|
|
127
sortix/ata.cpp
127
sortix/ata.cpp
|
@ -23,12 +23,18 @@
|
|||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/interlock.h>
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include "cpu.h"
|
||||
#include <sortix/kernel/refcount.h>
|
||||
#include <sortix/kernel/inode.h>
|
||||
#include <sortix/kernel/ioctx.h>
|
||||
#include <sortix/kernel/descriptor.h>
|
||||
#include <sortix/stat.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "ata.h"
|
||||
#include "fs/devfs.h"
|
||||
#include "cpu.h"
|
||||
|
||||
// TODO: Use the PCI to detect ATA devices instead of relying on them being on
|
||||
// standard locations.
|
||||
|
@ -62,27 +68,126 @@ const uint8_t CTL_RESET = (1<<2);
|
|||
|
||||
namespace ATA {
|
||||
|
||||
void DetectDrive(unsigned busid, ATABus* bus, unsigned driveid)
|
||||
class ATANode : public AbstractInode
|
||||
{
|
||||
public:
|
||||
ATANode(ATADrive* drive, uid_t owner, gid_t group, mode_t mode, dev_t dev,
|
||||
ino_t ino);
|
||||
virtual ~ATANode();
|
||||
virtual int sync(ioctx_t* ctx);
|
||||
virtual int truncate(ioctx_t* ctx, off_t length);
|
||||
virtual off_t lseek(ioctx_t* ctx, off_t offset, int whence);
|
||||
virtual ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count,
|
||||
off_t off);
|
||||
virtual ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
||||
off_t off);
|
||||
|
||||
private:
|
||||
kthread_mutex_t filelock;
|
||||
ATADrive* drive;
|
||||
|
||||
};
|
||||
|
||||
ATANode::ATANode(ATADrive* drive, uid_t owner, gid_t group, mode_t mode,
|
||||
dev_t dev, ino_t /*ino*/)
|
||||
{
|
||||
inode_type = INODE_TYPE_FILE;
|
||||
filelock = KTHREAD_MUTEX_INITIALIZER;
|
||||
this->dev = dev;
|
||||
this->ino = (ino_t) this;
|
||||
this->stat_uid = owner;
|
||||
this->stat_gid = group;
|
||||
this->type = S_IFBLK;
|
||||
this->stat_size = (off_t) drive->GetSize();
|
||||
this->stat_mode = (mode & S_SETABLE) | this->type;
|
||||
this->stat_blksize = (blksize_t) drive->GetSectorSize();
|
||||
this->stat_blocks = (blkcnt_t) drive->GetNumSectors();
|
||||
this->drive = drive;
|
||||
}
|
||||
|
||||
ATANode::~ATANode()
|
||||
{
|
||||
delete drive;
|
||||
}
|
||||
|
||||
int ATANode::sync(ioctx_t* /*ctx*/)
|
||||
{
|
||||
// TODO: Actually sync the device here!
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ATANode::truncate(ioctx_t* /*ctx*/, off_t length)
|
||||
{
|
||||
ScopedLock lock(&filelock);
|
||||
if ( length == drive->GetSize() ) { return 0; }
|
||||
errno = EPERM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
off_t ATANode::lseek(ioctx_t* /*ctx*/, off_t offset, int whence)
|
||||
{
|
||||
ScopedLock lock(&filelock);
|
||||
if ( whence == SEEK_SET )
|
||||
return offset;
|
||||
if ( whence == SEEK_END )
|
||||
return (off_t) drive->GetSize() + offset;
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t ATANode::pread(ioctx_t* /*ctx*/, uint8_t* buf, size_t count, off_t off)
|
||||
{
|
||||
// TODO: SECURITY: Use ioctx copy functions to copy or we have a serious
|
||||
// security hole if invoked from user-space!
|
||||
size_t numbytes = drive->Read(off, buf, count);
|
||||
if ( numbytes < count )
|
||||
return -1;
|
||||
return (ssize_t) numbytes;
|
||||
}
|
||||
|
||||
ssize_t ATANode::pwrite(ioctx_t* /*ctx*/, const uint8_t* buf, size_t count,
|
||||
off_t off)
|
||||
{
|
||||
// TODO: SECURITY: Use ioctx copy functions to copy or we have a serious
|
||||
// security hole if invoked from user-space!
|
||||
size_t numbytes = drive->Write(off, buf, count);
|
||||
if ( numbytes < count )
|
||||
return -1;
|
||||
return (ssize_t) numbytes;
|
||||
}
|
||||
|
||||
void DetectDrive(const char* devpath, Ref<Descriptor> slashdev, unsigned busid,
|
||||
ATABus* bus, unsigned driveid)
|
||||
{
|
||||
unsigned ataid = busid*2 + driveid;
|
||||
ATADrive* drive = bus->Instatiate(driveid);
|
||||
if ( !drive ) { return; }
|
||||
DeviceFS::RegisterATADrive(ataid, drive);
|
||||
if ( !drive )
|
||||
return;
|
||||
Ref<ATANode> node(new ATANode(drive, 0, 0, 0660, slashdev->dev, 0));
|
||||
if ( !node )
|
||||
Panic("Unable to allocate memory for ATA drive inode.");
|
||||
const size_t NAMELEN = 64;
|
||||
char name[NAMELEN];
|
||||
snprintf(name, NAMELEN, "ata%u", ataid);
|
||||
ioctx_t ctx; SetupKernelIOCtx(&ctx);
|
||||
if ( LinkInodeInDir(&ctx, slashdev, name, node) != 0 )
|
||||
PanicF("Unable to link %s/%s to ATA driver inode.", devpath, name);
|
||||
}
|
||||
|
||||
void DetectBus(unsigned busid, uint16_t ioport, uint16_t altio)
|
||||
void DetectBus(const char* devpath, Ref<Descriptor> slashdev, unsigned busid,
|
||||
uint16_t ioport, uint16_t altio)
|
||||
{
|
||||
ATABus* bus = ATA::CreateBus(ioport, altio);
|
||||
if ( !bus )
|
||||
return;
|
||||
DetectDrive(busid, bus, 0);
|
||||
DetectDrive(busid, bus, 1);
|
||||
DetectDrive(devpath, slashdev, busid, bus, 0);
|
||||
DetectDrive(devpath, slashdev, busid, bus, 1);
|
||||
}
|
||||
|
||||
void Init()
|
||||
void Init(const char* devpath, Ref<Descriptor> slashdev)
|
||||
{
|
||||
DetectBus(0, 0x1F0, 0x3F6);
|
||||
DetectBus(1, 0x170, 0x366);
|
||||
DetectBus(devpath, slashdev, 0, 0x1F0, 0x3F6);
|
||||
DetectBus(devpath, slashdev, 1, 0x170, 0x366);
|
||||
}
|
||||
|
||||
ATABus* CreateBus(uint16_t portoffset, uint16_t altport)
|
||||
|
|
|
@ -26,9 +26,11 @@
|
|||
#define SORTIX_ATA_H
|
||||
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
class Descriptor;
|
||||
class ATABus;
|
||||
class ATADrive;
|
||||
|
||||
|
@ -83,7 +85,7 @@ private:
|
|||
|
||||
namespace ATA {
|
||||
|
||||
void Init();
|
||||
void Init(const char* devpath, Ref<Descriptor> slashdev);
|
||||
ATABus* CreateBus(uint16_t portoffset, uint16_t altport);
|
||||
|
||||
} // namespace ATA
|
||||
|
|
149
sortix/com.cpp
149
sortix/com.cpp
|
@ -24,13 +24,16 @@
|
|||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
#include <sortix/kernel/ioctx.h>
|
||||
#include <sortix/kernel/inode.h>
|
||||
#include <sortix/kernel/descriptor.h>
|
||||
#include <sortix/kernel/interlock.h>
|
||||
#include <sortix/stat.h>
|
||||
#include <errno.h>
|
||||
#include "interrupt.h"
|
||||
#include "stream.h"
|
||||
#include "syscall.h"
|
||||
#include "thread.h"
|
||||
#include "signal.h"
|
||||
#include "fs/devfs.h"
|
||||
#include "com.h"
|
||||
|
||||
namespace Sortix {
|
||||
|
@ -51,13 +54,9 @@ namespace COM {
|
|||
|
||||
// Yet another alternative is to use POLL_HACK, but return EGAIN and let user-
|
||||
// space call retry, rather than relying on the broken syscall interstructure.
|
||||
#ifndef GOT_ACTUAL_KTHREAD
|
||||
#define POLL_EAGAIN 1
|
||||
#else
|
||||
#define POLL_EAGAIN 0
|
||||
#endif
|
||||
|
||||
#if !POLL_EAGAIN && !POLL_HACK && defined(GOT_ACTUAL_KTHREAD)
|
||||
#if !POLL_EAGAIN && !POLL_HACK
|
||||
#error The interrupt-based code was broken in the kthread branch.
|
||||
#error You need to port this to the new thread/interrupt API.
|
||||
#warning Oh, and fix the above mentioned bugs too.
|
||||
|
@ -211,133 +210,97 @@ void EarlyInit()
|
|||
}
|
||||
}
|
||||
|
||||
class DevCOMPort : public DevStream
|
||||
class DevCOMPort : public AbstractInode
|
||||
{
|
||||
public:
|
||||
typedef DevStream BaseClass;
|
||||
|
||||
public:
|
||||
DevCOMPort(uint16_t port);
|
||||
DevCOMPort(dev_t dev, uid_t owner, gid_t group, mode_t mode, uint16_t port);
|
||||
virtual ~DevCOMPort();
|
||||
|
||||
public:
|
||||
virtual ssize_t Read(uint8_t* dest, size_t count);
|
||||
virtual ssize_t Write(const uint8_t* src, size_t count);
|
||||
virtual bool IsReadable();
|
||||
virtual bool IsWritable();
|
||||
virtual int sync(ioctx_t* ctx);
|
||||
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
||||
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
||||
|
||||
public:
|
||||
void OnInterrupt();
|
||||
|
||||
private:
|
||||
uint16_t port;
|
||||
kthread_mutex_t portlock;
|
||||
#ifdef GOT_FAKE_KTHREAD
|
||||
Event dataevent;
|
||||
Event sentevent;
|
||||
#endif
|
||||
uint16_t port;
|
||||
|
||||
};
|
||||
|
||||
DevCOMPort::DevCOMPort(uint16_t port)
|
||||
DevCOMPort::DevCOMPort(dev_t dev, uid_t owner, gid_t group, mode_t mode,
|
||||
uint16_t port)
|
||||
{
|
||||
inode_type = INODE_TYPE_STREAM;
|
||||
this->port = port;
|
||||
this->portlock = KTHREAD_MUTEX_INITIALIZER;
|
||||
this->stat_uid = owner;
|
||||
this->stat_gid = group;
|
||||
this->type = S_IFCHR;
|
||||
this->stat_mode = (mode & S_SETABLE) | this->type;
|
||||
this->dev = dev;
|
||||
this->ino = (ino_t) this;
|
||||
}
|
||||
|
||||
DevCOMPort::~DevCOMPort()
|
||||
{
|
||||
}
|
||||
|
||||
bool DevCOMPort::IsReadable() { return true; }
|
||||
bool DevCOMPort::IsWritable() { return true; }
|
||||
int DevCOMPort::sync(ioctx_t* /*ctx*/)
|
||||
{
|
||||
// TODO: Not implemented yet, please wait for all outstanding requests.
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if POLL_HACK
|
||||
|
||||
const unsigned TRIES = 1000;
|
||||
|
||||
ssize_t DevCOMPort::Read(uint8_t* dest, size_t count)
|
||||
ssize_t DevCOMPort::read(ioctx_t* ctx, uint8_t* dest, size_t count)
|
||||
{
|
||||
if ( !count ) { return 0; }
|
||||
if ( SSIZE_MAX < count ) { count = SSIZE_MAX; }
|
||||
ScopedLock lock(&portlock);
|
||||
|
||||
#ifdef GOT_ACTUAL_KTHREAD
|
||||
while ( !(CPU::InPortB(port + LSR) & LSR_READY) )
|
||||
if ( Signal::IsPending() )
|
||||
{
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
uint8_t lsr;
|
||||
for ( unsigned i = 0; i < TRIES; i++ )
|
||||
{
|
||||
lsr = CPU::InPortB(port + LSR);
|
||||
if ( lsr & LSR_READY ) { break; }
|
||||
}
|
||||
|
||||
if ( !(lsr & LSR_READY) )
|
||||
{
|
||||
#if POLL_EAGAIN
|
||||
errno = EAGAIN;
|
||||
#else
|
||||
errno = EBLOCKING;
|
||||
Syscall::Yield();
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t sofar = 0;
|
||||
do
|
||||
{
|
||||
if ( count <= sofar ) { break; }
|
||||
dest[sofar++] = CPU::InPortB(port + RXR);
|
||||
uint8_t val = CPU::InPortB(port + RXR);
|
||||
if ( !ctx->copy_to_dest(dest + sofar++, &val, sizeof(val)) )
|
||||
return -1;
|
||||
} while ( CPU::InPortB(port + LSR) & LSR_READY);
|
||||
|
||||
return sofar;
|
||||
}
|
||||
|
||||
ssize_t DevCOMPort::Write(const uint8_t* src, size_t count)
|
||||
ssize_t DevCOMPort::write(ioctx_t* ctx, const uint8_t* src, size_t count)
|
||||
{
|
||||
if ( !count ) { return 0; }
|
||||
if ( SSIZE_MAX < count ) { count = SSIZE_MAX; };
|
||||
|
||||
ScopedLock lock(&portlock);
|
||||
|
||||
#ifdef GOT_ACTUAL_KTHREAD
|
||||
while ( !(CPU::InPortB(port + LSR) & LSR_THRE) )
|
||||
if ( Signal::IsPending() )
|
||||
{
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
uint8_t lsr;
|
||||
for ( unsigned i = 0; i < TRIES; i++ )
|
||||
{
|
||||
lsr = CPU::InPortB(port + LSR);
|
||||
if ( lsr & LSR_THRE ) { break; }
|
||||
}
|
||||
|
||||
if ( !(lsr & LSR_THRE) )
|
||||
{
|
||||
#if POLL_EAGAIN
|
||||
errno = EAGAIN;
|
||||
#else
|
||||
errno = EBLOCKING;
|
||||
Syscall::Yield();
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t sofar = 0;
|
||||
do
|
||||
{
|
||||
if ( count <= sofar ) { break; }
|
||||
CPU::OutPortB(port + TXR, src[sofar++]);
|
||||
uint8_t val;
|
||||
if ( !ctx->copy_from_src(&val, src + sofar++, sizeof(val)) )
|
||||
return -1;
|
||||
CPU::OutPortB(port + TXR, val);
|
||||
} while ( CPU::InPortB(port + LSR) & LSR_THRE );
|
||||
|
||||
return sofar;
|
||||
|
@ -345,7 +308,9 @@ ssize_t DevCOMPort::Write(const uint8_t* src, size_t count)
|
|||
|
||||
#else
|
||||
|
||||
ssize_t DevCOMPort::Read(uint8_t* dest, size_t count)
|
||||
#error Yeah, please port these to the new IO interface.
|
||||
|
||||
ssize_t DevCOMPort::Read(byte* dest, size_t count)
|
||||
{
|
||||
if ( !count ) { return 0; }
|
||||
if ( SSIZE_MAX < count ) { count = SSIZE_MAX; }
|
||||
|
@ -355,12 +320,8 @@ ssize_t DevCOMPort::Read(uint8_t* dest, size_t count)
|
|||
uint8_t lsr = CPU::InPortB(port + LSR);
|
||||
if ( !(lsr & LSR_READY) )
|
||||
{
|
||||
#ifdef GOT_ACTUAL_KTHREAD
|
||||
Panic("Can't wait for com data receive event");
|
||||
#else
|
||||
dataevent.Register();
|
||||
#endif
|
||||
errno = EBLOCKING;
|
||||
Error::Set(EBLOCKING);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -384,12 +345,8 @@ ssize_t DevCOMPort::Write(const uint8_t* src, size_t count)
|
|||
uint8_t lsr = CPU::InPortB(port + LSR);
|
||||
if ( !(lsr & LSR_THRE) )
|
||||
{
|
||||
#ifdef GOT_ACTUAL_KTHREAD
|
||||
Panic("Can't wait for com data sent event");
|
||||
#else
|
||||
sentevent.Register();
|
||||
#endif
|
||||
errno = EBLOCKING;
|
||||
Error::Set(EBLOCKING);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -424,18 +381,10 @@ void DevCOMPort::OnInterrupt()
|
|||
CPU::InPortB(port + LSR);
|
||||
break;
|
||||
case IIR_RECV_DATA:
|
||||
#ifdef GOT_ACTUAL_KTHREAD
|
||||
Panic("Can't wait for com data sent event");
|
||||
#else
|
||||
dataevent.Signal();
|
||||
#endif
|
||||
break;
|
||||
case IIR_SENT_DATA:
|
||||
#ifdef GOT_ACTUAL_KTHREAD
|
||||
Panic("Can't wait for com data sent event");
|
||||
#else
|
||||
sentevent.Signal();
|
||||
#endif
|
||||
CPU::InPortB(port + IIR);
|
||||
break;
|
||||
case IIR_MODEM_STATUS:
|
||||
|
@ -444,7 +393,7 @@ void DevCOMPort::OnInterrupt()
|
|||
}
|
||||
}
|
||||
|
||||
DevCOMPort* comdevices[1+NUMCOMPORTS];
|
||||
Ref<DevCOMPort> comdevices[1+NUMCOMPORTS];
|
||||
|
||||
static void UARTIRQHandler(CPU::InterruptRegisters* /*regs*/, void* /*user*/)
|
||||
{
|
||||
|
@ -455,12 +404,14 @@ static void UARTIRQHandler(CPU::InterruptRegisters* /*regs*/, void* /*user*/)
|
|||
}
|
||||
}
|
||||
|
||||
void Init()
|
||||
void Init(const char* devpath, Ref<Descriptor> slashdev)
|
||||
{
|
||||
ioctx_t ctx; SetupKernelIOCtx(&ctx);
|
||||
for ( size_t i = 1; i <= NUMCOMPORTS; i++ )
|
||||
{
|
||||
if ( !comports[i] ) { comdevices[i] = NULL; continue; }
|
||||
comdevices[i] = new DevCOMPort(comports[i]);
|
||||
if ( !comports[i] ) { comdevices[i] = Ref<DevCOMPort>(); continue; }
|
||||
comdevices[i] = Ref<DevCOMPort>
|
||||
(new DevCOMPort(slashdev->dev, 0, 0, 0660, comports[i]));
|
||||
if ( !comdevices[i] )
|
||||
{
|
||||
PanicF("Unable to allocate device for COM port %zu at 0x%x", i,
|
||||
|
@ -468,10 +419,8 @@ void Init()
|
|||
}
|
||||
char name[5] = "comN";
|
||||
name[3] = '0' + i;
|
||||
if ( !DeviceFS::RegisterDevice(name, comdevices[i]) )
|
||||
{
|
||||
PanicF("Unable to register device /dev/%s", name);
|
||||
}
|
||||
if ( LinkInodeInDir(&ctx, slashdev, name, comdevices[i]) != 0 )
|
||||
PanicF("Unable to link %s/%s to COM port driver.", devpath, name);
|
||||
}
|
||||
|
||||
Interrupt::RegisterHandler(Interrupt::IRQ3, UARTIRQHandler, NULL);
|
||||
|
|
|
@ -26,12 +26,16 @@
|
|||
#define SORTIX_COM_H
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
class Descriptor;
|
||||
|
||||
namespace COM {
|
||||
|
||||
void EarlyInit();
|
||||
void Init();
|
||||
void Init(const char* devpath, Ref<Descriptor> slashdev);
|
||||
|
||||
} // namespace COM
|
||||
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
||||
|
|
65
sortix/copy.cpp
Normal file
65
sortix/copy.cpp
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
|
||||
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/>.
|
||||
|
||||
copy.h
|
||||
The context for io operations: who made it, how should data be copied, etc.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/copy.h>
|
||||
#include <sortix/kernel/string.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
// TODO: These are currently insecure, please check userspace tables before
|
||||
// moving data to avoid security problems.
|
||||
|
||||
bool CopyToUser(void* userdst, const void* ksrc, size_t count)
|
||||
{
|
||||
memcpy(userdst, ksrc, count);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CopyFromUser(void* kdst, const void* usersrc, size_t count)
|
||||
{
|
||||
//Log::PrintF("[copy.cpp] Copying %zu bytes from 0x%zx to 0x%zx\n", count, usersrc, kdst);
|
||||
memcpy(kdst, usersrc, count);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CopyToKernel(void* kdst, const void* ksrc, size_t count)
|
||||
{
|
||||
memcpy(kdst, ksrc, count);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CopyFromKernel(void* kdst, const void* ksrc, size_t count)
|
||||
{
|
||||
memcpy(kdst, ksrc, count);
|
||||
return true;
|
||||
}
|
||||
|
||||
char* GetStringFromUser(const char* str)
|
||||
{
|
||||
return String::Clone(str);
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
419
sortix/descriptor.cpp
Normal file
419
sortix/descriptor.cpp
Normal file
|
@ -0,0 +1,419 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
|
||||
|
||||
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/>.
|
||||
|
||||
descriptor.cpp
|
||||
A file descriptor.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
#include <sortix/kernel/ioctx.h>
|
||||
#include <sortix/kernel/inode.h>
|
||||
#include <sortix/kernel/vnode.h>
|
||||
#include <sortix/kernel/descriptor.h>
|
||||
#include <sortix/kernel/fsfunc.h>
|
||||
#include <sortix/kernel/string.h>
|
||||
#include <sortix/kernel/copy.h> // DEBUG
|
||||
#include <sortix/dirent.h>
|
||||
#include <sortix/fcntl.h>
|
||||
#include <sortix/seek.h>
|
||||
#include <sortix/stat.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "process.h"
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
bool LinkInodeInDir(ioctx_t* ctx, Ref<Descriptor> dir, const char* name,
|
||||
Ref<Inode> inode)
|
||||
{
|
||||
Ref<Vnode> vnode(new Vnode(inode, Ref<Vnode>(), 0, 0));
|
||||
if ( !vnode ) return false;
|
||||
Ref<Descriptor> desc(new Descriptor(Ref<Vnode>(vnode), 0));
|
||||
if ( !desc ) return false;
|
||||
return dir->link(ctx, name, desc) != 0;
|
||||
}
|
||||
|
||||
Ref<Descriptor> OpenDirContainingPath(ioctx_t* ctx, Ref<Descriptor> from,
|
||||
const char* path, char** finalp)
|
||||
{
|
||||
if ( !path[0] ) { errno = EINVAL; return Ref<Descriptor>(); }
|
||||
char* dirpath;
|
||||
char* final;
|
||||
if ( !SplitFinalElem(path, &dirpath, &final) )
|
||||
return Ref<Descriptor>();
|
||||
// TODO: Removing trailing slashes in final may not the right thing.
|
||||
size_t finallen = strlen(final);
|
||||
while ( finallen && final[finallen-1] == '/' )
|
||||
final[--finallen] = 0;
|
||||
// Safe against buffer overflow because final contains at least one
|
||||
// character because we reject the empty string above.
|
||||
if ( !finallen )
|
||||
final[0] = '.',
|
||||
final[1] = '\0';
|
||||
if ( !dirpath[0] )
|
||||
{
|
||||
delete[] dirpath;
|
||||
*finalp = final;
|
||||
return from;
|
||||
}
|
||||
Ref<Descriptor> ret = from->open(ctx, dirpath, O_RDONLY | O_DIRECTORY, 0);
|
||||
delete[] dirpath;
|
||||
if ( !ret ) { delete[] final; return Ref<Descriptor>(); }
|
||||
*finalp = final;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// TODO: Add security checks.
|
||||
|
||||
Descriptor::Descriptor(Ref<Vnode> vnode, int dflags)
|
||||
{
|
||||
curofflock = KTHREAD_MUTEX_INITIALIZER;
|
||||
this->vnode = vnode;
|
||||
this->ino = vnode->ino;
|
||||
this->dev = vnode->dev;
|
||||
this->type = vnode->type;
|
||||
this->dflags = dflags;
|
||||
checked_seekable = false;
|
||||
curoff = 0;
|
||||
}
|
||||
|
||||
Descriptor::~Descriptor()
|
||||
{
|
||||
}
|
||||
|
||||
Ref<Descriptor> Descriptor::Fork()
|
||||
{
|
||||
Ref<Descriptor> ret(new Descriptor(vnode, dflags));
|
||||
if ( !ret )
|
||||
return Ref<Descriptor>();
|
||||
ret->curoff = curoff;
|
||||
ret->checked_seekable = checked_seekable;
|
||||
ret->seekable = seekable;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Descriptor::IsSeekable()
|
||||
{
|
||||
if ( !checked_seekable )
|
||||
{
|
||||
// TODO: Is this enough? Check that errno happens to be ESPIPE?
|
||||
ioctx_t ctx; SetupKernelIOCtx(&ctx);
|
||||
seekable = 0 <= vnode->lseek(&ctx, SEEK_SET, 0) || S_ISDIR(vnode->type);
|
||||
checked_seekable = true;
|
||||
}
|
||||
return seekable;
|
||||
}
|
||||
|
||||
int Descriptor::sync(ioctx_t* ctx)
|
||||
{
|
||||
return vnode->sync(ctx);
|
||||
}
|
||||
|
||||
int Descriptor::stat(ioctx_t* ctx, struct stat* st)
|
||||
{
|
||||
return vnode->stat(ctx, st);
|
||||
}
|
||||
|
||||
int Descriptor::chmod(ioctx_t* ctx, mode_t mode)
|
||||
{
|
||||
return vnode->chmod(ctx, mode);
|
||||
}
|
||||
|
||||
int Descriptor::chown(ioctx_t* ctx, uid_t owner, gid_t group)
|
||||
{
|
||||
if ( owner < 0 || group < 0 ) { errno = EINVAL; return -1; }
|
||||
return vnode->chown(ctx, owner, group);
|
||||
}
|
||||
|
||||
int Descriptor::truncate(ioctx_t* ctx, off_t length)
|
||||
{
|
||||
if ( length < 0 ) { errno = EINVAL; return -1; }
|
||||
return vnode->truncate(ctx, length);
|
||||
}
|
||||
|
||||
off_t Descriptor::lseek(ioctx_t* ctx, off_t offset, int whence)
|
||||
{
|
||||
if ( !IsSeekable() )
|
||||
return vnode->lseek(ctx, offset, whence);
|
||||
ScopedLock lock(&curofflock);
|
||||
off_t reloff;
|
||||
if ( whence == SEEK_SET )
|
||||
reloff = 0;
|
||||
else if ( whence == SEEK_CUR )
|
||||
reloff = curoff;
|
||||
else if ( whence == SEEK_END )
|
||||
{
|
||||
if ( (reloff = vnode->lseek(ctx, offset, SEEK_END)) < 0 )
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
return errno = EINVAL, -1;
|
||||
|
||||
if ( offset < 0 && reloff + offset < 0 )
|
||||
return errno = EOVERFLOW, -1;
|
||||
if ( OFF_MAX - curoff < offset )
|
||||
return errno = EOVERFLOW, -1;
|
||||
|
||||
return curoff = reloff + offset;
|
||||
}
|
||||
|
||||
ssize_t Descriptor::read(ioctx_t* ctx, uint8_t* buf, size_t count)
|
||||
{
|
||||
if ( !count ) { return 0; }
|
||||
if ( (size_t) SSIZE_MAX < count ) { count = SSIZE_MAX; }
|
||||
if ( !IsSeekable() )
|
||||
return vnode->read(ctx, buf, count);
|
||||
// TODO: Locking here only allows one task to read/write at once.
|
||||
ScopedLock lock(&curofflock);
|
||||
ssize_t ret = vnode->pread(ctx, buf, count, curoff);
|
||||
if ( 0 <= ret )
|
||||
curoff += ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t Descriptor::pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off)
|
||||
{
|
||||
if ( off < 0 ) { errno = EINVAL; return -1; }
|
||||
if ( !count ) { return 0; }
|
||||
if ( SSIZE_MAX < count ) { count = SSIZE_MAX; }
|
||||
return vnode->pread(ctx, buf, count, off);
|
||||
}
|
||||
|
||||
ssize_t Descriptor::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
||||
{
|
||||
if ( !count ) { return 0; }
|
||||
if ( SSIZE_MAX < count ) { count = SSIZE_MAX; }
|
||||
if ( !IsSeekable() )
|
||||
return vnode->write(ctx, buf, count);
|
||||
// TODO: Locking here only allows one task to read/write at once.
|
||||
ScopedLock lock(&curofflock);
|
||||
// TODO: What if lseek fails? Sets curoff = -1, which we forward to vnodes
|
||||
// and we are not allowed to do that!
|
||||
if ( dflags & O_APPEND )
|
||||
curoff = vnode->lseek(ctx, 0, SEEK_END);
|
||||
ssize_t ret = vnode->pwrite(ctx, buf, count, curoff);
|
||||
if ( 0 <= ret )
|
||||
curoff += ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t Descriptor::pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t off)
|
||||
{
|
||||
if ( off < 0 ) { errno = EINVAL; return -1; }
|
||||
if ( !count ) { return 0; }
|
||||
if ( SSIZE_MAX < count ) { count = SSIZE_MAX; }
|
||||
return vnode->pwrite(ctx, buf, count, off);
|
||||
}
|
||||
|
||||
int Descriptor::utimes(ioctx_t* ctx, const struct timeval times[2])
|
||||
{
|
||||
return vnode->utimes(ctx, times);
|
||||
}
|
||||
|
||||
int Descriptor::isatty(ioctx_t* ctx)
|
||||
{
|
||||
return vnode->isatty(ctx);
|
||||
}
|
||||
|
||||
ssize_t Descriptor::readdirents(ioctx_t* ctx, struct kernel_dirent* dirent,
|
||||
size_t size, size_t maxcount)
|
||||
{
|
||||
if ( !maxcount ) { return 0; }
|
||||
if ( SSIZE_MAX < size ) { size = SSIZE_MAX; }
|
||||
if ( size < sizeof(*dirent) ) { errno = EINVAL; return -1; }
|
||||
// TODO: Locking here only allows one task to read/write at once.
|
||||
ScopedLock lock(&curofflock);
|
||||
ssize_t ret = vnode->readdirents(ctx, dirent, size, curoff, maxcount);
|
||||
if ( ret == 0 )
|
||||
{
|
||||
const char* name = "";
|
||||
size_t namelen = strlen(name);
|
||||
size_t needed = sizeof(*dirent) + namelen + 1;
|
||||
struct kernel_dirent retdirent;
|
||||
memset(&retdirent, 0, sizeof(retdirent));
|
||||
retdirent.d_reclen = needed;
|
||||
retdirent.d_off = 0;
|
||||
retdirent.d_namelen = namelen;
|
||||
if ( !ctx->copy_to_dest(dirent, &retdirent, sizeof(retdirent)) )
|
||||
return -1;
|
||||
if ( size < needed )
|
||||
return errno = ERANGE, -1;
|
||||
if ( !ctx->copy_to_dest(dirent->d_name, name, namelen+1) )
|
||||
return -1;
|
||||
return needed;
|
||||
}
|
||||
// TODO: Accessing data here is dangerous if it is userspace:
|
||||
if ( 0 < ret )
|
||||
for ( ; dirent; curoff++, dirent = kernel_dirent_next(dirent) );
|
||||
return ret;
|
||||
}
|
||||
|
||||
Ref<Descriptor> Descriptor::open(ioctx_t* ctx, const char* filename, int flags,
|
||||
mode_t mode)
|
||||
{
|
||||
if ( !filename[0] )
|
||||
return errno = ENOENT, Ref<Descriptor>();
|
||||
// O_DIRECTORY makes us only open directories. It is therefore a logical
|
||||
// error to provide flags that only makes sense for non-directory. We also
|
||||
// filter reject them early to prevent O_TRUNC | O_DIRECTORY from opening a
|
||||
// file, truncating it, and then aborting the open with an error.
|
||||
if ( (flags & (O_CREAT | O_TRUNC)) && (flags & (O_DIRECTORY)) )
|
||||
return errno = EINVAL, Ref<Descriptor>();
|
||||
Ref<Descriptor> desc(this);
|
||||
while ( filename[0] )
|
||||
{
|
||||
if ( filename[0] == '/' )
|
||||
{
|
||||
if ( !S_ISDIR(desc->type) )
|
||||
return errno = ENOTDIR, Ref<Descriptor>();
|
||||
filename++;
|
||||
continue;
|
||||
}
|
||||
size_t slashpos = strcspn(filename, "/");
|
||||
bool lastelem = filename[slashpos] == '\0';
|
||||
char* elem = String::Substring(filename, 0, slashpos);
|
||||
if ( !elem )
|
||||
return Ref<Descriptor>();
|
||||
int open_flags = lastelem ? flags : O_RDONLY;
|
||||
// Forward O_DIRECTORY so the operation can fail earlier. If it doesn't
|
||||
// fail and we get a non-directory in return, we'll handle it on exit
|
||||
// with no consequences (since opening an existing file is harmless).
|
||||
open_flags &= ~(0 /*| O_DIRECTORY*/);
|
||||
mode_t open_mode = lastelem ? mode : 0;
|
||||
// TODO: O_NOFOLLOW.
|
||||
Ref<Descriptor> next = desc->open_elem(ctx, elem, open_flags, open_mode);
|
||||
delete[] elem;
|
||||
if ( !next )
|
||||
return Ref<Descriptor>();
|
||||
desc = next;
|
||||
filename += slashpos;
|
||||
}
|
||||
if ( flags & O_DIRECTORY && !S_ISDIR(desc->type) )
|
||||
return errno = ENOTDIR, Ref<Descriptor>();
|
||||
|
||||
// TODO: The new file descriptor may not be opened with the correct
|
||||
// permissions in the below case!
|
||||
// If the path only contains slashes, we'll get outselves back, be sure to
|
||||
// get ourselves back.
|
||||
return desc == this ? Fork() : desc;
|
||||
}
|
||||
|
||||
Ref<Descriptor> Descriptor::open_elem(ioctx_t* ctx, const char* filename,
|
||||
int flags, mode_t mode)
|
||||
{
|
||||
assert(!strchr(filename, '/'));
|
||||
int next_flags = flags & ~(O_APPEND | O_CLOEXEC);
|
||||
Ref<Vnode> retvnode = vnode->open(ctx, filename, next_flags, mode);
|
||||
if ( !retvnode )
|
||||
return Ref<Descriptor>();
|
||||
Ref<Descriptor> ret(new Descriptor(retvnode, flags & O_APPEND));
|
||||
if ( !ret )
|
||||
return Ref<Descriptor>();
|
||||
if ( (flags & O_TRUNC) && S_ISREG(ret->type) )
|
||||
if ( (flags & O_ACCMODE) == O_WRONLY ||
|
||||
(flags & O_ACCMODE) == O_RDWR )
|
||||
ret->truncate(ctx, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Descriptor::mkdir(ioctx_t* ctx, const char* filename, mode_t mode)
|
||||
{
|
||||
char* final;
|
||||
Ref<Descriptor> dir = OpenDirContainingPath(ctx, Ref<Descriptor>(this),
|
||||
filename, &final);
|
||||
if ( !dir )
|
||||
return -1;
|
||||
int ret = dir->vnode->mkdir(ctx, final, mode);
|
||||
delete[] final;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Descriptor::link(ioctx_t* ctx, const char* filename, Ref<Descriptor> node)
|
||||
{
|
||||
char* final;
|
||||
Ref<Descriptor> dir = OpenDirContainingPath(ctx, Ref<Descriptor>(this),
|
||||
filename, &final);
|
||||
if ( !dir )
|
||||
return -1;
|
||||
int ret = dir->vnode->link(ctx, final, node->vnode);
|
||||
delete[] final;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Descriptor::unlink(ioctx_t* ctx, const char* filename)
|
||||
{
|
||||
char* final;
|
||||
Ref<Descriptor> dir = OpenDirContainingPath(ctx, Ref<Descriptor>(this),
|
||||
filename, &final);
|
||||
if ( !dir )
|
||||
return -1;
|
||||
int ret = dir->vnode->unlink(ctx, final);
|
||||
delete[] final;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Descriptor::rmdir(ioctx_t* ctx, const char* filename)
|
||||
{
|
||||
char* final;
|
||||
Ref<Descriptor> dir = OpenDirContainingPath(ctx, Ref<Descriptor>(this),
|
||||
filename, &final);
|
||||
if ( !dir )
|
||||
return -1;
|
||||
int ret = dir->vnode->rmdir(ctx, final);
|
||||
delete[] final;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Descriptor::symlink(ioctx_t* ctx, const char* oldname, const char* filename)
|
||||
{
|
||||
char* final;
|
||||
Ref<Descriptor> dir = OpenDirContainingPath(ctx, Ref<Descriptor>(this),
|
||||
filename, &final);
|
||||
if ( !dir )
|
||||
return -1;
|
||||
int ret = dir->vnode->symlink(ctx, oldname, final);
|
||||
delete[] final;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t Descriptor::readlink(ioctx_t* ctx, char* buf, size_t bufsize)
|
||||
{
|
||||
return vnode->readlink(ctx, buf, bufsize);
|
||||
}
|
||||
|
||||
int Descriptor::tcgetwinsize(ioctx_t* ctx, struct winsize* ws)
|
||||
{
|
||||
return vnode->tcgetwinsize(ctx, ws);
|
||||
}
|
||||
|
||||
int Descriptor::settermmode(ioctx_t* ctx, unsigned mode)
|
||||
{
|
||||
return vnode->settermmode(ctx, mode);
|
||||
}
|
||||
|
||||
int Descriptor::gettermmode(ioctx_t* ctx, unsigned* mode)
|
||||
{
|
||||
return vnode->gettermmode(ctx, mode);
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
|
@ -1,195 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
|
||||
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/>.
|
||||
|
||||
descriptors.cpp
|
||||
Handles file descriptors, socket descriptors, and whatnot for each process.
|
||||
|
||||
********************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/string.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "descriptors.h"
|
||||
#include "device.h"
|
||||
#include <sortix/fcntl.h>
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
// When in doubt use brute-force. This class could easily be optimized.
|
||||
|
||||
Device* const RESERVED_DEVICE = (Device*) 0x1UL;
|
||||
|
||||
DescriptorTable::DescriptorTable()
|
||||
{
|
||||
numdevices = 0;
|
||||
devices = NULL;
|
||||
}
|
||||
|
||||
DescriptorTable::~DescriptorTable()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void DescriptorTable::Reset()
|
||||
{
|
||||
for ( int i = 0; i < numdevices; i++ )
|
||||
{
|
||||
Device* dev = devices[i].dev;
|
||||
if ( !dev || dev == RESERVED_DEVICE ) { continue; }
|
||||
|
||||
dev->Unref();
|
||||
delete[] devices[i].path;
|
||||
}
|
||||
|
||||
delete[] devices;
|
||||
devices = NULL;
|
||||
numdevices = 0;
|
||||
}
|
||||
|
||||
int DescriptorTable::Allocate(Device* object, char* pathcopy)
|
||||
{
|
||||
for ( int i = 0; i < numdevices; i++ )
|
||||
{
|
||||
if ( !devices[i].dev )
|
||||
{
|
||||
object->Refer();
|
||||
devices[i].dev = object;
|
||||
devices[i].flags = 0;
|
||||
devices[i].path = pathcopy;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
int newlistlength = numdevices*2;
|
||||
if ( newlistlength == 0 ) { newlistlength = 8; }
|
||||
|
||||
DescriptorEntry* newlist = new DescriptorEntry[newlistlength];
|
||||
if ( newlist == NULL ) { return -1; }
|
||||
|
||||
if ( devices != NULL )
|
||||
{
|
||||
memcpy(newlist, devices, sizeof(*devices) * numdevices);
|
||||
}
|
||||
|
||||
for ( int i = numdevices; i < newlistlength; i++ )
|
||||
newlist[i].dev = NULL,
|
||||
newlist[i].path = NULL,
|
||||
newlist[i].flags = 0;
|
||||
|
||||
delete[] devices;
|
||||
|
||||
devices = newlist;
|
||||
numdevices = newlistlength;
|
||||
|
||||
return Allocate(object, pathcopy);
|
||||
}
|
||||
|
||||
void DescriptorTable::Free(int index)
|
||||
{
|
||||
assert(index < numdevices);
|
||||
assert(devices[index].dev);
|
||||
|
||||
if ( devices[index].dev != RESERVED_DEVICE )
|
||||
{
|
||||
devices[index].dev->Unref();
|
||||
delete[] devices[index].path;
|
||||
}
|
||||
|
||||
devices[index].dev = NULL;
|
||||
devices[index].path = NULL;
|
||||
devices[index].flags = 0;
|
||||
}
|
||||
|
||||
int DescriptorTable::Reserve()
|
||||
{
|
||||
return Allocate(RESERVED_DEVICE, NULL);
|
||||
}
|
||||
|
||||
void DescriptorTable::UseReservation(int index, Device* object, char* pathcopy)
|
||||
{
|
||||
assert(index < index);
|
||||
assert(devices[index].dev != NULL);
|
||||
assert(devices[index].dev == RESERVED_DEVICE);
|
||||
assert(devices[index].path == NULL);
|
||||
|
||||
object->Refer();
|
||||
devices[index].dev = object;
|
||||
devices[index].flags = 0;
|
||||
devices[index].path = pathcopy;
|
||||
}
|
||||
|
||||
bool DescriptorTable::Fork(DescriptorTable* forkinto)
|
||||
{
|
||||
DescriptorEntry* newlist = new DescriptorEntry[numdevices];
|
||||
if ( !newlist ) { return false; }
|
||||
|
||||
for ( int i = 0; i < numdevices; i++ )
|
||||
{
|
||||
Device* dev = devices[i].dev;
|
||||
int flags = devices[i].flags;
|
||||
char* path = devices[i].path;
|
||||
if ( !dev || dev == RESERVED_DEVICE )
|
||||
path = NULL;
|
||||
path = path ? String::Clone(path) : NULL;
|
||||
if ( flags & FD_CLOFORK ) { dev = NULL; flags = 0; }
|
||||
newlist[i].dev = dev;
|
||||
newlist[i].flags = flags;
|
||||
if ( !dev || dev == RESERVED_DEVICE ) { continue; }
|
||||
newlist[i].dev->Refer();
|
||||
newlist[i].path = path;
|
||||
}
|
||||
|
||||
assert(!forkinto->devices);
|
||||
|
||||
forkinto->devices = newlist;
|
||||
forkinto->numdevices = numdevices;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DescriptorTable::OnExecute()
|
||||
{
|
||||
for ( int i = 0; i < numdevices; i++ )
|
||||
{
|
||||
if ( devices[i].flags & FD_CLOEXEC ) { Free(i); }
|
||||
}
|
||||
}
|
||||
|
||||
void DescriptorTable::SetFlags(int index, int flags)
|
||||
{
|
||||
assert(0 <= index && index < numdevices);
|
||||
assert(devices[index].dev);
|
||||
devices[index].flags = flags;
|
||||
}
|
||||
|
||||
int DescriptorTable::GetFlags(int index)
|
||||
{
|
||||
assert(0 <= index && index < numdevices);
|
||||
assert(devices[index].dev);
|
||||
return devices[index].flags;
|
||||
}
|
||||
|
||||
const char* DescriptorTable::GetPath(int index)
|
||||
{
|
||||
assert(0 <= index && index < numdevices);
|
||||
assert(devices[index].dev);
|
||||
return devices[index].path;
|
||||
}
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
|
||||
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/>.
|
||||
|
||||
descriptors.h
|
||||
Handles file descriptors, socket descriptors, and whatnot for each process.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_DESCRIPTORS_H
|
||||
#define SORTIX_DESCRIPTORS_H
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
class Device;
|
||||
|
||||
struct DescriptorEntry
|
||||
{
|
||||
Device* dev;
|
||||
int flags;
|
||||
char* path;
|
||||
};
|
||||
|
||||
class DescriptorTable
|
||||
{
|
||||
public:
|
||||
DescriptorTable();
|
||||
~DescriptorTable();
|
||||
|
||||
private:
|
||||
int numdevices;
|
||||
DescriptorEntry* devices;
|
||||
|
||||
public:
|
||||
int Allocate(Device* object, char* pathcopy);
|
||||
int Reserve();
|
||||
void Free(int index);
|
||||
void UseReservation(int index, Device* object, char* pathcopy);
|
||||
bool Fork(DescriptorTable* forkinto);
|
||||
void OnExecute();
|
||||
void Reset();
|
||||
void SetFlags(int index, int flags);
|
||||
int GetFlags(int index);
|
||||
const char* GetPath(int index);
|
||||
|
||||
public:
|
||||
inline Device* Get(int index)
|
||||
{
|
||||
if ( !devices ) { return NULL; }
|
||||
if ( index < 0 || numdevices <= index ) { return NULL; }
|
||||
return devices[index].dev;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,212 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
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/>.
|
||||
|
||||
directory.cpp
|
||||
Allows access to stored sequences of bytes in an orderly fashion.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "syscall.h"
|
||||
#include "process.h"
|
||||
#include "device.h"
|
||||
#include "directory.h"
|
||||
#include "filesystem.h"
|
||||
#include "mount.h"
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
namespace Directory
|
||||
{
|
||||
int SysReadDirEnts(int fd, sortix_dirent* dirent, size_t size)
|
||||
{
|
||||
Process* process = CurrentProcess();
|
||||
Device* dev = process->descriptors.Get(fd);
|
||||
if ( !dev ) { errno = EBADF; return -1; }
|
||||
if ( !dev->IsType(Device::DIRECTORY) ) { errno = EBADF; return -1; }
|
||||
DevDirectory* dir = (DevDirectory*) dev;
|
||||
|
||||
sortix_dirent* prev = NULL;
|
||||
|
||||
while ( true )
|
||||
{
|
||||
// Check if we got enough bytes left to tell how many bytes we
|
||||
// actually needed.
|
||||
if ( size < sizeof(sortix_dirent) )
|
||||
{
|
||||
if ( prev ) { return 0; } // We did some work.
|
||||
errno = EINVAL; // Nope, userspace was cheap.
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Attempt to read into the space left, and if we managed to
|
||||
// read at least one record, just say we succeded. The user
|
||||
// space buffer is empty on the next call, so that'll probably
|
||||
// succeed. The directory read function will store the number of
|
||||
// bytes needed in the d_namelen variable and set errno to
|
||||
// ERANGE such that userspace knows we need a larger buffer.
|
||||
if ( dir->Read(dirent, size) ) { return (prev) ? 0 : -1; }
|
||||
|
||||
// Insert the current dirent into the single-linked list for
|
||||
// easy iteration by userspace.
|
||||
if ( prev ) { prev->d_next = dirent; }
|
||||
dirent->d_next = NULL;
|
||||
|
||||
// Check for end-of-directory conditions. Signal to userspace
|
||||
// that we are done by giving them the empty filename.
|
||||
if ( dirent->d_namelen == 0 ) { return 0; }
|
||||
|
||||
// Alright, we managed to read a dirent. Now let's try reading
|
||||
// another one (provide as many as we can).
|
||||
prev = dirent;
|
||||
size_t bytesused = sizeof(sortix_dirent) + dirent->d_namelen + 1;
|
||||
assert(bytesused <= size);
|
||||
size -= bytesused;
|
||||
dirent = (sortix_dirent*) ( ((uint8_t*) dirent) + bytesused );
|
||||
}
|
||||
}
|
||||
|
||||
int SysChDir(const char* path)
|
||||
{
|
||||
// Calculate the absolute new path.
|
||||
Process* process = CurrentProcess();
|
||||
const char* wd = process->workingdir;
|
||||
char* abs = MakeAbsolute(wd, path);
|
||||
if ( !abs ) { errno = ENOMEM; return -1; }
|
||||
size_t abslen = strlen(abs);
|
||||
if ( 1 < abslen && abs[abslen-1] == '/' )
|
||||
{
|
||||
abs[abslen-1] = '\0';
|
||||
}
|
||||
|
||||
// Lookup the path and see if it is a directory.
|
||||
size_t pathoffset = 0;
|
||||
DevFileSystem* fs = Mount::WhichFileSystem(abs, &pathoffset);
|
||||
if ( !fs ) { delete[] abs; errno = EINVAL; return -1; }
|
||||
Device* dev = fs->Open(abs + pathoffset, O_SEARCH | O_DIRECTORY, 0);
|
||||
if ( !dev ) { errno = ENOTDIR; return -1; }
|
||||
dev->Unref();
|
||||
|
||||
// Alright, the path passed.
|
||||
delete[] process->workingdir; // Works if it was NULL.
|
||||
process->workingdir = abs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* SysGetCWD(char* buf, size_t size)
|
||||
{
|
||||
// Calculate the absolute new path.
|
||||
Process* process = CurrentProcess();
|
||||
const char* wd = process->workingdir;
|
||||
if ( !wd ) { wd = "/"; }
|
||||
size_t wdsize = strlen(wd) + 1;
|
||||
if ( size < wdsize ) { errno = ERANGE; return NULL; }
|
||||
strcpy(buf, wd);
|
||||
return buf;
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
Syscall::Register(SYSCALL_READDIRENTS, (void*) SysReadDirEnts);
|
||||
Syscall::Register(SYSCALL_CHDIR, (void*) SysChDir);
|
||||
Syscall::Register(SYSCALL_GETCWD, (void*) SysGetCWD);
|
||||
}
|
||||
|
||||
// Allocate a byte too much, in case you want to add a trailing slash.
|
||||
char* MakeAbsolute(const char* wd, const char* rel)
|
||||
{
|
||||
// If given no wd, then interpret from the root.
|
||||
if ( !wd ) { wd = "/"; }
|
||||
|
||||
// The resulting size won't ever be larger than this.
|
||||
size_t wdlen = strlen(wd);
|
||||
size_t resultsize = wdlen + strlen(rel) + 2;
|
||||
char* result = new char[resultsize + 1];
|
||||
if ( !result ) { return NULL; }
|
||||
|
||||
// Detect if rel is relative to / or to wd, and then continue the
|
||||
// interpretation from that point.
|
||||
size_t offset;
|
||||
if ( *rel == '/' ) { result[0] = '/'; offset = 1; rel++; }
|
||||
else { strcpy(result, wd); offset = wdlen; }
|
||||
|
||||
// Make sure the working directory ends with a slash.
|
||||
if ( result[offset-1] != '/' ) { result[offset++] = '/'; }
|
||||
|
||||
bool leadingdots = true;
|
||||
size_t dots = 0;
|
||||
int c = 1;
|
||||
while ( c ) // Exit after handling \0
|
||||
{
|
||||
c = *rel++;
|
||||
|
||||
// Don't insert double //'s into the final path.
|
||||
if ( c == '/' && result[offset-1] == '/' ) { continue; }
|
||||
|
||||
// / or \0 means that we should interpret . and ..
|
||||
if ( c == '/' || c == '\0' )
|
||||
{
|
||||
// If ., just remove the dot and ignore the slash.
|
||||
if ( leadingdots && dots == 1 )
|
||||
{
|
||||
result[--offset] = '\0';
|
||||
dots = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If .., remove .. and one element of the path.
|
||||
if ( leadingdots && dots == 2 )
|
||||
{
|
||||
offset -= 2; // Remove ..
|
||||
offset -= 1; // Remove the trailing slash
|
||||
while ( offset )
|
||||
{
|
||||
if ( result[--offset] == '/' ) { break; }
|
||||
}
|
||||
result[offset++] = '/'; // Need to re-insert a slash.
|
||||
result[offset] = '\0';
|
||||
dots = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Reset the dot count after a slash.
|
||||
dots = 0;
|
||||
}
|
||||
|
||||
// The newest path element consisted solely of dots.
|
||||
leadingdots = ( c == '/' || c == '.' );
|
||||
|
||||
// Count the number of leading dots in the path element.
|
||||
if ( c == '.' && leadingdots ) { dots++; }
|
||||
|
||||
// Insert the character into the result.
|
||||
result[offset++] = c;
|
||||
}
|
||||
|
||||
// TODO: To avoid wasting space, should we String::Clone(result)?
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
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/>.
|
||||
|
||||
directory.h
|
||||
A container for files and other directories.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_DIRECTORY_H
|
||||
#define SORTIX_DIRECTORY_H
|
||||
|
||||
#include "device.h"
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
// Keep this up to date with <sys/readdirents.h>
|
||||
struct sortix_dirent
|
||||
{
|
||||
struct sortix_dirent* d_next;
|
||||
unsigned char d_type;
|
||||
size_t d_namelen;
|
||||
char d_name[];
|
||||
};
|
||||
|
||||
class DevDirectory : public Device
|
||||
{
|
||||
public:
|
||||
typedef Device BaseClass;
|
||||
|
||||
public:
|
||||
virtual void Rewind() = 0;
|
||||
|
||||
// Precondition: available is at least sizeof(sortix_dirent).
|
||||
virtual int Read(sortix_dirent* dirent, size_t available) = 0;
|
||||
|
||||
public:
|
||||
virtual bool IsType(unsigned type) const { return type == Device::DIRECTORY; }
|
||||
|
||||
};
|
||||
|
||||
namespace Directory
|
||||
{
|
||||
void Init();
|
||||
char* MakeAbsolute(const char* wd, const char* rel);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
198
sortix/dtable.cpp
Normal file
198
sortix/dtable.cpp
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
|
||||
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/>.
|
||||
|
||||
dtable.cpp
|
||||
Table of file descriptors.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
#include <sortix/kernel/descriptor.h>
|
||||
#include <sortix/kernel/dtable.h>
|
||||
#include <sortix/fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "process.h"
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
DescriptorTable::DescriptorTable()
|
||||
{
|
||||
dtablelock = KTHREAD_MUTEX_INITIALIZER;
|
||||
entries = NULL;
|
||||
numentries = 0;
|
||||
}
|
||||
|
||||
DescriptorTable::~DescriptorTable()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
bool DescriptorTable::IsGoodEntry(int i)
|
||||
{
|
||||
bool ret = 0 <= i && i < numentries && entries[i].desc;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Ref<DescriptorTable> DescriptorTable::Fork()
|
||||
{
|
||||
ScopedLock lock(&dtablelock);
|
||||
Ref<DescriptorTable> ret(new DescriptorTable);
|
||||
if ( !ret ) { return Ref<DescriptorTable>(NULL); }
|
||||
ret->entries = new dtableent_t[numentries];
|
||||
if ( !ret->entries ) { return Ref<DescriptorTable>(NULL); }
|
||||
for ( ret->numentries = 0; ret->numentries < numentries; ret->numentries++ )
|
||||
{
|
||||
int i = ret->numentries;
|
||||
if ( entries[i].desc && !(entries[i].flags & FD_CLOFORK) )
|
||||
ret->entries[i] = entries[i];
|
||||
else
|
||||
/* Already set to NULL in dtableent_t::desc constructor. */{}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Ref<Descriptor> DescriptorTable::Get(int index)
|
||||
{
|
||||
ScopedLock lock(&dtablelock);
|
||||
if ( !IsGoodEntry(index) ) { errno = EBADF; return Ref<Descriptor>(NULL); }
|
||||
return entries[index].desc;
|
||||
}
|
||||
|
||||
bool DescriptorTable::Enlargen(int atleast)
|
||||
{
|
||||
if ( numentries == INT_MAX ) { errno = EOVERFLOW; return -1; }
|
||||
int newnumentries = INT_MAX - numentries < numentries ?
|
||||
INT_MAX :
|
||||
numentries ? 2 * numentries : 8;
|
||||
if ( newnumentries < atleast )
|
||||
newnumentries = atleast;
|
||||
dtableent_t* newentries = new dtableent_t[newnumentries];
|
||||
if ( !newentries )
|
||||
return false;
|
||||
for ( int i = 0; i < numentries; i++ )
|
||||
newentries[i].desc = entries[i].desc,
|
||||
newentries[i].flags = entries[i].flags;
|
||||
for ( int i = numentries; i < newnumentries; i++ )
|
||||
/* newentries[i].desc is set in dtableent_t::desc constructor */
|
||||
newentries[i].flags = 0;
|
||||
delete[] entries; entries = newentries;
|
||||
numentries = newnumentries;
|
||||
return true;
|
||||
}
|
||||
|
||||
int DescriptorTable::Allocate(Ref<Descriptor> desc, int flags)
|
||||
{
|
||||
if ( flags & ~__FD_ALLOWED_FLAGS )
|
||||
return errno = EINVAL, -1;
|
||||
ScopedLock lock(&dtablelock);
|
||||
for ( int i = 0; i < numentries; i++ )
|
||||
if ( !entries[i].desc )
|
||||
{
|
||||
entries[i].desc = desc;
|
||||
entries[i].flags = flags;
|
||||
return i;
|
||||
}
|
||||
int oldnumentries = numentries;
|
||||
if ( !Enlargen(0) )
|
||||
return -1;
|
||||
int i = oldnumentries++;
|
||||
entries[i].desc = desc;
|
||||
entries[i].flags = flags;
|
||||
return i;
|
||||
}
|
||||
|
||||
int DescriptorTable::Copy(int from, int to)
|
||||
{
|
||||
ScopedLock lock(&dtablelock);
|
||||
if ( from < 0 || to < 0 )
|
||||
return errno = EINVAL, -1;
|
||||
if ( !(from < numentries) )
|
||||
return errno = EBADF, -1;
|
||||
if ( !entries[from].desc )
|
||||
return errno = EBADF, -1;
|
||||
while ( !(to < numentries) )
|
||||
if ( !Enlargen(to+1) )
|
||||
return -1;
|
||||
if ( entries[to].desc != entries[from].desc )
|
||||
{
|
||||
if ( entries[to].desc )
|
||||
/* TODO: Should this be synced or otherwise properly closed? */{}
|
||||
entries[to].desc = entries[from].desc;
|
||||
entries[to].flags = entries[from].flags;
|
||||
}
|
||||
return to;
|
||||
}
|
||||
|
||||
Ref<Descriptor> DescriptorTable::FreeKeep(int index)
|
||||
{
|
||||
ScopedLock lock(&dtablelock);
|
||||
if ( !IsGoodEntry(index) ) { errno = EBADF; return Ref<Descriptor>(NULL); }
|
||||
Ref<Descriptor> ret = entries[index].desc;
|
||||
entries[index].desc.Reset();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DescriptorTable::Free(int index)
|
||||
{
|
||||
FreeKeep(index);
|
||||
}
|
||||
|
||||
void DescriptorTable::OnExecute()
|
||||
{
|
||||
ScopedLock lock(&dtablelock);
|
||||
for ( int i = 0; i < numentries; i++ )
|
||||
{
|
||||
if ( !entries[i].desc )
|
||||
continue;
|
||||
if ( !(entries[i].flags & FD_CLOEXEC) )
|
||||
continue;
|
||||
entries[i].desc.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
void DescriptorTable::Reset()
|
||||
{
|
||||
ScopedLock lock(&dtablelock);
|
||||
numentries = 0;
|
||||
delete[] entries;
|
||||
entries = NULL;
|
||||
}
|
||||
|
||||
bool DescriptorTable::SetFlags(int index, int flags)
|
||||
{
|
||||
if ( flags & ~__FD_ALLOWED_FLAGS )
|
||||
return errno = EINVAL, -1;
|
||||
ScopedLock lock(&dtablelock);
|
||||
if ( !IsGoodEntry(index) ) { errno = EBADF; return false; }
|
||||
entries[index].flags = flags;
|
||||
return true;
|
||||
}
|
||||
|
||||
int DescriptorTable::GetFlags(int index)
|
||||
{
|
||||
ScopedLock lock(&dtablelock);
|
||||
if ( !IsGoodEntry(index) ) { errno = EBADF; return -1; }
|
||||
return entries[index].flags;
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
|
@ -1,320 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
|
||||
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 <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/string.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "syscall.h"
|
||||
#include "process.h"
|
||||
#include "filesystem.h"
|
||||
#include "directory.h"
|
||||
#include "mount.h"
|
||||
#include <sortix/stat.h>
|
||||
#include <sortix/fcntl.h>
|
||||
#include <sortix/unistd.h>
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
namespace FileSystem
|
||||
{
|
||||
Device* Open(const char* path, int flags, mode_t mode)
|
||||
{
|
||||
Process* process = CurrentProcess();
|
||||
const char* wd = process->workingdir;
|
||||
char* abs = Directory::MakeAbsolute(wd, path);
|
||||
if ( !abs ) { errno = ENOMEM; return NULL; }
|
||||
|
||||
size_t pathoffset = 0;
|
||||
DevFileSystem* fs = Mount::WhichFileSystem(abs, &pathoffset);
|
||||
if ( !fs ) { delete[] abs; return NULL; }
|
||||
Device* result = fs->Open(abs + pathoffset, flags, mode);
|
||||
delete[] abs;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Unlink(const char* path)
|
||||
{
|
||||
Process* process = CurrentProcess();
|
||||
const char* wd = process->workingdir;
|
||||
char* abs = Directory::MakeAbsolute(wd, path);
|
||||
if ( !abs ) { errno = ENOMEM; return false; }
|
||||
|
||||
size_t pathoffset = 0;
|
||||
DevFileSystem* fs = Mount::WhichFileSystem(abs, &pathoffset);
|
||||
if ( !fs ) { delete[] abs; return false; }
|
||||
bool result = fs->Unlink(abs + pathoffset);
|
||||
delete[] abs;
|
||||
return result;
|
||||
}
|
||||
|
||||
int SysOpen(const char* path, int flags, mode_t mode)
|
||||
{
|
||||
char* pathcopy = String::Clone(path);
|
||||
if ( !pathcopy )
|
||||
return -1;
|
||||
Process* process = CurrentProcess();
|
||||
Device* dev = Open(path, flags, mode);
|
||||
if ( !dev ) { delete[] pathcopy; return -1; }
|
||||
int fd = process->descriptors.Allocate(dev, pathcopy);
|
||||
if ( fd < 0 ) { dev->Unref(); }
|
||||
int fdflags = 0;
|
||||
if ( flags & O_CLOEXEC ) { fdflags |= FD_CLOEXEC; }
|
||||
if ( flags & O_CLOFORK ) { fdflags |= FD_CLOFORK; }
|
||||
process->descriptors.SetFlags(fd, fdflags);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int SysOpenAt(int dirfd, const char* pathname, int flags, mode_t mode)
|
||||
{
|
||||
if ( pathname[0] == '/' )
|
||||
return SysOpen(pathname, flags, mode);
|
||||
Process* process = CurrentProcess();
|
||||
Device* dir = process->descriptors.Get(dirfd);
|
||||
if ( !dir ) { errno = EBADF; return -1; }
|
||||
const char* path = process->descriptors.GetPath(dirfd);
|
||||
char* fullpath = String::Combine(3, path, "/", pathname);
|
||||
if ( !fullpath )
|
||||
return -1;
|
||||
int ret = SysOpen(fullpath, flags, mode);
|
||||
delete[] fullpath;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SysAccess(const char* pathname, int mode)
|
||||
{
|
||||
int oflags = 0;
|
||||
bool exec = mode & X_OK;
|
||||
bool read = mode & R_OK;
|
||||
bool write = mode & W_OK;
|
||||
if ( mode == F_OK ) { oflags = O_RDONLY; }
|
||||
if ( exec && !read && !write ) { oflags = O_EXEC; }
|
||||
if ( exec && read && !write ) { oflags = O_EXEC; }
|
||||
if ( exec && !read && write ) { oflags = O_EXEC; }
|
||||
if ( exec && read && write ) { oflags = O_EXEC; }
|
||||
if ( !exec && read && write ) { oflags = O_RDWR; }
|
||||
if ( !exec && !read && write ) { oflags = O_WRONLY; }
|
||||
if ( !exec && read && !write ) { oflags = O_RDONLY; }
|
||||
Device* dev = Open(pathname, oflags, 0);
|
||||
if ( !dev ) { return -1; }
|
||||
dev->Unref();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SysUnlink(const char* path)
|
||||
{
|
||||
return Unlink(path) ? 0 : -1;
|
||||
}
|
||||
|
||||
int SysMkDir(const char* pathname, mode_t mode)
|
||||
{
|
||||
// TODO: Add the proper filesystem support!
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int SysRmDir(const char* pathname)
|
||||
{
|
||||
// TODO: Add the proper filesystem support!
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int SysTruncate(const char* pathname, off_t length)
|
||||
{
|
||||
// TODO: Add the proper filesystem support!
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int SysFTruncate(const char* pathname, off_t length)
|
||||
{
|
||||
// TODO: Add the proper filesystem support!
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void HackStat(Device* dev, struct stat* st)
|
||||
{
|
||||
memset(st, 0, sizeof(*st));
|
||||
st->st_mode = 0777;
|
||||
st->st_nlink = 1;
|
||||
if ( dev->IsType(Device::BUFFER) )
|
||||
{
|
||||
st->st_mode |= S_IFREG;
|
||||
DevBuffer* buffer = (DevBuffer*) dev;
|
||||
st->st_size = buffer->Size();
|
||||
st->st_blksize = 1;
|
||||
st->st_blocks = st->st_size;
|
||||
}
|
||||
if ( dev->IsType(Device::DIRECTORY) )
|
||||
{
|
||||
st->st_mode |= S_IFDIR;
|
||||
st->st_nlink = 2;
|
||||
}
|
||||
}
|
||||
|
||||
int SysStat(const char* pathname, struct stat* st)
|
||||
{
|
||||
Device* dev = Open(pathname, O_RDONLY, 0);
|
||||
if ( !dev && errno == EISDIR )
|
||||
{
|
||||
dev = Open(pathname, O_SEARCH, 0);
|
||||
}
|
||||
if ( !dev ) { return -1; }
|
||||
HackStat(dev, st);
|
||||
dev->Unref();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SysFStat(int fd, struct stat* st)
|
||||
{
|
||||
Process* process = CurrentProcess();
|
||||
DescriptorTable* descs = &(process->descriptors);
|
||||
Device* dev = descs->Get(fd);
|
||||
if ( !dev ) { errno = EBADF; return -1; }
|
||||
HackStat(dev, st);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SysFCntl(int fd, int cmd, unsigned long arg)
|
||||
{
|
||||
Process* process = CurrentProcess();
|
||||
DescriptorTable* descs = &(process->descriptors);
|
||||
Device* dev = descs->Get(fd);
|
||||
if ( !dev ) { errno = EBADF; return -1; }
|
||||
switch ( cmd )
|
||||
{
|
||||
case F_SETFD: descs->SetFlags(fd, (int) arg); return 0;
|
||||
case F_GETFD: return descs->GetFlags(fd);
|
||||
case F_SETFL: errno = ENOSYS; return -1;
|
||||
case F_GETFL:
|
||||
if ( dev->IsType(Device::DIRECTORY) ) { return O_SEARCH; }
|
||||
if ( !dev->IsType(Device::STREAM) )
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
DevStream* stream = (DevStream*) stream;
|
||||
bool write = stream->IsWritable();
|
||||
bool read = stream->IsReadable();
|
||||
if ( write && read ) { return O_RDWR; }
|
||||
if ( write && !read ) { return O_WRONLY; }
|
||||
if ( !write && read ) { return O_RDONLY; }
|
||||
return O_EXEC;
|
||||
break;
|
||||
}
|
||||
errno = EINVAL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
Syscall::Register(SYSCALL_OPEN, (void*) SysOpen);
|
||||
Syscall::Register(SYSCALL_OPENAT, (void*) SysOpenAt);
|
||||
Syscall::Register(SYSCALL_UNLINK, (void*) SysUnlink);
|
||||
Syscall::Register(SYSCALL_MKDIR, (void*) SysMkDir);
|
||||
Syscall::Register(SYSCALL_RMDIR, (void*) SysRmDir);
|
||||
Syscall::Register(SYSCALL_TRUNCATE, (void*) SysTruncate);
|
||||
Syscall::Register(SYSCALL_FTRUNCATE, (void*) SysFTruncate);
|
||||
Syscall::Register(SYSCALL_STAT, (void*) SysStat);
|
||||
Syscall::Register(SYSCALL_FSTAT, (void*) SysFStat);
|
||||
Syscall::Register(SYSCALL_FCNTL, (void*) SysFCntl);
|
||||
Syscall::Register(SYSCALL_ACCESS, (void*) SysAccess);
|
||||
}
|
||||
}
|
||||
|
||||
DevFileWrapper::DevFileWrapper(DevBuffer* buffer, int flags)
|
||||
{
|
||||
this->buffer = buffer;
|
||||
this->flags = flags;
|
||||
this->offset = 0;
|
||||
this->buffer->Refer();
|
||||
if ( flags & O_TRUNC ) { buffer->Resize(0); }
|
||||
}
|
||||
|
||||
DevFileWrapper::~DevFileWrapper()
|
||||
{
|
||||
buffer->Unref();
|
||||
}
|
||||
|
||||
size_t DevFileWrapper::BlockSize()
|
||||
{
|
||||
return buffer->BlockSize();
|
||||
}
|
||||
|
||||
uintmax_t DevFileWrapper::Size()
|
||||
{
|
||||
return buffer->Size();
|
||||
}
|
||||
|
||||
uintmax_t DevFileWrapper::Position()
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
|
||||
bool DevFileWrapper::Seek(uintmax_t position)
|
||||
{
|
||||
if ( !buffer->Seek(position) ) { return false; }
|
||||
offset = position;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DevFileWrapper::Resize(uintmax_t size)
|
||||
{
|
||||
return buffer->Resize(size);
|
||||
}
|
||||
|
||||
ssize_t DevFileWrapper::Read(uint8_t* dest, size_t count)
|
||||
{
|
||||
// TODO: Enforce read permission!
|
||||
if ( !buffer->Seek(offset) ) { return -1; }
|
||||
ssize_t result = buffer->Read(dest, count);
|
||||
if ( result < 0 ) { return result; }
|
||||
offset += result;
|
||||
return result;
|
||||
}
|
||||
|
||||
ssize_t DevFileWrapper::Write(const uint8_t* src, size_t count)
|
||||
{
|
||||
// TODO: Enforce write permission!
|
||||
if ( !buffer->Seek(offset) ) { return -1; }
|
||||
ssize_t result = buffer->Write(src, count);
|
||||
if ( result < 0 ) { return result; }
|
||||
offset += result;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DevFileWrapper::IsReadable()
|
||||
{
|
||||
// TODO: Enforce read permission!
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DevFileWrapper::IsWritable()
|
||||
{
|
||||
// TODO: Enforce write permission!
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
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.h
|
||||
Allows access to stored sequences of bytes in an orderly fashion.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_FILESYSTEM_H
|
||||
#define SORTIX_FILESYSTEM_H
|
||||
|
||||
#include "device.h"
|
||||
#include "stream.h"
|
||||
#include "fcntl.h"
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
class DevFileSystem : public Device
|
||||
{
|
||||
public:
|
||||
virtual Device* Open(const char* path, int flags, mode_t mode) = 0;
|
||||
virtual bool Unlink(const char* path) = 0;
|
||||
|
||||
public:
|
||||
virtual bool IsType(unsigned type) const { return type == Device::FILESYSTEM; }
|
||||
|
||||
};
|
||||
|
||||
class DevFileWrapper : public DevBuffer
|
||||
{
|
||||
public:
|
||||
DevFileWrapper(DevBuffer* buffer, int flags);
|
||||
virtual ~DevFileWrapper();
|
||||
|
||||
private:
|
||||
DevBuffer* buffer;
|
||||
int flags;
|
||||
uintmax_t offset;
|
||||
|
||||
public:
|
||||
virtual ssize_t Read(uint8_t* dest, size_t count);
|
||||
virtual ssize_t Write(const uint8_t* src, size_t count);
|
||||
virtual bool IsReadable();
|
||||
virtual bool IsWritable();
|
||||
virtual size_t BlockSize();
|
||||
virtual uintmax_t Size();
|
||||
virtual uintmax_t Position();
|
||||
virtual bool Seek(uintmax_t position);
|
||||
virtual bool Resize(uintmax_t size);
|
||||
};
|
||||
|
||||
namespace FileSystem
|
||||
{
|
||||
void Init();
|
||||
Device* Open(const char* path, int flags, mode_t mode);
|
||||
bool Unlink(const char* path);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,403 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
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/>.
|
||||
|
||||
fs/devfs.cpp
|
||||
Provides access to various block, character, and other kinds of devices.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "../filesystem.h"
|
||||
#include "../directory.h"
|
||||
#include "../stream.h"
|
||||
#include "../terminal.h"
|
||||
#include "../vga.h"
|
||||
#include "../ata.h"
|
||||
#include "devfs.h"
|
||||
#include "videofs.h"
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
class DevATA : public DevBuffer
|
||||
{
|
||||
public:
|
||||
typedef DevBuffer BaseClass;
|
||||
|
||||
public:
|
||||
DevATA(ATADrive* drive);
|
||||
virtual ~DevATA();
|
||||
|
||||
private:
|
||||
ATADrive* drive;
|
||||
off_t offset;
|
||||
|
||||
public:
|
||||
virtual ssize_t Read(uint8_t* dest, size_t count);
|
||||
virtual ssize_t Write(const uint8_t* src, size_t count);
|
||||
virtual bool IsReadable();
|
||||
virtual bool IsWritable();
|
||||
virtual size_t BlockSize();
|
||||
virtual uintmax_t Size();
|
||||
virtual uintmax_t Position();
|
||||
virtual bool Seek(uintmax_t position);
|
||||
virtual bool Resize(uintmax_t size);
|
||||
|
||||
};
|
||||
|
||||
DevATA::DevATA(ATADrive* drive)
|
||||
{
|
||||
this->drive = drive;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
DevATA::~DevATA()
|
||||
{
|
||||
}
|
||||
|
||||
ssize_t DevATA::Read(uint8_t* dest, size_t count)
|
||||
{
|
||||
if ( SIZE_MAX < count ) { count = SIZE_MAX; }
|
||||
if ( drive->GetSize() - offset < count ) { count = drive->GetSize() - offset; }
|
||||
size_t amount = drive->Read(offset, dest, count);
|
||||
if ( count && !amount ) { return -1; }
|
||||
offset += amount;
|
||||
return amount;
|
||||
}
|
||||
|
||||
ssize_t DevATA::Write(const uint8_t* src, size_t count)
|
||||
{
|
||||
if ( SIZE_MAX < count ) { count = SIZE_MAX; }
|
||||
if ( drive->GetSize() <= offset && count ) { errno = ENOSPC; return -1; }
|
||||
if ( drive->GetSize() - offset < count ) { count = drive->GetSize() - offset; }
|
||||
size_t amount = drive->Write(offset, src, count);
|
||||
if ( count && !amount ) { return -1; }
|
||||
offset += amount;
|
||||
return amount;
|
||||
}
|
||||
|
||||
bool DevATA::IsReadable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DevATA::IsWritable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t DevATA::BlockSize()
|
||||
{
|
||||
return drive->GetSectorSize();
|
||||
}
|
||||
|
||||
uintmax_t DevATA::Size()
|
||||
{
|
||||
return drive->GetSize();
|
||||
}
|
||||
|
||||
uintmax_t DevATA::Position()
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
|
||||
bool DevATA::Seek(uintmax_t position)
|
||||
{
|
||||
if ( drive->GetSize() <= position ) { errno = ENOSPC; return false; }
|
||||
offset = position;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DevATA::Resize(uintmax_t /*size*/)
|
||||
{
|
||||
errno = EPERM;
|
||||
return false;
|
||||
}
|
||||
|
||||
class DevNull : public DevStream
|
||||
{
|
||||
public:
|
||||
typedef DevStream BaseClass;
|
||||
|
||||
public:
|
||||
DevNull();
|
||||
virtual ~DevNull();
|
||||
|
||||
public:
|
||||
virtual ssize_t Read(uint8_t* dest, size_t count);
|
||||
virtual ssize_t Write(const uint8_t* src, size_t count);
|
||||
virtual bool IsReadable();
|
||||
virtual bool IsWritable();
|
||||
|
||||
};
|
||||
|
||||
DevNull::DevNull()
|
||||
{
|
||||
}
|
||||
|
||||
DevNull::~DevNull()
|
||||
{
|
||||
}
|
||||
|
||||
ssize_t DevNull::Read(uint8_t* /*dest*/, size_t /*count*/)
|
||||
{
|
||||
return 0; // Return EOF
|
||||
}
|
||||
|
||||
ssize_t DevNull::Write(const uint8_t* /*src*/, size_t count)
|
||||
{
|
||||
if ( SSIZE_MAX < count ) { count = SSIZE_MAX; }
|
||||
|
||||
// O' glorious bitbucket in the sky, I hereby sacrifice to You, my holy
|
||||
// data in trust You will keep it safe. That You will store it for all
|
||||
// eternity, until the day You will return to User-Land to rule the land
|
||||
// and preserve data-integrity for all eternity. Amen.
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
bool DevNull::IsReadable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DevNull::IsWritable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: Move this namespace into something like devicefs.cpp.
|
||||
namespace DeviceFS {
|
||||
|
||||
size_t entriesused;
|
||||
size_t entrieslength;
|
||||
DevEntry* deventries;
|
||||
DevVideoFS* videofs;
|
||||
|
||||
void Init()
|
||||
{
|
||||
deventries = NULL;
|
||||
entriesused = 0;
|
||||
entrieslength = 0;
|
||||
videofs = new DevVideoFS;
|
||||
if ( !videofs ) { Panic("Unable to allocate videofs\n"); }
|
||||
}
|
||||
|
||||
bool RegisterDevice(const char* name, Device* dev)
|
||||
{
|
||||
if ( entriesused == entrieslength )
|
||||
{
|
||||
size_t newentrieslength = entrieslength ? 2 * entrieslength : 32;
|
||||
DevEntry* newdeventries = new DevEntry[newentrieslength];
|
||||
if ( !newdeventries ) { return false; }
|
||||
size_t bytes = sizeof(DevEntry) * entriesused;
|
||||
memcpy(newdeventries, deventries, bytes);
|
||||
delete[] deventries;
|
||||
entrieslength = newentrieslength;
|
||||
deventries = newdeventries;
|
||||
}
|
||||
|
||||
char* nameclone = String::Clone(name);
|
||||
if ( !nameclone ) { return false; }
|
||||
|
||||
size_t index = entriesused++;
|
||||
dev->Refer();
|
||||
deventries[index].name = nameclone;
|
||||
deventries[index].dev = dev;
|
||||
return true;
|
||||
}
|
||||
|
||||
Device* LookUp(const char* name)
|
||||
{
|
||||
for ( size_t i = 0; i < entriesused; i++ )
|
||||
{
|
||||
if ( strcmp(name, deventries[i].name) ) { continue; }
|
||||
deventries[i].dev->Refer();
|
||||
return deventries[i].dev;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t GetNumDevices()
|
||||
{
|
||||
return entriesused;
|
||||
}
|
||||
|
||||
DevEntry* GetDevice(size_t index)
|
||||
{
|
||||
if ( entriesused <= index ) { return NULL; }
|
||||
return deventries + index;
|
||||
}
|
||||
|
||||
// TODO: Hack to register ATA devices.
|
||||
// FIXME: Move class DevATA into ata.cpp.
|
||||
void RegisterATADrive(unsigned ataid, ATADrive* drive)
|
||||
{
|
||||
DevATA* ata = new DevATA(drive);
|
||||
if ( !ata ) { Panic("Cannot allocate ATA device"); }
|
||||
ata->Refer();
|
||||
assert(ataid < 10);
|
||||
char name[5] = "ataN";
|
||||
name[3] = '0' + ataid;
|
||||
if ( !RegisterDevice(name, ata) )
|
||||
{
|
||||
PanicF("Cannot register /dev/%s", name);
|
||||
}
|
||||
ata->Unref();
|
||||
}
|
||||
|
||||
} // namespace DeviceFS
|
||||
|
||||
class DevDevFSDir : public DevDirectory
|
||||
{
|
||||
public:
|
||||
typedef Device DevDirectory;
|
||||
|
||||
public:
|
||||
DevDevFSDir();
|
||||
virtual ~DevDevFSDir();
|
||||
|
||||
public:
|
||||
size_t position;
|
||||
|
||||
public:
|
||||
virtual void Rewind();
|
||||
virtual int Read(sortix_dirent* dirent, size_t available);
|
||||
|
||||
};
|
||||
|
||||
DevDevFSDir::DevDevFSDir()
|
||||
{
|
||||
position = 0;
|
||||
}
|
||||
|
||||
DevDevFSDir::~DevDevFSDir()
|
||||
{
|
||||
}
|
||||
|
||||
void DevDevFSDir::Rewind()
|
||||
{
|
||||
position = 0;
|
||||
}
|
||||
|
||||
int DevDevFSDir::Read(sortix_dirent* dirent, size_t available)
|
||||
{
|
||||
const char* names[] = { ".", "..", "null", "tty", "video", "vga" };
|
||||
const char* name = NULL;
|
||||
if ( position < DeviceFS::GetNumDevices() )
|
||||
{
|
||||
name = DeviceFS::GetDevice(position)->name;
|
||||
}
|
||||
else
|
||||
{
|
||||
const size_t nameslength = 4;
|
||||
size_t index = position - DeviceFS::GetNumDevices();
|
||||
if ( nameslength <= index )
|
||||
{
|
||||
dirent->d_namelen = 0;
|
||||
dirent->d_name[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
name = names[index];
|
||||
}
|
||||
|
||||
if ( available <= sizeof(sortix_dirent) ) { return -1; }
|
||||
|
||||
size_t namelen = strlen(name);
|
||||
size_t needed = sizeof(sortix_dirent) + namelen + 1;
|
||||
|
||||
if ( available < needed )
|
||||
{
|
||||
dirent->d_namelen = needed;
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(dirent->d_name, name, namelen + 1);
|
||||
dirent->d_namelen = namelen;
|
||||
position++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DevDevFS::DevDevFS()
|
||||
{
|
||||
}
|
||||
|
||||
DevDevFS::~DevDevFS()
|
||||
{
|
||||
}
|
||||
|
||||
extern DevTerminal* tty;
|
||||
|
||||
Device* DevDevFS::Open(const char* path, int flags, mode_t mode)
|
||||
{
|
||||
int lowerflags = flags & O_LOWERFLAGS;
|
||||
|
||||
if ( !path[0] || (path[0] == '/' && !path[1]) )
|
||||
{
|
||||
if ( lowerflags != O_SEARCH ) { errno = EISDIR; return NULL; }
|
||||
return new DevDevFSDir();
|
||||
}
|
||||
|
||||
if ( strcmp(path, "/null") == 0 ) { return new DevNull; }
|
||||
if ( strcmp(path, "/tty") == 0 ) { tty->Refer(); return tty; }
|
||||
if ( strcmp(path, "/vga") == 0 ) { return new DevVGA; }
|
||||
if ( strcmp(path, "/video") == 0 ||
|
||||
String::StartsWith(path, "/video/") )
|
||||
{
|
||||
return DeviceFS::videofs->Open(path + strlen("/video"), flags, mode);
|
||||
}
|
||||
|
||||
Device* dev = DeviceFS::LookUp(path + 1);
|
||||
if ( !dev )
|
||||
{
|
||||
errno = flags & O_CREAT ? EPERM : ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
if ( dev->IsType(Device::BUFFER) )
|
||||
{
|
||||
DevBuffer* buffer = (DevBuffer*) dev;
|
||||
DevFileWrapper* wrapper = new DevFileWrapper(buffer, flags);
|
||||
buffer->Unref();
|
||||
return wrapper;
|
||||
}
|
||||
return dev;
|
||||
}
|
||||
|
||||
bool DevDevFS::Unlink(const char* path)
|
||||
{
|
||||
if ( strcmp(path, "/video") == 0 ||
|
||||
String::StartsWith(path, "/video/") )
|
||||
{
|
||||
return DeviceFS::videofs->Unlink(path);
|
||||
}
|
||||
|
||||
if ( *path == '\0' || ( *path++ == '/' && *path == '\0' ) )
|
||||
{
|
||||
errno = EISDIR;
|
||||
return false;
|
||||
}
|
||||
|
||||
errno = EPERM;
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
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/>.
|
||||
|
||||
fs/devfs.h
|
||||
Provides access to various block, character, and other kinds of devices.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_FS_DEVFS_H
|
||||
#define SORTIX_FS_DEVFS_H
|
||||
|
||||
#include <sortix/kernel/sortedlist.h>
|
||||
#include "../filesystem.h"
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
class ATADrive;
|
||||
|
||||
class DevDevFS : public DevFileSystem
|
||||
{
|
||||
public:
|
||||
DevDevFS();
|
||||
virtual ~DevDevFS();
|
||||
|
||||
public:
|
||||
virtual Device* Open(const char* path, int flags, mode_t mode);
|
||||
virtual bool Unlink(const char* path);
|
||||
|
||||
};
|
||||
|
||||
namespace DeviceFS {
|
||||
|
||||
struct DevEntry
|
||||
{
|
||||
char* name;
|
||||
Device* dev;
|
||||
};
|
||||
|
||||
void Init();
|
||||
void RegisterATADrive(unsigned ataid, ATADrive* drive);
|
||||
bool RegisterDevice(const char* name, Device* dev);
|
||||
Device* LookUp(const char* name);
|
||||
size_t GetNumDevices();
|
||||
DevEntry* GetDevice(size_t index);
|
||||
|
||||
} // namespace DeviceFS
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,249 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
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/>.
|
||||
|
||||
fs/initfs.cpp
|
||||
Provides access to the initial ramdisk.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/string.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "../filesystem.h"
|
||||
#include "../directory.h"
|
||||
#include "../stream.h"
|
||||
#include "initfs.h"
|
||||
#include "../initrd.h"
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
class DevInitFSFile : public DevBuffer
|
||||
{
|
||||
public:
|
||||
typedef DevBuffer BaseClass;
|
||||
|
||||
public:
|
||||
// Transfers ownership of name.
|
||||
DevInitFSFile(char* name, const uint8_t* buffer, size_t buffersize);
|
||||
virtual ~DevInitFSFile();
|
||||
|
||||
public:
|
||||
char* name;
|
||||
|
||||
private:
|
||||
size_t offset;
|
||||
const uint8_t* buffer;
|
||||
size_t buffersize;
|
||||
kthread_mutex_t filelock;
|
||||
|
||||
public:
|
||||
virtual size_t BlockSize();
|
||||
virtual uintmax_t Size();
|
||||
virtual uintmax_t Position();
|
||||
virtual bool Seek(uintmax_t position);
|
||||
virtual bool Resize(uintmax_t size);
|
||||
virtual ssize_t Read(uint8_t* dest, size_t count);
|
||||
virtual ssize_t Write(const uint8_t* src, size_t count);
|
||||
virtual bool IsReadable();
|
||||
virtual bool IsWritable();
|
||||
|
||||
};
|
||||
|
||||
DevInitFSFile::DevInitFSFile(char* name, const uint8_t* buffer, size_t buffersize)
|
||||
{
|
||||
this->name = name;
|
||||
this->buffer = buffer;
|
||||
this->buffersize = buffersize;
|
||||
this->offset = 0;
|
||||
this->filelock = KTHREAD_MUTEX_INITIALIZER;
|
||||
}
|
||||
|
||||
DevInitFSFile::~DevInitFSFile()
|
||||
{
|
||||
delete[] name;
|
||||
}
|
||||
|
||||
size_t DevInitFSFile::BlockSize()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
uintmax_t DevInitFSFile::Size()
|
||||
{
|
||||
return buffersize;
|
||||
}
|
||||
|
||||
uintmax_t DevInitFSFile::Position()
|
||||
{
|
||||
ScopedLock lock(&filelock);
|
||||
return offset;
|
||||
}
|
||||
|
||||
bool DevInitFSFile::Seek(uintmax_t position)
|
||||
{
|
||||
ScopedLock lock(&filelock);
|
||||
if ( SIZE_MAX < position ) { errno = EOVERFLOW; return false; }
|
||||
offset = position;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DevInitFSFile::Resize(uintmax_t /*size*/)
|
||||
{
|
||||
errno = EBADF;
|
||||
return false;
|
||||
}
|
||||
|
||||
ssize_t DevInitFSFile::Read(uint8_t* dest, size_t count)
|
||||
{
|
||||
ScopedLock lock(&filelock);
|
||||
if ( SSIZE_MAX < count ) { count = SSIZE_MAX; }
|
||||
size_t available = count;
|
||||
if ( buffersize < offset + count ) { available = buffersize - offset; }
|
||||
if ( available == 0 ) { return 0; }
|
||||
memcpy(dest, buffer + offset, available);
|
||||
offset += available;
|
||||
return available;
|
||||
}
|
||||
|
||||
ssize_t DevInitFSFile::Write(const uint8_t* /*src*/, size_t /*count*/)
|
||||
{
|
||||
errno = EBADF;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DevInitFSFile::IsReadable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DevInitFSFile::IsWritable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
class DevInitFSDir : public DevDirectory
|
||||
{
|
||||
public:
|
||||
typedef Device DevDirectory;
|
||||
|
||||
public:
|
||||
DevInitFSDir(uint32_t dir);
|
||||
virtual ~DevInitFSDir();
|
||||
|
||||
private:
|
||||
size_t position;
|
||||
uint32_t dir;
|
||||
uint32_t numfiles;
|
||||
|
||||
public:
|
||||
virtual void Rewind();
|
||||
virtual int Read(sortix_dirent* dirent, size_t available);
|
||||
|
||||
};
|
||||
|
||||
DevInitFSDir::DevInitFSDir(uint32_t dir)
|
||||
{
|
||||
this->position = 0;
|
||||
this->dir = dir;
|
||||
this->numfiles = InitRD::GetNumFiles(dir);
|
||||
}
|
||||
|
||||
DevInitFSDir::~DevInitFSDir()
|
||||
{
|
||||
}
|
||||
|
||||
void DevInitFSDir::Rewind()
|
||||
{
|
||||
position = 0;
|
||||
}
|
||||
|
||||
int DevInitFSDir::Read(sortix_dirent* dirent, size_t available)
|
||||
{
|
||||
if ( available <= sizeof(sortix_dirent) ) { return -1; }
|
||||
if ( numfiles <= position )
|
||||
{
|
||||
dirent->d_namelen = 0;
|
||||
dirent->d_name[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* name = InitRD::GetFilename(dir, position);
|
||||
size_t namelen = strlen(name);
|
||||
size_t needed = sizeof(sortix_dirent) + namelen + 1;
|
||||
|
||||
if ( available < needed )
|
||||
{
|
||||
dirent->d_namelen = needed;
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(dirent->d_name, name, namelen + 1);
|
||||
dirent->d_namelen = namelen;
|
||||
position++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DevInitFS::DevInitFS()
|
||||
{
|
||||
}
|
||||
|
||||
DevInitFS::~DevInitFS()
|
||||
{
|
||||
}
|
||||
|
||||
Device* DevInitFS::Open(const char* path, int flags, mode_t mode)
|
||||
{
|
||||
size_t buffersize;
|
||||
int lowerflags = flags & O_LOWERFLAGS;
|
||||
|
||||
if ( !path[0] || (path[0] == '/' && !path[1]) )
|
||||
{
|
||||
if ( lowerflags != O_SEARCH ) { errno = EISDIR; return NULL; }
|
||||
return new DevInitFSDir(InitRD::Root());
|
||||
}
|
||||
|
||||
if ( *path++ != '/' ) { errno = ENOENT; return NULL; }
|
||||
|
||||
uint32_t ino = InitRD::Traverse(InitRD::Root(), path);
|
||||
if ( !ino ) { return NULL; }
|
||||
|
||||
const uint8_t* buffer = InitRD::Open(ino, &buffersize);
|
||||
if ( !buffer ) { return NULL; }
|
||||
|
||||
if ( lowerflags == O_SEARCH ) { errno = ENOTDIR; return NULL; }
|
||||
if ( lowerflags != O_RDONLY ) { errno = EROFS; return NULL; }
|
||||
|
||||
char* newpath = String::Clone(path);
|
||||
if ( !newpath ) { errno = ENOSPC; return NULL; }
|
||||
|
||||
Device* result = new DevInitFSFile(newpath, buffer, buffersize);
|
||||
if ( !result ) { delete[] newpath; errno = ENOSPC; return NULL; }
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DevInitFS::Unlink(const char* path)
|
||||
{
|
||||
errno = EROFS;
|
||||
return false;
|
||||
}
|
||||
}
|
397
sortix/fs/kram.cpp
Normal file
397
sortix/fs/kram.cpp
Normal file
|
@ -0,0 +1,397 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
|
||||
|
||||
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/>.
|
||||
|
||||
fs/kram.cpp
|
||||
Kernel RAM filesystem.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/interlock.h>
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
#include <sortix/kernel/fsfunc.h>
|
||||
#include <sortix/kernel/ioctx.h>
|
||||
#include <sortix/kernel/inode.h>
|
||||
#include <sortix/kernel/string.h>
|
||||
#include <sortix/dirent.h>
|
||||
#include <sortix/fcntl.h>
|
||||
#include <sortix/stat.h>
|
||||
#include <sortix/seek.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "kram.h"
|
||||
|
||||
namespace Sortix {
|
||||
namespace KRAMFS {
|
||||
|
||||
File::File(dev_t dev, ino_t ino, uid_t owner, gid_t group, mode_t mode)
|
||||
{
|
||||
inode_type = INODE_TYPE_FILE;
|
||||
if ( !dev )
|
||||
dev = (dev_t) this;
|
||||
if ( !ino )
|
||||
ino = (ino_t) this;
|
||||
filelock = KTHREAD_MUTEX_INITIALIZER;
|
||||
this->type = S_IFREG;
|
||||
this->stat_uid = owner;
|
||||
this->stat_gid = group;
|
||||
this->stat_mode = (mode & S_SETABLE) | this->type;
|
||||
this->stat_size = 0;
|
||||
this->stat_blksize = 1;
|
||||
this->dev = dev;
|
||||
this->ino = ino;
|
||||
size = 0;
|
||||
bufsize = 0;
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
File::~File()
|
||||
{
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
int File::truncate(ioctx_t* ctx, off_t length)
|
||||
{
|
||||
ScopedLock lock(&filelock);
|
||||
return truncate_unlocked(ctx, length);
|
||||
}
|
||||
|
||||
int File::truncate_unlocked(ioctx_t* /*ctx*/, off_t length)
|
||||
{
|
||||
if ( SIZE_MAX < (uintmax_t) length ) { errno = EFBIG; return -1; }
|
||||
if ( (uintmax_t) length < size )
|
||||
memset(buf + length, 0, size - length);
|
||||
if ( bufsize < (size_t) length )
|
||||
{
|
||||
// TODO: Don't go above OFF_MAX (or what it is called)!
|
||||
size_t newbufsize = bufsize ? 2UL * bufsize : 128UL;
|
||||
if ( newbufsize < (size_t) length )
|
||||
newbufsize = (size_t) length;
|
||||
uint8_t* newbuf = new uint8_t[newbufsize];
|
||||
if ( !newbuf )
|
||||
return -1;
|
||||
memcpy(newbuf, buf, size);
|
||||
delete[] buf; buf = newbuf; bufsize = newbufsize;
|
||||
}
|
||||
kthread_mutex_lock(&metalock);
|
||||
size = stat_size = length;
|
||||
kthread_mutex_unlock(&metalock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
off_t File::lseek(ioctx_t* /*ctx*/, off_t offset, int whence)
|
||||
{
|
||||
ScopedLock lock(&filelock);
|
||||
if ( whence == SEEK_SET )
|
||||
return offset;
|
||||
if ( whence == SEEK_END )
|
||||
return (off_t) size + offset;
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t File::pread(ioctx_t* ctx, uint8_t* dest, size_t count, off_t off)
|
||||
{
|
||||
ScopedLock lock(&filelock);
|
||||
if ( size < (uintmax_t) off )
|
||||
return 0;
|
||||
size_t available = size - off;
|
||||
if ( available < count )
|
||||
count = available;
|
||||
if ( !ctx->copy_to_dest(dest, buf + off, count) )
|
||||
return -1;
|
||||
return count;
|
||||
}
|
||||
|
||||
ssize_t File::pwrite(ioctx_t* ctx, const uint8_t* src, size_t count, off_t off)
|
||||
{
|
||||
ScopedLock lock(&filelock);
|
||||
// TODO: Avoid having off + count overflow!
|
||||
if ( size < off + count )
|
||||
truncate_unlocked(ctx, off+count);
|
||||
if ( size <= (uintmax_t) off )
|
||||
return -1;
|
||||
size_t available = size - off;
|
||||
if ( available < count )
|
||||
count = available;
|
||||
ctx->copy_from_src(buf + off, src, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
Dir::Dir(dev_t dev, ino_t ino, uid_t owner, gid_t group, mode_t mode)
|
||||
{
|
||||
inode_type = INODE_TYPE_DIR;
|
||||
if ( !dev )
|
||||
dev = (dev_t) this;
|
||||
if ( !ino )
|
||||
ino = (ino_t) this;
|
||||
dirlock = KTHREAD_MUTEX_INITIALIZER;
|
||||
this->stat_gid = owner;
|
||||
this->stat_gid = group;
|
||||
this->type = S_IFDIR;
|
||||
this->stat_mode = (mode & S_SETABLE) | this->type;
|
||||
this->dev = dev;
|
||||
this->ino = ino;
|
||||
numchildren = 0;
|
||||
childrenlen = 0;
|
||||
children = NULL;
|
||||
shutdown = false;
|
||||
}
|
||||
|
||||
Dir::~Dir()
|
||||
{
|
||||
// We must not be deleted or garbage collected if we are still used by
|
||||
// someone. In that case the deleter should either delete our children or
|
||||
// simply forget about us.
|
||||
assert(!numchildren);
|
||||
delete[] children;
|
||||
}
|
||||
|
||||
ssize_t Dir::readdirents(ioctx_t* ctx, struct kernel_dirent* dirent,
|
||||
size_t size, off_t start, size_t /*maxcount*/)
|
||||
{
|
||||
ScopedLock lock(&dirlock);
|
||||
if ( numchildren <= (uintmax_t) start )
|
||||
return 0;
|
||||
struct kernel_dirent retdirent;
|
||||
memset(&retdirent, 0, sizeof(retdirent));
|
||||
const char* name = children[start].name;
|
||||
size_t namelen = strlen(name);
|
||||
size_t needed = sizeof(*dirent) + namelen + 1;
|
||||
ssize_t ret = -1;
|
||||
if ( size < needed )
|
||||
{
|
||||
errno = ERANGE;
|
||||
retdirent.d_namelen = namelen;
|
||||
}
|
||||
else
|
||||
{
|
||||
Ref<Inode> inode = children[start].inode;
|
||||
ret = needed;
|
||||
retdirent.d_reclen = needed;
|
||||
retdirent.d_off = 0;
|
||||
retdirent.d_namelen = namelen;
|
||||
retdirent.d_ino = inode->ino;
|
||||
retdirent.d_dev = inode->dev;
|
||||
retdirent.d_type = ModeToDT(inode->type);
|
||||
}
|
||||
if ( !ctx->copy_to_dest(dirent, &retdirent, sizeof(retdirent)) )
|
||||
return -1;
|
||||
if ( 0 <= ret && !ctx->copy_to_dest(dirent->d_name, name, namelen+1) )
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t Dir::FindChild(const char* filename)
|
||||
{
|
||||
for ( size_t i = 0; i < numchildren; i++ )
|
||||
if ( !strcmp(filename, children[i].name) )
|
||||
return i;
|
||||
return SIZE_MAX;
|
||||
}
|
||||
|
||||
bool Dir::AddChild(const char* filename, Ref<Inode> inode)
|
||||
{
|
||||
if ( numchildren == childrenlen )
|
||||
{
|
||||
size_t newchildrenlen = childrenlen ? 2 * childrenlen : 4;
|
||||
DirEntry* newchildren = new DirEntry[newchildrenlen];
|
||||
if ( !newchildren )
|
||||
return false;
|
||||
for ( size_t i = 0; i < numchildren; i++ )
|
||||
newchildren[i].inode = children[i].inode,
|
||||
newchildren[i].name = children[i].name;
|
||||
delete[] children; children = newchildren;
|
||||
childrenlen = newchildrenlen;
|
||||
}
|
||||
char* filenamecopy = String::Clone(filename);
|
||||
if ( !filenamecopy )
|
||||
return false;
|
||||
inode->linked();
|
||||
DirEntry* dirent = children + numchildren++;
|
||||
dirent->inode = inode;
|
||||
dirent->name = filenamecopy;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Dir::RemoveChild(size_t index)
|
||||
{
|
||||
assert(index < numchildren);
|
||||
if ( index != numchildren-1 )
|
||||
{
|
||||
DirEntry tmp = children[index];
|
||||
children[index] = children[numchildren-1];
|
||||
children[numchildren-1] = tmp;
|
||||
index = numchildren-1;
|
||||
}
|
||||
children[index].inode.Reset();
|
||||
delete[] children[index].name;
|
||||
numchildren--;
|
||||
}
|
||||
|
||||
Ref<Inode> Dir::open(ioctx_t* ctx, const char* filename, int flags, mode_t mode)
|
||||
{
|
||||
ScopedLock lock(&dirlock);
|
||||
if ( shutdown ) { errno = ENOENT; return Ref<Inode>(NULL); }
|
||||
size_t childindex = FindChild(filename);
|
||||
if ( childindex != SIZE_MAX )
|
||||
{
|
||||
if ( flags & O_EXCL ) { errno = EEXIST; return Ref<Inode>(NULL); }
|
||||
return children[childindex].inode;
|
||||
}
|
||||
if ( !(flags & O_CREAT) )
|
||||
return errno = ENOENT, Ref<Inode>(NULL);
|
||||
Ref<File> file(new File(dev, 0, ctx->uid, ctx->gid, mode));
|
||||
if ( !file )
|
||||
return Ref<Inode>(NULL);
|
||||
if ( !AddChild(filename, file) )
|
||||
return Ref<Inode>(NULL);
|
||||
return file;
|
||||
}
|
||||
|
||||
int Dir::mkdir(ioctx_t* ctx, const char* filename, mode_t mode)
|
||||
{
|
||||
ScopedLock lock(&dirlock);
|
||||
if ( shutdown ) { errno = ENOENT; return -1; }
|
||||
size_t childindex = FindChild(filename);
|
||||
if ( childindex != SIZE_MAX ) { errno = EEXIST; return -1; }
|
||||
Ref<Dir> dir(new Dir(dev, 0, ctx->uid, ctx->gid, mode));
|
||||
if ( !dir )
|
||||
goto cleanup_done;
|
||||
if ( dir->link_raw(ctx, ".", dir) )
|
||||
goto cleanup_done;
|
||||
if ( dir->link_raw(ctx, "..", Ref<Dir>(this)) )
|
||||
goto cleanup_dot;
|
||||
if ( !AddChild(filename, dir) )
|
||||
goto cleanup_dotdot;
|
||||
return 0;
|
||||
cleanup_dotdot:
|
||||
dir->unlink_raw(ctx, "..");
|
||||
cleanup_dot:
|
||||
dir->unlink_raw(ctx, ".");
|
||||
cleanup_done:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Dir::rmdir(ioctx_t* ctx, const char* filename)
|
||||
{
|
||||
if ( IsDotOrDotDot(filename) ) { errno = ENOTEMPTY; return -1; }
|
||||
ScopedLock lock(&dirlock);
|
||||
if ( shutdown ) { errno = ENOENT; return -1; }
|
||||
size_t childindex = FindChild(filename);
|
||||
if ( childindex == SIZE_MAX ) { errno = ENOENT; return -1; }
|
||||
Inode* child = children[childindex].inode.Get();
|
||||
if ( !S_ISDIR(child->type) ) { errno = ENOTDIR; return -1; }
|
||||
if ( child->rmdir_me(ctx) < 0 ) { return -1; }
|
||||
RemoveChild(childindex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Dir::rmdir_me(ioctx_t* /*ctx*/)
|
||||
{
|
||||
ScopedLock lock(&dirlock);
|
||||
if ( shutdown ) { errno = ENOENT; return -1; }
|
||||
for ( size_t i = 0; i < numchildren; i++ )
|
||||
if ( !IsDotOrDotDot(children[i].name) )
|
||||
return errno = ENOTEMPTY, -1;
|
||||
shutdown = true;
|
||||
for ( size_t i = 0; i < numchildren; i++ )
|
||||
{
|
||||
children[i].inode->unlinked();
|
||||
children[i].inode.Reset();
|
||||
delete[] children[i].name;
|
||||
}
|
||||
delete[] children; children = NULL;
|
||||
numchildren = childrenlen = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Dir::link(ioctx_t* /*ctx*/, const char* filename, Ref<Inode> node)
|
||||
{
|
||||
if ( S_ISDIR(node->type) ) { errno = EPERM; return -1; }
|
||||
// TODO: Is this needed? This may protect against file descriptors to
|
||||
// deleted directories being used to corrupt kernel state, or something.
|
||||
if ( IsDotOrDotDot(filename) ) { errno = EEXIST; return -1; }
|
||||
if ( node->dev != dev ) { errno = EXDEV; return -1; }
|
||||
ScopedLock lock(&dirlock);
|
||||
if ( shutdown ) { errno = ENOENT; return -1; }
|
||||
size_t childindex = FindChild(filename);
|
||||
if ( childindex != SIZE_MAX )
|
||||
{
|
||||
errno = EEXIST;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
if ( !AddChild(filename, node) )
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Dir::link_raw(ioctx_t* /*ctx*/, const char* filename, Ref<Inode> node)
|
||||
{
|
||||
if ( node->dev != dev ) { errno = EXDEV; return -1; }
|
||||
ScopedLock lock(&dirlock);
|
||||
size_t childindex = FindChild(filename);
|
||||
if ( childindex != SIZE_MAX )
|
||||
{
|
||||
children[childindex].inode->unlinked();
|
||||
children[childindex].inode = node;
|
||||
children[childindex].inode->linked();
|
||||
}
|
||||
else
|
||||
if ( !AddChild(filename, node) )
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Dir::unlink(ioctx_t* /*ctx*/, const char* filename)
|
||||
{
|
||||
ScopedLock lock(&dirlock);
|
||||
if ( shutdown ) { errno = ENOENT; return -1; }
|
||||
size_t childindex = FindChild(filename);
|
||||
if ( childindex == SIZE_MAX ) { errno = ENOENT; return -1; }
|
||||
Inode* child = children[childindex].inode.Get();
|
||||
if ( S_ISDIR(child->type) ) { errno = EISDIR; return -1; }
|
||||
RemoveChild(childindex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Dir::unlink_raw(ioctx_t* /*ctx*/, const char* filename)
|
||||
{
|
||||
ScopedLock lock(&dirlock);
|
||||
size_t childindex = FindChild(filename);
|
||||
if ( childindex == SIZE_MAX ) { errno = ENOENT; return -1; }
|
||||
RemoveChild(childindex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Dir::symlink(ioctx_t* /*ctx*/, const char* oldname, const char* filename)
|
||||
{
|
||||
ScopedLock lock(&dirlock);
|
||||
if ( shutdown ) { errno = ENOENT; return -1; }
|
||||
(void) oldname;
|
||||
(void) filename;
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace KRAMFS
|
||||
} // namespace Sortix
|
103
sortix/fs/kram.h
Normal file
103
sortix/fs/kram.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
|
||||
|
||||
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/>.
|
||||
|
||||
fs/kram.h
|
||||
Kernel RAM filesystem.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_FS_KRAM_H
|
||||
#define SORTIX_FS_KRAM_H
|
||||
|
||||
#include <sortix/kernel/inode.h>
|
||||
#include <sortix/kernel/kthread.h>
|
||||
|
||||
namespace Sortix {
|
||||
namespace KRAMFS {
|
||||
|
||||
struct DirEntry
|
||||
{
|
||||
Ref<Inode> inode;
|
||||
char* name;
|
||||
};
|
||||
|
||||
class File : public AbstractInode
|
||||
{
|
||||
public:
|
||||
File(dev_t dev, ino_t ino, uid_t owner, gid_t group, mode_t mode);
|
||||
virtual ~File();
|
||||
virtual int truncate(ioctx_t* ctx, off_t length);
|
||||
virtual off_t lseek(ioctx_t* ctx, off_t offset, int whence);
|
||||
virtual ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count,
|
||||
off_t off);
|
||||
virtual ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
||||
off_t off);
|
||||
|
||||
private:
|
||||
virtual int truncate_unlocked(ioctx_t* ctx, off_t length);
|
||||
|
||||
private:
|
||||
kthread_mutex_t filelock;
|
||||
uid_t owner;
|
||||
uid_t group;
|
||||
mode_t mode;
|
||||
size_t size;
|
||||
size_t bufsize;
|
||||
uint8_t* buf;
|
||||
size_t numlinks;
|
||||
|
||||
};
|
||||
|
||||
class Dir : public AbstractInode
|
||||
{
|
||||
public:
|
||||
Dir(dev_t dev, ino_t ino, uid_t owner, gid_t group, mode_t mode);
|
||||
virtual ~Dir();
|
||||
virtual ssize_t readdirents(ioctx_t* ctx, struct kernel_dirent* dirent,
|
||||
size_t size, off_t start, size_t maxcount);
|
||||
virtual Ref<Inode> open(ioctx_t* ctx, const char* filename, int flags,
|
||||
mode_t mode);
|
||||
virtual int mkdir(ioctx_t* ctx, const char* filename, mode_t mode);
|
||||
virtual int link(ioctx_t* ctx, const char* filename, Ref<Inode> node);
|
||||
virtual int link_raw(ioctx_t* ctx, const char* filename, Ref<Inode> node);
|
||||
virtual int unlink(ioctx_t* ctx, const char* filename);
|
||||
virtual int unlink_raw(ioctx_t* ctx, const char* filename);
|
||||
virtual int rmdir(ioctx_t* ctx, const char* filename);
|
||||
virtual int rmdir_me(ioctx_t* ctx);
|
||||
virtual int symlink(ioctx_t* ctx, const char* oldname,
|
||||
const char* filename);
|
||||
|
||||
private:
|
||||
size_t FindChild(const char* filename);
|
||||
bool AddChild(const char* filename, Ref<Inode> inode);
|
||||
void RemoveChild(size_t index);
|
||||
|
||||
private:
|
||||
kthread_mutex_t dirlock;
|
||||
size_t numchildren;
|
||||
size_t childrenlen;
|
||||
DirEntry* children;
|
||||
bool shutdown;
|
||||
|
||||
};
|
||||
|
||||
} // namespace KRAMFS
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
|
@ -1,369 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
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/>.
|
||||
|
||||
fs/ramfs.cpp
|
||||
A filesystem stored entirely in RAM.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "../filesystem.h"
|
||||
#include "../directory.h"
|
||||
#include "../stream.h"
|
||||
#include "ramfs.h"
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
class DevRAMFSFile : public DevBuffer
|
||||
{
|
||||
public:
|
||||
typedef DevBuffer BaseClass;
|
||||
|
||||
public:
|
||||
// Transfers ownership of name.
|
||||
DevRAMFSFile(char* name);
|
||||
virtual ~DevRAMFSFile();
|
||||
|
||||
public:
|
||||
char* name;
|
||||
|
||||
private:
|
||||
size_t offset;
|
||||
uint8_t* buffer;
|
||||
size_t bufferused;
|
||||
size_t buffersize;
|
||||
|
||||
public:
|
||||
virtual size_t BlockSize();
|
||||
virtual uintmax_t Size();
|
||||
virtual uintmax_t Position();
|
||||
virtual bool Seek(uintmax_t position);
|
||||
virtual bool Resize(uintmax_t size);
|
||||
virtual ssize_t Read(uint8_t* dest, size_t count);
|
||||
virtual ssize_t Write(const uint8_t* src, size_t count);
|
||||
virtual bool IsReadable();
|
||||
virtual bool IsWritable();
|
||||
|
||||
};
|
||||
|
||||
DevRAMFSFile::DevRAMFSFile(char* name)
|
||||
{
|
||||
this->name = name;
|
||||
buffer = NULL;
|
||||
bufferused = 0;
|
||||
buffersize = 0;
|
||||
}
|
||||
|
||||
DevRAMFSFile::~DevRAMFSFile()
|
||||
{
|
||||
delete[] name;
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
size_t DevRAMFSFile::BlockSize()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
uintmax_t DevRAMFSFile::Size()
|
||||
{
|
||||
return bufferused;
|
||||
}
|
||||
|
||||
uintmax_t DevRAMFSFile::Position()
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
|
||||
bool DevRAMFSFile::Seek(uintmax_t position)
|
||||
{
|
||||
if ( SIZE_MAX < position ) { errno = EOVERFLOW; return false; }
|
||||
offset = position;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DevRAMFSFile::Resize(uintmax_t size)
|
||||
{
|
||||
if ( SIZE_MAX < size ) { errno = EOVERFLOW; return false; }
|
||||
uint8_t* newbuffer = new uint8_t[size];
|
||||
if ( !newbuffer ) { errno = ENOSPC; return false; }
|
||||
size_t sharedmemsize = ( size < bufferused ) ? size : bufferused;
|
||||
memcpy(newbuffer, buffer, sharedmemsize);
|
||||
delete[] buffer;
|
||||
buffer = newbuffer;
|
||||
bufferused = sharedmemsize;
|
||||
buffersize = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t DevRAMFSFile::Read(uint8_t* dest, size_t count)
|
||||
{
|
||||
if ( SSIZE_MAX < count ) { count = SSIZE_MAX; }
|
||||
size_t available = count;
|
||||
if ( bufferused < offset + count ) { available = bufferused - offset; }
|
||||
if ( available == 0 ) { return 0; }
|
||||
memcpy(dest, buffer + offset, available);
|
||||
offset += available;
|
||||
return available;
|
||||
}
|
||||
|
||||
ssize_t DevRAMFSFile::Write(const uint8_t* src, size_t count)
|
||||
{
|
||||
if ( SSIZE_MAX < count ) { count = SSIZE_MAX; }
|
||||
if ( buffersize < offset + count )
|
||||
{
|
||||
uintmax_t newsize = (uintmax_t) offset + (uintmax_t) count;
|
||||
if ( newsize < buffersize * 2 ) { newsize = buffersize * 2; }
|
||||
if ( !Resize(newsize) ) { return -1; }
|
||||
}
|
||||
|
||||
memcpy(buffer + offset, src, count);
|
||||
offset += count;
|
||||
if ( bufferused < offset ) { bufferused = offset; }
|
||||
return count;
|
||||
}
|
||||
|
||||
bool DevRAMFSFile::IsReadable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DevRAMFSFile::IsWritable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
DevRAMFS::DevRAMFS()
|
||||
{
|
||||
files = NULL;
|
||||
}
|
||||
|
||||
DevRAMFS::~DevRAMFS()
|
||||
{
|
||||
if ( files )
|
||||
{
|
||||
while ( !files->Empty() ) { delete files->Remove(0); }
|
||||
delete files;
|
||||
}
|
||||
}
|
||||
|
||||
class DevRAMFSDir : public DevDirectory
|
||||
{
|
||||
public:
|
||||
typedef Device DevDirectory;
|
||||
|
||||
public:
|
||||
DevRAMFSDir(DevRAMFS* fs);
|
||||
virtual ~DevRAMFSDir();
|
||||
|
||||
private:
|
||||
DevRAMFS* fs;
|
||||
size_t position;
|
||||
|
||||
public:
|
||||
virtual void Rewind();
|
||||
virtual int Read(sortix_dirent* dirent, size_t available);
|
||||
|
||||
};
|
||||
|
||||
DevRAMFSDir::DevRAMFSDir(DevRAMFS* fs)
|
||||
{
|
||||
position = 0;
|
||||
this->fs = fs;
|
||||
fs->Refer();
|
||||
}
|
||||
|
||||
DevRAMFSDir::~DevRAMFSDir()
|
||||
{
|
||||
fs->Unref();
|
||||
}
|
||||
|
||||
void DevRAMFSDir::Rewind()
|
||||
{
|
||||
position = 0;
|
||||
}
|
||||
|
||||
int DevRAMFSDir::Read(sortix_dirent* dirent, size_t available)
|
||||
{
|
||||
if ( available <= sizeof(sortix_dirent) ) { return -1; }
|
||||
if ( fs->GetNumFiles() <= position )
|
||||
{
|
||||
dirent->d_namelen = 0;
|
||||
dirent->d_name[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* name = fs->GetFilename(position);
|
||||
if ( !name ) { return -1; }
|
||||
size_t namelen = strlen(name);
|
||||
size_t needed = sizeof(sortix_dirent) + namelen + 1;
|
||||
|
||||
if ( available < needed )
|
||||
{
|
||||
dirent->d_namelen = needed;
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(dirent->d_name, name, namelen + 1);
|
||||
dirent->d_namelen = namelen;
|
||||
position++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CompareFiles(DevRAMFSFile* file1, DevRAMFSFile* file2)
|
||||
{
|
||||
return strcmp(file1->name, file2->name);
|
||||
}
|
||||
|
||||
int LookupFile(DevRAMFSFile* file, const char* name)
|
||||
{
|
||||
return strcmp(file->name, name);
|
||||
}
|
||||
|
||||
Device* DevRAMFS::Open(const char* path, int flags, mode_t mode)
|
||||
{
|
||||
if ( path[0] == 0 || (path[0] == '/' && path[1] == 0) )
|
||||
{
|
||||
if ( (flags & O_LOWERFLAGS) == O_SEARCH )
|
||||
{
|
||||
return new DevRAMFSDir(this);
|
||||
}
|
||||
|
||||
errno = EISDIR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( (flags & O_LOWERFLAGS) == O_SEARCH ) { errno = ENOTDIR; return NULL; }
|
||||
|
||||
if ( *path++ != '/' ) { errno = ENOENT; return NULL; }
|
||||
|
||||
size_t pathlen = strlen(path);
|
||||
for ( size_t i = 0; i < pathlen; i++ )
|
||||
{
|
||||
if ( path[i] == '/' ) { errno = ENOENT; return NULL; }
|
||||
}
|
||||
|
||||
DevBuffer* file = OpenFile(path, flags, mode);
|
||||
if ( !file ) { return NULL; }
|
||||
Device* wrapper = new DevFileWrapper(file, flags);
|
||||
if ( !wrapper ) { errno = ENOSPC; return NULL; }
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
DevBuffer* DevRAMFS::OpenFile(const char* path, int flags, mode_t mode)
|
||||
{
|
||||
// Hack to prevent / from being a filename.
|
||||
if ( path == 0 ) { errno = ENOENT; return NULL; }
|
||||
|
||||
if ( files )
|
||||
{
|
||||
size_t fileindex = files->Search(LookupFile, path);
|
||||
if ( fileindex != SIZE_MAX )
|
||||
{
|
||||
DevRAMFSFile* file = files->Get(fileindex);
|
||||
if ( flags & O_TRUNC ) { file->Resize(0); }
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
||||
return CreateFile(path, flags, mode);
|
||||
}
|
||||
|
||||
DevBuffer* DevRAMFS::CreateFile(const char* path, int flags, mode_t mode)
|
||||
{
|
||||
if ( !(flags & O_CREAT) ) { errno = ENOENT; return NULL; }
|
||||
|
||||
if ( !files )
|
||||
{
|
||||
files = new SortedList<DevRAMFSFile*>(CompareFiles);
|
||||
if ( !files) { errno = ENOSPC; return NULL; }
|
||||
}
|
||||
|
||||
if ( files->Search(LookupFile, path) != SIZE_MAX )
|
||||
{
|
||||
errno = EEXIST;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* newpath = String::Clone(path);
|
||||
if ( !newpath ) { errno = ENOSPC; return NULL; }
|
||||
|
||||
DevRAMFSFile* file = new DevRAMFSFile(newpath);
|
||||
if ( !file ) { delete[] newpath; errno = ENOSPC; return NULL; }
|
||||
if ( !files->Add(file) ) { delete file; errno = ENOSPC; return NULL; }
|
||||
|
||||
file->Refer();
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
bool DevRAMFS::Unlink(const char* path)
|
||||
{
|
||||
if ( *path == '\0' || ( *path++ == '/' && *path == '\0' ) )
|
||||
{
|
||||
errno = EISDIR;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !files ) { errno = ENOENT; return false; }
|
||||
size_t index = files->Search(LookupFile, path);
|
||||
if ( index == SIZE_MAX ) { errno = ENOENT; return false; }
|
||||
|
||||
Device* dev = files->Remove(index);
|
||||
assert(dev);
|
||||
dev->Unref();
|
||||
return true;
|
||||
}
|
||||
|
||||
const bool BINDEVHACK = true;
|
||||
|
||||
size_t DevRAMFS::GetNumFiles()
|
||||
{
|
||||
size_t result = 2 + (BINDEVHACK ? 2 : 0);
|
||||
if ( files ) { result += files->Length(); }
|
||||
return result;
|
||||
}
|
||||
|
||||
const char* DevRAMFS::GetFilename(size_t index)
|
||||
{
|
||||
switch ( index )
|
||||
{
|
||||
case 0: return ".";
|
||||
case 1: return "..";
|
||||
default: index -= 2;
|
||||
}
|
||||
if ( BINDEVHACK ) switch ( index )
|
||||
{
|
||||
case 0: return "bin";
|
||||
case 1: return "dev";
|
||||
default: index -= 2;
|
||||
}
|
||||
if ( !files )
|
||||
return NULL;
|
||||
if ( files->Length() <= index )
|
||||
return NULL;
|
||||
DevRAMFSFile* file = files->Get(index);
|
||||
return file->name;
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
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/>.
|
||||
|
||||
fs/ramfs.h
|
||||
A filesystem stored entirely in RAM.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_FS_RAMFS_H
|
||||
#define SORTIX_FS_RAMFS_H
|
||||
|
||||
#include <sortix/kernel/sortedlist.h>
|
||||
#include "../filesystem.h"
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
class DevRAMFSFile;
|
||||
|
||||
class DevRAMFS : public DevFileSystem
|
||||
{
|
||||
public:
|
||||
DevRAMFS();
|
||||
virtual ~DevRAMFS();
|
||||
|
||||
public:
|
||||
virtual Device* Open(const char* path, int flags, mode_t mode);
|
||||
virtual bool Unlink(const char* path);
|
||||
|
||||
private:
|
||||
SortedList<DevRAMFSFile*>* files;
|
||||
|
||||
public:
|
||||
size_t GetNumFiles();
|
||||
const char* GetFilename(size_t index);
|
||||
|
||||
private:
|
||||
virtual DevBuffer* OpenFile(const char* path, int flags, mode_t mode);
|
||||
virtual DevBuffer* CreateFile(const char* path, int flags, mode_t mode);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -23,193 +23,93 @@
|
|||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/interlock.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
#include <sortix/kernel/ioctx.h>
|
||||
#include <sortix/kernel/inode.h>
|
||||
#include <sortix/stat.h>
|
||||
#include <sortix/seek.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "util.h"
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
DevStringBuffer::DevStringBuffer(char* str)
|
||||
{
|
||||
this->str = str;
|
||||
strlength = strlen(str);
|
||||
off = 0;
|
||||
}
|
||||
|
||||
DevStringBuffer::~DevStringBuffer()
|
||||
{
|
||||
delete[] str;
|
||||
}
|
||||
|
||||
size_t DevStringBuffer::BlockSize()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
uintmax_t DevStringBuffer::Size()
|
||||
{
|
||||
return strlength;
|
||||
}
|
||||
|
||||
uintmax_t DevStringBuffer::Position()
|
||||
{
|
||||
return off;
|
||||
}
|
||||
|
||||
bool DevStringBuffer::Seek(uintmax_t position)
|
||||
{
|
||||
if ( strlength <= position ) { errno = EINVAL; return false; }
|
||||
off = position;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DevStringBuffer::Resize(uintmax_t size)
|
||||
{
|
||||
if ( size != strlength ) { errno = EBADF; }
|
||||
return false;
|
||||
}
|
||||
|
||||
ssize_t DevStringBuffer::Read(uint8_t* dest, size_t count)
|
||||
{
|
||||
size_t available = strlength - off;
|
||||
if ( available < count ) { count = available; }
|
||||
memcpy(dest, str + off, count);
|
||||
off += count;
|
||||
return count;
|
||||
}
|
||||
|
||||
ssize_t DevStringBuffer::Write(const uint8_t* /*src*/, size_t /*count*/)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool DevStringBuffer::IsReadable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DevStringBuffer::IsWritable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
DevLineCommand::DevLineCommand(bool (*handler)(void*, const char*), void* user)
|
||||
{
|
||||
this->handler = handler;
|
||||
this->user = user;
|
||||
this->handled = false;
|
||||
this->sofar = 0;
|
||||
}
|
||||
|
||||
DevLineCommand::~DevLineCommand()
|
||||
{
|
||||
}
|
||||
|
||||
ssize_t DevLineCommand::Read(uint8_t* /*dest*/, size_t /*count*/)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t DevLineCommand::Write(const uint8_t* src, size_t count)
|
||||
{
|
||||
if ( handled ) { errno = EINVAL; return -1; }
|
||||
size_t available = CMDMAX - sofar;
|
||||
if ( !available && count ) { errno = ENOSPC; return -1; }
|
||||
if ( available < count ) { count = available; }
|
||||
memcpy(cmd + sofar, src, count);
|
||||
cmd[sofar += count] = 0;
|
||||
size_t newlinepos = strcspn(cmd, "\n");
|
||||
if ( !cmd[newlinepos] ) { return count; }
|
||||
cmd[newlinepos] = 0;
|
||||
if ( !handler(user, cmd) ) { return -1; }
|
||||
return count;
|
||||
}
|
||||
|
||||
bool DevLineCommand::IsReadable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DevLineCommand::IsWritable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
DevMemoryBuffer::DevMemoryBuffer(uint8_t* buf, size_t bufsize, bool write,
|
||||
bool deletebuf)
|
||||
UtilMemoryBuffer::UtilMemoryBuffer(dev_t dev, ino_t ino, uid_t owner,
|
||||
gid_t group, mode_t mode, uint8_t* buf,
|
||||
size_t bufsize, bool write, bool deletebuf)
|
||||
{
|
||||
inode_type = INODE_TYPE_FILE;
|
||||
this->filelock = KTHREAD_MUTEX_INITIALIZER;
|
||||
this->stat_uid = owner;
|
||||
this->stat_gid = group;
|
||||
this->type = S_IFREG;
|
||||
this->stat_mode = (mode & S_SETABLE) | this->type;
|
||||
this->stat_blksize = 1;
|
||||
this->stat_size = (off_t) bufsize;
|
||||
this->dev = dev;
|
||||
this->ino = ino ? ino : (ino_t) this;
|
||||
this->buf = buf;
|
||||
this->bufsize = bufsize;
|
||||
this->write = write;
|
||||
this->deletebuf = deletebuf;
|
||||
}
|
||||
|
||||
DevMemoryBuffer::~DevMemoryBuffer()
|
||||
UtilMemoryBuffer::~UtilMemoryBuffer()
|
||||
{
|
||||
if ( deletebuf )
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
size_t DevMemoryBuffer::BlockSize()
|
||||
int UtilMemoryBuffer::truncate(ioctx_t* /*ctx*/, off_t length)
|
||||
{
|
||||
return 1;
|
||||
ScopedLock lock(&filelock);
|
||||
if ( (uintmax_t) length != (uintmax_t) bufsize )
|
||||
return errno = ENOTSUP, -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uintmax_t DevMemoryBuffer::Size()
|
||||
off_t UtilMemoryBuffer::lseek(ioctx_t* /*ctx*/, off_t offset, int whence)
|
||||
{
|
||||
return bufsize;
|
||||
ScopedLock lock(&filelock);
|
||||
if ( whence == SEEK_SET )
|
||||
return offset;
|
||||
if ( whence == SEEK_END )
|
||||
return (off_t) bufsize + offset;
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
uintmax_t DevMemoryBuffer::Position()
|
||||
ssize_t UtilMemoryBuffer::pread(ioctx_t* ctx, uint8_t* dest, size_t count,
|
||||
off_t off)
|
||||
{
|
||||
return off;
|
||||
}
|
||||
|
||||
bool DevMemoryBuffer::Seek(uintmax_t position)
|
||||
{
|
||||
off = position;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DevMemoryBuffer::Resize(uintmax_t size)
|
||||
{
|
||||
if ( size != bufsize ) { errno = EPERM; return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t DevMemoryBuffer::Read(uint8_t* dest, size_t count)
|
||||
{
|
||||
if ( bufsize <= off ) { return 0; }
|
||||
ScopedLock lock(&filelock);
|
||||
if ( (uintmax_t) bufsize < (uintmax_t) off )
|
||||
return 0;
|
||||
size_t available = bufsize - off;
|
||||
if ( available < count ) { count = available; }
|
||||
memcpy(dest, buf + off, count);
|
||||
off += count;
|
||||
if ( available < count )
|
||||
count = available;
|
||||
if ( !ctx->copy_to_dest(dest, buf + off, count) )
|
||||
return -1;
|
||||
return count;
|
||||
}
|
||||
|
||||
ssize_t DevMemoryBuffer::Write(const uint8_t* src, size_t count)
|
||||
ssize_t UtilMemoryBuffer::pwrite(ioctx_t* ctx, const uint8_t* src, size_t count,
|
||||
off_t off)
|
||||
{
|
||||
ScopedLock lock(&filelock);
|
||||
if ( !write ) { errno = EBADF; return -1; }
|
||||
if ( bufsize <= off ) { errno = EPERM; return -1; }
|
||||
// TODO: Avoid having off + count overflow!
|
||||
if ( bufsize < off + count )
|
||||
return 0;
|
||||
if ( (uintmax_t) bufsize <= (uintmax_t) off )
|
||||
return -1;
|
||||
size_t available = bufsize - off;
|
||||
if ( available < count ) { count = available; }
|
||||
memcpy(buf + off, src, count);
|
||||
off += count;
|
||||
if ( available < count )
|
||||
count = available;
|
||||
ctx->copy_from_src(buf + off, src, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
bool DevMemoryBuffer::IsReadable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DevMemoryBuffer::IsWritable()
|
||||
{
|
||||
return write;
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -25,79 +25,31 @@
|
|||
#ifndef SORTIX_FS_UTIL_H
|
||||
#define SORTIX_FS_UTIL_H
|
||||
|
||||
#include "../stream.h"
|
||||
#include <sortix/kernel/inode.h>
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
class DevStringBuffer : public DevBuffer
|
||||
class UtilMemoryBuffer : public AbstractInode
|
||||
{
|
||||
public:
|
||||
DevStringBuffer(char* str);
|
||||
virtual ~DevStringBuffer();
|
||||
|
||||
private:
|
||||
char* str;
|
||||
size_t strlength;
|
||||
size_t off;
|
||||
|
||||
public:
|
||||
virtual size_t BlockSize();
|
||||
virtual uintmax_t Size();
|
||||
virtual uintmax_t Position();
|
||||
virtual bool Seek(uintmax_t position);
|
||||
virtual bool Resize(uintmax_t size);
|
||||
virtual ssize_t Read(uint8_t* dest, size_t count);
|
||||
virtual ssize_t Write(const uint8_t* src, size_t count);
|
||||
virtual bool IsReadable();
|
||||
virtual bool IsWritable();
|
||||
|
||||
};
|
||||
|
||||
class DevLineCommand : public DevStream
|
||||
{
|
||||
public:
|
||||
DevLineCommand(bool (*handler)(void*, const char*), void* user);
|
||||
virtual ~DevLineCommand();
|
||||
virtual ssize_t Read(uint8_t* dest, size_t count);
|
||||
virtual ssize_t Write(const uint8_t* src, size_t count);
|
||||
virtual bool IsReadable();
|
||||
virtual bool IsWritable();
|
||||
|
||||
private:
|
||||
bool (*handler)(void*, const char*);
|
||||
void* user;
|
||||
size_t sofar;
|
||||
static const size_t CMDMAX = 255;
|
||||
char cmd[CMDMAX+1];
|
||||
bool handled;
|
||||
|
||||
};
|
||||
|
||||
class DevMemoryBuffer : public DevBuffer
|
||||
{
|
||||
public:
|
||||
DevMemoryBuffer(uint8_t* buf, size_t bufsize, bool write = true,
|
||||
bool deletebuf = true);
|
||||
~DevMemoryBuffer();
|
||||
UtilMemoryBuffer(dev_t dev, ino_t ino, uid_t owner, gid_t group,
|
||||
mode_t mode, uint8_t* buf, size_t bufsize,
|
||||
bool write = true, bool deletebuf = true);
|
||||
virtual ~UtilMemoryBuffer();
|
||||
virtual int truncate(ioctx_t* ctx, off_t length);
|
||||
virtual off_t lseek(ioctx_t* ctx, off_t offset, int whence);
|
||||
virtual ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count,
|
||||
off_t off);
|
||||
virtual ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
||||
off_t off);
|
||||
|
||||
private:
|
||||
kthread_mutex_t filelock;
|
||||
uint8_t* buf;
|
||||
size_t bufsize;
|
||||
size_t off;
|
||||
bool write;
|
||||
bool deletebuf;
|
||||
|
||||
public:
|
||||
virtual size_t BlockSize();
|
||||
virtual uintmax_t Size();
|
||||
virtual uintmax_t Position();
|
||||
virtual bool Seek(uintmax_t position);
|
||||
virtual bool Resize(uintmax_t size);
|
||||
virtual ssize_t Read(uint8_t* dest, size_t count);
|
||||
virtual ssize_t Write(const uint8_t* src, size_t count);
|
||||
virtual bool IsReadable();
|
||||
virtual bool IsWritable();
|
||||
|
||||
};
|
||||
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -1,320 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
|
||||
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/>.
|
||||
|
||||
fs/videofs.cpp
|
||||
Provides filesystem access to the video framework.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/video.h>
|
||||
#include <sortix/kernel/string.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "../directory.h"
|
||||
#include "util.h"
|
||||
#include "videofs.h"
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
class DevFrameBuffer : public DevBuffer
|
||||
{
|
||||
public:
|
||||
DevFrameBuffer();
|
||||
virtual ~DevFrameBuffer();
|
||||
|
||||
private:
|
||||
uintmax_t off;
|
||||
|
||||
public:
|
||||
virtual size_t BlockSize();
|
||||
virtual uintmax_t Size();
|
||||
virtual uintmax_t Position();
|
||||
virtual bool Seek(uintmax_t position);
|
||||
virtual bool Resize(uintmax_t size);
|
||||
virtual ssize_t Read(uint8_t* dest, size_t count);
|
||||
virtual ssize_t Write(const uint8_t* src, size_t count);
|
||||
virtual bool IsReadable();
|
||||
virtual bool IsWritable();
|
||||
|
||||
};
|
||||
|
||||
DevFrameBuffer::DevFrameBuffer()
|
||||
{
|
||||
off = 0;
|
||||
}
|
||||
|
||||
DevFrameBuffer::~DevFrameBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
size_t DevFrameBuffer::BlockSize()
|
||||
{
|
||||
return 1; // Well, not really.
|
||||
}
|
||||
|
||||
uintmax_t DevFrameBuffer::Size()
|
||||
{
|
||||
return Video::FrameSize();
|
||||
}
|
||||
|
||||
uintmax_t DevFrameBuffer::Position()
|
||||
{
|
||||
return off;
|
||||
}
|
||||
|
||||
bool DevFrameBuffer::Seek(uintmax_t position)
|
||||
{
|
||||
off = position;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DevFrameBuffer::Resize(uintmax_t /*size*/)
|
||||
{
|
||||
errno = EBADF;
|
||||
return false;
|
||||
}
|
||||
|
||||
ssize_t DevFrameBuffer::Read(uint8_t* dest, size_t count)
|
||||
{
|
||||
ssize_t result = Video::ReadAt(off, dest, count);
|
||||
if ( 0 <= result ) { off += result; }
|
||||
return result;
|
||||
}
|
||||
|
||||
ssize_t DevFrameBuffer::Write(const uint8_t* src, size_t count)
|
||||
{
|
||||
ssize_t result = Video::WriteAt(off, src, count);
|
||||
if ( 0 <= result ) { off += result; }
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DevFrameBuffer::IsReadable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DevFrameBuffer::IsWritable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SetModeHandler(void* /*user*/, const char* cmd)
|
||||
{
|
||||
return Video::SwitchMode(cmd);
|
||||
}
|
||||
|
||||
bool SupportsModeHandler(void* /*user*/, const char* cmd)
|
||||
{
|
||||
return Video::Supports(cmd);
|
||||
}
|
||||
|
||||
Device* MakeGetMode(int /*flags*/, mode_t /*mode*/)
|
||||
{
|
||||
char* mode = Video::GetCurrentMode();
|
||||
if ( !mode ) { return NULL; }
|
||||
char* modeline = String::Combine(2, mode, "\n");
|
||||
delete[] mode; mode = NULL;
|
||||
if ( !modeline ) { return NULL; }
|
||||
Device* result = new DevStringBuffer(modeline);
|
||||
if ( !result ) { delete[] modeline; return NULL; }
|
||||
return result;
|
||||
}
|
||||
|
||||
Device* MakeSetMode(int /*flags*/, mode_t /*mode*/)
|
||||
{
|
||||
return new DevLineCommand(SetModeHandler, NULL);
|
||||
}
|
||||
|
||||
Device* MakeMode(int flags, mode_t mode)
|
||||
{
|
||||
int lowerflags = flags & O_LOWERFLAGS;
|
||||
if ( lowerflags == O_SEARCH ) { errno = ENOTDIR; return NULL; }
|
||||
if ( lowerflags == O_RDONLY ) { return MakeGetMode(flags, mode); }
|
||||
if ( lowerflags == O_WRONLY ) { return MakeSetMode(flags, mode); }
|
||||
errno = EPERM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Device* MakeModes(int flags, mode_t /*mode*/)
|
||||
{
|
||||
int lowerflags = flags & O_LOWERFLAGS;
|
||||
if ( lowerflags == O_SEARCH ) { errno = ENOTDIR; return NULL; }
|
||||
if ( lowerflags != O_RDONLY ) { errno = EPERM; return NULL; }
|
||||
size_t nummodes = 0;
|
||||
char** modes = Video::GetModes(&nummodes);
|
||||
if ( !modes ) { return NULL; }
|
||||
Device* result = NULL;
|
||||
size_t combinedlen = 0;
|
||||
for ( size_t i = 0; i < nummodes; i++ )
|
||||
{
|
||||
combinedlen += strlen(modes[i]) + 1 /*newline*/;
|
||||
}
|
||||
size_t sofar = 0;
|
||||
char* modesstr = new char[combinedlen + 1];
|
||||
if ( !modesstr ) { goto out; }
|
||||
for ( size_t i = 0; i < nummodes; i++ )
|
||||
{
|
||||
strcpy(modesstr + sofar, modes[i]);
|
||||
sofar += strlen(modes[i]);
|
||||
modesstr[sofar++] = '\n';
|
||||
}
|
||||
modesstr[sofar] = 0;
|
||||
result = new DevStringBuffer(modesstr);
|
||||
if ( !result ) { delete[] modesstr; }
|
||||
out:
|
||||
for ( size_t i = 0; i < nummodes; i++ ) { delete[] modes[i]; }
|
||||
delete[] modes;
|
||||
return result;
|
||||
}
|
||||
|
||||
Device* MakeSupports(int flags, mode_t /*mode*/)
|
||||
{
|
||||
int lowerflags = flags & O_LOWERFLAGS;
|
||||
if ( lowerflags == O_SEARCH ) { errno = ENOTDIR; return NULL; }
|
||||
return new DevLineCommand(SupportsModeHandler, NULL);
|
||||
}
|
||||
|
||||
Device* MakeFB(int flags, mode_t /*mode*/)
|
||||
{
|
||||
int lowerflags = flags & O_LOWERFLAGS;
|
||||
if ( lowerflags == O_SEARCH ) { errno = ENOTDIR; return NULL; }
|
||||
return new DevFrameBuffer();
|
||||
}
|
||||
|
||||
Device* MakeDot(int /*flags*/, mode_t /*mode*/)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Device* MakeDotDot(int /*flags*/, mode_t /*mode*/)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct
|
||||
{
|
||||
const char* name;
|
||||
Device* (*factory)(int, mode_t);
|
||||
} nodes[] =
|
||||
{
|
||||
{ ".", MakeDot },
|
||||
{ "..", MakeDotDot },
|
||||
{ "mode", MakeMode },
|
||||
{ "modes", MakeModes },
|
||||
{ "supports", MakeSupports },
|
||||
{ "fb", MakeFB },
|
||||
};
|
||||
|
||||
static inline size_t NumNodes()
|
||||
{
|
||||
return sizeof(nodes)/sizeof(nodes[0]);
|
||||
}
|
||||
|
||||
class DevVideoFSDir : public DevDirectory
|
||||
{
|
||||
public:
|
||||
DevVideoFSDir();
|
||||
virtual ~DevVideoFSDir();
|
||||
|
||||
private:
|
||||
size_t position;
|
||||
|
||||
public:
|
||||
virtual void Rewind();
|
||||
virtual int Read(sortix_dirent* dirent, size_t available);
|
||||
|
||||
};
|
||||
|
||||
DevVideoFSDir::DevVideoFSDir()
|
||||
{
|
||||
position = 0;
|
||||
}
|
||||
|
||||
DevVideoFSDir::~DevVideoFSDir()
|
||||
{
|
||||
}
|
||||
|
||||
void DevVideoFSDir::Rewind()
|
||||
{
|
||||
position = 0;
|
||||
}
|
||||
|
||||
int DevVideoFSDir::Read(sortix_dirent* dirent, size_t available)
|
||||
{
|
||||
if ( available <= sizeof(sortix_dirent) ) { return -1; }
|
||||
if ( NumNodes() <= position )
|
||||
{
|
||||
dirent->d_namelen = 0;
|
||||
dirent->d_name[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* name = nodes[position].name;
|
||||
size_t namelen = strlen(name);
|
||||
size_t needed = sizeof(sortix_dirent) + namelen + 1;
|
||||
|
||||
if ( available < needed )
|
||||
{
|
||||
dirent->d_namelen = needed;
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(dirent->d_name, name, namelen + 1);
|
||||
dirent->d_namelen = namelen;
|
||||
position++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DevVideoFS::DevVideoFS()
|
||||
{
|
||||
}
|
||||
|
||||
DevVideoFS::~DevVideoFS()
|
||||
{
|
||||
}
|
||||
|
||||
Device* DevVideoFS::Open(const char* path, int flags, mode_t mode)
|
||||
{
|
||||
if ( !strcmp(path, "") || !strcmp(path, "/") )
|
||||
{
|
||||
if ( (flags & O_LOWERFLAGS) == O_SEARCH ) { return new DevVideoFSDir; }
|
||||
errno = EISDIR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( *path++ != '/' ) { errno = ENOENT; return NULL; }
|
||||
|
||||
for ( size_t i = 0; i < NumNodes(); i++ )
|
||||
{
|
||||
if ( strcmp(path, nodes[i].name) ) { continue; }
|
||||
return nodes[i].factory(flags, mode);
|
||||
}
|
||||
errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool DevVideoFS::Unlink(const char* /*path*/)
|
||||
{
|
||||
errno = EPERM;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
81
sortix/fsfunc.cpp
Normal file
81
sortix/fsfunc.cpp
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
|
||||
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/>.
|
||||
|
||||
fsfunc.cpp
|
||||
Filesystem related utility functions.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/fsfunc.h>
|
||||
#include <sortix/kernel/string.h>
|
||||
#include <sortix/dirent.h>
|
||||
#include <sortix/stat.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
bool ModeToDT(mode_t mode)
|
||||
{
|
||||
if ( S_ISSOCK(mode) )
|
||||
return DT_SOCK;
|
||||
if ( S_ISLNK(mode) )
|
||||
return DT_LNK;
|
||||
if ( S_ISREG(mode) )
|
||||
return DT_REG;
|
||||
if ( S_ISBLK(mode) )
|
||||
return DT_BLK;
|
||||
if ( S_ISDIR(mode) )
|
||||
return DT_DIR;
|
||||
if ( S_ISCHR(mode) )
|
||||
return DT_CHR;
|
||||
if ( S_ISFIFO(mode) )
|
||||
return DT_FIFO;
|
||||
return DT_UNKNOWN;
|
||||
}
|
||||
|
||||
// '' -> '' ''
|
||||
// '/' -> '' '/'
|
||||
// '///' -> '' '///'
|
||||
// '.' -> '' '.'
|
||||
// 'test' -> '' 'test'
|
||||
// 'test/dir' -> 'test/' 'dir'
|
||||
// 'test/dir/foo' -> 'test/dir/' 'foo'
|
||||
// 'test/dir/' -> 'test/' 'dir/'
|
||||
// '../' -> '' '../'
|
||||
// 'foo///bar//test///' -> 'foo///bar//' 'test///'
|
||||
|
||||
bool SplitFinalElem(const char* path, char** dir, char** final)
|
||||
{
|
||||
size_t pathlen = strlen(path);
|
||||
size_t splitat = pathlen;
|
||||
while ( splitat && path[splitat-1] == '/' )
|
||||
splitat--;
|
||||
while ( splitat && path[splitat-1] != '/' )
|
||||
splitat--;
|
||||
char* retdir = String::Substring(path, 0, splitat);
|
||||
if ( !retdir ) { return false; }
|
||||
char* retfinal = String::Substring(path, splitat, pathlen - splitat);
|
||||
if ( !retfinal ) { delete[] retdir; return false; }
|
||||
*dir = retdir;
|
||||
*final = retfinal;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
61
sortix/include/sortix/dirent.h
Normal file
61
sortix/include/sortix/dirent.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
|
||||
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/>.
|
||||
|
||||
sortix/dirent.h
|
||||
Format of directory entries.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef INCLUDE_SORTIX_DIRENT_H
|
||||
#define INCLUDE_SORTIX_DIRENT_H
|
||||
|
||||
#include <features.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define DT_UNKNOWN 0
|
||||
#define DT_BLK 1
|
||||
#define DT_CHR 2
|
||||
#define DT_DIR 3
|
||||
#define DT_FIFO 4
|
||||
#define DT_LNK 5
|
||||
#define DT_REG 6
|
||||
#define DT_SOCK 7
|
||||
|
||||
struct kernel_dirent
|
||||
{
|
||||
size_t d_reclen;
|
||||
size_t d_off;
|
||||
size_t d_namelen;
|
||||
ino_t d_ino;
|
||||
dev_t d_dev;
|
||||
unsigned char d_type;
|
||||
char d_name[];
|
||||
};
|
||||
|
||||
static inline struct kernel_dirent* kernel_dirent_next(struct kernel_dirent* ent)
|
||||
{
|
||||
if ( !ent->d_off )
|
||||
return NULL;
|
||||
return (struct kernel_dirent*) ((uint8_t*) ent + ent->d_off);
|
||||
}
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
|
@ -47,11 +47,15 @@ __BEGIN_DECLS
|
|||
#define FD_CLOEXEC (1<<0)
|
||||
#define FD_CLOFORK (1<<1)
|
||||
|
||||
#define __FD_ALLOWED_FLAGS (FD_CLOEXEC | FD_CLOFORK)
|
||||
|
||||
#define F_SETFD 0
|
||||
#define F_GETFD 1
|
||||
#define F_SETFL 2
|
||||
#define F_GETFL 3
|
||||
|
||||
#define AT_FDCWD (-100)
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_INITRD_H
|
||||
#define SORTIX_INITRD_H
|
||||
#ifndef INCLUDE_SORTIX_INITRD_H
|
||||
#define INCLUDE_SORTIX_INITRD_H
|
||||
|
||||
#include <features.h>
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -17,32 +17,24 @@
|
|||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
fs/initfs.h
|
||||
Provides access to the initial ramdisk.
|
||||
sortix/kernel/copy.h
|
||||
The context for io operations: who made it, how should data be copied, etc.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_FS_INITFS_H
|
||||
#define SORTIX_FS_INITFS_H
|
||||
#ifndef SORTIX_COPY_H
|
||||
#define SORTIX_COPY_H
|
||||
|
||||
#include <sortix/kernel/sortedlist.h>
|
||||
#include "../filesystem.h"
|
||||
#include <stddef.h>
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
class DevInitFSFile;
|
||||
namespace Sortix {
|
||||
|
||||
class DevInitFS : public DevFileSystem
|
||||
{
|
||||
public:
|
||||
DevInitFS();
|
||||
virtual ~DevInitFS();
|
||||
bool CopyToUser(void* userdst, const void* ksrc, size_t count);
|
||||
bool CopyFromUser(void* kdst, const void* usersrc, size_t count);
|
||||
bool CopyToKernel(void* kdst, const void* ksrc, size_t count);
|
||||
bool CopyFromKernel(void* kdst, const void* ksrc, size_t count);
|
||||
char* GetStringFromUser(const char* str);
|
||||
|
||||
public:
|
||||
virtual Device* Open(const char* path, int flags, mode_t mode);
|
||||
virtual bool Unlink(const char* path);
|
||||
|
||||
};
|
||||
}
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
108
sortix/include/sortix/kernel/descriptor.h
Normal file
108
sortix/include/sortix/kernel/descriptor.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
|
||||
|
||||
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/>.
|
||||
|
||||
sortix/kernel/descriptor.h
|
||||
A file descriptor.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef INCLUDE_SORTIX_KERNEL_DESCRIPTOR_H
|
||||
#define INCLUDE_SORTIX_KERNEL_DESCRIPTOR_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <sortix/timespec.h>
|
||||
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
|
||||
struct stat;
|
||||
struct timeval;
|
||||
struct winsize;
|
||||
struct kernel_dirent;
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
class Inode;
|
||||
class Vnode;
|
||||
struct ioctx_struct;
|
||||
typedef struct ioctx_struct ioctx_t;
|
||||
|
||||
class Descriptor : public Refcountable
|
||||
{
|
||||
public:
|
||||
Descriptor(Ref<Vnode> vnode, int dflags);
|
||||
virtual ~Descriptor();
|
||||
Ref<Descriptor> Fork();
|
||||
int sync(ioctx_t* ctx);
|
||||
int stat(ioctx_t* ctx, struct stat* st);
|
||||
int chmod(ioctx_t* ctx, mode_t mode);
|
||||
int chown(ioctx_t* ctx, uid_t owner, gid_t group);
|
||||
int truncate(ioctx_t* ctx, off_t length);
|
||||
off_t lseek(ioctx_t* ctx, off_t offset, int whence);
|
||||
ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
||||
ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off);
|
||||
ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
||||
ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t off);
|
||||
int utimes(ioctx_t* ctx, const struct timeval times[2]);
|
||||
int isatty(ioctx_t* ctx);
|
||||
ssize_t readdirents(ioctx_t* ctx, struct kernel_dirent* dirent, size_t size,
|
||||
size_t maxcount);
|
||||
Ref<Descriptor> open(ioctx_t* ctx, const char* filename, int flags,
|
||||
mode_t mode = 0);
|
||||
int mkdir(ioctx_t* ctx, const char* filename, mode_t mode);
|
||||
int link(ioctx_t* ctx, const char* filename, Ref<Descriptor> node);
|
||||
int unlink(ioctx_t* ctx, const char* filename);
|
||||
int rmdir(ioctx_t* ctx, const char* filename);
|
||||
int symlink(ioctx_t* ctx, const char* oldname, const char* filename);
|
||||
ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz);
|
||||
int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
|
||||
int settermmode(ioctx_t* ctx, unsigned mode);
|
||||
int gettermmode(ioctx_t* ctx, unsigned* mode);
|
||||
|
||||
private:
|
||||
Ref<Descriptor> open_elem(ioctx_t* ctx, const char* filename, int flags,
|
||||
mode_t mode);
|
||||
bool IsSeekable();
|
||||
|
||||
public: /* These must never change after construction and is read-only. */
|
||||
ino_t ino;
|
||||
dev_t dev;
|
||||
mode_t type; // For use by S_IS* macros.
|
||||
|
||||
public /*TODO: private*/:
|
||||
Ref<Vnode> vnode;
|
||||
kthread_mutex_t curofflock;
|
||||
bool seekable;
|
||||
bool checked_seekable;
|
||||
off_t curoff;
|
||||
int dflags;
|
||||
|
||||
};
|
||||
|
||||
bool LinkInodeInDir(ioctx_t* ctx, Ref<Descriptor> dir, const char* name,
|
||||
Ref<Inode> inode);
|
||||
Ref<Descriptor> OpenDirContainingPath(ioctx_t* ctx, Ref<Descriptor> from,
|
||||
const char* path, char** finalp);
|
||||
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
69
sortix/include/sortix/kernel/dtable.h
Normal file
69
sortix/include/sortix/kernel/dtable.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
|
||||
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/>.
|
||||
|
||||
sortix/kernel/dtable.h
|
||||
Table of file descriptors.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_DTABLE_H
|
||||
#define SORTIX_DTABLE_H
|
||||
|
||||
#include <sortix/kernel/refcount.h>
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
class Descriptor;
|
||||
|
||||
typedef struct dtableent_struct
|
||||
{
|
||||
Ref<Descriptor> desc;
|
||||
int flags;
|
||||
} dtableent_t;
|
||||
|
||||
class DescriptorTable : public Refcountable
|
||||
{
|
||||
public:
|
||||
DescriptorTable();
|
||||
~DescriptorTable();
|
||||
Ref<DescriptorTable> Fork();
|
||||
Ref<Descriptor> Get(int index);
|
||||
int Allocate(Ref<Descriptor> desc, int flags);
|
||||
int Copy(int from, int to);
|
||||
void Free(int index);
|
||||
Ref<Descriptor> FreeKeep(int index);
|
||||
void OnExecute();
|
||||
bool SetFlags(int index, int flags);
|
||||
int GetFlags(int index);
|
||||
|
||||
private:
|
||||
void Reset(); // Hey, reference counted. Don't call this.
|
||||
bool IsGoodEntry(int i);
|
||||
bool Enlargen(int atleast);
|
||||
|
||||
private:
|
||||
kthread_mutex_t dtablelock;
|
||||
dtableent_t* entries;
|
||||
int numentries;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
|
@ -17,29 +17,24 @@
|
|||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
fs/videofs.h
|
||||
Provides filesystem access to the video framework.
|
||||
sortix/kernel/fsfunc.h
|
||||
Filesystem related utility functions.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_FS_VIDEOFS_H
|
||||
#define SORTIX_FS_VIDEOFS_H
|
||||
|
||||
#include "../filesystem.h"
|
||||
#ifndef SORTIX_FSFUNC_H
|
||||
#define SORTIX_FSFUNC_H
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
class DevVideoFS : public DevFileSystem
|
||||
static inline bool IsDotOrDotDot(const char* path)
|
||||
{
|
||||
public:
|
||||
DevVideoFS();
|
||||
virtual ~DevVideoFS();
|
||||
return path[0] == '.' && ((path[1] == '\0') ||
|
||||
(path[1] == '.' && path[2] == '\0'));
|
||||
}
|
||||
|
||||
public:
|
||||
virtual Device* Open(const char* path, int flags, mode_t mode);
|
||||
virtual bool Unlink(const char* path);
|
||||
|
||||
};
|
||||
bool ModeToDT(mode_t mode);
|
||||
bool SplitFinalElem(const char* path, char** dir, char** final);
|
||||
|
||||
} // namespace Sortix
|
||||
|
159
sortix/include/sortix/kernel/inode.h
Normal file
159
sortix/include/sortix/kernel/inode.h
Normal file
|
@ -0,0 +1,159 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
|
||||
|
||||
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/>.
|
||||
|
||||
sortix/kernel/inode.h
|
||||
Interfaces and utility classes for implementing inodes.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef INCLUDE_SORTIX_KERNEL_INODE_H
|
||||
#define INCLUDE_SORTIX_KERNEL_INODE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <sortix/timespec.h>
|
||||
|
||||
#include <sortix/kernel/refcount.h>
|
||||
|
||||
struct stat;
|
||||
struct timeval;
|
||||
struct winsize;
|
||||
struct kernel_dirent;
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
struct ioctx_struct;
|
||||
typedef struct ioctx_struct ioctx_t;
|
||||
|
||||
// An interface describing all operations possible on an inode.
|
||||
class Inode : public Refcountable
|
||||
{
|
||||
public: /* These must never change after construction and is read-only. */
|
||||
ino_t ino;
|
||||
dev_t dev;
|
||||
mode_t type; // For use by S_IS* macros.
|
||||
|
||||
public:
|
||||
virtual ~Inode() { }
|
||||
virtual void linked() = 0;
|
||||
virtual void unlinked() = 0;
|
||||
virtual int sync(ioctx_t* ctx) = 0;
|
||||
virtual int stat(ioctx_t* ctx, struct stat* st) = 0;
|
||||
virtual int chmod(ioctx_t* ctx, mode_t mode) = 0;
|
||||
virtual int chown(ioctx_t* ctx, uid_t owner, gid_t group) = 0;
|
||||
virtual int truncate(ioctx_t* ctx, off_t length) = 0;
|
||||
virtual off_t lseek(ioctx_t* ctx, off_t offset, int whence) = 0;
|
||||
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count) = 0;
|
||||
virtual ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count,
|
||||
off_t off) = 0;
|
||||
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count) = 0;
|
||||
virtual ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
||||
off_t off) = 0;
|
||||
virtual int utimes(ioctx_t* ctx, const struct timeval times[2]) = 0;
|
||||
virtual int isatty(ioctx_t* ctx) = 0;
|
||||
virtual ssize_t readdirents(ioctx_t* ctx, struct kernel_dirent* dirent,
|
||||
size_t size, off_t start, size_t maxcount) = 0;
|
||||
virtual Ref<Inode> open(ioctx_t* ctx, const char* filename, int flags,
|
||||
mode_t mode) = 0;
|
||||
virtual int mkdir(ioctx_t* ctx, const char* filename, mode_t mode) = 0;
|
||||
virtual int link(ioctx_t* ctx, const char* filename, Ref<Inode> node) = 0;
|
||||
virtual int link_raw(ioctx_t* ctx, const char* filename, Ref<Inode> node) = 0;
|
||||
virtual int unlink(ioctx_t* ctx, const char* filename) = 0;
|
||||
virtual int unlink_raw(ioctx_t* ctx, const char* filename) = 0;
|
||||
virtual int rmdir(ioctx_t* ctx, const char* filename) = 0;
|
||||
virtual int rmdir_me(ioctx_t* ctx) = 0;
|
||||
virtual int symlink(ioctx_t* ctx, const char* oldname,
|
||||
const char* filename) = 0;
|
||||
virtual ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz) = 0;
|
||||
virtual int tcgetwinsize(ioctx_t* ctx, struct winsize* ws) = 0;
|
||||
virtual int settermmode(ioctx_t* ctx, unsigned mode) = 0;
|
||||
virtual int gettermmode(ioctx_t* ctx, unsigned* mode) = 0;
|
||||
|
||||
};
|
||||
|
||||
enum InodeType
|
||||
{
|
||||
INODE_TYPE_UNKNOWN = 0,
|
||||
INODE_TYPE_FILE,
|
||||
INODE_TYPE_STREAM,
|
||||
INODE_TYPE_TTY,
|
||||
INODE_TYPE_DIR,
|
||||
};
|
||||
|
||||
class AbstractInode : public Inode
|
||||
{
|
||||
protected:
|
||||
kthread_mutex_t metalock;
|
||||
InodeType inode_type;
|
||||
mode_t stat_mode;
|
||||
/*nlink_t*/ unsigned long stat_nlink;
|
||||
uid_t stat_uid;
|
||||
gid_t stat_gid;
|
||||
off_t stat_size;
|
||||
time_t stat_atime;
|
||||
time_t stat_mtime;
|
||||
time_t stat_ctime;
|
||||
/* TODO: stat_atim, stat_mtim, stat_ctim */
|
||||
blksize_t stat_blksize;
|
||||
blkcnt_t stat_blocks;
|
||||
|
||||
public:
|
||||
AbstractInode();
|
||||
virtual ~AbstractInode();
|
||||
virtual void linked();
|
||||
virtual void unlinked();
|
||||
virtual int sync(ioctx_t* ctx);
|
||||
virtual int stat(ioctx_t* ctx, struct stat* st);
|
||||
virtual int chmod(ioctx_t* ctx, mode_t mode);
|
||||
virtual int chown(ioctx_t* ctx, uid_t owner, gid_t group);
|
||||
virtual int truncate(ioctx_t* ctx, off_t length);
|
||||
virtual off_t lseek(ioctx_t* ctx, off_t offset, int whence);
|
||||
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
||||
virtual ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off);
|
||||
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
||||
virtual ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
||||
off_t off);
|
||||
virtual int utimes(ioctx_t* ctx, const struct timeval times[2]);
|
||||
virtual int isatty(ioctx_t* ctx);
|
||||
virtual ssize_t readdirents(ioctx_t* ctx, struct kernel_dirent* dirent,
|
||||
size_t size, off_t start, size_t maxcount);
|
||||
virtual Ref<Inode> open(ioctx_t* ctx, const char* filename, int flags,
|
||||
mode_t mode);
|
||||
virtual int mkdir(ioctx_t* ctx, const char* filename, mode_t mode);
|
||||
virtual int link(ioctx_t* ctx, const char* filename, Ref<Inode> node);
|
||||
virtual int link_raw(ioctx_t* ctx, const char* filename, Ref<Inode> node);
|
||||
virtual int unlink(ioctx_t* ctx, const char* filename);
|
||||
virtual int unlink_raw(ioctx_t* ctx, const char* filename);
|
||||
virtual int rmdir(ioctx_t* ctx, const char* filename);
|
||||
virtual int rmdir_me(ioctx_t* ctx);
|
||||
virtual int symlink(ioctx_t* ctx, const char* oldname,
|
||||
const char* filename);
|
||||
virtual ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz);
|
||||
virtual int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
|
||||
virtual int settermmode(ioctx_t* ctx, unsigned mode);
|
||||
virtual int gettermmode(ioctx_t* ctx, unsigned* mode);
|
||||
|
||||
};
|
||||
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -17,42 +17,33 @@
|
|||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
device.cpp
|
||||
A base class for all devices.
|
||||
sortix/kernel/ioctx.h
|
||||
The context for io operations: who made it, how should data be copied, etc.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <string.h>
|
||||
#include "device.h"
|
||||
#ifndef SORTIX_IOCTX_H
|
||||
#define SORTIX_IOCTX_H
|
||||
|
||||
namespace Sortix
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
struct ioctx_struct
|
||||
{
|
||||
Device::Device()
|
||||
{
|
||||
refcountlock = KTHREAD_MUTEX_INITIALIZER;
|
||||
refcount = 0;
|
||||
}
|
||||
uid_t uid, auth_uid;
|
||||
gid_t gid, auth_gid;
|
||||
bool (*copy_to_dest)(void* dest, const void* src, size_t n);
|
||||
bool (*copy_from_src)(void* dest, const void* src, size_t n);
|
||||
};
|
||||
|
||||
Device::~Device()
|
||||
{
|
||||
typedef struct ioctx_struct ioctx_t;
|
||||
|
||||
}
|
||||
void SetupUserIOCtx(ioctx_t* ctx);
|
||||
void SetupKernelIOCtx(ioctx_t* ctx);
|
||||
|
||||
void Device::Unref()
|
||||
{
|
||||
bool shoulddelete = false;
|
||||
kthread_mutex_lock(&refcountlock);
|
||||
shoulddelete = --refcount == 0 || refcount == SIZE_MAX;
|
||||
kthread_mutex_unlock(&refcountlock);
|
||||
if ( shoulddelete )
|
||||
delete this;
|
||||
}
|
||||
} // namespace Sortix
|
||||
|
||||
void Device::Refer()
|
||||
{
|
||||
ScopedLock lock(&refcountlock);
|
||||
refcount++;
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -17,45 +17,46 @@
|
|||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
keyboard.h
|
||||
An interface to keyboards.
|
||||
sortix/kernel/keyboard.h
|
||||
Various interfaces for keyboard devices and layouts.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_KEYBOARD_H
|
||||
#define SORTIX_KEYBOARD_H
|
||||
|
||||
namespace Sortix
|
||||
namespace Sortix {
|
||||
|
||||
class Keyboard;
|
||||
class KeyboardOwner;
|
||||
|
||||
class Keyboard
|
||||
{
|
||||
class Keyboard;
|
||||
class KeyboardOwner;
|
||||
public:
|
||||
virtual ~Keyboard() { }
|
||||
virtual int Read() = 0;
|
||||
virtual size_t GetPending() const = 0;
|
||||
virtual bool HasPending() const = 0;
|
||||
virtual void SetOwner(KeyboardOwner* owner, void* user) = 0;
|
||||
|
||||
class Keyboard
|
||||
{
|
||||
public:
|
||||
static void Init();
|
||||
};
|
||||
|
||||
public:
|
||||
virtual ~Keyboard() { }
|
||||
virtual int Read() = 0;
|
||||
virtual size_t GetPending() const = 0;
|
||||
virtual bool HasPending() const = 0;
|
||||
virtual void SetOwner(KeyboardOwner* owner, void* user) = 0;
|
||||
};
|
||||
class KeyboardOwner
|
||||
{
|
||||
public:
|
||||
virtual ~KeyboardOwner() { }
|
||||
virtual void OnKeystroke(Keyboard* keyboard, void* user) = 0;
|
||||
|
||||
class KeyboardOwner
|
||||
{
|
||||
public:
|
||||
virtual ~KeyboardOwner() { }
|
||||
virtual void OnKeystroke(Keyboard* keyboard, void* user) = 0;
|
||||
};
|
||||
};
|
||||
|
||||
class KeyboardLayout
|
||||
{
|
||||
public:
|
||||
virtual ~KeyboardLayout() { }
|
||||
virtual uint32_t Translate(int kbkey) = 0;
|
||||
};
|
||||
}
|
||||
class KeyboardLayout
|
||||
{
|
||||
public:
|
||||
virtual ~KeyboardLayout() { }
|
||||
virtual uint32_t Translate(int kbkey) = 0;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
|
@ -27,8 +27,6 @@
|
|||
|
||||
#include <sortix/signal.h>
|
||||
|
||||
#define GOT_ACTUAL_KTHREAD
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
extern "C" {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -17,44 +17,46 @@
|
|||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
device.h
|
||||
A base class for all devices.
|
||||
sortix/kernel/mtable.h
|
||||
Class to keep track of mount points.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_DEVICE_H
|
||||
#define SORTIX_DEVICE_H
|
||||
#ifndef SORTIX_MTABLE_H
|
||||
#define SORTIX_MTABLE_H
|
||||
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
|
||||
namespace Sortix
|
||||
namespace Sortix {
|
||||
|
||||
class Inode;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
class Device
|
||||
{
|
||||
public:
|
||||
static const unsigned STREAM = 0;
|
||||
static const unsigned BUFFER = 1;
|
||||
static const unsigned VGABUFFER = 2;
|
||||
static const unsigned FILESYSTEM = 3;
|
||||
static const unsigned DIRECTORY = 4;
|
||||
static const unsigned TERMINAL = 5;
|
||||
Ref<Inode> inode;
|
||||
ino_t ino;
|
||||
dev_t dev;
|
||||
} mountpoint_t;
|
||||
|
||||
public:
|
||||
Device();
|
||||
virtual ~Device();
|
||||
class MountTable : public Refcountable
|
||||
{
|
||||
public:
|
||||
MountTable();
|
||||
~MountTable();
|
||||
Ref<MountTable> Fork();
|
||||
bool AddMount(ino_t ino, dev_t dev, Ref<Inode> inode);
|
||||
|
||||
private:
|
||||
kthread_mutex_t refcountlock;
|
||||
size_t refcount;
|
||||
public: // Consider these read-only.
|
||||
kthread_mutex_t mtablelock;
|
||||
mountpoint_t* mounts;
|
||||
size_t nummounts;
|
||||
|
||||
public:
|
||||
void Refer();
|
||||
void Unref();
|
||||
private:
|
||||
size_t mountsalloced;
|
||||
|
||||
public:
|
||||
virtual bool IsType(unsigned type) const = 0;
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -29,21 +29,95 @@
|
|||
|
||||
namespace Sortix {
|
||||
|
||||
class Refcounted
|
||||
class Refcountable
|
||||
{
|
||||
public:
|
||||
Refcounted();
|
||||
~Refcounted();
|
||||
Refcountable();
|
||||
virtual ~Refcountable();
|
||||
|
||||
public:
|
||||
void Refer();
|
||||
void Unref();
|
||||
inline size_t Refcount() const { return refcount; }
|
||||
void Refer_Renamed();
|
||||
void Unref_Renamed();
|
||||
size_t Refcount() const { return refcount; }
|
||||
bool IsUnique() const { return refcount == 1; }
|
||||
|
||||
private:
|
||||
kthread_mutex_t reflock;
|
||||
size_t refcount;
|
||||
|
||||
public:
|
||||
bool being_deleted;
|
||||
|
||||
};
|
||||
|
||||
template <class T> class Ref
|
||||
{
|
||||
public:
|
||||
constexpr Ref() : obj(NULL) { }
|
||||
explicit Ref(T* obj) : obj(obj) { if ( obj ) obj->Refer_Renamed(); }
|
||||
template <class U>
|
||||
explicit Ref(U* obj) : obj(obj) { if ( obj ) obj->Refer_Renamed(); }
|
||||
Ref(const Ref<T>& r) : obj(r.Get()) { if ( obj ) obj->Refer_Renamed(); }
|
||||
template <class U>
|
||||
Ref(const Ref<U>& r) : obj(r.Get()) { if ( obj ) obj->Refer_Renamed(); }
|
||||
~Ref() { if ( obj ) obj->Unref_Renamed(); }
|
||||
|
||||
Ref& operator=(const Ref r)
|
||||
{
|
||||
if ( obj ) { obj->Unref_Renamed(); obj = NULL; }
|
||||
if ( (obj = r.Get()) ) obj->Refer_Renamed();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class U>
|
||||
Ref operator=(const Ref<U> r)
|
||||
{
|
||||
if ( obj ) { obj->Unref_Renamed(); obj = NULL; }
|
||||
if ( (obj = r.Get()) ) obj->Refer_Renamed();
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const Ref& other)
|
||||
{
|
||||
return (*this).Get() == other.Get();
|
||||
}
|
||||
|
||||
template <class U> bool operator==(const Ref<U>& other)
|
||||
{
|
||||
return (*this).Get() == other.Get();
|
||||
}
|
||||
|
||||
template <class U> bool operator==(const U* const& other)
|
||||
{
|
||||
return (*this).Get() == other;
|
||||
}
|
||||
|
||||
bool operator!=(const Ref& other)
|
||||
{
|
||||
return !((*this) == other);
|
||||
}
|
||||
|
||||
template <class U> bool operator!=(const Ref<U>& other)
|
||||
{
|
||||
return !((*this) == other);
|
||||
}
|
||||
|
||||
template <class U> bool operator!=(const U* const& other)
|
||||
{
|
||||
return !((*this) == other);
|
||||
}
|
||||
|
||||
void Reset() { if ( obj ) obj->Unref_Renamed(); obj = NULL; }
|
||||
T* Get() const { return obj; }
|
||||
T& operator *() const { return *obj; }
|
||||
T* operator->() const { return obj; }
|
||||
operator bool() const { return obj != NULL; }
|
||||
size_t Refcount() const { return obj ? obj->Refcount : 0; }
|
||||
bool IsUnique() const { return obj->IsUnique(); }
|
||||
|
||||
private:
|
||||
T* obj;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -72,12 +72,12 @@ public:
|
|||
// the screen resolution or the graphics driver. The backing text buffer can
|
||||
// only be changed when there are no references (but our own) to the text buffer
|
||||
// so don't forget to release it when you are done.
|
||||
class TextBufferHandle : public Refcounted
|
||||
class TextBufferHandle : public Refcountable
|
||||
{
|
||||
public:
|
||||
TextBufferHandle(TextBuffer* textbuf = NULL, bool deletebuf = true,
|
||||
TextBuffer* def = NULL, bool deletedef = true);
|
||||
~TextBufferHandle();
|
||||
virtual ~TextBufferHandle();
|
||||
TextBuffer* Acquire();
|
||||
void Release(TextBuffer* textbuf);
|
||||
void Replace(TextBuffer* newtextbuf, bool deletebuf = true);
|
||||
|
@ -91,7 +91,6 @@ private:
|
|||
bool deletedef;
|
||||
bool deletebuf;
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#ifndef SORTIX_VIDEO_H
|
||||
#define SORTIX_VIDEO_H
|
||||
|
||||
#include <sortix/kernel/refcount.h>
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
class TextBuffer;
|
||||
|
@ -51,7 +53,7 @@ public:
|
|||
|
||||
namespace Video {
|
||||
|
||||
void Init(TextBufferHandle* textbufhandle);
|
||||
void Init(Ref<TextBufferHandle> textbufhandle);
|
||||
bool RegisterDriver(const char* name, VideoDriver* driver);
|
||||
char* GetCurrentMode();
|
||||
char* GetDriverName(size_t index);
|
||||
|
|
88
sortix/include/sortix/kernel/vnode.h
Normal file
88
sortix/include/sortix/kernel/vnode.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
|
||||
|
||||
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/>.
|
||||
|
||||
sortix/kernel/vnode.h
|
||||
Nodes in the virtual filesystem.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_VNODE_H
|
||||
#define SORTIX_VNODE_H
|
||||
|
||||
#include <sortix/kernel/refcount.h>
|
||||
|
||||
struct stat;
|
||||
struct timeval;
|
||||
struct winsize;
|
||||
struct kernel_dirent;
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
class Inode;
|
||||
struct ioctx_struct;
|
||||
typedef struct ioctx_struct ioctx_t;
|
||||
|
||||
// An interface describing all operations possible on an vnode.
|
||||
class Vnode : public Refcountable
|
||||
{
|
||||
public: /* These must never change after construction and is read-only. */
|
||||
ino_t ino;
|
||||
dev_t dev;
|
||||
mode_t type; // For use by S_IS* macros.
|
||||
|
||||
public:
|
||||
Vnode(Ref<Inode> inode, Ref<Vnode> mountedat, ino_t rootino, dev_t rootdev);
|
||||
virtual ~Vnode();
|
||||
int sync(ioctx_t* ctx);
|
||||
int stat(ioctx_t* ctx, struct stat* st);
|
||||
int chmod(ioctx_t* ctx, mode_t mode);
|
||||
int chown(ioctx_t* ctx, uid_t owner, gid_t group);
|
||||
int truncate(ioctx_t* ctx, off_t length);
|
||||
off_t lseek(ioctx_t* ctx, off_t offset, int whence);
|
||||
ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
||||
ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off);
|
||||
ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
||||
ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t off);
|
||||
int utimes(ioctx_t* ctx, const struct timeval times[2]);
|
||||
int isatty(ioctx_t* ctx);
|
||||
ssize_t readdirents(ioctx_t* ctx, struct kernel_dirent* dirent,
|
||||
size_t size, off_t start, size_t maxcount);
|
||||
Ref<Vnode> open(ioctx_t* ctx, const char* filename, int flags, mode_t mode);
|
||||
int mkdir(ioctx_t* ctx, const char* filename, mode_t mode);
|
||||
int unlink(ioctx_t* ctx, const char* filename);
|
||||
int rmdir(ioctx_t* ctx, const char* filename);
|
||||
int link(ioctx_t* ctx, const char* filename, Ref<Vnode> node);
|
||||
int symlink(ioctx_t* ctx, const char* oldname, const char* filename);
|
||||
ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz);
|
||||
int fsbind(ioctx_t* ctx, Vnode* node, int flags);
|
||||
int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
|
||||
int settermmode(ioctx_t* ctx, unsigned mode);
|
||||
int gettermmode(ioctx_t* ctx, unsigned* mode);
|
||||
|
||||
private:
|
||||
Ref<Inode> inode;
|
||||
Ref<Vnode> mountedat;
|
||||
ino_t rootino;
|
||||
dev_t rootdev;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -17,24 +17,23 @@
|
|||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
mount.h
|
||||
Handles system wide mount points and initialization of new file systems.
|
||||
sortix/mount.h
|
||||
Constants related to mounting and binding.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_MOUNT_H
|
||||
#define SORTIX_MOUNT_H
|
||||
#ifndef SORTIX_INCLUDE_MOUNT_H
|
||||
#define SORTIX_INCLUDE_MOUNT_H
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
class DevFileSystem;
|
||||
#include <features.h>
|
||||
|
||||
namespace Mount
|
||||
{
|
||||
void Init();
|
||||
DevFileSystem* WhichFileSystem(const char* path, size_t* pathoffset);
|
||||
bool Register(DevFileSystem* fs, const char* path);
|
||||
}
|
||||
}
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define MREPL (0<<0) /* Replace binding. */
|
||||
#define MBEFORE (1<<0) /* Add to start of directory union. */
|
||||
#define MAFTER (2<<0) /* Add to end of directory union. */
|
||||
#define MCREATE (1<<2) /* Create files here, otherwise try next in union. */
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
|
@ -27,6 +27,7 @@
|
|||
#define SORTIX_STAT_H
|
||||
|
||||
#include <features.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
|
@ -71,6 +72,7 @@ struct stat
|
|||
/*#define S_ISUID 0x0800 */
|
||||
/*#define S_ISGID 0x0400 */
|
||||
#define S_ISVTX 0x0200
|
||||
#define S_SETABLE (0777 | 0x0200 | 0x0400 | 0x0800)
|
||||
#define S_ISSOCK(mode) ((mode & S_IFMT) == S_IFSOCK)
|
||||
#define S_ISLNK(mode) ((mode & S_IFMT) == S_IFLNK)
|
||||
#define S_ISREG(mode) ((mode & S_IFMT) == S_IFREG)
|
||||
|
|
|
@ -49,7 +49,6 @@
|
|||
#define SYSCALL_OPEN 23
|
||||
#define SYSCALL_READDIRENTS 24
|
||||
#define SYSCALL_CHDIR 25
|
||||
#define SYSCALL_GETCWD 26
|
||||
#define SYSCALL_UNLINK 27
|
||||
#define SYSCALL_REGISTER_ERRNO 28
|
||||
#define SYSCALL_REGISTER_SIGNAL_HANDLER 29
|
||||
|
@ -78,6 +77,7 @@
|
|||
#define SYSCALL_RAISE 53
|
||||
#define SYSCALL_OPENAT 54
|
||||
#define SYSCALL_DISPMSG_ISSUE 55
|
||||
#define SYSCALL_MAX_NUM 56 /* index of highest constant + 1 */
|
||||
#define SYSCALL_FSTATAT 56
|
||||
#define SYSCALL_MAX_NUM 57 /* index of highest constant + 1 */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -23,12 +23,18 @@
|
|||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/vnode.h>
|
||||
#include <sortix/kernel/descriptor.h>
|
||||
#include <sortix/kernel/memorymanagement.h>
|
||||
#include <sortix/kernel/crc32.h>
|
||||
#include <sortix/kernel/string.h>
|
||||
#include <sortix/kernel/ioctx.h>
|
||||
#include <sortix/kernel/fsfunc.h>
|
||||
#include <sortix/fcntl.h>
|
||||
#include <sortix/initrd.h>
|
||||
#include <sortix/stat.h>
|
||||
#include <sortix/mman.h>
|
||||
#include <sortix/initrd.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "initrd.h"
|
||||
|
@ -37,7 +43,7 @@
|
|||
namespace Sortix {
|
||||
namespace InitRD {
|
||||
|
||||
uint8_t* initrd;
|
||||
uint8_t* initrd = NULL;
|
||||
size_t initrdsize;
|
||||
const initrd_superblock_t* sb;
|
||||
|
||||
|
@ -129,7 +135,6 @@ uint32_t Traverse(uint32_t ino, const char* name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const char* GetFilename(uint32_t dir, size_t index)
|
||||
{
|
||||
const initrd_inode_t* inode = GetInode(dir);
|
||||
|
@ -195,6 +200,7 @@ void CheckSum()
|
|||
|
||||
void Init(addr_t phys, size_t size)
|
||||
{
|
||||
assert(!initrd);
|
||||
// First up, map the initrd onto the kernel's address space.
|
||||
addr_t virt = Memory::GetInitRD();
|
||||
size_t amount = 0;
|
||||
|
@ -243,5 +249,96 @@ void Init(addr_t phys, size_t size)
|
|||
CheckSum();
|
||||
}
|
||||
|
||||
static bool ExtractDir(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> node);
|
||||
static bool ExtractFile(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> file);
|
||||
static bool ExtractNode(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> node);
|
||||
|
||||
static bool ExtractDir(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> dir)
|
||||
{
|
||||
size_t numfiles = GetNumFiles(ino);
|
||||
for ( size_t i = 0; i < numfiles; i++ )
|
||||
{
|
||||
const char* name = GetFilename(ino, i);
|
||||
if ( !name )
|
||||
return false;
|
||||
if ( IsDotOrDotDot(name) )
|
||||
continue;
|
||||
uint32_t childino = Traverse(ino, name);
|
||||
if ( !childino )
|
||||
return false;
|
||||
const initrd_inode_t* child = GetInode(childino);
|
||||
mode_t mode = InitRDModeToHost(child->mode);
|
||||
if ( INITRD_S_ISDIR(child->mode) )
|
||||
{
|
||||
if ( dir->mkdir(ctx, name, mode) && errno != EEXIST )
|
||||
return false;
|
||||
Ref<Descriptor> desc = dir->open(ctx, name, O_RDWR | O_DIRECTORY, 0);
|
||||
if ( !desc )
|
||||
return false;
|
||||
if ( !ExtractNode(ctx, childino, desc) )
|
||||
return false;
|
||||
}
|
||||
if ( INITRD_S_ISREG(child->mode) )
|
||||
{
|
||||
Ref<Descriptor> desc = dir->open(ctx, name, O_WRONLY | O_CREAT, mode);
|
||||
if ( !desc )
|
||||
return false;
|
||||
if ( !ExtractNode(ctx, childino, desc) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ExtractFile(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> file)
|
||||
{
|
||||
size_t filesize;
|
||||
const uint8_t* data = Open(ino, &filesize);
|
||||
if ( !data )
|
||||
return false;
|
||||
if ( file->truncate(ctx, filesize) != 0 )
|
||||
return false;
|
||||
size_t sofar = 0;
|
||||
while ( sofar < filesize )
|
||||
{
|
||||
ssize_t numbytes = file->write(ctx, data + sofar, filesize - sofar);
|
||||
if ( numbytes <= 0 )
|
||||
return false;
|
||||
sofar += numbytes;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ExtractNode(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> node)
|
||||
{
|
||||
const initrd_inode_t* inode = GetInode(ino);
|
||||
if ( !inode )
|
||||
return false;
|
||||
if ( node->chmod(ctx, InitRDModeToHost(inode->mode)) < 0 )
|
||||
return false;
|
||||
if ( node->chown(ctx, inode->uid, inode->gid) < 0 )
|
||||
return false;
|
||||
// TODO: utimes.
|
||||
if ( INITRD_S_ISDIR(inode->mode) )
|
||||
if ( !ExtractDir(ctx, ino, node) )
|
||||
return false;
|
||||
if ( INITRD_S_ISREG(inode->mode) )
|
||||
if ( !ExtractFile(ctx, ino, node) )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExtractInto(Ref<Descriptor> desc)
|
||||
{
|
||||
ioctx_t ctx; SetupKernelIOCtx(&ctx);
|
||||
return ExtractNode(&ctx, sb->root, desc);
|
||||
}
|
||||
|
||||
bool ExtractFromPhysicalInto(addr_t physaddr, size_t size, Ref<Descriptor> desc)
|
||||
{
|
||||
Init(physaddr, size);
|
||||
return ExtractInto(desc);
|
||||
}
|
||||
|
||||
} // namespace InitRD
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -22,21 +22,22 @@
|
|||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_INITRD_KERNEL_H
|
||||
#define SORTIX_INITRD_KERNEL_H
|
||||
#ifndef SORTIX_INITRD_H
|
||||
#define SORTIX_INITRD_H
|
||||
|
||||
#include <sortix/kernel/refcount.h>
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
class Descriptor;
|
||||
|
||||
namespace InitRD {
|
||||
|
||||
void Init(addr_t phys, size_t size);
|
||||
uint32_t Root();
|
||||
bool Stat(uint32_t inode, struct stat* st);
|
||||
uint8_t* Open(uint32_t inode, size_t* size);
|
||||
uint32_t Traverse(uint32_t inode, const char* name);
|
||||
const char* GetFilename(uint32_t dir, size_t index);
|
||||
size_t GetNumFiles(uint32_t dir);
|
||||
bool ExtractInto(Ref<Descriptor> desc);
|
||||
bool ExtractFromPhysicalInto(addr_t physaddr, size_t size, Ref<Descriptor> desc);
|
||||
|
||||
} // namespace InitRD
|
||||
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
||||
|
|
270
sortix/inode.cpp
Normal file
270
sortix/inode.cpp
Normal file
|
@ -0,0 +1,270 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
|
||||
|
||||
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/>.
|
||||
|
||||
inode.cpp
|
||||
Interfaces and utility classes for implementing inodes.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sortix/stat.h>
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/interlock.h>
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
#include <sortix/kernel/inode.h>
|
||||
#include <sortix/kernel/ioctx.h>
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
AbstractInode::AbstractInode()
|
||||
{
|
||||
metalock = KTHREAD_MUTEX_INITIALIZER;
|
||||
inode_type = INODE_TYPE_UNKNOWN;
|
||||
stat_mode = 0;
|
||||
stat_nlink = 0;
|
||||
stat_uid = 0;
|
||||
stat_gid = 0;
|
||||
stat_size = 0;
|
||||
stat_atime = 0;
|
||||
stat_mtime = 0;
|
||||
stat_ctime = 0;
|
||||
/* TODO: stat_atim, stat_mtim, stat_ctim */
|
||||
stat_blksize = 0;
|
||||
stat_blocks = 0;
|
||||
}
|
||||
|
||||
AbstractInode::~AbstractInode()
|
||||
{
|
||||
}
|
||||
|
||||
void AbstractInode::linked()
|
||||
{
|
||||
InterlockedIncrement(&stat_nlink);
|
||||
}
|
||||
|
||||
void AbstractInode::unlinked()
|
||||
{
|
||||
InterlockedDecrement(&stat_nlink);
|
||||
}
|
||||
|
||||
int AbstractInode::sync(ioctx_t* /*ctx*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AbstractInode::stat(ioctx_t* ctx, struct stat* st)
|
||||
{
|
||||
struct stat retst;
|
||||
ScopedLock lock(&metalock);
|
||||
memset(&retst, 0, sizeof(retst));
|
||||
retst.st_dev = dev;
|
||||
retst.st_ino = ino;
|
||||
retst.st_mode = stat_mode;
|
||||
retst.st_nlink = (nlink_t) stat_nlink;
|
||||
retst.st_uid = stat_uid;
|
||||
retst.st_gid = stat_gid;
|
||||
retst.st_size = stat_size;
|
||||
// TODO: Keep track of time.
|
||||
retst.st_blksize = stat_blksize;
|
||||
retst.st_blocks = stat_size / 512;
|
||||
if ( !ctx->copy_to_dest(st, &retst, sizeof(retst)) )
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AbstractInode::chmod(ioctx_t* /*ctx*/, mode_t mode)
|
||||
{
|
||||
ScopedLock lock(&metalock);
|
||||
stat_mode = (mode & S_SETABLE) | this->type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AbstractInode::chown(ioctx_t* /*ctx*/, uid_t owner, gid_t group)
|
||||
{
|
||||
ScopedLock lock(&metalock);
|
||||
stat_uid = owner;
|
||||
stat_gid= group;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AbstractInode::truncate(ioctx_t* /*ctx*/, off_t /*length*/)
|
||||
{
|
||||
if ( inode_type == INODE_TYPE_DIR )
|
||||
return errno = EISDIR, -1;
|
||||
return errno = EINVAL, -1;
|
||||
}
|
||||
|
||||
off_t AbstractInode::lseek(ioctx_t* /*ctx*/, off_t /*offset*/, int /*whence*/)
|
||||
{
|
||||
if ( inode_type == INODE_TYPE_STREAM || inode_type == INODE_TYPE_TTY )
|
||||
return errno = ESPIPE, -1;
|
||||
return errno = EBADF, -1;
|
||||
}
|
||||
|
||||
ssize_t AbstractInode::read(ioctx_t* /*ctx*/, uint8_t* /*buf*/,
|
||||
size_t /*count*/)
|
||||
{
|
||||
return errno = EBADF, -1;
|
||||
}
|
||||
|
||||
ssize_t AbstractInode::pread(ioctx_t* /*ctx*/, uint8_t* /*buf*/,
|
||||
size_t /*count*/, off_t /*off*/)
|
||||
{
|
||||
if ( inode_type == INODE_TYPE_STREAM || inode_type == INODE_TYPE_TTY )
|
||||
return errno = ESPIPE, -1;
|
||||
return errno = EBADF, -1;
|
||||
}
|
||||
|
||||
ssize_t AbstractInode::write(ioctx_t* /*ctx*/, const uint8_t* /*buf*/,
|
||||
size_t /*count*/)
|
||||
{
|
||||
return errno = EBADF, -1;
|
||||
}
|
||||
|
||||
ssize_t AbstractInode::pwrite(ioctx_t* /*ctx*/, const uint8_t* /*buf*/,
|
||||
size_t /*count*/, off_t /*off*/)
|
||||
{
|
||||
if ( inode_type == INODE_TYPE_STREAM || inode_type == INODE_TYPE_TTY )
|
||||
return errno = ESPIPE, -1;
|
||||
return errno = EBADF, -1;
|
||||
}
|
||||
|
||||
int AbstractInode::utimes(ioctx_t* /*ctx*/, const struct timeval /*times*/[2])
|
||||
{
|
||||
// TODO: Implement this!
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AbstractInode::isatty(ioctx_t* /*ctx*/)
|
||||
{
|
||||
if ( inode_type == INODE_TYPE_TTY )
|
||||
return 1;
|
||||
return errno = ENOTTY, 0;
|
||||
}
|
||||
|
||||
ssize_t AbstractInode::readdirents(ioctx_t* /*ctx*/,
|
||||
struct kernel_dirent* /*dirent*/,
|
||||
size_t /*size*/, off_t /*start*/,
|
||||
size_t /*maxcount*/)
|
||||
{
|
||||
if ( inode_type == INODE_TYPE_DIR )
|
||||
return errno = EBADF, -1;
|
||||
return errno = ENOTDIR, -1;
|
||||
}
|
||||
|
||||
Ref<Inode> AbstractInode::open(ioctx_t* /*ctx*/, const char* /*filename*/,
|
||||
int /*flags*/, mode_t /*mode*/)
|
||||
{
|
||||
if ( inode_type == INODE_TYPE_DIR )
|
||||
return errno = EBADF, Ref<Inode>(NULL);
|
||||
return errno = ENOTDIR, Ref<Inode>(NULL);
|
||||
}
|
||||
|
||||
int AbstractInode::mkdir(ioctx_t* /*ctx*/, const char* /*filename*/,
|
||||
mode_t /*mode*/)
|
||||
{
|
||||
if ( inode_type == INODE_TYPE_DIR )
|
||||
return errno = EBADF, -1;
|
||||
return errno = ENOTDIR, -1;
|
||||
}
|
||||
|
||||
int AbstractInode::link(ioctx_t* /*ctx*/, const char* /*filename*/,
|
||||
Ref<Inode> /*node*/)
|
||||
{
|
||||
if ( inode_type == INODE_TYPE_DIR )
|
||||
return errno = EBADF, -1;
|
||||
return errno = ENOTDIR, -1;
|
||||
}
|
||||
|
||||
int AbstractInode::link_raw(ioctx_t* /*ctx*/, const char* /*filename*/,
|
||||
Ref<Inode> /*node*/)
|
||||
{
|
||||
if ( inode_type == INODE_TYPE_DIR )
|
||||
return errno = EBADF, -1;
|
||||
return errno = ENOTDIR, -1;
|
||||
}
|
||||
|
||||
int AbstractInode::unlink(ioctx_t* /*ctx*/, const char* /*filename*/)
|
||||
{
|
||||
if ( inode_type == INODE_TYPE_DIR )
|
||||
return errno = EBADF, -1;
|
||||
return errno = ENOTDIR, -1;
|
||||
}
|
||||
|
||||
int AbstractInode::unlink_raw(ioctx_t* /*ctx*/, const char* /*filename*/)
|
||||
{
|
||||
if ( inode_type == INODE_TYPE_DIR )
|
||||
return errno = EBADF, -1;
|
||||
return errno = ENOTDIR, -1;
|
||||
}
|
||||
|
||||
int AbstractInode::rmdir(ioctx_t* /*ctx*/, const char* /*filename*/)
|
||||
{
|
||||
if ( inode_type == INODE_TYPE_DIR )
|
||||
return errno = EBADF, -1;
|
||||
return errno = ENOTDIR, -1;
|
||||
}
|
||||
|
||||
int AbstractInode::rmdir_me(ioctx_t* /*ctx*/)
|
||||
{
|
||||
if ( inode_type == INODE_TYPE_DIR )
|
||||
return errno = EBADF, -1;
|
||||
return errno = ENOTDIR, -1;
|
||||
}
|
||||
|
||||
int AbstractInode::symlink(ioctx_t* /*ctx*/, const char* /*oldname*/,
|
||||
const char* /*filename*/)
|
||||
{
|
||||
if ( inode_type == INODE_TYPE_DIR )
|
||||
return errno = EBADF, -1;
|
||||
return errno = ENOTDIR, -1;
|
||||
}
|
||||
|
||||
ssize_t AbstractInode::readlink(ioctx_t* /*ctx*/, char* /*buf*/,
|
||||
size_t /*bufsiz*/)
|
||||
{
|
||||
return errno = EINVAL, -1;
|
||||
}
|
||||
|
||||
int AbstractInode::tcgetwinsize(ioctx_t* /*ctx*/, struct winsize* /*ws*/)
|
||||
{
|
||||
if ( inode_type == INODE_TYPE_TTY )
|
||||
return errno = EBADF, -1;
|
||||
return errno = ENOTTY, -1;
|
||||
}
|
||||
|
||||
int AbstractInode::settermmode(ioctx_t* /*ctx*/, unsigned /*mode*/)
|
||||
{
|
||||
if ( inode_type == INODE_TYPE_TTY )
|
||||
return errno = EBADF, -1;
|
||||
return errno = ENOTTY, -1;
|
||||
}
|
||||
|
||||
int AbstractInode::gettermmode(ioctx_t* /*ctx*/, unsigned* /*mode*/)
|
||||
{
|
||||
if ( inode_type == INODE_TYPE_TTY )
|
||||
return errno = EBADF, -1;
|
||||
return errno = ENOTTY, -1;
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
516
sortix/io.cpp
516
sortix/io.cpp
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -23,178 +23,364 @@
|
|||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
#include <sortix/kernel/ioctx.h>
|
||||
#include <sortix/kernel/copy.h>
|
||||
#include <sortix/kernel/descriptor.h>
|
||||
#include <sortix/kernel/dtable.h>
|
||||
#include <sortix/kernel/string.h>
|
||||
#include <sortix/kernel/kthread.h>
|
||||
|
||||
#include <sortix/seek.h>
|
||||
#include <sortix/dirent.h>
|
||||
#include <sortix/fcntl.h>
|
||||
#include <sortix/stat.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include "thread.h"
|
||||
#include "process.h"
|
||||
#include "device.h"
|
||||
#include "stream.h"
|
||||
#include "syscall.h"
|
||||
#include "io.h"
|
||||
|
||||
namespace Sortix
|
||||
namespace Sortix {
|
||||
namespace IO {
|
||||
|
||||
static Ref<Descriptor> PrepareLookup(const char** path, int dirfd = AT_FDCWD)
|
||||
{
|
||||
namespace IO
|
||||
{
|
||||
#ifdef GOT_FAKE_KTHREAD
|
||||
struct SysWrite_t
|
||||
{
|
||||
union { size_t align1; int fd; };
|
||||
union { size_t align2; const uint8_t* buffer; };
|
||||
union { size_t align3; size_t count; };
|
||||
};
|
||||
|
||||
STATIC_ASSERT(sizeof(SysWrite_t) <= sizeof(Thread::scstate));
|
||||
#endif
|
||||
|
||||
ssize_t SysWrite(int fd, const uint8_t* buffer, size_t count)
|
||||
{
|
||||
// TODO: Check that buffer is a valid user-space buffer.
|
||||
if ( SSIZE_MAX < count ) { count = SSIZE_MAX; }
|
||||
Process* process = CurrentProcess();
|
||||
Device* dev = process->descriptors.Get(fd);
|
||||
if ( !dev ) { errno = EBADF; return -1; }
|
||||
if ( !dev->IsType(Device::STREAM) ) { errno = EBADF; return -1; }
|
||||
DevStream* stream = (DevStream*) dev;
|
||||
if ( !stream->IsWritable() ) { errno = EBADF; return -1; }
|
||||
#ifdef GOT_FAKE_KTHREAD
|
||||
ssize_t written = stream->Write(buffer, count);
|
||||
if ( 0 <= written ) { return written; }
|
||||
if ( errno != EBLOCKING ) { return -1; }
|
||||
|
||||
// The stream will resume our system call once progress has been
|
||||
// made. Our request is certainly not forgotten.
|
||||
|
||||
// Resume the system call with these parameters.
|
||||
Thread* thread = CurrentThread();
|
||||
thread->scfunc = (void*) SysWrite;
|
||||
SysWrite_t* state = (SysWrite_t*) thread->scstate;
|
||||
state->fd = fd;
|
||||
state->buffer = buffer;
|
||||
state->count = count;
|
||||
thread->scsize = sizeof(SysWrite_t);
|
||||
|
||||
// Now go do something else.
|
||||
Syscall::Incomplete();
|
||||
return 0;
|
||||
#else
|
||||
return stream->Write(buffer, count);
|
||||
#endif
|
||||
}
|
||||
|
||||
// TODO: Not implemented yet due to stupid internal kernel design.
|
||||
ssize_t SysPWrite(int fd, const uint8_t* buffer, size_t count, off_t off)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef GOT_FAKE_KTHREAD
|
||||
struct SysRead_t
|
||||
{
|
||||
union { size_t align1; int fd; };
|
||||
union { size_t align2; uint8_t* buffer; };
|
||||
union { size_t align3; size_t count; };
|
||||
};
|
||||
|
||||
STATIC_ASSERT(sizeof(SysRead_t) <= sizeof(Thread::scstate));
|
||||
#endif
|
||||
|
||||
ssize_t SysRead(int fd, uint8_t* buffer, size_t count)
|
||||
{
|
||||
// TODO: Check that buffer is a valid user-space buffer.
|
||||
if ( SSIZE_MAX < count ) { count = SSIZE_MAX; }
|
||||
Process* process = CurrentProcess();
|
||||
Device* dev = process->descriptors.Get(fd);
|
||||
if ( !dev ) { errno = EBADF; return -1; }
|
||||
if ( !dev->IsType(Device::STREAM) ) { errno = EBADF; return -1; }
|
||||
DevStream* stream = (DevStream*) dev;
|
||||
if ( !stream->IsReadable() ) { errno = EBADF; return -1;}
|
||||
#ifdef GOT_FAKE_KTHREAD
|
||||
ssize_t bytesread = stream->Read(buffer, count);
|
||||
if ( 0 <= bytesread ) { return bytesread; }
|
||||
if ( errno != EBLOCKING ) { return -1; }
|
||||
|
||||
// The stream will resume our system call once progress has been
|
||||
// made. Our request is certainly not forgotten.
|
||||
|
||||
// Resume the system call with these parameters.
|
||||
Thread* thread = CurrentThread();
|
||||
thread->scfunc = (void*) SysRead;
|
||||
SysRead_t* state = (SysRead_t*) thread->scstate;
|
||||
state->fd = fd;
|
||||
state->buffer = buffer;
|
||||
state->count = count;
|
||||
thread->scsize = sizeof(SysRead_t);
|
||||
|
||||
// Now go do something else.
|
||||
Syscall::Incomplete();
|
||||
return 0;
|
||||
#else
|
||||
return stream->Read(buffer, count);
|
||||
#endif
|
||||
}
|
||||
|
||||
// TODO: Not implemented yet due to stupid internal kernel design.
|
||||
ssize_t SysPRead(int fd, uint8_t* buffer, size_t count, off_t off)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int SysSeek(int fd, off_t* offset, int whence)
|
||||
{
|
||||
// TODO: Validate that offset is a legal user-space off_t!
|
||||
Process* process = CurrentProcess();
|
||||
Device* dev = process->descriptors.Get(fd);
|
||||
if ( !dev ) { errno = EBADF; *offset = -1; return -1; }
|
||||
if ( !dev->IsType(Device::BUFFER) ) { errno = EBADF; *offset = -1; return -1; }
|
||||
DevBuffer* buffer = (DevBuffer*) dev;
|
||||
off_t origin;
|
||||
switch ( whence )
|
||||
{
|
||||
case SEEK_SET: origin = 0; break;
|
||||
case SEEK_CUR: origin = buffer->Position(); break;
|
||||
case SEEK_END: origin = buffer->Size(); break;
|
||||
default: errno = EINVAL; *offset = -1; return -1;
|
||||
}
|
||||
off_t newposition = origin + *offset;
|
||||
if ( newposition < 0 ) { errno = EINVAL; *offset = -1; return -1; }
|
||||
if ( !buffer->Seek(newposition) ) { *offset = -1; return -1; }
|
||||
*offset = buffer->Position();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SysClose(int fd)
|
||||
{
|
||||
Process* process = CurrentProcess();
|
||||
Device* dev = process->descriptors.Get(fd);
|
||||
if ( !dev ) { errno = EBADF; return -1; }
|
||||
process->descriptors.Free(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SysDup(int fd)
|
||||
{
|
||||
Process* process = CurrentProcess();
|
||||
Device* dev = process->descriptors.Get(fd);
|
||||
if ( !dev ) { errno = EBADF; return -1; }
|
||||
const char* path = process->descriptors.GetPath(fd);
|
||||
char* pathcopy = path ? String::Clone(path) : NULL;
|
||||
return process->descriptors.Allocate(dev, pathcopy);
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
Syscall::Register(SYSCALL_WRITE, (void*) SysWrite);
|
||||
Syscall::Register(SYSCALL_PWRITE, (void*) SysPWrite);
|
||||
Syscall::Register(SYSCALL_READ, (void*) SysRead);
|
||||
Syscall::Register(SYSCALL_PREAD, (void*) SysPRead);
|
||||
Syscall::Register(SYSCALL_CLOSE, (void*) SysClose);
|
||||
Syscall::Register(SYSCALL_DUP, (void*) SysDup);
|
||||
Syscall::Register(SYSCALL_SEEK, (void*) SysSeek);
|
||||
}
|
||||
}
|
||||
if ( (*path)[0] == '/' )
|
||||
return CurrentProcess()->GetRoot();
|
||||
if ( dirfd == AT_FDCWD )
|
||||
return CurrentProcess()->GetCWD();
|
||||
return CurrentProcess()->GetDescriptor(dirfd);
|
||||
}
|
||||
|
||||
static ssize_t sys_write(int fd, const void* buffer, size_t count)
|
||||
{
|
||||
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
||||
if ( !desc )
|
||||
return -1;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
ssize_t ret = desc->write(&ctx, (const uint8_t*) buffer, count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t sys_pwrite(int fd, const void* buffer, size_t count, off_t off)
|
||||
{
|
||||
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
||||
if ( !desc )
|
||||
return -1;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
ssize_t ret = desc->pwrite(&ctx, (const uint8_t*) buffer, count, off);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t sys_read(int fd, void* buffer, size_t count)
|
||||
{
|
||||
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
||||
if ( !desc )
|
||||
return -1;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
ssize_t ret = desc->read(&ctx, (uint8_t*) buffer, count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t sys_pread(int fd, void* buffer, size_t count, off_t off)
|
||||
{
|
||||
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
||||
if ( !desc )
|
||||
return -1;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
ssize_t ret = desc->pread(&ctx, (uint8_t*) buffer, count, off);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static off_t sys_seek(int fd, off_t offset, int whence)
|
||||
{
|
||||
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
||||
if ( !desc )
|
||||
return -1;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
off_t ret = desc->lseek(&ctx, offset, whence);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sys_close(int fd)
|
||||
{
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
Ref<DescriptorTable> dtable = CurrentProcess()->GetDTable();
|
||||
Ref<Descriptor> desc = dtable->FreeKeep(fd);
|
||||
dtable.Reset();
|
||||
if ( !desc )
|
||||
return -1;
|
||||
return desc->sync(&ctx);
|
||||
}
|
||||
|
||||
static int sys_dup(int fd)
|
||||
{
|
||||
Ref<DescriptorTable> dtable = CurrentProcess()->GetDTable();
|
||||
Ref<Descriptor> desc = dtable->Get(fd);
|
||||
return dtable->Allocate(desc, 0);
|
||||
}
|
||||
|
||||
// TODO: If this function fails the file may still have been created. Does a
|
||||
// standard prohibit this and is that the wrong thing?
|
||||
static int sys_openat(int dirfd, const char* path, int flags, mode_t mode)
|
||||
{
|
||||
char* pathcopy = GetStringFromUser(path);
|
||||
if ( !pathcopy )
|
||||
return -1;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
int fdflags = 0;
|
||||
if ( flags & O_CLOEXEC ) fdflags |= FD_CLOEXEC;
|
||||
if ( flags & O_CLOFORK ) fdflags |= FD_CLOFORK;
|
||||
flags &= ~(O_CLOEXEC | O_CLOFORK);
|
||||
const char* relpath = pathcopy;
|
||||
Ref<Descriptor> from = PrepareLookup(&relpath, dirfd);
|
||||
if ( !from ) { delete[] pathcopy; return -1; }
|
||||
Ref<Descriptor> desc = from->open(&ctx, relpath, flags, mode);
|
||||
from.Reset();
|
||||
delete[] pathcopy;
|
||||
if ( !desc )
|
||||
return -1;
|
||||
Ref<DescriptorTable> dtable = CurrentProcess()->GetDTable();
|
||||
return dtable->Allocate(desc, fdflags);
|
||||
}
|
||||
|
||||
static int sys_open(const char* path, int flags, mode_t mode)
|
||||
{
|
||||
return sys_openat(AT_FDCWD, path, flags, mode);
|
||||
}
|
||||
|
||||
// TODO: This is a hack! Stat the file in some manner and check permissions.
|
||||
static int sys_access(const char* path, int /*mode*/)
|
||||
{
|
||||
char* pathcopy = GetStringFromUser(path);
|
||||
if ( !pathcopy )
|
||||
return -1;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
const char* relpath = pathcopy;
|
||||
Ref<Descriptor> from = PrepareLookup(&relpath);
|
||||
Ref<Descriptor> desc = from->open(&ctx, relpath, O_RDONLY);
|
||||
delete[] pathcopy;
|
||||
return desc ? 0 : -1;
|
||||
}
|
||||
|
||||
static int sys_unlink(const char* path)
|
||||
{
|
||||
char* pathcopy = GetStringFromUser(path);
|
||||
if ( !pathcopy )
|
||||
return -1;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
const char* relpath = pathcopy;
|
||||
Ref<Descriptor> from = PrepareLookup(&relpath);
|
||||
int ret = from->unlink(&ctx, relpath);
|
||||
delete[] pathcopy;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// TODO: unlinkat
|
||||
|
||||
static int sys_mkdir(const char* path, mode_t mode)
|
||||
{
|
||||
char* pathcopy = GetStringFromUser(path);
|
||||
if ( !pathcopy )
|
||||
return -1;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
const char* relpath = pathcopy;
|
||||
Ref<Descriptor> from = PrepareLookup(&relpath);
|
||||
int ret = from->mkdir(&ctx, relpath, mode);
|
||||
delete[] pathcopy;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// TODO: mkdirat
|
||||
|
||||
static int sys_rmdir(const char* path)
|
||||
{
|
||||
char* pathcopy = GetStringFromUser(path);
|
||||
if ( !pathcopy )
|
||||
return -1;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
const char* relpath = pathcopy;
|
||||
Ref<Descriptor> from = PrepareLookup(&relpath);
|
||||
int ret = from->rmdir(&ctx, relpath);
|
||||
delete[] pathcopy;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// TODO: unlinkat(AT_REMOVEDIR)
|
||||
|
||||
static int sys_truncate(const char* path, off_t length)
|
||||
{
|
||||
char* pathcopy = GetStringFromUser(path);
|
||||
if ( !pathcopy )
|
||||
return -1;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
const char* relpath = pathcopy;
|
||||
Ref<Descriptor> from = PrepareLookup(&relpath);
|
||||
Ref<Descriptor> desc = from->open(&ctx, relpath, O_WRONLY);
|
||||
delete[] pathcopy;
|
||||
if ( !desc )
|
||||
return -1;
|
||||
return desc->truncate(&ctx, length);
|
||||
}
|
||||
|
||||
static int sys_ftruncate(int fd, off_t length)
|
||||
{
|
||||
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
||||
if ( !desc )
|
||||
return -1;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
return desc->truncate(&ctx, length);
|
||||
}
|
||||
|
||||
static int sys_fstatat(int dirfd, const char* path, struct stat* st, int /*flags*/)
|
||||
{
|
||||
char* pathcopy = GetStringFromUser(path);
|
||||
if ( !pathcopy )
|
||||
return -1;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
const char* relpath = pathcopy;
|
||||
Ref<Descriptor> from = PrepareLookup(&relpath, dirfd);
|
||||
if ( !from ) { delete[] pathcopy; return -1; }
|
||||
Ref<Descriptor> desc = from->open(&ctx, relpath, O_RDONLY);
|
||||
delete[] pathcopy;
|
||||
if ( !desc )
|
||||
return -1;
|
||||
return desc->stat(&ctx, st);
|
||||
}
|
||||
|
||||
static int sys_stat(const char* path, struct stat* st)
|
||||
{
|
||||
return sys_fstatat(AT_FDCWD, path, st, 0);
|
||||
}
|
||||
|
||||
static int sys_fstat(int fd, struct stat* st)
|
||||
{
|
||||
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
||||
if ( !desc )
|
||||
return -1;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
return desc->stat(&ctx, st);
|
||||
}
|
||||
|
||||
static int sys_fcntl(int fd, int cmd, unsigned long arg)
|
||||
{
|
||||
Ref<DescriptorTable> dtable = CurrentProcess()->GetDTable();
|
||||
int ret = -1;
|
||||
switch ( cmd )
|
||||
{
|
||||
case F_SETFD:
|
||||
ret = dtable->SetFlags(fd, (int) arg) ? 0 : -1;
|
||||
break;
|
||||
case F_GETFD:
|
||||
ret = dtable->GetFlags(fd);
|
||||
break;
|
||||
case F_SETFL:
|
||||
case F_GETFL:
|
||||
errno = ENOSYS;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t sys_readdirents(int fd, kernel_dirent* dirent, size_t size/*,
|
||||
size_t maxcount*/)
|
||||
{
|
||||
if ( size < sizeof(kernel_dirent) ) { errno = EINVAL; return -1; }
|
||||
if ( SSIZE_MAX < size )
|
||||
size = SSIZE_MAX;
|
||||
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
||||
if ( !desc )
|
||||
return -1;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
return desc->readdirents(&ctx, dirent, size, 1 /*maxcount*/);
|
||||
}
|
||||
|
||||
static int sys_chdir(const char* path)
|
||||
{
|
||||
char* pathcopy = GetStringFromUser(path);
|
||||
if ( !pathcopy )
|
||||
return -1;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
const char* relpath = pathcopy;
|
||||
Ref<Descriptor> from = PrepareLookup(&relpath);
|
||||
Ref<Descriptor> desc = from->open(&ctx, relpath, O_RDONLY | O_DIRECTORY);
|
||||
from.Reset();
|
||||
delete[] pathcopy;
|
||||
if ( !desc )
|
||||
return -1;
|
||||
CurrentProcess()->SetCWD(desc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sys_settermmode(int fd, unsigned mode)
|
||||
{
|
||||
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
||||
if ( !desc )
|
||||
return -1;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
return desc->settermmode(&ctx, mode);
|
||||
}
|
||||
|
||||
static int sys_gettermmode(int fd, unsigned* mode)
|
||||
{
|
||||
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
||||
if ( !desc )
|
||||
return -1;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
return desc->gettermmode(&ctx, mode);
|
||||
}
|
||||
|
||||
static int sys_isatty(int fd)
|
||||
{
|
||||
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
||||
if ( !desc )
|
||||
return 0;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
return desc->isatty(&ctx);
|
||||
}
|
||||
|
||||
static int sys_tcgetwinsize(int fd, struct winsize* ws)
|
||||
{
|
||||
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
||||
if ( !desc )
|
||||
return -1;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
return desc->tcgetwinsize(&ctx, ws);
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
Syscall::Register(SYSCALL_ACCESS, (void*) sys_access);
|
||||
Syscall::Register(SYSCALL_CHDIR, (void*) sys_chdir);
|
||||
Syscall::Register(SYSCALL_CLOSE, (void*) sys_close);
|
||||
Syscall::Register(SYSCALL_DUP, (void*) sys_dup);
|
||||
Syscall::Register(SYSCALL_FCNTL, (void*) sys_fcntl);
|
||||
Syscall::Register(SYSCALL_FSTATAT, (void*) sys_fstatat);
|
||||
Syscall::Register(SYSCALL_FSTAT, (void*) sys_fstat);
|
||||
Syscall::Register(SYSCALL_FTRUNCATE, (void*) sys_ftruncate);
|
||||
Syscall::Register(SYSCALL_GETTERMMODE, (void*) sys_gettermmode);
|
||||
Syscall::Register(SYSCALL_ISATTY, (void*) sys_isatty);
|
||||
Syscall::Register(SYSCALL_MKDIR, (void*) sys_mkdir);
|
||||
Syscall::Register(SYSCALL_OPENAT, (void*) sys_openat);
|
||||
Syscall::Register(SYSCALL_OPEN, (void*) sys_open);
|
||||
Syscall::Register(SYSCALL_PREAD, (void*) sys_pread);
|
||||
Syscall::Register(SYSCALL_PWRITE, (void*) sys_pwrite);
|
||||
Syscall::Register(SYSCALL_READDIRENTS, (void*) sys_readdirents);
|
||||
Syscall::Register(SYSCALL_READ, (void*) sys_read);
|
||||
Syscall::Register(SYSCALL_RMDIR, (void*) sys_rmdir);
|
||||
Syscall::Register(SYSCALL_SEEK, (void*) sys_seek);
|
||||
Syscall::Register(SYSCALL_SETTERMMODE, (void*) sys_settermmode);
|
||||
Syscall::Register(SYSCALL_STAT, (void*) sys_stat);
|
||||
Syscall::Register(SYSCALL_TCGETWINSIZE, (void*) sys_tcgetwinsize);
|
||||
Syscall::Register(SYSCALL_TRUNCATE, (void*) sys_truncate);
|
||||
Syscall::Register(SYSCALL_UNLINK, (void*) sys_unlink);
|
||||
Syscall::Register(SYSCALL_WRITE, (void*) sys_write);
|
||||
}
|
||||
|
||||
} // namespace IO
|
||||
} // namespace Sortix
|
||||
|
|
16
sortix/io.h
16
sortix/io.h
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -25,12 +25,12 @@
|
|||
#ifndef SORTIX_IO_H
|
||||
#define SORTIX_IO_H
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
namespace IO
|
||||
{
|
||||
void Init();
|
||||
}
|
||||
}
|
||||
namespace Sortix {
|
||||
namespace IO {
|
||||
|
||||
void Init();
|
||||
|
||||
} // namespace IO
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -17,32 +17,32 @@
|
|||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
keyboard.cpp
|
||||
An interface to keyboards.
|
||||
ioctx.cpp
|
||||
The context for io operations: who made it, how should data be copied, etc.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include "interrupt.h"
|
||||
#include "syscall.h"
|
||||
#include "keyboard.h"
|
||||
#include "kb/ps2.h"
|
||||
#include "kb/layout/us.h"
|
||||
#include "logterminal.h"
|
||||
#include <sortix/kernel/ioctx.h>
|
||||
#include <sortix/kernel/copy.h>
|
||||
#include "process.h"
|
||||
|
||||
namespace Sortix
|
||||
namespace Sortix {
|
||||
|
||||
void SetupUserIOCtx(ioctx_t* ctx)
|
||||
{
|
||||
DevTerminal* tty;
|
||||
|
||||
void Keyboard::Init()
|
||||
{
|
||||
Keyboard* keyboard = new PS2Keyboard(0x60, Interrupt::IRQ1);
|
||||
if ( !keyboard ) { Panic("Could not allocate PS2 Keyboard driver"); }
|
||||
|
||||
KeyboardLayout* kblayout = new KBLayoutUS;
|
||||
if ( !kblayout ) { Panic("Could not allocate keyboard layout driver"); }
|
||||
|
||||
tty = new LogTerminal(keyboard, kblayout);
|
||||
if ( !tty ) { Panic("Could not allocate a simple terminal"); }
|
||||
}
|
||||
ctx->uid = ctx->auth_uid = CurrentProcess()->uid;
|
||||
ctx->gid = ctx->auth_gid = CurrentProcess()->gid;
|
||||
ctx->copy_to_dest = CopyToUser;
|
||||
ctx->copy_from_src = CopyFromUser;
|
||||
}
|
||||
|
||||
void SetupKernelIOCtx(ioctx_t* ctx)
|
||||
{
|
||||
ctx->uid = ctx->auth_uid = CurrentProcess()->uid;
|
||||
ctx->gid = ctx->auth_gid = CurrentProcess()->gid;
|
||||
ctx->copy_to_dest = CopyToKernel;
|
||||
ctx->copy_from_src = CopyFromKernel;
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
|
@ -23,7 +23,7 @@
|
|||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include "../../keyboard.h"
|
||||
#include <sortix/kernel/keyboard.h>
|
||||
#include <sortix/keycodes.h>
|
||||
#include "us.h"
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#ifndef SORTIX_KB_LAYOUT_US_H
|
||||
#define SORTIX_KB_LAYOUT_US_H
|
||||
|
||||
#include "../../keyboard.h"
|
||||
#include <sortix/kernel/keyboard.h>
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
|
|
|
@ -23,11 +23,11 @@
|
|||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/keyboard.h>
|
||||
#include <sortix/keycodes.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "../interrupt.h"
|
||||
#include "../keyboard.h"
|
||||
#include <sortix/keycodes.h>
|
||||
#include "ps2.h"
|
||||
|
||||
namespace Sortix
|
||||
|
@ -87,14 +87,10 @@ namespace Sortix
|
|||
void PS2Keyboard::OnInterrupt(CPU::InterruptRegisters* /*regs*/)
|
||||
{
|
||||
uint8_t scancode = PopScancode();
|
||||
#ifdef GOT_ACTUAL_KTHREAD
|
||||
PS2KeyboardWork work;
|
||||
work.kb = this;
|
||||
work.scancode = scancode;
|
||||
Interrupt::ScheduleWork(PS2Keyboard__InterruptWork, &work, sizeof(work));
|
||||
#else
|
||||
InterruptWork(scancode);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PS2Keyboard::InterruptWork(uint8_t scancode)
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#define SORTIX_KB_PS2_H
|
||||
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include "../keyboard.h"
|
||||
#include <sortix/kernel/keyboard.h>
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -33,15 +33,25 @@
|
|||
#include <sortix/kernel/pci.h>
|
||||
#include <sortix/kernel/worker.h>
|
||||
#include <sortix/kernel/memorymanagement.h>
|
||||
#include <sortix/kernel/ioctx.h>
|
||||
#include <sortix/kernel/copy.h>
|
||||
#include <sortix/kernel/inode.h>
|
||||
#include <sortix/kernel/vnode.h>
|
||||
#include <sortix/kernel/descriptor.h>
|
||||
#include <sortix/kernel/dtable.h>
|
||||
#include <sortix/kernel/mtable.h>
|
||||
#include <sortix/kernel/keyboard.h>
|
||||
#include <sortix/fcntl.h>
|
||||
#include <sortix/stat.h>
|
||||
#include <sortix/mman.h>
|
||||
#include <sortix/wait.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include "kernelinfo.h"
|
||||
#include "x86-family/gdt.h"
|
||||
#include "x86-family/float.h"
|
||||
#include "time.h"
|
||||
#include "keyboard.h"
|
||||
#include "multiboot.h"
|
||||
#include "thread.h"
|
||||
#include "process.h"
|
||||
|
@ -51,8 +61,8 @@
|
|||
#include "ata.h"
|
||||
#include "com.h"
|
||||
#include "uart.h"
|
||||
#include "logterminal.h"
|
||||
#include "vgatextbuffer.h"
|
||||
#include "terminal.h"
|
||||
#include "serialterminal.h"
|
||||
#include "textterminal.h"
|
||||
#include "elf.h"
|
||||
|
@ -62,12 +72,11 @@
|
|||
#include "sound.h"
|
||||
#include "io.h"
|
||||
#include "pipe.h"
|
||||
#include "filesystem.h"
|
||||
#include "mount.h"
|
||||
#include "directory.h"
|
||||
#include "interrupt.h"
|
||||
#include "dispmsg.h"
|
||||
#include "fs/devfs.h"
|
||||
#include "fs/kram.h"
|
||||
#include "kb/ps2.h"
|
||||
#include "kb/layout/us.h"
|
||||
|
||||
// Keep the stack size aligned with $CPU/base.s
|
||||
const size_t STACK_SIZE = 64*1024;
|
||||
|
@ -121,10 +130,18 @@ static size_t TextTermHeight(void* user)
|
|||
return ((TextTerminal*) user)->Height();
|
||||
}
|
||||
|
||||
addr_t initrd;
|
||||
size_t initrdsize;
|
||||
Ref<TextBufferHandle> textbufhandle;
|
||||
|
||||
extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
||||
{
|
||||
(void) magic;
|
||||
|
||||
//
|
||||
// Stage 1. Initialization of Early Environment.
|
||||
//
|
||||
|
||||
// Initialize system calls.
|
||||
Syscall::Init();
|
||||
|
||||
|
@ -137,10 +154,11 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
|||
const size_t VGA_HEIGHT = 25;
|
||||
static uint16_t vga_attr_buffer[VGA_WIDTH*VGA_HEIGHT];
|
||||
VGATextBuffer textbuf(VGAFB, vga_attr_buffer, VGA_WIDTH, VGA_HEIGHT);
|
||||
TextBufferHandle textbufhandle(NULL, false, &textbuf, false);
|
||||
TextBufferHandle textbufhandlestack(NULL, false, &textbuf, false);
|
||||
textbufhandle = Ref<TextBufferHandle>(&textbufhandlestack);
|
||||
|
||||
// Setup a text terminal instance.
|
||||
TextTerminal textterm(&textbufhandle);
|
||||
TextTerminal textterm(textbufhandle);
|
||||
|
||||
// Register the text terminal as the kernel log and initialize it.
|
||||
Log::Init(PrintToTextTerminal, TextTermWidth, TextTermHeight, &textterm);
|
||||
|
@ -182,8 +200,8 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
|||
"multiboot compliant?");
|
||||
}
|
||||
|
||||
addr_t initrd = 0;
|
||||
size_t initrdsize = 0;
|
||||
initrd = 0;
|
||||
initrdsize = 0;
|
||||
|
||||
uint32_t* modules = (uint32_t*) (addr_t) bootinfo->mods_addr;
|
||||
for ( uint32_t i = 0; i < bootinfo->mods_count; i++ )
|
||||
|
@ -209,26 +227,12 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
|||
// Initialize the kernel heap.
|
||||
_init_heap();
|
||||
|
||||
// Initialize the interrupt worker.
|
||||
// Initialize the interrupt worker (before scheduling is enabled).
|
||||
Interrupt::InitWorker();
|
||||
|
||||
// Initialize the list of kernel devices.
|
||||
DeviceFS::Init();
|
||||
|
||||
// Initialize the COM ports.
|
||||
COM::Init();
|
||||
|
||||
// Initialize the keyboard.
|
||||
Keyboard::Init();
|
||||
|
||||
// Initialize the terminal.
|
||||
Terminal::Init();
|
||||
|
||||
// Initialize the VGA driver.
|
||||
VGA::Init();
|
||||
|
||||
// Initialize the sound driver.
|
||||
Sound::Init();
|
||||
//
|
||||
// Stage 2. Transition to Multithreaded Environment
|
||||
//
|
||||
|
||||
// Initialize the process system.
|
||||
Process::Init();
|
||||
|
@ -236,47 +240,11 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
|||
// Initialize the thread system.
|
||||
Thread::Init();
|
||||
|
||||
// Initialize the IO system.
|
||||
IO::Init();
|
||||
|
||||
// Initialize the pipe system.
|
||||
Pipe::Init();
|
||||
|
||||
// Initialize the filesystem system.
|
||||
FileSystem::Init();
|
||||
|
||||
// Initialize the directory system.
|
||||
Directory::Init();
|
||||
|
||||
// Initialize the mount system.
|
||||
Mount::Init();
|
||||
|
||||
// Initialize the scheduler.
|
||||
Scheduler::Init();
|
||||
|
||||
// Initialize Unix Signals.
|
||||
Signal::Init();
|
||||
|
||||
// Initialize the worker thread data structures.
|
||||
Worker::Init();
|
||||
|
||||
// Initialize the kernel information query syscall.
|
||||
Info::Init();
|
||||
|
||||
// Set up the initial ram disk.
|
||||
InitRD::Init(initrd, initrdsize);
|
||||
|
||||
// Initialize the Video Driver framework.
|
||||
Video::Init(&textbufhandle);
|
||||
|
||||
// Search for PCI devices and load their drivers.
|
||||
PCI::Init();
|
||||
|
||||
// Initialize ATA devices.
|
||||
ATA::Init();
|
||||
|
||||
// Initialize the BGA driver.
|
||||
BGA::Init();
|
||||
// Initialize the scheduler.
|
||||
Scheduler::Init();
|
||||
|
||||
// Initialize the Display Message framework.
|
||||
DisplayMessage::Init();
|
||||
|
@ -294,6 +262,7 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
|||
// _nothing_ else to run on this CPU.
|
||||
Thread* idlethread = new Thread;
|
||||
idlethread->process = system;
|
||||
idlethread->addrspace = idlethread->process->addrspace;
|
||||
idlethread->kernelstackpos = (addr_t) stack;
|
||||
idlethread->kernelstacksize = STACK_SIZE;
|
||||
idlethread->kernelstackmalloced = false;
|
||||
|
@ -302,8 +271,9 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
|||
Scheduler::SetIdleThread(idlethread);
|
||||
|
||||
// Let's create a regular kernel thread that can decide what happens next.
|
||||
// Note that we don't do the work here: should it block, then there is
|
||||
// nothing to run. Therefore we must become the system idle thread.
|
||||
// Note that we don't do the work here: if all other threads are not running
|
||||
// and this thread isn't runnable, then there is nothing to run. Therefore
|
||||
// we must become the system idle thread.
|
||||
RunKernelThread(BootThread, NULL);
|
||||
|
||||
// Set up such that floating point registers are lazily switched.
|
||||
|
@ -319,27 +289,130 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
|||
static void SystemIdleThread(void* /*user*/)
|
||||
{
|
||||
// Alright, we are now the system idle thread. If there is nothing to do,
|
||||
// then we are run. Note that we must never do any real work here.
|
||||
// then we are run. Note that we must never do any real work here as the
|
||||
// idle thread must always be runnable.
|
||||
while(true);
|
||||
}
|
||||
|
||||
static void BootThread(void* /*user*/)
|
||||
{
|
||||
//
|
||||
// Stage 3. Spawning Kernel Worker Threads.
|
||||
//
|
||||
|
||||
// Hello, threaded world! You can now regard the kernel as a multi-threaded
|
||||
// process with super-root access to the system. Before we boot the full
|
||||
// system we need to start some worker threads.
|
||||
|
||||
// Let's create the interrupt worker thread that executes additional work
|
||||
// requested by interrupt handlers, where such work isn't safe.
|
||||
Thread* interruptworker = RunKernelThread(Interrupt::WorkerThread, NULL);
|
||||
if ( !interruptworker )
|
||||
Panic("Could not create interrupt worker");
|
||||
|
||||
// Initialize the worker thread data structures.
|
||||
Worker::Init();
|
||||
|
||||
// Create a general purpose worker thread.
|
||||
Thread* workerthread = RunKernelThread(Worker::Thread, NULL);
|
||||
if ( !workerthread )
|
||||
Panic("Unable to create general purpose worker thread");
|
||||
|
||||
//
|
||||
// Stage 4. Initialize the Filesystem
|
||||
//
|
||||
|
||||
Ref<DescriptorTable> dtable(new DescriptorTable());
|
||||
if ( !dtable )
|
||||
Panic("Unable to allocate descriptor table");
|
||||
Ref<MountTable> mtable(new MountTable());
|
||||
if ( !mtable )
|
||||
Panic("Unable to allocate mount table.");
|
||||
CurrentProcess()->BootstrapTables(dtable, mtable);
|
||||
|
||||
// Let's begin preparing the filesystem.
|
||||
// TODO: Setup the right device id for the KRAMFS dir?
|
||||
Ref<Inode> iroot(new KRAMFS::Dir((dev_t) 0, (ino_t) 0, 0, 0, 0755));
|
||||
if ( !iroot )
|
||||
Panic("Unable to allocate root inode.");
|
||||
ioctx_t ctx; SetupKernelIOCtx(&ctx);
|
||||
Ref<Vnode> vroot(new Vnode(iroot, Ref<Vnode>(NULL), 0, 0));
|
||||
if ( !vroot )
|
||||
Panic("Unable to allocate root vnode.");
|
||||
Ref<Descriptor> droot(new Descriptor(vroot, 0));
|
||||
if ( !droot )
|
||||
Panic("Unable to allocate root descriptor.");
|
||||
CurrentProcess()->BootstrapDirectories(droot);
|
||||
|
||||
// Initialize the root directory.
|
||||
if ( iroot->link_raw(&ctx, ".", iroot) != 0 )
|
||||
Panic("Unable to link /. to /");
|
||||
if ( iroot->link_raw(&ctx, "..", iroot) != 0 )
|
||||
Panic("Unable to link /.. to /");
|
||||
|
||||
// Install the initrd into our fresh RAM filesystem.
|
||||
if ( !InitRD::ExtractFromPhysicalInto(initrd, initrdsize, droot) )
|
||||
Panic("Unable to extract initrd into RAM root filesystem.");
|
||||
// TODO: It's safe to free the original initrd now.
|
||||
|
||||
// Get a descriptor for the /dev directory so we can populate it.
|
||||
if ( droot->mkdir(&ctx, "dev", 0775) != 0 && errno != EEXIST )
|
||||
Panic("Unable to create RAM filesystem /dev directory.");
|
||||
Ref<Descriptor> slashdev = droot->open(&ctx, "dev", O_RDONLY | O_DIRECTORY);
|
||||
if ( !slashdev )
|
||||
Panic("Unable to create descriptor for RAM filesystem /dev directory.");
|
||||
|
||||
//
|
||||
// Stage 5. Loading and Initializing Core Drivers.
|
||||
//
|
||||
|
||||
// Initialize the keyboard.
|
||||
Keyboard* keyboard = new PS2Keyboard(0x60, Interrupt::IRQ1);
|
||||
if ( !keyboard )
|
||||
Panic("Could not allocate PS2 Keyboard driver");
|
||||
KeyboardLayout* kblayout = new KBLayoutUS;
|
||||
if ( !kblayout )
|
||||
Panic("Could not allocate keyboard layout driver");
|
||||
|
||||
// Register the kernel terminal as /dev/tty.
|
||||
Ref<Inode> tty(new LogTerminal(slashdev->dev, 0666, 0, 0, keyboard, kblayout));
|
||||
if ( !tty )
|
||||
Panic("Could not allocate a kernel terminal");
|
||||
if ( LinkInodeInDir(&ctx, slashdev, "tty", tty) != 0 )
|
||||
Panic("Unable to link /dev/tty to kernel terminal.");
|
||||
|
||||
// Initialize the COM ports.
|
||||
COM::Init("/dev", slashdev);
|
||||
|
||||
// Initialize the VGA driver.
|
||||
VGA::Init("/dev", slashdev);
|
||||
|
||||
// Initialize the sound driver.
|
||||
Sound::Init();
|
||||
|
||||
// Initialize the IO system.
|
||||
IO::Init();
|
||||
|
||||
// Initialize the pipe system.
|
||||
Pipe::Init();
|
||||
|
||||
// Initialize the kernel information query syscall.
|
||||
Info::Init();
|
||||
|
||||
// Initialize the Video Driver framework.
|
||||
Video::Init(textbufhandle);
|
||||
|
||||
// Search for PCI devices and load their drivers.
|
||||
PCI::Init();
|
||||
|
||||
// Initialize ATA devices.
|
||||
ATA::Init("/dev", slashdev);
|
||||
|
||||
// Initialize the BGA driver.
|
||||
BGA::Init();
|
||||
|
||||
//
|
||||
// Stage 6. Executing Hosted Environment ("User-Space")
|
||||
//
|
||||
// Finally, let's transfer control to a new kernel process that will
|
||||
// eventually run user-space code known as the operating system.
|
||||
addr_t initaddrspace = Memory::Fork();
|
||||
|
@ -350,11 +423,18 @@ static void BootThread(void* /*user*/)
|
|||
|
||||
CurrentProcess()->AddChildProcess(init);
|
||||
|
||||
// TODO: Why don't we fork from pid=0 and this is done for us?
|
||||
// TODO: Fork dtable and mtable, don't share them!
|
||||
init->BootstrapTables(dtable, mtable);
|
||||
dtable.Reset();
|
||||
mtable.Reset();
|
||||
init->BootstrapDirectories(droot);
|
||||
init->addrspace = initaddrspace;
|
||||
Scheduler::SetInitProcess(init);
|
||||
|
||||
Thread* initthread = RunKernelThread(init, InitThread, NULL);
|
||||
if ( !initthread ) { Panic("Coul not create init thread"); }
|
||||
if ( !initthread )
|
||||
Panic("Could not create init thread");
|
||||
|
||||
// Wait until init init is done and then shut down the computer.
|
||||
int status;
|
||||
|
@ -373,6 +453,14 @@ static void BootThread(void* /*user*/)
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(PLATFORM_X86)
|
||||
#define CPUTYPE_STR "i486-sortix"
|
||||
#elif defined(PLATFORM_X64)
|
||||
#define CPUTYPE_STR "x86_64-sortix"
|
||||
#else
|
||||
#error No cputype environmental variable provided here.
|
||||
#endif
|
||||
|
||||
static void InitThread(void* /*user*/)
|
||||
{
|
||||
// We are the init process's first thread. Let's load the init program from
|
||||
|
@ -382,12 +470,36 @@ static void InitThread(void* /*user*/)
|
|||
Thread* thread = CurrentThread();
|
||||
Process* process = CurrentProcess();
|
||||
|
||||
uint32_t inode = InitRD::Traverse(InitRD::Root(), "init");
|
||||
if ( !inode ) { Panic("InitRD did not contain an 'init' program."); }
|
||||
const char* initpath = "/" CPUTYPE_STR "/bin/init";
|
||||
|
||||
size_t programsize;
|
||||
uint8_t* program = InitRD::Open(inode, &programsize);
|
||||
if ( !program ) { Panic("InitRD did not contain an 'init' program."); }
|
||||
ioctx_t ctx; SetupKernelIOCtx(&ctx);
|
||||
Ref<Descriptor> root = CurrentProcess()->GetRoot();
|
||||
Ref<Descriptor> init = root->open(&ctx, initpath, O_EXEC);
|
||||
if ( !init )
|
||||
PanicF("Could not open %s in early kernel RAM filesystem:\n%s",
|
||||
initpath, strerror(errno));
|
||||
struct stat st;
|
||||
if ( init->stat(&ctx, &st) )
|
||||
PanicF("Could not stat '%s' in initrd.", initpath);
|
||||
assert(0 <= st.st_size);
|
||||
if ( (uintmax_t) SIZE_MAX < (uintmax_t) st.st_size )
|
||||
PanicF("%s is bigger than SIZE_MAX.", initpath);
|
||||
size_t programsize = st.st_size;
|
||||
uint8_t* program = new uint8_t[programsize];
|
||||
if ( !program )
|
||||
PanicF("Unable to allocate 0x%zx bytes needed for %s.", programsize, initpath);
|
||||
size_t sofar = 0;
|
||||
while ( sofar < programsize )
|
||||
{
|
||||
ssize_t numbytes = init->read(&ctx, program+sofar, programsize-sofar);
|
||||
if ( !numbytes )
|
||||
PanicF("Premature EOF when reading %s.", initpath);
|
||||
if ( numbytes < 0 )
|
||||
PanicF("IO error when reading %s.", initpath);
|
||||
sofar += numbytes;
|
||||
}
|
||||
|
||||
init.Reset();
|
||||
|
||||
const size_t DEFAULT_STACK_SIZE = 64UL * 1024UL;
|
||||
|
||||
|
@ -399,32 +511,23 @@ static void InitThread(void* /*user*/)
|
|||
|
||||
int prot = PROT_FORK | PROT_READ | PROT_WRITE | PROT_KREAD | PROT_KWRITE;
|
||||
if ( !Memory::MapRange(stackpos, stacksize, prot) )
|
||||
{
|
||||
Panic("Could not allocate init stack memory");
|
||||
}
|
||||
|
||||
thread->stackpos = stackpos;
|
||||
thread->stacksize = stacksize;
|
||||
|
||||
int argc = 1;
|
||||
const char* argv[] = { "init", NULL };
|
||||
#if defined(PLATFORM_X86)
|
||||
const char* cputype = "cputype=i486-sortix";
|
||||
#elif defined(PLATFORM_X64)
|
||||
const char* cputype = "cputype=x86_64-sortix";
|
||||
#else
|
||||
#warning No cputype environmental variable provided here.
|
||||
const char* cputype = "cputype=unknown-sortix";
|
||||
#endif
|
||||
const char* cputype = "cputype=" CPUTYPE_STR;
|
||||
int envc = 1;
|
||||
const char* envp[] = { cputype, NULL };
|
||||
CPU::InterruptRegisters regs;
|
||||
|
||||
if ( process->Execute("init", program, programsize, argc, argv, envc, envp,
|
||||
®s) )
|
||||
{
|
||||
Panic("Unable to execute init program");
|
||||
}
|
||||
if ( process->Execute(initpath, program, programsize, argc, argv, envc,
|
||||
envp, ®s) )
|
||||
PanicF("Unable to execute %s.", initpath);
|
||||
|
||||
delete[] program;
|
||||
|
||||
// Now become the init process and the operation system shall run.
|
||||
CPU::LoadRegisters(®s);
|
||||
|
|
|
@ -23,303 +23,294 @@
|
|||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/interlock.h>
|
||||
#include <sortix/kernel/ioctx.h>
|
||||
#include <sortix/kernel/inode.h>
|
||||
#include <sortix/kernel/keyboard.h>
|
||||
#include <sortix/termmode.h>
|
||||
#include <sortix/termios.h>
|
||||
#include <sortix/keycodes.h>
|
||||
#include <sortix/signal.h>
|
||||
#include <sortix/stat.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "utf8.h"
|
||||
#include "keyboard.h"
|
||||
#include "process.h"
|
||||
#include "scheduler.h"
|
||||
#include "terminal.h"
|
||||
#include "logterminal.h"
|
||||
|
||||
namespace Sortix
|
||||
namespace Sortix {
|
||||
|
||||
const unsigned SUPPORTED_MODES = TERMMODE_KBKEY
|
||||
| TERMMODE_UNICODE
|
||||
| TERMMODE_SIGNAL
|
||||
| TERMMODE_UTF8
|
||||
| TERMMODE_LINEBUFFER
|
||||
| TERMMODE_ECHO
|
||||
| TERMMODE_NONBLOCK;
|
||||
|
||||
LogTerminal::LogTerminal(dev_t dev, mode_t mode, uid_t owner, gid_t group,
|
||||
Keyboard* keyboard, KeyboardLayout* kblayout)
|
||||
{
|
||||
const unsigned SUPPORTED_MODES = TERMMODE_KBKEY
|
||||
| TERMMODE_UNICODE
|
||||
| TERMMODE_SIGNAL
|
||||
| TERMMODE_UTF8
|
||||
| TERMMODE_LINEBUFFER
|
||||
| TERMMODE_ECHO
|
||||
| TERMMODE_NONBLOCK;
|
||||
|
||||
LogTerminal::LogTerminal(Keyboard* keyboard, KeyboardLayout* kblayout)
|
||||
{
|
||||
this->keyboard = keyboard;
|
||||
this->kblayout = kblayout;
|
||||
this->partiallywritten = 0;
|
||||
this->control = false;
|
||||
this->mode = TERMMODE_UNICODE
|
||||
| TERMMODE_SIGNAL
|
||||
| TERMMODE_UTF8
|
||||
| TERMMODE_LINEBUFFER
|
||||
| TERMMODE_ECHO;
|
||||
this->termlock = KTHREAD_MUTEX_INITIALIZER;
|
||||
this->datacond = KTHREAD_COND_INITIALIZER;
|
||||
this->numwaiting = 0;
|
||||
this->numeofs = 0;
|
||||
keyboard->SetOwner(this, NULL);
|
||||
}
|
||||
|
||||
LogTerminal::~LogTerminal()
|
||||
{
|
||||
delete keyboard;
|
||||
delete kblayout;
|
||||
}
|
||||
|
||||
bool LogTerminal::SetMode(unsigned newmode)
|
||||
{
|
||||
ScopedLock lock(&termlock);
|
||||
unsigned oldmode = mode;
|
||||
if ( oldmode & ~SUPPORTED_MODES ) { errno = ENOSYS; return false; }
|
||||
bool oldutf8 = mode & TERMMODE_UTF8;
|
||||
bool newutf8 = newmode & TERMMODE_UTF8;
|
||||
if ( oldutf8 ^ newutf8 ) { partiallywritten = 0; }
|
||||
mode = newmode;
|
||||
if ( !(newmode & TERMMODE_LINEBUFFER) ) { CommitLineBuffer(); }
|
||||
partiallywritten = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LogTerminal::SetWidth(unsigned width)
|
||||
{
|
||||
ScopedLock lock(&termlock);
|
||||
if ( width != GetWidth() ) { errno = ENOTSUP; return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LogTerminal::SetHeight(unsigned height)
|
||||
{
|
||||
ScopedLock lock(&termlock);
|
||||
if ( height != GetHeight() ) { errno = ENOTSUP; return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned LogTerminal::GetMode() const
|
||||
{
|
||||
ScopedLock lock(&termlock);
|
||||
return mode;
|
||||
}
|
||||
|
||||
unsigned LogTerminal::GetWidth() const
|
||||
{
|
||||
return (unsigned) Log::Width();
|
||||
}
|
||||
|
||||
unsigned LogTerminal::GetHeight() const
|
||||
{
|
||||
return (unsigned) Log::Height();
|
||||
}
|
||||
|
||||
void LogTerminal::OnKeystroke(Keyboard* kb, void* /*user*/)
|
||||
{
|
||||
while ( kb->HasPending() )
|
||||
{
|
||||
ProcessKeystroke(kb->Read());
|
||||
}
|
||||
}
|
||||
|
||||
void LogTerminal::ProcessKeystroke(int kbkey)
|
||||
{
|
||||
if ( !kbkey ) { return; }
|
||||
|
||||
ScopedLock lock(&termlock);
|
||||
|
||||
if ( kbkey == KBKEY_LCTRL ) { control = true; }
|
||||
if ( kbkey == -KBKEY_LCTRL ) { control = false; }
|
||||
if ( mode & TERMMODE_SIGNAL && control && kbkey == KBKEY_C )
|
||||
{
|
||||
while ( linebuffer.CanBackspace() )
|
||||
linebuffer.Backspace();
|
||||
pid_t pid = Process::HackGetForegroundProcess();
|
||||
Process* process = Process::Get(pid);
|
||||
if ( process )
|
||||
process->DeliverSignal(SIGINT);
|
||||
return;
|
||||
}
|
||||
if ( mode & TERMMODE_SIGNAL && control && kbkey == KBKEY_D )
|
||||
{
|
||||
if ( !linebuffer.CanPop() )
|
||||
{
|
||||
numeofs++;
|
||||
#ifdef GOT_ACTUAL_KTHREAD
|
||||
if ( numwaiting )
|
||||
kthread_cond_broadcast(&datacond);
|
||||
#else
|
||||
queuecommitevent.Signal();
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
uint32_t unikbkey = KBKEY_ENCODE(kbkey);
|
||||
QueueUnicode(unikbkey);
|
||||
uint32_t unicode = kblayout->Translate(kbkey);
|
||||
if ( 0 < kbkey ) { QueueUnicode(unicode); }
|
||||
}
|
||||
|
||||
void LogTerminal::QueueUnicode(uint32_t unicode)
|
||||
{
|
||||
if ( !unicode ) { return; }
|
||||
|
||||
int kbkey = KBKEY_DECODE(unicode);
|
||||
int abskbkey = (kbkey < 0) ? -kbkey : kbkey;
|
||||
bool wasenter = kbkey == KBKEY_ENTER || unicode == '\n';
|
||||
bool kbkeymode = mode & TERMMODE_KBKEY;
|
||||
bool unicodemode = mode && TERMMODE_UNICODE;
|
||||
bool linemode = mode & TERMMODE_LINEBUFFER;
|
||||
bool echomode = mode & TERMMODE_ECHO;
|
||||
|
||||
if ( linemode && abskbkey == KBKEY_BKSPC ) { return; }
|
||||
while ( linemode && unicode == '\b' )
|
||||
{
|
||||
if ( !linebuffer.CanBackspace() ) { return; }
|
||||
uint32_t delchar = linebuffer.Backspace();
|
||||
bool waskbkey = KBKEY_DECODE(delchar);
|
||||
bool wasuni = !waskbkey;
|
||||
if ( waskbkey && !kbkeymode ) { continue; }
|
||||
if ( wasuni && !unicodemode ) { continue; }
|
||||
if ( !echomode ) { return; }
|
||||
if ( wasuni ) { Log::Print("\b"); }
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !linebuffer.Push(unicode) )
|
||||
{
|
||||
Log::PrintF("Warning: LogTerminal driver dropping keystroke due "
|
||||
"to insufficient buffer space\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Could it be the right thing to print the unicode character even
|
||||
// if it is unprintable (it's an encoded keystroke)?
|
||||
if ( !KBKEY_DECODE(unicode) && echomode )
|
||||
{
|
||||
char utf8buf[6];
|
||||
unsigned numbytes = UTF8::Encode(unicode, utf8buf);
|
||||
Log::PrintData(utf8buf, numbytes);
|
||||
}
|
||||
|
||||
bool commit = !linemode || wasenter;
|
||||
if ( commit ) { CommitLineBuffer(); }
|
||||
}
|
||||
|
||||
void LogTerminal::CommitLineBuffer()
|
||||
{
|
||||
linebuffer.Commit();
|
||||
#ifdef GOT_ACTUAL_KTHREAD
|
||||
if ( numwaiting )
|
||||
kthread_cond_broadcast(&datacond);
|
||||
#else
|
||||
queuecommitevent.Signal();
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t LogTerminal::Read(uint8_t* dest, size_t count)
|
||||
{
|
||||
ScopedLockSignal lock(&termlock);
|
||||
if ( !lock.IsAcquired() ) { errno = EINTR; return -1; }
|
||||
size_t sofar = 0;
|
||||
size_t left = count;
|
||||
#ifdef GOT_ACTUAL_KTHREAD
|
||||
bool blocking = !(mode & TERMMODE_NONBLOCK);
|
||||
while ( left && !linebuffer.CanPop() && blocking && !numeofs )
|
||||
{
|
||||
numwaiting++;
|
||||
bool abort = !kthread_cond_wait_signal(&datacond, &termlock);
|
||||
numwaiting--;
|
||||
if ( abort ) { errno = EINTR; return -1; }
|
||||
}
|
||||
if ( left && !linebuffer.CanPop() && !blocking && !numeofs )
|
||||
{
|
||||
errno = EWOULDBLOCK;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
if ( numeofs )
|
||||
{
|
||||
numeofs--;
|
||||
return 0;
|
||||
}
|
||||
while ( left && linebuffer.CanPop() )
|
||||
{
|
||||
uint32_t codepoint = linebuffer.Peek();
|
||||
int kbkey = KBKEY_DECODE(codepoint);
|
||||
|
||||
bool ignore = false;
|
||||
if ( !(mode & TERMMODE_KBKEY) && kbkey ) { ignore = true; }
|
||||
if ( !(mode & TERMMODE_UNICODE) && !kbkey ) { ignore = true; }
|
||||
if ( ignore ) { linebuffer.Pop(); continue; }
|
||||
|
||||
uint8_t* buf;
|
||||
size_t bufsize;
|
||||
uint8_t codepointbuf[4];
|
||||
char utf8buf[6];
|
||||
|
||||
if ( mode & TERMMODE_UTF8 )
|
||||
{
|
||||
unsigned numbytes = UTF8::Encode(codepoint, utf8buf);
|
||||
if ( !numbytes )
|
||||
{
|
||||
Log::PrintF("Warning: logterminal driver dropping invalid "
|
||||
"codepoint 0x%x\n", codepoint);
|
||||
}
|
||||
buf = (uint8_t*) utf8buf;
|
||||
bufsize = numbytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
codepointbuf[0] = (codepoint >> 24U) & 0xFFU;
|
||||
codepointbuf[1] = (codepoint >> 16U) & 0xFFU;
|
||||
codepointbuf[2] = (codepoint >> 8U) & 0xFFU;
|
||||
codepointbuf[3] = (codepoint >> 0U) & 0xFFU;
|
||||
buf = (uint8_t*) &codepointbuf;
|
||||
bufsize = sizeof(codepointbuf);
|
||||
// TODO: Whoops, the above is big-endian and the user programs
|
||||
// expect the data to be in the host endian. That's bad. For now
|
||||
// just send the data in host endian, but this will break when
|
||||
// terminals are accessed over the network.
|
||||
buf = (uint8_t*) &codepoint;
|
||||
}
|
||||
if ( bufsize < partiallywritten ) { partiallywritten = bufsize; }
|
||||
buf += partiallywritten;
|
||||
bufsize -= partiallywritten;
|
||||
if ( sofar && left < bufsize ) { return sofar; }
|
||||
size_t amount = left < bufsize ? left : bufsize;
|
||||
memcpy(dest + sofar, buf, amount);
|
||||
partiallywritten = (amount < bufsize) ? partiallywritten + amount : 0;
|
||||
left -= amount;
|
||||
sofar += amount;
|
||||
if ( !partiallywritten ) { linebuffer.Pop(); }
|
||||
}
|
||||
|
||||
#ifdef GOT_FAKE_KTHREAD
|
||||
// Block if no data were ready.
|
||||
if ( !sofar )
|
||||
{
|
||||
if ( mode & TERMMODE_NONBLOCK ) { errno = EWOULDBLOCK; }
|
||||
else { queuecommitevent.Register(); errno = EBLOCKING; }
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return sofar;
|
||||
}
|
||||
|
||||
ssize_t LogTerminal::Write(const uint8_t* src, size_t count)
|
||||
{
|
||||
Log::PrintData(src, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
bool LogTerminal::IsReadable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LogTerminal::IsWritable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
inode_type = INODE_TYPE_TTY;
|
||||
this->dev = dev;
|
||||
this->ino = (ino_t) this;
|
||||
this->type = S_IFCHR;
|
||||
this->stat_mode = (mode & S_SETABLE) | this->type;
|
||||
this->stat_uid = owner;
|
||||
this->stat_gid = group;
|
||||
this->keyboard = keyboard;
|
||||
this->kblayout = kblayout;
|
||||
this->partiallywritten = 0;
|
||||
this->control = false;
|
||||
this->termmode = TERMMODE_UNICODE
|
||||
| TERMMODE_SIGNAL
|
||||
| TERMMODE_UTF8
|
||||
| TERMMODE_LINEBUFFER
|
||||
| TERMMODE_ECHO;
|
||||
this->termlock = KTHREAD_MUTEX_INITIALIZER;
|
||||
this->datacond = KTHREAD_COND_INITIALIZER;
|
||||
this->numwaiting = 0;
|
||||
this->numeofs = 0;
|
||||
keyboard->SetOwner(this, NULL);
|
||||
}
|
||||
|
||||
LogTerminal::~LogTerminal()
|
||||
{
|
||||
delete keyboard;
|
||||
delete kblayout;
|
||||
}
|
||||
|
||||
int LogTerminal::settermmode(ioctx_t* /*ctx*/, unsigned newtermmode)
|
||||
{
|
||||
if ( newtermmode & ~SUPPORTED_MODES ) { errno = EINVAL; return -1; }
|
||||
ScopedLock lock(&termlock);
|
||||
unsigned oldtermmode = termmode;
|
||||
bool oldutf8 = oldtermmode & TERMMODE_UTF8;
|
||||
bool newutf8 = newtermmode & TERMMODE_UTF8;
|
||||
if ( oldutf8 != newutf8 )
|
||||
partiallywritten = 0;
|
||||
termmode = newtermmode;
|
||||
if ( (!newtermmode & TERMMODE_LINEBUFFER) )
|
||||
CommitLineBuffer();
|
||||
partiallywritten = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LogTerminal::gettermmode(ioctx_t* ctx, unsigned* mode)
|
||||
{
|
||||
ScopedLock lock(&termlock);
|
||||
if ( !ctx->copy_to_dest(mode, &termmode, sizeof(termmode)) )
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LogTerminal::tcgetwinsize(ioctx_t* ctx, struct winsize* ws)
|
||||
{
|
||||
struct winsize retws;
|
||||
memset(&retws, 0, sizeof(retws));
|
||||
retws.ws_col = Log::Width();
|
||||
retws.ws_row = Log::Height();
|
||||
if ( !ctx->copy_to_dest(ws, &retws, sizeof(retws)) )
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LogTerminal::sync(ioctx_t* /*ctx*/)
|
||||
{
|
||||
return 0; // Not needed.
|
||||
}
|
||||
|
||||
void LogTerminal::OnKeystroke(Keyboard* kb, void* /*user*/)
|
||||
{
|
||||
while ( kb->HasPending() )
|
||||
ProcessKeystroke(kb->Read());
|
||||
}
|
||||
|
||||
void LogTerminal::ProcessKeystroke(int kbkey)
|
||||
{
|
||||
if ( !kbkey )
|
||||
return;
|
||||
|
||||
ScopedLock lock(&termlock);
|
||||
|
||||
if ( kbkey == KBKEY_LCTRL ) { control = true; }
|
||||
if ( kbkey == -KBKEY_LCTRL ) { control = false; }
|
||||
if ( termmode & TERMMODE_SIGNAL && control && kbkey == KBKEY_C )
|
||||
{
|
||||
while ( linebuffer.CanBackspace() )
|
||||
linebuffer.Backspace();
|
||||
pid_t pid = Process::HackGetForegroundProcess();
|
||||
Process* process = Process::Get(pid);
|
||||
if ( process )
|
||||
process->DeliverSignal(SIGINT);
|
||||
return;
|
||||
}
|
||||
if ( termmode & TERMMODE_SIGNAL && control && kbkey == KBKEY_D )
|
||||
{
|
||||
if ( !linebuffer.CanPop() )
|
||||
{
|
||||
numeofs++;
|
||||
if ( numwaiting )
|
||||
kthread_cond_broadcast(&datacond);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t unikbkey = KBKEY_ENCODE(kbkey);
|
||||
QueueUnicode(unikbkey);
|
||||
uint32_t unicode = kblayout->Translate(kbkey);
|
||||
if ( 0 < kbkey )
|
||||
QueueUnicode(unicode);
|
||||
}
|
||||
|
||||
void LogTerminal::QueueUnicode(uint32_t unicode)
|
||||
{
|
||||
if ( !unicode )
|
||||
return;
|
||||
|
||||
int kbkey = KBKEY_DECODE(unicode);
|
||||
int abskbkey = (kbkey < 0) ? -kbkey : kbkey;
|
||||
bool wasenter = kbkey == KBKEY_ENTER || unicode == '\n';
|
||||
bool kbkeymode = termmode & TERMMODE_KBKEY;
|
||||
bool unicodemode = termmode && TERMMODE_UNICODE;
|
||||
bool linemode = termmode & TERMMODE_LINEBUFFER;
|
||||
bool echomode = termmode & TERMMODE_ECHO;
|
||||
|
||||
if ( linemode && abskbkey == KBKEY_BKSPC ) { return; }
|
||||
while ( linemode && unicode == '\b' )
|
||||
{
|
||||
if ( !linebuffer.CanBackspace() ) { return; }
|
||||
uint32_t delchar = linebuffer.Backspace();
|
||||
bool waskbkey = KBKEY_DECODE(delchar);
|
||||
bool wasuni = !waskbkey;
|
||||
if ( waskbkey && !kbkeymode ) { continue; }
|
||||
if ( wasuni && !unicodemode ) { continue; }
|
||||
if ( !echomode ) { return; }
|
||||
if ( wasuni ) { Log::Print("\b"); }
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !linebuffer.Push(unicode) )
|
||||
{
|
||||
Log::PrintF("Warning: LogTerminal driver dropping keystroke due "
|
||||
"to insufficient buffer space\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Could it be the right thing to print the unicode character even
|
||||
// if it is unprintable (it's an encoded keystroke)?
|
||||
if ( !KBKEY_DECODE(unicode) && echomode )
|
||||
{
|
||||
char utf8buf[6];
|
||||
unsigned numbytes = UTF8::Encode(unicode, utf8buf);
|
||||
Log::PrintData(utf8buf, numbytes);
|
||||
}
|
||||
|
||||
bool commit = !linemode || wasenter;
|
||||
if ( commit )
|
||||
CommitLineBuffer();
|
||||
}
|
||||
|
||||
void LogTerminal::CommitLineBuffer()
|
||||
{
|
||||
linebuffer.Commit();
|
||||
if ( numwaiting )
|
||||
kthread_cond_broadcast(&datacond);
|
||||
}
|
||||
|
||||
ssize_t LogTerminal::read(ioctx_t* ctx, uint8_t* userbuf, size_t count)
|
||||
{
|
||||
ScopedLockSignal lock(&termlock);
|
||||
if ( !lock.IsAcquired() ) { errno = EINTR; return -1; }
|
||||
size_t sofar = 0;
|
||||
size_t left = count;
|
||||
bool blocking = !(termmode & TERMMODE_NONBLOCK);
|
||||
while ( left && !linebuffer.CanPop() && blocking && !numeofs )
|
||||
{
|
||||
numwaiting++;
|
||||
bool abort = !kthread_cond_wait_signal(&datacond, &termlock);
|
||||
numwaiting--;
|
||||
if ( abort ) { errno = EINTR; return -1; }
|
||||
}
|
||||
if ( left && !linebuffer.CanPop() && !blocking && !numeofs )
|
||||
{
|
||||
errno = EWOULDBLOCK;
|
||||
return -1;
|
||||
}
|
||||
if ( numeofs )
|
||||
{
|
||||
numeofs--;
|
||||
return 0;
|
||||
}
|
||||
while ( left && linebuffer.CanPop() )
|
||||
{
|
||||
uint32_t codepoint = linebuffer.Peek();
|
||||
int kbkey = KBKEY_DECODE(codepoint);
|
||||
|
||||
bool ignore = false;
|
||||
if ( !(termmode & TERMMODE_KBKEY) && kbkey ) { ignore = true; }
|
||||
if ( !(termmode & TERMMODE_UNICODE) && !kbkey ) { ignore = true; }
|
||||
if ( ignore ) { linebuffer.Pop(); continue; }
|
||||
|
||||
uint8_t* buf;
|
||||
size_t bufsize;
|
||||
uint8_t codepointbuf[4];
|
||||
char utf8buf[6];
|
||||
|
||||
if ( termmode & TERMMODE_UTF8 )
|
||||
{
|
||||
unsigned numbytes = UTF8::Encode(codepoint, utf8buf);
|
||||
if ( !numbytes )
|
||||
{
|
||||
Log::PrintF("Warning: logterminal driver dropping invalid "
|
||||
"codepoint 0x%x\n", codepoint);
|
||||
}
|
||||
buf = (uint8_t*) utf8buf;
|
||||
bufsize = numbytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
codepointbuf[0] = (codepoint >> 24U) & 0xFFU;
|
||||
codepointbuf[1] = (codepoint >> 16U) & 0xFFU;
|
||||
codepointbuf[2] = (codepoint >> 8U) & 0xFFU;
|
||||
codepointbuf[3] = (codepoint >> 0U) & 0xFFU;
|
||||
buf = (uint8_t*) &codepointbuf;
|
||||
bufsize = sizeof(codepointbuf);
|
||||
// TODO: Whoops, the above is big-endian and the user programs
|
||||
// expect the data to be in the host endian. That's bad. For now
|
||||
// just send the data in host endian, but this will break when
|
||||
// terminals are accessed over the network.
|
||||
buf = (uint8_t*) &codepoint;
|
||||
}
|
||||
if ( bufsize < partiallywritten ) { partiallywritten = bufsize; }
|
||||
buf += partiallywritten;
|
||||
bufsize -= partiallywritten;
|
||||
if ( sofar && left < bufsize ) { return sofar; }
|
||||
size_t amount = left < bufsize ? left : bufsize;
|
||||
ctx->copy_to_dest(userbuf + sofar, buf, amount);
|
||||
partiallywritten = (amount < bufsize) ? partiallywritten + amount : 0;
|
||||
left -= amount;
|
||||
sofar += amount;
|
||||
if ( !partiallywritten ) { linebuffer.Pop(); }
|
||||
}
|
||||
|
||||
return sofar;
|
||||
}
|
||||
|
||||
ssize_t LogTerminal::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
||||
{
|
||||
// TODO: Add support for ioctx to the kernel log.
|
||||
const size_t BUFFER_SIZE = 64UL;
|
||||
if ( BUFFER_SIZE < count )
|
||||
count = BUFFER_SIZE;
|
||||
char buffer[BUFFER_SIZE];
|
||||
if ( !ctx->copy_from_src(buffer, buf, count) )
|
||||
return -1;
|
||||
Log::PrintData(buf, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -26,60 +26,49 @@
|
|||
#define SORTIX_LOGTERMINAL_H
|
||||
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#ifdef GOT_FAKE_KTHREAD
|
||||
#include "event.h"
|
||||
#endif
|
||||
#include "stream.h"
|
||||
#include "terminal.h"
|
||||
#include "keyboard.h"
|
||||
#include <sortix/kernel/inode.h>
|
||||
#include <sortix/kernel/keyboard.h>
|
||||
#include "linebuffer.h"
|
||||
|
||||
namespace Sortix
|
||||
namespace Sortix {
|
||||
|
||||
class LogTerminal : public AbstractInode, public KeyboardOwner
|
||||
{
|
||||
class LogTerminal : public DevTerminal, public KeyboardOwner
|
||||
{
|
||||
public:
|
||||
LogTerminal(Keyboard* keyboard, KeyboardLayout* kblayout);
|
||||
virtual ~LogTerminal();
|
||||
public:
|
||||
LogTerminal(dev_t dev, mode_t mode, uid_t owner, gid_t group,
|
||||
Keyboard* keyboard, KeyboardLayout* kblayout);
|
||||
virtual ~LogTerminal();
|
||||
|
||||
public:
|
||||
virtual ssize_t Read(uint8_t* dest, size_t count);
|
||||
virtual ssize_t Write(const uint8_t* src, size_t count);
|
||||
virtual bool IsReadable();
|
||||
virtual bool IsWritable();
|
||||
public:
|
||||
virtual int sync(ioctx_t* ctx);
|
||||
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
||||
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
||||
virtual int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
|
||||
virtual int settermmode(ioctx_t* ctx, unsigned termmode);
|
||||
virtual int gettermmode(ioctx_t* ctx, unsigned* termmode);
|
||||
|
||||
public:
|
||||
virtual bool SetMode(unsigned mode);
|
||||
virtual bool SetWidth(unsigned width);
|
||||
virtual bool SetHeight(unsigned height);
|
||||
virtual unsigned GetMode() const;
|
||||
virtual unsigned GetWidth() const;
|
||||
virtual unsigned GetHeight() const;
|
||||
public:
|
||||
virtual void OnKeystroke(Keyboard* keyboard, void* user);
|
||||
|
||||
public:
|
||||
virtual void OnKeystroke(Keyboard* keyboard, void* user);
|
||||
private:
|
||||
void ProcessKeystroke(int kbkey);
|
||||
void QueueUnicode(uint32_t unicode);
|
||||
void CommitLineBuffer();
|
||||
|
||||
private:
|
||||
void ProcessKeystroke(int kbkey);
|
||||
void QueueUnicode(uint32_t unicode);
|
||||
void CommitLineBuffer();
|
||||
private:
|
||||
mutable kthread_mutex_t termlock;
|
||||
kthread_cond_t datacond;
|
||||
size_t numwaiting;
|
||||
size_t numeofs;
|
||||
Keyboard* keyboard;
|
||||
KeyboardLayout* kblayout;
|
||||
LineBuffer linebuffer;
|
||||
size_t partiallywritten;
|
||||
unsigned termmode;
|
||||
bool control;
|
||||
|
||||
private:
|
||||
mutable kthread_mutex_t termlock;
|
||||
kthread_cond_t datacond;
|
||||
size_t numwaiting;
|
||||
size_t numeofs;
|
||||
Keyboard* keyboard;
|
||||
KeyboardLayout* kblayout;
|
||||
LineBuffer linebuffer;
|
||||
#ifdef GOT_FAKE_KTHREAD
|
||||
Event queuecommitevent;
|
||||
#endif
|
||||
size_t partiallywritten;
|
||||
unsigned mode;
|
||||
bool control;
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
||||
|
|
139
sortix/mount.cpp
139
sortix/mount.cpp
|
@ -1,139 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
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/>.
|
||||
|
||||
mount.cpp
|
||||
Handles system wide mount points and initialization of new file systems.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/panic.h>
|
||||
#include <sortix/kernel/string.h>
|
||||
#include <string.h>
|
||||
#include "mount.h"
|
||||
#include "fs/ramfs.h"
|
||||
#include "fs/initfs.h"
|
||||
#include "fs/devfs.h"
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
class MountPoint
|
||||
{
|
||||
public:
|
||||
MountPoint(DevFileSystem* fs, char* path);
|
||||
~MountPoint();
|
||||
|
||||
public:
|
||||
MountPoint* prev;
|
||||
MountPoint* next;
|
||||
|
||||
public:
|
||||
DevFileSystem* fs;
|
||||
char* path;
|
||||
|
||||
};
|
||||
|
||||
MountPoint::MountPoint(DevFileSystem* fs, char* path)
|
||||
{
|
||||
this->path = path;
|
||||
this->fs = fs;
|
||||
this->fs->Refer();
|
||||
prev = NULL;
|
||||
next = NULL;
|
||||
}
|
||||
|
||||
MountPoint::~MountPoint()
|
||||
{
|
||||
fs->Unref();
|
||||
delete[] path;
|
||||
}
|
||||
|
||||
namespace Mount
|
||||
{
|
||||
MountPoint* root;
|
||||
|
||||
bool MatchesMountPath(const char* path, const char* mount)
|
||||
{
|
||||
size_t mountlen = strlen(mount);
|
||||
if ( !String::StartsWith(path, mount) ) { return false; }
|
||||
int c = path[mountlen];
|
||||
return c == '/' || c == '\0';
|
||||
}
|
||||
|
||||
DevFileSystem* WhichFileSystem(const char* path, size_t* pathoffset)
|
||||
{
|
||||
DevFileSystem* result = NULL;
|
||||
*pathoffset = 0;
|
||||
|
||||
for ( MountPoint* tmp = root; tmp; tmp = tmp->next )
|
||||
{
|
||||
if ( MatchesMountPath(path, tmp->path) )
|
||||
{
|
||||
result = tmp->fs;
|
||||
*pathoffset = strlen(tmp->path);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Register(DevFileSystem* fs, const char* path)
|
||||
{
|
||||
char* newpath = String::Clone(path);
|
||||
if ( !newpath ) { return false; }
|
||||
|
||||
MountPoint* mp = new MountPoint(fs, newpath);
|
||||
if ( !mp ) { delete[] newpath; return false; }
|
||||
|
||||
if ( !root ) { root = mp; return true; }
|
||||
|
||||
if ( strcmp(path, root->path) < 0 )
|
||||
{
|
||||
mp->next = root;
|
||||
root->prev = mp;
|
||||
root = mp;
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( MountPoint* tmp = root; tmp; tmp = tmp->next )
|
||||
{
|
||||
if ( tmp->next == NULL || strcmp(path, tmp->next->path) < 0 )
|
||||
{
|
||||
mp->next = tmp->next;
|
||||
tmp->next = mp;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false; // Shouldn't happen.
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
root = NULL;
|
||||
|
||||
DevFileSystem* rootfs = new DevRAMFS();
|
||||
if ( !rootfs || !Register(rootfs, "") ) { Panic("Unable to allocate rootfs"); }
|
||||
DevFileSystem* initfs = new DevInitFS();
|
||||
if ( !initfs || !Register(initfs, "/bin") ) { Panic("Unable to allocate initfs"); }
|
||||
DevFileSystem* devfs = new DevDevFS();
|
||||
if ( !devfs || !Register(devfs, "/dev") ) { Panic("Unable to allocate devfs"); }
|
||||
}
|
||||
}
|
||||
}
|
85
sortix/mtable.cpp
Normal file
85
sortix/mtable.cpp
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
|
||||
|
||||
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/>.
|
||||
|
||||
mtable.cpp
|
||||
Class to keep track of mount points.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
#include <sortix/kernel/inode.h>
|
||||
#include <sortix/kernel/mtable.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
MountTable::MountTable()
|
||||
{
|
||||
mtablelock = KTHREAD_MUTEX_INITIALIZER;
|
||||
mounts = NULL;
|
||||
nummounts = 0;
|
||||
mountsalloced = 0;
|
||||
}
|
||||
|
||||
MountTable::~MountTable()
|
||||
{
|
||||
delete[] mounts;
|
||||
}
|
||||
|
||||
Ref<MountTable> MountTable::Fork()
|
||||
{
|
||||
ScopedLock lock(&mtablelock);
|
||||
Ref<MountTable> clone(new MountTable);
|
||||
if ( !clone )
|
||||
return Ref<MountTable>(NULL);
|
||||
clone->mounts = new mountpoint_t[nummounts];
|
||||
if ( !clone->mounts )
|
||||
return Ref<MountTable>(NULL);
|
||||
clone->nummounts = nummounts;
|
||||
clone->mountsalloced = nummounts;
|
||||
for ( size_t i = 0; i < nummounts; i++ )
|
||||
clone->mounts[i] = mounts[i];
|
||||
return clone;
|
||||
}
|
||||
|
||||
bool MountTable::AddMount(ino_t ino, dev_t dev, Ref<Inode> inode)
|
||||
{
|
||||
ScopedLock lock(&mtablelock);
|
||||
if ( nummounts == mountsalloced )
|
||||
{
|
||||
size_t newalloced = mountsalloced ? 2UL * mountsalloced : 4UL;
|
||||
mountpoint_t* newmounts = new mountpoint_t[newalloced];
|
||||
if ( !newmounts )
|
||||
return false;
|
||||
for ( size_t i = 0; i < nummounts; i++ )
|
||||
newmounts[i] = mounts[i];
|
||||
delete[] mounts;
|
||||
mounts = newmounts;
|
||||
mountsalloced = newalloced;
|
||||
}
|
||||
mountpoint_t* mp = mounts + nummounts++;
|
||||
mp->ino = ino;
|
||||
mp->dev = dev;
|
||||
mp->inode = inode;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
570
sortix/pipe.cpp
570
sortix/pipe.cpp
|
@ -24,340 +24,270 @@
|
|||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/interlock.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
#include <sortix/kernel/ioctx.h>
|
||||
#include <sortix/kernel/copy.h>
|
||||
#include <sortix/kernel/inode.h>
|
||||
#include <sortix/kernel/vnode.h>
|
||||
#include <sortix/kernel/descriptor.h>
|
||||
#include <sortix/kernel/dtable.h>
|
||||
#include <sortix/signal.h>
|
||||
#include <sortix/stat.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#ifdef GOT_FAKE_KTHREAD
|
||||
#include "event.h"
|
||||
#endif
|
||||
#include "signal.h"
|
||||
#include "thread.h"
|
||||
#include "process.h"
|
||||
#include "syscall.h"
|
||||
#include "pipe.h"
|
||||
|
||||
namespace Sortix
|
||||
namespace Sortix {
|
||||
|
||||
class PipeChannel
|
||||
{
|
||||
class DevPipeStorage : public DevStream
|
||||
public:
|
||||
PipeChannel(uint8_t* buffer, size_t buffersize);
|
||||
~PipeChannel();
|
||||
void StartReading();
|
||||
void StartWriting();
|
||||
void CloseReading();
|
||||
void CloseWriting();
|
||||
void PerhapsShutdown();
|
||||
ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
||||
ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
||||
|
||||
private:
|
||||
kthread_mutex_t pipelock;
|
||||
kthread_cond_t readcond;
|
||||
kthread_cond_t writecond;
|
||||
uint8_t* buffer;
|
||||
size_t bufferoffset;
|
||||
size_t bufferused;
|
||||
size_t buffersize;
|
||||
bool anyreading;
|
||||
bool anywriting;
|
||||
|
||||
};
|
||||
|
||||
PipeChannel::PipeChannel(uint8_t* buffer, size_t buffersize)
|
||||
{
|
||||
pipelock = KTHREAD_MUTEX_INITIALIZER;
|
||||
readcond = KTHREAD_COND_INITIALIZER;
|
||||
writecond = KTHREAD_COND_INITIALIZER;
|
||||
this->buffer = buffer;
|
||||
this->buffersize = buffersize;
|
||||
bufferoffset = bufferused = 0;
|
||||
anyreading = anywriting = false;
|
||||
}
|
||||
|
||||
PipeChannel::~PipeChannel()
|
||||
{
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
void PipeChannel::StartReading()
|
||||
{
|
||||
ScopedLock lock(&pipelock);
|
||||
assert(!anyreading);
|
||||
anyreading = true;
|
||||
}
|
||||
|
||||
void PipeChannel::StartWriting()
|
||||
{
|
||||
ScopedLock lock(&pipelock);
|
||||
assert(!anywriting);
|
||||
anywriting = true;
|
||||
}
|
||||
|
||||
void PipeChannel::CloseReading()
|
||||
{
|
||||
anyreading = false;
|
||||
kthread_cond_broadcast(&writecond);
|
||||
PerhapsShutdown();
|
||||
}
|
||||
|
||||
void PipeChannel::CloseWriting()
|
||||
{
|
||||
anywriting = false;
|
||||
kthread_cond_broadcast(&readcond);
|
||||
PerhapsShutdown();
|
||||
}
|
||||
|
||||
void PipeChannel::PerhapsShutdown()
|
||||
{
|
||||
kthread_mutex_lock(&pipelock);
|
||||
bool deleteme = !anyreading & !anywriting;
|
||||
kthread_mutex_unlock(&pipelock);
|
||||
if ( deleteme )
|
||||
delete this;
|
||||
}
|
||||
|
||||
ssize_t PipeChannel::read(ioctx_t* ctx, uint8_t* buf, size_t count)
|
||||
{
|
||||
ScopedLockSignal lock(&pipelock);
|
||||
if ( !lock.IsAcquired() ) { errno = EINTR; return -1; }
|
||||
while ( anywriting && !bufferused )
|
||||
{
|
||||
public:
|
||||
typedef Device BaseClass;
|
||||
|
||||
public:
|
||||
DevPipeStorage(uint8_t* buffer, size_t buffersize);
|
||||
~DevPipeStorage();
|
||||
|
||||
private:
|
||||
uint8_t* buffer;
|
||||
size_t buffersize;
|
||||
size_t bufferoffset;
|
||||
size_t bufferused;
|
||||
#ifdef GOT_FAKE_KTHREAD
|
||||
Event readevent;
|
||||
Event writeevent;
|
||||
#endif
|
||||
bool anyreading;
|
||||
bool anywriting;
|
||||
kthread_mutex_t pipelock;
|
||||
kthread_cond_t readcond;
|
||||
kthread_cond_t writecond;
|
||||
|
||||
public:
|
||||
virtual ssize_t Read(uint8_t* dest, size_t count);
|
||||
virtual ssize_t Write(const uint8_t* src, size_t count);
|
||||
virtual bool IsReadable();
|
||||
virtual bool IsWritable();
|
||||
|
||||
public:
|
||||
void NotReading();
|
||||
void NotWriting();
|
||||
|
||||
};
|
||||
|
||||
DevPipeStorage::DevPipeStorage(uint8_t* buffer, size_t buffersize)
|
||||
{
|
||||
this->buffer = buffer;
|
||||
this->buffersize = buffersize;
|
||||
this->bufferoffset = 0;
|
||||
this->bufferused = 0;
|
||||
this->anyreading = true;
|
||||
this->anywriting = true;
|
||||
this->pipelock = KTHREAD_MUTEX_INITIALIZER;
|
||||
this->readcond = KTHREAD_COND_INITIALIZER;
|
||||
this->writecond = KTHREAD_COND_INITIALIZER;
|
||||
}
|
||||
|
||||
DevPipeStorage::~DevPipeStorage()
|
||||
{
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
bool DevPipeStorage::IsReadable() { return true; }
|
||||
bool DevPipeStorage::IsWritable() { return true; }
|
||||
|
||||
ssize_t DevPipeStorage::Read(uint8_t* dest, size_t count)
|
||||
{
|
||||
if ( count == 0 ) { return 0; }
|
||||
#ifdef GOT_ACTUAL_KTHREAD
|
||||
ScopedLockSignal lock(&pipelock);
|
||||
if ( !lock.IsAcquired() ) { errno = EINTR; return -1; }
|
||||
while ( anywriting && !bufferused )
|
||||
if ( !kthread_cond_wait_signal(&readcond, &pipelock) )
|
||||
{
|
||||
if ( !kthread_cond_wait_signal(&readcond, &pipelock) )
|
||||
{
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if ( !bufferused && !anywriting ) { return 0; }
|
||||
if ( bufferused < count ) { count = bufferused; }
|
||||
size_t amount = count;
|
||||
size_t linear = buffersize - bufferoffset;
|
||||
if ( linear < amount ) { amount = linear; }
|
||||
assert(amount);
|
||||
memcpy(dest, buffer + bufferoffset, amount);
|
||||
bufferoffset = (bufferoffset + amount) % buffersize;
|
||||
bufferused -= amount;
|
||||
kthread_cond_broadcast(&writecond);
|
||||
return amount;
|
||||
#else
|
||||
if ( bufferused )
|
||||
{
|
||||
if ( bufferused < count ) { count = bufferused; }
|
||||
size_t amount = count;
|
||||
size_t linear = buffersize - bufferoffset;
|
||||
if ( linear < amount ) { amount = linear; }
|
||||
assert(amount);
|
||||
memcpy(dest, buffer + bufferoffset, amount);
|
||||
bufferoffset = (bufferoffset + amount) % buffersize;
|
||||
bufferused -= amount;
|
||||
writeevent.Signal();
|
||||
return amount;
|
||||
}
|
||||
|
||||
if ( !anywriting ) { return 0; }
|
||||
|
||||
errno = EBLOCKING;
|
||||
readevent.Register();
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t DevPipeStorage::Write(const uint8_t* src, size_t count)
|
||||
{
|
||||
if ( count == 0 ) { return 0; }
|
||||
#ifdef GOT_ACTUAL_KTHREAD
|
||||
ScopedLockSignal lock(&pipelock);
|
||||
if ( !lock.IsAcquired() ) { errno = EINTR; return -1; }
|
||||
while ( anyreading && bufferused == buffersize )
|
||||
{
|
||||
if ( !kthread_cond_wait_signal(&writecond, &pipelock) )
|
||||
{
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if ( !anyreading )
|
||||
{
|
||||
CurrentThread()->DeliverSignal(SIGPIPE);
|
||||
errno = EPIPE;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
if ( buffersize - bufferused < count ) { count = buffersize - bufferused; }
|
||||
size_t writeoffset = (bufferoffset + bufferused) % buffersize;
|
||||
size_t amount = count;
|
||||
size_t linear = buffersize - writeoffset;
|
||||
if ( linear < amount ) { amount = linear; }
|
||||
assert(amount);
|
||||
memcpy(buffer + writeoffset, src, amount);
|
||||
bufferused += amount;
|
||||
kthread_cond_broadcast(&readcond);
|
||||
return amount;
|
||||
#else
|
||||
if ( bufferused < buffersize )
|
||||
{
|
||||
if ( buffersize - bufferused < count ) { count = buffersize - bufferused; }
|
||||
size_t writeoffset = (bufferoffset + bufferused) % buffersize;
|
||||
size_t amount = count;
|
||||
size_t linear = buffersize - writeoffset;
|
||||
if ( linear < amount ) { amount = linear; }
|
||||
assert(amount);
|
||||
memcpy(buffer + writeoffset, src, amount);
|
||||
bufferused += amount;
|
||||
readevent.Signal();
|
||||
return amount;
|
||||
}
|
||||
|
||||
errno = EBLOCKING;
|
||||
writeevent.Register();
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void DevPipeStorage::NotReading()
|
||||
{
|
||||
ScopedLock lock(&pipelock);
|
||||
anyreading = false;
|
||||
kthread_cond_broadcast(&readcond);
|
||||
}
|
||||
|
||||
void DevPipeStorage::NotWriting()
|
||||
{
|
||||
ScopedLock lock(&pipelock);
|
||||
anywriting = false;
|
||||
kthread_cond_broadcast(&writecond);
|
||||
}
|
||||
|
||||
class DevPipeReading : public DevStream
|
||||
{
|
||||
public:
|
||||
typedef Device BaseClass;
|
||||
|
||||
public:
|
||||
DevPipeReading(DevStream* stream);
|
||||
~DevPipeReading();
|
||||
|
||||
private:
|
||||
DevStream* stream;
|
||||
|
||||
public:
|
||||
virtual ssize_t Read(uint8_t* dest, size_t count);
|
||||
virtual ssize_t Write(const uint8_t* src, size_t count);
|
||||
virtual bool IsReadable();
|
||||
virtual bool IsWritable();
|
||||
|
||||
};
|
||||
|
||||
DevPipeReading::DevPipeReading(DevStream* stream)
|
||||
{
|
||||
stream->Refer();
|
||||
this->stream = stream;
|
||||
}
|
||||
|
||||
DevPipeReading::~DevPipeReading()
|
||||
{
|
||||
((DevPipeStorage*) stream)->NotReading();
|
||||
stream->Unref();
|
||||
}
|
||||
|
||||
ssize_t DevPipeReading::Read(uint8_t* dest, size_t count)
|
||||
{
|
||||
return stream->Read(dest, count);
|
||||
}
|
||||
|
||||
ssize_t DevPipeReading::Write(const uint8_t* /*src*/, size_t /*count*/)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool DevPipeReading::IsReadable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DevPipeReading::IsWritable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
class DevPipeWriting : public DevStream
|
||||
{
|
||||
public:
|
||||
typedef Device BaseClass;
|
||||
|
||||
public:
|
||||
DevPipeWriting(DevStream* stream);
|
||||
~DevPipeWriting();
|
||||
|
||||
private:
|
||||
DevStream* stream;
|
||||
|
||||
public:
|
||||
virtual ssize_t Read(uint8_t* dest, size_t count);
|
||||
virtual ssize_t Write(const uint8_t* src, size_t count);
|
||||
virtual bool IsReadable();
|
||||
virtual bool IsWritable();
|
||||
|
||||
};
|
||||
|
||||
DevPipeWriting::DevPipeWriting(DevStream* stream)
|
||||
{
|
||||
stream->Refer();
|
||||
this->stream = stream;
|
||||
}
|
||||
|
||||
DevPipeWriting::~DevPipeWriting()
|
||||
{
|
||||
((DevPipeStorage*) stream)->NotWriting();
|
||||
stream->Unref();
|
||||
}
|
||||
|
||||
ssize_t DevPipeWriting::Read(uint8_t* /*dest*/, size_t /*count*/)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t DevPipeWriting::Write(const uint8_t* src, size_t count)
|
||||
{
|
||||
return stream->Write(src, count);
|
||||
}
|
||||
|
||||
bool DevPipeWriting::IsReadable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DevPipeWriting::IsWritable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace Pipe
|
||||
{
|
||||
const size_t BUFFER_SIZE = 4096UL;
|
||||
|
||||
int SysPipe(int pipefd[2])
|
||||
{
|
||||
// TODO: Validate that pipefd is a valid user-space array!
|
||||
|
||||
size_t buffersize = BUFFER_SIZE;
|
||||
uint8_t* buffer = new uint8_t[buffersize];
|
||||
if ( !buffer ) { return -1; /* TODO: ENOMEM */ }
|
||||
|
||||
// Transfer ownership of the buffer to the storage device.
|
||||
DevStream* storage = new DevPipeStorage(buffer, buffersize);
|
||||
if ( !storage ) { delete[] buffer; return -1; /* TODO: ENOMEM */ }
|
||||
|
||||
DevStream* reading = new DevPipeReading(storage);
|
||||
if ( !reading ) { delete storage; return -1; /* TODO: ENOMEM */ }
|
||||
|
||||
DevStream* writing = new DevPipeWriting(storage);
|
||||
if ( !writing ) { delete reading; return -1; /* TODO: ENOMEM */ }
|
||||
|
||||
Process* process = CurrentProcess();
|
||||
int readfd = process->descriptors.Allocate(reading, NULL);
|
||||
int writefd = process->descriptors.Allocate(writing, NULL);
|
||||
|
||||
if ( readfd < 0 || writefd < 0 )
|
||||
{
|
||||
if ( 0 <= readfd ) { process->descriptors.Free(readfd); } else { delete reading; }
|
||||
if ( 0 <= writefd ) { process->descriptors.Free(writefd); } else { delete writing; }
|
||||
|
||||
return -1; /* TODO: ENOMEM/EMFILE/ENFILE */
|
||||
}
|
||||
|
||||
pipefd[0] = readfd;
|
||||
pipefd[1] = writefd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
Syscall::Register(SYSCALL_PIPE, (void*) SysPipe);
|
||||
}
|
||||
}
|
||||
if ( !bufferused && !anywriting ) { return 0; }
|
||||
if ( bufferused < count ) { count = bufferused; }
|
||||
size_t amount = count;
|
||||
size_t linear = buffersize - bufferoffset;
|
||||
if ( linear < amount ) { amount = linear; }
|
||||
assert(amount);
|
||||
ctx->copy_to_dest(buf, buffer + bufferoffset, amount);
|
||||
bufferoffset = (bufferoffset + amount) % buffersize;
|
||||
bufferused -= amount;
|
||||
kthread_cond_broadcast(&writecond);
|
||||
return amount;
|
||||
}
|
||||
|
||||
ssize_t PipeChannel::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
||||
{
|
||||
ScopedLockSignal lock(&pipelock);
|
||||
if ( !lock.IsAcquired() ) { errno = EINTR; return -1; }
|
||||
while ( anyreading && bufferused == buffersize )
|
||||
{
|
||||
if ( !kthread_cond_wait_signal(&writecond, &pipelock) )
|
||||
{
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if ( !anyreading )
|
||||
{
|
||||
CurrentThread()->DeliverSignal(SIGPIPE);
|
||||
errno = EPIPE;
|
||||
return -1;
|
||||
}
|
||||
if ( buffersize - bufferused < count ) { count = buffersize - bufferused; }
|
||||
size_t writeoffset = (bufferoffset + bufferused) % buffersize;
|
||||
size_t amount = count;
|
||||
size_t linear = buffersize - writeoffset;
|
||||
if ( linear < amount ) { amount = linear; }
|
||||
assert(amount);
|
||||
ctx->copy_from_src(buffer + writeoffset, buf, amount);
|
||||
bufferused += amount;
|
||||
kthread_cond_broadcast(&readcond);
|
||||
return amount;
|
||||
}
|
||||
|
||||
class PipeEndpoint : public AbstractInode
|
||||
{
|
||||
public:
|
||||
PipeEndpoint(dev_t dev, uid_t owner, gid_t group, mode_t mode,
|
||||
PipeChannel* channel, bool reading);
|
||||
~PipeEndpoint();
|
||||
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
||||
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
||||
|
||||
private:
|
||||
kthread_mutex_t pipelock;
|
||||
PipeChannel* channel;
|
||||
bool reading;
|
||||
|
||||
};
|
||||
|
||||
PipeEndpoint::PipeEndpoint(dev_t dev, uid_t owner, gid_t group, mode_t mode,
|
||||
PipeChannel* channel, bool reading)
|
||||
{
|
||||
inode_type = INODE_TYPE_STREAM;
|
||||
this->dev = dev;
|
||||
this->ino = (ino_t) this;
|
||||
this->channel = channel;
|
||||
this->reading = reading;
|
||||
if ( reading )
|
||||
channel->StartReading();
|
||||
else
|
||||
channel->StartWriting();
|
||||
pipelock = KTHREAD_MUTEX_INITIALIZER;
|
||||
this->stat_uid = owner;
|
||||
this->stat_gid = group;
|
||||
this->type = S_IFCHR;
|
||||
this->stat_mode = (mode & S_SETABLE) | this->type;
|
||||
}
|
||||
|
||||
PipeEndpoint::~PipeEndpoint()
|
||||
{
|
||||
if ( reading )
|
||||
channel->CloseReading();
|
||||
else
|
||||
channel->CloseWriting();
|
||||
}
|
||||
|
||||
ssize_t PipeEndpoint::read(ioctx_t* ctx, uint8_t* buf, size_t count)
|
||||
{
|
||||
if ( !reading ) { errno = EBADF; return -1; }
|
||||
return channel->read(ctx, buf, count);
|
||||
}
|
||||
|
||||
ssize_t PipeEndpoint::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
||||
{
|
||||
if ( reading ) { errno = EBADF; return -1; }
|
||||
return channel->write(ctx, buf, count);
|
||||
}
|
||||
|
||||
namespace Pipe {
|
||||
|
||||
const size_t BUFFER_SIZE = 4096UL;
|
||||
|
||||
static int sys_pipe(int pipefd[2])
|
||||
{
|
||||
Process* process = CurrentProcess();
|
||||
uid_t uid = process->uid;
|
||||
uid_t gid = process->gid;
|
||||
mode_t mode = 0600;
|
||||
|
||||
size_t buffersize = BUFFER_SIZE;
|
||||
uint8_t* buffer = new uint8_t[buffersize];
|
||||
if ( !buffer ) return -1;
|
||||
|
||||
PipeChannel* channel = new PipeChannel(buffer, buffersize);
|
||||
if ( !channel ) { delete[] buffer; return -1; }
|
||||
|
||||
Ref<Inode> recv_inode(new PipeEndpoint(0, uid, gid, mode, channel, true));
|
||||
if ( !recv_inode ) { delete channel; return -1; }
|
||||
Ref<Inode> send_inode(new PipeEndpoint(0, uid, gid, mode, channel, false));
|
||||
if ( !send_inode ) return -1;
|
||||
|
||||
Ref<Vnode> recv_vnode(new Vnode(recv_inode, Ref<Vnode>(NULL), 0, 0));
|
||||
Ref<Vnode> send_vnode(new Vnode(send_inode, Ref<Vnode>(NULL), 0, 0));
|
||||
if ( !recv_vnode || !send_vnode ) return -1;
|
||||
|
||||
Ref<Descriptor> recv_desc(new Descriptor(recv_vnode, 0));
|
||||
Ref<Descriptor> send_desc(new Descriptor(send_vnode, 0));
|
||||
if ( !recv_desc || !send_desc ) return -1;
|
||||
|
||||
Ref<DescriptorTable> dtable = process->GetDTable();
|
||||
|
||||
int recv_index, send_index;
|
||||
if ( 0 <= (recv_index = dtable->Allocate(recv_desc, 0)) )
|
||||
{
|
||||
if ( 0 <= (send_index = dtable->Allocate(send_desc, 0)) )
|
||||
{
|
||||
int ret[2] = { recv_index, send_index };
|
||||
if ( CopyToUser(pipefd, ret, sizeof(ret)) )
|
||||
return 0;
|
||||
|
||||
dtable->Free(send_index);
|
||||
}
|
||||
dtable->Free(recv_index);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
Syscall::Register(SYSCALL_PIPE, (void*) sys_pipe);
|
||||
}
|
||||
|
||||
} // namespace Pipe
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -22,18 +22,19 @@
|
|||
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
#ifndef SORTIX_PIPE_H
|
||||
#define SORTIX_PIPE_H
|
||||
|
||||
#include "stream.h"
|
||||
namespace Sortix {
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
namespace Pipe
|
||||
{
|
||||
void Init();
|
||||
}
|
||||
}
|
||||
class Inode;
|
||||
|
||||
namespace Pipe {
|
||||
|
||||
void Init();
|
||||
bool CreatePipes(Inode* pipes[2]);
|
||||
|
||||
} // namespace Pipe
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -24,11 +24,19 @@
|
|||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
#include <sortix/kernel/ioctx.h>
|
||||
#include <sortix/kernel/copy.h>
|
||||
#include <sortix/kernel/descriptor.h>
|
||||
#include <sortix/kernel/dtable.h>
|
||||
#include <sortix/kernel/mtable.h>
|
||||
#include <sortix/kernel/worker.h>
|
||||
#include <sortix/kernel/memorymanagement.h>
|
||||
#include <sortix/kernel/string.h>
|
||||
#include <sortix/signal.h>
|
||||
#include <sortix/unistd.h>
|
||||
#include <sortix/fcntl.h>
|
||||
#include <sortix/stat.h>
|
||||
#include <sortix/fork.h>
|
||||
#include <sortix/mman.h>
|
||||
#include <sortix/wait.h>
|
||||
|
@ -38,10 +46,6 @@
|
|||
#include <string.h>
|
||||
#include "thread.h"
|
||||
#include "process.h"
|
||||
#include "device.h"
|
||||
#include "stream.h"
|
||||
#include "filesystem.h"
|
||||
#include "directory.h"
|
||||
#include "scheduler.h"
|
||||
#include "initrd.h"
|
||||
#include "elf.h"
|
||||
|
@ -113,7 +117,7 @@ namespace Sortix
|
|||
nozombify = false;
|
||||
firstthread = NULL;
|
||||
threadlock = KTHREAD_MUTEX_INITIALIZER;
|
||||
workingdir = NULL;
|
||||
ptrlock = KTHREAD_MUTEX_INITIALIZER;
|
||||
mmapfrom = 0x80000000UL;
|
||||
exitstatus = -1;
|
||||
pid = AllocatePID();
|
||||
|
@ -126,9 +130,30 @@ namespace Sortix
|
|||
assert(!firstchild);
|
||||
assert(!addrspace);
|
||||
assert(!segments);
|
||||
assert(!dtable);
|
||||
assert(!mtable);
|
||||
assert(!cwd);
|
||||
assert(!root);
|
||||
|
||||
Remove(this);
|
||||
delete[] workingdir;
|
||||
}
|
||||
|
||||
void Process::BootstrapTables(Ref<DescriptorTable> dtable, Ref<MountTable> mtable)
|
||||
{
|
||||
ScopedLock lock(&ptrlock);
|
||||
assert(!this->dtable);
|
||||
assert(!this->mtable);
|
||||
this->dtable = dtable;
|
||||
this->mtable = mtable;
|
||||
}
|
||||
|
||||
void Process::BootstrapDirectories(Ref<Descriptor> root)
|
||||
{
|
||||
ScopedLock lock(&ptrlock);
|
||||
assert(!this->root);
|
||||
assert(!this->cwd);
|
||||
this->root = root;
|
||||
this->cwd = root;
|
||||
}
|
||||
|
||||
void Process__OnLastThreadExit(void* user);
|
||||
|
@ -205,7 +230,11 @@ namespace Sortix
|
|||
addr_t prevaddrspace = curthread->SwitchAddressSpace(addrspace);
|
||||
|
||||
ResetAddressSpace();
|
||||
descriptors.Reset();
|
||||
|
||||
if ( dtable ) dtable.Reset();
|
||||
if ( cwd ) cwd.Reset();
|
||||
if ( root ) root.Reset();
|
||||
if ( mtable ) mtable.Reset();
|
||||
|
||||
// Destroy the address space and safely switch to the replacement
|
||||
// address space before things get dangerous.
|
||||
|
@ -436,6 +465,48 @@ namespace Sortix
|
|||
firstchild = child;
|
||||
}
|
||||
|
||||
Ref<MountTable> Process::GetMTable()
|
||||
{
|
||||
ScopedLock lock(&ptrlock);
|
||||
assert(mtable);
|
||||
return mtable;
|
||||
}
|
||||
|
||||
Ref<DescriptorTable> Process::GetDTable()
|
||||
{
|
||||
ScopedLock lock(&ptrlock);
|
||||
assert(dtable);
|
||||
return dtable;
|
||||
}
|
||||
|
||||
Ref<Descriptor> Process::GetRoot()
|
||||
{
|
||||
ScopedLock lock(&ptrlock);
|
||||
assert(root);
|
||||
return root;
|
||||
}
|
||||
|
||||
Ref<Descriptor> Process::GetCWD()
|
||||
{
|
||||
ScopedLock lock(&ptrlock);
|
||||
assert(cwd);
|
||||
return cwd;
|
||||
}
|
||||
|
||||
void Process::SetCWD(Ref<Descriptor> newcwd)
|
||||
{
|
||||
ScopedLock lock(&ptrlock);
|
||||
assert(newcwd);
|
||||
cwd = newcwd;
|
||||
}
|
||||
|
||||
Ref<Descriptor> Process::GetDescriptor(int fd)
|
||||
{
|
||||
ScopedLock lock(&ptrlock);
|
||||
assert(dtable);
|
||||
return dtable->Get(fd);
|
||||
}
|
||||
|
||||
Process* Process::Fork()
|
||||
{
|
||||
assert(CurrentProcess() == this);
|
||||
|
@ -475,16 +546,30 @@ namespace Sortix
|
|||
// Remember the relation to the child process.
|
||||
AddChildProcess(clone);
|
||||
|
||||
bool failure = false;
|
||||
|
||||
if ( !descriptors.Fork(&clone->descriptors) )
|
||||
failure = true;
|
||||
|
||||
// Initialize everything that is safe and can't fail.
|
||||
clone->mmapfrom = mmapfrom;
|
||||
|
||||
clone->workingdir = NULL;
|
||||
if ( workingdir && !(clone->workingdir = String::Clone(workingdir)) )
|
||||
kthread_mutex_lock(&ptrlock);
|
||||
clone->root = root;
|
||||
clone->cwd = cwd;
|
||||
kthread_mutex_unlock(&ptrlock);
|
||||
|
||||
// Initialize things that can fail and abort if needed.
|
||||
bool failure = false;
|
||||
|
||||
kthread_mutex_lock(&ptrlock);
|
||||
if ( !(clone->dtable = dtable->Fork()) )
|
||||
failure = true;
|
||||
//if ( !(clone->mtable = mtable->Fork()) )
|
||||
// failure = true;
|
||||
clone->mtable = mtable;
|
||||
kthread_mutex_unlock(&ptrlock);
|
||||
|
||||
if ( pid == 1)
|
||||
assert(dtable->Get(1));
|
||||
|
||||
if ( pid == 1)
|
||||
assert(clone->dtable->Get(1));
|
||||
|
||||
// If the proces creation failed, ask the process to commit suicide and
|
||||
// not become a zombie, as we don't wait for it to exit. It will clean
|
||||
|
@ -560,27 +645,20 @@ namespace Sortix
|
|||
|
||||
stackpos = envppos - envpsize;
|
||||
|
||||
descriptors.OnExecute();
|
||||
dtable->OnExecute();
|
||||
|
||||
ExecuteCPU(argc, stackargv, envc, stackenvp, stackpos, entry, regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DevBuffer* OpenProgramImage(const char* progname, const char* wd, const char* path)
|
||||
// TODO. This is a hack. Please remove this when execve is moved to another
|
||||
// file/class, it doesn't belong here, it's a program loader ffs!
|
||||
Ref<Descriptor> Process::Open(ioctx_t* ctx, const char* path, int flags, mode_t mode)
|
||||
{
|
||||
(void) wd;
|
||||
(void) path;
|
||||
char* abs = Directory::MakeAbsolute("/", progname);
|
||||
if ( !abs ) { errno = ENOMEM; return NULL; }
|
||||
|
||||
// TODO: Use O_EXEC here!
|
||||
Device* dev = FileSystem::Open(abs, O_RDONLY, 0);
|
||||
delete[] abs;
|
||||
|
||||
if ( !dev ) { return NULL; }
|
||||
if ( !dev->IsType(Device::BUFFER) ) { errno = EACCES; dev->Unref(); return NULL; }
|
||||
return (DevBuffer*) dev;
|
||||
// TODO: Locking the root/cwd pointers. How should that be arranged?
|
||||
Ref<Descriptor> dir = path[0] == '/' ? root : cwd;
|
||||
return dir->open(ctx, path, flags, mode);
|
||||
}
|
||||
|
||||
int SysExecVE(const char* _filename, char* const _argv[], char* const _envp[])
|
||||
|
@ -590,8 +668,9 @@ namespace Sortix
|
|||
int envc;
|
||||
char** argv;
|
||||
char** envp;
|
||||
DevBuffer* dev;
|
||||
uintmax_t needed;
|
||||
ioctx_t ctx;
|
||||
Ref<Descriptor> desc;
|
||||
struct stat st;
|
||||
size_t sofar;
|
||||
size_t count;
|
||||
uint8_t* buffer;
|
||||
|
@ -627,24 +706,25 @@ namespace Sortix
|
|||
if ( !envp[i] ) { goto cleanup_envp; }
|
||||
}
|
||||
|
||||
dev = OpenProgramImage(filename, process->workingdir, "/bin");
|
||||
if ( !dev ) { goto cleanup_envp; }
|
||||
SetupKernelIOCtx(&ctx);
|
||||
|
||||
dev->Refer(); // TODO: Rules of GC may change soon.
|
||||
needed = dev->Size();
|
||||
if ( SIZE_MAX < needed ) { errno = ENOMEM; goto cleanup_dev; }
|
||||
// TODO: Somehow mark the executable as busy and don't permit writes?
|
||||
desc = process->Open(&ctx, filename, O_RDONLY, 0);
|
||||
if ( !desc ) { goto cleanup_envp; }
|
||||
|
||||
if ( !dev->IsReadable() ) { errno = EBADF; goto cleanup_dev; }
|
||||
if ( desc->stat(&ctx, &st) ) { goto cleanup_desc; }
|
||||
if ( st.st_size < 0 ) { errno = EINVAL; goto cleanup_desc; }
|
||||
if ( SIZE_MAX < (uintmax_t) st.st_size ) { errno = ERANGE; goto cleanup_desc; }
|
||||
|
||||
count = needed;
|
||||
count = (size_t) st.st_size;
|
||||
buffer = new uint8_t[count];
|
||||
if ( !buffer ) { goto cleanup_dev; }
|
||||
if ( !buffer ) { goto cleanup_desc; }
|
||||
sofar = 0;
|
||||
while ( sofar < count )
|
||||
{
|
||||
ssize_t bytesread = dev->Read(buffer + sofar, count - sofar);
|
||||
ssize_t bytesread = desc->read(&ctx, buffer + sofar, count - sofar);
|
||||
if ( bytesread < 0 ) { goto cleanup_buffer; }
|
||||
if ( bytesread == 0 ) { errno = EEOF; return -1; }
|
||||
if ( bytesread == 0 ) { errno = EEOF; goto cleanup_buffer; }
|
||||
sofar += bytesread;
|
||||
}
|
||||
|
||||
|
@ -653,8 +733,8 @@ namespace Sortix
|
|||
|
||||
cleanup_buffer:
|
||||
delete[] buffer;
|
||||
cleanup_dev:
|
||||
dev->Unref();
|
||||
cleanup_desc:
|
||||
desc.Reset();
|
||||
cleanup_envp:
|
||||
for ( int i = 0; i < envc; i++) { delete[] envp[i]; }
|
||||
delete[] envp;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -25,16 +25,21 @@
|
|||
#ifndef SORTIX_PROCESS_H
|
||||
#define SORTIX_PROCESS_H
|
||||
|
||||
#include "descriptors.h"
|
||||
#include "cpu.h"
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
#include <sortix/fork.h>
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
class Thread;
|
||||
class Process;
|
||||
class Descriptor;
|
||||
class DescriptorTable;
|
||||
class MountTable;
|
||||
struct ProcessSegment;
|
||||
struct ioctx_struct;
|
||||
typedef struct ioctx_struct ioctx_t;
|
||||
|
||||
const int SEG_NONE = 0;
|
||||
const int SEG_TEXT = 1;
|
||||
|
@ -76,8 +81,28 @@ namespace Sortix
|
|||
|
||||
public:
|
||||
addr_t addrspace;
|
||||
char* workingdir;
|
||||
pid_t pid;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
|
||||
private:
|
||||
kthread_mutex_t ptrlock;
|
||||
Ref<Descriptor> root;
|
||||
Ref<Descriptor> cwd;
|
||||
Ref<MountTable> mtable;
|
||||
Ref<DescriptorTable> dtable;
|
||||
|
||||
public:
|
||||
void BootstrapTables(Ref<DescriptorTable> dtable, Ref<MountTable> mtable);
|
||||
void BootstrapDirectories(Ref<Descriptor> root);
|
||||
Ref<MountTable> GetMTable();
|
||||
Ref<DescriptorTable> GetDTable();
|
||||
Ref<Descriptor> GetRoot();
|
||||
Ref<Descriptor> GetCWD();
|
||||
Ref<Descriptor> GetDescriptor(int fd);
|
||||
// TODO: This should be removed, don't call it.
|
||||
Ref<Descriptor> Open(ioctx_t* ctx, const char* path, int flags, mode_t mode = 0);
|
||||
void SetCWD(Ref<Descriptor> newcwd);
|
||||
|
||||
private:
|
||||
// A process may only access its parent if parentlock is locked. A process
|
||||
|
@ -102,7 +127,6 @@ namespace Sortix
|
|||
kthread_mutex_t threadlock;
|
||||
|
||||
public:
|
||||
DescriptorTable descriptors;
|
||||
ProcessSegment* segments;
|
||||
|
||||
public:
|
||||
|
|
|
@ -29,32 +29,38 @@
|
|||
|
||||
namespace Sortix {
|
||||
|
||||
Refcounted::Refcounted()
|
||||
Refcountable::Refcountable()
|
||||
{
|
||||
reflock = KTHREAD_MUTEX_INITIALIZER;
|
||||
refcount = 1;
|
||||
refcount = 0;
|
||||
being_deleted = false;
|
||||
}
|
||||
|
||||
Refcounted::~Refcounted()
|
||||
Refcountable::~Refcountable()
|
||||
{
|
||||
// It's OK to be deleted if our refcount is 1, it won't mess with any
|
||||
// other owners that might need us.
|
||||
assert(refcount <= 1);
|
||||
}
|
||||
|
||||
void Refcounted::Refer()
|
||||
void Refcountable::Refer_Renamed()
|
||||
{
|
||||
ScopedLock lock(&reflock);
|
||||
refcount++;
|
||||
}
|
||||
|
||||
void Refcounted::Unref()
|
||||
void Refcountable::Unref_Renamed()
|
||||
{
|
||||
assert(!being_deleted);
|
||||
kthread_mutex_lock(&reflock);
|
||||
bool deleteme = !--refcount;
|
||||
assert(refcount);
|
||||
bool deleteme = !refcount || !--refcount;
|
||||
kthread_mutex_unlock(&reflock);
|
||||
if ( deleteme )
|
||||
{
|
||||
being_deleted = true;
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -39,6 +39,9 @@
|
|||
namespace Sortix {
|
||||
namespace Scheduler {
|
||||
|
||||
const uint32_t SCHED_MAGIC = 0x1234567;
|
||||
|
||||
volatile unsigned long premagic;
|
||||
static Thread* currentthread;
|
||||
} // namespace Scheduler
|
||||
Thread* CurrentThread() { return Scheduler::currentthread; }
|
||||
|
@ -51,6 +54,7 @@ Thread* idlethread;
|
|||
Thread* firstrunnablethread;
|
||||
Thread* firstsleepingthread;
|
||||
Process* initprocess;
|
||||
volatile unsigned long postmagic;
|
||||
|
||||
static inline void SetCurrentThread(Thread* newcurrentthread)
|
||||
{
|
||||
|
@ -71,6 +75,8 @@ static Thread* PopNextThread()
|
|||
|
||||
static Thread* ValidatedPopNextThread()
|
||||
{
|
||||
assert(premagic == SCHED_MAGIC);
|
||||
assert(postmagic == SCHED_MAGIC);
|
||||
Thread* nextthread = PopNextThread();
|
||||
if ( !nextthread ) { Panic("Had no thread to switch to."); }
|
||||
if ( nextthread->terminated )
|
||||
|
@ -120,9 +126,13 @@ static void DoActualSwitch(CPU::InterruptRegisters* regs)
|
|||
|
||||
void Switch(CPU::InterruptRegisters* regs)
|
||||
{
|
||||
assert(premagic == SCHED_MAGIC);
|
||||
assert(postmagic == SCHED_MAGIC);
|
||||
DoActualSwitch(regs);
|
||||
if ( regs->signal_pending && regs->InUserspace() )
|
||||
Signal::Dispatch(regs);
|
||||
assert(premagic == SCHED_MAGIC);
|
||||
assert(postmagic == SCHED_MAGIC);
|
||||
}
|
||||
|
||||
const bool DEBUG_BEGINCTXSWITCH = false;
|
||||
|
@ -271,6 +281,8 @@ extern "C" void thread_exit_handler();
|
|||
|
||||
void Init()
|
||||
{
|
||||
premagic = postmagic = SCHED_MAGIC;
|
||||
|
||||
// We use a dummy so that the first context switch won't crash when the
|
||||
// current thread is accessed. This lets us avoid checking whether it is
|
||||
// NULL (which it only will be once), which gives simpler code.
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/log.h>
|
||||
#include <sortix/kernel/keyboard.h>
|
||||
#include <string.h>
|
||||
#include "vga.h"
|
||||
#include "keyboard.h"
|
||||
#include "uart.h"
|
||||
#include "serialterminal.h"
|
||||
#include "scheduler.h"
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
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/>.
|
||||
|
||||
stream.h
|
||||
Various device types that provides a sequence of bytes.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_STREAM_H
|
||||
#define SORTIX_STREAM_H
|
||||
|
||||
#include "device.h"
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
class DevStream : public Device
|
||||
{
|
||||
public:
|
||||
typedef Device BaseClass;
|
||||
|
||||
public:
|
||||
virtual bool IsType(unsigned type) const { return type == Device::STREAM; }
|
||||
|
||||
public:
|
||||
virtual ssize_t Read(uint8_t* dest, size_t count) = 0;
|
||||
virtual ssize_t Write(const uint8_t* src, size_t count) = 0;
|
||||
virtual bool IsReadable() = 0;
|
||||
virtual bool IsWritable() = 0;
|
||||
|
||||
};
|
||||
|
||||
class DevBuffer : public DevStream
|
||||
{
|
||||
public:
|
||||
typedef DevStream BaseClass;
|
||||
|
||||
public:
|
||||
virtual bool IsType(unsigned type) const
|
||||
{
|
||||
return type == Device::BUFFER || BaseClass::IsType(type);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual size_t BlockSize() = 0;
|
||||
virtual uintmax_t Size() = 0;
|
||||
virtual uintmax_t Position() = 0;
|
||||
virtual bool Seek(uintmax_t position) = 0;
|
||||
virtual bool Resize(uintmax_t size) = 0;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,89 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
|
||||
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/>.
|
||||
|
||||
terminal.cpp
|
||||
Provides an interface to terminals for user-space.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/termios.h>
|
||||
#include <errno.h>
|
||||
#include "syscall.h"
|
||||
#include "process.h"
|
||||
#include "terminal.h"
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
int SysSetTermMode(int fd, unsigned mode)
|
||||
{
|
||||
Process* process = CurrentProcess();
|
||||
Device* dev = process->descriptors.Get(fd);
|
||||
if ( !dev ) { errno = EBADF; return -1; }
|
||||
if ( !dev->IsType(Device::TERMINAL) ) { errno = ENOTTY; return -1; }
|
||||
DevTerminal* term = (DevTerminal*) dev;
|
||||
return term->SetMode(mode) ? 0 : -1;
|
||||
}
|
||||
|
||||
int SysGetTermMode(int fd, unsigned* mode)
|
||||
{
|
||||
Process* process = CurrentProcess();
|
||||
Device* dev = process->descriptors.Get(fd);
|
||||
if ( !dev ) { errno = EBADF; return -1; }
|
||||
if ( !dev->IsType(Device::TERMINAL) ) { errno = ENOTTY; return -1; }
|
||||
DevTerminal* term = (DevTerminal*) dev;
|
||||
// TODO: Check that mode is a valid user-space pointer.
|
||||
*mode = term->GetMode();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SysIsATTY(int fd)
|
||||
{
|
||||
Process* process = CurrentProcess();
|
||||
Device* dev = process->descriptors.Get(fd);
|
||||
if ( !dev ) { errno = EBADF; return 0; }
|
||||
if ( !dev->IsType(Device::TERMINAL) ) { errno = ENOTTY; return 0; }
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SysTCGetWinSize(int fd, struct winsize* ws)
|
||||
{
|
||||
Process* process = CurrentProcess();
|
||||
Device* dev = process->descriptors.Get(fd);
|
||||
if ( !dev ) { errno = EBADF; return -1; }
|
||||
if ( !dev->IsType(Device::TERMINAL) ) { errno = ENOTTY; return -1; }
|
||||
DevTerminal* term = (DevTerminal*) dev;
|
||||
struct winsize ret;
|
||||
ret.ws_col = term->GetWidth();
|
||||
ret.ws_row = term->GetHeight();
|
||||
ret.ws_xpixel = 0; // Not supported by DevTerminal interface.
|
||||
ret.ws_ypixel = 0; // Not supported by DevTerminal interface.
|
||||
// TODO: Check that ws is a valid user-space pointer.
|
||||
*ws = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Terminal::Init()
|
||||
{
|
||||
Syscall::Register(SYSCALL_SETTERMMODE, (void*) SysSetTermMode);
|
||||
Syscall::Register(SYSCALL_GETTERMMODE, (void*) SysGetTermMode);
|
||||
Syscall::Register(SYSCALL_ISATTY, (void*) SysIsATTY);
|
||||
Syscall::Register(SYSCALL_TCGETWINSIZE, (void*) SysTCGetWinSize);
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
|
||||
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/>.
|
||||
|
||||
terminal.h
|
||||
Reads data from an input source (such as a keyboard), optionally does line-
|
||||
buffering, and redirects data to an output device (such as the VGA).
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_TERMINAL_H
|
||||
#define SORTIX_TERMINAL_H
|
||||
|
||||
#include "device.h"
|
||||
#include "stream.h"
|
||||
#include <sortix/termmode.h>
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
class DevTerminal : public DevStream
|
||||
{
|
||||
public:
|
||||
typedef DevStream BaseClass;
|
||||
|
||||
public:
|
||||
virtual bool IsType(unsigned type) const
|
||||
{
|
||||
return type == Device::TERMINAL || BaseClass::IsType(type);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual bool SetMode(unsigned mode) = 0;
|
||||
virtual bool SetWidth(unsigned width) = 0;
|
||||
virtual bool SetHeight(unsigned height) = 0;
|
||||
virtual unsigned GetMode() const = 0;
|
||||
virtual unsigned GetWidth() const = 0;
|
||||
virtual unsigned GetHeight() const = 0;
|
||||
|
||||
};
|
||||
|
||||
namespace Terminal
|
||||
{
|
||||
void Init();
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -33,9 +33,9 @@ namespace Sortix {
|
|||
const uint16_t DEFAULT_COLOR = COLOR8_LIGHT_GREY << 0U | COLOR8_BLACK << 4U;
|
||||
const uint16_t ATTR_CHAR = 1U << 0U;
|
||||
|
||||
TextTerminal::TextTerminal(TextBufferHandle* textbufhandle)
|
||||
TextTerminal::TextTerminal(Ref<TextBufferHandle> textbufhandle)
|
||||
{
|
||||
this->textbufhandle = textbufhandle; textbufhandle->Refer();
|
||||
this->textbufhandle = textbufhandle;
|
||||
this->termlock = KTHREAD_MUTEX_INITIALIZER;
|
||||
Reset();
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#define SORTIX_TEXTTERMINAL_H
|
||||
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
|
@ -34,7 +35,7 @@ class TextBufferHandle;
|
|||
class TextTerminal //: public Printable ?
|
||||
{
|
||||
public:
|
||||
TextTerminal(TextBufferHandle* textbufhandle);
|
||||
TextTerminal(Ref<TextBufferHandle> textbufhandle);
|
||||
~TextTerminal();
|
||||
size_t Print(const char* string, size_t stringlen);
|
||||
size_t Width() const;
|
||||
|
@ -52,7 +53,7 @@ private:
|
|||
void Reset();
|
||||
|
||||
private:
|
||||
mutable TextBufferHandle* textbufhandle;
|
||||
mutable Ref<TextBufferHandle> textbufhandle;
|
||||
mutable kthread_mutex_t termlock;
|
||||
uint8_t vgacolor;
|
||||
unsigned column;
|
||||
|
|
113
sortix/vga.cpp
113
sortix/vga.cpp
|
@ -23,15 +23,19 @@
|
|||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
#include <sortix/kernel/ioctx.h>
|
||||
#include <sortix/kernel/inode.h>
|
||||
#include <sortix/kernel/descriptor.h>
|
||||
#include <sortix/kernel/interlock.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "fs/util.h"
|
||||
#include "fs/devfs.h"
|
||||
#include "vga.h"
|
||||
#include "scheduler.h"
|
||||
#include "syscall.h"
|
||||
#include "process.h"
|
||||
#include "serialterminal.h"
|
||||
|
||||
#define TEST_VGAFONT 0
|
||||
|
||||
|
@ -119,7 +123,7 @@ const uint8_t* GetFont()
|
|||
return vgafont;
|
||||
}
|
||||
|
||||
void Init()
|
||||
void Init(const char* devpath, Ref<Descriptor> slashdev)
|
||||
{
|
||||
vgafontsize = VGA_FONT_NUMCHARS * VGA_FONT_CHARSIZE;
|
||||
if ( !(vgafont = new uint8_t[vgafontsize]) )
|
||||
|
@ -129,12 +133,25 @@ void Init()
|
|||
PrintFontChar(vgafont, 'A');
|
||||
PrintFontChar(vgafont, 'S');
|
||||
#endif
|
||||
DevMemoryBuffer* vgamembuf = new DevMemoryBuffer(vgafont, vgafontsize,
|
||||
false, false);
|
||||
if ( !vgamembuf )
|
||||
Panic("Unable to allocate vga font filesystem object");
|
||||
if ( !DeviceFS::RegisterDevice("vgafont", vgamembuf) )
|
||||
Panic("Unable to register vga font filesystem object");
|
||||
|
||||
ioctx_t ctx; SetupKernelIOCtx(&ctx);
|
||||
|
||||
// Setup the vgafont device.
|
||||
Ref<Inode> vgafontnode(new UtilMemoryBuffer(slashdev->dev, (ino_t) 0, 0, 0,
|
||||
0660, vgafont, vgafontsize,
|
||||
false, false));
|
||||
if ( !vgafontnode )
|
||||
PanicF("Unable to allocate %s/vgafont inode.", devpath);
|
||||
if ( LinkInodeInDir(&ctx, slashdev, "vgafont", vgafontnode) != 0 )
|
||||
PanicF("Unable to link %s/vgafont to vga font.", devpath);
|
||||
|
||||
// Setup the vga device.
|
||||
Ref<Inode> vganode(new UtilMemoryBuffer(slashdev->dev, (ino_t) 0, 0, 0,
|
||||
0660, VGA, VGA_SIZE, true, false));
|
||||
if ( !vganode )
|
||||
PanicF("Unable to allocate %s/vga inode.", devpath);
|
||||
if ( LinkInodeInDir(&ctx, slashdev, "vga", vganode) != 0 )
|
||||
PanicF("Unable to link %s/vga to vga.", devpath);
|
||||
}
|
||||
|
||||
// Changes the position of the hardware cursor.
|
||||
|
@ -153,82 +170,4 @@ void SetCursor(unsigned x, unsigned y)
|
|||
}
|
||||
|
||||
} // namespace VGA
|
||||
|
||||
DevVGA::DevVGA()
|
||||
{
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
DevVGA::~DevVGA()
|
||||
{
|
||||
#ifdef PLATFORM_SERIAL
|
||||
// TODO: HACK: This is a hack that is unrelated to this file.
|
||||
// This is a hack to make the cursor a proper color after the vga buffer
|
||||
// has been radically modified. The best solution would be for the VGA
|
||||
// to ANSI Escape Codes converter to keep track of colors and restoring
|
||||
// them, but this will do for now.
|
||||
Log::PrintF("\e[m");
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t DevVGA::Read(uint8_t* dest, size_t count)
|
||||
{
|
||||
if ( VGA::VGA_SIZE - offset < count ) { count = VGA::VGA_SIZE - offset; }
|
||||
memcpy(dest, VGA::VGA + offset, count);
|
||||
offset += count;
|
||||
return count;
|
||||
}
|
||||
|
||||
ssize_t DevVGA::Write(const uint8_t* src, size_t count)
|
||||
{
|
||||
if ( offset == VGA::VGA_SIZE && count ) { errno = ENOSPC; return -1; }
|
||||
if ( VGA::VGA_SIZE - offset < count ) { count = VGA::VGA_SIZE - offset; }
|
||||
memcpy(VGA::VGA + offset, src, count);
|
||||
offset = (offset + count) % VGA::VGA_SIZE;
|
||||
VGA::SetCursor(VGA::WIDTH, VGA::HEIGHT-1);
|
||||
#ifdef PLATFORM_SERIAL
|
||||
SerialTerminal::OnVGAModified();
|
||||
#endif
|
||||
return count;
|
||||
}
|
||||
|
||||
bool DevVGA::IsReadable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DevVGA::IsWritable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t DevVGA::BlockSize()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
uintmax_t DevVGA::Size()
|
||||
{
|
||||
return VGA::VGA_SIZE;
|
||||
}
|
||||
|
||||
uintmax_t DevVGA::Position()
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
|
||||
bool DevVGA::Seek(uintmax_t position)
|
||||
{
|
||||
if ( VGA::VGA_SIZE < position ) { errno = EINVAL; return false; }
|
||||
offset = position;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DevVGA::Resize(uintmax_t size)
|
||||
{
|
||||
if ( size == VGA::VGA_SIZE ) { return false; }
|
||||
errno = ENOSPC;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
||||
|
|
34
sortix/vga.h
34
sortix/vga.h
|
@ -25,11 +25,12 @@
|
|||
#ifndef SORTIX_VGA_H
|
||||
#define SORTIX_VGA_H
|
||||
|
||||
#include "device.h"
|
||||
#include "stream.h"
|
||||
#include <sortix/kernel/refcount.h>
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
class Descriptor;
|
||||
|
||||
const size_t VGA_FONT_WIDTH = 8UL;
|
||||
const size_t VGA_FONT_HEIGHT = 16UL;
|
||||
const size_t VGA_FONT_NUMCHARS = 256UL;
|
||||
|
@ -37,39 +38,12 @@ const size_t VGA_FONT_CHARSIZE = VGA_FONT_WIDTH * VGA_FONT_HEIGHT / 8UL;
|
|||
|
||||
namespace VGA {
|
||||
|
||||
void Init();
|
||||
void Init(const char* devpath, Ref<Descriptor> slashdev);
|
||||
void SetCursor(unsigned x, unsigned y);
|
||||
const uint8_t* GetFont();
|
||||
|
||||
} // namespace VGA
|
||||
|
||||
// TODO: This class shouldn't be exposed publicly; it is used in a hack in the
|
||||
// /dev filesystem. However, vga.cpp should register /dev/vga instead.
|
||||
class DevVGA : public DevBuffer
|
||||
{
|
||||
public:
|
||||
typedef DevBuffer BaseClass;
|
||||
|
||||
public:
|
||||
DevVGA();
|
||||
virtual ~DevVGA();
|
||||
|
||||
private:
|
||||
size_t offset;
|
||||
|
||||
public:
|
||||
virtual ssize_t Read(uint8_t* dest, size_t count);
|
||||
virtual ssize_t Write(const uint8_t* src, size_t count);
|
||||
virtual bool IsReadable();
|
||||
virtual bool IsWritable();
|
||||
virtual size_t BlockSize();
|
||||
virtual uintmax_t Size();
|
||||
virtual uintmax_t Position();
|
||||
virtual bool Seek(uintmax_t position);
|
||||
virtual bool Resize(uintmax_t size);
|
||||
|
||||
};
|
||||
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
||||
|
|
|
@ -105,9 +105,9 @@ size_t currentdrvid;
|
|||
bool newdrivers;
|
||||
|
||||
kthread_mutex_t videolock;
|
||||
TextBufferHandle* textbufhandle;
|
||||
Ref<TextBufferHandle> textbufhandle;
|
||||
|
||||
void Init(TextBufferHandle* thetextbufhandle)
|
||||
void Init(Ref<TextBufferHandle> thetextbufhandle)
|
||||
{
|
||||
videolock = KTHREAD_MUTEX_INITIALIZER;
|
||||
textbufhandle = thetextbufhandle;
|
||||
|
|
216
sortix/vnode.cpp
Normal file
216
sortix/vnode.cpp
Normal file
|
@ -0,0 +1,216 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
|
||||
|
||||
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/>.
|
||||
|
||||
vnode.cpp
|
||||
Nodes in the virtual filesystem.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
#include <sortix/kernel/ioctx.h>
|
||||
#include <sortix/kernel/inode.h>
|
||||
#include <sortix/kernel/vnode.h>
|
||||
#include <sortix/kernel/mtable.h>
|
||||
#include <sortix/mount.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include "process.h"
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
static Ref<Inode> LookupMount(Ref<Inode> inode)
|
||||
{
|
||||
Ref<MountTable> mtable = CurrentProcess()->GetMTable();
|
||||
ScopedLock lock(&mtable->mtablelock);
|
||||
for ( size_t i = 0; i < mtable->nummounts; i++ )
|
||||
{
|
||||
mountpoint_t* mp = mtable->mounts + i;
|
||||
if ( mp->ino != inode->ino || mp->dev != inode->dev )
|
||||
continue;
|
||||
return mp->inode;
|
||||
}
|
||||
return Ref<Inode>(NULL);
|
||||
}
|
||||
|
||||
Vnode::Vnode(Ref<Inode> inode, Ref<Vnode> mountedat, ino_t rootino, dev_t rootdev)
|
||||
{
|
||||
for ( Ref<Vnode> tmp = mountedat; tmp; tmp = tmp->mountedat )
|
||||
assert(tmp != this);
|
||||
this->inode = inode;
|
||||
this->mountedat = mountedat;
|
||||
this->rootino = rootino;
|
||||
this->rootdev = rootdev;
|
||||
this->ino = inode->ino;
|
||||
this->dev = inode->dev;
|
||||
this->type = inode->type;
|
||||
}
|
||||
|
||||
Vnode::~Vnode()
|
||||
{
|
||||
}
|
||||
|
||||
Ref<Vnode> Vnode::open(ioctx_t* ctx, const char* filename, int flags, mode_t mode)
|
||||
{
|
||||
// Handle transition across filesystem mount points.
|
||||
bool isroot = inode->ino == rootino && inode->dev == rootdev;
|
||||
bool dotdot = strcmp(filename, "..") == 0;
|
||||
if ( isroot && dotdot && mountedat )
|
||||
return mountedat;
|
||||
|
||||
// Move within the current filesystem.
|
||||
Ref<Inode> retinode = inode->open(ctx, filename, flags, mode);
|
||||
if ( !retinode ) { return Ref<Vnode>(NULL); }
|
||||
Ref<Vnode> retmountedat = mountedat;
|
||||
ino_t retrootino = rootino;
|
||||
dev_t retrootdev = rootdev;
|
||||
|
||||
// Check whether we moved into a filesystem mount point.
|
||||
Ref<Inode> mounted = LookupMount(retinode);
|
||||
if ( mounted )
|
||||
{
|
||||
retinode = mounted;
|
||||
retmountedat = Ref<Vnode>(this);
|
||||
retrootino = mounted->ino;
|
||||
retrootdev = mounted->dev;
|
||||
}
|
||||
|
||||
return Ref<Vnode>(new Vnode(retinode, retmountedat, retrootino, retrootdev));
|
||||
}
|
||||
|
||||
int Vnode::sync(ioctx_t* ctx)
|
||||
{
|
||||
return inode->sync(ctx);
|
||||
}
|
||||
|
||||
int Vnode::stat(ioctx_t* ctx, struct stat* st)
|
||||
{
|
||||
return inode->stat(ctx, st);
|
||||
}
|
||||
|
||||
int Vnode::chmod(ioctx_t* ctx, mode_t mode)
|
||||
{
|
||||
return inode->chmod(ctx, mode);
|
||||
}
|
||||
|
||||
int Vnode::chown(ioctx_t* ctx, uid_t owner, gid_t group)
|
||||
{
|
||||
return inode->chown(ctx, owner, group);
|
||||
}
|
||||
|
||||
int Vnode::truncate(ioctx_t* ctx, off_t length)
|
||||
{
|
||||
return inode->truncate(ctx, length);
|
||||
}
|
||||
|
||||
off_t Vnode::lseek(ioctx_t* ctx, off_t offset, int whence)
|
||||
{
|
||||
return inode->lseek(ctx, offset, whence);
|
||||
}
|
||||
|
||||
ssize_t Vnode::read(ioctx_t* ctx, uint8_t* buf, size_t count)
|
||||
{
|
||||
return inode->read(ctx, buf, count);
|
||||
}
|
||||
|
||||
ssize_t Vnode::pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off)
|
||||
{
|
||||
return inode->pread(ctx, buf, count, off);
|
||||
}
|
||||
|
||||
ssize_t Vnode::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
|
||||
{
|
||||
return inode->write(ctx, buf, count);
|
||||
}
|
||||
|
||||
ssize_t Vnode::pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t off)
|
||||
{
|
||||
return inode->pwrite(ctx, buf, count, off);
|
||||
}
|
||||
|
||||
int Vnode::utimes(ioctx_t* ctx, const struct timeval times[2])
|
||||
{
|
||||
return inode->utimes(ctx, times);
|
||||
}
|
||||
|
||||
int Vnode::isatty(ioctx_t* ctx)
|
||||
{
|
||||
return inode->isatty(ctx);
|
||||
}
|
||||
|
||||
ssize_t Vnode::readdirents(ioctx_t* ctx, struct kernel_dirent* dirent,
|
||||
size_t size, off_t start, size_t count)
|
||||
{
|
||||
return inode->readdirents(ctx, dirent, size, start, count);
|
||||
}
|
||||
|
||||
int Vnode::mkdir(ioctx_t* ctx, const char* filename, mode_t mode)
|
||||
{
|
||||
return inode->mkdir(ctx, filename, mode);
|
||||
}
|
||||
|
||||
int Vnode::unlink(ioctx_t* ctx, const char* filename)
|
||||
{
|
||||
return inode->unlink(ctx, filename);
|
||||
}
|
||||
|
||||
int Vnode::rmdir(ioctx_t* ctx, const char* filename)
|
||||
{
|
||||
return inode->rmdir(ctx, filename);
|
||||
}
|
||||
|
||||
int Vnode::link(ioctx_t* ctx, const char* filename, Ref<Vnode> node)
|
||||
{
|
||||
if ( node->inode->dev != inode->dev ) { errno = EXDEV; return -1; }
|
||||
return inode->link(ctx, filename, node->inode);
|
||||
}
|
||||
|
||||
int Vnode::symlink(ioctx_t* ctx, const char* oldname, const char* filename)
|
||||
{
|
||||
return inode->symlink(ctx, oldname, filename);
|
||||
}
|
||||
|
||||
ssize_t Vnode::readlink(ioctx_t* ctx, char* buf, size_t bufsiz)
|
||||
{
|
||||
return inode->readlink(ctx, buf, bufsiz);
|
||||
}
|
||||
|
||||
int Vnode::fsbind(ioctx_t* /*ctx*/, Vnode* /*node*/, int /*flags*/)
|
||||
{
|
||||
// TODO: Support binding in namespaces.
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Vnode::tcgetwinsize(ioctx_t* ctx, struct winsize* ws)
|
||||
{
|
||||
return inode->tcgetwinsize(ctx, ws);
|
||||
}
|
||||
|
||||
int Vnode::settermmode(ioctx_t* ctx, unsigned mode)
|
||||
{
|
||||
return inode->settermmode(ctx, mode);
|
||||
}
|
||||
|
||||
int Vnode::gettermmode(ioctx_t* ctx, unsigned* mode)
|
||||
{
|
||||
return inode->gettermmode(ctx, mode);
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
|
@ -43,7 +43,7 @@ int docat(const char* inputname, int fd)
|
|||
}
|
||||
if ( (ssize_t) writeall(1, buffer, bytesread) < bytesread )
|
||||
{
|
||||
error(0, errno, "write: %s", inputname);
|
||||
error(0, errno, "write: <stdout>", inputname);
|
||||
return 1;
|
||||
}
|
||||
} while ( true );
|
||||
|
|
30
utils/cp.cpp
30
utils/cp.cpp
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2013.
|
||||
|
||||
This program 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
|
||||
|
@ -20,6 +20,8 @@
|
|||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
@ -40,24 +42,26 @@ int main(int argc, char* argv[])
|
|||
|
||||
const char* frompath = argv[1];
|
||||
const char* topath = argv[2];
|
||||
char tobuffer[256];
|
||||
|
||||
int fromfd = open(frompath, O_RDONLY);
|
||||
if ( fromfd < 0 ) { error(1, errno, "%s", frompath); return 1; }
|
||||
|
||||
int tofd = open(topath, O_WRONLY | O_TRUNC | O_CREAT, 0777);
|
||||
if ( tofd < 0 )
|
||||
{
|
||||
if ( errno == EISDIR )
|
||||
{
|
||||
strcpy(tobuffer, topath);
|
||||
if ( tobuffer[strlen(tobuffer)-1] != '/' ) { strcat(tobuffer, "/"); }
|
||||
strcat(tobuffer, basename(frompath));
|
||||
topath = tobuffer;
|
||||
tofd = open(topath, O_WRONLY | O_TRUNC | O_CREAT, 0777);
|
||||
}
|
||||
error(1, errno, "%s", topath);
|
||||
|
||||
if ( tofd < 0 ) { error(1, errno, "%s", topath); return 1; }
|
||||
struct stat st;
|
||||
if ( fstat(tofd, &st) )
|
||||
error(1, errno, "stat: %s", topath);
|
||||
|
||||
if ( S_ISDIR(st.st_mode) )
|
||||
{
|
||||
int dirfd = tofd;
|
||||
const char* name = basename(frompath);
|
||||
tofd = openat(dirfd, name, O_WRONLY | O_TRUNC | O_CREAT, 0777);
|
||||
close(dirfd);
|
||||
if ( tofd < 0 )
|
||||
error(1, errno, "%s/%s", topath, name);
|
||||
}
|
||||
|
||||
while ( true )
|
||||
|
@ -67,7 +71,7 @@ int main(int argc, char* argv[])
|
|||
ssize_t bytesread = read(fromfd, buffer, BUFFER_SIZE);
|
||||
if ( bytesread < 0 ) { error(1, errno, "read: %s", frompath); return 1; }
|
||||
if ( bytesread == 0 ) { return 0; }
|
||||
if ( (ssize_t) writeall(tofd, buffer, bytesread) < bytesread )
|
||||
if ( writeall(tofd, buffer, bytesread) < (size_t) bytesread )
|
||||
{
|
||||
error(1, errno, "write: %s", topath);
|
||||
return 1;
|
||||
|
|
|
@ -20,7 +20,10 @@
|
|||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -77,5 +80,8 @@ int main(int /*argc*/, char* /*argv*/[])
|
|||
// we are running.
|
||||
setenv("objtype", getenv("cputype"), 0);
|
||||
|
||||
// Make sure that we have a /tmp directory.
|
||||
mkdir("/tmp", 01777);
|
||||
|
||||
return runsystem();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue