diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs index 256a886877..60d1720ba7 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs @@ -97,9 +97,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver int successfulAssetRestores = 0; int failedAssetRestores = 0; int successfulItemRestores = 0; - List nodesLoaded = new List(); + + List loadedNodes = new List(); - //InventoryFolderImpl rootDestinationFolder = m_userInfo.RootFolder.FindFolderByPath(m_invPath); InventoryFolderBase rootDestinationFolder = InventoryArchiveUtils.FindFolderByPath( m_scene.InventoryService, m_userInfo.PrincipalID, m_invPath); @@ -109,14 +109,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver // Possibly provide an option later on to automatically create this folder if it does not exist m_log.ErrorFormat("[INVENTORY ARCHIVER]: Inventory path {0} does not exist", m_invPath); - return nodesLoaded; + return loadedNodes; } archive = new TarArchiveReader(m_loadStream); // In order to load identically named folders, we need to keep track of the folders that we have already - // created - Dictionary foldersCreated = new Dictionary(); + // resolved + Dictionary resolvedFolders = new Dictionary(); byte[] data; TarArchiveReader.TarEntryType entryType; @@ -147,7 +147,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver InventoryFolderBase foundFolder = ReplicateArchivePathToUserInventory( - filePath, rootDestinationFolder, foldersCreated, nodesLoaded); + filePath, rootDestinationFolder, resolvedFolders, loadedNodes); if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY != entryType) { @@ -160,7 +160,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver // If we're loading an item directly into the given destination folder then we need to record // it separately from any loaded root folders if (rootDestinationFolder == foundFolder) - nodesLoaded.Add(item); + loadedNodes.Add(item); } } } @@ -176,7 +176,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver successfulAssetRestores, failedAssetRestores); m_log.InfoFormat("[INVENTORY ARCHIVER]: Successfully loaded {0} items", successfulItemRestores); - return nodesLoaded; + return loadedNodes; } public void Close() @@ -190,117 +190,33 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// /// The item archive path to replicate /// The root folder for the inventory load - /// - /// The folders created so far. This method will add more folders if necessary + /// + /// The folders that we have resolved so far for a given archive path. + /// This method will add more folders if necessary /// - /// - /// Track the inventory nodes created. This is distinct from the folders created since for a particular folder - /// chain, only the root node needs to be recorded + /// + /// Track the inventory nodes created. /// /// The last user inventory folder created or found for the archive path public InventoryFolderBase ReplicateArchivePathToUserInventory( string archivePath, InventoryFolderBase rootDestFolder, - Dictionary foldersCreated, - List nodesLoaded) + Dictionary resolvedFolders, + List loadedNodes) { string originalArchivePath = archivePath; // m_log.DebugFormat( // "[INVENTORY ARCHIVER]: Loading folder {0} {1}", rootDestFolder.Name, rootDestFolder.ID); - - InventoryFolderBase destFolder = null; - - // XXX: Nasty way of dealing with a path that has no directory component - if (archivePath.Length > 0) - { - while (null == destFolder && archivePath.Length > 0) - { - if (foldersCreated.ContainsKey(archivePath)) - { -// m_log.DebugFormat( -// "[INVENTORY ARCHIVER]: Found previously created folder from archive path {0}", archivePath); - destFolder = foldersCreated[archivePath]; - } - else - { - // Don't include the last slash - int penultimateSlashIndex = archivePath.LastIndexOf("/", archivePath.Length - 2); - - if (penultimateSlashIndex >= 0) - { - archivePath = archivePath.Remove(penultimateSlashIndex + 1); - } - else - { - m_log.DebugFormat( - "[INVENTORY ARCHIVER]: Found no previously created folder for archive path {0}", - originalArchivePath); - archivePath = string.Empty; - destFolder = rootDestFolder; - } - } - } - } - else - { - destFolder = rootDestFolder; - } - + + InventoryFolderBase destFolder = ResolveDestinationFolder(rootDestFolder, ref archivePath, resolvedFolders); + +// m_log.DebugFormat( +// "[INVENTORY ARCHIVER]: originalArchivePath [{0}], section already loaded [{1}]", +// originalArchivePath, archivePath); + string archivePathSectionToCreate = originalArchivePath.Substring(archivePath.Length); - string[] rawDirsToCreate - = archivePathSectionToCreate.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); - int i = 0; - - while (i < rawDirsToCreate.Length) - { - m_log.DebugFormat("[INVENTORY ARCHIVER]: Loading archived folder {0}", rawDirsToCreate[i]); - - int identicalNameIdentifierIndex - = rawDirsToCreate[i].LastIndexOf( - ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR); - - if (identicalNameIdentifierIndex < 0) - { - i++; - continue; - } - string newFolderName = rawDirsToCreate[i].Remove(identicalNameIdentifierIndex); - - newFolderName = InventoryArchiveUtils.UnescapeArchivePath(newFolderName); - UUID newFolderId = UUID.Random(); - - // Asset type has to be Unknown here rather than Folder, otherwise the created folder can't be - // deleted once the client has relogged. - // The root folder appears to be labelled AssetType.Folder (shows up as "Category" in the client) - // even though there is a AssetType.RootCategory - destFolder - = new InventoryFolderBase( - newFolderId, newFolderName, m_userInfo.PrincipalID, - (short)AssetType.Unknown, destFolder.ID, 1); - m_scene.InventoryService.AddFolder(destFolder); - -// UUID newFolderId = UUID.Random(); -// m_scene.InventoryService.AddFolder( -// m_userInfo.CreateFolder( -// folderName, newFolderId, (ushort)AssetType.Folder, foundFolder.ID); - -// m_log.DebugFormat("[INVENTORY ARCHIVER]: Retrieving newly created folder {0}", folderName); -// foundFolder = foundFolder.GetChildFolder(newFolderId); -// m_log.DebugFormat( -// "[INVENTORY ARCHIVER]: Retrieved newly created folder {0} with ID {1}", -// foundFolder.Name, foundFolder.ID); - - // Record that we have now created this folder - archivePath += rawDirsToCreate[i] + "/"; - m_log.DebugFormat("[INVENTORY ARCHIVER]: Loaded archive path {0}", archivePath); - foldersCreated[archivePath] = destFolder; - - if (0 == i) - nodesLoaded.Add(destFolder); - - i++; - } + CreateFoldersForPath(destFolder, archivePathSectionToCreate, resolvedFolders, loadedNodes); return destFolder; @@ -339,6 +255,136 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver */ } + /// + /// Resolve a destination folder + /// + /// + /// We require here a root destination folder (usually the root of the user's inventory) and the archive + /// path. We also pass in a list of previously resolved folders in case we've found this one previously. + /// + /// + /// The item archive path to resolve. The portion of the path passed back is that + /// which corresponds to the resolved desintation folder. + /// + /// The root folder for the inventory load + /// + /// + /// The folders that we have resolved so far for a given archive path. + /// + /// + /// The folder in the user's inventory that matches best the archive path given. If no such folder was found + /// then the passed in root destination folder is returned. + /// + protected InventoryFolderBase ResolveDestinationFolder( + InventoryFolderBase rootDestFolder, + ref string archivePath, + Dictionary resolvedFolders) + { + string originalArchivePath = archivePath; + + InventoryFolderBase destFolder = null; + + if (archivePath.Length > 0) + { + while (null == destFolder && archivePath.Length > 0) + { + if (resolvedFolders.ContainsKey(archivePath)) + { +// m_log.DebugFormat( +// "[INVENTORY ARCHIVER]: Found previously created folder from archive path {0}", archivePath); + destFolder = resolvedFolders[archivePath]; + } + else + { + // Don't include the last slash so find the penultimate one + int penultimateSlashIndex = archivePath.LastIndexOf("/", archivePath.Length - 2); + + if (penultimateSlashIndex >= 0) + { + // Remove the last section of path so that we can see if we've already resolved the parent + archivePath = archivePath.Remove(penultimateSlashIndex + 1); + } + else + { + m_log.DebugFormat( + "[INVENTORY ARCHIVER]: Found no previously created folder for archive path {0}", + originalArchivePath); + archivePath = string.Empty; + destFolder = rootDestFolder; + } + } + } + } + + if (null == destFolder) + destFolder = rootDestFolder; + + return destFolder; + } + + /// + /// Create a set of folders for the given path. + /// + /// + /// The root folder from which the creation will take place. + /// + /// + /// The path to create + /// + /// + /// The folders that we have resolved so far for a given archive path. + /// + /// + /// Track the inventory nodes created. + /// + protected void CreateFoldersForPath( + InventoryFolderBase destFolder, string path, Dictionary resolvedFolders, + List loadedNodes) + { + string pathCreated = ""; + string[] rawDirsToCreate = path.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); + int i = 0; + + while (i < rawDirsToCreate.Length) + { +// m_log.DebugFormat("[INVENTORY ARCHIVER]: Creating folder {0} from IAR", rawDirsToCreate[i]); + + int identicalNameIdentifierIndex + = rawDirsToCreate[i].LastIndexOf( + ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR); + + if (identicalNameIdentifierIndex < 0) + { + i++; + continue; + } + string newFolderName = rawDirsToCreate[i].Remove(identicalNameIdentifierIndex); + + newFolderName = InventoryArchiveUtils.UnescapeArchivePath(newFolderName); + UUID newFolderId = UUID.Random(); + + // Asset type has to be Unknown here rather than Folder, otherwise the created folder can't be + // deleted once the client has relogged. + // The root folder appears to be labelled AssetType.Folder (shows up as "Category" in the client) + // even though there is a AssetType.RootCategory + destFolder + = new InventoryFolderBase( + newFolderId, newFolderName, m_userInfo.PrincipalID, + (short)AssetType.Unknown, destFolder.ID, 1); + m_scene.InventoryService.AddFolder(destFolder); + + // Record that we have now created this folder + pathCreated += rawDirsToCreate[i] + "/"; + m_log.DebugFormat("[INVENTORY ARCHIVER]: Created folder {0} from IAR", pathCreated); + resolvedFolders[pathCreated] = destFolder; + + if (0 == i) + loadedNodes.Add(destFolder); + + i++; + } + } + /// /// Load an item from the archive /// @@ -429,4 +475,4 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver } } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs index cb6bf76b87..59cd386c0c 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs @@ -279,7 +279,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests public void TestIarV0_1WithEscapedChars() { TestHelper.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); + log4net.Config.XmlConfigurator.Configure(); string itemName = "You & you are a mean/man/"; string humanEscapedItemName = @"You & you are a mean\/man\/";