Merge branch 'rebase-p-first-parent' into devel
[git/mingw/j6t.git] / test-stat.c
blobe3be5756626581994711ff0c65a729acaede3d59
1 #include <sys/stat.h>
2 #include <time.h>
3 #include <stdio.h>
5 #ifdef EMULATE
6 #define HINT fprintf(stderr, "emulated stat\n")
7 #include <errno.h>
8 #include <windows.h>
9 #include <unistd.h>
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)
20 #define PATH_MAX 260
22 static inline int file_attr_to_st_mode (DWORD attr)
24 int fMode = S_IREAD;
25 if (attr & FILE_ATTRIBUTE_DIRECTORY)
26 fMode |= S_IFDIR;
27 else
28 fMode |= S_IFREG;
29 if (!(attr & FILE_ATTRIBUTE_READONLY))
30 fMode |= S_IWRITE;
31 return fMode;
34 static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fdata)
36 if (GetFileAttributesExA(fname, GetFileExInfoStandard, fdata))
37 return 0;
39 switch (GetLastError()) {
40 case ERROR_ACCESS_DENIED:
41 case ERROR_SHARING_VIOLATION:
42 case ERROR_LOCK_VIOLATION:
43 case ERROR_SHARING_BUFFER_EXCEEDED:
44 return EACCES;
45 case ERROR_BUFFER_OVERFLOW:
46 return ENAMETOOLONG;
47 case ERROR_NOT_ENOUGH_MEMORY:
48 return ENOMEM;
49 default:
50 return ENOENT;
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))) {
71 buf->st_ino = 0;
72 buf->st_gid = 0;
73 buf->st_uid = 0;
74 buf->st_nlink = 1;
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));
81 return 0;
83 return -1;
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)
94 int namelen;
95 static char alt_name[PATH_MAX];
97 if (!do_lstat(file_name, buf))
98 return 0;
100 /* if file_name ended in a '/', Windows returned ENOENT;
101 * try again without trailing slashes
103 if (errno != ENOENT)
104 return -1;
106 namelen = strlen(file_name);
107 if (namelen && file_name[namelen-1] != '/')
108 return -1;
109 while (namelen && file_name[namelen-1] == '/')
110 --namelen;
111 if (!namelen || namelen >= PATH_MAX)
112 return -1;
114 memcpy(alt_name, file_name, namelen);
115 alt_name[namelen] = 0;
116 return do_lstat(alt_name, buf);
119 #undef fstat
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) {
126 errno = EBADF;
127 return -1;
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)) {
134 buf->st_ino = 0;
135 buf->st_gid = 0;
136 buf->st_uid = 0;
137 buf->st_nlink = 1;
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));
144 return 0;
146 errno = EBADF;
147 return -1;
150 #else
151 #define HINT (void)0
152 #endif
154 int main(int argc, char**argv)
156 int i;
157 int err = 0;
158 HINT;
159 for (i = 1; i < argc; i++)
161 struct stat st;
162 if (stat(argv[i], &st)) {
163 perror(argv[i]);
164 err = 1;
165 continue;
167 printf("%s: %s\n", argv[i], ctime(&st.st_mtime));
169 return err;