#include "gsManifest.h" #include #include #include gsManifest::gsManifest(installManager &manager) : installAgent(manager) { // do nothing! } gsManifest::gsManifest(installManager &manager, FilePath &root) : installAgent(manager), fileCopyMonitor() { this->getManifest(root); this->expandGroups(); } bool gsManifest::getManifest(FilePath &root) { FilePath *manifestPath = new FilePath((char *) root.cString(), "manifest.cfg"); FILE *file; DWORD fileSize; string currentgroup; char *buffer; char *line; char *eol; // open file handle for read access file = fopen(manifestPath->cString(), "rb"); if (file == NULL) { return false; } // get size of file File f(manifestPath->cString()); fileSize = f.getFileSize(); // allocate buffer for whole file and read it in buffer = new char[fileSize]; if (fread(buffer, 1, fileSize, file) < fileSize) { // TODO: error handling } fclose(file); //parse file into lines and send to the line fn line = buffer; while ((eol = strchr(line, '\x0a')) != NULL) // use 0a for the eol to remove // dependency on dos 0d,0a eol { *eol = '\0'; this->getManifestLine(line, currentgroup); line = eol + 1; } this->getManifestLine(line, currentgroup); delete buffer; return true; } bool gsManifest::getManifestLine(char *line, string &group) { char *eol; // we (potentially) need to clean up the end of // line, and we won't use the eol from the main // getManifest fn. as for the last line it'd be // null. // clean up the start of the line while (*line <= ' ' && *line != '\0') { line ++; } // it's a blank line - don't bother! if (*line == '\0') { return true; } // clean up the end of line eol = line + strlen(line) - 1; while (*eol <= ' ' && eol >= line) { *eol = '\0'; eol --; } // does the line end with a colon?; if so take it as a group definition if (*eol == ':') { if (eol == line) // if it's literally just a colon do nothing { return true; } // note the new group name string newgroup(line, 0, eol - line); group = newgroup; } // if it starts with a hash it's just a comment line; skip it else if (*line == '#') { // do nothing! } // an actual line of member items; read them in else { stringArray array; array = stringArray::words(line); if (group.length() == 0) { this->manifests["all"].add(array); } else { this->manifests[group].add(array); } } return true; } /** * Expand all groups */ void gsManifest::expandGroups() { strArrayMap::iterator here = this->manifests.begin(); strArrayMap::iterator end = this->manifests.end(); while (here != end) { this->expandGroup((*here).first); here ++; } } /** * expand a particular group */ void gsManifest::expandGroup(const string &group) { stringArray &array = this->manifests[group]; unsigned int i = 0; while (i < array.size()) { if (this->isGroup(array[i])) { this->expandGroupInstance(group, array[i]); } else { i ++; } } } /** * expand a group instance inside a given group */ void gsManifest::expandGroupInstance(const string &parentgroup, string groupName) { // remove the group instance from the parent this->manifests[parentgroup].remove(groupName); // create a "clean" name without the { } brackets string group(groupName, 1, groupName.length() - 2); // circular reference - we're kind and ignore it!! if (parentgroup.compare(group) == 0) { return; } // lookup chidl group and add it to the parent this->manifests[parentgroup].add(this->manifests[group]); } /** * Check if a member of a group is itself a group - look for { } brackets * around the name */ bool gsManifest::isGroup(string &name) { if (name[0] == '{' && name[name.length()-1] == '}') { return true; } return false; } void gsManifest::expandMacro(string macro, string value) { // illegal escape sequence ?? // string macroRef = "\$(" + macro + ")"; string macroRef = "$(" + macro + ")"; strArrayMap::iterator here = this->manifests.begin(); strArrayMap::iterator end = this->manifests.end(); while (here != end) { stringArray &array = this->manifests[(*here).first]; unsigned int i = 0; while (i < array.size()) { unsigned int pos; while ((pos = array[i].find(macroRef)) < array[i].length() && pos != -1) { array[i].replace(pos, macroRef.length(), value); } i ++; } here ++; } } void gsManifest::clearSelection() { this->selected.empty(); } void gsManifest::selectGroup(string groupName, FilePath &destination) { stringArray &groupArray = this->manifests[groupName]; this->selected[destination].add(groupArray); if (groupName == "collection") { FilePath *temp = new FilePath(destination, "\\collect"); this->collectRoot = *temp; delete temp; } } /** * Copy the manifest */ bool gsManifest::copy(FilePath *source) { fileCopier copy(this); pathStringArrayMap::iterator here = this->selected.begin(); pathStringArrayMap::iterator end = this->selected.end(); // add all the sets to copy to the manifest while (here != end) { FileVector *fileList; stringArray &array = (*here).second; FilePath path((*here).first); // TODO: eliminate inefficiency; we're doing FilePath->string->FilePath in // effect between constructing the copy lists, and then the sets, as far // as the destinations go fileList = this->selection(*source, array); fileCopySet copySet("", *fileList, *source, path); copy.addSet(copySet); delete fileList; here ++; } // check that we've got enough space @ the destination(s) if (!copy.checkSpace()) { return false; } // do the actual copying copy.copy(); return true; } void gsManifest::copiedFile(string from, string to) { if (!this->collectRoot.isAncestorOf(to)) { this->logAction("Manifest.CopyFile", from, to); } } void gsManifest::createdDir(string dirName) { this->logAction("Manifest.CreateDir", dirName); } void gsManifest::copiedDir(string dirName) { if (!this->collectRoot.isAncestorOf(dirName)) { if (this->collectRoot.pathString() == dirName) { this->logAction("Manifest.CopyDir", dirName); } else { this->logAction("Manifest.CreateDir", dirName); } } } void gsManifest::logAction(string actionName, string file) { unInstallCommand command(actionName); command.addParameter(file); manager->storeCommand(command); } void gsManifest::logAction(string actionName, string source, string dest) { unInstallCommand command(actionName); command.addParameter(source); command.addParameter(dest); manager->storeCommand(command); } bool gsManifest::undoAction(string actionName, stringArray ¶ms) { if (actionName == "Manifest.CreateDir" || actionName == "CreateDir") { if (!RemoveDirectory(params[0].c_str())) { this->removeFailed.add(params[0]); } return true; } else if (actionName == "Manifest.CopyDir") { // do a recursive delete then File f(params[0]); if (!f.remove()) { this->removeFailed.add(params[0]); } return true; } else if (actionName == "Manifest.CopyFile" || actionName == "CopyFile") { DeleteFile(params[1].c_str()); return true; } return false; } bool gsManifest::undoFailed(string path) { return this->removeFailed.includes(path); } FileVector *gsManifest::selection(FilePath &root, stringArray &array) { FileVector *reply = new FileVector(); for (unsigned int i = 0; i < array.size(); i++) { FilePath fileName(root.pathString(), array[i]); File file(fileName.pathString()); reply->push_back(file); } return reply; } FileVector *gsManifest::selection(FilePath &source, FilePath &destination) { return this->selection(source, this->selected[destination]); }