Skip to content

Commit cb1b350

Browse files
committed
Merge branch 'fscache'
2 parents 8cf7cc7 + e6eb0f7 commit cb1b350

File tree

16 files changed

+748
-91
lines changed

16 files changed

+748
-91
lines changed

Documentation/config.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,18 @@ relatively high IO latencies. When enabled, Git will do the
909909
index comparison to the filesystem data in parallel, allowing
910910
overlapping IO's. Defaults to true.
911911

912+
core.fscache::
913+
Enable additional caching of file system data for some operations.
914+
+
915+
Git for Windows uses this to bulk-read and cache lstat data of entire
916+
directories (instead of doing lstat file by file).
917+
918+
core.unsetenvvars::
919+
EXPERIMENTAL, Windows-only: comma-separated list of environment
920+
variables' names that need to be unset before spawning any other
921+
process. Defaults to `PERL5LIB` to account for the fact that Git
922+
for Windows insists on using its own Perl interpreter.
923+
912924
core.createObject::
913925
You can set this to 'link', in which case a hardlink followed by
914926
a delete of the source are used to make sure that object creation

builtin/commit.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,6 +1355,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
13551355
PATHSPEC_PREFER_FULL,
13561356
prefix, argv);
13571357

1358+
enable_fscache(1);
13581359
read_cache_preload(&s.pathspec);
13591360
refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &s.pathspec, NULL, NULL);
13601361

cache.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -901,14 +901,6 @@ int use_optional_locks(void);
901901
extern char comment_line_char;
902902
extern int auto_comment_line_char;
903903

904-
/* Windows only */
905-
enum hide_dotfiles_type {
906-
HIDE_DOTFILES_FALSE = 0,
907-
HIDE_DOTFILES_TRUE,
908-
HIDE_DOTFILES_DOTGITONLY
909-
};
910-
extern enum hide_dotfiles_type hide_dotfiles;
911-
912904
enum log_refs_config {
913905
LOG_REFS_UNSET = -1,
914906
LOG_REFS_NONE = 0,

compat/mingw.c

Lines changed: 65 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "../strbuf.h"
66
#include "../run-command.h"
77
#include "../cache.h"
8+
#include "../config.h"
89

910
#define HCAST(type, handle) ((type)(intptr_t)handle)
1011

@@ -202,6 +203,41 @@ static int ask_yes_no_if_possible(const char *format, ...)
202203
}
203204
}
204205

206+
/* Windows only */
207+
enum hide_dotfiles_type {
208+
HIDE_DOTFILES_FALSE = 0,
209+
HIDE_DOTFILES_TRUE,
210+
HIDE_DOTFILES_DOTGITONLY
211+
};
212+
213+
static enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
214+
static char *unset_environment_variables;
215+
int core_fscache;
216+
217+
int mingw_core_config(const char *var, const char *value, void *cb)
218+
{
219+
if (!strcmp(var, "core.hidedotfiles")) {
220+
if (value && !strcasecmp(value, "dotgitonly"))
221+
hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
222+
else
223+
hide_dotfiles = git_config_bool(var, value);
224+
return 0;
225+
}
226+
227+
if (!strcmp(var, "core.fscache")) {
228+
core_fscache = git_config_bool(var, value);
229+
return 0;
230+
}
231+
232+
if (!strcmp(var, "core.unsetenvvars")) {
233+
free(unset_environment_variables);
234+
unset_environment_variables = xstrdup(value);
235+
return 0;
236+
}
237+
238+
return 0;
239+
}
240+
205241
/* Normalizes NT paths as returned by some low-level APIs. */
206242
static wchar_t *normalize_ntpath(wchar_t *wbuf)
207243
{
@@ -576,24 +612,6 @@ int mingw_chmod(const char *filename, int mode)
576612
return _wchmod(wfilename, mode);
577613
}
578614

579-
/*
580-
* The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
581-
* Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
582-
*/
583-
static inline long long filetime_to_hnsec(const FILETIME *ft)
584-
{
585-
long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
586-
/* Windows to Unix Epoch conversion */
587-
return winTime - 116444736000000000LL;
588-
}
589-
590-
static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
591-
{
592-
long long hnsec = filetime_to_hnsec(ft);
593-
ts->tv_sec = (time_t)(hnsec / 10000000);
594-
ts->tv_nsec = (hnsec % 10000000) * 100;
595-
}
596-
597615
/**
598616
* Verifies that safe_create_leading_directories() would succeed.
599617
*/
@@ -733,6 +751,8 @@ static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
733751
return do_lstat(follow, alt_name, buf);
734752
}
735753

754+
int (*lstat)(const char *file_name, struct stat *buf) = mingw_lstat;
755+
736756
static int get_file_info_by_handle(HANDLE hnd, struct stat *buf)
737757
{
738758
BY_HANDLE_FILE_INFORMATION fdata;
@@ -1227,6 +1247,27 @@ static wchar_t *make_environment_block(char **deltaenv)
12271247
return result;
12281248
}
12291249

