mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 14:16:07 -06:00
1052 lines
22 KiB
C++
1052 lines
22 KiB
C++
#include "Core.h"
|
|
#include "Core.h"
|
|
//#BLITZ_APPROVE
|
|
|
|
#ifdef PLATFORM_POSIX
|
|
#include <sys/types.h>
|
|
#include <utime.h>
|
|
#endif//PLATFORM_POSIX
|
|
|
|
#ifdef PLATFORM_WIN32
|
|
|
|
#define Ptr Ptr_
|
|
#define byte byte_
|
|
#define CY win32_CY_
|
|
|
|
#include <winnls.h>
|
|
#include <winnetwk.h>
|
|
|
|
#include <wincon.h>
|
|
|
|
#ifdef COMPILER_MINGW
|
|
#undef CY
|
|
#endif
|
|
|
|
#include <shlobj.h>
|
|
|
|
#undef Ptr
|
|
#undef byte
|
|
#undef CY
|
|
|
|
#endif
|
|
|
|
namespace Upp {
|
|
|
|
static int sDirSep(int c) {
|
|
return c == '/' || c == '\\' ? c : 0;
|
|
}
|
|
|
|
static bool strecmp0(const char *p, const char *s) {
|
|
while(*p) {
|
|
if(*p == '*') {
|
|
while(*p == '*') p++;
|
|
do
|
|
if(ToUpper(*p) == ToUpper(*s) && strecmp0(p, s)) return true;
|
|
while(*s++);
|
|
return false;
|
|
}
|
|
if(*p == '?') {
|
|
if(*s == '\0') return false;
|
|
}
|
|
else
|
|
if(ToUpper(*p) != ToUpper(*s)) return false;
|
|
s++;
|
|
p++;
|
|
}
|
|
return *s == '\0';
|
|
}
|
|
|
|
bool PatternMatch(const char *p, const char *s) {
|
|
const char *q;
|
|
q = strchr(p, '.');
|
|
if(q) {
|
|
if(q[1] == '\0') {
|
|
if(strchr(s, '.')) return false;
|
|
String h(p, q);
|
|
return strecmp0(h, s);
|
|
}
|
|
else
|
|
if(q[1] == '*' && q[2] == '\0') {
|
|
String h(p, q);
|
|
return strecmp0(h, s) || strecmp0(p, s);
|
|
}
|
|
}
|
|
return strecmp0(p, s);
|
|
}
|
|
|
|
bool PatternMatchMulti(const char *p, const char *s) {
|
|
String pt;
|
|
while(*p) {
|
|
if(*p == ';' || *p == ',' || *p == ' ') {
|
|
if(PatternMatch(pt, s)) return true;
|
|
p++;
|
|
while(*p == ';' || *p == ',' || *p == ' ') p++;
|
|
pt.Clear();
|
|
}
|
|
else
|
|
pt.Cat(*p++);
|
|
}
|
|
return pt.IsEmpty() ? false : PatternMatch(pt, s);
|
|
}
|
|
|
|
const char *GetFileNamePos(const char *fileName) {
|
|
const char *s = fileName;
|
|
const char *fname = s;
|
|
char c;
|
|
while((c = *s++) != '\0')
|
|
#ifdef PLATFORM_WIN32
|
|
if(c == '\\' || c == ':' || c == '/')
|
|
#else
|
|
if(c == '/')
|
|
#endif
|
|
fname = s;
|
|
return fname;
|
|
}
|
|
|
|
const char *GetFileExtPos(const char *fileName) {
|
|
fileName = GetFileNamePos(fileName);
|
|
const char *ext = strrchr(fileName, '.');
|
|
return ext ? ext : fileName + strlen(fileName);
|
|
}
|
|
|
|
bool HasFileExt(const char *path) {
|
|
return *GetFileExtPos(path);
|
|
}
|
|
|
|
bool HasWildcards(const char *fileName) {
|
|
return strchr(fileName, '*') || strchr(fileName, '?');
|
|
}
|
|
|
|
bool IsFullPath(const char *r) {
|
|
#ifdef PLATFORM_WIN32
|
|
return *r && r[1] && (r[1] == ':' || r[0] == '\\' && r[1] == '\\' || r[0] == '/' && r[1] == '/');
|
|
#endif
|
|
#ifdef PLATFORM_POSIX
|
|
return *r == '/';
|
|
#endif
|
|
}
|
|
|
|
String GetFileDirectory(const char *fileName) {
|
|
return String(fileName, (int)(GetFileNamePos(fileName) - fileName));
|
|
}
|
|
|
|
String GetFileFolder(const char *fileName) {
|
|
const char *s = GetFileNamePos(fileName);
|
|
#ifdef PLATFORM_WIN32
|
|
if(s - fileName == 3 && fileName[1] == ':')
|
|
return String(fileName, 3);
|
|
#endif
|
|
#ifdef PLATFORM_POSIX
|
|
if(s - fileName == 1 && s[0] == '/')
|
|
return "/";
|
|
#endif
|
|
if(s > fileName)
|
|
return String(fileName, (int)(s - fileName) - 1);
|
|
return Null;
|
|
}
|
|
|
|
String GetFileTitle(const char *fileName) {
|
|
fileName = GetFileNamePos(fileName);
|
|
const char *ext = GetFileExtPos(fileName);
|
|
if(*ext)
|
|
return String(fileName, (int)(ext - fileName));
|
|
else
|
|
return fileName;
|
|
}
|
|
|
|
String GetFileExt(const char *fileName) {
|
|
return GetFileExtPos(fileName);
|
|
}
|
|
|
|
String GetFileName(const char *fileName) {
|
|
return GetFileNamePos(fileName);
|
|
}
|
|
|
|
String AppendFileName(const String& path, const char *fileName) {
|
|
String result = path;
|
|
if(result.GetLength() && *result.Last() != DIR_SEP && *fileName != DIR_SEP)
|
|
result += DIR_SEP;
|
|
result += fileName;
|
|
return result;
|
|
}
|
|
|
|
#ifdef PLATFORM_WIN32
|
|
bool PathIsEqual(const char *p1, const char *p2)
|
|
{
|
|
return ToLower(NormalizePath(p1)) == ToLower(NormalizePath(p2));
|
|
}
|
|
#endif
|
|
|
|
#ifdef PLATFORM_POSIX
|
|
bool PathIsEqual(const char *p1, const char *p2)
|
|
{
|
|
return NormalizePath(p1) == NormalizePath(p2);
|
|
}
|
|
#endif
|
|
|
|
#ifndef PLATFORM_WINCE
|
|
String GetCurrentDirectory() {
|
|
#if defined(PLATFORM_WIN32)
|
|
wchar h[MAX_PATH];
|
|
GetCurrentDirectoryW(MAX_PATH, h);
|
|
return FromSystemCharsetW(h);
|
|
#elif defined(PLATFORM_POSIX)
|
|
char h[1024];
|
|
return getcwd(h, 1024) ? FromSystemCharset(h) : String();
|
|
#else
|
|
#error GetCurrentDirectory not implemented for this platform, comment this line to get Null
|
|
return Null;
|
|
#endif//PLATFORM
|
|
}
|
|
#endif
|
|
|
|
#ifdef PLATFORM_POSIX
|
|
bool SetCurrentDirectory(const char *path)
|
|
{
|
|
return chdir(path) == 0;
|
|
}
|
|
#endif
|
|
|
|
#if defined(PLATFORM_WIN32) && !defined(PLATFORM_WINCE)
|
|
|
|
String GetTempPath()
|
|
{
|
|
wchar h[MAX_PATH];
|
|
GetTempPathW(MAX_PATH, h);
|
|
return FromSystemCharsetW(h);
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef PLATFORM_POSIX
|
|
|
|
String GetTempPath()
|
|
{
|
|
return FromSystemCharset(P_tmpdir);
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifndef PLATFORM_WINCE
|
|
String GetTempFileName(const char *prefix) {
|
|
Uuid id = Uuid::Create();
|
|
return AppendFileName(GetTempPath(), String(prefix) + Format(id) + ".tmp");
|
|
}
|
|
#endif
|
|
|
|
String FromUnixName(const char* fn, const char* stop = NULL) {
|
|
String s;
|
|
char c;
|
|
while(fn != stop && (c = *fn++))
|
|
s += (c == '/' ? '\\' : c);
|
|
return s;
|
|
}
|
|
|
|
String ToUnixName(const char* fn, const char* stop = NULL) {
|
|
String s;
|
|
char c;
|
|
while(fn != stop && (c = *fn++))
|
|
s += (c == '\\' ? '/' : c);
|
|
return s;
|
|
}
|
|
|
|
String GetFullPath(const char *file) {
|
|
#ifdef PLATFORM_WIN32
|
|
String ufn = FromUnixName(file);
|
|
wchar h[MAX_PATH];
|
|
GetFullPathNameW(ToSystemCharsetW(ufn), MAX_PATH, h, 0);
|
|
return FromSystemCharsetW(h);
|
|
#else
|
|
return NormalizePath(file);
|
|
#endif
|
|
}
|
|
|
|
String GetFileOnPath(const char* file, const char* paths, bool current, const char *curdir) {
|
|
String ufn = NativePath(file);
|
|
if(IsFullPath(ufn) && FileExists(ufn))
|
|
return ufn;
|
|
String fn;
|
|
String cd = curdir;
|
|
if(!curdir)
|
|
cd = GetCurrentDirectory();
|
|
if(current && FileExists(fn = NormalizePath(ufn, cd)))
|
|
;
|
|
else if(paths)
|
|
{
|
|
fn = Null;
|
|
while(*paths) {
|
|
const char* start = paths;
|
|
#ifdef PLATFORM_WIN32
|
|
while(*paths && *paths != ';')
|
|
paths++;
|
|
#else
|
|
while(*paths && *paths != ';' && *paths != ':')
|
|
paths++;
|
|
#endif
|
|
String dir(start, (int)(paths - start));
|
|
if(!dir.IsEmpty()) {
|
|
#ifdef PLATFORM_WINCE
|
|
dir = NormalizePath(AppendFileName(NativePath(dir), ufn));
|
|
#else
|
|
dir = NormalizePath(AppendFileName(NativePath(dir), ufn), cd);
|
|
#endif
|
|
if(FileExists(dir)) {
|
|
fn = dir;
|
|
break;
|
|
}
|
|
}
|
|
if(*paths)
|
|
paths++;
|
|
}
|
|
}
|
|
return fn;
|
|
}
|
|
|
|
String WinPath(const char *p) {
|
|
String r;
|
|
while(*p) {
|
|
r.Cat(*p == '/' ? '\\' : *p);
|
|
p++;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
String UnixPath(const char *p) {
|
|
String r;
|
|
while(*p) {
|
|
r.Cat(*p == '\\' ? '/' : *p);
|
|
p++;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
String AppendExt(const char* fn, const char* ext) {
|
|
String result = NativePath(fn);
|
|
if(!HasFileExt(fn))
|
|
result += ext;
|
|
return result;
|
|
}
|
|
|
|
String ForceExt(const char* fn, const char* ext) {
|
|
return NativePath(String(fn, GetFileExtPos(fn))) + ext;
|
|
}
|
|
|
|
#ifdef PLATFORM_WIN32
|
|
|
|
FindFile::~FindFile()
|
|
{
|
|
Close();
|
|
}
|
|
|
|
FindFile::FindFile()
|
|
{
|
|
handle = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
FindFile::FindFile(const char *name) {
|
|
handle = INVALID_HANDLE_VALUE;
|
|
Search(name);
|
|
}
|
|
|
|
bool FindFile::Search(const char *name) {
|
|
pattern = GetFileName(name);
|
|
path = NormalizePath(GetFileDirectory(name));
|
|
Close();
|
|
handle = FindFirstFileW(ToSystemCharsetW(name), data);
|
|
if(handle == INVALID_HANDLE_VALUE)
|
|
return false;
|
|
if(!PatternMatch(pattern, GetName()))
|
|
return Next();
|
|
return true;
|
|
}
|
|
|
|
static bool sGetSymLinkPath0(const char *linkpath, String *path)
|
|
{
|
|
bool ret = false;
|
|
HRESULT hres;
|
|
IShellLink* psl;
|
|
IPersistFile* ppf;
|
|
CoInitialize(NULL);
|
|
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink,
|
|
(PVOID *) &psl);
|
|
if(SUCCEEDED(hres)) {
|
|
hres = psl->QueryInterface(IID_IPersistFile, (PVOID *) &ppf);
|
|
if(SUCCEEDED(hres)) {
|
|
hres = ppf->Load(ToSystemCharsetW(linkpath), STGM_READ);
|
|
if(SUCCEEDED(hres)) {
|
|
if(path) {
|
|
char fileW[_MAX_PATH] = {0};
|
|
psl->GetPath(fileW, _MAX_PATH, NULL, 0);
|
|
*path = FromSystemCharset(fileW);
|
|
}
|
|
else
|
|
ret = true;
|
|
}
|
|
ppf->Release();
|
|
}
|
|
psl->Release();
|
|
}
|
|
CoUninitialize();
|
|
return ret;
|
|
}
|
|
|
|
bool FindFile::IsSymLink() const
|
|
{
|
|
String name = GetName();
|
|
if(GetFileExt(name) != ".lnk")
|
|
return false;
|
|
return sGetSymLinkPath0(AppendFileName(path, name), NULL);
|
|
}
|
|
|
|
bool FindFile::IsExecutable() const
|
|
{
|
|
return !IsDirectory() && ToLower(GetName()).EndsWith(".exe");
|
|
}
|
|
|
|
void FindFile::Close() {
|
|
if(handle != INVALID_HANDLE_VALUE) FindClose(handle);
|
|
handle = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
bool FindFile::Next0() {
|
|
if(!FindNextFileW(handle, data)) {
|
|
Close();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool FindFile::Next()
|
|
{
|
|
for(;;) {
|
|
if(!Next0())
|
|
return false;
|
|
if(PatternMatch(pattern, GetName()))
|
|
return true;
|
|
}
|
|
}
|
|
|
|
String FindFile::GetName() const
|
|
{
|
|
return FromSystemCharsetW(data->cFileName);
|
|
}
|
|
|
|
int64 FindFile::GetLength() const
|
|
{
|
|
return (int64)data->nFileSizeLow | ((int64)data->nFileSizeHigh << 32);
|
|
}
|
|
|
|
bool FindFile::IsFolder() const {
|
|
auto h = data->cFileName;
|
|
return IsDirectory() && !(h[0] == '.' && h[1] == 0) && !(h[0] == '.' && h[1] == '.' && h[2] == 0);
|
|
}
|
|
|
|
String NormalizePath(const char *path, const char *currdir)
|
|
{
|
|
String join_path;
|
|
if(!IsFullPath(path))
|
|
path = join_path = AppendFileName(currdir, path);
|
|
String out;
|
|
if(*path && path[1] == ':') {
|
|
out << path[0] << ":\\";
|
|
path += 3;
|
|
}
|
|
else
|
|
if(path[0] == '\\' && path[1] == '\\') {
|
|
out = "\\\\";
|
|
path += 2;
|
|
}
|
|
else
|
|
if(sDirSep(*path)) {
|
|
if(*currdir)
|
|
out << *currdir << ':';
|
|
out.Cat(DIR_SEP);
|
|
path++;
|
|
}
|
|
int outstart = out.GetLength();
|
|
while(*path) {
|
|
if(sDirSep(*path)) {
|
|
while(sDirSep(*path))
|
|
path++;
|
|
if(*path == '\0')
|
|
break;
|
|
if(out.IsEmpty() || *out.Last() != DIR_SEP)
|
|
out.Cat(DIR_SEP);
|
|
}
|
|
const char *b = path;
|
|
while(*path && !sDirSep(*path))
|
|
path++;
|
|
if(path - b == 1 && *b == '.')
|
|
; //no-op
|
|
else if(path - b == 2 && *b == '.' && b[1] == '.') {
|
|
const char *ob = ~out + outstart, *oe = out.End();
|
|
if(oe - 1 > ob && oe[-1] == DIR_SEP)
|
|
oe--;
|
|
while(oe > ob && oe[-1] != DIR_SEP)
|
|
oe--;
|
|
out.Trim((int)(oe - out.Begin()));
|
|
}
|
|
else
|
|
out.Cat(b, (int)(path - b));
|
|
}
|
|
return out;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef PLATFORM_POSIX
|
|
|
|
void FindFile::Close() {
|
|
if(dir) {
|
|
closedir(dir);
|
|
dir = NULL;
|
|
}
|
|
}
|
|
|
|
bool FindFile::IsFolder() const {
|
|
return IsDirectory()
|
|
&& !(name[0] == '.' && name[1] == '\0')
|
|
&& !(name[0] == '.' && name[1] == '.' && name[2] == '\0');
|
|
}
|
|
|
|
struct stat& FindFile::Stat() const {
|
|
if(!statis) {
|
|
statis = true;
|
|
if(file)
|
|
stat(ToSystemCharset(AppendFileName(path, name)), &statf);
|
|
}
|
|
return statf;
|
|
}
|
|
|
|
bool FindFile::CanMode(dword usr, dword grp, dword oth) const
|
|
{
|
|
const struct stat& s = Stat();
|
|
dword mode = GetMode();
|
|
static uid_t uid = getuid();
|
|
static gid_t gid = getgid();
|
|
return (mode & oth) ||
|
|
(mode & grp) && gid == s.st_gid ||
|
|
(mode & usr) && uid == s.st_uid;
|
|
}
|
|
|
|
bool FindFile::IsSymLink() const
|
|
{
|
|
if(file) {
|
|
struct stat stf;
|
|
lstat(AppendFileName(path, name), &stf);
|
|
return S_ISLNK(stf.st_mode);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool FindFile::IsExecutable() const
|
|
{
|
|
return !IsDirectory() && ((S_IXUSR|S_IXGRP|S_IXOTH) & GetMode());
|
|
}
|
|
|
|
bool FindFile::Next() {
|
|
file = false;
|
|
if(!dir) return false;
|
|
statis = false;
|
|
for(;;) {
|
|
struct dirent *e = readdir(dir);
|
|
if(!e) {
|
|
name.Clear();
|
|
file = false;
|
|
Close();
|
|
return false;
|
|
}
|
|
name = FromSystemCharset(e->d_name);
|
|
if(PatternMatch(pattern, name)) {
|
|
file = true;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FindFile::Search(const char *fn) {
|
|
Close();
|
|
path = NormalizePath(GetFileDirectory(fn));
|
|
statis = false;
|
|
file = false;
|
|
if(HasWildcards(fn)) {
|
|
pattern = GetFileName(fn);
|
|
dir = opendir(ToSystemCharset(path));
|
|
return Next();
|
|
}
|
|
else {
|
|
name = GetFileName(fn);
|
|
if(stat(ToSystemCharset(fn), &statf)) return false;
|
|
statis = true;
|
|
file = true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
FindFile::FindFile(const char *fn) {
|
|
dir = NULL;
|
|
Search(fn);
|
|
}
|
|
|
|
String NormalizePath(const char *path, const char *currdir) {
|
|
Vector<String> si = Split(path, sDirSep);
|
|
Vector<String> p;
|
|
int i = 0;
|
|
String out;
|
|
if(path[0] == '~') {
|
|
out = GetHomeDirectory();
|
|
i++;
|
|
}
|
|
else
|
|
if(sDirSep(path[0]))
|
|
out = (sDirSep(path[1]) ? "//" : "/");
|
|
else {
|
|
out = (sDirSep(currdir[0]) && sDirSep(currdir[1]) ? "//" : "/");
|
|
p = Split(currdir, sDirSep);
|
|
}
|
|
for(; i < si.GetCount(); i++) {
|
|
String s = si[i];
|
|
if(s != "." && !s.IsEmpty()) {
|
|
if(s[0] == '.' && s[1] == '.') {
|
|
if(!p.IsEmpty()) p.Drop();
|
|
}
|
|
else
|
|
p.Add(s);
|
|
}
|
|
}
|
|
out.Cat(Join(p, DIR_SEPS));
|
|
return out;
|
|
}
|
|
|
|
#endif//PLATFORM_POSIX
|
|
|
|
String FindFile::GetPath() const
|
|
{
|
|
return AppendFileName(path, GetName());
|
|
}
|
|
|
|
bool FileExists(const char *name) {
|
|
FindFile ff(name);
|
|
return ff && ff.IsFile();
|
|
}
|
|
|
|
int64 GetFileLength(const char *name) {
|
|
FindFile ff(name);
|
|
return ff ? ff.GetLength() : -1;
|
|
}
|
|
|
|
bool DirectoryExists(const char *name) {
|
|
FindFile ff(name + String("/*"));
|
|
return ff;
|
|
}
|
|
|
|
String NormalizePath(const char *path) {
|
|
#ifdef PLATFORM_WINCE
|
|
return NormalizePath(path, "");
|
|
#else
|
|
return NormalizePath(path, GetCurrentDirectory());
|
|
#endif
|
|
}
|
|
|
|
bool FileCopy(const char *oldname, const char *newname)
|
|
{
|
|
#if defined(PLATFORM_WIN32)
|
|
return CopyFileW(ToSystemCharsetW(oldname), ToSystemCharsetW(newname), false);
|
|
#elif defined(PLATFORM_POSIX)
|
|
FileIn fi(oldname);
|
|
if(!fi.IsOpen())
|
|
return false;
|
|
FileOut fo(newname);
|
|
if(!fo.IsOpen())
|
|
return false;
|
|
CopyStream(fo, fi, fi.GetLeft());
|
|
fi.Close();
|
|
fo.Close();
|
|
if(fo.IsError())
|
|
{
|
|
unlink(newname);
|
|
return false;
|
|
}
|
|
FileSetTime(newname, FileGetTime(oldname));
|
|
return true;
|
|
#else
|
|
#error
|
|
#endif//PLATFORM
|
|
}
|
|
|
|
bool FileMove(const char *oldname, const char *newname)
|
|
{
|
|
#if defined(PLATFORM_WIN32)
|
|
return !!MoveFileW(ToSystemCharsetW(oldname), ToSystemCharsetW(newname));
|
|
#elif defined(PLATFORM_POSIX)
|
|
return !rename(ToSystemCharset(oldname), ToSystemCharset(newname));
|
|
#else
|
|
#error
|
|
#endif//PLATFORM
|
|
}
|
|
|
|
bool FileDelete(const char *filename)
|
|
{
|
|
#if defined(PLATFORM_WIN32)
|
|
return !!DeleteFileW(ToSystemCharsetW(filename));
|
|
#elif defined(PLATFORM_POSIX)
|
|
return !unlink(ToSystemCharset(filename));
|
|
#else
|
|
#error
|
|
#endif//PLATFORM
|
|
return false;
|
|
}
|
|
|
|
bool DirectoryDelete(const char *dirname)
|
|
{
|
|
#if defined(PLATFORM_WIN32)
|
|
return !!RemoveDirectoryW(ToSystemCharsetW(dirname));
|
|
#elif defined(PLATFORM_POSIX)
|
|
return !rmdir(ToSystemCharset(dirname));
|
|
#else
|
|
#error
|
|
#endif//PLATFORM
|
|
return false;
|
|
}
|
|
|
|
#ifdef PLATFORM_WIN32
|
|
int Compare_FileTime(const FileTime& fa, const FileTime& fb)
|
|
{
|
|
return CompareFileTime(&fa, &fb);
|
|
}
|
|
#endif
|
|
|
|
Time FileGetTime(const char *filename)
|
|
{
|
|
#if defined(PLATFORM_WIN32)
|
|
HANDLE handle;
|
|
handle = CreateFileW(ToSystemCharsetW(filename), GENERIC_READ,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
if(handle == INVALID_HANDLE_VALUE)
|
|
return Null;
|
|
FileTime ft;
|
|
bool res = GetFileTime(handle, 0, 0, &ft);
|
|
CloseHandle(handle);
|
|
return res ? Time(ft) : Time(Null);
|
|
#elif defined(PLATFORM_POSIX)
|
|
struct stat st;
|
|
if(stat(ToSystemCharset(filename), &st))
|
|
return Null;
|
|
return Time(st.st_mtime);
|
|
#else
|
|
#error
|
|
#endif//PLATFORM
|
|
}
|
|
|
|
FileTime GetFileTime(const char *filename)
|
|
{
|
|
#if defined(PLATFORM_WIN32)
|
|
HANDLE handle;
|
|
handle = CreateFileW(ToSystemCharsetW(filename), GENERIC_READ,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
FileTime ft0;
|
|
memset(&ft0, 0, sizeof(ft0));
|
|
if(handle == INVALID_HANDLE_VALUE)
|
|
return ft0;
|
|
FileTime ft;
|
|
bool res = GetFileTime(handle, 0, 0, &ft);
|
|
CloseHandle(handle);
|
|
return res ? ft : ft0;
|
|
#elif defined(PLATFORM_POSIX)
|
|
struct stat st;
|
|
if(stat(ToSystemCharset(filename), &st))
|
|
return 0;
|
|
return st.st_mtime;
|
|
#else
|
|
#error
|
|
#endif//PLATFORM
|
|
}
|
|
|
|
bool SetFileTime(const char *filename, FileTime ft)
|
|
{
|
|
#if defined(PLATFORM_WIN32)
|
|
HANDLE handle;
|
|
handle = CreateFileW(ToSystemCharsetW(filename), GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
if(handle == INVALID_HANDLE_VALUE)
|
|
return false;
|
|
bool res = SetFileTime(handle, 0, 0, &ft);
|
|
CloseHandle(handle);
|
|
return res;
|
|
#elif defined(PLATFORM_POSIX)
|
|
struct utimbuf ub;
|
|
ub.actime = ub.modtime = ft;
|
|
return !utime(ToSystemCharset(filename), &ub);
|
|
#else
|
|
#error
|
|
#endif//PLATFORM
|
|
}
|
|
|
|
bool FileSetTime(const char *filename, Time time)
|
|
{
|
|
return SetFileTime(filename, TimeToFileTime(time));
|
|
}
|
|
|
|
FileTime TimeToFileTime(Time time)
|
|
{
|
|
#ifdef PLATFORM_WIN32
|
|
SYSTEMTIME tm;
|
|
Zero(tm);
|
|
tm.wYear = time.year;
|
|
tm.wMonth = time.month;
|
|
tm.wDay = time.day;
|
|
tm.wHour = time.hour;
|
|
tm.wMinute = time.minute;
|
|
tm.wSecond = time.second;
|
|
FileTime ftl, ftg;
|
|
SystemTimeToFileTime(&tm, &ftl);
|
|
LocalFileTimeToFileTime(&ftl, &ftg);
|
|
return ftg;
|
|
#endif
|
|
#ifdef PLATFORM_POSIX
|
|
struct tm t;
|
|
t.tm_sec = time.second;
|
|
t.tm_min = time.minute;
|
|
t.tm_hour = time.hour;
|
|
t.tm_mday = time.day;
|
|
t.tm_mon = time.month - 1;
|
|
t.tm_year = time.year - 1900;
|
|
return mktime(&t);
|
|
#endif
|
|
}
|
|
|
|
#ifdef PLATFORM_POSIX
|
|
bool DirectoryCreate(const char *path, int mode)
|
|
{
|
|
return ::mkdir(ToSystemCharset(path), mode) == 0;
|
|
}
|
|
|
|
bool RealizePath(const String& file, int mode)
|
|
{
|
|
return RealizeDirectory(GetFileFolder(file), mode);
|
|
}
|
|
#else
|
|
bool DirectoryCreate(const char *path)
|
|
{
|
|
return !!CreateDirectoryW(ToSystemCharsetW(path), 0);
|
|
}
|
|
|
|
bool RealizePath(const String& file)
|
|
{
|
|
return RealizeDirectory(GetFileFolder(file));
|
|
}
|
|
#endif
|
|
|
|
#ifdef PLATFORM_WIN32
|
|
#define DIR_MIN 3 //!! wrong! what about \a\b\c ?
|
|
#endif
|
|
|
|
#ifdef PLATFORM_POSIX
|
|
#define DIR_MIN 1
|
|
#endif
|
|
|
|
#ifdef PLATFORM_POSIX
|
|
bool RealizeDirectory(const String& d, int mode)
|
|
#else
|
|
bool RealizeDirectory(const String& d)
|
|
#endif
|
|
{
|
|
String dir = NormalizePath(d);
|
|
Vector<String> p;
|
|
while(dir.GetLength() > DIR_MIN && !DirectoryExists(dir)) {
|
|
p.Add(dir);
|
|
dir = GetFileFolder(dir);
|
|
}
|
|
for(int i = p.GetCount() - 1; i >= 0; i--)
|
|
#ifdef PLATFORM_POSIX
|
|
if(!DirectoryCreate(p[i], mode))
|
|
#else
|
|
if(!DirectoryCreate(p[i]))
|
|
#endif
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
void SetWritePermission(const char *path)
|
|
{
|
|
#ifdef PLATFORM_WIN32
|
|
SetFileAttributes(path, GetFileAttributes(path) & ~FILE_ATTRIBUTE_READONLY);
|
|
#endif
|
|
#ifdef PLATFORM_POSIX
|
|
chmod(path, S_IRWXU);
|
|
#endif
|
|
}
|
|
|
|
bool DeleteFolderDeep(const char *dir, bool rdonly)
|
|
{
|
|
bool ok = true;
|
|
{
|
|
FindFile ff(AppendFileName(dir, "*.*"));
|
|
while(ff) {
|
|
String name = ff.GetName();
|
|
String p = AppendFileName(dir, name);
|
|
if(ff.IsFile() || ff.IsSymLink()) {
|
|
if(ff.IsReadOnly() && rdonly)
|
|
SetWritePermission(p);
|
|
ok = ok && FileDelete(p);
|
|
}
|
|
else
|
|
if(ff.IsFolder())
|
|
ok = ok && DeleteFolderDeep(p, rdonly);
|
|
ff.Next();
|
|
}
|
|
}
|
|
SetWritePermission(dir);
|
|
return ok && DirectoryDelete(dir);
|
|
}
|
|
|
|
String GetSymLinkPath(const char *linkpath)
|
|
{
|
|
#ifdef PLATFORM_WIN32
|
|
String path;
|
|
sGetSymLinkPath0(linkpath, &path);
|
|
return path;
|
|
#else
|
|
char buff[_MAX_PATH + 1];
|
|
int len = readlink(linkpath, buff, _MAX_PATH);
|
|
if(len > 0 && len < _MAX_PATH)
|
|
return String(buff, len);
|
|
return Null;
|
|
#endif
|
|
}
|
|
|
|
FileSystemInfo::FileInfo::FileInfo()
|
|
: length(Null), read_only(false), is_directory(false)
|
|
, is_folder(false), is_file(false), is_symlink(false), is_archive(false)
|
|
, is_compressed(false), is_hidden(false), is_read_only(false), is_system(false)
|
|
, is_temporary(false), root_style(ROOT_NO_ROOT_DIR)
|
|
{}
|
|
|
|
FileSystemInfo& StdFileSystemInfo()
|
|
{
|
|
static FileSystemInfo h;
|
|
return h;
|
|
}
|
|
|
|
int FileSystemInfo::GetStyle() const
|
|
{
|
|
#ifdef PLATFORM_WIN32
|
|
return STYLE_WIN32;
|
|
#endif
|
|
#ifdef PLATFORM_POSIX
|
|
return STYLE_POSIX;
|
|
#endif
|
|
}
|
|
|
|
Array<FileSystemInfo::FileInfo> FileSystemInfo::Find(String mask, int max_count, bool unmounted) const
|
|
{
|
|
Array<FileInfo> fi;
|
|
if(IsNull(mask))
|
|
{ // root
|
|
#ifdef PLATFORM_WINCE
|
|
FileInfo& f = fi.Add();
|
|
f.filename = "\\";
|
|
f.root_style = ROOT_FIXED;
|
|
#elif defined(PLATFORM_WIN32)
|
|
char drive[4] = "?:\\";
|
|
for(int c = 'A'; c <= 'Z'; c++) {
|
|
*drive = c;
|
|
int n = GetDriveType(drive);
|
|
if(n == DRIVE_NO_ROOT_DIR)
|
|
continue;
|
|
FileInfo& f = fi.Add();
|
|
f.filename = drive;
|
|
char name[256], system[256];
|
|
DWORD d;
|
|
if(c != 'A' && c != 'B' && n != DRIVE_UNKNOWN) {
|
|
bool b = GetVolumeInformation(drive, name, 256, &d, &d, &d, system, 256);
|
|
if(b) {
|
|
if(*name) f.root_desc << " " << FromSystemCharset(name);
|
|
}
|
|
else if(n == DRIVE_REMOVABLE || n == DRIVE_CDROM) {
|
|
if(unmounted) {
|
|
f.root_desc = t_("Empty drive");
|
|
} else {
|
|
fi.Drop();
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
switch(n)
|
|
{
|
|
default:
|
|
case DRIVE_UNKNOWN: f.root_style = ROOT_UNKNOWN; break;
|
|
case DRIVE_NO_ROOT_DIR: f.root_style = ROOT_NO_ROOT_DIR; break;
|
|
case DRIVE_REMOVABLE: f.root_style = ROOT_REMOVABLE; break;
|
|
case DRIVE_FIXED: f.root_style = ROOT_FIXED; break;
|
|
case DRIVE_REMOTE: f.root_style = ROOT_REMOTE; break;
|
|
case DRIVE_CDROM: f.root_style = ROOT_CDROM; break;
|
|
case DRIVE_RAMDISK: f.root_style = ROOT_RAMDISK; break;
|
|
}
|
|
}
|
|
|
|
#elif defined(PLATFORM_POSIX)
|
|
FileInfo& f = fi.Add();
|
|
f.filename = "/";
|
|
f.root_style = ROOT_FIXED;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
FindFile ff;
|
|
if(ff.Search(mask))
|
|
do
|
|
{
|
|
FileInfo& f = fi.Add();
|
|
f.filename = ff.GetName();
|
|
#ifndef PLATFORM_POSIX
|
|
f.is_archive = ff.IsArchive();
|
|
f.is_compressed = ff.IsCompressed();
|
|
f.is_hidden = ff.IsHidden();
|
|
f.is_system = ff.IsSystem();
|
|
f.is_temporary = ff.IsTemporary();
|
|
#endif
|
|
f.is_read_only = ff.IsReadOnly();
|
|
f.length = ff.GetLength();
|
|
#ifdef PLATFORM_POSIX
|
|
f.creation_time = ff.GetLastChangeTime();
|
|
f.unix_mode = ff.GetMode();
|
|
#endif
|
|
f.last_access_time = ff.GetLastAccessTime();
|
|
f.last_write_time = ff.GetLastWriteTime();
|
|
#ifdef PLATFORM_WIN32
|
|
f.creation_time = ff.GetCreationTime();
|
|
f.unix_mode = 0;
|
|
#endif
|
|
f.read_only = ff.IsReadOnly();
|
|
f.is_directory = ff.IsDirectory();
|
|
f.is_folder = ff.IsFolder();
|
|
f.is_file = ff.IsFile();
|
|
#ifdef PLATFORM_POSIX
|
|
f.is_symlink = ff.IsSymLink();
|
|
#endif
|
|
}
|
|
while(ff.Next() && fi.GetCount() < max_count);
|
|
}
|
|
return fi;
|
|
}
|
|
|
|
bool FileSystemInfo::CreateFolder(String path, String& error) const
|
|
{
|
|
if(UPP::DirectoryCreate(path))
|
|
return true;
|
|
error = GetErrorMessage(GetLastError());
|
|
return false;
|
|
}
|
|
|
|
bool FileSystemInfo::FolderExists(String path) const
|
|
{
|
|
if(IsNull(path))
|
|
return true;
|
|
if(path.Find('*') >= 0 || path.Find('?') >= 0)
|
|
return false;
|
|
Array<FileInfo> fi = Find(path, 1);
|
|
return !fi.IsEmpty() && fi[0].is_directory;
|
|
}
|
|
|
|
}
|