aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2012-09-07 23:30:54 +0100
committerJustin Clark-Casey (justincc)2012-09-14 20:25:44 +0100
commitd7e6fe488d5258ec92230b6c652969f2d0420376 (patch)
tree2541ddb0752c20f372baffa2a9c6b72fee954a81 /OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
parentSupport multi-region OAR files (diff)
downloadopensim-SC_OLD-d7e6fe488d5258ec92230b6c652969f2d0420376.zip
opensim-SC_OLD-d7e6fe488d5258ec92230b6c652969f2d0420376.tar.gz
opensim-SC_OLD-d7e6fe488d5258ec92230b6c652969f2d0420376.tar.bz2
opensim-SC_OLD-d7e6fe488d5258ec92230b6c652969f2d0420376.tar.xz
Rename ArchiveWriteRequestPreparatio nto ArchiveWriteRequest since after the multi-OAR patch there is now only one class that handles this operation.
Adapation of 0004-Renamed-ArchiveWriteRequestPreparation-to-ArchiveWri.patch in http://opensimulator.org/mantis/view.php?id=6105 since that did not directly apply
Diffstat (limited to 'OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs')
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs634
1 files changed, 634 insertions, 0 deletions
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
new file mode 100644
index 0000000..d751b1c
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
@@ -0,0 +1,634 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.IO.Compression;
32using System.Reflection;
33using System.Text.RegularExpressions;
34using System.Threading;
35using System.Xml;
36using log4net;
37using OpenMetaverse;
38using OpenSim.Framework;
39using OpenSim.Framework.Serialization;
40using OpenSim.Region.CoreModules.World.Terrain;
41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes;
43using Ionic.Zlib;
44using GZipStream = Ionic.Zlib.GZipStream;
45using CompressionMode = Ionic.Zlib.CompressionMode;
46using OpenSim.Framework.Serialization.External;
47
48namespace OpenSim.Region.CoreModules.World.Archiver
49{
50 /// <summary>
51 /// Prepare to write out an archive.
52 /// </summary>
53 public class ArchiveWriteRequest
54 {
55 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
56
57 /// <summary>
58 /// The minimum major version of OAR that we can write.
59 /// </summary>
60 public static int MIN_MAJOR_VERSION = 0;
61
62 /// <summary>
63 /// The maximum major version of OAR that we can write.
64 /// </summary>
65 public static int MAX_MAJOR_VERSION = 1;
66
67 /// <summary>
68 /// Whether we're saving a multi-region archive.
69 /// </summary>
70 public bool MultiRegionFormat { get; set; }
71
72 /// <summary>
73 /// Determine whether this archive will save assets. Default is true.
74 /// </summary>
75 public bool SaveAssets { get; set; }
76
77 /// <summary>
78 /// Determines which objects will be included in the archive, according to their permissions.
79 /// Default is null, meaning no permission checks.
80 /// </summary>
81 public string CheckPermissions { get; set; }
82
83 protected Scene m_rootScene;
84 protected Stream m_saveStream;
85 protected TarArchiveWriter m_archiveWriter;
86 protected Guid m_requestId;
87 protected Dictionary<string, object> m_options;
88
89 /// <summary>
90 /// Constructor
91 /// </summary>
92 /// <param name="module">Calling module</param>
93 /// <param name="savePath">The path to which to save data.</param>
94 /// <param name="requestId">The id associated with this request</param>
95 /// <exception cref="System.IO.IOException">
96 /// If there was a problem opening a stream for the file specified by the savePath
97 /// </exception>
98 public ArchiveWriteRequest(Scene scene, string savePath, Guid requestId) : this(scene, requestId)
99 {
100 try
101 {
102 m_saveStream = new GZipStream(new FileStream(savePath, FileMode.Create), CompressionMode.Compress, CompressionLevel.BestCompression);
103 }
104 catch (EntryPointNotFoundException e)
105 {
106 m_log.ErrorFormat(
107 "[ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream."
108 + "If you've manually installed Mono, have you appropriately updated zlib1g as well?");
109 m_log.ErrorFormat("{0} {1}", e.Message, e.StackTrace);
110 }
111 }
112
113 /// <summary>
114 /// Constructor.
115 /// </summary>
116 /// <param name="scene">The root scene to archive</param>
117 /// <param name="saveStream">The stream to which to save data.</param>
118 /// <param name="requestId">The id associated with this request</param>
119 public ArchiveWriteRequest(Scene scene, Stream saveStream, Guid requestId) : this(scene, requestId)
120 {
121 m_saveStream = saveStream;
122 }
123
124 protected ArchiveWriteRequest(Scene scene, Guid requestId)
125 {
126 m_rootScene = scene;
127 m_requestId = requestId;
128 m_archiveWriter = null;
129
130 MultiRegionFormat = false;
131 SaveAssets = true;
132 CheckPermissions = null;
133 }
134
135 /// <summary>
136 /// Archive the region requested.
137 /// </summary>
138 /// <exception cref="System.IO.IOException">if there was an io problem with creating the file</exception>
139 public void ArchiveRegion(Dictionary<string, object> options)
140 {
141 m_options = options;
142
143 if (options.ContainsKey("all") && (bool)options["all"])
144 MultiRegionFormat = true;
145
146 if (options.ContainsKey("noassets") && (bool)options["noassets"])
147 SaveAssets = false;
148
149 Object temp;
150 if (options.TryGetValue("checkPermissions", out temp))
151 CheckPermissions = (string)temp;
152
153
154 // Find the regions to archive
155 ArchiveScenesGroup scenesGroup = new ArchiveScenesGroup();
156 if (MultiRegionFormat)
157 {
158 m_log.InfoFormat("[ARCHIVER]: Saving {0} regions", SceneManager.Instance.Scenes.Count);
159 SceneManager.Instance.ForEachScene(delegate(Scene scene)
160 {
161 scenesGroup.AddScene(scene);
162 });
163 }
164 else
165 {
166 scenesGroup.AddScene(m_rootScene);
167 }
168 scenesGroup.CalcSceneLocations();
169
170
171 m_archiveWriter = new TarArchiveWriter(m_saveStream);
172
173 try
174 {
175 // Write out control file. It should be first so that it will be found ASAP when loading the file.
176 m_archiveWriter.WriteFile(ArchiveConstants.CONTROL_FILE_PATH, CreateControlFile(scenesGroup));
177 m_log.InfoFormat("[ARCHIVER]: Added control file to archive.");
178
179 // Archive the regions
180
181 Dictionary<UUID, AssetType> assetUuids = new Dictionary<UUID, AssetType>();
182
183 scenesGroup.ForEachScene(delegate(Scene scene)
184 {
185 string regionDir = MultiRegionFormat ? scenesGroup.GetRegionDir(scene.RegionInfo.RegionID) : "";
186 ArchiveOneRegion(scene, regionDir, assetUuids);
187 });
188
189 // Archive the assets
190
191 if (SaveAssets)
192 {
193 m_log.DebugFormat("[ARCHIVER]: Saving {0} assets", assetUuids.Count);
194
195 // Asynchronously request all the assets required to perform this archive operation
196 AssetsRequest ar
197 = new AssetsRequest(
198 new AssetsArchiver(m_archiveWriter), assetUuids,
199 m_rootScene.AssetService, m_rootScene.UserAccountService,
200 m_rootScene.RegionInfo.ScopeID, options, ReceivedAllAssets);
201
202 Util.FireAndForget(o => ar.Execute());
203
204 // CloseArchive() will be called from ReceivedAllAssets()
205 }
206 else
207 {
208 m_log.DebugFormat("[ARCHIVER]: Not saving assets since --noassets was specified");
209 CloseArchive(string.Empty);
210 }
211 }
212 catch (Exception e)
213 {
214 CloseArchive(e.Message);
215 throw;
216 }
217 }
218
219
220 private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, AssetType> assetUuids)
221 {
222 m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.RegionInfo.RegionName);
223
224 EntityBase[] entities = scene.GetEntities();
225 List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>();
226
227 int numObjectsSkippedPermissions = 0;
228
229 // Filter entities so that we only have scene objects.
230 // FIXME: Would be nicer to have this as a proper list in SceneGraph, since lots of methods
231 // end up having to do this
232 IPermissionsModule permissionsModule = scene.RequestModuleInterface<IPermissionsModule>();
233 foreach (EntityBase entity in entities)
234 {
235 if (entity is SceneObjectGroup)
236 {
237 SceneObjectGroup sceneObject = (SceneObjectGroup)entity;
238
239 if (!sceneObject.IsDeleted && !sceneObject.IsAttachment)
240 {
241 if (!CanUserArchiveObject(scene.RegionInfo.EstateSettings.EstateOwner, sceneObject, CheckPermissions, permissionsModule))
242 {
243 // The user isn't allowed to copy/transfer this object, so it will not be included in the OAR.
244 ++numObjectsSkippedPermissions;
245 }
246 else
247 {
248 sceneObjects.Add(sceneObject);
249 }
250 }
251 }
252 }
253
254 if (SaveAssets)
255 {
256 UuidGatherer assetGatherer = new UuidGatherer(scene.AssetService);
257 int prevAssets = assetUuids.Count;
258
259 foreach (SceneObjectGroup sceneObject in sceneObjects)
260 {
261 assetGatherer.GatherAssetUuids(sceneObject, assetUuids);
262 }
263
264 m_log.DebugFormat(
265 "[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets",
266 sceneObjects.Count, assetUuids.Count - prevAssets);
267 }
268
269 if (numObjectsSkippedPermissions > 0)
270 {
271 m_log.DebugFormat(
272 "[ARCHIVER]: {0} scene objects skipped due to lack of permissions",
273 numObjectsSkippedPermissions);
274 }
275
276 // Make sure that we also request terrain texture assets
277 RegionSettings regionSettings = scene.RegionInfo.RegionSettings;
278
279 if (regionSettings.TerrainTexture1 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_1)
280 assetUuids[regionSettings.TerrainTexture1] = AssetType.Texture;
281
282 if (regionSettings.TerrainTexture2 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_2)
283 assetUuids[regionSettings.TerrainTexture2] = AssetType.Texture;
284
285 if (regionSettings.TerrainTexture3 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_3)
286 assetUuids[regionSettings.TerrainTexture3] = AssetType.Texture;
287
288 if (regionSettings.TerrainTexture4 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_4)
289 assetUuids[regionSettings.TerrainTexture4] = AssetType.Texture;
290
291 Save(scene, sceneObjects, regionDir);
292 }
293
294 /// <summary>
295 /// Checks whether the user has permission to export an object group to an OAR.
296 /// </summary>
297 /// <param name="user">The user</param>
298 /// <param name="objGroup">The object group</param>
299 /// <param name="checkPermissions">Which permissions to check: "C" = Copy, "T" = Transfer</param>
300 /// <param name="permissionsModule">The scene's permissions module</param>
301 /// <returns>Whether the user is allowed to export the object to an OAR</returns>
302 private bool CanUserArchiveObject(UUID user, SceneObjectGroup objGroup, string checkPermissions, IPermissionsModule permissionsModule)
303 {
304 if (checkPermissions == null)
305 return true;
306
307 if (permissionsModule == null)
308 return true; // this shouldn't happen
309
310 // Check whether the user is permitted to export all of the parts in the SOG. If any
311 // part can't be exported then the entire SOG can't be exported.
312
313 bool permitted = true;
314 //int primNumber = 1;
315
316 foreach (SceneObjectPart obj in objGroup.Parts)
317 {
318 uint perm;
319 PermissionClass permissionClass = permissionsModule.GetPermissionClass(user, obj);
320 switch (permissionClass)
321 {
322 case PermissionClass.Owner:
323 perm = obj.BaseMask;
324 break;
325 case PermissionClass.Group:
326 perm = obj.GroupMask | obj.EveryoneMask;
327 break;
328 case PermissionClass.Everyone:
329 default:
330 perm = obj.EveryoneMask;
331 break;
332 }
333
334 bool canCopy = (perm & (uint)PermissionMask.Copy) != 0;
335 bool canTransfer = (perm & (uint)PermissionMask.Transfer) != 0;
336
337 // Special case: if Everyone can copy the object then this implies it can also be
338 // Transferred.
339 // However, if the user is the Owner then we don't check EveryoneMask, because it seems that the mask
340 // always (incorrectly) includes the Copy bit set in this case. But that's a mistake: the viewer
341 // does NOT show that the object has Everyone-Copy permissions, and doesn't allow it to be copied.
342 if (permissionClass != PermissionClass.Owner)
343 canTransfer |= (obj.EveryoneMask & (uint)PermissionMask.Copy) != 0;
344
345 bool partPermitted = true;
346 if (checkPermissions.Contains("C") && !canCopy)
347 partPermitted = false;
348 if (checkPermissions.Contains("T") && !canTransfer)
349 partPermitted = false;
350
351 // If the user is the Creator of the object then it can always be included in the OAR
352 bool creator = (obj.CreatorID.Guid == user.Guid);
353 if (creator)
354 partPermitted = true;
355
356 //string name = (objGroup.PrimCount == 1) ? objGroup.Name : string.Format("{0} ({1}/{2})", obj.Name, primNumber, objGroup.PrimCount);
357 //m_log.DebugFormat("[ARCHIVER]: Object permissions: {0}: Base={1:X4}, Owner={2:X4}, Everyone={3:X4}, permissionClass={4}, checkPermissions={5}, canCopy={6}, canTransfer={7}, creator={8}, permitted={9}",
358 // name, obj.BaseMask, obj.OwnerMask, obj.EveryoneMask,
359 // permissionClass, checkPermissions, canCopy, canTransfer, creator, partPermitted);
360
361 if (!partPermitted)
362 {
363 permitted = false;
364 break;
365 }
366
367 //++primNumber;
368 }
369
370 return permitted;
371 }
372
373 /// <summary>
374 /// Create the control file.
375 /// </summary>
376 /// <returns></returns>
377 public string CreateControlFile(ArchiveScenesGroup scenesGroup)
378 {
379 int majorVersion;
380 int minorVersion;
381
382 if (MultiRegionFormat)
383 {
384 majorVersion = MAX_MAJOR_VERSION;
385 minorVersion = 0;
386 }
387 else
388 {
389 // To support older versions of OpenSim, we continue to create single-region OARs
390 // using the old file format. In the future this format will be discontinued.
391 majorVersion = 0;
392 minorVersion = 8;
393 }
394//
395// if (m_options.ContainsKey("version"))
396// {
397// string[] parts = m_options["version"].ToString().Split('.');
398// if (parts.Length >= 1)
399// {
400// majorVersion = Int32.Parse(parts[0]);
401//
402// if (parts.Length >= 2)
403// minorVersion = Int32.Parse(parts[1]);
404// }
405// }
406//
407// if (majorVersion < MIN_MAJOR_VERSION || majorVersion > MAX_MAJOR_VERSION)
408// {
409// throw new Exception(
410// string.Format(
411// "OAR version number for save must be between {0} and {1}",
412// MIN_MAJOR_VERSION, MAX_MAJOR_VERSION));
413// }
414// else if (majorVersion == MAX_MAJOR_VERSION)
415// {
416// // Force 1.0
417// minorVersion = 0;
418// }
419// else if (majorVersion == MIN_MAJOR_VERSION)
420// {
421// // Force 0.4
422// minorVersion = 4;
423// }
424
425 m_log.InfoFormat("[ARCHIVER]: Creating version {0}.{1} OAR", majorVersion, minorVersion);
426 if (majorVersion == 1)
427 {
428 m_log.WarnFormat("[ARCHIVER]: Please be aware that version 1.0 OARs are not compatible with OpenSim versions prior to 0.7.4. Do not use the --all option if you want to produce a compatible OAR");
429 }
430
431 String s;
432
433 using (StringWriter sw = new StringWriter())
434 {
435 using (XmlTextWriter xtw = new XmlTextWriter(sw))
436 {
437 xtw.Formatting = Formatting.Indented;
438 xtw.WriteStartDocument();
439 xtw.WriteStartElement("archive");
440 xtw.WriteAttributeString("major_version", majorVersion.ToString());
441 xtw.WriteAttributeString("minor_version", minorVersion.ToString());
442
443 xtw.WriteStartElement("creation_info");
444 DateTime now = DateTime.UtcNow;
445 TimeSpan t = now - new DateTime(1970, 1, 1);
446 xtw.WriteElementString("datetime", ((int)t.TotalSeconds).ToString());
447 if (!MultiRegionFormat)
448 xtw.WriteElementString("id", m_rootScene.RegionInfo.RegionID.ToString());
449 xtw.WriteEndElement();
450
451 xtw.WriteElementString("assets_included", SaveAssets.ToString());
452
453 if (MultiRegionFormat)
454 {
455 WriteRegionsManifest(scenesGroup, xtw);
456 }
457 else
458 {
459 xtw.WriteStartElement("region_info");
460 WriteRegionInfo(m_rootScene, xtw);
461 xtw.WriteEndElement();
462 }
463
464 xtw.WriteEndElement();
465
466 xtw.Flush();
467 }
468
469 s = sw.ToString();
470 }
471
472 return s;
473 }
474
475 /// <summary>
476 /// Writes the list of regions included in a multi-region OAR.
477 /// </summary>
478 private static void WriteRegionsManifest(ArchiveScenesGroup scenesGroup, XmlTextWriter xtw)
479 {
480 xtw.WriteStartElement("regions");
481
482 // Write the regions in order: rows from South to North, then regions from West to East.
483 // The list of regions can have "holes"; we write empty elements in their position.
484
485 for (uint y = (uint)scenesGroup.Rect.Top; y < scenesGroup.Rect.Bottom; ++y)
486 {
487 SortedDictionary<uint, Scene> row;
488 if (scenesGroup.Regions.TryGetValue(y, out row))
489 {
490 xtw.WriteStartElement("row");
491
492 for (uint x = (uint)scenesGroup.Rect.Left; x < scenesGroup.Rect.Right; ++x)
493 {
494 Scene scene;
495 if (row.TryGetValue(x, out scene))
496 {
497 xtw.WriteStartElement("region");
498 xtw.WriteElementString("id", scene.RegionInfo.RegionID.ToString());
499 xtw.WriteElementString("dir", scenesGroup.GetRegionDir(scene.RegionInfo.RegionID));
500 WriteRegionInfo(scene, xtw);
501 xtw.WriteEndElement();
502 }
503 else
504 {
505 // Write a placeholder for a missing region
506 xtw.WriteElementString("region", "");
507 }
508 }
509
510 xtw.WriteEndElement();
511 }
512 else
513 {
514 // Write a placeholder for a missing row
515 xtw.WriteElementString("row", "");
516 }
517 }
518
519 xtw.WriteEndElement(); // "regions"
520 }
521
522 protected static void WriteRegionInfo(Scene scene, XmlTextWriter xtw)
523 {
524 bool isMegaregion;
525 Vector2 size;
526
527 IRegionCombinerModule rcMod = scene.RequestModuleInterface<IRegionCombinerModule>();
528
529 if (rcMod != null)
530 isMegaregion = rcMod.IsRootForMegaregion(scene.RegionInfo.RegionID);
531 else
532 isMegaregion = false;
533
534 if (isMegaregion)
535 size = rcMod.GetSizeOfMegaregion(scene.RegionInfo.RegionID);
536 else
537 size = new Vector2((float)Constants.RegionSize, (float)Constants.RegionSize);
538
539 xtw.WriteElementString("is_megaregion", isMegaregion.ToString());
540 xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y));
541 }
542
543
544 protected void Save(Scene scene, List<SceneObjectGroup> sceneObjects, string regionDir)
545 {
546 if (regionDir != string.Empty)
547 regionDir = ArchiveConstants.REGIONS_PATH + regionDir + "/";
548
549 m_log.InfoFormat("[ARCHIVER]: Adding region settings to archive.");
550
551 // Write out region settings
552 string settingsPath = String.Format("{0}{1}{2}.xml",
553 regionDir, ArchiveConstants.SETTINGS_PATH, scene.RegionInfo.RegionName);
554 m_archiveWriter.WriteFile(settingsPath, RegionSettingsSerializer.Serialize(scene.RegionInfo.RegionSettings));
555
556 m_log.InfoFormat("[ARCHIVER]: Adding parcel settings to archive.");
557
558 // Write out land data (aka parcel) settings
559 List<ILandObject> landObjects = scene.LandChannel.AllParcels();
560 foreach (ILandObject lo in landObjects)
561 {
562 LandData landData = lo.LandData;
563 string landDataPath = String.Format("{0}{1}{2}.xml",
564 regionDir, ArchiveConstants.LANDDATA_PATH, landData.GlobalID.ToString());
565 m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options));
566 }
567
568 m_log.InfoFormat("[ARCHIVER]: Adding terrain information to archive.");
569
570 // Write out terrain
571 string terrainPath = String.Format("{0}{1}{2}.r32",
572 regionDir, ArchiveConstants.TERRAINS_PATH, scene.RegionInfo.RegionName);
573
574 MemoryStream ms = new MemoryStream();
575 scene.RequestModuleInterface<ITerrainModule>().SaveToStream(terrainPath, ms);
576 m_archiveWriter.WriteFile(terrainPath, ms.ToArray());
577 ms.Close();
578
579 m_log.InfoFormat("[ARCHIVER]: Adding scene objects to archive.");
580
581 // Write out scene object metadata
582 IRegionSerialiserModule serializer = scene.RequestModuleInterface<IRegionSerialiserModule>();
583 foreach (SceneObjectGroup sceneObject in sceneObjects)
584 {
585 //m_log.DebugFormat("[ARCHIVER]: Saving {0} {1}, {2}", entity.Name, entity.UUID, entity.GetType());
586
587 string serializedObject = serializer.SerializeGroupToXml2(sceneObject, m_options);
588 string objectPath = string.Format("{0}{1}", regionDir, ArchiveHelpers.CreateObjectPath(sceneObject));
589 m_archiveWriter.WriteFile(objectPath, serializedObject);
590 }
591 }
592
593 protected void ReceivedAllAssets(
594 ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids)
595 {
596 foreach (UUID uuid in assetsNotFoundUuids)
597 {
598 m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid);
599 }
600
601 // m_log.InfoFormat(
602 // "[ARCHIVER]: Received {0} of {1} assets requested",
603 // assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count);
604
605 CloseArchive(String.Empty);
606 }
607
608
609 /// <summary>
610 /// Closes the archive and notifies that we're done.
611 /// </summary>
612 /// <param name="errorMessage">The error that occurred, or empty for success</param>
613 protected void CloseArchive(string errorMessage)
614 {
615 try
616 {
617 if (m_archiveWriter != null)
618 m_archiveWriter.Close();
619 m_saveStream.Close();
620 }
621 catch (Exception e)
622 {
623 m_log.Error(string.Format("[ARCHIVER]: Error closing archive: {0} ", e.Message), e);
624 if (errorMessage == string.Empty)
625 errorMessage = e.Message;
626 }
627
628 m_log.InfoFormat("[ARCHIVER]: Finished writing out OAR for {0}", m_rootScene.RegionInfo.RegionName);
629
630 m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage);
631 }
632
633 }
634}