Try to workaround #17 - windows not letting to open the file while rqbit has it

This commit is contained in:
Igor Katson 2023-07-10 12:18:08 +01:00
parent a800048b7e
commit e1a3f86a24
No known key found for this signature in database
GPG key ID: B4EC22B66D61A3F5
2 changed files with 39 additions and 3 deletions

View file

@ -173,10 +173,10 @@ impl TorrentManager {
options: Option<TorrentManagerOptions>,
) -> anyhow::Result<TorrentManagerHandle> {
let options = options.unwrap_or_default();
let files = {
let (files, filenames) = {
let mut files =
Vec::<Arc<Mutex<File>>>::with_capacity(info.iter_file_lengths()?.count());
let mut filenames = Vec::new();
for (path_bits, _) in info.iter_filenames_and_lengths()? {
let mut full_path = out.as_ref().to_owned();
let relative_path = path_bits
@ -200,9 +200,10 @@ impl TorrentManager {
.with_context(|| format!("error creating {:?}", &full_path))?;
OpenOptions::new().read(true).write(true).open(&full_path)?
};
filenames.push(full_path);
files.push(Arc::new(Mutex::new(file)))
}
files
(files, filenames)
};
let peer_id = options.peer_id.unwrap_or_else(generate_peer_id);
@ -270,6 +271,7 @@ impl TorrentManager {
info_hash,
peer_id,
files,
filenames,
chunk_tracker,
lengths,
initial_check_results.have_bytes,

View file

@ -2,6 +2,7 @@ use std::{
collections::{HashMap, HashSet},
fs::File,
net::SocketAddr,
path::PathBuf,
sync::{
atomic::{AtomicU64, Ordering},
Arc,
@ -232,6 +233,7 @@ pub struct TorrentState {
info: TorrentMetaV1Info<ByteString>,
locked: Arc<RwLock<TorrentStateLocked>>,
files: Vec<Arc<Mutex<File>>>,
filenames: Vec<PathBuf>,
info_hash: Id20,
peer_id: Id20,
lengths: Lengths,
@ -253,6 +255,7 @@ impl TorrentState {
info_hash: Id20,
peer_id: Id20,
files: Vec<Arc<Mutex<File>>>,
filenames: Vec<PathBuf>,
chunk_tracker: ChunkTracker,
lengths: Lengths,
have_bytes: u64,
@ -271,6 +274,7 @@ impl TorrentState {
chunks: chunk_tracker,
})),
files,
filenames,
stats: AtomicStats {
have: AtomicU64::new(have_bytes),
..Default::default()
@ -894,6 +898,35 @@ impl PeerHandler {
}
}
fn reopen_read_only(&self) -> anyhow::Result<()> {
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))
}
for (file, filename) in self.state.files.iter().zip(self.state.filenames.iter()) {
let mut g = file.lock();
// this should close the original file
// putting in a block just in case to guarantee drop.
{
*g = dummy_file()?;
}
*g = std::fs::OpenOptions::new()
.read(true)
.open(filename)
.with_context(|| format!("error re-opening {:?} readonly", filename))?;
debug!("reopened {:?} read-only", filename);
}
Ok(())
}
fn on_i_am_unchoked(&self, handle: PeerHandle) {
debug!("we are unchoked by {}", handle);
let mut g = self.state.locked.write();
@ -1032,6 +1065,7 @@ impl PeerHandler {
if self.state.get_left_to_download() == 0 {
self.state.finished_notify.notify_waiters();
self.reopen_read_only()?;
}
self.state.maybe_transmit_haves(chunk_info.piece_index);