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
0 commit comments