mirror of
https://github.com/drakmor/ShadowMountPlus.git
synced 2026-10-21 22:22:28 -05:00
Detect unreadable image mounts and report them as damaged images
This commit is contained in:
1 parent
ef814ad56b
commit
270264cc75
2 files changed
+109
-53
No files matched your search
+106
-49
@@ -409,6 +409,62 @@ static bool directory_has_visible_entries(const char *path) {
|
||||
return found;
|
||||
}
|
||||
|
||||
static bool is_image_mount_root_accessible(const char *mount_point,
|
||||
int *error_out) {
|
||||
if (error_out)
|
||||
*error_out = 0;
|
||||
|
||||
DIR *dir = opendir(mount_point);
|
||||
if (!dir) {
|
||||
if (error_out)
|
||||
*error_out = errno;
|
||||
return false;
|
||||
}
|
||||
closedir(dir);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool reject_mounted_image_io(const char *file_path,
|
||||
attach_backend_t attach_backend, int unit_id,
|
||||
const char *devname,
|
||||
const char *mount_point, int io_err,
|
||||
const char *stage) {
|
||||
sm_error_set("IMG", io_err, file_path, "Mounted image is unreadable or damaged");
|
||||
log_debug(" [IMG][%s] unreadable or damaged mount (%s -> %s, %s): %s",
|
||||
attach_backend_name(attach_backend), devname, mount_point, stage,
|
||||
strerror(io_err));
|
||||
(void)unmount_image(file_path, unit_id, attach_backend);
|
||||
errno = io_err;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool prepare_image_mount_retry(const image_cache_entry_t *cached_entry,
|
||||
char mount_point[MAX_PATH],
|
||||
char source_path[MAX_PATH]) {
|
||||
build_image_mount_point(cached_entry->path, mount_point);
|
||||
(void)strlcpy(source_path, cached_entry->path, MAX_PATH);
|
||||
|
||||
if (is_active_image_mount_point(mount_point)) {
|
||||
int root_err = 0;
|
||||
if (is_image_mount_root_accessible(mount_point, &root_err))
|
||||
return false;
|
||||
|
||||
log_debug(" [IMG][%s] mount unreadable, retrying: %s -> %s: %s",
|
||||
attach_backend_name(cached_entry->backend), source_path,
|
||||
mount_point, strerror(root_err));
|
||||
if (!unmount_image(source_path, cached_entry->unit_id, cached_entry->backend))
|
||||
return false;
|
||||
} else {
|
||||
log_debug(" [IMG][%s] mount lost, retrying: %s -> %s",
|
||||
attach_backend_name(cached_entry->backend), source_path,
|
||||
mount_point);
|
||||
clear_cached_game(mount_point);
|
||||
}
|
||||
|
||||
clear_missing_param_entry(mount_point);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool reuse_existing_image_mount(const char *file_path,
|
||||
const char *mount_point,
|
||||
bool *cache_failed_out) {
|
||||
@@ -418,12 +474,22 @@ static bool reuse_existing_image_mount(const char *file_path,
|
||||
struct stat mount_st;
|
||||
if (stat(mount_point, &mount_st) != 0 || !S_ISDIR(mount_st.st_mode))
|
||||
return false;
|
||||
if (!directory_has_visible_entries(mount_point))
|
||||
return false;
|
||||
|
||||
attach_backend_t existing_backend = ATTACH_BACKEND_NONE;
|
||||
int existing_unit = -1;
|
||||
if (resolve_device_from_mount(mount_point, &existing_backend, &existing_unit)) {
|
||||
int root_err = 0;
|
||||
if (!is_image_mount_root_accessible(mount_point, &root_err)) {
|
||||
log_debug(" [IMG][%s] Existing mount unreadable, reattaching: %s -> %s: %s",
|
||||
attach_backend_name(existing_backend), file_path, mount_point,
|
||||
strerror(root_err));
|
||||
if (!unmount_image(file_path, existing_unit, existing_backend)) {
|
||||
if (cache_failed_out)
|
||||
*cache_failed_out = true;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!cache_image_mount(file_path, mount_point, existing_unit,
|
||||
existing_backend)) {
|
||||
sm_error_set("IMG", ENOSPC, file_path,
|
||||
@@ -441,6 +507,9 @@ static bool reuse_existing_image_mount(const char *file_path,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!directory_has_visible_entries(mount_point))
|
||||
return false;
|
||||
|
||||
log_debug(" [IMG] Mount point exists and is non-empty but is not an active "
|
||||
"mount, reattaching: %s", mount_point);
|
||||
return false;
|
||||
@@ -596,9 +665,8 @@ static bool validate_mounted_image(const char *file_path, image_fs_type_t fs_typ
|
||||
const char *mount_point) {
|
||||
struct statfs mounted_sfs;
|
||||
if (statfs(mount_point, &mounted_sfs) != 0) {
|
||||
log_debug(" [IMG][%s] statfs after mount failed for %s: %s",
|
||||
attach_backend_name(attach_backend), mount_point, strerror(errno));
|
||||
return true;
|
||||
return reject_mounted_image_io(file_path, attach_backend, unit_id, devname,
|
||||
mount_point, errno, "statfs");
|
||||
}
|
||||
|
||||
uint32_t min_device_sector =
|
||||
@@ -606,24 +674,31 @@ static bool validate_mounted_image(const char *file_path, image_fs_type_t fs_typ
|
||||
: get_lvd_sector_size(file_path,
|
||||
fs_type);
|
||||
uint64_t fs_block_size = (uint64_t)mounted_sfs.f_bsize;
|
||||
if (fs_block_size >= (uint64_t)min_device_sector)
|
||||
return true;
|
||||
if (fs_block_size < (uint64_t)min_device_sector) {
|
||||
sm_error_set("IMG", EINVAL, file_path,
|
||||
"Filesystem cluster size (%llu) is smaller than device "
|
||||
"sector size (%u) for %s",
|
||||
(unsigned long long)fs_block_size, min_device_sector, devname);
|
||||
log_debug(" [IMG][%s] %s", attach_backend_name(attach_backend),
|
||||
sm_last_error()->message);
|
||||
notify_system("Image mount rejected:\n%s\nCluster size is too small "
|
||||
"(%llu < %u).\nUse a larger cluster size in the image or "
|
||||
"lower sector size in config.",
|
||||
file_path, (unsigned long long)fs_block_size,
|
||||
min_device_sector);
|
||||
sm_error_mark_notified();
|
||||
(void)unmount_image(file_path, unit_id, attach_backend);
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
sm_error_set("IMG", EINVAL, file_path,
|
||||
"Filesystem cluster size (%llu) is smaller than device "
|
||||
"sector size (%u) for %s",
|
||||
(unsigned long long)fs_block_size, min_device_sector, devname);
|
||||
log_debug(" [IMG][%s] %s", attach_backend_name(attach_backend),
|
||||
sm_last_error()->message);
|
||||
notify_system("Image mount rejected:\n%s\nCluster size is too small "
|
||||
"(%llu < %u).\nUse a larger cluster size in the image or "
|
||||
"lower sector size in config.",
|
||||
file_path, (unsigned long long)fs_block_size,
|
||||
min_device_sector);
|
||||
sm_error_mark_notified();
|
||||
(void)unmount_image(file_path, unit_id, attach_backend);
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
int root_err = 0;
|
||||
if (!is_image_mount_root_accessible(mount_point, &root_err)) {
|
||||
return reject_mounted_image_io(file_path, attach_backend, unit_id, devname,
|
||||
mount_point, root_err, "root access");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// --- Image Attach + nmount Pipeline ---
|
||||
@@ -677,16 +752,16 @@ bool mount_image(const char *file_path, image_fs_type_t fs_type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
log_debug(" [IMG][%s] Mounted (%s) %s -> %s",
|
||||
attach_backend_name(attach_backend), image_fs_name(fs_type),
|
||||
devname, mount_point);
|
||||
log_fs_stats("IMG", mount_point, image_fs_name(fs_type));
|
||||
|
||||
if (!validate_mounted_image(file_path, fs_type, attach_backend, unit_id,
|
||||
devname, mount_point)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
log_debug(" [IMG][%s] Mounted (%s) %s -> %s",
|
||||
attach_backend_name(attach_backend), image_fs_name(fs_type),
|
||||
devname, mount_point);
|
||||
log_fs_stats("IMG", mount_point, image_fs_name(fs_type));
|
||||
|
||||
if (!cache_image_mount(file_path, mount_point, unit_id, attach_backend)) {
|
||||
sm_error_set("IMG", ENOSPC, file_path,
|
||||
"Image cache full (%u entries), rolling back mount",
|
||||
@@ -803,18 +878,9 @@ void cleanup_stale_image_mounts(void) {
|
||||
|
||||
image_fs_type_t fs_type = detect_image_fs_type(cached_entry.path);
|
||||
char mount_point[MAX_PATH];
|
||||
build_image_mount_point(cached_entry.path, mount_point);
|
||||
if (is_active_image_mount_point(mount_point))
|
||||
continue;
|
||||
|
||||
char source_path[MAX_PATH];
|
||||
(void)strlcpy(source_path, cached_entry.path, sizeof(source_path));
|
||||
log_debug(" [IMG][%s] mount lost, retrying: %s -> %s",
|
||||
attach_backend_name(cached_entry.backend), source_path,
|
||||
mount_point);
|
||||
|
||||
clear_cached_game(mount_point);
|
||||
clear_missing_param_entry(mount_point);
|
||||
if (!prepare_image_mount_retry(&cached_entry, mount_point, source_path))
|
||||
continue;
|
||||
|
||||
invalidate_image_cache_entry(k);
|
||||
if (mount_image(source_path, fs_type)) {
|
||||
@@ -860,18 +926,9 @@ void cleanup_stale_image_mounts_for_root(const char *root) {
|
||||
|
||||
image_fs_type_t fs_type = detect_image_fs_type(cached_entry.path);
|
||||
char mount_point[MAX_PATH];
|
||||
build_image_mount_point(cached_entry.path, mount_point);
|
||||
if (is_active_image_mount_point(mount_point))
|
||||
continue;
|
||||
|
||||
char source_path[MAX_PATH];
|
||||
(void)strlcpy(source_path, cached_entry.path, sizeof(source_path));
|
||||
log_debug(" [IMG][%s] mount lost, retrying: %s -> %s",
|
||||
attach_backend_name(cached_entry.backend), source_path,
|
||||
mount_point);
|
||||
|
||||
clear_cached_game(mount_point);
|
||||
clear_missing_param_entry(mount_point);
|
||||
if (!prepare_image_mount_retry(&cached_entry, mount_point, source_path))
|
||||
continue;
|
||||
|
||||
invalidate_image_cache_entry(k);
|
||||
if (mount_image(source_path, fs_type)) {
|
||||
|
||||
+3
-4
@@ -357,10 +357,9 @@ void notify_system(const char *fmt, ...) {
|
||||
|
||||
void notify_image_mount_failed(const char *path, int mount_err) {
|
||||
if (g_last_error.valid && g_last_error.message[0] != '\0') {
|
||||
notify_system("Image mount failed: 0x%08X (%s)\n%s\n%s",
|
||||
(uint32_t)mount_err, strerror(mount_err),
|
||||
g_last_error.message,
|
||||
(g_last_error.path[0] != '\0') ? g_last_error.path : path);
|
||||
const char *error_path =
|
||||
(g_last_error.path[0] != '\0') ? g_last_error.path : path;
|
||||
notify_system("%s\n%s", g_last_error.message, error_path);
|
||||
g_last_error.notified = true;
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user