diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs index a4445eb203..4c02214952 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs @@ -161,14 +161,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver failedAssetRestores++; } else if (filePath.StartsWith(ArchiveConstants.INVENTORY_PATH)) - { + { InventoryFolderBase foundFolder = ReplicateArchivePathToUserInventory( filePath, TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType, rootDestinationFolder, foldersCreated, nodesLoaded); if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY != entryType) - { + { + // Escape back characters + filePath = filePath.Replace("/", "/"); + filePath = filePath.Replace("&", "&"); + InventoryItemBase item = UserInventoryItemSerializer.Deserialize(data); // Don't use the item ID that's in the file @@ -289,6 +293,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR); string newFolderName = rawDirsToCreate[i].Remove(identicalNameIdentifierIndex); + + // Escape back characters + newFolderName = newFolderName.Replace("/", "/"); + newFolderName = newFolderName.Replace("&", "&"); + UUID newFolderId = UUID.Random(); // Asset type has to be Unknown here rather than Folder, otherwise the created folder can't be diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs index 499c552a4a..af0b72f664 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs @@ -394,6 +394,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// public static string CreateArchiveFolderName(string name, UUID id) { + // Only encode ampersands (for escaping anything) and / (since this is used as general dir separator). + name = name.Replace("&", "&"); + name = name.Replace("/", "/"); + return string.Format( "{0}{1}{2}/", name, @@ -409,6 +413,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// public static string CreateArchiveItemName(string name, UUID id) { + name = name.Replace("&", "&"); + name = name.Replace("/", "/"); + return string.Format( "{0}{1}{2}.xml", name, diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs index 8ee9194533..41bb9dc5ef 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs @@ -135,7 +135,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests InventoryFolderBase objsFolder = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, userId, "Objects"); item1.Folder = objsFolder.ID; - scene.AddInventoryItem(userId, item1); + scene.AddInventoryItem(userId, item1); MemoryStream archiveWriteStream = new MemoryStream(); archiverModule.OnInventoryArchiveSaved += SaveCompleted; @@ -217,14 +217,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests string userItemCreatorLastName = "Lucan"; UUID userItemCreatorUuid = UUID.Parse("00000000-0000-0000-0000-000000000666"); - string itemName = "b.lsl"; - string archiveItemName = InventoryArchiveWriteRequest.CreateArchiveItemName(itemName, UUID.Random()); + string item1Name = "b.lsl"; + string archiveItemName = InventoryArchiveWriteRequest.CreateArchiveItemName(item1Name, UUID.Random()); MemoryStream archiveWriteStream = new MemoryStream(); TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream); InventoryItemBase item1 = new InventoryItemBase(); - item1.Name = itemName; + item1.Name = item1Name; item1.AssetID = UUID.Random(); item1.GroupID = UUID.Random(); item1.CreatorId = OspResolver.MakeOspa(userItemCreatorFirstName, userItemCreatorLastName); @@ -258,7 +258,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests = scene.CommsManager.UserProfileCacheService.GetUserDetails(userFirstName, userLastName); InventoryItemBase foundItem1 - = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, userInfo.UserProfile.ID, itemName); + = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, userInfo.UserProfile.ID, item1Name); Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1"); Assert.That( @@ -276,7 +276,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests archiverModule.DearchiveInventory(userFirstName, userLastName, "xA", "meowfood", archiveReadStream); InventoryItemBase foundItem2 - = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, userInfo.UserProfile.ID, "xA/" + itemName); + = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, userInfo.UserProfile.ID, "xA/" + item1Name); Assert.That(foundItem2, Is.Not.Null, "Didn't find loaded item 2"); // Now try loading to a more deeply nested folder @@ -285,10 +285,102 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests archiverModule.DearchiveInventory(userFirstName, userLastName, "xB/xC", "meowfood", archiveReadStream); InventoryItemBase foundItem3 - = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, userInfo.UserProfile.ID, "xB/xC/" + itemName); + = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, userInfo.UserProfile.ID, "xB/xC/" + item1Name); Assert.That(foundItem3, Is.Not.Null, "Didn't find loaded item 3"); } + [Test] + public void TestIarV0_1WithEscapedChars() + { + TestHelper.InMethod(); + log4net.Config.XmlConfigurator.Configure(); + + string itemName = "You & you are a mean man"; + string userPassword = "meowfood"; + + InventoryArchiverModule archiverModule = new InventoryArchiverModule(true); + + Scene scene = SceneSetupHelpers.SetupScene("Inventory"); + SceneSetupHelpers.SetupSceneModules(scene, archiverModule); + CommunicationsManager cm = scene.CommsManager; + + // Create user + string userFirstName = "Jock"; + string userLastName = "Stirrup"; + UUID userId = UUID.Parse("00000000-0000-0000-0000-000000000020"); + + lock (this) + { + UserProfileTestUtils.CreateUserWithInventory( + cm, userFirstName, userLastName, userPassword, userId, InventoryReceived); + Monitor.Wait(this, 60000); + } + + // Create asset + SceneObjectGroup object1; + SceneObjectPart part1; + { + string partName = "part name"; + UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); + PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); + Vector3 groupPosition = new Vector3(10, 20, 30); + Quaternion rotationOffset = new Quaternion(20, 30, 40, 50); + Vector3 offsetPosition = new Vector3(5, 10, 15); + + part1 + = new SceneObjectPart( + ownerId, shape, groupPosition, rotationOffset, offsetPosition); + part1.Name = partName; + + object1 = new SceneObjectGroup(part1); + scene.AddNewSceneObject(object1, false); + } + + UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); + AssetBase asset1 = new AssetBase(); + asset1.FullID = asset1Id; + asset1.Data = Encoding.ASCII.GetBytes(SceneObjectSerializer.ToXml2Format(object1)); + scene.AssetService.Store(asset1); + + // Create item + UUID item1Id = UUID.Parse("00000000-0000-0000-0000-000000000080"); + InventoryItemBase item1 = new InventoryItemBase(); + item1.Name = itemName; + item1.AssetID = asset1.FullID; + item1.ID = item1Id; + InventoryFolderBase objsFolder + = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, userId, "Objects"); + item1.Folder = objsFolder.ID; + scene.AddInventoryItem(userId, item1); + + MemoryStream archiveWriteStream = new MemoryStream(); + archiverModule.OnInventoryArchiveSaved += SaveCompleted; + + mre.Reset(); + archiverModule.ArchiveInventory( + Guid.NewGuid(), userFirstName, userLastName, "Objects", userPassword, archiveWriteStream); + mre.WaitOne(60000, false); + + /// LOAD ITEM + MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray()); + + archiverModule.DearchiveInventory(userFirstName, userLastName, "Scripts", userPassword, archiveReadStream); + + CachedUserInfo userInfo + = scene.CommsManager.UserProfileCacheService.GetUserDetails(userFirstName, userLastName); + + InventoryItemBase foundItem1 + = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, userId, "Scripts/Objects/" + itemName); + + Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1"); +// Assert.That( +// foundItem1.CreatorId, Is.EqualTo(userUuid), +// "Loaded item non-uuid creator doesn't match that of the loading user"); + Assert.That( + foundItem1.Name, Is.EqualTo(itemName), + "Loaded item name doesn't match saved name"); + } + /// /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where /// embedded creators do not exist in the system @@ -301,7 +393,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests { TestHelper.InMethod(); - log4net.Config.XmlConfigurator.Configure(); + //log4net.Config.XmlConfigurator.Configure(); string userFirstName = "Charlie"; string userLastName = "Chan"; @@ -369,7 +461,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests { TestHelper.InMethod(); - log4net.Config.XmlConfigurator.Configure(); + //log4net.Config.XmlConfigurator.Configure(); string userFirstName = "Dennis"; string userLastName = "Menace"; diff --git a/OpenSim/Tests/Common/Setup/UserProfileTestUtils.cs b/OpenSim/Tests/Common/Setup/UserProfileTestUtils.cs index 3ca44a12d1..1b06a46747 100644 --- a/OpenSim/Tests/Common/Setup/UserProfileTestUtils.cs +++ b/OpenSim/Tests/Common/Setup/UserProfileTestUtils.cs @@ -84,15 +84,35 @@ namespace OpenSim.Tests.Common.Setup public static CachedUserInfo CreateUserWithInventory( CommunicationsManager commsManager, string firstName, string lastName, UUID userId, OnInventoryReceivedDelegate callback) + { + return CreateUserWithInventory(commsManager, firstName, lastName, "troll", userId, callback); + } + + /// + /// Create a test user with a standard inventory + /// + /// + /// First name of user + /// Last name of user + /// Password + /// User ID + /// + /// Callback to invoke when inventory has been loaded. This is required because + /// loading may be asynchronous, even on standalone + /// + /// + public static CachedUserInfo CreateUserWithInventory( + CommunicationsManager commsManager, string firstName, string lastName, string password, + UUID userId, OnInventoryReceivedDelegate callback) { LocalUserServices lus = (LocalUserServices)commsManager.UserService; - lus.AddUser(firstName, lastName, "troll", "bill@bailey.com", 1000, 1000, userId); + lus.AddUser(firstName, lastName, password, "bill@bailey.com", 1000, 1000, userId); CachedUserInfo userInfo = commsManager.UserProfileCacheService.GetUserDetails(userId); userInfo.OnInventoryReceived += callback; userInfo.FetchInventory(); return userInfo; - } + } } } diff --git a/OpenSim/Tests/Common/TestHelper.cs b/OpenSim/Tests/Common/TestHelper.cs index 4abf2e3688..9d530635f3 100644 --- a/OpenSim/Tests/Common/TestHelper.cs +++ b/OpenSim/Tests/Common/TestHelper.cs @@ -54,6 +54,7 @@ namespace OpenSim.Tests.Common public static void InMethod() { StackTrace stackTrace = new StackTrace(); + Console.WriteLine(); Console.WriteLine("===> In Test Method : {0} <===", stackTrace.GetFrame(1).GetMethod().Name); } }