xref: /reactos/sdk/lib/crt/stdio/stat64.c (revision 62919904)
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 
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 
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