* Add the abilty to load and save iar item nodes where folders have identical names

0.6.4-rc1
Justin Clarke Casey 2009-03-04 20:31:03 +00:00
parent e57ac6e0bf
commit b52ac542ad
6 changed files with 161 additions and 49 deletions

View File

@ -76,7 +76,7 @@ namespace OpenSim
/// <summary> /// <summary>
/// The file used to load and save an opensim archive if no filename has been specified /// The file used to load and save an opensim archive if no filename has been specified
/// </summary> /// </summary>
protected const string DEFAULT_OAR_BACKUP_FILENAME = "scene_oar.tar.gz"; protected const string DEFAULT_OAR_BACKUP_FILENAME = "scene.oar";
public ConfigSettings ConfigurationSettings public ConfigSettings ConfigurationSettings
{ {

View File

@ -50,6 +50,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
/// </summary> /// </summary>
public static readonly string ASSET_EXTENSION_SEPARATOR = "_"; public static readonly string ASSET_EXTENSION_SEPARATOR = "_";
/// <summary>
/// Used to separate components in an inventory node name
/// </summary>
public static readonly string INVENTORY_NODE_NAME_COMPONENT_SEPARATOR = "__";
/// <summary> /// <summary>
/// Extensions used for asset types in the archive /// Extensions used for asset types in the archive
/// </summary> /// </summary>

View File

@ -85,7 +85,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
if (contents.Equals("")) return null; if (contents.Equals("")) return null;
reader.ReadStartElement("InventoryObject"); reader.ReadStartElement("InventoryItem");
reader.ReadStartElement("Name"); reader.ReadStartElement("Name");
item.Name = reader.ReadString(); item.Name = reader.ReadString();
reader.ReadEndElement(); reader.ReadEndElement();
@ -138,10 +138,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
reader.ReadStartElement("GroupOwned"); reader.ReadStartElement("GroupOwned");
item.GroupOwned = Convert.ToBoolean(reader.ReadString()); item.GroupOwned = Convert.ToBoolean(reader.ReadString());
reader.ReadEndElement(); reader.ReadEndElement();
//reader.ReadStartElement("ParentFolderID");
//item.Folder = UUID.Parse(reader.ReadString());
//reader.ReadEndElement();
//reader.ReadEndElement();
return item; return item;
} }
@ -187,7 +183,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
if (null == rootDestinationFolder) 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); m_log.ErrorFormat("[INVENTORY ARCHIVER]: Inventory path {0} does not exist", m_invPath);
return nodesLoaded; return nodesLoaded;
@ -195,6 +191,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
archive = new TarArchiveReader(m_loadStream); 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 <string, InventoryFolderImpl> foldersCreated = new Dictionary<string, InventoryFolderImpl>();
byte[] data; byte[] data;
TarArchiveReader.TarEntryType entryType; TarArchiveReader.TarEntryType entryType;
while ((data = archive.ReadEntry(out filePath, out entryType)) != null) while ((data = archive.ReadEntry(out filePath, out entryType)) != null)
@ -222,11 +222,71 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
item.Creator = m_userInfo.UserProfile.ID; item.Creator = m_userInfo.UserProfile.ID;
item.Owner = m_userInfo.UserProfile.ID; item.Owner = m_userInfo.UserProfile.ID;
filePath = filePath.Substring(InventoryArchiveConstants.INVENTORY_PATH.Length); string fsPath = filePath.Substring(InventoryArchiveConstants.INVENTORY_PATH.Length);
filePath = filePath.Remove(filePath.LastIndexOf("/")); 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);
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[] { '/' }); string[] rawFolders = filePath.Split(new char[] { '/' });
// Find the folders that do exist along the path given // Find the folders that do exist along the path given
@ -258,14 +318,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
rawFolders[i++], newFolderId, (ushort)AssetType.Folder, foundFolder.ID); rawFolders[i++], newFolderId, (ushort)AssetType.Folder, foundFolder.ID);
foundFolder = foundFolder.GetChildFolder(newFolderId); foundFolder = foundFolder.GetChildFolder(newFolderId);
} }
*/
// Reset folder ID to the one in which we want to load it // Reset folder ID to the one in which we want to load it
item.Folder = foundFolder.ID; item.Folder = foundFolder.ID;
//item.Folder = rootDestinationFolder.ID;
m_userInfo.AddItem(item); m_userInfo.AddItem(item);
successfulItemRestores++; successfulItemRestores++;
// 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); nodesLoaded.Add(item);
} }
} }

View File

