Merge branch 'jc/t5551-posix-sed-bre' into maint
[git] / compat / cygwin.c
1 #define CYGWIN_C
2 #define WIN32_LEAN_AND_MEAN
3 #ifdef CYGWIN_V15_WIN32API
4 #include "../git-compat-util.h"
5 #include "win32.h"
6 #else
7 #include <sys/stat.h>
8 #include <sys/errno.h>
9 #include "win32.h"
10 #include "../git-compat-util.h"
11 #endif
12 #include "../cache.h" /* to read configuration */
13
14 /*
15  * Return POSIX permission bits, regardless of core.ignorecygwinfstricks
16  */
17 int cygwin_get_st_mode_bits(const char *path, int *mode)
18 {
19         struct stat st;
20         if (lstat(path, &st) < 0)
21                 return -1;
22         *mode = st.st_mode;
23         return 0;
24 }
25
26 static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
27 {
28         long long winTime = ((long long)ft->dwHighDateTime << 32) +
29                         ft->dwLowDateTime;
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;
34 }
35
36 #define size_to_blocks(s) (((s)+511)/512)
37
38 /* do_stat is a common implementation for cygwin_lstat and cygwin_stat.
39  *
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
42  * last argument.
43  */
44 static int do_stat(const char *file_name, struct stat *buf, stat_fn_t cygstat)
45 {
46         WIN32_FILE_ATTRIBUTE_DATA fdata;
47
48         if (file_name[0] == '/')
49                 return cygstat (file_name, buf);
50
51         if (!(errno = get_file_attr(file_name, &fdata))) {
52                 /*
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.
58                  */
59                 if ((fdata.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) &&
60                     !(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
61                         return cygstat(file_name, buf);
62
63                 /* fill out the stat structure */
64                 buf->st_dev = buf->st_rdev = 0; /* not used by Git */
65                 buf->st_ino = 0;
66                 buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
67                 buf->st_nlink = 1;
68                 buf->st_uid = buf->st_gid = 0;
69 #ifdef __CYGWIN_USE_BIG_TYPES__
70                 buf->st_size = ((_off64_t)fdata.nFileSizeHigh << 32) +
71                         fdata.nFileSizeLow;
72 #else
73                 buf->st_size = (off_t)fdata.nFileSizeLow;
74 #endif
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);
79                 return 0;
80         } else if (errno == ENOENT) {
81                 /*
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.
87                  */
88                 return cygstat(file_name, buf);
89         }
90         return -1;
91 }
92
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.
97  */
98 static int cygwin_lstat(const char *path, struct stat *buf)
99 {
100         return do_stat(path, buf, lstat);
101 }
102
103 static int cygwin_stat(const char *path, struct stat *buf)
104 {
105         return do_stat(path, buf, stat);
106 }
107
108
109 /*
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.
116  *
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.
122  */
123 static int native_stat = 1;
124 static int core_filemode = 1; /* matches trust_executable_bit default */
125
126 static int git_cygwin_config(const char *var, const char *value, void *cb)
127 {
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);
132         return 0;
133 }
134
135 static int init_stat(void)
136 {
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;
141                 } else {
142                         cygwin_stat_fn = stat;
143                         cygwin_lstat_fn = lstat;
144                 }
145                 return 0;
146         }
147         return 1;
148 }
149
150 static int cygwin_stat_stub(const char *file_name, struct stat *buf)
151 {
152         return (init_stat() ? stat : *cygwin_stat_fn)(file_name, buf);
153 }
154
155 static int cygwin_lstat_stub(const char *file_name, struct stat *buf)
156 {
157         return (init_stat() ? lstat : *cygwin_lstat_fn)(file_name, buf);
158 }
159
160 stat_fn_t cygwin_stat_fn = cygwin_stat_stub;
161 stat_fn_t cygwin_lstat_fn = cygwin_lstat_stub;
162