6 #define HINT fprintf(stderr, "emulated stat\n")
11 /* Use mingw_lstat() instead of lstat()/stat() and
12 * mingw_fstat() instead of fstat() on Windows.
14 int mingw_lstat(const char *file_name
, struct stat
*buf
);
15 int mingw_fstat(int fd
, struct stat
*buf
);
16 #define fstat mingw_fstat
17 #define lstat mingw_lstat
18 #define stat(x,y) mingw_lstat(x,y)
22 static inline int file_attr_to_st_mode (DWORD attr
)
25 if (attr
& FILE_ATTRIBUTE_DIRECTORY
)
29 if (!(attr
& FILE_ATTRIBUTE_READONLY
))
34 static inline int get_file_attr(const char *fname
, WIN32_FILE_ATTRIBUTE_DATA
*fdata
)
36 if (GetFileAttributesExA(fname
, GetFileExInfoStandard
, fdata
))
39 switch (GetLastError()) {
40 case ERROR_ACCESS_DENIED
:
41 case ERROR_SHARING_VIOLATION
:
42 case ERROR_LOCK_VIOLATION
:
43 case ERROR_SHARING_BUFFER_EXCEEDED
:
45 case ERROR_BUFFER_OVERFLOW
:
47 case ERROR_NOT_ENOUGH_MEMORY
:
54 static inline time_t filetime_to_time_t(const FILETIME
*ft
)
56 long long winTime
= ((long long)ft
->dwHighDateTime
<< 32) + ft
->dwLowDateTime
;
57 winTime
-= 116444736000000000LL; /* Windows to Unix Epoch conversion */
58 winTime
/= 10000000; /* Nano to seconds resolution */
59 return (time_t)winTime
;
62 /* We keep the do_lstat code in a separate function to avoid recursion.
63 * When a path ends with a slash, the stat will fail with ENOENT. In
64 * this case, we strip the trailing slashes and stat again.
66 static int do_lstat(const char *file_name
, struct stat
*buf
)
68 WIN32_FILE_ATTRIBUTE_DATA fdata
;
70 if (!(errno
= get_file_attr(file_name
, &fdata
))) {
75 buf
->st_mode
= file_attr_to_st_mode(fdata
.dwFileAttributes
);
76 buf
->st_size
= fdata
.nFileSizeLow
; /* Can't use nFileSizeHigh, since it's not a stat64 */
77 buf
->st_dev
= buf
->st_rdev
= 0; /* not used by Git */
78 buf
->st_atime
= filetime_to_time_t(&(fdata
.ftLastAccessTime
));
79 buf
->st_mtime
= filetime_to_time_t(&(fdata
.ftLastWriteTime
));
80 buf
->st_ctime
= filetime_to_time_t(&(fdata
.ftCreationTime
));
86 /* We provide our own lstat/fstat functions, since the provided
87 * lstat/fstat functions are so slow. These stat functions are
88 * tailored for Git's usage (read: fast), and are not meant to be
89 * complete. Note that Git stat()s are redirected to mingw_lstat()
90 * too, since Windows doesn't really handle symlinks that well.
92 int mingw_lstat(const char *file_name
, struct stat
*buf
)
95 static char alt_name
[PATH_MAX
];
97 if (!do_lstat(file_name
, buf
))
100 /* if file_name ended in a '/', Windows returned ENOENT;
101 * try again without trailing slashes
106 namelen
= strlen(file_name
);
107 if (namelen
&& file_name
[namelen
-1] != '/')
109 while (namelen
&& file_name
[namelen
-1] == '/')
111 if (!namelen
|| namelen
>= PATH_MAX
)
114 memcpy(alt_name
, file_name
, namelen
);
115 alt_name
[namelen
] = 0;
116 return do_lstat(alt_name
, buf
);
120 int mingw_fstat(int fd
, struct stat
*buf
)
122 HANDLE fh
= (HANDLE
)_get_osfhandle(fd
);
123 BY_HANDLE_FILE_INFORMATION fdata
;
125 if (fh
== INVALID_HANDLE_VALUE
) {
129 /* direct non-file handles to MS's fstat() */
130 if (GetFileType(fh
) != FILE_TYPE_DISK
)
131 return fstat(fd
, buf
);
133 if (GetFileInformationByHandle(fh
, &fdata
)) {
138 buf
->st_mode
= file_attr_to_st_mode(fdata
.dwFileAttributes
);
139 buf
->st_size
= fdata
.nFileSizeLow
; /* Can't use nFileSizeHigh, since it's not a stat64 */
140 buf
->st_dev
= buf
->st_rdev
= 0; /* not used by Git */
141 buf
->st_atime
= filetime_to_time_t(&(fdata
.ftLastAccessTime
));
142 buf
->st_mtime
= filetime_to_time_t(&(fdata
.ftLastWriteTime
));
143 buf
->st_ctime
= filetime_to_time_t(&(fdata
.ftCreationTime
));
154 int main(int argc
, char**argv
)
159 for (i
= 1; i
< argc
; i
++)
162 if (stat(argv
[i
], &st
)) {
167 printf("%s: %s\n", argv
[i
], ctime(&st
.st_mtime
));