From 6d81180b3b7328466b976b69c5f7782aa66d8a89 Mon Sep 17 00:00:00 2001 From: LoGin Date: Tue, 8 Aug 2023 23:39:22 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A7=BB=E6=A4=8Dsqlite3,=E5=B9=B6=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E4=B8=80=E4=BA=9Bbug=20(#323)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * bugfix: 程序加载器映射内存时,计算要映射的大小不正确的问题。 * 修正brk系统调用不符合规范的地方 * bugfix: 修正fat文件系统未能正确的扩展文件大小的bug * 增加fcntl系统调用 * 移植sqlite3 --- kernel/src/filesystem/fat/entry.rs | 51 +++++---- kernel/src/filesystem/fat/fs.rs | 42 +++++++ kernel/src/filesystem/vfs/fcntl.rs | 62 ++++++++++ kernel/src/filesystem/vfs/file.rs | 64 ++++++++++- kernel/src/filesystem/vfs/mod.rs | 4 + kernel/src/filesystem/vfs/syscall.rs | 133 +++++++++++++++++++++- kernel/src/libs/elf.rs | 5 +- kernel/src/mm/syscall.rs | 7 ++ kernel/src/syscall/mod.rs | 45 +++++++- user/Makefile | 6 +- user/apps/test_sqlite3/.gitignore | 2 + user/apps/test_sqlite3/Makefile | 44 +++++++ user/apps/test_sqlite3/main.c | 99 ++++++++++++++++ user/dadk/config/test_sqlite3-3.42.0.dadk | 28 +++++ 14 files changed, 562 insertions(+), 30 deletions(-) create mode 100644 kernel/src/filesystem/vfs/fcntl.rs create mode 100644 user/apps/test_sqlite3/.gitignore create mode 100644 user/apps/test_sqlite3/Makefile create mode 100644 user/apps/test_sqlite3/main.c create mode 100644 user/dadk/config/test_sqlite3-3.42.0.dadk diff --git a/kernel/src/filesystem/fat/entry.rs b/kernel/src/filesystem/fat/entry.rs index 53b10103..f10140a2 100644 --- a/kernel/src/filesystem/fat/entry.rs +++ b/kernel/src/filesystem/fat/entry.rs @@ -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), 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)? { diff --git a/kernel/src/filesystem/fat/fs.rs b/kernel/src/filesystem/fat/fs.rs index bf3dc90e..e0cce03c 100644 --- a/kernel/src/filesystem/fat/fs.rs +++ b/kernel/src/filesystem/fat/fs.rs @@ -350,6 +350,10 @@ impl FATFileSystem { /// @return Err(SystemError) 错误码 pub fn get_fat_entry(&self, cluster: Cluster) -> Result { 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 { return Ok(self.0.lock().metadata.clone()); } + fn resize(&self, len: usize) -> Result<(), SystemError> { + let mut guard: SpinLockGuard = self.0.lock(); + let fs: &Arc = &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 = 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, SystemError> { let mut guard: SpinLockGuard = self.0.lock(); diff --git a/kernel/src/filesystem/vfs/fcntl.rs b/kernel/src/filesystem/vfs/fcntl.rs new file mode 100644 index 00000000..94c6e46d --- /dev/null +++ b/kernel/src/filesystem/vfs/fcntl.rs @@ -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; diff --git a/kernel/src/filesystem/vfs/file.rs b/kernel/src/filesystem/vfs/file.rs index c216360c..769df7f6 100644 --- a/kernel/src/filesystem/vfs/file.rs +++ b/kernel/src/filesystem/vfs/file.rs @@ -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 { diff --git a/kernel/src/filesystem/vfs/mod.rs b/kernel/src/filesystem/vfs/mod.rs index 02793047..0e4a1c1e 100644 --- a/kernel/src/filesystem/vfs/mod.rs +++ b/kernel/src/filesystem/vfs/mod.rs @@ -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(错误码) diff --git a/kernel/src/filesystem/vfs/syscall.rs b/kernel/src/filesystem/vfs/syscall.rs index a55561ea..3c94947c 100644 --- a/kernel/src/filesystem/vfs/syscall.rs +++ b/kernel/src/filesystem/vfs/syscall.rs @@ -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 { + // 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 { + // 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 { + // 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 { + // 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 { + // 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 { + 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 { + 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)] diff --git a/kernel/src/libs/elf.rs b/kernel/src/libs/elf.rs index fe45cf52..d65f3e1f 100644 --- a/kernel/src/libs/elf.rs +++ b/kernel/src/libs/elf.rs @@ -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; diff --git a/kernel/src/mm/syscall.rs b/kernel/src/mm/syscall.rs index ef60a006..233d858a 100644 --- a/kernel/src/mm/syscall.rs +++ b/kernel/src/mm/syscall.rs @@ -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()))) diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 9aaff16d..626f92fe 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -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 = + ::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), }; diff --git a/user/Makefile b/user/Makefile index d791bea2..8e19d10f 100644 --- a/user/Makefile +++ b/user/Makefile @@ -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 diff --git a/user/apps/test_sqlite3/.gitignore b/user/apps/test_sqlite3/.gitignore new file mode 100644 index 00000000..9c2f57c4 --- /dev/null +++ b/user/apps/test_sqlite3/.gitignore @@ -0,0 +1,2 @@ +sqlite*.zip +sqlite-*/ \ No newline at end of file diff --git a/user/apps/test_sqlite3/Makefile b/user/apps/test_sqlite3/Makefile new file mode 100644 index 00000000..7d3ed8f3 --- /dev/null +++ b/user/apps/test_sqlite3/Makefile @@ -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 diff --git a/user/apps/test_sqlite3/main.c b/user/apps/test_sqlite3/main.c new file mode 100644 index 00000000..e57c18f1 --- /dev/null +++ b/user/apps/test_sqlite3/main.c @@ -0,0 +1,99 @@ +// This is a test program for sqlite3. +// We take it from rcore-os/arceos, thanks to @rcore-os community. +#include +#include +#include +#include + +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; +} diff --git a/user/dadk/config/test_sqlite3-3.42.0.dadk b/user/dadk/config/test_sqlite3-3.42.0.dadk new file mode 100644 index 00000000..5aff8398 --- /dev/null +++ b/user/dadk/config/test_sqlite3-3.42.0.dadk @@ -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": [] +}