You've already forked wine-staging
mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2025-12-15 08:03:15 -08:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be758e634e | ||
|
|
c8cf8c5b8d | ||
|
|
b6ba963ad0 | ||
|
|
8ea0f4968f | ||
|
|
217f208541 | ||
|
|
54f4c57fd6 | ||
|
|
0c0b6c45da | ||
|
|
da6c42770b | ||
|
|
b7f859e90d | ||
|
|
463f0b7936 | ||
|
|
959925fc2f | ||
|
|
3e92d6c89c | ||
|
|
3bb1cddffc | ||
|
|
4741f1abc6 | ||
|
|
0229597809 | ||
|
|
3392f477c5 | ||
|
|
e97aabbb86 | ||
|
|
ed8a24d79b | ||
|
|
2bf94fc85b | ||
|
|
3950dc0efe | ||
|
|
635849c3ed | ||
|
|
4ee9edf610 | ||
|
|
514e3884c5 | ||
|
|
ece1fa8409 | ||
|
|
e61b45155f | ||
|
|
66e568f047 | ||
|
|
ef9ef7bf9d | ||
|
|
2d58cc0eb9 |
File diff suppressed because it is too large
Load Diff
@@ -1,2 +0,0 @@
|
||||
Fixes: [45533] - Implement D3DX11CreateTextureFromMemory
|
||||
Disabled: True
|
||||
@@ -1,4 +1,4 @@
|
||||
From b2b7c4c294cc7ea290250c419720899d457f63ec Mon Sep 17 00:00:00 2001
|
||||
From ec240b5cd624f7a16a00ce98ff72188aba1a6524 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Mon, 5 Sep 2016 15:31:29 +0200
|
||||
Subject: [PATCH] inseng: Implement CIF reader and download functions.
|
||||
@@ -10,9 +10,9 @@ FIXME: Needs splitting.
|
||||
dlls/inseng/inf.c | 443 +++++++++
|
||||
dlls/inseng/inseng.spec | 4 +-
|
||||
dlls/inseng/inseng_main.c | 989 ++++++++++++++++++-
|
||||
dlls/inseng/inseng_private.h | 79 ++
|
||||
dlls/inseng/inseng_private.h | 78 ++
|
||||
include/inseng.idl | 276 +++++-
|
||||
7 files changed, 3488 insertions(+), 52 deletions(-)
|
||||
7 files changed, 3487 insertions(+), 52 deletions(-)
|
||||
create mode 100644 dlls/inseng/icif.c
|
||||
create mode 100644 dlls/inseng/inf.c
|
||||
create mode 100644 dlls/inseng/inseng_private.h
|
||||
@@ -35,7 +35,7 @@ index 40eda55661a..72fa3533930 100644
|
||||
inseng_main.c
|
||||
diff --git a/dlls/inseng/icif.c b/dlls/inseng/icif.c
|
||||
new file mode 100644
|
||||
index 00000000000..27f6f6dfd93
|
||||
index 00000000000..e65463f1d8d
|
||||
--- /dev/null
|
||||
+++ b/dlls/inseng/icif.c
|
||||
@@ -0,0 +1,1745 @@
|
||||
@@ -243,14 +243,14 @@ index 00000000000..27f6f6dfd93
|
||||
+
|
||||
+static void url_entry_free(struct url_info *url)
|
||||
+{
|
||||
+ heap_free(url->url);
|
||||
+ heap_free(url);
|
||||
+ HeapFree(GetProcessHeap(), 0, url->url);
|
||||
+ HeapFree(GetProcessHeap(), 0, url);
|
||||
+}
|
||||
+
|
||||
+static void dependency_entry_free(struct dependency_info *dependency)
|
||||
+{
|
||||
+ heap_free(dependency->id);
|
||||
+ heap_free(dependency);
|
||||
+ HeapFree(GetProcessHeap(), 0, dependency->id);
|
||||
+ HeapFree(GetProcessHeap(), 0, dependency);
|
||||
+}
|
||||
+
|
||||
+static void component_free(struct cifcomponent *comp)
|
||||
@@ -258,20 +258,20 @@ index 00000000000..27f6f6dfd93
|
||||
+ struct dependency_info *dependency, *dependency_next;
|
||||
+ struct url_info *url, *url_next;
|
||||
+
|
||||
+ heap_free(comp->id);
|
||||
+ heap_free(comp->guid);
|
||||
+ heap_free(comp->description);
|
||||
+ heap_free(comp->details);
|
||||
+ heap_free(comp->group);
|
||||
+ HeapFree(GetProcessHeap(), 0, comp->id);
|
||||
+ HeapFree(GetProcessHeap(), 0, comp->guid);
|
||||
+ HeapFree(GetProcessHeap(), 0, comp->description);
|
||||
+ HeapFree(GetProcessHeap(), 0, comp->details);
|
||||
+ HeapFree(GetProcessHeap(), 0, comp->group);
|
||||
+
|
||||
+ heap_free(comp->patchid);
|
||||
+ HeapFree(GetProcessHeap(), 0, comp->patchid);
|
||||
+
|
||||
+ heap_free(comp->locale);
|
||||
+ heap_free(comp->key_uninstall);
|
||||
+ HeapFree(GetProcessHeap(), 0, comp->locale);
|
||||
+ HeapFree(GetProcessHeap(), 0, comp->key_uninstall);
|
||||
+
|
||||
+ heap_free(comp->key_success);
|
||||
+ heap_free(comp->key_progress);
|
||||
+ heap_free(comp->key_cancel);
|
||||
+ HeapFree(GetProcessHeap(), 0, comp->key_success);
|
||||
+ HeapFree(GetProcessHeap(), 0, comp->key_progress);
|
||||
+ HeapFree(GetProcessHeap(), 0, comp->key_cancel);
|
||||
+
|
||||
+ LIST_FOR_EACH_ENTRY_SAFE(dependency, dependency_next, &comp->dependencies, struct dependency_info, entry)
|
||||
+ {
|
||||
@@ -285,14 +285,14 @@ index 00000000000..27f6f6dfd93
|
||||
+ url_entry_free(url);
|
||||
+ }
|
||||
+
|
||||
+ heap_free(comp);
|
||||
+ HeapFree(GetProcessHeap(), 0, comp);
|
||||
+}
|
||||
+
|
||||
+static void group_free(struct cifgroup *group)
|
||||
+{
|
||||
+ heap_free(group->id);
|
||||
+ heap_free(group->description);
|
||||
+ heap_free(group);
|
||||
+ HeapFree(GetProcessHeap(), 0, group->id);
|
||||
+ HeapFree(GetProcessHeap(), 0, group->description);
|
||||
+ HeapFree(GetProcessHeap(), 0, group);
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI group_GetID(ICifGroup *iface, char *id, DWORD size)
|
||||
@@ -872,7 +872,7 @@ index 00000000000..27f6f6dfd93
|
||||
+ if(!ref)
|
||||
+ {
|
||||
+ ICifFile_Release(This->file);
|
||||
+ heap_free(This);
|
||||
+ HeapFree(GetProcessHeap(), 0, This);
|
||||
+ }
|
||||
+
|
||||
+ return ref;
|
||||
@@ -933,7 +933,7 @@ index 00000000000..27f6f6dfd93
|
||||
+{
|
||||
+ struct ciffenum_components *enumerator;
|
||||
+
|
||||
+ enumerator = heap_alloc_zero(sizeof(*enumerator));
|
||||
+ enumerator = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,sizeof(*enumerator));
|
||||
+ if (!enumerator) return E_OUTOFMEMORY;
|
||||
+
|
||||
+ enumerator->IEnumCifComponents_iface.lpVtbl = &enum_componentsVtbl;
|
||||
@@ -996,7 +996,7 @@ index 00000000000..27f6f6dfd93
|
||||
+ if(!ref)
|
||||
+ {
|
||||
+ ICifFile_Release(This->file);
|
||||
+ heap_free(This);
|
||||
+ HeapFree(GetProcessHeap(), 0, This);
|
||||
+ }
|
||||
+
|
||||
+ return ref;
|
||||
@@ -1045,7 +1045,7 @@ index 00000000000..27f6f6dfd93
|
||||
+{
|
||||
+ struct ciffenum_groups *enumerator;
|
||||
+
|
||||
+ enumerator = heap_alloc_zero(sizeof(*enumerator));
|
||||
+ enumerator = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,sizeof(*enumerator));
|
||||
+ if (!enumerator) return E_OUTOFMEMORY;
|
||||
+
|
||||
+ enumerator->IEnumCifGroups_iface.lpVtbl = &enum_groupsVtbl;
|
||||
@@ -1107,7 +1107,7 @@ index 00000000000..27f6f6dfd93
|
||||
+ struct cifcomponent *comp, *comp_next;
|
||||
+ struct cifgroup *group, *group_next;
|
||||
+
|
||||
+ heap_free(This->name);
|
||||
+ HeapFree(GetProcessHeap(), 0, This->name);
|
||||
+
|
||||
+ LIST_FOR_EACH_ENTRY_SAFE(comp, comp_next, &This->components, struct cifcomponent, entry)
|
||||
+ {
|
||||
@@ -1121,7 +1121,7 @@ index 00000000000..27f6f6dfd93
|
||||
+ group_free(group);
|
||||
+ }
|
||||
+
|
||||
+ heap_free(This);
|
||||
+ HeapFree(GetProcessHeap(), 0, This);
|
||||
+ }
|
||||
+
|
||||
+ return ref;
|
||||
@@ -1306,7 +1306,7 @@ index 00000000000..27f6f6dfd93
|
||||
+ if (field == i)
|
||||
+ {
|
||||
+ BOOL ret = copy_string(value, str);
|
||||
+ heap_free(line);
|
||||
+ HeapFree(GetProcessHeap(), 0, line);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
@@ -1344,7 +1344,7 @@ index 00000000000..27f6f6dfd93
|
||||
+ if (!str) return FALSE;
|
||||
+
|
||||
+ *value = atoi(str);
|
||||
+ heap_free(str);
|
||||
+ HeapFree(GetProcessHeap(), 0, str);
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
@@ -1363,7 +1363,7 @@ index 00000000000..27f6f6dfd93
|
||||
+ }
|
||||
+
|
||||
+ *value = atoi(value_str);
|
||||
+ heap_free(value_str);
|
||||
+ HeapFree(GetProcessHeap(), 0, value_str);
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
@@ -1421,7 +1421,7 @@ index 00000000000..27f6f6dfd93
|
||||
+ build |= atoi(str) & 0xffff;
|
||||
+
|
||||
+done:
|
||||
+ heap_free(line);
|
||||
+ HeapFree(GetProcessHeap(), 0, line);
|
||||
+ *ret_ver = version;
|
||||
+ *ret_build = build;
|
||||
+ return TRUE;
|
||||
@@ -1463,7 +1463,7 @@ index 00000000000..27f6f6dfd93
|
||||
+ } while (str);
|
||||
+
|
||||
+done:
|
||||
+ heap_free(line);
|
||||
+ HeapFree(GetProcessHeap(), 0, line);
|
||||
+ *ret_platform = platform;
|
||||
+ return TRUE;
|
||||
+}
|
||||
@@ -1484,13 +1484,13 @@ index 00000000000..27f6f6dfd93
|
||||
+ {
|
||||
+ next = next_part(&str, TRUE);
|
||||
+
|
||||
+ dependency = heap_alloc_zero(sizeof(*dependency));
|
||||
+ dependency = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,sizeof(*dependency));
|
||||
+ if (!dependency) goto done;
|
||||
+
|
||||
+ dependency->id = strdupA(str);
|
||||
+ if (!dependency->id)
|
||||
+ {
|
||||
+ heap_free(dependency);
|
||||
+ HeapFree(GetProcessHeap(), 0, dependency);
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
@@ -1505,7 +1505,7 @@ index 00000000000..27f6f6dfd93
|
||||
+ ret = TRUE;
|
||||
+
|
||||
+done:
|
||||
+ heap_free(line);
|
||||
+ HeapFree(GetProcessHeap(), 0, line);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
@@ -1532,7 +1532,7 @@ index 00000000000..27f6f6dfd93
|
||||
+ goto next;
|
||||
+ index--;
|
||||
+
|
||||
+ url_entry = heap_alloc_zero(sizeof(*url_entry));
|
||||
+ url_entry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,sizeof(*url_entry));
|
||||
+ if (!url_entry) goto error;
|
||||
+
|
||||
+ url_entry->index = index;
|
||||
@@ -1551,13 +1551,13 @@ index 00000000000..27f6f6dfd93
|
||||
+ list_add_tail(&component->urls, &url_entry->entry);
|
||||
+
|
||||
+ next:
|
||||
+ heap_free(str);
|
||||
+ HeapFree(GetProcessHeap(), 0, str);
|
||||
+ }
|
||||
+
|
||||
+ return TRUE;
|
||||
+
|
||||
+error:
|
||||
+ heap_free(str);
|
||||
+ HeapFree(GetProcessHeap(), 0, str);
|
||||
+ url_entry_free(url_entry);
|
||||
+ return FALSE;
|
||||
+};
|
||||
@@ -1583,7 +1583,7 @@ index 00000000000..27f6f6dfd93
|
||||
+ struct cifcomponent *component;
|
||||
+ HRESULT hr = E_OUTOFMEMORY;
|
||||
+
|
||||
+ component = heap_alloc_zero(sizeof(*component));
|
||||
+ component = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,sizeof(*component));
|
||||
+ if (!component) return E_OUTOFMEMORY;
|
||||
+
|
||||
+ component->ICifComponent_iface.lpVtbl = &cifcomponentVtbl;
|
||||
@@ -1662,7 +1662,7 @@ index 00000000000..27f6f6dfd93
|
||||
+ struct cifgroup *group;
|
||||
+ HRESULT hr = E_OUTOFMEMORY;
|
||||
+
|
||||
+ group = heap_alloc_zero(sizeof(*group));
|
||||
+ group = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,sizeof(*group));
|
||||
+ if (!group) return E_OUTOFMEMORY;
|
||||
+
|
||||
+ group->ICifGroup_iface.lpVtbl = &cifgroupVtbl;
|
||||
@@ -1699,7 +1699,7 @@ index 00000000000..27f6f6dfd93
|
||||
+ else
|
||||
+ FIXME("Don't know how to process %s\n", debugstr_a(type));
|
||||
+
|
||||
+ heap_free(type);
|
||||
+ HeapFree(GetProcessHeap(), 0, type);
|
||||
+ return hr;
|
||||
+}
|
||||
+
|
||||
@@ -1727,7 +1727,7 @@ index 00000000000..27f6f6dfd93
|
||||
+ hr = process_section(file, section, section_name);
|
||||
+
|
||||
+ TRACE("Finished processing section %s, hr %#lx.\n", debugstr_a(section_name), hr);
|
||||
+ heap_free(section_name);
|
||||
+ HeapFree(GetProcessHeap(), 0, section_name);
|
||||
+ }
|
||||
+
|
||||
+ /* In case there was no version section, set the default installer description */
|
||||
@@ -1746,7 +1746,7 @@ index 00000000000..27f6f6dfd93
|
||||
+ struct ciffile *file;
|
||||
+ HRESULT hr = E_FAIL;
|
||||
+
|
||||
+ file = heap_alloc_zero(sizeof(*file));
|
||||
+ file = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,sizeof(*file));
|
||||
+ if(!file) return E_OUTOFMEMORY;
|
||||
+
|
||||
+ file->ICifFile_iface.lpVtbl = &ciffileVtbl;
|
||||
@@ -1786,7 +1786,7 @@ index 00000000000..27f6f6dfd93
|
||||
+}
|
||||
diff --git a/dlls/inseng/inf.c b/dlls/inseng/inf.c
|
||||
new file mode 100644
|
||||
index 00000000000..bead72c082c
|
||||
index 00000000000..d803d7c1693
|
||||
--- /dev/null
|
||||
+++ b/dlls/inseng/inf.c
|
||||
@@ -0,0 +1,443 @@
|
||||
@@ -1846,7 +1846,7 @@ index 00000000000..bead72c082c
|
||||
+
|
||||
+static void inf_value_free(struct inf_value *value)
|
||||
+{
|
||||
+ heap_free(value);
|
||||
+ HeapFree(GetProcessHeap(), 0, value);
|
||||
+}
|
||||
+
|
||||
+static void inf_section_free(struct inf_section *section)
|
||||
@@ -1858,7 +1858,7 @@ index 00000000000..bead72c082c
|
||||
+ inf_value_free(val);
|
||||
+ }
|
||||
+
|
||||
+ heap_free(section);
|
||||
+ HeapFree(GetProcessHeap(), 0, section);
|
||||
+}
|
||||
+
|
||||
+static const char *get_substitution(struct inf_file *inf, const char *name, int len)
|
||||
@@ -1954,7 +1954,7 @@ index 00000000000..bead72c082c
|
||||
+ int len;
|
||||
+
|
||||
+ len = expand_variables_buffer(inf, str, NULL);
|
||||
+ buffer = heap_alloc(len);
|
||||
+ buffer = HeapAlloc(GetProcessHeap(), 0, len);
|
||||
+ if (!len) return NULL;
|
||||
+
|
||||
+ expand_variables_buffer(inf, str, buffer);
|
||||
@@ -1970,8 +1970,8 @@ index 00000000000..bead72c082c
|
||||
+ inf_section_free(sec);
|
||||
+ }
|
||||
+
|
||||
+ heap_free(inf->content);
|
||||
+ heap_free(inf);
|
||||
+ HeapFree(GetProcessHeap(), 0, inf->content);
|
||||
+ HeapFree(GetProcessHeap(), 0, inf);
|
||||
+}
|
||||
+
|
||||
+BOOL inf_next_section(struct inf_file *inf, struct inf_section **sec)
|
||||
@@ -2137,7 +2137,7 @@ index 00000000000..bead72c082c
|
||||
+ name = trim(line, NULL, FALSE);
|
||||
+ if (!name) return S_OK;
|
||||
+
|
||||
+ sec = heap_alloc_zero(sizeof(*sec));
|
||||
+ sec = HeapAlloc(GetProcessHeap(), 0, sizeof(*sec));
|
||||
+ if (!sec) return E_OUTOFMEMORY;
|
||||
+
|
||||
+ sec->name = name;
|
||||
@@ -2165,7 +2165,7 @@ index 00000000000..bead72c082c
|
||||
+ key = trim(key, NULL, FALSE);
|
||||
+ value = trim(value, NULL, TRUE);
|
||||
+
|
||||
+ key_val = heap_alloc_zero(sizeof(*key_val));
|
||||
+ key_val = HeapAlloc(GetProcessHeap(), 0, sizeof(*key_val));
|
||||
+ if (!key_val) return E_OUTOFMEMORY;
|
||||
+
|
||||
+ key_val->key = key;
|
||||
@@ -2205,7 +2205,7 @@ index 00000000000..bead72c082c
|
||||
+ file = CreateFileA(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
+ if (file == INVALID_HANDLE_VALUE) return E_FAIL;
|
||||
+
|
||||
+ inf = heap_alloc_zero(sizeof(*inf));
|
||||
+ inf = HeapAlloc(GetProcessHeap(), 0, sizeof(*inf));
|
||||
+ if (!inf) goto error;
|
||||
+
|
||||
+ if (!GetFileSizeEx(file, &file_size))
|
||||
@@ -2213,7 +2213,7 @@ index 00000000000..bead72c082c
|
||||
+
|
||||
+ inf->size = file_size.QuadPart;
|
||||
+
|
||||
+ inf->content = heap_alloc_zero(inf->size);
|
||||
+ inf->content = HeapAlloc(GetProcessHeap(), 0, inf->size);
|
||||
+ if (!inf->content) goto error;
|
||||
+
|
||||
+ list_init(&inf->sections);
|
||||
@@ -2247,7 +2247,7 @@ index 82c0b4d5fe1..7ae46fad3a7 100644
|
||||
+@ stdcall GetICifRWFileFromFile(ptr str)
|
||||
@ stub PurgeDownloadDirectory
|
||||
diff --git a/dlls/inseng/inseng_main.c b/dlls/inseng/inseng_main.c
|
||||
index f7ce3f173c2..ad6fe6b4de8 100644
|
||||
index f7ce3f173c2..0b6c9841b68 100644
|
||||
--- a/dlls/inseng/inseng_main.c
|
||||
+++ b/dlls/inseng/inseng_main.c
|
||||
@@ -2,6 +2,7 @@
|
||||
@@ -2385,11 +2385,11 @@ index f7ce3f173c2..ad6fe6b4de8 100644
|
||||
+
|
||||
+ if (!ref)
|
||||
+ {
|
||||
+ heap_free(This->file_name);
|
||||
+ heap_free(This->cache_file);
|
||||
+ HeapFree(GetProcessHeap(), 0, This->file_name);
|
||||
+ HeapFree(GetProcessHeap(), 0, This->cache_file);
|
||||
+
|
||||
+ IInstallEngine2_Release(&This->engine->IInstallEngine2_iface);
|
||||
+ heap_free(This);
|
||||
+ HeapFree(GetProcessHeap(), 0, This);
|
||||
+ }
|
||||
+
|
||||
+ return ref;
|
||||
@@ -2550,7 +2550,7 @@ index f7ce3f173c2..ad6fe6b4de8 100644
|
||||
+{
|
||||
+ struct downloadcb *cb;
|
||||
+
|
||||
+ cb = heap_alloc_zero(sizeof(*cb));
|
||||
+ cb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,sizeof(*cb));
|
||||
+ if (!cb) return E_OUTOFMEMORY;
|
||||
+
|
||||
+ cb->IBindStatusCallback_iface.lpVtbl = &BindStatusCallbackVtbl;
|
||||
@@ -2565,7 +2565,7 @@ index f7ce3f173c2..ad6fe6b4de8 100644
|
||||
+ cb->file_name = strAtoW(file_name);
|
||||
+ if (!cb->file_name)
|
||||
+ {
|
||||
+ heap_free(cb);
|
||||
+ HeapFree(GetProcessHeap(), 0, cb);
|
||||
+ return E_OUTOFMEMORY;
|
||||
+ }
|
||||
+
|
||||
@@ -2702,14 +2702,14 @@ index f7ce3f173c2..ad6fe6b4de8 100644
|
||||
+ do
|
||||
+ {
|
||||
+ size *= 2;
|
||||
+ heap_free(url_temp);
|
||||
+ url_temp = heap_alloc(size);
|
||||
+ HeapFree(GetProcessHeap(), 0, url_temp);
|
||||
+ url_temp = HeapAlloc(GetProcessHeap(), 0, size);
|
||||
+ if (!url_temp) return E_OUTOFMEMORY;
|
||||
+
|
||||
+ hr = ICifComponent_GetUrl(comp, index, url_temp, size, flags);
|
||||
+ if (FAILED(hr))
|
||||
+ {
|
||||
+ heap_free(url_temp);
|
||||
+ HeapFree(GetProcessHeap(), 0, url_temp);
|
||||
+ return hr;
|
||||
+ }
|
||||
+ }
|
||||
@@ -2725,7 +2725,7 @@ index f7ce3f173c2..ad6fe6b4de8 100644
|
||||
+ int len_url = strlen(url);
|
||||
+ char *combined;
|
||||
+
|
||||
+ combined = heap_alloc(len_base + len_url + 2);
|
||||
+ combined = HeapAlloc(GetProcessHeap(), 0, len_base + len_url + 2);
|
||||
+ if (!combined) return NULL;
|
||||
+
|
||||
+ strcpy(combined, baseurl);
|
||||
@@ -2751,7 +2751,7 @@ index f7ce3f173c2..ad6fe6b4de8 100644
|
||||
+ if (!combined) return E_OUTOFMEMORY;
|
||||
+
|
||||
+ urlW = strAtoW(combined);
|
||||
+ heap_free(combined);
|
||||
+ HeapFree(GetProcessHeap(), 0, combined);
|
||||
+ if (!urlW) return E_OUTOFMEMORY;
|
||||
+ }
|
||||
+ else
|
||||
@@ -2761,14 +2761,14 @@ index f7ce3f173c2..ad6fe6b4de8 100644
|
||||
+ }
|
||||
+
|
||||
+ hr = CreateURLMoniker(NULL, urlW, moniker);
|
||||
+ heap_free(urlW);
|
||||
+ HeapFree(GetProcessHeap(), 0, urlW);
|
||||
+ return hr;
|
||||
+}
|
||||
+
|
||||
+static char *merge_path(char *path1, char *path2)
|
||||
+{
|
||||
+ int len = strlen(path1) + strlen(path2) + 2;
|
||||
+ char *combined = heap_alloc(len);
|
||||
+ char *combined = HeapAlloc(GetProcessHeap(), 0, len);
|
||||
+
|
||||
+ if (!combined) return NULL;
|
||||
+ strcpy(combined, path1);
|
||||
@@ -2828,7 +2828,7 @@ index f7ce3f173c2..ad6fe6b4de8 100644
|
||||
+ if (FAILED(hr)) goto error;
|
||||
+ if (unk) IUnknown_Release(unk);
|
||||
+
|
||||
+ heap_free(filename);
|
||||
+ HeapFree(GetProcessHeap(), 0, filename);
|
||||
+ IMoniker_Release(mon);
|
||||
+ IBindCtx_Release(bindctx);
|
||||
+
|
||||
@@ -2844,7 +2844,7 @@ index f7ce3f173c2..ad6fe6b4de8 100644
|
||||
+ if (event) CloseHandle(event);
|
||||
+ if (callback) IBindStatusCallback_Release(&callback->IBindStatusCallback_iface);
|
||||
+ if (bindctx) IBindCtx_Release(bindctx);
|
||||
+ if (filename) heap_free(filename);
|
||||
+ if (filename) HeapFree(GetProcessHeap(), 0, filename);
|
||||
+ return hr;
|
||||
+}
|
||||
+
|
||||
@@ -2912,7 +2912,7 @@ index f7ce3f173c2..ad6fe6b4de8 100644
|
||||
+ TRACE("processing url %s\n", debugstr_a(url));
|
||||
+
|
||||
+ hr = download_url(This, id, display, url, flags, size_dl);
|
||||
+ heap_free(url);
|
||||
+ HeapFree(GetProcessHeap(), 0, url);
|
||||
+ if (FAILED(hr))
|
||||
+ {
|
||||
+ DWORD retry = 0;
|
||||
@@ -3222,7 +3222,7 @@ index f7ce3f173c2..ad6fe6b4de8 100644
|
||||
+ TRACE("(%p)->(%s)\n", This, debugstr_a(base_name));
|
||||
+
|
||||
+ if (This->baseurl)
|
||||
+ heap_free(This->baseurl);
|
||||
+ HeapFree(GetProcessHeap(), 0, This->baseurl);
|
||||
+
|
||||
+ This->baseurl = strdupA(base_name);
|
||||
+ return This->baseurl ? S_OK : E_OUTOFMEMORY;
|
||||
@@ -3237,7 +3237,7 @@ index f7ce3f173c2..ad6fe6b4de8 100644
|
||||
+ TRACE("(%p)->(%s)\n", This, debugstr_a(download_dir));
|
||||
+
|
||||
+ if (This->downloaddir)
|
||||
+ heap_free(This->downloaddir);
|
||||
+ HeapFree(GetProcessHeap(), 0, This->downloaddir);
|
||||
+
|
||||
+ This->downloaddir = strdupA(download_dir);
|
||||
+ return This->downloaddir ? S_OK : E_OUTOFMEMORY;
|
||||
@@ -3449,10 +3449,10 @@ index f7ce3f173c2..ad6fe6b4de8 100644
|
||||
IInstallEngine2_Release(&engine->IInstallEngine2_iface);
|
||||
diff --git a/dlls/inseng/inseng_private.h b/dlls/inseng/inseng_private.h
|
||||
new file mode 100644
|
||||
index 00000000000..49d4241d65e
|
||||
index 00000000000..33f7869195b
|
||||
--- /dev/null
|
||||
+++ b/dlls/inseng/inseng_private.h
|
||||
@@ -0,0 +1,79 @@
|
||||
@@ -0,0 +1,78 @@
|
||||
+/*
|
||||
+ * Copyright 2016 Michael MĂĽller
|
||||
+ *
|
||||
@@ -3477,12 +3477,11 @@ index 00000000000..49d4241d65e
|
||||
+#include "ole2.h"
|
||||
+#include "rpcproxy.h"
|
||||
+#include "inseng.h"
|
||||
+#include "wine/heap.h"
|
||||
+
|
||||
+
|
||||
+static inline char *strdupA(const char *src)
|
||||
+{
|
||||
+ char *dest = heap_alloc(strlen(src) + 1);
|
||||
+ char *dest = HeapAlloc(GetProcessHeap(), 0, strlen(src) + 1);
|
||||
+ if (dest) strcpy(dest, src);
|
||||
+ return dest;
|
||||
+}
|
||||
@@ -3859,5 +3858,5 @@ index 8a3f4c4d270..82927418a99 100644
|
||||
+cpp_quote("HRESULT WINAPI GetICifFileFromFile(ICifFile **, const char *);")
|
||||
+cpp_quote("HRESULT WINAPI GetICifRWFileFromFile(ICifRWFile **, const char *);")
|
||||
--
|
||||
2.42.0
|
||||
2.51.0
|
||||
|
||||
|
||||
@@ -1,413 +0,0 @@
|
||||
From 5f3feef99f8c9740f04dbe0ee1b23ca27d60548e Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Thu, 16 Jan 2014 20:56:49 -0700
|
||||
Subject: [PATCH] ntdll: Add support for creating reparse points.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
configure.ac | 2 +
|
||||
dlls/ntdll/Makefile.in | 2 +-
|
||||
dlls/ntdll/unix/file.c | 302 +++++++++++++++++++++++++++++++++++++++++
|
||||
include/ddk/ntifs.h | 5 +
|
||||
4 files changed, 310 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index b675da34d58..63e3bb5bdc7 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -2137,6 +2137,8 @@ AC_CHECK_FUNCS(\
|
||||
process_vm_writev \
|
||||
sched_getcpu \
|
||||
sched_yield \
|
||||
+ renameat \
|
||||
+ renameat2 \
|
||||
setproctitle \
|
||||
setprogname \
|
||||
sigprocmask \
|
||||
diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in
|
||||
index 3c0dfa7a895..b9a8bcba4cf 100644
|
||||
--- a/dlls/ntdll/Makefile.in
|
||||
+++ b/dlls/ntdll/Makefile.in
|
||||
@@ -5,7 +5,7 @@ IMPORTLIB = ntdll
|
||||
IMPORTS = $(TOMCRYPT_PE_LIBS) $(MUSL_PE_LIBS)
|
||||
EXTRAINCL = $(TOMCRYPT_PE_CFLAGS)
|
||||
UNIX_CFLAGS = $(UNWIND_CFLAGS) $(HWLOC_CFLAGS)
|
||||
-UNIX_LIBS = $(IOKIT_LIBS) $(COREFOUNDATION_LIBS) $(CORESERVICES_LIBS) $(RT_LIBS) $(PTHREAD_LIBS) $(UNWIND_LIBS) $(I386_LIBS) $(PROCSTAT_LIBS) $(HWLOC_LIBS)
|
||||
+UNIX_LIBS = $(IOKIT_LIBS) $(COREFOUNDATION_LIBS) $(CORESERVICES_LIBS) $(RT_LIBS) $(PTHREAD_LIBS) $(UNWIND_LIBS) $(I386_LIBS) $(PROCSTAT_LIBS) $(HWLOC_LIBS) -lm
|
||||
|
||||
EXTRADLLFLAGS = -nodefaultlibs
|
||||
i386_EXTRADLLFLAGS = -Wl,--image-base,0x7bc00000
|
||||
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
|
||||
index 7ab1dbb2b55..5b4fcb3711d 100644
|
||||
--- a/dlls/ntdll/unix/file.c
|
||||
+++ b/dlls/ntdll/unix/file.c
|
||||
@@ -36,6 +36,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
+#include <math.h>
|
||||
+#include <libgen.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_MNTENT_H
|
||||
@@ -121,6 +123,7 @@
|
||||
#include "wine/list.h"
|
||||
#include "wine/debug.h"
|
||||
#include "unix_private.h"
|
||||
+#include "ddk/ntifs.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(file);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(winediag);
|
||||
@@ -132,6 +135,12 @@ WINE_DECLARE_DEBUG_CHANNEL(winediag);
|
||||
#undef EXT2_IOC_GETFLAGS
|
||||
#undef EXT4_CASEFOLD_FL
|
||||
|
||||
+#ifndef RENAME_EXCHANGE
|
||||
+#define RENAME_EXCHANGE (1 << 1)
|
||||
+#endif
|
||||
+
|
||||
+#define SYM_MAX (PATH_MAX-1) /* PATH_MAX includes the NUL character */
|
||||
+
|
||||
#ifdef linux
|
||||
|
||||
/* We want the real kernel dirent structure, not the libc one */
|
||||
@@ -249,6 +258,95 @@ static const BOOL is_case_sensitive = FALSE;
|
||||
static pthread_mutex_t dir_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_mutex_t mnt_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
+#ifndef HAVE_RENAMEAT2
|
||||
+int renameat2( int olddirfd, const char *oldpath, int newdirfd, const char *newpath,
|
||||
+ unsigned int flags )
|
||||
+{
|
||||
+ if (flags == 0)
|
||||
+ return renameat( olddirfd, oldpath, newdirfd, newpath );
|
||||
+#if defined(__NR_renameat2)
|
||||
+ return syscall( __NR_renameat2, olddirfd, oldpath, newdirfd, newpath, flags );
|
||||
+#elif defined(RENAME_SWAP)
|
||||
+ return renameatx_np(olddirfd, oldpath, newdirfd, newpath,
|
||||
+ (flags & RENAME_EXCHANGE ? RENAME_SWAP : 0));
|
||||
+#else
|
||||
+ errno = ENOSYS;
|
||||
+ return -1;
|
||||
+#endif
|
||||
+}
|
||||
+#endif /* HAVE_RENAMEAT2 */
|
||||
+
|
||||
+static char *itoa( int i )
|
||||
+{
|
||||
+ static char buffer[11];
|
||||
+
|
||||
+ snprintf(buffer, sizeof(buffer), "%d", i);
|
||||
+ return buffer;
|
||||
+}
|
||||
+
|
||||
+/* base64url (RFC 4648 §5) encode a binary string
|
||||
+ * 1) start with base64
|
||||
+ * 2) replace '+' by '-' and replace '/' by '_'
|
||||
+ * 3) do not add padding characters
|
||||
+ * 4) do not add line separators
|
||||
+ */
|
||||
+static UINT encode_base64url( const char *bin, unsigned int len, char *base64 )
|
||||
+{
|
||||
+ UINT n = 0, x;
|
||||
+ static const char base64enc[] =
|
||||
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
+
|
||||
+ while (len > 0)
|
||||
+ {
|
||||
+ /* first 6 bits, all from bin[0] */
|
||||
+ base64[n++] = base64enc[(bin[0] & 0xfc) >> 2];
|
||||
+ x = (bin[0] & 3) << 4;
|
||||
+
|
||||
+ /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
|
||||
+ if (len == 1)
|
||||
+ {
|
||||
+ base64[n++] = base64enc[x];
|
||||
+ break;
|
||||
+ }
|
||||
+ base64[n++] = base64enc[x | ((bin[1] & 0xf0) >> 4)];
|
||||
+ x = (bin[1] & 0x0f) << 2;
|
||||
+
|
||||
+ /* next 6 bits 4 from bin[1] and 2 from bin[2] */
|
||||
+ if (len == 2)
|
||||
+ {
|
||||
+ base64[n++] = base64enc[x];
|
||||
+ break;
|
||||
+ }
|
||||
+ base64[n++] = base64enc[x | ((bin[2] & 0xc0) >> 6)];
|
||||
+
|
||||
+ /* last 6 bits, all from bin [2] */
|
||||
+ base64[n++] = base64enc[bin[2] & 0x3f];
|
||||
+ bin += 3;
|
||||
+ len -= 3;
|
||||
+ }
|
||||
+ base64[n] = 0;
|
||||
+ return n;
|
||||
+}
|
||||
+
|
||||
+/* create a directory and all the needed parent directories */
|
||||
+static int mkdir_p( int dirfd, const char *path, mode_t mode )
|
||||
+{
|
||||
+ char path_tmp[PATH_MAX], *p;
|
||||
+
|
||||
+ strcpy( path_tmp, path );
|
||||
+ for (p = path_tmp + 1; *p; p++) {
|
||||
+ if (*p == '/') {
|
||||
+ *p = '\0';
|
||||
+ if (mkdirat( dirfd, path_tmp, mode ) != 0 && errno != EEXIST)
|
||||
+ return -1;
|
||||
+ *p = '/';
|
||||
+ }
|
||||
+ }
|
||||
+ if (mkdirat( dirfd, path_tmp, mode ) != 0 && errno != EEXIST)
|
||||
+ return -1;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
/* check if a given Unicode char is OK in a DOS short name */
|
||||
static inline BOOL is_invalid_dos_char( WCHAR ch )
|
||||
{
|
||||
@@ -1653,6 +1751,28 @@ static int parse_samba_dos_attrib_data( char *data, int len )
|
||||
}
|
||||
|
||||
|
||||
+/* determine whether a reparse point is meant to be a directory or a file */
|
||||
+static int is_reparse_dir( int fd, const char *path, BOOL *is_dir )
|
||||
+{
|
||||
+ char link_path[PATH_MAX], *p;
|
||||
+ int ret;
|
||||
+
|
||||
+ if ((ret = readlinkat( fd, path, link_path, sizeof(link_path) )) < 0)
|
||||
+ return ret;
|
||||
+ /* confirm that this file is a reparse point */
|
||||
+ if (strncmp( link_path, ".REPARSE_POINT/", 15) != 0)
|
||||
+ return -1;
|
||||
+ /* skip past the reparse point indicator and the filename */
|
||||
+ p = &link_path[15];
|
||||
+ if ((p = strchr( p, '/' )) == NULL)
|
||||
+ return -1;
|
||||
+ p++;
|
||||
+ /* read the flag indicating whether this reparse point is a directory */
|
||||
+ if (is_dir) *is_dir = (*p == '.');
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
static BOOL fd_is_mount_point( int fd, const struct stat *st )
|
||||
{
|
||||
struct stat parent;
|
||||
@@ -3455,6 +3575,181 @@ done:
|
||||
}
|
||||
|
||||
|
||||
+/*
|
||||
+ * Retrieve the unix name corresponding to a file handle, remove that directory, and then symlink
|
||||
+ * the requested directory to the location of the old directory.
|
||||
+ */
|
||||
+NTSTATUS create_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
|
||||
+{
|
||||
+ int buffer_len = buffer->ReparseDataLength+FIELD_OFFSET(typeof(*buffer), GenericReparseBuffer);
|
||||
+ char target_path[PATH_MAX], link_path[PATH_MAX], link_dir[PATH_MAX];
|
||||
+ int encoded_len = (int)ceil(buffer_len*4/3.0) + 1, chunk_len;
|
||||
+ char tmpdir[PATH_MAX], tmplink[PATH_MAX], *d;
|
||||
+ BOOL needs_close, tempdir_created = FALSE;
|
||||
+ char filename_buf[PATH_MAX], *filename;
|
||||
+ char *unix_src = NULL, *encoded = NULL;
|
||||
+ int i = 0, j = 0, depth = 0, fd;
|
||||
+ int link_dir_fd = -1;
|
||||
+ NTSTATUS status;
|
||||
+ struct stat st;
|
||||
+ BOOL is_dir;
|
||||
+
|
||||
+ if (buffer_len > 16*1024)
|
||||
+ return STATUS_IO_REPARSE_DATA_INVALID;
|
||||
+
|
||||
+ if ((status = server_get_unix_fd( handle, FILE_SPECIAL_ACCESS, &fd, &needs_close, NULL, NULL )))
|
||||
+ return status;
|
||||
+ if (fstat( fd, &st ) == -1)
|
||||
+ {
|
||||
+ status = errno_to_status( errno );
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ if ((status = server_get_unix_name( handle, &unix_src )))
|
||||
+ goto cleanup;
|
||||
+ is_dir = S_ISDIR( st.st_mode );
|
||||
+ is_reparse_dir( AT_FDCWD, unix_src, &is_dir ); /* keep type (replace existing reparse point) */
|
||||
+ encoded = malloc( encoded_len );
|
||||
+ if (!encoded)
|
||||
+ {
|
||||
+ status = STATUS_NO_MEMORY;
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ encoded_len = encode_base64url( (const char *)buffer, buffer_len, encoded );
|
||||
+
|
||||
+ TRACE( "Linking %s to %s\n", debugstr_a(unix_src), encoded );
|
||||
+ strcpy( filename_buf, unix_src );
|
||||
+ filename = basename( filename_buf );
|
||||
+
|
||||
+ /* Create the symlink that represents the initial data in the reparse tag:
|
||||
+ * *) Begin all reparse tags with the hidden folder .REPARSE_POINT. This serves two purposes:
|
||||
+ * 1) it makes it easy to identify reparse points
|
||||
+ * 2) if the reparse buffer exceeds what can be stored in a single symlink (4095+1 bytes)
|
||||
+ * then we need to store additional data, so link to it and store it in a hidden folder
|
||||
+ * *) Append the filename of the reparse point to the hidden folder, this ensures that if
|
||||
+ * multiple reparse points contain the same data that there is no possibility of collision
|
||||
+ * *) Append a special flag to indicate whether this is a directory (./) or file (/)
|
||||
+ * *) Append the base64-url encoded reparse point buffer
|
||||
+ * *) Append the filename of the first continuing symlink (0) in case we need it
|
||||
+ */
|
||||
+ strcpy( target_path, ".REPARSE_POINT/" );
|
||||
+ strcat( target_path, filename );
|
||||
+ strcat( target_path, "/" );
|
||||
+ if (is_dir)
|
||||
+ strcat( target_path, "." );
|
||||
+ strcat( target_path, "/" );
|
||||
+ i = 0;
|
||||
+ for (depth=0; i<encoded_len && strlen(target_path)<SYM_MAX-2; i+=chunk_len, depth++)
|
||||
+ {
|
||||
+ chunk_len = min(NAME_MAX, SYM_MAX-2-strlen(target_path));
|
||||
+ strncat( target_path, &encoded[i], chunk_len );
|
||||
+ strcat( target_path, "/" );
|
||||
+ }
|
||||
+ strcat( target_path, itoa(j) );
|
||||
+
|
||||
+ /* Produce the link in a temporary location in the same folder */
|
||||
+ strcpy( tmpdir, unix_src );
|
||||
+ d = dirname( tmpdir);
|
||||
+ if (d != tmpdir) strcpy( tmpdir, d );
|
||||
+ strcat( tmpdir, "/.winelink.XXXXXX" );
|
||||
+ if (mkdtemp( tmpdir ) == NULL)
|
||||
+ {
|
||||
+ status = errno_to_status( errno );
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ tempdir_created = TRUE;
|
||||
+ strcpy( tmplink, tmpdir );
|
||||
+ strcat( tmplink, "/tmplink" );
|
||||
+ if (symlink( target_path, tmplink ))
|
||||
+ {
|
||||
+ status = errno_to_status( errno );
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ /* change to the link folder so that we can build any necessary additional data */
|
||||
+ strcpy( link_dir, tmpdir );
|
||||
+ link_dir[strlen(link_dir)-16] = 0;
|
||||
+ link_dir_fd = open( link_dir, O_RDONLY|O_DIRECTORY );
|
||||
+
|
||||
+ /* If there is any further information in the reparse tag then store it in the hidden folder */
|
||||
+ while(i < encoded_len)
|
||||
+ {
|
||||
+ int fd;
|
||||
+
|
||||
+ j++;
|
||||
+ strcpy( link_path, target_path );
|
||||
+
|
||||
+ target_path[0] = 0;
|
||||
+ for (; depth>0; depth--)
|
||||
+ {
|
||||
+ strcat( target_path, "../" );
|
||||
+ }
|
||||
+ for (depth=0; i<encoded_len && strlen(target_path)<SYM_MAX-2; i+=chunk_len, depth++)
|
||||
+ {
|
||||
+ chunk_len = min(NAME_MAX, SYM_MAX-2-strlen(target_path));
|
||||
+ strncat( target_path, &encoded[i], chunk_len );
|
||||
+ strcat( target_path, "/" );
|
||||
+ }
|
||||
+ strcat( target_path, itoa(j) );
|
||||
+
|
||||
+ strcpy( link_dir, link_path );
|
||||
+ link_dir[strlen(link_dir)-1] = 0;
|
||||
+ if (mkdir_p( link_dir_fd, link_dir, 0777))
|
||||
+ {
|
||||
+ status = errno_to_status( errno );
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ if (symlinkat( target_path, link_dir_fd, link_path ))
|
||||
+ {
|
||||
+ status = errno_to_status( errno );
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ fd = openat( link_dir_fd, link_dir, O_RDONLY|O_DIRECTORY );
|
||||
+ close( link_dir_fd );
|
||||
+ link_dir_fd = fd;
|
||||
+ }
|
||||
+
|
||||
+ /* Atomically move the initial link into position */
|
||||
+ if (!renameat2( -1, tmplink, -1, unix_src, RENAME_EXCHANGE ))
|
||||
+ {
|
||||
+ /* success: link and folder/file have switched locations */
|
||||
+ if (S_ISDIR( st.st_mode ))
|
||||
+ rmdir( tmplink ); /* remove the folder (at link location) */
|
||||
+ else
|
||||
+ unlink( tmplink ); /* remove the file (at link location) */
|
||||
+ }
|
||||
+ else if (errno == ENOSYS)
|
||||
+ {
|
||||
+ FIXME( "Atomic exchange of directory with symbolic link unsupported on this system, "
|
||||
+ "using unsafe exchange instead.\n" );
|
||||
+ if (rmdir( unix_src ))
|
||||
+ {
|
||||
+ status = errno_to_status( errno );
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ if (rename( tmplink, unix_src ))
|
||||
+ {
|
||||
+ status = errno_to_status( errno );
|
||||
+ goto cleanup; /* not moved, orignal file/folder at destination is orphaned */
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ status = errno_to_status( errno );
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ status = STATUS_SUCCESS;
|
||||
+
|
||||
+cleanup:
|
||||
+ if (link_dir_fd != -1) close( link_dir_fd );
|
||||
+ if (tempdir_created) rmdir( tmpdir );
|
||||
+ if (needs_close) close( fd );
|
||||
+ free( unix_src );
|
||||
+ free( encoded );
|
||||
+
|
||||
+ return status;
|
||||
+}
|
||||
+
|
||||
+
|
||||
/******************************************************************************
|
||||
* lookup_unix_name
|
||||
*
|
||||
@@ -6400,6 +6695,13 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
|
||||
break;
|
||||
}
|
||||
|
||||
+ case FSCTL_SET_REPARSE_POINT:
|
||||
+ {
|
||||
+ REPARSE_DATA_BUFFER *buffer = (REPARSE_DATA_BUFFER *)in_buffer;
|
||||
+ status = create_reparse_point( handle, buffer );
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
case FSCTL_SET_SPARSE:
|
||||
TRACE("FSCTL_SET_SPARSE: Ignoring request\n");
|
||||
status = STATUS_SUCCESS;
|
||||
diff --git a/include/ddk/ntifs.h b/include/ddk/ntifs.h
|
||||
index 980235abdc9..90248b4897c 100644
|
||||
--- a/include/ddk/ntifs.h
|
||||
+++ b/include/ddk/ntifs.h
|
||||
@@ -166,6 +166,11 @@ typedef struct _REPARSE_DATA_BUFFER
|
||||
WCHAR PathBuffer[1];
|
||||
} MountPointReparseBuffer;
|
||||
|
||||
+ struct {
|
||||
+ ULONG Version;
|
||||
+ UCHAR PathBuffer[1];
|
||||
+ } LinuxSymbolicLinkReparseBuffer;
|
||||
+
|
||||
struct
|
||||
{
|
||||
UCHAR DataBuffer[1];
|
||||
--
|
||||
2.51.0
|
||||
|
||||
@@ -1,266 +0,0 @@
|
||||
From 369f4d92683910c01d82719e448d21a74b7b82d8 Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Thu, 16 Jan 2014 20:57:57 -0700
|
||||
Subject: [PATCH] ntdll: Add support for reading reparse points.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
dlls/ntdll/unix/file.c | 221 ++++++++++++++++++++++++++++++++++++++--
|
||||
2 files changed, 231 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
|
||||
index 0d58abbfa84..3e160fb1e5c 100644
|
||||
--- a/dlls/ntdll/unix/file.c
|
||||
+++ b/dlls/ntdll/unix/file.c
|
||||
@@ -325,6 +325,84 @@ static UINT encode_base64url( const char *bin, unsigned int len, char *base64 )
|
||||
return n;
|
||||
}
|
||||
|
||||
+static inline char decode_base64url_char( char c )
|
||||
+{
|
||||
+ if (c >= 'A' && c <= 'Z') return c - 'A';
|
||||
+ if (c >= 'a' && c <= 'z') return c - 'a' + 26;
|
||||
+ if (c >= '0' && c <= '9') return c - '0' + 52;
|
||||
+ if (c == '-') return 62;
|
||||
+ if (c == '_') return 63;
|
||||
+ return 64;
|
||||
+}
|
||||
+
|
||||
+/* decode a base64url (RFC 4648 §5) binary string
|
||||
+ * 1) start with base64
|
||||
+ * 2) replace '+' by '-' and replace '/' by '_'
|
||||
+ * 3) do not add padding characters
|
||||
+ * 4) do not add line separators
|
||||
+ */
|
||||
+static unsigned int decode_base64url( const char *base64, unsigned int len, char *buf )
|
||||
+{
|
||||
+ unsigned int i = 0;
|
||||
+ char c0, c1, c2, c3;
|
||||
+ const char *p = base64;
|
||||
+
|
||||
+ while (len > 4)
|
||||
+ {
|
||||
+ if ((c0 = decode_base64url_char( p[0] )) > 63) return 0;
|
||||
+ if ((c1 = decode_base64url_char( p[1] )) > 63) return 0;
|
||||
+ if ((c2 = decode_base64url_char( p[2] )) > 63) return 0;
|
||||
+ if ((c3 = decode_base64url_char( p[3] )) > 63) return 0;
|
||||
+
|
||||
+ if (buf)
|
||||
+ {
|
||||
+ buf[i + 0] = (c0 << 2) | (c1 >> 4);
|
||||
+ buf[i + 1] = (c1 << 4) | (c2 >> 2);
|
||||
+ buf[i + 2] = (c2 << 6) | c3;
|
||||
+ }
|
||||
+ len -= 4;
|
||||
+ i += 3;
|
||||
+ p += 4;
|
||||
+ }
|
||||
+ if (len == 2)
|
||||
+ {
|
||||
+ if ((c0 = decode_base64url_char( p[0] )) > 63) return 0;
|
||||
+ if ((c1 = decode_base64url_char( p[1] )) > 63) return 0;
|
||||
+
|
||||
+ if (buf) buf[i] = (c0 << 2) | (c1 >> 4);
|
||||
+ i++;
|
||||
+ }
|
||||
+ else if (len == 3)
|
||||
+ {
|
||||
+ if ((c0 = decode_base64url_char( p[0] )) > 63) return 0;
|
||||
+ if ((c1 = decode_base64url_char( p[1] )) > 63) return 0;
|
||||
+ if ((c2 = decode_base64url_char( p[2] )) > 63) return 0;
|
||||
+
|
||||
+ if (buf)
|
||||
+ {
|
||||
+ buf[i + 0] = (c0 << 2) | (c1 >> 4);
|
||||
+ buf[i + 1] = (c1 << 4) | (c2 >> 2);
|
||||
+ }
|
||||
+ i += 2;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ if ((c0 = decode_base64url_char( p[0] )) > 63) return 0;
|
||||
+ if ((c1 = decode_base64url_char( p[1] )) > 63) return 0;
|
||||
+ if ((c2 = decode_base64url_char( p[2] )) > 63) return 0;
|
||||
+ if ((c3 = decode_base64url_char( p[3] )) > 63) return 0;
|
||||
+
|
||||
+ if (buf)
|
||||
+ {
|
||||
+ buf[i + 0] = (c0 << 2) | (c1 >> 4);
|
||||
+ buf[i + 1] = (c1 << 4) | (c2 >> 2);
|
||||
+ buf[i + 2] = (c2 << 6) | c3;
|
||||
+ }
|
||||
+ i += 3;
|
||||
+ }
|
||||
+ return i;
|
||||
+}
|
||||
+
|
||||
/* create a directory and all the needed parent directories */
|
||||
static int mkdir_p( int dirfd, const char *path, mode_t mode )
|
||||
{
|
||||
@@ -3715,6 +3793,132 @@ cleanup:
|
||||
}
|
||||
|
||||
|
||||
+/*
|
||||
+ * Retrieve the unix name corresponding to a file handle and use that to find the destination of the
|
||||
+ * symlink corresponding to that file handle.
|
||||
+ */
|
||||
+NTSTATUS get_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG *size)
|
||||
+{
|
||||
+ char link_dir[PATH_MAX], link_path[PATH_MAX], *d;
|
||||
+ int link_path_len, buffer_len, encoded_len;
|
||||
+ REPARSE_DATA_BUFFER header;
|
||||
+ ULONG out_size = *size;
|
||||
+ char *unix_name = NULL;
|
||||
+ char *encoded = NULL;
|
||||
+ int link_dir_fd = -1;
|
||||
+ NTSTATUS status;
|
||||
+ ssize_t ret;
|
||||
+ int depth;
|
||||
+ char *p;
|
||||
+
|
||||
+ if ((status = server_get_unix_name( handle, &unix_name )))
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ ret = readlink( unix_name, link_path, sizeof(link_path) );
|
||||
+ if (ret < 0)
|
||||
+ {
|
||||
+ status = errno_to_status( errno );
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ link_path_len = ret;
|
||||
+ link_path[link_path_len] = 0;
|
||||
+ if (strncmp( link_path, ".REPARSE_POINT/", 15 ) != 0)
|
||||
+ {
|
||||
+ status = STATUS_NOT_IMPLEMENTED;
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ encoded_len = link_path_len;
|
||||
+ encoded = malloc( encoded_len );
|
||||
+ if (!encoded)
|
||||
+ {
|
||||
+ status = STATUS_NO_MEMORY;
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ /* Copy the encoded data from the inital symlink */
|
||||
+ encoded[0] = 0;
|
||||
+ p = &link_path[15];
|
||||
+ if ((p = strchr( p, '/' )) == NULL)
|
||||
+ {
|
||||
+ status = STATUS_IO_REPARSE_DATA_INVALID;
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ p++;
|
||||
+ if (*(p++) == '.')
|
||||
+ p++;
|
||||
+ for (depth=0; p < link_path + link_path_len; p += NAME_MAX+1, depth++)
|
||||
+ strncat( encoded, p, NAME_MAX );
|
||||
+ encoded[strlen(encoded)-1] = 0; /* chunk id */
|
||||
+ encoded[strlen(encoded)-1] = 0; /* final slash */
|
||||
+
|
||||
+ /* get the length of the full buffer so that we know when to stop collecting data */
|
||||
+ decode_base64url( encoded, sizeof(header), (char*)&header );
|
||||
+ buffer_len = header.ReparseDataLength+FIELD_OFFSET(typeof(header), GenericReparseBuffer);
|
||||
+ *size = buffer_len;
|
||||
+
|
||||
+ if (buffer_len > out_size)
|
||||
+ {
|
||||
+ status = STATUS_BUFFER_TOO_SMALL;
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ encoded_len = (int)ceil(buffer_len*4/3.0);
|
||||
+ encoded = realloc( encoded, encoded_len + 3 ); /* 3 chars = slash, chunk ID, NUL character */
|
||||
+ if (!encoded)
|
||||
+ {
|
||||
+ status = STATUS_NO_MEMORY;
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ /* change to the link folder so that we can build any necessary additional data */
|
||||
+ strcpy( link_dir, unix_name );
|
||||
+ d = dirname( link_dir);
|
||||
+ if (d != link_dir) strcpy( link_dir, d );
|
||||
+ link_dir_fd = open( link_dir, O_RDONLY|O_DIRECTORY );
|
||||
+
|
||||
+ /* Copy the encoded data from the follow on symlinks */
|
||||
+ while(strlen(encoded) < encoded_len)
|
||||
+ {
|
||||
+ int fd;
|
||||
+
|
||||
+ strcpy( link_dir, link_path );
|
||||
+ ret = readlinkat( link_dir_fd, link_dir, link_path, sizeof(link_path) );
|
||||
+ if (ret < 0)
|
||||
+ {
|
||||
+ status = errno_to_status( errno );
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ link_path_len = ret;
|
||||
+ link_path[link_path_len] = 0; /* readlink does not NUL terminate */
|
||||
+
|
||||
+ p = &link_path[3*depth];
|
||||
+ for (depth=0; p < link_path + link_path_len; p += NAME_MAX+1, depth++)
|
||||
+ strncat( encoded, p, NAME_MAX );
|
||||
+ encoded[strlen(encoded)-1] = 0; /* chunk id */
|
||||
+ encoded[strlen(encoded)-1] = 0; /* final slash */
|
||||
+
|
||||
+ link_dir[strlen(link_dir)-1] = 0;
|
||||
+ fd = openat( link_dir_fd, link_dir, O_RDONLY|O_DIRECTORY );
|
||||
+ close( link_dir_fd );
|
||||
+ link_dir_fd = fd;
|
||||
+ }
|
||||
+
|
||||
+ /* Decode the reparse buffer from the base64-encoded symlink data */
|
||||
+ *size = decode_base64url( encoded, strlen(encoded), (char*)buffer );
|
||||
+ status = STATUS_SUCCESS;
|
||||
+ if (buffer_len != *size)
|
||||
+ {
|
||||
+ status = STATUS_IO_REPARSE_DATA_INVALID;
|
||||
+ ERR("Size mismatch decoding reparse point buffer (%d != %d)\n", *size, buffer_len);
|
||||
+ }
|
||||
+
|
||||
+cleanup:
|
||||
+ if (link_dir_fd != -1) close( link_dir_fd );
|
||||
+ free( unix_name );
|
||||
+ free( encoded );
|
||||
+ return status;
|
||||
+}
|
||||
+
|
||||
+
|
||||
/******************************************************************************
|
||||
* lookup_unix_name
|
||||
*
|
||||
@@ -6525,15 +6729,6 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
|
||||
break;
|
||||
}
|
||||
|
||||
- case FSCTL_GET_REPARSE_POINT:
|
||||
- if (out_buffer && out_size)
|
||||
- {
|
||||
- FIXME("FSCTL_GET_REPARSE_POINT semi-stub\n");
|
||||
- status = STATUS_NOT_A_REPARSE_POINT;
|
||||
- }
|
||||
- else status = STATUS_INVALID_USER_BUFFER;
|
||||
- break;
|
||||
-
|
||||
case FSCTL_GET_OBJECT_ID:
|
||||
{
|
||||
FILE_OBJECTID_BUFFER *info = out_buffer;
|
||||
@@ -6555,6 +6750,14 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
|
||||
break;
|
||||
}
|
||||
|
||||
+ case FSCTL_GET_REPARSE_POINT:
|
||||
+ {
|
||||
+ REPARSE_DATA_BUFFER *buffer = (REPARSE_DATA_BUFFER *)out_buffer;
|
||||
+ ULONG size = out_size;
|
||||
+ status = get_reparse_point( handle, buffer, &size );
|
||||
+ io->Information = size;
|
||||
+ break;
|
||||
+ }
|
||||
case FSCTL_SET_REPARSE_POINT:
|
||||
{
|
||||
REPARSE_DATA_BUFFER *buffer = (REPARSE_DATA_BUFFER *)in_buffer;
|
||||
--
|
||||
2.43.0
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
From 3c25b2e7839c1493f97d144f137822cbf9a498a3 Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Thu, 16 Jan 2014 21:00:21 -0700
|
||||
Subject: [PATCH] ntdll: Add support for deleting reparse points.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
dlls/ntdll/unix/file.c | 99 +++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 121 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
|
||||
index 92ce83b685e..ba77aab61b7 100644
|
||||
--- a/dlls/ntdll/unix/file.c
|
||||
+++ b/dlls/ntdll/unix/file.c
|
||||
@@ -3812,6 +3812,99 @@ cleanup:
|
||||
}
|
||||
|
||||
|
||||
+/*
|
||||
+ * Retrieve the unix name corresponding to a file handle, remove that symlink, and then recreate
|
||||
+ * a directory at the location of the old filename.
|
||||
+ */
|
||||
+NTSTATUS remove_reparse_point(HANDLE handle, REPARSE_GUID_DATA_BUFFER *buffer)
|
||||
+{
|
||||
+ char tmpdir[PATH_MAX], tmplink[PATH_MAX], *d;
|
||||
+ BOOL tempdir_created = FALSE;
|
||||
+ int dest_fd, needs_close;
|
||||
+ BOOL is_dir = TRUE;
|
||||
+ NTSTATUS status;
|
||||
+ char *unix_name;
|
||||
+ struct stat st;
|
||||
+
|
||||
+ if ((status = server_get_unix_fd( handle, FILE_SPECIAL_ACCESS, &dest_fd, &needs_close, NULL, NULL )))
|
||||
+ return status;
|
||||
+
|
||||
+ if ((status = server_get_unix_name( handle, &unix_name )))
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ TRACE( "Deleting symlink %s\n", unix_name );
|
||||
+
|
||||
+ /* Produce the file/directory in a temporary location in the same folder */
|
||||
+ if (fstat( dest_fd, &st ) == -1)
|
||||
+ {
|
||||
+ status = errno_to_status( errno );
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ is_dir = S_ISDIR(st.st_mode);
|
||||
+ strcpy( tmpdir, unix_name );
|
||||
+ d = dirname( tmpdir);
|
||||
+ if (d != tmpdir) strcpy( tmpdir, d );
|
||||
+ strcat( tmpdir, "/.winelink.XXXXXX" );
|
||||
+ if (mkdtemp( tmpdir ) == NULL)
|
||||
+ {
|
||||
+ status = errno_to_status( errno );
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ tempdir_created = TRUE;
|
||||
+ strcpy( tmplink, tmpdir );
|
||||
+ strcat( tmplink, "/tmplink" );
|
||||
+ if (is_dir && mkdir( tmplink, st.st_mode ))
|
||||
+ {
|
||||
+ status = errno_to_status( errno );
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ else if (!is_dir)
|
||||
+ {
|
||||
+ int fd = open( tmplink, O_CREAT|O_WRONLY|O_TRUNC, st.st_mode );
|
||||
+ if (fd < 0)
|
||||
+ {
|
||||
+ status = errno_to_status( errno );
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ close( fd );
|
||||
+ }
|
||||
+ /* attemp to retain the ownership (if possible) */
|
||||
+ lchown( tmplink, st.st_uid, st.st_gid );
|
||||
+ /* Atomically move the directory into position */
|
||||
+ if (!renameat2( -1, tmplink, -1, unix_name, RENAME_EXCHANGE ))
|
||||
+ {
|
||||
+ /* success: link and folder/file have switched locations */
|
||||
+ unlink( tmplink ); /* remove the file (at link location) */
|
||||
+ }
|
||||
+ else if (errno == ENOSYS)
|
||||
+ {
|
||||
+ FIXME( "Atomic exchange of directory with symbolic link unsupported on this system, "
|
||||
+ "using unsafe exchange instead.\n" );
|
||||
+ if (unlink( unix_name ))
|
||||
+ {
|
||||
+ status = errno_to_status( errno );
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ if (rename( tmplink, unix_name ))
|
||||
+ {
|
||||
+ status = errno_to_status( errno );
|
||||
+ goto cleanup; /* not moved, orignal file/folder at destination is orphaned */
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ status = errno_to_status( errno );
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ status = STATUS_SUCCESS;
|
||||
+
|
||||
+cleanup:
|
||||
+ if (tempdir_created) rmdir( tmpdir );
|
||||
+ if (needs_close) close( dest_fd );
|
||||
+ return status;
|
||||
+}
|
||||
+
|
||||
+
|
||||
/******************************************************************************
|
||||
* lookup_unix_name
|
||||
*
|
||||
@@ -6571,6 +6664,12 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
|
||||
break;
|
||||
}
|
||||
|
||||
+ case FSCTL_DELETE_REPARSE_POINT:
|
||||
+ {
|
||||
+ REPARSE_GUID_DATA_BUFFER *buffer = (REPARSE_GUID_DATA_BUFFER *)in_buffer;
|
||||
+ status = remove_reparse_point( handle, buffer );
|
||||
+ break;
|
||||
+ }
|
||||
case FSCTL_GET_REPARSE_POINT:
|
||||
{
|
||||
REPARSE_DATA_BUFFER *buffer = (REPARSE_DATA_BUFFER *)out_buffer;
|
||||
--
|
||||
2.37.2
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
From a093cbbe7bd8ea6b1e5d48a552f2712dc2915f2c Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Thu, 16 Jan 2014 21:01:25 -0700
|
||||
Subject: ntdll: Add support for testing for reparse points with
|
||||
GetFileAttributes.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
dlls/ntdll/unix/file.c | 23 +++++++++++++++++++----
|
||||
2 files changed, 24 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
|
||||
index 4c221f53bfd..948074b35ec 100644
|
||||
--- a/dlls/ntdll/unix/file.c
|
||||
+++ b/dlls/ntdll/unix/file.c
|
||||
@@ -1755,6 +1755,16 @@ static int fd_get_file_info( int fd, unsigned int options, struct stat *st, ULON
|
||||
*attr = 0;
|
||||
ret = fstat( fd, st );
|
||||
if (ret == -1) return ret;
|
||||
+ if (S_ISLNK( st->st_mode ))
|
||||
+ {
|
||||
+ BOOL is_dir;
|
||||
+
|
||||
+ /* symbolic links (either junction points or NT symlinks) are "reparse points" */
|
||||
+ *attr |= FILE_ATTRIBUTE_REPARSE_POINT;
|
||||
+ /* whether a reparse point is a file or a directory is stored inside the link target */
|
||||
+ if (is_reparse_dir( fd, "", &is_dir ) == 0)
|
||||
+ st->st_mode = (st->st_mode & ~S_IFMT) | (is_dir ? S_IFDIR : S_IFREG);
|
||||
+ }
|
||||
*attr |= get_file_attributes( st );
|
||||
/* consider mount points to be reparse points (IO_REPARSE_TAG_MOUNT_POINT) */
|
||||
if ((options & FILE_OPEN_REPARSE_POINT) && fd_is_mount_point( fd, st ))
|
||||
@@ -1828,10 +1838,15 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr )
|
||||
if (ret == -1) return ret;
|
||||
if (S_ISLNK( st->st_mode ))
|
||||
{
|
||||
- ret = stat( path, st );
|
||||
- if (ret == -1) return ret;
|
||||
- /* is a symbolic link and a directory, consider these "reparse points" */
|
||||
- if (S_ISDIR( st->st_mode )) *attr |= FILE_ATTRIBUTE_REPARSE_POINT;
|
||||
+ BOOL is_dir;
|
||||
+
|
||||
+ /* return information about the destination (unless this is a dangling symlink) */
|
||||
+ stat( path, st );
|
||||
+ /* symbolic links (either junction points or NT symlinks) are "reparse points" */
|
||||
+ *attr |= FILE_ATTRIBUTE_REPARSE_POINT;
|
||||
+ /* whether a reparse point is a file or a directory is stored inside the link target */
|
||||
+ if (is_reparse_dir( AT_FDCWD, path, &is_dir ) == 0)
|
||||
+ st->st_mode = (st->st_mode & ~S_IFMT) | (is_dir ? S_IFDIR : S_IFREG);
|
||||
}
|
||||
else if (S_ISDIR( st->st_mode ) && (parent_path = malloc( strlen(path) + 4 )))
|
||||
{
|
||||
--
|
||||
2.17.1
|
||||
|
||||
@@ -1,288 +0,0 @@
|
||||
From 742f9b17c321b671e6b7bcd3bc7772e3ef66729d Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Thu, 16 Jan 2014 21:02:11 -0700
|
||||
Subject: [PATCH] server: Implement FILE_OPEN_REPARSE_POINT option.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
dlls/kernelbase/file.c | 2 +
|
||||
server/fd.c | 147 +++++++++++++++++++++++++++++++++++++++--
|
||||
2 files changed, 142 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c
|
||||
index 249f476eb7e..2ea3d81a264 100644
|
||||
--- a/dlls/kernelbase/file.c
|
||||
+++ b/dlls/kernelbase/file.c
|
||||
@@ -769,6 +769,8 @@ static UINT get_nt_file_options( DWORD attributes )
|
||||
options |= FILE_SEQUENTIAL_ONLY;
|
||||
if (attributes & FILE_FLAG_WRITE_THROUGH)
|
||||
options |= FILE_WRITE_THROUGH;
|
||||
+ if (attributes & FILE_FLAG_OPEN_REPARSE_POINT)
|
||||
+ options |= FILE_OPEN_REPARSE_POINT;
|
||||
return options;
|
||||
}
|
||||
|
||||
diff --git a/server/fd.c b/server/fd.c
|
||||
index c82ed49034e..cd4b35915d4 100644
|
||||
--- a/server/fd.c
|
||||
+++ b/server/fd.c
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
+#include <libgen.h>
|
||||
#include <poll.h>
|
||||
#ifdef HAVE_LINUX_MAJOR_H
|
||||
#include <linux/major.h>
|
||||
@@ -99,6 +100,10 @@
|
||||
#include "winioctl.h"
|
||||
#include "ddk/wdm.h"
|
||||
|
||||
+#if !defined(O_SYMLINK) && defined(O_PATH)
|
||||
+# define O_SYMLINK (O_NOFOLLOW | O_PATH)
|
||||
+#endif
|
||||
+
|
||||
#if defined(HAVE_SYS_EPOLL_H) && defined(HAVE_EPOLL_CREATE)
|
||||
# include <sys/epoll.h>
|
||||
# define USE_EPOLL
|
||||
@@ -1064,6 +1069,9 @@ static void device_destroy( struct object *obj )
|
||||
list_remove( &device->entry ); /* remove it from the hash table */
|
||||
}
|
||||
|
||||
+static int is_reparse_dir( const char *path, int *is_dir );
|
||||
+static int rmdir_recursive( int dir_fd, const char *pathname );
|
||||
+
|
||||
/****************************************************************/
|
||||
/* inode functions */
|
||||
|
||||
@@ -1071,10 +1079,29 @@ static void unlink_closed_fd( struct inode *inode, struct closed_fd *fd )
|
||||
{
|
||||
/* make sure it is still the same file */
|
||||
struct stat st;
|
||||
- if (!stat( fd->unix_name, &st ) && st.st_dev == inode->device->dev && st.st_ino == inode->ino)
|
||||
+ if (!lstat( fd->unix_name, &st ) && st.st_dev == inode->device->dev && st.st_ino == inode->ino)
|
||||
{
|
||||
+ int is_reparse_point = (is_reparse_dir( fd->unix_name, NULL ) == 0);
|
||||
if (S_ISDIR(st.st_mode)) rmdir( fd->unix_name );
|
||||
else unlink( fd->unix_name );
|
||||
+ /* remove reparse point metadata (if applicable) */
|
||||
+ if (is_reparse_point)
|
||||
+ {
|
||||
+ char tmp[PATH_MAX], metadata_path[PATH_MAX], *p;
|
||||
+
|
||||
+ strcpy( tmp, fd->unix_name );
|
||||
+ p = dirname( tmp );
|
||||
+ if (p != tmp ) strcpy( tmp, p );
|
||||
+ strcpy( metadata_path, tmp );
|
||||
+ strcat( metadata_path, "/.REPARSE_POINT/" );
|
||||
+ strcpy( tmp, fd->unix_name );
|
||||
+ p = basename( tmp );
|
||||
+ if (p != tmp) strcpy( tmp, p );
|
||||
+ strcat( metadata_path, tmp );
|
||||
+
|
||||
+ rmdir_recursive( AT_FDCWD, metadata_path );
|
||||
+ rmdir( dirname( metadata_path ) );
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1113,6 +1140,59 @@ static void inode_dump( struct object *obj, int verbose )
|
||||
fprintf( stderr, "\n" );
|
||||
}
|
||||
|
||||
+/* recursively delete everything in a directory */
|
||||
+static int rmdir_recursive( int dir_fd, const char *pathname )
|
||||
+{
|
||||
+ int ret = 0, tmp_fd;
|
||||
+ struct dirent *p;
|
||||
+ struct stat st;
|
||||
+ DIR *d;
|
||||
+
|
||||
+ tmp_fd = openat( dir_fd, pathname, O_DIRECTORY|O_RDONLY|O_NONBLOCK|O_CLOEXEC );
|
||||
+ d = fdopendir( tmp_fd );
|
||||
+ if (!d)
|
||||
+ {
|
||||
+ close( tmp_fd );
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ while (!ret && (p = readdir( d )))
|
||||
+ {
|
||||
+ if (!strcmp( p->d_name, "." ) || !strcmp( p->d_name, ".." ))
|
||||
+ continue;
|
||||
+ if (!fstatat( dirfd(d), p->d_name, &st, AT_SYMLINK_NOFOLLOW ))
|
||||
+ {
|
||||
+ if (S_ISDIR( st.st_mode ))
|
||||
+ ret = rmdir_recursive( dirfd(d), p->d_name );
|
||||
+ else
|
||||
+ ret = unlinkat( dirfd(d), p->d_name, 0 );
|
||||
+ }
|
||||
+ }
|
||||
+ closedir( d );
|
||||
+ return unlinkat( dir_fd, pathname, AT_REMOVEDIR );
|
||||
+}
|
||||
+
|
||||
+/* determine whether a reparse point is meant to be a directory or a file */
|
||||
+static int is_reparse_dir( const char *path, int *is_dir )
|
||||
+{
|
||||
+ char link_path[PATH_MAX], *p;
|
||||
+ int ret;
|
||||
+
|
||||
+ if ((ret = readlink( path, link_path, sizeof(link_path) )) < 0)
|
||||
+ return ret;
|
||||
+ /* confirm that this file is a reparse point */
|
||||
+ if (strncmp( link_path, ".REPARSE_POINT/", 15) != 0)
|
||||
+ return -1;
|
||||
+ /* skip past the reparse point indicator and the filename */
|
||||
+ p = &link_path[15];
|
||||
+ if ((p = strchr( p, '/' )) == NULL)
|
||||
+ return -1;
|
||||
+ p++;
|
||||
+ /* read the flag indicating whether this reparse point is a directory */
|
||||
+ if (is_dir) *is_dir = (*p == '.');
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static void inode_destroy( struct object *obj )
|
||||
{
|
||||
struct inode *inode = (struct inode *)obj;
|
||||
@@ -1861,6 +1941,38 @@ void get_nt_name( struct fd *fd, struct unicode_str *name )
|
||||
name->len = fd->nt_namelen;
|
||||
}
|
||||
|
||||
+/* check whether a file is a symlink */
|
||||
+int check_symlink( char *name )
|
||||
+{
|
||||
+ struct stat st;
|
||||
+
|
||||
+ lstat( name, &st );
|
||||
+ return S_ISLNK( st.st_mode );
|
||||
+}
|
||||
+
|
||||
+/* if flags does not contain O_SYMLINK then just use realpath */
|
||||
+/* otherwise return the real path of the parent and append the filename of the symlink */
|
||||
+char *normalize_path( const char *path, int flags )
|
||||
+{
|
||||
+ char tmp[PATH_MAX], resolved_path[PATH_MAX], *p;
|
||||
+
|
||||
+#if defined(O_SYMLINK)
|
||||
+ if ((flags & O_SYMLINK) != O_SYMLINK)
|
||||
+ return realpath( path, NULL );
|
||||
+#endif
|
||||
+
|
||||
+ strcpy( tmp, path );
|
||||
+ p = dirname( tmp );
|
||||
+ if (p != tmp ) strcpy( tmp, p );
|
||||
+ realpath( tmp, resolved_path );
|
||||
+ strcat( resolved_path, "/" );
|
||||
+ strcpy( tmp, path );
|
||||
+ p = basename( tmp );
|
||||
+ if (p != tmp) strcpy( tmp, p );
|
||||
+ strcat( resolved_path, tmp );
|
||||
+ return strdup( resolved_path );
|
||||
+}
|
||||
+
|
||||
/* open() wrapper that returns a struct fd with no fd user set */
|
||||
struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_name,
|
||||
int flags, mode_t *mode, unsigned int access,
|
||||
@@ -1921,6 +2033,15 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam
|
||||
}
|
||||
else rw_mode = O_RDONLY;
|
||||
|
||||
+ if ((path = dup_fd_name( root, name )))
|
||||
+ {
|
||||
+#if defined(O_SYMLINK)
|
||||
+ if (check_symlink( path ) && (options & FILE_OPEN_REPARSE_POINT) && !(flags & O_CREAT))
|
||||
+ flags |= O_SYMLINK;
|
||||
+#endif
|
||||
+ free( path );
|
||||
+ }
|
||||
+
|
||||
if ((fd->unix_fd = open( name, rw_mode | (flags & ~O_TRUNC), *mode )) == -1)
|
||||
{
|
||||
/* if we tried to open a directory for write access, retry read-only */
|
||||
@@ -1947,10 +2068,11 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam
|
||||
*mode = st.st_mode;
|
||||
|
||||
/* only bother with an inode for normal files and directories */
|
||||
- if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
|
||||
+ if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode))
|
||||
{
|
||||
unsigned int err;
|
||||
struct inode *inode = get_inode( st.st_dev, st.st_ino, fd->unix_fd );
|
||||
+ int is_link = S_ISLNK(st.st_mode), is_dir;
|
||||
|
||||
if (!inode)
|
||||
{
|
||||
@@ -1962,7 +2084,7 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam
|
||||
|
||||
if ((path = dup_fd_name( root, name )))
|
||||
{
|
||||
- fd->unix_name = realpath( path, NULL );
|
||||
+ fd->unix_name = normalize_path( path, flags );
|
||||
free( path );
|
||||
}
|
||||
|
||||
@@ -1975,13 +2097,17 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam
|
||||
list_add_head( &inode->open, &fd->inode_entry );
|
||||
closed_fd = NULL;
|
||||
|
||||
+ is_dir = S_ISDIR(st.st_mode);
|
||||
+ if (is_link)
|
||||
+ is_reparse_dir(fd->unix_name, &is_dir);
|
||||
+
|
||||
/* check directory options */
|
||||
- if ((options & FILE_DIRECTORY_FILE) && !S_ISDIR(st.st_mode))
|
||||
+ if ((options & FILE_DIRECTORY_FILE) && !is_dir)
|
||||
{
|
||||
set_error( STATUS_NOT_A_DIRECTORY );
|
||||
goto error;
|
||||
}
|
||||
- if ((options & FILE_NON_DIRECTORY_FILE) && S_ISDIR(st.st_mode))
|
||||
+ if ((options & FILE_NON_DIRECTORY_FILE) && is_dir)
|
||||
{
|
||||
set_error( STATUS_FILE_IS_A_DIRECTORY );
|
||||
goto error;
|
||||
@@ -2428,6 +2554,7 @@ static struct fd *get_handle_fd_obj( struct process *process, obj_handle_t handl
|
||||
|
||||
static int is_dir_empty( int fd )
|
||||
{
|
||||
+ int dir_fd;
|
||||
DIR *dir;
|
||||
int empty;
|
||||
struct dirent *de;
|
||||
@@ -2435,8 +2562,13 @@ static int is_dir_empty( int fd )
|
||||
if ((fd = dup( fd )) == -1)
|
||||
return -1;
|
||||
|
||||
- if (!(dir = fdopendir( fd )))
|
||||
+ /* use openat() so that if 'fd' was opened with O_SYMLINK we can still check the contents */
|
||||
+ dir_fd = openat( fd, ".", O_RDONLY | O_DIRECTORY | O_NONBLOCK );
|
||||
+ if (dir_fd == -1)
|
||||
+ return -1;
|
||||
+ if (!(dir = fdopendir( dir_fd )))
|
||||
{
|
||||
+ close( dir_fd );
|
||||
close( fd );
|
||||
return -1;
|
||||
}
|
||||
@@ -2448,6 +2580,7 @@ static int is_dir_empty( int fd )
|
||||
empty = 0;
|
||||
}
|
||||
closedir( dir );
|
||||
+ close( dir_fd );
|
||||
return empty;
|
||||
}
|
||||
|
||||
@@ -2486,7 +2619,7 @@ static void set_fd_disposition( struct fd *fd, unsigned int flags )
|
||||
file_set_error();
|
||||
return;
|
||||
}
|
||||
- if (S_ISREG( st.st_mode )) /* can't unlink files we don't have permission to write */
|
||||
+ if (S_ISREG( st.st_mode ) || S_ISLNK( st.st_mode )) /* can't unlink files we don't have permission to write */
|
||||
{
|
||||
if (!(flags & FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE) &&
|
||||
!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
|
||||
--
|
||||
2.45.2
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
From 0423cf43baf2938b4b1e7d705c20af11fb13f82c Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@wine-staging.com>
|
||||
Date: Sat, 12 Dec 2020 17:35:21 -0700
|
||||
Subject: kernelbase: Add support for deleting reparse points with
|
||||
RemoveDirectory.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
dlls/kernelbase/file.c | 2 +-
|
||||
2 files changed, 28 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c
|
||||
index bfb291fa925..6214f549406 100644
|
||||
--- a/dlls/kernelbase/file.c
|
||||
+++ b/dlls/kernelbase/file.c
|
||||
@@ -3493,7 +3493,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH RemoveDirectoryW( LPCWSTR path )
|
||||
InitializeObjectAttributes( &attr, &nt_name, OBJ_CASE_INSENSITIVE, 0, NULL );
|
||||
status = NtOpenFile( &handle, DELETE | SYNCHRONIZE, &attr, &io,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
- FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
|
||||
+ FILE_OPEN_REPARSE_POINT | FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
|
||||
RtlFreeUnicodeString( &nt_name );
|
||||
|
||||
if (!status)
|
||||
--
|
||||
2.17.1
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
From afd4ad0f6725f49daaa0fe2351c98faa6a57519a Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@wine-staging.com>
|
||||
Date: Sat, 6 Feb 2021 12:52:51 -0700
|
||||
Subject: [PATCH] kernelbase: Add support for deleting reparse points with
|
||||
DeleteFile.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
dlls/kernelbase/file.c | 3 ++-
|
||||
2 files changed, 11 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c
|
||||
index 36b43d345d6..b7d16410d75 100644
|
||||
--- a/dlls/kernelbase/file.c
|
||||
+++ b/dlls/kernelbase/file.c
|
||||
@@ -1002,7 +1002,8 @@ BOOL WINAPI DECLSPEC_HOTPATCH DeleteFileW( LPCWSTR path )
|
||||
InitializeObjectAttributes( &attr, &nameW, OBJ_CASE_INSENSITIVE, 0, NULL );
|
||||
status = NtCreateFile(&hFile, SYNCHRONIZE | DELETE, &attr, &io, NULL, 0,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
- FILE_OPEN, FILE_DELETE_ON_CLOSE | FILE_NON_DIRECTORY_FILE, NULL, 0);
|
||||
+ FILE_OPEN, FILE_DELETE_ON_CLOSE | FILE_NON_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT,
|
||||
+ NULL, 0);
|
||||
if (status == STATUS_SUCCESS) status = NtClose(hFile);
|
||||
|
||||
RtlFreeUnicodeString( &nameW );
|
||||
--
|
||||
2.47.2
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
From 51373e0350ff1b507d7b47d6e5acd84b8af9d328 Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@wine-staging.com>
|
||||
Date: Sat, 6 Feb 2021 12:46:30 -0700
|
||||
Subject: [PATCH] kernelbase: Add support for moving reparse points with
|
||||
MoveFile*.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
dlls/kernelbase/file.c | 2 +-
|
||||
dlls/ntdll/unix/file.c | 24 ++++++++++++++++++++++--
|
||||
server/fd.c | 6 ++++--
|
||||
3 files changed, 27 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c
|
||||
index 36045116e43..f1b1326353f 100644
|
||||
--- a/dlls/kernelbase/file.c
|
||||
+++ b/dlls/kernelbase/file.c
|
||||
@@ -2597,7 +2597,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH MoveFileWithProgressW( const WCHAR *source, const
|
||||
InitializeObjectAttributes( &attr, &nt_name, OBJ_CASE_INSENSITIVE, 0, NULL );
|
||||
status = NtOpenFile( &source_handle, DELETE | SYNCHRONIZE, &attr, &io,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
- FILE_SYNCHRONOUS_IO_NONALERT );
|
||||
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT );
|
||||
RtlFreeUnicodeString( &nt_name );
|
||||
if (!set_ntstatus( status )) goto error;
|
||||
|
||||
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
|
||||
index 3c341a6d702..9076da9f763 100644
|
||||
--- a/dlls/ntdll/unix/file.c
|
||||
+++ b/dlls/ntdll/unix/file.c
|
||||
@@ -5572,6 +5572,8 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
|
||||
unsigned int flags;
|
||||
UNICODE_STRING name_str, nt_name;
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
+ REPARSE_DATA_BUFFER *buffer = NULL;
|
||||
+ ULONG buffer_len = 0;
|
||||
char *unix_name;
|
||||
|
||||
if (class == FileRenameInformation)
|
||||
@@ -5586,6 +5588,20 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
|
||||
name_str.Length = info->FileNameLength;
|
||||
name_str.MaximumLength = info->FileNameLength + sizeof(WCHAR);
|
||||
InitializeObjectAttributes( &attr, &name_str, OBJ_CASE_INSENSITIVE, info->RootDirectory, NULL );
|
||||
+
|
||||
+ /* obtain all the data from the reparse point (if applicable) */
|
||||
+ status = get_reparse_point( handle, NULL, &buffer_len );
|
||||
+ if (status == STATUS_BUFFER_TOO_SMALL)
|
||||
+ {
|
||||
+ buffer = malloc( buffer_len );
|
||||
+ status = get_reparse_point( handle, buffer, &buffer_len );
|
||||
+ if (status != STATUS_SUCCESS)
|
||||
+ {
|
||||
+ free( buffer );
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
status = get_nt_and_unix_names( &attr, &nt_name, &unix_name, FILE_OPEN_IF );
|
||||
if (status == STATUS_SUCCESS || status == STATUS_NO_SUCH_FILE)
|
||||
{
|
||||
@@ -5602,8 +5618,13 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
+ /* rebuild reparse point in new location (if applicable) */
|
||||
+ if (buffer && status == STATUS_SUCCESS)
|
||||
+ status = create_reparse_point( handle, buffer );
|
||||
+
|
||||
+ free( unix_name );
|
||||
}
|
||||
- free( unix_name );
|
||||
+ free( buffer );
|
||||
free( nt_name.Buffer );
|
||||
}
|
||||
else status = STATUS_INVALID_PARAMETER_3;
|
||||
@@ -5646,7 +5667,6 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
|
||||
status = wine_server_call( req );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
-
|
||||
}
|
||||
free( unix_name );
|
||||
free( nt_name.Buffer );
|
||||
diff --git a/server/fd.c b/server/fd.c
|
||||
index 466259ae567..7f88fcd6e33 100644
|
||||
--- a/server/fd.c
|
||||
+++ b/server/fd.c
|
||||
@@ -2771,7 +2771,7 @@ static void set_fd_name( struct fd *fd, struct fd *root, const char *nameptr, da
|
||||
goto failed;
|
||||
}
|
||||
|
||||
- if (!stat( name, &st ))
|
||||
+ if (!lstat( name, &st ))
|
||||
{
|
||||
if (!fstat( fd->unix_fd, &st2 ) && st.st_ino == st2.st_ino && st.st_dev == st2.st_dev)
|
||||
{
|
||||
@@ -2787,7 +2787,7 @@ static void set_fd_name( struct fd *fd, struct fd *root, const char *nameptr, da
|
||||
}
|
||||
|
||||
/* can't replace directories or special files */
|
||||
- if (!S_ISREG( st.st_mode ))
|
||||
+ if (!S_ISREG( st.st_mode ) && !S_ISLNK( st.st_mode ))
|
||||
{
|
||||
set_error( STATUS_ACCESS_DENIED );
|
||||
goto failed;
|
||||
@@ -2853,6 +2853,8 @@ static void set_fd_name( struct fd *fd, struct fd *root, const char *nameptr, da
|
||||
fd->nt_name = dup_nt_name( root, nt_name, &fd->nt_namelen );
|
||||
free( fd->unix_name );
|
||||
fd->closed->unix_name = fd->unix_name = realpath( name, NULL );
|
||||
+ if (!fd->unix_name)
|
||||
+ fd->closed->unix_name = fd->unix_name = dup_fd_name( root, name ); /* dangling symlink */
|
||||
free( name );
|
||||
if (!fd->unix_name)
|
||||
set_error( STATUS_NO_MEMORY );
|
||||
--
|
||||
2.47.2
|
||||
|
||||
@@ -1,349 +0,0 @@
|
||||
From a9773394980e77b017dcb797766ec422b384a5cc Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Sat, 3 Sep 2022 11:23:31 -0600
|
||||
Subject: [PATCH] ntdll: Follow reparse points during path resolution.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
dlls/ntdll/unix/file.c | 196 +++++++++++++++++++++++++++++++++++-----
|
||||
2 files changed, 184 insertions(+), 23 deletions(-)
|
||||
|
||||
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
|
||||
index f3274478ae2..860e563f69d 100644
|
||||
--- a/dlls/ntdll/unix/file.c
|
||||
+++ b/dlls/ntdll/unix/file.c
|
||||
@@ -3741,6 +3741,35 @@ done:
|
||||
}
|
||||
|
||||
|
||||
+static NTSTATUS get_reparse_target( UNICODE_STRING *nt_target, REPARSE_DATA_BUFFER *buffer,
|
||||
+ int *is_relative )
|
||||
+{
|
||||
+ int target_len, offset;
|
||||
+ WCHAR *target;
|
||||
+
|
||||
+ switch( buffer->ReparseTag )
|
||||
+ {
|
||||
+ case IO_REPARSE_TAG_MOUNT_POINT:
|
||||
+ offset = buffer->MountPointReparseBuffer.SubstituteNameOffset/sizeof(WCHAR);
|
||||
+ target = &buffer->MountPointReparseBuffer.PathBuffer[offset];
|
||||
+ target_len = buffer->MountPointReparseBuffer.SubstituteNameLength;
|
||||
+ *is_relative = FALSE;
|
||||
+ break;
|
||||
+ case IO_REPARSE_TAG_SYMLINK:
|
||||
+ offset = buffer->SymbolicLinkReparseBuffer.SubstituteNameOffset/sizeof(WCHAR);
|
||||
+ target = &buffer->SymbolicLinkReparseBuffer.PathBuffer[offset];
|
||||
+ target_len = buffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
|
||||
+ *is_relative = (buffer->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE) == SYMLINK_FLAG_RELATIVE;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return STATUS_IO_REPARSE_TAG_NOT_HANDLED;
|
||||
+ }
|
||||
+ nt_target->Buffer = target;
|
||||
+ nt_target->Length = target_len;
|
||||
+ return STATUS_REPARSE;
|
||||
+}
|
||||
+
|
||||
+
|
||||
/*
|
||||
* Retrieve the unix name corresponding to a file handle, remove that directory, and then symlink
|
||||
* the requested directory to the location of the old directory.
|
||||
@@ -3917,16 +3946,14 @@ cleanup:
|
||||
|
||||
|
||||
/*
|
||||
- * Retrieve the unix name corresponding to a file handle and use that to find the destination of the
|
||||
- * symlink corresponding to that file handle.
|
||||
+ * Obtain the reparse point buffer from the unix filename for the reparse point.
|
||||
*/
|
||||
-NTSTATUS get_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG *size)
|
||||
+NTSTATUS get_reparse_point_unix(const char *unix_name, REPARSE_DATA_BUFFER *buffer, ULONG *size)
|
||||
{
|
||||
char link_dir[PATH_MAX], link_path[PATH_MAX], *d;
|
||||
int link_path_len, buffer_len, encoded_len;
|
||||
REPARSE_DATA_BUFFER header;
|
||||
ULONG out_size = *size;
|
||||
- char *unix_name = NULL;
|
||||
char *encoded = NULL;
|
||||
int link_dir_fd = -1;
|
||||
NTSTATUS status;
|
||||
@@ -3934,9 +3961,6 @@ NTSTATUS get_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG *si
|
||||
int depth;
|
||||
char *p;
|
||||
|
||||
- if ((status = server_get_unix_name( handle, &unix_name )))
|
||||
- goto cleanup;
|
||||
-
|
||||
ret = readlink( unix_name, link_path, sizeof(link_path) );
|
||||
if (ret < 0)
|
||||
{
|
||||
@@ -4036,12 +4060,76 @@ NTSTATUS get_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG *si
|
||||
|
||||
cleanup:
|
||||
if (link_dir_fd != -1) close( link_dir_fd );
|
||||
- free( unix_name );
|
||||
free( encoded );
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
+/*
|
||||
+ * Retrieve the unix name corresponding to a file handle and use that to find the destination of the
|
||||
+ * symlink corresponding to that file handle.
|
||||
+ */
|
||||
+NTSTATUS get_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG *size)
|
||||
+{
|
||||
+ char *unix_name = NULL;
|
||||
+ NTSTATUS status;
|
||||
+
|
||||
+ if ((status = server_get_unix_name( handle, &unix_name )))
|
||||
+ return status;
|
||||
+ status = get_reparse_point_unix( unix_name, buffer, size );
|
||||
+ free( unix_name );
|
||||
+ return status;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/* find the NT target of a reparse point */
|
||||
+static NTSTATUS find_reparse_target( const char *unix_name, const WCHAR *parent, int parent_len,
|
||||
+ WCHAR **new_name, int *new_name_len)
|
||||
+{
|
||||
+ REPARSE_DATA_BUFFER *buffer = NULL;
|
||||
+ UNICODE_STRING nt_target;
|
||||
+ ULONG buffer_len = 0;
|
||||
+ int is_relative;
|
||||
+ NTSTATUS status;
|
||||
+
|
||||
+ status = get_reparse_point_unix( unix_name, NULL, &buffer_len );
|
||||
+ if (status != STATUS_BUFFER_TOO_SMALL)
|
||||
+ return status;
|
||||
+
|
||||
+ buffer = malloc( buffer_len );
|
||||
+ if (!buffer)
|
||||
+ return STATUS_NO_MEMORY;
|
||||
+ if ((status = get_reparse_point_unix( unix_name, buffer, &buffer_len )) != STATUS_SUCCESS)
|
||||
+ {
|
||||
+ free( buffer );
|
||||
+ return status;
|
||||
+ }
|
||||
+ if ((status = get_reparse_target( &nt_target, buffer, &is_relative )) == STATUS_REPARSE)
|
||||
+ {
|
||||
+ WCHAR *p;
|
||||
+
|
||||
+ p = *new_name = malloc( nt_target.Length + parent_len*sizeof(WCHAR) );
|
||||
+ if (!p)
|
||||
+ {
|
||||
+ status = STATUS_NO_MEMORY;
|
||||
+ goto done;
|
||||
+ }
|
||||
+ if (is_relative)
|
||||
+ {
|
||||
+ memcpy( p, parent, parent_len*sizeof(WCHAR) );
|
||||
+ p += parent_len;
|
||||
+ }
|
||||
+ memcpy( p, nt_target.Buffer, nt_target.Length );
|
||||
+ p += nt_target.Length/sizeof(WCHAR);
|
||||
+ *new_name_len = p - *new_name;
|
||||
+ }
|
||||
+
|
||||
+done:
|
||||
+ free( buffer );
|
||||
+ return status;
|
||||
+}
|
||||
+
|
||||
+
|
||||
/*
|
||||
* Retrieve the unix name corresponding to a file handle, remove that symlink, and then recreate
|
||||
* a directory at the location of the old filename.
|
||||
@@ -4135,15 +4223,24 @@ cleanup:
|
||||
}
|
||||
|
||||
|
||||
+static NTSTATUS IoReplaceFileObjectName( FILE_OBJECT *fileobj, PWSTR name, USHORT name_len )
|
||||
+{
|
||||
+ fileobj->FileName.Buffer = name;
|
||||
+ fileobj->FileName.Length = name_len;
|
||||
+ return STATUS_SUCCESS;
|
||||
+}
|
||||
+
|
||||
+
|
||||
/******************************************************************************
|
||||
* lookup_unix_name
|
||||
*
|
||||
* Helper for nt_to_unix_file_name
|
||||
*/
|
||||
-static NTSTATUS lookup_unix_name( int root_fd, const WCHAR *name, int name_len, char **buffer, int unix_len,
|
||||
+static NTSTATUS lookup_unix_name( FILE_OBJECT *fileobj, int root_fd, const WCHAR *name, int name_len, char **buffer, int unix_len,
|
||||
int pos, UINT disposition, BOOL is_unix )
|
||||
{
|
||||
static const WCHAR invalid_charsW[] = { INVALID_NT_CHARS, '/', 0 };
|
||||
+ const WCHAR *fullname = fileobj->FileName.Buffer;
|
||||
NTSTATUS status;
|
||||
int ret;
|
||||
struct stat st;
|
||||
@@ -4200,6 +4297,8 @@ static NTSTATUS lookup_unix_name( int root_fd, const WCHAR *name, int name_len,
|
||||
while (name_len)
|
||||
{
|
||||
const WCHAR *end, *next;
|
||||
+ WCHAR *target = NULL;
|
||||
+ int target_len = 0;
|
||||
|
||||
end = name;
|
||||
while (end < name + name_len && *end != '\\') end++;
|
||||
@@ -4219,8 +4318,31 @@ static NTSTATUS lookup_unix_name( int root_fd, const WCHAR *name, int name_len,
|
||||
|
||||
status = find_file_in_dir( root_fd, unix_name, pos, name, end - name, is_unix );
|
||||
|
||||
+ /* follow reparse point and restart from there (if applicable) */
|
||||
+ if (name_len && find_reparse_target( unix_name, fullname, name - fullname, &target, &target_len ) == STATUS_REPARSE)
|
||||
+ {
|
||||
+ int new_name_len = target_len + name_len + 1;
|
||||
+ WCHAR *p, *new_name;
|
||||
+
|
||||
+ if (!(p = new_name = malloc( new_name_len*sizeof(WCHAR) )))
|
||||
+ {
|
||||
+ free( target );
|
||||
+ status = STATUS_NO_MEMORY;
|
||||
+ break;
|
||||
+ }
|
||||
+ memcpy( p, target, target_len*sizeof(WCHAR) );
|
||||
+ p += target_len;
|
||||
+ (p++)[0] = '\\';
|
||||
+ memcpy( p, next, name_len*sizeof(WCHAR) );
|
||||
+ TRACE( "Follow reparse point %s => %s\n", debugstr_wn(fullname, end-fullname),
|
||||
+ debugstr_wn(new_name, new_name_len) );
|
||||
+ free( target );
|
||||
+ if (IoReplaceFileObjectName( fileobj, new_name, new_name_len*sizeof(WCHAR) ))
|
||||
+ free( new_name );
|
||||
+ return STATUS_REPARSE;
|
||||
+ }
|
||||
/* if this is the last element, not finding it is not necessarily fatal */
|
||||
- if (!name_len)
|
||||
+ else if (!name_len)
|
||||
{
|
||||
if (status == STATUS_OBJECT_NAME_NOT_FOUND)
|
||||
{
|
||||
@@ -4259,12 +4381,12 @@ static NTSTATUS lookup_unix_name( int root_fd, const WCHAR *name, int name_len,
|
||||
/******************************************************************************
|
||||
* nt_to_unix_file_name_no_root
|
||||
*/
|
||||
-static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char **unix_name_ret,
|
||||
+static NTSTATUS nt_to_unix_file_name_no_root( FILE_OBJECT *fileobj, char **unix_name_ret,
|
||||
UINT disposition )
|
||||
{
|
||||
static const WCHAR unixW[] = {'u','n','i','x'};
|
||||
static const WCHAR invalid_charsW[] = { INVALID_NT_CHARS, 0 };
|
||||
-
|
||||
+ const UNICODE_STRING *nameW = &fileobj->FileName;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
const WCHAR *name;
|
||||
struct stat st;
|
||||
@@ -4354,7 +4476,7 @@ static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char
|
||||
name += prefix_len;
|
||||
name_len -= prefix_len;
|
||||
|
||||
- status = lookup_unix_name( AT_FDCWD, name, name_len, &unix_name, unix_len, pos, disposition, is_unix );
|
||||
+ status = lookup_unix_name( fileobj, AT_FDCWD, name, name_len, &unix_name, unix_len, pos, disposition, is_unix );
|
||||
if (status == STATUS_SUCCESS || status == STATUS_NO_SUCH_FILE)
|
||||
{
|
||||
TRACE( "%s -> %s\n", debugstr_us(nameW), debugstr_a(unix_name) );
|
||||
@@ -4362,7 +4484,8 @@ static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char
|
||||
}
|
||||
else
|
||||
{
|
||||
- TRACE( "%s not found in %s\n", debugstr_w(name), debugstr_an(unix_name, pos) );
|
||||
+ if (status != STATUS_REPARSE)
|
||||
+ TRACE( "%s not found in %s\n", debugstr_w(name), debugstr_an(unix_name, pos) );
|
||||
free( unix_name );
|
||||
}
|
||||
return status;
|
||||
@@ -4380,18 +4503,30 @@ static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char
|
||||
*/
|
||||
static NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, UINT disposition )
|
||||
{
|
||||
+ HANDLE rootdir = attr->RootDirectory;
|
||||
enum server_fd_type type;
|
||||
- int root_fd, needs_close;
|
||||
+ int old_cwd, root_fd, needs_close;
|
||||
+ int reparse_count = 0;
|
||||
+ FILE_OBJECT fileobj;
|
||||
const WCHAR *name;
|
||||
char *unix_name;
|
||||
int name_len, unix_len;
|
||||
NTSTATUS status;
|
||||
|
||||
- if (!attr->RootDirectory) /* without root dir fall back to normal lookup */
|
||||
- return nt_to_unix_file_name_no_root( attr->ObjectName, name_ret, disposition );
|
||||
+ fileobj.FileName = *attr->ObjectName;
|
||||
+reparse:
|
||||
+ if (reparse_count++ == 31)
|
||||
+ return STATUS_REPARSE_POINT_NOT_RESOLVED;
|
||||
+ if (!rootdir) /* without root dir fall back to normal lookup */
|
||||
+ {
|
||||
+ status = nt_to_unix_file_name_no_root( &fileobj, name_ret, disposition );
|
||||
+ if (status == STATUS_REPARSE) goto reparse;
|
||||
+ if (fileobj.FileName.Buffer != attr->ObjectName->Buffer) free( fileobj.FileName.Buffer);
|
||||
+ return status;
|
||||
+ }
|
||||
|
||||
- name = attr->ObjectName->Buffer;
|
||||
- name_len = attr->ObjectName->Length / sizeof(WCHAR);
|
||||
+ name = fileobj.FileName.Buffer;
|
||||
+ name_len = fileobj.FileName.Length / sizeof(WCHAR);
|
||||
|
||||
if (name_len && name[0] == '\\') return STATUS_INVALID_PARAMETER;
|
||||
|
||||
@@ -4399,7 +4534,7 @@ static NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name
|
||||
if (!(unix_name = malloc( unix_len ))) return STATUS_NO_MEMORY;
|
||||
unix_name[0] = '.';
|
||||
|
||||
- if (!(status = server_get_unix_fd( attr->RootDirectory, 0, &root_fd, &needs_close, &type, NULL )))
|
||||
+ if (!(status = server_get_unix_fd( rootdir, 0, &root_fd, &needs_close, &type, NULL )))
|
||||
{
|
||||
if (type != FD_TYPE_DIR)
|
||||
{
|
||||
@@ -4408,7 +4543,16 @@ static NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name
|
||||
}
|
||||
else
|
||||
{
|
||||
- status = lookup_unix_name( root_fd, name, name_len, &unix_name, unix_len, 1, disposition, FALSE );
|
||||
+ mutex_lock( &dir_mutex );
|
||||
+ if ((old_cwd = open( ".", O_RDONLY )) != -1 && fchdir( root_fd ) != -1)
|
||||
+ {
|
||||
+ status = lookup_unix_name( &fileobj, root_fd, name, name_len, &unix_name, unix_len, 1,
|
||||
+ disposition, FALSE );
|
||||
+ if (fchdir( old_cwd ) == -1) chdir( "/" );
|
||||
+ }
|
||||
+ else status = errno_to_status( errno );
|
||||
+ mutex_unlock( &dir_mutex );
|
||||
+ if (old_cwd != -1) close( old_cwd );
|
||||
if (needs_close) close( root_fd );
|
||||
}
|
||||
}
|
||||
@@ -4416,14 +4560,22 @@ static NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name
|
||||
|
||||
if (status == STATUS_SUCCESS || status == STATUS_NO_SUCH_FILE)
|
||||
{
|
||||
- TRACE( "%s -> %s\n", debugstr_us(attr->ObjectName), debugstr_a(unix_name) );
|
||||
+ TRACE( "%s -> %s\n", debugstr_us(&fileobj.FileName), debugstr_a(unix_name) );
|
||||
*name_ret = unix_name;
|
||||
}
|
||||
+ else if (status == STATUS_REPARSE)
|
||||
+ {
|
||||
+ if (fileobj.FileName.Buffer[0] == '\\') rootdir = 0;
|
||||
+ free( unix_name );
|
||||
+ goto reparse;
|
||||
+ }
|
||||
else
|
||||
{
|
||||
TRACE( "%s not found in %s\n", debugstr_w(name), unix_name );
|
||||
free( unix_name );
|
||||
}
|
||||
+
|
||||
+ if (fileobj.FileName.Buffer != attr->ObjectName->Buffer) free( fileobj.FileName.Buffer);
|
||||
return status;
|
||||
}
|
||||
|
||||
--
|
||||
2.47.2
|
||||
|
||||
@@ -1,214 +0,0 @@
|
||||
From 09318135fc87cd27e9df660958dcda6fe7d6f997 Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@wine-staging.com>
|
||||
Date: Sat, 12 Dec 2020 17:28:31 -0700
|
||||
Subject: [PATCH] kernel32: Advertise reparse point support.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
dlls/mountmgr.sys/device.c | 33 ++++++++++++-
|
||||
dlls/mountmgr.sys/unixlib.c | 97 +++++++++++++++++++++++++++++++++++++
|
||||
dlls/mountmgr.sys/unixlib.h | 8 +++
|
||||
3 files changed, 137 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/mountmgr.sys/device.c b/dlls/mountmgr.sys/device.c
|
||||
index 6c62ac78c76..1ee82e92c97 100644
|
||||
--- a/dlls/mountmgr.sys/device.c
|
||||
+++ b/dlls/mountmgr.sys/device.c
|
||||
@@ -177,6 +177,36 @@ static void get_filesystem_serial( struct volume *volume )
|
||||
volume->serial = strtoul( buffer, NULL, 16 );
|
||||
}
|
||||
|
||||
+/* get the flags for the volume by looking at the type of underlying filesystem */
|
||||
+static DWORD get_filesystem_flags( struct volume *volume )
|
||||
+{
|
||||
+ char fstypename[256];
|
||||
+ ULONG size = sizeof(fstypename);
|
||||
+ struct get_volume_filesystem_params params = { volume->device->unix_mount, fstypename, &size };
|
||||
+
|
||||
+ if (!volume->device->unix_mount) return 0;
|
||||
+ if (MOUNTMGR_CALL( get_volume_filesystem, ¶ms )) return 0;
|
||||
+
|
||||
+ if (!strcmp("apfs", fstypename) ||
|
||||
+ !strcmp("nfs", fstypename) ||
|
||||
+ !strcmp("cifs", fstypename) ||
|
||||
+ !strcmp("ncpfs", fstypename) ||
|
||||
+ !strcmp("tmpfs", fstypename) ||
|
||||
+ !strcmp("cramfs", fstypename) ||
|
||||
+ !strcmp("devfs", fstypename) ||
|
||||
+ !strcmp("procfs", fstypename) ||
|
||||
+ !strcmp("ext2", fstypename) ||
|
||||
+ !strcmp("ext3", fstypename) ||
|
||||
+ !strcmp("ext4", fstypename) ||
|
||||
+ !strcmp("hfs", fstypename) ||
|
||||
+ !strcmp("hpfs", fstypename) ||
|
||||
+ !strcmp("ntfs", fstypename))
|
||||
+ {
|
||||
+ return FILE_SUPPORTS_REPARSE_POINTS;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
|
||||
/******************************************************************
|
||||
* VOLUME_FindCdRomDataBestVoldesc
|
||||
@@ -1704,7 +1734,8 @@ static NTSTATUS WINAPI harddisk_query_volume( DEVICE_OBJECT *device, IRP *irp )
|
||||
break;
|
||||
default:
|
||||
fsname = L"NTFS";
|
||||
- info->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_PERSISTENT_ACLS;
|
||||
+ info->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_PERSISTENT_ACLS
|
||||
+ | get_filesystem_flags( volume );
|
||||
info->MaximumComponentNameLength = 255;
|
||||
break;
|
||||
}
|
||||
diff --git a/dlls/mountmgr.sys/unixlib.c b/dlls/mountmgr.sys/unixlib.c
|
||||
index 80e7c850854..55489d9965b 100644
|
||||
--- a/dlls/mountmgr.sys/unixlib.c
|
||||
+++ b/dlls/mountmgr.sys/unixlib.c
|
||||
@@ -38,6 +38,21 @@
|
||||
#endif
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
+#ifdef HAVE_SYS_STATFS_H
|
||||
+# include <sys/statfs.h>
|
||||
+#endif
|
||||
+#ifdef HAVE_SYS_SYSCALL_H
|
||||
+# include <sys/syscall.h>
|
||||
+#endif
|
||||
+#ifdef HAVE_SYS_VFS_H
|
||||
+# include <sys/vfs.h>
|
||||
+#endif
|
||||
+#ifdef HAVE_SYS_PARAM_H
|
||||
+#include <sys/param.h>
|
||||
+#endif
|
||||
+#ifdef HAVE_SYS_MOUNT_H
|
||||
+#include <sys/mount.h>
|
||||
+#endif
|
||||
|
||||
#include "unixlib.h"
|
||||
#include "wine/debug.h"
|
||||
@@ -463,6 +478,87 @@ static NTSTATUS read_volume_file( void *args )
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
+static NTSTATUS get_volume_filesystem( void *args )
|
||||
+{
|
||||
+#if defined(__NR_renameat2) || defined(RENAME_SWAP)
|
||||
+ const struct get_volume_filesystem_params *params = args;
|
||||
+#if defined(HAVE_FSTATFS)
|
||||
+ struct statfs stfs;
|
||||
+#elif defined(HAVE_FSTATVFS)
|
||||
+ struct statvfs stfs;
|
||||
+#endif
|
||||
+ const char *fstypename = "unknown";
|
||||
+ int fd = -1;
|
||||
+
|
||||
+ if (params->volume[0] != '/')
|
||||
+ {
|
||||
+ char *path = get_dosdevices_path( params->volume );
|
||||
+ if (path) fd = open( path, O_RDONLY );
|
||||
+ free( path );
|
||||
+ }
|
||||
+ else fd = open( params->volume, O_RDONLY );
|
||||
+ if (fd == -1) return STATUS_NO_SUCH_FILE;
|
||||
+
|
||||
+#if defined(HAVE_FSTATFS)
|
||||
+ if (fstatfs(fd, &stfs))
|
||||
+ return STATUS_NO_SUCH_FILE;
|
||||
+#elif defined(HAVE_FSTATVFS)
|
||||
+ if (fstatvfs(fd, &stfs))
|
||||
+ return STATUS_NO_SUCH_FILE;
|
||||
+#endif
|
||||
+ close( fd );
|
||||
+#if defined(HAVE_FSTATFS) && defined(linux)
|
||||
+ switch (stfs.f_type)
|
||||
+ {
|
||||
+ case 0x6969: /* nfs */
|
||||
+ fstypename = "nfs";
|
||||
+ break;
|
||||
+ case 0xff534d42: /* cifs */
|
||||
+ fstypename = "cifs";
|
||||
+ break;
|
||||
+ case 0x564c: /* ncpfs */
|
||||
+ fstypename = "ncpfs";
|
||||
+ break;
|
||||
+ case 0x01021994: /* tmpfs */
|
||||
+ fstypename = "tmpfs";
|
||||
+ break;
|
||||
+ case 0x28cd3d45: /* cramfs */
|
||||
+ fstypename = "cramfs";
|
||||
+ break;
|
||||
+ case 0x1373: /* devfs */
|
||||
+ fstypename = "devfs";
|
||||
+ break;
|
||||
+ case 0x9fa0: /* procfs */
|
||||
+ fstypename = "procfs";
|
||||
+ break;
|
||||
+ case 0xef51: /* old ext2 */
|
||||
+ fstypename = "ext2";
|
||||
+ break;
|
||||
+ case 0xef53: /* ext2/3/4 */
|
||||
+ fstypename = "ext2";
|
||||
+ break;
|
||||
+ case 0x4244: /* hfs */
|
||||
+ fstypename = "hfs";
|
||||
+ break;
|
||||
+ case 0xf995e849: /* hpfs */
|
||||
+ fstypename = "hpfs";
|
||||
+ break;
|
||||
+ case 0x5346544e: /* ntfs */
|
||||
+ fstypename = "ntfs";
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__) || defined(__NetBSD__)
|
||||
+ fstypename = stfs.f_fstypename;
|
||||
+#endif
|
||||
+ lstrcpynA( params->fstypename, fstypename, *params->size );
|
||||
+ return STATUS_SUCCESS;
|
||||
+#else
|
||||
+ return STATUS_NOT_IMPLEMENTED;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
static NTSTATUS match_unixdev( void *args )
|
||||
{
|
||||
const struct match_unixdev_params *params = args;
|
||||
@@ -607,6 +703,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
|
||||
write_credential,
|
||||
delete_credential,
|
||||
enumerate_credentials,
|
||||
+ get_volume_filesystem,
|
||||
};
|
||||
|
||||
C_ASSERT( ARRAYSIZE(__wine_unix_call_funcs) == unix_funcs_count );
|
||||
diff --git a/dlls/mountmgr.sys/unixlib.h b/dlls/mountmgr.sys/unixlib.h
|
||||
index 7a3d0038512..ac7e6a553c7 100644
|
||||
--- a/dlls/mountmgr.sys/unixlib.h
|
||||
+++ b/dlls/mountmgr.sys/unixlib.h
|
||||
@@ -107,6 +107,13 @@ struct read_volume_file_params
|
||||
ULONG *size;
|
||||
};
|
||||
|
||||
+struct get_volume_filesystem_params
|
||||
+{
|
||||
+ const char *volume;
|
||||
+ void *fstypename;
|
||||
+ ULONG *size;
|
||||
+};
|
||||
+
|
||||
struct match_unixdev_params
|
||||
{
|
||||
const char *device;
|
||||
@@ -173,6 +180,7 @@ enum mountmgr_funcs
|
||||
unix_write_credential,
|
||||
unix_delete_credential,
|
||||
unix_enumerate_credentials,
|
||||
+ unix_get_volume_filesystem,
|
||||
unix_funcs_count
|
||||
};
|
||||
|
||||
--
|
||||
2.40.1
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
From 6b96b85136b078f9779c07e5c0daecd7b1006e09 Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Sun, 4 Sep 2022 13:19:16 -0600
|
||||
Subject: [PATCH] ntdll: Allow reparse points to target the applicable Unix
|
||||
file/directory.
|
||||
|
||||
Allows lookup_unix_name 'shortcut' to succeed, as well as allowing
|
||||
the user to follow the symlink outside of Wine.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
dlls/ntdll/unix/file.c | 90 ++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 90 insertions(+)
|
||||
|
||||
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
|
||||
index f83a30d36ed..234a0fa7397 100644
|
||||
--- a/dlls/ntdll/unix/file.c
|
||||
+++ b/dlls/ntdll/unix/file.c
|
||||
@@ -3714,6 +3714,86 @@ static NTSTATUS get_reparse_target( UNICODE_STRING *nt_target, REPARSE_DATA_BUFF
|
||||
}
|
||||
|
||||
|
||||
+/* add a symlink to the unix target at the last point of the reparse point metadata */
|
||||
+NTSTATUS create_reparse_target( int dirfd, const char *unix_src, int depth, const char *link_path,
|
||||
+ REPARSE_DATA_BUFFER *buffer )
|
||||
+{
|
||||
+ UNICODE_STRING nt_target, nt_full_target;
|
||||
+ char *unix_path = NULL, *d;
|
||||
+ char target_path[PATH_MAX];
|
||||
+ int nt_target_len;
|
||||
+ char *unix_target;
|
||||
+ int is_relative;
|
||||
+ NTSTATUS status;
|
||||
+ WCHAR *nt_path;
|
||||
+
|
||||
+ if ((status = get_reparse_target( &nt_target, buffer, &is_relative )) != STATUS_REPARSE)
|
||||
+ return status;
|
||||
+ /* if the target path is relative then turn the source path into an NT path */
|
||||
+ if (is_relative)
|
||||
+ {
|
||||
+ /* resolve the NT path of the source */
|
||||
+ unix_path = malloc( strlen(unix_src) + 2 );
|
||||
+ if (!unix_path) return STATUS_NO_MEMORY;
|
||||
+ strcpy( unix_path, unix_src );
|
||||
+ d = dirname( unix_path );
|
||||
+ if (d != unix_path) strcpy( unix_path, d );
|
||||
+ strcat( unix_path, "/");
|
||||
+ status = unix_to_nt_file_name( unix_path, &nt_path, FILE_OPEN );
|
||||
+ free( unix_path );
|
||||
+ if (status != STATUS_SUCCESS)
|
||||
+ return status;
|
||||
+ /* re-resolve the unix path for the source */
|
||||
+ status = ntdll_get_unix_file_name( nt_path, &unix_path, FILE_OPEN_IF );
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ nt_path = malloc( sizeof(WCHAR) );
|
||||
+ if (!nt_path) return STATUS_NO_MEMORY;
|
||||
+ nt_path[0] = 0;
|
||||
+ }
|
||||
+ /* append the target path (if absolute, appends to empty string) */
|
||||
+ nt_target_len = nt_target.Length + sizeof(WCHAR);
|
||||
+ nt_full_target.MaximumLength = nt_target_len + wcslen(nt_path) * sizeof(WCHAR);
|
||||
+ nt_full_target.Buffer = malloc( nt_full_target.MaximumLength + 2 );
|
||||
+ if (!nt_full_target.Buffer)
|
||||
+ {
|
||||
+ status = STATUS_NO_MEMORY;
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ wcscpy( nt_full_target.Buffer, nt_path );
|
||||
+ free( nt_path );
|
||||
+ memcpy( &nt_full_target.Buffer[wcslen(nt_full_target.Buffer)], nt_target.Buffer, nt_target_len );
|
||||
+ /* find the unix path for the target */
|
||||
+ status = ntdll_get_unix_file_name( nt_full_target.Buffer, &unix_target, FILE_OPEN_IF );
|
||||
+ /* create the symlink to the target at the last metadata location */
|
||||
+ if (status == STATUS_SUCCESS || status == STATUS_NO_SUCH_FILE)
|
||||
+ {
|
||||
+ int relative_offset;
|
||||
+
|
||||
+ target_path[0] = 0;
|
||||
+ relative_offset = unix_path ? strlen( unix_path ) : 0;
|
||||
+ if (unix_path && strncmp( unix_path, unix_target, relative_offset ) != 0)
|
||||
+ {
|
||||
+ relative_offset = 0;
|
||||
+ is_relative = FALSE;
|
||||
+ }
|
||||
+ for (;is_relative && depth > 0; depth--)
|
||||
+ strcat( target_path, "../" );
|
||||
+ strcat( target_path, &unix_target[relative_offset] );
|
||||
+ TRACE( "adding reparse point target: %s\n", debugstr_a(target_path) );
|
||||
+ symlinkat( target_path, dirfd, link_path );
|
||||
+ }
|
||||
+ free( unix_target );
|
||||
+ status = STATUS_SUCCESS;
|
||||
+
|
||||
+cleanup:
|
||||
+ free( unix_path );
|
||||
+ free( nt_full_target.Buffer );
|
||||
+ return status;
|
||||
+}
|
||||
+
|
||||
+
|
||||
/*
|
||||
* Retrieve the unix name corresponding to a file handle, remove that directory, and then symlink
|
||||
* the requested directory to the location of the old directory.
|
||||
@@ -3847,6 +3927,16 @@ NTSTATUS create_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
|
||||
link_dir_fd = fd;
|
||||
}
|
||||
|
||||
+ /* create the very last link directory */
|
||||
+ if (IsReparseTagNameSurrogate( buffer->ReparseTag ))
|
||||
+ {
|
||||
+ strcpy( link_path, target_path );
|
||||
+ strcpy( link_dir, link_path );
|
||||
+ link_dir[strlen(link_dir)-1] = 0;
|
||||
+ if (mkdir_p( link_dir_fd, link_dir, 0777 ) == 0)
|
||||
+ create_reparse_target( link_dir_fd, unix_src, depth + 2, link_path, buffer );
|
||||
+ }
|
||||
+
|
||||
/* Atomically move the initial link into position */
|
||||
if (!renameat2( -1, tmplink, -1, unix_src, RENAME_EXCHANGE ))
|
||||
{
|
||||
--
|
||||
2.47.2
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
From 1f891d01326bcb1b7bf6bcaa35f6f10d311fe660 Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@wine-staging.com>
|
||||
Date: Sat, 6 Feb 2021 16:16:17 -0700
|
||||
Subject: [PATCH] ntdll: Add an intermediary prefix symlink in reparse point
|
||||
metadata.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
dlls/ntdll/unix/file.c | 39 +++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 39 insertions(+)
|
||||
|
||||
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
|
||||
index 63a27b89e20..a15c5e19dcb 100644
|
||||
--- a/dlls/ntdll/unix/file.c
|
||||
+++ b/dlls/ntdll/unix/file.c
|
||||
@@ -3577,6 +3577,18 @@ static NTSTATUS get_reparse_target( UNICODE_STRING *nt_target, REPARSE_DATA_BUFF
|
||||
}
|
||||
|
||||
|
||||
+int find_prefix_end( const char *path, int *offset )
|
||||
+{
|
||||
+ static int config_dir_len = 0;
|
||||
+
|
||||
+ if (!config_dir_len) config_dir_len = strlen(config_dir);
|
||||
+ if (path[config_dir_len] != '/') return FALSE;
|
||||
+ if (strncmp( config_dir, path, config_dir_len ) != 0) return FALSE;
|
||||
+ *offset = config_dir_len;
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+
|
||||
/* add a symlink to the unix target at the last point of the reparse point metadata */
|
||||
NTSTATUS create_reparse_target( int dirfd, const char *unix_src, int depth, const char *link_path,
|
||||
REPARSE_DATA_BUFFER *buffer )
|
||||
@@ -3671,6 +3683,8 @@ NTSTATUS create_reparse_target( int dirfd, const char *unix_src, int depth, cons
|
||||
/* create the symlink to the target at the last metadata location */
|
||||
if (status == STATUS_SUCCESS || status == STATUS_NO_SUCH_FILE)
|
||||
{
|
||||
+ const char prefix_string[] = "${WINEPREFIX}";
|
||||
+ int append_prefix = FALSE;
|
||||
int relative_offset;
|
||||
|
||||
target_path[0] = 0;
|
||||
@@ -3680,8 +3694,21 @@ NTSTATUS create_reparse_target( int dirfd, const char *unix_src, int depth, cons
|
||||
relative_offset = 0;
|
||||
is_relative = FALSE;
|
||||
}
|
||||
+ else if (find_prefix_end( unix_target, &relative_offset ))
|
||||
+ {
|
||||
+ char prefix_link[PATH_MAX];
|
||||
+
|
||||
+ append_prefix = TRUE;
|
||||
+ is_relative = FALSE;
|
||||
+ strcpy( prefix_link, link_path );
|
||||
+ prefix_link[strlen(prefix_link)-1] = 0;
|
||||
+ strcat( prefix_link, prefix_string );
|
||||
+ symlinkat( config_dir, dirfd, prefix_link );
|
||||
+ }
|
||||
for (;is_relative && depth > 0; depth--)
|
||||
strcat( target_path, "../" );
|
||||
+ if (append_prefix)
|
||||
+ strcat( target_path, prefix_string );
|
||||
strcat( target_path, &unix_target[relative_offset] );
|
||||
TRACE( "adding reparse point target: %s\n", debugstr_a(target_path) );
|
||||
symlinkat( target_path, dirfd, link_path );
|
||||
@@ -3887,6 +3914,7 @@ cleanup:
|
||||
NTSTATUS get_reparse_point_unix(const char *unix_name, REPARSE_DATA_BUFFER *buffer, ULONG *size)
|
||||
{
|
||||
char link_dir[PATH_MAX], link_path[PATH_MAX], *d;
|
||||
+ const char prefix_string[] = "${WINEPREFIX}";
|
||||
int link_path_len, buffer_len, encoded_len;
|
||||
REPARSE_DATA_BUFFER header;
|
||||
ULONG out_size = *size;
|
||||
@@ -3985,6 +4013,17 @@ NTSTATUS get_reparse_point_unix(const char *unix_name, REPARSE_DATA_BUFFER *buff
|
||||
link_dir_fd = fd;
|
||||
}
|
||||
|
||||
+ /* if the prefix location has moved then update the Unix prefix passthrough link */
|
||||
+ strcpy( link_dir, link_path );
|
||||
+ link_dir[strlen(link_dir)-1] = 0;
|
||||
+ link_path_len = readlinkat( link_dir_fd, prefix_string, link_path, sizeof(link_path) );
|
||||
+ if (link_path_len > 0) link_path[link_path_len] = 0;
|
||||
+ if (link_path_len > 0 && strcmp( config_dir, link_path) != 0)
|
||||
+ {
|
||||
+ unlinkat( link_dir_fd, prefix_string, 0 );
|
||||
+ symlinkat( config_dir, link_dir_fd, prefix_string );
|
||||
+ }
|
||||
+
|
||||
/* Decode the reparse buffer from the base64-encoded symlink data */
|
||||
*size = decode_base64url( encoded, strlen(encoded), (char*)buffer );
|
||||
status = STATUS_SUCCESS;
|
||||
--
|
||||
2.43.0
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
From b0eff92e78691d5f864d14b96131d2a38a3aea1a Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Wed, 1 May 2019 12:06:20 -0600
|
||||
Subject: ntdll: Always report symbolic links as containing zero bytes.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
dlls/ntdll/unix/file.c | 4 ++++
|
||||
2 files changed, 36 insertions(+)
|
||||
|
||||
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
|
||||
index f298b1f7a6c..caa454c024f 100644
|
||||
--- a/dlls/ntdll/unix/file.c
|
||||
+++ b/dlls/ntdll/unix/file.c
|
||||
@@ -1761,6 +1761,8 @@ static int fd_get_file_info( int fd, unsigned int options, struct stat *st, ULON
|
||||
|
||||
/* symbolic links (either junction points or NT symlinks) are "reparse points" */
|
||||
*attr |= FILE_ATTRIBUTE_REPARSE_POINT;
|
||||
+ /* symbolic links always report size 0 */
|
||||
+ st->st_size = 0;
|
||||
/* whether a reparse point is a file or a directory is stored inside the link target */
|
||||
if (is_reparse_dir( fd, "", &is_dir ) == 0)
|
||||
st->st_mode = (st->st_mode & ~S_IFMT) | (is_dir ? S_IFDIR : S_IFREG);
|
||||
@@ -1844,6 +1846,8 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr )
|
||||
stat( path, st );
|
||||
/* symbolic links (either junction points or NT symlinks) are "reparse points" */
|
||||
*attr |= FILE_ATTRIBUTE_REPARSE_POINT;
|
||||
+ /* symbolic links always report size 0 */
|
||||
+ st->st_size = 0;
|
||||
/* whether a reparse point is a file or a directory is stored inside the link target */
|
||||
if (is_reparse_dir( AT_FDCWD, path, &is_dir ) == 0)
|
||||
st->st_mode = (st->st_mode & ~S_IFMT) | (is_dir ? S_IFDIR : S_IFREG);
|
||||
--
|
||||
2.17.1
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
From 6b1c261760080d470254b25b512625f4c1e3d935 Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@wine-staging.com>
|
||||
Date: Mon, 23 Nov 2020 13:08:02 -0700
|
||||
Subject: ntdll: Succeed with no data for NtReadFile on reparse points.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
dlls/ntdll/unix/file.c | 5 +++++
|
||||
server/file.c | 1 +
|
||||
server/protocol.def | 1 +
|
||||
4 files changed, 8 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
|
||||
index b26b239574b..bf80708b41e 100644
|
||||
--- a/dlls/ntdll/unix/file.c
|
||||
+++ b/dlls/ntdll/unix/file.c
|
||||
@@ -6312,6 +6312,11 @@ NTSTATUS WINAPI NtReadFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, vo
|
||||
if (needs_close) close( unix_handle );
|
||||
return status;
|
||||
}
|
||||
+ else if (type == FD_TYPE_SYMLINK)
|
||||
+ {
|
||||
+ status = STATUS_SUCCESS;
|
||||
+ goto done;
|
||||
+ }
|
||||
|
||||
if (type == FD_TYPE_SERIAL && async_read && length)
|
||||
{
|
||||
diff --git a/server/file.c b/server/file.c
|
||||
index 76c687833c9..b4f99ddc93b 100644
|
||||
--- a/server/file.c
|
||||
+++ b/server/file.c
|
||||
@@ -294,6 +294,7 @@ static enum server_fd_type file_get_fd_type( struct fd *fd )
|
||||
{
|
||||
struct file *file = get_fd_user( fd );
|
||||
|
||||
+ if (S_ISLNK(file->mode)) return FD_TYPE_SYMLINK;
|
||||
if (S_ISREG(file->mode) || S_ISBLK(file->mode)) return FD_TYPE_FILE;
|
||||
if (S_ISDIR(file->mode)) return FD_TYPE_DIR;
|
||||
return FD_TYPE_CHAR;
|
||||
diff --git a/server/protocol.def b/server/protocol.def
|
||||
index d828d41d1f7..aa7398369ad 100644
|
||||
--- a/server/protocol.def
|
||||
+++ b/server/protocol.def
|
||||
@@ -1381,6 +1381,7 @@ enum server_fd_type
|
||||
{
|
||||
FD_TYPE_INVALID, /* invalid file (no associated fd) */
|
||||
FD_TYPE_FILE, /* regular file */
|
||||
+ FD_TYPE_SYMLINK, /* symbolic link */
|
||||
FD_TYPE_DIR, /* directory */
|
||||
FD_TYPE_SOCKET, /* socket */
|
||||
FD_TYPE_SERIAL, /* serial port */
|
||||
--
|
||||
2.17.1
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
From 76c4816f9015329c24968849f20063c07016a2da Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@wine-staging.com>
|
||||
Date: Wed, 25 Nov 2020 09:19:42 -0700
|
||||
Subject: ntdll: Add support for FileAttributeTagInformation.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
dlls/ntdll/unix/file.c | 15 ++++++++++++++-
|
||||
2 files changed, 20 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
|
||||
index bf80708b41e..51d6aed85f0 100644
|
||||
--- a/dlls/ntdll/unix/file.c
|
||||
+++ b/dlls/ntdll/unix/file.c
|
||||
@@ -5421,7 +5421,20 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
|
||||
{
|
||||
FILE_ATTRIBUTE_TAG_INFORMATION *info = ptr;
|
||||
info->FileAttributes = attr;
|
||||
- info->ReparseTag = 0; /* FIXME */
|
||||
+ info->ReparseTag = 0;
|
||||
+ if (attr & FILE_ATTRIBUTE_REPARSE_POINT)
|
||||
+ {
|
||||
+ REPARSE_DATA_BUFFER *buffer = NULL;
|
||||
+ ULONG buffer_len = 0;
|
||||
+
|
||||
+ if (get_reparse_point( handle, NULL, &buffer_len ) == STATUS_BUFFER_TOO_SMALL)
|
||||
+ {
|
||||
+ buffer = malloc( buffer_len );
|
||||
+ if (get_reparse_point( handle, buffer, &buffer_len ) == STATUS_SUCCESS)
|
||||
+ info->ReparseTag = buffer->ReparseTag;
|
||||
+ free( buffer );
|
||||
+ }
|
||||
+ }
|
||||
if ((options & FILE_OPEN_REPARSE_POINT) && fd_is_mount_point( fd, &st ))
|
||||
info->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
|
||||
}
|
||||
--
|
||||
2.17.1
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,48 +0,0 @@
|
||||
From 4039b5b7bd3e8df9052006c5755a63aab93d52ef Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Wed, 29 May 2019 15:11:42 -0600
|
||||
Subject: kernel32: Add reparse support to FindNextFile.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
dlls/kernelbase/file.c | 24 ++++++++++++++++++++++++
|
||||
1 file changed, 24 insertions(+)
|
||||
|
||||
diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c
|
||||
index bf6e9e17c9e..26d3dde5ad6 100644
|
||||
--- a/dlls/kernelbase/file.c
|
||||
+++ b/dlls/kernelbase/file.c
|
||||
@@ -1508,6 +1508,30 @@ BOOL WINAPI DECLSPEC_HOTPATCH FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *da
|
||||
memcpy( data->cFileName, dir_info->FileName, dir_info->FileNameLength );
|
||||
data->cFileName[dir_info->FileNameLength/sizeof(WCHAR)] = 0;
|
||||
|
||||
+ /* get reparse tag */
|
||||
+ if (dir_info->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
|
||||
+ {
|
||||
+ INT path_len = info->path.Length + dir_info->FileNameLength + sizeof(WCHAR);
|
||||
+ WCHAR *path = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, path_len );
|
||||
+ FILE_ATTRIBUTE_TAG_INFORMATION taginfo;
|
||||
+ IO_STATUS_BLOCK iosb;
|
||||
+ NTSTATUS status;
|
||||
+ HANDLE hlink;
|
||||
+
|
||||
+ if (!path) break;
|
||||
+
|
||||
+ lstrcpynW( path, info->path.Buffer, info->path.Length/sizeof(WCHAR) + 1 );
|
||||
+ lstrcatW( path, data->cFileName );
|
||||
+
|
||||
+ hlink = CreateFileW( path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
|
||||
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0 );
|
||||
+ HeapFree( GetProcessHeap(), 0, path );
|
||||
+ status = NtQueryInformationFile( hlink, &iosb, &taginfo, sizeof(taginfo),
|
||||
+ FileAttributeTagInformation );
|
||||
+ if (status == STATUS_SUCCESS) data->dwReserved0 = taginfo.ReparseTag;
|
||||
+ CloseHandle( hlink );
|
||||
+ }
|
||||
+
|
||||
if (info->level != FindExInfoBasic)
|
||||
{
|
||||
memcpy( data->cAlternateFileName, dir_info->ShortName, dir_info->ShortNameLength );
|
||||
--
|
||||
2.17.1
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user