1 /********************************************************************************
2 * *
3 * F i l e S t a t i s t i c s *
4 * *
5 *********************************************************************************
6 * Copyright (C) 2005,2021 by Jeroen van der Zijp. All Rights Reserved. *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU Lesser General Public License as published by *
10 * the Free Software Foundation; either version 3 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public License *
19 * along with this program. If not, see <http://www.gnu.org/licenses/> *
20 ********************************************************************************/
21 #include "xincs.h"
22 #include "fxver.h"
23 #include "fxdefs.h"
24 #include "fxmath.h"
25 #include "fxascii.h"
26 #include "FXArray.h"
27 #include "FXHash.h"
28 #include "FXStream.h"
29 #include "FXString.h"
30 #include "FXPath.h"
31 #include "FXStat.h"
32 #include "FXFile.h"
33
34
35
36 /*
37 Notes:
38 - Find out stuff about files and directories.
39 */
40
41
42 using namespace FX;
43
44 /*******************************************************************************/
45
46 namespace FX {
47
48
49 // Return true if it is a hidden file (note: Windows-only attribute)
isHidden() const50 FXbool FXStat::isHidden() const {
51 return (modeFlags&FXIO::Hidden)!=0;
52 }
53
54 // Return true if input path is a directory
isDirectory() const55 FXbool FXStat::isDirectory() const {
56 return (modeFlags&FXIO::Directory)!=0;
57 }
58
59 // Return true if it is a regular file
isFile() const60 FXbool FXStat::isFile() const {
61 return (modeFlags&FXIO::File)!=0;
62 }
63
64 // Return true if it is a link
isLink() const65 FXbool FXStat::isLink() const {
66 return (modeFlags&FXIO::SymLink)!=0;
67 }
68
69 // Return true if the file sets the user id on execution
isSetUid() const70 FXbool FXStat::isSetUid() const {
71 return (modeFlags&FXIO::SetUser)!=0;
72 }
73
74 // Return true if the file sets the group id on execution
isSetGid() const75 FXbool FXStat::isSetGid() const {
76 return (modeFlags&FXIO::SetGroup)!=0;
77 }
78
79 // Return true if the file has the sticky bit set
isSetSticky() const80 FXbool FXStat::isSetSticky() const {
81 return (modeFlags&FXIO::Sticky)!=0;
82 }
83
84 // Return true if special device (character or block device)
isDevice() const85 FXbool FXStat::isDevice() const {
86 return (modeFlags&(FXIO::Character|FXIO::Block))!=0;
87 }
88
89 // Return true if character device
isCharacter() const90 FXbool FXStat::isCharacter() const {
91 return (modeFlags&FXIO::Character)!=0;
92 }
93
94 // Return true if block device
isBlock() const95 FXbool FXStat::isBlock() const {
96 return (modeFlags&FXIO::Block)!=0;
97 }
98
99 // Return true if socket device
isSocket() const100 FXbool FXStat::isSocket() const {
101 return (modeFlags&FXIO::Socket)!=0;
102 }
103
104 // Return true if fifo device
isFifo() const105 FXbool FXStat::isFifo() const {
106 return (modeFlags&FXIO::Fifo)!=0;
107 }
108
109 // Return true if file is readable
isReadable() const110 FXbool FXStat::isReadable() const {
111 return (modeFlags&(FXIO::OtherRead|FXIO::GroupRead|FXIO::OwnerRead))!=0;
112 }
113
114 // Return true if file is writable
isWritable() const115 FXbool FXStat::isWritable() const {
116 return (modeFlags&(FXIO::OtherWrite|FXIO::GroupWrite|FXIO::OwnerWrite))!=0;
117 }
118
119 // Return true if file is executable
isExecutable() const120 FXbool FXStat::isExecutable() const {
121 return (modeFlags&(FXIO::OtherExec|FXIO::GroupExec|FXIO::OwnerExec))!=0;
122 }
123
124 // Return true if owner has read-write-execute permissions
isOwnerReadWriteExecute() const125 FXbool FXStat::isOwnerReadWriteExecute() const {
126 return (modeFlags&FXIO::OwnerExec) && (modeFlags&FXIO::OwnerWrite) && (modeFlags&FXIO::OwnerRead);
127 }
128
129 // Return true if owner has read permissions
isOwnerReadable() const130 FXbool FXStat::isOwnerReadable() const {
131 return (modeFlags&FXIO::OwnerRead)!=0;
132 }
133
134 // Return true if owner has write permissions
isOwnerWritable() const135 FXbool FXStat::isOwnerWritable() const {
136 return (modeFlags&FXIO::OwnerWrite)!=0;
137 }
138
139 // Return true if owner has execute permissions
isOwnerExecutable() const140 FXbool FXStat::isOwnerExecutable() const {
141 return (modeFlags&FXIO::OwnerExec)!=0;
142 }
143
144 // Return true if group has read-write-execute permissions
isGroupReadWriteExecute() const145 FXbool FXStat::isGroupReadWriteExecute() const {
146 return (modeFlags&FXIO::GroupExec) && (modeFlags&FXIO::GroupWrite) && (modeFlags&FXIO::GroupRead);
147 }
148
149 // Return true if group has read permissions
isGroupReadable() const150 FXbool FXStat::isGroupReadable() const {
151 return (modeFlags&FXIO::GroupRead)!=0;
152 }
153
154 // Return true if group has write permissions
isGroupWritable() const155 FXbool FXStat::isGroupWritable() const {
156 return (modeFlags&FXIO::GroupWrite)!=0;
157 }
158
159 // Return true if group has execute permissions
isGroupExecutable() const160 FXbool FXStat::isGroupExecutable() const {
161 return (modeFlags&FXIO::GroupExec)!=0;
162 }
163
164 // Return true if others have read-write-execute permissions
isOtherReadWriteExecute() const165 FXbool FXStat::isOtherReadWriteExecute() const {
166 return (modeFlags&FXIO::OtherExec) && (modeFlags&FXIO::OtherWrite) && (modeFlags&FXIO::OtherRead);
167 }
168
169 // Return true if others have read permissions
isOtherReadable() const170 FXbool FXStat::isOtherReadable() const {
171 return (modeFlags&FXIO::OtherRead)!=0;
172 }
173
174 // Return true if others have write permissions
isOtherWritable() const175 FXbool FXStat::isOtherWritable() const {
176 return (modeFlags&FXIO::OtherWrite)!=0;
177 }
178
179 // Return true if others have execute permissions
isOtherExecutable() const180 FXbool FXStat::isOtherExecutable() const {
181 return (modeFlags&FXIO::OtherExec)!=0;
182 }
183
184
185 #if defined(WIN32)
186
187 // Convert 100ns since 01/01/1601 to ns since 01/01/1970
fxunixtime(FXTime ft)188 static inline FXTime fxunixtime(FXTime ft){
189 return (ft-FXLONG(116444736000000000))*FXLONG(100);
190 }
191
192 // Convert ns since 01/01/1970 to 100ns since 01/01/1601
fxwintime(FXTime ut)193 static inline FXTime fxwintime(FXTime ut){
194 return ut/FXLONG(100)+FXLONG(116444736000000000);
195 }
196
197 #endif
198
199
200 // Get statistics of given file
statFile(const FXString & file,FXStat & info)201 FXbool FXStat::statFile(const FXString& file,FXStat& info){
202 FXbool result=false;
203 info.modeFlags=0;
204 info.userNumber=0;
205 info.groupNumber=0;
206 info.linkCount=0;
207 info.createTime=0;
208 info.accessTime=0;
209 info.modifyTime=0;
210 info.fileVolume=0;
211 info.fileIndex=0;
212 info.fileSize=0;
213 if(!file.empty()){
214 #ifdef WIN32
215 #ifdef UNICODE
216 FXnchar unifile[MAXPATHLEN];
217 HANDLE hfile;
218 utf2ncs(unifile,file.text(),MAXPATHLEN);
219 if((hfile=::CreateFile(unifile,FILE_READ_ATTRIBUTES,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS,NULL))!=INVALID_HANDLE_VALUE){
220 BY_HANDLE_FILE_INFORMATION data;
221 if(::GetFileInformationByHandle(hfile,&data)){
222 info.modeFlags=FXIO::AllFull;
223 if(data.dwFileAttributes&FILE_ATTRIBUTE_HIDDEN) info.modeFlags|=FXIO::Hidden;
224 if(data.dwFileAttributes&FILE_ATTRIBUTE_READONLY) info.modeFlags&=~FXIO::AllWrite;
225 if(data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) info.modeFlags|=FXIO::Directory|FXIO::AllWrite; else info.modeFlags|=FXIO::File; // Directories (folders) always writable on Windows
226 if((info.modeFlags&FXIO::File) && !FXPath::hasExecExtension(file)) info.modeFlags&=~FXIO::AllExec;
227 info.userNumber=0;
228 info.groupNumber=0;
229 info.linkCount=data.nNumberOfLinks;
230 info.accessTime=fxunixtime(*((FXTime*)&data.ftLastAccessTime));
231 info.modifyTime=fxunixtime(*((FXTime*)&data.ftLastWriteTime));
232 info.createTime=fxunixtime(*((FXTime*)&data.ftCreationTime));
233 info.fileVolume=data.dwVolumeSerialNumber;
234 info.fileIndex=(((FXulong)data.nFileIndexHigh)<<32)|((FXulong)data.nFileIndexLow);
235 info.fileSize=(((FXlong)data.nFileSizeHigh)<<32)|((FXlong)data.nFileSizeLow);
236 result=true;
237 }
238 ::CloseHandle(hfile);
239 }
240 #else
241 HANDLE hfile;
242 if((hfile=::CreateFile(file.text(),FILE_READ_ATTRIBUTES,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS,NULL))!=INVALID_HANDLE_VALUE){
243 BY_HANDLE_FILE_INFORMATION data;
244 if(::GetFileInformationByHandle(hfile,&data)){
245 info.modeFlags=FXIO::AllFull;
246 if(data.dwFileAttributes&FILE_ATTRIBUTE_HIDDEN) info.modeFlags|=FXIO::Hidden;
247 if(data.dwFileAttributes&FILE_ATTRIBUTE_READONLY) info.modeFlags&=~FXIO::AllWrite;
248 if(data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) info.modeFlags|=FXIO::Directory|FXIO::AllWrite; else info.modeFlags|=FXIO::File; // Directories (folders) always writable on Windows
249 if((info.modeFlags&FXIO::File) && !FXPath::hasExecExtension(file)) info.modeFlags&=~FXIO::AllExec;
250 info.userNumber=0;
251 info.groupNumber=0;
252 info.linkCount=data.nNumberOfLinks;
253 info.accessTime=fxunixtime(*((FXTime*)&data.ftLastAccessTime));
254 info.modifyTime=fxunixtime(*((FXTime*)&data.ftLastWriteTime));
255 info.createTime=fxunixtime(*((FXTime*)&data.ftCreationTime));
256 info.fileVolume=data.dwVolumeSerialNumber;
257 info.fileIndex=(((FXulong)data.nFileIndexHigh)<<32)|((FXulong)data.nFileIndexLow);
258 info.fileSize=(((FXlong)data.nFileSizeHigh)<<32)|((FXlong)data.nFileSizeLow);
259 result=true;
260 }
261 ::CloseHandle(hfile);
262 }
263 #endif
264 #else
265 const FXTime seconds=1000000000;
266 struct stat data;
267 if(::stat(file.text(),&data)==0){
268 info.modeFlags=(data.st_mode&FXIO::AllFull);
269 if(S_ISDIR(data.st_mode)) info.modeFlags|=FXIO::Directory;
270 if(S_ISREG(data.st_mode)) info.modeFlags|=FXIO::File;
271 if(S_ISLNK(data.st_mode)) info.modeFlags|=FXIO::SymLink;
272 if(S_ISCHR(data.st_mode)) info.modeFlags|=FXIO::Character;
273 if(S_ISBLK(data.st_mode)) info.modeFlags|=FXIO::Block;
274 if(S_ISFIFO(data.st_mode)) info.modeFlags|=FXIO::Fifo;
275 if(S_ISSOCK(data.st_mode)) info.modeFlags|=FXIO::Socket;
276 if(data.st_mode&S_ISUID) info.modeFlags|=FXIO::SetUser;
277 if(data.st_mode&S_ISGID) info.modeFlags|=FXIO::SetGroup;
278 if(data.st_mode&S_ISVTX) info.modeFlags|=FXIO::Sticky;
279 info.userNumber=data.st_uid;
280 info.groupNumber=data.st_gid;
281 info.linkCount=data.st_nlink;
282 #if (_POSIX_C_SOURCE >= 200809L) || (_XOPEN_SOURCE >= 700)
283 info.accessTime=data.st_atim.tv_sec*seconds+data.st_atim.tv_nsec;
284 info.modifyTime=data.st_mtim.tv_sec*seconds+data.st_mtim.tv_nsec;
285 info.createTime=data.st_ctim.tv_sec*seconds+data.st_ctim.tv_nsec;
286 #else
287 info.accessTime=data.st_atime*seconds;
288 info.modifyTime=data.st_mtime*seconds;
289 info.createTime=data.st_ctime*seconds;
290 #endif
291 info.fileVolume=(FXlong)data.st_dev;
292 info.fileIndex=(FXlong)data.st_ino;
293 info.fileSize=(FXlong)data.st_size;
294 result=true;
295 }
296 #endif
297 }
298 return result;
299 }
300
301
302 // Get statistice of the linked file
statLink(const FXString & file,FXStat & info)303 FXbool FXStat::statLink(const FXString& file,FXStat& info){
304 FXbool result=false;
305 info.modeFlags=0;
306 info.userNumber=0;
307 info.groupNumber=0;
308 info.linkCount=0;
309 info.createTime=0;
310 info.accessTime=0;
311 info.modifyTime=0;
312 info.fileVolume=0;
313 info.fileIndex=0;
314 info.fileSize=0;
315 if(!file.empty()){
316 #ifdef WIN32
317 #ifdef UNICODE
318 FXnchar unifile[MAXPATHLEN];
319 HANDLE hfile;
320 utf2ncs(unifile,file.text(),MAXPATHLEN);
321 if((hfile=::CreateFile(unifile,FILE_READ_ATTRIBUTES,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS,NULL))!=INVALID_HANDLE_VALUE){
322 BY_HANDLE_FILE_INFORMATION data;
323 if(::GetFileInformationByHandle(hfile,&data)){
324 info.modeFlags=FXIO::AllFull;
325 if(data.dwFileAttributes&FILE_ATTRIBUTE_HIDDEN) info.modeFlags|=FXIO::Hidden;
326 if(data.dwFileAttributes&FILE_ATTRIBUTE_READONLY) info.modeFlags&=~FXIO::AllWrite;
327 if(data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) info.modeFlags|=FXIO::Directory|FXIO::AllWrite; else info.modeFlags|=FXIO::File; // Directories (folders) always writable on Windows
328 if((info.modeFlags&FXIO::File) && !FXPath::hasExecExtension(file)) info.modeFlags&=~FXIO::AllExec;
329 info.userNumber=0;
330 info.groupNumber=0;
331 info.linkCount=data.nNumberOfLinks;
332 info.accessTime=fxunixtime(*((FXTime*)&data.ftLastAccessTime));
333 info.modifyTime=fxunixtime(*((FXTime*)&data.ftLastWriteTime));
334 info.createTime=fxunixtime(*((FXTime*)&data.ftCreationTime));
335 info.fileVolume=data.dwVolumeSerialNumber;
336 info.fileIndex=(((FXulong)data.nFileIndexHigh)<<32)|((FXulong)data.nFileIndexLow);
337 info.fileSize=(((FXlong)data.nFileSizeHigh)<<32)|((FXlong)data.nFileSizeLow);
338 result=true;
339 }
340 ::CloseHandle(hfile);
341 }
342 #else
343 HANDLE hfile;
344 if((hfile=::CreateFile(file.text(),FILE_READ_ATTRIBUTES,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS,NULL))!=INVALID_HANDLE_VALUE){
345 BY_HANDLE_FILE_INFORMATION data;
346 if(::GetFileInformationByHandle(hfile,&data)){
347 info.modeFlags=FXIO::AllFull;
348 if(data.dwFileAttributes&FILE_ATTRIBUTE_HIDDEN) info.modeFlags|=FXIO::Hidden;
349 if(data.dwFileAttributes&FILE_ATTRIBUTE_READONLY) info.modeFlags&=~FXIO::AllWrite;
350 if(data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) info.modeFlags|=FXIO::Directory|FXIO::AllWrite; else info.modeFlags|=FXIO::File; // Directories (folders) always writable on Windows
351 if((info.modeFlags&FXIO::File) && !FXPath::hasExecExtension(file)) info.modeFlags&=~FXIO::AllExec;
352 info.userNumber=0;
353 info.groupNumber=0;
354 info.linkCount=data.nNumberOfLinks;
355 info.accessTime=fxunixtime(*((FXTime*)&data.ftLastAccessTime));
356 info.modifyTime=fxunixtime(*((FXTime*)&data.ftLastWriteTime));
357 info.createTime=fxunixtime(*((FXTime*)&data.ftCreationTime));
358 info.fileVolume=data.dwVolumeSerialNumber;
359 info.fileIndex=(((FXulong)data.nFileIndexHigh)<<32)|((FXulong)data.nFileIndexLow);
360 info.fileSize=(((FXlong)data.nFileSizeHigh)<<32)|((FXlong)data.nFileSizeLow);
361 result=true;
362 }
363 ::CloseHandle(hfile);
364 }
365 #endif
366 #else
367 const FXTime seconds=1000000000;
368 struct stat data;
369 if(::lstat(file.text(),&data)==0){
370 info.modeFlags=(data.st_mode&FXIO::AllFull);
371 if(S_ISDIR(data.st_mode)) info.modeFlags|=FXIO::Directory;
372 if(S_ISREG(data.st_mode)) info.modeFlags|=FXIO::File;
373 if(S_ISLNK(data.st_mode)) info.modeFlags|=FXIO::SymLink;
374 if(S_ISCHR(data.st_mode)) info.modeFlags|=FXIO::Character;
375 if(S_ISBLK(data.st_mode)) info.modeFlags|=FXIO::Block;
376 if(S_ISFIFO(data.st_mode)) info.modeFlags|=FXIO::Fifo;
377 if(S_ISSOCK(data.st_mode)) info.modeFlags|=FXIO::Socket;
378 if(data.st_mode&S_ISUID) info.modeFlags|=FXIO::SetUser;
379 if(data.st_mode&S_ISGID) info.modeFlags|=FXIO::SetGroup;
380 if(data.st_mode&S_ISVTX) info.modeFlags|=FXIO::Sticky;
381 info.userNumber=data.st_uid;
382 info.groupNumber=data.st_gid;
383 info.linkCount=data.st_nlink;
384 #if (_POSIX_C_SOURCE >= 200809L) || (_XOPEN_SOURCE >= 700)
385 info.accessTime=data.st_atim.tv_sec*seconds+data.st_atim.tv_nsec;
386 info.modifyTime=data.st_mtim.tv_sec*seconds+data.st_mtim.tv_nsec;
387 info.createTime=data.st_ctim.tv_sec*seconds+data.st_ctim.tv_nsec;
388 #else
389 info.accessTime=data.st_atime*seconds;
390 info.modifyTime=data.st_mtime*seconds;
391 info.createTime=data.st_ctime*seconds;
392 #endif
393 info.fileVolume=(FXlong)data.st_dev;
394 info.fileIndex=(FXlong)data.st_ino;
395 info.fileSize=(FXlong)data.st_size;
396 result=true;
397 }
398 #endif
399 }
400 return result;
401 }
402
403
404 // Get statistice of the already open file
stat(const FXFile & file,FXStat & info)405 FXbool FXStat::stat(const FXFile& file,FXStat& info){
406 info.modeFlags=0;
407 info.userNumber=0;
408 info.groupNumber=0;
409 info.linkCount=0;
410 info.createTime=0;
411 info.accessTime=0;
412 info.modifyTime=0;
413 info.fileVolume=0;
414 info.fileIndex=0;
415 info.fileSize=0;
416 #ifdef WIN32
417 BY_HANDLE_FILE_INFORMATION data;
418 if(::GetFileInformationByHandle(file.handle(),&data)){
419 info.modeFlags=FXIO::AllFull;
420 if(data.dwFileAttributes&FILE_ATTRIBUTE_HIDDEN) info.modeFlags|=FXIO::Hidden;
421 if(data.dwFileAttributes&FILE_ATTRIBUTE_READONLY) info.modeFlags&=~FXIO::AllWrite;
422 if(data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) info.modeFlags|=FXIO::Directory|FXIO::AllWrite; else info.modeFlags|=FXIO::File; // Directories (folders) always writable on Windows
423 info.userNumber=0;
424 info.groupNumber=0;
425 info.linkCount=data.nNumberOfLinks;
426 info.accessTime=fxunixtime(*((FXTime*)&data.ftLastAccessTime));
427 info.modifyTime=fxunixtime(*((FXTime*)&data.ftLastWriteTime));
428 info.createTime=fxunixtime(*((FXTime*)&data.ftCreationTime));
429 info.fileVolume=data.dwVolumeSerialNumber;
430 info.fileIndex=(((FXulong)data.nFileIndexHigh)<<32)|((FXulong)data.nFileIndexLow);
431 info.fileSize=(((FXulong)data.nFileSizeHigh)<<32)|((FXulong)data.nFileSizeLow);
432 return true;
433 }
434 #else
435 const FXTime seconds=1000000000;
436 struct stat data;
437 if(::fstat(file.handle(),&data)==0){
438 info.modeFlags=(data.st_mode&FXIO::AllFull);
439 if(S_ISDIR(data.st_mode)) info.modeFlags|=FXIO::Directory;
440 if(S_ISREG(data.st_mode)) info.modeFlags|=FXIO::File;
441 if(S_ISLNK(data.st_mode)) info.modeFlags|=FXIO::SymLink;
442 if(S_ISCHR(data.st_mode)) info.modeFlags|=FXIO::Character;
443 if(S_ISBLK(data.st_mode)) info.modeFlags|=FXIO::Block;
444 if(S_ISFIFO(data.st_mode)) info.modeFlags|=FXIO::Fifo;
445 if(S_ISSOCK(data.st_mode)) info.modeFlags|=FXIO::Socket;
446 if(data.st_mode&S_ISUID) info.modeFlags|=FXIO::SetUser;
447 if(data.st_mode&S_ISGID) info.modeFlags|=FXIO::SetGroup;
448 if(data.st_mode&S_ISVTX) info.modeFlags|=FXIO::Sticky;
449 info.userNumber=data.st_uid;
450 info.groupNumber=data.st_gid;
451 info.linkCount=data.st_nlink;
452 #if (_POSIX_C_SOURCE >= 200809L) || (_XOPEN_SOURCE >= 700)
453 info.accessTime=data.st_atim.tv_sec*seconds+data.st_atim.tv_nsec;
454 info.modifyTime=data.st_mtim.tv_sec*seconds+data.st_mtim.tv_nsec;
455 info.createTime=data.st_ctim.tv_sec*seconds+data.st_ctim.tv_nsec;
456 #else
457 info.accessTime=data.st_atime*seconds;
458 info.modifyTime=data.st_mtime*seconds;
459 info.createTime=data.st_ctime*seconds;
460 #endif
461 info.fileVolume=(FXlong)data.st_dev;
462 info.fileIndex=(FXlong)data.st_ino;
463 info.fileSize=(FXlong)data.st_size;
464 return true;
465 }
466 #endif
467 return false;
468 }
469
470
471 // Return file mode flags
mode(const FXString & file)472 FXuint FXStat::mode(const FXString& file){
473 FXStat data;
474 statFile(file,data);
475 return data.mode();
476 }
477
478
479
480 // Change the mode flags for this file
mode(const FXString & file,FXuint perm)481 FXbool FXStat::mode(const FXString& file,FXuint perm){
482 if(!file.empty()){
483 #ifdef WIN32
484 /*
485 #ifdef UNICODE
486 FXnchar unifile[MAXPATHLEN];
487 utf2ncs(unifile,file.text(),MAXPATHLEN);
488 FXuint flags=::GetFileAttributesW(unifile);
489 if(flags!=INVALID_FILE_ATTRIBUTES){
490 if(flags&FILE_ATTRIBUTE_DIRECTORY){
491 }
492 else{
493 }
494
495 if((flags&FILE_ATTRIBUTE_DIRECTORY) || (perm&FXIO::AllWrite)){
496 flags&=~FILE_ATTRIBUTE_READONLY;
497 }
498 else{
499 flags|=FILE_ATTRIBUTE_READONLY;
500 }
501 if(perm&FXIO::Hidden) flags|=FILE_ATTRIBUTE_HIDDEN; else flags&=~FILE_ATTRIBUTE_HIDDEN;
502 flags&=FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_NOT_CONTENT_INDEXED|FILE_ATTRIBUTE_OFFLINE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_TEMPORARY;
503 return ::SetFileAttributesW(unifile,flags)!=0;
504 }
505 return false;
506 #else
507 FXuint flags=::GetFileAttributesA(unifile);
508 if(flags!=INVALID_FILE_ATTRIBUTES){
509 if((flags&FILE_ATTRIBUTE_DIRECTORY) || (perm&FXIO::AllWrite)) flags&=~FILE_ATTRIBUTE_READONLY; else flags|=FILE_ATTRIBUTE_READONLY;
510 if(perm&FXIO::Hidden) flags|=FILE_ATTRIBUTE_HIDDEN; else flags&=~FILE_ATTRIBUTE_HIDDEN;
511 flags&=FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_NOT_CONTENT_INDEXED|FILE_ATTRIBUTE_OFFLINE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_TEMPORARY;
512 return ::SetFileAttributesA(file.text(),flags)!=0;
513 }
514 return false;
515 #endif
516 */
517 #else
518 FXuint bits=perm&0777;
519 if(perm&FXIO::SetUser) bits|=S_ISUID;
520 if(perm&FXIO::SetGroup) bits|=S_ISGID;
521 if(perm&FXIO::Sticky) bits|=S_ISVTX;
522 return ::chmod(file.text(),bits)==0;
523 #endif
524 }
525 return false;
526 }
527
528
529 // Return true if file exists
exists(const FXString & file)530 FXbool FXStat::exists(const FXString& file){
531 FXTRACE((100,"FXStat::exists(\"%s\"\n",file.text()));
532 if(!file.empty()){
533 #ifdef WIN32
534 #ifdef UNICODE
535 FXnchar unifile[MAXPATHLEN];
536 utf2ncs(unifile,file.text(),MAXPATHLEN);
537 FXTRACE((100,"FXStat::exists: %d\n",(::GetFileAttributesW(unifile)!=INVALID_FILE_ATTRIBUTES)));
538 return ::GetFileAttributesW(unifile)!=INVALID_FILE_ATTRIBUTES;
539 #else
540 FXTRACE((100,"FXStat::exists: %d\n",(::GetFileAttributesA(file.text())!=INVALID_FILE_ATTRIBUTES)));
541 return ::GetFileAttributesA(file.text())!=INVALID_FILE_ATTRIBUTES;
542 #endif
543 #else
544 struct stat status;
545 FXTRACE((100,"FXStat::exists: %d\n",(::stat(file.text(),&status)==0)));
546 return ::stat(file.text(),&status)==0;
547 #endif
548 }
549 return false;
550 }
551
552
553 // Get file size
size(const FXString & file)554 FXlong FXStat::size(const FXString& file){
555 FXStat data;
556 statFile(file,data);
557 return data.size();
558 }
559
560
561 // Return file volume number
volume(const FXString & file)562 FXlong FXStat::volume(const FXString& file){
563 FXStat data;
564 statFile(file,data);
565 return data.volume();
566 }
567
568
569 // Return file index number
index(const FXString & file)570 FXlong FXStat::index(const FXString& file){
571 FXStat data;
572 statFile(file,data);
573 return data.index();
574 }
575
576
577 // Return number of links to file
links(const FXString & file)578 FXuint FXStat::links(const FXString& file){
579 FXStat data;
580 statFile(file,data);
581 return data.links();
582 }
583
584
585 // Return time file was last modified
modified(const FXString & file)586 FXTime FXStat::modified(const FXString& file){
587 FXStat data;
588 statFile(file,data);
589 return data.modified();
590 }
591
592
593 // Change tiome when file was last modified
modified(const FXString & file,FXTime ns)594 FXbool FXStat::modified(const FXString& file,FXTime ns){
595 if(!file.empty()){
596 #ifdef WIN32
597 #ifdef UNICODE
598 FXnchar unifile[MAXPATHLEN];
599 utf2ncs(unifile,file.text(),MAXPATHLEN);
600 FXInputHandle hnd=CreateFileW(unifile,GENERIC_READ|FILE_WRITE_ATTRIBUTES,0,NULL,OPEN_EXISTING,0,NULL);
601 #else
602 FXInputHandle hnd=CreateFileA(file.text(),GENERIC_READ|FILE_WRITE_ATTRIBUTES,0,NULL,OPEN_EXISTING,0,NULL);
603 #endif
604 if(hnd!=INVALID_HANDLE_VALUE){
605 FILETIME wintime;
606 *((FXTime*)&wintime)=fxwintime(ns);
607 if(SetFileTime(hnd,NULL,NULL,&wintime)!=0){
608 CloseHandle(hnd);
609 return true;
610 }
611 CloseHandle(hnd);
612 }
613 #else
614 #if (defined(_ATFILE_SOURCE) && defined(UTIME_OMIT))
615 const FXTime seconds=1000000000;
616 struct timespec values[2];
617 values[0].tv_sec=UTIME_OMIT;
618 values[0].tv_nsec=UTIME_OMIT;
619 values[1].tv_sec=ns/seconds;
620 values[1].tv_nsec=ns%seconds;
621 return utimensat(AT_FDCWD,file.text(),values,0)==0;
622 #else
623 const FXTime seconds=1000000;
624 struct stat data;
625 if(::stat(file.text(),&data)==0){
626 struct timeval values[2];
627 values[0].tv_sec=data.st_atime;
628 values[0].tv_usec=0;
629 values[1].tv_sec=ns/seconds;
630 values[1].tv_usec=ns%seconds;
631 return utimes(file.text(),values)==0;
632 }
633 #endif
634 #endif
635 }
636 return false;
637 }
638
639
640 // Return time file was last accessed
accessed(const FXString & file)641 FXTime FXStat::accessed(const FXString& file){
642 FXStat data;
643 statFile(file,data);
644 return data.accessed();
645 }
646
647
648 // Change tiome when file was last accessed
accessed(const FXString & file,FXTime ns)649 FXbool FXStat::accessed(const FXString& file,FXTime ns){
650 if(!file.empty()){
651 #ifdef WIN32
652 #ifdef UNICODE
653 FXnchar unifile[MAXPATHLEN];
654 utf2ncs(unifile,file.text(),MAXPATHLEN);
655 FXInputHandle hnd=CreateFileW(unifile,GENERIC_READ|FILE_WRITE_ATTRIBUTES,0,NULL,OPEN_EXISTING,0,NULL);
656 #else
657 FXInputHandle hnd=CreateFileA(file.text(),GENERIC_READ|FILE_WRITE_ATTRIBUTES,0,NULL,OPEN_EXISTING,0,NULL);
658 #endif
659 if(hnd!=INVALID_HANDLE_VALUE){
660 FILETIME wintime;
661 *((FXTime*)&wintime)=fxwintime(ns);
662 if(SetFileTime(hnd,NULL,&wintime,NULL)!=0){
663 CloseHandle(hnd);
664 return true;
665 }
666 CloseHandle(hnd);
667 }
668 #else
669 #if (defined(_ATFILE_SOURCE) && defined(UTIME_OMIT))
670 const FXTime seconds=1000000000;
671 struct timespec values[2];
672 values[0].tv_sec=ns/seconds;
673 values[0].tv_nsec=ns%seconds;
674 values[1].tv_sec=UTIME_OMIT;
675 values[1].tv_nsec=UTIME_OMIT;
676 return utimensat(AT_FDCWD,file.text(),values,0)==0;
677 #else
678 const FXTime seconds=1000000;
679 struct stat data;
680 if(::stat(file.text(),&data)==0){
681 struct timeval values[2];
682 values[0].tv_sec=ns/seconds;
683 values[0].tv_usec=ns%seconds;
684 values[1].tv_sec=data.st_mtime;
685 values[1].tv_usec=0;
686 return utimes(file.text(),values)==0;
687 }
688 #endif
689 #endif
690 }
691 return false;
692 }
693
694
695 // Return time when created
created(const FXString & file)696 FXTime FXStat::created(const FXString& file){
697 FXStat data;
698 statFile(file,data);
699 return data.created();
700 }
701
702
703 // Change time when file was last created
created(const FXString & file,FXTime ns)704 FXbool FXStat::created(const FXString& file,FXTime ns){
705 if(!file.empty()){
706 #ifdef WIN32
707 #ifdef UNICODE
708 FXnchar unifile[MAXPATHLEN];
709 utf2ncs(unifile,file.text(),MAXPATHLEN);
710 FXInputHandle hnd=CreateFileW(unifile,GENERIC_READ|FILE_WRITE_ATTRIBUTES,0,NULL,OPEN_EXISTING,0,NULL);
711 #else
712 FXInputHandle hnd=CreateFileA(file.text(),GENERIC_READ|FILE_WRITE_ATTRIBUTES,0,NULL,OPEN_EXISTING,0,NULL);
713 #endif
714 if(hnd!=INVALID_HANDLE_VALUE){
715 FILETIME wintime;
716 *((FXTime*)&wintime)=fxwintime(ns);
717 if(SetFileTime(hnd,&wintime,NULL,NULL)!=0){
718 CloseHandle(hnd);
719 return true;
720 }
721 CloseHandle(hnd);
722 }
723 #else
724 return false; // Not available on *NIX
725 #endif
726 }
727 return false;
728 }
729
730
731 // Return true if file is hidden
isHidden(const FXString & file)732 FXbool FXStat::isHidden(const FXString& file){
733 FXStat data;
734 return statFile(file,data) && data.isHidden();
735 }
736
737
738 // Check if file represents a file
isFile(const FXString & file)739 FXbool FXStat::isFile(const FXString& file){
740 FXStat data;
741 return statFile(file,data) && data.isFile();
742 }
743
744
745 // Check if file represents a link
isLink(const FXString & file)746 FXbool FXStat::isLink(const FXString& file){
747 FXStat data;
748 return statLink(file,data) && data.isLink();
749 }
750
751
752 // Check if file represents a directory
isDirectory(const FXString & file)753 FXbool FXStat::isDirectory(const FXString& file){
754 FXStat data;
755 return statFile(file,data) && data.isDirectory();
756 }
757
758
759 // Return true if file is readable
isReadable(const FXString & file)760 FXbool FXStat::isReadable(const FXString& file){
761 FXStat data;
762 return statFile(file,data) && data.isReadable();
763 }
764
765
766 // Return true if file is writable
isWritable(const FXString & file)767 FXbool FXStat::isWritable(const FXString& file){
768 FXStat data;
769 return statFile(file,data) && data.isWritable();
770 }
771
772
773 // Return true if file is executable
isExecutable(const FXString & file)774 FXbool FXStat::isExecutable(const FXString& file){
775 FXStat data;
776 return statFile(file,data) && data.isExecutable();
777 }
778
779
780 // Check if owner has full permissions
isOwnerReadWriteExecute(const FXString & file)781 FXbool FXStat::isOwnerReadWriteExecute(const FXString& file){
782 FXStat data;
783 return statFile(file,data) && data.isOwnerReadWriteExecute();
784 }
785
786
787 // Check if owner can read
isOwnerReadable(const FXString & file)788 FXbool FXStat::isOwnerReadable(const FXString& file){
789 FXStat data;
790 return statFile(file,data) && data.isOwnerReadable();
791 }
792
793
794 // Check if owner can write
isOwnerWritable(const FXString & file)795 FXbool FXStat::isOwnerWritable(const FXString& file){
796 FXStat data;
797 return statFile(file,data) && data.isOwnerWritable();
798 }
799
800
801 // Check if owner can execute
isOwnerExecutable(const FXString & file)802 FXbool FXStat::isOwnerExecutable(const FXString& file){
803 FXStat data;
804 return statFile(file,data) && data.isOwnerExecutable();
805 }
806
807
808 // Check if group has full permissions
isGroupReadWriteExecute(const FXString & file)809 FXbool FXStat::isGroupReadWriteExecute(const FXString& file){
810 FXStat data;
811 return statFile(file,data) && data.isGroupReadWriteExecute();
812 }
813
814
815 // Check if group can read
isGroupReadable(const FXString & file)816 FXbool FXStat::isGroupReadable(const FXString& file){
817 FXStat data;
818 return statFile(file,data) && data.isGroupReadable();
819 }
820
821
822 // Check if group can write
isGroupWritable(const FXString & file)823 FXbool FXStat::isGroupWritable(const FXString& file){
824 FXStat data;
825 return statFile(file,data) && data.isGroupWritable();
826 }
827
828
829 // Check if group can execute
isGroupExecutable(const FXString & file)830 FXbool FXStat::isGroupExecutable(const FXString& file){
831 FXStat data;
832 return statFile(file,data) && data.isGroupExecutable();
833 }
834
835
836 // Check if everybody has full permissions
isOtherReadWriteExecute(const FXString & file)837 FXbool FXStat::isOtherReadWriteExecute(const FXString& file){
838 FXStat data;
839 return statFile(file,data) && data.isOtherReadWriteExecute();
840 }
841
842
843 // Check if everybody can read
isOtherReadable(const FXString & file)844 FXbool FXStat::isOtherReadable(const FXString& file){
845 FXStat data;
846 return statFile(file,data) && data.isOtherReadable();
847 }
848
849
850 // Check if everybody can write
isOtherWritable(const FXString & file)851 FXbool FXStat::isOtherWritable(const FXString& file){
852 FXStat data;
853 return statFile(file,data) && data.isOtherWritable();
854 }
855
856
857 // Check if everybody can execute
isOtherExecutable(const FXString & file)858 FXbool FXStat::isOtherExecutable(const FXString& file){
859 FXStat data;
860 return statFile(file,data) && data.isOtherExecutable();
861 }
862
863
864 // Test if suid bit set
isSetUid(const FXString & file)865 FXbool FXStat::isSetUid(const FXString& file){
866 FXStat data;
867 return statFile(file,data) && data.isSetUid();
868 }
869
870
871 // Test if sgid bit set
isSetGid(const FXString & file)872 FXbool FXStat::isSetGid(const FXString& file){
873 FXStat data;
874 return statFile(file,data) && data.isSetGid();
875 }
876
877
878 // Test if sticky bit set
isSetSticky(const FXString & file)879 FXbool FXStat::isSetSticky(const FXString& file){
880 FXStat data;
881 return statFile(file,data) && data.isSetSticky();
882 }
883
884
885 // Return true if file is accessible
isAccessible(const FXString & file,FXuint m)886 FXbool FXStat::isAccessible(const FXString& file,FXuint m){
887 if(!file.empty()){
888 #ifdef WIN32
889 #ifdef UNICODE
890 FXnchar unifile[MAXPATHLEN];
891 FXuint mode=0;
892 if(m&FXIO::ReadOnly) mode|=4;
893 if(m&FXIO::WriteOnly) mode|=2;
894 utf2ncs(unifile,file.text(),MAXPATHLEN);
895 return _waccess(unifile,mode)==0;
896 #else
897 FXuint mode=0;
898 if(m&FXIO::ReadOnly) mode|=4;
899 if(m&FXIO::WriteOnly) mode|=2;
900 return _access(file.text(),mode)==0;
901 #endif
902 #else
903 FXuint mode=F_OK;
904 if(m&FXIO::ReadOnly) mode|=R_OK;
905 if(m&FXIO::WriteOnly) mode|=W_OK;
906 if(m&FXIO::Executable) mode|=X_OK;
907 return access(file.text(),mode)==0;
908 #endif
909 }
910 return false;
911 }
912
913
914 // Obtain total amount of space on disk
getTotalDiskSpace(const FXString & path,FXulong & space)915 FXbool FXStat::getTotalDiskSpace(const FXString& path,FXulong& space){
916 #ifdef WIN32
917 #ifdef UNICODE
918 FXnchar unifile[MAXPATHLEN];
919 utf2ncs(unifile,path.text(),MAXPATHLEN);
920 if(GetDiskFreeSpaceExW(unifile,NULL,(PULARGE_INTEGER)&space,NULL)){
921 return true;
922 }
923 #else
924 if(GetDiskFreeSpaceExA(path.text(),NULL,(PULARGE_INTEGER)&space,NULL)){
925 return true;
926 }
927 #endif
928 #else
929 #if defined(HAVE_STATVFS) && defined(HAVE_SYS_STATVFS_H)
930 struct statvfs info;
931 if(statvfs(path.text(),&info)==0){
932 space=info.f_bsize*info.f_blocks;
933 return true;
934 }
935 #endif
936 #endif
937 return false;
938 }
939
940
941 // Obtain available amount of space on disk
getAvailableDiskSpace(const FXString & path,FXulong & space)942 FXbool FXStat::getAvailableDiskSpace(const FXString& path,FXulong& space){
943 #ifdef WIN32
944 #ifdef UNICODE
945 FXnchar unifile[MAXPATHLEN];
946 utf2ncs(unifile,path.text(),MAXPATHLEN);
947 if(GetDiskFreeSpaceExW(unifile,(PULARGE_INTEGER)&space,NULL,NULL)){
948 return true;
949 }
950 #else
951 if(GetDiskFreeSpaceExA(path.text(),(PULARGE_INTEGER)&space,NULL,NULL)){
952 return true;
953 }
954 #endif
955 #else
956 #if defined(HAVE_STATVFS) && defined(HAVE_SYS_STATVFS_H)
957 struct statvfs info;
958 if(statvfs(path.text(),&info)==0){
959 space=info.f_bsize*info.f_bfree;
960 return true;
961 }
962 #endif
963 #endif
964 return false;
965 }
966
967 }
968