Skip to content

Commit 4255e7b

Browse files
Copilotbranchseer
andcommitted
Address code review feedback: improve Windows error handling, API design, and error propagation
Co-authored-by: branchseer <3612422+branchseer@users.noreply.github.com>
1 parent 0fd43c2 commit 4255e7b

1 file changed

Lines changed: 68 additions & 32 deletions

File tree

  • crates/vite_task/src

crates/vite_task/src/fs.rs

Lines changed: 68 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -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

9996
impl 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

Comments
 (0)