diff options
author | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2010-04-14 06:52:06 +0200 |
---|---|---|
committer | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2010-04-20 19:14:13 +0200 |
commit | 1712a701605d6599507bec1a2e88b7e28590c07a (patch) | |
tree | 3def65840b4c5d266c455d500d33cadbce00dee4 | |
parent | d32669a273676eaec45d55de35a2470f23035aca (diff) | |
download | busybox-w32-1712a701605d6599507bec1a2e88b7e28590c07a.tar.gz busybox-w32-1712a701605d6599507bec1a2e88b7e28590c07a.tar.bz2 busybox-w32-1712a701605d6599507bec1a2e88b7e28590c07a.zip |
win32: Replace stat/lstat
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
-rw-r--r-- | win32/mingw.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/win32/mingw.c b/win32/mingw.c index eede8ef6d..4721f89cb 100644 --- a/win32/mingw.c +++ b/win32/mingw.c | |||
@@ -149,6 +149,140 @@ FILE *mingw_fopen (const char *filename, const char *mode) | |||
149 | return fopen(filename, mode); | 149 | return fopen(filename, mode); |
150 | } | 150 | } |
151 | 151 | ||
152 | static inline time_t filetime_to_time_t(const FILETIME *ft) | ||
153 | { | ||
154 | long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime; | ||
155 | winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */ | ||
156 | winTime /= 10000000; /* Nano to seconds resolution */ | ||
157 | return (time_t)winTime; | ||
158 | } | ||
159 | |||
160 | static inline int file_attr_to_st_mode (DWORD attr) | ||
161 | { | ||
162 | int fMode = S_IREAD; | ||
163 | if (attr & FILE_ATTRIBUTE_DIRECTORY) | ||
164 | fMode |= S_IFDIR; | ||
165 | else | ||
166 | fMode |= S_IFREG; | ||
167 | if (!(attr & FILE_ATTRIBUTE_READONLY)) | ||
168 | fMode |= S_IWRITE; | ||
169 | return fMode; | ||
170 | } | ||
171 | |||
172 | static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fdata) | ||
173 | { | ||
174 | if (GetFileAttributesExA(fname, GetFileExInfoStandard, fdata)) | ||
175 | return 0; | ||
176 | |||
177 | switch (GetLastError()) { | ||
178 | case ERROR_ACCESS_DENIED: | ||
179 | case ERROR_SHARING_VIOLATION: | ||
180 | case ERROR_LOCK_VIOLATION: | ||
181 | case ERROR_SHARING_BUFFER_EXCEEDED: | ||
182 | return EACCES; | ||
183 | case ERROR_BUFFER_OVERFLOW: | ||
184 | return ENAMETOOLONG; | ||
185 | case ERROR_NOT_ENOUGH_MEMORY: | ||
186 | return ENOMEM; | ||
187 | default: | ||
188 | return ENOENT; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | /* We keep the do_lstat code in a separate function to avoid recursion. | ||
193 | * When a path ends with a slash, the stat will fail with ENOENT. In | ||
194 | * this case, we strip the trailing slashes and stat again. | ||
195 | */ | ||
196 | static int do_lstat(const char *file_name, struct stat *buf) | ||
197 | { | ||
198 | WIN32_FILE_ATTRIBUTE_DATA fdata; | ||
199 | |||
200 | if (!(errno = get_file_attr(file_name, &fdata))) { | ||
201 | int len = strlen(file_name); | ||
202 | |||
203 | buf->st_ino = 0; | ||
204 | buf->st_gid = 0; | ||
205 | buf->st_uid = 0; | ||
206 | buf->st_nlink = 1; | ||
207 | buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); | ||
208 | if (len > 4 && !strcmp(file_name+len-4, ".exe")) | ||
209 | buf->st_mode |= S_IEXEC; | ||
210 | buf->st_size = fdata.nFileSizeLow | | ||
211 | (((off64_t)fdata.nFileSizeHigh)<<32); | ||
212 | buf->st_dev = buf->st_rdev = 0; /* not used by Git */ | ||
213 | buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); | ||
214 | buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); | ||
215 | buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); | ||
216 | return 0; | ||
217 | } | ||
218 | return -1; | ||
219 | } | ||
220 | |||
221 | /* We provide our own lstat/fstat functions, since the provided | ||
222 | * lstat/fstat functions are so slow. These stat functions are | ||
223 | * tailored for Git's usage (read: fast), and are not meant to be | ||
224 | * complete. Note that Git stat()s are redirected to mingw_lstat() | ||
225 | * too, since Windows doesn't really handle symlinks that well. | ||
226 | */ | ||
227 | int mingw_lstat(const char *file_name, struct stat *buf) | ||
228 | { | ||
229 | int namelen; | ||
230 | static char alt_name[PATH_MAX]; | ||
231 | |||
232 | if (!do_lstat(file_name, buf)) | ||
233 | return 0; | ||
234 | |||
235 | /* if file_name ended in a '/', Windows returned ENOENT; | ||
236 | * try again without trailing slashes | ||
237 | */ | ||
238 | if (errno != ENOENT) | ||
239 | return -1; | ||
240 | |||
241 | namelen = strlen(file_name); | ||
242 | if (namelen && file_name[namelen-1] != '/') | ||
243 | return -1; | ||
244 | while (namelen && file_name[namelen-1] == '/') | ||
245 | --namelen; | ||
246 | if (!namelen || namelen >= PATH_MAX) | ||
247 | return -1; | ||
248 | |||
249 | memcpy(alt_name, file_name, namelen); | ||
250 | alt_name[namelen] = 0; | ||
251 | return do_lstat(alt_name, buf); | ||
252 | } | ||
253 | |||
254 | #undef fstat | ||
255 | int mingw_fstat(int fd, struct stat *buf) | ||
256 | { | ||
257 | HANDLE fh = (HANDLE)_get_osfhandle(fd); | ||
258 | BY_HANDLE_FILE_INFORMATION fdata; | ||
259 | |||
260 | if (fh == INVALID_HANDLE_VALUE) { | ||
261 | errno = EBADF; | ||
262 | return -1; | ||
263 | } | ||
264 | /* direct non-file handles to MS's fstat() */ | ||
265 | if (GetFileType(fh) != FILE_TYPE_DISK) | ||
266 | return _fstati64(fd, buf); | ||
267 | |||
268 | if (GetFileInformationByHandle(fh, &fdata)) { | ||
269 | buf->st_ino = 0; | ||
270 | buf->st_gid = 0; | ||
271 | buf->st_uid = 0; | ||
272 | buf->st_nlink = 1; | ||
273 | buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); | ||
274 | buf->st_size = fdata.nFileSizeLow | | ||
275 | (((off64_t)fdata.nFileSizeHigh)<<32); | ||
276 | buf->st_dev = buf->st_rdev = 0; /* not used by Git */ | ||
277 | buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); | ||
278 | buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); | ||
279 | buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); | ||
280 | return 0; | ||
281 | } | ||
282 | errno = EBADF; | ||
283 | return -1; | ||
284 | } | ||
285 | |||
152 | unsigned int sleep (unsigned int seconds) | 286 | unsigned int sleep (unsigned int seconds) |
153 | { | 287 | { |
154 | Sleep(seconds*1000); | 288 | Sleep(seconds*1000); |