To: vim_dev@googlegroups.com Subject: Patch 8.2.2451 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.2451 Problem: MS-Windows: Extended Attributes not preserved. Solution: Preserve Extended Attributes when writing a file. (Ken Takata, closes #7765) Files: src/os_win32.c *** ../vim-8.2.2450/src/os_win32.c 2020-12-18 19:49:52.345571854 +0100 --- src/os_win32.c 2021-02-01 20:50:12.478466893 +0100 *************** *** 33,38 **** --- 33,39 ---- // cproto fails on missing include files #ifndef PROTO # include + # include #endif #undef chdir *************** *** 7254,7259 **** --- 7255,7438 ---- } /* + * 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,7268 **** --- 7442,7448 ---- { // File streams only work on Windows NT and later. copy_infostreams(from, to); + copy_extattr(from, to); return 0; } *** ../vim-8.2.2450/src/version.c 2021-02-01 20:34:57.249893201 +0100 --- src/version.c 2021-02-01 20:47:46.815122290 +0100 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 2451, /**/ -- Microsoft's definition of a boolean: TRUE, FALSE, MAYBE "Embrace and extend"...? /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///