1250+
static void do_unset_environment_variables(void)
1251+
{
1252+
static int done;
1253+
char *p = unset_environment_variables;
1254+
1255+
if (done || !p)
1256+
return;
1257+
done = 1;
1258+
1259+
for (;;) {
1260+
char *comma = strchr(p, ',');
1261+
1262+
if (comma)
1263+
*comma = '\0';
1264+
unsetenv(p);
1265+
if (!comma)
1266+
break;
1267+
p = comma + 1;
1268+
}
1269+
}
1270+
12301271
struct pinfo_t {
12311272
struct pinfo_t *next;
12321273
pid_t pid;
@@ -1245,9 +1286,12 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
12451286
wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs, *wenvblk = NULL;
12461287
unsigned flags = CREATE_UNICODE_ENVIRONMENT;
12471288
BOOL ret;
1289+
HANDLE cons;
1290+
1291+
do_unset_environment_variables();
12481292

12491293
/* Determine whether or not we are associated to a console */
1250-
HANDLE cons = CreateFile("CONOUT$", GENERIC_WRITE,
1294+
cons = CreateFile("CONOUT$", GENERIC_WRITE,
12511295
FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
12521296
FILE_ATTRIBUTE_NORMAL, NULL);
12531297
if (cons == INVALID_HANDLE_VALUE) {
@@ -2476,6 +2520,8 @@ int wmain(int argc, const wchar_t **wargv)
24762520
/* fix Windows specific environment settings */
24772521
setup_windows_environment();
24782522

2523+
unset_environment_variables = xstrdup("PERL5LIB");
2524+
24792525
/* initialize critical section for waitpid pinfo_t list */
24802526
InitializeCriticalSection(&pinfo_cs);
24812527

compat/mingw.h

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ typedef _sigset_t sigset_t;
1111
#undef _POSIX_THREAD_SAFE_FUNCTIONS
1212
#endif
1313

14+
extern int core_fscache;
15+
16+
extern int mingw_core_config(const char *var, const char *value, void *cb);
17+
#define platform_core_config mingw_core_config
18+
1419
/*
1520
* things that are not available in header files
1621
*/
@@ -350,6 +355,17 @@ static inline int getrlimit(int resource, struct rlimit *rlp)
350355
return 0;
351356
}
352357

358+
/*
359+
* The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
360+
* Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
361+
*/
362+
static inline long long filetime_to_hnsec(const FILETIME *ft)
363+
{
364+
long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
365+
/* Windows to Unix Epoch conversion */
366+
return winTime - 116444736000000000LL;
367+
}
368+
353369
/*
354370
* Use mingw specific stat()/lstat()/fstat() implementations on Windows,
355371
* including our own struct stat with 64 bit st_size and nanosecond-precision
@@ -366,6 +382,13 @@ struct timespec {
366382
#endif
367383
#endif
368384

385+
static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
386+
{
387+
long long hnsec = filetime_to_hnsec(ft);
388+
ts->tv_sec = (time_t)(hnsec / 10000000);
389+
ts->tv_nsec = (hnsec % 10000000) * 100;
390+
}
391+
369392
struct mingw_stat {
370393
_dev_t st_dev;
371394
_ino_t st_ino;
@@ -398,7 +421,7 @@ int mingw_fstat(int fd, struct stat *buf);
398421
#ifdef lstat
399422
#undef lstat
400423
#endif
401-
#define lstat mingw_lstat
424+
extern int (*lstat)(const char *file_name, struct stat *buf);
402425

403426

404427
int mingw_utime(const char *file_name, const struct utimbuf *times);
@@ -432,6 +455,9 @@ int mingw_raise(int sig);
432455
int winansi_isatty(int fd);
433456
#define isatty winansi_isatty
434457

458+
int winansi_dup2(int oldfd, int newfd);
459+
#define dup2 winansi_dup2
460+
435461
void winansi_init(void);
436462
HANDLE winansi_get_osfhandle(int fd);
437463

compat/win32/dirent.c

Lines changed: 47 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
#include "../../git-compat-util.h"
22

3-
struct DIR {
3+
typedef struct dirent_DIR {
4+
struct DIR base_dir; /* extend base struct DIR */
45
struct dirent dd_dir; /* includes d_type */
56
HANDLE dd_handle; /* FindFirstFile handle */
67
int dd_stat; /* 0-based index */
7-
};
8+
char dd_name[MAX_PATH * 3]; /* file name (* 3 for UTF-8 conversion) */
9+
} dirent_DIR;
10+
11+
DIR *(*opendir)(const char *dirname) = dirent_opendir;
812

913
static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAW *fdata)
1014
{
11-
/* convert UTF-16 name to UTF-8 */
12-
xwcstoutf(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
15+
/* convert UTF-16 name to UTF-8 (d_name points to dirent_DIR.dd_name) */
16+
xwcstoutf(ent->d_name, fdata->cFileName, MAX_PATH * 3);
1317

1418
/* Set file type, based on WIN32_FIND_DATA */
1519
if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
@@ -18,41 +22,7 @@ static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAW *fdata)
1822
ent->d_type = DT_REG;
1923
}
2024

