mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 22:36:48 +00:00
移植sqlite3,并修复一些bug (#323)
* bugfix: 程序加载器映射内存时,计算要映射的大小不正确的问题。 * 修正brk系统调用不符合规范的地方 * bugfix: 修正fat文件系统未能正确的扩展文件大小的bug * 增加fcntl系统调用 * 移植sqlite3
This commit is contained in:
parent
26887c6334
commit
6d81180b3b
@ -1,11 +1,5 @@
|
||||
#![allow(dead_code)]
|
||||
use core::cmp::min;
|
||||
|
||||
use alloc::{
|
||||
string::{String, ToString},
|
||||
sync::Arc,
|
||||
vec::Vec,
|
||||
};
|
||||
use core::{cmp::min, intrinsics::unlikely};
|
||||
|
||||
use crate::{
|
||||
io::{device::LBA_SIZE, SeekFrom},
|
||||
@ -13,6 +7,11 @@ use crate::{
|
||||
libs::vec_cursor::VecCursor,
|
||||
syscall::SystemError,
|
||||
};
|
||||
use alloc::{
|
||||
string::{String, ToString},
|
||||
sync::Arc,
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
use super::{
|
||||
fs::{Cluster, FATFileSystem, MAX_FILE_SIZE},
|
||||
@ -166,7 +165,6 @@ impl FATFile {
|
||||
|
||||
// 要写入的第一个簇的簇号
|
||||
let start_cluster_num = offset / fs.bytes_per_cluster();
|
||||
|
||||
// 获取要写入的第一个簇
|
||||
let mut current_cluster: Cluster = if let Some(c) =
|
||||
fs.get_cluster_by_relative(self.first_cluster, start_cluster_num as usize)
|
||||
@ -239,22 +237,26 @@ impl FATFile {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// 计算文件的最后一个簇中有多少空闲空间
|
||||
let in_cluster_offset = self.size() % fs.bytes_per_cluster();
|
||||
let mut bytes_remain_in_cluster = if in_cluster_offset == 0 {
|
||||
0
|
||||
} else {
|
||||
fs.bytes_per_cluster() - in_cluster_offset
|
||||
};
|
||||
|
||||
// 计算还需要申请多少空间
|
||||
let extra_bytes = min((offset + len) - self.size(), MAX_FILE_SIZE - self.size());
|
||||
|
||||
// 如果文件大小为0,证明它还没有分配簇,因此分配一个簇给它
|
||||
if self.size() == 0 {
|
||||
// first_cluster应当为0,否则将产生空间泄露的错误
|
||||
assert_eq!(self.first_cluster, Cluster::default());
|
||||
self.first_cluster = fs.allocate_cluster(None)?;
|
||||
self.short_dir_entry.set_first_cluster(self.first_cluster);
|
||||
bytes_remain_in_cluster = fs.bytes_per_cluster();
|
||||
}
|
||||
|
||||
// 计算文件的最后一个簇中有多少空闲空间
|
||||
|
||||
let in_cluster_offset = self.size() % fs.bytes_per_cluster();
|
||||
let bytes_remain_in_cluster = fs.bytes_per_cluster() - in_cluster_offset;
|
||||
|
||||
// 计算还需要申请多少空间
|
||||
let extra_bytes = min((offset + len) - self.size(), MAX_FILE_SIZE - self.size());
|
||||
|
||||
// 如果还需要更多的簇
|
||||
if bytes_remain_in_cluster < extra_bytes {
|
||||
let clusters_to_allocate =
|
||||
@ -343,17 +345,24 @@ impl FATFile {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let new_last_cluster = new_size / fs.bytes_per_cluster();
|
||||
let new_last_cluster = (new_size + fs.bytes_per_cluster() - 1) / fs.bytes_per_cluster();
|
||||
if let Some(begin_delete) =
|
||||
fs.get_cluster_by_relative(self.first_cluster, (new_last_cluster + 1) as usize)
|
||||
fs.get_cluster_by_relative(self.first_cluster, new_last_cluster as usize)
|
||||
{
|
||||
fs.deallocate_cluster(begin_delete)?;
|
||||
fs.deallocate_cluster_chain(begin_delete)?;
|
||||
};
|
||||
|
||||
if new_size == 0 {
|
||||
assert!(new_last_cluster == 0);
|
||||
self.short_dir_entry.set_first_cluster(Cluster::new(0));
|
||||
self.first_cluster = Cluster::new(0);
|
||||
}
|
||||
|
||||
self.set_size(new_size as u32);
|
||||
// 计算短目录项在磁盘内的字节偏移量
|
||||
let short_entry_offset = fs.cluster_bytes_offset((self.loc.1).0) + (self.loc.1).1;
|
||||
self.short_dir_entry.flush(fs, short_entry_offset)?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
@ -1406,6 +1415,10 @@ impl FATDirIter {
|
||||
/// @return Err(错误码) 可能出现了内部错误,或者是磁盘错误等。具体原因看错误码。
|
||||
fn get_dir_entry(&mut self) -> Result<(Cluster, u64, Option<FATDirEntry>), SystemError> {
|
||||
loop {
|
||||
if unlikely(self.current_cluster.cluster_num < 2) {
|
||||
return Ok((self.current_cluster, self.offset, None));
|
||||
}
|
||||
|
||||
// 如果当前簇已经被读完,那么尝试获取下一个簇
|
||||
if self.offset >= self.fs.bytes_per_cluster() && !self.is_root {
|
||||
match self.fs.get_fat_entry(self.current_cluster)? {
|
||||
|
@ -350,6 +350,10 @@ impl FATFileSystem {
|
||||
/// @return Err(SystemError) 错误码
|
||||
pub fn get_fat_entry(&self, cluster: Cluster) -> Result<FATEntry, SystemError> {
|
||||
let current_cluster = cluster.cluster_num;
|
||||
if current_cluster < 2 {
|
||||
// 0号簇和1号簇是保留簇,不允许用户使用
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
let fat_type: FATType = self.bpb.fat_type;
|
||||
// 获取FAT表的起始扇区(相对分区起始扇区的偏移量)
|
||||
@ -1460,6 +1464,44 @@ impl IndexNode for LockedFATInode {
|
||||
fn metadata(&self) -> Result<Metadata, SystemError> {
|
||||
return Ok(self.0.lock().metadata.clone());
|
||||
}
|
||||
fn resize(&self, len: usize) -> Result<(), SystemError> {
|
||||
let mut guard: SpinLockGuard<FATInode> = self.0.lock();
|
||||
let fs: &Arc<FATFileSystem> = &guard.fs.upgrade().unwrap();
|
||||
let old_size = guard.metadata.size as usize;
|
||||
|
||||
match &mut guard.inode_type {
|
||||
FATDirEntry::File(file) | FATDirEntry::VolId(file) => {
|
||||
// 如果新的长度和旧的长度相同,那么就直接返回
|
||||
if len == old_size {
|
||||
return Ok(());
|
||||
} else if len > old_size {
|
||||
// 如果新的长度比旧的长度大,那么就在文件末尾添加空白
|
||||
let mut buf: Vec<u8> = Vec::new();
|
||||
let mut remain_size = len - old_size;
|
||||
let buf_size = remain_size;
|
||||
// let buf_size = core::cmp::min(remain_size, 512 * 1024);
|
||||
buf.resize(buf_size, 0);
|
||||
|
||||
let mut offset = old_size;
|
||||
while remain_size > 0 {
|
||||
let write_size = core::cmp::min(remain_size, buf_size);
|
||||
file.write(fs, &buf[0..write_size], offset as u64)?;
|
||||
remain_size -= write_size;
|
||||
offset += write_size;
|
||||
}
|
||||
} else {
|
||||
file.truncate(fs, len as u64)?;
|
||||
}
|
||||
guard.update_metadata();
|
||||
return Ok(());
|
||||
}
|
||||
FATDirEntry::Dir(_) => return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP),
|
||||
FATDirEntry::UnInit => {
|
||||
kerror!("FATFS: param: Inode_type uninitialized.");
|
||||
return Err(SystemError::EROFS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn list(&self) -> Result<Vec<String>, SystemError> {
|
||||
let mut guard: SpinLockGuard<FATInode> = self.0.lock();
|
||||
|
62
kernel/src/filesystem/vfs/fcntl.rs
Normal file
62
kernel/src/filesystem/vfs/fcntl.rs
Normal file
@ -0,0 +1,62 @@
|
||||
const F_LINUX_SPECIFIC_BASE: u32 = 1024;
|
||||
|
||||
/// fcntl syscall command
|
||||
///
|
||||
/// for linux-specific fcntl commands, see:
|
||||
/// https://opengrok.ringotek.cn/xref/linux-5.19.10/tools/include/uapi/linux/fcntl.h#8
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, FromPrimitive, ToPrimitive)]
|
||||
#[repr(u32)]
|
||||
pub enum FcntlCommand {
|
||||
/// dup
|
||||
DupFd = 0,
|
||||
/// get close-on-exec
|
||||
GetFd = 1,
|
||||
/// set/clear close-on-exec
|
||||
SetFd = 2,
|
||||
/// get file flags
|
||||
GetFlags = 3,
|
||||
/// set file flags
|
||||
SetFlags = 4,
|
||||
/// get record locking info
|
||||
GetLock = 5,
|
||||
/// set record locking info (non-blocking)
|
||||
SetLock = 6,
|
||||
/// set record locking info (blocking)
|
||||
SetLockWait = 7,
|
||||
|
||||
SetLease = F_LINUX_SPECIFIC_BASE + 0,
|
||||
GetLease = F_LINUX_SPECIFIC_BASE + 1,
|
||||
|
||||
/// Request nofications on a directory.
|
||||
/// See below for events that may be notified.
|
||||
Notify = F_LINUX_SPECIFIC_BASE + 2,
|
||||
|
||||
/// Cancel a blocking posix lock; internal use only until we expose an
|
||||
/// asynchronous lock api to userspace
|
||||
CancelLock = F_LINUX_SPECIFIC_BASE + 5,
|
||||
/// Create a file descriptor with FD_CLOEXEC set.
|
||||
DupFdCloexec = F_LINUX_SPECIFIC_BASE + 6,
|
||||
|
||||
/// Set pipe page size array
|
||||
SetPipeSize = F_LINUX_SPECIFIC_BASE + 7,
|
||||
/// Get pipe page size array
|
||||
GetPipeSize = F_LINUX_SPECIFIC_BASE + 8,
|
||||
|
||||
/// Set seals
|
||||
AddSeals = F_LINUX_SPECIFIC_BASE + 9,
|
||||
/// Get seals
|
||||
GetSeals = F_LINUX_SPECIFIC_BASE + 10,
|
||||
|
||||
/**
|
||||
* Set/Get write life time hints. {GET,SET}_RW_HINT operate on the
|
||||
* underlying inode, while {GET,SET}_FILE_RW_HINT operate only on
|
||||
* the specific file.
|
||||
*/
|
||||
GetRwHint = F_LINUX_SPECIFIC_BASE + 11,
|
||||
SetRwHint = F_LINUX_SPECIFIC_BASE + 12,
|
||||
GetFileRwHint = F_LINUX_SPECIFIC_BASE + 13,
|
||||
SetFileRwHint = F_LINUX_SPECIFIC_BASE + 14,
|
||||
}
|
||||
|
||||
/// for F_[GET|SET]FL
|
||||
pub const FD_CLOEXEC: u32 = 1;
|
@ -132,6 +132,12 @@ impl File {
|
||||
if buf.len() < len {
|
||||
return Err(SystemError::ENOBUFS);
|
||||
}
|
||||
|
||||
// 如果文件指针已经超过了文件大小,则返回0
|
||||
if self.offset > self.inode.metadata()?.size as usize {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
let len = self
|
||||
.inode
|
||||
.read_at(self.offset, len, buf, &mut self.private_data)?;
|
||||
@ -152,6 +158,12 @@ impl File {
|
||||
if buf.len() < len {
|
||||
return Err(SystemError::ENOBUFS);
|
||||
}
|
||||
|
||||
// 如果文件指针已经超过了文件大小,则需要扩展文件大小
|
||||
let file_size = self.inode.metadata()?.size as usize;
|
||||
if self.offset > file_size {
|
||||
self.inode.resize(self.offset)?;
|
||||
}
|
||||
let len = self
|
||||
.inode
|
||||
.write_at(self.offset, len, buf, &mut self.private_data)?;
|
||||
@ -197,8 +209,9 @@ impl File {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
if pos < 0 || pos > self.metadata()?.size {
|
||||
// 根据linux man page, lseek允许超出文件末尾,并且不改变文件大小
|
||||
// 当pos超出文件末尾时,read返回0。直到开始写入数据时,才会改变文件大小
|
||||
if pos < 0 {
|
||||
return Err(SystemError::EOVERFLOW);
|
||||
}
|
||||
self.offset = pos as usize;
|
||||
@ -301,6 +314,53 @@ impl File {
|
||||
pub fn file_type(&self) -> FileType {
|
||||
return self.file_type;
|
||||
}
|
||||
|
||||
/// @brief 获取文件的打开模式
|
||||
#[inline]
|
||||
pub fn mode(&self) -> FileMode {
|
||||
return self.mode;
|
||||
}
|
||||
|
||||
/// 获取文件是否在execve时关闭
|
||||
#[inline]
|
||||
pub fn close_on_exec(&self) -> bool {
|
||||
return self.mode.contains(FileMode::O_CLOEXEC);
|
||||
}
|
||||
|
||||
/// 设置文件是否在execve时关闭
|
||||
#[inline]
|
||||
pub fn set_close_on_exec(&mut self, close_on_exec: bool) {
|
||||
if close_on_exec {
|
||||
self.mode.insert(FileMode::O_CLOEXEC);
|
||||
} else {
|
||||
self.mode.remove(FileMode::O_CLOEXEC);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_mode(&mut self, mode: FileMode) -> Result<(), SystemError> {
|
||||
// todo: 是否需要调用inode的open方法,以更新private data(假如它与mode有关的话)?
|
||||
// 也许需要加个更好的设计,让inode知晓文件的打开模式发生了变化,让它自己决定是否需要更新private data
|
||||
|
||||
// 直接修改文件的打开模式
|
||||
self.mode = mode;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// @brief 重新设置文件的大小
|
||||
///
|
||||
/// 如果文件大小增加,则文件内容不变,但是文件的空洞部分会被填充为0
|
||||
/// 如果文件大小减小,则文件内容会被截断
|
||||
///
|
||||
/// @return 成功:Ok()
|
||||
/// 失败:Err(错误码)
|
||||
pub fn ftruncate(&mut self, len: usize) -> Result<(), SystemError> {
|
||||
// 如果文件不可写,返回错误
|
||||
self.writeable()?;
|
||||
|
||||
// 调用inode的truncate方法
|
||||
self.inode.resize(len)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for File {
|
||||
|
@ -1,6 +1,7 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub mod core;
|
||||
pub mod fcntl;
|
||||
pub mod file;
|
||||
pub mod mount;
|
||||
pub mod syscall;
|
||||
@ -161,6 +162,9 @@ pub trait IndexNode: Any + Sync + Send + Debug {
|
||||
}
|
||||
|
||||
/// @brief 重新设置文件的大小
|
||||
///
|
||||
/// 如果文件大小增加,则文件内容不变,但是文件的空洞部分会被填充为0
|
||||
/// 如果文件大小减小,则文件内容会被截断
|
||||
///
|
||||
/// @return 成功:Ok()
|
||||
/// 失败:Err(错误码)
|
||||
|
@ -11,6 +11,7 @@ use crate::{
|
||||
|
||||
use super::{
|
||||
core::{do_mkdir, do_remove_dir, do_unlink_at},
|
||||
fcntl::{FcntlCommand, FD_CLOEXEC},
|
||||
file::{File, FileMode},
|
||||
utils::rsplit_path,
|
||||
Dirent, FileType, IndexNode, ROOT_INODE,
|
||||
@ -29,6 +30,7 @@ impl Syscall {
|
||||
///
|
||||
/// @return 文件描述符编号,或者是错误码
|
||||
pub fn open(path: &str, mode: FileMode) -> Result<usize, SystemError> {
|
||||
// kdebug!("open: path: {}, mode: {:?}", path, mode);
|
||||
// 文件名过长
|
||||
if path.len() > PAGE_4K_SIZE as usize {
|
||||
return Err(SystemError::ENAMETOOLONG);
|
||||
@ -82,7 +84,9 @@ impl Syscall {
|
||||
}
|
||||
|
||||
// 把文件对象存入pcb
|
||||
return current_pcb().alloc_fd(file, None).map(|fd| fd as usize);
|
||||
let r = current_pcb().alloc_fd(file, None).map(|fd| fd as usize);
|
||||
// kdebug!("open: fd: {:?}", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
/// @brief 关闭文件
|
||||
@ -91,6 +95,7 @@ impl Syscall {
|
||||
///
|
||||
/// @return 成功返回0,失败返回错误码
|
||||
pub fn close(fd: usize) -> Result<usize, SystemError> {
|
||||
// kdebug!("syscall::close: fd: {}", fd);
|
||||
return current_pcb().drop_fd(fd as i32).map(|_| 0);
|
||||
}
|
||||
|
||||
@ -102,6 +107,7 @@ impl Syscall {
|
||||
/// @return Ok(usize) 成功读取的数据的字节数
|
||||
/// @return Err(SystemError) 读取失败,返回posix错误码
|
||||
pub fn read(fd: i32, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
// kdebug!("syscall::read: fd: {}, len={}", fd, buf.len());
|
||||
let file: Option<&mut File> = current_pcb().get_file_mut_by_fd(fd);
|
||||
if file.is_none() {
|
||||
return Err(SystemError::EBADF);
|
||||
@ -119,6 +125,7 @@ impl Syscall {
|
||||
/// @return Ok(usize) 成功写入的数据的字节数
|
||||
/// @return Err(SystemError) 写入失败,返回posix错误码
|
||||
pub fn write(fd: i32, buf: &[u8]) -> Result<usize, SystemError> {
|
||||
// kdebug!("syscall::write: fd: {}, len={}", fd, buf.len());
|
||||
let file: Option<&mut File> = current_pcb().get_file_mut_by_fd(fd);
|
||||
if file.is_none() {
|
||||
return Err(SystemError::EBADF);
|
||||
@ -136,6 +143,7 @@ impl Syscall {
|
||||
/// @return Ok(usize) 调整后,文件访问指针相对于文件头部的偏移量
|
||||
/// @return Err(SystemError) 调整失败,返回posix错误码
|
||||
pub fn lseek(fd: i32, seek: SeekFrom) -> Result<usize, SystemError> {
|
||||
// kdebug!("syscall::lseek: fd: {}, seek={:?}", fd, seek);
|
||||
let file: Option<&mut File> = current_pcb().get_file_mut_by_fd(fd);
|
||||
if file.is_none() {
|
||||
return Err(SystemError::EBADF);
|
||||
@ -343,6 +351,129 @@ impl Syscall {
|
||||
// 从pcb获取文件描述符数组失败
|
||||
return Err(SystemError::EMFILE);
|
||||
}
|
||||
|
||||
/// # fcntl
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `fd`:文件描述符
|
||||
/// - `cmd`:命令
|
||||
/// - `arg`:参数
|
||||
pub fn fcntl(fd: i32, cmd: FcntlCommand, arg: i32) -> Result<usize, SystemError> {
|
||||
match cmd {
|
||||
FcntlCommand::DupFd => {
|
||||
if arg < 0 || arg as usize >= FileDescriptorVec::PROCESS_MAX_FD {
|
||||
return Err(SystemError::EBADF);
|
||||
}
|
||||
let arg = arg as usize;
|
||||
for i in arg..FileDescriptorVec::PROCESS_MAX_FD {
|
||||
if let Some(fds) = FileDescriptorVec::from_pcb(current_pcb()) {
|
||||
if fds.fds[i as usize].is_none() {
|
||||
return Self::dup2(fd, i as i32);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Err(SystemError::EMFILE);
|
||||
}
|
||||
FcntlCommand::GetFd => {
|
||||
// Get file descriptor flags.
|
||||
|
||||
if let Some(fds) = FileDescriptorVec::from_pcb(current_pcb()) {
|
||||
if FileDescriptorVec::validate_fd(fd) {
|
||||
if let Some(file) = &fds.fds[fd as usize] {
|
||||
if file.close_on_exec() {
|
||||
return Ok(FD_CLOEXEC as usize);
|
||||
}
|
||||
}
|
||||
return Err(SystemError::EBADF);
|
||||
}
|
||||
}
|
||||
return Err(SystemError::EBADF);
|
||||
}
|
||||
FcntlCommand::SetFd => {
|
||||
// Set file descriptor flags.
|
||||
if let Some(fds) = FileDescriptorVec::from_pcb(current_pcb()) {
|
||||
if FileDescriptorVec::validate_fd(fd) {
|
||||
if let Some(file) = &mut fds.fds[fd as usize] {
|
||||
let arg = arg as u32;
|
||||
if arg & FD_CLOEXEC != 0 {
|
||||
file.set_close_on_exec(true);
|
||||
} else {
|
||||
file.set_close_on_exec(false);
|
||||
}
|
||||
return Ok(0);
|
||||
}
|
||||
return Err(SystemError::EBADF);
|
||||
}
|
||||
}
|
||||
return Err(SystemError::EBADF);
|
||||
}
|
||||
|
||||
FcntlCommand::GetFlags => {
|
||||
// Get file status flags.
|
||||
if let Some(fds) = FileDescriptorVec::from_pcb(current_pcb()) {
|
||||
if FileDescriptorVec::validate_fd(fd) {
|
||||
if let Some(file) = &fds.fds[fd as usize] {
|
||||
return Ok(file.mode().bits() as usize);
|
||||
}
|
||||
return Err(SystemError::EBADF);
|
||||
}
|
||||
}
|
||||
return Err(SystemError::EBADF);
|
||||
}
|
||||
FcntlCommand::SetFlags => {
|
||||
// Set file status flags.
|
||||
if let Some(fds) = FileDescriptorVec::from_pcb(current_pcb()) {
|
||||
if FileDescriptorVec::validate_fd(fd) {
|
||||
if let Some(file) = &mut fds.fds[fd as usize] {
|
||||
let arg = arg as u32;
|
||||
let mode = FileMode::from_bits(arg).ok_or(SystemError::EINVAL)?;
|
||||
file.set_mode(mode)?;
|
||||
return Ok(0);
|
||||
}
|
||||
return Err(SystemError::EBADF);
|
||||
}
|
||||
}
|
||||
return Err(SystemError::EBADF);
|
||||
}
|
||||
_ => {
|
||||
// TODO: unimplemented
|
||||
// 未实现的命令,返回0,不报错。
|
||||
|
||||
// kwarn!("fcntl: unimplemented command: {:?}, defaults to 0.", cmd);
|
||||
return Ok(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// # ftruncate
|
||||
///
|
||||
/// ## 描述
|
||||
///
|
||||
/// 改变文件大小.
|
||||
/// 如果文件大小大于原来的大小,那么文件的内容将会被扩展到指定的大小,新的空间将会用0填充.
|
||||
/// 如果文件大小小于原来的大小,那么文件的内容将会被截断到指定的大小.
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `fd`:文件描述符
|
||||
/// - `len`:文件大小
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// 如果成功,返回0,否则返回错误码.
|
||||
pub fn ftruncate(fd: i32, len: usize) -> Result<usize, SystemError> {
|
||||
if let Some(fds) = FileDescriptorVec::from_pcb(current_pcb()) {
|
||||
if FileDescriptorVec::validate_fd(fd) {
|
||||
if let Some(file) = &mut fds.fds[fd as usize] {
|
||||
let r = file.ftruncate(len).map(|_| 0);
|
||||
return r;
|
||||
}
|
||||
return Err(SystemError::EBADF);
|
||||
}
|
||||
}
|
||||
return Err(SystemError::EBADF);
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
@ -93,7 +93,6 @@ impl ElfLoader {
|
||||
) -> Result<(), ExecError> {
|
||||
let start = self.elf_page_start(start);
|
||||
let end = self.elf_page_align_up(end);
|
||||
// kdebug!("set_elf_brk: start={:?}, end={:?}", start, end);
|
||||
if end > start {
|
||||
let r = user_vm_guard.map_anonymous(
|
||||
start,
|
||||
@ -177,9 +176,7 @@ impl ElfLoader {
|
||||
let beginning_page_offset = self.elf_page_offset(addr_to_map);
|
||||
addr_to_map = self.elf_page_start(addr_to_map);
|
||||
// 计算要映射的内存的大小
|
||||
let map_size = phent.p_filesz as usize
|
||||
+ self.elf_page_offset(VirtAddr::new(phent.p_vaddr as usize))
|
||||
+ beginning_page_offset;
|
||||
let map_size = phent.p_filesz as usize + beginning_page_offset;
|
||||
let map_size = self.elf_page_align_up(VirtAddr::new(map_size)).data();
|
||||
// 当前段在文件中的大小
|
||||
let seg_in_file_size = phent.p_filesz as usize;
|
||||
|
@ -72,6 +72,13 @@ impl Syscall {
|
||||
let address_space = AddressSpace::current()?;
|
||||
let mut address_space = address_space.write();
|
||||
|
||||
if new_addr < address_space.brk_start || new_addr >= MMArch::USER_END_VADDR {
|
||||
return Ok(address_space.brk);
|
||||
}
|
||||
if new_addr == address_space.brk {
|
||||
return Ok(address_space.brk);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
address_space
|
||||
.set_brk(VirtAddr::new(page_align_up(new_addr.data())))
|
||||
|
@ -9,6 +9,7 @@ use crate::{
|
||||
arch::{cpu::cpu_reset, MMArch},
|
||||
filesystem::syscall::PosixKstat,
|
||||
filesystem::vfs::{
|
||||
fcntl::FcntlCommand,
|
||||
file::FileMode,
|
||||
syscall::{SEEK_CUR, SEEK_END, SEEK_MAX, SEEK_SET},
|
||||
MAX_PATHLEN,
|
||||
@ -363,9 +364,18 @@ pub const SYS_GETPEERNAME: usize = 42;
|
||||
pub const SYS_GETTIMEOFDAY: usize = 43;
|
||||
pub const SYS_MMAP: usize = 44;
|
||||
pub const SYS_MUNMAP: usize = 45;
|
||||
pub const SYS_MPROTECT: usize = 46;
|
||||
|
||||
pub const SYS_MPROTECT: usize = 46;
|
||||
pub const SYS_FSTAT: usize = 47;
|
||||
#[allow(dead_code)]
|
||||
pub const SYS_GETCWD: usize = 48;
|
||||
#[allow(dead_code)]
|
||||
pub const SYS_GETPPID: usize = 49;
|
||||
#[allow(dead_code)]
|
||||
pub const SYS_GETPGID: usize = 50;
|
||||
|
||||
pub const SYS_FCNTL: usize = 51;
|
||||
pub const SYS_FTRUNCATE: usize = 52;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Syscall;
|
||||
@ -413,7 +423,7 @@ impl Syscall {
|
||||
|
||||
Self::open(path, open_flags)
|
||||
};
|
||||
// kdebug!("open: {:?}, res: {:?}", path, res);
|
||||
|
||||
res
|
||||
}
|
||||
SYS_CLOSE => {
|
||||
@ -433,9 +443,10 @@ impl Syscall {
|
||||
let buf: &mut [u8] = unsafe {
|
||||
core::slice::from_raw_parts_mut::<'static, u8>(buf_vaddr as *mut u8, len)
|
||||
};
|
||||
|
||||
Self::read(fd, buf)
|
||||
};
|
||||
|
||||
// kdebug!("sys read, fd: {}, len: {}, res: {:?}", fd, len, res);
|
||||
res
|
||||
}
|
||||
SYS_WRITE => {
|
||||
@ -451,9 +462,12 @@ impl Syscall {
|
||||
let buf: &[u8] = unsafe {
|
||||
core::slice::from_raw_parts::<'static, u8>(buf_vaddr as *const u8, len)
|
||||
};
|
||||
|
||||
Self::write(fd, buf)
|
||||
};
|
||||
|
||||
// kdebug!("sys write, fd: {}, len: {}, res: {:?}", fd, len, res);
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
@ -476,6 +490,7 @@ impl Syscall {
|
||||
let w = w.unwrap();
|
||||
Self::lseek(fd, w)
|
||||
};
|
||||
// kdebug!("sys lseek, fd: {}, offset: {}, whence: {}, res: {:?}", fd, offset, whence, res);
|
||||
|
||||
res
|
||||
}
|
||||
@ -674,6 +689,7 @@ impl Syscall {
|
||||
if pathname.is_err() {
|
||||
Err(pathname.unwrap_err())
|
||||
} else {
|
||||
// kdebug!("sys unlinkat: dirfd: {}, pathname: {}", dirfd, pathname.as_ref().unwrap());
|
||||
Self::unlinkat(dirfd, pathname.unwrap(), flags)
|
||||
}
|
||||
}
|
||||
@ -952,6 +968,29 @@ impl Syscall {
|
||||
}
|
||||
}
|
||||
|
||||
SYS_FCNTL => {
|
||||
let fd = args[0] as i32;
|
||||
let cmd: Option<FcntlCommand> =
|
||||
<FcntlCommand as FromPrimitive>::from_u32(args[1] as u32);
|
||||
let arg = args[2] as i32;
|
||||
let res = if let Some(cmd) = cmd {
|
||||
Self::fcntl(fd, cmd, arg)
|
||||
} else {
|
||||
Err(SystemError::EINVAL)
|
||||
};
|
||||
|
||||
// kdebug!("FCNTL: fd: {}, cmd: {:?}, arg: {}, res: {:?}", fd, cmd, arg, res);
|
||||
res
|
||||
}
|
||||
|
||||
SYS_FTRUNCATE => {
|
||||
let fd = args[0] as i32;
|
||||
let len = args[1] as usize;
|
||||
let res = Self::ftruncate(fd, len);
|
||||
// kdebug!("FTRUNCATE: fd: {}, len: {}, res: {:?}", fd, len, res);
|
||||
res
|
||||
}
|
||||
|
||||
_ => panic!("Unsupported syscall ID: {}", syscall_num),
|
||||
};
|
||||
|
||||
|
@ -48,14 +48,17 @@ ifneq ($(shell printf '%s\n%s' "$(DADK_VERSION)" "$(MIN_DADK_VERSION)" | sort -V
|
||||
endif
|
||||
endif
|
||||
|
||||
.PHONY: dadk_run
|
||||
dadk_run: install_dadk
|
||||
mkdir -p $(DADK_CACHE_DIR)
|
||||
# 之所以在这里临时设置ARCH为空,是因为如果要设置这个环境变量,应当在DADK的配置文件中设置
|
||||
ARCH= dadk --config-dir dadk/config --cache-dir $(DADK_CACHE_DIR) --dragonos-dir $(ROOT_PATH)/bin/sysroot build
|
||||
ARCH= dadk --config-dir dadk/config --cache-dir $(DADK_CACHE_DIR) --dragonos-dir $(ROOT_PATH)/bin/sysroot install
|
||||
|
||||
.PHONY: dadk_clean
|
||||
dadk_clean: install_dadk
|
||||
dadk --config-dir dadk/config --cache-dir $(DADK_CACHE_DIR) --dragonos-dir $(ROOT_PATH)/bin/sysroot clean
|
||||
dadk --config-dir dadk/config --cache-dir $(DADK_CACHE_DIR) --dragonos-dir $(ROOT_PATH)/bin/sysroot clean src
|
||||
dadk --config-dir dadk/config --cache-dir $(DADK_CACHE_DIR) --dragonos-dir $(ROOT_PATH)/bin/sysroot clean target
|
||||
|
||||
$(user_sub_dirs): ECHO sys_api_lib
|
||||
|
||||
@ -99,6 +102,7 @@ sys_api_lib: sys_api_lib_stage_1
|
||||
$(shell cp -r $(ROOT_PATH)/user/libs/libc/src/include/export/* $(OLD_LIBC_INSTALL_PATH)/include/)
|
||||
$(shell cp -r $(ROOT_PATH)/user/libs/libc/src/arch/x86_64/c*.o $(OLD_LIBC_INSTALL_PATH)/lib/)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(GARBAGE)
|
||||
$(MAKE) dadk_clean
|
||||
|
2
user/apps/test_sqlite3/.gitignore
vendored
Normal file
2
user/apps/test_sqlite3/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
sqlite*.zip
|
||||
sqlite-*/
|
44
user/apps/test_sqlite3/Makefile
Normal file
44
user/apps/test_sqlite3/Makefile
Normal file
@ -0,0 +1,44 @@
|
||||
CC=$(DragonOS_GCC)/x86_64-elf-gcc
|
||||
LD=ld
|
||||
OBJCOPY=objcopy
|
||||
SQLITE_FILENAME=sqlite-amalgamation-3420000
|
||||
SQLITE3_DIR=$(shell pwd)/$(SQLITE_FILENAME)
|
||||
|
||||
RELIBC_OPT=$(DADK_BUILD_CACHE_DIR_RELIBC_0_1_0)
|
||||
CFLAGS=-I $(RELIBC_OPT)/include -I $(SQLITE3_DIR) -D__dragonos__ -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_FLOATING_POINT -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_DEBUG
|
||||
|
||||
tmp_output_dir=$(ROOT_PATH)/bin/tmp/user
|
||||
output_dir=$(DADK_BUILD_CACHE_DIR_TEST_SQLITE3_3_42_0)
|
||||
|
||||
LIBC_OBJS:=$(shell find $(RELIBC_OPT)/lib -name "*.o" | sort )
|
||||
LIBC_OBJS+=$(RELIBC_OPT)/lib/libc.a
|
||||
|
||||
.PHONY: all clean download_sqlite3 __download_sqlite3
|
||||
|
||||
|
||||
all: main.o sqlite3.o
|
||||
mkdir -p $(tmp_output_dir)
|
||||
|
||||
$(LD) -b elf64-x86-64 -z muldefs -o $(tmp_output_dir)/test_sqlite3 $(shell find . -name "*.o") $(LIBC_OBJS)
|
||||
|
||||
$(OBJCOPY) -I elf64-x86-64 -R ".eh_frame" -R ".comment" -O elf64-x86-64 $(tmp_output_dir)/test_sqlite3 $(output_dir)/test_sqlite3.elf
|
||||
mv $(output_dir)/test_sqlite3.elf $(output_dir)/test_sqlite3
|
||||
|
||||
main.o: main.c
|
||||
$(CC) $(CFLAGS) -c main.c -o main.o
|
||||
|
||||
sqlite3.o: $(SQLITE3_DIR)/sqlite3.c
|
||||
$(CC) $(CFLAGS) -c $(SQLITE3_DIR)/sqlite3.c -o sqlite3.o
|
||||
|
||||
__download_sqlite3:
|
||||
@echo "Download sqlite3 from https://mirrors.ringotek.cn/pub/third_party/sqlite/$(SQLITE_FILENAME).zip"
|
||||
@wget https://mirrors.ringotek.cn/pub/third_party/sqlite/$(SQLITE_FILENAME).zip || (@echo "Download sqlite3 failed" && rm $(SQLITE_FILENAME).zip && exit 1)
|
||||
@unzip -o $(SQLITE_FILENAME).zip || (@echo "Unzip sqlite3 failed" && exit 1)
|
||||
@rm $(SQLITE_FILENAME).zip || (@echo "Remove $(SQLITE_FILENAME).zip failed" && exit 1)
|
||||
|
||||
download_sqlite3:
|
||||
# 如果文件夹不存在,则下载,否则不下载
|
||||
@test -d $(SQLITE3_DIR) || $(MAKE) __download_sqlite3
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
99
user/apps/test_sqlite3/main.c
Normal file
99
user/apps/test_sqlite3/main.c
Normal file
@ -0,0 +1,99 @@
|
||||
// This is a test program for sqlite3.
|
||||
// We take it from rcore-os/arceos, thanks to @rcore-os community.
|
||||
#include <sqlite3.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int callback(void *NotUsed, int argc, char **argv, char **azColName)
|
||||
{
|
||||
NotUsed = NULL;
|
||||
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
printf("%s = %s\n", azColName[i], (argv[i] ? argv[i] : "NULL"));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void exec(sqlite3 *db, char *sql)
|
||||
{
|
||||
printf("sqlite exec:\n %s\n", sql);
|
||||
char *errmsg = NULL;
|
||||
int rc = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
|
||||
if (rc != SQLITE_OK) {
|
||||
printf("sqlite exec error: %s\n", errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
void query(sqlite3 *db, char *sql)
|
||||
{
|
||||
printf("sqlite query:\n %s\n", sql);
|
||||
char *errmsg = NULL;
|
||||
int rc = sqlite3_exec(db, sql, callback, NULL, &errmsg);
|
||||
|
||||
if (rc != SQLITE_OK) {
|
||||
printf("%s\n", errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
void query_test(sqlite3 *db, const char *args)
|
||||
{
|
||||
puts("======== init user table ========");
|
||||
exec(db, "create table user("
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
|
||||
"username TEXT,"
|
||||
"password TEXT"
|
||||
")");
|
||||
|
||||
puts("======== insert user 1, 2, 3 into user table ========");
|
||||
|
||||
char cmd[256] = {0};
|
||||
sprintf(cmd,
|
||||
"insert into user (username, password) VALUES ('%s_1', 'password1'), ('%s_2', "
|
||||
"'password2'), ('%s_3', 'password3')",
|
||||
args, args, args);
|
||||
exec(db, cmd);
|
||||
|
||||
puts("======== select all ========");
|
||||
query(db, "select * from user");
|
||||
|
||||
puts("======== select id = 2 ========");
|
||||
query(db, "select * from user where id = 2");
|
||||
}
|
||||
|
||||
void memory()
|
||||
{
|
||||
sqlite3 *db;
|
||||
printf("sqlite open memory\n");
|
||||
int ret = sqlite3_open(":memory:", &db);
|
||||
printf("sqlite open memory status %d \n", ret);
|
||||
|
||||
query_test(db, "memory");
|
||||
}
|
||||
|
||||
void file()
|
||||
{
|
||||
sqlite3 *db;
|
||||
int ret = sqlite3_open("file.sqlite", &db);
|
||||
printf("sqlite open /file.sqlite status %d \n", ret);
|
||||
|
||||
if (ret != 0) {
|
||||
printf("sqlite open error");
|
||||
return;
|
||||
}
|
||||
|
||||
query_test(db, "file");
|
||||
sqlite3_close(db);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("sqlite version: %s\n", sqlite3_libversion());
|
||||
|
||||
memory();
|
||||
file();
|
||||
return 0;
|
||||
}
|
28
user/dadk/config/test_sqlite3-3.42.0.dadk
Normal file
28
user/dadk/config/test_sqlite3-3.42.0.dadk
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "test_sqlite3",
|
||||
"version": "3.42.0",
|
||||
"description": "测试sqlite3",
|
||||
"task_type": {
|
||||
"BuildFromSource": {
|
||||
"Local": {
|
||||
"path": "apps/test_sqlite3"
|
||||
}
|
||||
}
|
||||
},
|
||||
"depends": [
|
||||
{
|
||||
"name": "relibc",
|
||||
"version": "0.1.0"
|
||||
}
|
||||
],
|
||||
"build": {
|
||||
"build_command": "make download_sqlite3 && make -j $(nproc)"
|
||||
},
|
||||
"install": {
|
||||
"in_dragonos_path": "/bin"
|
||||
},
|
||||
"clean": {
|
||||
"clean_command": "make clean"
|
||||
},
|
||||
"envs": []
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user