comparison src/os_win32.c @ 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 b545334ae654
children c1de90bc6e63
comparison
equal deleted inserted replaced
23818:8103ec7fda36 23819:7237ed5f89bd
31 #include <limits.h> 31 #include <limits.h>
32 32
33 // cproto fails on missing include files 33 // cproto fails on missing include files
34 #ifndef PROTO 34 #ifndef PROTO
35 # include <process.h> 35 # include <process.h>
36 # include <winternl.h>
36 #endif 37 #endif
37 38
38 #undef chdir 39 #undef chdir
39 #ifdef __GNUC__ 40 #ifdef __GNUC__
40 # ifndef __MINGW32__ 41 # ifndef __MINGW32__
7252 vim_free(fromw); 7253 vim_free(fromw);
7253 vim_free(tow); 7254 vim_free(tow);
7254 } 7255 }
7255 7256
7256 /* 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
7435 /*
7257 * Copy file attributes from file "from" to file "to". 7436 * Copy file attributes from file "from" to file "to".
7258 * For Windows NT and later we copy info streams. 7437 * For Windows NT and later we copy info streams.
7259 * Always returns zero, errors are ignored. 7438 * Always returns zero, errors are ignored.
7260 */ 7439 */
7261 int 7440 int
7262 mch_copy_file_attribute(char_u *from, char_u *to) 7441 mch_copy_file_attribute(char_u *from, char_u *to)
7263 { 7442 {
7264 // File streams only work on Windows NT and later. 7443 // File streams only work on Windows NT and later.
7265 copy_infostreams(from, to); 7444 copy_infostreams(from, to);
7445 copy_extattr(from, to);
7266 return 0; 7446 return 0;
7267 } 7447 }
7268 7448
7269 #if defined(MYRESETSTKOFLW) || defined(PROTO) 7449 #if defined(MYRESETSTKOFLW) || defined(PROTO)
7270 /* 7450 /*