From 5344875c96c085833bfd79a591d76bc6219acc4b Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Tue, 20 May 2025 21:35:34 -0500 Subject: [PATCH 1/9] Allow a file path to act as an ID --- src/bin/edit/documents.rs | 19 ++++++++++--------- src/sys/mod.rs | 13 +------------ src/sys/unix.rs | 9 ++++++++- src/sys/windows.rs | 38 ++++++++++++++++++++++++++++---------- 4 files changed, 47 insertions(+), 32 deletions(-) diff --git a/src/bin/edit/documents.rs b/src/bin/edit/documents.rs index 349f4f389e7..056507d8030 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_at(&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_at(&path) { self.file_id = Some(id); } @@ -150,17 +150,12 @@ impl DocumentManager { let (path, goto) = Self::parse_filename_goto(path); let path = path::normalize(path); - let mut file = match Self::open_for_reading(&path) { - Ok(file) => Some(file), + let file_id = match sys::file_id_at(&path) { + Ok(id) => Some(id), Err(err) if sys::apperr_is_not_found(err) => None, Err(err) => return Err(err), }; - let file_id = match &file { - Some(file) => Some(sys::file_id(file)?), - None => None, - }; - // Check if the file is already open. if file_id.is_some() && self.update_active(|doc| doc.file_id == file_id) { let doc = self.active_mut().unwrap(); @@ -170,6 +165,12 @@ impl DocumentManager { return Ok(doc); } + let mut file = match Self::open_for_reading(&path) { + Ok(file) => Some(file), + Err(err) if sys::apperr_is_not_found(err) => None, + Err(err) => return Err(err), + }; + let buffer = TextBuffer::new_rc(false)?; { let mut tb = buffer.borrow_mut(); diff --git a/src/sys/mod.rs b/src/sys/mod.rs index f5305c05f3b..94e1c56a503 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)] @@ -19,10 +14,4 @@ pub use std::fs::canonicalize; #[cfg(unix)] 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) -} +pub use windows::*; \ No newline at end of file diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 826a0d33a78..0bb27e9cff3 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -350,7 +350,7 @@ pub struct FileId { st_ino: libc::ino_t, } -/// Returns a unique identifier for the given file. +/// Returns a unique identifier for the given file, by handle. pub fn file_id(file: &File) -> apperr::Result { unsafe { let mut stat = MaybeUninit::::uninit(); @@ -360,6 +360,13 @@ pub fn file_id(file: &File) -> apperr::Result { } } +/// Returns a unique identifier for the given file, by path. +pub fn file_id_at(path: &Path) -> apperr::Result { + let file = File::open(path)?; + let file_id = file_id(&file)?; + Ok(file_id) +} + /// Reserves a virtual memory region of the given size. /// To commit the memory, use `virtual_commit`. /// To release the memory, use `virtual_release`. diff --git a/src/sys/windows.rs b/src/sys/windows.rs index 952ca474378..d7266186b43 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -398,23 +398,30 @@ 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. +/// Returns a unique identifier for the given file, by open handle. pub fn file_id(file: &File) -> apperr::Result { unsafe { let mut info = MaybeUninit::::uninit(); @@ -424,7 +431,18 @@ 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())) + } +} + +/// Returns a unique identifier for the given file, by path. +pub fn file_id_at(path: &Path) -> apperr::Result { + let file = File::open(path)?; + match file_id(&file) { + Ok(v) => Ok(v), + // Propagate file not found + Err(err) if apperr_is_not_found(err) => Err(err), + Err(_) => Ok(FileId::Path(path.to_path_buf())), } } From 021a5f798d5251d3789ce2c8f3faca500eb68541 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Tue, 20 May 2025 21:55:31 -0500 Subject: [PATCH 2/9] Try another approach --- src/bin/edit/documents.rs | 18 +++++++++--------- src/bin/edit/draw_filepicker.rs | 3 +-- src/sys/unix.rs | 22 +++++++++++++++------- src/sys/windows.rs | 26 +++++++++++++++++--------- 4 files changed, 42 insertions(+), 27 deletions(-) diff --git a/src/bin/edit/documents.rs b/src/bin/edit/documents.rs index 056507d8030..1665dd5b1ff 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_at(&path) { + if let Ok(id) = sys::file_id(&None, &Some(path.to_path_buf())) { self.file_id = Some(id); } @@ -52,7 +52,7 @@ impl Document { tb.read_file(&mut file, encoding)?; } - if let Ok(id) = sys::file_id_at(&path) { + if let Ok(id) = sys::file_id(&None, &Some(path.to_path_buf())) { self.file_id = Some(id); } @@ -150,7 +150,13 @@ impl DocumentManager { let (path, goto) = Self::parse_filename_goto(path); let path = path::normalize(path); - let file_id = match sys::file_id_at(&path) { + let mut file = match Self::open_for_reading(&path) { + Ok(file) => Some(file), + Err(err) if sys::apperr_is_not_found(err) => None, + Err(err) => return Err(err), + }; + + let file_id = match sys::file_id(&file, &Some(path.to_path_buf())) { Ok(id) => Some(id), Err(err) if sys::apperr_is_not_found(err) => None, Err(err) => return Err(err), @@ -165,12 +171,6 @@ impl DocumentManager { return Ok(doc); } - let mut file = match Self::open_for_reading(&path) { - Ok(file) => Some(file), - Err(err) if sys::apperr_is_not_found(err) => None, - Err(err) => return Err(err), - }; - let buffer = TextBuffer::new_rc(false)?; { let mut tb = buffer.borrow_mut(); diff --git a/src/bin/edit/draw_filepicker.rs b/src/bin/edit/draw_filepicker.rs index 79733d1e14a..8df106dc767 100644 --- a/src/bin/edit/draw_filepicker.rs +++ b/src/bin/edit/draw_filepicker.rs @@ -113,10 +113,9 @@ pub fn draw_file_picker(ctx: &mut Context, state: &mut State) { // Check if the file already exists and show an overwrite warning in that case. if state.wants_file_picker != StateFilePicker::Open - && 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, &doit).is_ok_and(|id| &id == file_id) { state.file_picker_overwrite_warning = doit.take(); } diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 0bb27e9cff3..7c48491e37a 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -350,8 +350,7 @@ pub struct FileId { st_ino: libc::ino_t, } -/// Returns a unique identifier for the given file, by handle. -pub fn file_id(file: &File) -> apperr::Result { +fn _file_id_from_handle(file: &File) -> apperr::Result { unsafe { let mut stat = MaybeUninit::::uninit(); check_int_return(libc::fstat(file.as_raw_fd(), stat.as_mut_ptr()))?; @@ -360,11 +359,20 @@ pub fn file_id(file: &File) -> apperr::Result { } } -/// Returns a unique identifier for the given file, by path. -pub fn file_id_at(path: &Path) -> apperr::Result { - let file = File::open(path)?; - let file_id = file_id(&file)?; - Ok(file_id) +/// Returns a unique identifier for the given file, by handle or path. +pub fn file_id(file: &Option, path: &Option) -> apperr::Result { + if let Some(f) = file { + if let Ok(id) = _file_id_from_handle(&f) { + return Ok(id); + } + } + + if let Some(p) = path { + let file = File::open(p)?; + _file_id_from_handle(&file) + } + + Err(errno_to_apperr(libc::ENOENT)) } /// Reserves a virtual memory region of the given size. diff --git a/src/sys/windows.rs b/src/sys/windows.rs index d7266186b43..d44f585a4fc 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -422,7 +422,7 @@ impl PartialEq for FileId { impl Eq for FileId {} /// Returns a unique identifier for the given file, by open handle. -pub fn file_id(file: &File) -> apperr::Result { +pub fn _file_id_from_handle(file: &File) -> apperr::Result { unsafe { let mut info = MaybeUninit::::uninit(); check_bool_return(FileSystem::GetFileInformationByHandleEx( @@ -435,15 +435,23 @@ pub fn file_id(file: &File) -> apperr::Result { } } -/// Returns a unique identifier for the given file, by path. -pub fn file_id_at(path: &Path) -> apperr::Result { - let file = File::open(path)?; - match file_id(&file) { - Ok(v) => Ok(v), - // Propagate file not found - Err(err) if apperr_is_not_found(err) => Err(err), - Err(_) => Ok(FileId::Path(path.to_path_buf())), +pub fn file_id(file: &Option, path: &Option) -> apperr::Result { + if let Some(f) = file { + if let Ok(id) = _file_id_from_handle(&f) { + return Ok(id); + } } + + if let Some(p) = path { + let file = File::open(p)?; + return match _file_id_from_handle(&file) { + Ok(v) => Ok(v), + Err(err) if apperr_is_not_found(err) => Err(err), + Err(_) => Ok(FileId::Path(canonicalize(p)?)), + }; + } + + Err(gle_to_apperr(Foundation::ERROR_FILE_NOT_FOUND)) } /// Canonicalizes the given path. From 79e8fa04866d46ebda8d3efccddd299876e5a34a Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Wed, 21 May 2025 12:34:39 -0500 Subject: [PATCH 3/9] Foo --- src/bin/edit/documents.rs | 7 +++---- src/bin/edit/draw_filepicker.rs | 3 ++- src/sys/unix.rs | 21 ++++++++++----------- src/sys/windows.rs | 26 ++++++++++++-------------- 4 files changed, 27 insertions(+), 30 deletions(-) diff --git a/src/bin/edit/documents.rs b/src/bin/edit/documents.rs index 1665dd5b1ff..8309ee627aa 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(&None, &Some(path.to_path_buf())) { + if let Ok(id) = sys::file_id(None, Some(&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(&None, &Some(path.to_path_buf())) { + if let Ok(id) = sys::file_id(None, Some(&path)) { self.file_id = Some(id); } @@ -156,9 +156,8 @@ impl DocumentManager { Err(err) => return Err(err), }; - let file_id = match sys::file_id(&file, &Some(path.to_path_buf())) { + let file_id = match sys::file_id(file.as_ref(), Some(&path)) { Ok(id) => Some(id), - Err(err) if sys::apperr_is_not_found(err) => None, Err(err) => return Err(err), }; diff --git a/src/bin/edit/draw_filepicker.rs b/src/bin/edit/draw_filepicker.rs index 8df106dc767..21935f07ff6 100644 --- a/src/bin/edit/draw_filepicker.rs +++ b/src/bin/edit/draw_filepicker.rs @@ -113,9 +113,10 @@ pub fn draw_file_picker(ctx: &mut Context, state: &mut State) { // Check if the file already exists and show an overwrite warning in that case. if state.wants_file_picker != StateFilePicker::Open + && doit.is_some() && let Some(doc) = state.documents.active() && let Some(file_id) = &doc.file_id - && sys::file_id(&None, &doit).is_ok_and(|id| &id == file_id) + && sys::file_id(None, doit.as_deref()).is_ok_and(|id| &id == file_id) { state.file_picker_overwrite_warning = doit.take(); } diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 7c48491e37a..bcb30d7c5bc 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -8,6 +8,7 @@ use std::ffi::{CStr, c_int, c_void}; use std::fs::{self, File}; +use std::path::Path; use std::mem::{self, ManuallyDrop, MaybeUninit}; use std::os::fd::{AsRawFd as _, FromRawFd as _}; use std::ptr::{self, NonNull, null_mut}; @@ -360,19 +361,17 @@ fn _file_id_from_handle(file: &File) -> apperr::Result { } /// Returns a unique identifier for the given file, by handle or path. -pub fn file_id(file: &Option, path: &Option) -> apperr::Result { - if let Some(f) = file { - if let Ok(id) = _file_id_from_handle(&f) { - return Ok(id); +pub fn file_id(file: Option<&File>, path: Option<&Path>) -> apperr::Result { + let handle = match file { + Some(f) => f, + None if path.is_some() => &File::open(path.unwrap())?, + None => { + // Neither open file nor path provided. + return Err(errno_to_apperr(libc::ENOENT)); } - } - - if let Some(p) = path { - let file = File::open(p)?; - _file_id_from_handle(&file) - } + }; - Err(errno_to_apperr(libc::ENOENT)) + _file_id_from_handle(&handle) } /// Reserves a virtual memory region of the given size. diff --git a/src/sys/windows.rs b/src/sys/windows.rs index d44f585a4fc..25b894c19bb 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -435,23 +435,21 @@ pub fn _file_id_from_handle(file: &File) -> apperr::Result { } } -pub fn file_id(file: &Option, path: &Option) -> apperr::Result { - if let Some(f) = file { - if let Ok(id) = _file_id_from_handle(&f) { - return Ok(id); +pub fn file_id(file: Option<&File>, path: Option<&Path>) -> apperr::Result { + let handle = match file { + Some(f) => f, + None if path.is_some() => &File::open(path.unwrap())?, + None => { + // Neither open file nor path provided. + return Err(gle_to_apperr(Foundation::ERROR_FILE_NOT_FOUND)); } - } + }; - if let Some(p) = path { - let file = File::open(p)?; - return match _file_id_from_handle(&file) { - Ok(v) => Ok(v), - Err(err) if apperr_is_not_found(err) => Err(err), - Err(_) => Ok(FileId::Path(canonicalize(p)?)), - }; + match _file_id_from_handle(&handle) { + Ok(i) => Ok(i), + Err(_) if path.is_some() => Ok(FileId::Path(canonicalize(path.unwrap())?)), + Err(v) => Err(v), } - - Err(gle_to_apperr(Foundation::ERROR_FILE_NOT_FOUND)) } /// Canonicalizes the given path. From 863cd431de004b7084f19d180e8d12de13fc8816 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Wed, 21 May 2025 12:38:43 -0500 Subject: [PATCH 4/9] eh fix doc yea --- src/sys/unix.rs | 2 +- src/sys/windows.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sys/unix.rs b/src/sys/unix.rs index bcb30d7c5bc..0f851d42ca9 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -360,7 +360,7 @@ fn _file_id_from_handle(file: &File) -> apperr::Result { } } -/// Returns a unique identifier for the given file, by handle or path. +/// Returns a unique identifier for the given file by handle or path. pub fn file_id(file: Option<&File>, path: Option<&Path>) -> apperr::Result { let handle = match file { Some(f) => f, diff --git a/src/sys/windows.rs b/src/sys/windows.rs index 25b894c19bb..32ae2796a8f 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -421,8 +421,7 @@ impl PartialEq for FileId { impl Eq for FileId {} -/// Returns a unique identifier for the given file, by open handle. -pub fn _file_id_from_handle(file: &File) -> apperr::Result { +fn _file_id_from_handle(file: &File) -> apperr::Result { unsafe { let mut info = MaybeUninit::::uninit(); check_bool_return(FileSystem::GetFileInformationByHandleEx( @@ -435,6 +434,7 @@ pub fn _file_id_from_handle(file: &File) -> apperr::Result { } } +/// Returns a unique identifier for the given file by handle or path. pub fn file_id(file: Option<&File>, path: Option<&Path>) -> apperr::Result { let handle = match file { Some(f) => f, From 2de1179c74d25a3548370674371feb12fa40e990 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Wed, 21 May 2025 13:21:30 -0500 Subject: [PATCH 5/9] I dunno if this is right? --- src/bin/edit/documents.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/bin/edit/documents.rs b/src/bin/edit/documents.rs index 8309ee627aa..ee641d58224 100644 --- a/src/bin/edit/documents.rs +++ b/src/bin/edit/documents.rs @@ -156,13 +156,10 @@ impl DocumentManager { Err(err) => return Err(err), }; - let file_id = match sys::file_id(file.as_ref(), Some(&path)) { - Ok(id) => Some(id), - Err(err) => return Err(err), - }; + let file_id = sys::file_id(file.as_ref(), Some(&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.is_some_and(|i| i == file_id)) { let doc = self.active_mut().unwrap(); if let Some(goto) = goto { doc.buffer.borrow_mut().cursor_move_to_logical(goto); From 61bf7be4d1ebe576de444ddd4d66bb61fa64618e Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Wed, 21 May 2025 15:39:54 -0500 Subject: [PATCH 6/9] Address PR feedback --- src/bin/edit/documents.rs | 4 ++-- src/sys/mod.rs | 2 +- src/sys/unix.rs | 20 ++++++++------------ src/sys/windows.rs | 28 ++++++++++++++-------------- 4 files changed, 25 insertions(+), 29 deletions(-) diff --git a/src/bin/edit/documents.rs b/src/bin/edit/documents.rs index ee641d58224..b78bedb4488 100644 --- a/src/bin/edit/documents.rs +++ b/src/bin/edit/documents.rs @@ -159,7 +159,7 @@ impl DocumentManager { let file_id = sys::file_id(file.as_ref(), Some(&path))?; // Check if the file is already open. - if self.update_active(|doc| doc.file_id.is_some_and(|i| i == file_id)) { + if self.update_active(|doc| doc.file_id.as_ref().is_some_and(|i| *i == file_id)) { let doc = self.active_mut().unwrap(); if let Some(goto) = goto { doc.buffer.borrow_mut().cursor_move_to_logical(goto); @@ -189,7 +189,7 @@ impl DocumentManager { path: None, dir: None, filename: Default::default(), - file_id, + file_id: Some(file_id), new_file_counter: 0, }; doc.set_path(path); diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 94e1c56a503..91d59881248 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -14,4 +14,4 @@ pub use std::fs::canonicalize; #[cfg(unix)] pub use unix::*; #[cfg(windows)] -pub use windows::*; \ No newline at end of file +pub use windows::*; diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 0f851d42ca9..fa7d7b7864c 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -8,9 +8,9 @@ use std::ffi::{CStr, c_int, c_void}; use std::fs::{self, File}; -use std::path::Path; 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}; @@ -351,18 +351,9 @@ pub struct FileId { st_ino: libc::ino_t, } -fn _file_id_from_handle(file: &File) -> apperr::Result { - unsafe { - let mut stat = MaybeUninit::::uninit(); - check_int_return(libc::fstat(file.as_raw_fd(), stat.as_mut_ptr()))?; - let stat = stat.assume_init(); - Ok(FileId { st_dev: stat.st_dev, st_ino: stat.st_ino }) - } -} - /// Returns a unique identifier for the given file by handle or path. pub fn file_id(file: Option<&File>, path: Option<&Path>) -> apperr::Result { - let handle = match file { + let file = match file { Some(f) => f, None if path.is_some() => &File::open(path.unwrap())?, None => { @@ -371,7 +362,12 @@ pub fn file_id(file: Option<&File>, path: Option<&Path>) -> apperr::Result::uninit(); + check_int_return(libc::fstat(file.as_raw_fd(), stat.as_mut_ptr()))?; + let stat = stat.assume_init(); + Ok(FileId { st_dev: stat.st_dev, st_ino: stat.st_ino }) + } } /// Reserves a virtual memory region of the given size. diff --git a/src/sys/windows.rs b/src/sys/windows.rs index 32ae2796a8f..a1d9a70e19e 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -421,22 +421,10 @@ impl PartialEq for FileId { impl Eq for FileId {} -fn _file_id_from_handle(file: &File) -> apperr::Result { - unsafe { - let mut info = MaybeUninit::::uninit(); - check_bool_return(FileSystem::GetFileInformationByHandleEx( - file.as_raw_handle(), - FileSystem::FileIdInfo, - info.as_mut_ptr() as *mut _, - mem::size_of::() as u32, - ))?; - Ok(FileId::Id(info.assume_init())) - } -} /// Returns a unique identifier for the given file by handle or path. pub fn file_id(file: Option<&File>, path: Option<&Path>) -> apperr::Result { - let handle = match file { + let file = match file { Some(f) => f, None if path.is_some() => &File::open(path.unwrap())?, None => { @@ -445,13 +433,25 @@ pub fn file_id(file: Option<&File>, path: Option<&Path>) -> apperr::Result Ok(i), Err(_) if path.is_some() => Ok(FileId::Path(canonicalize(path.unwrap())?)), Err(v) => Err(v), } } +fn file_id_from_handle(file: &File) -> apperr::Result { + unsafe { + let mut info = MaybeUninit::::uninit(); + check_bool_return(FileSystem::GetFileInformationByHandleEx( + file.as_raw_handle(), + FileSystem::FileIdInfo, + info.as_mut_ptr() as *mut _, + mem::size_of::() as u32, + ))?; + Ok(FileId::Id(info.assume_init())) + } +} /// Canonicalizes the given path. /// /// This differs from [`fs::canonicalize`] in that it strips the `\\?\` UNC From 3cff29a608a61c67866ac8dd44122ca1e676999f Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Wed, 21 May 2025 15:44:26 -0500 Subject: [PATCH 7/9] cliipy --- src/bin/edit/documents.rs | 4 ++-- src/sys/windows.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bin/edit/documents.rs b/src/bin/edit/documents.rs index b78bedb4488..1477cbcff50 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(None, Some(&path)) { + if let Ok(id) = sys::file_id(None, Some(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(None, Some(&path)) { + if let Ok(id) = sys::file_id(None, Some(path)) { self.file_id = Some(id); } diff --git a/src/sys/windows.rs b/src/sys/windows.rs index a1d9a70e19e..92d9b8de3d4 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -433,7 +433,7 @@ pub fn file_id(file: Option<&File>, path: Option<&Path>) -> apperr::Result Ok(i), Err(_) if path.is_some() => Ok(FileId::Path(canonicalize(path.unwrap())?)), Err(v) => Err(v), From b0ba70ebee8856c8dab7b8f31b3e7b6ed441a51e Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Wed, 21 May 2025 17:27:49 -0500 Subject: [PATCH 8/9] oh there's always a path --- src/bin/edit/documents.rs | 10 +++++----- src/bin/edit/draw_filepicker.rs | 4 ++-- src/sys/unix.rs | 8 ++------ src/sys/windows.rs | 16 ++++------------ 4 files changed, 13 insertions(+), 25 deletions(-) diff --git a/src/bin/edit/documents.rs b/src/bin/edit/documents.rs index 1477cbcff50..7e0da29537a 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(None, Some(path)) { + 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(None, Some(path)) { + if let Ok(id) = sys::file_id(None, path) { self.file_id = Some(id); } @@ -156,10 +156,10 @@ impl DocumentManager { Err(err) => return Err(err), }; - let file_id = sys::file_id(file.as_ref(), Some(&path))?; + let file_id = Some(sys::file_id(file.as_ref(), &path)?); // Check if the file is already open. - if self.update_active(|doc| doc.file_id.as_ref().is_some_and(|i| *i == 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); @@ -189,7 +189,7 @@ impl DocumentManager { path: None, dir: None, filename: Default::default(), - file_id: Some(file_id), + file_id, new_file_counter: 0, }; doc.set_path(path); diff --git a/src/bin/edit/draw_filepicker.rs b/src/bin/edit/draw_filepicker.rs index 21935f07ff6..d5b8ebb4ee7 100644 --- a/src/bin/edit/draw_filepicker.rs +++ b/src/bin/edit/draw_filepicker.rs @@ -113,10 +113,10 @@ pub fn draw_file_picker(ctx: &mut Context, state: &mut State) { // Check if the file already exists and show an overwrite warning in that case. if state.wants_file_picker != StateFilePicker::Open - && doit.is_some() + && let Some(path) = doit.as_deref() && let Some(doc) = state.documents.active() && let Some(file_id) = &doc.file_id - && sys::file_id(None, doit.as_deref()).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/unix.rs b/src/sys/unix.rs index fa7d7b7864c..b660357905d 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -352,14 +352,10 @@ pub struct FileId { } /// Returns a unique identifier for the given file by handle or path. -pub fn file_id(file: Option<&File>, path: Option<&Path>) -> apperr::Result { +pub fn file_id(file: Option<&File>, path: &Path) -> apperr::Result { let file = match file { Some(f) => f, - None if path.is_some() => &File::open(path.unwrap())?, - None => { - // Neither open file nor path provided. - return Err(errno_to_apperr(libc::ENOENT)); - } + None => &File::open(path)?, }; unsafe { diff --git a/src/sys/windows.rs b/src/sys/windows.rs index 92d9b8de3d4..83410656f8a 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -421,23 +421,14 @@ impl PartialEq for FileId { impl Eq for FileId {} - /// Returns a unique identifier for the given file by handle or path. -pub fn file_id(file: Option<&File>, path: Option<&Path>) -> apperr::Result { +pub fn file_id(file: Option<&File>, path: &Path) -> apperr::Result { let file = match file { Some(f) => f, - None if path.is_some() => &File::open(path.unwrap())?, - None => { - // Neither open file nor path provided. - return Err(gle_to_apperr(Foundation::ERROR_FILE_NOT_FOUND)); - } + None => &File::open(path)?, }; - match file_id_from_handle(file) { - Ok(i) => Ok(i), - Err(_) if path.is_some() => Ok(FileId::Path(canonicalize(path.unwrap())?)), - Err(v) => Err(v), - } + file_id_from_handle(file).or_else(|_| Ok(FileId::Path(canonicalize(path)?))) } fn file_id_from_handle(file: &File) -> apperr::Result { @@ -452,6 +443,7 @@ fn file_id_from_handle(file: &File) -> apperr::Result { Ok(FileId::Id(info.assume_init())) } } + /// Canonicalizes the given path. /// /// This differs from [`fs::canonicalize`] in that it strips the `\\?\` UNC From 254aa69a44c12eb3574f55b82ff00c51f396d099 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Wed, 21 May 2025 17:33:39 -0500 Subject: [PATCH 9/9] use std::fs::canonicalize --- src/sys/windows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/windows.rs b/src/sys/windows.rs index 83410656f8a..e4f20b0e64a 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -428,7 +428,7 @@ pub fn file_id(file: Option<&File>, path: &Path) -> apperr::Result { None => &File::open(path)?, }; - file_id_from_handle(file).or_else(|_| Ok(FileId::Path(canonicalize(path)?))) + file_id_from_handle(file).or_else(|_| Ok(FileId::Path(std::fs::canonicalize(path)?))) } fn file_id_from_handle(file: &File) -> apperr::Result {