21-
DIR *opendir(const char *name)
22-
{
23-
wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */
24-
WIN32_FIND_DATAW fdata;
25-
HANDLE h;
26-
int len;
27-
DIR *dir;
28-
29-
/* convert name to UTF-16 and check length < MAX_PATH */
30-
if ((len = xutftowcs_path(pattern, name)) < 0)
31-
return NULL;
32-
33-
/* append optional '/' and wildcard '*' */
34-
if (len && !is_dir_sep(pattern[len - 1]))
35-
pattern[len++] = '/';
36-
pattern[len++] = '*';
37-
pattern[len] = 0;
38-
39-
/* open find handle */
40-
h = FindFirstFileW(pattern, &fdata);
41-
if (h == INVALID_HANDLE_VALUE) {
42-
DWORD err = GetLastError();
43-
errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
44-
return NULL;
45-
}
46-
47-
/* initialize DIR structure and copy first dir entry */
48-
dir = xmalloc(sizeof(DIR));
49-
dir->dd_handle = h;
50-
dir->dd_stat = 0;
51-
finddata2dirent(&dir->dd_dir, &fdata);
52-
return dir;
53-
}
54-
55-
struct dirent *readdir(DIR *dir)
25+
static struct dirent *dirent_readdir(dirent_DIR *dir)
5626
{
5727
if (!dir) {
5828
errno = EBADF; /* No set_errno for mingw */
@@ -79,7 +49,7 @@ struct dirent *readdir(DIR *dir)
7949
return &dir->dd_dir;
8050
}
8151

82-
int closedir(DIR *dir)
52+
static int dirent_closedir(dirent_DIR *dir)
8353
{
8454
if (!dir) {
8555
errno = EBADF;
@@ -90,3 +60,40 @@ int closedir(DIR *dir)
9060
free(dir);
9161
return 0;
9262
}
63+
64+
DIR *dirent_opendir(const char *name)
65+
{
66+
wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */
67+
WIN32_FIND_DATAW fdata;
68+
HANDLE h;
69+
int len;
70+
dirent_DIR *dir;
71+
72+
/* convert name to UTF-16 and check length < MAX_PATH */
73+
if ((len = xutftowcs_path(pattern, name)) < 0)
74+
return NULL;
75+
76+
/* append optional '/' and wildcard '*' */
77+
if (len && !is_dir_sep(pattern[len - 1]))
78+
pattern[len++] = '/';
79+
pattern[len++] = '*';
80+
pattern[len] = 0;
81+
82+
/* open find handle */
83+
h = FindFirstFileW(pattern, &fdata);
84+
if (h == INVALID_HANDLE_VALUE) {
85+
DWORD err = GetLastError();
86+
errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
87+
return NULL;
88+
}
89+
90+
/* initialize DIR structure and copy first dir entry */
91+
dir = xmalloc(sizeof(dirent_DIR));
92+
dir->base_dir.preaddir = (struct dirent *(*)(DIR *dir)) dirent_readdir;
93+
dir->base_dir.pclosedir = (int (*)(DIR *dir)) dirent_closedir;
94+
dir->dd_dir.d_name = dir->dd_name;
95+
dir->dd_handle = h;
96+
dir->dd_stat = 0;
97+
finddata2dirent(&dir->dd_dir, &fdata);
98+
return (DIR*) dir;
99+
}

compat/win32/dirent.h

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,32 @@
11
#ifndef DIRENT_H
22
#define DIRENT_H
33

4-
typedef struct DIR DIR;
5-
64
#define DT_UNKNOWN 0
75
#define DT_DIR 1
86
#define DT_REG 2
97
#define DT_LNK 3
108

119
struct dirent {
12-
unsigned char d_type; /* file type to prevent lstat after readdir */
13-
char d_name[MAX_PATH * 3]; /* file name (* 3 for UTF-8 conversion) */
10+
unsigned char d_type; /* file type to prevent lstat after readdir */
11+
char *d_name; /* file name */
1412
};
1513

16-
DIR *opendir(const char *dirname);
17-
struct dirent *readdir(DIR *dir);
18-
int closedir(DIR *dir);
14+
/*
15+
* Base DIR structure, contains pointers to readdir/closedir implementations so
16+
* that opendir may choose a concrete implementation on a call-by-call basis.
17+
*/
18+
typedef struct DIR {
19+
struct dirent *(*preaddir)(struct DIR *dir);
20+
int (*pclosedir)(struct DIR *dir);
21+
} DIR;
22+
23+
/* default dirent implementation */
24+
extern DIR *dirent_opendir(const char *dirname);
25+
26+
/* current dirent implementation */
27+
extern DIR *(*opendir)(const char *dirname);
28+
29+
#define readdir(dir) (dir->preaddir(dir))
30+
#define closedir(dir) (dir->pclosedir(dir))
1931

2032
#endif /* DIRENT_H */

0 commit comments

Comments
 (0)