diff --git a/src/bin/edit/documents.rs b/src/bin/edit/documents.rs index 349f4f389e77..7e0da29537ab 100644 --- a/src/bin/edit/documents.rs +++ b/src/bin/edit/documents.rs @@ -32,7 +32,7 @@ impl Document { tb.write_file(&mut file)?; } - if let Ok(id) = sys::file_id(&file) { + if let Ok(id) = sys::file_id(None, path) { self.file_id = Some(id); } @@ -52,7 +52,7 @@ impl Document { tb.read_file(&mut file, encoding)?; } - if let Ok(id) = sys::file_id(&file) { + if let Ok(id) = sys::file_id(None, path) { self.file_id = Some(id); } @@ -156,13 +156,10 @@ impl DocumentManager { Err(err) => return Err(err), }; - let file_id = match &file { - Some(file) => Some(sys::file_id(file)?), - None => None, - }; + let file_id = Some(sys::file_id(file.as_ref(), &path)?); // Check if the file is already open. - if file_id.is_some() && self.update_active(|doc| doc.file_id == file_id) { + if self.update_active(|doc| doc.file_id == file_id) { let doc = self.active_mut().unwrap(); if let Some(goto) = goto { doc.buffer.borrow_mut().cursor_move_to_logical(goto); diff --git a/src/bin/edit/draw_filepicker.rs b/src/bin/edit/draw_filepicker.rs index 79733d1e14a5..d5b8ebb4ee7d 100644 --- a/src/bin/edit/draw_filepicker.rs +++ b/src/bin/edit/draw_filepicker.rs @@ -116,7 +116,7 @@ pub fn draw_file_picker(ctx: &mut Context, state: &mut State) { && let Some(path) = doit.as_deref() && let Some(doc) = state.documents.active() && let Some(file_id) = &doc.file_id - && sys::file_id_at(path).is_ok_and(|id| &id == file_id) + && sys::file_id(None, path).is_ok_and(|id| &id == file_id) { state.file_picker_overwrite_warning = doit.take(); } diff --git a/src/sys/mod.rs b/src/sys/mod.rs index f5305c05f3be..91d598812484 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -3,11 +3,6 @@ //! Platform abstractions. -use std::fs::File; -use std::path::Path; - -use crate::apperr; - #[cfg(unix)] mod unix; #[cfg(windows)] @@ -20,9 +15,3 @@ pub use std::fs::canonicalize; pub use unix::*; #[cfg(windows)] pub use windows::*; - -pub fn file_id_at(path: &Path) -> apperr::Result { - let file = File::open(path)?; - let file_id = file_id(&file)?; - Ok(file_id) -} diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 826a0d33a78c..b660357905d7 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -10,6 +10,7 @@ use std::ffi::{CStr, c_int, c_void}; use std::fs::{self, File}; use std::mem::{self, ManuallyDrop, MaybeUninit}; use std::os::fd::{AsRawFd as _, FromRawFd as _}; +use std::path::Path; use std::ptr::{self, NonNull, null_mut}; use std::{thread, time}; @@ -350,8 +351,13 @@ pub struct FileId { st_ino: libc::ino_t, } -/// Returns a unique identifier for the given file. -pub fn file_id(file: &File) -> apperr::Result { +/// Returns a unique identifier for the given file by handle or path. +pub fn file_id(file: Option<&File>, path: &Path) -> apperr::Result { + let file = match file { + Some(f) => f, + None => &File::open(path)?, + }; + unsafe { let mut stat = MaybeUninit::::uninit(); check_int_return(libc::fstat(file.as_raw_fd(), stat.as_mut_ptr()))?; diff --git a/src/sys/windows.rs b/src/sys/windows.rs index 952ca4743782..e4f20b0e64a0 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -398,24 +398,40 @@ pub fn open_stdin_if_redirected() -> Option { } /// A unique identifier for a file. -#[derive(Clone)] -#[repr(transparent)] -pub struct FileId(FileSystem::FILE_ID_INFO); +pub enum FileId { + Id(FileSystem::FILE_ID_INFO), + Path(PathBuf), +} impl PartialEq for FileId { fn eq(&self, other: &Self) -> bool { - // Lowers to an efficient word-wise comparison. - const SIZE: usize = std::mem::size_of::(); - let a: &[u8; SIZE] = unsafe { mem::transmute(&self.0) }; - let b: &[u8; SIZE] = unsafe { mem::transmute(&other.0) }; - a == b + match (self, other) { + (FileId::Id(left), FileId::Id(right)) => { + // Lowers to an efficient word-wise comparison. + const SIZE: usize = std::mem::size_of::(); + let a: &[u8; SIZE] = unsafe { mem::transmute(left) }; + let b: &[u8; SIZE] = unsafe { mem::transmute(right) }; + a == b + } + (FileId::Path(left), FileId::Path(right)) => left == right, + _ => false, + } } } impl Eq for FileId {} -/// Returns a unique identifier for the given file. -pub fn file_id(file: &File) -> apperr::Result { +/// Returns a unique identifier for the given file by handle or path. +pub fn file_id(file: Option<&File>, path: &Path) -> apperr::Result { + let file = match file { + Some(f) => f, + None => &File::open(path)?, + }; + + file_id_from_handle(file).or_else(|_| Ok(FileId::Path(std::fs::canonicalize(path)?))) +} + +fn file_id_from_handle(file: &File) -> apperr::Result { unsafe { let mut info = MaybeUninit::::uninit(); check_bool_return(FileSystem::GetFileInformationByHandleEx( @@ -424,7 +440,7 @@ pub fn file_id(file: &File) -> apperr::Result { info.as_mut_ptr() as *mut _, mem::size_of::() as u32, ))?; - Ok(FileId(info.assume_init())) + Ok(FileId::Id(info.assume_init())) } }