forked from aniani/vim
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)
This commit is contained in:
180
src/os_win32.c
180
src/os_win32.c
@@ -33,6 +33,7 @@
|
|||||||
// cproto fails on missing include files
|
// cproto fails on missing include files
|
||||||
#ifndef PROTO
|
#ifndef PROTO
|
||||||
# include <process.h>
|
# include <process.h>
|
||||||
|
# include <winternl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#undef chdir
|
#undef chdir
|
||||||
@@ -7253,6 +7254,184 @@ copy_infostreams(char_u *from, char_u *to)
|
|||||||
vim_free(tow);
|
vim_free(tow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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".
|
* Copy file attributes from file "from" to file "to".
|
||||||
* For Windows NT and later we copy info streams.
|
* For Windows NT and later we copy info streams.
|
||||||
@@ -7263,6 +7442,7 @@ mch_copy_file_attribute(char_u *from, char_u *to)
|
|||||||
{
|
{
|
||||||
// File streams only work on Windows NT and later.
|
// File streams only work on Windows NT and later.
|
||||||
copy_infostreams(from, to);
|
copy_infostreams(from, to);
|
||||||
|
copy_extattr(from, to);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -750,6 +750,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
2451,
|
||||||
/**/
|
/**/
|
||||||
2450,
|
2450,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user