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-09-10 19:28:25 +1000 |
commit | 20f590615177543c0d52959516c7984e48397c9b (patch) | |
tree | 65dc276ee72156923842298cdfb872009a3384a7 | |
parent | 3d88e4b6c9d3bb7b5eb75575049ed6d06f47bcd9 (diff) | |
download | busybox-w32-20f590615177543c0d52959516c7984e48397c9b.tar.gz busybox-w32-20f590615177543c0d52959516c7984e48397c9b.tar.bz2 busybox-w32-20f590615177543c0d52959516c7984e48397c9b.zip |
win32: Replace stat/lstat
-rw-r--r-- | include/mingw.h | 12 | ||||
-rw-r--r-- | win32/mingw.c | 134 |
2 files changed, 145 insertions, 1 deletions
diff --git a/include/mingw.h b/include/mingw.h index ba73c362e..a828bd835 100644 --- a/include/mingw.h +++ b/include/mingw.h | |||
@@ -207,8 +207,18 @@ NOIMPL(fchmod,int fildes UNUSED_PARAM, mode_t mode UNUSED_PARAM); | |||
207 | NOIMPL(fchown,int fd UNUSED_PARAM, uid_t uid UNUSED_PARAM, gid_t gid UNUSED_PARAM); | 207 | NOIMPL(fchown,int fd UNUSED_PARAM, uid_t uid UNUSED_PARAM, gid_t gid UNUSED_PARAM); |
208 | int mingw_mkdir(const char *path, int mode); | 208 | int mingw_mkdir(const char *path, int mode); |
209 | 209 | ||
210 | /* Use mingw_lstat() instead of lstat()/stat() and | ||
211 | * mingw_fstat() instead of fstat() on Windows. | ||
212 | */ | ||
213 | int mingw_lstat(const char *file_name, struct stat *buf); | ||
214 | int mingw_fstat(int fd, struct stat *buf); | ||
215 | |||
210 | #define mkdir mingw_mkdir | 216 | #define mkdir mingw_mkdir |
211 | #define lstat stat | 217 | #define stat(x,y) mingw_lstat(x,y) |
218 | #define lseek _lseeki64 | ||
219 | #define fstat mingw_fstat | ||
220 | #define lstat mingw_lstat | ||
221 | #define _stati64 mingw_lstat | ||
212 | 222 | ||
213 | /* | 223 | /* |
214 | * sys/sysmacros.h | 224 | * sys/sysmacros.h |
diff --git a/win32/mingw.c b/win32/mingw.c index cc266462f..e8096b5bc 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); |