merge trunk head (37902)
[reactos.git] / reactos / lib / sdk / crt / stdio / stat64.c
1 #include <precomp.h>
2 #include "wine/unicode.h"
3
4 #include <direct.h>
5 #include <tchar.h>
6 #include <sys/stat.h>
7
8 #ifndef _UNICODE
9 #include <string.h>
10 #endif
11
12 #ifndef _USE_STAT64
13 #define _USE_STAT64 1
14 #endif
15
16 /* for stat mode, permissions apply to all,owner and group */
17 #define ALL_S_IREAD (_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6))
18 #define ALL_S_IWRITE (_S_IWRITE | (_S_IWRITE >> 3) | (_S_IWRITE >> 6))
19 #define ALL_S_IEXEC (_S_IEXEC | (_S_IEXEC >> 3) | (_S_IEXEC >> 6))
20
21 #define EXE ('e' << 16 | 'x' << 8 | 'e')
22 #define BAT ('b' << 16 | 'a' << 8 | 't')
23 #define CMD ('c' << 16 | 'm' << 8 | 'd')
24 #define COM ('c' << 16 | 'o' << 8 | 'm')
25
26 #define TOUL(x) (ULONGLONG)(x)
27 #define WCEXE (TOUL('e') << 32 | TOUL('x') << 16 | TOUL('e'))
28 #define WCBAT (TOUL('b') << 32 | TOUL('a') << 16 | TOUL('t'))
29 #define WCCMD (TOUL('c') << 32 | TOUL('m') << 16 | TOUL('d'))
30 #define WCCOM (TOUL('c') << 32 | TOUL('o') << 16 | TOUL('m'))
31
32 HANDLE fdtoh(int fd);
33 void stat64_to_stati64(const struct __stat64 *buf64, struct _stati64 *buf);
34
35 #if _USE_STAT64
36
37 //int _tstati64(const TCHAR* path, struct _stati64 * buf)
38 //{
39 // int ret;
40 // struct __stat64 buf64;
41 //
42 // ret = _tstat64(path, &buf64);
43 // if (!ret)
44 // stat64_to_stati64(&buf64, buf);
45 // return ret;
46 //}
47
48 #endif
49
50
51 #if _USE_STAT64
52 int CDECL _tstat64(const _TCHAR *path, struct _stat64 *buf)
53 #else
54 int CDECL _tstat64i32(const _TCHAR *path, struct _stat64i32 *buf)
55 #endif
56 {
57 DWORD dw;
58 WIN32_FILE_ATTRIBUTE_DATA hfi;
59 unsigned short mode = ALL_S_IREAD;
60 int plen;
61
62 TRACE(":file (%s) buf(%p)\n",path,buf);
63
64 if (!GetFileAttributesEx(path, GetFileExInfoStandard, &hfi))
65 {
66 TRACE("failed (%d)\n",GetLastError());
67 __set_errno(ERROR_FILE_NOT_FOUND);
68 return -1;
69 }
70
71 memset(buf,0,sizeof(struct __stat64));
72
73 /* FIXME: rdev isn't drive num, despite what the docs say-what is it?
74 Bon 011120: This FIXME seems incorrect
75 Also a letter as first char isn't enough to be classified
76 as a drive letter
77 */
78 #ifndef _UNICODE
79 if (isalpha(*path)&& (*(path+1)==':'))
80 buf->st_dev = buf->st_rdev = toupper(*path) - 'A'; /* drive num */
81 #else
82 if (iswalpha(*path))
83 buf->st_dev = buf->st_rdev = toupperW(*path - 'A'); /* drive num */
84 #endif
85 else
86 buf->st_dev = buf->st_rdev = _getdrive() - 1;
87
88 #ifndef _UNICODE
89 plen = strlen(path);
90 #else
91 plen = strlenW(path);
92 #endif
93
94 /* Dir, or regular file? */
95 if ((hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
96 (path[plen-1] == '\\'))
97 mode |= (_S_IFDIR | ALL_S_IEXEC);
98 else
99 {
100 mode |= _S_IFREG;
101 /* executable? */
102 if (plen > 6 && path[plen-4] == '.') /* shortest exe: "\x.exe" */
103 {
104 #ifndef _UNICODE
105 unsigned int ext = tolower(path[plen-1]) | (tolower(path[plen-2]) << 8) |
106 (tolower(path[plen-3]) << 16);
107 if (ext == EXE || ext == BAT || ext == CMD || ext == COM)
108 mode |= ALL_S_IEXEC;
109 #else
110 ULONGLONG ext = tolowerW(path[plen-1]) | (tolowerW(path[plen-2]) << 16) |
111 ((ULONGLONG)tolowerW(path[plen-3]) << 32);
112 if (ext == WCEXE || ext == WCBAT || ext == WCCMD || ext == WCCOM)
113 mode |= ALL_S_IEXEC;
114 #endif
115 }
116 }
117
118 if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
119 mode |= ALL_S_IWRITE;
120
121 buf->st_mode = mode;
122 buf->st_nlink = 1;
123 #if _USE_STAT64
124 buf->st_size = buf->st_size = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow;
125 #else
126 buf->st_size = hfi.nFileSizeLow;
127 #endif
128 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
129 buf->st_atime = dw;
130 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
131 buf->st_mtime = buf->st_ctime = dw;
132 TRACE("%d %d 0x%08lx%08lx %ld %ld %ld\n", buf->st_mode,buf->st_nlink,
133 (long)(buf->st_size >> 16),(long)buf->st_size,
134 (long)buf->st_atime,(long)buf->st_mtime,(long)buf->st_ctime);
135 return 0;
136 }
137
138 /*********************************************************************
139 * _stat (MSVCRT.@)
140 */
141 #if _USE_STAT64
142 int CDECL _tstat32i64(const _TCHAR *path,struct _stat32i64 *buf)
143 #else
144 int CDECL _tstat32(const _TCHAR *path,struct _stat32 *buf)
145 #endif
146 {
147 DWORD dw;
148 WIN32_FILE_ATTRIBUTE_DATA hfi;
149 unsigned short mode = ALL_S_IREAD;
150 int plen;
151
152 TRACE(":file (%s) buf(%p)\n",path,buf);
153
154 if (!GetFileAttributesEx(path, GetFileExInfoStandard, &hfi))
155 {
156 TRACE("failed (%d)\n",GetLastError());
157 __set_errno(ERROR_FILE_NOT_FOUND);
158 return -1;
159 }
160
161 memset(buf,0,sizeof(*buf));
162
163 /* FIXME: rdev isn't drive num, despite what the docs say-what is it?
164 Bon 011120: This FIXME seems incorrect
165 Also a letter as first char isn't enough to be classified
166 as a drive letter
167 */
168 #ifndef _UNICODE
169 if (isalpha(*path)&& (*(path+1)==':'))
170 buf->st_dev = buf->st_rdev = toupper(*path) - 'A'; /* drive num */
171 #else
172 if (iswalpha(*path))
173 buf->st_dev = buf->st_rdev = toupperW(*path - 'A'); /* drive num */
174 #endif
175 else
176 buf->st_dev = buf->st_rdev = _getdrive() - 1;
177
178 #ifndef _UNICODE
179 plen = strlen(path);
180 #else
181 plen = strlenW(path);
182 #endif
183
184 /* Dir, or regular file? */
185 if ((hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
186 (path[plen-1] == '\\'))
187 mode |= (_S_IFDIR | ALL_S_IEXEC);
188 else
189 {
190 mode |= _S_IFREG;
191 /* executable? */
192 if (plen > 6 && path[plen-4] == '.') /* shortest exe: "\x.exe" */
193 {
194 #ifndef _UNICODE
195 unsigned int ext = tolower(path[plen-1]) | (tolower(path[plen-2]) << 8) |
196 (tolower(path[plen-3]) << 16);
197 if (ext == EXE || ext == BAT || ext == CMD || ext == COM)
198 mode |= ALL_S_IEXEC;
199 #else
200 ULONGLONG ext = tolowerW(path[plen-1]) | (tolowerW(path[plen-2]) << 16) |
201 ((ULONGLONG)tolowerW(path[plen-3]) << 32);
202 if (ext == WCEXE || ext == WCBAT || ext == WCCMD || ext == WCCOM)
203 mode |= ALL_S_IEXEC;
204 #endif
205 }
206 }
207
208 if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
209 mode |= ALL_S_IWRITE;
210
211 buf->st_mode = mode;
212 buf->st_nlink = 1;
213 #if _USE_STAT64
214 buf->st_size = ((__int32)hfi.nFileSizeHigh << 16) + hfi.nFileSizeLow;
215 #else
216 buf->st_size = hfi.nFileSizeLow;
217 #endif
218 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
219 buf->st_atime = dw;
220 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
221 buf->st_mtime = buf->st_ctime = dw;
222 TRACE("%d %d 0x%08lx%08lx %ld %ld %ld\n", buf->st_mode,buf->st_nlink,
223 (long)(buf->st_size >> 16),(long)buf->st_size,
224 (long)buf->st_atime,(long)buf->st_mtime,(long)buf->st_ctime);
225 return 0;
226 }
227
228 #ifndef _UNICODE //No wide versions needed
229
230 #if _USE_STAT64
231 int CDECL _fstat64(int fd, struct _stat64* buf)
232 #else
233 int CDECL _fstat64i32(int fd, struct _stat64i32* buf)
234 #endif
235 {
236 DWORD dw;
237 DWORD type;
238 BY_HANDLE_FILE_INFORMATION hfi;
239 HANDLE hand = fdtoh(fd);
240
241 TRACE(":fd (%d) stat (%p)\n",fd,buf);
242 if (hand == INVALID_HANDLE_VALUE)
243 return -1;
244
245 if (!buf)
246 {
247 WARN(":failed-NULL buf\n");
248 __set_errno(ERROR_INVALID_PARAMETER);
249 return -1;
250 }
251
252 memset(&hfi, 0, sizeof(hfi));
253 memset(buf, 0, sizeof(struct __stat64));
254 type = GetFileType(hand);
255 if (type == FILE_TYPE_PIPE)
256 {
257 buf->st_dev = buf->st_rdev = fd;
258 buf->st_mode = S_IFIFO;
259 buf->st_nlink = 1;
260 }
261 else if (type == FILE_TYPE_CHAR)
262 {
263 buf->st_dev = buf->st_rdev = fd;
264 buf->st_mode = S_IFCHR;
265 buf->st_nlink = 1;
266 }
267 else /* FILE_TYPE_DISK etc. */
268 {
269 if (!GetFileInformationByHandle(hand, &hfi))
270 {
271 WARN(":failed-last error (%d)\n",GetLastError());
272 __set_errno(ERROR_INVALID_PARAMETER);
273 return -1;
274 }
275 buf->st_mode = S_IFREG | S_IREAD;
276 if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
277 buf->st_mode |= S_IWRITE;
278 buf->st_size = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow;
279 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
280 buf->st_atime = dw;
281 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
282 buf->st_mtime = buf->st_ctime = dw;
283 buf->st_nlink = hfi.nNumberOfLinks;
284 }
285 TRACE(":dwFileAttributes = 0x%x, mode set to 0x%x\n",hfi.dwFileAttributes,
286 buf->st_mode);
287 return 0;
288 }
289
290 /*********************************************************************
291 * _fstat (MSVCRT.@)
292 */
293 #if _USE_STAT64
294 int CDECL _fstat32(int fd, struct _stat32* buf)
295 #else
296 int CDECL _fstat32i64(int fd, struct _stat32i64* buf)
297 #endif
298 {
299 DWORD dw;
300 DWORD type;
301 BY_HANDLE_FILE_INFORMATION hfi;
302 HANDLE hand = fdtoh(fd);
303
304 TRACE(":fd (%d) stat (%p)\n",fd,buf);
305 if (hand == INVALID_HANDLE_VALUE)
306 return -1;
307
308 if (!buf)
309 {
310 WARN(":failed-NULL buf\n");
311 __set_errno(ERROR_INVALID_PARAMETER);
312 return -1;
313 }
314
315 memset(&hfi, 0, sizeof(hfi));
316 memset(buf, 0, sizeof(struct _stat32));
317 type = GetFileType(hand);
318 if (type == FILE_TYPE_PIPE)
319 {
320 buf->st_dev = buf->st_rdev = fd;
321 buf->st_mode = S_IFIFO;
322 buf->st_nlink = 1;
323 }
324 else if (type == FILE_TYPE_CHAR)
325 {
326 buf->st_dev = buf->st_rdev = fd;
327 buf->st_mode = S_IFCHR;
328 buf->st_nlink = 1;
329 }
330 else /* FILE_TYPE_DISK etc. */
331 {
332 if (!GetFileInformationByHandle(hand, &hfi))
333 {
334 WARN(":failed-last error (%d)\n",GetLastError());
335 __set_errno(ERROR_INVALID_PARAMETER);
336 return -1;
337 }
338 buf->st_mode = S_IFREG | S_IREAD;
339 if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
340 buf->st_mode |= S_IWRITE;
341 buf->st_size = ((__int32)hfi.nFileSizeHigh << 16) + hfi.nFileSizeLow;
342 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
343 buf->st_atime = dw;
344 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
345 buf->st_mtime = buf->st_ctime = dw;
346 buf->st_nlink = hfi.nNumberOfLinks;
347 }
348 TRACE(":dwFileAttributes = 0x%x, mode set to 0x%x\n",hfi.dwFileAttributes,
349 buf->st_mode);
350 return 0;
351 }
352
353 #endif