Skip to content

Commit e7bebc4

Browse files
committed
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)
1 parent 7781ebe commit e7bebc4

2 files changed

Lines changed: 182 additions & 0 deletions

File tree

src/os_win32.c

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
// cproto fails on missing include files
3434
#ifndef PROTO
3535
# include <process.h>
36+
# include <winternl.h>
3637
#endif
3738

3839
#undef chdir
@@ -7253,6 +7254,184 @@ copy_infostreams(char_u *from, char_u *to)
72537254
vim_free(tow);
72547255
}
72557256

7257+
/*
7258+
* ntdll.dll definitions
7259+
*/
7260+
#define FileEaInformation 7
7261+
#ifndef STATUS_SUCCESS
7262+
# define STATUS_SUCCESS ((NTSTATUS) 0x00000000L)
7263+
#endif
7264+
7265+
typedef struct _FILE_FULL_EA_INFORMATION_ {
7266+
ULONG NextEntryOffset;
7267+
UCHAR Flags;
7268+
UCHAR EaNameLength;
7269+
USHORT EaValueLength;
7270+
CHAR EaName[1];
7271+
} FILE_FULL_EA_INFORMATION_, *PFILE_FULL_EA_INFORMATION_;
7272+
7273+
typedef struct _FILE_EA_INFORMATION_ {
7274+
ULONG EaSize;
7275+
} FILE_EA_INFORMATION_, *PFILE_EA_INFORMATION_;
7276+
7277+
typedef NTSTATUS (NTAPI *PfnNtOpenFile)(
7278+
PHANDLE FileHandle,
7279+
ACCESS_MASK DesiredAccess,
7280+
POBJECT_ATTRIBUTES ObjectAttributes,
7281+
PIO_STATUS_BLOCK IoStatusBlock,
7282+
ULONG ShareAccess,
7283+
ULONG OpenOptions);
7284+
typedef NTSTATUS (NTAPI *PfnNtClose)(
7285+
HANDLE Handle);
7286+
typedef NTSTATUS (NTAPI *PfnNtSetEaFile)(
7287+
HANDLE FileHandle,
7288+
PIO_STATUS_BLOCK IoStatusBlock,
7289+
PVOID Buffer,
7290+
ULONG Length);
7291+
typedef NTSTATUS (NTAPI *PfnNtQueryEaFile)(
7292+
HANDLE FileHandle,
7293+
PIO_STATUS_BLOCK IoStatusBlock,
7294+
PVOID Buffer,
7295+
ULONG Length,
7296+
BOOLEAN ReturnSingleEntry,
7297+
PVOID EaList,
7298+
ULONG EaListLength,
7299+
PULONG EaIndex,
7300+
BOOLEAN RestartScan);
7301+
typedef NTSTATUS (NTAPI *PfnNtQueryInformationFile)(
7302+
HANDLE FileHandle,
7303+
PIO_STATUS_BLOCK IoStatusBlock,
7304+
PVOID FileInformation,
7305+
ULONG Length,
7306+
FILE_INFORMATION_CLASS FileInformationClass);
7307+
typedef VOID (NTAPI *PfnRtlInitUnicodeString)(
7308+
PUNICODE_STRING DestinationString,
7309+
PCWSTR SourceString);
7310+
7311+
PfnNtOpenFile pNtOpenFile = NULL;
7312+
PfnNtClose pNtClose = NULL;
7313+
PfnNtSetEaFile pNtSetEaFile = NULL;
7314+
PfnNtQueryEaFile pNtQueryEaFile = NULL;
7315+
PfnNtQueryInformationFile pNtQueryInformationFile = NULL;
7316+
PfnRtlInitUnicodeString pRtlInitUnicodeString = NULL;
7317+
7318+
/*
7319+
* Load ntdll.dll functions.
7320+
*/
7321+
static BOOL
7322+
load_ntdll(void)
7323+
{
7324+
static int loaded = -1;
7325+
7326+
if (loaded == -1)
7327+
{
7328+
HMODULE hNtdll = GetModuleHandle("ntdll.dll");
7329+
if (hNtdll != NULL)
7330+
{
7331+
pNtOpenFile = (PfnNtOpenFile) GetProcAddress(hNtdll, "NtOpenFile");
7332+
pNtClose = (PfnNtClose) GetProcAddress(hNtdll, "NtClose");
7333+
pNtSetEaFile = (PfnNtSetEaFile)
7334+
GetProcAddress(hNtdll, "NtSetEaFile");
7335+
pNtQueryEaFile = (PfnNtQueryEaFile)
7336+
GetProcAddress(hNtdll, "NtQueryEaFile");
7337+
pNtQueryInformationFile = (PfnNtQueryInformationFile)
7338+
GetProcAddress(hNtdll, "NtQueryInformationFile");
7339+
pRtlInitUnicodeString = (PfnRtlInitUnicodeString)
7340+
GetProcAddress(hNtdll, "RtlInitUnicodeString");
7341+
}
7342+
if (pNtOpenFile == NULL
7343+
|| pNtClose == NULL
7344+
|| pNtSetEaFile == NULL
7345+
|| pNtQueryEaFile == NULL
7346+
|| pNtQueryInformationFile == NULL
7347+
|| pRtlInitUnicodeString == NULL)
7348+
loaded = FALSE;
7349+
else
7350+
loaded = TRUE;
7351+
}
7352+
return (BOOL) loaded;
7353+
}
7354+
7355+
/*
7356+
* Copy extended attributes (EA) from file "from" to file "to".
7357+
*/
7358+
static void
7359+
copy_extattr(char_u *from, char_u *to)
7360+
{
7361+
char_u *fromf = NULL;
7362+
char_u *tof = NULL;
7363+
WCHAR *fromw = NULL;
7364+
WCHAR *tow = NULL;
7365+
UNICODE_STRING u;
7366+
HANDLE h;
7367+
OBJECT_ATTRIBUTES oa;
7368+
IO_STATUS_BLOCK iosb;
7369+
FILE_EA_INFORMATION_ eainfo = {0};
7370+
void *ea = NULL;
7371+
7372+
if (!load_ntdll())
7373+
return;
7374+
7375+
// Convert the file names to the fully qualified object names.
7376+
fromf = alloc(STRLEN(from) + 5);
7377+
tof = alloc(STRLEN(to) + 5);
7378+
if (fromf == NULL || tof == NULL)
7379+
goto theend;
7380+
STRCPY(fromf, "\\??\\");
7381+
STRCAT(fromf, from);
7382+
STRCPY(tof, "\\??\\");
7383+
STRCAT(tof, to);
7384+
7385+
// Convert the names to wide characters.
7386+
fromw = enc_to_utf16(fromf, NULL);
7387+
tow = enc_to_utf16(tof, NULL);
7388+
if (fromw == NULL || tow == NULL)
7389+
goto theend;
7390+
7391+
// Get the EA.
7392+
pRtlInitUnicodeString(&u, fromw);
7393+
InitializeObjectAttributes(&oa, &u, 0, NULL, NULL);
7394+
if (pNtOpenFile(&h, FILE_READ_EA, &oa, &iosb, 0,
7395+
FILE_NON_DIRECTORY_FILE) != STATUS_SUCCESS)
7396+
goto theend;
7397+
pNtQueryInformationFile(h, &iosb, &eainfo, sizeof(eainfo),
7398+
FileEaInformation);
7399+
if (eainfo.EaSize != 0)
7400+
{
7401+
ea = alloc(eainfo.EaSize);
7402+
if (ea != NULL)
7403+
{
7404+
if (pNtQueryEaFile(h, &iosb, ea, eainfo.EaSize, FALSE,
7405+
NULL, 0, NULL, TRUE) != STATUS_SUCCESS)
7406+
{
7407+
vim_free(ea);
7408+
ea = NULL;
7409+
}
7410+
}
7411+
}
7412+
pNtClose(h);
7413+
7414+
// Set the EA.
7415+
if (ea != NULL)
7416+
{
7417+
pRtlInitUnicodeString(&u, tow);
7418+
InitializeObjectAttributes(&oa, &u, 0, NULL, NULL);
7419+
if (pNtOpenFile(&h, FILE_WRITE_EA, &oa, &iosb, 0,
7420+
FILE_NON_DIRECTORY_FILE) != STATUS_SUCCESS)
7421+
goto theend;
7422+
7423+
pNtSetEaFile(h, &iosb, ea, eainfo.EaSize);
7424+
pNtClose(h);
7425+
}
7426+
7427+
theend:
7428+
vim_free(fromf);
7429+
vim_free(tof);
7430+
vim_free(fromw);
7431+
vim_free(tow);
7432+
vim_free(ea);
7433+
}
7434+
72567435
/*
72577436
* Copy file attributes from file "from" to file "to".
72587437
* For Windows NT and later we copy info streams.
@@ -7263,6 +7442,7 @@ mch_copy_file_attribute(char_u *from, char_u *to)
72637442
{
72647443
// File streams only work on Windows NT and later.
72657444
copy_infostreams(from, to);
7445+
copy_extattr(from, to);
72667446
return 0;
72677447
}
72687448

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,8 @@ static char *(features[]) =
750750

751751
static int included_patches[] =
752752
{ /* Add new patch number below this line */
753+
/**/
754+
2451,
753755
/**/
754756
2450,
755757
/**/

0 commit comments

Comments
 (0)