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