mirror of
https://github.com/git/git.git
synced 2024-11-24 18:33:43 +08:00
Merge branch 'dp/cywginstat'
* dp/cywginstat: cygwin: Use native Win32 API for stat mingw: move common functionality to win32.h add have_git_dir() function
This commit is contained in:
commit
ed187bd593
@ -117,6 +117,15 @@ core.fileMode::
|
||||
the working copy are ignored; useful on broken filesystems like FAT.
|
||||
See linkgit:git-update-index[1]. True by default.
|
||||
|
||||
core.ignoreCygwinFSTricks::
|
||||
This option is only used by Cygwin implementation of Git. If false,
|
||||
the Cygwin stat() and lstat() functions are used. This may be useful
|
||||
if your repository consists of a few separate directories joined in
|
||||
one hierarchy using Cygwin mount. If true, Git uses native Win32 API
|
||||
whenever it is possible and falls back to Cygwin functions only to
|
||||
handle symbol links. The native mode is more than twice faster than
|
||||
normal Cygwin l/stat() functions. True by default.
|
||||
|
||||
core.trustctime::
|
||||
If false, the ctime differences between the index and the
|
||||
working copy are ignored; useful when the inode change time
|
||||
|
4
Makefile
4
Makefile
@ -346,6 +346,7 @@ LIB_H += cache.h
|
||||
LIB_H += cache-tree.h
|
||||
LIB_H += commit.h
|
||||
LIB_H += compat/mingw.h
|
||||
LIB_H += compat/cygwin.h
|
||||
LIB_H += csum-file.h
|
||||
LIB_H += decorate.h
|
||||
LIB_H += delta.h
|
||||
@ -748,6 +749,9 @@ ifeq ($(uname_S),HP-UX)
|
||||
NO_SYS_SELECT_H = YesPlease
|
||||
SNPRINTF_RETURNS_BOGUS = YesPlease
|
||||
endif
|
||||
ifneq (,$(findstring CYGWIN,$(uname_S)))
|
||||
COMPAT_OBJS += compat/cygwin.o
|
||||
endif
|
||||
ifneq (,$(findstring MINGW,$(uname_S)))
|
||||
NO_MMAP = YesPlease
|
||||
NO_PREAD = YesPlease
|
||||
|
1
cache.h
1
cache.h
@ -319,6 +319,7 @@ extern int is_bare_repository(void);
|
||||
extern int is_inside_git_dir(void);
|
||||
extern char *git_work_tree_cfg;
|
||||
extern int is_inside_work_tree(void);
|
||||
extern int have_git_dir(void);
|
||||
extern const char *get_git_dir(void);
|
||||
extern char *get_object_directory(void);
|
||||
extern char *get_index_file(void);
|
||||
|
127
compat/cygwin.c
Normal file
127
compat/cygwin.c
Normal file
@ -0,0 +1,127 @@
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include "../git-compat-util.h"
|
||||
#include "win32.h"
|
||||
#include "../cache.h" /* to read configuration */
|
||||
|
||||
static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
|
||||
{
|
||||
long long winTime = ((long long)ft->dwHighDateTime << 32) +
|
||||
ft->dwLowDateTime;
|
||||
winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */
|
||||
/* convert 100-nsecond interval to seconds and nanoseconds */
|
||||
ts->tv_sec = (time_t)(winTime/10000000);
|
||||
ts->tv_nsec = (long)(winTime - ts->tv_sec*10000000LL) * 100;
|
||||
}
|
||||
|
||||
#define size_to_blocks(s) (((s)+511)/512)
|
||||
|
||||
/* do_stat is a common implementation for cygwin_lstat and cygwin_stat.
|
||||
*
|
||||
* To simplify its logic, in the case of cygwin symlinks, this implementation
|
||||
* falls back to the cygwin version of stat/lstat, which is provided as the
|
||||
* last argument.
|
||||
*/
|
||||
static int do_stat(const char *file_name, struct stat *buf, stat_fn_t cygstat)
|
||||
{
|
||||
WIN32_FILE_ATTRIBUTE_DATA fdata;
|
||||
|
||||
if (file_name[0] == '/')
|
||||
return cygstat (file_name, buf);
|
||||
|
||||
if (!(errno = get_file_attr(file_name, &fdata))) {
|
||||
/*
|
||||
* If the system attribute is set and it is not a directory then
|
||||
* it could be a symbol link created in the nowinsymlinks mode.
|
||||
* Normally, Cygwin works in the winsymlinks mode, so this situation
|
||||
* is very unlikely. For the sake of simplicity of our code, let's
|
||||
* Cygwin to handle it.
|
||||
*/
|
||||
if ((fdata.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) &&
|
||||
!(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||
return cygstat(file_name, buf);
|
||||
|
||||
/* fill out the stat structure */
|
||||
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
|
||||
buf->st_ino = 0;
|
||||
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
|
||||
buf->st_nlink = 1;
|
||||
buf->st_uid = buf->st_gid = 0;
|
||||
#ifdef __CYGWIN_USE_BIG_TYPES__
|
||||
buf->st_size = ((_off64_t)fdata.nFileSizeHigh << 32) +
|
||||
fdata.nFileSizeLow;
|
||||
#else
|
||||
buf->st_size = (off_t)fdata.nFileSizeLow;
|
||||
#endif
|
||||
buf->st_blocks = size_to_blocks(buf->st_size);
|
||||
filetime_to_timespec(&fdata.ftLastAccessTime, &buf->st_atim);
|
||||
filetime_to_timespec(&fdata.ftLastWriteTime, &buf->st_mtim);
|
||||
filetime_to_timespec(&fdata.ftCreationTime, &buf->st_ctim);
|
||||
return 0;
|
||||
} else if (errno == ENOENT) {
|
||||
/*
|
||||
* In the winsymlinks mode (which is the default), Cygwin
|
||||
* emulates symbol links using Windows shortcut files. These
|
||||
* files are formed by adding .lnk extension. So, if we have
|
||||
* not found the specified file name, it could be that it is
|
||||
* a symbol link. Let's Cygwin to deal with that.
|
||||
*/
|
||||
return cygstat(file_name, buf);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* We provide our own lstat/stat functions, since the provided Cygwin versions
|
||||
* of these functions are too slow. These stat functions are tailored for Git's
|
||||
* usage, and therefore they are not meant to be complete and correct emulation
|
||||
* of lstat/stat functionality.
|
||||
*/
|
||||
static int cygwin_lstat(const char *path, struct stat *buf)
|
||||
{
|
||||
return do_stat(path, buf, lstat);
|
||||
}
|
||||
|
||||
static int cygwin_stat(const char *path, struct stat *buf)
|
||||
{
|
||||
return do_stat(path, buf, stat);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* At start up, we are trying to determine whether Win32 API or cygwin stat
|
||||
* functions should be used. The choice is determined by core.ignorecygwinfstricks.
|
||||
* Reading this option is not always possible immediately as git_dir may be
|
||||
* not be set yet. So until it is set, use cygwin lstat/stat functions.
|
||||
*/
|
||||
static int native_stat = 1;
|
||||
|
||||
static int git_cygwin_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
if (!strcmp(var, "core.ignorecygwinfstricks"))
|
||||
native_stat = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_stat(void)
|
||||
{
|
||||
if (have_git_dir()) {
|
||||
git_config(git_cygwin_config, NULL);
|
||||
cygwin_stat_fn = native_stat ? cygwin_stat : stat;
|
||||
cygwin_lstat_fn = native_stat ? cygwin_lstat : lstat;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int cygwin_stat_stub(const char *file_name, struct stat *buf)
|
||||
{
|
||||
return (init_stat() ? stat : *cygwin_stat_fn)(file_name, buf);
|
||||
}
|
||||
|
||||
static int cygwin_lstat_stub(const char *file_name, struct stat *buf)
|
||||
{
|
||||
return (init_stat() ? lstat : *cygwin_lstat_fn)(file_name, buf);
|
||||
}
|
||||
|
||||
stat_fn_t cygwin_stat_fn = cygwin_stat_stub;
|
||||
stat_fn_t cygwin_lstat_fn = cygwin_lstat_stub;
|
||||
|
9
compat/cygwin.h
Normal file
9
compat/cygwin.h
Normal file
@ -0,0 +1,9 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
typedef int (*stat_fn_t)(const char*, struct stat*);
|
||||
extern stat_fn_t cygwin_stat_fn;
|
||||
extern stat_fn_t cygwin_lstat_fn;
|
||||
|
||||
#define stat(path, buf) (*cygwin_stat_fn)(path, buf)
|
||||
#define lstat(path, buf) (*cygwin_lstat_fn)(path, buf)
|
@ -1,4 +1,5 @@
|
||||
#include "../git-compat-util.h"
|
||||
#include "win32.h"
|
||||
#include "../strbuf.h"
|
||||
|
||||
unsigned int _CRT_fmode = _O_BINARY;
|
||||
@ -39,46 +40,19 @@ static int do_lstat(const char *file_name, struct stat *buf)
|
||||
{
|
||||
WIN32_FILE_ATTRIBUTE_DATA fdata;
|
||||
|
||||
if (GetFileAttributesExA(file_name, GetFileExInfoStandard, &fdata)) {
|
||||
int fMode = S_IREAD;
|
||||
if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
fMode |= S_IFDIR;
|
||||
else
|
||||
fMode |= S_IFREG;
|
||||
if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
|
||||
fMode |= S_IWRITE;
|
||||
|
||||
if (!(errno = get_file_attr(file_name, &fdata))) {
|
||||
buf->st_ino = 0;
|
||||
buf->st_gid = 0;
|
||||
buf->st_uid = 0;
|
||||
buf->st_nlink = 1;
|
||||
buf->st_mode = fMode;
|
||||
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
|
||||
buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */
|
||||
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
|
||||
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
|
||||
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
|
||||
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
|
||||
errno = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (GetLastError()) {
|
||||
case ERROR_ACCESS_DENIED:
|
||||
case ERROR_SHARING_VIOLATION:
|
||||
case ERROR_LOCK_VIOLATION:
|
||||
case ERROR_SHARING_BUFFER_EXCEEDED:
|
||||
errno = EACCES;
|
||||
break;
|
||||
case ERROR_BUFFER_OVERFLOW:
|
||||
errno = ENAMETOOLONG;
|
||||
break;
|
||||
case ERROR_NOT_ENOUGH_MEMORY:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
default:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -130,19 +104,11 @@ int mingw_fstat(int fd, struct stat *buf)
|
||||
return fstat(fd, buf);
|
||||
|
||||
if (GetFileInformationByHandle(fh, &fdata)) {
|
||||
int fMode = S_IREAD;
|
||||
if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
fMode |= S_IFDIR;
|
||||
else
|
||||
fMode |= S_IFREG;
|
||||
if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
|
||||
fMode |= S_IWRITE;
|
||||
|
||||
buf->st_ino = 0;
|
||||
buf->st_gid = 0;
|
||||
buf->st_uid = 0;
|
||||
buf->st_nlink = 1;
|
||||
buf->st_mode = fMode;
|
||||
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
|
||||
buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */
|
||||
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
|
||||
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
|
||||
|
34
compat/win32.h
Normal file
34
compat/win32.h
Normal file
@ -0,0 +1,34 @@
|
||||
/* common Win32 functions for MinGW and Cygwin */
|
||||
#include <windows.h>
|
||||
|
||||
static inline int file_attr_to_st_mode (DWORD attr)
|
||||
{
|
||||
int fMode = S_IREAD;
|
||||
if (attr & FILE_ATTRIBUTE_DIRECTORY)
|
||||
fMode |= S_IFDIR;
|
||||
else
|
||||
fMode |= S_IFREG;
|
||||
if (!(attr & FILE_ATTRIBUTE_READONLY))
|
||||
fMode |= S_IWRITE;
|
||||
return fMode;
|
||||
}
|
||||
|
||||
static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fdata)
|
||||
{
|
||||
if (GetFileAttributesExA(fname, GetFileExInfoStandard, fdata))
|
||||
return 0;
|
||||
|
||||
switch (GetLastError()) {
|
||||
case ERROR_ACCESS_DENIED:
|
||||
case ERROR_SHARING_VIOLATION:
|
||||
case ERROR_LOCK_VIOLATION:
|
||||
case ERROR_SHARING_BUFFER_EXCEEDED:
|
||||
return EACCES;
|
||||
case ERROR_BUFFER_OVERFLOW:
|
||||
return ENAMETOOLONG;
|
||||
case ERROR_NOT_ENOUGH_MEMORY:
|
||||
return ENOMEM;
|
||||
default:
|
||||
return ENOENT;
|
||||
}
|
||||
}
|
@ -80,6 +80,11 @@ int is_bare_repository(void)
|
||||
return is_bare_repository_cfg && !get_git_work_tree();
|
||||
}
|
||||
|
||||
int have_git_dir(void)
|
||||
{
|
||||
return !!git_dir;
|
||||
}
|
||||
|
||||
const char *get_git_dir(void)
|
||||
{
|
||||
if (!git_dir)
|
||||
|
@ -85,6 +85,7 @@
|
||||
#undef _XOPEN_SOURCE
|
||||
#include <grp.h>
|
||||
#define _XOPEN_SOURCE 600
|
||||
#include "compat/cygwin.h"
|
||||
#else
|
||||
#undef _ALL_SOURCE /* AIX 5.3L defines a struct list with _ALL_SOURCE. */
|
||||
#include <grp.h>
|
||||
|
Loading…
Reference in New Issue
Block a user