@@ -44,18 +44,17 @@ impl FileSystem for RealFileSystem {
4444 path : & Arc < AbsolutePath > ,
4545 path_read : PathRead ,
4646 ) -> Result < PathFingerprint , Error > {
47- let file = match File :: open ( path. as_ref ( ) ) {
47+ let path_ref: & std:: path:: Path = path. as_ref ( ) . as_ref ( ) ;
48+
49+ let file = match File :: open ( path_ref) {
4850 Ok ( file) => file,
4951 Err ( err) => {
50- // On Windows, File::open fails for directories, so we need to check
51- // if this might be a directory before giving up
52+ // On Windows, File::open fails specifically for directories with PermissionDenied
5253 #[ cfg( windows) ]
5354 {
54- // On Windows, opening a directory can fail with various error codes
55- // Try to check if it's a directory first
56- let path_ref: & std:: path:: Path = path. as_ref ( ) ;
57- if let Ok ( dir_iter) = std:: fs:: read_dir ( path_ref) {
58- return RealFileSystem :: process_directory ( dir_iter, path_read) ;
55+ if err. kind ( ) == io:: ErrorKind :: PermissionDenied {
56+ // This might be a directory - try reading it as such
57+ return RealFileSystem :: process_directory ( path_ref, path_read) ;
5958 }
6059 }
6160
@@ -81,15 +80,13 @@ impl FileSystem for RealFileSystem {
8180 // Is a directory on Unix - use the optimized nix implementation first
8281 #[ cfg( unix) ]
8382 {
84- return RealFileSystem :: process_directory_unix ( reader, path_read) ;
83+ return RealFileSystem :: process_directory_unix ( reader. into_inner ( ) , path_read) ;
8584 }
8685 #[ cfg( windows) ]
8786 {
8887 // This shouldn't happen on Windows since File::open should have failed
8988 // But if it does, fallback to std::fs::read_dir
90- let path_ref: & std:: path:: Path = path. as_ref ( ) ;
91- let dir_iter = std:: fs:: read_dir ( path_ref) ?;
92- return RealFileSystem :: process_directory ( dir_iter, path_read) ;
89+ return RealFileSystem :: process_directory ( path_ref, path_read) ;
9390 }
9491 }
9592 Ok ( PathFingerprint :: FileContentHash ( hash_content ( reader) ?) )
@@ -98,21 +95,25 @@ impl FileSystem for RealFileSystem {
9895
9996impl RealFileSystem {
10097 #[ cfg( unix) ]
101- fn process_directory_unix (
102- reader : io:: BufReader < File > ,
103- path_read : PathRead ,
104- ) -> Result < PathFingerprint , Error > {
98+ fn process_directory_unix ( fd : File , path_read : PathRead ) -> Result < PathFingerprint , Error > {
10599 use bstr:: ByteSlice ;
106100 use nix:: dir:: { Dir , Type } ;
107101
108102 let dir_entries: Option < HashMap < Str , DirEntryKind > > = if path_read. read_dir_entries {
109103 let mut dir_entries = HashMap :: < Str , DirEntryKind > :: new ( ) ;
110- let dir = Dir :: from_fd ( reader . into_inner ( ) . into ( ) ) ?;
104+ let dir = Dir :: from_fd ( fd . into ( ) ) ?;
111105 for entry in dir {
112106 let entry = entry?;
113107
114108 let entry_kind = match entry. file_type ( ) {
115- None => todo ! ( "handle DT_UNKNOWN (see readdir(3))" ) ,
109+ None => {
110+ // Handle DT_UNKNOWN by returning an error
111+ // We don't have the path here, so use a generic error
112+ return Err ( Error :: Io ( io:: Error :: new (
113+ io:: ErrorKind :: Other ,
114+ "Unknown file type (DT_UNKNOWN)" ,
115+ ) ) ) ;
116+ }
116117 Some ( Type :: File ) => DirEntryKind :: File ,
117118 Some ( Type :: Directory ) => DirEntryKind :: Dir ,
118119 Some ( Type :: Symlink ) => DirEntryKind :: Symlink ,
@@ -133,22 +134,22 @@ impl RealFileSystem {
133134 Ok ( PathFingerprint :: Folder ( dir_entries) )
134135 }
135136
136- #[ cfg( any ( unix , windows) ) ]
137+ #[ cfg( windows) ]
137138 fn process_directory (
138- dir_iter : std:: fs :: ReadDir ,
139+ path : & std:: path :: Path ,
139140 path_read : PathRead ,
140141 ) -> Result < PathFingerprint , Error > {
141142 let dir_entries: Option < HashMap < Str , DirEntryKind > > = if path_read. read_dir_entries {
142143 let mut dir_entries = HashMap :: < Str , DirEntryKind > :: new ( ) ;
144+ let dir_iter = std:: fs:: read_dir ( path) ?;
143145
144146 for entry in dir_iter {
145147 let entry = entry?;
146148 let file_name = entry. file_name ( ) ;
147149
148150 // Skip special entries (same as Unix version)
149- // Convert OsStr to bytes for comparison to avoid to_string_lossy
150- let file_name_bytes = file_name. as_encoded_bytes ( ) ;
151- if matches ! ( file_name_bytes, b"." | b".." | b".DS_Store" ) {
151+ // Use direct OsStr comparison with str
152+ if file_name == "." || file_name == ".." || file_name == ".DS_Store" {
152153 continue ;
153154 }
154155
@@ -162,25 +163,60 @@ impl RealFileSystem {
162163 } else if file_type. is_symlink ( ) {
163164 DirEntryKind :: Symlink
164165 } else {
165- // For any other file type, we'll treat it as a file
166- // This is a conservative approach
167- DirEntryKind :: File
166+ // Return error for unsupported file types instead of treating as file
167+ return Err ( Error :: IoWithPath {
168+ err : io:: Error :: new ( io:: ErrorKind :: Other , "Unsupported file type" ) ,
169+ path : Arc :: new ( AbsolutePath :: new ( path) . ok_or_else ( || {
170+ Error :: IoWithPath {
171+ err : io:: Error :: new (
172+ io:: ErrorKind :: InvalidInput ,
173+ "Invalid path" ,
174+ ) ,
175+ path : Arc :: new ( AbsolutePath :: new ( "/" ) . unwrap ( ) ) ,
176+ }
177+ } ) ?) ,
178+ } ) ;
168179 }
169180 }
170- Err ( _) => {
171- // If we can't determine the file type, treat as file
172- DirEntryKind :: File
181+ Err ( err) => {
182+ // Return error instead of treating as file
183+ return Err ( Error :: IoWithPath {
184+ err,
185+ path : Arc :: new ( AbsolutePath :: new ( path) . ok_or_else ( || {
186+ Error :: IoWithPath {
187+ err : io:: Error :: new (
188+ io:: ErrorKind :: InvalidInput ,
189+ "Invalid path" ,
190+ ) ,
191+ path : Arc :: new ( AbsolutePath :: new ( "/" ) . unwrap ( ) ) ,
192+ }
193+ } ) ?) ,
194+ } ) ;
173195 }
174196 } ;
175197
176- // Convert filename to Str - need to ensure it's valid UTF-8
198+ // Convert filename to Str - return error for invalid UTF-8
177199 match file_name. to_str ( ) {
178200 Some ( filename_str) => {
179201 dir_entries. insert ( filename_str. into ( ) , entry_kind) ;
180202 }
181203 None => {
182- // Skip files with invalid UTF-8 names
183- continue ;
204+ // Return error instead of skipping files with invalid UTF-8 names
205+ return Err ( Error :: IoWithPath {
206+ err : io:: Error :: new (
207+ io:: ErrorKind :: InvalidData ,
208+ "Invalid UTF-8 in filename" ,
209+ ) ,
210+ path : Arc :: new ( AbsolutePath :: new ( path) . ok_or_else ( || {
211+ Error :: IoWithPath {
212+ err : io:: Error :: new (
213+ io:: ErrorKind :: InvalidInput ,
214+ "Invalid path" ,
215+ ) ,
216+ path : Arc :: new ( AbsolutePath :: new ( "/" ) . unwrap ( ) ) ,
217+ }
218+ } ) ?) ,
219+ } ) ;
184220 }
185221 }
186222 }
0 commit comments