2 #define WIN32_LEAN_AND_MEAN
3 #ifdef CYGWIN_V15_WIN32API
4 #include "../git-compat-util.h"
10 #include "../git-compat-util.h"
12 #include "../cache.h" /* to read configuration */
15 * Return POSIX permission bits, regardless of core.ignorecygwinfstricks
17 int cygwin_get_st_mode_bits(const char *path
, int *mode
)
20 if (lstat(path
, &st
) < 0)
26 static inline void filetime_to_timespec(const FILETIME
*ft
, struct timespec
*ts
)
28 long long winTime
= ((long long)ft
->dwHighDateTime
<< 32) +
30 winTime
-= 116444736000000000LL; /* Windows to Unix Epoch conversion */
31 /* convert 100-nsecond interval to seconds and nanoseconds */
32 ts
->tv_sec
= (time_t)(winTime
/10000000);
33 ts
->tv_nsec
= (long)(winTime
- ts
->tv_sec
*10000000LL) * 100;
36 #define size_to_blocks(s) (((s)+511)/512)
38 /* do_stat is a common implementation for cygwin_lstat and cygwin_stat.
40 * To simplify its logic, in the case of cygwin symlinks, this implementation
41 * falls back to the cygwin version of stat/lstat, which is provided as the
44 static int do_stat(const char *file_name
, struct stat
*buf
, stat_fn_t cygstat
)
46 WIN32_FILE_ATTRIBUTE_DATA fdata
;
48 if (file_name
[0] == '/')
49 return cygstat (file_name
, buf
);
51 if (!(errno
= get_file_attr(file_name
, &fdata
))) {
53 * If the system attribute is set and it is not a directory then
54 * it could be a symbol link created in the nowinsymlinks mode.
55 * Normally, Cygwin works in the winsymlinks mode, so this situation
56 * is very unlikely. For the sake of simplicity of our code, let's
57 * Cygwin to handle it.
59 if ((fdata
.dwFileAttributes
& FILE_ATTRIBUTE_SYSTEM
) &&
60 !(fdata
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
61 return cygstat(file_name
, buf
);
63 /* fill out the stat structure */
64 buf
->st_dev
= buf
->st_rdev
= 0; /* not used by Git */
66 buf
->st_mode
= file_attr_to_st_mode(fdata
.dwFileAttributes
);
68 buf
->st_uid
= buf
->st_gid
= 0;
69 #ifdef __CYGWIN_USE_BIG_TYPES__
70 buf
->st_size
= ((_off64_t
)fdata
.nFileSizeHigh
<< 32) +
73 buf
->st_size
= (off_t
)fdata
.nFileSizeLow
;
75 buf
->st_blocks
= size_to_blocks(buf
->st_size
);
76 filetime_to_timespec(&fdata
.ftLastAccessTime
, &buf
->st_atim
);
77 filetime_to_timespec(&fdata
.ftLastWriteTime
, &buf
->st_mtim
);
78 filetime_to_timespec(&fdata
.ftCreationTime
, &buf
->st_ctim
);
80 } else if (errno
== ENOENT
) {
82 * In the winsymlinks mode (which is the default), Cygwin
83 * emulates symbol links using Windows shortcut files. These
84 * files are formed by adding .lnk extension. So, if we have
85 * not found the specified file name, it could be that it is
86 * a symbol link. Let's Cygwin to deal with that.
88 return cygstat(file_name
, buf
);
93 /* We provide our own lstat/stat functions, since the provided Cygwin versions
94 * of these functions are too slow. These stat functions are tailored for Git's
95 * usage, and therefore they are not meant to be complete and correct emulation
96 * of lstat/stat functionality.
98 static int cygwin_lstat(const char *path
, struct stat
*buf
)
100 return do_stat(path
, buf
, lstat
);
103 static int cygwin_stat(const char *path
, struct stat
*buf
)
105 return do_stat(path
, buf
, stat
);
110 * At start up, we are trying to determine whether Win32 API or cygwin stat
111 * functions should be used. The choice is determined by core.ignorecygwinfstricks.
112 * Reading this option is not always possible immediately as git_dir may
113 * not be set yet. So until it is set, use cygwin lstat/stat functions.
114 * However, if core.filemode is set, we must use the Cygwin posix
115 * stat/lstat as the Windows stat functions do not determine posix filemode.
117 * Note that git_cygwin_config() does NOT call git_default_config() and this
118 * is deliberate. Many commands read from config to establish initial
119 * values in variables and later tweak them from elsewhere (e.g. command line).
120 * init_stat() is called lazily on demand, typically much late in the program,
121 * and calling git_default_config() from here would break such variables.
123 static int native_stat
= 1;
124 static int core_filemode
= 1; /* matches trust_executable_bit default */
126 static int git_cygwin_config(const char *var
, const char *value
, void *cb
)
128 if (!strcmp(var
, "core.ignorecygwinfstricks"))
129 native_stat
= git_config_bool(var
, value
);
130 else if (!strcmp(var
, "core.filemode"))
131 core_filemode
= git_config_bool(var
, value
);
135 static int init_stat(void)
137 if (have_git_dir() && git_config(git_cygwin_config
,NULL
)) {
138 if (!core_filemode
&& native_stat
) {
139 cygwin_stat_fn
= cygwin_stat
;
140 cygwin_lstat_fn
= cygwin_lstat
;
142 cygwin_stat_fn
= stat
;
143 cygwin_lstat_fn
= lstat
;
150 static int cygwin_stat_stub(const char *file_name
, struct stat
*buf
)
152 return (init_stat() ? stat
: *cygwin_stat_fn
)(file_name
, buf
);
155 static int cygwin_lstat_stub(const char *file_name
, struct stat
*buf
)
157 return (init_stat() ? lstat
: *cygwin_lstat_fn
)(file_name
, buf
);
160 stat_fn_t cygwin_stat_fn
= cygwin_stat_stub
;
161 stat_fn_t cygwin_lstat_fn
= cygwin_lstat_stub
;