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