1 #include "Core.h"
2 #include "Core.h"
3 //#BLITZ_APPROVE
4
5 #ifdef PLATFORM_POSIX
6 #include <sys/types.h>
7 #include <utime.h>
8 #endif//PLATFORM_POSIX
9
10 #ifdef PLATFORM_WIN32
11
12 #define Ptr Ptr_
13 #define byte byte_
14 #define CY win32_CY_
15
16 #include <winnls.h>
17 #include <winnetwk.h>
18
19 #include <wincon.h>
20
21 #ifdef COMPILER_MINGW
22 #undef CY
23 #endif
24
25 #include <shlobj.h>
26
27 #undef Ptr
28 #undef byte
29 #undef CY
30
31 #endif
32
33 namespace Upp {
34
sDirSep(int c)35 static int sDirSep(int c) {
36 return c == '/' || c == '\\' ? c : 0;
37 }
38
strecmp0(const char * p,const char * s)39 static bool strecmp0(const char *p, const char *s) {
40 while(*p) {
41 if(*p == '*') {
42 while(*p == '*') p++;
43 do
44 if(ToUpper(*p) == ToUpper(*s) && strecmp0(p, s)) return true;
45 while(*s++);
46 return false;
47 }
48 if(*p == '?') {
49 if(*s == '\0') return false;
50 }
51 else
52 if(ToUpper(*p) != ToUpper(*s)) return false;
53 s++;
54 p++;
55 }
56 return *s == '\0';
57 }
58
PatternMatch(const char * p,const char * s)59 bool PatternMatch(const char *p, const char *s) {
60 const char *q;
61 q = strchr(p, '.');
62 if(q) {
63 if(q[1] == '\0') {
64 if(strchr(s, '.')) return false;
65 String h(p, q);
66 return strecmp0(h, s);
67 }
68 else
69 if(q[1] == '*' && q[2] == '\0') {
70 String h(p, q);
71 return strecmp0(h, s) || strecmp0(p, s);
72 }
73 }
74 return strecmp0(p, s);
75 }
76
PatternMatchMulti(const char * p,const char * s)77 bool PatternMatchMulti(const char *p, const char *s) {
78 String pt;
79 while(*p) {
80 if(*p == ';' || *p == ',' || *p == ' ') {
81 if(PatternMatch(pt, s)) return true;
82 p++;
83 while(*p == ';' || *p == ',' || *p == ' ') p++;
84 pt.Clear();
85 }
86 else
87 pt.Cat(*p++);
88 }
89 return pt.IsEmpty() ? false : PatternMatch(pt, s);
90 }
91
GetFileNamePos(const char * fileName)92 const char *GetFileNamePos(const char *fileName) {
93 const char *s = fileName;
94 const char *fname = s;
95 char c;
96 while((c = *s++) != '\0')
97 #ifdef PLATFORM_WIN32
98 if(c == '\\' || c == ':' || c == '/')
99 #else
100 if(c == '/')
101 #endif
102 fname = s;
103 return fname;
104 }
105
GetFileExtPos(const char * fileName)106 const char *GetFileExtPos(const char *fileName) {
107 fileName = GetFileNamePos(fileName);
108 const char *ext = strrchr(fileName, '.');
109 return ext ? ext : fileName + strlen(fileName);
110 }
111
HasFileExt(const char * path)112 bool HasFileExt(const char *path) {
113 return *GetFileExtPos(path);
114 }
115
HasWildcards(const char * fileName)116 bool HasWildcards(const char *fileName) {
117 return strchr(fileName, '*') || strchr(fileName, '?');
118 }
119
IsFullPath(const char * r)120 bool IsFullPath(const char *r) {
121 #ifdef PLATFORM_WIN32
122 return *r && r[1] && (r[1] == ':' || r[0] == '\\' && r[1] == '\\' || r[0] == '/' && r[1] == '/');
123 #endif
124 #ifdef PLATFORM_POSIX
125 return *r == '/';
126 #endif
127 }
128
GetFileDirectory(const char * fileName)129 String GetFileDirectory(const char *fileName) {
130 return String(fileName, (int)(GetFileNamePos(fileName) - fileName));
131 }
132
GetFileFolder(const char * fileName)133 String GetFileFolder(const char *fileName) {
134 const char *s = GetFileNamePos(fileName);
135 #ifdef PLATFORM_WIN32
136 if(s - fileName == 3 && fileName[1] == ':')
137 return String(fileName, 3);
138 #endif
139 #ifdef PLATFORM_POSIX
140 if(s - fileName == 1 && s[0] == '/')
141 return "/";
142 #endif
143 if(s > fileName)
144 return String(fileName, (int)(s - fileName) - 1);
145 return Null;
146 }
147
GetFileTitle(const char * fileName)148 String GetFileTitle(const char *fileName) {
149 fileName = GetFileNamePos(fileName);
150 const char *ext = GetFileExtPos(fileName);
151 if(*ext)
152 return String(fileName, (int)(ext - fileName));
153 else
154 return fileName;
155 }
156
GetFileExt(const char * fileName)157 String GetFileExt(const char *fileName) {
158 return GetFileExtPos(fileName);
159 }
160
GetFileName(const char * fileName)161 String GetFileName(const char *fileName) {
162 return GetFileNamePos(fileName);
163 }
164
AppendFileName(const String & path,const char * fileName)165 String AppendFileName(const String& path, const char *fileName) {
166 String result = path;
167 if(result.GetLength() && *result.Last() != DIR_SEP && *fileName != DIR_SEP)
168 result += DIR_SEP;
169 result += fileName;
170 return result;
171 }
172
173 #ifdef PLATFORM_WIN32
PathIsEqual(const char * p1,const char * p2)174 bool PathIsEqual(const char *p1, const char *p2)
175 {
176 return ToLower(NormalizePath(p1)) == ToLower(NormalizePath(p2));
177 }
178 #endif
179
180 #ifdef PLATFORM_POSIX
PathIsEqual(const char * p1,const char * p2)181 bool PathIsEqual(const char *p1, const char *p2)
182 {
183 return NormalizePath(p1) == NormalizePath(p2);
184 }
185 #endif
186
187 #ifndef PLATFORM_WINCE
GetCurrentDirectory()188 String GetCurrentDirectory() {
189 #if defined(PLATFORM_WIN32)
190 wchar h[MAX_PATH];
191 GetCurrentDirectoryW(MAX_PATH, h);
192 return FromSystemCharsetW(h);
193 #elif defined(PLATFORM_POSIX)
194 char h[1024];
195 return getcwd(h, 1024) ? FromSystemCharset(h) : String();
196 #else
197 #error GetCurrentDirectory not implemented for this platform, comment this line to get Null
198 return Null;
199 #endif//PLATFORM
200 }
201 #endif
202
203 #ifdef PLATFORM_POSIX
SetCurrentDirectory(const char * path)204 bool SetCurrentDirectory(const char *path)
205 {
206 return chdir(path) == 0;
207 }
208 #endif
209
210 #if defined(PLATFORM_WIN32) && !defined(PLATFORM_WINCE)
211
GetTempPath()212 String GetTempPath()
213 {
214 wchar h[MAX_PATH];
215 GetTempPathW(MAX_PATH, h);
216 return FromSystemCharsetW(h);
217 }
218
219 #endif
220
221 #ifdef PLATFORM_POSIX
222
GetTempPath()223 String GetTempPath()
224 {
225 return FromSystemCharset(P_tmpdir);
226 }
227
228 #endif
229
230 #ifndef PLATFORM_WINCE
GetTempFileName(const char * prefix)231 String GetTempFileName(const char *prefix) {
232 Uuid id = Uuid::Create();
233 return AppendFileName(GetTempPath(), String(prefix) + Format(id) + ".tmp");
234 }
235 #endif
236
FromUnixName(const char * fn,const char * stop=NULL)237 String FromUnixName(const char* fn, const char* stop = NULL) {
238 String s;
239 char c;
240 while(fn != stop && (c = *fn++))
241 s += (c == '/' ? '\\' : c);
242 return s;
243 }
244
ToUnixName(const char * fn,const char * stop=NULL)245 String ToUnixName(const char* fn, const char* stop = NULL) {
246 String s;
247 char c;
248 while(fn != stop && (c = *fn++))
249 s += (c == '\\' ? '/' : c);
250 return s;
251 }
252
GetFullPath(const char * file)253 String GetFullPath(const char *file) {
254 #ifdef PLATFORM_WIN32
255 String ufn = FromUnixName(file);
256 wchar h[MAX_PATH];
257 GetFullPathNameW(ToSystemCharsetW(ufn), MAX_PATH, h, 0);
258 return FromSystemCharsetW(h);
259 #else
260 return NormalizePath(file);
261 #endif
262 }
263
GetFileOnPath(const char * file,const char * paths,bool current,const char * curdir)264 String GetFileOnPath(const char* file, const char* paths, bool current, const char *curdir) {
265 String ufn = NativePath(file);
266 if(IsFullPath(ufn) && FileExists(ufn))
267 return ufn;
268 String fn;
269 String cd = curdir;
270 if(!curdir)
271 cd = GetCurrentDirectory();
272 if(current && FileExists(fn = NormalizePath(ufn, cd)))
273 ;
274 else if(paths)
275 {
276 fn = Null;
277 while(*paths) {
278 const char* start = paths;
279 #ifdef PLATFORM_WIN32
280 while(*paths && *paths != ';')
281 paths++;
282 #else
283 while(*paths && *paths != ';' && *paths != ':')
284 paths++;
285 #endif
286 String dir(start, (int)(paths - start));
287 if(!dir.IsEmpty()) {
288 #ifdef PLATFORM_WINCE
289 dir = NormalizePath(AppendFileName(NativePath(dir), ufn));
290 #else
291 dir = NormalizePath(AppendFileName(NativePath(dir), ufn), cd);
292 #endif
293 if(FileExists(dir)) {
294 fn = dir;
295 break;
296 }
297 }
298 if(*paths)
299 paths++;
300 }
301 }
302 return fn;
303 }
304
WinPath(const char * p)305 String WinPath(const char *p) {
306 String r;
307 while(*p) {
308 r.Cat(*p == '/' ? '\\' : *p);
309 p++;
310 }
311 return r;
312 }
313
UnixPath(const char * p)314 String UnixPath(const char *p) {
315 String r;
316 while(*p) {
317 r.Cat(*p == '\\' ? '/' : *p);
318 p++;
319 }
320 return r;
321 }
322
AppendExt(const char * fn,const char * ext)323 String AppendExt(const char* fn, const char* ext) {
324 String result = NativePath(fn);
325 if(!HasFileExt(fn))
326 result += ext;
327 return result;
328 }
329
ForceExt(const char * fn,const char * ext)330 String ForceExt(const char* fn, const char* ext) {
331 return NativePath(String(fn, GetFileExtPos(fn))) + ext;
332 }
333
334 #ifdef PLATFORM_WIN32
335
~FindFile()336 FindFile::~FindFile()
337 {
338 Close();
339 }
340
FindFile()341 FindFile::FindFile()
342 {
343 handle = INVALID_HANDLE_VALUE;
344 }
345
FindFile(const char * name)346 FindFile::FindFile(const char *name) {
347 handle = INVALID_HANDLE_VALUE;
348 Search(name);
349 }
350
Search(const char * name)351 bool FindFile::Search(const char *name) {
352 pattern = GetFileName(name);
353 path = NormalizePath(GetFileDirectory(name));
354 Close();
355 handle = FindFirstFileW(ToSystemCharsetW(name), data);
356 if(handle == INVALID_HANDLE_VALUE)
357 return false;
358 if(!PatternMatch(pattern, GetName()))
359 return Next();
360 return true;
361 }
362
sGetSymLinkPath0(const char * linkpath,String * path)363 static bool sGetSymLinkPath0(const char *linkpath, String *path)
364 {
365 bool ret = false;
366 HRESULT hres;
367 IShellLink* psl;
368 IPersistFile* ppf;
369 CoInitialize(NULL);
370 hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink,
371 (PVOID *) &psl);
372 if(SUCCEEDED(hres)) {
373 hres = psl->QueryInterface(IID_IPersistFile, (PVOID *) &ppf);
374 if(SUCCEEDED(hres)) {
375 hres = ppf->Load(ToSystemCharsetW(linkpath), STGM_READ);
376 if(SUCCEEDED(hres)) {
377 if(path) {
378 char fileW[_MAX_PATH] = {0};
379 psl->GetPath(fileW, _MAX_PATH, NULL, 0);
380 *path = FromSystemCharset(fileW);
381 }
382 else
383 ret = true;
384 }
385 ppf->Release();
386 }
387 psl->Release();
388 }
389 CoUninitialize();
390 return ret;
391 }
392
IsSymLink() const393 bool FindFile::IsSymLink() const
394 {
395 String name = GetName();
396 if(GetFileExt(name) != ".lnk")
397 return false;
398 return sGetSymLinkPath0(AppendFileName(path, name), NULL);
399 }
400
IsExecutable() const401 bool FindFile::IsExecutable() const
402 {
403 return !IsDirectory() && ToLower(GetName()).EndsWith(".exe");
404 }
405
Close()406 void FindFile::Close() {
407 if(handle != INVALID_HANDLE_VALUE) FindClose(handle);
408 handle = INVALID_HANDLE_VALUE;
409 }
410
Next0()411 bool FindFile::Next0() {
412 if(!FindNextFileW(handle, data)) {
413 Close();
414 return false;
415 }
416 return true;
417 }
418
Next()419 bool FindFile::Next()
420 {
421 for(;;) {
422 if(!Next0())
423 return false;
424 if(PatternMatch(pattern, GetName()))
425 return true;
426 }
427 }
428
GetName() const429 String FindFile::GetName() const
430 {
431 return FromSystemCharsetW(data->cFileName);
432 }
433
GetLength() const434 int64 FindFile::GetLength() const
435 {
436 return (int64)data->nFileSizeLow | ((int64)data->nFileSizeHigh << 32);
437 }
438
IsFolder() const439 bool FindFile::IsFolder() const {
440 auto h = data->cFileName;
441 return IsDirectory() && !(h[0] == '.' && h[1] == 0) && !(h[0] == '.' && h[1] == '.' && h[2] == 0);
442 }
443
NormalizePath(const char * path,const char * currdir)444 String NormalizePath(const char *path, const char *currdir)
445 {
446 String join_path;
447 if(!IsFullPath(path))
448 path = join_path = AppendFileName(currdir, path);
449 String out;
450 if(*path && path[1] == ':') {
451 out << path[0] << ":\\";
452 path += 3;
453 }
454 else
455 if(path[0] == '\\' && path[1] == '\\') {
456 out = "\\\\";
457 path += 2;
458 }
459 else
460 if(sDirSep(*path)) {
461 if(*currdir)
462 out << *currdir << ':';
463 out.Cat(DIR_SEP);
464 path++;
465 }
466 int outstart = out.GetLength();
467 while(*path) {
468 if(sDirSep(*path)) {
469 while(sDirSep(*path))
470 path++;
471 if(*path == '\0')
472 break;
473 if(out.IsEmpty() || *out.Last() != DIR_SEP)
474 out.Cat(DIR_SEP);
475 }
476 const char *b = path;
477 while(*path && !sDirSep(*path))
478 path++;
479 if(path - b == 1 && *b == '.')
480 ; //no-op
481 else if(path - b == 2 && *b == '.' && b[1] == '.') {
482 const char *ob = ~out + outstart, *oe = out.End();
483 if(oe - 1 > ob && oe[-1] == DIR_SEP)
484 oe--;
485 while(oe > ob && oe[-1] != DIR_SEP)
486 oe--;
487 out.Trim((int)(oe - out.Begin()));
488 }
489 else
490 out.Cat(b, (int)(path - b));
491 }
492 return out;
493 }
494
495 #endif
496
497 #ifdef PLATFORM_POSIX
498
Close()499 void FindFile::Close() {
500 if(dir) {
501 closedir(dir);
502 dir = NULL;
503 }
504 }
505
IsFolder() const506 bool FindFile::IsFolder() const {
507 return IsDirectory()
508 && !(name[0] == '.' && name[1] == '\0')
509 && !(name[0] == '.' && name[1] == '.' && name[2] == '\0');
510 }
511
Stat() const512 struct stat& FindFile::Stat() const {
513 if(!statis) {
514 statis = true;
515 if(file)
516 stat(ToSystemCharset(AppendFileName(path, name)), &statf);
517 }
518 return statf;
519 }
520
CanMode(dword usr,dword grp,dword oth) const521 bool FindFile::CanMode(dword usr, dword grp, dword oth) const
522 {
523 const struct stat& s = Stat();
524 dword mode = GetMode();
525 static uid_t uid = getuid();
526 static gid_t gid = getgid();
527 return (mode & oth) ||
528 (mode & grp) && gid == s.st_gid ||
529 (mode & usr) && uid == s.st_uid;
530 }
531
IsSymLink() const532 bool FindFile::IsSymLink() const
533 {
534 if(file) {
535 struct stat stf;
536 lstat(AppendFileName(path, name), &stf);
537 return S_ISLNK(stf.st_mode);
538 }
539 return false;
540 }
541
IsExecutable() const542 bool FindFile::IsExecutable() const
543 {
544 return !IsDirectory() && ((S_IXUSR|S_IXGRP|S_IXOTH) & GetMode());
545 }
546
Next()547 bool FindFile::Next() {
548 file = false;
549 if(!dir) return false;
550 statis = false;
551 for(;;) {
552 struct dirent *e = readdir(dir);
553 if(!e) {
554 name.Clear();
555 file = false;
556 Close();
557 return false;
558 }
559 name = FromSystemCharset(e->d_name);
560 if(PatternMatch(pattern, name)) {
561 file = true;
562 return true;
563 }
564 }
565 }
566
Search(const char * fn)567 bool FindFile::Search(const char *fn) {
568 Close();
569 path = NormalizePath(GetFileDirectory(fn));
570 statis = false;
571 file = false;
572 if(HasWildcards(fn)) {
573 pattern = GetFileName(fn);
574 dir = opendir(ToSystemCharset(path));
575 return Next();
576 }
577 else {
578 name = GetFileName(fn);
579 if(stat(ToSystemCharset(fn), &statf)) return false;
580 statis = true;
581 file = true;
582 return true;
583 }
584 }
585
FindFile(const char * fn)586 FindFile::FindFile(const char *fn) {
587 dir = NULL;
588 Search(fn);
589 }
590
NormalizePath(const char * path,const char * currdir)591 String NormalizePath(const char *path, const char *currdir) {
592 Vector<String> si = Split(path, sDirSep);
593 Vector<String> p;
594 int i = 0;
595 String out;
596 if(path[0] == '~') {
597 out = GetHomeDirectory();
598 i++;
599 }
600 else
601 if(sDirSep(path[0]))
602 out = (sDirSep(path[1]) ? "//" : "/");
603 else {
604 out = (sDirSep(currdir[0]) && sDirSep(currdir[1]) ? "//" : "/");
605 p = Split(currdir, sDirSep);
606 }
607 for(; i < si.GetCount(); i++) {
608 String s = si[i];
609 if(s != "." && !s.IsEmpty()) {
610 if(s[0] == '.' && s[1] == '.') {
611 if(!p.IsEmpty()) p.Drop();
612 }
613 else
614 p.Add(s);
615 }
616 }
617 out.Cat(Join(p, DIR_SEPS));
618 return out;
619 }
620
621 #endif//PLATFORM_POSIX
622
GetPath() const623 String FindFile::GetPath() const
624 {
625 return AppendFileName(path, GetName());
626 }
627
FileExists(const char * name)628 bool FileExists(const char *name) {
629 FindFile ff(name);
630 return ff && ff.IsFile();
631 }
632
GetFileLength(const char * name)633 int64 GetFileLength(const char *name) {
634 FindFile ff(name);
635 return ff ? ff.GetLength() : -1;
636 }
637
DirectoryExists(const char * name)638 bool DirectoryExists(const char *name) {
639 FindFile ff(name + String("/*"));
640 return ff;
641 }
642
NormalizePath(const char * path)643 String NormalizePath(const char *path) {
644 #ifdef PLATFORM_WINCE
645 return NormalizePath(path, "");
646 #else
647 return NormalizePath(path, GetCurrentDirectory());
648 #endif
649 }
650
FileCopy(const char * oldname,const char * newname)651 bool FileCopy(const char *oldname, const char *newname)
652 {
653 #if defined(PLATFORM_WIN32)
654 return CopyFileW(ToSystemCharsetW(oldname), ToSystemCharsetW(newname), false);
655 #elif defined(PLATFORM_POSIX)
656 FileIn fi(oldname);
657 if(!fi.IsOpen())
658 return false;
659 FileOut fo(newname);
660 if(!fo.IsOpen())
661 return false;
662 CopyStream(fo, fi, fi.GetLeft());
663 fi.Close();
664 fo.Close();
665 if(fo.IsError())
666 {
667 unlink(newname);
668 return false;
669 }
670 FileSetTime(newname, FileGetTime(oldname));
671 return true;
672 #else
673 #error
674 #endif//PLATFORM
675 }
676
FileMove(const char * oldname,const char * newname)677 bool FileMove(const char *oldname, const char *newname)
678 {
679 #if defined(PLATFORM_WIN32)
680 return !!MoveFileW(ToSystemCharsetW(oldname), ToSystemCharsetW(newname));
681 #elif defined(PLATFORM_POSIX)
682 return !rename(ToSystemCharset(oldname), ToSystemCharset(newname));
683 #else
684 #error
685 #endif//PLATFORM
686 }
687
FileDelete(const char * filename)688 bool FileDelete(const char *filename)
689 {
690 #if defined(PLATFORM_WIN32)
691 return !!DeleteFileW(ToSystemCharsetW(filename));
692 #elif defined(PLATFORM_POSIX)
693 return !unlink(ToSystemCharset(filename));
694 #else
695 #error
696 #endif//PLATFORM
697 return false;
698 }
699
DirectoryDelete(const char * dirname)700 bool DirectoryDelete(const char *dirname)
701 {
702 #if defined(PLATFORM_WIN32)
703 return !!RemoveDirectoryW(ToSystemCharsetW(dirname));
704 #elif defined(PLATFORM_POSIX)
705 return !rmdir(ToSystemCharset(dirname));
706 #else
707 #error
708 #endif//PLATFORM
709 return false;
710 }
711
712 #ifdef PLATFORM_WIN32
Compare_FileTime(const FileTime & fa,const FileTime & fb)713 int Compare_FileTime(const FileTime& fa, const FileTime& fb)
714 {
715 return CompareFileTime(&fa, &fb);
716 }
717 #endif
718
FileGetTime(const char * filename)719 Time FileGetTime(const char *filename)
720 {
721 #if defined(PLATFORM_WIN32)
722 HANDLE handle;
723 handle = CreateFileW(ToSystemCharsetW(filename), GENERIC_READ,
724 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
725 if(handle == INVALID_HANDLE_VALUE)
726 return Null;
727 FileTime ft;
728 bool res = GetFileTime(handle, 0, 0, &ft);
729 CloseHandle(handle);
730 return res ? Time(ft) : Time(Null);
731 #elif defined(PLATFORM_POSIX)
732 struct stat st;
733 if(stat(ToSystemCharset(filename), &st))
734 return Null;
735 return Time(st.st_mtime);
736 #else
737 #error
738 #endif//PLATFORM
739 }
740
GetFileTime(const char * filename)741 FileTime GetFileTime(const char *filename)
742 {
743 #if defined(PLATFORM_WIN32)
744 HANDLE handle;
745 handle = CreateFileW(ToSystemCharsetW(filename), GENERIC_READ,
746 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
747 FileTime ft0;
748 memset(&ft0, 0, sizeof(ft0));
749 if(handle == INVALID_HANDLE_VALUE)
750 return ft0;
751 FileTime ft;
752 bool res = GetFileTime(handle, 0, 0, &ft);
753 CloseHandle(handle);
754 return res ? ft : ft0;
755 #elif defined(PLATFORM_POSIX)
756 struct stat st;
757 if(stat(ToSystemCharset(filename), &st))
758 return 0;
759 return st.st_mtime;
760 #else
761 #error
762 #endif//PLATFORM
763 }
764
SetFileTime(const char * filename,FileTime ft)765 bool SetFileTime(const char *filename, FileTime ft)
766 {
767 #if defined(PLATFORM_WIN32)
768 HANDLE handle;
769 handle = CreateFileW(ToSystemCharsetW(filename), GENERIC_READ | GENERIC_WRITE,
770 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
771 if(handle == INVALID_HANDLE_VALUE)
772 return false;
773 bool res = SetFileTime(handle, 0, 0, &ft);
774 CloseHandle(handle);
775 return res;
776 #elif defined(PLATFORM_POSIX)
777 struct utimbuf ub;
778 ub.actime = ub.modtime = ft;
779 return !utime(ToSystemCharset(filename), &ub);
780 #else
781 #error
782 #endif//PLATFORM
783 }
784
FileSetTime(const char * filename,Time time)785 bool FileSetTime(const char *filename, Time time)
786 {
787 return SetFileTime(filename, TimeToFileTime(time));
788 }
789
TimeToFileTime(Time time)790 FileTime TimeToFileTime(Time time)
791 {
792 #ifdef PLATFORM_WIN32
793 SYSTEMTIME tm;
794 Zero(tm);
795 tm.wYear = time.year;
796 tm.wMonth = time.month;
797 tm.wDay = time.day;
798 tm.wHour = time.hour;
799 tm.wMinute = time.minute;
800 tm.wSecond = time.second;
801 FileTime ftl, ftg;
802 SystemTimeToFileTime(&tm, &ftl);
803 LocalFileTimeToFileTime(&ftl, &ftg);
804 return ftg;
805 #endif
806 #ifdef PLATFORM_POSIX
807 struct tm t;
808 t.tm_sec = time.second;
809 t.tm_min = time.minute;
810 t.tm_hour = time.hour;
811 t.tm_mday = time.day;
812 t.tm_mon = time.month - 1;
813 t.tm_year = time.year - 1900;
814 return mktime(&t);
815 #endif
816 }
817
818 #ifdef PLATFORM_POSIX
DirectoryCreate(const char * path,int mode)819 bool DirectoryCreate(const char *path, int mode)
820 {
821 return ::mkdir(ToSystemCharset(path), mode) == 0;
822 }
823
RealizePath(const String & file,int mode)824 bool RealizePath(const String& file, int mode)
825 {
826 return RealizeDirectory(GetFileFolder(file), mode);
827 }
828 #else
DirectoryCreate(const char * path)829 bool DirectoryCreate(const char *path)
830 {
831 return !!CreateDirectoryW(ToSystemCharsetW(path), 0);
832 }
833
RealizePath(const String & file)834 bool RealizePath(const String& file)
835 {
836 return RealizeDirectory(GetFileFolder(file));
837 }
838 #endif
839
840 #ifdef PLATFORM_WIN32
841 #define DIR_MIN 3 //!! wrong! what about \a\b\c ?
842 #endif
843
844 #ifdef PLATFORM_POSIX
845 #define DIR_MIN 1
846 #endif
847
848 #ifdef PLATFORM_POSIX
RealizeDirectory(const String & d,int mode)849 bool RealizeDirectory(const String& d, int mode)
850 #else
851 bool RealizeDirectory(const String& d)
852 #endif
853 {
854 String dir = NormalizePath(d);
855 Vector<String> p;
856 while(dir.GetLength() > DIR_MIN && !DirectoryExists(dir)) {
857 p.Add(dir);
858 dir = GetFileFolder(dir);
859 }
860 for(int i = p.GetCount() - 1; i >= 0; i--)
861 #ifdef PLATFORM_POSIX
862 if(!DirectoryCreate(p[i], mode))
863 #else
864 if(!DirectoryCreate(p[i]))
865 #endif
866 return false;
867 return true;
868 }
869
DeleteFolderDeep(const char * dir)870 bool DeleteFolderDeep(const char *dir)
871 {
872 {
873 FindFile ff(AppendFileName(dir, "*.*"));
874 while(ff) {
875 String name = ff.GetName();
876 String p = AppendFileName(dir, name);
877 if(ff.IsFile() || ff.IsSymLink())
878 FileDelete(p);
879 else
880 if(ff.IsFolder())
881 DeleteFolderDeep(p);
882 ff.Next();
883 }
884 }
885 return DirectoryDelete(dir);
886 }
887
GetSymLinkPath(const char * linkpath)888 String GetSymLinkPath(const char *linkpath)
889 {
890 #ifdef PLATFORM_WIN32
891 String path;
892 sGetSymLinkPath0(linkpath, &path);
893 return path;
894 #else
895 char buff[_MAX_PATH + 1];
896 int len = readlink(linkpath, buff, _MAX_PATH);
897 if(len > 0 && len < _MAX_PATH)
898 return String(buff, len);
899 return Null;
900 #endif
901 }
902
FileInfo()903 FileSystemInfo::FileInfo::FileInfo()
904 : length(Null), read_only(false), is_directory(false)
905 , is_folder(false), is_file(false), is_symlink(false), is_archive(false)
906 , is_compressed(false), is_hidden(false), is_read_only(false), is_system(false)
907 , is_temporary(false), root_style(ROOT_NO_ROOT_DIR)
908 {}
909
StdFileSystemInfo()910 FileSystemInfo& StdFileSystemInfo()
911 {
912 static FileSystemInfo h;
913 return h;
914 }
915
GetStyle() const916 int FileSystemInfo::GetStyle() const
917 {
918 #ifdef PLATFORM_WIN32
919 return STYLE_WIN32;
920 #endif
921 #ifdef PLATFORM_POSIX
922 return STYLE_POSIX;
923 #endif
924 }
925
Find(String mask,int max_count,bool unmounted) const926 Array<FileSystemInfo::FileInfo> FileSystemInfo::Find(String mask, int max_count, bool unmounted) const
927 {
928 Array<FileInfo> fi;
929 if(IsNull(mask))
930 { // root
931 #ifdef PLATFORM_WINCE
932 FileInfo& f = fi.Add();
933 f.filename = "\\";
934 f.root_style = ROOT_FIXED;
935 #elif defined(PLATFORM_WIN32)
936 char drive[4] = "?:\\";
937 for(int c = 'A'; c <= 'Z'; c++) {
938 *drive = c;
939 int n = GetDriveType(drive);
940 if(n == DRIVE_NO_ROOT_DIR)
941 continue;
942 FileInfo& f = fi.Add();
943 f.filename = drive;
944 char name[256], system[256];
945 DWORD d;
946 if(c != 'A' && c != 'B' && n != DRIVE_REMOTE && n != DRIVE_UNKNOWN) {
947 bool b = GetVolumeInformation(drive, name, 256, &d, &d, &d, system, 256);
948 if(b) {
949 if(*name) f.root_desc << " " << FromSystemCharset(name);
950 }
951 else if(n == DRIVE_REMOVABLE || n == DRIVE_CDROM) {
952 if(unmounted) {
953 f.root_desc = t_("Empty drive");
954 } else {
955 fi.Drop();
956 continue;
957 }
958 }
959 }
960 switch(n)
961 {
962 default:
963 case DRIVE_UNKNOWN: f.root_style = ROOT_UNKNOWN; break;
964 case DRIVE_NO_ROOT_DIR: f.root_style = ROOT_NO_ROOT_DIR; break;
965 case DRIVE_REMOVABLE: f.root_style = ROOT_REMOVABLE; break;
966 case DRIVE_FIXED: f.root_style = ROOT_FIXED; break;
967 case DRIVE_REMOTE: f.root_style = ROOT_REMOTE; break;
968 case DRIVE_CDROM: f.root_style = ROOT_CDROM; break;
969 case DRIVE_RAMDISK: f.root_style = ROOT_RAMDISK; break;
970 }
971 }
972
973 #elif defined(PLATFORM_POSIX)
974 FileInfo& f = fi.Add();
975 f.filename = "/";
976 f.root_style = ROOT_FIXED;
977 #endif
978 }
979 else
980 {
981 FindFile ff;
982 if(ff.Search(mask))
983 do
984 {
985 FileInfo& f = fi.Add();
986 f.filename = ff.GetName();
987 #ifndef PLATFORM_POSIX
988 f.is_archive = ff.IsArchive();
989 f.is_compressed = ff.IsCompressed();
990 f.is_hidden = ff.IsHidden();
991 f.is_system = ff.IsSystem();
992 f.is_temporary = ff.IsTemporary();
993 #endif
994 f.is_read_only = ff.IsReadOnly();
995 f.length = ff.GetLength();
996 #ifdef PLATFORM_POSIX
997 f.creation_time = ff.GetLastChangeTime();
998 f.unix_mode = ff.GetMode();
999 #endif
1000 f.last_access_time = ff.GetLastAccessTime();
1001 f.last_write_time = ff.GetLastWriteTime();
1002 #ifdef PLATFORM_WIN32
1003 f.creation_time = ff.GetCreationTime();
1004 f.unix_mode = 0;
1005 #endif
1006 f.read_only = ff.IsReadOnly();
1007 f.is_directory = ff.IsDirectory();
1008 f.is_folder = ff.IsFolder();
1009 f.is_file = ff.IsFile();
1010 #ifdef PLATFORM_POSIX
1011 f.is_symlink = ff.IsSymLink();
1012 #endif
1013 }
1014 while(ff.Next() && fi.GetCount() < max_count);
1015 }
1016 return fi;
1017 }
1018
CreateFolder(String path,String & error) const1019 bool FileSystemInfo::CreateFolder(String path, String& error) const
1020 {
1021 if(UPP::DirectoryCreate(path))
1022 return true;
1023 error = GetErrorMessage(GetLastError());
1024 return false;
1025 }
1026
FolderExists(String path) const1027 bool FileSystemInfo::FolderExists(String path) const
1028 {
1029 if(IsNull(path))
1030 return true;
1031 if(path.Find('*') >= 0 || path.Find('?') >= 0)
1032 return false;
1033 Array<FileInfo> fi = Find(path, 1);
1034 return !fi.IsEmpty() && fi[0].is_directory;
1035 }
1036
1037 }
1038