mirror of
https://github.com/git-for-windows/git.git
synced 2026-02-03 18:59:59 -06:00
Merge branch 'wsl-file-mode-bits'
This patch introduces support to set special NTFS attributes that are interpreted by the Windows Subsystem for Linux as file mode bits, UID and GID. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
commit
5f7201b50f
@ -790,3 +790,9 @@ core.maxTreeDepth::
|
||||
to allow Git to abort cleanly, and should not generally need to
|
||||
be adjusted. When Git is compiled with MSVC, the default is 512.
|
||||
Otherwise, the default is 2048.
|
||||
|
||||
core.WSLCompat::
|
||||
Tells Git whether to enable wsl compatibility mode.
|
||||
The default value is false. When set to true, Git will set the mode
|
||||
bits of the file in the way of wsl, so that the executable flag of
|
||||
files can be set or read correctly.
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
#include "win32.h"
|
||||
#include "win32/fscache.h"
|
||||
#include "win32/lazyload.h"
|
||||
#include "win32/wsl.h"
|
||||
#include "wrapper.h"
|
||||
#include "write-or-die.h"
|
||||
#include <aclapi.h>
|
||||
@ -920,6 +921,11 @@ int mingw_open (const char *filename, int oflags, ...)
|
||||
if (fd < 0 && create && GetLastError() == ERROR_ACCESS_DENIED &&
|
||||
INIT_PROC_ADDR(RtlGetLastNtStatus) && RtlGetLastNtStatus() == STATUS_DELETE_PENDING)
|
||||
errno = EEXIST;
|
||||
else if ((oflags & O_CREAT) && fd >= 0 && are_wsl_compatible_mode_bits_enabled()) {
|
||||
_mode_t wsl_mode = S_IFREG | (mode&0777);
|
||||
set_wsl_mode_bits_by_handle((HANDLE)_get_osfhandle(fd), wsl_mode);
|
||||
}
|
||||
|
||||
if (fd < 0 && (oflags & O_ACCMODE) != O_RDONLY && errno == EACCES) {
|
||||
DWORD attrs = GetFileAttributesW(wfilename);
|
||||
if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
|
||||
@ -1307,6 +1313,11 @@ int mingw_lstat(const char *file_name, struct stat *buf)
|
||||
filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
|
||||
filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
|
||||
filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
|
||||
if (S_ISREG(buf->st_mode) &&
|
||||
are_wsl_compatible_mode_bits_enabled()) {
|
||||
copy_wsl_mode_bits_from_disk(wfilename, -1,
|
||||
&buf->st_mode);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1358,6 +1369,8 @@ static int get_file_info_by_handle(HANDLE hnd, struct stat *buf)
|
||||
filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
|
||||
filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
|
||||
filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
|
||||
if (are_wsl_compatible_mode_bits_enabled())
|
||||
get_wsl_mode_bits_by_handle(hnd, &buf->st_mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#include "config.h"
|
||||
#include "../../mem-pool.h"
|
||||
#include "ntifs.h"
|
||||
#include "wsl.h"
|
||||
|
||||
static volatile long initialized;
|
||||
static DWORD dwTlsIndex;
|
||||
@ -242,6 +243,21 @@ static struct fsentry *fseentry_create_entry(struct fscache *cache,
|
||||
&(fse->u.s.st_mtim));
|
||||
filetime_to_timespec((FILETIME *)&(fdata->CreationTime),
|
||||
&(fse->u.s.st_ctim));
|
||||
if (fdata->EaSize > 0 &&
|
||||
sizeof(buf) >= (size_t)(list ? list->len+1 : 0) + fse->len+1 &&
|
||||
are_wsl_compatible_mode_bits_enabled()) {
|
||||
size_t off = 0;
|
||||
wchar_t wpath[MAX_LONG_PATH];
|
||||
if (list && list->len) {
|
||||
memcpy(buf, list->dirent.d_name, list->len);
|
||||
buf[list->len] = '/';
|
||||
off = list->len + 1;
|
||||
}
|
||||
memcpy(buf + off, fse->dirent.d_name, fse->len);
|
||||
buf[off + fse->len] = '\0';
|
||||
if (xutftowcs_long_path(wpath, buf) >= 0)
|
||||
copy_wsl_mode_bits_from_disk(wpath, -1, &fse->st_mode);
|
||||
}
|
||||
|
||||
return fse;
|
||||
}
|
||||
|
||||
142
compat/win32/wsl.c
Normal file
142
compat/win32/wsl.c
Normal file
@ -0,0 +1,142 @@
|
||||
#define USE_THE_REPOSITORY_VARIABLE
|
||||
#include "../../git-compat-util.h"
|
||||
#include "../win32.h"
|
||||
#include "../../repository.h"
|
||||
#include "config.h"
|
||||
#include "ntifs.h"
|
||||
#include "wsl.h"
|
||||
|
||||
int are_wsl_compatible_mode_bits_enabled(void)
|
||||
{
|
||||
/* default to `false` during initialization */
|
||||
static const int fallback = 0;
|
||||
static int enabled = -1;
|
||||
|
||||
if (enabled < 0) {
|
||||
/* avoid infinite recursion */
|
||||
if (!the_repository)
|
||||
return fallback;
|
||||
|
||||
if (the_repository->config &&
|
||||
the_repository->config->hash_initialized &&
|
||||
repo_config_get_bool(the_repository, "core.wslcompat", &enabled) < 0)
|
||||
enabled = 0;
|
||||
}
|
||||
|
||||
return enabled < 0 ? fallback : enabled;
|
||||
}
|
||||
|
||||
int copy_wsl_mode_bits_from_disk(const wchar_t *wpath, ssize_t wpathlen,
|
||||
_mode_t *mode)
|
||||
{
|
||||
int ret = -1;
|
||||
HANDLE h;
|
||||
if (wpathlen >= 0) {
|
||||
/*
|
||||
* It's caller's duty to make sure wpathlen is reasonable so
|
||||
* it does not overflow.
|
||||
*/
|
||||
wchar_t *fn2 = (wchar_t*)alloca((wpathlen + 1) * sizeof(wchar_t));
|
||||
memcpy(fn2, wpath, wpathlen * sizeof(wchar_t));
|
||||
fn2[wpathlen] = 0;
|
||||
wpath = fn2;
|
||||
}
|
||||
h = CreateFileW(wpath, FILE_READ_EA | SYNCHRONIZE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL, OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS |
|
||||
FILE_FLAG_OPEN_REPARSE_POINT,
|
||||
NULL);
|
||||
if (h != INVALID_HANDLE_VALUE) {
|
||||
ret = get_wsl_mode_bits_by_handle(h, mode);
|
||||
CloseHandle(h);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef LX_FILE_METADATA_HAS_UID
|
||||
#define LX_FILE_METADATA_HAS_UID 0x1
|
||||
#define LX_FILE_METADATA_HAS_GID 0x2
|
||||
#define LX_FILE_METADATA_HAS_MODE 0x4
|
||||
#define LX_FILE_METADATA_HAS_DEVICE_ID 0x8
|
||||
#define LX_FILE_CASE_SENSITIVE_DIR 0x10
|
||||
typedef struct _FILE_STAT_LX_INFORMATION {
|
||||
LARGE_INTEGER FileId;
|
||||
LARGE_INTEGER CreationTime;
|
||||
LARGE_INTEGER LastAccessTime;
|
||||
LARGE_INTEGER LastWriteTime;
|
||||
LARGE_INTEGER ChangeTime;
|
||||
LARGE_INTEGER AllocationSize;
|
||||
LARGE_INTEGER EndOfFile;
|
||||
uint32_t FileAttributes;
|
||||
uint32_t ReparseTag;
|
||||
uint32_t NumberOfLinks;
|
||||
ACCESS_MASK EffectiveAccess;
|
||||
uint32_t LxFlags;
|
||||
uint32_t LxUid;
|
||||
uint32_t LxGid;
|
||||
uint32_t LxMode;
|
||||
uint32_t LxDeviceIdMajor;
|
||||
uint32_t LxDeviceIdMinor;
|
||||
} FILE_STAT_LX_INFORMATION, *PFILE_STAT_LX_INFORMATION;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This struct is extended from the original FILE_FULL_EA_INFORMATION of
|
||||
* Microsoft Windows.
|
||||
*/
|
||||
struct wsl_full_ea_info_t {
|
||||
uint32_t NextEntryOffset;
|
||||
uint8_t Flags;
|
||||
uint8_t EaNameLength;
|
||||
uint16_t EaValueLength;
|
||||
char EaName[7];
|
||||
char EaValue[4];
|
||||
char Padding[1];
|
||||
};
|
||||
|
||||
enum {
|
||||
FileStatLxInformation = 70,
|
||||
};
|
||||
__declspec(dllimport) NTSTATUS WINAPI
|
||||
NtQueryInformationFile(HANDLE FileHandle,
|
||||
PIO_STATUS_BLOCK IoStatusBlock,
|
||||
PVOID FileInformation, ULONG Length,
|
||||
uint32_t FileInformationClass);
|
||||
__declspec(dllimport) NTSTATUS WINAPI
|
||||
NtSetInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock,
|
||||
PVOID FileInformation, ULONG Length,
|
||||
uint32_t FileInformationClass);
|
||||
__declspec(dllimport) NTSTATUS WINAPI
|
||||
NtSetEaFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock,
|
||||
PVOID EaBuffer, ULONG EaBufferSize);
|
||||
|
||||
int set_wsl_mode_bits_by_handle(HANDLE h, _mode_t mode)
|
||||
{
|
||||
uint32_t value = mode;
|
||||
struct wsl_full_ea_info_t ea_info;
|
||||
IO_STATUS_BLOCK iob;
|
||||
/* mode should be valid to make WSL happy */
|
||||
assert(S_ISREG(mode) || S_ISDIR(mode));
|
||||
ea_info.NextEntryOffset = 0;
|
||||
ea_info.Flags = 0;
|
||||
ea_info.EaNameLength = 6;
|
||||
ea_info.EaValueLength = sizeof(value); /* 4 */
|
||||
strlcpy(ea_info.EaName, "$LXMOD", sizeof(ea_info.EaName));
|
||||
memcpy(ea_info.EaValue, &value, sizeof(value));
|
||||
ea_info.Padding[0] = 0;
|
||||
return NtSetEaFile(h, &iob, &ea_info, sizeof(ea_info));
|
||||
}
|
||||
|
||||
int get_wsl_mode_bits_by_handle(HANDLE h, _mode_t *mode)
|
||||
{
|
||||
FILE_STAT_LX_INFORMATION fxi;
|
||||
IO_STATUS_BLOCK iob;
|
||||
if (NtQueryInformationFile(h, &iob, &fxi, sizeof(fxi),
|
||||
FileStatLxInformation) == 0) {
|
||||
if (fxi.LxFlags & LX_FILE_METADATA_HAS_MODE)
|
||||
*mode = (_mode_t)fxi.LxMode;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
12
compat/win32/wsl.h
Normal file
12
compat/win32/wsl.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef COMPAT_WIN32_WSL_H
|
||||
#define COMPAT_WIN32_WSL_H
|
||||
|
||||
int are_wsl_compatible_mode_bits_enabled(void);
|
||||
|
||||
int copy_wsl_mode_bits_from_disk(const wchar_t *wpath, ssize_t wpathlen,
|
||||
_mode_t *mode);
|
||||
|
||||
int get_wsl_mode_bits_by_handle(HANDLE h, _mode_t *mode);
|
||||
int set_wsl_mode_bits_by_handle(HANDLE h, _mode_t mode);
|
||||
|
||||
#endif
|
||||
@ -509,7 +509,7 @@ endif
|
||||
compat/win32/path-utils.o \
|
||||
compat/win32/pthread.o compat/win32/syslog.o \
|
||||
compat/win32/trace2_win32_process_info.o \
|
||||
compat/win32/dirent.o compat/win32/fscache.o
|
||||
compat/win32/dirent.o compat/win32/fscache.o compat/win32/wsl.o
|
||||
COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DDETECT_MSYS_TTY \
|
||||
-DENSURE_MSYSTEM_IS_SET="\"$(MSYSTEM)\"" -DMINGW_PREFIX="\"$(patsubst /%,%,$(MINGW_PREFIX))\"" \
|
||||
-DNOGDI -DHAVE_STRING_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
|
||||
@ -714,7 +714,7 @@ ifeq ($(uname_S),MINGW)
|
||||
compat/win32/flush.o \
|
||||
compat/win32/path-utils.o \
|
||||
compat/win32/pthread.o compat/win32/syslog.o \
|
||||
compat/win32/dirent.o compat/win32/fscache.o
|
||||
compat/win32/dirent.o compat/win32/fscache.o compat/win32/wsl.o
|
||||
BASIC_CFLAGS += -DWIN32
|
||||
EXTLIBS += -lws2_32
|
||||
GITLIBS += git.res
|
||||
|
||||
@ -300,6 +300,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
compat/win32/syslog.c
|
||||
compat/win32/trace2_win32_process_info.c
|
||||
compat/win32/dirent.c
|
||||
compat/win32/wsl.c
|
||||
compat/nedmalloc/nedmalloc.c
|
||||
compat/strdup.c
|
||||
compat/win32/fscache.c)
|
||||
|
||||
@ -1264,6 +1264,7 @@ elif host_machine.system() == 'windows'
|
||||
'compat/win32/path-utils.c',
|
||||
'compat/win32/pthread.c',
|
||||
'compat/win32/syslog.c',
|
||||
'compat/win32/wsl.c',
|
||||
'compat/win32mmap.c',
|
||||
'compat/nedmalloc/nedmalloc.c',
|
||||
]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user