diff options
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs')
-rw-r--r-- | OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs | 220 |
1 files changed, 165 insertions, 55 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs index 6030706..01170aa 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs | |||
@@ -41,6 +41,7 @@ using OpenSim.Framework.Serialization; | |||
41 | using OpenSim.Framework.Serialization.External; | 41 | using OpenSim.Framework.Serialization.External; |
42 | using OpenSim.Region.CoreModules.World.Archiver; | 42 | using OpenSim.Region.CoreModules.World.Archiver; |
43 | using OpenSim.Region.Framework.Scenes; | 43 | using OpenSim.Region.Framework.Scenes; |
44 | using OpenSim.Region.Framework.Scenes.Serialization; | ||
44 | using OpenSim.Region.Framework.Interfaces; | 45 | using OpenSim.Region.Framework.Interfaces; |
45 | using OpenSim.Services.Interfaces; | 46 | using OpenSim.Services.Interfaces; |
46 | 47 | ||
@@ -75,6 +76,41 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
75 | /// The stream from which the inventory archive will be loaded. | 76 | /// The stream from which the inventory archive will be loaded. |
76 | /// </value> | 77 | /// </value> |
77 | private Stream m_loadStream; | 78 | private Stream m_loadStream; |
79 | |||
80 | /// <summary> | ||
81 | /// FIXME: Do not perform this check since older versions of OpenSim do save the control file after other things | ||
82 | /// (I thought they weren't). We will need to bump the version number and perform this check on all | ||
83 | /// subsequent IAR versions only | ||
84 | /// </summary> | ||
85 | protected bool m_controlFileLoaded = true; | ||
86 | protected bool m_assetsLoaded; | ||
87 | protected bool m_inventoryNodesLoaded; | ||
88 | |||
89 | protected int m_successfulAssetRestores; | ||
90 | protected int m_failedAssetRestores; | ||
91 | protected int m_successfulItemRestores; | ||
92 | |||
93 | /// <summary> | ||
94 | /// Root destination folder for the IAR load. | ||
95 | /// </summary> | ||
96 | protected InventoryFolderBase m_rootDestinationFolder; | ||
97 | |||
98 | /// <summary> | ||
99 | /// Inventory nodes loaded from the iar. | ||
100 | /// </summary> | ||
101 | protected HashSet<InventoryNodeBase> m_loadedNodes = new HashSet<InventoryNodeBase>(); | ||
102 | |||
103 | /// <summary> | ||
104 | /// In order to load identically named folders, we need to keep track of the folders that we have already | ||
105 | /// resolved. | ||
106 | /// </summary> | ||
107 | Dictionary <string, InventoryFolderBase> m_resolvedFolders = new Dictionary<string, InventoryFolderBase>(); | ||
108 | |||
109 | /// <summary> | ||
110 | /// Record the creator id that should be associated with an asset. This is used to adjust asset creator ids | ||
111 | /// after OSP resolution (since OSP creators are only stored in the item | ||
112 | /// </summary> | ||
113 | protected Dictionary<UUID, UUID> m_creatorIdForAssetId = new Dictionary<UUID, UUID>(); | ||
78 | 114 | ||
79 | public InventoryArchiveReadRequest( | 115 | public InventoryArchiveReadRequest( |
80 | Scene scene, UserAccount userInfo, string invPath, string loadPath, bool merge) | 116 | Scene scene, UserAccount userInfo, string invPath, string loadPath, bool merge) |
@@ -100,20 +136,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
100 | /// <summary> | 136 | /// <summary> |
101 | /// Execute the request | 137 | /// Execute the request |
102 | /// </summary> | 138 | /// </summary> |
139 | /// <remarks> | ||
140 | /// Only call this once. To load another IAR, construct another request object. | ||
141 | /// </remarks> | ||
103 | /// <returns> | 142 | /// <returns> |
104 | /// A list of the inventory nodes loaded. If folders were loaded then only the root folders are | 143 | /// A list of the inventory nodes loaded. If folders were loaded then only the root folders are |
105 | /// returned | 144 | /// returned |
106 | /// </returns> | 145 | /// </returns> |
146 | /// <exception cref="System.Exception">Thrown if load fails.</exception> | ||
107 | public HashSet<InventoryNodeBase> Execute() | 147 | public HashSet<InventoryNodeBase> Execute() |
108 | { | 148 | { |
109 | try | 149 | try |
110 | { | 150 | { |
111 | string filePath = "ERROR"; | 151 | string filePath = "ERROR"; |
112 | int successfulAssetRestores = 0; | ||
113 | int failedAssetRestores = 0; | ||
114 | int successfulItemRestores = 0; | ||
115 | |||
116 | HashSet<InventoryNodeBase> loadedNodes = new HashSet<InventoryNodeBase>(); | ||
117 | 152 | ||
118 | List<InventoryFolderBase> folderCandidates | 153 | List<InventoryFolderBase> folderCandidates |
119 | = InventoryArchiveUtils.FindFolderByPath( | 154 | = InventoryArchiveUtils.FindFolderByPath( |
@@ -124,16 +159,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
124 | // Possibly provide an option later on to automatically create this folder if it does not exist | 159 | // Possibly provide an option later on to automatically create this folder if it does not exist |
125 | m_log.ErrorFormat("[INVENTORY ARCHIVER]: Inventory path {0} does not exist", m_invPath); | 160 | m_log.ErrorFormat("[INVENTORY ARCHIVER]: Inventory path {0} does not exist", m_invPath); |
126 | 161 | ||
127 | return loadedNodes; | 162 | return m_loadedNodes; |
128 | } | 163 | } |
129 | 164 | ||
130 | InventoryFolderBase rootDestinationFolder = folderCandidates[0]; | 165 | m_rootDestinationFolder = folderCandidates[0]; |
131 | archive = new TarArchiveReader(m_loadStream); | 166 | archive = new TarArchiveReader(m_loadStream); |
132 | |||
133 | // In order to load identically named folders, we need to keep track of the folders that we have already | ||
134 | // resolved | ||
135 | Dictionary <string, InventoryFolderBase> resolvedFolders = new Dictionary<string, InventoryFolderBase>(); | ||
136 | |||
137 | byte[] data; | 167 | byte[] data; |
138 | TarArchiveReader.TarEntryType entryType; | 168 | TarArchiveReader.TarEntryType entryType; |
139 | 169 | ||
@@ -142,45 +172,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
142 | if (filePath == ArchiveConstants.CONTROL_FILE_PATH) | 172 | if (filePath == ArchiveConstants.CONTROL_FILE_PATH) |
143 | { | 173 | { |
144 | LoadControlFile(filePath, data); | 174 | LoadControlFile(filePath, data); |
145 | } | 175 | } |
146 | else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH)) | 176 | else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH)) |
147 | { | 177 | { |
148 | if (LoadAsset(filePath, data)) | 178 | LoadAssetFile(filePath, data); |
149 | successfulAssetRestores++; | ||
150 | else | ||
151 | failedAssetRestores++; | ||
152 | |||
153 | if ((successfulAssetRestores) % 50 == 0) | ||
154 | m_log.DebugFormat( | ||
155 | "[INVENTORY ARCHIVER]: Loaded {0} assets...", | ||
156 | successfulAssetRestores); | ||
157 | } | 179 | } |
158 | else if (filePath.StartsWith(ArchiveConstants.INVENTORY_PATH)) | 180 | else if (filePath.StartsWith(ArchiveConstants.INVENTORY_PATH)) |
159 | { | 181 | { |
160 | filePath = filePath.Substring(ArchiveConstants.INVENTORY_PATH.Length); | 182 | LoadInventoryFile(filePath, entryType, data); |
161 | |||
162 | // Trim off the file portion if we aren't already dealing with a directory path | ||
163 | if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY != entryType) | ||
164 | filePath = filePath.Remove(filePath.LastIndexOf("/") + 1); | ||
165 | |||
166 | InventoryFolderBase foundFolder | ||
167 | = ReplicateArchivePathToUserInventory( | ||
168 | filePath, rootDestinationFolder, resolvedFolders, loadedNodes); | ||
169 | |||
170 | if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY != entryType) | ||
171 | { | ||
172 | InventoryItemBase item = LoadItem(data, foundFolder); | ||
173 | |||
174 | if (item != null) | ||
175 | { | ||
176 | successfulItemRestores++; | ||
177 | |||
178 | // If we aren't loading the folder containing the item then well need to update the | ||
179 | // viewer separately for that item. | ||
180 | if (!loadedNodes.Contains(foundFolder)) | ||
181 | loadedNodes.Add(item); | ||
182 | } | ||
183 | } | ||
184 | } | 183 | } |
185 | } | 184 | } |
186 | 185 | ||
@@ -188,10 +187,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
188 | 187 | ||
189 | m_log.DebugFormat( | 188 | m_log.DebugFormat( |
190 | "[INVENTORY ARCHIVER]: Successfully loaded {0} assets with {1} failures", | 189 | "[INVENTORY ARCHIVER]: Successfully loaded {0} assets with {1} failures", |
191 | successfulAssetRestores, failedAssetRestores); | 190 | m_successfulAssetRestores, m_failedAssetRestores); |
192 | m_log.InfoFormat("[INVENTORY ARCHIVER]: Successfully loaded {0} items", successfulItemRestores); | 191 | m_log.InfoFormat("[INVENTORY ARCHIVER]: Successfully loaded {0} items", m_successfulItemRestores); |
193 | 192 | ||
194 | return loadedNodes; | 193 | return m_loadedNodes; |
195 | } | 194 | } |
196 | finally | 195 | finally |
197 | { | 196 | { |
@@ -400,9 +399,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
400 | UUID ospResolvedId = OspResolver.ResolveOspa(item.CreatorId, m_scene.UserAccountService); | 399 | UUID ospResolvedId = OspResolver.ResolveOspa(item.CreatorId, m_scene.UserAccountService); |
401 | if (UUID.Zero != ospResolvedId) // The user exists in this grid | 400 | if (UUID.Zero != ospResolvedId) // The user exists in this grid |
402 | { | 401 | { |
402 | // m_log.DebugFormat("[INVENTORY ARCHIVER]: Found creator {0} via OSPA resolution", ospResolvedId); | ||
403 | |||
403 | item.CreatorIdAsUuid = ospResolvedId; | 404 | item.CreatorIdAsUuid = ospResolvedId; |
404 | 405 | ||
405 | // XXX: For now, don't preserve the OSPA in the creator id (which actually gets persisted to the | 406 | // Don't preserve the OSPA in the creator id (which actually gets persisted to the |
406 | // database). Instead, replace with the UUID that we found. | 407 | // database). Instead, replace with the UUID that we found. |
407 | item.CreatorId = ospResolvedId.ToString(); | 408 | item.CreatorId = ospResolvedId.ToString(); |
408 | 409 | ||
@@ -410,7 +411,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
410 | } | 411 | } |
411 | else if (item.CreatorData == null || item.CreatorData == String.Empty) | 412 | else if (item.CreatorData == null || item.CreatorData == String.Empty) |
412 | { | 413 | { |
413 | item.CreatorIdAsUuid = m_userInfo.PrincipalID; | 414 | item.CreatorId = m_userInfo.PrincipalID.ToString(); |
415 | item.CreatorIdAsUuid = new UUID(item.CreatorId); | ||
414 | } | 416 | } |
415 | 417 | ||
416 | item.Owner = m_userInfo.PrincipalID; | 418 | item.Owner = m_userInfo.PrincipalID; |
@@ -418,6 +420,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
418 | // Reset folder ID to the one in which we want to load it | 420 | // Reset folder ID to the one in which we want to load it |
419 | item.Folder = loadFolder.ID; | 421 | item.Folder = loadFolder.ID; |
420 | 422 | ||
423 | // Record the creator id for the item's asset so that we can use it later, if necessary, when the asset | ||
424 | // is loaded. | ||
425 | // FIXME: This relies on the items coming before the assets in the TAR file. Need to create stronger | ||
426 | // checks for this, and maybe even an external tool for creating OARs which enforces this, rather than | ||
427 | // relying on native tar tools. | ||
428 | m_creatorIdForAssetId[item.AssetID] = item.CreatorIdAsUuid; | ||
429 | |||
421 | m_scene.AddInventoryItem(item); | 430 | m_scene.AddInventoryItem(item); |
422 | 431 | ||
423 | return item; | 432 | return item; |
@@ -446,18 +455,38 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
446 | } | 455 | } |
447 | 456 | ||
448 | string extension = filename.Substring(i); | 457 | string extension = filename.Substring(i); |
449 | string uuid = filename.Remove(filename.Length - extension.Length); | 458 | string rawUuid = filename.Remove(filename.Length - extension.Length); |
459 | UUID assetId = new UUID(rawUuid); | ||
450 | 460 | ||
451 | if (ArchiveConstants.EXTENSION_TO_ASSET_TYPE.ContainsKey(extension)) | 461 | if (ArchiveConstants.EXTENSION_TO_ASSET_TYPE.ContainsKey(extension)) |
452 | { | 462 | { |
453 | sbyte assetType = ArchiveConstants.EXTENSION_TO_ASSET_TYPE[extension]; | 463 | sbyte assetType = ArchiveConstants.EXTENSION_TO_ASSET_TYPE[extension]; |
454 | 464 | ||
455 | if (assetType == (sbyte)AssetType.Unknown) | 465 | if (assetType == (sbyte)AssetType.Unknown) |
456 | m_log.WarnFormat("[INVENTORY ARCHIVER]: Importing {0} byte asset {1} with unknown type", data.Length, uuid); | 466 | { |
467 | m_log.WarnFormat("[INVENTORY ARCHIVER]: Importing {0} byte asset {1} with unknown type", data.Length, assetId); | ||
468 | } | ||
469 | else if (assetType == (sbyte)AssetType.Object) | ||
470 | { | ||
471 | if (m_creatorIdForAssetId.ContainsKey(assetId)) | ||
472 | { | ||
473 | string xmlData = Utils.BytesToString(data); | ||
474 | SceneObjectGroup sog = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); | ||
475 | foreach (SceneObjectPart sop in sog.Parts) | ||
476 | { | ||
477 | if (sop.CreatorData == null || sop.CreatorData == "") | ||
478 | { | ||
479 | sop.CreatorID = m_creatorIdForAssetId[assetId]; | ||
480 | } | ||
481 | } | ||
482 | |||
483 | data = Utils.StringToBytes(SceneObjectSerializer.ToOriginalXmlFormat(sog)); | ||
484 | } | ||
485 | } | ||
457 | 486 | ||
458 | //m_log.DebugFormat("[INVENTORY ARCHIVER]: Importing asset {0}, type {1}", uuid, assetType); | 487 | //m_log.DebugFormat("[INVENTORY ARCHIVER]: Importing asset {0}, type {1}", uuid, assetType); |
459 | 488 | ||
460 | AssetBase asset = new AssetBase(new UUID(uuid), "RandomName", assetType, UUID.Zero.ToString()); | 489 | AssetBase asset = new AssetBase(assetId, "From IAR", assetType, UUID.Zero.ToString()); |
461 | asset.Data = data; | 490 | asset.Data = data; |
462 | 491 | ||
463 | m_scene.AssetService.Store(asset); | 492 | m_scene.AssetService.Store(asset); |
@@ -495,7 +524,88 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
495 | majorVersion, MAX_MAJOR_VERSION)); | 524 | majorVersion, MAX_MAJOR_VERSION)); |
496 | } | 525 | } |
497 | 526 | ||
498 | m_log.InfoFormat("[INVENTORY ARCHIVER]: Loading IAR with version {0}", version); | 527 | m_controlFileLoaded = true; |
528 | m_log.InfoFormat("[INVENTORY ARCHIVER]: Loading IAR with version {0}", version); | ||
529 | } | ||
530 | |||
531 | /// <summary> | ||
532 | /// Load inventory file | ||
533 | /// </summary> | ||
534 | /// <param name="path"></param> | ||
535 | /// <param name="entryType"></param> | ||
536 | /// <param name="data"></param> | ||
537 | protected void LoadInventoryFile(string path, TarArchiveReader.TarEntryType entryType, byte[] data) | ||
538 | { | ||
539 | if (!m_controlFileLoaded) | ||
540 | throw new Exception( | ||
541 | string.Format( | ||
542 | "The IAR you are trying to load does not list {0} before {1}. Aborting load", | ||
543 | ArchiveConstants.CONTROL_FILE_PATH, ArchiveConstants.INVENTORY_PATH)); | ||
544 | |||
545 | if (m_assetsLoaded) | ||
546 | throw new Exception( | ||
547 | string.Format( | ||
548 | "The IAR you are trying to load does not list all {0} before {1}. Aborting load", | ||
549 | ArchiveConstants.INVENTORY_PATH, ArchiveConstants.ASSETS_PATH)); | ||
550 | |||
551 | path = path.Substring(ArchiveConstants.INVENTORY_PATH.Length); | ||
552 | |||
553 | // Trim off the file portion if we aren't already dealing with a directory path | ||
554 | if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY != entryType) | ||
555 | path = path.Remove(path.LastIndexOf("/") + 1); | ||
556 | |||
557 | InventoryFolderBase foundFolder | ||
558 | = ReplicateArchivePathToUserInventory( | ||
559 | path, m_rootDestinationFolder, m_resolvedFolders, m_loadedNodes); | ||
560 | |||
561 | if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY != entryType) | ||
562 | { | ||
563 | InventoryItemBase item = LoadItem(data, foundFolder); | ||
564 | |||
565 | if (item != null) | ||
566 | { | ||
567 | m_successfulItemRestores++; | ||
568 | |||
569 | // If we aren't loading the folder containing the item then well need to update the | ||
570 | // viewer separately for that item. | ||
571 | if (!m_loadedNodes.Contains(foundFolder)) | ||
572 | m_loadedNodes.Add(item); | ||
573 | } | ||
574 | } | ||
575 | |||
576 | m_inventoryNodesLoaded = true; | ||
499 | } | 577 | } |
578 | |||
579 | /// <summary> | ||
580 | /// Load asset file | ||
581 | /// </summary> | ||
582 | /// <param name="path"></param> | ||
583 | /// <param name="data"></param> | ||
584 | protected void LoadAssetFile(string path, byte[] data) | ||
585 | { | ||
586 | if (!m_controlFileLoaded) | ||
587 | throw new Exception( | ||
588 | string.Format( | ||
589 | "The IAR you are trying to load does not list {0} before {1}. Aborting load", | ||
590 | ArchiveConstants.CONTROL_FILE_PATH, ArchiveConstants.ASSETS_PATH)); | ||
591 | |||
592 | if (!m_inventoryNodesLoaded) | ||
593 | throw new Exception( | ||
594 | string.Format( | ||
595 | "The IAR you are trying to load does not list all {0} before {1}. Aborting load", | ||
596 | ArchiveConstants.INVENTORY_PATH, ArchiveConstants.ASSETS_PATH)); | ||
597 | |||
598 | if (LoadAsset(path, data)) | ||
599 | m_successfulAssetRestores++; | ||
600 | else | ||
601 | m_failedAssetRestores++; | ||
602 | |||
603 | if ((m_successfulAssetRestores) % 50 == 0) | ||
604 | m_log.DebugFormat( | ||
605 | "[INVENTORY ARCHIVER]: Loaded {0} assets...", | ||
606 | m_successfulAssetRestores); | ||
607 | |||
608 | m_assetsLoaded = true; | ||
609 | } | ||
500 | } | 610 | } |
501 | } \ No newline at end of file | 611 | } \ No newline at end of file |