Move files around a bit
This commit is contained in:
parent
f2ae2f67f4
commit
cd33f99352
3 changed files with 5 additions and 2 deletions
110
crates/librqbit/src/storage/filesystem/mod.rs
Normal file
110
crates/librqbit/src/storage/filesystem/mod.rs
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
mod opened_file;
|
||||
|
||||
use std::{
|
||||
fs::OpenOptions,
|
||||
io::{Read, Seek, SeekFrom, Write},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use anyhow::Context;
|
||||
|
||||
use crate::torrent_state::ManagedTorrentInfo;
|
||||
|
||||
use self::opened_file::OpenedFile;
|
||||
|
||||
use super::{StorageFactory, TorrentStorage};
|
||||
|
||||
pub struct FilesystemStorageFactory {
|
||||
pub output_folder: PathBuf,
|
||||
pub allow_overwrite: bool,
|
||||
}
|
||||
|
||||
impl StorageFactory for FilesystemStorageFactory {
|
||||
fn init_storage(&self, meta: &ManagedTorrentInfo) -> anyhow::Result<Box<dyn TorrentStorage>> {
|
||||
let mut files = Vec::<OpenedFile>::new();
|
||||
for file_details in meta.info.iter_file_details(&meta.lengths)? {
|
||||
let mut full_path = self.output_folder.clone();
|
||||
let relative_path = file_details
|
||||
.filename
|
||||
.to_pathbuf()
|
||||
.context("error converting file to path")?;
|
||||
full_path.push(relative_path);
|
||||
|
||||
std::fs::create_dir_all(full_path.parent().context("bug: no parent")?)?;
|
||||
let file = if self.allow_overwrite {
|
||||
OpenOptions::new()
|
||||
.create(true)
|
||||
.truncate(false)
|
||||
.read(true)
|
||||
.write(true)
|
||||
.open(&full_path)
|
||||
.with_context(|| format!("error opening {full_path:?} in read/write mode"))?
|
||||
} else {
|
||||
// create_new does not seem to work with read(true), so calling this twice.
|
||||
OpenOptions::new()
|
||||
.create_new(true)
|
||||
.write(true)
|
||||
.open(&full_path)
|
||||
.with_context(|| format!("error creating {:?}", &full_path))?;
|
||||
OpenOptions::new().read(true).write(true).open(&full_path)?
|
||||
};
|
||||
files.push(OpenedFile::new(file));
|
||||
}
|
||||
Ok(Box::new(FilesystemStorage {
|
||||
output_folder: self.output_folder.clone(),
|
||||
opened_files: files,
|
||||
}))
|
||||
}
|
||||
|
||||
fn output_folder(&self) -> Option<&Path> {
|
||||
Some(&self.output_folder)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FilesystemStorage {
|
||||
output_folder: PathBuf,
|
||||
opened_files: Vec<OpenedFile>,
|
||||
}
|
||||
|
||||
impl TorrentStorage for FilesystemStorage {
|
||||
fn pread_exact(&self, file_id: usize, offset: u64, buf: &mut [u8]) -> anyhow::Result<()> {
|
||||
let mut g = self
|
||||
.opened_files
|
||||
.get(file_id)
|
||||
.context("no such file")?
|
||||
.file
|
||||
.lock();
|
||||
g.seek(SeekFrom::Start(offset))?;
|
||||
Ok(g.read_exact(buf)?)
|
||||
}
|
||||
|
||||
fn pwrite_all(&self, file_id: usize, offset: u64, buf: &[u8]) -> anyhow::Result<()> {
|
||||
let mut g = self
|
||||
.opened_files
|
||||
.get(file_id)
|
||||
.context("no such file")?
|
||||
.file
|
||||
.lock();
|
||||
g.seek(SeekFrom::Start(offset))?;
|
||||
Ok(g.write_all(buf)?)
|
||||
}
|
||||
|
||||
fn remove_file(&self, _file_id: usize, filename: &Path) -> anyhow::Result<()> {
|
||||
Ok(std::fs::remove_file(self.output_folder.join(filename))?)
|
||||
}
|
||||
|
||||
fn ensure_file_length(&self, file_id: usize, len: u64) -> anyhow::Result<()> {
|
||||
Ok(self.opened_files[file_id].file.lock().set_len(len)?)
|
||||
}
|
||||
|
||||
fn take(&self) -> anyhow::Result<Box<dyn TorrentStorage>> {
|
||||
Ok(Box::new(Self {
|
||||
opened_files: self
|
||||
.opened_files
|
||||
.iter()
|
||||
.map(|f| f.take_clone())
|
||||
.collect::<anyhow::Result<Vec<_>>>()?,
|
||||
output_folder: self.output_folder.clone(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
43
crates/librqbit/src/storage/filesystem/opened_file.rs
Normal file
43
crates/librqbit/src/storage/filesystem/opened_file.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
use std::fs::File;
|
||||
|
||||
use anyhow::Context;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct OpenedFile {
|
||||
pub file: Mutex<File>,
|
||||
}
|
||||
|
||||
pub(crate) fn dummy_file() -> anyhow::Result<std::fs::File> {
|
||||
#[cfg(target_os = "windows")]
|
||||
const DEVNULL: &str = "NUL";
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
const DEVNULL: &str = "/dev/null";
|
||||
|
||||
std::fs::OpenOptions::new()
|
||||
.read(true)
|
||||
.open(DEVNULL)
|
||||
.with_context(|| format!("error opening {}", DEVNULL))
|
||||
}
|
||||
|
||||
impl OpenedFile {
|
||||
pub fn new(f: File) -> Self {
|
||||
Self {
|
||||
file: Mutex::new(f),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn take(&self) -> anyhow::Result<File> {
|
||||
let mut f = self.file.lock();
|
||||
let dummy = dummy_file()?;
|
||||
let f = std::mem::replace(&mut *f, dummy);
|
||||
Ok(f)
|
||||
}
|
||||
|
||||
pub fn take_clone(&self) -> anyhow::Result<Self> {
|
||||
let f = self.take()?;
|
||||
Ok(Self {
|
||||
file: Mutex::new(f),
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue