diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index 323d90c226..93201e1c8b 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs @@ -76,7 +76,7 @@ namespace OpenSim /// /// The file used to load and save an opensim archive if no filename has been specified /// - protected const string DEFAULT_OAR_BACKUP_FILENAME = "scene_oar.tar.gz"; + protected const string DEFAULT_OAR_BACKUP_FILENAME = "scene.oar"; public ConfigSettings ConfigurationSettings { diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveConstants.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveConstants.cs index b274af230a..e2bce16650 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveConstants.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveConstants.cs @@ -50,6 +50,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// public static readonly string ASSET_EXTENSION_SEPARATOR = "_"; + /// + /// Used to separate components in an inventory node name + /// + public static readonly string INVENTORY_NODE_NAME_COMPONENT_SEPARATOR = "__"; + /// /// Extensions used for asset types in the archive /// diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs index fc639575ab..4a681bc19e 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs @@ -85,7 +85,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver if (contents.Equals("")) return null; - reader.ReadStartElement("InventoryObject"); + reader.ReadStartElement("InventoryItem"); reader.ReadStartElement("Name"); item.Name = reader.ReadString(); reader.ReadEndElement(); @@ -138,10 +138,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver reader.ReadStartElement("GroupOwned"); item.GroupOwned = Convert.ToBoolean(reader.ReadString()); reader.ReadEndElement(); - //reader.ReadStartElement("ParentFolderID"); - //item.Folder = UUID.Parse(reader.ReadString()); - //reader.ReadEndElement(); - //reader.ReadEndElement(); return item; } @@ -187,13 +183,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver if (null == rootDestinationFolder) { - // TODO: Later on, automatically create this folder if it does not exist + // 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; } 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(); byte[] data; TarArchiveReader.TarEntryType entryType; @@ -222,12 +222,72 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver item.Creator = m_userInfo.UserProfile.ID; item.Owner = m_userInfo.UserProfile.ID; - filePath = filePath.Substring(InventoryArchiveConstants.INVENTORY_PATH.Length); - filePath = filePath.Remove(filePath.LastIndexOf("/")); + string fsPath = filePath.Substring(InventoryArchiveConstants.INVENTORY_PATH.Length); + fsPath = fsPath.Remove(fsPath.LastIndexOf("/") + 1); + string originalFsPath = fsPath; - m_log.DebugFormat("[INVENTORY ARCHIVER]: Loading to file path {0}", filePath); + m_log.DebugFormat("[INVENTORY ARCHIVER]: Loading to folder {0}", fsPath); - string[] rawFolders = filePath.Split(new char[] { '/' }); + InventoryFolderImpl foundFolder = null; + while (null == foundFolder && fsPath.Length > 0) + { + if (foldersCreated.ContainsKey(fsPath)) + { + m_log.DebugFormat("[INVENTORY ARCHIVER]: Found previously created fs path {0}", fsPath); + foundFolder = foldersCreated[fsPath]; + } + else + { + // Don't include the last slash + int penultimateSlashIndex = fsPath.LastIndexOf("/", fsPath.Length - 2); + + if (penultimateSlashIndex >= 0) + { + fsPath = fsPath.Remove(penultimateSlashIndex + 1); + } + else + { + m_log.DebugFormat( + "[INVENTORY ARCHIVER]: Found no previously created fs path for {0}", + originalFsPath); + fsPath = string.Empty; + foundFolder = rootDestinationFolder; + } + } + } + + string fsPathSectionToCreate = originalFsPath.Substring(fsPath.Length); + string[] rawDirsToCreate + = fsPathSectionToCreate.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); + int i = 0; + + while (i < rawDirsToCreate.Length) + { + m_log.DebugFormat("[INVENTORY ARCHIVER]: Creating folder {0}", rawDirsToCreate[i]); + + int identicalNameIdentifierIndex + = rawDirsToCreate[i].LastIndexOf( + InventoryArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR); + string folderName = rawDirsToCreate[i].Remove(identicalNameIdentifierIndex); + + UUID newFolderId = UUID.Random(); + m_userInfo.CreateFolder( + folderName, newFolderId, (ushort)AssetType.Folder, foundFolder.ID); + foundFolder = foundFolder.GetChildFolder(newFolderId); + + // Record that we have now created this folder + fsPath += rawDirsToCreate[i] + "/"; + m_log.DebugFormat("[INVENTORY ARCHIVER]: Recording creation of fs path {0}", fsPath); + foldersCreated[fsPath] = foundFolder; + + if (0 == i) + nodesLoaded.Add(foundFolder); + + i++; + } + + /* + string[] rawFolders = filePath.Split(new char[] { '/' }); // Find the folders that do exist along the path given int i = 0; @@ -257,16 +317,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver m_userInfo.CreateFolder( rawFolders[i++], newFolderId, (ushort)AssetType.Folder, foundFolder.ID); foundFolder = foundFolder.GetChildFolder(newFolderId); - } + } + */ // Reset folder ID to the one in which we want to load it item.Folder = foundFolder.ID; - - //item.Folder = rootDestinationFolder.ID; m_userInfo.AddItem(item); successfulItemRestores++; - nodesLoaded.Add(item); + + // 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); } } } diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs index 2b071f066a..357ed401cb 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs @@ -106,14 +106,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver m_module.TriggerInventoryArchiveSaved(succeeded, m_userInfo, m_invPath, m_saveStream, reportedException); } - protected void saveInvItem(InventoryItemBase inventoryItem, string path) + protected void SaveInvItem(InventoryItemBase inventoryItem, string path) { string filename = string.Format("{0}{1}_{2}.xml", path, inventoryItem.Name, inventoryItem.ID); StringWriter sw = new StringWriter(); XmlTextWriter writer = new XmlTextWriter(sw); writer.Formatting = Formatting.Indented; - writer.WriteStartElement("InventoryObject"); + writer.WriteStartElement("InventoryItem"); + writer.WriteStartElement("Name"); writer.WriteString(inventoryItem.Name); writer.WriteEndElement(); @@ -168,9 +169,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver writer.WriteStartElement("GroupOwned"); writer.WriteString(inventoryItem.GroupOwned.ToString()); writer.WriteEndElement(); - writer.WriteStartElement("ParentFolderID"); - writer.WriteString(inventoryItem.Folder.ToString()); - writer.WriteEndElement(); + writer.WriteEndElement(); archive.AddFile(filename, sw.ToString()); @@ -178,20 +177,48 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver m_assetGatherer.GatherAssetUuids(inventoryItem.AssetID, (AssetType)inventoryItem.AssetType, assetUuids); } - protected void saveInvDir(InventoryFolderImpl inventoryFolder, string path) + protected void SaveInvDir(InventoryFolderImpl inventoryFolder, string path) { - List inventories = inventoryFolder.RequestListOfFolderImpls(); - List items = inventoryFolder.RequestListOfItems(); - string newPath = path + inventoryFolder.Name + InventoryFolderImpl.PATH_DELIMITER; - archive.AddDir(newPath); + path += + string.Format( + "{0}{1}{2}/", + inventoryFolder.Name, + InventoryArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR, + inventoryFolder.ID); + archive.AddDir(path); + + List childFolders = inventoryFolder.RequestListOfFolderImpls(); + List items = inventoryFolder.RequestListOfItems(); + + /* + Dictionary identicalFolderNames = new Dictionary(); foreach (InventoryFolderImpl folder in inventories) { - saveInvDir(folder, newPath); + + if (!identicalFolderNames.ContainsKey(folder.Name)) + identicalFolderNames[folder.Name] = 0; + else + identicalFolderNames[folder.Name] = identicalFolderNames[folder.Name]++; + + int folderNameNumber = identicalFolderName[folder.Name]; + + SaveInvDir( + folder, + string.Format( + "{0}{1}{2}/", + path, InventoryArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR, folderNameNumber)); } + */ + + foreach (InventoryFolderImpl childFolder in childFolders) + { + SaveInvDir(childFolder, path); + } + foreach (InventoryItemBase item in items) { - saveInvItem(item, newPath); + SaveInvItem(item, path); } } @@ -270,7 +297,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver inventoryItem.Name, inventoryItem.ID, m_invPath); //get and export item info - saveInvItem(inventoryItem, m_invPath); + SaveInvItem(inventoryItem, m_invPath); } } else @@ -280,7 +307,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver inventoryFolder.Name, inventoryFolder.ID, m_invPath); //recurse through all dirs getting dirs and files - saveInvDir(inventoryFolder, InventoryArchiveConstants.INVENTORY_PATH); + SaveInvDir(inventoryFolder, InventoryArchiveConstants.INVENTORY_PATH); } new AssetsRequest(assetUuids.Keys, m_module.CommsManager.AssetCache, ReceivedAllAssets).Execute(); diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs index cb613f7e9a..5cc03406f9 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs @@ -124,15 +124,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests MemoryStream archiveReadStream = new MemoryStream(archive); TarArchiveReader tar = new TarArchiveReader(archiveReadStream); + InventoryFolderImpl objectsFolder = userInfo.RootFolder.FindFolderByPath("Objects"); + //bool gotControlFile = false; bool gotObject1File = false; //bool gotObject2File = false; string expectedObject1FilePath = string.Format( - "{0}{1}{2}_{3}.xml", + "{0}{1}/{2}_{3}.xml", InventoryArchiveConstants.INVENTORY_PATH, - "Objects/", + string.Format( + "Objects{0}{1}", InventoryArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR, objectsFolder.ID), item1.Name, item1Id); + /* string expectedObject2FileName = string.Format( "{0}_{1:000}-{2:000}-{3:000}__{4}.xml", @@ -146,6 +150,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests while (tar.ReadEntry(out filePath, out tarEntryType) != null) { + Console.WriteLine("Got {0}", filePath); + /* if (ArchiveConstants.CONTROL_FILE_PATH == filePath) { @@ -153,7 +159,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests } */ if (filePath.StartsWith(InventoryArchiveConstants.INVENTORY_PATH) && filePath.EndsWith(".xml")) - { + { //string fileName = filePath.Remove(0, "Objects/".Length); //if (fileName.StartsWith(part1.Name)) diff --git a/OpenSim/Region/CoreModules/World/Archiver/TarArchiveReader.cs b/OpenSim/Region/CoreModules/World/Archiver/TarArchiveReader.cs index afe59382d1..19d2629d3e 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/TarArchiveReader.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/TarArchiveReader.cs @@ -89,22 +89,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver return null; entryType = header.EntryType; - filePath = header.FilePath; - byte[] data = m_br.ReadBytes(header.FileSize); - - //m_log.DebugFormat("[TAR ARCHIVE READER]: filePath {0}, fileSize {1}", filePath, header.FileSize); - - // Read the rest of the empty padding in the 512 byte block - if (header.FileSize % 512 != 0) - { - int paddingLeft = 512 - (header.FileSize % 512); - - //m_log.DebugFormat("[TAR ARCHIVE READER]: Reading {0} padding bytes", paddingLeft); - - m_br.ReadBytes(paddingLeft); - } - - return data; + filePath = header.FilePath; + return ReadData(header.FileSize); } /// @@ -126,7 +112,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver if (header[156] == (byte)'L') { int longNameLength = ConvertOctalBytesToDecimal(header, 124, 11); - tarHeader.FilePath = m_asciiEncoding.GetString(m_br.ReadBytes(longNameLength)); + tarHeader.FilePath = m_asciiEncoding.GetString(ReadData(longNameLength)); m_log.DebugFormat("[TAR ARCHIVE READER]: Got long file name {0}", tarHeader.FilePath); header = m_br.ReadBytes(512); } @@ -134,6 +120,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver { tarHeader.FilePath = m_asciiEncoding.GetString(header, 0, 100); tarHeader.FilePath = tarHeader.FilePath.Trim(m_nullCharArray); + m_log.DebugFormat("[TAR ARCHIVE READER]: Got short file name {0}", tarHeader.FilePath); } tarHeader.FileSize = ConvertOctalBytesToDecimal(header, 124, 11); @@ -171,6 +158,30 @@ namespace OpenSim.Region.CoreModules.World.Archiver return tarHeader; } + + /// + /// Read data following a header + /// + /// + /// + protected byte[] ReadData(int fileSize) + { + byte[] data = m_br.ReadBytes(fileSize); + + m_log.DebugFormat("[TAR ARCHIVE READER]: fileSize {0}", fileSize); + + // Read the rest of the empty padding in the 512 byte block + if (fileSize % 512 != 0) + { + int paddingLeft = 512 - (fileSize % 512); + + m_log.DebugFormat("[TAR ARCHIVE READER]: Reading {0} padding bytes", paddingLeft); + + m_br.ReadBytes(paddingLeft); + } + + return data; + } public void Close() {