Implementation PersistentZoneIdentifer object without any writing and reading zone information. OS Windows uses NTFS alternative data stream Zone.Identifer to write and read zone information. Also due to lack of reading zone information some test cases fails.
-- v4: urlmon: Add PersistentZoneIdentifier implementation urlmon: Add PersistentZoneIdentifier test cases
From: Mike Kozelkov augenzi@etersoft.ru
--- dlls/urlmon/tests/Makefile.in | 3 +- dlls/urlmon/tests/zone_id.c | 569 ++++++++++++++++++++++++++++++++++ 2 files changed, 571 insertions(+), 1 deletion(-) create mode 100644 dlls/urlmon/tests/zone_id.c
diff --git a/dlls/urlmon/tests/Makefile.in b/dlls/urlmon/tests/Makefile.in index 797a3434e1f..ed3cacd02fd 100644 --- a/dlls/urlmon/tests/Makefile.in +++ b/dlls/urlmon/tests/Makefile.in @@ -8,4 +8,5 @@ SOURCES = \ sec_mgr.c \ stream.c \ uri.c \ - url.c + url.c \ + zone_id.c diff --git a/dlls/urlmon/tests/zone_id.c b/dlls/urlmon/tests/zone_id.c new file mode 100644 index 00000000000..28c455e0935 --- /dev/null +++ b/dlls/urlmon/tests/zone_id.c @@ -0,0 +1,569 @@ +/* + * Copyright 2025 Mike Kozelkov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS +#define CONST_VTABLE + +#include <wine/test.h> + +#include "windows.h" +#include "urlmon.h" + +#define UNINIT_TEST(str) "uninitialized: " str +#define ZONE_TEST(str) "zone_identifier: " str +#define FILE_TEST(str) "persist_file: " str + +#define URLZONE_CUSTOM1 URLZONE_UNTRUSTED + 1 +#define URLZONE_CUSTOM2 URLZONE_USER_MAX + 1 + +#define TMP_PATH_LEN 2 * MAX_PATH + +typedef struct _zone_id_op_test { + URLZONE id; + HRESULT hres; +} zone_id_op_test; + +typedef struct _zone_id_test { + zone_id_op_test set; + zone_id_op_test get; +} zone_id_test; + +static const zone_id_test zone_id_tests[] = { + { + { URLZONE_INVALID, E_INVALIDARG }, + { URLZONE_UNTRUSTED, E_ACCESSDENIED } + }, + { + { URLZONE_LOCAL_MACHINE, S_OK }, + { URLZONE_LOCAL_MACHINE, S_OK } + }, + { + { URLZONE_INTRANET, S_OK }, + { URLZONE_INTRANET, S_OK } + }, + { + { URLZONE_TRUSTED, S_OK }, + { URLZONE_TRUSTED, S_OK } + }, + { + { URLZONE_INTERNET, S_OK }, + { URLZONE_INTERNET, S_OK } + }, + { + { URLZONE_UNTRUSTED, S_OK }, + { URLZONE_UNTRUSTED, S_OK } + }, + { + { URLZONE_CUSTOM1, E_INVALIDARG }, + { URLZONE_UNTRUSTED, E_ACCESSDENIED } + }, + { + { URLZONE_USER_MIN, E_INVALIDARG }, + { URLZONE_UNTRUSTED, E_ACCESSDENIED } + }, + { + { URLZONE_USER_MAX, E_INVALIDARG }, + { URLZONE_UNTRUSTED, E_ACCESSDENIED } + }, + { + { URLZONE_CUSTOM2, E_INVALIDARG }, + { URLZONE_UNTRUSTED, E_ACCESSDENIED } + } +}; + +typedef struct _get_cur_file_test { + LPCWSTR name; + HRESULT hres; +} get_cur_file_test; + +typedef struct load_file_test { + LPCWSTR name; + DWORD mode; + HRESULT hres; +} load_file_test; + +typedef struct _save_file_test { + LPCWSTR name; + BOOL remember; + HRESULT hres; +} save_file_test; + + +typedef struct _persist_file_test { + zone_id_op_test set; + HRESULT is_dirty_before_save; + save_file_test save; + HRESULT is_dirty_after_save; + get_cur_file_test cur_file; + HRESULT is_dirty_before_load; + load_file_test load; + HRESULT is_dirty_after_load; + zone_id_op_test get; +} persist_file_test; + +static const persist_file_test persist_file_tests[] = { + { + { URLZONE_UNTRUSTED, S_OK }, + S_OK, + { NULL, FALSE, E_INVALIDARG }, + S_OK, + { NULL, E_NOTIMPL }, + S_OK, + { NULL, 0, E_INVALIDARG }, + S_OK, + { URLZONE_UNTRUSTED, __HRESULT_FROM_WIN32(ERROR_NOT_FOUND) }, + }, + { + { URLZONE_INTERNET, S_OK }, + S_OK, + { L"00000000-0000-0000-0000-000000000000", FALSE, S_OK }, + S_OK, + { NULL, E_NOTIMPL }, + S_OK, + { L"00000000-0000-0000-0000-000000000000", STGM_READWRITE | STGM_SHARE_DENY_NONE, S_OK }, + S_OK, + { URLZONE_INTERNET, S_OK }, + }, + { + { URLZONE_LOCAL_MACHINE, S_OK }, + S_OK, + { L"00000000-0000-0000-0000-000000000000", TRUE, S_OK }, + S_OK, + { NULL, E_NOTIMPL }, + S_OK, + { L"00000000-0000-0000-0000-000000000000", STGM_READWRITE | STGM_SHARE_DENY_NONE, S_OK }, + S_OK, + { URLZONE_LOCAL_MACHINE, S_OK }, + }, + { + { URLZONE_TRUSTED, S_OK }, + S_OK, + { NULL, FALSE, __HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) }, + S_OK, + { NULL, E_NOTIMPL }, + S_OK, + { + L"00000000-0000-0000-0000-000000000000", + STGM_READWRITE | STGM_SHARE_DENY_NONE, + __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) + }, + S_OK, + { URLZONE_UNTRUSTED, __HRESULT_FROM_WIN32(ERROR_NOT_FOUND) } + }, + { + { URLZONE_INTRANET, S_OK }, + S_OK, + { NULL, TRUE, __HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) }, + S_OK, + { NULL, E_NOTIMPL }, + S_OK, + { + L"00000000-0000-0000-0000-000000000000", + STGM_READWRITE | STGM_SHARE_DENY_NONE, + __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) + }, + S_OK, + { URLZONE_UNTRUSTED, __HRESULT_FROM_WIN32(ERROR_NOT_FOUND) } + }, + { + { URLZONE_INTERNET, S_OK }, + S_OK, + { L"11111111-1111-1111-1111-111111111111", FALSE, S_OK }, + S_OK, + { NULL, E_NOTIMPL }, + S_OK, + { L"11111111-1111-1111-1111-111111111111", STGM_READWRITE | STGM_SHARE_DENY_NONE, S_OK }, + S_OK, + { URLZONE_INTERNET, S_OK } + }, + { + { URLZONE_LOCAL_MACHINE, S_OK }, + S_OK, + { L"00000000-0000-0000-0000-000000000000", TRUE, S_OK }, + S_OK, + { NULL, E_NOTIMPL }, + S_OK, + { NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) }, + S_OK, + { URLZONE_UNTRUSTED, __HRESULT_FROM_WIN32(ERROR_NOT_FOUND) }, + }, + { + { URLZONE_LOCAL_MACHINE, S_OK }, + S_OK, + { L"00000000-0000-0000-0000-000000000000", TRUE, S_OK }, + S_OK, + { NULL, E_NOTIMPL }, + S_OK, + { L"00000000-0000-0000-0000-000000000000", STGM_READ | STGM_SHARE_EXCLUSIVE, S_OK }, + S_OK, + { URLZONE_LOCAL_MACHINE, S_OK }, + }, +}; + + +static void test_Uninitialized(void) +{ + const zone_id_op_test get = { URLZONE_UNTRUSTED, HRESULT_FROM_WIN32(ERROR_NOT_FOUND) }; + const zone_id_op_test set = { URLZONE_INTERNET, S_OK }; + const get_cur_file_test get_cur_file = { NULL, E_NOTIMPL }; + const load_file_test load = { NULL, STGM_READ, E_INVALIDARG }; + const save_file_test save = { NULL, FALSE, E_INVALIDARG }; + IUnknown *unk; + IZoneIdentifier *zone_id; + IPersistFile *persist_file; + HRESULT hres; + DWORD zone; + CLSID clsid; + LPWSTR file_name; + + hres = CoCreateInstance(&CLSID_PersistentZoneIdentifier, NULL, + CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&unk); + ok(hres == S_OK, UNINIT_TEST("failed to obtain IUnknown iface: 0x%08lx\n"), hres); + + hres = IUnknown_QueryInterface(unk, &IID_IZoneIdentifier, (void**)&zone_id); + ok(hres == S_OK, UNINIT_TEST("failed to obtain IZoneIdentifier iface: 0x%08lx\n"), hres); + + hres = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&persist_file); + ok(hres == S_OK, UNINIT_TEST("failed to obtain IPersistFile iface: 0x%08lx\n"), hres); + + hres = IZoneIdentifier_GetId(zone_id, &zone); + ok(hres == get.hres, + UNINIT_TEST("unexpected get zone id result: 0x%08lx, expected result: 0x%08lx\n"), + hres, get.hres); + ok(zone == get.id, + UNINIT_TEST("unexpected default zone: 0x%08lx, expected zone: 0x%08x\n"), zone, get.id); + + hres = IPersistFile_GetClassID(persist_file, &clsid); + ok(hres == S_OK, + UNINIT_TEST("unexpected get class id result: 0x%08lx, expected result: 0x%08lx\n"), + hres, S_OK); + ok(IsEqualCLSID(&clsid, &CLSID_PersistentZoneIdentifier), + UNINIT_TEST("unexpected class id: %s, expected class id: %s\n"), + debugstr_guid(&clsid), debugstr_guid(&CLSID_PersistentZoneIdentifier)); + + hres = IPersistFile_GetCurFile(persist_file, &file_name); + ok(hres == get_cur_file.hres, + UNINIT_TEST("unexpected get current file result: 0x%08lx, expected result: 0x%08lx\n"), + hres, get_cur_file.hres); + ok(!lstrcmpW(file_name, get_cur_file.name), + UNINIT_TEST("unexpected current file name: %s, expected file name: %s\n"), + debugstr_w(file_name), debugstr_w(get_cur_file.name)); + if (hres == S_OK || hres == S_FALSE) + CoTaskMemFree(file_name); + + hres = IPersistFile_IsDirty(persist_file); + ok(hres == S_OK, + UNINIT_TEST("unexpected change object state: 0x%08lx, expected state: 0x%08lx\n"), hres, S_OK); + + hres = IZoneIdentifier_SetId(zone_id, set.id); + ok(hres == set.hres, + UNINIT_TEST("unexpected set zone id result: 0x%08lx, expected result: 0x%08lx\n"), + hres, set.hres); + + hres = IPersistFile_IsDirty(persist_file); + ok(hres == S_OK, + UNINIT_TEST("unexpected change object state after set zone: 0x%08lx, expected state: 0x%08lx\n"), + hres, S_OK); + + hres = IPersistFile_Save(persist_file, save.name, save.remember); + ok(hres == save.hres, + UNINIT_TEST("unexpected save result: 0x%08lx, expected result: 0x%08lx\n"), hres, save.hres); + + hres = IPersistFile_Load(persist_file, load.name, load.mode); + ok(hres == load.hres, + UNINIT_TEST("unexpected load result: 0x%08lx, expected result: 0x%08lx\n"), hres, load.hres); +} + +static void test_IZoneIdentifier(void) +{ + const zone_id_op_test get_removed = { URLZONE_UNTRUSTED, HRESULT_FROM_WIN32(ERROR_NOT_FOUND)}; + IUnknown *unk; + IZoneIdentifier *zone_id; + zone_id_op_test set; + zone_id_op_test get; + HRESULT hres; + DWORD i; + DWORD zone; + + hres = CoCreateInstance(&CLSID_PersistentZoneIdentifier, NULL, + CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&unk); + ok(hres == S_OK, ZONE_TEST("failed to obtain IUnknown iface: 0x%08lx\n"), hres); + + hres = IUnknown_QueryInterface(unk, &IID_IZoneIdentifier, (void**)&zone_id); + ok(hres == S_OK, ZONE_TEST("failed to obtain IZoneIdentifier iface: 0x%08lx\n"), hres); + + for(i = 0; i < ARRAY_SIZE(zone_id_tests); ++i) + { + set = zone_id_tests[i].set; + get = zone_id_tests[i].get; + + hres = IZoneIdentifier_SetId(zone_id, set.id); + ok(hres == set.hres, + ZONE_TEST("unexpected set zone id result: 0x%08lx, expected result: 0x%08lx\n"), + hres, set.hres); + + hres = IZoneIdentifier_GetId(zone_id, &zone); + ok(hres == get.hres, + ZONE_TEST("unexpected get zone id result: 0x%08lx, expected result: 0x%08lx\n"), + hres, get.hres); + ok(zone == get.id, + ZONE_TEST("unexpected zone id: 0x%08lx, expected zone: 0x%08x\n"), zone, get.id); + } + + hres = IZoneIdentifier_Remove(zone_id); + ok(hres == S_OK, + ZONE_TEST("unexpected remove zone id result: 0x%08lx, expected result: 0x%08lx\n"), + hres, S_OK); + + hres = IZoneIdentifier_GetId(zone_id, &zone); + ok(hres == get_removed.hres, + ZONE_TEST("unexpected get zone id result after remove: 0x%08lx, expected result: 0x%08lx\n"), + hres, get_removed.hres); + ok(zone == get_removed.id, + ZONE_TEST("unexpected zone id after remove: 0x%08lx, expected zone: 0x%08x\n"), + zone, get_removed.id); +} + +static void remove_dir(const WCHAR* dir_path) +{ + WCHAR files_mask[TMP_PATH_LEN]; + WCHAR file_path[TMP_PATH_LEN]; + HANDLE hfiles; + WIN32_FIND_DATAW file_data; + + wsprintfW(files_mask, L"%s\*-*-*-*", dir_path); + + hfiles = FindFirstFileW(files_mask, &file_data); + if (hfiles != INVALID_HANDLE_VALUE) + do { + wsprintfW(file_path, L"%s\%s", dir_path, file_data.cFileName); + DeleteFileW(file_path); + } while(FindNextFileW(hfiles, &file_data)); + + RemoveDirectoryW(dir_path); +} + +static void test_IPersistFile(void) +{ + IUnknown *unk; + IZoneIdentifier *zone_id_save; + IZoneIdentifier *zone_id_load; + IPersistFile *persist_file_save; + IPersistFile *persist_file_load; + HRESULT hres; + WCHAR tmp_dir[TMP_PATH_LEN]; + WCHAR sub_dir [] = L"PersistentZoneIdentifier"; + WCHAR tmp_file_path[TMP_PATH_LEN]; + WCHAR *file_path; + HANDLE hfile; + DWORD zone; + LPWSTR file_name; + DWORD i; + persist_file_test test; + + hres = CoCreateInstance(&CLSID_PersistentZoneIdentifier, NULL, + CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&unk); + ok(hres == S_OK, FILE_TEST("failed to obtain IUnknown save iface: 0x%08lx\n"), hres); + + hres = IUnknown_QueryInterface(unk, &IID_IZoneIdentifier, (void**)&zone_id_save); + ok(hres == S_OK, FILE_TEST("failed to obtain IZoneIdentifier save iface: 0x%08lx\n"), hres); + + hres = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&persist_file_save); + ok(hres == S_OK, FILE_TEST("failed to obtain IPersistFile save iface: 0x%08lx\n"), hres); + + hres = CoCreateInstance(&CLSID_PersistentZoneIdentifier, NULL, + CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&unk); + ok(hres == S_OK, FILE_TEST("failed to obtain IUnknown load iface: 0x%08lx\n"), hres); + + hres = IUnknown_QueryInterface(unk, &IID_IZoneIdentifier, (void**)&zone_id_load); + ok(hres == S_OK, FILE_TEST("failed to obtain IZoneIdentifier load iface: 0x%08lx\n"), hres); + + hres = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&persist_file_load); + ok(hres == S_OK, FILE_TEST("failed to obtain IPersistFile load iface: 0x%08lx\n"), hres); + + hres = IZoneIdentifier_Remove(zone_id_save); + ok(hres == S_OK, + FILE_TEST("unexpected remove zone id result: 0x%08lx, expected result: 0x%08lx\n"), + hres, S_OK); + + if (!GetTempPathW(sizeof(tmp_dir), tmp_dir)) + { + skip("Cannot get temporary directory path\n"); + return; + } + + if (lstrcatW(tmp_dir, sub_dir) != tmp_dir) + { + skip("Cannot get temporary subdirectory path\n"); + return; + } + + if (!CreateDirectoryW(tmp_dir, NULL)) + { + skip("Cannot create temporary directory\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(persist_file_tests); ++i) { + file_name = NULL; + file_path = NULL; + + test = persist_file_tests[i]; + hres = IZoneIdentifier_SetId(zone_id_save, test.set.id); + ok(hres == test.set.hres, + FILE_TEST("unexpected set zone id result: 0x%08lx, expected result: 0x%08lx\n"), + hres, test.set.hres); + + hres = IPersistFile_IsDirty(persist_file_save); + ok(hres == test.is_dirty_before_save, + FILE_TEST("unexpected change object state before save: 0x%08lx, expected state: 0x%08lx\n"), + hres, test.is_dirty_before_save); + + if (test.save.name) + { + wsprintfW(tmp_file_path, L"%s\%s", tmp_dir, test.save.name); + file_path = tmp_file_path; + } + else + file_path = (WCHAR *)test.save.name; + + if (file_path) + { + hfile = CreateFileW(file_path, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hfile == INVALID_HANDLE_VALUE) + { + skip("Failed to create file %s, error: 0x%08lx\n", debugstr_w(file_path), + GetLastError()); + continue; + } + CloseHandle(hfile); + } + + hres = IPersistFile_Save(persist_file_save, file_path, test.save.remember); + ok(hres == test.save.hres, + FILE_TEST("unexpected save result: 0x%08lx, expected result: 0x%08lx\n"), + hres, test.save.hres); + + hres = IPersistFile_IsDirty(persist_file_save); + ok(hres == test.is_dirty_after_save, + FILE_TEST("unexpected change object state after save: 0x%08lx, expected state: 0x%08lx\n"), + hres, test.is_dirty_after_save); + + if (test.cur_file.name && test.cur_file.hres == S_OK) + { + wsprintfW(tmp_file_path, L"%s\%s", tmp_dir, test.cur_file.name); + file_path = tmp_file_path; + } + else + file_path = (WCHAR *)test.cur_file.name; + + hres = IPersistFile_GetCurFile(persist_file_save, &file_name); + ok(hres == test.cur_file.hres, + FILE_TEST("unexpected get current file result: 0x%08lx, expected result: 0x%08lx\n"), + hres, test.cur_file.hres); + ok(!lstrcmpW(file_name, file_path), + FILE_TEST("unexpected current file name: %s, expected file name: %s\n"), + debugstr_w(file_name), debugstr_w(file_path)); + + if (hres == S_OK || hres == S_FALSE) + CoTaskMemFree(file_name); + + hres = IZoneIdentifier_Remove(zone_id_load); + ok(hres == S_OK, + FILE_TEST("unexpected remove zone id result: 0x%08lx, expected result: 0x%08lx\n"), + hres, S_OK); + + hres = IPersistFile_IsDirty(persist_file_load); + ok(hres == test.is_dirty_before_load, + FILE_TEST("unexpected change object state before load: 0x%08lx, expected state: 0x%08lx\n"), + hres, test.is_dirty_before_load); + + if (test.load.name) + { + wsprintfW(tmp_file_path, L"%s\%s", tmp_dir, test.load.name); + file_path = tmp_file_path; + } + else + file_path = (WCHAR *)test.load.name; + + hres = IPersistFile_Load(persist_file_load, file_path, test.load.mode); + ok(hres == test.load.hres, + FILE_TEST("unexpected load result: 0x%08lx, expected result: 0x%08lx\n"), + hres, test.load.hres); + + hres = IPersistFile_Load(persist_file_save, file_path, test.load.mode); + + hres = IPersistFile_IsDirty(persist_file_load); + ok(hres == test.is_dirty_after_load, + FILE_TEST("unexpected change object state after load: 0x%08lx, expected state: 0x%08lx\n"), + hres, test.is_dirty_after_load); + + hres = IZoneIdentifier_GetId(zone_id_load, &zone); + + /* GetId checks after expected Load falure shouldn't be marked as todo_wine */ + if (test.get.hres == __HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) + { + ok(hres == test.get.hres, + FILE_TEST("unexpected get zone id result after load: 0x%08lx, expected result: 0x%08lx\n"), + hres, test.get.hres); + ok(zone == test.get.id, + FILE_TEST("unexpected zone id after load: 0x%08lx, expected zone: 0x%08x\n"), + zone, test.get.id); + + } + else + { + todo_wine ok(hres == test.get.hres, + FILE_TEST("unexpected get zone id result after load: 0x%08lx, expected result: 0x%08lx\n"), + hres, test.get.hres); + todo_wine ok(zone == test.get.id, + FILE_TEST("unexpected zone id after load: 0x%08lx, expected zone: 0x%08x\n"), + zone, test.get.id); + } + + if (test.save.name) + { + wsprintfW(tmp_file_path, L"%s\%s", tmp_dir, test.save.name); + file_path = tmp_file_path; + } + else + file_path = (WCHAR *)test.save.name; + + if (file_path) + DeleteFileW(file_path); + + } + + remove_dir(tmp_dir); + +} + + +START_TEST(zone_id) +{ + + CoInitialize(NULL); + + test_Uninitialized(); + test_IZoneIdentifier(); + test_IPersistFile(); + + CoUninitialize(); + +}
From: Mike Kozelkov augenzi@etersoft.ru
--- dlls/urlmon/zone_id.c | 154 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 137 insertions(+), 17 deletions(-)
diff --git a/dlls/urlmon/zone_id.c b/dlls/urlmon/zone_id.c index 43712fadbf7..e7bf816a7e4 100644 --- a/dlls/urlmon/zone_id.c +++ b/dlls/urlmon/zone_id.c @@ -27,6 +27,13 @@ typedef struct { IPersistFile IPersistFile_iface; IZoneIdentifier IZoneIdentifier_iface;
+ BOOL is_dirty; + LPWSTR save_file_name; + LPWSTR load_file_name; + + URLZONE zone; + BOOL is_zone_removed; + IUnknown *outer;
LONG ref; @@ -147,16 +154,21 @@ static HRESULT WINAPI PZIPersistFile_GetClassID(IPersistFile *iface, CLSID *clsi { PersistentZoneIdentifier *This = impl_from_IPersistFile(iface);
- FIXME("(%p, %p) not implemented\n", This, clsid); + TRACE("(%p, %p)\n", This, clsid);
- return E_NOTIMPL; + *clsid = CLSID_PersistentZoneIdentifier; + + return S_OK; }
static HRESULT WINAPI PZIPersistFile_GetCurFile(IPersistFile *iface, LPOLESTR *file_name) { PersistentZoneIdentifier *This = impl_from_IPersistFile(iface);
- FIXME("(%p, %p) not implemented\n", This, file_name); + /* GetCurFile isn't implemented in Windows*/ + TRACE("(%p, %p)\n", This, file_name); + + *file_name = NULL;
return E_NOTIMPL; } @@ -165,36 +177,102 @@ static HRESULT WINAPI PZIPersistFile_IsDirty(IPersistFile *iface) { PersistentZoneIdentifier *This = impl_from_IPersistFile(iface);
- FIXME("(%p) not implemented\n", This); + TRACE("(%p)\n", This);
- return E_NOTIMPL; + return S_OK; }
static HRESULT WINAPI PZIPersistFile_Load(IPersistFile *iface, LPCOLESTR file_name, DWORD mode) { PersistentZoneIdentifier *This = impl_from_IPersistFile(iface); + HANDLE hfile;
- FIXME("(%p, %s, 0x%08lx) not implemented\n", This, debugstr_w(file_name), mode); + FIXME("(%p, %s, 0x%08lx) semi-stub\n", This, debugstr_w(file_name), mode);
- return E_NOTIMPL; + if (!file_name) + { + if (!This->load_file_name) + return E_INVALIDARG; + + file_name = This->load_file_name; + } + + /* FIXME: Read zone information from Zone.Identifier NTFS alternate data stream */ + + hfile = CreateFileW(file_name, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (hfile == INVALID_HANDLE_VALUE) + return HRESULT_FROM_WIN32(GetLastError()); + + CloseHandle(hfile); + + if (lstrcmpW(This->load_file_name, file_name)) + { + if (This->load_file_name) + free(This->load_file_name); + + This->load_file_name = wcsdup(file_name); + } + + return S_OK; }
static HRESULT WINAPI PZIPersistFile_Save(IPersistFile *iface, LPCOLESTR file_name, BOOL remember) { PersistentZoneIdentifier *This = impl_from_IPersistFile(iface); + WCHAR *new_file_name; + HANDLE hfile;
- FIXME("(%p, %s, %d) not implemented\n", This, debugstr_w(file_name), remember); + FIXME("(%p, %s, %d) semi-stub\n", This, debugstr_w(file_name), remember);
- return E_NOTIMPL; + if (!file_name) + { + if (!This->save_file_name) + return E_INVALIDARG; + + file_name = This->save_file_name; + remember = FALSE; + } + + /* FIXME: Write zone information to Zone.Identifier NTFS alternate data stream */ + + hfile = CreateFileW(file_name, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (hfile == INVALID_HANDLE_VALUE) + return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); + + CloseHandle(hfile); + + if (!lstrcmpW(This->save_file_name, file_name)) + This->is_dirty = FALSE; + + if (remember) + { + new_file_name = wcsdup(file_name); + if (!new_file_name) + return E_OUTOFMEMORY; + + if (This->save_file_name) + free(This->save_file_name); + + This->save_file_name = new_file_name; + This->is_dirty = FALSE; + } + + return S_OK; }
static HRESULT WINAPI PZIPersistFile_SaveCompleted(IPersistFile* iface, LPCOLESTR pszFileName) { PersistentZoneIdentifier *This = impl_from_IPersistFile(iface);
- FIXME("(%p, %p) not implemented\n", This, pszFileName); + FIXME("(%p, %p) semi-stub \n", This, pszFileName);
- return E_NOTIMPL; + /* FIXME: Add a notification to the object that it can write to its file */ + + return S_OK; }
static const IPersistFileVtbl PZIPersistFileVtbl = { @@ -236,31 +314,66 @@ static ULONG WINAPI PZIZoneId_Release(IZoneIdentifier *iface) return IUnknown_Release(This->outer); }
+ +static BOOL is_trusted_zone(URLZONE zone) +{ + switch (zone) + { + case URLZONE_LOCAL_MACHINE: + case URLZONE_INTRANET: + case URLZONE_TRUSTED: + case URLZONE_INTERNET: + case URLZONE_UNTRUSTED: + return TRUE; + default: + return FALSE; + } +} + + static HRESULT WINAPI PZIZoneId_GetId(IZoneIdentifier* iface, DWORD* pdwZone) { PersistentZoneIdentifier *This = impl_from_IZoneIdentifier(iface);
- FIXME("(%p, %p) not implemented\n", This, pdwZone); + TRACE("(%p, %p)\n", This, pdwZone);
- return E_NOTIMPL; + if (This->is_zone_removed) + { + *pdwZone = URLZONE_UNTRUSTED; + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + } else if (!is_trusted_zone(This->zone)) + { + *pdwZone = URLZONE_UNTRUSTED; + return E_ACCESSDENIED; + } else + { + *pdwZone = This->zone; + return S_OK; + } }
static HRESULT WINAPI PZIZoneId_Remove(IZoneIdentifier* iface) { PersistentZoneIdentifier *This = impl_from_IZoneIdentifier(iface);
- FIXME("(%p) not implemented\n", This); + TRACE("(%p)\n", This);
- return E_NOTIMPL; + This->zone = URLZONE_LOCAL_MACHINE; + This->is_zone_removed = TRUE; + + return S_OK; }
static HRESULT WINAPI PZIZoneId_SetId(IZoneIdentifier* iface, DWORD dwZone) { PersistentZoneIdentifier *This = impl_from_IZoneIdentifier(iface);
- FIXME("(%p, 0x%08lx) not implemented\n", This, dwZone); + TRACE("(%p, 0x%08lx)\n", This, dwZone);
- return E_NOTIMPL; + This->zone = dwZone; + This->is_zone_removed = FALSE; + + return is_trusted_zone(This->zone) ? S_OK : E_INVALIDARG; }
static const IZoneIdentifierVtbl PZIZoneIdVtbl = { @@ -290,6 +403,13 @@ HRESULT PersistentZoneIdentifier_Construct(IUnknown *outer, LPVOID *ppobj) ret->IPersistFile_iface.lpVtbl = &PZIPersistFileVtbl; ret->IZoneIdentifier_iface.lpVtbl = &PZIZoneIdVtbl;
+ ret->save_file_name = NULL; + ret->load_file_name = NULL; + ret->is_dirty = FALSE; + + ret->zone = URLZONE_INVALID; + ret->is_zone_removed = TRUE; + ret->ref = 1; ret->outer = outer ? outer : &ret->IUnknown_inner;