@ -106,14 +106,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
m_module.TriggerInventoryArchiveSaved(succeeded, m_userInfo, m_invPath, m_saveStream, reportedException); 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); string filename = string.Format("{0}{1}_{2}.xml", path, inventoryItem.Name, inventoryItem.ID);
StringWriter sw = new StringWriter(); StringWriter sw = new StringWriter();
XmlTextWriter writer = new XmlTextWriter(sw); XmlTextWriter writer = new XmlTextWriter(sw);
writer.Formatting = Formatting.Indented; writer.Formatting = Formatting.Indented;
writer.WriteStartElement("InventoryObject"); writer.WriteStartElement("InventoryItem");
writer.WriteStartElement("Name"); writer.WriteStartElement("Name");
writer.WriteString(inventoryItem.Name); writer.WriteString(inventoryItem.Name);
writer.WriteEndElement(); writer.WriteEndElement();
@ -168,9 +169,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
writer.WriteStartElement("GroupOwned"); writer.WriteStartElement("GroupOwned");
writer.WriteString(inventoryItem.GroupOwned.ToString()); writer.WriteString(inventoryItem.GroupOwned.ToString());
writer.WriteEndElement(); writer.WriteEndElement();
writer.WriteStartElement("ParentFolderID");
writer.WriteString(inventoryItem.Folder.ToString());
writer.WriteEndElement();
writer.WriteEndElement(); writer.WriteEndElement();
archive.AddFile(filename, sw.ToString()); 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); m_assetGatherer.GatherAssetUuids(inventoryItem.AssetID, (AssetType)inventoryItem.AssetType, assetUuids);
} }
protected void saveInvDir(InventoryFolderImpl inventoryFolder, string path) protected void SaveInvDir(InventoryFolderImpl inventoryFolder, string path)
{ {
List<InventoryFolderImpl> inventories = inventoryFolder.RequestListOfFolderImpls(); path +=
string.Format(
"{0}{1}{2}/",
inventoryFolder.Name,
InventoryArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR,
inventoryFolder.ID);
archive.AddDir(path);
List<InventoryFolderImpl> childFolders = inventoryFolder.RequestListOfFolderImpls();
List<InventoryItemBase> items = inventoryFolder.RequestListOfItems(); List<InventoryItemBase> items = inventoryFolder.RequestListOfItems();
string newPath = path + inventoryFolder.Name + InventoryFolderImpl.PATH_DELIMITER;
archive.AddDir(newPath); /*
Dictionary identicalFolderNames = new Dictionary<string, int>();
foreach (InventoryFolderImpl folder in inventories) 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) 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); inventoryItem.Name, inventoryItem.ID, m_invPath);
//get and export item info //get and export item info
saveInvItem(inventoryItem, m_invPath); SaveInvItem(inventoryItem, m_invPath);
} }
} }
else else
@ -280,7 +307,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
inventoryFolder.Name, inventoryFolder.ID, m_invPath); inventoryFolder.Name, inventoryFolder.ID, m_invPath);
//recurse through all dirs getting dirs and files //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(); new AssetsRequest(assetUuids.Keys, m_module.CommsManager.AssetCache, ReceivedAllAssets).Execute();

View File

@ -124,15 +124,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
MemoryStream archiveReadStream = new MemoryStream(archive); MemoryStream archiveReadStream = new MemoryStream(archive);
TarArchiveReader tar = new TarArchiveReader(archiveReadStream); TarArchiveReader tar = new TarArchiveReader(archiveReadStream);
InventoryFolderImpl objectsFolder = userInfo.RootFolder.FindFolderByPath("Objects");
//bool gotControlFile = false; //bool gotControlFile = false;
bool gotObject1File = false; bool gotObject1File = false;
//bool gotObject2File = false; //bool gotObject2File = false;
string expectedObject1FilePath = string.Format( string expectedObject1FilePath = string.Format(
"{0}{1}{2}_{3}.xml", "{0}{1}/{2}_{3}.xml",
InventoryArchiveConstants.INVENTORY_PATH, InventoryArchiveConstants.INVENTORY_PATH,
"Objects/", string.Format(
"Objects{0}{1}", InventoryArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR, objectsFolder.ID),
item1.Name, item1.Name,
item1Id); item1Id);
/* /*
string expectedObject2FileName = string.Format( string expectedObject2FileName = string.Format(
"{0}_{1:000}-{2:000}-{3:000}__{4}.xml", "{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) while (tar.ReadEntry(out filePath, out tarEntryType) != null)
{ {
Console.WriteLine("Got {0}", filePath);
/* /*
if (ArchiveConstants.CONTROL_FILE_PATH == filePath) if (ArchiveConstants.CONTROL_FILE_PATH == filePath)
{ {

View File

@ -90,21 +90,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
entryType = header.EntryType; entryType = header.EntryType;
filePath = header.FilePath; filePath = header.FilePath;
byte[] data = m_br.ReadBytes(header.FileSize); return ReadData(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;
} }
/// <summary> /// <summary>
@ -126,7 +112,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
if (header[156] == (byte)'L') if (header[156] == (byte)'L')
{ {
int longNameLength = ConvertOctalBytesToDecimal(header, 124, 11); 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); m_log.DebugFormat("[TAR ARCHIVE READER]: Got long file name {0}", tarHeader.FilePath);
header = m_br.ReadBytes(512); 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 = m_asciiEncoding.GetString(header, 0, 100);
tarHeader.FilePath = tarHeader.FilePath.Trim(m_nullCharArray); 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); tarHeader.FileSize = ConvertOctalBytesToDecimal(header, 124, 11);
@ -172,6 +159,30 @@ namespace OpenSim.Region.CoreModules.World.Archiver
return tarHeader; return tarHeader;
} }
/// <summary>
/// Read data following a header
/// </summary>
/// <param name="fileSize"></param>
/// <returns></returns>
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() public void Close()
{ {
m_br.Close(); m_br.Close();