Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions src/bin/edit/documents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand All @@ -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);
}

Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/bin/edit/draw_filepicker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
11 changes: 0 additions & 11 deletions src/sys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@

//! Platform abstractions.

use std::fs::File;
use std::path::Path;

use crate::apperr;

#[cfg(unix)]
mod unix;
#[cfg(windows)]
Expand All @@ -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<FileId> {
let file = File::open(path)?;
let file_id = file_id(&file)?;
Ok(file_id)
}
10 changes: 8 additions & 2 deletions src/sys/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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<FileId> {
/// Returns a unique identifier for the given file by handle or path.
pub fn file_id(file: Option<&File>, path: &Path) -> apperr::Result<FileId> {
let file = match file {
Some(f) => f,
None => &File::open(path)?,
};

unsafe {
let mut stat = MaybeUninit::<libc::stat>::uninit();
check_int_return(libc::fstat(file.as_raw_fd(), stat.as_mut_ptr()))?;
Expand Down
38 changes: 27 additions & 11 deletions src/sys/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,24 +398,40 @@ pub fn open_stdin_if_redirected() -> Option<File> {
}

/// 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::<FileSystem::FILE_ID_INFO>();
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::<FileSystem::FILE_ID_INFO>();
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<FileId> {
/// Returns a unique identifier for the given file by handle or path.
pub fn file_id(file: Option<&File>, path: &Path) -> apperr::Result<FileId> {
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<FileId> {
unsafe {
let mut info = MaybeUninit::<FileSystem::FILE_ID_INFO>::uninit();
check_bool_return(FileSystem::GetFileInformationByHandleEx(
Expand All @@ -424,7 +440,7 @@ pub fn file_id(file: &File) -> apperr::Result<FileId> {
info.as_mut_ptr() as *mut _,
mem::size_of::<FileSystem::FILE_ID_INFO>() as u32,
))?;
Ok(FileId(info.assume_init()))
Ok(FileId::Id(info.assume_init()))
}
}

Expand Down