Code:
//file: direntry.hpp
//Author: William Putnam
//Last Updated: 9.26.2013
#ifndef direntry_hpp
#define direntry_hpp
#include "tools.hpp"
//dirent is defined exactly as in the instructions
class direntry : public dirent{
public:
direntry(){};
~direntry();
void print(ostream& out);
};
#endif
//*
//file: direntry.cpp
//Author: William Putnam
//Last Updated: 9.26.2013
#include "direntry.hpp"
void direntry::print(ostream& out){
out << "File type: " << setw(30) << d_type << endl
<< "Inode #: " << setw(30) << d_ino << endl
<< "Name: " << setw(30) << d_name << endl;
}
//*
//file: stats.hpp
//Author: William Putnam
//Last Updated: 9.26.2013
#include "direntry.hpp"
//stat is defined exactly as in the instructions
class stats : public stat{
public:
stats();
virtual ~stats();
void print(ostream& out);
int getInode(){ return st_ino;};
int getMode(){ return st_mode;};
int getLink(){ return st_nlink;};
int getUID(){ return st_uid;};
int getGID(){ return st_gid;};
int getMTime(){ return st_mtimespec.tv_sec;};
int getCTime(){ return st_ctimespec.tv_sec;};
};
//*
//file: stats.cpp
//Author: William Putnam
//Last Updated: 9.26.2013
#include "stats.hpp"
stats::print(ostream& out){
out << "Inode: " << setw(30) << st_ino << endl
<< "Protection mode: " << setw(30) << st_mode << endl
<< "Hard link count: " << setw(30) << st_nlink << endl
<< "User ID: " << setw(30) << st_uid << endl
<< "Group ID: " << setw(30) << st_gid << endl
<< "Last Updated: " setw(30) << st_mtimespec << endl
<< "Last Status Change: " setw(30) << st_ctimespec << endl;
}
//*
//file: fileData.hpp
//Author: William Putnam
//Last Updated: 9.26.2013
#include "stats.hpp"
class fileData{
private:
char directName[256], *directType;
int inodeNum;
//---------
int statNode, statMode, statLink, statUID, statGID, statMTime, statCTime;
//---------
char SHA1[20];
public:
fileData(direntry d, stats s);
~fileData();
//WARNING: ERRORS STEM FROM THIS NEXT LINE!!!!!!!!!!!!
bool operator<(const fileData& f) const { return strcmp(directName, f.directName) < 0;}
void print(ostream& out);
void serialize(ostream& out);
};
//*
//file: fileData.cpp
//Author: William Putnam
//Last Updated: 9.26.2013
#include "fileData.hpp"
fileData::fileData(direntry d, stats s){
fileData.directName = d.d_name;
fileData.directType = d.d_type;
fileData.inodeNum = d.d_ino;
fileData.statNode = s.getInode();
fileData.statMode = s.getMode();
fileData.statLink = s.getLink();
fileData.statUID = s.getUID();
fileData.statGID = s.getGID();
fileData.statMTime = s.getMTime();
fileData.statCTime = s.getCTime();
//SHA algorithm goes here
}
void fileData::print(ostream& out){
out << directName << ", " << inodeNum << endl
<< statNode << "/" << statMode << ", " << statLink
<< ", " << statUID << "/" << statGID << ", "
<< statMTime << "/" << statCTime << endl;
}
void fileData::serialize(ostream& out){
out << "File type: \t" << setw(30) << directType << endl
<< "Inode #: \t" << setw(30) << inodeNum << endl
<< "Name: \t" << setw(30) << directName << endl
<< "Inode: \t" << << statNode << endl
<< "Protection mode: \t" << setw(30) << statMode << endl
<< "Hard link count: \t" << setw(30) << statLink<< endl
<< "User ID: \t" << setw(30) << statUID << endl
<< "Group ID: \t" << setw(30) << statGID << endl
<< "Last Updated: \t" setw(30) << statMTime << endl
<< "Last Status Change: \t" setw(30) << statCTime << endl << "#\n";
}
//*
//file: dirData.hpp
//Author: William Putnam
//Last Updated: 9.26.2013
#include "fileData.hpp"
class dirData{
private:
char* directoryName;
int statNode, statMode, statLink, statUID, statGID, statMTime, statCTime;
vector<fileData> fD;
vector<string> subDir;
int nFiles = 0, nDirs = 0;
public:
dirData(char* name, stats s);
~dirData();
void print(ostream& out);
void serialize(ostream& out);
void pushfDVec(fileData f){ fD.push_back(f);}
void printStrings(ostream& out){ for (int i = 0; i < nDirs; i++) out << subDir[i] << endl;};
void serialFD(int i, ostream& out){ fD[i].serialize(out);}
void sortFD(){ std::sort(fD.begin(), fD.end());}
void sortStr(){ std::sort(subDir.begin(), subDir.end());}
void incFiles(){ ++nFiles;};
void incDirs(){ ++nDirs;};
int getFileCnt(){ return nFiles;};
};
//*
//file: dirData.cpp
//Author: William Putnam
//Last Updated: 9.26.2013
#include "dirData.hpp"
dirData::dirData(char* name, stats s){
directoryName = name;
fileData.statNode = s.getInode();
fileData.statMode = s.getMode();
fileData.statLink = s.getLink();
fileData.statUID = s.getUID();
fileData.statGID = s.getGID();
fileData.statMTime = s.getMTime();
fileData.statCTime = s.getCTime();
}
void dirData::print(ostream& out){
out << directoryName << ", " << inodeNum << endl
<< statNode << "/" << statMode << ", " << statLink
<< ", " << statUID << "/" << statGID << ", "
<< statMTime << "/" << statCTime << endl;
}
void fileData::serialize(ostream& out){
out << "File type: \t" << setw(30) << directType << endl
<< "Inode #: \t" << setw(30) << inodeNum << endl
<< "Name: \t" << setw(30) << directName << endl
<< "Inode: \t" << << statNode << endl
<< "Protection mode: \t" << setw(30) << statMode << endl
<< "Hard link count: \t" << setw(30) << statLink<< endl
<< "User ID: \t" << setw(30) << statUID << endl
<< "Group ID: \t" << setw(30) << statGID << endl
<< "Last Updated: \t" setw(30) << statMTime << endl
<< "Last Status Change: \t" setw(30) << statCTime << endl << "#\n";
}
//*
//file: controller.hpp
//Author: William Putnam
//Last Updated: 9.24.2013
#include "dirData.hpp"
class controller{
private:
char *dbFile = NULL, *reportFile = NULL, *rootPath = NULL, *dirName = NULL;
bool c = false, d = false, h = false, o = false, r = false,
u = false, v = false;
int argDiag = 0;
bool lvl[4] = {false, false, false, false};
dirData* currentStats = NULL;
public:
controller(){};
~controller(){};
void run(int argc, char* argv[]);
void decodeLine(int argc, char* argv[]);
void printReport(int argc, char* argv[]);
void processDir(char* directoryName);
void processLevel(char* currentName);
void cSwitch();
void dSwitch();
void hSwitch();
void oSwitch();
void rSwitch();
void uSwitch();
void vSwitch(int getArg);
void noArg(){ cout << "Missing an argument. Can't process.\n"; exit(1);};
void extraArg(){ cout << "Argument overflow. Can't process.\n"; exit(1);};
};
//*
//file: controller.cpp
//Author: William Putnam
//Last Updated: 9.24.2013
#include "controller.hpp"
void controller::run(int argc, char* argv[]){
decodeLine(argc, argv);
printReport(argc, argv);
processDir(rootPath);
}
//---------------------------------------------------------------------------
void controller::decodeLine(int argc, char* argv[]){
int getArg = 0, index = 0, cnt = 0;
extern int opterr;
static struct option argOpts[] = {
{"database", required_argument, 0, 'D'},
{"output", required_argument, 0, 'o'},
{"help", no_argument, 0, 'h'},
{"create", no_argument, 0, 'C'},
{"update", no_argument, 0, 'U'},
{"verify", required_argument, 0, 'V'},
{"recur", no_argument, 0, 'r'},
{0,0,0,0}};
opterr = 0; //don't print out non-args
//NOTE: required arguments are stored in optarg
while (getArg != -1){
getArg = getopt_long(argc, argv, "D:o:hCUV:r", argOpts, &index);
switch(getArg){
case 'C': {cSwitch(); ++cnt; break;} //create database
case 'D': {dSwitch(); ++cnt; break;} //database name
case 'h': {hSwitch(); ++cnt; break;} //help
case 'o': {oSwitch(); ++cnt; break;} //output file
case 'r': {rSwitch(); ++cnt; break;} //recursive
case 'U': {uSwitch(); ++cnt; break;} //update
case 'V': {vSwitch(getArg); ++cnt; break;} //verify
}
}
++cnt;
if (cnt == argc) noArg();
else if (cnt == argc-2) extraArg();
rootPath = argv[cnt];
dirName = strchr(rootPath, '/');
if (!v){ //set default diag to 5
lvl[0] = true;
lvl[2] = true;
argDiag = 5;
}
if (!d) dbFile = strdup("trippy.dat");
if (!reportFile) reportFile = strdup("trippy.dat");
}
//---------------------------------------------------------------------------
void controller::printReport(int argc, char* argv[]){
for (int i = 0; i < argc; ++i) cout << argv[i] << " ";
cout << endl;
cout << "Output file name: " << (reportFile? reportFile : "") << endl;
cout << "Input file name: " << (dbFile? dbFile : "") << endl;
cout << "Create Database? " << (c? "YES\n" : "NO\n");
cout << "Update: " << (u? "YES\n" : "NO\n");
cout << "Diagnostic level: " << argDiag << endl;
cout << "Recursive? " << (r? "YES\n" : "NO\n");
cout << "Directory: " << (rootPath? rootPath : "") << endl;
}
//---------------------------------------------------------------------------
void controller::processDir(char* directoryName){
ofstream rFile(reportFile);
fstream dFile(dbFile, fstream::app);
if (!rFile.is_open() || !dFile.is_open()){
fatal("Error opening specified files.\n");
}
rFile << rootPath << endl;
dFile << rootPath << endl;
processLevel(directoryName);
}
//---------------------------------------------------------------------------
void controller::processLevel(char* currentName){
stats s;
direntry d;
DIR* dr = opendir(currentName);
struct dirent* index;
string str;
currentStats = new dirData(currentName, s);
fstream dB(rootPath, fstream::app);
while (index != 0){
index = readdir(dr);
if (index->d_type != DT_REG && index->d_type != DT_DIR){}
else {
//malloc(d);
if (index->d_type == DT_REG){
currentStats->pushfDVec(fileData(direntry(),s));
currentStats->incFiles();
}
else if (index->d_type == DT_DIR){
currentStats->pushfDVec(fileData(direntry(), s));
currentStats->incDirs();
}
}
}
closedir(dr);
currentStats->sortFD();
currentStats->sortStr();
currentStats->serialize(dB);
for (int i = 0; i < currentStats->getFileCnt(); i++)
currentStats->serialFD(i, dB);
currentStats->printStrings(dB);
if (r){} //for recursion (later)
}
//---------------------------------------------------------------------------
void controller::cSwitch(){
char contin = '\0';
if (v || u){
cerr << "Can't verify/update a database that doesn't exist.\n";
exit(1);
}
else if (d){
cout << "The file you specified will be overwritten.\n" <<
"Type y to continue, n to exit.\n";
while (contin != 'n' || contin != 'N'){
cin >> contin;
if (contin == 'y' || contin == 'Y') break;
else if (contin == 'n' || contin == 'N'){
d = false; return;
}
else cout << "Invalid entry.\nType y to continue, n to exit.\n";
}
}
else c = true;
}
//---------------------------------------------------------------------------
void controller::dSwitch(){
char contin = '\0';
d = true;
if (c){
fstream dFile(optarg);
if (dFile.is_open()){
cout << "The file you specified will be overwritten.\n" <<
"Type y to continue, n to exit.\n";
while (contin != 'n' || contin != 'N'){
cin >> contin;
if (contin == 'y' || contin == 'Y') break;
else if (contin == 'n' || contin == 'N'){
d = false; return;
}
else cout << "Invalid entry.\nType y to continue, n to exit.\n";
}
}
dbFile = optarg;
}
//implement stream here (later)
}
//---------------------------------------------------------------------------
void controller::hSwitch(){
h = true;
cout << "HELP:" << endl << "-o[utput] specifies output file" <<
endl << "-i[nput] specifies input file" <<
endl << "-d[atabase] specifies file containing checkpoint database" <<
endl << "-c[reate] specifies the creation of a new database file" <<
endl << "-v[erify] determines the diagnostic level" <<
endl << "-u[pdate] updates the database file" <<
endl << "-r[ecursive] process the directories recursively\n";
exit(1);
}
//---------------------------------------------------------------------------
void controller::oSwitch(){
o = true;
reportFile = optarg;
}
//---------------------------------------------------------------------------
void controller::rSwitch(){
r = true;
}
//---------------------------------------------------------------------------
void controller::uSwitch(){
if (v || c){
cerr << "Can't verify/update a database that doesn't exist.\n";
exit(1);
}
else u = true;
}
//---------------------------------------------------------------------------
void controller::vSwitch(int getArg){
if (c){
cerr << "Can't verify/update a database that doesn't exist.\n";
exit(1);
}
v = true;
getArg = strtol(optarg, NULL, 10);
argDiag = getArg;
for (int i = 0; i < 4; i++){
getArg = getArg >> 1;
if (!!(getArg & 1) == 0b1) lvl[i] = true;
}
}
//*
//file: main.cpp
//Author: William Putnam
//Last Updated: 9.24.2013
#include "controller.hpp"
int main(int argc, char* argv[]){
banner();
controller cont;
cout << "a greeting comment" << endl;
cont.run(argc, argv);
bye();
}
As a bonus, if it helps, I'm going to include the actual line that she gave to us to use for the operator in one of her class examples: