Refactor kernel VFS.
Note: This is an incompatible ABI change.
This commit is contained in:
parent
9634a0c3d2
commit
1444683ea8
11
Makefile
11
Makefile
|
@ -162,8 +162,17 @@ release-all-archs:
|
||||||
$(INITRD): sysroot
|
$(INITRD): sysroot
|
||||||
mkdir -p `dirname $(INITRD)`
|
mkdir -p `dirname $(INITRD)`
|
||||||
echo -n > $(INITRD).filter
|
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
|
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
|
rm -f $(INITRD).filter
|
||||||
|
|
||||||
.PHONY: initrd
|
.PHONY: initrd
|
||||||
|
|
|
@ -144,6 +144,7 @@ fdio.o \
|
||||||
fileno.o \
|
fileno.o \
|
||||||
fork.o \
|
fork.o \
|
||||||
fpipe.o \
|
fpipe.o \
|
||||||
|
fstatat.o \
|
||||||
fstat.o \
|
fstat.o \
|
||||||
ftruncate.o \
|
ftruncate.o \
|
||||||
getc.o \
|
getc.o \
|
||||||
|
@ -165,8 +166,8 @@ memstat.o \
|
||||||
mkdir.o \
|
mkdir.o \
|
||||||
mktemp.o \
|
mktemp.o \
|
||||||
on_exit.o \
|
on_exit.o \
|
||||||
open.o \
|
|
||||||
openat.o \
|
openat.o \
|
||||||
|
open.o \
|
||||||
pipe.o \
|
pipe.o \
|
||||||
print.o \
|
print.o \
|
||||||
putc.o \
|
putc.o \
|
||||||
|
|
|
@ -26,6 +26,14 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.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.
|
// Note that the only PATH variable in Sortix is the one used here.
|
||||||
extern "C" int execvpe(const char* filename, char* const* argv,
|
extern "C" int execvpe(const char* filename, char* const* argv,
|
||||||
char* const* envp)
|
char* const* envp)
|
||||||
|
@ -33,7 +41,7 @@ extern "C" int execvpe(const char* filename, char* const* argv,
|
||||||
if ( strchr(filename, '/') )
|
if ( strchr(filename, '/') )
|
||||||
return execve(filename, argv, envp);
|
return execve(filename, argv, envp);
|
||||||
size_t filenamelen = strlen(filename);
|
size_t filenamelen = strlen(filename);
|
||||||
const char* PATH = "/bin";
|
const char* PATH = "/" CPUTYPE_STR "/bin";
|
||||||
size_t pathlen = strlen(PATH);
|
size_t pathlen = strlen(PATH);
|
||||||
char* pathname = (char*) malloc(filenamelen + 1 + pathlen + 1);
|
char* pathname = (char*) malloc(filenamelen + 1 + pathlen + 1);
|
||||||
if ( !pathname ) { return -1; }
|
if ( !pathname ) { return -1; }
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -34,8 +35,8 @@
|
||||||
|
|
||||||
typedef struct fddir_sortix_struct
|
typedef struct fddir_sortix_struct
|
||||||
{
|
{
|
||||||
struct sortix_dirent* dirent;
|
struct kernel_dirent* dirent;
|
||||||
struct sortix_dirent* current;
|
struct kernel_dirent* current;
|
||||||
size_t direntsize;
|
size_t direntsize;
|
||||||
int fd;
|
int fd;
|
||||||
} fddir_sortix_t;
|
} fddir_sortix_t;
|
||||||
|
@ -44,18 +45,23 @@ int fddir_sortix_readents(fddir_sortix_t* info)
|
||||||
{
|
{
|
||||||
if ( !info->dirent )
|
if ( !info->dirent )
|
||||||
{
|
{
|
||||||
// Allocate a buffer of at least sizeof(sortix_dirent).
|
// Allocate a buffer of at least sizeof(kernel_dirent).
|
||||||
info->direntsize = sizeof(struct sortix_dirent) + 4UL;
|
info->direntsize = sizeof(struct kernel_dirent) + 4UL;
|
||||||
info->dirent = malloc(info->direntsize);
|
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; }
|
if ( errno != ERANGE )
|
||||||
size_t newdirentsize = info->dirent->d_namelen;
|
return -1;
|
||||||
struct sortix_dirent* newdirent = malloc(newdirentsize);
|
size_t newdirentsize = sizeof(struct kernel_dirent) + info->dirent->d_namelen + 1;
|
||||||
if ( !newdirent ) { return -1; }
|
if ( newdirentsize < info->direntsize )
|
||||||
|
newdirentsize *= 2;
|
||||||
|
struct kernel_dirent* newdirent = malloc(newdirentsize);
|
||||||
|
if ( !newdirent )
|
||||||
|
return -1;
|
||||||
free(info->dirent);
|
free(info->dirent);
|
||||||
info->dirent = newdirent;
|
info->dirent = newdirent;
|
||||||
info->direntsize = newdirentsize;
|
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;
|
fddir_sortix_t* info = (fddir_sortix_t*) user;
|
||||||
if ( !info->current )
|
if ( !info->current )
|
||||||
{
|
{
|
||||||
if ( fddir_sortix_readents(info) ) { return -1; }
|
if ( fddir_sortix_readents(info) )
|
||||||
|
return -1;
|
||||||
info->current = info->dirent;
|
info->current = info->dirent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +89,7 @@ int fddir_sortix_read(void* user, struct dirent* dirent, size_t* size)
|
||||||
dirent->d_reclen = needed;
|
dirent->d_reclen = needed;
|
||||||
strcpy(dirent->d_name, info->current->d_name);
|
strcpy(dirent->d_name, info->current->d_name);
|
||||||
|
|
||||||
info->current = info->current->d_next;
|
info->current = kernel_dirent_next(info->current);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -90,7 +97,7 @@ int fddir_sortix_read(void* user, struct dirent* dirent, size_t* size)
|
||||||
int fddir_sortix_rewind(void* user)
|
int fddir_sortix_rewind(void* user)
|
||||||
{
|
{
|
||||||
fddir_sortix_t* info = (fddir_sortix_t*) 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)
|
int fddir_sortix_fd(void* user)
|
||||||
|
@ -116,7 +123,9 @@ DIR* fdopendir(int fd)
|
||||||
DIR* dir = dnewdir();
|
DIR* dir = dnewdir();
|
||||||
if ( !dir ) { free(info); return NULL; }
|
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;
|
info->fd = fd;
|
||||||
|
|
||||||
|
@ -131,7 +140,7 @@ DIR* fdopendir(int fd)
|
||||||
|
|
||||||
DIR* opendir(const char* path)
|
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; }
|
if ( fd < 0 ) { return NULL; }
|
||||||
DIR* dir = fdopendir(fd);
|
DIR* dir = fdopendir(fd);
|
||||||
if ( !dir ) { close(fd); return NULL; }
|
if ( !dir ) { close(fd); return NULL; }
|
||||||
|
|
|
@ -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>
|
#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)
|
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 fcntl(int fd, int cmd, ...);
|
||||||
int open(const char* path, int oflag, ...);
|
int open(const char* path, int oflag, ...);
|
||||||
|
int openat(int fd, const char* path, int oflag, ...);
|
||||||
#if defined(__SORTIX_SHOW_UNIMPLEMENTED)
|
#if defined(__SORTIX_SHOW_UNIMPLEMENTED)
|
||||||
int creat(const char* path, mode_t mode);
|
int creat(const char* path, mode_t mode);
|
||||||
int openat(int fd, const char* path, int oflag, ...);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
|
@ -26,21 +26,16 @@
|
||||||
#define _SYS_READDIRENTS_H 1
|
#define _SYS_READDIRENTS_H 1
|
||||||
|
|
||||||
#include <features.h>
|
#include <features.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sortix/dirent.h>
|
||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
@include(size_t.h)
|
@include(size_t.h)
|
||||||
|
|
||||||
// Keep this up to date with <sortix/directory.h>
|
ssize_t readdirents(int fd, struct kernel_dirent* dirent, size_t size);
|
||||||
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);
|
|
||||||
|
|
||||||
__END_DECLS
|
__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.
|
This file is part of the Sortix C Library.
|
||||||
|
|
||||||
|
@ -45,13 +45,16 @@ __END_DECLS
|
||||||
#include <sortix/stat.h>
|
#include <sortix/stat.h>
|
||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
int chmod(const char* path, mode_t mode);
|
int chmod(const char* path, mode_t mode);
|
||||||
int fchmod(int fd, mode_t mode);
|
int fchmod(int fd, mode_t mode);
|
||||||
int fstat(int fd, struct stat* st);
|
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 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);
|
int stat(const char* restrict path, struct stat* restrict st);
|
||||||
mode_t umask(mode_t mask);
|
mode_t umask(mode_t mask);
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -165,6 +165,7 @@ int execvp(const char*, char* const []);
|
||||||
pid_t fork(void);
|
pid_t fork(void);
|
||||||
int ftruncate(int, off_t);
|
int ftruncate(int, off_t);
|
||||||
char* getcwd(char*, size_t);
|
char* getcwd(char*, size_t);
|
||||||
|
char* get_current_dir_name(void);
|
||||||
pid_t getpid(void);
|
pid_t getpid(void);
|
||||||
pid_t getppid(void);
|
pid_t getppid(void);
|
||||||
int isatty(int);
|
int isatty(int);
|
||||||
|
|
|
@ -25,10 +25,9 @@
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <unistd.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)
|
extern "C" off_t lseek(int fd, off_t offset, int whence)
|
||||||
{
|
{
|
||||||
SysSeek(fd, &offset, whence);
|
return sys_seek(fd, offset, whence);
|
||||||
return offset;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,14 +26,11 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.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)
|
extern "C" ssize_t read(int fd, void* buf, size_t count)
|
||||||
{
|
{
|
||||||
retry:
|
return sys_read(fd, buf, count);
|
||||||
ssize_t result = SysRead(fd, buf, count);
|
|
||||||
if ( result < 0 && errno == EAGAIN ) { goto retry; }
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFN_SYSCALL4(ssize_t, sys_pread, SYSCALL_PREAD, int, void*, size_t, off_t);
|
DEFN_SYSCALL4(ssize_t, sys_pread, SYSCALL_PREAD, int, void*, size_t, off_t);
|
||||||
|
|
|
@ -25,9 +25,9 @@
|
||||||
#include <sys/readdirents.h>
|
#include <sys/readdirents.h>
|
||||||
#include <sys/syscall.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 <errno.h>
|
||||||
#include <unistd.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)
|
extern "C" ssize_t write(int fd, const void* buf, size_t count)
|
||||||
{
|
{
|
||||||
retry:
|
return sys_write(fd, buf, count);
|
||||||
ssize_t result = SysWrite(fd, buf, count);
|
|
||||||
if ( result < 0 && errno == EAGAIN ) { goto retry; }
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFN_SYSCALL4(ssize_t, sys_pwrite, SYSCALL_PWRITE, int, const void*, size_t, off_t);
|
DEFN_SYSCALL4(ssize_t, sys_pwrite, SYSCALL_PWRITE, int, const void*, size_t, off_t);
|
||||||
|
|
|
@ -74,36 +74,34 @@ ata.o \
|
||||||
bga.o \
|
bga.o \
|
||||||
calltrace.o \
|
calltrace.o \
|
||||||
com.o \
|
com.o \
|
||||||
|
copy.o \
|
||||||
$(CPU)/calltrace.o \
|
$(CPU)/calltrace.o \
|
||||||
$(CPU)/kthread.o \
|
$(CPU)/kthread.o \
|
||||||
crc32.o \
|
crc32.o \
|
||||||
descriptors.o \
|
descriptor.o \
|
||||||
device.o \
|
|
||||||
directory.o \
|
|
||||||
dispmsg.o \
|
dispmsg.o \
|
||||||
|
dtable.o \
|
||||||
elf.o \
|
elf.o \
|
||||||
filesystem.o \
|
fsfunc.o \
|
||||||
fs/devfs.o \
|
fs/kram.o \
|
||||||
fs/initfs.o \
|
|
||||||
fs/ramfs.o \
|
|
||||||
fs/util.o \
|
fs/util.o \
|
||||||
fs/videofs.o \
|
|
||||||
initrd.o \
|
initrd.o \
|
||||||
|
inode.o \
|
||||||
interlock.o \
|
interlock.o \
|
||||||
interrupt.o \
|
interrupt.o \
|
||||||
|
ioctx.o \
|
||||||
io.o \
|
io.o \
|
||||||
kb/layout/us.o \
|
kb/layout/us.o \
|
||||||
kb/ps2.o \
|
kb/ps2.o \
|
||||||
kernelinfo.o \
|
kernelinfo.o \
|
||||||
kernel.o \
|
kernel.o \
|
||||||
keyboard.o \
|
|
||||||
kthread.o \
|
kthread.o \
|
||||||
lfbtextbuffer.o \
|
lfbtextbuffer.o \
|
||||||
linebuffer.o \
|
linebuffer.o \
|
||||||
log.o \
|
log.o \
|
||||||
logterminal.o \
|
logterminal.o \
|
||||||
memorymanagement.o \
|
memorymanagement.o \
|
||||||
mount.o \
|
mtable.o \
|
||||||
panic.o \
|
panic.o \
|
||||||
pci.o \
|
pci.o \
|
||||||
pipe.o \
|
pipe.o \
|
||||||
|
@ -115,7 +113,6 @@ signal.o \
|
||||||
sound.o \
|
sound.o \
|
||||||
string.o \
|
string.o \
|
||||||
syscall.o \
|
syscall.o \
|
||||||
terminal.o \
|
|
||||||
textbuffer.o \
|
textbuffer.o \
|
||||||
textterminal.o \
|
textterminal.o \
|
||||||
thread.o \
|
thread.o \
|
||||||
|
@ -125,6 +122,7 @@ utf8.o \
|
||||||
vga.o \
|
vga.o \
|
||||||
vgatextbuffer.o \
|
vgatextbuffer.o \
|
||||||
video.o \
|
video.o \
|
||||||
|
vnode.o \
|
||||||
worker.o \
|
worker.o \
|
||||||
|
|
||||||
ALLOBJS=\
|
ALLOBJS=\
|
||||||
|
|
127
sortix/ata.cpp
127
sortix/ata.cpp
|
@ -23,12 +23,18 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#include <sortix/kernel/platform.h>
|
#include <sortix/kernel/platform.h>
|
||||||
|
#include <sortix/kernel/interlock.h>
|
||||||
#include <sortix/kernel/kthread.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 <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "ata.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
|
// TODO: Use the PCI to detect ATA devices instead of relying on them being on
|
||||||
// standard locations.
|
// standard locations.
|
||||||
|
@ -62,27 +68,126 @@ const uint8_t CTL_RESET = (1<<2);
|
||||||
|
|
||||||
namespace ATA {
|
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;
|
unsigned ataid = busid*2 + driveid;
|
||||||
ATADrive* drive = bus->Instatiate(driveid);
|
ATADrive* drive = bus->Instatiate(driveid);
|
||||||
if ( !drive ) { return; }
|
if ( !drive )
|
||||||
DeviceFS::RegisterATADrive(ataid, 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);
|
ATABus* bus = ATA::CreateBus(ioport, altio);
|
||||||
if ( !bus )
|
if ( !bus )
|
||||||
return;
|
return;
|
||||||
DetectDrive(busid, bus, 0);
|
DetectDrive(devpath, slashdev, busid, bus, 0);
|
||||||
DetectDrive(busid, bus, 1);
|
DetectDrive(devpath, slashdev, busid, bus, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Init()
|
void Init(const char* devpath, Ref<Descriptor> slashdev)
|
||||||
{
|
{
|
||||||
DetectBus(0, 0x1F0, 0x3F6);
|
DetectBus(devpath, slashdev, 0, 0x1F0, 0x3F6);
|
||||||
DetectBus(1, 0x170, 0x366);
|
DetectBus(devpath, slashdev, 1, 0x170, 0x366);
|
||||||
}
|
}
|
||||||
|
|
||||||
ATABus* CreateBus(uint16_t portoffset, uint16_t altport)
|
ATABus* CreateBus(uint16_t portoffset, uint16_t altport)
|
||||||
|
|
|
@ -26,9 +26,11 @@
|
||||||
#define SORTIX_ATA_H
|
#define SORTIX_ATA_H
|
||||||
|
|
||||||
#include <sortix/kernel/kthread.h>
|
#include <sortix/kernel/kthread.h>
|
||||||
|
#include <sortix/kernel/refcount.h>
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
|
|
||||||
|
class Descriptor;
|
||||||
class ATABus;
|
class ATABus;
|
||||||
class ATADrive;
|
class ATADrive;
|
||||||
|
|
||||||
|
@ -83,7 +85,7 @@ private:
|
||||||
|
|
||||||
namespace ATA {
|
namespace ATA {
|
||||||
|
|
||||||
void Init();
|
void Init(const char* devpath, Ref<Descriptor> slashdev);
|
||||||
ATABus* CreateBus(uint16_t portoffset, uint16_t altport);
|
ATABus* CreateBus(uint16_t portoffset, uint16_t altport);
|
||||||
|
|
||||||
} // namespace ATA
|
} // namespace ATA
|
||||||
|
|
149
sortix/com.cpp
149
sortix/com.cpp
|
@ -24,13 +24,16 @@
|
||||||
|
|
||||||
#include <sortix/kernel/platform.h>
|
#include <sortix/kernel/platform.h>
|
||||||
#include <sortix/kernel/kthread.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 <errno.h>
|
||||||
#include "interrupt.h"
|
#include "interrupt.h"
|
||||||
#include "stream.h"
|
|
||||||
#include "syscall.h"
|
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "signal.h"
|
#include "signal.h"
|
||||||
#include "fs/devfs.h"
|
|
||||||
#include "com.h"
|
#include "com.h"
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
|
@ -51,13 +54,9 @@ namespace COM {
|
||||||
|
|
||||||
// Yet another alternative is to use POLL_HACK, but return EGAIN and let user-
|
// 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.
|
// space call retry, rather than relying on the broken syscall interstructure.
|
||||||
#ifndef GOT_ACTUAL_KTHREAD
|
|
||||||
#define POLL_EAGAIN 1
|
#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 The interrupt-based code was broken in the kthread branch.
|
||||||
#error You need to port this to the new thread/interrupt API.
|
#error You need to port this to the new thread/interrupt API.
|
||||||
#warning Oh, and fix the above mentioned bugs too.
|
#warning Oh, and fix the above mentioned bugs too.
|
||||||
|
@ -211,133 +210,97 @@ void EarlyInit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DevCOMPort : public DevStream
|
class DevCOMPort : public AbstractInode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef DevStream BaseClass;
|
DevCOMPort(dev_t dev, uid_t owner, gid_t group, mode_t mode, uint16_t port);
|
||||||
|
|
||||||
public:
|
|
||||||
DevCOMPort(uint16_t port);
|
|
||||||
virtual ~DevCOMPort();
|
virtual ~DevCOMPort();
|
||||||
|
virtual int sync(ioctx_t* ctx);
|
||||||
public:
|
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
||||||
virtual ssize_t Read(uint8_t* dest, size_t count);
|
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
||||||
virtual ssize_t Write(const uint8_t* src, size_t count);
|
|
||||||
virtual bool IsReadable();
|
|
||||||
virtual bool IsWritable();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void OnInterrupt();
|
void OnInterrupt();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint16_t port;
|
|
||||||
kthread_mutex_t portlock;
|
kthread_mutex_t portlock;
|
||||||
#ifdef GOT_FAKE_KTHREAD
|
uint16_t port;
|
||||||
Event dataevent;
|
|
||||||
Event sentevent;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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->port = port;
|
||||||
this->portlock = KTHREAD_MUTEX_INITIALIZER;
|
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()
|
DevCOMPort::~DevCOMPort()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DevCOMPort::IsReadable() { return true; }
|
int DevCOMPort::sync(ioctx_t* /*ctx*/)
|
||||||
bool DevCOMPort::IsWritable() { return true; }
|
{
|
||||||
|
// TODO: Not implemented yet, please wait for all outstanding requests.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#if POLL_HACK
|
#if POLL_HACK
|
||||||
|
|
||||||
const unsigned TRIES = 1000;
|
ssize_t DevCOMPort::read(ioctx_t* ctx, uint8_t* dest, size_t count)
|
||||||
|
|
||||||
ssize_t DevCOMPort::Read(uint8_t* dest, size_t count)
|
|
||||||
{
|
{
|
||||||
if ( !count ) { return 0; }
|
if ( !count ) { return 0; }
|
||||||
if ( SSIZE_MAX < count ) { count = SSIZE_MAX; }
|
if ( SSIZE_MAX < count ) { count = SSIZE_MAX; }
|
||||||
ScopedLock lock(&portlock);
|
ScopedLock lock(&portlock);
|
||||||
|
|
||||||
#ifdef GOT_ACTUAL_KTHREAD
|
|
||||||
while ( !(CPU::InPortB(port + LSR) & LSR_READY) )
|
while ( !(CPU::InPortB(port + LSR) & LSR_READY) )
|
||||||
if ( Signal::IsPending() )
|
if ( Signal::IsPending() )
|
||||||
{
|
{
|
||||||
errno = EINTR;
|
errno = EINTR;
|
||||||
return -1;
|
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;
|
size_t sofar = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if ( count <= sofar ) { break; }
|
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);
|
} while ( CPU::InPortB(port + LSR) & LSR_READY);
|
||||||
|
|
||||||
return sofar;
|
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 ( !count ) { return 0; }
|
||||||
if ( SSIZE_MAX < count ) { count = SSIZE_MAX; };
|
if ( SSIZE_MAX < count ) { count = SSIZE_MAX; };
|
||||||
|
|
||||||
ScopedLock lock(&portlock);
|
ScopedLock lock(&portlock);
|
||||||
|
|
||||||
#ifdef GOT_ACTUAL_KTHREAD
|
|
||||||
while ( !(CPU::InPortB(port + LSR) & LSR_THRE) )
|
while ( !(CPU::InPortB(port + LSR) & LSR_THRE) )
|
||||||
if ( Signal::IsPending() )
|
if ( Signal::IsPending() )
|
||||||
{
|
{
|
||||||
errno = EINTR;
|
errno = EINTR;
|
||||||
return -1;
|
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;
|
size_t sofar = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if ( count <= sofar ) { break; }
|
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 );
|
} while ( CPU::InPortB(port + LSR) & LSR_THRE );
|
||||||
|
|
||||||
return sofar;
|
return sofar;
|
||||||
|
@ -345,7 +308,9 @@ ssize_t DevCOMPort::Write(const uint8_t* src, size_t count)
|
||||||
|
|
||||||
#else
|
#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 ( !count ) { return 0; }
|
||||||
if ( SSIZE_MAX < count ) { count = SSIZE_MAX; }
|
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);
|
uint8_t lsr = CPU::InPortB(port + LSR);
|
||||||
if ( !(lsr & LSR_READY) )
|
if ( !(lsr & LSR_READY) )
|
||||||
{
|
{
|
||||||
#ifdef GOT_ACTUAL_KTHREAD
|
|
||||||
Panic("Can't wait for com data receive event");
|
Panic("Can't wait for com data receive event");
|
||||||
#else
|
Error::Set(EBLOCKING);
|
||||||
dataevent.Register();
|
|
||||||
#endif
|
|
||||||
errno = EBLOCKING;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,12 +345,8 @@ ssize_t DevCOMPort::Write(const uint8_t* src, size_t count)
|
||||||
uint8_t lsr = CPU::InPortB(port + LSR);
|
uint8_t lsr = CPU::InPortB(port + LSR);
|
||||||
if ( !(lsr & LSR_THRE) )
|
if ( !(lsr & LSR_THRE) )
|
||||||
{
|
{
|
||||||
#ifdef GOT_ACTUAL_KTHREAD
|
|
||||||
Panic("Can't wait for com data sent event");
|
Panic("Can't wait for com data sent event");
|
||||||
#else
|
Error::Set(EBLOCKING);
|
||||||
sentevent.Register();
|
|
||||||
#endif
|
|
||||||
errno = EBLOCKING;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,18 +381,10 @@ void DevCOMPort::OnInterrupt()
|
||||||
CPU::InPortB(port + LSR);
|
CPU::InPortB(port + LSR);
|
||||||
break;
|
break;
|
||||||
case IIR_RECV_DATA:
|
case IIR_RECV_DATA:
|
||||||
#ifdef GOT_ACTUAL_KTHREAD
|
|
||||||
Panic("Can't wait for com data sent event");
|
Panic("Can't wait for com data sent event");
|
||||||
#else
|
|
||||||
dataevent.Signal();
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
case IIR_SENT_DATA:
|
case IIR_SENT_DATA:
|
||||||
#ifdef GOT_ACTUAL_KTHREAD
|
|
||||||
Panic("Can't wait for com data sent event");
|
Panic("Can't wait for com data sent event");
|
||||||
#else
|
|
||||||
sentevent.Signal();
|
|
||||||
#endif
|
|
||||||
CPU::InPortB(port + IIR);
|
CPU::InPortB(port + IIR);
|
||||||
break;
|
break;
|
||||||
case IIR_MODEM_STATUS:
|
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*/)
|
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++ )
|
for ( size_t i = 1; i <= NUMCOMPORTS; i++ )
|
||||||
{
|
{
|
||||||
if ( !comports[i] ) { comdevices[i] = NULL; continue; }
|
if ( !comports[i] ) { comdevices[i] = Ref<DevCOMPort>(); continue; }
|
||||||
comdevices[i] = new DevCOMPort(comports[i]);
|
comdevices[i] = Ref<DevCOMPort>
|
||||||
|
(new DevCOMPort(slashdev->dev, 0, 0, 0660, comports[i]));
|
||||||
if ( !comdevices[i] )
|
if ( !comdevices[i] )
|
||||||
{
|
{
|
||||||
PanicF("Unable to allocate device for COM port %zu at 0x%x", i,
|
PanicF("Unable to allocate device for COM port %zu at 0x%x", i,
|
||||||
|
@ -468,10 +419,8 @@ void Init()
|
||||||
}
|
}
|
||||||
char name[5] = "comN";
|
char name[5] = "comN";
|
||||||
name[3] = '0' + i;
|
name[3] = '0' + i;
|
||||||
if ( !DeviceFS::RegisterDevice(name, comdevices[i]) )
|
if ( LinkInodeInDir(&ctx, slashdev, name, comdevices[i]) != 0 )
|
||||||
{
|
PanicF("Unable to link %s/%s to COM port driver.", devpath, name);
|
||||||
PanicF("Unable to register device /dev/%s", name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Interrupt::RegisterHandler(Interrupt::IRQ3, UARTIRQHandler, NULL);
|
Interrupt::RegisterHandler(Interrupt::IRQ3, UARTIRQHandler, NULL);
|
||||||
|
|
|
@ -26,12 +26,16 @@
|
||||||
#define SORTIX_COM_H
|
#define SORTIX_COM_H
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
|
|
||||||
|
class Descriptor;
|
||||||
|
|
||||||
namespace COM {
|
namespace COM {
|
||||||
|
|
||||||
void EarlyInit();
|
void EarlyInit();
|
||||||
void Init();
|
void Init(const char* devpath, Ref<Descriptor> slashdev);
|
||||||
|
|
||||||
} // namespace COM
|
} // namespace COM
|
||||||
|
|
||||||
} // namespace Sortix
|
} // namespace Sortix
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
@ -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/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 <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
|
|
||||||
DevStringBuffer::DevStringBuffer(char* str)
|
UtilMemoryBuffer::UtilMemoryBuffer(dev_t dev, ino_t ino, uid_t owner,
|
||||||
{
|
gid_t group, mode_t mode, uint8_t* buf,
|
||||||
this->str = str;
|
size_t bufsize, bool write, bool deletebuf)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
|
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->buf = buf;
|
||||||
this->bufsize = bufsize;
|
this->bufsize = bufsize;
|
||||||
this->write = write;
|
this->write = write;
|
||||||
this->deletebuf = deletebuf;
|
this->deletebuf = deletebuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
DevMemoryBuffer::~DevMemoryBuffer()
|
UtilMemoryBuffer::~UtilMemoryBuffer()
|
||||||
{
|
{
|
||||||
if ( deletebuf )
|
if ( deletebuf )
|
||||||
delete[] buf;
|
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;
|
ScopedLock lock(&filelock);
|
||||||
}
|
if ( (uintmax_t) bufsize < (uintmax_t) off )
|
||||||
|
return 0;
|
||||||
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; }
|
|
||||||
size_t available = bufsize - off;
|
size_t available = bufsize - off;
|
||||||
if ( available < count ) { count = available; }
|
if ( available < count )
|
||||||
memcpy(dest, buf + off, count);
|
count = available;
|
||||||
off += count;
|
if ( !ctx->copy_to_dest(dest, buf + off, count) )
|
||||||
|
return -1;
|
||||||
return count;
|
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 ( !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;
|
size_t available = bufsize - off;
|
||||||
if ( available < count ) { count = available; }
|
if ( available < count )
|
||||||
memcpy(buf + off, src, count);
|
count = available;
|
||||||
off += count;
|
ctx->copy_from_src(buf + off, src, count);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DevMemoryBuffer::IsReadable()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DevMemoryBuffer::IsWritable()
|
|
||||||
{
|
|
||||||
return write;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Sortix
|
} // namespace Sortix
|
||||||
|
|
|
@ -25,79 +25,31 @@
|
||||||
#ifndef SORTIX_FS_UTIL_H
|
#ifndef SORTIX_FS_UTIL_H
|
||||||
#define SORTIX_FS_UTIL_H
|
#define SORTIX_FS_UTIL_H
|
||||||
|
|
||||||
#include "../stream.h"
|
#include <sortix/kernel/inode.h>
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
|
|
||||||
class DevStringBuffer : public DevBuffer
|
class UtilMemoryBuffer : public AbstractInode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DevStringBuffer(char* str);
|
UtilMemoryBuffer(dev_t dev, ino_t ino, uid_t owner, gid_t group,
|
||||||
virtual ~DevStringBuffer();
|
mode_t mode, uint8_t* buf, size_t bufsize,
|
||||||
|
bool write = true, bool deletebuf = true);
|
||||||
private:
|
virtual ~UtilMemoryBuffer();
|
||||||
char* str;
|
virtual int truncate(ioctx_t* ctx, off_t length);
|
||||||
size_t strlength;
|
virtual off_t lseek(ioctx_t* ctx, off_t offset, int whence);
|
||||||
size_t off;
|
virtual ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count,
|
||||||
|
off_t off);
|
||||||
public:
|
virtual ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
||||||
virtual size_t BlockSize();
|
off_t off);
|
||||||
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();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
kthread_mutex_t filelock;
|
||||||
uint8_t* buf;
|
uint8_t* buf;
|
||||||
size_t bufsize;
|
size_t bufsize;
|
||||||
size_t off;
|
|
||||||
bool write;
|
bool write;
|
||||||
bool deletebuf;
|
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
|
} // 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
|
|
|
@ -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
|
|
@ -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_CLOEXEC (1<<0)
|
||||||
#define FD_CLOFORK (1<<1)
|
#define FD_CLOFORK (1<<1)
|
||||||
|
|
||||||
|
#define __FD_ALLOWED_FLAGS (FD_CLOEXEC | FD_CLOFORK)
|
||||||
|
|
||||||
#define F_SETFD 0
|
#define F_SETFD 0
|
||||||
#define F_GETFD 1
|
#define F_GETFD 1
|
||||||
#define F_SETFL 2
|
#define F_SETFL 2
|
||||||
#define F_GETFL 3
|
#define F_GETFL 3
|
||||||
|
|
||||||
|
#define AT_FDCWD (-100)
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#ifndef SORTIX_INITRD_H
|
#ifndef INCLUDE_SORTIX_INITRD_H
|
||||||
#define SORTIX_INITRD_H
|
#define INCLUDE_SORTIX_INITRD_H
|
||||||
|
|
||||||
#include <features.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.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -17,32 +17,24 @@
|
||||||
You should have received a copy of the GNU General Public License along with
|
You should have received a copy of the GNU General Public License along with
|
||||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
fs/initfs.h
|
sortix/kernel/copy.h
|
||||||
Provides access to the initial ramdisk.
|
The context for io operations: who made it, how should data be copied, etc.
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#ifndef SORTIX_FS_INITFS_H
|
#ifndef SORTIX_COPY_H
|
||||||
#define SORTIX_FS_INITFS_H
|
#define SORTIX_COPY_H
|
||||||
|
|
||||||
#include <sortix/kernel/sortedlist.h>
|
#include <stddef.h>
|
||||||
#include "../filesystem.h"
|
|
||||||
|
|
||||||
namespace Sortix
|
namespace Sortix {
|
||||||
{
|
|
||||||
class DevInitFSFile;
|
|
||||||
|
|
||||||
class DevInitFS : public DevFileSystem
|
bool CopyToUser(void* userdst, const void* ksrc, size_t count);
|
||||||
{
|
bool CopyFromUser(void* kdst, const void* usersrc, size_t count);
|
||||||
public:
|
bool CopyToKernel(void* kdst, const void* ksrc, size_t count);
|
||||||
DevInitFS();
|
bool CopyFromKernel(void* kdst, const void* ksrc, size_t count);
|
||||||
virtual ~DevInitFS();
|
char* GetStringFromUser(const char* str);
|
||||||
|
|
||||||
public:
|
} // namespace Sortix
|
||||||
virtual Device* Open(const char* path, int flags, mode_t mode);
|
|
||||||
virtual bool Unlink(const char* path);
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -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
|
|
@ -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
|
You should have received a copy of the GNU General Public License along with
|
||||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
fs/videofs.h
|
sortix/kernel/fsfunc.h
|
||||||
Provides filesystem access to the video framework.
|
Filesystem related utility functions.
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#ifndef SORTIX_FS_VIDEOFS_H
|
#ifndef SORTIX_FSFUNC_H
|
||||||
#define SORTIX_FS_VIDEOFS_H
|
#define SORTIX_FSFUNC_H
|
||||||
|
|
||||||
#include "../filesystem.h"
|
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
|
|
||||||
class DevVideoFS : public DevFileSystem
|
static inline bool IsDotOrDotDot(const char* path)
|
||||||
{
|
{
|
||||||
public:
|
return path[0] == '.' && ((path[1] == '\0') ||
|
||||||
DevVideoFS();
|
(path[1] == '.' && path[2] == '\0'));
|
||||||
virtual ~DevVideoFS();
|
}
|
||||||
|
|
||||||
public:
|
bool ModeToDT(mode_t mode);
|
||||||
virtual Device* Open(const char* path, int flags, mode_t mode);
|
bool SplitFinalElem(const char* path, char** dir, char** final);
|
||||||
virtual bool Unlink(const char* path);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Sortix
|
} // namespace Sortix
|
||||||
|
|
|
@ -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.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -17,42 +17,33 @@
|
||||||
You should have received a copy of the GNU General Public License along with
|
You should have received a copy of the GNU General Public License along with
|
||||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
device.cpp
|
sortix/kernel/ioctx.h
|
||||||
A base class for all devices.
|
The context for io operations: who made it, how should data be copied, etc.
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#include <sortix/kernel/platform.h>
|
#ifndef SORTIX_IOCTX_H
|
||||||
#include <sortix/kernel/kthread.h>
|
#define SORTIX_IOCTX_H
|
||||||
#include <string.h>
|
|
||||||
#include "device.h"
|
|
||||||
|
|
||||||
namespace Sortix
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace Sortix {
|
||||||
|
|
||||||
|
struct ioctx_struct
|
||||||
{
|
{
|
||||||
Device::Device()
|
uid_t uid, auth_uid;
|
||||||
{
|
gid_t gid, auth_gid;
|
||||||
refcountlock = KTHREAD_MUTEX_INITIALIZER;
|
bool (*copy_to_dest)(void* dest, const void* src, size_t n);
|
||||||
refcount = 0;
|
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()
|
} // namespace Sortix
|
||||||
{
|
|
||||||
bool shoulddelete = false;
|
|
||||||
kthread_mutex_lock(&refcountlock);
|
|
||||||
shoulddelete = --refcount == 0 || refcount == SIZE_MAX;
|
|
||||||
kthread_mutex_unlock(&refcountlock);
|
|
||||||
if ( shoulddelete )
|
|
||||||
delete this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Device::Refer()
|
#endif
|
||||||
{
|
|
||||||
ScopedLock lock(&refcountlock);
|
|
||||||
refcount++;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -17,45 +17,46 @@
|
||||||
You should have received a copy of the GNU General Public License along with
|
You should have received a copy of the GNU General Public License along with
|
||||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
keyboard.h
|
sortix/kernel/keyboard.h
|
||||||
An interface to keyboards.
|
Various interfaces for keyboard devices and layouts.
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#ifndef SORTIX_KEYBOARD_H
|
#ifndef SORTIX_KEYBOARD_H
|
||||||
#define SORTIX_KEYBOARD_H
|
#define SORTIX_KEYBOARD_H
|
||||||
|
|
||||||
namespace Sortix
|
namespace Sortix {
|
||||||
|
|
||||||
|
class Keyboard;
|
||||||
|
class KeyboardOwner;
|
||||||
|
|
||||||
|
class Keyboard
|
||||||
{
|
{
|
||||||
class Keyboard;
|
public:
|
||||||
class KeyboardOwner;
|
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:
|
class KeyboardOwner
|
||||||
virtual ~Keyboard() { }
|
{
|
||||||
virtual int Read() = 0;
|
public:
|
||||||
virtual size_t GetPending() const = 0;
|
virtual ~KeyboardOwner() { }
|
||||||
virtual bool HasPending() const = 0;
|
virtual void OnKeystroke(Keyboard* keyboard, void* user) = 0;
|
||||||
virtual void SetOwner(KeyboardOwner* owner, void* user) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class KeyboardOwner
|
};
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~KeyboardOwner() { }
|
|
||||||
virtual void OnKeystroke(Keyboard* keyboard, void* user) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class KeyboardLayout
|
class KeyboardLayout
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~KeyboardLayout() { }
|
virtual ~KeyboardLayout() { }
|
||||||
virtual uint32_t Translate(int kbkey) = 0;
|
virtual uint32_t Translate(int kbkey) = 0;
|
||||||
};
|
|
||||||
}
|
};
|
||||||
|
|
||||||
|
} // namespace Sortix
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -27,8 +27,6 @@
|
||||||
|
|
||||||
#include <sortix/signal.h>
|
#include <sortix/signal.h>
|
||||||
|
|
||||||
#define GOT_ACTUAL_KTHREAD
|
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
|
|
||||||
extern "C" {
|
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.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -17,44 +17,46 @@
|
||||||
You should have received a copy of the GNU General Public License along with
|
You should have received a copy of the GNU General Public License along with
|
||||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
device.h
|
sortix/kernel/mtable.h
|
||||||
A base class for all devices.
|
Class to keep track of mount points.
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#ifndef SORTIX_DEVICE_H
|
#ifndef SORTIX_MTABLE_H
|
||||||
#define SORTIX_DEVICE_H
|
#define SORTIX_MTABLE_H
|
||||||
|
|
||||||
#include <sortix/kernel/kthread.h>
|
#include <sortix/kernel/kthread.h>
|
||||||
|
#include <sortix/kernel/refcount.h>
|
||||||
|
|
||||||
namespace Sortix
|
namespace Sortix {
|
||||||
|
|
||||||
|
class Inode;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
{
|
{
|
||||||
class Device
|
Ref<Inode> inode;
|
||||||
{
|
ino_t ino;
|
||||||
public:
|
dev_t dev;
|
||||||
static const unsigned STREAM = 0;
|
} mountpoint_t;
|
||||||
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;
|
|
||||||
|
|
||||||
public:
|
class MountTable : public Refcountable
|
||||||
Device();
|
{
|
||||||
virtual ~Device();
|
public:
|
||||||
|
MountTable();
|
||||||
|
~MountTable();
|
||||||
|
Ref<MountTable> Fork();
|
||||||
|
bool AddMount(ino_t ino, dev_t dev, Ref<Inode> inode);
|
||||||
|
|
||||||
private:
|
public: // Consider these read-only.
|
||||||
kthread_mutex_t refcountlock;
|
kthread_mutex_t mtablelock;
|
||||||
size_t refcount;
|
mountpoint_t* mounts;
|
||||||
|
size_t nummounts;
|
||||||
|
|
||||||
public:
|
private:
|
||||||
void Refer();
|
size_t mountsalloced;
|
||||||
void Unref();
|
|
||||||
|
|
||||||
public:
|
};
|
||||||
virtual bool IsType(unsigned type) const = 0;
|
|
||||||
|
|
||||||
};
|
} // namespace Sortix
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -1,6 +1,6 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
|
||||||
|
|
||||||
This file is part of Sortix.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -29,21 +29,95 @@
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
|
|
||||||
class Refcounted
|
class Refcountable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Refcounted();
|
Refcountable();
|
||||||
~Refcounted();
|
virtual ~Refcountable();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void Refer();
|
void Refer_Renamed();
|
||||||
void Unref();
|
void Unref_Renamed();
|
||||||
inline size_t Refcount() const { return refcount; }
|
size_t Refcount() const { return refcount; }
|
||||||
|
bool IsUnique() const { return refcount == 1; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
kthread_mutex_t reflock;
|
kthread_mutex_t reflock;
|
||||||
size_t refcount;
|
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
|
} // namespace Sortix
|
||||||
|
|
|
@ -72,12 +72,12 @@ public:
|
||||||
// the screen resolution or the graphics driver. The backing text buffer can
|
// 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
|
// 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.
|
// so don't forget to release it when you are done.
|
||||||
class TextBufferHandle : public Refcounted
|
class TextBufferHandle : public Refcountable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TextBufferHandle(TextBuffer* textbuf = NULL, bool deletebuf = true,
|
TextBufferHandle(TextBuffer* textbuf = NULL, bool deletebuf = true,
|
||||||
TextBuffer* def = NULL, bool deletedef = true);
|
TextBuffer* def = NULL, bool deletedef = true);
|
||||||
~TextBufferHandle();
|
virtual ~TextBufferHandle();
|
||||||
TextBuffer* Acquire();
|
TextBuffer* Acquire();
|
||||||
void Release(TextBuffer* textbuf);
|
void Release(TextBuffer* textbuf);
|
||||||
void Replace(TextBuffer* newtextbuf, bool deletebuf = true);
|
void Replace(TextBuffer* newtextbuf, bool deletebuf = true);
|
||||||
|
@ -91,7 +91,6 @@ private:
|
||||||
bool deletedef;
|
bool deletedef;
|
||||||
bool deletebuf;
|
bool deletebuf;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Sortix
|
} // namespace Sortix
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
#ifndef SORTIX_VIDEO_H
|
#ifndef SORTIX_VIDEO_H
|
||||||
#define SORTIX_VIDEO_H
|
#define SORTIX_VIDEO_H
|
||||||
|
|
||||||
|
#include <sortix/kernel/refcount.h>
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
|
|
||||||
class TextBuffer;
|
class TextBuffer;
|
||||||
|
@ -51,7 +53,7 @@ public:
|
||||||
|
|
||||||
namespace Video {
|
namespace Video {
|
||||||
|
|
||||||
void Init(TextBufferHandle* textbufhandle);
|
void Init(Ref<TextBufferHandle> textbufhandle);
|
||||||
bool RegisterDriver(const char* name, VideoDriver* driver);
|
bool RegisterDriver(const char* name, VideoDriver* driver);
|
||||||
char* GetCurrentMode();
|
char* GetCurrentMode();
|
||||||
char* GetDriverName(size_t index);
|
char* GetDriverName(size_t index);
|
||||||
|
|
|
@ -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.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -17,24 +17,23 @@
|
||||||
You should have received a copy of the GNU General Public License along with
|
You should have received a copy of the GNU General Public License along with
|
||||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
mount.h
|
sortix/mount.h
|
||||||
Handles system wide mount points and initialization of new file systems.
|
Constants related to mounting and binding.
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#ifndef SORTIX_MOUNT_H
|
#ifndef SORTIX_INCLUDE_MOUNT_H
|
||||||
#define SORTIX_MOUNT_H
|
#define SORTIX_INCLUDE_MOUNT_H
|
||||||
|
|
||||||
namespace Sortix
|
#include <features.h>
|
||||||
{
|
|
||||||
class DevFileSystem;
|
|
||||||
|
|
||||||
namespace Mount
|
__BEGIN_DECLS
|
||||||
{
|
|
||||||
void Init();
|
#define MREPL (0<<0) /* Replace binding. */
|
||||||
DevFileSystem* WhichFileSystem(const char* path, size_t* pathoffset);
|
#define MBEFORE (1<<0) /* Add to start of directory union. */
|
||||||
bool Register(DevFileSystem* fs, const char* path);
|
#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
|
#endif
|
|
@ -27,6 +27,7 @@
|
||||||
#define SORTIX_STAT_H
|
#define SORTIX_STAT_H
|
||||||
|
|
||||||
#include <features.h>
|
#include <features.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
@ -71,6 +72,7 @@ struct stat
|
||||||
/*#define S_ISUID 0x0800 */
|
/*#define S_ISUID 0x0800 */
|
||||||
/*#define S_ISGID 0x0400 */
|
/*#define S_ISGID 0x0400 */
|
||||||
#define S_ISVTX 0x0200
|
#define S_ISVTX 0x0200
|
||||||
|
#define S_SETABLE (0777 | 0x0200 | 0x0400 | 0x0800)
|
||||||
#define S_ISSOCK(mode) ((mode & S_IFMT) == S_IFSOCK)
|
#define S_ISSOCK(mode) ((mode & S_IFMT) == S_IFSOCK)
|
||||||
#define S_ISLNK(mode) ((mode & S_IFMT) == S_IFLNK)
|
#define S_ISLNK(mode) ((mode & S_IFMT) == S_IFLNK)
|
||||||
#define S_ISREG(mode) ((mode & S_IFMT) == S_IFREG)
|
#define S_ISREG(mode) ((mode & S_IFMT) == S_IFREG)
|
||||||
|
|
|
@ -49,7 +49,6 @@
|
||||||
#define SYSCALL_OPEN 23
|
#define SYSCALL_OPEN 23
|
||||||
#define SYSCALL_READDIRENTS 24
|
#define SYSCALL_READDIRENTS 24
|
||||||
#define SYSCALL_CHDIR 25
|
#define SYSCALL_CHDIR 25
|
||||||
#define SYSCALL_GETCWD 26
|
|
||||||
#define SYSCALL_UNLINK 27
|
#define SYSCALL_UNLINK 27
|
||||||
#define SYSCALL_REGISTER_ERRNO 28
|
#define SYSCALL_REGISTER_ERRNO 28
|
||||||
#define SYSCALL_REGISTER_SIGNAL_HANDLER 29
|
#define SYSCALL_REGISTER_SIGNAL_HANDLER 29
|
||||||
|
@ -78,6 +77,7 @@
|
||||||
#define SYSCALL_RAISE 53
|
#define SYSCALL_RAISE 53
|
||||||
#define SYSCALL_OPENAT 54
|
#define SYSCALL_OPENAT 54
|
||||||
#define SYSCALL_DISPMSG_ISSUE 55
|
#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
|
#endif
|
||||||
|
|
|
@ -23,12 +23,18 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#include <sortix/kernel/platform.h>
|
#include <sortix/kernel/platform.h>
|
||||||
|
#include <sortix/kernel/vnode.h>
|
||||||
|
#include <sortix/kernel/descriptor.h>
|
||||||
#include <sortix/kernel/memorymanagement.h>
|
#include <sortix/kernel/memorymanagement.h>
|
||||||
#include <sortix/kernel/crc32.h>
|
#include <sortix/kernel/crc32.h>
|
||||||
#include <sortix/kernel/string.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/stat.h>
|
||||||
#include <sortix/mman.h>
|
#include <sortix/mman.h>
|
||||||
#include <sortix/initrd.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "initrd.h"
|
#include "initrd.h"
|
||||||
|
@ -37,7 +43,7 @@
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
namespace InitRD {
|
namespace InitRD {
|
||||||
|
|
||||||
uint8_t* initrd;
|
uint8_t* initrd = NULL;
|
||||||
size_t initrdsize;
|
size_t initrdsize;
|
||||||
const initrd_superblock_t* sb;
|
const initrd_superblock_t* sb;
|
||||||
|
|
||||||
|
@ -129,7 +135,6 @@ uint32_t Traverse(uint32_t ino, const char* name)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char* GetFilename(uint32_t dir, size_t index)
|
const char* GetFilename(uint32_t dir, size_t index)
|
||||||
{
|
{
|
||||||
const initrd_inode_t* inode = GetInode(dir);
|
const initrd_inode_t* inode = GetInode(dir);
|
||||||
|
@ -195,6 +200,7 @@ void CheckSum()
|
||||||
|
|
||||||
void Init(addr_t phys, size_t size)
|
void Init(addr_t phys, size_t size)
|
||||||
{
|
{
|
||||||
|
assert(!initrd);
|
||||||
// First up, map the initrd onto the kernel's address space.
|
// First up, map the initrd onto the kernel's address space.
|
||||||
addr_t virt = Memory::GetInitRD();
|
addr_t virt = Memory::GetInitRD();
|
||||||
size_t amount = 0;
|
size_t amount = 0;
|
||||||
|
@ -243,5 +249,96 @@ void Init(addr_t phys, size_t size)
|
||||||
CheckSum();
|
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 InitRD
|
||||||
} // namespace Sortix
|
} // namespace Sortix
|
||||||
|
|
|
@ -22,21 +22,22 @@
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#ifndef SORTIX_INITRD_KERNEL_H
|
#ifndef SORTIX_INITRD_H
|
||||||
#define SORTIX_INITRD_KERNEL_H
|
#define SORTIX_INITRD_H
|
||||||
|
|
||||||
|
#include <sortix/kernel/refcount.h>
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
|
|
||||||
|
class Descriptor;
|
||||||
|
|
||||||
namespace InitRD {
|
namespace InitRD {
|
||||||
|
|
||||||
void Init(addr_t phys, size_t size);
|
bool ExtractInto(Ref<Descriptor> desc);
|
||||||
uint32_t Root();
|
bool ExtractFromPhysicalInto(addr_t physaddr, size_t size, Ref<Descriptor> desc);
|
||||||
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);
|
|
||||||
|
|
||||||
} // namespace InitRD
|
} // namespace InitRD
|
||||||
|
|
||||||
} // namespace Sortix
|
} // namespace Sortix
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -23,178 +23,364 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#include <sortix/kernel/platform.h>
|
#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/string.h>
|
||||||
#include <sortix/kernel/kthread.h>
|
#include <sortix/kernel/kthread.h>
|
||||||
|
|
||||||
#include <sortix/seek.h>
|
#include <sortix/seek.h>
|
||||||
|
#include <sortix/dirent.h>
|
||||||
|
#include <sortix/fcntl.h>
|
||||||
|
#include <sortix/stat.h>
|
||||||
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "device.h"
|
|
||||||
#include "stream.h"
|
|
||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
|
||||||
namespace Sortix
|
namespace Sortix {
|
||||||
|
namespace IO {
|
||||||
|
|
||||||
|
static Ref<Descriptor> PrepareLookup(const char** path, int dirfd = AT_FDCWD)
|
||||||
{
|
{
|
||||||
namespace IO
|
if ( (*path)[0] == '/' )
|
||||||
{
|
return CurrentProcess()->GetRoot();
|
||||||
#ifdef GOT_FAKE_KTHREAD
|
if ( dirfd == AT_FDCWD )
|
||||||
struct SysWrite_t
|
return CurrentProcess()->GetCWD();
|
||||||
{
|
return CurrentProcess()->GetDescriptor(dirfd);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -25,12 +25,12 @@
|
||||||
#ifndef SORTIX_IO_H
|
#ifndef SORTIX_IO_H
|
||||||
#define SORTIX_IO_H
|
#define SORTIX_IO_H
|
||||||
|
|
||||||
namespace Sortix
|
namespace Sortix {
|
||||||
{
|
namespace IO {
|
||||||
namespace IO
|
|
||||||
{
|
void Init();
|
||||||
void Init();
|
|
||||||
}
|
} // namespace IO
|
||||||
}
|
} // namespace Sortix
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
Copyright(C) Jonas 'Sortie' Termansen 2011.
|
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
|
||||||
|
|
||||||
This file is part of Sortix.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -17,32 +17,32 @@
|
||||||
You should have received a copy of the GNU General Public License along with
|
You should have received a copy of the GNU General Public License along with
|
||||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
keyboard.cpp
|
ioctx.cpp
|
||||||
An interface to keyboards.
|
The context for io operations: who made it, how should data be copied, etc.
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#include <sortix/kernel/platform.h>
|
#include <sortix/kernel/platform.h>
|
||||||
#include "interrupt.h"
|
#include <sortix/kernel/ioctx.h>
|
||||||
#include "syscall.h"
|
#include <sortix/kernel/copy.h>
|
||||||
#include "keyboard.h"
|
#include "process.h"
|
||||||
#include "kb/ps2.h"
|
|
||||||
#include "kb/layout/us.h"
|
|
||||||
#include "logterminal.h"
|
|
||||||
|
|
||||||
namespace Sortix
|
namespace Sortix {
|
||||||
|
|
||||||
|
void SetupUserIOCtx(ioctx_t* ctx)
|
||||||
{
|
{
|
||||||
DevTerminal* tty;
|
ctx->uid = ctx->auth_uid = CurrentProcess()->uid;
|
||||||
|
ctx->gid = ctx->auth_gid = CurrentProcess()->gid;
|
||||||
void Keyboard::Init()
|
ctx->copy_to_dest = CopyToUser;
|
||||||
{
|
ctx->copy_from_src = CopyFromUser;
|
||||||
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"); }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 <sortix/kernel/platform.h>
|
||||||
#include "../../keyboard.h"
|
#include <sortix/kernel/keyboard.h>
|
||||||
#include <sortix/keycodes.h>
|
#include <sortix/keycodes.h>
|
||||||
#include "us.h"
|
#include "us.h"
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#ifndef SORTIX_KB_LAYOUT_US_H
|
#ifndef SORTIX_KB_LAYOUT_US_H
|
||||||
#define SORTIX_KB_LAYOUT_US_H
|
#define SORTIX_KB_LAYOUT_US_H
|
||||||
|
|
||||||
#include "../../keyboard.h"
|
#include <sortix/kernel/keyboard.h>
|
||||||
|
|
||||||
namespace Sortix
|
namespace Sortix
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,11 +23,11 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#include <sortix/kernel/platform.h>
|
#include <sortix/kernel/platform.h>
|
||||||
|
#include <sortix/kernel/keyboard.h>
|
||||||
|
#include <sortix/keycodes.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../interrupt.h"
|
#include "../interrupt.h"
|
||||||
#include "../keyboard.h"
|
|
||||||
#include <sortix/keycodes.h>
|
|
||||||
#include "ps2.h"
|
#include "ps2.h"
|
||||||
|
|
||||||
namespace Sortix
|
namespace Sortix
|
||||||
|
@ -87,14 +87,10 @@ namespace Sortix
|
||||||
void PS2Keyboard::OnInterrupt(CPU::InterruptRegisters* /*regs*/)
|
void PS2Keyboard::OnInterrupt(CPU::InterruptRegisters* /*regs*/)
|
||||||
{
|
{
|
||||||
uint8_t scancode = PopScancode();
|
uint8_t scancode = PopScancode();
|
||||||
#ifdef GOT_ACTUAL_KTHREAD
|
|
||||||
PS2KeyboardWork work;
|
PS2KeyboardWork work;
|
||||||
work.kb = this;
|
work.kb = this;
|
||||||
work.scancode = scancode;
|
work.scancode = scancode;
|
||||||
Interrupt::ScheduleWork(PS2Keyboard__InterruptWork, &work, sizeof(work));
|
Interrupt::ScheduleWork(PS2Keyboard__InterruptWork, &work, sizeof(work));
|
||||||
#else
|
|
||||||
InterruptWork(scancode);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PS2Keyboard::InterruptWork(uint8_t scancode)
|
void PS2Keyboard::InterruptWork(uint8_t scancode)
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
#define SORTIX_KB_PS2_H
|
#define SORTIX_KB_PS2_H
|
||||||
|
|
||||||
#include <sortix/kernel/kthread.h>
|
#include <sortix/kernel/kthread.h>
|
||||||
#include "../keyboard.h"
|
#include <sortix/kernel/keyboard.h>
|
||||||
|
|
||||||
namespace Sortix
|
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.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -33,15 +33,25 @@
|
||||||
#include <sortix/kernel/pci.h>
|
#include <sortix/kernel/pci.h>
|
||||||
#include <sortix/kernel/worker.h>
|
#include <sortix/kernel/worker.h>
|
||||||
#include <sortix/kernel/memorymanagement.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/mman.h>
|
||||||
#include <sortix/wait.h>
|
#include <sortix/wait.h>
|
||||||
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include "kernelinfo.h"
|
#include "kernelinfo.h"
|
||||||
#include "x86-family/gdt.h"
|
#include "x86-family/gdt.h"
|
||||||
#include "x86-family/float.h"
|
#include "x86-family/float.h"
|
||||||
#include "time.h"
|
#include "time.h"
|
||||||
#include "keyboard.h"
|
|
||||||
#include "multiboot.h"
|
#include "multiboot.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
|
@ -51,8 +61,8 @@
|
||||||
#include "ata.h"
|
#include "ata.h"
|
||||||
#include "com.h"
|
#include "com.h"
|
||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
|
#include "logterminal.h"
|
||||||
#include "vgatextbuffer.h"
|
#include "vgatextbuffer.h"
|
||||||
#include "terminal.h"
|
|
||||||
#include "serialterminal.h"
|
#include "serialterminal.h"
|
||||||
#include "textterminal.h"
|
#include "textterminal.h"
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
|
@ -62,12 +72,11 @@
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "pipe.h"
|
#include "pipe.h"
|
||||||
#include "filesystem.h"
|
|
||||||
#include "mount.h"
|
|
||||||
#include "directory.h"
|
|
||||||
#include "interrupt.h"
|
#include "interrupt.h"
|
||||||
#include "dispmsg.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
|
// Keep the stack size aligned with $CPU/base.s
|
||||||
const size_t STACK_SIZE = 64*1024;
|
const size_t STACK_SIZE = 64*1024;
|
||||||
|
@ -121,10 +130,18 @@ static size_t TextTermHeight(void* user)
|
||||||
return ((TextTerminal*) user)->Height();
|
return ((TextTerminal*) user)->Height();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addr_t initrd;
|
||||||
|
size_t initrdsize;
|
||||||
|
Ref<TextBufferHandle> textbufhandle;
|
||||||
|
|
||||||
extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
||||||
{
|
{
|
||||||
(void) magic;
|
(void) magic;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Stage 1. Initialization of Early Environment.
|
||||||
|
//
|
||||||
|
|
||||||
// Initialize system calls.
|
// Initialize system calls.
|
||||||
Syscall::Init();
|
Syscall::Init();
|
||||||
|
|
||||||
|
@ -137,10 +154,11 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
||||||
const size_t VGA_HEIGHT = 25;
|
const size_t VGA_HEIGHT = 25;
|
||||||
static uint16_t vga_attr_buffer[VGA_WIDTH*VGA_HEIGHT];
|
static uint16_t vga_attr_buffer[VGA_WIDTH*VGA_HEIGHT];
|
||||||
VGATextBuffer textbuf(VGAFB, 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.
|
// Setup a text terminal instance.
|
||||||
TextTerminal textterm(&textbufhandle);
|
TextTerminal textterm(textbufhandle);
|
||||||
|
|
||||||
// Register the text terminal as the kernel log and initialize it.
|
// Register the text terminal as the kernel log and initialize it.
|
||||||
Log::Init(PrintToTextTerminal, TextTermWidth, TextTermHeight, &textterm);
|
Log::Init(PrintToTextTerminal, TextTermWidth, TextTermHeight, &textterm);
|
||||||
|
@ -182,8 +200,8 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
||||||
"multiboot compliant?");
|
"multiboot compliant?");
|
||||||
}
|
}
|
||||||
|
|
||||||
addr_t initrd = 0;
|
initrd = 0;
|
||||||
size_t initrdsize = 0;
|
initrdsize = 0;
|
||||||
|
|
||||||
uint32_t* modules = (uint32_t*) (addr_t) bootinfo->mods_addr;
|
uint32_t* modules = (uint32_t*) (addr_t) bootinfo->mods_addr;
|
||||||
for ( uint32_t i = 0; i < bootinfo->mods_count; i++ )
|
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.
|
// Initialize the kernel heap.
|
||||||
_init_heap();
|
_init_heap();
|
||||||
|
|
||||||
// Initialize the interrupt worker.
|
// Initialize the interrupt worker (before scheduling is enabled).
|
||||||
Interrupt::InitWorker();
|
Interrupt::InitWorker();
|
||||||
|
|
||||||
// Initialize the list of kernel devices.
|
//
|
||||||
DeviceFS::Init();
|
// Stage 2. Transition to Multithreaded Environment
|
||||||
|
//
|
||||||
// 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();
|
|
||||||
|
|
||||||
// Initialize the process system.
|
// Initialize the process system.
|
||||||
Process::Init();
|
Process::Init();
|
||||||
|
@ -236,47 +240,11 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
||||||
// Initialize the thread system.
|
// Initialize the thread system.
|
||||||
Thread::Init();
|
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.
|
// Initialize Unix Signals.
|
||||||
Signal::Init();
|
Signal::Init();
|
||||||
|
|
||||||
// Initialize the worker thread data structures.
|
// Initialize the scheduler.
|
||||||
Worker::Init();
|
Scheduler::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 Display Message framework.
|
// Initialize the Display Message framework.
|
||||||
DisplayMessage::Init();
|
DisplayMessage::Init();
|
||||||
|
@ -294,6 +262,7 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
||||||
// _nothing_ else to run on this CPU.
|
// _nothing_ else to run on this CPU.
|
||||||
Thread* idlethread = new Thread;
|
Thread* idlethread = new Thread;
|
||||||
idlethread->process = system;
|
idlethread->process = system;
|
||||||
|
idlethread->addrspace = idlethread->process->addrspace;
|
||||||
idlethread->kernelstackpos = (addr_t) stack;
|
idlethread->kernelstackpos = (addr_t) stack;
|
||||||
idlethread->kernelstacksize = STACK_SIZE;
|
idlethread->kernelstacksize = STACK_SIZE;
|
||||||
idlethread->kernelstackmalloced = false;
|
idlethread->kernelstackmalloced = false;
|
||||||
|
@ -302,8 +271,9 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
||||||
Scheduler::SetIdleThread(idlethread);
|
Scheduler::SetIdleThread(idlethread);
|
||||||
|
|
||||||
// Let's create a regular kernel thread that can decide what happens next.
|
// 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
|
// Note that we don't do the work here: if all other threads are not running
|
||||||
// nothing to run. Therefore we must become the system idle thread.
|
// and this thread isn't runnable, then there is nothing to run. Therefore
|
||||||
|
// we must become the system idle thread.
|
||||||
RunKernelThread(BootThread, NULL);
|
RunKernelThread(BootThread, NULL);
|
||||||
|
|
||||||
// Set up such that floating point registers are lazily switched.
|
// 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*/)
|
static void SystemIdleThread(void* /*user*/)
|
||||||
{
|
{
|
||||||
// Alright, we are now the system idle thread. If there is nothing to do,
|
// 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);
|
while(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void BootThread(void* /*user*/)
|
static void BootThread(void* /*user*/)
|
||||||
{
|
{
|
||||||
|
//
|
||||||
|
// Stage 3. Spawning Kernel Worker Threads.
|
||||||
|
//
|
||||||
|
|
||||||
// Hello, threaded world! You can now regard the kernel as a multi-threaded
|
// 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
|
// process with super-root access to the system. Before we boot the full
|
||||||
// system we need to start some worker threads.
|
// system we need to start some worker threads.
|
||||||
|
|
||||||
// Let's create the interrupt worker thread that executes additional work
|
// Let's create the interrupt worker thread that executes additional work
|
||||||
// requested by interrupt handlers, where such work isn't safe.
|
// requested by interrupt handlers, where such work isn't safe.
|
||||||
Thread* interruptworker = RunKernelThread(Interrupt::WorkerThread, NULL);
|
Thread* interruptworker = RunKernelThread(Interrupt::WorkerThread, NULL);
|
||||||
if ( !interruptworker )
|
if ( !interruptworker )
|
||||||
Panic("Could not create interrupt worker");
|
Panic("Could not create interrupt worker");
|
||||||
|
|
||||||
|
// Initialize the worker thread data structures.
|
||||||
|
Worker::Init();
|
||||||
|
|
||||||
// Create a general purpose worker thread.
|
// Create a general purpose worker thread.
|
||||||
Thread* workerthread = RunKernelThread(Worker::Thread, NULL);
|
Thread* workerthread = RunKernelThread(Worker::Thread, NULL);
|
||||||
if ( !workerthread )
|
if ( !workerthread )
|
||||||
Panic("Unable to create general purpose worker thread");
|
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
|
// Finally, let's transfer control to a new kernel process that will
|
||||||
// eventually run user-space code known as the operating system.
|
// eventually run user-space code known as the operating system.
|
||||||
addr_t initaddrspace = Memory::Fork();
|
addr_t initaddrspace = Memory::Fork();
|
||||||
|
@ -350,11 +423,18 @@ static void BootThread(void* /*user*/)
|
||||||
|
|
||||||
CurrentProcess()->AddChildProcess(init);
|
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;
|
init->addrspace = initaddrspace;
|
||||||
Scheduler::SetInitProcess(init);
|
Scheduler::SetInitProcess(init);
|
||||||
|
|
||||||
Thread* initthread = RunKernelThread(init, InitThread, NULL);
|
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.
|
// Wait until init init is done and then shut down the computer.
|
||||||
int status;
|
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*/)
|
static void InitThread(void* /*user*/)
|
||||||
{
|
{
|
||||||
// We are the init process's first thread. Let's load the init program from
|
// 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();
|
Thread* thread = CurrentThread();
|
||||||
Process* process = CurrentProcess();
|
Process* process = CurrentProcess();
|
||||||
|
|
||||||
uint32_t inode = InitRD::Traverse(InitRD::Root(), "init");
|
const char* initpath = "/" CPUTYPE_STR "/bin/init";
|
||||||
if ( !inode ) { Panic("InitRD did not contain an 'init' program."); }
|
|
||||||
|
|
||||||
size_t programsize;
|
ioctx_t ctx; SetupKernelIOCtx(&ctx);
|
||||||
uint8_t* program = InitRD::Open(inode, &programsize);
|
Ref<Descriptor> root = CurrentProcess()->GetRoot();
|
||||||
if ( !program ) { Panic("InitRD did not contain an 'init' program."); }
|
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;
|
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;
|
int prot = PROT_FORK | PROT_READ | PROT_WRITE | PROT_KREAD | PROT_KWRITE;
|
||||||
if ( !Memory::MapRange(stackpos, stacksize, prot) )
|
if ( !Memory::MapRange(stackpos, stacksize, prot) )
|
||||||
{
|
|
||||||
Panic("Could not allocate init stack memory");
|
Panic("Could not allocate init stack memory");
|
||||||
}
|
|
||||||
|
|
||||||
thread->stackpos = stackpos;
|
thread->stackpos = stackpos;
|
||||||
thread->stacksize = stacksize;
|
thread->stacksize = stacksize;
|
||||||
|
|
||||||
int argc = 1;
|
int argc = 1;
|
||||||
const char* argv[] = { "init", NULL };
|
const char* argv[] = { "init", NULL };
|
||||||
#if defined(PLATFORM_X86)
|
const char* cputype = "cputype=" CPUTYPE_STR;
|
||||||
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
|
|
||||||
int envc = 1;
|
int envc = 1;
|
||||||
const char* envp[] = { cputype, NULL };
|
const char* envp[] = { cputype, NULL };
|
||||||
CPU::InterruptRegisters regs;
|
CPU::InterruptRegisters regs;
|
||||||
|
|
||||||
if ( process->Execute("init", program, programsize, argc, argv, envc, envp,
|
if ( process->Execute(initpath, program, programsize, argc, argv, envc,
|
||||||
®s) )
|
envp, ®s) )
|
||||||
{
|
PanicF("Unable to execute %s.", initpath);
|
||||||
Panic("Unable to execute init program");
|
|
||||||
}
|
delete[] program;
|
||||||
|
|
||||||
// Now become the init process and the operation system shall run.
|
// Now become the init process and the operation system shall run.
|
||||||
CPU::LoadRegisters(®s);
|
CPU::LoadRegisters(®s);
|
||||||
|
|
|
@ -23,303 +23,294 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#include <sortix/kernel/platform.h>
|
#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/keycodes.h>
|
||||||
#include <sortix/signal.h>
|
#include <sortix/signal.h>
|
||||||
|
#include <sortix/stat.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "utf8.h"
|
#include "utf8.h"
|
||||||
#include "keyboard.h"
|
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
#include "terminal.h"
|
|
||||||
#include "logterminal.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
|
inode_type = INODE_TYPE_TTY;
|
||||||
| TERMMODE_UNICODE
|
this->dev = dev;
|
||||||
| TERMMODE_SIGNAL
|
this->ino = (ino_t) this;
|
||||||
| TERMMODE_UTF8
|
this->type = S_IFCHR;
|
||||||
| TERMMODE_LINEBUFFER
|
this->stat_mode = (mode & S_SETABLE) | this->type;
|
||||||
| TERMMODE_ECHO
|
this->stat_uid = owner;
|
||||||
| TERMMODE_NONBLOCK;
|
this->stat_gid = group;
|
||||||
|
this->keyboard = keyboard;
|
||||||
LogTerminal::LogTerminal(Keyboard* keyboard, KeyboardLayout* kblayout)
|
this->kblayout = kblayout;
|
||||||
{
|
this->partiallywritten = 0;
|
||||||
this->keyboard = keyboard;
|
this->control = false;
|
||||||
this->kblayout = kblayout;
|
this->termmode = TERMMODE_UNICODE
|
||||||
this->partiallywritten = 0;
|
| TERMMODE_SIGNAL
|
||||||
this->control = false;
|
| TERMMODE_UTF8
|
||||||
this->mode = TERMMODE_UNICODE
|
| TERMMODE_LINEBUFFER
|
||||||
| TERMMODE_SIGNAL
|
| TERMMODE_ECHO;
|
||||||
| TERMMODE_UTF8
|
this->termlock = KTHREAD_MUTEX_INITIALIZER;
|
||||||
| TERMMODE_LINEBUFFER
|
this->datacond = KTHREAD_COND_INITIALIZER;
|
||||||
| TERMMODE_ECHO;
|
this->numwaiting = 0;
|
||||||
this->termlock = KTHREAD_MUTEX_INITIALIZER;
|
this->numeofs = 0;
|
||||||
this->datacond = KTHREAD_COND_INITIALIZER;
|
keyboard->SetOwner(this, NULL);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
#define SORTIX_LOGTERMINAL_H
|
||||||
|
|
||||||
#include <sortix/kernel/kthread.h>
|
#include <sortix/kernel/kthread.h>
|
||||||
#ifdef GOT_FAKE_KTHREAD
|
#include <sortix/kernel/inode.h>
|
||||||
#include "event.h"
|
#include <sortix/kernel/keyboard.h>
|
||||||
#endif
|
|
||||||
#include "stream.h"
|
|
||||||
#include "terminal.h"
|
|
||||||
#include "keyboard.h"
|
|
||||||
#include "linebuffer.h"
|
#include "linebuffer.h"
|
||||||
|
|
||||||
namespace Sortix
|
namespace Sortix {
|
||||||
|
|
||||||
|
class LogTerminal : public AbstractInode, public KeyboardOwner
|
||||||
{
|
{
|
||||||
class LogTerminal : public DevTerminal, public KeyboardOwner
|
public:
|
||||||
{
|
LogTerminal(dev_t dev, mode_t mode, uid_t owner, gid_t group,
|
||||||
public:
|
Keyboard* keyboard, KeyboardLayout* kblayout);
|
||||||
LogTerminal(Keyboard* keyboard, KeyboardLayout* kblayout);
|
virtual ~LogTerminal();
|
||||||
virtual ~LogTerminal();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ssize_t Read(uint8_t* dest, size_t count);
|
virtual int sync(ioctx_t* ctx);
|
||||||
virtual ssize_t Write(const uint8_t* src, size_t count);
|
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
||||||
virtual bool IsReadable();
|
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
||||||
virtual bool IsWritable();
|
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:
|
public:
|
||||||
virtual bool SetMode(unsigned mode);
|
virtual void OnKeystroke(Keyboard* keyboard, void* user);
|
||||||
virtual bool SetWidth(unsigned width);
|
|
||||||
virtual bool SetHeight(unsigned height);
|
|
||||||
virtual unsigned GetMode() const;
|
|
||||||
virtual unsigned GetWidth() const;
|
|
||||||
virtual unsigned GetHeight() const;
|
|
||||||
|
|
||||||
public:
|
private:
|
||||||
virtual void OnKeystroke(Keyboard* keyboard, void* user);
|
void ProcessKeystroke(int kbkey);
|
||||||
|
void QueueUnicode(uint32_t unicode);
|
||||||
|
void CommitLineBuffer();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ProcessKeystroke(int kbkey);
|
mutable kthread_mutex_t termlock;
|
||||||
void QueueUnicode(uint32_t unicode);
|
kthread_cond_t datacond;
|
||||||
void CommitLineBuffer();
|
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
|
#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"); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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/platform.h>
|
||||||
#include <sortix/kernel/kthread.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/signal.h>
|
||||||
|
#include <sortix/stat.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#ifdef GOT_FAKE_KTHREAD
|
|
||||||
#include "event.h"
|
|
||||||
#endif
|
|
||||||
#include "signal.h"
|
#include "signal.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
#include "pipe.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:
|
if ( !kthread_cond_wait_signal(&readcond, &pipelock) )
|
||||||
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) )
|
errno = EINTR;
|
||||||
{
|
|
||||||
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;
|
|
||||||
return -1;
|
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
|
#ifndef SORTIX_PIPE_H
|
||||||
#define SORTIX_PIPE_H
|
#define SORTIX_PIPE_H
|
||||||
|
|
||||||
#include "stream.h"
|
namespace Sortix {
|
||||||
|
|
||||||
namespace Sortix
|
class Inode;
|
||||||
{
|
|
||||||
namespace Pipe
|
namespace Pipe {
|
||||||
{
|
|
||||||
void Init();
|
void Init();
|
||||||
}
|
bool CreatePipes(Inode* pipes[2]);
|
||||||
}
|
|
||||||
|
} // namespace Pipe
|
||||||
|
} // namespace Sortix
|
||||||
|
|
||||||
#endif
|
#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.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -24,11 +24,19 @@
|
||||||
|
|
||||||
#include <sortix/kernel/platform.h>
|
#include <sortix/kernel/platform.h>
|
||||||
#include <sortix/kernel/kthread.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/worker.h>
|
||||||
#include <sortix/kernel/memorymanagement.h>
|
#include <sortix/kernel/memorymanagement.h>
|
||||||
#include <sortix/kernel/string.h>
|
#include <sortix/kernel/string.h>
|
||||||
#include <sortix/signal.h>
|
#include <sortix/signal.h>
|
||||||
#include <sortix/unistd.h>
|
#include <sortix/unistd.h>
|
||||||
|
#include <sortix/fcntl.h>
|
||||||
|
#include <sortix/stat.h>
|
||||||
#include <sortix/fork.h>
|
#include <sortix/fork.h>
|
||||||
#include <sortix/mman.h>
|
#include <sortix/mman.h>
|
||||||
#include <sortix/wait.h>
|
#include <sortix/wait.h>
|
||||||
|
@ -38,10 +46,6 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "device.h"
|
|
||||||
#include "stream.h"
|
|
||||||
#include "filesystem.h"
|
|
||||||
#include "directory.h"
|
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
#include "initrd.h"
|
#include "initrd.h"
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
|
@ -113,7 +117,7 @@ namespace Sortix
|
||||||
nozombify = false;
|
nozombify = false;
|
||||||
firstthread = NULL;
|
firstthread = NULL;
|
||||||
threadlock = KTHREAD_MUTEX_INITIALIZER;
|
threadlock = KTHREAD_MUTEX_INITIALIZER;
|
||||||
workingdir = NULL;
|
ptrlock = KTHREAD_MUTEX_INITIALIZER;
|
||||||
mmapfrom = 0x80000000UL;
|
mmapfrom = 0x80000000UL;
|
||||||
exitstatus = -1;
|
exitstatus = -1;
|
||||||
pid = AllocatePID();
|
pid = AllocatePID();
|
||||||
|
@ -126,9 +130,30 @@ namespace Sortix
|
||||||
assert(!firstchild);
|
assert(!firstchild);
|
||||||
assert(!addrspace);
|
assert(!addrspace);
|
||||||
assert(!segments);
|
assert(!segments);
|
||||||
|
assert(!dtable);
|
||||||
|
assert(!mtable);
|
||||||
|
assert(!cwd);
|
||||||
|
assert(!root);
|
||||||
|
|
||||||
Remove(this);
|
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);
|
void Process__OnLastThreadExit(void* user);
|
||||||
|
@ -205,7 +230,11 @@ namespace Sortix
|
||||||
addr_t prevaddrspace = curthread->SwitchAddressSpace(addrspace);
|
addr_t prevaddrspace = curthread->SwitchAddressSpace(addrspace);
|
||||||
|
|
||||||
ResetAddressSpace();
|
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
|
// Destroy the address space and safely switch to the replacement
|
||||||
// address space before things get dangerous.
|
// address space before things get dangerous.
|
||||||
|
@ -436,6 +465,48 @@ namespace Sortix
|
||||||
firstchild = child;
|
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()
|
Process* Process::Fork()
|
||||||
{
|
{
|
||||||
assert(CurrentProcess() == this);
|
assert(CurrentProcess() == this);
|
||||||
|
@ -475,16 +546,30 @@ namespace Sortix
|
||||||
// Remember the relation to the child process.
|
// Remember the relation to the child process.
|
||||||
AddChildProcess(clone);
|
AddChildProcess(clone);
|
||||||
|
|
||||||
bool failure = false;
|
// Initialize everything that is safe and can't fail.
|
||||||
|
|
||||||
if ( !descriptors.Fork(&clone->descriptors) )
|
|
||||||
failure = true;
|
|
||||||
|
|
||||||
clone->mmapfrom = mmapfrom;
|
clone->mmapfrom = mmapfrom;
|
||||||
|
|
||||||
clone->workingdir = NULL;
|
kthread_mutex_lock(&ptrlock);
|
||||||
if ( workingdir && !(clone->workingdir = String::Clone(workingdir)) )
|
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;
|
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
|
// 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
|
// 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;
|
stackpos = envppos - envpsize;
|
||||||
|
|
||||||
descriptors.OnExecute();
|
dtable->OnExecute();
|
||||||
|
|
||||||
ExecuteCPU(argc, stackargv, envc, stackenvp, stackpos, entry, regs);
|
ExecuteCPU(argc, stackargv, envc, stackenvp, stackpos, entry, regs);
|
||||||
|
|
||||||
return 0;
|
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;
|
// TODO: Locking the root/cwd pointers. How should that be arranged?
|
||||||
(void) path;
|
Ref<Descriptor> dir = path[0] == '/' ? root : cwd;
|
||||||
char* abs = Directory::MakeAbsolute("/", progname);
|
return dir->open(ctx, path, flags, mode);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int SysExecVE(const char* _filename, char* const _argv[], char* const _envp[])
|
int SysExecVE(const char* _filename, char* const _argv[], char* const _envp[])
|
||||||
|
@ -590,8 +668,9 @@ namespace Sortix
|
||||||
int envc;
|
int envc;
|
||||||
char** argv;
|
char** argv;
|
||||||
char** envp;
|
char** envp;
|
||||||
DevBuffer* dev;
|
ioctx_t ctx;
|
||||||
uintmax_t needed;
|
Ref<Descriptor> desc;
|
||||||
|
struct stat st;
|
||||||
size_t sofar;
|
size_t sofar;
|
||||||
size_t count;
|
size_t count;
|
||||||
uint8_t* buffer;
|
uint8_t* buffer;
|
||||||
|
@ -627,24 +706,25 @@ namespace Sortix
|
||||||
if ( !envp[i] ) { goto cleanup_envp; }
|
if ( !envp[i] ) { goto cleanup_envp; }
|
||||||
}
|
}
|
||||||
|
|
||||||
dev = OpenProgramImage(filename, process->workingdir, "/bin");
|
SetupKernelIOCtx(&ctx);
|
||||||
if ( !dev ) { goto cleanup_envp; }
|
|
||||||
|
|
||||||
dev->Refer(); // TODO: Rules of GC may change soon.
|
// TODO: Somehow mark the executable as busy and don't permit writes?
|
||||||
needed = dev->Size();
|
desc = process->Open(&ctx, filename, O_RDONLY, 0);
|
||||||
if ( SIZE_MAX < needed ) { errno = ENOMEM; goto cleanup_dev; }
|
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];
|
buffer = new uint8_t[count];
|
||||||
if ( !buffer ) { goto cleanup_dev; }
|
if ( !buffer ) { goto cleanup_desc; }
|
||||||
sofar = 0;
|
sofar = 0;
|
||||||
while ( sofar < count )
|
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 ) { goto cleanup_buffer; }
|
||||||
if ( bytesread == 0 ) { errno = EEOF; return -1; }
|
if ( bytesread == 0 ) { errno = EEOF; goto cleanup_buffer; }
|
||||||
sofar += bytesread;
|
sofar += bytesread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -653,8 +733,8 @@ namespace Sortix
|
||||||
|
|
||||||
cleanup_buffer:
|
cleanup_buffer:
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
cleanup_dev:
|
cleanup_desc:
|
||||||
dev->Unref();
|
desc.Reset();
|
||||||
cleanup_envp:
|
cleanup_envp:
|
||||||
for ( int i = 0; i < envc; i++) { delete[] envp[i]; }
|
for ( int i = 0; i < envc; i++) { delete[] envp[i]; }
|
||||||
delete[] envp;
|
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.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -25,16 +25,21 @@
|
||||||
#ifndef SORTIX_PROCESS_H
|
#ifndef SORTIX_PROCESS_H
|
||||||
#define SORTIX_PROCESS_H
|
#define SORTIX_PROCESS_H
|
||||||
|
|
||||||
#include "descriptors.h"
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include <sortix/kernel/kthread.h>
|
#include <sortix/kernel/kthread.h>
|
||||||
|
#include <sortix/kernel/refcount.h>
|
||||||
#include <sortix/fork.h>
|
#include <sortix/fork.h>
|
||||||
|
|
||||||
namespace Sortix
|
namespace Sortix
|
||||||
{
|
{
|
||||||
class Thread;
|
class Thread;
|
||||||
class Process;
|
class Process;
|
||||||
|
class Descriptor;
|
||||||
|
class DescriptorTable;
|
||||||
|
class MountTable;
|
||||||
struct ProcessSegment;
|
struct ProcessSegment;
|
||||||
|
struct ioctx_struct;
|
||||||
|
typedef struct ioctx_struct ioctx_t;
|
||||||
|
|
||||||
const int SEG_NONE = 0;
|
const int SEG_NONE = 0;
|
||||||
const int SEG_TEXT = 1;
|
const int SEG_TEXT = 1;
|
||||||
|
@ -76,8 +81,28 @@ namespace Sortix
|
||||||
|
|
||||||
public:
|
public:
|
||||||
addr_t addrspace;
|
addr_t addrspace;
|
||||||
char* workingdir;
|
|
||||||
pid_t pid;
|
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:
|
private:
|
||||||
// A process may only access its parent if parentlock is locked. A process
|
// A process may only access its parent if parentlock is locked. A process
|
||||||
|
@ -102,7 +127,6 @@ namespace Sortix
|
||||||
kthread_mutex_t threadlock;
|
kthread_mutex_t threadlock;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DescriptorTable descriptors;
|
|
||||||
ProcessSegment* segments;
|
ProcessSegment* segments;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -29,32 +29,38 @@
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
|
|
||||||
Refcounted::Refcounted()
|
Refcountable::Refcountable()
|
||||||
{
|
{
|
||||||
reflock = KTHREAD_MUTEX_INITIALIZER;
|
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
|
// It's OK to be deleted if our refcount is 1, it won't mess with any
|
||||||
// other owners that might need us.
|
// other owners that might need us.
|
||||||
assert(refcount <= 1);
|
assert(refcount <= 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Refcounted::Refer()
|
void Refcountable::Refer_Renamed()
|
||||||
{
|
{
|
||||||
ScopedLock lock(&reflock);
|
ScopedLock lock(&reflock);
|
||||||
refcount++;
|
refcount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Refcounted::Unref()
|
void Refcountable::Unref_Renamed()
|
||||||
{
|
{
|
||||||
|
assert(!being_deleted);
|
||||||
kthread_mutex_lock(&reflock);
|
kthread_mutex_lock(&reflock);
|
||||||
bool deleteme = !--refcount;
|
assert(refcount);
|
||||||
|
bool deleteme = !refcount || !--refcount;
|
||||||
kthread_mutex_unlock(&reflock);
|
kthread_mutex_unlock(&reflock);
|
||||||
if ( deleteme )
|
if ( deleteme )
|
||||||
|
{
|
||||||
|
being_deleted = true;
|
||||||
delete this;
|
delete this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Sortix
|
} // namespace Sortix
|
||||||
|
|
|
@ -39,6 +39,9 @@
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
namespace Scheduler {
|
namespace Scheduler {
|
||||||
|
|
||||||
|
const uint32_t SCHED_MAGIC = 0x1234567;
|
||||||
|
|
||||||
|
volatile unsigned long premagic;
|
||||||
static Thread* currentthread;
|
static Thread* currentthread;
|
||||||
} // namespace Scheduler
|
} // namespace Scheduler
|
||||||
Thread* CurrentThread() { return Scheduler::currentthread; }
|
Thread* CurrentThread() { return Scheduler::currentthread; }
|
||||||
|
@ -51,6 +54,7 @@ Thread* idlethread;
|
||||||
Thread* firstrunnablethread;
|
Thread* firstrunnablethread;
|
||||||
Thread* firstsleepingthread;
|
Thread* firstsleepingthread;
|
||||||
Process* initprocess;
|
Process* initprocess;
|
||||||
|
volatile unsigned long postmagic;
|
||||||
|
|
||||||
static inline void SetCurrentThread(Thread* newcurrentthread)
|
static inline void SetCurrentThread(Thread* newcurrentthread)
|
||||||
{
|
{
|
||||||
|
@ -71,6 +75,8 @@ static Thread* PopNextThread()
|
||||||
|
|
||||||
static Thread* ValidatedPopNextThread()
|
static Thread* ValidatedPopNextThread()
|
||||||
{
|
{
|
||||||
|
assert(premagic == SCHED_MAGIC);
|
||||||
|
assert(postmagic == SCHED_MAGIC);
|
||||||
Thread* nextthread = PopNextThread();
|
Thread* nextthread = PopNextThread();
|
||||||
if ( !nextthread ) { Panic("Had no thread to switch to."); }
|
if ( !nextthread ) { Panic("Had no thread to switch to."); }
|
||||||
if ( nextthread->terminated )
|
if ( nextthread->terminated )
|
||||||
|
@ -120,9 +126,13 @@ static void DoActualSwitch(CPU::InterruptRegisters* regs)
|
||||||
|
|
||||||
void Switch(CPU::InterruptRegisters* regs)
|
void Switch(CPU::InterruptRegisters* regs)
|
||||||
{
|
{
|
||||||
|
assert(premagic == SCHED_MAGIC);
|
||||||
|
assert(postmagic == SCHED_MAGIC);
|
||||||
DoActualSwitch(regs);
|
DoActualSwitch(regs);
|
||||||
if ( regs->signal_pending && regs->InUserspace() )
|
if ( regs->signal_pending && regs->InUserspace() )
|
||||||
Signal::Dispatch(regs);
|
Signal::Dispatch(regs);
|
||||||
|
assert(premagic == SCHED_MAGIC);
|
||||||
|
assert(postmagic == SCHED_MAGIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool DEBUG_BEGINCTXSWITCH = false;
|
const bool DEBUG_BEGINCTXSWITCH = false;
|
||||||
|
@ -271,6 +281,8 @@ extern "C" void thread_exit_handler();
|
||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
|
premagic = postmagic = SCHED_MAGIC;
|
||||||
|
|
||||||
// We use a dummy so that the first context switch won't crash when the
|
// 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
|
// current thread is accessed. This lets us avoid checking whether it is
|
||||||
// NULL (which it only will be once), which gives simpler code.
|
// NULL (which it only will be once), which gives simpler code.
|
||||||
|
|
|
@ -23,9 +23,9 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#include <sortix/kernel/platform.h>
|
#include <sortix/kernel/platform.h>
|
||||||
#include <sortix/kernel/log.h>
|
#include <sortix/kernel/keyboard.h>
|
||||||
|
#include <string.h>
|
||||||
#include "vga.h"
|
#include "vga.h"
|
||||||
#include "keyboard.h"
|
|
||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
#include "serialterminal.h"
|
#include "serialterminal.h"
|
||||||
#include "scheduler.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 DEFAULT_COLOR = COLOR8_LIGHT_GREY << 0U | COLOR8_BLACK << 4U;
|
||||||
const uint16_t ATTR_CHAR = 1U << 0U;
|
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;
|
this->termlock = KTHREAD_MUTEX_INITIALIZER;
|
||||||
Reset();
|
Reset();
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#define SORTIX_TEXTTERMINAL_H
|
#define SORTIX_TEXTTERMINAL_H
|
||||||
|
|
||||||
#include <sortix/kernel/kthread.h>
|
#include <sortix/kernel/kthread.h>
|
||||||
|
#include <sortix/kernel/refcount.h>
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
|
|
||||||
|
@ -34,7 +35,7 @@ class TextBufferHandle;
|
||||||
class TextTerminal //: public Printable ?
|
class TextTerminal //: public Printable ?
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TextTerminal(TextBufferHandle* textbufhandle);
|
TextTerminal(Ref<TextBufferHandle> textbufhandle);
|
||||||
~TextTerminal();
|
~TextTerminal();
|
||||||
size_t Print(const char* string, size_t stringlen);
|
size_t Print(const char* string, size_t stringlen);
|
||||||
size_t Width() const;
|
size_t Width() const;
|
||||||
|
@ -52,7 +53,7 @@ private:
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable TextBufferHandle* textbufhandle;
|
mutable Ref<TextBufferHandle> textbufhandle;
|
||||||
mutable kthread_mutex_t termlock;
|
mutable kthread_mutex_t termlock;
|
||||||
uint8_t vgacolor;
|
uint8_t vgacolor;
|
||||||
unsigned column;
|
unsigned column;
|
||||||
|
|
113
sortix/vga.cpp
113
sortix/vga.cpp
|
@ -23,15 +23,19 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#include <sortix/kernel/platform.h>
|
#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 <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "fs/util.h"
|
#include "fs/util.h"
|
||||||
#include "fs/devfs.h"
|
|
||||||
#include "vga.h"
|
#include "vga.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "serialterminal.h"
|
|
||||||
|
|
||||||
#define TEST_VGAFONT 0
|
#define TEST_VGAFONT 0
|
||||||
|
|
||||||
|
@ -119,7 +123,7 @@ const uint8_t* GetFont()
|
||||||
return vgafont;
|
return vgafont;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Init()
|
void Init(const char* devpath, Ref<Descriptor> slashdev)
|
||||||
{
|
{
|
||||||
vgafontsize = VGA_FONT_NUMCHARS * VGA_FONT_CHARSIZE;
|
vgafontsize = VGA_FONT_NUMCHARS * VGA_FONT_CHARSIZE;
|
||||||
if ( !(vgafont = new uint8_t[vgafontsize]) )
|
if ( !(vgafont = new uint8_t[vgafontsize]) )
|
||||||
|
@ -129,12 +133,25 @@ void Init()
|
||||||
PrintFontChar(vgafont, 'A');
|
PrintFontChar(vgafont, 'A');
|
||||||
PrintFontChar(vgafont, 'S');
|
PrintFontChar(vgafont, 'S');
|
||||||
#endif
|
#endif
|
||||||
DevMemoryBuffer* vgamembuf = new DevMemoryBuffer(vgafont, vgafontsize,
|
|
||||||
false, false);
|
ioctx_t ctx; SetupKernelIOCtx(&ctx);
|
||||||
if ( !vgamembuf )
|
|
||||||
Panic("Unable to allocate vga font filesystem object");
|
// Setup the vgafont device.
|
||||||
if ( !DeviceFS::RegisterDevice("vgafont", vgamembuf) )
|
Ref<Inode> vgafontnode(new UtilMemoryBuffer(slashdev->dev, (ino_t) 0, 0, 0,
|
||||||
Panic("Unable to register vga font filesystem object");
|
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.
|
// Changes the position of the hardware cursor.
|
||||||
|
@ -153,82 +170,4 @@ void SetCursor(unsigned x, unsigned y)
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace VGA
|
} // 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
|
} // namespace Sortix
|
||||||
|
|
34
sortix/vga.h
34
sortix/vga.h
|
@ -25,11 +25,12 @@
|
||||||
#ifndef SORTIX_VGA_H
|
#ifndef SORTIX_VGA_H
|
||||||
#define SORTIX_VGA_H
|
#define SORTIX_VGA_H
|
||||||
|
|
||||||
#include "device.h"
|
#include <sortix/kernel/refcount.h>
|
||||||
#include "stream.h"
|
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
|
|
||||||
|
class Descriptor;
|
||||||
|
|
||||||
const size_t VGA_FONT_WIDTH = 8UL;
|
const size_t VGA_FONT_WIDTH = 8UL;
|
||||||
const size_t VGA_FONT_HEIGHT = 16UL;
|
const size_t VGA_FONT_HEIGHT = 16UL;
|
||||||
const size_t VGA_FONT_NUMCHARS = 256UL;
|
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 {
|
namespace VGA {
|
||||||
|
|
||||||
void Init();
|
void Init(const char* devpath, Ref<Descriptor> slashdev);
|
||||||
void SetCursor(unsigned x, unsigned y);
|
void SetCursor(unsigned x, unsigned y);
|
||||||
const uint8_t* GetFont();
|
const uint8_t* GetFont();
|
||||||
|
|
||||||
} // namespace VGA
|
} // 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
|
} // namespace Sortix
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -105,9 +105,9 @@ size_t currentdrvid;
|
||||||
bool newdrivers;
|
bool newdrivers;
|
||||||
|
|
||||||
kthread_mutex_t videolock;
|
kthread_mutex_t videolock;
|
||||||
TextBufferHandle* textbufhandle;
|
Ref<TextBufferHandle> textbufhandle;
|
||||||
|
|
||||||
void Init(TextBufferHandle* thetextbufhandle)
|
void Init(Ref<TextBufferHandle> thetextbufhandle)
|
||||||
{
|
{
|
||||||
videolock = KTHREAD_MUTEX_INITIALIZER;
|
videolock = KTHREAD_MUTEX_INITIALIZER;
|
||||||
textbufhandle = thetextbufhandle;
|
textbufhandle = thetextbufhandle;
|
||||||
|
|
|
@ -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 )
|
if ( (ssize_t) writeall(1, buffer, bytesread) < bytesread )
|
||||||
{
|
{
|
||||||
error(0, errno, "write: %s", inputname);
|
error(0, errno, "write: <stdout>", inputname);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} while ( true );
|
} 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
|
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
|
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 <stdio.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -40,24 +42,26 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
const char* frompath = argv[1];
|
const char* frompath = argv[1];
|
||||||
const char* topath = argv[2];
|
const char* topath = argv[2];
|
||||||
char tobuffer[256];
|
|
||||||
|
|
||||||
int fromfd = open(frompath, O_RDONLY);
|
int fromfd = open(frompath, O_RDONLY);
|
||||||
if ( fromfd < 0 ) { error(1, errno, "%s", frompath); return 1; }
|
if ( fromfd < 0 ) { error(1, errno, "%s", frompath); return 1; }
|
||||||
|
|
||||||
int tofd = open(topath, O_WRONLY | O_TRUNC | O_CREAT, 0777);
|
int tofd = open(topath, O_WRONLY | O_TRUNC | O_CREAT, 0777);
|
||||||
if ( tofd < 0 )
|
if ( tofd < 0 )
|
||||||
{
|
error(1, errno, "%s", topath);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 )
|
while ( true )
|
||||||
|
@ -67,7 +71,7 @@ int main(int argc, char* argv[])
|
||||||
ssize_t bytesread = read(fromfd, buffer, BUFFER_SIZE);
|
ssize_t bytesread = read(fromfd, buffer, BUFFER_SIZE);
|
||||||
if ( bytesread < 0 ) { error(1, errno, "read: %s", frompath); return 1; }
|
if ( bytesread < 0 ) { error(1, errno, "read: %s", frompath); return 1; }
|
||||||
if ( bytesread == 0 ) { return 0; }
|
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);
|
error(1, errno, "write: %s", topath);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -20,7 +20,10 @@
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -77,5 +80,8 @@ int main(int /*argc*/, char* /*argv*/[])
|
||||||
// we are running.
|
// we are running.
|
||||||
setenv("objtype", getenv("cputype"), 0);
|
setenv("objtype", getenv("cputype"), 0);
|
||||||
|
|
||||||
|
// Make sure that we have a /tmp directory.
|
||||||
|
mkdir("/tmp", 01777);
|
||||||
|
|
||||||
return runsystem();
|
return runsystem();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue