mirror of
https://github.com/claunia/apprepodbmgr.git
synced 2025-12-16 19:24:42 +00:00
Added support for symbolic links on non-Windows platforms.
This commit is contained in:
@@ -54,6 +54,7 @@ namespace osrepodbmgr.Core
|
||||
public static bool usableDotNetZip;
|
||||
public static string clamdVersion;
|
||||
public static bool virusTotalEnabled;
|
||||
public static Dictionary<string, string> symlinks;
|
||||
|
||||
public delegate void UnarChangeStatusDelegate();
|
||||
public static event UnarChangeStatusDelegate UnarChangeStatus;
|
||||
|
||||
@@ -659,6 +659,18 @@ namespace osrepodbmgr.Core
|
||||
trans = dbCon.BeginTransaction();
|
||||
dbcmd.Transaction = trans;
|
||||
|
||||
sql = string.Format("DROP TABLE IF EXISTS `os_{0}_symlinks`;", id);
|
||||
|
||||
dbcmd.CommandText = sql;
|
||||
|
||||
dbcmd.ExecuteNonQuery();
|
||||
trans.Commit();
|
||||
dbcmd.Dispose();
|
||||
|
||||
dbcmd = dbCon.CreateCommand();
|
||||
trans = dbCon.BeginTransaction();
|
||||
dbcmd.Transaction = trans;
|
||||
|
||||
sql = string.Format("DELETE FROM oses WHERE id = '{0}';", id);
|
||||
|
||||
dbcmd.CommandText = sql;
|
||||
@@ -866,6 +878,95 @@ namespace osrepodbmgr.Core
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool HasSymlinks(long osId)
|
||||
{
|
||||
IDbCommand dbcmd = dbCon.CreateCommand();
|
||||
dbcmd.CommandText = string.Format("SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name = 'os_{0}_symlinks'", osId);
|
||||
object count = dbcmd.ExecuteScalar();
|
||||
dbcmd.Dispose();
|
||||
|
||||
return Convert.ToUInt64(count) > 0;
|
||||
}
|
||||
|
||||
public bool CreateSymlinkTableForOS(long id)
|
||||
{
|
||||
IDbCommand dbcmd = dbCon.CreateCommand();
|
||||
IDbTransaction trans = dbCon.BeginTransaction();
|
||||
dbcmd.Transaction = trans;
|
||||
|
||||
string sql = string.Format("DROP TABLE IF EXISTS `os_{0}_symlinks`;\n\n" +
|
||||
"CREATE TABLE IF NOT EXISTS `os_{0}_symlinks` (\n" +
|
||||
" `path` VARCHAR(8192) PRIMARY KEY,\n" +
|
||||
" `target` VARCHAR(8192) NOT NULL);\n\n" +
|
||||
"CREATE UNIQUE INDEX `os_{0}_symlinks_path_UNIQUE` ON `os_{0}_symlinks` (`path` ASC);\n\n" +
|
||||
"CREATE INDEX `os_{0}_symlinks_target_idx` ON `os_{0}_symlinks` (`target` ASC);", id);
|
||||
|
||||
dbcmd.CommandText = sql;
|
||||
|
||||
dbcmd.ExecuteNonQuery();
|
||||
trans.Commit();
|
||||
dbcmd.Dispose();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool AddSymlinkToOS(string path, string target, long os)
|
||||
{
|
||||
IDbCommand dbcmd = dbCon.CreateCommand();
|
||||
|
||||
IDbDataParameter param1 = dbcmd.CreateParameter();
|
||||
IDbDataParameter param2 = dbcmd.CreateParameter();
|
||||
|
||||
param1.ParameterName = "@path";
|
||||
param2.ParameterName = "@target";
|
||||
|
||||
param1.DbType = DbType.String;
|
||||
param2.DbType = DbType.String;
|
||||
|
||||
param1.Value = path;
|
||||
param2.Value = target;
|
||||
|
||||
dbcmd.Parameters.Add(param1);
|
||||
dbcmd.Parameters.Add(param2);
|
||||
|
||||
IDbTransaction trans = dbCon.BeginTransaction();
|
||||
dbcmd.Transaction = trans;
|
||||
|
||||
string sql = string.Format("INSERT INTO `os_{0}_symlinks` (`path`, `target`)" +
|
||||
" VALUES (@path, @target)", os);
|
||||
|
||||
dbcmd.CommandText = sql;
|
||||
|
||||
dbcmd.ExecuteNonQuery();
|
||||
trans.Commit();
|
||||
dbcmd.Dispose();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool GetAllSymlinks(out Dictionary<string, string> entries, long id)
|
||||
{
|
||||
entries = new Dictionary<string, string>();
|
||||
|
||||
string sql = string.Format("SELECT * from os_{0}_symlinks", id);
|
||||
|
||||
IDbCommand dbcmd = dbCon.CreateCommand();
|
||||
IDbDataAdapter dataAdapter = dbCore.GetNewDataAdapter();
|
||||
dbcmd.CommandText = sql;
|
||||
DataSet dataSet = new DataSet();
|
||||
dataAdapter.SelectCommand = dbcmd;
|
||||
dataAdapter.Fill(dataSet);
|
||||
DataTable dataTable = dataSet.Tables[0];
|
||||
|
||||
foreach(DataRow dRow in dataTable.Rows)
|
||||
{
|
||||
if(!entries.ContainsKey(dRow["path"].ToString()))
|
||||
entries.Add(dRow["path"].ToString(), dRow["target"].ToString());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
35
osrepodbmgr.Core/Symlinks.cs
Normal file
35
osrepodbmgr.Core/Symlinks.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace osrepodbmgr.Core
|
||||
{
|
||||
public static class Symlinks
|
||||
{
|
||||
[DllImport("libc", CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
internal static extern int readlink(string path, IntPtr buf, int bufsize);
|
||||
|
||||
public static string ReadLink(string path)
|
||||
{
|
||||
IntPtr buf = Marshal.AllocHGlobal(16384);
|
||||
|
||||
int ret = readlink(path, buf, 16384);
|
||||
|
||||
if(ret < 0)
|
||||
return null;
|
||||
|
||||
byte[] target = new byte[ret];
|
||||
Marshal.Copy(buf, target, 0, ret);
|
||||
|
||||
return Encoding.UTF8.GetString(target);
|
||||
}
|
||||
|
||||
[DllImport("libc", CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
internal static extern int symlink(string target, string path);
|
||||
|
||||
public static int Symlink(string target, string path)
|
||||
{
|
||||
return symlink(target, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -366,29 +366,11 @@ namespace osrepodbmgr.Core
|
||||
#endif
|
||||
long counter = 0;
|
||||
string format = null;
|
||||
bool isLink = false;
|
||||
JsonTextReader jsReader = new JsonTextReader(new StringReader(lsarOutput));
|
||||
while(jsReader.Read())
|
||||
{
|
||||
if(jsReader.TokenType == JsonToken.PropertyName && jsReader.Value != null && jsReader.Value.ToString() == "XADFileName")
|
||||
counter++;
|
||||
else if(jsReader.TokenType == JsonToken.PropertyName && jsReader.Value != null && jsReader.Value.ToString() == "XADIsLink")
|
||||
{
|
||||
jsReader.Read();
|
||||
if(jsReader.TokenType == JsonToken.Integer)
|
||||
isLink = int.Parse(jsReader.Value.ToString()) > 0;
|
||||
}
|
||||
else if(jsReader.TokenType == JsonToken.PropertyName && jsReader.Value != null && jsReader.Value.ToString() == "XADIsHardLink")
|
||||
{
|
||||
jsReader.Read();
|
||||
// TODO: Support symlinks, devices, hardlinks, whatever?
|
||||
if(jsReader.TokenType == JsonToken.Integer && isLink && int.Parse(jsReader.Value.ToString()) == 0)
|
||||
{
|
||||
if(Failed != null)
|
||||
Failed("Archive contains unsupported symbolic links, not continuing.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(jsReader.TokenType == JsonToken.PropertyName && jsReader.Value != null && jsReader.Value.ToString() == "lsarFormatName")
|
||||
{
|
||||
jsReader.Read();
|
||||
@@ -637,6 +619,13 @@ namespace osrepodbmgr.Core
|
||||
return;
|
||||
}
|
||||
|
||||
if(dbCore.DBOps.HasSymlinks(Context.dbInfo.id))
|
||||
{
|
||||
if(Failed != null)
|
||||
Failed("Cannot create symbolic links on ZIP files");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!Context.usableDotNetZip)
|
||||
{
|
||||
if(Failed != null)
|
||||
|
||||
@@ -293,6 +293,24 @@ namespace osrepodbmgr.Core
|
||||
#if DEBUG
|
||||
stopwatch.Stop();
|
||||
Console.WriteLine("Core.AddFilesToDb(): Took {0} seconds to add all folders to the database", stopwatch.Elapsed.TotalSeconds);
|
||||
stopwatch.Restart();
|
||||
#endif
|
||||
counter = 0;
|
||||
if(Context.symlinks.Count > 0)
|
||||
dbCore.DBOps.CreateSymlinkTableForOS(Context.dbInfo.id);
|
||||
|
||||
foreach(KeyValuePair<string, string> kvp in Context.symlinks)
|
||||
{
|
||||
if(UpdateProgress != null)
|
||||
UpdateProgress(null, "Adding symbolic links to OS in database", counter, Context.symlinks.Count);
|
||||
|
||||
dbCore.DBOps.AddSymlinkToOS(kvp.Key, kvp.Value, Context.dbInfo.id);
|
||||
|
||||
counter++;
|
||||
}
|
||||
#if DEBUG
|
||||
stopwatch.Stop();
|
||||
Console.WriteLine("Core.AddFilesToDb(): Took {0} seconds to add all symbolic links to the database", stopwatch.Elapsed.TotalSeconds);
|
||||
#endif
|
||||
|
||||
if(Finished != null)
|
||||
|
||||
@@ -39,6 +39,7 @@ using Schemas;
|
||||
using SharpCompress.Compressors.BZip2;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
using DiscImageChef.Interop;
|
||||
|
||||
namespace osrepodbmgr.Core
|
||||
{
|
||||
@@ -106,8 +107,14 @@ namespace osrepodbmgr.Core
|
||||
{
|
||||
Context.hashes = new Dictionary<string, DBOSFile>();
|
||||
Context.foldersDict = new Dictionary<string, DBFolder>();
|
||||
Context.symlinks = new Dictionary<string, string>();
|
||||
List<string> alreadyMetadata = new List<string>();
|
||||
bool foundMetadata = false;
|
||||
bool symlinksSupported = DetectOS.GetRealPlatformID() != DiscImageChef.Interop.PlatformID.WinCE &&
|
||||
DetectOS.GetRealPlatformID() != DiscImageChef.Interop.PlatformID.Win32S &&
|
||||
DetectOS.GetRealPlatformID() != DiscImageChef.Interop.PlatformID.Win32NT &&
|
||||
DetectOS.GetRealPlatformID() != DiscImageChef.Interop.PlatformID.Win32Windows &&
|
||||
DetectOS.GetRealPlatformID() != DiscImageChef.Interop.PlatformID.WindowsPhone;
|
||||
|
||||
// For metadata
|
||||
List<ArchitecturesTypeArchitecture> architectures = new List<ArchitecturesTypeArchitecture>();
|
||||
@@ -159,52 +166,52 @@ namespace osrepodbmgr.Core
|
||||
XmlSerializer xs = new XmlSerializer(typeof(CICMMetadataType));
|
||||
try
|
||||
{
|
||||
if (xs.CanDeserialize(xr))
|
||||
if(xs.CanDeserialize(xr))
|
||||
{
|
||||
CICMMetadataType thisMetadata = (CICMMetadataType)xs.Deserialize(xr);
|
||||
if (thisMetadata.Architectures != null)
|
||||
if(thisMetadata.Architectures != null)
|
||||
architectures.AddRange(thisMetadata.Architectures);
|
||||
if (thisMetadata.Barcodes != null)
|
||||
if(thisMetadata.Barcodes != null)
|
||||
barcodes.AddRange(thisMetadata.Barcodes);
|
||||
if (thisMetadata.BlockMedia != null)
|
||||
if(thisMetadata.BlockMedia != null)
|
||||
disks.AddRange(thisMetadata.BlockMedia);
|
||||
if (thisMetadata.Categories != null)
|
||||
if(thisMetadata.Categories != null)
|
||||
categories.AddRange(thisMetadata.Categories);
|
||||
if (thisMetadata.Keywords != null)
|
||||
if(thisMetadata.Keywords != null)
|
||||
keywords.AddRange(thisMetadata.Keywords);
|
||||
if (thisMetadata.Languages != null)
|
||||
if(thisMetadata.Languages != null)
|
||||
languages.AddRange(thisMetadata.Languages);
|
||||
if (thisMetadata.OpticalDisc != null)
|
||||
if(thisMetadata.OpticalDisc != null)
|
||||
discs.AddRange(thisMetadata.OpticalDisc);
|
||||
if (thisMetadata.Subcategories != null)
|
||||
if(thisMetadata.Subcategories != null)
|
||||
subcategories.AddRange(thisMetadata.Subcategories);
|
||||
if (thisMetadata.Systems != null)
|
||||
if(thisMetadata.Systems != null)
|
||||
systems.AddRange(thisMetadata.Systems);
|
||||
if (thisMetadata.Author != null)
|
||||
if(thisMetadata.Author != null)
|
||||
authors.AddRange(thisMetadata.Author);
|
||||
if (thisMetadata.Developer != null)
|
||||
if(thisMetadata.Developer != null)
|
||||
developers.AddRange(thisMetadata.Developer);
|
||||
if (thisMetadata.Performer != null)
|
||||
if(thisMetadata.Performer != null)
|
||||
performers.AddRange(thisMetadata.Performer);
|
||||
if (thisMetadata.Publisher != null)
|
||||
if(thisMetadata.Publisher != null)
|
||||
publishers.AddRange(thisMetadata.Publisher);
|
||||
if (string.IsNullOrWhiteSpace(metadataName) && !string.IsNullOrWhiteSpace(thisMetadata.Name))
|
||||
if(string.IsNullOrWhiteSpace(metadataName) && !string.IsNullOrWhiteSpace(thisMetadata.Name))
|
||||
metadataName = thisMetadata.Name;
|
||||
if (string.IsNullOrWhiteSpace(metadataPartNo) && !string.IsNullOrWhiteSpace(thisMetadata.PartNumber))
|
||||
if(string.IsNullOrWhiteSpace(metadataPartNo) && !string.IsNullOrWhiteSpace(thisMetadata.PartNumber))
|
||||
metadataPartNo = thisMetadata.PartNumber;
|
||||
if (string.IsNullOrWhiteSpace(metadataSerial) && !string.IsNullOrWhiteSpace(thisMetadata.SerialNumber))
|
||||
if(string.IsNullOrWhiteSpace(metadataSerial) && !string.IsNullOrWhiteSpace(thisMetadata.SerialNumber))
|
||||
metadataSerial = thisMetadata.SerialNumber;
|
||||
if (string.IsNullOrWhiteSpace(metadataVersion) && !string.IsNullOrWhiteSpace(thisMetadata.Version))
|
||||
if(string.IsNullOrWhiteSpace(metadataVersion) && !string.IsNullOrWhiteSpace(thisMetadata.Version))
|
||||
metadataVersion = thisMetadata.Version;
|
||||
if (thisMetadata.ReleaseDateSpecified)
|
||||
if(thisMetadata.ReleaseDateSpecified)
|
||||
{
|
||||
if (thisMetadata.ReleaseDate > releaseDate)
|
||||
if(thisMetadata.ReleaseDate > releaseDate)
|
||||
{
|
||||
releaseDateSpecified = true;
|
||||
releaseDate = thisMetadata.ReleaseDate;
|
||||
}
|
||||
}
|
||||
if (thisMetadata.ReleaseTypeSpecified)
|
||||
if(thisMetadata.ReleaseTypeSpecified)
|
||||
{
|
||||
releaseTypeSpecified = true;
|
||||
releaseType = thisMetadata.ReleaseType;
|
||||
@@ -243,7 +250,7 @@ namespace osrepodbmgr.Core
|
||||
continue;
|
||||
}
|
||||
}
|
||||
catch (XmlException)
|
||||
catch(XmlException)
|
||||
{
|
||||
xr.Close();
|
||||
xrs.Close();
|
||||
@@ -355,12 +362,30 @@ namespace osrepodbmgr.Core
|
||||
|
||||
string relpath = file.Substring(filesPath.Length + 1);
|
||||
|
||||
// TODO: Support symlinks, devices, hardlinks, whatever?
|
||||
if(fi.Attributes.HasFlag(FileAttributes.ReparsePoint))
|
||||
{
|
||||
if(Failed != null)
|
||||
Failed(string.Format("{0} is an unsupported symbolic link, not continuing.", relpath));
|
||||
return;
|
||||
// TODO: Symlinks not supported on any Windows platform
|
||||
if(!symlinksSupported)
|
||||
{
|
||||
if(Failed != null)
|
||||
Failed(string.Format("{0} is an unsupported symbolic link, not continuing.", relpath));
|
||||
return;
|
||||
}
|
||||
|
||||
if(UpdateProgress != null)
|
||||
UpdateProgress(string.Format("Resolving symlink on file {0} of {1}", counter, Context.files.Count), null, counter, Context.files.Count);
|
||||
|
||||
string target = Symlinks.ReadLink(file);
|
||||
if(target == null)
|
||||
{
|
||||
if(Failed != null)
|
||||
Failed(string.Format("Could not resolve symbolic link at {0}, not continuing.", relpath));
|
||||
return;
|
||||
}
|
||||
|
||||
Context.symlinks.Add(relpath, target);
|
||||
counter++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(UpdateProgress != null)
|
||||
@@ -650,8 +675,15 @@ namespace osrepodbmgr.Core
|
||||
return;
|
||||
}
|
||||
|
||||
bool symlinksSupported = DetectOS.GetRealPlatformID() != DiscImageChef.Interop.PlatformID.WinCE &&
|
||||
DetectOS.GetRealPlatformID() != DiscImageChef.Interop.PlatformID.Win32S &&
|
||||
DetectOS.GetRealPlatformID() != DiscImageChef.Interop.PlatformID.Win32NT &&
|
||||
DetectOS.GetRealPlatformID() != DiscImageChef.Interop.PlatformID.Win32Windows &&
|
||||
DetectOS.GetRealPlatformID() != DiscImageChef.Interop.PlatformID.WindowsPhone;
|
||||
|
||||
List<DBOSFile> files;
|
||||
List<DBFolder> folders;
|
||||
Dictionary<string, string> symlinks = new Dictionary<string, string>();
|
||||
long counter;
|
||||
|
||||
if(UpdateProgress != null)
|
||||
@@ -665,7 +697,22 @@ namespace osrepodbmgr.Core
|
||||
dbCore.DBOps.GetAllFolders(out folders, Context.dbInfo.id);
|
||||
|
||||
if(UpdateProgress != null)
|
||||
UpdateProgress("", "Creating folders...", 3, 100);
|
||||
UpdateProgress("", "Asking DB for symbolic links...", 3, 100);
|
||||
|
||||
if(dbCore.DBOps.HasSymlinks(Context.dbInfo.id))
|
||||
{
|
||||
if(!symlinksSupported)
|
||||
{
|
||||
if(Failed != null)
|
||||
Failed("Symbolic links cannot be created on this platform.");
|
||||
return;
|
||||
}
|
||||
|
||||
dbCore.DBOps.GetAllSymlinks(out symlinks, Context.dbInfo.id);
|
||||
}
|
||||
|
||||
if(UpdateProgress != null)
|
||||
UpdateProgress("", "Creating folders...", 4, 100);
|
||||
|
||||
#if DEBUG
|
||||
stopwatch.Restart();
|
||||
@@ -689,14 +736,35 @@ namespace osrepodbmgr.Core
|
||||
Console.WriteLine("Core.SaveAs(): Took {0} seconds to create all folders", stopwatch.Elapsed.TotalSeconds);
|
||||
#endif
|
||||
|
||||
if(UpdateProgress != null)
|
||||
UpdateProgress("", "Creating symbolic links...", 4, 100);
|
||||
|
||||
#if DEBUG
|
||||
stopwatch.Restart();
|
||||
#endif
|
||||
counter = 3;
|
||||
counter = 0;
|
||||
foreach(KeyValuePair<string, string> kvp in symlinks)
|
||||
{
|
||||
if(UpdateProgress2 != null)
|
||||
UpdateProgress2("", kvp.Key, counter, folders.Count);
|
||||
|
||||
Symlinks.Symlink(kvp.Value, kvp.Key);
|
||||
counter++;
|
||||
}
|
||||
#if DEBUG
|
||||
stopwatch.Stop();
|
||||
Console.WriteLine("Core.SaveAs(): Took {0} seconds to create all symbolic links", stopwatch.Elapsed.TotalSeconds);
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
stopwatch.Restart();
|
||||
#endif
|
||||
|
||||
counter = 4;
|
||||
foreach(DBOSFile file in files)
|
||||
{
|
||||
if(UpdateProgress != null)
|
||||
UpdateProgress("", string.Format("Creating {0}...", file.Path), counter, 3 + files.Count);
|
||||
UpdateProgress("", string.Format("Creating {0}...", file.Path), counter, 4 + files.Count);
|
||||
|
||||
Stream zStream = null;
|
||||
string repoPath;
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
<Compile Include="Workers\DiscImageChef.cs" />
|
||||
<Compile Include="Workers\Clamd.cs" />
|
||||
<Compile Include="Workers\VirusTotal.cs" />
|
||||
<Compile Include="Symlinks.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
@@ -125,10 +126,7 @@
|
||||
<MonoDevelop>
|
||||
<Properties>
|
||||
<Policies>
|
||||
<DotNetNamingPolicy DirectoryNamespaceAssociation="PrefixedHierarchical" ResourceNamePolicy="MSBuild">
|
||||
<inheritsSet />
|
||||
<inheritsScope />
|
||||
</DotNetNamingPolicy>
|
||||
<DotNetNamingPolicy DirectoryNamespaceAssociation="PrefixedHierarchical" ResourceNamePolicy="MSBuild" />
|
||||
</Policies>
|
||||
</Properties>
|
||||
</MonoDevelop>
|
||||
|
||||
Reference in New Issue
Block a user