2727//! let file_id = file_id::get_high_res_file_id(file.path()).unwrap();
2828//! println!("{file_id:?}");
2929//! ```
30+ //!
31+ //! ## Example (Not Following Symlinks/Reparse Points)
32+ //!
33+ //! ```
34+ //! let file = tempfile::NamedTempFile::new().unwrap();
35+ //!
36+ //! // Get file ID without following symlinks
37+ //! let file_id = file_id::get_file_id_no_follow(file.path()).unwrap();
38+ //! println!("{file_id:?}");
39+ //! ```
3040use std:: { fs, io, path:: Path } ;
3141
3242#[ cfg( feature = "serde" ) ]
@@ -122,6 +132,16 @@ pub fn get_file_id(path: impl AsRef<Path>) -> io::Result<FileId> {
122132 Ok ( FileId :: new_inode ( metadata. dev ( ) , metadata. ino ( ) ) )
123133}
124134
135+ /// Get the `FileId` for the file or directory at `path` without following symlinks
136+ #[ cfg( target_family = "unix" ) ]
137+ pub fn get_file_id_no_follow ( path : impl AsRef < Path > ) -> io:: Result < FileId > {
138+ use std:: os:: unix:: fs:: MetadataExt ;
139+
140+ let metadata = fs:: symlink_metadata ( path. as_ref ( ) ) ?;
141+
142+ Ok ( FileId :: new_inode ( metadata. dev ( ) , metadata. ino ( ) ) )
143+ }
144+
125145/// Get the `FileId` for the file or directory at `path`
126146#[ cfg( target_family = "windows" ) ]
127147pub fn get_file_id ( path : impl AsRef < Path > ) -> io:: Result < FileId > {
@@ -130,6 +150,14 @@ pub fn get_file_id(path: impl AsRef<Path>) -> io::Result<FileId> {
130150 unsafe { get_file_info_ex ( & file) . or_else ( |_| get_file_info ( & file) ) }
131151}
132152
153+ /// Get the `FileId` for the file or directory at `path` without following symlinks/reparse points
154+ #[ cfg( target_family = "windows" ) ]
155+ pub fn get_file_id_no_follow ( path : impl AsRef < Path > ) -> io:: Result < FileId > {
156+ let file = open_file_no_follow ( path) ?;
157+
158+ unsafe { get_file_info_ex ( & file) . or_else ( |_| get_file_info ( & file) ) }
159+ }
160+
133161/// Get the `FileId` with the low resolution variant for the file or directory at `path`
134162#[ cfg( target_family = "windows" ) ]
135163pub fn get_low_res_file_id ( path : impl AsRef < Path > ) -> io:: Result < FileId > {
@@ -138,6 +166,14 @@ pub fn get_low_res_file_id(path: impl AsRef<Path>) -> io::Result<FileId> {
138166 unsafe { get_file_info ( & file) }
139167}
140168
169+ /// Get the `FileId` with the low resolution variant for the file or directory at `path` without following symlinks/reparse points
170+ #[ cfg( target_family = "windows" ) ]
171+ pub fn get_low_res_file_id_no_follow ( path : impl AsRef < Path > ) -> io:: Result < FileId > {
172+ let file = open_file_no_follow ( path) ?;
173+
174+ unsafe { get_file_info ( & file) }
175+ }
176+
141177/// Get the `FileId` with the high resolution variant for the file or directory at `path`
142178#[ cfg( target_family = "windows" ) ]
143179pub fn get_high_res_file_id ( path : impl AsRef < Path > ) -> io:: Result < FileId > {
@@ -146,6 +182,14 @@ pub fn get_high_res_file_id(path: impl AsRef<Path>) -> io::Result<FileId> {
146182 unsafe { get_file_info_ex ( & file) }
147183}
148184
185+ /// Get the `FileId` with the high resolution variant for the file or directory at `path` without following symlinks/reparse points
186+ #[ cfg( target_family = "windows" ) ]
187+ pub fn get_high_res_file_id_no_follow ( path : impl AsRef < Path > ) -> io:: Result < FileId > {
188+ let file = open_file_no_follow ( path) ?;
189+
190+ unsafe { get_file_info_ex ( & file) }
191+ }
192+
149193#[ cfg( target_family = "windows" ) ]
150194unsafe fn get_file_info_ex ( file : & fs:: File ) -> Result < FileId , io:: Error > {
151195 use std:: { mem, os:: windows:: prelude:: * } ;
@@ -202,3 +246,16 @@ fn open_file<P: AsRef<Path>>(path: P) -> io::Result<fs::File> {
202246 . custom_flags ( FILE_FLAG_BACKUP_SEMANTICS )
203247 . open ( path)
204248}
249+
250+ #[ cfg( target_family = "windows" ) ]
251+ fn open_file_no_follow < P : AsRef < Path > > ( path : P ) -> io:: Result < fs:: File > {
252+ use std:: { fs:: OpenOptions , os:: windows:: fs:: OpenOptionsExt } ;
253+ use windows_sys:: Win32 :: Storage :: FileSystem :: {
254+ FILE_FLAG_BACKUP_SEMANTICS , FILE_FLAG_OPEN_REPARSE_POINT ,
255+ } ;
256+
257+ OpenOptions :: new ( )
258+ . access_mode ( 0 )
259+ . custom_flags ( FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT )
260+ . open ( path)
261+ }
0 commit comments