mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Add umount(2) and unmountat(2).
This commit is contained in:
parent
e88a3ef654
commit
d890d3082d
28 changed files with 599 additions and 477 deletions
346
ext/extfs.cpp
346
ext/extfs.cpp
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014.
|
||||
|
||||
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
|
||||
|
@ -23,6 +23,7 @@
|
|||
#define __STDC_CONSTANT_MACROS
|
||||
#define __STDC_LIMIT_MACROS
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
|
@ -49,6 +50,7 @@
|
|||
#endif
|
||||
|
||||
#if defined(__sortix__)
|
||||
#include <ioleast.h>
|
||||
#include <timespec.h>
|
||||
#else
|
||||
struct timespec timespec_make(time_t sec, long nsec)
|
||||
|
@ -80,6 +82,8 @@ struct timespec timespec_make(time_t sec, long nsec)
|
|||
#include "ioleast.h"
|
||||
#include "util.h"
|
||||
|
||||
static volatile bool should_terminate = false;
|
||||
|
||||
const uint32_t EXT2_FEATURE_COMPAT_SUPPORTED = 0;
|
||||
const uint32_t EXT2_FEATURE_INCOMPAT_SUPPORTED = \
|
||||
EXT2_FEATURE_INCOMPAT_FILETYPE;
|
||||
|
@ -146,105 +150,103 @@ void StatInode(Inode* inode, struct stat* st)
|
|||
|
||||
#if defined(__sortix__)
|
||||
|
||||
bool RespondData(int svr, int chl, const void* ptr, size_t count)
|
||||
bool RespondData(int chl, const void* ptr, size_t count)
|
||||
{
|
||||
return fsm_send(svr, chl, ptr, count) == (ssize_t) count;
|
||||
return writeall(chl, ptr, count) == count;
|
||||
}
|
||||
|
||||
bool RespondHeader(int svr, int chl, size_t type, size_t size)
|
||||
bool RespondHeader(int chl, size_t type, size_t size)
|
||||
{
|
||||
struct fsm_msg_header hdr;
|
||||
hdr.msgtype = type;
|
||||
hdr.msgsize = size;
|
||||
return RespondData(svr, chl, &hdr, sizeof(hdr));
|
||||
return RespondData(chl, &hdr, sizeof(hdr));
|
||||
}
|
||||
|
||||
bool RespondMessage(int svr, int chl, unsigned int type, const void* ptr,
|
||||
size_t count)
|
||||
bool RespondMessage(int chl, unsigned int type, const void* ptr, size_t count)
|
||||
{
|
||||
return RespondHeader(svr, chl, type, count) &&
|
||||
RespondData(svr, chl, ptr, count);
|
||||
return RespondHeader(chl, type, count) &&
|
||||
RespondData(chl, ptr, count);
|
||||
}
|
||||
|
||||
bool RespondError(int svr, int chl, int errnum)
|
||||
bool RespondError(int chl, int errnum)
|
||||
{
|
||||
struct fsm_resp_error body;
|
||||
body.errnum = errnum;
|
||||
//fprintf(stderr, "extfs: sending error %i (%s)\n", errnum, strerror(errnum));
|
||||
return RespondMessage(svr, chl, FSM_RESP_ERROR, &body, sizeof(body));
|
||||
return RespondMessage(chl, FSM_RESP_ERROR, &body, sizeof(body));
|
||||
}
|
||||
|
||||
bool RespondSuccess(int svr, int chl)
|
||||
bool RespondSuccess(int chl)
|
||||
{
|
||||
struct fsm_resp_success body;
|
||||
return RespondMessage(svr, chl, FSM_RESP_SUCCESS, &body, sizeof(body));
|
||||
return RespondMessage(chl, FSM_RESP_SUCCESS, &body, sizeof(body));
|
||||
}
|
||||
|
||||
bool RespondStat(int svr, int chl, struct stat* st)
|
||||
bool RespondStat(int chl, struct stat* st)
|
||||
{
|
||||
struct fsm_resp_stat body;
|
||||
body.st = *st;
|
||||
return RespondMessage(svr, chl, FSM_RESP_STAT, &body, sizeof(body));
|
||||
return RespondMessage(chl, FSM_RESP_STAT, &body, sizeof(body));
|
||||
}
|
||||
|
||||
bool RespondSeek(int svr, int chl, off_t offset)
|
||||
bool RespondSeek(int chl, off_t offset)
|
||||
{
|
||||
struct fsm_resp_lseek body;
|
||||
body.offset = offset;
|
||||
return RespondMessage(svr, chl, FSM_RESP_LSEEK, &body, sizeof(body));
|
||||
return RespondMessage(chl, FSM_RESP_LSEEK, &body, sizeof(body));
|
||||
}
|
||||
|
||||
bool RespondRead(int svr, int chl, const uint8_t* buf, size_t count)
|
||||
bool RespondRead(int chl, const uint8_t* buf, size_t count)
|
||||
{
|
||||
struct fsm_resp_read body;
|
||||
body.count = count;
|
||||
return RespondMessage(svr, chl, FSM_RESP_READ, &body, sizeof(body)) &&
|
||||
RespondData(svr, chl, buf, count);
|
||||
return RespondMessage(chl, FSM_RESP_READ, &body, sizeof(body)) &&
|
||||
RespondData(chl, buf, count);
|
||||
}
|
||||
|
||||
bool RespondReadlink(int svr, int chl, const uint8_t* buf, size_t count)
|
||||
bool RespondReadlink(int chl, const uint8_t* buf, size_t count)
|
||||
{
|
||||
struct fsm_resp_readlink body;
|
||||
body.targetlen = count;
|
||||
return RespondMessage(svr, chl, FSM_RESP_READLINK, &body, sizeof(body)) &&
|
||||
RespondData(svr, chl, buf, count);
|
||||
return RespondMessage(chl, FSM_RESP_READLINK, &body, sizeof(body)) &&
|
||||
RespondData(chl, buf, count);
|
||||
}
|
||||
|
||||
bool RespondWrite(int svr, int chl, size_t count)
|
||||
bool RespondWrite(int chl, size_t count)
|
||||
{
|
||||
struct fsm_resp_write body;
|
||||
body.count = count;
|
||||
return RespondMessage(svr, chl, FSM_RESP_WRITE, &body, sizeof(body));
|
||||
return RespondMessage(chl, FSM_RESP_WRITE, &body, sizeof(body));
|
||||
}
|
||||
|
||||
bool RespondOpen(int svr, int chl, ino_t ino, mode_t type)
|
||||
bool RespondOpen(int chl, ino_t ino, mode_t type)
|
||||
{
|
||||
struct fsm_resp_open body;
|
||||
body.ino = ino;
|
||||
body.type = type;
|
||||
return RespondMessage(svr, chl, FSM_RESP_OPEN, &body, sizeof(body));
|
||||
return RespondMessage(chl, FSM_RESP_OPEN, &body, sizeof(body));
|
||||
}
|
||||
|
||||
bool RespondMakeDir(int svr, int chl, ino_t ino)
|
||||
bool RespondMakeDir(int chl, ino_t ino)
|
||||
{
|
||||
struct fsm_resp_mkdir body;
|
||||
body.ino = ino;
|
||||
return RespondMessage(svr, chl, FSM_RESP_MKDIR, &body, sizeof(body));
|
||||
return RespondMessage(chl, FSM_RESP_MKDIR, &body, sizeof(body));
|
||||
}
|
||||
|
||||
bool RespondReadDir(int svr, int chl, struct kernel_dirent* dirent)
|
||||
bool RespondReadDir(int chl, struct kernel_dirent* dirent)
|
||||
{
|
||||
struct fsm_resp_readdirents body;
|
||||
body.ino = dirent->d_ino;
|
||||
body.type = dirent->d_type;
|
||||
body.namelen = dirent->d_namlen;
|
||||
return RespondMessage(svr, chl, FSM_RESP_READDIRENTS, &body, sizeof(body)) &&
|
||||
RespondData(svr, chl, dirent->d_name, dirent->d_namlen);
|
||||
return RespondMessage(chl, FSM_RESP_READDIRENTS, &body, sizeof(body)) &&
|
||||
RespondData(chl, dirent->d_name, dirent->d_namlen);
|
||||
}
|
||||
|
||||
void HandleRefer(int svr, int chl, struct fsm_req_refer* msg, Filesystem* fs)
|
||||
void HandleRefer(int chl, struct fsm_req_refer* msg, Filesystem* fs)
|
||||
{
|
||||
(void) svr;
|
||||
(void) chl;
|
||||
if ( fs->num_inodes <= msg->ino )
|
||||
return;
|
||||
|
@ -252,9 +254,8 @@ void HandleRefer(int svr, int chl, struct fsm_req_refer* msg, Filesystem* fs)
|
|||
inode->RemoteRefer();
|
||||
}
|
||||
|
||||
void HandleUnref(int svr, int chl, struct fsm_req_unref* msg, Filesystem* fs)
|
||||
void HandleUnref(int chl, struct fsm_req_unref* msg, Filesystem* fs)
|
||||
{
|
||||
(void) svr;
|
||||
(void) chl;
|
||||
if ( fs->num_inodes <= msg->ino )
|
||||
return;
|
||||
|
@ -262,32 +263,32 @@ void HandleUnref(int svr, int chl, struct fsm_req_unref* msg, Filesystem* fs)
|
|||
inode->RemoteUnref();
|
||||
}
|
||||
|
||||
void HandleSync(int svr, int chl, struct fsm_req_sync* msg, Filesystem* fs)
|
||||
void HandleSync(int chl, struct fsm_req_sync* msg, Filesystem* fs)
|
||||
{
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
|
||||
Inode* inode = fs->GetInode((uint32_t) msg->ino);
|
||||
if ( !inode ) { RespondError(svr, chl, errno); return; }
|
||||
if ( !inode ) { RespondError(chl, errno); return; }
|
||||
inode->Sync();
|
||||
inode->Unref();
|
||||
RespondSuccess(svr, chl);
|
||||
RespondSuccess(chl);
|
||||
}
|
||||
|
||||
void HandleStat(int svr, int chl, struct fsm_req_stat* msg, Filesystem* fs)
|
||||
void HandleStat(int chl, struct fsm_req_stat* msg, Filesystem* fs)
|
||||
{
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
|
||||
Inode* inode = fs->GetInode((uint32_t) msg->ino);
|
||||
if ( !inode ) { RespondError(svr, chl, errno); return; }
|
||||
if ( !inode ) { RespondError(chl, errno); return; }
|
||||
struct stat st;
|
||||
StatInode(inode, &st);
|
||||
inode->Unref();
|
||||
RespondStat(svr, chl, &st);
|
||||
RespondStat(chl, &st);
|
||||
}
|
||||
|
||||
void HandleChangeMode(int svr, int chl, struct fsm_req_chmod* msg, Filesystem* fs)
|
||||
void HandleChangeMode(int chl, struct fsm_req_chmod* msg, Filesystem* fs)
|
||||
{
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
|
||||
Inode* inode = fs->GetInode((uint32_t) msg->ino);
|
||||
if ( !inode ) { RespondError(svr, chl, errno); return; }
|
||||
if ( !inode ) { RespondError(chl, errno); return; }
|
||||
uint32_t req_mode = ExtModeFromHostMode(msg->mode);
|
||||
uint32_t old_mode = inode->Mode();
|
||||
uint32_t new_mode = (old_mode & ~S_SETABLE) | (req_mode & S_SETABLE);
|
||||
|
@ -295,96 +296,96 @@ void HandleChangeMode(int svr, int chl, struct fsm_req_chmod* msg, Filesystem* f
|
|||
inode->Unref();
|
||||
}
|
||||
|
||||
void HandleChangeOwner(int svr, int chl, struct fsm_req_chown* msg, Filesystem* fs)
|
||||
void HandleChangeOwner(int chl, struct fsm_req_chown* msg, Filesystem* fs)
|
||||
{
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
|
||||
Inode* inode = fs->GetInode((uint32_t) msg->ino);
|
||||
if ( !inode ) { RespondError(svr, chl, errno); return; }
|
||||
if ( !inode ) { RespondError(chl, errno); return; }
|
||||
inode->SetUserId((uint32_t) msg->uid);
|
||||
inode->SetGroupId((uint32_t) msg->gid);
|
||||
inode->Unref();
|
||||
RespondSuccess(svr, chl);
|
||||
RespondSuccess(chl);
|
||||
}
|
||||
|
||||
void HandleUTimens(int svr, int chl, struct fsm_req_utimens* msg, Filesystem* fs)
|
||||
void HandleUTimens(int chl, struct fsm_req_utimens* msg, Filesystem* fs)
|
||||
{
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
|
||||
Inode* inode = fs->GetInode((uint32_t) msg->ino);
|
||||
if ( !inode ) { RespondError(svr, chl, errno); return; }
|
||||
if ( !inode ) { RespondError(chl, errno); return; }
|
||||
inode->data->i_atime = msg->times[0].tv_sec;
|
||||
inode->data->i_mtime = msg->times[1].tv_sec;
|
||||
inode->Dirty();
|
||||
inode->Unref();
|
||||
RespondSuccess(svr, chl);
|
||||
RespondSuccess(chl);
|
||||
}
|
||||
|
||||
void HandleTruncate(int svr, int chl, struct fsm_req_truncate* msg, Filesystem* fs)
|
||||
void HandleTruncate(int chl, struct fsm_req_truncate* msg, Filesystem* fs)
|
||||
{
|
||||
if( msg->size < 0 ) { RespondError(svr, chl, EINVAL); return; }
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
|
||||
if( msg->size < 0 ) { RespondError(chl, EINVAL); return; }
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
|
||||
Inode* inode = fs->GetInode((uint32_t) msg->ino);
|
||||
if ( !inode ) { RespondError(svr, chl, errno); return; }
|
||||
if ( !inode ) { RespondError(chl, errno); return; }
|
||||
inode->Truncate((uint64_t) msg->size);
|
||||
inode->Unref();
|
||||
RespondSuccess(svr, chl);
|
||||
RespondSuccess(chl);
|
||||
}
|
||||
|
||||
void HandleSeek(int svr, int chl, struct fsm_req_lseek* msg, Filesystem* fs)
|
||||
void HandleSeek(int chl, struct fsm_req_lseek* msg, Filesystem* fs)
|
||||
{
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
|
||||
Inode* inode = fs->GetInode((uint32_t) msg->ino);
|
||||
if ( !inode ) { RespondError(svr, chl, errno); return; }
|
||||
if ( !inode ) { RespondError(chl, errno); return; }
|
||||
if ( msg->whence == SEEK_SET )
|
||||
RespondSeek(svr, chl, msg->offset);
|
||||
RespondSeek(chl, msg->offset);
|
||||
else if ( msg->whence == SEEK_END )
|
||||
{
|
||||
off_t inode_size = inode->Size();
|
||||
if ( (msg->offset < 0 && inode_size + msg->offset < 0) ||
|
||||
(0 <= msg->offset && OFF_MAX - inode_size < msg->offset) )
|
||||
RespondError(svr, chl, EOVERFLOW);
|
||||
RespondError(chl, EOVERFLOW);
|
||||
else
|
||||
RespondSeek(svr, chl, msg->offset + inode_size);
|
||||
RespondSeek(chl, msg->offset + inode_size);
|
||||
}
|
||||
else
|
||||
RespondError(svr, chl, EINVAL);
|
||||
RespondError(chl, EINVAL);
|
||||
inode->Unref();
|
||||
}
|
||||
|
||||
void HandleReadAt(int svr, int chl, struct fsm_req_pread* msg, Filesystem* fs)
|
||||
void HandleReadAt(int chl, struct fsm_req_pread* msg, Filesystem* fs)
|
||||
{
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
|
||||
Inode* inode = fs->GetInode((uint32_t) msg->ino);
|
||||
if ( !inode ) { RespondError(svr, chl, errno); return; }
|
||||
if ( !inode ) { RespondError(chl, errno); return; }
|
||||
uint8_t* buf = (uint8_t*) malloc(msg->count);
|
||||
if ( !buf ) { inode->Unref(); RespondError(svr, chl, errno); return; }
|
||||
if ( !buf ) { inode->Unref(); RespondError(chl, errno); return; }
|
||||
ssize_t amount = inode->ReadAt(buf, msg->count, msg->offset);
|
||||
RespondRead(svr, chl, buf, amount);
|
||||
RespondRead(chl, buf, amount);
|
||||
inode->Unref();
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void HandleWriteAt(int svr, int chl, struct fsm_req_pread* msg, Filesystem* fs)
|
||||
void HandleWriteAt(int chl, struct fsm_req_pread* msg, Filesystem* fs)
|
||||
{
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
|
||||
Inode* inode = fs->GetInode((uint32_t) msg->ino);
|
||||
if ( !inode ) { RespondError(svr, chl, errno); return; }
|
||||
if ( !inode ) { RespondError(chl, errno); return; }
|
||||
const uint8_t* buf = (const uint8_t*) &msg[1];
|
||||
ssize_t amount = inode->WriteAt(buf, msg->count, msg->offset);
|
||||
RespondWrite(svr, chl, amount);
|
||||
RespondWrite(chl, amount);
|
||||
inode->Unref();
|
||||
}
|
||||
|
||||
void HandleOpen(int svr, int chl, struct fsm_req_open* msg, Filesystem* fs)
|
||||
void HandleOpen(int chl, struct fsm_req_open* msg, Filesystem* fs)
|
||||
{
|
||||
if ( fs->num_inodes <= msg->dirino ) { RespondError(svr, chl, EBADF); return; }
|
||||
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; }
|
||||
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
|
||||
if ( !inode ) { RespondError(svr, chl, errno); return; }
|
||||
if ( !inode ) { RespondError(chl, errno); return; }
|
||||
|
||||
char* pathraw = (char*) &(msg[1]);
|
||||
char* path = (char*) malloc(msg->namelen+1);
|
||||
if ( !path )
|
||||
{
|
||||
RespondError(svr, chl, errno);
|
||||
RespondError(chl, errno);
|
||||
inode->Unref();
|
||||
return;
|
||||
}
|
||||
|
@ -396,23 +397,23 @@ void HandleOpen(int svr, int chl, struct fsm_req_open* msg, Filesystem* fs)
|
|||
free(path);
|
||||
inode->Unref();
|
||||
|
||||
if ( !result ) { RespondError(svr, chl, errno); return; }
|
||||
if ( !result ) { RespondError(chl, errno); return; }
|
||||
|
||||
RespondOpen(svr, chl, result->inode_id, result->Mode() & S_IFMT);
|
||||
RespondOpen(chl, result->inode_id, result->Mode() & S_IFMT);
|
||||
result->Unref();
|
||||
}
|
||||
|
||||
void HandleMakeDir(int svr, int chl, struct fsm_req_open* msg, Filesystem* fs)
|
||||
void HandleMakeDir(int chl, struct fsm_req_open* msg, Filesystem* fs)
|
||||
{
|
||||
if ( fs->num_inodes <= msg->dirino ) { RespondError(svr, chl, EBADF); return; }
|
||||
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; }
|
||||
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
|
||||
if ( !inode ) { RespondError(svr, chl, errno); return; }
|
||||
if ( !inode ) { RespondError(chl, errno); return; }
|
||||
|
||||
char* pathraw = (char*) &(msg[1]);
|
||||
char* path = (char*) malloc(msg->namelen+1);
|
||||
if ( !path )
|
||||
{
|
||||
RespondError(svr, chl, errno);
|
||||
RespondError(chl, errno);
|
||||
inode->Unref();
|
||||
return;
|
||||
}
|
||||
|
@ -424,21 +425,21 @@ void HandleMakeDir(int svr, int chl, struct fsm_req_open* msg, Filesystem* fs)
|
|||
free(path);
|
||||
inode->Unref();
|
||||
|
||||
if ( !result ) { RespondError(svr, chl, errno); return; }
|
||||
if ( !result ) { RespondError(chl, errno); return; }
|
||||
|
||||
RespondMakeDir(svr, chl, result->inode_id);
|
||||
RespondMakeDir(chl, result->inode_id);
|
||||
result->Unref();
|
||||
}
|
||||
|
||||
void HandleReadDir(int svr, int chl, struct fsm_req_readdirents* msg, Filesystem* fs)
|
||||
void HandleReadDir(int chl, struct fsm_req_readdirents* msg, Filesystem* fs)
|
||||
{
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
|
||||
Inode* inode = fs->GetInode((uint32_t) msg->ino);
|
||||
if ( !inode ) { RespondError(svr, chl, errno); return; }
|
||||
if ( !inode ) { RespondError(chl, errno); return; }
|
||||
if ( !S_ISDIR(inode->Mode()) )
|
||||
{
|
||||
inode->Unref();
|
||||
RespondError(svr, chl, ENOTDIR);
|
||||
RespondError(chl, ENOTDIR);
|
||||
return;
|
||||
}
|
||||
union
|
||||
|
@ -462,7 +463,7 @@ void HandleReadDir(int svr, int chl, struct fsm_req_readdirents* msg, Filesystem
|
|||
if ( !block && !(block = inode->GetBlock(block_id = entry_block_id)) )
|
||||
{
|
||||
inode->Unref();
|
||||
RespondError(svr, chl, errno);
|
||||
RespondError(chl, errno);
|
||||
return;
|
||||
}
|
||||
const uint8_t* block_data = block->block_data + entry_block_offset;
|
||||
|
@ -480,7 +481,7 @@ void HandleReadDir(int svr, int chl, struct fsm_req_readdirents* msg, Filesystem
|
|||
padding[dname_offset + kernel_entry.d_namlen] = '\0';
|
||||
block->Unref();
|
||||
inode->Unref();
|
||||
RespondReadDir(svr, chl, &kernel_entry);
|
||||
RespondReadDir(chl, &kernel_entry);
|
||||
return;
|
||||
}
|
||||
offset += entry->reclen;
|
||||
|
@ -489,29 +490,29 @@ void HandleReadDir(int svr, int chl, struct fsm_req_readdirents* msg, Filesystem
|
|||
block->Unref();
|
||||
|
||||
kernel_entry.d_reclen = sizeof(kernel_entry);
|
||||
RespondReadDir(svr, chl, &kernel_entry);
|
||||
RespondReadDir(chl, &kernel_entry);
|
||||
}
|
||||
|
||||
void HandleIsATTY(int svr, int chl, struct fsm_req_isatty* msg, Filesystem* fs)
|
||||
void HandleIsATTY(int chl, struct fsm_req_isatty* msg, Filesystem* fs)
|
||||
{
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
|
||||
Inode* inode = fs->GetInode((uint32_t) msg->ino);
|
||||
if ( !inode ) { RespondError(svr, chl, errno); return; }
|
||||
RespondError(svr, chl, ENOTTY);
|
||||
if ( !inode ) { RespondError(chl, errno); return; }
|
||||
RespondError(chl, ENOTTY);
|
||||
inode->Unref();
|
||||
}
|
||||
|
||||
void HandleUnlink(int svr, int chl, struct fsm_req_unlink* msg, Filesystem* fs)
|
||||
void HandleUnlink(int chl, struct fsm_req_unlink* msg, Filesystem* fs)
|
||||
{
|
||||
if ( fs->num_inodes <= msg->dirino ) { RespondError(svr, chl, EBADF); return; }
|
||||
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; }
|
||||
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
|
||||
if ( !inode ) { RespondError(svr, chl, errno); return; }
|
||||
if ( !inode ) { RespondError(chl, errno); return; }
|
||||
|
||||
char* pathraw = (char*) &(msg[1]);
|
||||
char* path = (char*) malloc(msg->namelen+1);
|
||||
if ( !path )
|
||||
{
|
||||
RespondError(svr, chl, errno);
|
||||
RespondError(chl, errno);
|
||||
inode->Unref();
|
||||
return;
|
||||
}
|
||||
|
@ -522,24 +523,24 @@ void HandleUnlink(int svr, int chl, struct fsm_req_unlink* msg, Filesystem* fs)
|
|||
free(path);
|
||||
inode->Unref();
|
||||
|
||||
if ( !result ) { RespondError(svr, chl, errno); return; }
|
||||
if ( !result ) { RespondError(chl, errno); return; }
|
||||
|
||||
result->Unref();
|
||||
|
||||
RespondSuccess(svr, chl);
|
||||
RespondSuccess(chl);
|
||||
}
|
||||
|
||||
void HandleRemoveDir(int svr, int chl, struct fsm_req_unlink* msg, Filesystem* fs)
|
||||
void HandleRemoveDir(int chl, struct fsm_req_unlink* msg, Filesystem* fs)
|
||||
{
|
||||
if ( fs->num_inodes <= msg->dirino ) { RespondError(svr, chl, EBADF); return; }
|
||||
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; }
|
||||
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
|
||||
if ( !inode ) { RespondError(svr, chl, errno); return; }
|
||||
if ( !inode ) { RespondError(chl, errno); return; }
|
||||
|
||||
char* pathraw = (char*) &(msg[1]);
|
||||
char* path = (char*) malloc(msg->namelen+1);
|
||||
if ( !path )
|
||||
{
|
||||
RespondError(svr, chl, errno);
|
||||
RespondError(chl, errno);
|
||||
inode->Unref();
|
||||
return;
|
||||
}
|
||||
|
@ -547,28 +548,28 @@ void HandleRemoveDir(int svr, int chl, struct fsm_req_unlink* msg, Filesystem* f
|
|||
path[msg->namelen] = '\0';
|
||||
|
||||
if ( inode->RemoveDirectory(path) )
|
||||
RespondSuccess(svr, chl);
|
||||
RespondSuccess(chl);
|
||||
else
|
||||
RespondError(svr, chl, errno);
|
||||
RespondError(chl, errno);
|
||||
|
||||
free(path);
|
||||
inode->Unref();
|
||||
}
|
||||
|
||||
void HandleLink(int svr, int chl, struct fsm_req_link* msg, Filesystem* fs)
|
||||
void HandleLink(int chl, struct fsm_req_link* msg, Filesystem* fs)
|
||||
{
|
||||
if ( fs->num_inodes <= msg->dirino ) { RespondError(svr, chl, EBADF); return; }
|
||||
if ( fs->num_inodes <= msg->linkino ) { RespondError(svr, chl, EBADF); return; }
|
||||
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; }
|
||||
if ( fs->num_inodes <= msg->linkino ) { RespondError(chl, EBADF); return; }
|
||||
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
|
||||
if ( !inode ) { RespondError(svr, chl, errno); return; }
|
||||
if ( !inode ) { RespondError(chl, errno); return; }
|
||||
Inode* dest = fs->GetInode((uint32_t) msg->linkino);
|
||||
if ( !dest ) { inode->Unref(); RespondError(svr, chl, errno); return; }
|
||||
if ( !dest ) { inode->Unref(); RespondError(chl, errno); return; }
|
||||
|
||||
char* pathraw = (char*) &(msg[1]);
|
||||
char* path = (char*) malloc(msg->namelen+1);
|
||||
if ( !path )
|
||||
{
|
||||
RespondError(svr, chl, errno);
|
||||
RespondError(chl, errno);
|
||||
inode->Unref();
|
||||
return;
|
||||
}
|
||||
|
@ -576,26 +577,26 @@ void HandleLink(int svr, int chl, struct fsm_req_link* msg, Filesystem* fs)
|
|||
path[msg->namelen] = '\0';
|
||||
|
||||
if ( inode->Link(path, dest, false) )
|
||||
RespondSuccess(svr, chl);
|
||||
RespondSuccess(chl);
|
||||
else
|
||||
RespondError(svr, chl, errno);
|
||||
RespondError(chl, errno);
|
||||
|
||||
free(path);
|
||||
dest->Unref();
|
||||
inode->Unref();
|
||||
}
|
||||
|
||||
void HandleSymlink(int svr, int chl, struct fsm_req_symlink* msg, Filesystem* fs)
|
||||
void HandleSymlink(int chl, struct fsm_req_symlink* msg, Filesystem* fs)
|
||||
{
|
||||
if ( fs->num_inodes <= msg->dirino ) { RespondError(svr, chl, EBADF); return; }
|
||||
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; }
|
||||
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
|
||||
if ( !inode ) { RespondError(svr, chl, errno); return; }
|
||||
if ( !inode ) { RespondError(chl, errno); return; }
|
||||
|
||||
char* dest_raw = (char*) &(msg[1]);
|
||||
char* dest = (char*) malloc(msg->targetlen + 1);
|
||||
if ( !dest )
|
||||
{
|
||||
RespondError(svr, chl, errno);
|
||||
RespondError(chl, errno);
|
||||
inode->Unref();
|
||||
return;
|
||||
}
|
||||
|
@ -606,7 +607,7 @@ void HandleSymlink(int svr, int chl, struct fsm_req_symlink* msg, Filesystem* fs
|
|||
char* path = (char*) malloc(msg->namelen + 1);
|
||||
if ( !path )
|
||||
{
|
||||
RespondError(svr, chl, errno);
|
||||
RespondError(chl, errno);
|
||||
inode->Unref();
|
||||
return;
|
||||
}
|
||||
|
@ -614,38 +615,38 @@ void HandleSymlink(int svr, int chl, struct fsm_req_symlink* msg, Filesystem* fs
|
|||
path[msg->namelen] = '\0';
|
||||
|
||||
if ( inode->Symlink(path, dest) )
|
||||
RespondSuccess(svr, chl);
|
||||
RespondSuccess(chl);
|
||||
else
|
||||
RespondError(svr, chl, errno);
|
||||
RespondError(chl, errno);
|
||||
|
||||
free(path);
|
||||
free(dest);
|
||||
inode->Unref();
|
||||
}
|
||||
|
||||
void HandleReadlink(int svr, int chl, struct fsm_req_readlink* msg, Filesystem* fs)
|
||||
void HandleReadlink(int chl, struct fsm_req_readlink* msg, Filesystem* fs)
|
||||
{
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
|
||||
Inode* inode = fs->GetInode((uint32_t) msg->ino);
|
||||
if ( !inode ) { RespondError(svr, chl, errno); return; }
|
||||
if ( !EXT2_S_ISLNK(inode->Mode()) ) { RespondError(svr, chl, EINVAL); return; }
|
||||
if ( !inode ) { RespondError(chl, errno); return; }
|
||||
if ( !EXT2_S_ISLNK(inode->Mode()) ) { RespondError(chl, EINVAL); return; }
|
||||
size_t count = inode->Size();
|
||||
uint8_t* buf = (uint8_t*) malloc(count);
|
||||
if ( !buf ) { inode->Unref(); RespondError(svr, chl, errno); return; }
|
||||
if ( !buf ) { inode->Unref(); RespondError(chl, errno); return; }
|
||||
ssize_t amount = inode->ReadAt(buf, count, 0);
|
||||
RespondReadlink(svr, chl, buf, amount);
|
||||
RespondReadlink(chl, buf, amount);
|
||||
inode->Unref();
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void HandleRename(int svr, int chl, struct fsm_req_rename* msg, Filesystem* fs)
|
||||
void HandleRename(int chl, struct fsm_req_rename* msg, Filesystem* fs)
|
||||
{
|
||||
if ( fs->num_inodes <= msg->olddirino ) { RespondError(svr, chl, EBADF); return; }
|
||||
if ( fs->num_inodes <= msg->newdirino ) { RespondError(svr, chl, EBADF); return; }
|
||||
if ( fs->num_inodes <= msg->olddirino ) { RespondError(chl, EBADF); return; }
|
||||
if ( fs->num_inodes <= msg->newdirino ) { RespondError(chl, EBADF); return; }
|
||||
|
||||
char* pathraw = (char*) &(msg[1]);
|
||||
char* path = (char*) malloc(msg->oldnamelen+1 + msg->newnamelen+1);
|
||||
if ( !path ) { RespondError(svr, chl, errno); return; }
|
||||
if ( !path ) { RespondError(chl, errno); return; }
|
||||
memcpy(path, pathraw, msg->oldnamelen);
|
||||
path[msg->oldnamelen] = '\0';
|
||||
memcpy(path + msg->oldnamelen + 1, pathraw + msg->oldnamelen, msg->newnamelen);
|
||||
|
@ -655,24 +656,23 @@ void HandleRename(int svr, int chl, struct fsm_req_rename* msg, Filesystem* fs)
|
|||
const char* newname = path + msg->oldnamelen + 1;
|
||||
|
||||
Inode* olddir = fs->GetInode((uint32_t) msg->olddirino);
|
||||
if ( !olddir ) { free(path); RespondError(svr, chl, errno); return; }
|
||||
if ( !olddir ) { free(path); RespondError(chl, errno); return; }
|
||||
Inode* newdir = fs->GetInode((uint32_t) msg->newdirino);
|
||||
if ( !newdir ) { olddir->Unref(); free(path); RespondError(svr, chl, errno); return; }
|
||||
if ( !newdir ) { olddir->Unref(); free(path); RespondError(chl, errno); return; }
|
||||
|
||||
if ( newdir->Rename(olddir, oldname, newname) )
|
||||
RespondSuccess(svr, chl);
|
||||
RespondSuccess(chl);
|
||||
else
|
||||
RespondError(svr, chl, errno);
|
||||
RespondError(chl, errno);
|
||||
|
||||
newdir->Unref();
|
||||
olddir->Unref();
|
||||
free(path);
|
||||
}
|
||||
|
||||
void HandleIncomingMessage(int svr, int chl, struct fsm_msg_header* hdr,
|
||||
Filesystem* fs)
|
||||
void HandleIncomingMessage(int chl, struct fsm_msg_header* hdr, Filesystem* fs)
|
||||
{
|
||||
typedef void (*handler_t)(int, int, void*, Filesystem*);
|
||||
typedef void (*handler_t)(int, void*, Filesystem*);
|
||||
handler_t handlers[FSM_MSG_NUM] = { NULL };
|
||||
handlers[FSM_REQ_SYNC] = (handler_t) HandleSync;
|
||||
handlers[FSM_REQ_STAT] = (handler_t) HandleStat;
|
||||
|
@ -700,25 +700,25 @@ void HandleIncomingMessage(int svr, int chl, struct fsm_msg_header* hdr,
|
|||
if ( FSM_MSG_NUM <= hdr->msgtype || !handlers[hdr->msgtype] )
|
||||
{
|
||||
fprintf(stderr, "extfs: message type %zu not supported!\n", hdr->msgtype);
|
||||
RespondError(svr, chl, ENOTSUP);
|
||||
RespondError(chl, ENOTSUP);
|
||||
return;
|
||||
}
|
||||
uint8_t* body = (uint8_t*) malloc(hdr->msgsize);
|
||||
if ( !body )
|
||||
{
|
||||
fprintf(stderr, "extfs: message of type %zu too large: %zu bytes\n", hdr->msgtype, hdr->msgsize);
|
||||
RespondError(svr, chl, errno);
|
||||
RespondError(chl, errno);
|
||||
return;
|
||||
}
|
||||
ssize_t amount = fsm_recv(svr, chl, body, hdr->msgsize);
|
||||
if ( amount < (ssize_t) hdr->msgsize )
|
||||
size_t amount = readall(chl, body, hdr->msgsize);
|
||||
if ( amount < hdr->msgsize )
|
||||
{
|
||||
fprintf(stderr, "extfs: incomplete message of type %zu: got %zi of %zu bytes\n", hdr->msgtype, amount, hdr->msgsize);
|
||||
RespondError(svr, chl, errno);
|
||||
RespondError(chl, errno);
|
||||
free(body);
|
||||
return;
|
||||
}
|
||||
handlers[hdr->msgtype](svr, chl, body, fs);
|
||||
handlers[hdr->msgtype](chl, body, fs);
|
||||
free(body);
|
||||
}
|
||||
|
||||
|
@ -726,7 +726,6 @@ void AlarmHandler(int)
|
|||
{
|
||||
}
|
||||
|
||||
static volatile bool should_terminate = false;
|
||||
void TerminationHandler(int)
|
||||
{
|
||||
should_terminate = true;
|
||||
|
@ -1471,32 +1470,22 @@ int main(int argc, char* argv[])
|
|||
for ( size_t i = 0; i < fs->num_groups; i++ )
|
||||
fs->block_groups[i] = NULL;
|
||||
|
||||
#if defined(__sortix__)
|
||||
if ( !mount_path )
|
||||
return 0;
|
||||
|
||||
// Open the mount point.
|
||||
int mountfd = open(mount_path, O_RDWR | O_DIRECTORY);
|
||||
if ( mountfd < 0 )
|
||||
error(1, errno, "%s", mount_path);
|
||||
#if defined(__sortix__)
|
||||
// Stat the root inode.
|
||||
struct stat root_inode_st;
|
||||
Inode* root_inode = fs->GetInode((uint32_t) EXT2_ROOT_INO);
|
||||
if ( !root_inode )
|
||||
error(1, errno, "GetInode(%u)", EXT2_ROOT_INO);
|
||||
StatInode(root_inode, &root_inode_st);
|
||||
root_inode->Unref();
|
||||
|
||||
// Create a filesystem server connected to the kernel that we'll listen on.
|
||||
int serverfd = fsm_mkserver();
|
||||
int serverfd = fsm_mountat(AT_FDCWD, mount_path, &root_inode_st, 0);
|
||||
if ( serverfd < 0 )
|
||||
error(1, errno, "fsm_mkserver");
|
||||
|
||||
// Create a file descriptor for our root directory. The kernel won't send
|
||||
// a message to this file descriptor so we can mount it before starting to
|
||||
// listen for messages.
|
||||
int rootfd = fsm_bootstraprootfd(serverfd, EXT2_ROOT_INO, O_RDWR | O_CREAT,
|
||||
S_IFDIR);
|
||||
if ( rootfd < 0 )
|
||||
error(1, errno, "fsm_bootstraprootfd");
|
||||
|
||||
if ( fsm_fsbind(rootfd, mountfd, 0) < 0 )
|
||||
error(1, errno, "fsm_fsbind");
|
||||
|
||||
close(mountfd);
|
||||
error(1, errno, "%s", mount_path);
|
||||
|
||||
// Make sure the server isn't unexpectedly killed and data is lost.
|
||||
signal(SIGINT, TerminationHandler);
|
||||
|
@ -1506,7 +1495,10 @@ int main(int argc, char* argv[])
|
|||
// Become a background process in its own process group by default.
|
||||
if ( !foreground )
|
||||
{
|
||||
if ( fork() )
|
||||
pid_t child_pid = fork();
|
||||
if ( child_pid < 0 )
|
||||
error(1, errno, "fork");
|
||||
if ( child_pid )
|
||||
exit(0);
|
||||
setpgid(0, 0);
|
||||
}
|
||||
|
@ -1515,20 +1507,20 @@ int main(int argc, char* argv[])
|
|||
struct timespec last_sync_at;
|
||||
clock_gettime(CLOCK_MONOTONIC, &last_sync_at);
|
||||
int channel;
|
||||
while ( 0 <= (channel = fsm_listen(serverfd)) )
|
||||
while ( 0 <= (channel = accept(serverfd, NULL, NULL)) )
|
||||
{
|
||||
if ( should_terminate )
|
||||
break;
|
||||
struct fsm_msg_header hdr;
|
||||
ssize_t amount;
|
||||
if ( (amount = fsm_recv(serverfd, channel, &hdr, sizeof(hdr))) != sizeof(hdr) )
|
||||
size_t amount;
|
||||
if ( (amount = readall(channel, &hdr, sizeof(hdr))) != sizeof(hdr) )
|
||||
{
|
||||
error(0, errno, "incomplete header: got %zi of %zu bytes", amount, sizeof(hdr));
|
||||
errno = 0;
|
||||
continue;
|
||||
}
|
||||
HandleIncomingMessage(serverfd, channel, &hdr, fs);
|
||||
fsm_closechannel(serverfd, channel);
|
||||
HandleIncomingMessage(channel, &hdr, fs);
|
||||
close(channel);
|
||||
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
@ -1549,7 +1541,7 @@ int main(int argc, char* argv[])
|
|||
fprintf(stderr, " done.\n");
|
||||
}
|
||||
|
||||
fsm_closeserver(serverfd);
|
||||
close(serverfd);
|
||||
|
||||
#elif defined(__linux__)
|
||||
|
||||
|
|
|
@ -26,14 +26,17 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fsmarshall-msg.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sortix/dirent.h>
|
||||
#include <sortix/fcntl.h>
|
||||
#include <sortix/mount.h>
|
||||
#include <sortix/seek.h>
|
||||
#include <sortix/stat.h>
|
||||
|
||||
#include <sortix/kernel/copy.h>
|
||||
#include <sortix/kernel/descriptor.h>
|
||||
#include <sortix/kernel/fsfunc.h>
|
||||
#include <sortix/kernel/inode.h>
|
||||
|
@ -109,17 +112,40 @@ Ref<Descriptor> OpenDirContainingPath(ioctx_t* ctx,
|
|||
|
||||
// TODO: Add security checks.
|
||||
|
||||
Descriptor::Descriptor()
|
||||
{
|
||||
current_offset_lock = KTHREAD_MUTEX_INITIALIZER;
|
||||
this->vnode = Ref<Vnode>(NULL);
|
||||
this->ino = 0;
|
||||
this->dev = 0;
|
||||
this->type = 0;
|
||||
this->dflags = 0;
|
||||
checked_seekable = false;
|
||||
seekable = false /* unused */;
|
||||
current_offset = 0;
|
||||
}
|
||||
|
||||
Descriptor::Descriptor(Ref<Vnode> vnode, int dflags)
|
||||
{
|
||||
current_offset_lock = KTHREAD_MUTEX_INITIALIZER;
|
||||
this->vnode = Ref<Vnode>(NULL);
|
||||
this->ino = 0;
|
||||
this->dev = 0;
|
||||
this->type = 0;
|
||||
this->dflags = 0;
|
||||
checked_seekable = false;
|
||||
seekable = false /* unused */;
|
||||
current_offset = 0;
|
||||
LateConstruct(vnode, dflags);
|
||||
}
|
||||
|
||||
void Descriptor::LateConstruct(Ref<Vnode> vnode, int dflags)
|
||||
{
|
||||
this->vnode = vnode;
|
||||
this->ino = vnode->ino;
|
||||
this->dev = vnode->dev;
|
||||
this->type = vnode->type;
|
||||
this->dflags = dflags;
|
||||
checked_seekable = false;
|
||||
seekable = false /* unused */;
|
||||
current_offset = 0;
|
||||
}
|
||||
|
||||
Descriptor::~Descriptor()
|
||||
|
@ -749,4 +775,60 @@ ssize_t Descriptor::tcsetblob(ioctx_t* ctx, const char* name, const void* buffer
|
|||
return vnode->tcsetblob(ctx, name, buffer, count);
|
||||
}
|
||||
|
||||
int Descriptor::unmount(ioctx_t* ctx, const char* filename, int flags)
|
||||
{
|
||||
if ( flags & ~(UNMOUNT_FORCE | UNMOUNT_DETACH | UNMOUNT_NOFOLLOW) )
|
||||
return errno = EINVAL, -1;
|
||||
int subflags = flags & ~(UNMOUNT_NOFOLLOW);
|
||||
char* final;
|
||||
// TODO: This may follow a symlink when not supposed to!
|
||||
Ref<Descriptor> dir =
|
||||
OpenDirContainingPath(ctx, Ref<Descriptor>(this), filename, &final);
|
||||
if ( !dir )
|
||||
return -1;
|
||||
if ( !(flags & UNMOUNT_NOFOLLOW) )
|
||||
{
|
||||
// TODO: Potentially follow a symlink here!
|
||||
}
|
||||
int ret = dir->vnode->unmount(ctx, final, subflags);
|
||||
delete[] final;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Descriptor::fsm_fsbind(ioctx_t* ctx, Ref<Descriptor> target, int flags)
|
||||
{
|
||||
return vnode->fsm_fsbind(ctx, target->vnode, flags);
|
||||
}
|
||||
|
||||
Ref<Descriptor> Descriptor::fsm_mount(ioctx_t* ctx,
|
||||
const char* filename,
|
||||
const struct stat* rootst,
|
||||
int flags)
|
||||
{
|
||||
if ( flags & ~(FSM_MOUNT_NOFOLLOW | FSM_MOUNT_NONBLOCK) )
|
||||
return errno = EINVAL, Ref<Descriptor>(NULL);
|
||||
int result_dflags = O_READ | O_WRITE;
|
||||
if ( flags & FSM_MOUNT_NOFOLLOW ) result_dflags |= O_NONBLOCK;
|
||||
int subflags = flags & ~(FSM_MOUNT_NOFOLLOW | FSM_MOUNT_NONBLOCK);
|
||||
char* final;
|
||||
// TODO: This may follow a symlink when not supposed to!
|
||||
Ref<Descriptor> dir =
|
||||
OpenDirContainingPath(ctx, Ref<Descriptor>(this), filename, &final);
|
||||
if ( !dir )
|
||||
return errno = EINVAL, Ref<Descriptor>(NULL);
|
||||
if ( !(flags & FSM_MOUNT_NOFOLLOW) )
|
||||
{
|
||||
// TODO: Potentially follow a symlink here!
|
||||
}
|
||||
Ref<Descriptor> result(new Descriptor());
|
||||
if ( !result )
|
||||
return Ref<Descriptor>(NULL);
|
||||
Ref<Vnode> result_vnode = dir->vnode->fsm_mount(ctx, final, rootst, subflags);
|
||||
delete[] final;
|
||||
if ( !result_vnode )
|
||||
return Ref<Descriptor>(NULL);
|
||||
result->LateConstruct(result_vnode, result_dflags);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -158,8 +158,9 @@ public:
|
|||
Server();
|
||||
virtual ~Server();
|
||||
void Disconnect();
|
||||
void Unmount();
|
||||
Channel* Connect();
|
||||
Channel* Listen();
|
||||
Channel* Accept();
|
||||
Ref<Inode> BootstrapNode(ino_t ino, mode_t type);
|
||||
Ref<Inode> OpenNode(ino_t ino, mode_t type);
|
||||
|
||||
|
@ -171,6 +172,7 @@ private:
|
|||
uintptr_t connecter_system_tid;
|
||||
Channel* connecting;
|
||||
bool disconnected;
|
||||
bool unmounted;
|
||||
|
||||
};
|
||||
|
||||
|
@ -179,8 +181,8 @@ class ServerNode : public AbstractInode
|
|||
public:
|
||||
ServerNode(Ref<Server> server);
|
||||
virtual ~ServerNode();
|
||||
virtual Ref<Inode> open(ioctx_t* ctx, const char* filename, int flags,
|
||||
mode_t mode);
|
||||
virtual Ref<Inode> accept(ioctx_t* ctx, uint8_t* addr, size_t* addrlen,
|
||||
int flags);
|
||||
|
||||
private:
|
||||
Ref<Server> server;
|
||||
|
@ -248,6 +250,7 @@ public:
|
|||
const void* option_value, size_t option_size);
|
||||
virtual ssize_t tcgetblob(ioctx_t* ctx, const char* name, void* buffer, size_t count);
|
||||
virtual ssize_t tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count);
|
||||
virtual int unmounted(ioctx_t* ctx);
|
||||
|
||||
private:
|
||||
bool SendMessage(Channel* channel, size_t type, void* ptr, size_t size,
|
||||
|
@ -527,6 +530,7 @@ Server::Server()
|
|||
listener_system_tid = 0;
|
||||
connecting = NULL;
|
||||
disconnected = false;
|
||||
unmounted = false;
|
||||
}
|
||||
|
||||
Server::~Server()
|
||||
|
@ -540,6 +544,13 @@ void Server::Disconnect()
|
|||
kthread_cond_signal(&connectable_cond);
|
||||
}
|
||||
|
||||
void Server::Unmount()
|
||||
{
|
||||
ScopedLock lock(&connect_lock);
|
||||
unmounted = true;
|
||||
kthread_cond_signal(&connecting_cond);
|
||||
}
|
||||
|
||||
Channel* Server::Connect()
|
||||
{
|
||||
Channel* channel = new Channel();
|
||||
|
@ -565,13 +576,15 @@ Channel* Server::Connect()
|
|||
return channel;
|
||||
}
|
||||
|
||||
Channel* Server::Listen()
|
||||
Channel* Server::Accept()
|
||||
{
|
||||
ScopedLock lock(&connect_lock);
|
||||
listener_system_tid = CurrentThread()->system_tid;
|
||||
while ( !connecting )
|
||||
while ( !connecting && !unmounted )
|
||||
if ( !kthread_cond_wait_signal(&connecting_cond, &connect_lock) )
|
||||
return errno = EINTR, (Channel*) NULL;
|
||||
if ( unmounted )
|
||||
return errno = ECONNRESET, (Channel*) NULL;
|
||||
Channel* result = connecting;
|
||||
connecting = NULL;
|
||||
kthread_cond_signal(&connectable_cond);
|
||||
|
@ -596,7 +609,7 @@ ServerNode::ServerNode(Ref<Server> server)
|
|||
{
|
||||
inode_type = INODE_TYPE_UNKNOWN;
|
||||
this->server = server;
|
||||
this->type = S_IFDIR;
|
||||
this->type = S_IFSOCK;
|
||||
this->dev = (dev_t) this;
|
||||
this->ino = 0;
|
||||
// TODO: Set uid, gid, mode.
|
||||
|
@ -607,36 +620,22 @@ ServerNode::~ServerNode()
|
|||
server->Disconnect();
|
||||
}
|
||||
|
||||
Ref<Inode> ServerNode::open(ioctx_t* /*ctx*/, const char* filename, int flags,
|
||||
mode_t mode)
|
||||
Ref<Inode> ServerNode::accept(ioctx_t* ctx, uint8_t* addr, size_t* addrlen,
|
||||
int flags)
|
||||
{
|
||||
unsigned long long ull_ino;
|
||||
char* end;
|
||||
int saved_errno = errno; errno = 0;
|
||||
if ( !isspace(*filename) &&
|
||||
0 < (ull_ino = strtoull(filename, &end, 10)) &&
|
||||
*end == '\0' &&
|
||||
errno != ERANGE )
|
||||
{
|
||||
errno = saved_errno;
|
||||
if ( !(flags & O_CREATE) )
|
||||
return errno = ENOENT, Ref<Inode>(NULL);
|
||||
ino_t ino = (ino_t) ull_ino;
|
||||
return server->BootstrapNode(ino, mode & S_IFMT);
|
||||
}
|
||||
errno = saved_errno;
|
||||
if ( !strcmp(filename, "listen") )
|
||||
{
|
||||
Ref<ChannelNode> node(new ChannelNode);
|
||||
if ( !node )
|
||||
return Ref<Inode>(NULL);
|
||||
Channel* channel = server->Listen();
|
||||
if ( !channel )
|
||||
return Ref<Inode>(NULL);
|
||||
node->Construct(channel);
|
||||
return node;
|
||||
}
|
||||
return errno = ENOENT, Ref<Inode>(NULL);
|
||||
(void) addr;
|
||||
(void) flags;
|
||||
size_t out_addrlen = 0;
|
||||
if ( addrlen && !ctx->copy_to_dest(addrlen, &out_addrlen, sizeof(out_addrlen)) )
|
||||
return Ref<Inode>(NULL);
|
||||
Ref<ChannelNode> node(new ChannelNode);
|
||||
if ( !node )
|
||||
return Ref<Inode>(NULL);
|
||||
Channel* channel = server->Accept();
|
||||
if ( !channel )
|
||||
return Ref<Inode>(NULL);
|
||||
node->Construct(channel);
|
||||
return node;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -1443,86 +1442,31 @@ ssize_t Unode::tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, siz
|
|||
return ret;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialization.
|
||||
//
|
||||
|
||||
class FactoryNode : public AbstractInode
|
||||
int Unode::unmounted(ioctx_t* /*ctx*/)
|
||||
{
|
||||
public:
|
||||
FactoryNode(uid_t owner, gid_t group, mode_t mode);
|
||||
virtual ~FactoryNode() { }
|
||||
virtual Ref<Inode> open(ioctx_t* ctx, const char* filename, int flags,
|
||||
mode_t mode);
|
||||
|
||||
};
|
||||
|
||||
FactoryNode::FactoryNode(uid_t owner, gid_t group, mode_t mode)
|
||||
{
|
||||
inode_type = INODE_TYPE_UNKNOWN;
|
||||
dev = (dev_t) this;
|
||||
ino = 0;
|
||||
this->type = S_IFDIR;
|
||||
this->stat_uid = owner;
|
||||
this->stat_gid = group;
|
||||
this->stat_mode = (mode & S_SETABLE) | this->type;
|
||||
server->Unmount();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Ref<Inode> FactoryNode::open(ioctx_t* /*ctx*/, const char* filename,
|
||||
int /*flags*/, mode_t /*mode*/)
|
||||
bool Bootstrap(Ref<Inode>* out_root,
|
||||
Ref<Inode>* out_server,
|
||||
const struct stat* rootst)
|
||||
{
|
||||
if ( !strcmp(filename, "new") )
|
||||
{
|
||||
Ref<Server> server(new Server());
|
||||
if ( !server )
|
||||
return Ref<Inode>(NULL);
|
||||
Ref<ServerNode> node(new ServerNode(server));
|
||||
if ( !node )
|
||||
return Ref<Inode>(NULL);
|
||||
return node;
|
||||
}
|
||||
return errno = ENOENT, Ref<Inode>(NULL);
|
||||
}
|
||||
|
||||
} // namespace UserFS
|
||||
} // namespace Sortix
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
int sys_fsm_fsbind(int rootfd, int mpointfd, int /*flags*/)
|
||||
{
|
||||
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(rootfd);
|
||||
if ( !desc ) { return -1; }
|
||||
Ref<Descriptor> mpoint = CurrentProcess()->GetDescriptor(mpointfd);
|
||||
if ( !mpoint ) { return -1; }
|
||||
Ref<MountTable> mtable = CurrentProcess()->GetMTable();
|
||||
Ref<Inode> node = desc->vnode->inode;
|
||||
return mtable->AddMount(mpoint->ino, mpoint->dev, node) ? 0 : -1;
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
||||
|
||||
namespace Sortix {
|
||||
namespace UserFS {
|
||||
|
||||
void Init(const char* devpath, Ref<Descriptor> slashdev)
|
||||
{
|
||||
ioctx_t ctx; SetupKernelIOCtx(&ctx);
|
||||
Ref<Inode> node(new FactoryNode(0, 0, 0666));
|
||||
if ( !node )
|
||||
PanicF("Unable to allocate %s/fs inode.", devpath);
|
||||
// TODO: Race condition! Create a mkdir function that returns what it
|
||||
// created, possibly with a O_MKDIR flag to open.
|
||||
if ( slashdev->mkdir(&ctx, "fs", 0755) < 0 && errno != EEXIST )
|
||||
PanicF("Could not create a %s/fs directory", devpath);
|
||||
Ref<Descriptor> mpoint = slashdev->open(&ctx, "fs", O_READ | O_WRITE, 0);
|
||||
if ( !mpoint )
|
||||
PanicF("Could not open the %s/fs directory", devpath);
|
||||
Ref<MountTable> mtable = CurrentProcess()->GetMTable();
|
||||
// TODO: Make sure that the mount point is *empty*! Add a proper function
|
||||
// for this on the file descriptor class!
|
||||
if ( !mtable->AddMount(mpoint->ino, mpoint->dev, node) )
|
||||
PanicF("Unable to mount filesystem on %s/fs", devpath);
|
||||
Ref<Server> server(new Server());
|
||||
if ( !server )
|
||||
return false;
|
||||
|
||||
ino_t root_inode_ino = rootst->st_ino;
|
||||
mode_t root_inode_type = rootst->st_mode & S_IFMT;
|
||||
Ref<Inode> root_inode = server->OpenNode(root_inode_ino, root_inode_type);
|
||||
if ( !root_inode )
|
||||
return false;
|
||||
|
||||
Ref<ServerNode> server_inode(new ServerNode(server));
|
||||
if ( !server_inode )
|
||||
return false;
|
||||
|
||||
return *out_root = root_inode, *out_server = server_inode, true;
|
||||
}
|
||||
|
||||
} // namespace UserFS
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -25,10 +25,15 @@
|
|||
#ifndef SORTIX_FS_USER_H
|
||||
#define SORTIX_FS_USER_H
|
||||
|
||||
#include <sortix/stat.h>
|
||||
|
||||
#include <sortix/kernel/refcount.h>
|
||||
#include <sortix/kernel/vnode.h>
|
||||
|
||||
namespace Sortix {
|
||||
namespace UserFS {
|
||||
|
||||
void Init(const char* devpath, Ref<Descriptor> slashdev);
|
||||
bool Bootstrap(Ref<Inode>* out_root, Ref<Inode>* out_server, const struct stat* rootst);
|
||||
|
||||
} // namespace UserFS
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -50,6 +50,10 @@ typedef struct ioctx_struct ioctx_t;
|
|||
|
||||
class Descriptor : public Refcountable
|
||||
{
|
||||
private:
|
||||
Descriptor();
|
||||
void LateConstruct(Ref<Vnode> vnode, int dflags);
|
||||
|
||||
public:
|
||||
Descriptor(Ref<Vnode> vnode, int dflags);
|
||||
virtual ~Descriptor();
|
||||
|
@ -102,6 +106,10 @@ public:
|
|||
const void* option_value, size_t option_size);
|
||||
ssize_t tcgetblob(ioctx_t* ctx, const char* name, void* buffer, size_t count);
|
||||
ssize_t tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count);
|
||||
int unmount(ioctx_t* ctx, const char* filename, int flags);
|
||||
int fsm_fsbind(ioctx_t* ctx, Ref<Descriptor> target, int flags);
|
||||
Ref<Descriptor> fsm_mount(ioctx_t* ctx, const char* filename,
|
||||
const struct stat* rootst, int flags);
|
||||
|
||||
private:
|
||||
Ref<Descriptor> open_elem(ioctx_t* ctx, const char* filename, int flags,
|
||||
|
|
|
@ -112,6 +112,7 @@ public:
|
|||
const void* option_value, size_t option_size) = 0;
|
||||
virtual ssize_t tcgetblob(ioctx_t* ctx, const char* name, void* buffer, size_t count) = 0;
|
||||
virtual ssize_t tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count) = 0;
|
||||
virtual int unmounted(ioctx_t* ctx) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
@ -199,6 +200,7 @@ public:
|
|||
const void* option_value, size_t option_size);
|
||||
virtual ssize_t tcgetblob(ioctx_t* ctx, const char* name, void* buffer, size_t count);
|
||||
virtual ssize_t tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count);
|
||||
virtual int unmounted(ioctx_t* ctx);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ typedef struct
|
|||
Ref<Inode> inode;
|
||||
ino_t ino;
|
||||
dev_t dev;
|
||||
bool fsbind;
|
||||
} mountpoint_t;
|
||||
|
||||
class MountTable : public Refcountable
|
||||
|
@ -47,7 +48,8 @@ public:
|
|||
MountTable();
|
||||
virtual ~MountTable();
|
||||
Ref<MountTable> Fork();
|
||||
bool AddMount(ino_t ino, dev_t dev, Ref<Inode> inode);
|
||||
bool AddMount(ino_t ino, dev_t dev, Ref<Inode> inode, bool fsbind);
|
||||
bool AddMountUnlocked(ino_t ino, dev_t dev, Ref<Inode> inode, bool fsbind);
|
||||
|
||||
public: // Consider these read-only.
|
||||
kthread_mutex_t mtablelock;
|
||||
|
|
|
@ -78,6 +78,7 @@ int sys_fchroot(int);
|
|||
int sys_fchrootat(int, const char*);
|
||||
int sys_fcntl(int, int, uintptr_t);
|
||||
int sys_fsm_fsbind(int, int, int);
|
||||
int sys_fsm_mountat(int, const char*, const struct stat*, int flags);
|
||||
int sys_fstat(int, struct stat*);
|
||||
int sys_fstatat(int, const char*, struct stat*, int);
|
||||
int sys_fstatvfs(int, struct statvfs*);
|
||||
|
@ -166,6 +167,7 @@ int sys_timer_settime(timer_t, int, const struct itimerspec*, struct itimerspec*
|
|||
int sys_truncateat(int, const char*, off_t);
|
||||
mode_t sys_umask(mode_t);
|
||||
int sys_unlinkat(int, const char*, int);
|
||||
int sys_unmountat(int, const char*, int);
|
||||
int sys_utimensat(int, const char*, const struct timespec [2], int);
|
||||
pid_t sys_waitpid(pid_t, int*, int);
|
||||
ssize_t sys_write(int, const void*, size_t);
|
||||
|
|
|
@ -102,6 +102,9 @@ public:
|
|||
const void* option_value, size_t option_size);
|
||||
ssize_t tcgetblob(ioctx_t* ctx, const char* name, void* buffer, size_t count);
|
||||
ssize_t tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count);
|
||||
int unmount(ioctx_t* ctx, const char* filename, int flags);
|
||||
int fsm_fsbind(ioctx_t* ctx, Ref<Vnode> target, int flags);
|
||||
Ref<Vnode> fsm_mount(ioctx_t* ctx, const char* filename, const struct stat* rootst, int flags);
|
||||
|
||||
public /*TODO: private*/:
|
||||
Ref<Inode> inode;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -29,10 +29,9 @@
|
|||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define MREPL (0<<0) /* Replace binding. */
|
||||
#define MBEFORE (1<<0) /* Add to start of directory union. */
|
||||
#define MAFTER (2<<0) /* Add to end of directory union. */
|
||||
#define MCREATE (1<<2) /* Create files here, otherwise try next in union. */
|
||||
#define UNMOUNT_FORCE (1 << 0)
|
||||
#define UNMOUNT_DETACH (1 << 1)
|
||||
#define UNMOUNT_NOFOLLOW (1 << 2)
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
|
|
@ -175,6 +175,8 @@
|
|||
#define SYSCALL_GETENTROPY 147
|
||||
#define SYSCALL_GETHOSTNAME 148
|
||||
#define SYSCALL_SETHOSTNAME 149
|
||||
#define SYSCALL_MAX_NUM 150 /* index of highest constant + 1 */
|
||||
#define SYSCALL_UNMOUNTAT 150
|
||||
#define SYSCALL_FSM_MOUNTAT 151
|
||||
#define SYSCALL_MAX_NUM 152 /* index of highest constant + 1 */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -406,4 +406,9 @@ ssize_t AbstractInode::tcsetblob(ioctx_t* /*ctx*/, const char* /*name*/, const v
|
|||
return errno = ENOTTY, -1;
|
||||
}
|
||||
|
||||
int AbstractInode::unmounted(ioctx_t* /*ctx*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fsmarshall-msg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -174,7 +175,13 @@ int sys_openat(int dirfd, const char* path, int flags, mode_t mode)
|
|||
if ( !desc )
|
||||
return -1;
|
||||
Ref<DescriptorTable> dtable = CurrentProcess()->GetDTable();
|
||||
return dtable->Allocate(desc, fdflags);
|
||||
int ret = dtable->Allocate(desc, fdflags);
|
||||
if ( ret < 0 )
|
||||
{
|
||||
// TODO: We should use a fail-safe dtable reservation mechanism that
|
||||
// causes this error earlier before we have side effects.
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// TODO: This is a hack! Stat the file in some manner and check permissions.
|
||||
|
@ -1079,4 +1086,65 @@ int sys_shutdown(int fd, int how)
|
|||
return errno = ENOSYS, -1;
|
||||
}
|
||||
|
||||
int sys_unmountat(int dirfd, const char* path, 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 )
|
||||
return delete[] pathcopy, -1;
|
||||
int ret = from->unmount(&ctx, relpath, flags);
|
||||
delete[] pathcopy;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sys_fsm_fsbind(int rootfd, int mpointfd, int flags)
|
||||
{
|
||||
if ( flags & ~(0) )
|
||||
return errno = EINVAL, -1;
|
||||
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(rootfd);
|
||||
if ( !desc )
|
||||
return -1;
|
||||
Ref<Descriptor> mpoint = CurrentProcess()->GetDescriptor(mpointfd);
|
||||
if ( !mpoint )
|
||||
return -1;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
return mpoint->fsm_fsbind(&ctx, desc, flags);
|
||||
}
|
||||
|
||||
int sys_fsm_mountat(int dirfd, const char* path, const struct stat* rootst, int flags)
|
||||
{
|
||||
if ( flags & ~(FSM_MOUNT_CLOEXEC | FSM_MOUNT_CLOFORK |
|
||||
FSM_MOUNT_NOFOLLOW | FSM_MOUNT_NONBLOCK) )
|
||||
return -1;
|
||||
int fdflags = 0;
|
||||
if ( flags & FSM_MOUNT_CLOEXEC ) fdflags |= FD_CLOEXEC;
|
||||
if ( flags & FSM_MOUNT_CLOFORK ) fdflags |= FD_CLOFORK;
|
||||
flags &= ~(FSM_MOUNT_CLOEXEC | FSM_MOUNT_CLOFORK);
|
||||
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 )
|
||||
return delete[] pathcopy, -1;
|
||||
Ref<Descriptor> desc = from->fsm_mount(&ctx, relpath, rootst, flags);
|
||||
delete[] pathcopy;
|
||||
Ref<DescriptorTable> dtable = CurrentProcess()->GetDTable();
|
||||
int ret = dtable->Allocate(desc, fdflags);
|
||||
if ( ret < 0 )
|
||||
{
|
||||
// TODO: We should use a fail-safe dtable reservation mechanism that
|
||||
// causes this error earlier before we have side effects.
|
||||
int errnum = errno;
|
||||
from->unmount(&ctx, relpath, 0);
|
||||
return errno = errnum, -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -73,7 +73,6 @@
|
|||
#include "fs/full.h"
|
||||
#include "fs/kram.h"
|
||||
#include "fs/null.h"
|
||||
#include "fs/user.h"
|
||||
#include "fs/zero.h"
|
||||
#include "gpu/bga/bga.h"
|
||||
#include "initrd.h"
|
||||
|
@ -601,9 +600,6 @@ static void BootThread(void* /*user*/)
|
|||
// Initialize the filesystem network-
|
||||
NetFS::Init("/dev", slashdev);
|
||||
|
||||
// Initialize the user-space filesystem framework.
|
||||
UserFS::Init("/dev", slashdev);
|
||||
|
||||
//
|
||||
// Stage 6. Executing Hosted Environment ("User-Space")
|
||||
//
|
||||
|
|
|
@ -61,9 +61,14 @@ Ref<MountTable> MountTable::Fork()
|
|||
return clone;
|
||||
}
|
||||
|
||||
bool MountTable::AddMount(ino_t ino, dev_t dev, Ref<Inode> inode)
|
||||
bool MountTable::AddMount(ino_t ino, dev_t dev, Ref<Inode> inode, bool fsbind)
|
||||
{
|
||||
ScopedLock lock(&mtablelock);
|
||||
return AddMountUnlocked(ino, dev, inode, fsbind);
|
||||
}
|
||||
|
||||
bool MountTable::AddMountUnlocked(ino_t ino, dev_t dev, Ref<Inode> inode, bool fsbind)
|
||||
{
|
||||
if ( nummounts == mountsalloced )
|
||||
{
|
||||
size_t newalloced = mountsalloced ? 2UL * mountsalloced : 4UL;
|
||||
|
@ -80,6 +85,7 @@ bool MountTable::AddMount(ino_t ino, dev_t dev, Ref<Inode> inode)
|
|||
mp->ino = ino;
|
||||
mp->dev = dev;
|
||||
mp->inode = inode;
|
||||
mp->fsbind = fsbind;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -536,7 +536,7 @@ void Init(const char* devpath, Ref<Descriptor> slashdev)
|
|||
Ref<MountTable> mtable = CurrentProcess()->GetMTable();
|
||||
// TODO: Make sure that the mount point is *empty*! Add a proper function
|
||||
// for this on the file descriptor class!
|
||||
if ( !mtable->AddMount(mpoint->ino, mpoint->dev, node) )
|
||||
if ( !mtable->AddMount(mpoint->ino, mpoint->dev, node, false) )
|
||||
PanicF("Unable to mount filesystem on %s/net/fs", devpath);
|
||||
}
|
||||
|
||||
|
|
|
@ -185,6 +185,8 @@ void* syscall_list[SYSCALL_MAX_NUM + 1] =
|
|||
[SYSCALL_GETENTROPY] = (void*) sys_getentropy,
|
||||
[SYSCALL_GETHOSTNAME] = (void*) sys_gethostname,
|
||||
[SYSCALL_SETHOSTNAME] = (void*) sys_sethostname,
|
||||
[SYSCALL_UNMOUNTAT] = (void*) sys_unmountat,
|
||||
[SYSCALL_FSM_MOUNTAT] = (void*) sys_fsm_mountat,
|
||||
[SYSCALL_MAX_NUM] = (void*) sys_bad_syscall,
|
||||
};
|
||||
} // extern "C"
|
||||
|
|
120
kernel/vnode.cpp
120
kernel/vnode.cpp
|
@ -25,7 +25,9 @@
|
|||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sortix/fcntl.h>
|
||||
#include <sortix/mount.h>
|
||||
#include <sortix/stat.h>
|
||||
|
||||
#include <sortix/kernel/kernel.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
|
@ -36,20 +38,31 @@
|
|||
#include <sortix/kernel/mtable.h>
|
||||
#include <sortix/kernel/process.h>
|
||||
|
||||
#include "fs/user.h"
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
static Ref<Inode> LookupMount(Ref<Inode> inode)
|
||||
static Ref<Inode> LookupMountUnlocked(Ref<Inode> inode, size_t* out_index = NULL)
|
||||
{
|
||||
Ref<Inode> result_inode(NULL);
|
||||
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;
|
||||
if ( out_index )
|
||||
*out_index = i;
|
||||
result_inode = mp->inode;
|
||||
}
|
||||
return Ref<Inode>(NULL);
|
||||
return result_inode;
|
||||
}
|
||||
|
||||
static Ref<Inode> LookupMount(Ref<Inode> inode)
|
||||
{
|
||||
Ref<MountTable> mtable = CurrentProcess()->GetMTable();
|
||||
ScopedLock mtable_lock(&mtable->mtablelock);
|
||||
return LookupMountUnlocked(inode);
|
||||
}
|
||||
|
||||
Vnode::Vnode(Ref<Inode> inode, Ref<Vnode> mountedat, ino_t rootino, dev_t rootdev)
|
||||
|
@ -88,7 +101,8 @@ Ref<Vnode> Vnode::open(ioctx_t* ctx, const char* filename, int flags, mode_t mod
|
|||
|
||||
// Move within the current filesystem.
|
||||
Ref<Inode> retinode = inode->open(ctx, filename, flags, mode);
|
||||
if ( !retinode ) { return Ref<Vnode>(NULL); }
|
||||
if ( !retinode )
|
||||
return Ref<Vnode>(NULL);
|
||||
Ref<Vnode> retmountedat = mountedat;
|
||||
ino_t retrootino = rootino;
|
||||
dev_t retrootdev = rootdev;
|
||||
|
@ -106,6 +120,102 @@ Ref<Vnode> Vnode::open(ioctx_t* ctx, const char* filename, int flags, mode_t mod
|
|||
return Ref<Vnode>(new Vnode(retinode, retmountedat, retrootino, retrootdev));
|
||||
}
|
||||
|
||||
int Vnode::fsm_fsbind(ioctx_t* ctx, Ref<Vnode> target, int flags)
|
||||
{
|
||||
(void) ctx;
|
||||
if ( flags & ~(0) )
|
||||
return errno = EINVAL, -1;
|
||||
Ref<MountTable> mtable = CurrentProcess()->GetMTable();
|
||||
if ( !mtable->AddMount(ino, dev, target->inode, true) )
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Ref<Vnode> Vnode::fsm_mount(ioctx_t* ctx,
|
||||
const char* filename,
|
||||
const struct stat* rootst_ptr,
|
||||
int flags)
|
||||
{
|
||||
if ( flags & ~(0) )
|
||||
return Ref<Vnode>(NULL);
|
||||
|
||||
if ( !strcmp(filename, ".") || !strcmp(filename, "..") )
|
||||
return errno = EINVAL, Ref<Vnode>(NULL);
|
||||
|
||||
struct stat rootst;
|
||||
if ( !ctx->copy_from_src(&rootst, rootst_ptr, sizeof(struct stat)) )
|
||||
return Ref<Vnode>(NULL);
|
||||
|
||||
Ref<Inode> normal_inode = inode->open(ctx, filename, O_READ, 0);
|
||||
if ( !normal_inode )
|
||||
return Ref<Vnode>(NULL);
|
||||
|
||||
Ref<Inode> root_inode;
|
||||
Ref<Inode> server_inode;
|
||||
if ( !UserFS::Bootstrap(&root_inode, &server_inode, &rootst) )
|
||||
return Ref<Vnode>(NULL);
|
||||
|
||||
Ref<Vnode> server_vnode(new Vnode(server_inode, Ref<Vnode>(NULL), 0, 0));
|
||||
if ( !server_vnode )
|
||||
return Ref<Vnode>(NULL);
|
||||
|
||||
Ref<MountTable> mtable = CurrentProcess()->GetMTable();
|
||||
ScopedLock lock(&mtable->mtablelock);
|
||||
if ( Ref<Inode> mounted = LookupMountUnlocked(normal_inode) )
|
||||
normal_inode = mounted;
|
||||
|
||||
if ( !mtable->AddMountUnlocked(normal_inode->ino, normal_inode->dev, root_inode, false) )
|
||||
return Ref<Vnode>(NULL);
|
||||
|
||||
return server_vnode;
|
||||
}
|
||||
|
||||
int Vnode::unmount(ioctx_t* ctx, const char* filename, int flags)
|
||||
{
|
||||
if ( flags & ~(UNMOUNT_FORCE | UNMOUNT_DETACH) )
|
||||
return errno = EINVAL, -1;
|
||||
|
||||
if ( !strcmp(filename, ".") || !strcmp(filename, "..") )
|
||||
return errno = EINVAL, -1;
|
||||
|
||||
Ref<Inode> normal_inode = inode->open(ctx, filename, O_READ, 0);
|
||||
if ( !normal_inode )
|
||||
return -1;
|
||||
|
||||
Ref<MountTable> mtable = CurrentProcess()->GetMTable();
|
||||
ScopedLock mtable_lock(&mtable->mtablelock);
|
||||
|
||||
size_t mp_index;
|
||||
if ( !LookupMountUnlocked(normal_inode, &mp_index) )
|
||||
return errno = EINVAL, -1;
|
||||
mountpoint_t* mp = mtable->mounts + mp_index;
|
||||
|
||||
Ref<Inode> mp_inode = mp->inode;
|
||||
bool mp_fsbind = mp->fsbind;
|
||||
|
||||
mp->inode.Reset();
|
||||
for ( size_t n = mp_index; n < mtable->nummounts - 1; n++ )
|
||||
{
|
||||
mtable->mounts[n].inode.Reset();
|
||||
mtable->mounts[n] = mtable->mounts[n+1];
|
||||
}
|
||||
if ( mp_index + 1 != mtable->nummounts )
|
||||
mtable->mounts[mtable->nummounts].inode.Reset();
|
||||
mtable->nummounts--;
|
||||
|
||||
mtable_lock.Reset();
|
||||
|
||||
if ( !mp_fsbind )
|
||||
{
|
||||
// TODO: Implement the !UNMOUNT_DETACH case.
|
||||
// TODO: Implement the UNMOUNT_FORCE case.
|
||||
mp_inode->unmounted(ctx);
|
||||
}
|
||||
mp_inode.Reset();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Vnode::sync(ioctx_t* ctx)
|
||||
{
|
||||
return inode->sync(ctx);
|
||||
|
|
|
@ -333,14 +333,8 @@ fcntl/creat.o \
|
|||
fcntl/fcntl.o \
|
||||
fcntl/openat.o \
|
||||
fcntl/open.o \
|
||||
fsmarshall/fsm_bootstraprootfd.o \
|
||||
fsmarshall/fsm_closechannel.o \
|
||||
fsmarshall/fsm_closeserver.o \
|
||||
fsmarshall/fsm_fsbind.o \
|
||||
fsmarshall/fsm_listen.o \
|
||||
fsmarshall/fsm_mkserver.o \
|
||||
fsmarshall/fsm_recv.o \
|
||||
fsmarshall/fsm_send.o \
|
||||
fsmarshall/fsm_mountat.o \
|
||||
getopt/getopt_long.o \
|
||||
getopt/getopt.o \
|
||||
grp/endgrent.o \
|
||||
|
@ -476,6 +470,8 @@ syslog/vsyslog.o \
|
|||
sys/mman/mmap.o \
|
||||
sys/mman/mprotect.o \
|
||||
sys/mman/munmap.o \
|
||||
sys/mount/unmountat.o \
|
||||
sys/mount/unmount.o \
|
||||
sys/readdirents/readdirents.o \
|
||||
sys/resource/getpriority.o \
|
||||
sys/resource/getrlimit.o \
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 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/>.
|
||||
|
||||
fsmarshall/fsm_bootstraprootfd.cpp
|
||||
Creates a root file descriptor associated with a user-space filesystem.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <fsmarshall.h>
|
||||
|
||||
extern "C" int fsm_bootstraprootfd(int server, ino_t ino, int open_flags,
|
||||
mode_t mode)
|
||||
{
|
||||
char name[sizeof(uintmax_t)*3];
|
||||
snprintf(name, sizeof(name), "%ju", (uintmax_t) ino);
|
||||
return openat(server, name, open_flags, mode);
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2014.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -17,16 +17,18 @@
|
|||
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/>.
|
||||
|
||||
fsmarshall/fsm_listen.cpp
|
||||
Listens for a new channel on a given filesystem server.
|
||||
fsmarshall/fsm_mountat.cpp
|
||||
Attaches a user-space filesystem at the specified mount point.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <fsmarshall.h>
|
||||
|
||||
extern "C" int fsm_listen(int server)
|
||||
DEFN_SYSCALL4(int, sys_fsm_mountat, SYSCALL_FSM_MOUNTAT, int, const char*, const struct stat*, int);
|
||||
|
||||
extern "C" int fsm_mountat(int dirfd, const char* path, const struct stat* rootst, int flags)
|
||||
{
|
||||
return openat(server, "listen", O_RDWR);
|
||||
return sys_fsm_mountat(dirfd, path, rootst, flags);
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 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/>.
|
||||
|
||||
fsmarshall/fsm_recv.cpp
|
||||
Reads a message from a filesystem communication channel.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <fsmarshall.h>
|
||||
|
||||
extern "C" ssize_t fsm_recv(int /*server*/, int channel, void* ptr, size_t count)
|
||||
{
|
||||
return read(channel, ptr, count);
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 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/>.
|
||||
|
||||
fsmarshall/fsm_send.cpp
|
||||
Send a message to a filesystem communication channel.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <fsmarshall.h>
|
||||
|
||||
extern "C" ssize_t fsm_send(int /*server*/, int channel, const void* ptr,
|
||||
size_t count)
|
||||
{
|
||||
return write(channel, ptr, count);
|
||||
}
|
|
@ -25,6 +25,8 @@
|
|||
#ifndef INCLUDE_FSMARSHALL_MSG_H
|
||||
#define INCLUDE_FSMARSHALL_MSG_H
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <sortix/stat.h>
|
||||
|
@ -32,9 +34,12 @@
|
|||
#include <sortix/termios.h>
|
||||
#include <sortix/timespec.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define FSM_MOUNT_CLOEXEC (1 << 0)
|
||||
#define FSM_MOUNT_CLOFORK (1 << 1)
|
||||
#define FSM_MOUNT_NOFOLLOW (1 << 2)
|
||||
#define FSM_MOUNT_NONBLOCK (1 << 3)
|
||||
|
||||
struct fsm_msg_header
|
||||
{
|
||||
|
@ -427,8 +432,6 @@ struct fsm_resp_tcsetblob
|
|||
|
||||
#define FSM_MSG_NUM 53
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -25,29 +25,17 @@
|
|||
#ifndef INCLUDE_FSMARSHALL_H
|
||||
#define INCLUDE_FSMARSHALL_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <sortix/stat.h>
|
||||
#include <sortix/termios.h>
|
||||
#include <sortix/timespec.h>
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <fsmarshall-msg.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
__BEGIN_DECLS
|
||||
|
||||
int fsm_mkserver();
|
||||
int fsm_closeserver(int server);
|
||||
int fsm_bootstraprootfd(int server, ino_t ino, int open_flags, mode_t mode);
|
||||
int fsm_fsbind(int rootfd, int mountpoint, int flags);
|
||||
int fsm_listen(int server);
|
||||
int fsm_closechannel(int server, int channel);
|
||||
ssize_t fsm_recv(int server, int channel, void* ptr, size_t count);
|
||||
ssize_t fsm_send(int server, int channel, const void* ptr, size_t count);
|
||||
struct stat;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
int fsm_fsbind(int, int, int);
|
||||
int fsm_mountat(int, const char*, const struct stat*, int);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2014.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -17,16 +17,23 @@
|
|||
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/>.
|
||||
|
||||
fsmarshall/fsm_closechannel.cpp
|
||||
Closes a user-space filesystem communication channel.
|
||||
sys/mount.h
|
||||
Filesystem mount functionality.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <unistd.h>
|
||||
#ifndef INCLUDE_SYS_MOUNT_H
|
||||
#define INCLUDE_SYS_MOUNT_H
|
||||
|
||||
#include <fsmarshall.h>
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
extern "C" int fsm_closechannel(int /*server*/, int channel)
|
||||
{
|
||||
return close(channel);
|
||||
}
|
||||
#include <sortix/mount.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
int unmount(const char*, int);
|
||||
int unmountat(int, const char*, int);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2014.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -17,16 +17,16 @@
|
|||
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/>.
|
||||
|
||||
fsmarshall/fsm_mkserver.cpp
|
||||
Creates a user-space filesystem server.
|
||||
sys/mount/unmount.cpp
|
||||
Unmount filesystem at path.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <fsmarshall.h>
|
||||
|
||||
extern "C" int fsm_mkserver()
|
||||
extern "C" int unmount(const char* path, int flags)
|
||||
{
|
||||
return open("/dev/fs/new", O_RDWR | O_CREAT, 0666);
|
||||
return unmountat(AT_FDCWD, path, flags);
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2014.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -17,16 +17,17 @@
|
|||
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/>.
|
||||
|
||||
fsmarshall/fsm_closeserver.cpp
|
||||
Destroys a user-space filesystem server.
|
||||
sys/mount/unmountat.cpp
|
||||
Unmount filesystem at path.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <fsmarshall.h>
|
||||
DEFN_SYSCALL3(int, sys_unmountat, SYSCALL_UNMOUNTAT, int, const char*, int);
|
||||
|
||||
extern "C" int fsm_closeserver(int server)
|
||||
extern "C" int unmountat(int dirfd, const char* path, int flags)
|
||||
{
|
||||
return close(server);
|
||||
return sys_unmountat(dirfd, path, flags);
|
||||
}
|
Loading…
Add table
Reference in a new issue