mirror of
https://github.com/drakmor/ShadowMountPlus.git
synced 2026-10-23 07:02:26 -05:00
bugfixes, revert 512 md sector size
This commit is contained in:
1 parent
f4cd231010
commit
428856cd89
1 file changed
+158
-68
+158
-68
@@ -104,6 +104,38 @@ struct UfsCache {
|
||||
};
|
||||
struct UfsCache ufs_cache[MAX_UFS_MOUNTS];
|
||||
|
||||
static void copy_cstr(char *dst, size_t dst_size, const char *src) {
|
||||
if (dst_size == 0)
|
||||
return;
|
||||
if (!src)
|
||||
src = "";
|
||||
snprintf(dst, dst_size, "%s", src);
|
||||
}
|
||||
|
||||
static void cache_game_entry(const char *path, const char *title_id,
|
||||
const char *title_name) {
|
||||
for (int k = 0; k < MAX_PENDING; k++) {
|
||||
if (!cache[k].valid) {
|
||||
copy_cstr(cache[k].path, sizeof(cache[k].path), path);
|
||||
copy_cstr(cache[k].title_id, sizeof(cache[k].title_id), title_id);
|
||||
copy_cstr(cache[k].title_name, sizeof(cache[k].title_name), title_name);
|
||||
cache[k].valid = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cache_ufs_mount(const char *path, unsigned md_unit) {
|
||||
for (int k = 0; k < MAX_UFS_MOUNTS; k++) {
|
||||
if (!ufs_cache[k].valid) {
|
||||
copy_cstr(ufs_cache[k].path, sizeof(ufs_cache[k].path), path);
|
||||
ufs_cache[k].md_unit = md_unit;
|
||||
ufs_cache[k].valid = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- LOGGING ---
|
||||
void log_to_file(const char *fmt, va_list args) {
|
||||
mkdir(LOG_DIR, 0777);
|
||||
@@ -123,10 +155,13 @@ void log_to_file(const char *fmt, va_list args) {
|
||||
}
|
||||
void log_debug(const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_list args_copy;
|
||||
va_start(args, fmt);
|
||||
va_copy(args_copy, args);
|
||||
vprintf(fmt, args);
|
||||
printf("\n");
|
||||
log_to_file(fmt, args);
|
||||
log_to_file(fmt, args_copy);
|
||||
va_end(args_copy);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
@@ -206,12 +241,14 @@ static int remount_system_ex(void) {
|
||||
IOVEC_ENTRY("ignoreacl"), IOVEC_ENTRY(NULL)};
|
||||
return nmount(iov, IOVEC_SIZE(iov), MNT_UPDATE);
|
||||
}
|
||||
|
||||
static int mount_nullfs(const char *src, const char *dst) {
|
||||
struct iovec iov[] = {IOVEC_ENTRY("fstype"), IOVEC_ENTRY("nullfs"),
|
||||
IOVEC_ENTRY("from"), IOVEC_ENTRY(src),
|
||||
IOVEC_ENTRY("fspath"), IOVEC_ENTRY(dst)};
|
||||
return nmount(iov, IOVEC_SIZE(iov), MNT_RDONLY);
|
||||
}
|
||||
|
||||
static int copy_dir(const char *src, const char *dst) {
|
||||
mkdir(dst, 0777);
|
||||
DIR *d = opendir(src);
|
||||
@@ -249,6 +286,7 @@ static int copy_dir(const char *src, const char *dst) {
|
||||
closedir(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int copy_file(const char *src, const char *dst) {
|
||||
char buf[8192];
|
||||
FILE *fs = fopen(src, "rb");
|
||||
@@ -268,26 +306,53 @@ int copy_file(const char *src, const char *dst) {
|
||||
}
|
||||
|
||||
// --- UFS2 IMAGE MOUNTING ---
|
||||
static void build_iovec(struct iovec **iov, int *iovlen, const char *name,
|
||||
static bool build_iovec(struct iovec **iov, int *iovlen, const char *name,
|
||||
const void *val, size_t len) {
|
||||
int i;
|
||||
if (*iovlen < 0)
|
||||
return;
|
||||
i = *iovlen;
|
||||
*iov = realloc(*iov, sizeof(**iov) * (i + 2));
|
||||
if (*iov == NULL) {
|
||||
*iovlen = -1;
|
||||
return;
|
||||
}
|
||||
(*iov)[i].iov_base = strdup(name);
|
||||
int i = *iovlen;
|
||||
struct iovec *tmp = realloc(*iov, sizeof(**iov) * (i + 2));
|
||||
if (!tmp)
|
||||
return false;
|
||||
*iov = tmp;
|
||||
|
||||
char *name_copy = strdup(name);
|
||||
if (!name_copy)
|
||||
return false;
|
||||
|
||||
(*iov)[i].iov_base = name_copy;
|
||||
(*iov)[i].iov_len = strlen(name) + 1;
|
||||
i++;
|
||||
(*iov)[i].iov_base = (void *)val;
|
||||
if (len == (size_t)-1) {
|
||||
if (len == (size_t)-1)
|
||||
len = val ? strlen((const char *)val) + 1 : 0;
|
||||
}
|
||||
(*iov)[i].iov_len = (int)len;
|
||||
*iovlen = ++i;
|
||||
*iovlen = i + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void free_iovec(struct iovec *iov, int iovlen) {
|
||||
if (!iov)
|
||||
return;
|
||||
for (int i = 0; i < iovlen; i += 2)
|
||||
free(iov[i].iov_base);
|
||||
free(iov);
|
||||
}
|
||||
|
||||
static void detach_md_unit(unsigned md_unit) {
|
||||
int mdctl = open("/dev/mdctl", O_RDWR);
|
||||
if (mdctl < 0) {
|
||||
log_debug(" [UFS] open /dev/mdctl for detach failed: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
struct md_ioctl mdio;
|
||||
memset(&mdio, 0, sizeof(mdio));
|
||||
mdio.md_version = MDIOVERSION;
|
||||
mdio.md_unit = md_unit;
|
||||
if (ioctl(mdctl, MDIOCDETACH, &mdio) != 0) {
|
||||
log_debug(" [UFS] MDIOCDETACH /dev/md%u failed: %s", md_unit,
|
||||
strerror(errno));
|
||||
}
|
||||
close(mdctl);
|
||||
}
|
||||
|
||||
static bool is_ufs_image(const char *name) {
|
||||
@@ -306,6 +371,34 @@ static void strip_extension(const char *filename, char *out, size_t out_size) {
|
||||
out[len] = '\0';
|
||||
}
|
||||
|
||||
static void build_ufs_mount_point(const char *file_path, char *mount_point,
|
||||
size_t mount_point_size) {
|
||||
const char *filename = strrchr(file_path, '/');
|
||||
filename = filename ? filename + 1 : file_path;
|
||||
char mount_name[MAX_PATH];
|
||||
strip_extension(filename, mount_name, sizeof(mount_name));
|
||||
snprintf(mount_point, mount_point_size, "%s/%s", UFS_MOUNT_BASE, mount_name);
|
||||
}
|
||||
|
||||
static void unmount_ufs_image(const char *file_path, unsigned md_unit) {
|
||||
char mount_point[MAX_PATH];
|
||||
build_ufs_mount_point(file_path, mount_point, sizeof(mount_point));
|
||||
|
||||
if (unmount(mount_point, 0) != 0) {
|
||||
int unmount_err = errno;
|
||||
if (unmount_err != ENOENT && unmount_err != EINVAL) {
|
||||
if (unmount(mount_point, MNT_FORCE) != 0 && errno != ENOENT &&
|
||||
errno != EINVAL) {
|
||||
log_debug(" [UFS] unmount failed for %s: %s", mount_point,
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (md_unit != 0)
|
||||
detach_md_unit(md_unit);
|
||||
}
|
||||
|
||||
static bool mount_ufs_image(const char *file_path) {
|
||||
// Check if already in UFS cache
|
||||
for (int k = 0; k < MAX_UFS_MOUNTS; k++) {
|
||||
@@ -313,15 +406,11 @@ static bool mount_ufs_image(const char *file_path) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Extract filename and strip extension for mount point name
|
||||
// Extract filename for logs and mount point
|
||||
const char *filename = strrchr(file_path, '/');
|
||||
filename = filename ? filename + 1 : file_path;
|
||||
char mount_name[MAX_PATH];
|
||||
strip_extension(filename, mount_name, sizeof(mount_name));
|
||||
|
||||
char mount_point[MAX_PATH];
|
||||
snprintf(mount_point, sizeof(mount_point), "%s/%s", UFS_MOUNT_BASE,
|
||||
mount_name);
|
||||
build_ufs_mount_point(file_path, mount_point, sizeof(mount_point));
|
||||
|
||||
// Check if already mounted (e.g. from previous run)
|
||||
struct stat mst;
|
||||
@@ -341,14 +430,7 @@ static bool mount_ufs_image(const char *file_path) {
|
||||
if (count > 0) {
|
||||
log_debug(" [UFS] Already mounted: %s", mount_point);
|
||||
// Add to cache so we don't re-check
|
||||
for (int k = 0; k < MAX_UFS_MOUNTS; k++) {
|
||||
if (!ufs_cache[k].valid) {
|
||||
strncpy(ufs_cache[k].path, file_path, MAX_PATH);
|
||||
ufs_cache[k].md_unit = 0;
|
||||
ufs_cache[k].valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
cache_ufs_mount(file_path, 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -387,8 +469,8 @@ static bool mount_ufs_image(const char *file_path) {
|
||||
mdio.md_type = MD_VNODE;
|
||||
mdio.md_file = (char *)file_path;
|
||||
mdio.md_mediasize = st.st_size;
|
||||
mdio.md_sectorsize = 4096; // was 512
|
||||
mdio.md_options = MD_AUTOUNIT | MD_READONLY;
|
||||
mdio.md_sectorsize = 512; // was 512
|
||||
mdio.md_options = MD_AUTOUNIT | MD_READONLY | MD_ASYNC;
|
||||
|
||||
int ret = ioctl(mdctl, MDIOCATTACH, &mdio);
|
||||
if (ret != 0) {
|
||||
@@ -408,13 +490,18 @@ static bool mount_ufs_image(const char *file_path) {
|
||||
|
||||
struct iovec *iov = NULL;
|
||||
int iovlen = 0;
|
||||
build_iovec(&iov, &iovlen, "from", devname, (size_t)-1);
|
||||
build_iovec(&iov, &iovlen, "fspath", mount_point, (size_t)-1);
|
||||
build_iovec(&iov, &iovlen, "fstype", "exfatfs", (size_t)-1);
|
||||
build_iovec(&iov, &iovlen, "large", "yes", (size_t)-1);
|
||||
build_iovec(&iov, &iovlen, "timezone", "static", (size_t)-1);
|
||||
build_iovec(&iov, &iovlen, "async", NULL, (size_t)-1);
|
||||
build_iovec(&iov, &iovlen, "ignoreacl",NULL, (size_t)-1);
|
||||
if (!build_iovec(&iov, &iovlen, "from", devname, (size_t)-1) ||
|
||||
!build_iovec(&iov, &iovlen, "fspath", mount_point, (size_t)-1) ||
|
||||
!build_iovec(&iov, &iovlen, "fstype", "exfatfs", (size_t)-1) ||
|
||||
!build_iovec(&iov, &iovlen, "large", "yes", (size_t)-1) ||
|
||||
!build_iovec(&iov, &iovlen, "timezone", "static", (size_t)-1) ||
|
||||
!build_iovec(&iov, &iovlen, "async", NULL, (size_t)-1) ||
|
||||
!build_iovec(&iov, &iovlen, "ignoreacl", NULL, (size_t)-1)) {
|
||||
log_debug(" [UFS] build_iovec failed");
|
||||
free_iovec(iov, iovlen);
|
||||
detach_md_unit(mdio.md_unit);
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = nmount(iov, iovlen, MNT_RDONLY);
|
||||
if (ret != 0) {
|
||||
@@ -423,32 +510,27 @@ static bool mount_ufs_image(const char *file_path) {
|
||||
ret = nmount(iov, iovlen, 0);
|
||||
if (ret != 0) {
|
||||
log_debug(" [UFS] nmount failed: %s", strerror(errno));
|
||||
free(iov);
|
||||
free_iovec(iov, iovlen);
|
||||
detach_md_unit(mdio.md_unit);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
free(iov);
|
||||
free_iovec(iov, iovlen);
|
||||
|
||||
log_debug(" [UFS] Mounted %s -> %s", devname, mount_point);
|
||||
|
||||
// Cache it
|
||||
for (int k = 0; k < MAX_UFS_MOUNTS; k++) {
|
||||
if (!ufs_cache[k].valid) {
|
||||
strncpy(ufs_cache[k].path, file_path, MAX_PATH);
|
||||
ufs_cache[k].md_unit = mdio.md_unit;
|
||||
ufs_cache[k].valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
cache_ufs_mount(file_path, mdio.md_unit);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void scan_ufs_images() {
|
||||
// Clean stale UFS cache entries
|
||||
// UFS cache handles mount/unmount lifecycle only.
|
||||
for (int k = 0; k < MAX_UFS_MOUNTS; k++) {
|
||||
if (ufs_cache[k].valid && access(ufs_cache[k].path, F_OK) != 0) {
|
||||
log_debug(" [UFS] Cache invalidated: %s", ufs_cache[k].path);
|
||||
log_debug(" [UFS] Source removed, unmounting: %s", ufs_cache[k].path);
|
||||
unmount_ufs_image(ufs_cache[k].path, ufs_cache[k].md_unit);
|
||||
ufs_cache[k].valid = false;
|
||||
}
|
||||
}
|
||||
@@ -484,6 +566,15 @@ static void scan_ufs_images() {
|
||||
}
|
||||
}
|
||||
|
||||
static void shutdown_ufs_mounts(void) {
|
||||
for (int k = 0; k < MAX_UFS_MOUNTS; k++) {
|
||||
if (!ufs_cache[k].valid)
|
||||
continue;
|
||||
unmount_ufs_image(ufs_cache[k].path, ufs_cache[k].md_unit);
|
||||
ufs_cache[k].valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
// --- JSON ---
|
||||
static int extract_json_string(const char *json, const char *key, char *out,
|
||||
size_t out_size) {
|
||||
@@ -510,6 +601,9 @@ static int extract_json_string(const char *json, const char *key, char *out,
|
||||
}
|
||||
|
||||
bool get_game_info(const char *base_path, char *out_id, char *out_name) {
|
||||
out_id[0] = '\0';
|
||||
out_name[0] = '\0';
|
||||
|
||||
char path[MAX_PATH];
|
||||
snprintf(path, sizeof(path), "%s/sce_sys/param.json", base_path);
|
||||
FILE *f = fopen(path, "rb");
|
||||
@@ -532,7 +626,7 @@ bool get_game_info(const char *base_path, char *out_id, char *out_name) {
|
||||
MAX_TITLE_NAME) != 0)
|
||||
extract_json_string(buf, "titleName", out_name, MAX_TITLE_NAME);
|
||||
if (strlen(out_name) == 0)
|
||||
strncpy(out_name, out_id, MAX_TITLE_NAME);
|
||||
copy_cstr(out_name, MAX_TITLE_NAME, out_id);
|
||||
free(buf);
|
||||
fclose(f);
|
||||
return true;
|
||||
@@ -682,17 +776,7 @@ void scan_all_paths() {
|
||||
|
||||
char title_id[MAX_TITLE_ID];
|
||||
char title_name[MAX_TITLE_NAME];
|
||||
if (get_game_info(full_path, title_id, title_name)) {
|
||||
for (int k = 0; k < MAX_PENDING; k++) {
|
||||
if (!cache[k].valid) {
|
||||
strncpy(cache[k].path, full_path, MAX_PATH);
|
||||
strncpy(cache[k].title_id, title_id, MAX_TITLE_ID);
|
||||
strncpy(cache[k].title_name, title_name, MAX_TITLE_NAME);
|
||||
cache[k].valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!get_game_info(full_path, title_id, title_name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -718,7 +802,9 @@ void scan_all_paths() {
|
||||
is_remount = false;
|
||||
}
|
||||
|
||||
mount_and_install(full_path, title_id, title_name, is_remount);
|
||||
if (mount_and_install(full_path, title_id, title_name, is_remount)) {
|
||||
cache_game_entry(full_path, title_id, title_name);
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
@@ -734,7 +820,7 @@ int main() {
|
||||
remove(LOG_FILE);
|
||||
mkdir(LOG_DIR, 0777);
|
||||
|
||||
log_debug("SHADOWMOUNT v1.4 START");
|
||||
log_debug("SHADOWMOUNT v1.4 START exFAT");
|
||||
|
||||
// --- MOUNT UFS IMAGES ---
|
||||
scan_ufs_images();
|
||||
@@ -744,10 +830,10 @@ int main() {
|
||||
|
||||
if (new_games == 0) {
|
||||
// SCENARIO A: Nothing to do.
|
||||
notify_system("ShadowMount v1.4: Library Ready.\n- VoidWhisper");
|
||||
notify_system("ShadowMount v1.4 exFAT: Library Ready.\n- VoidWhisper");
|
||||
} else {
|
||||
// SCENARIO B: Work needed.
|
||||
notify_system("ShadowMount v1.4: Found %d Games. Executing...", new_games);
|
||||
notify_system("ShadowMount v1.4 exFAT: Found %d Games. Executing...", new_games);
|
||||
|
||||
// Run the scan immediately to process them
|
||||
scan_all_paths();
|
||||
@@ -759,14 +845,14 @@ int main() {
|
||||
// --- DAEMON LOOP ---
|
||||
int lock = open(LOCK_FILE, O_CREAT | O_EXCL | O_RDWR, 0666);
|
||||
if (lock < 0 && errno == EEXIST) {
|
||||
sceUserServiceTerminate();
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (access(KILL_FILE, F_OK) == 0) {
|
||||
remove(KILL_FILE);
|
||||
remove(LOCK_FILE);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// Sleep FIRST since we either just finished scan above, or library was
|
||||
@@ -777,6 +863,10 @@ int main() {
|
||||
scan_all_paths();
|
||||
}
|
||||
|
||||
if (lock >= 0)
|
||||
close(lock);
|
||||
shutdown_ufs_mounts();
|
||||
remove(LOCK_FILE);
|
||||
sceUserServiceTerminate();
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user