Merge tag 'gitgui-0.18.0' of git://repo.or.cz/git-gui
[git] / compat / cygwin.c
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