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