diff --git a/platform/vfs.c b/platform/vfs.c index 41c32cf..84e8f16 100644 --- a/platform/vfs.c +++ b/platform/vfs.c @@ -16,9 +16,17 @@ static void vfs_slashify(wchar_t *path, size_t max_count); static HRESULT vfs_mkdir_rec(const wchar_t *path); static HRESULT vfs_path_hook(const wchar_t *src, wchar_t *dest, size_t *count); +static HRESULT vfs_path_hook_nthome( + const wchar_t *src, + wchar_t *dest, + size_t *count); static HRESULT vfs_reg_read_amfs(void *bytes, uint32_t *nbytes); static HRESULT vfs_reg_read_appdata(void *bytes, uint32_t *nbytes); +static wchar_t vfs_nthome_real[MAX_PATH]; +static const wchar_t vfs_nthome[] = L"C:\\Documents and Settings\\AppUser\\"; +static const size_t vfs_nthome_len = _countof(vfs_nthome) - 1; + static const struct reg_hook_val vfs_reg_vals[] = { { .name = L"AMFS", @@ -35,6 +43,9 @@ static struct vfs_config vfs_config; HRESULT vfs_hook_init(const struct vfs_config *config) { + wchar_t temp[MAX_PATH]; + size_t nthome_len; + DWORD home_ok; HRESULT hr; assert(config != NULL); @@ -43,10 +54,24 @@ HRESULT vfs_hook_init(const struct vfs_config *config) return S_FALSE; } + home_ok = GetEnvironmentVariableW( + L"USERPROFILE", + vfs_nthome_real, + _countof(vfs_nthome_real)); + + if (!home_ok) { + hr = HRESULT_FROM_WIN32(GetLastError()); + dprintf("Vfs: Failed to query %%USERPROFILE%% env var: %x\n", + (int) hr); + + return hr; + } + memcpy(&vfs_config, config, sizeof(*config)); vfs_slashify(vfs_config.amfs, _countof(vfs_config.amfs)); vfs_slashify(vfs_config.appdata, _countof(vfs_config.appdata)); + vfs_slashify(vfs_nthome_real, _countof(vfs_nthome_real)); hr = vfs_mkdir_rec(vfs_config.amfs); @@ -66,12 +91,30 @@ HRESULT vfs_hook_init(const struct vfs_config *config) dprintf("Vfs: NOTE: SEGA Y: drive APPDATA, not Windows %%APPDATA%%.\n"); } + /* Need to create the temp subdirectory, not just nthome itself */ + + nthome_len = wcslen(vfs_nthome_real); + wcscpy_s(temp, _countof(temp), vfs_nthome_real); + wcscpy_s(temp + nthome_len, _countof(temp) - nthome_len, L"temp"); + + hr = vfs_mkdir_rec(temp); + + if (FAILED(hr)) { + dprintf("Vfs: Failed to create %S: %x\n", temp, (int) hr); + } + hr = path_hook_push(vfs_path_hook); if (FAILED(hr)) { return hr; } + hr = path_hook_push(vfs_path_hook_nthome); + + if (FAILED(hr)) { + return hr; + } + hr = reg_hook_push_key( HKEY_LOCAL_MACHINE, L"SYSTEM\\SEGA\\SystemProperty\\mount", @@ -206,6 +249,42 @@ static HRESULT vfs_path_hook(const wchar_t *src, wchar_t *dest, size_t *count) return S_OK; } +static HRESULT vfs_path_hook_nthome( + const wchar_t *src, + wchar_t *dest, + size_t *count) +{ + size_t required; + size_t redir_len; + + assert(src != NULL); + assert(count != NULL); + + /* Case-insensitive check to see if src starts with vfs_nthome */ + + if (_wcsnicmp(src, vfs_nthome, vfs_nthome_len) != 0) { + return S_FALSE; + } + + /* Cut off the matched prefix, add the replaced prefix, count NUL */ + + redir_len = wcslen(vfs_nthome_real); + required = wcslen(src) - vfs_nthome_len + redir_len + 1; + + if (dest != NULL) { + if (required > *count) { + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + + wcscpy_s(dest, *count, vfs_nthome_real); + wcscpy_s(dest + redir_len, *count - redir_len, src + vfs_nthome_len); + } + + *count = required; + + return S_OK; +} + static HRESULT vfs_reg_read_amfs(void *bytes, uint32_t *nbytes) { return reg_hook_read_wstr(bytes, nbytes, vfs_config.amfs);