changeset 23819:7237ed5f89bd v8.2.2451

patch 8.2.2451: MS-Windows: Extended Attributes not preserved Commit: https://github.com/vim/vim/commit/e7bebc495d4014d7bc81f863939c35268cb8e97d Author: Bram Moolenaar <Bram@vim.org> Date: Mon Feb 1 20:50:37 2021 +0100 patch 8.2.2451: MS-Windows: Extended Attributes not preserved Problem: MS-Windows: Extended Attributes not preserved. Solution: Preserve Extended Attributes when writing a file. (Ken Takata, closes #7765)
author Bram Moolenaar <Bram@vim.org>
date Mon, 01 Feb 2021 21:00:03 +0100
parents 8103ec7fda36
children 8460878018c0
files src/os_win32.c src/version.c
diffstat 2 files changed, 182 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -33,6 +33,7 @@
 // cproto fails on missing include files
 #ifndef PROTO
 # include <process.h>
+# include <winternl.h>
 #endif
 
 #undef chdir
@@ -7254,6 +7255,184 @@ copy_infostreams(char_u *from, char_u *t
 }
 
 /*
+ * ntdll.dll definitions
+ */
+#define FileEaInformation   7
+#ifndef STATUS_SUCCESS
+# define STATUS_SUCCESS	    ((NTSTATUS) 0x00000000L)
+#endif
+
+typedef struct _FILE_FULL_EA_INFORMATION_ {
+    ULONG  NextEntryOffset;
+    UCHAR  Flags;
+    UCHAR  EaNameLength;
+    USHORT EaValueLength;
+    CHAR   EaName[1];
+} FILE_FULL_EA_INFORMATION_, *PFILE_FULL_EA_INFORMATION_;
+
+typedef struct _FILE_EA_INFORMATION_ {
+    ULONG EaSize;
+} FILE_EA_INFORMATION_, *PFILE_EA_INFORMATION_;
+
+typedef NTSTATUS (NTAPI *PfnNtOpenFile)(
+	PHANDLE FileHandle,
+	ACCESS_MASK DesiredAccess,
+	POBJECT_ATTRIBUTES ObjectAttributes,
+	PIO_STATUS_BLOCK IoStatusBlock,
+	ULONG ShareAccess,
+	ULONG OpenOptions);
+typedef NTSTATUS (NTAPI *PfnNtClose)(
+	HANDLE Handle);
+typedef NTSTATUS (NTAPI *PfnNtSetEaFile)(
+	HANDLE           FileHandle,
+	PIO_STATUS_BLOCK IoStatusBlock,
+	PVOID            Buffer,
+	ULONG            Length);
+typedef NTSTATUS (NTAPI *PfnNtQueryEaFile)(
+	HANDLE FileHandle,
+	PIO_STATUS_BLOCK IoStatusBlock,
+	PVOID Buffer,
+	ULONG Length,
+	BOOLEAN ReturnSingleEntry,
+	PVOID EaList,
+	ULONG EaListLength,
+	PULONG EaIndex,
+	BOOLEAN RestartScan);
+typedef NTSTATUS (NTAPI *PfnNtQueryInformationFile)(
+	HANDLE                 FileHandle,
+	PIO_STATUS_BLOCK       IoStatusBlock,
+	PVOID                  FileInformation,
+	ULONG                  Length,
+	FILE_INFORMATION_CLASS FileInformationClass);
+typedef VOID (NTAPI *PfnRtlInitUnicodeString)(
+	PUNICODE_STRING DestinationString,
+	PCWSTR SourceString);
+
+PfnNtOpenFile pNtOpenFile = NULL;
+PfnNtClose pNtClose = NULL;
+PfnNtSetEaFile pNtSetEaFile = NULL;
+PfnNtQueryEaFile pNtQueryEaFile = NULL;
+PfnNtQueryInformationFile pNtQueryInformationFile = NULL;
+PfnRtlInitUnicodeString pRtlInitUnicodeString = NULL;
+
+/*
+ * Load ntdll.dll functions.
+ */
+    static BOOL
+load_ntdll(void)
+{
+    static int	loaded = -1;
+
+    if (loaded == -1)
+    {
+	HMODULE hNtdll = GetModuleHandle("ntdll.dll");
+	if (hNtdll != NULL)
+	{
+	    pNtOpenFile = (PfnNtOpenFile) GetProcAddress(hNtdll, "NtOpenFile");
+	    pNtClose = (PfnNtClose) GetProcAddress(hNtdll, "NtClose");
+	    pNtSetEaFile = (PfnNtSetEaFile)
+		GetProcAddress(hNtdll, "NtSetEaFile");
+	    pNtQueryEaFile = (PfnNtQueryEaFile)
+		GetProcAddress(hNtdll, "NtQueryEaFile");
+	    pNtQueryInformationFile = (PfnNtQueryInformationFile)
+		GetProcAddress(hNtdll, "NtQueryInformationFile");
+	    pRtlInitUnicodeString = (PfnRtlInitUnicodeString)
+		GetProcAddress(hNtdll, "RtlInitUnicodeString");
+	}
+	if (pNtOpenFile == NULL
+		|| pNtClose == NULL
+		|| pNtSetEaFile == NULL
+		|| pNtQueryEaFile == NULL
+		|| pNtQueryInformationFile == NULL
+		|| pRtlInitUnicodeString == NULL)
+	    loaded = FALSE;
+	else
+	    loaded = TRUE;
+    }
+    return (BOOL) loaded;
+}
+
+/*
+ * Copy extended attributes (EA) from file "from" to file "to".
+ */
+    static void
+copy_extattr(char_u *from, char_u *to)
+{
+    char_u		    *fromf = NULL;
+    char_u		    *tof = NULL;
+    WCHAR		    *fromw = NULL;
+    WCHAR		    *tow = NULL;
+    UNICODE_STRING	    u;
+    HANDLE		    h;
+    OBJECT_ATTRIBUTES	    oa;
+    IO_STATUS_BLOCK	    iosb;
+    FILE_EA_INFORMATION_    eainfo = {0};
+    void		    *ea = NULL;
+
+    if (!load_ntdll())
+	return;
+
+    // Convert the file names to the fully qualified object names.
+    fromf = alloc(STRLEN(from) + 5);
+    tof = alloc(STRLEN(to) + 5);
+    if (fromf == NULL || tof == NULL)
+	goto theend;
+    STRCPY(fromf, "\\??\\");
+    STRCAT(fromf, from);
+    STRCPY(tof, "\\??\\");
+    STRCAT(tof, to);
+
+    // Convert the names to wide characters.
+    fromw = enc_to_utf16(fromf, NULL);
+    tow = enc_to_utf16(tof, NULL);
+    if (fromw == NULL || tow == NULL)
+	goto theend;
+
+    // Get the EA.
+    pRtlInitUnicodeString(&u, fromw);
+    InitializeObjectAttributes(&oa, &u, 0, NULL, NULL);
+    if (pNtOpenFile(&h, FILE_READ_EA, &oa, &iosb, 0,
+		FILE_NON_DIRECTORY_FILE) != STATUS_SUCCESS)
+	goto theend;
+    pNtQueryInformationFile(h, &iosb, &eainfo, sizeof(eainfo),
+	    FileEaInformation);
+    if (eainfo.EaSize != 0)
+    {
+	ea = alloc(eainfo.EaSize);
+	if (ea != NULL)
+	{
+	    if (pNtQueryEaFile(h, &iosb, ea, eainfo.EaSize, FALSE,
+			NULL, 0, NULL, TRUE) != STATUS_SUCCESS)
+	    {
+		vim_free(ea);
+		ea = NULL;
+	    }
+	}
+    }
+    pNtClose(h);
+
+    // Set the EA.
+    if (ea != NULL)
+    {
+	pRtlInitUnicodeString(&u, tow);
+	InitializeObjectAttributes(&oa, &u, 0, NULL, NULL);
+	if (pNtOpenFile(&h, FILE_WRITE_EA, &oa, &iosb, 0,
+		    FILE_NON_DIRECTORY_FILE) != STATUS_SUCCESS)
+	    goto theend;
+
+	pNtSetEaFile(h, &iosb, ea, eainfo.EaSize);
+	pNtClose(h);
+    }
+
+theend:
+    vim_free(fromf);
+    vim_free(tof);
+    vim_free(fromw);
+    vim_free(tow);
+    vim_free(ea);
+}
+
+/*
  * Copy file attributes from file "from" to file "to".
  * For Windows NT and later we copy info streams.
  * Always returns zero, errors are ignored.
@@ -7263,6 +7442,7 @@ mch_copy_file_attribute(char_u *from, ch
 {
     // File streams only work on Windows NT and later.
     copy_infostreams(from, to);
+    copy_extattr(from, to);
     return 0;
 }
 
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2451,
+/**/
     2450,
 /**/
     2449,