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