diff options
Diffstat (limited to 'indra/newview/llinventorymodel.cpp')
-rw-r--r-- | indra/newview/llinventorymodel.cpp | 192 |
1 files changed, 140 insertions, 52 deletions
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 221258fbc3..54cea3334d 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -138,6 +138,8 @@ bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item) LLInventoryValidationInfo::LLInventoryValidationInfo(): mFatalErrorCount(0), mWarningCount(0), + mLoopCount(0), + mOrphanedCount(0), mInitialized(false), mFatalNoRootFolder(false), mFatalNoLibraryRootFolder(false), @@ -147,7 +149,10 @@ LLInventoryValidationInfo::LLInventoryValidationInfo(): void LLInventoryValidationInfo::toOstream(std::ostream& os) const { - os << "mFatalErrorCount " << mFatalErrorCount << " mWarningCount " << mWarningCount; + os << "mFatalErrorCount " << mFatalErrorCount + << " mWarningCount " << mWarningCount + << " mLoopCount " << mLoopCount + << " mOrphanedCount " << mOrphanedCount; } @@ -161,6 +166,8 @@ void LLInventoryValidationInfo::asLLSD(LLSD& sd) const { sd["fatal_error_count"] = mFatalErrorCount; sd["warning_count"] = mWarningCount; + sd["loop_count"] = mLoopCount; + sd["orphaned_count"] = mOrphanedCount; sd["initialized"] = mInitialized; sd["missing_system_folders_count"] = LLSD::Integer(mMissingRequiredSystemFolders.size()); sd["fatal_no_root_folder"] = mFatalNoRootFolder; @@ -337,21 +344,35 @@ const LLViewerInventoryCategory* LLInventoryModel::getFirstDescendantOf(const LL return NULL; } -bool LLInventoryModel::getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const +LLInventoryModel::EAnscestorResult LLInventoryModel::getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const { LLInventoryObject *object = getObject(object_id); - while (object && object->getParentUUID().notNull()) - { - LLInventoryObject *parent_object = getObject(object->getParentUUID()); + if (!object) + { + LL_WARNS(LOG_INV) << "Unable to trace topmost ancestor, initial object " << object_id << " does not exist" << LL_ENDL; + return ANSCESTOR_MISSING; + } + + std::set<LLUUID> object_ids{ object_id }; // loop protection + while (object->getParentUUID().notNull()) + { + LLUUID parent_id = object->getParentUUID(); + if (object_ids.find(parent_id) != object_ids.end()) + { + LL_WARNS(LOG_INV) << "Detected a loop on an object " << parent_id << " when searching for ancestor of " << object_id << LL_ENDL; + return ANSCESTOR_LOOP; + } + object_ids.insert(parent_id); + LLInventoryObject *parent_object = getObject(parent_id); if (!parent_object) { - LL_WARNS(LOG_INV) << "unable to trace topmost ancestor, missing item for uuid " << object->getParentUUID() << LL_ENDL; - return false; + LL_WARNS(LOG_INV) << "unable to trace topmost ancestor of " << object_id << ", missing item for uuid " << parent_id << LL_ENDL; + return ANSCESTOR_MISSING; } object = parent_object; } result = object->getUUID(); - return true; + return ANSCESTOR_OK; } // Get the object by id. Returns NULL if not found. @@ -2956,42 +2977,69 @@ bool LLInventoryModel::saveToFile(const std::string& filename, LL_INFOS(LOG_INV) << "saving inventory to: (" << filename << ")" << LL_ENDL; - llofstream fileXML(filename.c_str()); - if (!fileXML.is_open()) - { - LL_WARNS(LOG_INV) << "unable to save inventory to: " << filename << LL_ENDL; - return false; - } + try + { + llofstream fileXML(filename.c_str()); + if (!fileXML.is_open()) + { + LL_WARNS(LOG_INV) << "Failed to open file. Unable to save inventory to: " << filename << LL_ENDL; + return false; + } - LLSD cache_ver; - cache_ver["inv_cache_version"] = sCurrentInvCacheVersion; + LLSD cache_ver; + cache_ver["inv_cache_version"] = sCurrentInvCacheVersion; - fileXML << LLSDOStreamer<LLSDNotationFormatter>(cache_ver) << std::endl; + if (fileXML.fail()) + { + LL_WARNS(LOG_INV) << "Failed to write cache version to file. Unable to save inventory to: " << filename << LL_ENDL; + return false; + } - S32 count = categories.size(); - S32 cat_count = 0; - S32 i; - for(i = 0; i < count; ++i) - { - LLViewerInventoryCategory* cat = categories[i]; - if(cat->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) - { - fileXML << LLSDOStreamer<LLSDNotationFormatter>(cat->exportLLSD()) << std::endl; - cat_count++; - } - } + fileXML << LLSDOStreamer<LLSDNotationFormatter>(cache_ver) << std::endl; - S32 it_count = items.size(); - for(i = 0; i < it_count; ++i) - { - fileXML << LLSDOStreamer<LLSDNotationFormatter>(items[i]->asLLSD()) << std::endl; - } + S32 count = categories.size(); + S32 cat_count = 0; + S32 i; + for (i = 0; i < count; ++i) + { + LLViewerInventoryCategory* cat = categories[i]; + if (cat->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) + { + fileXML << LLSDOStreamer<LLSDNotationFormatter>(cat->exportLLSD()) << std::endl; + cat_count++; + } - fileXML.close(); + if (fileXML.fail()) + { + LL_WARNS(LOG_INV) << "Failed to write a folder to file. Unable to save inventory to: " << filename << LL_ENDL; + return false; + } + } - LL_INFOS(LOG_INV) << "Inventory saved: " << cat_count << " categories, " << it_count << " items." << LL_ENDL; + S32 it_count = items.size(); + for (i = 0; i < it_count; ++i) + { + fileXML << LLSDOStreamer<LLSDNotationFormatter>(items[i]->asLLSD()) << std::endl; - return true; + if (fileXML.fail()) + { + LL_WARNS(LOG_INV) << "Failed to write an item to file. Unable to save inventory to: " << filename << LL_ENDL; + return false; + } + } + + fileXML.close(); + + LL_INFOS(LOG_INV) << "Inventory saved: " << cat_count << " categories, " << it_count << " items." << LL_ENDL; + } + catch (...) + { + LOG_UNHANDLED_EXCEPTION(""); + LL_INFOS(LOG_INV) << "Failed to save inventory to: (" << filename << ")" << LL_ENDL; + return false; + } + + return true; } // message handling functionality @@ -3859,20 +3907,23 @@ void LLInventoryModel::dumpInventory() const LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const { LLPointer<LLInventoryValidationInfo> validation_info = new LLInventoryValidationInfo; - S32 fatalities = 0; + S32 fatal_errs = 0; S32 warnings = 0; + S32 loops = 0; + S32 orphaned = 0; if (getRootFolderID().isNull()) { LL_WARNS("Inventory") << "Fatal inventory corruption: no root folder id" << LL_ENDL; validation_info->mFatalNoRootFolder = true; - fatalities++; + fatal_errs++; } if (getLibraryRootFolderID().isNull()) { + // Probably shouldn't be a fatality, inventory can function without a library LL_WARNS("Inventory") << "Fatal inventory corruption: no library root folder id" << LL_ENDL; validation_info->mFatalNoLibraryRootFolder = true; - fatalities++; + fatal_errs++; } if (mCategoryMap.size() + 1 != mParentChildCategoryTree.size()) @@ -3904,7 +3955,23 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const } LLUUID topmost_ancestor_id; // Will leave as null uuid on failure - getObjectTopmostAncestor(cat_id, topmost_ancestor_id); + EAnscestorResult res = getObjectTopmostAncestor(cat_id, topmost_ancestor_id); + switch (res) + { + case ANSCESTOR_MISSING: + orphaned++; + break; + case ANSCESTOR_LOOP: + loops++; + break; + case ANSCESTOR_OK: + break; + default: + LL_WARNS("Inventory") << "Unknown ancestor error for " << cat_id << LL_ENDL; + warnings++; + break; + } + if (cat_id != cat->getUUID()) { LL_WARNS("Inventory") << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL; @@ -4004,8 +4071,8 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const // Topmost ancestor should be root or library. LLUUID topmost_ancestor_id; - bool found = getObjectTopmostAncestor(item_id, topmost_ancestor_id); - if (!found) + EAnscestorResult found = getObjectTopmostAncestor(item_id, topmost_ancestor_id); + if (found != ANSCESTOR_OK) { LL_WARNS("Inventory") << "unable to find topmost ancestor for " << item_id << LL_ENDL; warnings++; @@ -4035,7 +4102,7 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const { LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName() << "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL; - warnings++; + orphaned++; } else { @@ -4053,6 +4120,7 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const { LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName() << "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL; + orphaned++; } } } @@ -4061,7 +4129,7 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const LLFolderType::EType folder_type = cat->getPreferredType(); bool cat_is_in_library = false; LLUUID topmost_id; - if (getObjectTopmostAncestor(cat->getUUID(),topmost_id) && topmost_id == getLibraryRootFolderID()) + if (getObjectTopmostAncestor(cat->getUUID(),topmost_id) == ANSCESTOR_OK && topmost_id == getLibraryRootFolderID()) { cat_is_in_library = true; } @@ -4101,6 +4169,7 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const if (parent_id.isNull()) { LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL; + orphaned++; } else { @@ -4111,6 +4180,7 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const { LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() << "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL; + orphaned++; } else { @@ -4127,6 +4197,7 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const { LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() << "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL; + orphaned++; } } @@ -4144,15 +4215,18 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const LL_WARNS("Inventory") << "link " << item->getUUID() << " type " << item->getActualType() << " missing backlink info at target_id " << target_id << LL_ENDL; + orphaned++; } // Links should have referents. if (item->getActualType() == LLAssetType::AT_LINK && !target_item) { LL_WARNS("Inventory") << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL; + orphaned++; } else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat) { LL_WARNS("Inventory") << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL; + orphaned++; } if (target_item && target_item->getIsLinkType()) { @@ -4224,8 +4298,8 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const if (is_automatic) { LL_WARNS("Inventory") << "Fatal inventory corruption: cannot create system folder of type " << ft << LL_ENDL; - fatalities++; - validation_info->mMissingRequiredSystemFolders.insert(LLFolderType::EType(ft)); + fatal_errs++; + validation_info->mMissingRequiredSystemFolders.insert(folder_type); } else { @@ -4236,8 +4310,20 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const else if (count_under_root > 1) { LL_WARNS("Inventory") << "Fatal inventory corruption: system folder type has excess copies under root, type " << ft << " count " << count_under_root << LL_ENDL; - validation_info->mDuplicateRequiredSystemFolders.insert(LLFolderType::EType(ft)); - fatalities++; + validation_info->mDuplicateRequiredSystemFolders.insert(folder_type); + if (!is_automatic && folder_type != LLFolderType::FT_SETTINGS) + { + // It is a fatal problem or can lead to fatal problems for COF, + // outfits, trash and other non-automatic folders. + fatal_errs++; + } + else + { + // For automatic folders it's not a fatal issue and shouldn't + // break inventory or other functionality further + // Exception: FT_SETTINGS is not automatic, but only deserves a warning. + warnings++; + } } if (count_elsewhere > 0) { @@ -4263,11 +4349,13 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const } // FIXME need to fail login and tell user to retry, contact support if problem persists. - bool valid = (fatalities == 0); - LL_INFOS("Inventory") << "Validate done, fatal errors: " << fatalities << ", warnings: " << warnings << ", valid: " << valid << LL_ENDL; + bool valid = (fatal_errs == 0); + LL_INFOS("Inventory") << "Validate done, fatal errors: " << fatal_errs << ", warnings: " << warnings << ", valid: " << valid << LL_ENDL; - validation_info->mFatalErrorCount = fatalities; + validation_info->mFatalErrorCount = fatal_errs; validation_info->mWarningCount = warnings; + validation_info->mLoopCount = loops; + validation_info->mOrphanedCount = orphaned; return validation_info; } |