/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "install-ds.h" #include #include #include #include #define PORT_Strcasecmp PL_strcasecmp #define MODULE_FILE_STRING "ModuleFile" #define MODULE_NAME_STRING "ModuleName" #define MECH_FLAGS_STRING "DefaultMechanismFlags" #define CIPHER_FLAGS_STRING "DefaultCipherFlags" #define FILES_STRING "Files" #define FORWARD_COMPATIBLE_STRING "ForwardCompatible" #define PLATFORMS_STRING "Platforms" #define RELATIVE_DIR_STRING "RelativePath" #define ABSOLUTE_DIR_STRING "AbsolutePath" #define FILE_PERMISSIONS_STRING "FilePermissions" #define EQUIVALENT_PLATFORM_STRING "EquivalentPlatform" #define EXECUTABLE_STRING "Executable" #define DEFAULT_PERMISSIONS 0777 #define PLATFORM_SEPARATOR_CHAR ':' /* Error codes */ enum { BOGUS_RELATIVE_DIR = 0, BOGUS_ABSOLUTE_DIR, BOGUS_FILE_PERMISSIONS, NO_RELATIVE_DIR, NO_ABSOLUTE_DIR, EMPTY_PLATFORM_STRING, BOGUS_PLATFORM_STRING, REPEAT_MODULE_FILE, REPEAT_MODULE_NAME, BOGUS_MODULE_FILE, BOGUS_MODULE_NAME, REPEAT_MECH, BOGUS_MECH_FLAGS, REPEAT_CIPHER, BOGUS_CIPHER_FLAGS, REPEAT_FILES, REPEAT_EQUIV, BOGUS_EQUIV, EQUIV_TOO_MUCH_INFO, NO_FILES, NO_MODULE_FILE, NO_MODULE_NAME, NO_PLATFORMS, EQUIV_LOOP, UNKNOWN_MODULE_FILE }; /* Indexed by the above error codes */ static const char* errString[] = { "%s: Invalid relative directory", "%s: Invalid absolute directory", "%s: Invalid file permissions", "%s: No relative directory specified", "%s: No absolute directory specified", "Empty string given for platform name", "%s: invalid platform string", "More than one ModuleFile entry given for platform %s", "More than one ModuleName entry given for platform %s", "Invalid ModuleFile specification for platform %s", "Invalid ModuleName specification for platform %s", "More than one DefaultMechanismFlags entry given for platform %s", "Invalid DefaultMechanismFlags specification for platform %s", "More than one DefaultCipherFlags entry given for platform %s", "Invalid DefaultCipherFlags entry given for platform %s", "More than one Files entry given for platform %s", "More than one EquivalentPlatform entry given for platform %s", "Invalid EquivalentPlatform specification for platform %s", "Module %s uses an EquivalentPlatform but also specifies its own" " information", "No Files specification in module %s", "No ModuleFile specification in module %s", "No ModuleName specification in module %s", "No Platforms specification in installer script", "Platform %s has an equivalency loop", "Module file \"%s\" in platform \"%s\" does not exist" }; static char* PR_Strdup(const char* str); #define PAD(x) \ { \ int pad_i; \ for (pad_i = 0; pad_i < (x); pad_i++) \ printf(" "); \ } #define PADINC 4 Pk11Install_File* Pk11Install_File_new() { Pk11Install_File* new_this; new_this = (Pk11Install_File*)PR_Malloc(sizeof(Pk11Install_File)); Pk11Install_File_init(new_this); return new_this; } void Pk11Install_File_init(Pk11Install_File* _this) { _this->jarPath = NULL; _this->relativePath = NULL; _this->absolutePath = NULL; _this->executable = PR_FALSE; _this->permissions = 0; } /* ////////////////////////////////////////////////////////////////////////// // Method: ~Pk11Install_File // Class: Pk11Install_File // Notes: Destructor. */ void Pk11Install_File_delete(Pk11Install_File* _this) { Pk11Install_File_Cleanup(_this); } /* ////////////////////////////////////////////////////////////////////////// // Method: Cleanup // Class: Pk11Install_File */ void Pk11Install_File_Cleanup(Pk11Install_File* _this) { if (_this->jarPath) { PR_Free(_this->jarPath); _this->jarPath = NULL; } if (_this->relativePath) { PR_Free(_this->relativePath); _this->relativePath = NULL; } if (_this->absolutePath) { PR_Free(_this->absolutePath); _this->absolutePath = NULL; } _this->permissions = 0; _this->executable = PR_FALSE; } /* ////////////////////////////////////////////////////////////////////////// // Method: Generate // Class: Pk11Install_File // Notes: Creates a file data structure from a syntax tree. // Returns: NULL for success, otherwise an error message. */ char* Pk11Install_File_Generate(Pk11Install_File* _this, const Pk11Install_Pair* pair) { Pk11Install_ListIter* iter; Pk11Install_Value* val; Pk11Install_Pair* subpair; Pk11Install_ListIter* subiter; Pk11Install_Value* subval; char* errStr; char* endp; PRBool gotPerms; iter = NULL; subiter = NULL; errStr = NULL; gotPerms = PR_FALSE; /* Clear out old values */ Pk11Install_File_Cleanup(_this); _this->jarPath = PR_Strdup(pair->key); /* Go through all the pairs under this file heading */ iter = Pk11Install_ListIter_new(pair->list); for (; (val = iter->current); Pk11Install_ListIter_nextItem(iter)) { if (val->type == PAIR_VALUE) { subpair = val->pair; /* Relative directory */ if (!PORT_Strcasecmp(subpair->key, RELATIVE_DIR_STRING)) { subiter = Pk11Install_ListIter_new(subpair->list); subval = subiter->current; if (!subval || (subval->type != STRING_VALUE)) { errStr = PR_smprintf(errString[BOGUS_RELATIVE_DIR], _this->jarPath); goto loser; } _this->relativePath = PR_Strdup(subval->string); Pk11Install_ListIter_delete(&subiter); /* Absolute directory */ } else if (!PORT_Strcasecmp(subpair->key, ABSOLUTE_DIR_STRING)) { subiter = Pk11Install_ListIter_new(subpair->list); subval = subiter->current; if (!subval || (subval->type != STRING_VALUE)) { errStr = PR_smprintf(errString[BOGUS_ABSOLUTE_DIR], _this->jarPath); goto loser; } _this->absolutePath = PR_Strdup(subval->string); Pk11Install_ListIter_delete(&subiter); /* file permissions */ } else if (!PORT_Strcasecmp(subpair->key, FILE_PERMISSIONS_STRING)) { subiter = Pk11Install_ListIter_new(subpair->list); subval = subiter->current; if (!subval || (subval->type != STRING_VALUE) || !subval->string || !subval->string[0]) { errStr = PR_smprintf(errString[BOGUS_FILE_PERMISSIONS], _this->jarPath); goto loser; } _this->permissions = (int)strtol(subval->string, &endp, 8); if (*endp != '\0') { errStr = PR_smprintf(errString[BOGUS_FILE_PERMISSIONS], _this->jarPath); goto loser; } gotPerms = PR_TRUE; Pk11Install_ListIter_delete(&subiter); } } else { if (!PORT_Strcasecmp(val->string, EXECUTABLE_STRING)) { _this->executable = PR_TRUE; } } } /* Default permission value */ if (!gotPerms) { _this->permissions = DEFAULT_PERMISSIONS; } /* Make sure we got all the information */ if (!_this->relativePath && !_this->absolutePath) { errStr = PR_smprintf(errString[NO_ABSOLUTE_DIR], _this->jarPath); goto loser; } #if 0 if(!_this->relativePath ) { errStr = PR_smprintf(errString[NO_RELATIVE_DIR], _this->jarPath); goto loser; } if(!_this->absolutePath) { errStr = PR_smprintf(errString[NO_ABSOLUTE_DIR], _this->jarPath); goto loser; } #endif loser: if (iter) { Pk11Install_ListIter_delete(&iter); } if (subiter) { Pk11Install_ListIter_delete(&subiter); } return errStr; } /* ////////////////////////////////////////////////////////////////////////// // Method: Print // Class: Pk11Install_File */ void Pk11Install_File_Print(Pk11Install_File* _this, int pad) { PAD(pad); printf("jarPath: %s\n", _this->jarPath ? _this->jarPath : ""); PAD(pad); printf("relativePath: %s\n", _this->relativePath ? _this->relativePath : ""); PAD(pad); printf("absolutePath: %s\n", _this->absolutePath ? _this->absolutePath : ""); PAD(pad); printf("permissions: %o\n", _this->permissions); } Pk11Install_PlatformName* Pk11Install_PlatformName_new() { Pk11Install_PlatformName* new_this; new_this = (Pk11Install_PlatformName*) PR_Malloc(sizeof(Pk11Install_PlatformName)); Pk11Install_PlatformName_init(new_this); return new_this; } void Pk11Install_PlatformName_init(Pk11Install_PlatformName* _this) { _this->OS = NULL; _this->verString = NULL; _this->numDigits = 0; _this->arch = NULL; } /* ////////////////////////////////////////////////////////////////////////// // Method: ~Pk11Install_PlatformName // Class: Pk11Install_PlatformName */ void Pk11Install_PlatformName_delete(Pk11Install_PlatformName* _this) { Pk11Install_PlatformName_Cleanup(_this); } /* ////////////////////////////////////////////////////////////////////////// // Method: Cleanup // Class: Pk11Install_PlatformName */ void Pk11Install_PlatformName_Cleanup(Pk11Install_PlatformName* _this) { if (_this->OS) { PR_Free(_this->OS); _this->OS = NULL; } if (_this->verString) { int i; for (i = 0; i < _this->numDigits; i++) { PR_Free(_this->verString[i]); } PR_Free(_this->verString); _this->verString = NULL; } if (_this->arch) { PR_Free(_this->arch); _this->arch = NULL; } _this->numDigits = 0; } /* ////////////////////////////////////////////////////////////////////////// // Method: Generate // Class: Pk11Install_PlatformName // Notes: Extracts the information from a platform string. */ char* Pk11Install_PlatformName_Generate(Pk11Install_PlatformName* _this, const char* str) { char* errStr; char* copy; char *end, *start; /* start and end of a section (OS, version, arch)*/ char *pend, *pstart; /* start and end of one portion of version*/ char* endp; /* used by strtol*/ int periods, i; errStr = NULL; copy = NULL; if (!str) { errStr = PR_smprintf(errString[EMPTY_PLATFORM_STRING]); goto loser; } copy = PR_Strdup(str); /* // Get the OS */ end = strchr(copy, PLATFORM_SEPARATOR_CHAR); if (!end || end == copy) { errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str); goto loser; } *end = '\0'; _this->OS = PR_Strdup(copy); /* // Get the digits of the version of form: x.x.x (arbitrary number of digits) */ start = end + 1; end = strchr(start, PLATFORM_SEPARATOR_CHAR); if (!end) { errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str); goto loser; } *end = '\0'; if (end != start) { /* Find out how many periods*/ periods = 0; pstart = start; while ((pend = strchr(pstart, '.'))) { periods++; pstart = pend + 1; } _this->numDigits = 1 + periods; _this->verString = (char**)PR_Malloc(sizeof(char*) * _this->numDigits); pstart = start; i = 0; /* Get the digits before each period*/ while ((pend = strchr(pstart, '.'))) { if (pend == pstart) { errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str); goto loser; } *pend = '\0'; _this->verString[i] = PR_Strdup(pstart); endp = pend; if (endp == pstart || (*endp != '\0')) { errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str); goto loser; } pstart = pend + 1; i++; } /* Last digit comes after the last period*/ if (*pstart == '\0') { errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str); goto loser; } _this->verString[i] = PR_Strdup(pstart); /* if(endp==pstart || (*endp != '\0')) { errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str); goto loser; } */ } else { _this->verString = NULL; _this->numDigits = 0; } /* // Get the architecture */ start = end + 1; if (strchr(start, PLATFORM_SEPARATOR_CHAR)) { errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str); goto loser; } _this->arch = PR_Strdup(start); if (copy) { PR_Free(copy); } return NULL; loser: if (_this->OS) { PR_Free(_this->OS); _this->OS = NULL; } if (_this->verString) { for (i = 0; i < _this->numDigits; i++) { PR_Free(_this->verString[i]); } PR_Free(_this->verString); _this->verString = NULL; } _this->numDigits = 0; if (_this->arch) { PR_Free(_this->arch); _this->arch = NULL; } if (copy) { PR_Free(copy); } return errStr; } /* ////////////////////////////////////////////////////////////////////////// // Method: operator == // Class: Pk11Install_PlatformName // Returns: PR_TRUE if the platform have the same OS, arch, and version */ PRBool Pk11Install_PlatformName_equal(Pk11Install_PlatformName* _this, Pk11Install_PlatformName* cmp) { int i; if (!_this->OS || !_this->arch || !cmp->OS || !cmp->arch) { return PR_FALSE; } if (PORT_Strcasecmp(_this->OS, cmp->OS) || PORT_Strcasecmp(_this->arch, cmp->arch) || _this->numDigits != cmp->numDigits) { return PR_FALSE; } for (i = 0; i < _this->numDigits; i++) { if (PORT_Strcasecmp(_this->verString[i], cmp->verString[i])) { return PR_FALSE; } } return PR_TRUE; } /* ////////////////////////////////////////////////////////////////////////// // Method: operator <= // Class: Pk11Install_PlatformName // Returns: PR_TRUE if the platform have the same OS and arch and a lower // or equal release. */ PRBool Pk11Install_PlatformName_lteq(Pk11Install_PlatformName* _this, Pk11Install_PlatformName* cmp) { return (Pk11Install_PlatformName_equal(_this, cmp) || Pk11Install_PlatformName_lt(_this, cmp)) ? PR_TRUE : PR_FALSE; } /* ////////////////////////////////////////////////////////////////////////// // Method: operator < // Class: Pk11Install_PlatformName // Returns: PR_TRUE if the platform have the same OS and arch and a greater // release. */ PRBool Pk11Install_PlatformName_lt(Pk11Install_PlatformName* _this, Pk11Install_PlatformName* cmp) { int i, scmp; if (!_this->OS || !_this->arch || !cmp->OS || !cmp->arch) { return PR_FALSE; } if (PORT_Strcasecmp(_this->OS, cmp->OS)) { return PR_FALSE; } if (PORT_Strcasecmp(_this->arch, cmp->arch)) { return PR_FALSE; } for (i = 0; (i < _this->numDigits) && (i < cmp->numDigits); i++) { scmp = PORT_Strcasecmp(_this->verString[i], cmp->verString[i]); if (scmp > 0) { return PR_FALSE; } else if (scmp < 0) { return PR_TRUE; } } /* All the digits they have in common are the same. */ if (_this->numDigits < cmp->numDigits) { return PR_TRUE; } return PR_FALSE; } /* ////////////////////////////////////////////////////////////////////////// // Method: GetString // Class: Pk11Install_PlatformName // Returns: String composed of OS, release, and architecture separated // by the separator char. Memory is allocated by this function // but is the responsibility of the caller to de-allocate. */ char* Pk11Install_PlatformName_GetString(Pk11Install_PlatformName* _this) { char* ret; char* ver; char* OS_; char* arch_; OS_ = NULL; arch_ = NULL; OS_ = _this->OS ? _this->OS : ""; arch_ = _this->arch ? _this->arch : ""; ver = Pk11Install_PlatformName_GetVerString(_this); ret = PR_smprintf("%s%c%s%c%s", OS_, PLATFORM_SEPARATOR_CHAR, ver, PLATFORM_SEPARATOR_CHAR, arch_); PR_Free(ver); return ret; } /* ////////////////////////////////////////////////////////////////////////// // Method: GetVerString // Class: Pk11Install_PlatformName // Returns: The version string for this platform, in the form x.x.x with an // arbitrary number of digits. Memory allocated by function, // must be de-allocated by caller. */ char* Pk11Install_PlatformName_GetVerString(Pk11Install_PlatformName* _this) { char* tmp; char* ret; int i; char buf[80]; tmp = (char*)PR_Malloc(80 * _this->numDigits + 1); tmp[0] = '\0'; for (i = 0; i < _this->numDigits - 1; i++) { sprintf(buf, "%s.", _this->verString[i]); strcat(tmp, buf); } if (i < _this->numDigits) { sprintf(buf, "%s", _this->verString[i]); strcat(tmp, buf); } ret = PR_Strdup(tmp); free(tmp); return ret; } /* ////////////////////////////////////////////////////////////////////////// // Method: Print // Class: Pk11Install_PlatformName */ void Pk11Install_PlatformName_Print(Pk11Install_PlatformName* _this, int pad) { char* str = NULL; PAD(pad); printf("OS: %s\n", _this->OS ? _this->OS : ""); PAD(pad); printf("Digits: "); if (_this->numDigits == 0) { printf("None\n"); } else { str = Pk11Install_PlatformName_GetVerString(_this); printf("%s\n", str); PR_Free(str); } PAD(pad); printf("arch: %s\n", _this->arch ? _this->arch : ""); } Pk11Install_Platform* Pk11Install_Platform_new() { Pk11Install_Platform* new_this; new_this = (Pk11Install_Platform*)PR_Malloc(sizeof(Pk11Install_Platform)); Pk11Install_Platform_init(new_this); return new_this; } void Pk11Install_Platform_init(Pk11Install_Platform* _this) { Pk11Install_PlatformName_init(&_this->name); Pk11Install_PlatformName_init(&_this->equivName); _this->equiv = NULL; _this->usesEquiv = PR_FALSE; _this->moduleFile = NULL; _this->moduleName = NULL; _this->modFile = -1; _this->mechFlags = 0; _this->cipherFlags = 0; _this->files = NULL; _this->numFiles = 0; } /* ////////////////////////////////////////////////////////////////////////// // Method: ~Pk11Install_Platform // Class: Pk11Install_Platform */ void Pk11Install_Platform_delete(Pk11Install_Platform* _this) { Pk11Install_Platform_Cleanup(_this); } /* ////////////////////////////////////////////////////////////////////////// // Method: Cleanup // Class: Pk11Install_Platform */ void Pk11Install_Platform_Cleanup(Pk11Install_Platform* _this) { int i; if (_this->moduleFile) { PR_Free(_this->moduleFile); _this->moduleFile = NULL; } if (_this->moduleName) { PR_Free(_this->moduleName); _this->moduleName = NULL; } if (_this->files) { for (i = 0; i < _this->numFiles; i++) { Pk11Install_File_delete(&_this->files[i]); } PR_Free(_this->files); _this->files = NULL; } _this->equiv = NULL; _this->usesEquiv = PR_FALSE; _this->modFile = -1; _this->numFiles = 0; _this->mechFlags = _this->cipherFlags = 0; } /* ////////////////////////////////////////////////////////////////////////// // Method: Generate // Class: Pk11Install_Platform // Notes: Creates a platform data structure from a syntax tree. // Returns: NULL for success, otherwise an error message. */ char* Pk11Install_Platform_Generate(Pk11Install_Platform* _this, const Pk11Install_Pair* pair) { char* errStr; char* endptr; char* tmp; int i; Pk11Install_ListIter* iter; Pk11Install_Value* val; Pk11Install_Value* subval; Pk11Install_Pair* subpair; Pk11Install_ListIter* subiter; PRBool gotModuleFile, gotModuleName, gotMech, gotCipher, gotFiles, gotEquiv; errStr = NULL; iter = subiter = NULL; val = subval = NULL; subpair = NULL; gotModuleFile = gotModuleName = gotMech = gotCipher = gotFiles = gotEquiv = PR_FALSE; Pk11Install_Platform_Cleanup(_this); errStr = Pk11Install_PlatformName_Generate(&_this->name, pair->key); if (errStr) { tmp = PR_smprintf("%s: %s", pair->key, errStr); PR_smprintf_free(errStr); errStr = tmp; goto loser; } iter = Pk11Install_ListIter_new(pair->list); for (; (val = iter->current); Pk11Install_ListIter_nextItem(iter)) { if (val->type == PAIR_VALUE) { subpair = val->pair; if (!PORT_Strcasecmp(subpair->key, MODULE_FILE_STRING)) { if (gotModuleFile) { errStr = PR_smprintf(errString[REPEAT_MODULE_FILE], Pk11Install_PlatformName_GetString(&_this->name)); goto loser; } subiter = Pk11Install_ListIter_new(subpair->list); subval = subiter->current; if (!subval || (subval->type != STRING_VALUE)) { errStr = PR_smprintf(errString[BOGUS_MODULE_FILE], Pk11Install_PlatformName_GetString(&_this->name)); goto loser; } _this->moduleFile = PR_Strdup(subval->string); Pk11Install_ListIter_delete(&subiter); gotModuleFile = PR_TRUE; } else if (!PORT_Strcasecmp(subpair->key, MODULE_NAME_STRING)) { if (gotModuleName) { errStr = PR_smprintf(errString[REPEAT_MODULE_NAME], Pk11Install_PlatformName_GetString(&_this->name)); goto loser; } subiter = Pk11Install_ListIter_new(subpair->list); subval = subiter->current; if (!subval || (subval->type != STRING_VALUE)) { errStr = PR_smprintf(errString[BOGUS_MODULE_NAME], Pk11Install_PlatformName_GetString(&_this->name)); goto loser; } _this->moduleName = PR_Strdup(subval->string); Pk11Install_ListIter_delete(&subiter); gotModuleName = PR_TRUE; } else if (!PORT_Strcasecmp(subpair->key, MECH_FLAGS_STRING)) { endptr = NULL; if (gotMech) { errStr = PR_smprintf(errString[REPEAT_MECH], Pk11Install_PlatformName_GetString(&_this->name)); goto loser; } subiter = Pk11Install_ListIter_new(subpair->list); subval = subiter->current; if (!subval || (subval->type != STRING_VALUE)) { errStr = PR_smprintf(errString[BOGUS_MECH_FLAGS], Pk11Install_PlatformName_GetString(&_this->name)); goto loser; } _this->mechFlags = strtol(subval->string, &endptr, 0); if (*endptr != '\0' || (endptr == subval->string)) { errStr = PR_smprintf(errString[BOGUS_MECH_FLAGS], Pk11Install_PlatformName_GetString(&_this->name)); goto loser; } Pk11Install_ListIter_delete(&subiter); gotMech = PR_TRUE; } else if (!PORT_Strcasecmp(subpair->key, CIPHER_FLAGS_STRING)) { endptr = NULL; if (gotCipher) { errStr = PR_smprintf(errString[REPEAT_CIPHER], Pk11Install_PlatformName_GetString(&_this->name)); goto loser; } subiter = Pk11Install_ListIter_new(subpair->list); subval = subiter->current; if (!subval || (subval->type != STRING_VALUE)) { errStr = PR_smprintf(errString[BOGUS_CIPHER_FLAGS], Pk11Install_PlatformName_GetString(&_this->name)); goto loser; } _this->cipherFlags = strtol(subval->string, &endptr, 0); if (*endptr != '\0' || (endptr == subval->string)) { errStr = PR_smprintf(errString[BOGUS_CIPHER_FLAGS], Pk11Install_PlatformName_GetString(&_this->name)); goto loser; } Pk11Install_ListIter_delete(&subiter); gotCipher = PR_TRUE; } else if (!PORT_Strcasecmp(subpair->key, FILES_STRING)) { if (gotFiles) { errStr = PR_smprintf(errString[REPEAT_FILES], Pk11Install_PlatformName_GetString(&_this->name)); goto loser; } subiter = Pk11Install_ListIter_new(subpair->list); _this->numFiles = subpair->list->numPairs; _this->files = (Pk11Install_File*) PR_Malloc(sizeof(Pk11Install_File) * _this->numFiles); for (i = 0; i < _this->numFiles; i++, Pk11Install_ListIter_nextItem(subiter)) { Pk11Install_File_init(&_this->files[i]); val = subiter->current; if (val && (val->type == PAIR_VALUE)) { errStr = Pk11Install_File_Generate(&_this->files[i], val->pair); if (errStr) { tmp = PR_smprintf("%s: %s", Pk11Install_PlatformName_GetString(&_this->name), errStr); PR_smprintf_free(errStr); errStr = tmp; goto loser; } } } gotFiles = PR_TRUE; } else if (!PORT_Strcasecmp(subpair->key, EQUIVALENT_PLATFORM_STRING)) { if (gotEquiv) { errStr = PR_smprintf(errString[REPEAT_EQUIV], Pk11Install_PlatformName_GetString(&_this->name)); goto loser; } subiter = Pk11Install_ListIter_new(subpair->list); subval = subiter->current; if (!subval || (subval->type != STRING_VALUE)) { errStr = PR_smprintf(errString[BOGUS_EQUIV], Pk11Install_PlatformName_GetString(&_this->name)); goto loser; } errStr = Pk11Install_PlatformName_Generate(&_this->equivName, subval->string); if (errStr) { tmp = PR_smprintf("%s: %s", Pk11Install_PlatformName_GetString(&_this->name), errStr); tmp = PR_smprintf("%s: %s", Pk11Install_PlatformName_GetString(&_this->name), errStr); PR_smprintf_free(errStr); errStr = tmp; goto loser; } _this->usesEquiv = PR_TRUE; } } } /* Make sure we either have an EquivalentPlatform or all the other info */ if (_this->usesEquiv && (gotFiles || gotModuleFile || gotModuleName || gotMech || gotCipher)) { errStr = PR_smprintf(errString[EQUIV_TOO_MUCH_INFO], Pk11Install_PlatformName_GetString(&_this->name)); goto loser; } if (!gotFiles && !_this->usesEquiv) { errStr = PR_smprintf(errString[NO_FILES], Pk11Install_PlatformName_GetString(&_this->name)); goto loser; } if (!gotModuleFile && !_this->usesEquiv) { errStr = PR_smprintf(errString[NO_MODULE_FILE], Pk11Install_PlatformName_GetString(&_this->name)); goto loser; } if (!gotModuleName && !_this->usesEquiv) { errStr = PR_smprintf(errString[NO_MODULE_NAME], Pk11Install_PlatformName_GetString(&_this->name)); goto loser; } /* Point the modFile pointer to the correct file */ if (gotModuleFile) { for (i = 0; i < _this->numFiles; i++) { if (!PORT_Strcasecmp(_this->moduleFile, _this->files[i].jarPath)) { _this->modFile = i; break; } } if (_this->modFile == -1) { errStr = PR_smprintf(errString[UNKNOWN_MODULE_FILE], _this->moduleFile, Pk11Install_PlatformName_GetString(&_this->name)); goto loser; } } loser: if (iter) { PR_Free(iter); } if (subiter) { PR_Free(subiter); } return errStr; } /* ////////////////////////////////////////////////////////////////////////// // Method: Print // Class: Pk11Install_Platform */ void Pk11Install_Platform_Print(Pk11Install_Platform* _this, int pad) { int i; PAD(pad); printf("Name:\n"); Pk11Install_PlatformName_Print(&_this->name, pad + PADINC); PAD(pad); printf("equivName:\n"); Pk11Install_PlatformName_Print(&_this->equivName, pad + PADINC); PAD(pad); if (_this->usesEquiv) { printf("Uses equiv, which points to:\n"); Pk11Install_Platform_Print(_this->equiv, pad + PADINC); } else { printf("Doesn't use equiv\n"); } PAD(pad); printf("Module File: %s\n", _this->moduleFile ? _this->moduleFile : ""); PAD(pad); printf("mechFlags: %lx\n", _this->mechFlags); PAD(pad); printf("cipherFlags: %lx\n", _this->cipherFlags); PAD(pad); printf("Files:\n"); for (i = 0; i < _this->numFiles; i++) { Pk11Install_File_Print(&_this->files[i], pad + PADINC); PAD(pad); printf("--------------------\n"); } } /* ////////////////////////////////////////////////////////////////////////// // Method: Pk11Install_Info // Class: Pk11Install_Info */ Pk11Install_Info* Pk11Install_Info_new() { Pk11Install_Info* new_this; new_this = (Pk11Install_Info*)PR_Malloc(sizeof(Pk11Install_Info)); Pk11Install_Info_init(new_this); return new_this; } void Pk11Install_Info_init(Pk11Install_Info* _this) { _this->platforms = NULL; _this->numPlatforms = 0; _this->forwardCompatible = NULL; _this->numForwardCompatible = 0; } /* ////////////////////////////////////////////////////////////////////////// // Method: ~Pk11Install_Info // Class: Pk11Install_Info */ void Pk11Install_Info_delete(Pk11Install_Info* _this) { Pk11Install_Info_Cleanup(_this); } /* ////////////////////////////////////////////////////////////////////////// // Method: Cleanup // Class: Pk11Install_Info */ void Pk11Install_Info_Cleanup(Pk11Install_Info* _this) { int i; if (_this->platforms) { for (i = 0; i < _this->numPlatforms; i++) { Pk11Install_Platform_delete(&_this->platforms[i]); } PR_Free(&_this->platforms); _this->platforms = NULL; _this->numPlatforms = 0; } if (_this->forwardCompatible) { for (i = 0; i < _this->numForwardCompatible; i++) { Pk11Install_PlatformName_delete(&_this->forwardCompatible[i]); } PR_Free(&_this->forwardCompatible); _this->numForwardCompatible = 0; } } /* ////////////////////////////////////////////////////////////////////////// // Method: Generate // Class: Pk11Install_Info // Takes: Pk11Install_ValueList *list, the top-level list // resulting from parsing an installer file. // Returns: char*, NULL if successful, otherwise an error string. // Caller is responsible for freeing memory. */ char* Pk11Install_Info_Generate(Pk11Install_Info* _this, const Pk11Install_ValueList* list) { char* errStr; Pk11Install_ListIter* iter; Pk11Install_Value* val; Pk11Install_Pair* pair; Pk11Install_ListIter* subiter; Pk11Install_Value* subval; Pk11Install_Platform *first, *second; int i, j; errStr = NULL; iter = subiter = NULL; Pk11Install_Info_Cleanup(_this); iter = Pk11Install_ListIter_new(list); for (; (val = iter->current); Pk11Install_ListIter_nextItem(iter)) { if (val->type == PAIR_VALUE) { pair = val->pair; if (!PORT_Strcasecmp(pair->key, FORWARD_COMPATIBLE_STRING)) { subiter = Pk11Install_ListIter_new(pair->list); _this->numForwardCompatible = pair->list->numStrings; _this->forwardCompatible = (Pk11Install_PlatformName*) PR_Malloc(sizeof(Pk11Install_PlatformName) * _this->numForwardCompatible); for (i = 0; i < _this->numForwardCompatible; i++, Pk11Install_ListIter_nextItem(subiter)) { subval = subiter->current; if (subval->type == STRING_VALUE) { errStr = Pk11Install_PlatformName_Generate( &_this->forwardCompatible[i], subval->string); if (errStr) { goto loser; } } } Pk11Install_ListIter_delete(&subiter); } else if (!PORT_Strcasecmp(pair->key, PLATFORMS_STRING)) { subiter = Pk11Install_ListIter_new(pair->list); _this->numPlatforms = pair->list->numPairs; _this->platforms = (Pk11Install_Platform*) PR_Malloc(sizeof(Pk11Install_Platform) * _this->numPlatforms); for (i = 0; i < _this->numPlatforms; i++, Pk11Install_ListIter_nextItem(subiter)) { Pk11Install_Platform_init(&_this->platforms[i]); subval = subiter->current; if (subval->type == PAIR_VALUE) { errStr = Pk11Install_Platform_Generate(&_this->platforms[i], subval->pair); if (errStr) { goto loser; } } } Pk11Install_ListIter_delete(&subiter); } } } if (_this->numPlatforms == 0) { errStr = PR_smprintf(errString[NO_PLATFORMS]); goto loser; } /* // // Now process equivalent platforms // // First the naive pass */ for (i = 0; i < _this->numPlatforms; i++) { if (_this->platforms[i].usesEquiv) { _this->platforms[i].equiv = NULL; for (j = 0; j < _this->numPlatforms; j++) { if (Pk11Install_PlatformName_equal(&_this->platforms[i].equivName, &_this->platforms[j].name)) { if (i == j) { errStr = PR_smprintf(errString[EQUIV_LOOP], Pk11Install_PlatformName_GetString(&_this->platforms[i].name)); goto loser; } _this->platforms[i].equiv = &_this->platforms[j]; break; } } if (_this->platforms[i].equiv == NULL) { errStr = PR_smprintf(errString[BOGUS_EQUIV], Pk11Install_PlatformName_GetString(&_this->platforms[i].name)); goto loser; } } } /* // Now the intelligent pass, which will also detect loops. // We will send two pointers through the linked list of equivalent // platforms. Both start with the current node. "first" traverses // two nodes for each iteration. "second" lags behind, only traversing // one node per iteration. Eventually one of two things will happen: // first will hit the end of the list (a platform that doesn't use // an equivalency), or first will equal second if there is a loop. */ for (i = 0; i < _this->numPlatforms; i++) { if (_this->platforms[i].usesEquiv) { second = _this->platforms[i].equiv; if (!second->usesEquiv) { /* The first link is the terminal node */ continue; } first = second->equiv; while (first->usesEquiv) { if (first == second) { errStr = PR_smprintf(errString[EQUIV_LOOP], Pk11Install_PlatformName_GetString(&_this->platforms[i].name)); goto loser; } first = first->equiv; if (!first->usesEquiv) { break; } if (first == second) { errStr = PR_smprintf(errString[EQUIV_LOOP], Pk11Install_PlatformName_GetString(&_this->platforms[i].name)); goto loser; } second = second->equiv; first = first->equiv; } _this->platforms[i].equiv = first; } } loser: if (iter) { Pk11Install_ListIter_delete(&iter); } if (subiter) { Pk11Install_ListIter_delete(&subiter); } return errStr; } /* ////////////////////////////////////////////////////////////////////////// // Method: GetBestPlatform // Class: Pk11Install_Info // Takes: char *myPlatform, the platform we are currently running // on. */ Pk11Install_Platform* Pk11Install_Info_GetBestPlatform(Pk11Install_Info* _this, char* myPlatform) { Pk11Install_PlatformName plat; char* errStr; int i, j; errStr = NULL; Pk11Install_PlatformName_init(&plat); if ((errStr = Pk11Install_PlatformName_Generate(&plat, myPlatform))) { PR_smprintf_free(errStr); return NULL; } /* First try real platforms */ for (i = 0; i < _this->numPlatforms; i++) { if (Pk11Install_PlatformName_equal(&_this->platforms[i].name, &plat)) { if (_this->platforms[i].equiv) { return _this->platforms[i].equiv; } else { return &_this->platforms[i]; } } } /* Now try forward compatible platforms */ for (i = 0; i < _this->numForwardCompatible; i++) { if (Pk11Install_PlatformName_lteq(&_this->forwardCompatible[i], &plat)) { break; } } if (i == _this->numForwardCompatible) { return NULL; } /* Got a forward compatible name, find the actual platform. */ for (j = 0; j < _this->numPlatforms; j++) { if (Pk11Install_PlatformName_equal(&_this->platforms[j].name, &_this->forwardCompatible[i])) { if (_this->platforms[j].equiv) { return _this->platforms[j].equiv; } else { return &_this->platforms[j]; } } } return NULL; } /* ////////////////////////////////////////////////////////////////////////// // Method: Print // Class: Pk11Install_Info */ void Pk11Install_Info_Print(Pk11Install_Info* _this, int pad) { int i; PAD(pad); printf("Forward Compatible:\n"); for (i = 0; i < _this->numForwardCompatible; i++) { Pk11Install_PlatformName_Print(&_this->forwardCompatible[i], pad + PADINC); PAD(pad); printf("-------------------\n"); } PAD(pad); printf("Platforms:\n"); for (i = 0; i < _this->numPlatforms; i++) { Pk11Install_Platform_Print(&_this->platforms[i], pad + PADINC); PAD(pad); printf("-------------------\n"); } } /* ////////////////////////////////////////////////////////////////////////// */ static char* PR_Strdup(const char* str) { char* tmp; tmp = (char*)PR_Malloc((unsigned int)(strlen(str) + 1)); strcpy(tmp, str); return tmp; } /* The global value list, the top of the tree */ Pk11Install_ValueList* Pk11Install_valueList = NULL; /****************************************************************************/ void Pk11Install_ValueList_AddItem(Pk11Install_ValueList* _this, Pk11Install_Value* item) { _this->numItems++; if (item->type == STRING_VALUE) { _this->numStrings++; } else { _this->numPairs++; } item->next = _this->head; _this->head = item; } /****************************************************************************/ Pk11Install_ListIter* Pk11Install_ListIter_new_default() { Pk11Install_ListIter* new_this; new_this = (Pk11Install_ListIter*) PR_Malloc(sizeof(Pk11Install_ListIter)); Pk11Install_ListIter_init(new_this); return new_this; } /****************************************************************************/ void Pk11Install_ListIter_init(Pk11Install_ListIter* _this) { _this->list = NULL; _this->current = NULL; } /****************************************************************************/ Pk11Install_ListIter* Pk11Install_ListIter_new(const Pk11Install_ValueList* _list) { Pk11Install_ListIter* new_this; new_this = (Pk11Install_ListIter*) PR_Malloc(sizeof(Pk11Install_ListIter)); new_this->list = _list; new_this->current = _list->head; return new_this; } /****************************************************************************/ void Pk11Install_ListIter_delete(Pk11Install_ListIter** _this) { (*_this)->list = NULL; (*_this)->current = NULL; PR_Free(*_this); *_this = NULL; } /****************************************************************************/ void Pk11Install_ListIter_reset(Pk11Install_ListIter* _this) { if (_this->list) { _this->current = _this->list->head; } } /*************************************************************************/ Pk11Install_Value* Pk11Install_ListIter_nextItem(Pk11Install_ListIter* _this) { if (_this->current) { _this->current = _this->current->next; } return _this->current; } /****************************************************************************/ Pk11Install_ValueList* Pk11Install_ValueList_new() { Pk11Install_ValueList* new_this; new_this = (Pk11Install_ValueList*) PR_Malloc(sizeof(Pk11Install_ValueList)); new_this->numItems = 0; new_this->numPairs = 0; new_this->numStrings = 0; new_this->head = NULL; return new_this; } /****************************************************************************/ void Pk11Install_ValueList_delete(Pk11Install_ValueList* _this) { Pk11Install_Value* tmp; Pk11Install_Value* list; list = _this->head; while (list != NULL) { tmp = list; list = list->next; PR_Free(tmp); } PR_Free(_this); } /****************************************************************************/ Pk11Install_Value* Pk11Install_Value_new_default() { Pk11Install_Value* new_this; new_this = (Pk11Install_Value*)PR_Malloc(sizeof(Pk11Install_Value)); new_this->type = STRING_VALUE; new_this->string = NULL; new_this->pair = NULL; new_this->next = NULL; return new_this; } /****************************************************************************/ Pk11Install_Value* Pk11Install_Value_new(ValueType _type, Pk11Install_Pointer ptr) { Pk11Install_Value* new_this; new_this = Pk11Install_Value_new_default(); new_this->type = _type; if (_type == STRING_VALUE) { new_this->pair = NULL; new_this->string = ptr.string; } else { new_this->string = NULL; new_this->pair = ptr.pair; } return new_this; } /****************************************************************************/ void Pk11Install_Value_delete(Pk11Install_Value* _this) { if (_this->type == STRING_VALUE) { PR_Free(_this->string); } else { PR_Free(_this->pair); } } /****************************************************************************/ Pk11Install_Pair* Pk11Install_Pair_new_default() { return Pk11Install_Pair_new(NULL, NULL); } /****************************************************************************/ Pk11Install_Pair* Pk11Install_Pair_new(char* _key, Pk11Install_ValueList* _list) { Pk11Install_Pair* new_this; new_this = (Pk11Install_Pair*)PR_Malloc(sizeof(Pk11Install_Pair)); new_this->key = _key; new_this->list = _list; return new_this; } /****************************************************************************/ void Pk11Install_Pair_delete(Pk11Install_Pair* _this) { PR_Free(_this->key); Pk11Install_ValueList_delete(_this->list); } /*************************************************************************/ void Pk11Install_Pair_Print(Pk11Install_Pair* _this, int pad) { while (_this) { /*PAD(pad); printf("**Pair\n"); PAD(pad); printf("***Key====\n");*/ PAD(pad); printf("%s {\n", _this->key); /*PAD(pad); printf("====\n");*/ /*PAD(pad); printf("***ValueList\n");*/ Pk11Install_ValueList_Print(_this->list, pad + PADINC); PAD(pad); printf("}\n"); } } /*************************************************************************/ void Pk11Install_ValueList_Print(Pk11Install_ValueList* _this, int pad) { Pk11Install_Value* v; /*PAD(pad);printf("**Value List**\n");*/ for (v = _this->head; v != NULL; v = v->next) { Pk11Install_Value_Print(v, pad); } } /*************************************************************************/ void Pk11Install_Value_Print(Pk11Install_Value* _this, int pad) { /*PAD(pad); printf("**Value, type=%s\n", type==STRING_VALUE ? "string" : "pair");*/ if (_this->type == STRING_VALUE) { /*PAD(pad+PADINC); printf("====\n");*/ PAD(pad); printf("%s\n", _this->string); /*PAD(pad+PADINC); printf("====\n");*/ } else { Pk11Install_Pair_Print(_this->pair, pad + PADINC); } }