From fdb2208a7fb794480282211c566843d69aed20c4 Mon Sep 17 00:00:00 2001 From: lifegpc Date: Mon, 20 Jun 2022 13:52:51 +0000 Subject: [PATCH] Add set_len --- src/downloader/downloader.rs | 38 +++++++++++++++++++++++++++++----- src/downloader/local_file.rs | 22 ++++++++++++++++++-- src/downloader/pd_file/file.rs | 23 +++++++++++++++++--- src/downloader/tasks.rs | 19 ++++++++++------- 4 files changed, 85 insertions(+), 17 deletions(-) diff --git a/src/downloader/downloader.rs b/src/downloader/downloader.rs index 606fc0a..66fdf68 100644 --- a/src/downloader/downloader.rs +++ b/src/downloader/downloader.rs @@ -54,9 +54,20 @@ pub trait GetTargetFileName { } } +/// Truncates or extends the underlying file, updating the size of this file. +pub trait SetLen { + /// Truncates or extends the underlying file, updating the size of this file to become `size`. + /// + /// If the `size` is less than the current file’s size, then the file will be shrunk. + /// If it is greater than the current file’s size, then the file will be extended to `size` and have all of the intermediate data filled in with 0s. + fn set_len(&mut self, size: u64) -> Result<(), DownloaderError>; +} + #[derive(Debug)] /// A file downloader -pub struct DownloaderInternal { +pub struct DownloaderInternal< + T: Write + Seek + Send + Sync + ClearFile + GetTargetFileName + SetLen, +> { /// The webclient pub client: Arc, /// The download status @@ -185,7 +196,7 @@ impl DownloaderInternal { } } -impl DownloaderInternal { +impl DownloaderInternal { /// Add a new task to tasks /// * `task` - Task pub fn add_task(&self, task: JoinHandle>) { @@ -395,6 +406,19 @@ impl DownloaderIn self.dropped.qstore(true); } + #[inline] + /// Truncates or extends the underlying file, updating the size of this file to become `size`. + /// + /// If the `size` is less than the current file’s size, then the file will be shrunk. + /// If it is greater than the current file’s size, then the file will be extended to `size` and have all of the intermediate data filled in with 0s. + pub fn set_len(&self, size: u64) -> Result<(), DownloaderError> { + match self.file.get_mut().deref_mut() { + Some(f) => f.set_len(size)?, + None => {} + } + Ok(()) + } + #[inline] /// Set the downloader is panic and set the error. /// * `err` - Error @@ -491,7 +515,7 @@ impl DownloaderIn /// /// When dropping downloader, the downloader need some times to let all threads exited. /// This process is handled after [Drop]. -pub struct Downloader { +pub struct Downloader { /// internal type downloader: Arc>, } @@ -553,7 +577,9 @@ macro_rules! define_downloader_fn { } } -impl Downloader { +impl + Downloader +{ /// Start download if download not started. /// /// Returns the status of the Downloader @@ -703,7 +729,9 @@ impl Do define_downloader_fn!(is_panic, bool, "Returns true if the downloader is panic."); } -impl Drop for Downloader { +impl Drop + for Downloader +{ fn drop(&mut self) { self.downloader.set_dropped(); #[cfg(test)] diff --git a/src/downloader/local_file.rs b/src/downloader/local_file.rs index 24535b5..c8cc3a8 100644 --- a/src/downloader/local_file.rs +++ b/src/downloader/local_file.rs @@ -1,7 +1,9 @@ use super::downloader::GetTargetFileName; +use super::downloader::SetLen; use crate::ext::io::ClearFile; use std::fs::remove_file; use std::fs::File; +use std::fs::OpenOptions; use std::io::Seek; use std::io::Write; use std::ops::Deref; @@ -22,7 +24,12 @@ impl LocalFile { /// This function will create a file if it does not exist, and will truncate it if it does. pub fn create>(path: P) -> std::io::Result { let p = path.as_ref().to_owned(); - let f = File::create(&p)?; + let f = OpenOptions::new() + .create(true) + .read(true) + .write(true) + .truncate(true) + .open(&p)?; Ok(Self { file: Some(f), path: p, @@ -32,7 +39,11 @@ impl LocalFile { /// Attempts to open a file in read-only mode. pub fn open>(path: P) -> std::io::Result { let p = path.as_ref().to_owned(); - let f = File::open(&p)?; + let f = OpenOptions::new() + .read(true) + .write(true) + .truncate(true) + .open(&p)?; Ok(Self { file: Some(f), path: p, @@ -72,6 +83,13 @@ impl Seek for LocalFile { } } +impl SetLen for LocalFile { + fn set_len(&mut self, size: u64) -> Result<(), super::DownloaderError> { + self.file.as_ref().unwrap().set_len(size)?; + Ok(()) + } +} + impl Write for LocalFile { fn write(&mut self, buf: &[u8]) -> std::io::Result { self.file.as_ref().unwrap().write(buf) diff --git a/src/downloader/pd_file/file.rs b/src/downloader/pd_file/file.rs index 9d2720a..5393e64 100644 --- a/src/downloader/pd_file/file.rs +++ b/src/downloader/pd_file/file.rs @@ -21,6 +21,7 @@ use std::fs::create_dir; use std::fs::metadata; use std::fs::remove_file; use std::fs::File; +use std::fs::OpenOptions; use std::io::Read; use std::io::Seek; use std::io::SeekFrom; @@ -392,7 +393,11 @@ impl PdFile { /// Returns errors or a new instance. pub fn read_from_file + ?Sized>(path: &P) -> Result { let p = path.as_ref(); - let mut f = File::open(p)?; + let mut f = OpenOptions::new() + .read(true) + .write(true) + .truncate(true) + .open(p)?; f.seek(SeekFrom::Start(0))?; let mut buf = [0u8, 0, 0, 0]; f.read_exact(&mut buf)?; @@ -446,7 +451,12 @@ impl PdFile { if p.exists() { remove_file(p)?; } - let f = File::create(p)?; + let f = OpenOptions::new() + .read(true) + .write(true) + .truncate(true) + .create(true) + .open(p)?; self.file.get_mut().replace(f); self.file_path.get_mut().replace(PathBuf::from(p)); self.mem_only.qstore(false); @@ -485,7 +495,14 @@ impl PdFile { } remove_file(self.file_path.get_ref().as_ref().unwrap())?; f.take(); - f.replace(File::create(self.file_path.get_ref().as_ref().unwrap())?); + f.replace( + OpenOptions::new() + .read(true) + .write(true) + .truncate(true) + .create(true) + .open(self.file_path.get_ref().as_ref().unwrap())?, + ); Ok(()) } diff --git a/src/downloader/tasks.rs b/src/downloader/tasks.rs index faee770..5507fe8 100644 --- a/src/downloader/tasks.rs +++ b/src/downloader/tasks.rs @@ -1,5 +1,6 @@ use super::downloader::DownloaderInternal; use super::downloader::GetTargetFileName; +use super::downloader::SetLen; use super::error::DownloaderError; use super::pd_file::PdFilePartStatus; use crate::concat_error; @@ -43,7 +44,7 @@ macro_rules! check_dropped { /// Create a download tasks in simple thread mode. pub async fn create_download_tasks_simple< - T: Seek + Write + Send + Sync + ClearFile + GetTargetFileName, + T: Seek + Write + Send + Sync + ClearFile + GetTargetFileName + SetLen, >( d: Arc>, ) -> Result<(), DownloaderError> { @@ -133,6 +134,7 @@ pub async fn create_download_tasks_simple< if d.enabled_progress_bar() { d.set_progress_bar_length(len); } + d.set_len(len)?; } None => {} } @@ -147,7 +149,7 @@ pub async fn create_download_tasks_simple< /// Do first job when download in multiple mode. pub async fn create_download_tasks_multi_first< - T: Seek + Write + Send + Sync + ClearFile + GetTargetFileName, + T: Seek + Write + Send + Sync + ClearFile + GetTargetFileName + SetLen, >( d: Arc>, ) -> Result<(), DownloaderError> { @@ -185,6 +187,7 @@ pub async fn create_download_tasks_multi_first< if d.enabled_progress_bar() { d.set_progress_bar_length(len); } + d.set_len(len)?; } None => { d.fallback_to_simp(); @@ -209,7 +212,7 @@ pub async fn create_download_tasks_multi_first< /// Create a new download task in multiple thread mode. pub async fn create_download_tasks_multi< - T: Seek + Write + Send + Sync + ClearFile + GetTargetFileName, + T: Seek + Write + Send + Sync + ClearFile + GetTargetFileName + SetLen, >( d: Arc>, pd: Arc, @@ -224,7 +227,7 @@ pub async fn create_download_tasks_multi< /// Create a new download task in multiple thread mode. pub async fn create_download_tasks_multi_internal< - T: Seek + Write + Send + Sync + ClearFile + GetTargetFileName, + T: Seek + Write + Send + Sync + ClearFile + GetTargetFileName + SetLen, >( d: Arc>, pd: Arc, @@ -260,7 +263,9 @@ pub async fn create_download_tasks_multi_internal< } /// Handle download process -pub async fn handle_download( +pub async fn handle_download< + T: Seek + Write + Send + Sync + ClearFile + GetTargetFileName + SetLen, +>( d: Arc>, re: Response, pd: Option>, @@ -365,7 +370,7 @@ pub async fn handle_download( d: &Arc>, ) -> Result<(), DownloaderError> { @@ -395,7 +400,7 @@ pub async fn add_new_multi_tasks< /// Check tasks are completed or not. And create new tasks if needed. pub async fn check_tasks< - T: Seek + Write + Send + Sync + ClearFile + GetTargetFileName + 'static, + T: Seek + Write + Send + Sync + ClearFile + GetTargetFileName + SetLen + 'static, >( d: Arc>, ) -> Result<(), DownloaderError> {