aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2010-06-30 00:10:44 +0100
committerJustin Clark-Casey (justincc)2010-06-30 00:10:44 +0100
commit5925aac859ee493fd7f6b10026c84a6a22626c79 (patch)
treef7584dad5efc48c29ab51ef433a014900df98a29 /OpenSim
parentRevert "stop exceptions in setting and getting state from propogating since t... (diff)
downloadopensim-SC-5925aac859ee493fd7f6b10026c84a6a22626c79.zip
opensim-SC-5925aac859ee493fd7f6b10026c84a6a22626c79.tar.gz
opensim-SC-5925aac859ee493fd7f6b10026c84a6a22626c79.tar.bz2
opensim-SC-5925aac859ee493fd7f6b10026c84a6a22626c79.tar.xz
Add --merge switch to load iar.
When this switch is used, iar folders are merged with existing same-name user inventory folders. This makes it a little easier to back and restore entire individual user inventories, among other things Added unit test to check behaviour
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/Framework/Serialization/ArchiveConstants.cs29
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs110
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs60
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs50
-rw-r--r--OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs8
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs2
6 files changed, 169 insertions, 90 deletions
diff --git a/OpenSim/Framework/Serialization/ArchiveConstants.cs b/OpenSim/Framework/Serialization/ArchiveConstants.cs
index 475a9de..3143e3b 100644
--- a/OpenSim/Framework/Serialization/ArchiveConstants.cs
+++ b/OpenSim/Framework/Serialization/ArchiveConstants.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Text;
30using OpenMetaverse; 31using OpenMetaverse;
31 32
32namespace OpenSim.Framework.Serialization 33namespace OpenSim.Framework.Serialization
@@ -171,6 +172,30 @@ namespace OpenSim.Framework.Serialization
171 public static string CreateOarObjectPath(string objectName, UUID uuid, Vector3 pos) 172 public static string CreateOarObjectPath(string objectName, UUID uuid, Vector3 pos)
172 { 173 {
173 return OBJECTS_PATH + CreateOarObjectFilename(objectName, uuid, pos); 174 return OBJECTS_PATH + CreateOarObjectFilename(objectName, uuid, pos);
174 } 175 }
176
177 /// <summary>
178 /// Extract a plain path from an IAR path
179 /// </summary>
180 /// <param name="iarPath"></param>
181 /// <returns></returns>
182 public static string ExtractPlainPathFromIarPath(string iarPath)
183 {
184 List<string> plainDirs = new List<string>();
185
186 string[] iarDirs = iarPath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
187
188 foreach (string iarDir in iarDirs)
189 {
190 if (!iarDir.Contains(ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR))
191 plainDirs.Add(iarDir);
192
193 int i = iarDir.LastIndexOf(ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR);
194
195 plainDirs.Add(iarDir.Remove(i));
196 }
197
198 return string.Join("/", plainDirs.ToArray());
199 }
175 } 200 }
176} 201} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
index 9996074..f130b3e 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
@@ -54,6 +54,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
54 54
55 private UserAccount m_userInfo; 55 private UserAccount m_userInfo;
56 private string m_invPath; 56 private string m_invPath;
57
58 /// <summary>
59 /// Do we want to merge this load with existing inventory?
60 /// </summary>
61 protected bool m_merge;
57 62
58 /// <value> 63 /// <value>
59 /// We only use this to request modules 64 /// We only use this to request modules
@@ -66,19 +71,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
66 private Stream m_loadStream; 71 private Stream m_loadStream;
67 72
68 public InventoryArchiveReadRequest( 73 public InventoryArchiveReadRequest(
69 Scene scene, UserAccount userInfo, string invPath, string loadPath) 74 Scene scene, UserAccount userInfo, string invPath, string loadPath, bool merge)
70 : this( 75 : this(
71 scene, 76 scene,
72 userInfo, 77 userInfo,
73 invPath, 78 invPath,
74 new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress)) 79 new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress),
80 merge)
75 { 81 {
76 } 82 }
77 83
78 public InventoryArchiveReadRequest( 84 public InventoryArchiveReadRequest(
79 Scene scene, UserAccount userInfo, string invPath, Stream loadStream) 85 Scene scene, UserAccount userInfo, string invPath, Stream loadStream, bool merge)
80 { 86 {
81 m_scene = scene; 87 m_scene = scene;
88 m_merge = merge;
82 m_userInfo = userInfo; 89 m_userInfo = userInfo;
83 m_invPath = invPath; 90 m_invPath = invPath;
84 m_loadStream = loadStream; 91 m_loadStream = loadStream;
@@ -91,14 +98,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
91 /// A list of the inventory nodes loaded. If folders were loaded then only the root folders are 98 /// A list of the inventory nodes loaded. If folders were loaded then only the root folders are
92 /// returned 99 /// returned
93 /// </returns> 100 /// </returns>
94 public List<InventoryNodeBase> Execute() 101 public HashSet<InventoryNodeBase> Execute()
95 { 102 {
96 string filePath = "ERROR"; 103 string filePath = "ERROR";
97 int successfulAssetRestores = 0; 104 int successfulAssetRestores = 0;
98 int failedAssetRestores = 0; 105 int failedAssetRestores = 0;
99 int successfulItemRestores = 0; 106 int successfulItemRestores = 0;
100 107
101 List<InventoryNodeBase> loadedNodes = new List<InventoryNodeBase>(); 108 HashSet<InventoryNodeBase> loadedNodes = new HashSet<InventoryNodeBase>();
102 109
103 List<InventoryFolderBase> folderCandidates 110 List<InventoryFolderBase> folderCandidates
104 = InventoryArchiveUtils.FindFolderByPath( 111 = InventoryArchiveUtils.FindFolderByPath(
@@ -158,9 +165,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
158 { 165 {
159 successfulItemRestores++; 166 successfulItemRestores++;
160 167
161 // If we're loading an item directly into the given destination folder then we need to record 168 // If we aren't loading the folder containing the item then well need to update the
162 // it separately from any loaded root folders 169 // viewer separately for that item.
163 if (rootDestinationFolder == foundFolder) 170 if (!loadedNodes.Contains(foundFolder))
164 loadedNodes.Add(item); 171 loadedNodes.Add(item);
165 } 172 }
166 } 173 }
@@ -203,14 +210,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
203 string iarPath, 210 string iarPath,
204 InventoryFolderBase rootDestFolder, 211 InventoryFolderBase rootDestFolder,
205 Dictionary <string, InventoryFolderBase> resolvedFolders, 212 Dictionary <string, InventoryFolderBase> resolvedFolders,
206 List<InventoryNodeBase> loadedNodes) 213 HashSet<InventoryNodeBase> loadedNodes)
207 { 214 {
208 string iarPathExisting = iarPath; 215 string iarPathExisting = iarPath;
209 216
210// m_log.DebugFormat( 217// m_log.DebugFormat(
211// "[INVENTORY ARCHIVER]: Loading folder {0} {1}", rootDestFolder.Name, rootDestFolder.ID); 218// "[INVENTORY ARCHIVER]: Loading folder {0} {1}", rootDestFolder.Name, rootDestFolder.ID);
212 219
213 InventoryFolderBase destFolder = ResolveDestinationFolder(rootDestFolder, ref iarPathExisting, resolvedFolders); 220 InventoryFolderBase destFolder
221 = ResolveDestinationFolder(rootDestFolder, ref iarPathExisting, resolvedFolders);
214 222
215 m_log.DebugFormat( 223 m_log.DebugFormat(
216 "[INVENTORY ARCHIVER]: originalArchivePath [{0}], section already loaded [{1}]", 224 "[INVENTORY ARCHIVER]: originalArchivePath [{0}], section already loaded [{1}]",
@@ -249,46 +257,55 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
249 { 257 {
250 string originalArchivePath = archivePath; 258 string originalArchivePath = archivePath;
251 259
252 InventoryFolderBase destFolder = null; 260 while (archivePath.Length > 0)
253
254 if (archivePath.Length > 0)
255 { 261 {
256 while (null == destFolder && archivePath.Length > 0) 262 m_log.DebugFormat("[INVENTORY ARCHIVER]: Trying to resolve destination folder {0}", archivePath);
263
264 if (resolvedFolders.ContainsKey(archivePath))
257 { 265 {
258 m_log.DebugFormat("[INVENTORY ARCHIVER]: Trying to resolve destination folder {0}", archivePath); 266 m_log.DebugFormat(
267 "[INVENTORY ARCHIVER]: Found previously created folder from archive path {0}", archivePath);
268 return resolvedFolders[archivePath];
269 }
270 else
271 {
272 if (m_merge)
273 {
274 // TODO: Using m_invPath is totally wrong - what we need to do is strip the uuid from the
275 // iar name and try to find that instead.
276 string plainPath = ArchiveConstants.ExtractPlainPathFromIarPath(archivePath);
277 List<InventoryFolderBase> folderCandidates
278 = InventoryArchiveUtils.FindFolderByPath(
279 m_scene.InventoryService, m_userInfo.PrincipalID, plainPath);
280
281 if (folderCandidates.Count != 0)
282 {
283 InventoryFolderBase destFolder = folderCandidates[0];
284 resolvedFolders[archivePath] = destFolder;
285 return destFolder;
286 }
287 }
259 288
260 if (resolvedFolders.ContainsKey(archivePath)) 289 // Don't include the last slash so find the penultimate one
290 int penultimateSlashIndex = archivePath.LastIndexOf("/", archivePath.Length - 2);
291
292 if (penultimateSlashIndex >= 0)
261 { 293 {
262 m_log.DebugFormat( 294 // Remove the last section of path so that we can see if we've already resolved the parent
263 "[INVENTORY ARCHIVER]: Found previously created folder from archive path {0}", archivePath); 295 archivePath = archivePath.Remove(penultimateSlashIndex + 1);
264 destFolder = resolvedFolders[archivePath];
265 } 296 }
266 else 297 else
267 { 298 {
268 // Don't include the last slash so find the penultimate one 299 m_log.DebugFormat(
269 int penultimateSlashIndex = archivePath.LastIndexOf("/", archivePath.Length - 2); 300 "[INVENTORY ARCHIVER]: Found no previously created folder for archive path {0}",
270 301 originalArchivePath);
271 if (penultimateSlashIndex >= 0) 302 archivePath = string.Empty;
272 { 303 return rootDestFolder;
273 // Remove the last section of path so that we can see if we've already resolved the parent
274 archivePath = archivePath.Remove(penultimateSlashIndex + 1);
275 }
276 else
277 {
278 m_log.DebugFormat(
279 "[INVENTORY ARCHIVER]: Found no previously created folder for archive path {0}",
280 originalArchivePath);
281 archivePath = string.Empty;
282 destFolder = rootDestFolder;
283 }
284 } 304 }
285 } 305 }
286 } 306 }
287 307
288 if (null == destFolder) 308 return rootDestFolder;
289 destFolder = rootDestFolder;
290
291 return destFolder;
292 } 309 }
293 310
294 /// <summary> 311 /// <summary>
@@ -314,24 +331,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
314 string iarPathExisting, 331 string iarPathExisting,
315 string iarPathToReplicate, 332 string iarPathToReplicate,
316 Dictionary <string, InventoryFolderBase> resolvedFolders, 333 Dictionary <string, InventoryFolderBase> resolvedFolders,
317 List<InventoryNodeBase> loadedNodes) 334 HashSet<InventoryNodeBase> loadedNodes)
318 { 335 {
319 string[] rawDirsToCreate = iarPathToReplicate.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); 336 string[] rawDirsToCreate = iarPathToReplicate.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
320 int i = 0;
321 337
322 while (i < rawDirsToCreate.Length) 338 for (int i = 0; i < rawDirsToCreate.Length; i++)
323 { 339 {
324// m_log.DebugFormat("[INVENTORY ARCHIVER]: Creating folder {0} from IAR", rawDirsToCreate[i]); 340// m_log.DebugFormat("[INVENTORY ARCHIVER]: Creating folder {0} from IAR", rawDirsToCreate[i]);
325 341
342 if (!rawDirsToCreate[i].Contains(ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR))
343 continue;
344
326 int identicalNameIdentifierIndex 345 int identicalNameIdentifierIndex
327 = rawDirsToCreate[i].LastIndexOf( 346 = rawDirsToCreate[i].LastIndexOf(
328 ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR); 347 ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR);
329 348
330 if (identicalNameIdentifierIndex < 0)
331 {
332 i++;
333 continue;
334 }
335 string newFolderName = rawDirsToCreate[i].Remove(identicalNameIdentifierIndex); 349 string newFolderName = rawDirsToCreate[i].Remove(identicalNameIdentifierIndex);
336 350
337 newFolderName = InventoryArchiveUtils.UnescapeArchivePath(newFolderName); 351 newFolderName = InventoryArchiveUtils.UnescapeArchivePath(newFolderName);
@@ -354,8 +368,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
354 368
355 if (0 == i) 369 if (0 == i)
356 loadedNodes.Add(destFolder); 370 loadedNodes.Add(destFolder);
357
358 i++;
359 } 371 }
360 } 372 }
361 373
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs
index cfefbe9..668c344 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs
@@ -91,12 +91,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
91 91
92 scene.AddCommand( 92 scene.AddCommand(
93 this, "load iar", 93 this, "load iar",
94 "load iar <first> <last> <inventory path> <password> [<IAR path>]", 94 "load iar <first> <last> <inventory path> <password> [<IAR path>]",
95 //"load iar [--merge] <first> <last> <inventory path> <password> [<IAR path>]", 95 //"load iar [--merge] <first> <last> <inventory path> <password> [<IAR path>]",
96 "Load user inventory archive (IAR).", 96 "Load user inventory archive (IAR).",
97 //"--merge is an option which merges the loaded IAR with existing inventory folders where possible, rather than always creating new ones" 97 //"--merge is an option which merges the loaded IAR with existing inventory folders where possible, rather than always creating new ones"
98 //+ "<first> is user's first name." + Environment.NewLine 98 //+ "<first> is user's first name." + Environment.NewLine
99 "<first> is user's first name." + Environment.NewLine 99 "<first> is user's first name." + Environment.NewLine
100 + "<last> is user's last name." + Environment.NewLine 100 + "<last> is user's last name." + Environment.NewLine
101 + "<inventory path> is the path inside the user's inventory where the IAR should be loaded." + Environment.NewLine 101 + "<inventory path> is the path inside the user's inventory where the IAR should be loaded." + Environment.NewLine
102 + "<password> is the user's password." + Environment.NewLine 102 + "<password> is the user's password." + Environment.NewLine
@@ -136,16 +136,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
136 if (handlerInventoryArchiveSaved != null) 136 if (handlerInventoryArchiveSaved != null)
137 handlerInventoryArchiveSaved(id, succeeded, userInfo, invPath, saveStream, reportedException); 137 handlerInventoryArchiveSaved(id, succeeded, userInfo, invPath, saveStream, reportedException);
138 } 138 }
139 139
140 public bool ArchiveInventory( 140 public bool ArchiveInventory(
141 Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream) 141 Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream)
142 { 142 {
143 return ArchiveInventory(id, firstName, lastName, invPath, pass, saveStream, new Dictionary<string, object>()); 143 return ArchiveInventory(id, firstName, lastName, invPath, pass, saveStream, new Dictionary<string, object>());
144 } 144 }
145 145
146 public bool ArchiveInventory( 146 public bool ArchiveInventory(
147 Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream, 147 Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream,
148 Dictionary<string, object> options) 148 Dictionary<string, object> options)
149 { 149 {
150 if (m_scenes.Count > 0) 150 if (m_scenes.Count > 0)
151 { 151 {
@@ -184,8 +184,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
184 } 184 }
185 185
186 public bool ArchiveInventory( 186 public bool ArchiveInventory(
187 Guid id, string firstName, string lastName, string invPath, string pass, string savePath, 187 Guid id, string firstName, string lastName, string invPath, string pass, string savePath,
188 Dictionary<string, object> options) 188 Dictionary<string, object> options)
189 { 189 {
190 if (m_scenes.Count > 0) 190 if (m_scenes.Count > 0)
191 { 191 {
@@ -224,13 +224,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
224 } 224 }
225 225
226 public bool DearchiveInventory(string firstName, string lastName, string invPath, string pass, Stream loadStream) 226 public bool DearchiveInventory(string firstName, string lastName, string invPath, string pass, Stream loadStream)
227 { 227 {
228 return DearchiveInventory(firstName, lastName, invPath, pass, loadStream, new Dictionary<string, object>()); 228 return DearchiveInventory(firstName, lastName, invPath, pass, loadStream, new Dictionary<string, object>());
229 } 229 }
230 230
231 public bool DearchiveInventory( 231 public bool DearchiveInventory(
232 string firstName, string lastName, string invPath, string pass, Stream loadStream, 232 string firstName, string lastName, string invPath, string pass, Stream loadStream,
233 Dictionary<string, object> options) 233 Dictionary<string, object> options)
234 { 234 {
235 if (m_scenes.Count > 0) 235 if (m_scenes.Count > 0)
236 { 236 {
@@ -241,10 +241,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
241 if (CheckPresence(userInfo.PrincipalID)) 241 if (CheckPresence(userInfo.PrincipalID))
242 { 242 {
243 InventoryArchiveReadRequest request; 243 InventoryArchiveReadRequest request;
244 bool merge = (options.ContainsKey("merge") ? (bool)options["merge"] : false);
244 245
245 try 246 try
246 { 247 {
247 request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadStream); 248 request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadStream, merge);
248 } 249 }
249 catch (EntryPointNotFoundException e) 250 catch (EntryPointNotFoundException e)
250 { 251 {
@@ -273,8 +274,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
273 } 274 }
274 275
275 public bool DearchiveInventory( 276 public bool DearchiveInventory(
276 string firstName, string lastName, string invPath, string pass, string loadPath, 277 string firstName, string lastName, string invPath, string pass, string loadPath,
277 Dictionary<string, object> options) 278 Dictionary<string, object> options)
278 { 279 {
279 if (m_scenes.Count > 0) 280 if (m_scenes.Count > 0)
280 { 281 {
@@ -285,10 +286,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
285 if (CheckPresence(userInfo.PrincipalID)) 286 if (CheckPresence(userInfo.PrincipalID))
286 { 287 {
287 InventoryArchiveReadRequest request; 288 InventoryArchiveReadRequest request;
289 bool merge = (options.ContainsKey("merge") ? (bool)options["merge"] : false);
288 290
289 try 291 try
290 { 292 {
291 request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadPath); 293 request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadPath, merge);
292 } 294 }
293 catch (EntryPointNotFoundException e) 295 catch (EntryPointNotFoundException e)
294 { 296 {
@@ -322,13 +324,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
322 /// <param name="cmdparams"></param> 324 /// <param name="cmdparams"></param>
323 protected void HandleLoadInvConsoleCommand(string module, string[] cmdparams) 325 protected void HandleLoadInvConsoleCommand(string module, string[] cmdparams)
324 { 326 {
325 m_log.Info("[INVENTORY ARCHIVER]: PLEASE NOTE THAT THIS FACILITY IS EXPERIMENTAL. BUG REPORTS WELCOME."); 327 m_log.Info("[INVENTORY ARCHIVER]: PLEASE NOTE THAT THIS FACILITY IS EXPERIMENTAL. BUG REPORTS WELCOME.");
326 328
327 Dictionary<string, object> options = new Dictionary<string, object>(); 329 Dictionary<string, object> options = new Dictionary<string, object>();
328 OptionSet optionSet = new OptionSet().Add("m|merge", delegate (string v) { options["merge"] = v != null; }); 330 OptionSet optionSet = new OptionSet().Add("m|merge", delegate (string v) { options["merge"] = v != null; });
329 331
330 List<string> mainParams = optionSet.Parse(cmdparams); 332 List<string> mainParams = optionSet.Parse(cmdparams);
331 333
332 if (mainParams.Count < 6) 334 if (mainParams.Count < 6)
333 { 335 {
334 m_log.Error( 336 m_log.Error(
@@ -349,7 +351,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
349 if (DearchiveInventory(firstName, lastName, invPath, pass, loadPath, options)) 351 if (DearchiveInventory(firstName, lastName, invPath, pass, loadPath, options))
350 m_log.InfoFormat( 352 m_log.InfoFormat(
351 "[INVENTORY ARCHIVER]: Loaded archive {0} for {1} {2}", 353 "[INVENTORY ARCHIVER]: Loaded archive {0} for {1} {2}",
352 loadPath, firstName, lastName); 354 loadPath, firstName, lastName);
353 } 355 }
354 356
355 /// <summary> 357 /// <summary>
@@ -454,7 +456,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
454 /// Notify the client of loaded nodes if they are logged in 456 /// Notify the client of loaded nodes if they are logged in
455 /// </summary> 457 /// </summary>
456 /// <param name="loadedNodes">Can be empty. In which case, nothing happens</param> 458 /// <param name="loadedNodes">Can be empty. In which case, nothing happens</param>
457 private void UpdateClientWithLoadedNodes(UserAccount userInfo, List<InventoryNodeBase> loadedNodes) 459 private void UpdateClientWithLoadedNodes(UserAccount userInfo, HashSet<InventoryNodeBase> loadedNodes)
458 { 460 {
459 if (loadedNodes.Count == 0) 461 if (loadedNodes.Count == 0)
460 return; 462 return;
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs
index 5130fa5..5fad0a9 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs
@@ -514,7 +514,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
514 UserAccount ua1 = UserProfileTestUtils.CreateUserWithInventory(scene); 514 UserAccount ua1 = UserProfileTestUtils.CreateUserWithInventory(scene);
515 515
516 Dictionary <string, InventoryFolderBase> foldersCreated = new Dictionary<string, InventoryFolderBase>(); 516 Dictionary <string, InventoryFolderBase> foldersCreated = new Dictionary<string, InventoryFolderBase>();
517 List<InventoryNodeBase> nodesLoaded = new List<InventoryNodeBase>(); 517 HashSet<InventoryNodeBase> nodesLoaded = new HashSet<InventoryNodeBase>();
518 518
519 string folder1Name = "1"; 519 string folder1Name = "1";
520 string folder2aName = "2a"; 520 string folder2aName = "2a";
@@ -529,7 +529,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
529 529
530 { 530 {
531 // Test replication of path1 531 // Test replication of path1
532 new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null) 532 new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false)
533 .ReplicateArchivePathToUserInventory( 533 .ReplicateArchivePathToUserInventory(
534 iarPath1, scene.InventoryService.GetRootFolder(ua1.PrincipalID), 534 iarPath1, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
535 foldersCreated, nodesLoaded); 535 foldersCreated, nodesLoaded);
@@ -546,7 +546,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
546 546
547 { 547 {
548 // Test replication of path2 548 // Test replication of path2
549 new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null) 549 new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false)
550 .ReplicateArchivePathToUserInventory( 550 .ReplicateArchivePathToUserInventory(
551 iarPath2, scene.InventoryService.GetRootFolder(ua1.PrincipalID), 551 iarPath2, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
552 foldersCreated, nodesLoaded); 552 foldersCreated, nodesLoaded);
@@ -592,10 +592,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
592 592
593 string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName }); 593 string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName });
594 594
595 new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null) 595 new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false)
596 .ReplicateArchivePathToUserInventory( 596 .ReplicateArchivePathToUserInventory(
597 itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID), 597 itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
598 new Dictionary<string, InventoryFolderBase>(), new List<InventoryNodeBase>()); 598 new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>());
599 599
600 List<InventoryFolderBase> folder1PostCandidates 600 List<InventoryFolderBase> folder1PostCandidates
601 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName); 601 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName);
@@ -617,5 +617,45 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
617 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1Post, "b"); 617 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1Post, "b");
618 Assert.That(folder2PostCandidates.Count, Is.EqualTo(1)); 618 Assert.That(folder2PostCandidates.Count, Is.EqualTo(1));
619 } 619 }
620
621 /// <summary>
622 /// Test replication of a partly existing archive path to the user's inventory. This should create
623 /// a merged path.
624 /// </summary>
625 [Test]
626 public void TestMergeIarPath()
627 {
628 TestHelper.InMethod();
629 log4net.Config.XmlConfigurator.Configure();
630
631 Scene scene = SceneSetupHelpers.SetupScene("inventory");
632 UserAccount ua1 = UserProfileTestUtils.CreateUserWithInventory(scene);
633
634 string folder1ExistingName = "a";
635 string folder2Name = "b";
636
637 InventoryFolderBase folder1
638 = UserInventoryTestUtils.CreateInventoryFolder(
639 scene.InventoryService, ua1.PrincipalID, folder1ExistingName);
640
641 string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random());
642 string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random());
643
644 string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName });
645
646 new InventoryArchiveReadRequest(scene, ua1, folder1ExistingName, (Stream)null, true)
647 .ReplicateArchivePathToUserInventory(
648 itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
649 new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>());
650
651 List<InventoryFolderBase> folder1PostCandidates
652 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName);
653 Assert.That(folder1PostCandidates.Count, Is.EqualTo(1));
654 Assert.That(folder1PostCandidates[0].ID, Is.EqualTo(folder1.ID));
655
656 List<InventoryFolderBase> folder2PostCandidates
657 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1PostCandidates[0], "b");
658 Assert.That(folder2PostCandidates.Count, Is.EqualTo(1));
659 }
620 } 660 }
621} \ No newline at end of file 661} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs
index 36dae6b..9c20d68 100644
--- a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -173,16 +173,16 @@ namespace OpenSim.Region.CoreModules.Framework.Library
173 m_log.InfoFormat("[LIBRARY MODULE]: Loading library archive {0} ({1})...", iarFileName, simpleName); 173 m_log.InfoFormat("[LIBRARY MODULE]: Loading library archive {0} ({1})...", iarFileName, simpleName);
174 simpleName = GetInventoryPathFromName(simpleName); 174 simpleName = GetInventoryPathFromName(simpleName);
175 175
176 InventoryArchiveReadRequest archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, simpleName, iarFileName); 176 InventoryArchiveReadRequest archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, simpleName, iarFileName, false);
177 try 177 try
178 { 178 {
179 List<InventoryNodeBase> nodes = archread.Execute(); 179 HashSet<InventoryNodeBase> nodes = archread.Execute();
180 if (nodes != null && nodes.Count == 0) 180 if (nodes != null && nodes.Count == 0)
181 { 181 {
182 // didn't find the subfolder with the given name; place it on the top 182 // didn't find the subfolder with the given name; place it on the top
183 m_log.InfoFormat("[LIBRARY MODULE]: Didn't find {0} in library. Placing archive on the top level", simpleName); 183 m_log.InfoFormat("[LIBRARY MODULE]: Didn't find {0} in library. Placing archive on the top level", simpleName);
184 archread.Close(); 184 archread.Close();
185 archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, "/", iarFileName); 185 archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, "/", iarFileName, false);
186 archread.Execute(); 186 archread.Execute();
187 } 187 }
188 foreach (InventoryNodeBase node in nodes) 188 foreach (InventoryNodeBase node in nodes)
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs
index fe71ed5..5ae6439 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *