1#define WIN32_LEAN_AND_MEAN 2#ifdef CYGWIN_V15_WIN32API 3#include"../git-compat-util.h" 4#include"win32.h" 5#else 6#include <sys/stat.h> 7#include <sys/errno.h> 8#include"win32.h" 9#include"../git-compat-util.h" 10#endif 11#include"../cache.h"/* to read configuration */ 12 13staticinlinevoidfiletime_to_timespec(const FILETIME *ft,struct timespec *ts) 14{ 15long 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 intdo_stat(const char*file_name,struct stat *buf, stat_fn_t cygstat) 32{ 33 WIN32_FILE_ATTRIBUTE_DATA fdata; 34 35if(file_name[0] =='/') 36returncygstat(file_name, buf); 37 38if(!(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 */ 46if((fdata.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) && 47!(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) 48returncygstat(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); 63filetime_to_timespec(&fdata.ftLastAccessTime, &buf->st_atim); 64filetime_to_timespec(&fdata.ftLastWriteTime, &buf->st_mtim); 65filetime_to_timespec(&fdata.ftCreationTime, &buf->st_ctim); 66return0; 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 */ 75returncygstat(file_name, buf); 76} 77return-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 intcygwin_lstat(const char*path,struct stat *buf) 86{ 87returndo_stat(path, buf, lstat); 88} 89 90static intcygwin_stat(const char*path,struct stat *buf) 91{ 92returndo_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. 99 * Reading this option is not always possible immediately as git_dir may 100 * not be set yet. So until it is set, use cygwin lstat/stat functions. 101 * However, if core.filemode is set, we must use the Cygwin posix 102 * stat/lstat as the Windows stat functions do not determine posix filemode. 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. 109 */ 110static int native_stat =1; 111static int core_filemode =1;/* matches trust_executable_bit default */ 112 113static intgit_cygwin_config(const char*var,const char*value,void*cb) 114{ 115if(!strcmp(var,"core.ignorecygwinfstricks")) 116 native_stat =git_config_bool(var, value); 117else if(!strcmp(var,"core.filemode")) 118 core_filemode =git_config_bool(var, value); 119return0; 120} 121 122static intinit_stat(void) 123{ 124if(have_git_dir() &&git_config(git_cygwin_config,NULL)) { 125if(!core_filemode && native_stat) { 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} 132return0; 133} 134return1; 135} 136 137static intcygwin_stat_stub(const char*file_name,struct stat *buf) 138{ 139return(init_stat() ? stat : *cygwin_stat_fn)(file_name, buf); 140} 141 142static intcygwin_lstat_stub(const char*file_name,struct stat *buf) 143{ 144return(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