#define CS_SYSDEF_PROVIDE_DIR // define for cssysdef.h #include #include "registry.h" #include "fileutil.h" #include "registrycreator.h" #include "updaterconfig.h" #include #include #include #include "updaterglobals.h" // "Test/String/Words" -> "Words" void GetSlicedPathLast(const char* path,csString& mod) { csString path2 = path; mod = path2.Slice(path2.FindLast('/'),path2.Length() - path2.FindLast('/')); if(!mod || mod == path2) mod = path2.Slice(path2.FindLast('\\'),path2.Length() - path2.FindLast('\\')); mod = mod.Slice(1,mod.Length()-1); } // "Test/String/Words" -> "Test" void GetSlicedPathFirst(const char* path,csString& mod) { csString path2 = path; mod = path2.Slice(0,path2.FindFirst('/')); if(!mod || mod == path2) mod = path2.Slice(0,path2.FindFirst('\\')); } // "Test/String/Words" -> "Test/String" void GetSlicedPathFirstLast(const char* path,csString& mod) { csString path2 = path; mod = path2.Slice(0,path2.FindLast('/')); if(!mod || mod == path2) mod = path2.Slice(0,path2.FindLast('\\')); } namespace updater { RegistryCreator::RegistryCreator (iObjectRegistry* newobjreg) { objreg = newobjreg; registry = NULL; } RegistryCreator::~RegistryCreator () { } Registry* RegistryCreator::CreateRegistry () { // Check for critical files first if(!psupdaterengine->GetUpdater()->GetConfig()->CheckCriticalFiles()) { psupdaterengine->CriticalError("One or more critical files are missing!\n"); return NULL; } registry = new Registry(objreg); srand(time(NULL)); MD5Sum ver; // Randomize a version stamp int multi = rand()%100; unsigned int version = rand()%1000000; version *= multi; csString verStr; verStr = version; ver.Calculate((char*)verStr.GetData(),verStr.Length()); registry->SetReposVersion(ver.Get()); // Stat root dir first CreateModule("."); DIR* dir = opendir ("."); if (!dir) { delete registry; psupdaterengine->CriticalError("Couldn't open current directory for reading."); } struct dirent* file; while ( (file = readdir (dir)) ) { // skip files starting with dot if (file->d_name[0] == '.') continue; FileStat* stat = StatFile(file->d_name); if (!stat) { printf ("Warning: Couldn't stat file '%s'.\n", file->d_name); continue; } if (stat->type == FileStat::TYPE_DIRECTORY) { // Check if we should ignore this dir or not if (psupdaterengine->GetUpdater()->GetConfig()->ShouldIgnoreDir(file->d_name)) { printf("I - %s\n", (const char*)file->d_name ); continue; } CreateModule (file->d_name); } delete stat; } closedir (dir); return registry; } void RegistryCreator::CreateModule (const char* name) { printf("Creating Module: %s\n", name ); Module* mod = registry->CreateModule (name); ReadSubDir (mod, ""); } void RegistryCreator::ReadSubDir (Module* mod, const char* directory) { csString module = mod->GetName(); csString dirname = module; if (dirname == "root") dirname = "."; if (strcmp (directory, "") != 0) { dirname += "/"; dirname += directory; } printf ("Reading Directory %s\n", (const char*) dirname); DIR* dir = opendir(dirname); if (!dir) psupdaterengine->CriticalError("Couldn't open directory '%s'.", (const char*) dirname); struct dirent* file; while ( (file = readdir(dir)) ) { // ignore files starting with a dot. if (file->d_name[0] == '.') continue; csString path; path = dirname; path += "/"; path += file->d_name; FileStat* stat = StatFile(path); if (!stat) { printf ("Warning: Couldn't stat file '%s'.\n", (const char*) path); continue; } if (stat->type == FileStat::TYPE_DIRECTORY && csString(mod->GetName()) != "root") { // Check if we should ignore this dir or not if (psupdaterengine->GetUpdater()->GetConfig()->ShouldIgnoreDir(path)) { printf("I - %s\n", path.GetData()); continue; } csString subdir = directory; if (strcmp(directory, "") != 0) { subdir += "/"; } subdir += file->d_name; ReadSubDir (mod, subdir); } else if (stat->type == FileStat::TYPE_FILE) { // Check if we should ignore this file or not if (psupdaterengine->GetUpdater()->GetConfig()->ShouldIgnoreFile(path)) { printf("I - %s\n", path.GetData()); continue; } RegistryFile* regfile = new RegistryFile(path, 0); // Special handle if we are the root module csString toCopy = path; if (module == "root") { toCopy = toCopy.Slice(2,toCopy.Length()); regfile->file = toCopy; } // Set some general stats regfile->size = stat->size; regfile->md5.ReadFile ("/this/" + path, false); csString filename = file->d_name; bool zip = false; // Check if there is a possiblilty that the file is a zip if (filename.Length() > 3) { if (filename.Slice( filename.Length() - 3, filename.Length()) == "zip") { zip = true; } } // ZIP is special if (zip) ReadZip(mod,filename,dirname); else { if (psupdaterengine->GetUpdater()->GetConfig()->IsConfig(path)) { regfile->flags |= RegistryFile::FLAG_CONFIGFILE; } Sort(path,mod,regfile); } } delete stat; } } void RegistryCreator::ReadZip(Module* mod, const char* file, const char* path) { csString zipfile = "/this/" + csString(path) + csString("/") + csString(file); csRef fileBuff = psupdaterengine->GetVFS()->GetRealPath(zipfile); if (!psupdaterengine->GetVFS()->Mount("/zip",fileBuff->GetData() )) { printf("Couldn't mount VFS path!\n"); return; } csString filename; filename = "/storage/"; filename += mod->GetName(); filename += "/"; if (path) { filename += path; filename += "/"; } csString csfile = file; filename += csfile.Slice(0,csfile.FindLast('.')); filename += "_all.zip"; psupdaterengine->GetUpdater()->CopyFile( zipfile, filename,true); // Fill a ZipFile struct with info to give all files in this zip ZipFile zipstru; zipstru.file = file; // Get Size size_t size; psupdaterengine->GetVFS()->GetFileSize(filename,size); zipstru.size = size; // Get MD5 for this zip if(!zipstru.md5.ReadFile(filename,false)) printf("ERROR! COULDN'T GET MD5 SUM FOR FILE %s!\n",filename.GetData()); // Get files and loop through them csRef buff = psupdaterengine->GetVFS()->FindFiles("/zip/"); for (size_t i = 0;i < buff->Length();i++) { bool dir = false; csString fileName = buff->Get(i); if (fileName.GetAt(fileName.Length()-1) == '/') dir = true; fileName = fileName.Slice(5,fileName.Length()); if (dir) { csString subpath = buff->Get(i); ReadZipSubDir(mod,subpath.Slice(5,subpath.Length()),&zipstru,path); } else { if (!fileName) continue; ReadZipFile(mod,fileName,path,&zipstru); } } if (!psupdaterengine->GetVFS()->Unmount("/zip",fileBuff->GetData())) { printf("Couldn't unmount VFS path!\n"); return; } } void RegistryCreator::ReadZipSubDirNames(Module* mod, const char* dir,ZipFile* zipname,const char* realpath ) { csRef buff = psupdaterengine->GetVFS()->FindFiles("/zip/" + csString(dir)); for (size_t i = 0;i < buff->Length();i++) { csString file = buff->Get(i); bool direct = false; if (file.GetAt(file.Length()-1) == '/') direct = true; file = file.Slice(5,file.Length()); if (direct) { csString subpath = buff->Get(i); ReadZipSubDirNames(mod,subpath.Slice(5,subpath.Length()),zipname,realpath); } else { if (!file) continue; size_t first = file.FindFirst('/'); csString myFile = file.Slice( first+1, file.Length() ); psupdaterengine->GetUpdater()->CopyFile( "/zip/" + file, "/myzip/" + myFile, true ); } } } void RegistryCreator::ReadZipSubDir(Module* mod, const char* dir,ZipFile* zipname,const char* realpath, int level ) { //printf("******* Reading SubZipDir: %s from ZIP: %s level: %d\n", dir, zipname->file.GetData(), level ); // /zip is already mounted from ReadZip // Get files and loop through them csRef buff = psupdaterengine->GetVFS()->FindFiles("/zip/" + csString(dir)); for (size_t i = 0;i < buff->Length();i++) { bool direct = false; csString fileName = buff->Get(i); if (fileName.GetAt(fileName.Length()-1) == '/') direct = true; fileName = fileName.Slice(5,fileName.Length()); if (direct) { csString subpath = buff->Get(i); ReadZipSubDir(mod,subpath.Slice(5,subpath.Length()),zipname,realpath, level+1); } else { if (!fileName) continue; ReadZipFile(mod,fileName,realpath,zipname, level+1); } } //printf("******* Finished Reading SubZipDir: %s %d\n", dir, level ); if ( level == 0 ) { csString filename("test.zip"); // This will copy the file to something like /www/updater/art/models.zip/thing.spr psupdaterengine->GetVFS()->DeleteFile("/this/test.zip"); psupdaterengine->GetVFS()->Mount("/myzip",filename ); for (size_t i = 0;i < buff->Length();i++) { csString file = buff->Get(i); bool direct = false; if (file.GetAt(file.Length()-1) == '/') direct = true; file = file.Slice(5,file.Length()); if (direct) { csString subpath = buff->Get(i); ReadZipSubDirNames(mod,subpath.Slice(5,subpath.Length()),zipname,realpath); } else { if (!file) continue; size_t first = file.FindFirst('/'); csString myFile = file.Slice( first+1, file.Length() ); //printf("---> High Level File: %s Directory: %s \n", myFile.GetData(), dir ); //printf("Source: /zip/%s dest /myzip/%s", file.GetData(), myFile.GetData() ); psupdaterengine->GetUpdater()->CopyFile( "/zip/" + file, "/myzip/" + myFile, true ); psupdaterengine->GetVFS()->Sync(); } } csString directoryName = dir; if (directoryName.GetAt(directoryName.Length()-1) == '/') directoryName.DeleteAt(directoryName.Length()-1); csString finalLocation; finalLocation.Format("/storage/%s/%s/%s/%s.zip", mod->GetName(), realpath, zipname->file.GetData(), directoryName.GetData() ); psupdaterengine->GetVFS()->Sync(); if ( !psupdaterengine->GetUpdater()->CopyFile("/this/test.zip", finalLocation,true) ) printf("Failed Copy!\n"); psupdaterengine->GetVFS()->Sync(); psupdaterengine->GetVFS()->Unmount("/myzip", "test.zip"); } } void RegistryCreator::ReadZipFile (Module* mod, const char* file, const char* path,ZipFile* zipname, int level ) { //printf("Reading: %s in %s level %d\n", file, zipname->file.GetData(), level ); // Will set filename later RegistryFile* regfile = new RegistryFile("", 0); // Get file stats size_t filesize; psupdaterengine->GetVFS()->GetFileSize("/zip/" + csString(file),filesize); regfile->size = filesize; // Get MD5 sum if (!regfile->md5.ReadFile ("/zip/" + csString(file), false)) { printf("Couldn't calculate MD5 checksum for file %s! Skipping..\n",file); return; } csString ender; if (path) { ender = path; ender += "/"; } ender += csString(zipname->file) + csString("/") + csString(file); /** * parentZip = ZIP file (art/test.zip) * zipFile = Internal file (file.ext) * file = server file (art/test.zip/file.ext) */ regfile->inZip = true; regfile->parentZip = ender.Slice(0,ender.Length() - strlen(file) - 1); //Remove filename and trailing / regfile->parentSize = zipname->size; regfile->parentMD5.Set( zipname->md5.Get()); regfile->zipFile = file; regfile->file = ender; mod->AddRegistryFile(regfile); // This will copy the file to something like /www/updater/art/models.zip/thing.spr if ( level == 0 ) psupdaterengine->GetUpdater()->CopyFile( "/zip/" + csString(file), "/storage/" + csString(mod->GetName()) + csString("/") + ender, true); } void RegistryCreator::Sort(const char* path,Module* mod, RegistryFile* regfile) { Module* modToUse = mod; csString cspath = path; // Sort the path csString sortedPath = psupdaterengine->GetUpdater()->GetConfig()->GetSortedPath(path,mod->GetName()); if (sortedPath != path) { csString module = sortedPath.Slice(0,sortedPath.FindFirst('/')); // This will get the module if it exists, or create if it doesn't modToUse = registry->CreateModule(module); } size_t pathS; if(psupdaterengine->GetUpdater()->GetConfig()->HasCustomSortDest(path)) pathS = sortedPath.FindLast('/')+1; else { pathS = sortedPath.FindFirst('/')+1; } sortedPath = sortedPath.Slice(pathS,sortedPath.Length()-pathS); if(sortedPath.Slice(0,2) == "./") { sortedPath = sortedPath.Slice(2,sortedPath.Length()-2); cspath = cspath.Slice(2,cspath.Length()-2); } regfile->file = sortedPath; if(mod != modToUse || sortedPath != cspath) { printf("S - %s to %s",cspath.GetData(),sortedPath.GetData()); if(mod != modToUse) printf(" (%s => %s)",mod->GetName(),modToUse->GetName()); printf("\n"); } if (psupdaterengine->GetUpdater()->CopyFile( "/this/" + cspath, "/storage/" + csString(modToUse->GetName()) + "/" + sortedPath,true) ) modToUse->AddRegistryFile(regfile); } void RegistryCreator::UpdateRegistry(const char* registrypath,const char* filename) { if(!filename) { printf("Got empty filename!\n"); return; } if(!registrypath) { printf("Got empty registry filename!\n"); return; } Config* config = psupdaterengine->GetUpdater()->GetConfig(); csString file = filename; //Convert because of the csString functions csString mod; GetSlicedPathFirst(file,mod); csString path = registrypath; GetSlicedPathFirstLast(path,path); // Now get the sorted path (i.e /art/models.zip becomes /art/art/models.zip) csString sorted = config->GetSortedPath(file,mod); // Get the new module if the file is sorted GetSlicedPathFirst(sorted,mod); //Mount registry path csString registryDir; GetSlicedPathFirstLast(registrypath,registryDir); psupdaterengine->GetVFS()->Mount("/storage",registryDir+"/"); // Load the registry csString registryFile; GetSlicedPathLast(registrypath,registryFile); Registry* registry = new Registry(psupdaterengine->GetObjectRegistry()); if(!registry->Load("/storage/" + registryFile)) { printf("Couldn't load registry %s!\n",registrypath); delete registry; return; } // Find the module Module* module = registry->GetModule(mod); if(!module) { printf("Couldn't find the module %s!\n",mod.GetData()); delete registry; return; } uint32_t flags = 0; if(config->IsConfig(file)) flags |= RegistryFile::FLAG_CONFIGFILE; RegistryFile* regfile = new RegistryFile(filename,flags); size_t size; psupdaterengine->GetVFS()->GetFileSize("/this/" + file,size); regfile->size = size; regfile->md5.ReadFile("/this/" + file,false); // This will copy the file to something like /www/updater/art/models.zip/thing.spr if (psupdaterengine->GetUpdater()->CopyFile( "/this/" + file, "/storage/" + sorted, true)) { module->AddRegistryFile(regfile); printf("File %s added to %s\n",file.GetData(),sorted.GetData()); } registry->Save("/storage/" + registryFile); psupdaterengine->GetVFS()->Unmount("/storage",registryDir); } } // end of namespace updater