Fix stuck on non-regular files and report loading errors

This commit is contained in:
oxalica 2023-04-29 11:12:41 +08:00
parent 5700b00872
commit f2b2647975
3 changed files with 53 additions and 18 deletions

14
Cargo.lock generated
View file

@ -388,15 +388,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.141"
version = "0.2.142"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317"
[[package]]
name = "linux-raw-sys"
version = "0.3.1"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f"
checksum = "b64f40e5e03e0d54f03845c8197d0291253cdbedfb1cb46b13c2c117554a9f4c"
[[package]]
name = "lock_api"
@ -476,10 +476,10 @@ dependencies = [
"atty",
"codespan-reporting",
"ide",
"libc",
"log",
"lsp-types",
"nix-interop",
"rustix",
"serde_json",
"slab",
"syntax",
@ -710,9 +710,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustix"
version = "0.37.11"
version = "0.37.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77"
checksum = "bc809f704c03a812ac71f22456c857be34185cac691a4316f27ab0f633bb9009"
dependencies = [
"bitflags",
"errno",

View file

@ -34,5 +34,5 @@ features = [
"tracing-log",
]
[target.'cfg(target_os = "linux")'.dependencies]
libc = "0.2.137"
[target.'cfg(unix)'.dependencies]
rustix = { version = "0.37.17", default-features = false, features = ["fs"] }

View file

@ -26,6 +26,7 @@ use std::borrow::BorrowMut;
use std::cell::Cell;
use std::collections::HashMap;
use std::future::{ready, Future};
use std::io::{ErrorKind, Read};
use std::ops::ControlFlow;
use std::panic::UnwindSafe;
use std::path::Path;
@ -352,23 +353,57 @@ impl Server {
tracing::debug!("Watched files changed: {params:?}");
let mut flake_files_changed = true;
for FileEvent { uri, typ } in &params.changes {
for &FileEvent { ref uri, mut typ } in &params.changes {
// Don't reload files maintained by the client.
if self.opened_files.contains_key(uri) {
continue;
}
let Ok(path) = uri.to_file_path() else { continue };
match *typ {
FileChangeType::CREATED | FileChangeType::CHANGED => {
if let Ok(text) = std::fs::read_to_string(&path) {
self.set_vfs_file_content(uri, text);
if matches!(typ, FileChangeType::CREATED | FileChangeType::CHANGED) {
match (|| -> std::io::Result<_> {
#[cfg(unix)]
use rustix::fs::{fcntl_getfl, fcntl_setfl, OFlags, OpenOptionsExt};
// Rule out non-regular files which may block `open()` infinitely
// (eg. FIFO). We open it with `O_NONBLOCK` and check it before reading.
let mut options = std::fs::File::options();
options.read(true);
#[cfg(unix)]
options.custom_flags(OFlags::NONBLOCK.bits() as _);
let mut file = options.open(&path)?;
let ft = file.metadata()?.file_type();
if !ft.is_file() {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("non-regular file type: {ft:?}"),
));
}
// Remove the O_NONBLOCK flag for blocking read.
#[cfg(unix)]
{
let flags = fcntl_getfl(&file)? - OFlags::NONBLOCK;
fcntl_setfl(&file, flags)?;
}
let mut buf = String::new();
file.read_to_string(&mut buf)?;
Ok(buf)
})() {
Ok(text) => self.set_vfs_file_content(uri, text),
Err(err) if matches!(err.kind(), ErrorKind::NotFound) => {
// File gets removed at the time calling `open()`.
typ = FileChangeType::DELETED;
}
Err(err) => tracing::error!("Ignore file {path:?}: {err}"),
}
FileChangeType::DELETED => {
let _: Result<_> = self.vfs.write().unwrap().remove_uri(uri);
}
_ => continue,
}
if typ == FileChangeType::DELETED {
let _: Result<_> = self.vfs.write().unwrap().remove_uri(uri);
}
if let Ok(relative) = path.strip_prefix(&self.config.root_path) {
if relative == Path::new(FLAKE_FILE) || relative == Path::new(FLAKE_LOCK_FILE) {
flake_files_changed = true;