#include stdafx.h
#include <iostream>
#include <string>
#include <sstream>
const int ERROR_NONE = 0;
const int ERROR_INI_OPEN = 1;
const int ERROR_INI_SYN = 2;
const int ERROR_OPEN_TARGET_DIR = 3;
const int ERROR_DEL_FILE = 4;
std::string errStrings[] = {
,
INI-Datei kann nicht geoeffnet werden.,
Fehler beim Auslesen der INI-Datei im Abschnitt:,
Auf das Zielverzeichnis kann nicht zugegriffen werden.,
Loeschen der Datei fehlgeschlagen.
};
class Ini {
private:
static const std::string istr_basedir;
static const std::string vstr_basedir;
static const std::string istr_subdirs;
static const std::string vstr_subdirs[];
static const std::string istr_ext;
static const std::string istr_older;
static const std::string vstr_older;
static const std::string deferr;
static const int stdBufSize = 255;
static const int iNDays = 7;
static const int maxExt = 30;
static const int minBaseDirLen = 3;
static const int minSubDirLen = 1;
static const int minRelFileAgeMax = 365;
std::string basedir;
std::string dirs[iNDays];
std::string wildCards[maxExt];
int numExt;
int minRelFileAge;
static bool instance;
static Ini* sngl;
Ini() : numExt(), minRelFileAge() {}
Ini(const Ini&);
Ini& operator=(const Ini&);
bool chkS(const std::string& str) const;
TCHAR* str2charry(const std::string& str, TCHAR* buffer) const;
TCHAR* str2charry(const std::string& str, TCHAR* buffer, int n) const;
bool GetPrivateProfileStringWerr(const std::string& appName, const std::string& keyName,
std::string& returnedString, const std::string& fileName) const;
bool fileExists(const std::string& fname);
public:
static Ini* getInstance();
~Ini() {instance = false;}
DWORD read(const std::string iniName, std::string& errex);
void getBaseDir(std::string& baseDir) const;
void getSubDirFromDayIndex(int didx, std::string& subDir) const;
void getWildCard(int widx, std::string& wildCard) const;
int getNumExts() const;
int getMinRelFileAge() const;
static int getNumberOfDays();
};
const std::string Ini::istr_basedir = basedir;
const std::string Ini::vstr_basedir = dir;
const std::string Ini::istr_subdirs = subdirs;
const std::string Ini::vstr_subdirs[] = {monday, tuesday, wednesday, thursday, friday, saturday, sunday};
const std::string Ini::istr_ext = ext;
const std::string Ini::istr_older = minrelage;
const std::string Ini::vstr_older = days;
const std::string Ini::deferr = :;
bool Ini::instance = false;
Ini* Ini::sngl = NULL;
Ini* Ini::getInstance()
{
if(!instance)
{
sngl = new Ini();
instance = true;
return sngl;
}
else
return sngl;
}
bool Ini::chkS(const std::string& str) const {
if(str == deferr)
return false;
else return true;
}
TCHAR* Ini::str2charry(const std::string& str, TCHAR* buffer) const {
if(buffer == NULL)
return NULL;
strcpy(buffer, str.c_str());
return buffer;
}
TCHAR* Ini::str2charry(const std::string& str, TCHAR* buffer, int n) const {
if(buffer == NULL)
return NULL;
strncpy(buffer, str.c_str(), n);
return buffer;
}
bool Ini::GetPrivateProfileStringWerr(const std::string& appName, const std::string& keyName, std::string& returnedString, const std::string& fileName) const {
TCHAR buf[stdBufSize];
GetPrivateProfileString(appName.c_str(), keyName.c_str(), deferr.c_str(), str2charry(returnedString, buf), stdBufSize, fileName.c_str());
returnedString = buf;
return chkS(returnedString.c_str());
}
bool Ini::fileExists(const std::string& fname) {
WIN32_FIND_DATA fileData;
HANDLE hFind = FindFirstFile(fname.c_str(), &fileData);
if(hFind == INVALID_HANDLE_VALUE)
return false;
else {
FindClose(hFind);
return true;
}
}
DWORD Ini::read(const std::string iniName, std::string& errex) {
if(!fileExists(iniName)) {
errex = iniName;
return ERROR_INI_OPEN;
}
// Basisverzeichnis auslesen
if((GetPrivateProfileStringWerr(istr_basedir, vstr_basedir, basedir, iniName) == false) ||
(basedir.size() < minBaseDirLen))
{
errex = istr_basedir;
return ERROR_INI_SYN;
}
if(basedir[basedir.size()-1] !=->\\')
basedir.append(\\);
// Unterverzeichnisse auslesen
for(int day = 0; day < iNDays; ++day) {
if((GetPrivateProfileStringWerr(istr_subdirs, vstr_subdirs[day], dirs[day], iniName) == false) ||
(dirs[day].size() < minSubDirLen))
{
errex = istr_subdirs;
return ERROR_INI_SYN;
}
if(dirs[day][0] ==->\\')
dirs[day] = dirs[day].substr(1);
if(dirs[day][dirs[day].size()-1] ==->\\')
dirs[day].resize(dirs[day].size()-1);
}
// Minimales Alter ist optional
std::string ageStr;
GetPrivateProfileStringWerr(istr_older, vstr_older, ageStr, iniName);
if(chkS(ageStr)) {
long l = strtol(ageStr.c_str(),->\0', 10);
if(l>0 && l<minRelFileAgeMax)
minRelFileAge = l;
}
// Extensions auslesen
numExt = 0;
std::ostringstream oss;
std::string curExt;
for(int extnum = 1; extnum < maxExt; ++extnum) {
oss << extnum;
curExt = oss.str();
oss.str();
std::string ext;
if(GetPrivateProfileStringWerr(istr_ext, curExt, ext, iniName) == false)
break;
else {
wildCards[extnum-1] = *.;
wildCards[extnum-1].append(ext);
numExt++;
}
}
// Mindestens eine Wildcard muss oben im Array abgelegt worden sein (*.txt etc.)
if(!wildCards[0].empty())
return ERROR_NONE;
else {
errex = istr_ext;
return ERROR_INI_SYN;
}
}
void Ini::getBaseDir(std::string& baseDir) const {
baseDir = basedir;
}
void Ini::getSubDirFromDayIndex(int didx, std::string& subDir) const {
subDir= dirs[didx];
}
void Ini::getWildCard(int widx, std::string& wildCard) const {
wildCard = wildCards[widx];
}
int Ini::getNumExts() const {
return numExt;
}
int Ini::getMinRelFileAge() const {
return minRelFileAge;
}
int Ini::getNumberOfDays() {
return iNDays;
}
//---------------------------------------------------
namespace datetime {
time_t fileTimeToTime(const FILETIME* ft) {
// Bed.: Zeit >= 1.1.1970, 00:00
return (time_t) ((*(LONGLONG*)ft - 0x19DB1DED53E8000) / 10000000);
}
time_t getCurTime() {
return time(0);
}
int getLocalDayOfWeek() {
time_t now = getCurTime();
return localtime(&now)->tm_wday;
}
tm* getLocalTime() {
time_t now = getCurTime();
return localtime(&now);
}
}
void showError(int errIdx, bool defTxt, bool extraTxt, const std::string* extra, bool lastErrorLookup) {
if(defTxt)
std::cout << errStrings[errIdx] << std::endl;
if(extraTxt && (extra != NULL))
std::cout << extra << std::endl;
if(lastErrorLookup) {
DWORD error = GetLastError();
LPSTR error_msg;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
error,
MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN),
(LPTSTR) &error_msg,
0,
NULL);
std::cout << error_msg;
LocalFree(error_msg);
}
std::cout << std::endl;
}
//---------------------------------------------------
class BupDel {
public:
struct Stats {
tm *timeStarted, *timeCompleted;
int nFiles, nFilesDeleted, nFilesError;
Stats() : nFiles(), nFilesDeleted(), nFilesError(),
timeStarted(0), timeCompleted(0) {}
void clear() {
nFiles = nFilesDeleted = nFilesError = 0;
timeStarted = 0;
timeCompleted = 0;
}
};
BupDel(const Ini& ini_) : ini(ini_) {}
void getStats(Stats& stats_) const;
void showStats() const;
int traverseFiles(time_t curTime);
private:
Stats stats;
const Ini& ini;
void getTomorrowsSubDirName(std::string& dirName) const;
bool dirOrReadonly(DWORD fileAttributes, int& nFiles) const;
void checkAndDelete(const WIN32_FIND_DATA& fileData, time_t curTime, const std::string& cplteDirName);
};
void BupDel::getStats(Stats& stats_) const {
stats_ = stats;
}
void BupDel::showStats() const {
char tbuf[50];
std::cout << std::endl << *** BupDel Statistik **************** << std::endl << std::endl;
strftime(tbuf, sizeof(tbuf), %H:%M:%S, stats.timeStarted);
std::cout << Gestartet: << tbuf << std::endl;
strftime(tbuf, sizeof(tbuf), %H:%M:%S, stats.timeCompleted);
std::cout << Beendet: << tbuf << std::endl;
std::cout << Anzahl der gefundenen Dateien: << stats.nFiles << std::endl;
std::cout << Anzahl der geloeschten Dateien: << stats.nFilesDeleted << std::endl;
std::cout << Anzahl der Fehler beim Loeschen: << stats.nFilesError << std::endl;
std::cout << ************************************* << std::endl << std::endl;
}
int BupDel::traverseFiles(time_t curTime) {
stats.clear();
stats.timeStarted = datetime::getLocalTime();
std::string cplteDirName;
ini.getBaseDir(cplteDirName);
std::string tsn;
getTomorrowsSubDirName(tsn);
cplteDirName.append(tsn + \\);
std::string cplteWildName(cplteDirName + *.*);
WIN32_FIND_DATA fileData;
HANDLE hFind;
hFind = FindFirstFile(cplteWildName.c_str(), &fileData);
if (hFind == INVALID_HANDLE_VALUE)
{
showError(ERROR_OPEN_TARGET_DIR, true, false, NULL, true);
return ERROR_OPEN_TARGET_DIR;
} else {
BOOL found = TRUE;
while(found) {
if(!dirOrReadonly(fileData.dwFileAttributes, stats.nFiles)) {
checkAndDelete(fileData, curTime, cplteDirName);
}
found = FindNextFile(hFind, &fileData);
}
FindClose(hFind);
}
stats.timeCompleted = datetime::getLocalTime();
return ERROR_NONE;
}
void BupDel::getTomorrowsSubDirName(std::string& dirName) const {
int day = datetime::getLocalDayOfWeek();
int delDay = day == ini.getNumberOfDays() ? 1 : day+1;
ini.getSubDirFromDayIndex(delDay-1, dirName);
}
bool BupDel::dirOrReadonly(DWORD fileAttributes, int& nFiles) const {
if(fileAttributes & FILE_ATTRIBUTE_DIRECTORY)
return true;
nFiles++;
if (fileAttributes & FILE_ATTRIBUTE_READONLY)
return true;
else
return false;
}
void BupDel::checkAndDelete(const WIN32_FIND_DATA& fileData, time_t curTime, const std::string& cplteDirName) {
// Die in der INI-Datei angegebenen Extensions abklappern ...
for(int nExt = 0; nExt < ini.getNumExts(); ++nExt) {
// ... und vergleichen
std::string wc;
ini.getWildCard(nExt, wc);
if(PathMatchSpec(fileData.cFileName, wc.c_str())) {
// Alter der Datei berechnen, wenn nötig
time_t ddays = 0;
if(ini.getMinRelFileAge() > 0) {
const time_t secPerDay = 86400;
time_t diff = curTime - datetime::fileTimeToTime(&fileData.ftLastWriteTime);
ddays = diff / secPerDay;
}
if(ddays >= ini.getMinRelFileAge()) {
// Verzeichnis + Dateiname
std::string fullName(cplteDirName);
fullName.append(fileData.cFileName);
// Datei löschen & Info ausgeben
if(!DeleteFile(fullName.c_str())) {
showError(ERROR_DEL_FILE, true, false, NULL, true);
stats.nFilesError++;
} else {
std::cout << Datei << fullName << geloescht. << // Alter: << ddays << Tage << std::endl;
stats.nFilesDeleted++;
}
}
}
}
}
//---------------------------------------------------
int main(int argc[], char *argv[])
{
std::string iniName(argv[0]);
iniName.resize(iniName.size()-3);
iniName.append(ini);
Ini* ini = Ini::getInstance();
std::string exerr;
DWORD error = ini->read(iniName, exerr);
if(error != ERROR_NONE) {
showError(error, true, true, &exerr, false);
} else {
BupDel bdel(*ini);
if(bdel.traverseFiles(datetime::getCurTime()) == ERROR_NONE)
bdel.showStats();
}
}