55e5c8f9f1061cdca3896628e1615664098132a8
[reactos.git] / reactos / lib / sdk / crt / stdio / stat64.c
1 #include <precomp.h>
2 #include <tchar.h>
3 #include <direct.h>
4
5 HANDLE fdtoh(int fd);
6
7 #define ALL_S_IREAD (_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6))
8 #define ALL_S_IWRITE (_S_IWRITE | (_S_IWRITE >> 3) | (_S_IWRITE >> 6))
9 #define ALL_S_IEXEC (_S_IEXEC | (_S_IEXEC >> 3) | (_S_IEXEC >> 6))
10
11 #ifdef UNICODE
12 #define TCHAR4 ULONGLONG
13 #else
14 #define TCHAR4 ULONG
15 #endif
16
17 #define TCSIZE sizeof(_TCHAR)
18 #define TOULL(x) ((TCHAR4)(x))
19
20 #define EXE ((TOULL('e')<<(2*TCSIZE)) | (TOULL('x')<<TCSIZE) | (TOULL('e')))
21 #define BAT ((TOULL('b')<<(2*TCSIZE)) | (TOULL('a')<<TCSIZE) | (TOULL('t')))
22 #define CMD ((TOULL('c')<<(2*TCSIZE)) | (TOULL('m')<<TCSIZE) | (TOULL('d')))
23 #define COM ((TOULL('c')<<(2*TCSIZE)) | (TOULL('o')<<TCSIZE) | (TOULL('m')))
24
25 int CDECL _tstat64(const _TCHAR *path, struct __stat64 *buf)
26 {
27 DWORD dw;
28 WIN32_FILE_ATTRIBUTE_DATA hfi;
29 unsigned short mode = ALL_S_IREAD;
30 size_t plen;
31
32 TRACE(":file (%s) buf(%p)\n",path,buf);
33
34 if (!GetFileAttributesEx(path, GetFileExInfoStandard, &hfi))
35 {
36 TRACE("failed (%d)\n",GetLastError());
37 _dosmaperr(ERROR_FILE_NOT_FOUND);
38 return -1;
39 }
40
41 memset(buf,0,sizeof(struct __stat64));
42
43 /* FIXME: rdev isn't drive num, despite what the docs say-what is it?
44 Bon 011120: This FIXME seems incorrect
45 Also a letter as first char isn't enough to be classified
46 as a drive letter
47 */
48 if (isalpha((unsigned char)*path)&& (*(path+1)==':'))
49 buf->st_dev = buf->st_rdev = _totupper(*path) - 'A'; /* drive num */
50 else
51 buf->st_dev = buf->st_rdev = _getdrive() - 1;
52
53 plen = _tcslen(path);
54
55 /* Dir, or regular file? */
56 if ((hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
57 (path[plen-1] == '\\'))
58 mode |= (_S_IFDIR | ALL_S_IEXEC);
59 else
60 {
61 mode |= _S_IFREG;
62 /* executable? */
63 if (plen > 6 && path[plen-4] == '.') /* shortest exe: "\x.exe" */
64 {
65 TCHAR4 ext = _totlower(path[plen-1]) | (_totlower(path[plen-2]) << TCSIZE) |
66 (_totlower(path[plen-3]) << (2*TCSIZE));
67 if (ext == EXE || ext == BAT || ext == CMD || ext == COM)
68 mode |= ALL_S_IEXEC;
69 }
70 }
71
72 if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
73 mode |= ALL_S_IWRITE;
74
75 buf->st_mode = mode;
76 buf->st_nlink = 1;
77 buf->st_size = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow;
78 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
79 buf->st_atime = dw;
80 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
81 buf->st_mtime = buf->st_ctime = dw;
82 TRACE("%d %d 0x%08lx%08lx %ld %ld %ld\n", buf->st_mode,buf->st_nlink,
83 (long)(buf->st_size >> 32),(long)buf->st_size,
84 (long)buf->st_atime,(long)buf->st_mtime,(long)buf->st_ctime);
85 return 0;
86 }
87
88 #ifndef _UNICODE
89
90 int CDECL _fstat64(int fd, struct __stat64* buf)
91 {
92 DWORD dw;
93 DWORD type;
94 BY_HANDLE_FILE_INFORMATION hfi;
95 HANDLE hand = fdtoh(fd);
96
97 TRACE(":fd (%d) stat (%p)\n",fd,buf);
98 if (hand == INVALID_HANDLE_VALUE)
99 return -1;
100
101 if (!buf)
102 {
103 WARN(":failed-NULL buf\n");
104 _dosmaperr(ERROR_INVALID_PARAMETER);
105 return -1;
106 }
107
108 memset(&hfi, 0, sizeof(hfi));
109 memset(buf, 0, sizeof(struct __stat64));
110 type = GetFileType(hand);
111 if (type == FILE_TYPE_PIPE)
112 {
113 buf->st_dev = buf->st_rdev = fd;
114 buf->st_mode = _S_IFIFO;
115 buf->st_nlink = 1;
116 }
117 else if (type == FILE_TYPE_CHAR)
118 {
119 buf->st_dev = buf->st_rdev = fd;
120 buf->st_mode = _S_IFCHR;
121 buf->st_nlink = 1;
122 }
123 else /* FILE_TYPE_DISK etc. */
124 {
125 if (!GetFileInformationByHandle(hand, &hfi))
126 {
127 WARN(":failed-last error (%d)\n",GetLastError());
128 _dosmaperr(ERROR_INVALID_PARAMETER);
129 return -1;
130 }
131 buf->st_mode = _S_IFREG | ALL_S_IREAD;
132 if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
133 buf->st_mode |= ALL_S_IWRITE;
134 buf->st_size = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow;
135 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
136 buf->st_atime = dw;
137 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
138 buf->st_mtime = buf->st_ctime = dw;
139 buf->st_nlink = (short)hfi.nNumberOfLinks;
140 }
141 TRACE(":dwFileAttributes = 0x%x, mode set to 0x%x\n",hfi.dwFileAttributes,
142 buf->st_mode);
143 return 0;
144 }
145
146 #endif