1
0
Fork 0
mirror of https://github.com/HamletDuFromage/sigpatches-updater.git synced 2024-12-31 21:46:02 +00:00
sigpatches-updater/libs/minizip/source/CDirEntry.cpp
2020-09-12 18:12:07 +02:00

622 lines
14 KiB
C++

// Copyright (C) 2010 - 2014 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.
// Copyright (C) 2008 - 2009 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.
// Copyright (C) 2005 - 2007 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.
#include <algorithm>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef WIN32
# include <io.h>
# include <direct.h>
typedef struct _stat STAT;
# define stat _stat
# define S_IFREG _S_IFREG
# define S_IFDIR _S_IFDIR
# define access _access
# define mkdir _mkdir
# define rmdir _rmdir
#else
typedef struct stat STAT;
# include <dirent.h>
# include <unistd.h>
#endif // WIN32
#include "CDirEntry.h"
#include <stdlib.h>
#include <fstream>
using namespace zipper;
#ifdef WIN32
const std::string CDirEntry::Separator = "\\";
#else
const std::string CDirEntry::Separator = "/";
#endif
bool CDirEntry::isFile(const std::string & path)
{
STAT st;
if (stat(path.c_str(), & st) == -1) return false;
#ifdef WIN32
return ((st.st_mode & S_IFREG) == S_IFREG);
#else
return S_ISREG(st.st_mode);
#endif
}
bool CDirEntry::isDir(const std::string & path)
{
STAT st;
if (stat(path.c_str(), & st) == -1) return false;
#ifdef WIN32
return ((st.st_mode & S_IFDIR) == S_IFDIR);
#else
return S_ISDIR(st.st_mode);
#endif
}
bool CDirEntry::exist(const std::string & path)
{
STAT st;
if (stat(path.c_str(), & st) == -1) return false;
#ifdef WIN32
return ((st.st_mode & S_IFREG) == S_IFREG ||
(st.st_mode & S_IFDIR) == S_IFDIR);
#else
return (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode));
#endif
}
bool CDirEntry::isReadable(const std::string & path)
{return (access(path.c_str(), 0x4) == 0);}
bool CDirEntry::isWritable(const std::string & path)
{return (access(path.c_str(), 0x2) == 0);}
std::string CDirEntry::baseName(const std::string & path)
{
std::string::size_type start = path.find_last_of(Separator);
#ifdef WIN32 // WIN32 also understands '/' as the separator.
if (start == std::string::npos)
start = path.find_last_of("/");
#endif
if (start == std::string::npos) start = 0;
else start++; // We do not want the separator.
std::string::size_type end = path.find_last_of(".");
if (end == std::string::npos || end < start)
end = path.length();
return path.substr(start, end - start);
}
std::string CDirEntry::fileName(const std::string & path)
{
std::string::size_type start = path.find_last_of(Separator);
#ifdef WIN32 // WIN32 also understands '/' as the separator.
if (start == std::string::npos)
start = path.find_last_of("/");
#endif
if (start == std::string::npos) start = 0;
else start++; // We do not want the separator.
return path.substr(start);
}
std::string CDirEntry::dirName(const std::string & path)
{
if (path == "") return path;
#ifdef WIN32 // WIN32 also understands '/' as the separator.
std::string::size_type end = path.find_last_of(Separator + "/");
#else
std::string::size_type end = path.find_last_of(Separator);
#endif
if (end == path.length() - 1)
{
#ifdef WIN32 // WIN32 also understands '/' as the separator.
end = path.find_last_of(Separator + "/", end);
#else
end = path.find_last_of(Separator, end);
#endif
}
if (end == std::string::npos) return "";
return path.substr(0, end);
}
std::string CDirEntry::suffix(const std::string & path)
{
std::string::size_type start = path.find_last_of(Separator);
#ifdef WIN32 // WIN32 also understands '/' as the separator.
if (start == std::string::npos)
start = path.find_last_of("/");
#endif
if (start == std::string::npos) start = 0;
else start++; // We do not want the separator.
std::string::size_type end = path.find_last_of(".");
if (end == std::string::npos || end < start)
return "";
else
return path.substr(end);
}
bool CDirEntry::createDir(const std::string & dir,
const std::string & parent)
{
std::string Dir;
if (parent != "") Dir = parent + Separator;
Dir += dir;
// Check whether the directory already exists and is writable.
if (isDir(Dir) && isWritable(Dir)) return true;
// Check whether the parent directory exists and is writable.
if (!parent.empty() && (!isDir(parent) || !isWritable(parent))) return false;
Dir = normalize(Dir);
// ensure we have parent
std::string actualParent = dirName(Dir);
if (!actualParent.empty() && (!exist(actualParent)))
createDir(actualParent);
#ifdef WIN32
return (mkdir(Dir.c_str()) == 0);
#else
return (mkdir(Dir.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) == 0);
#endif
}
std::string CDirEntry::createTmpName(const std::string & dir,
const std::string & suffix)
{
std::string RandomName;
do
{
RandomName = dir + Separator;
unsigned int Char;
for (size_t i = 0; i < 8; i++)
{
Char = int((rand()/double(RAND_MAX))*35.0);
if (Char < 10)
RandomName += '0' + Char;
else
RandomName += 'a' - 10 + Char;
}
RandomName += suffix;
}
while (exist(RandomName));
return RandomName;
}
bool CDirEntry::move(const std::string & from,
const std::string & to)
{
if (!isFile(from)) return false;
std::string To = to;
// Check whether To is a directory and append the
// filename of from
if (isDir(To))
To += Separator + fileName(from);
if (isDir(To)) return false;
#ifdef WIN32
// The target must not exist under WIN32 for rename to succeed.
if (exist(To) && !remove(To))
return false;
#endif // WIN32
bool success =
(::rename(from.c_str(), To.c_str()) == 0);
if (!success)
{
{
std::ifstream in(from.c_str());
std::ofstream out(To.c_str());
out << in.rdbuf();
success = out.good();
}
remove(from);
}
return success;
}
bool CDirEntry::remove(const std::string & path)
{
if (isDir(path))
return (rmdir(path.c_str()) == 0);
else if (isFile(path))
#ifdef WIN32
return (::remove(path.c_str()) == 0);
#else
return (::remove(path.c_str()) == 0);
#endif
return false;
}
bool CDirEntry::removeFiles(const std::string & pattern,
const std::string & path)
{
bool success = true;
std::vector< std::string > PatternList;
PatternList = compilePattern(pattern);
#ifdef WIN32
// We want the same pattern matching behaviour for all platforms.
// Therefore, we do not use the MS provided one and list all files instead.
std::string FilePattern = path + "\\*";
// Open directory stream and try read info about first entry
struct _finddata_t Entry;
intptr_t hList = _findfirst(FilePattern.c_str(), &Entry);
if (hList == -1) return success;
do
{
std::string Utf8 = Entry.name;
if (match(Utf8, PatternList))
{
if (Entry.attrib | _A_NORMAL)
{
#ifdef WIN32
if (::remove((path + Separator + Utf8).c_str()) != 0) success = false;
#else
if (::remove((path + Separator + Utf8).c_str()) != 0) success = false;
#endif
}
else
{
if (rmdir((path + Separator + Utf8).c_str()) != 0) success = false;
}
}
}
while (_findnext(hList, &Entry) == 0);
_findclose(hList);
#else
DIR * pDir = opendir(path.c_str());
if (!pDir) return false;
struct dirent * pEntry;
while ((pEntry = readdir(pDir)) != NULL)
{
std::string Utf8 = pEntry->d_name;
if (match(Utf8, PatternList))
{
if (isDir(Utf8))
{
if (::rmdir((path + Separator + Utf8).c_str()) != 0)
success = false;
}
else
{
if (::remove((path + Separator + Utf8).c_str()) != 0)
success = false;
}
}
}
closedir(pDir);
#endif // WIN32
return success;
}
std::vector< std::string > CDirEntry::compilePattern(const std::string & pattern)
{
std::string::size_type pos = 0;
std::string::size_type start = 0;
std::string::size_type end = 0;
std::vector< std::string > PatternList;
while (pos != std::string::npos)
{
start = pos;
pos = pattern.find_first_of("*?", pos);
end = std::min(pos, pattern.length());
if (start != end)
PatternList.push_back(pattern.substr(start, end - start));
else
{
PatternList.push_back(pattern.substr(start, 1));
pos++;
}
};
return PatternList;
}
bool CDirEntry::match(const std::string & name,
const std::vector< std::string > & patternList)
{
std::vector< std::string >::const_iterator it = patternList.begin();
std::vector< std::string >::const_iterator end = patternList.end();
std::string::size_type at = 0;
std::string::size_type after = 0;
bool Match = true;
while (it != end && Match)
Match = matchInternal(name, *it++, at, after);
return Match;
}
bool CDirEntry::isRelativePath(const std::string & path)
{
#ifdef WIN32
std::string Path = normalize(path);
if (Path.length() < 2)
return true;
if (Path[1] == ':')
return false;
if (Path[0] == '/' && Path[1] == '/')
return false;
return true;
#else
return (path.length() < 1 || path[0] != '/');
#endif
}
bool CDirEntry::makePathRelative(std::string & absolutePath,
const std::string & relativeTo)
{
if (isRelativePath(absolutePath) ||
isRelativePath(relativeTo)) return false; // Nothing can be done.
std:: string RelativeTo = normalize(relativeTo);
if (isFile(RelativeTo)) RelativeTo = dirName(RelativeTo);
if (!isDir(RelativeTo)) return false;
absolutePath = normalize(absolutePath);
size_t i, imax = std::min(absolutePath.length(), RelativeTo.length());
for (i = 0; i < imax; i++)
if (absolutePath[i] != RelativeTo[i]) break;
// We need to retract to the beginning of the current directory.
if (i != imax)
i = absolutePath.find_last_of('/', i) + 1;
#ifdef WIN32
if (i == 0) return false; // A different drive letter we cannot do anything
#endif
RelativeTo = RelativeTo.substr(i);
std::string relativePath;
while (RelativeTo != "")
{
relativePath += "../";
RelativeTo = dirName(RelativeTo);
}
if (relativePath != "")
absolutePath = relativePath + absolutePath.substr(i);
else
absolutePath = absolutePath.substr(i + 1);
return true;
}
bool CDirEntry::makePathAbsolute(std::string & relativePath,
const std::string & absoluteTo)
{
if (!isRelativePath(relativePath) ||
isRelativePath(absoluteTo)) return false; // Nothing can be done.
std:: string AbsoluteTo = normalize(absoluteTo);
if (isFile(AbsoluteTo)) AbsoluteTo = dirName(AbsoluteTo);
if (!isDir(AbsoluteTo)) return false;
relativePath = normalize(relativePath);
while (!relativePath.compare(0, 3, "../"))
{
AbsoluteTo = dirName(AbsoluteTo);
relativePath = relativePath.substr(3);
}
relativePath = AbsoluteTo + "/" + relativePath;
return true;
}
bool CDirEntry::matchInternal(const std::string & name,
const std::string pattern,
std::string::size_type & at,
std::string::size_type & after)
{
bool Match = true;
switch (pattern[0])
{
case '*':
if (at != std::string::npos)
{
after = at;
at = std::string::npos;
}
break;
case '?':
if (at != std::string::npos)
{
++at;
Match = (name.length() >= at);
}
else
{
++after;
Match = (name.length() >= after);
}
break;
default:
if (at != std::string::npos)
{
Match = (name.compare(at, pattern.length(), pattern) == 0);
at += pattern.length();
}
else
{
at = name.find(pattern, after);
Match = (at != std::string::npos);
at += pattern.length();
}
break;
}
return Match;
}
std::string CDirEntry::normalize(const std::string & path)
{
std::string Normalized = path;
#ifdef WIN32
// converts all '\' to '/' (only on WIN32)
size_t i, imax;
for (i = 0, imax = Normalized.length(); i < imax; i++)
if (Normalized[i] == '\\') Normalized[i] = '/';
#endif
// Remove leading './'
while (!Normalized.compare(0, 2, "./"))
Normalized = Normalized.substr(2);
// Collapse '//' to '/'
std::string::size_type pos = 1;
while (true)
{
pos = Normalized.find("//", pos);
if (pos == std::string::npos) break;
Normalized.erase(pos, 1);
}
// Collapse '/./' to '/'
pos = 0;
while (true)
{
pos = Normalized.find("/./", pos);
if (pos == std::string::npos) break;
Normalized.erase(pos, 2);
}
// Collapse '[^/]+/../' to '/'
std::string::size_type start = Normalized.length();
while (true)
{
pos = Normalized.rfind("/../", start);
if (pos == std::string::npos) break;
start = Normalized.rfind('/', pos - 1);
if (start == std::string::npos) break;
if (!Normalized.compare(start, 4, "/../")) continue;
Normalized.erase(start, pos - start + 3);
start = Normalized.length();
}
return Normalized;
}