]>
Commit | Line | Data |
---|---|---|
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 | ||
13 | static 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 | */ | |
31 | static 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 | */ | |
85 | static int cygwin_lstat(const char *path, struct stat *buf) | |
86 | { | |
87 | return do_stat(path, buf, lstat); | |
88 | } | |
89 | ||
90 | static 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 | */ |
110 | static int native_stat = 1; | |
085479e7 | 111 | static int core_filemode = 1; /* matches trust_executable_bit default */ |
adbc0b6b DP |
112 | |
113 | static 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 | ||
122 | static 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 | ||
137 | static 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 | ||
142 | static 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 | ||
147 | stat_fn_t cygwin_stat_fn = cygwin_stat_stub; | |
148 | stat_fn_t cygwin_lstat_fn = cygwin_lstat_stub; | |
149 |