/* * registry.cpp by Matthias Braun * * Copyright (C) 2002 Atomic Blue (info@planeshift.it, http://www.atomicblue.org) * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation (version 2 of the License) * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include #include #include #include #include #include #include #include "registry.h" #include "sortarray.h" #include "updaterconfig.h" #include "updaterglobals.h" namespace updater { Registry::Registry (iObjectRegistry* newobjreg) { objreg = newobjreg; vfs = psupdaterengine->GetVFS(); if (!vfs) psupdaterengine->CriticalError("Couldn't find vfs plugin!\n"); xml = psupdaterengine->GetDocumentSystem(); if (!xml) psupdaterengine->CriticalError("Error creating xml document system!"); } Registry::~Registry () { vfs = NULL; } bool Registry::Load (const char* filename) { csRef buf = vfs->ReadFile (filename); if (!buf || !buf->GetSize()) { if (csString(filename) == "/this/updatercurrent.xml") printf("Couldn't load cached file list. If this is the first time you run, there is nothing to worry about!\n"); else printf("Error loading registry file '%s'\n", filename); return false; } csRef doc = xml->CreateDocument(); const char* error = doc->Parse (buf); if (error) { printf("Couldn't parse xml: '%s'", error); return false; } csRef root = doc->GetRoot (); if (!root) { printf("Error when getting top registry node!"); return false; } csRef topnode = root->GetNode ("registry"); if (!topnode) { printf("Couldn't find registry topnode!"); return false; } // read list of modules csRef it = topnode->GetNodes (); while (it->HasNext ()) { csRef node = it->Next(); if (node->GetType() != CS_NODE_ELEMENT) continue; if (!strcmp(node->GetValue(),"information")) { version = node->GetAttributeValue("version"); updaterVersion = node->GetAttributeValueAsInt("updater_version"); updaterWin = node->GetAttributeValue("updater_win"); updaterMac = node->GetAttributeValue("updater_mac"); updaterLinux = node->GetAttributeValue("updater_linux"); md5Win = node->GetAttributeValue("md5_win"); md5Mac = node->GetAttributeValue("md5_mac"); md5Linux = node->GetAttributeValue("md5_linux"); continue; } if (strcmp(node->GetValue(), "module") != 0) { fprintf (stderr, "Warning expected module, got: '%s'\n", node->GetValue()); continue; } // XXX: Read conditon? const char* name = node->GetAttributeValue ("name"); if (!name) { fprintf (stderr, "WARNING: directory node without name!\n"); continue; } bool used = node->GetAttributeValueAsBool ("used"); Module* mod = new Module(name); mod->SetUsed(used); size_t modindex = modules.Push (mod); ParseModule (node, modules[modindex]); } return true; } void Registry::ParseModule (iDocumentNode* node, Module* objectlist) { csRef it = node->GetNodes (); while (it->HasNext ()) { csRef node = it->Next(); if (node->GetType() != CS_NODE_ELEMENT) continue; if (!strcmp (node->GetValue(),"zip")) { //Do zip csString zip = node->GetAttributeValue("file"); csString zipMd5 = node->GetAttributeValue("md5"); unsigned long zipSize = 0; if(node->GetAttributeValue("size")) zipSize = atol(node->GetAttributeValue("size")); csRef it2 = node->GetNodes (); while (it2->HasNext ()) { csRef node2 = it2->Next(); //Add file? if (!strcmp(node2->GetValue(),"add")) { RegistryFile* object = new RegistryFile(node2->GetAttributeValue ("realfile"), 0); object->zipFile = node2->GetAttributeValue ("zipfile"); object->parentZip = zip; if(zipMd5.Length() == 32) object->parentMD5.Set(zipMd5); object->parentSize = zipSize; object->inZip = true; object->size = node2->GetAttributeValueAsInt ("size"); const char* md5 = node2->GetAttributeValue ("md5"); if (md5) object->md5.Set(md5); objectlist->AddRegistryFile (object); } //Remove file? if (!strcmp(node2->GetValue(),"remove")) { RegistryFile* object = new RegistryFile(node2->GetAttributeValue ("file"), 0); object->parentZip = zip; object->inZip = true; object->removeFromZip = true; objectlist->AddRegistryFile (object); } } continue; } else if (strcmp (node->GetValue(), "file") != 0) { fprintf (stderr, "Warning: Expected 'file' node got '%s'.\n", node->GetValue()); continue; } const char* path = node->GetAttributeValue ("path"); if (!path) { fprintf (stderr, "Warning: Expected filename for file.\n"); continue; } // reading flags uint32_t flags = 0; if (node->GetAttributeValueAsInt ("executable") == 1) flags |= RegistryFile::FLAG_EXECUTABLE; if (node->GetAttributeValueAsInt ("textfile") == 1) flags |= RegistryFile::FLAG_TEXTFILE; if (node->GetAttributeValueAsInt ("config") == 1) flags |= RegistryFile::FLAG_CONFIGFILE; const char* link = node->GetAttributeValue ("link"); if (link) flags |= RegistryFile::FLAG_LINK; RegistryFile* object = new RegistryFile(path, flags); object->size = node->GetAttributeValueAsInt ("size"); const char* md5 = node->GetAttributeValue ("md5"); if (md5) object->md5.Set(md5); objectlist->AddRegistryFile (object); } // SortArray (objectlist); } void Registry::Save (const char* filename) { csRef doc = xml->CreateDocument(); csRef root = doc->CreateRoot (); csRef topnode = root->CreateNodeBefore (CS_NODE_ELEMENT); topnode->SetValue ("registry"); csRef infonode = topnode->CreateNodeBefore (CS_NODE_ELEMENT); infonode->SetValue ("information"); infonode->SetAttribute("version",version); infonode->SetAttributeAsInt("updater_version",UPDATER_VERSION); if(psupdaterengine->GetCreateMode()) { MD5Sum updaterWin,updaterMac,updaterLinux; if(updaterWin.ReadFile(csString("/this/") + psupdaterengine->GetUpdater()->GetConfig()->GetUpdaterWinPath(),false)) { infonode->SetAttribute("updater_win",psupdaterengine->GetUpdater()->GetConfig()->GetUpdaterWinPath()); infonode->SetAttribute("md5_win",updaterWin.Get()); } else printf("Couldn't hash updater Win application\n"); if(updaterMac.ReadFile(csString("/this/") + psupdaterengine->GetUpdater()->GetConfig()->GetUpdaterMacPath(),false)) { infonode->SetAttribute("updater_mac",psupdaterengine->GetUpdater()->GetConfig()->GetUpdaterMacPath()); infonode->SetAttribute("md5_mac",updaterWin.Get()); } else printf("Couldn't hash updater Mac application\n"); if(updaterLinux.ReadFile(csString("/this/") + psupdaterengine->GetUpdater()->GetConfig()->GetUpdaterLinuxPath(),false)) { infonode->SetAttribute("updater_linux",psupdaterengine->GetUpdater()->GetConfig()->GetUpdaterLinuxPath()); infonode->SetAttribute("md5_linux",updaterLinux.Get()); } else printf("Couldn't hash updater Linux application\n"); } if (psupdaterengine->GetCreateMode()) { //Copy module csString newUpdater = "updater"; newUpdater += UPDATER_VERSION; newUpdater += ".zip"; if (!vfs->Mount("/zip",newUpdater )) { printf("Couldn't mount VFS path!\n"); } for(size_t i = 0;i < psupdaterengine->GetUpdater()->GetConfig()->systemFiles.Length();i++) { if(!psupdaterengine->GetUpdater()->CopyFile( "/this/" + psupdaterengine->GetUpdater()->GetConfig()->systemFiles.Get(i), "/zip/" + psupdaterengine->GetUpdater()->GetConfig()->systemFiles.Get(i), true )) { printf("Couldn't copy file into system zip!\n"); } } if (!vfs->Sync()) { printf("Couldn't Sync VFS path!\n"); } if (!vfs->Unmount( "/zip",newUpdater )) { printf("Couldn't unmount VFS path!\n"); } psupdaterengine->GetUpdater()->CopyFile("/this/" + newUpdater,"/storage/" + newUpdater,true); vfs->DeleteFile("/this/" + newUpdater); } csArray modulesXml; psupdaterengine->GetUpdater()->GetConfig()->ModuleSetup(modulesXml); // Save all modules for (size_t i=0;i modulenode = topnode->CreateNodeBefore (CS_NODE_ELEMENT); modulenode->SetValue ("module"); modulenode->SetAttribute ("name", modules[i]->GetName()); if(!psupdaterengine->GetCreateMode() && modulesXml.Find(modules[i]->GetName()) != csArrayItemNotFound) modulenode->SetAttributeAsInt ("used", true); WriteModule (modulenode, modules[i]); } const char* error = doc->Write (vfs, filename); if (error) printf("When writing '%s': %s, check read only setting\n", filename, error); } void Registry::WriteModule (iDocumentNode* node,Module* mod) { for (unsigned int i=0;iGetRegistryLength();i++) { RegistryFile* file = mod->GetRegistryFile(i) ; if (file->inZip) { csRef zipnode = node->CreateNodeBefore (CS_NODE_ELEMENT); zipnode->SetValue ("zip"); zipnode->SetAttribute("file",file->parentZip); zipnode->SetAttributeAsInt("size",(int)file->parentSize); zipnode->SetAttribute("md5",file->parentMD5.Get()); csString zipfile = file->parentZip; csString oldzipfile = zipfile; while(zipfile == oldzipfile) { csRef filenode = zipnode->CreateNodeBefore (CS_NODE_ELEMENT); filenode->SetValue ("add"); filenode->SetAttribute ("zipfile", file->zipFile); filenode->SetAttribute ("realfile", file->file); filenode->SetAttributeAsInt ("size",(int) file->size); if (file->md5.Get()) filenode->SetAttribute ("md5", file->md5.Get()); i++; if (i >= mod->GetRegistryLength()) break; file = mod->GetRegistryFile(i); zipfile = file->parentZip; } i--; // Do this to not skip the last file } else { csRef filenode = node->CreateNodeBefore (CS_NODE_ELEMENT); filenode->SetValue ("file"); filenode->SetAttribute ("path", file->file); filenode->SetAttributeAsInt ("size", (int)file->size); if (file->md5.Get()) filenode->SetAttribute ("md5", file->md5.Get()); if (file->flags & RegistryFile::FLAG_EXECUTABLE) filenode->SetAttribute ("executable", "1"); if (file->flags & RegistryFile::FLAG_TEXTFILE) filenode->SetAttribute ("textfile", "1"); if (file->flags & RegistryFile::FLAG_LINK) filenode->SetAttribute ("link", file->link); if (file->flags & RegistryFile::FLAG_CONFIGFILE) filenode->SetAttribute ("config", "1"); } } } Module* Registry::GetModule (const char* modulename) { for (size_t i=0;iGetName(), modulename) == 0) return modules[i]; } return NULL; } Module* Registry::CreateModule (const char* modulename) { // Check if we already have one module with that name Module* existing = GetModule(modulename); if (existing) return existing; Module* mod = new Module (modulename); size_t idx = modules.Push (mod); return modules[idx]; } bool Registry::operator == (Registry* other) const { // registries are sorted so just comparing for (size_t m=0;mGetName(); Module* othermod = other->GetModule (module); if (!othermod || modules[m]->GetRegistryLength() != othermod->GetRegistryLength()) return false; for (unsigned int f=0;fGetRegistryLength();f++) { if (! (modules[m]->GetRegistryFile(f) == othermod->GetRegistryFile(f) ) ) return false; } } return true; } const char* Registry::GetUpdaterMD5() { #ifdef CS_PLATFORM_WIN32 return md5Win; #endif #ifdef CS_PLATFORM_MACOSX return md5Mac; #else return NULL; #endif } const char* Registry::GetUpdaterPath() { #ifdef CS_PLATFORM_WIN32 return updaterWin.GetData(); #endif #ifdef CS_PLATFORM_MACOSX return updaterMac.GetData(); #else return NULL; #endif } //--------------------------------------------------------------------------- Module::Module (const char* newname) { name = csStrNew(newname); } Module::~Module () { delete[] name; } const char* Module::GetName () const { if (csString(name) == ".") return "root"; return name; } RegistryFile* Module::GetRegistryFile(size_t id) { return list.Get(id); } } // end of namespace updater