diff --git a/apps/lightcraft/src/session.rs b/apps/lightcraft/src/session.rs index 082e1a757..7d9db79bd 100644 --- a/apps/lightcraft/src/session.rs +++ b/apps/lightcraft/src/session.rs @@ -278,9 +278,8 @@ fn open_library_session(in_memory: bool, dir: Option, rememb log::warn!("no library location (set --library or LIGHTCRAFT_LIBRARY)"); return (unopened(), Some(LibraryProblem::new("", "There is no home folder to keep the library in. Choose a folder for it."))); }; - if remembered && !lightcraft_engine::library::is_library(&dir) { - log::error!("library {} is missing", dir.display()); - let why = lightcraft_ui_egui::panels::library_problem::missing_library_reason(&dir); + if remembered && let Some(why) = lightcraft_ui_egui::panels::library_problem::missing_library_reason(&dir) { + log::error!("library {} can't be opened: {why}", dir.display()); // Try Again must not make one there either (an empty mount point, issue #3239) return (unopened(), Some(LibraryProblem { existing_only: true, ..LibraryProblem::new(dir.to_string_lossy(), why) })); } diff --git a/apps/lightcraft/src/tests.rs b/apps/lightcraft/src/tests.rs index e54deed04..a223f20e1 100644 --- a/apps/lightcraft/src/tests.rs +++ b/apps/lightcraft/src/tests.rs @@ -93,6 +93,44 @@ fn a_remembered_library_missing_at_launch_is_reported_not_made_anew() { let _ = std::fs::remove_dir_all(&d); } +/// Issue #3239: a remembered library whose folder can't be looked into (no permission) is +/// reported as unreadable at launch, not as gone, and nothing is opened or written there. +#[cfg(unix)] +#[test] +fn a_remembered_library_it_may_not_read_at_launch_says_so() { + use std::os::unix::fs::PermissionsExt; + let d = dir("denied-library"); + let lib = d.join("Lib"); + let mut s = lightcraft_engine::Session::new().with_fs(); + s.open_library(&lib, false).unwrap(); + s.close_library().unwrap(); + drop(s); + let names = |dir: &std::path::Path| { + let mut names: Vec<_> = std::fs::read_dir(dir).unwrap().flatten().map(|e| e.file_name()).collect(); + names.sort(); + names + }; + let before = names(&lib); + std::fs::set_permissions(&lib, std::fs::Permissions::from_mode(0o000)).unwrap(); + if std::fs::read_dir(&lib).is_ok() { + std::fs::set_permissions(&lib, std::fs::Permissions::from_mode(0o755)).unwrap(); + let _ = std::fs::remove_dir_all(&d); + lightcraft_testkit::skip!(System, "running as root: a folder with mode 000 is still readable"); + return; + } + let launch = Launch::Open { dir: Some(lib.clone()), alt_asks: true, remembered: true }; + let (s, problem) = open_session(false, &launch, true); + std::fs::set_permissions(&lib, std::fs::Permissions::from_mode(0o755)).unwrap(); + let problem = problem.expect("the unreadable library is reported"); + assert!(problem.error.starts_with("This folder can't be read:"), "{}", problem.error); + assert!(problem.error.to_lowercase().contains("permission denied"), "{}", problem.error); + assert!(problem.existing_only, "Try Again makes no library there either"); + assert!(s.library.is_none() && s.catalog.is_empty(), "no library, no demo photos"); + assert_eq!(names(&lib), before, "nothing written there"); + drop(s); + let _ = std::fs::remove_dir_all(&d); +} + /// Issue #103: a damaged ui.json (which holds the library location) is kept aside and /// reported, not silently replaced by the defaults. #[test] diff --git a/crates/engine/src/library.rs b/crates/engine/src/library.rs index a5071b4b3..b3c1884fc 100644 --- a/crates/engine/src/library.rs +++ b/crates/engine/src/library.rs @@ -58,6 +58,22 @@ pub fn is_library(dir: &Path) -> bool { dir.join(lightcraft_catalog::journal::SNAPSHOT).is_file() || dir.join(lightcraft_catalog::journal::LOG).is_file() } +/// [`is_library`] that tells "no library there" from "can't tell": `Ok(false)` only when the +/// folder or its catalog files are definitely missing; a lookup that fails otherwise (a folder it +/// may not read, a share that timed out) is the error, so a library that is there but can't be +/// read isn't reported as gone (issue #3239). +pub fn library_state(dir: &Path) -> std::io::Result { + for name in [lightcraft_catalog::journal::SNAPSHOT, lightcraft_catalog::journal::LOG] { + match std::fs::metadata(dir.join(name)) { + Ok(m) if m.is_file() => return Ok(true), + Ok(_) => {} + Err(e) if matches!(e.kind(), std::io::ErrorKind::NotFound | std::io::ErrorKind::NotADirectory) => {} + Err(e) => return Err(e), + } + } + Ok(false) +} + /// The default library location: `$LIGHTCRAFT_LIBRARY` if set, else `~/Pictures/LightCraft Library` /// (`%USERPROFILE%\Pictures\LightCraft Library` on Windows). pub fn default_dir() -> Option { diff --git a/crates/ui-egui/locales/cs.json b/crates/ui-egui/locales/cs.json index 52ca94a52..8bec61540 100644 --- a/crates/ui-egui/locales/cs.json +++ b/crates/ui-egui/locales/cs.json @@ -1020,6 +1020,9 @@ "LightCraft could not start": "LightCraft se nepodařilo spustit", "LightCraft couldn't find where to keep your library.": "LightCraft nedokázal najít místo pro uložení knihovny.", "LightCraft couldn't open the library at": "LightCraft nedokázal otevřít knihovnu v umístění", + "There is no LightCraft library in this folder any more.": "V této složce už žádná knihovna LightCraft není.", + "The library isn't there: it was moved or renamed, or its drive or network share isn't connected.": "Knihovna tu není: byla přesunuta nebo přejmenována, nebo není připojen její disk či síťové úložiště.", + "This folder can't be read:": "Tuto složku nelze přečíst:", "LightCraft does not know this model, so it assumed:": "LightCraft tento model nezná, a proto předpokládá:", "LightCraft on GitHub": "LightCraft na GitHubu", "LightCraft website": "Web LightCraft", diff --git a/crates/ui-egui/locales/de.json b/crates/ui-egui/locales/de.json index e2205db78..ca43782a1 100644 --- a/crates/ui-egui/locales/de.json +++ b/crates/ui-egui/locales/de.json @@ -801,6 +801,9 @@ "LightCraft could not start": "LightCraft konnte nicht starten", "LightCraft couldn't find where to keep your library.": "LightCraft konnte keinen Speicherort für deine Bibliothek finden.", "LightCraft couldn't open the library at": "LightCraft konnte die Bibliothek nicht öffnen unter", + "There is no LightCraft library in this folder any more.": "In diesem Ordner ist keine LightCraft-Bibliothek mehr.", + "The library isn't there: it was moved or renamed, or its drive or network share isn't connected.": "Die Bibliothek ist nicht da: Sie wurde verschoben oder umbenannt, oder ihr Laufwerk bzw. ihre Netzwerkfreigabe ist nicht verbunden.", + "This folder can't be read:": "Dieser Ordner kann nicht gelesen werden:", "LightCraft no longer crashes at launch on Windows PCs whose Vulkan driver is broken (issue #136, e.g. some Intel UHD": "LightCraft stürzt beim Start auf Windows-PCs mit defektem Vulkan-Treiber nicht mehr ab (Issue #136, etwa bestimmte Intel-UHD-630-Treiber).", "LightCraft on GitHub": "LightCraft auf GitHub", "LightCraft website": "LightCraft-Website", diff --git a/crates/ui-egui/locales/es.json b/crates/ui-egui/locales/es.json index 888af077f..a5da85cd4 100644 --- a/crates/ui-egui/locales/es.json +++ b/crates/ui-egui/locales/es.json @@ -806,6 +806,9 @@ "LightCraft could not start": "No se pudo iniciar LightCraft", "LightCraft couldn't find where to keep your library.": "LightCraft no encontró dónde guardar la biblioteca.", "LightCraft couldn't open the library at": "LightCraft no pudo abrir la biblioteca en", + "There is no LightCraft library in this folder any more.": "Ya no hay ninguna biblioteca de LightCraft en esta carpeta.", + "The library isn't there: it was moved or renamed, or its drive or network share isn't connected.": "La biblioteca no está: se movió o se le cambió el nombre, o su disco o carpeta de red no está conectado.", + "This folder can't be read:": "No se puede leer esta carpeta:", "LightCraft on GitHub": "LightCraft en GitHub", "LightCraft website": "Sitio web de LightCraft", "LightCraft — Second Window": "LightCraft: segunda ventana", diff --git a/crates/ui-egui/locales/fi.json b/crates/ui-egui/locales/fi.json index e0a8c622a..5d54cb2e1 100644 --- a/crates/ui-egui/locales/fi.json +++ b/crates/ui-egui/locales/fi.json @@ -1040,6 +1040,9 @@ "LightCraft could not start": "LightCraft ei voinut käynnistyä", "LightCraft couldn't find where to keep your library.": "LightCraft ei löytänyt paikkaa kirjastosi säilytykselle.", "LightCraft couldn't open the library at": "LightCraft ei voinut avata kirjastoa kohteessa", + "There is no LightCraft library in this folder any more.": "Tässä kansiossa ei ole enää LightCraft-kirjastoa.", + "The library isn't there: it was moved or renamed, or its drive or network share isn't connected.": "Kirjastoa ei löydy: se on siirretty tai nimetty uudelleen, tai sen asemaa tai verkkojakoa ei ole yhdistetty.", + "This folder can't be read:": "Tätä kansiota ei voi lukea:", "LightCraft does not know this model, so it assumed:": "LightCraft ei tunne tätä mallia, joten se oletti:", "LightCraft on GitHub": "LightCraft GitHubissa", "LightCraft stopped": "LightCraft pysähtyi", diff --git a/crates/ui-egui/locales/fr.json b/crates/ui-egui/locales/fr.json index 3278d6ccd..a56424150 100644 --- a/crates/ui-egui/locales/fr.json +++ b/crates/ui-egui/locales/fr.json @@ -759,6 +759,8 @@ "LightCraft could not start": "LightCraft n'a pas pu démarrer", "LightCraft couldn't find where to keep your library.": "LightCraft n'a pas trouvé où conserver votre bibliothèque.", "LightCraft couldn't open the library at": "LightCraft n'a pas pu ouvrir la bibliothèque à l'emplacement", + "There is no LightCraft library in this folder any more.": "Ce dossier ne contient plus de bibliothèque LightCraft.", + "The library isn't there: it was moved or renamed, or its drive or network share isn't connected.": "La bibliothèque est introuvable : elle a été déplacée ou renommée, ou son disque ou son partage réseau n'est pas connecté.", "LightCraft on GitHub": "LightCraft sur GitHub", "LightCraft website": "Site web de LightCraft", "LightCraft — Second Window": "LightCraft : deuxième fenêtre", diff --git a/crates/ui-egui/locales/id.json b/crates/ui-egui/locales/id.json index 0d6da9b8f..37a336ffa 100644 --- a/crates/ui-egui/locales/id.json +++ b/crates/ui-egui/locales/id.json @@ -1041,6 +1041,9 @@ "LightCraft could not start": "LightCraft gagal dijalankan", "LightCraft couldn't find where to keep your library.": "LightCraft tidak dapat menemukan lokasi untuk menyimpan pustaka Anda.", "LightCraft couldn't open the library at": "LightCraft tidak dapat membuka pustaka di", + "There is no LightCraft library in this folder any more.": "Folder ini tidak lagi berisi pustaka LightCraft.", + "The library isn't there: it was moved or renamed, or its drive or network share isn't connected.": "Pustaka tidak ada di sini: pustaka dipindahkan atau diganti namanya, atau drive atau berbagi jaringannya tidak terhubung.", + "This folder can't be read:": "Folder ini tidak dapat dibaca:", "LightCraft does not know this model, so it assumed:": "LightCraft tidak mengenali model ini, jadi menggunakan asumsi berikut:", "LightCraft on GitHub": "LightCraft di GitHub", "LightCraft stopped": "LightCraft berhenti", diff --git a/crates/ui-egui/locales/it.json b/crates/ui-egui/locales/it.json index e159fd47d..cf8ca0702 100644 --- a/crates/ui-egui/locales/it.json +++ b/crates/ui-egui/locales/it.json @@ -761,6 +761,9 @@ "LightCraft could not start": "Impossibile avviare LightCraft", "LightCraft couldn't find where to keep your library.": "LightCraft non ha trovato dove salvare la tua libreria.", "LightCraft couldn't open the library at": "LightCraft non è riuscito ad aprire la libreria in", + "There is no LightCraft library in this folder any more.": "In questa cartella non c'è più una libreria LightCraft.", + "The library isn't there: it was moved or renamed, or its drive or network share isn't connected.": "La libreria non c'è: è stata spostata o rinominata, oppure il suo disco o la sua condivisione di rete non è collegata.", + "This folder can't be read:": "Impossibile leggere questa cartella:", "LightCraft on GitHub": "LightCraft su GitHub", "LightCraft website": "Sito web di LightCraft", "LightCraft — Second Window": "LightCraft: seconda finestra", diff --git a/crates/ui-egui/locales/ja.json b/crates/ui-egui/locales/ja.json index e1834555b..6cc026807 100644 --- a/crates/ui-egui/locales/ja.json +++ b/crates/ui-egui/locales/ja.json @@ -1634,6 +1634,9 @@ "Your library couldn't be opened": "ライブラリを開けませんでした", "LightCraft couldn't find where to keep your library.": "ライブラリの保存場所が見つかりませんでした。", "LightCraft couldn't open the library at": "次の場所にあるライブラリを開けませんでした:", + "There is no LightCraft library in this folder any more.": "このフォルダーには LightCraft ライブラリがもうありません。", + "The library isn't there: it was moved or renamed, or its drive or network share isn't connected.": "ライブラリが見つかりません。移動されたか名前が変更されたか、ドライブまたはネットワーク共有が接続されていません。", + "This folder can't be read:": "このフォルダーを読み取れません:", "Try Again": "再試行", "Choose Another Library…": "別のライブラリを選択…", "Continue Without Saving": "保存せずに続行", diff --git a/crates/ui-egui/locales/ka.json b/crates/ui-egui/locales/ka.json index 32c407700..d27a94c70 100644 --- a/crates/ui-egui/locales/ka.json +++ b/crates/ui-egui/locales/ka.json @@ -1120,6 +1120,9 @@ "LightCraft could not start": "LightCraft ვერ გაეშვა", "LightCraft couldn't find where to keep your library.": "LightCraft-მა ვერ იპოვა, სად შეინახოს თქვენი ბიბლიოთეკა.", "LightCraft couldn't open the library at": "LightCraft-მა ვერ გახსნა ბიბლიოთეკა მისამართზე", + "There is no LightCraft library in this folder any more.": "ამ საქაღალდეში LightCraft-ის ბიბლიოთეკა აღარ არის.", + "The library isn't there: it was moved or renamed, or its drive or network share isn't connected.": "ბიბლიოთეკა აქ არ არის: ის გადაიტანეს ან გადაარქვეს სახელი, ან მისი დისკი ან ქსელური საქაღალდე არ არის მიერთებული.", + "This folder can't be read:": "ამ საქაღალდის წაკითხვა ვერ ხერხდება:", "LightCraft does not know this model, so it assumed:": "LightCraft-მა ეს მოდელი არ იცის, ამიტომ ივარაუდა:", "LightCraft no longer crashes at launch on Windows PCs whose Vulkan driver is broken (issue #136, e.g. some Intel UHD": "LightCraft აღარ ითიშება გაშვებისას Windows კომპიუტერებზე, რომელთა Vulkan დრაივერი გაუმართავია (ხარვეზი #136, მაგ. ზოგიერთი Intel UHD", "LightCraft on GitHub": "LightCraft GitHub-ზე", diff --git a/crates/ui-egui/locales/pl.json b/crates/ui-egui/locales/pl.json index adac22e62..867bb5f44 100644 --- a/crates/ui-egui/locales/pl.json +++ b/crates/ui-egui/locales/pl.json @@ -743,6 +743,9 @@ "LightCraft could not start": "Nie można uruchomić LightCraft", "LightCraft couldn't find where to keep your library.": "LightCraft nie znalazł miejsca na przechowywanie biblioteki.", "LightCraft couldn't open the library at": "LightCraft nie mógł otworzyć biblioteki w lokalizacji", + "There is no LightCraft library in this folder any more.": "W tym folderze nie ma już biblioteki LightCraft.", + "The library isn't there: it was moved or renamed, or its drive or network share isn't connected.": "Biblioteki tu nie ma: została przeniesiona lub zmieniono jej nazwę albo jej dysk lub udział sieciowy nie jest podłączony.", + "This folder can't be read:": "Nie można odczytać tego folderu:", "LightCraft on GitHub": "LightCraft w serwisie GitHub", "LightCraft website": "Strona internetowa LightCraft", "LightCraft — Second Window": "LightCraft — drugie okno", diff --git a/crates/ui-egui/locales/pt-br.json b/crates/ui-egui/locales/pt-br.json index e84fb7615..9070e7025 100644 --- a/crates/ui-egui/locales/pt-br.json +++ b/crates/ui-egui/locales/pt-br.json @@ -770,6 +770,9 @@ "LightCraft could not start": "Não foi possível iniciar o LightCraft", "LightCraft couldn't find where to keep your library.": "O LightCraft não conseguiu encontrar onde guardar sua biblioteca.", "LightCraft couldn't open the library at": "O LightCraft não conseguiu abrir a biblioteca em", + "There is no LightCraft library in this folder any more.": "Esta pasta não tem mais uma biblioteca do LightCraft.", + "The library isn't there: it was moved or renamed, or its drive or network share isn't connected.": "A biblioteca não está aqui: foi movida ou renomeada, ou o disco ou compartilhamento de rede dela não está conectado.", + "This folder can't be read:": "Não é possível ler esta pasta:", "LightCraft on GitHub": "LightCraft no GitHub", "LightCraft website": "Site do LightCraft", "LightCraft — Second Window": "LightCraft — segunda janela", diff --git a/crates/ui-egui/locales/ru.json b/crates/ui-egui/locales/ru.json index 306804df0..b460423e8 100644 --- a/crates/ui-egui/locales/ru.json +++ b/crates/ui-egui/locales/ru.json @@ -640,6 +640,9 @@ "LightCraft could not start": "Не удалось запустить LightCraft", "LightCraft couldn't find where to keep your library.": "LightCraft не удалось найти место для хранения вашей библиотеки.", "LightCraft couldn't open the library at": "LightCraft не удалось открыть библиотеку в", + "There is no LightCraft library in this folder any more.": "В этой папке больше нет библиотеки LightCraft.", + "The library isn't there: it was moved or renamed, or its drive or network share isn't connected.": "Библиотеки здесь нет: её переместили или переименовали, либо её диск или сетевая папка не подключены.", + "This folder can't be read:": "Не удаётся прочитать эту папку:", "LightCraft on GitHub": "LightCraft на GitHub", "LightCraft website": "Сайт LightCraft", "LightCraft — Second Window": "LightCraft — второе окно", diff --git a/crates/ui-egui/locales/sv.json b/crates/ui-egui/locales/sv.json index 66e69b7ba..e78e4fce0 100644 --- a/crates/ui-egui/locales/sv.json +++ b/crates/ui-egui/locales/sv.json @@ -1137,6 +1137,9 @@ "LightCraft could not start": "LightCraft kunde inte starta", "LightCraft couldn't find where to keep your library.": "LightCraft hittade ingen plats att spara ditt bibliotek på.", "LightCraft couldn't open the library at": "LightCraft kunde inte öppna biblioteket på", + "There is no LightCraft library in this folder any more.": "Det finns inte längre något LightCraft-bibliotek i den här mappen.", + "The library isn't there: it was moved or renamed, or its drive or network share isn't connected.": "Biblioteket finns inte där: det har flyttats eller bytt namn, eller så är dess enhet eller nätverksresurs inte ansluten.", + "This folder can't be read:": "Den här mappen kan inte läsas:", "LightCraft Default": "LightCraft-standard", "LightCraft does not know this model, so it assumed:": "LightCraft känner inte till den här modellen och antog därför:", "LightCraft Help": "LightCraft-hjälp", diff --git a/crates/ui-egui/locales/uk.json b/crates/ui-egui/locales/uk.json index ee694ed4f..c9718cab2 100644 --- a/crates/ui-egui/locales/uk.json +++ b/crates/ui-egui/locales/uk.json @@ -1629,6 +1629,9 @@ "Your library couldn't be opened": "Не вдалося відкрити вашу бібліотеку", "LightCraft couldn't find where to keep your library.": "LightCraft не вдалося знайти місце для бібліотеки.", "LightCraft couldn't open the library at": "LightCraft не вдалося відкрити бібліотеку в", + "There is no LightCraft library in this folder any more.": "У цій папці більше немає бібліотеки LightCraft.", + "The library isn't there: it was moved or renamed, or its drive or network share isn't connected.": "Бібліотеки тут немає: її перемістили чи перейменували, або її диск чи мережеву папку не підключено.", + "This folder can't be read:": "Не вдається прочитати цю папку:", "Try Again": "Спробувати знову", "Choose Another Library…": "Вибрати іншу бібліотеку…", "Continue Without Saving": "Продовжити без збереження", diff --git a/crates/ui-egui/locales/vi.json b/crates/ui-egui/locales/vi.json index e4fb8feb8..c9132ed84 100644 --- a/crates/ui-egui/locales/vi.json +++ b/crates/ui-egui/locales/vi.json @@ -958,6 +958,9 @@ "LightCraft could not start": "LightCraft không thể khởi động", "LightCraft couldn't find where to keep your library.": "LightCraft không tìm được nơi lưu thư viện của bạn.", "LightCraft couldn't open the library at": "LightCraft không mở được thư viện tại", + "There is no LightCraft library in this folder any more.": "Thư mục này không còn thư viện LightCraft nào.", + "The library isn't there: it was moved or renamed, or its drive or network share isn't connected.": "Thư viện không có ở đây: nó đã bị di chuyển hoặc đổi tên, hoặc ổ đĩa hay ổ mạng của nó chưa được kết nối.", + "This folder can't be read:": "Không đọc được thư mục này:", "LightCraft does not know this model, so it assumed:": "LightCraft không biết mô hình này, nên đã giả định:", "LightCraft no longer crashes at launch on Windows PCs whose Vulkan driver is broken (issue #136, e.g. some Intel UHD": "LightCraft không còn sự cố khi khởi động trên PC Windows có driver Vulkan lỗi (issue #136, ví dụ một số Intel UHD", "LightCraft on GitHub": "LightCraft trên GitHub", diff --git a/crates/ui-egui/locales/zh-hans.json b/crates/ui-egui/locales/zh-hans.json index 270af8a62..10190086a 100644 --- a/crates/ui-egui/locales/zh-hans.json +++ b/crates/ui-egui/locales/zh-hans.json @@ -867,6 +867,9 @@ "LightCraft Website": "LightCraft 网站", "LightCraft couldn't find where to keep your library.": "LightCraft 找不到保存图库的位置。", "LightCraft couldn't open the library at": "LightCraft 无法打开以下位置的图库:", + "There is no LightCraft library in this folder any more.": "此文件夹中已经没有 LightCraft 图库。", + "The library isn't there: it was moved or renamed, or its drive or network share isn't connected.": "图库不在这里:它已被移动或重命名,或者它所在的驱动器或网络共享未连接。", + "This folder can't be read:": "无法读取此文件夹:", "LightCraft on GitHub": "GitHub 上的 LightCraft", "LightCraft website": "LightCraft 网站", "LightCraft — Second Window": "LightCraft — 第二窗口", diff --git a/crates/ui-egui/locales/zh-hant.json b/crates/ui-egui/locales/zh-hant.json index 0408e23ec..259ae52da 100644 --- a/crates/ui-egui/locales/zh-hant.json +++ b/crates/ui-egui/locales/zh-hant.json @@ -868,6 +868,9 @@ "LightCraft Website": "LightCraft 網站", "LightCraft couldn't find where to keep your library.": "LightCraft 找不到儲存照片庫的位置。", "LightCraft couldn't open the library at": "LightCraft 無法開啟此位置的照片庫:", + "There is no LightCraft library in this folder any more.": "這個資料夾中已經沒有 LightCraft 照片庫。", + "The library isn't there: it was moved or renamed, or its drive or network share isn't connected.": "照片庫不在這裡:它已被移動或重新命名,或是它所在的磁碟機或網路共用資料夾未連線。", + "This folder can't be read:": "無法讀取這個資料夾:", "LightCraft on GitHub": "GitHub 上的 LightCraft", "LightCraft website": "LightCraft 網站", "LightCraft — Second Window": "LightCraft — 第二視窗", diff --git a/crates/ui-egui/src/panels/library_problem.rs b/crates/ui-egui/src/panels/library_problem.rs index 1d83a2ff5..6ba99b0c6 100644 --- a/crates/ui-egui/src/panels/library_problem.rs +++ b/crates/ui-egui/src/panels/library_problem.rs @@ -720,12 +720,17 @@ fn unavailable(path: &str) -> Option { } /// Why the library at `dir` that has to exist already (a remembered one, issue #3239) can't be -/// opened: the folder is there without a catalog, or the folder itself is missing. -pub fn missing_library_reason(dir: &Path) -> &'static str { - if dir.exists() { - "There is no LightCraft library in this folder any more." - } else { - "The library isn't there: it was moved or renamed, or its drive or network share isn't connected." +/// opened (`None`: it's there): the folder is there without a catalog, or the folder itself is +/// missing. A folder that can't be looked into (no permission, a share that timed out) says so +/// instead: the library may well be there. +pub fn missing_library_reason(dir: &Path) -> Option { + match lightcraft_engine::library::library_state(dir) { + Ok(true) => None, + Ok(false) if dir.exists() => Some(crate::i18n::tr("There is no LightCraft library in this folder any more.").to_string()), + Ok(false) => { + Some(crate::i18n::tr("The library isn't there: it was moved or renamed, or its drive or network share isn't connected.").to_string()) + } + Err(e) => Some(format!("{} {e}", crate::i18n::tr("This folder can't be read:"))), } } @@ -733,10 +738,11 @@ pub fn missing_library_reason(dir: &Path) -> &'static str { /// opened only once its folder holds a library again (a share remounted): until then the window /// stays with the reason, and nothing is created there (issue #3239). fn retry(app: &mut LightcraftApp, problem: LibraryProblem) { - let dir = Path::new(&problem.path); - if problem.existing_only && !lightcraft_engine::library::is_library(dir) { + if problem.existing_only + && let Some(why) = missing_library_reason(Path::new(&problem.path)) + { if let Some(p) = app.library_problem.as_mut() { - p.error = missing_library_reason(dir).to_string(); + p.error = why; p.dismissed = false; } return; diff --git a/crates/ui-egui/src/tests/launch_library.rs b/crates/ui-egui/src/tests/launch_library.rs index 9d71b7978..935a44b25 100644 --- a/crates/ui-egui/src/tests/launch_library.rs +++ b/crates/ui-egui/src/tests/launch_library.rs @@ -1063,3 +1063,72 @@ fn try_again_on_a_missing_remembered_library_makes_nothing_in_an_empty_folder() drop(h); let _ = std::fs::remove_dir_all(&dir); } + +/// Issue #3239: why Try Again didn't open a remembered library is in the interface language, +/// both when its folder is empty and when the folder itself is gone. +#[test] +fn try_again_says_why_the_remembered_library_is_missing_in_the_interface_language() { + let dir = temp("retry-lang"); + let mount = dir.join("Share"); + std::fs::create_dir_all(&mount).unwrap(); + let path = mount.to_string_lossy().into_owned(); + let mut app = LightcraftApp::new(lightcraft_engine::Session::new().with_fs(), Services::default()); + app.ui.language = crate::i18n::Locale::De; + app.library_problem = Some(LibraryProblem { existing_only: true, ..LibraryProblem::new(path, "missing") }); + let mut h = Headless::new(app, [1300.0, 900.0], 1.0); + settle(&mut h); + assert_eq!(h.request("ui.clickWidget", json!({"id": "button:libraryRetry"}), T)["ok"], true); + settle(&mut h); + let error = h.app.library_problem.as_ref().map(|p| p.error.clone()).unwrap_or_default(); + assert_eq!(error, "In diesem Ordner ist keine LightCraft-Bibliothek mehr."); + std::fs::remove_dir(&mount).unwrap(); + assert_eq!(h.request("ui.clickWidget", json!({"id": "button:libraryRetry"}), T)["ok"], true); + settle(&mut h); + let error = h.app.library_problem.as_ref().map(|p| p.error.clone()).unwrap_or_default(); + crate::i18n::set_language(crate::i18n::Locale::En); + assert!(error.starts_with("Die Bibliothek ist nicht da:"), "{error}"); + assert!(!mount.exists(), "nothing is made where it was"); + drop(h); + let _ = std::fs::remove_dir_all(&dir); +} + +/// Issue #3239: a remembered library whose folder can't be looked into (no permission) isn't +/// reported as gone: Try Again says the folder can't be read, and nothing is written there. +#[cfg(unix)] +#[test] +fn try_again_on_a_remembered_library_it_may_not_read_says_so() { + use std::os::unix::fs::PermissionsExt; + let dir = temp("retry-denied"); + let locked = dir.join("Locked"); + let path = make_library(&locked); + let names = |dir: &Path| { + let mut names: Vec<_> = std::fs::read_dir(dir).unwrap().flatten().map(|e| e.file_name()).collect(); + names.sort(); + names + }; + let before = names(&locked); + std::fs::set_permissions(&locked, std::fs::Permissions::from_mode(0o000)).unwrap(); + let readable = std::fs::read_dir(&locked).is_ok(); + let mut app = LightcraftApp::new(lightcraft_engine::Session::new().with_fs(), Services::default()); + app.library_problem = Some(LibraryProblem { existing_only: true, ..LibraryProblem::new(path, "missing") }); + let mut h = Headless::new(app, [1300.0, 900.0], 1.0); + settle(&mut h); + if !readable { + assert_eq!(h.request("ui.clickWidget", json!({"id": "button:libraryRetry"}), T)["ok"], true); + settle(&mut h); + } + let error = h.app.library_problem.as_ref().map(|p| p.error.clone()).unwrap_or_default(); + let library = h.app.session.library.is_some(); + drop(h); + std::fs::set_permissions(&locked, std::fs::Permissions::from_mode(0o755)).unwrap(); + if readable { + let _ = std::fs::remove_dir_all(&dir); + lightcraft_testkit::skip!(System, "running as root: a folder with mode 000 is still readable"); + return; + } + assert!(error.starts_with("This folder can't be read:"), "{error}"); + assert!(error.to_lowercase().contains("permission denied"), "{error}"); + assert!(!library, "nothing opened"); + assert_eq!(names(&locked), before, "nothing written there"); + let _ = std::fs::remove_dir_all(&dir); +} diff --git a/docs/whats-new.md b/docs/whats-new.md index fa3564385..5c8bb9d89 100644 --- a/docs/whats-new.md +++ b/docs/whats-new.md @@ -9,8 +9,9 @@ filled it with the demo photos and opened it, so it looked as if the photos and edits were gone. Nothing is written there now, and Try Again opens the library once its drive or share is back: on an empty folder left in its place, such as a share's mount point, it says so again instead of making a new library there. A library - given with `--library` or `LIGHTCRAFT_LIBRARY`, and the default location on first launch, are still created as - before. + folder LightCraft isn't allowed to read is reported as unreadable, with the system's reason, not as gone. A + library given with `--library` or `LIGHTCRAFT_LIBRARY`, and the default location on first launch, are still + created as before. ## 2026-10-24