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