checkpoint for real

This commit is contained in:
2020-04-27 12:34:56 -04:00
parent 6ed92261ec
commit c1618deb83
31 changed files with 1429 additions and 626 deletions

18
API.cs
View File

@@ -1,4 +1,18 @@
$HEADER$namespace $NAMESPACE$
using System;
namespace Foodsoft.Alpm
{
public class $CLASS$ {$END$}
public static class API
{
public static readonly string Version = alpm.alpm_version();
internal static void WrapError(SafeAlpmHandle h, Func<int> f)
{
var err = f();
if (err != 0)
{
throw new Exception(alpm.alpm_errno(h));
}
}
}
}

View File

@@ -1,10 +1,8 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnassignedReadonlyField
@@ -12,538 +10,12 @@ using System.Runtime.Serialization;
// ReSharper disable InconsistentNaming
namespace Alpm
namespace Foodsoft.Alpm
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct alpm_pkg_p
{
private IntPtr ptr;
}
[StructLayout(LayoutKind.Sequential)]
public struct alpm_list_t
{
public IntPtr data;
public unsafe alpm_list_t* prev;
public unsafe alpm_list_t* next;
}
public interface IAlpmItemsAccessor<TElement>
{
SafeAlpmHandle Handle { get; }
public IntPtr GetItems();
public int SetItems(IntPtr list);
public int AddItem(TElement item);
public int RemoveItem(TElement item);
public IntPtr FindItem(TElement item);
public TElement PtrToItem(IntPtr p);
}
public class SafeAlpmHandle : SafeHandle
{
private SafeAlpmHandle() : base(IntPtr.Zero, true) { }
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
return alpm.alpm_release(handle) == 0;
}
public override bool IsInvalid => handle == IntPtr.Zero;
}
public sealed class Handle : IDisposable
{
private readonly SafeAlpmHandle _handle;
public Handle(string root, string dbpath)
{
var err = ErrNo.ERR_OK;
_handle = alpm.alpm_initialize(root, dbpath, ref err);
if (_handle.IsInvalid)
{
throw new Exception(err);
}
}
public void Dispose()
{
_handle.Dispose();
}
private Database DatabaseAccess(IntPtr ptr)
{
if (ptr == IntPtr.Zero)
{
throw new Exception(_handle);
}
Database db;
RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally
{
// adding this ref and getting the Database object the handle must not interrupted
var addedRef = false;
_handle.DangerousAddRef(ref addedRef);
if (!addedRef)
throw new ObjectDisposedException(GetType().FullName);
db = new Database(_handle, new DatabaseHandle(ptr));
}
return db;
}
public Database LocalDB => DatabaseAccess(alpm.alpm_get_localdb(_handle));
public Database RegisterSyncDB(string treename, SigLevel sigLevel) =>
DatabaseAccess(alpm.alpm_register_syncdb(_handle, treename, sigLevel));
public readonly struct CacheDirsAccessor : IAlpmItemsAccessor<string>
{
public CacheDirsAccessor(SafeAlpmHandle handle) => Handle = handle;
public SafeAlpmHandle Handle { get; }
public IntPtr GetItems() => alpm.alpm_option_get_cachedirs(Handle);
public int SetItems(IntPtr list) => alpm.alpm_option_set_cachedirs(Handle, list);
public int AddItem(string item) => alpm.alpm_option_add_cachedir(Handle, item);
public int RemoveItem(string item) => alpm.alpm_option_remove_cachedir(Handle, item);
public IntPtr FindItem(string item) => alpm.alpm_list_find_str(GetItems(), item);
public string PtrToItem(IntPtr p) => Marshal.PtrToStringUTF8(p)!;
}
#nullable enable
public struct CollectionWrapper<TImpl, TElement> : ICollection<TElement> where TImpl : IAlpmItemsAccessor<TElement>,
ICollection<TElement>
{
private TImpl _impl;
public CollectionWrapper(TImpl impl)
{
_impl = impl;
}
IEnumerator<TElement> IEnumerable<TElement>.GetEnumerator()
{
return (IEnumerator<TElement>) GetEnumerator();
}
public IEnumerator GetEnumerator()
{
var result = new List<TElement>();
var intPtr = _impl.GetItems();
unsafe
{
for (var list = (alpm_list_t*) intPtr; list != null; list = alpm.alpm_list_next(list))
{
result.Add(_impl.PtrToItem(list->data));
}
}
return result.GetEnumerator();
}
public void Add(TElement item)
{
_impl.AddItem(item);
}
public void Clear()
{
_impl.SetItems(IntPtr.Zero);
}
public bool Contains(TElement item) =>
_impl.FindItem(item) != IntPtr.Zero;
public void CopyTo(TElement[] array, int arrayIndex)
{
var intPtr = _impl.GetItems();
unsafe
{
for (var list = (alpm_list_t*) intPtr; list != null; list = alpm.alpm_list_next(list))
{
array[arrayIndex++] = _impl.PtrToItem(list->data);
}
}
}
public bool Remove(TElement item)
{
var err = _impl.RemoveItem(item);
if (err < 0)
{
throw new Exception(alpm.alpm_errno(_impl.Handle));
}
return err == 0;
}
public int Count => (int) alpm.alpm_list_count(_impl.GetItems());
public bool IsReadOnly => false;
}
private readonly struct CacheDirCollection : ICollection<string>
{
private readonly SafeAlpmHandle _handle;
public CacheDirCollection(SafeAlpmHandle handle)
{
_handle = handle;
}
public IEnumerator<string> GetEnumerator()
{
var result = new List<string>();
var intPtr = alpm.alpm_option_get_cachedirs(_handle);
unsafe
{
for (var list = (alpm_list_t*) intPtr; list != null; list = alpm.alpm_list_next(list))
{
result.Add(Marshal.PtrToStringUTF8(list->data));
}
}
return result.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(string item)
{
var handle = _handle;
Alpm.ErrWrap(_handle, () => alpm.alpm_option_add_cachedir(handle, item));
}
public void Clear()
{
var handle = _handle;
Alpm.ErrWrap(_handle, () => alpm.alpm_option_set_cachedirs(handle, IntPtr.Zero));
}
public bool Contains(string item) =>
alpm.alpm_list_find_str(alpm.alpm_option_get_cachedirs(_handle), item) != IntPtr.Zero;
public void CopyTo(string[] array, int arrayIndex)
{
var intPtr = alpm.alpm_option_get_cachedirs(_handle);
unsafe
{
for (var list = (alpm_list_t*) intPtr; list != null; list = alpm.alpm_list_next(list))
{
array[arrayIndex++] = Marshal.PtrToStringUTF8(list->data);
}
}
}
public bool Remove(string item)
{
var err = alpm.alpm_option_remove_cachedir(_handle, item);
if (err < 0)
{
throw new Exception(alpm.alpm_errno(_handle));
}
return err == 0;
}
public int Count => (int) alpm.alpm_list_count(alpm.alpm_option_get_cachedirs(_handle));
public bool IsReadOnly => false;
}
public ICollection<string> CacheDirs
{
get => new CacheDirCollection(_handle);
set
{
foreach (var s in value)
{
Alpm.ErrWrap(_handle, () => alpm.alpm_option_add_cachedir(_handle, s));
}
}
}
}
public enum caps
{
ALPM_CAPABILITY_NLS = (1 << 0),
ALPM_CAPABILITY_DOWNLOADER = (1 << 1),
ALPM_CAPABILITY_SIGNATURES = (1 << 2)
}
[Serializable()]
public class Exception : System.Exception
{
public Exception() { }
public Exception(SafeAlpmHandle handle) : base(Alpm.StrError(alpm.alpm_errno(handle))) { }
public Exception(ErrNo errno) : base(Alpm.StrError(errno)) { }
public Exception(ErrNo errno, System.Exception inner) : base(Alpm.StrError(errno), inner) { }
protected Exception(SerializationInfo info,
StreamingContext context) : base(info, context) { }
}
public class DatabaseHandle : SafeHandle
{
private DatabaseHandle() : base(IntPtr.Zero, true) { }
public DatabaseHandle(IntPtr h) : this()
{
SetHandle(h);
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
return alpm.alpm_db_unregister(handle) == 0;
}
public override bool IsInvalid => handle == IntPtr.Zero;
}
public sealed class Database : IDisposable
{
private SafeAlpmHandle _handle;
private DatabaseHandle _db;
public Database(SafeAlpmHandle handle, DatabaseHandle db)
{
_handle = handle;
_db = db;
}
private readonly struct ServerCollection : ICollection<string>
{
private readonly SafeAlpmHandle _handle;
private readonly DatabaseHandle _db;
public ServerCollection(SafeAlpmHandle handle, DatabaseHandle db)
{
_handle = handle;
_db = db;
}
public IEnumerator<string> GetEnumerator()
{
var result = new List<string>();
var intPtr = alpm.alpm_db_get_servers(_db);
unsafe
{
for (var list = (alpm_list_t*) intPtr; list != null; list = alpm.alpm_list_next(list))
{
result.Add(Marshal.PtrToStringUTF8(list->data));
}
}
return result.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(string item)
{
var db = _db;
Alpm.ErrWrap(_handle, () => alpm.alpm_db_add_server(db, item));
}
public void Clear()
{
var db = _db;
Alpm.ErrWrap(_handle, () => alpm.alpm_db_set_servers(db, IntPtr.Zero));
}
public bool Contains(string item) =>
alpm.alpm_list_find_str(alpm.alpm_db_get_servers(_db), item) != IntPtr.Zero;
public void CopyTo(string[] array, int arrayIndex)
{
var intPtr = alpm.alpm_db_get_servers(_db);
unsafe
{
for (var list = (alpm_list_t*) intPtr; list != null; list = alpm.alpm_list_next(list))
{
array[arrayIndex++] = Marshal.PtrToStringUTF8(list->data);
}
}
}
public bool Remove(string item)
{
var err = alpm.alpm_db_remove_server(_db, item);
if (err < 0)
{
throw new Exception(alpm.alpm_errno(_handle));
}
return err == 0;
}
public int Count => (int) alpm.alpm_list_count(alpm.alpm_db_get_servers(_db));
public bool IsReadOnly => false;
}
public ICollection<string> Servers
{
get => new ServerCollection(_handle, _db);
set
{
foreach (var s in value)
{
Alpm.ErrWrap(_handle, () => alpm.alpm_db_add_server(_db, s));
}
}
}
public string Name => Marshal.PtrToStringUTF8(alpm.alpm_db_get_name(_db));
public SigLevel SigLevel => alpm.alpm_db_get_siglevel(_db);
public ErrNo Valid => alpm.alpm_db_get_valid(_db) != 0 ? alpm.alpm_errno(_handle) : ErrNo.ERR_OK;
public bool Update(bool force)
{
var err = alpm.alpm_db_update(force ? 1 : 0, _db);
if (err < 0)
{
throw new Exception(_handle);
}
return err == 0;
}
public void Dispose()
{
_db.Dispose();
RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally
{
_handle.DangerousRelease();
}
}
}
public static class alpm
{
[DllImport(nameof(alpm))]
public static extern IntPtr alpm_option_get_cachedirs(SafeAlpmHandle handle);
[DllImport(nameof(alpm))]
public static extern int alpm_option_set_cachedirs(SafeAlpmHandle handle, IntPtr cachedirs);
[DllImport(nameof(alpm), CharSet = CharSet.Ansi)]
public static extern int alpm_option_add_cachedir(SafeAlpmHandle handle, string cachedir);
[DllImport(nameof(alpm), CharSet = CharSet.Ansi)]
public static extern int alpm_option_remove_cachedir(SafeAlpmHandle handle, string cachedir);
[DllImport(nameof(alpm))]
public static extern ErrNo alpm_errno(SafeAlpmHandle handle);
[DllImport(nameof(alpm))]
public static extern IntPtr alpm_strerror(ErrNo err);
[DllImport(nameof(alpm))]
public static extern IntPtr alpm_get_localdb(SafeAlpmHandle handle);
[DllImport(nameof(alpm))]
public static extern unsafe alpm_list_t* alpm_option_get_syncdbs();
[DllImport(nameof(alpm), CharSet = CharSet.Ansi)]
public static extern IntPtr alpm_register_syncdb(SafeAlpmHandle handle, string treename, SigLevel sigLevel);
[DllImport(nameof(alpm))]
public static extern int alpm_db_unregister_all_syncdbs(SafeAlpmHandle handle);
[DllImport(nameof(alpm))]
public static extern unsafe alpm_list_t* alpm_list_next(alpm_list_t* list);
[DllImport(nameof(alpm))]
public static extern UIntPtr alpm_list_count(IntPtr list);
[DllImport(nameof(alpm))]
public static extern void alpm_list_free(IntPtr list);
[DllImport(nameof(alpm), CharSet = CharSet.Ansi)]
public static extern IntPtr alpm_list_find_str(IntPtr list, string needle);
[DllImport(nameof(alpm))]
public static extern int alpm_unlock(Handle handle);
[DllImport(nameof(alpm))]
public static extern IntPtr alpm_version();
[DllImport(nameof(alpm))]
public static extern caps alpm_capabilities();
[DllImport(nameof(alpm), CharSet = CharSet.Ansi)]
public static extern SafeAlpmHandle alpm_initialize(string root, string dbpath, ref ErrNo err);
[DllImport(nameof(alpm))]
public static extern int alpm_release(IntPtr handle);
[DllImport(nameof(alpm))]
public static extern int alpm_db_remove_server(DatabaseHandle db, string url);
[DllImport(nameof(alpm))]
public static extern int alpm_db_unregister(IntPtr db);
[DllImport(nameof(alpm))]
public static extern IntPtr alpm_db_get_name(DatabaseHandle db);
[DllImport(nameof(alpm))]
public static extern SigLevel alpm_db_get_siglevel(DatabaseHandle db);
[DllImport(nameof(alpm))]
public static extern int alpm_db_get_valid(DatabaseHandle db);
[DllImport(nameof(alpm))]
public static extern int alpm_db_update(int force, DatabaseHandle db);
[DllImport(nameof(alpm))]
public static extern IntPtr alpm_db_get_servers(DatabaseHandle db);
[DllImport(nameof(alpm))]
public static extern int alpm_db_set_servers(DatabaseHandle db, IntPtr list);
[DllImport(nameof(alpm), CharSet = CharSet.Ansi)]
public static extern int alpm_db_add_server(DatabaseHandle db, string url);
}
internal static class Alpm
{
public static string Version()
{
return Marshal.PtrToStringUTF8(alpm.alpm_version());
}
public static string StrError(ErrNo err)
{
return Marshal.PtrToStringUTF8(alpm.alpm_strerror(err));
}
internal static void ErrWrap(SafeAlpmHandle h, Func<int> f)
{
var err = f();
if (err != 0)
{
throw new Exception(alpm.alpm_errno(h));
}
}
}
}

8
Backup.cs Normal file
View File

@@ -0,0 +1,8 @@
namespace Foodsoft.Alpm
{
public struct Backup
{
private string _name;
private string _hash;
}
}

19
CachePackage.cs Normal file
View File

@@ -0,0 +1,19 @@
namespace Foodsoft.Alpm
{
public class CachePackage : Package
{
// ReSharper disable once SuggestBaseTypeForParameter
internal CachePackage(SafeCachePackageHandle handle, Database db) : base(handle)
{
DB = db;
}
public override Database? DB { get; }
public void SetInstallReason(InstallReason reason)
{
if (alpm.alpm_pkg_set_reason(Handle, reason) != 0)
throw new Exception(alpm.alpm_errno(((SafeCachePackageHandle) Handle).SafeAlpmHandle));
}
}
}

View File

@@ -1,12 +1,12 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Foodsoft.Alpm;
using System.Runtime.CompilerServices;
namespace Foodsoft.Alpm
{
internal struct CollectionWrapper<TImpl, TElement> : ICollection<TElement> where TImpl : struct,
IAlpmItemsAccessor<TElement>
internal class CollectionWrapper<TImpl, TElement> : ICollection<TElement> where TImpl : struct,
IItemsAccessor<TElement>
{
private TImpl _impl;
@@ -15,26 +15,31 @@ namespace Foodsoft.Alpm
_impl = impl;
}
IEnumerator<TElement> IEnumerable<TElement>.GetEnumerator()
private static unsafe IntPtr ListNext(IntPtr list) => ((alpm_list_t*) list)->next;
private static unsafe IntPtr ListData(IntPtr list) => ((alpm_list_t*) list)->data;
public IEnumerator<TElement> GetEnumerator()
{
return (IEnumerator<TElement>) GetEnumerator();
}
var safeAlpmHandle = _impl.SafeAlpmHandle;
var release = false;
public IEnumerator GetEnumerator()
{
var result = new List<TElement>();
var intPtr = _impl.GetItems();
unsafe
RuntimeHelpers.PrepareConstrainedRegions();
try
{
for (var list = (alpm_list_t*) intPtr; list != null; list = alpm.alpm_list_next(list))
safeAlpmHandle.DangerousAddRef(ref release);
if (!release) throw new ObjectDisposedException(_impl.GetType().FullName);
for (var list = _impl.GetItems(); list != IntPtr.Zero; list = ListNext(list))
{
result.Add(_impl.PtrToItem(list->data));
yield return _impl.PtrToItem(ListData(list));
}
}
return result.GetEnumerator();
finally
{
if (release)
safeAlpmHandle.DangerousRelease();
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public void Add(TElement item)
{
@@ -47,19 +52,45 @@ namespace Foodsoft.Alpm
}
public bool Contains(TElement item) =>
_impl.FindItem(item) != IntPtr.Zero;
public bool Contains(TElement item)
{
var safeAlpmHandle = _impl.SafeAlpmHandle;
var release = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
safeAlpmHandle.DangerousAddRef(ref release);
return _impl.FindItem(item) != IntPtr.Zero;
}
finally
{
if (release)
safeAlpmHandle.DangerousRelease();
}
}
public void CopyTo(TElement[] array, int arrayIndex)
{
var intPtr = _impl.GetItems();
unsafe
var safeAlpmHandle = _impl.SafeAlpmHandle;
var release = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
for (var list = (alpm_list_t*) intPtr; list != null; list = alpm.alpm_list_next(list))
safeAlpmHandle.DangerousAddRef(ref release);
var intPtr = _impl.GetItems();
unsafe
{
array[arrayIndex++] = _impl.PtrToItem(list->data);
for (var list = (alpm_list_t*) intPtr; list != null; list = alpm.alpm_list_next(list))
{
array[arrayIndex++] = _impl.PtrToItem(list->data);
}
}
}
finally
{
if (release)
safeAlpmHandle.DangerousRelease();
}
}
public bool Remove(TElement item)
@@ -73,7 +104,26 @@ namespace Foodsoft.Alpm
return err == 0;
}
public int Count => (int) alpm.alpm_list_count(_impl.GetItems());
public int Count
{
get
{
var safeAlpmHandle = _impl.SafeAlpmHandle;
var release = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
safeAlpmHandle.DangerousAddRef(ref release);
return (int) alpm.alpm_list_count(_impl.GetItems());
}
finally
{
if (release)
safeAlpmHandle.DangerousRelease();
}
}
}
public bool IsReadOnly => false;
}
}

View File

@@ -1,4 +1,95 @@
$HEADER$namespace $NAMESPACE$
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Foodsoft.Alpm
{
public class $CLASS$ {$END$}
public sealed class Database : IDisposable
{
private readonly SafeDatabaseHandle _handle;
internal Database(SafeDatabaseHandle handle) => _handle = handle;
private readonly struct ServersAccessor : IItemsAccessor<string>
{
private readonly SafeDatabaseHandle _handle;
internal ServersAccessor(SafeDatabaseHandle handle)
{
_handle = handle;
}
public SafeAlpmHandle SafeAlpmHandle => _handle.SafeAlpmHandle;
public IntPtr GetItems() => alpm.alpm_db_get_servers(_handle);
public int SetItems(IntPtr list) => alpm.alpm_db_set_servers(_handle, list);
public int AddItem(string item) => alpm.alpm_db_add_server(_handle, item);
public int RemoveItem(string item) => alpm.alpm_db_remove_server(_handle, item);
public IntPtr FindItem(string item) => alpm.alpm_list_find_str(GetItems(), item);
public string PtrToItem(IntPtr p) => Marshal.PtrToStringUTF8(p)!;
}
public ICollection<string> Servers
{
get => new CollectionWrapper<ServersAccessor, string>(new ServersAccessor(_handle));
set
{
foreach (var s in value)
{
API.WrapError(_handle.SafeAlpmHandle, () => alpm.alpm_db_add_server(_handle, s));
}
}
}
public string Name => alpm.alpm_db_get_name(_handle);
public SigLevel SigLevel => alpm.alpm_db_get_siglevel(_handle);
public ErrNo Valid =>
alpm.alpm_db_get_valid(_handle) != 0 ? alpm.alpm_errno(_handle.SafeAlpmHandle) : ErrNo.ERR_OK;
public bool Update(bool force)
{
var err = alpm.alpm_db_update(force ? 1 : 0, _handle);
if (err < 0)
{
throw new Exception(_handle.SafeAlpmHandle);
}
return err == 0;
}
public Package? GetPackage(string name)
{
var pkgPtr = alpm.alpm_pkg_get_pkg(_handle, name);
if (pkgPtr == IntPtr.Zero)
{
var err = alpm.alpm_errno(_handle.SafeAlpmHandle);
if (err == ErrNo.ERR_PKG_NOT_FOUND)
return null;
throw new Exception(err);
}
return new CachePackage(new SafeCachePackageHandle(pkgPtr, _handle), this);
}
private readonly struct PkgCacheAccessor : IReadOnlyItemsAccessor<Package>
{
private readonly SafeDatabaseHandle _handle;
public SafeAlpmHandle SafeAlpmHandle => _handle.SafeAlpmHandle;
public IntPtr GetItems()
{
throw new NotImplementedException();
}
public Package PtrToItem(IntPtr p)
{
throw new NotImplementedException();
}
}
public void Dispose()
{
_handle.Dispose();
}
}
}

34
Depend.cs Normal file
View File

@@ -0,0 +1,34 @@
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
namespace Foodsoft.Alpm
{
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "ConvertToConstant.Local")]
public class Depend
{
public enum ModType
{
Any = 1,
Equal,
GreaterThanOrEqual,
LessThanOrEqual,
GreaterThan,
LessThan
}
[field: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public string Name { get; } = null!;
[field: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public string Version { get; } = null!;
[field: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public string Description { get; } = null!;
public ulong NameHash { get; } = 0;
public ModType Mod { get; } = ModType.Any;
}
}

View File

@@ -5,7 +5,7 @@
<TargetFramework>netcoreapp3.1</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Nullable>enable</Nullable>
<RootNamespace>nalpm</RootNamespace>
<RootNamespace>Foodsoft.Alpm</RootNamespace>
</PropertyGroup>
</Project>

View File

@@ -1,4 +1,81 @@
$HEADER$namespace $NAMESPACE$
namespace Foodsoft.Alpm
{
public enum $ENUM$ {$END$}
public enum ErrNo
{
ERR_OK = 0,
ERR_MEMORY,
ERR_SYSTEM,
ERR_BADPERMS,
ERR_NOT_A_FILE,
ERR_NOT_A_DIR,
ERR_WRONG_ARGS,
ERR_DISK_SPACE,
/* Interface */
ERR_HANDLE_NULL,
ERR_HANDLE_NOT_NULL,
ERR_HANDLE_LOCK,
/* Databases */
ERR_DB_OPEN,
ERR_DB_CREATE,
ERR_DB_NULL,
ERR_DB_NOT_NULL,
ERR_DB_NOT_FOUND,
ERR_DB_INVALID,
ERR_DB_INVALID_SIG,
ERR_DB_VERSION,
ERR_DB_WRITE,
ERR_DB_REMOVE,
/* Servers */
ERR_SERVER_BAD_URL,
ERR_SERVER_NONE,
/* Transactions */
ERR_TRANS_NOT_NULL,
ERR_TRANS_NULL,
ERR_TRANS_DUP_TARGET,
ERR_TRANS_NOT_INITIALIZED,
ERR_TRANS_NOT_PREPARED,
ERR_TRANS_ABORT,
ERR_TRANS_TYPE,
ERR_TRANS_NOT_LOCKED,
ERR_TRANS_HOOK_FAILED,
/* Packages */
ERR_PKG_NOT_FOUND,
ERR_PKG_IGNORED,
ERR_PKG_INVALID,
ERR_PKG_INVALID_CHECKSUM,
ERR_PKG_INVALID_SIG,
ERR_PKG_MISSING_SIG,
ERR_PKG_OPEN,
ERR_PKG_CANT_REMOVE,
ERR_PKG_INVALID_NAME,
ERR_PKG_INVALID_ARCH,
ERR_PKG_REPO_NOT_FOUND,
/* Signatures */
ERR_SIG_MISSING,
ERR_SIG_INVALID,
/* Dependencies */
ERR_UNSATISFIED_DEPS,
ERR_CONFLICTING_DEPS,
ERR_FILE_CONFLICTS,
/* Misc */
ERR_RETRIEVE,
ERR_INVALID_REGEX,
/* External library errors */
ERR_LIBARCHIVE,
ERR_LIBCURL,
ERR_EXTERNAL_DOWNLOAD,
ERR_GPGME,
/* Missing compile-time features */
ERR_MISSING_CAPABILITY_SIGNATURES
}
}

View File

@@ -1,4 +1,18 @@
$HEADER$namespace $NAMESPACE$
using System;
using System.Runtime.Serialization;
using Foodsoft.Alpm;
namespace Foodsoft.Alpm
{
public class $CLASS$ {$END$}
[Serializable()]
public class Exception : System.Exception
{
public Exception() { }
internal Exception(SafeAlpmHandle handle) : base(alpm.alpm_strerror(alpm.alpm_errno(handle))) { }
public Exception(ErrNo errno) : base(alpm.alpm_strerror(errno)) { }
public Exception(ErrNo errno, System.Exception inner) : base(alpm.alpm_strerror(errno), inner) { }
protected Exception(SerializationInfo info,
StreamingContext context) : base(info, context) { }
}
}

15
File.cs Normal file
View File

@@ -0,0 +1,15 @@
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
namespace Foodsoft.Alpm
{
[SuppressMessage("ReSharper", "UnassignedGetOnlyAutoProperty")]
public readonly struct File
{
[field: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public string Name { get; }
public long Size { get; }
public uint Mode { get; }
}
}

23
FileList.cs Normal file
View File

@@ -0,0 +1,23 @@
using System.Collections;
using System.Collections.Generic;
namespace Foodsoft.Alpm
{
public class FileList : IReadOnlyList<File>
{
public IEnumerator<File> GetEnumerator()
{
throw new System.NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public int Count { get; }
public File this[int index] => throw new System.NotImplementedException();
}
}

View File

@@ -1,6 +1,10 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=alpm/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=cachedir/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=cachedirs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Foodsoft/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=libalpm/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Marshaler/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=siglevel/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=strerror/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=syncdb/@EntryIndexedValue">True</s:Boolean>

View File

@@ -1,4 +1,75 @@
$HEADER$namespace $NAMESPACE$
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Foodsoft.Alpm
{
public class $CLASS$ {$END$}
public sealed class Handle : IDisposable
{
private readonly SafeAlpmHandle _handle;
public Handle(string root, string dbpath)
{
_handle = alpm.alpm_initialize(root, dbpath, out var err);
if (_handle.IsInvalid)
{
throw new Exception(err);
}
}
public void Dispose()
{
_handle.Dispose();
}
private Database ToDatabase(IntPtr ptr)
{
// It's ok that the database pointer is kept outside atomic section, because the resource is actually
// managed by the alpm handle.
if (ptr == IntPtr.Zero)
{
throw new Exception(_handle);
}
return new Database(new SafeDatabaseHandle(ptr, _handle));
}
public Database LocalDB => ToDatabase(alpm.alpm_get_localdb(_handle));
public Database RegisterSyncDB(string treename, SigLevel sigLevel) =>
ToDatabase(alpm.alpm_register_syncdb(_handle, treename, sigLevel));
private readonly struct CacheDirsAccessor : IItemsAccessor<string>
{
internal CacheDirsAccessor(SafeAlpmHandle safeAlpmHandle)
{
SafeAlpmHandle = safeAlpmHandle;
}
public SafeAlpmHandle SafeAlpmHandle { get; }
public IntPtr GetItems() => alpm.alpm_option_get_cachedirs(SafeAlpmHandle);
public int SetItems(IntPtr list) => alpm.alpm_option_set_cachedirs(SafeAlpmHandle, list);
public int AddItem(string item) => alpm.alpm_option_add_cachedir(SafeAlpmHandle, item);
public int RemoveItem(string item) => alpm.alpm_option_remove_cachedir(SafeAlpmHandle, item);
public IntPtr FindItem(string item) => alpm.alpm_list_find_str(GetItems(), item);
public string PtrToItem(IntPtr p) => Marshal.PtrToStringUTF8(p)!;
}
public ICollection<string> CacheDirs
{
get => new CollectionWrapper<CacheDirsAccessor, string>(new CacheDirsAccessor(_handle));
set
{
foreach (var s in value)
{
API.WrapError(_handle, () => alpm.alpm_option_add_cachedir(_handle, s));
}
}
}
public bool ShouldIgnorePackage(Package pkg)
{
return alpm.alpm_pkg_should_ignore(_handle, pkg.Handle) == 0;
}
}
}

View File

@@ -2,7 +2,7 @@ using System;
namespace Foodsoft.Alpm
{
internal interface IAlpmItemsAccessor<TElement>
internal interface IItemsAccessor<TElement>
{
SafeAlpmHandle SafeAlpmHandle { get; }
public IntPtr GetItems();
@@ -12,5 +12,4 @@ namespace Foodsoft.Alpm
public IntPtr FindItem(TElement item);
public TElement PtrToItem(IntPtr p);
}
}

View File

@@ -1,7 +0,0 @@
namespace Foodsoft.Alpm
{
public class IAlpmReadOnlyItemsAccessor
{
}
}

64
IPackageData.cs Normal file
View File

@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
namespace Foodsoft.Alpm
{
public enum PackageOrigin
{
File = 1,
LocalDB,
SyncDB
}
public enum InstallReason
{
Explicit = 0,
Depend = 1
}
[Flags]
public enum ValidationType
{
Unknown = 0,
None = (1 << 0),
MD5Sum = (1 << 1),
SHA256Sum = (1 << 2),
Signature = (1 << 3)
}
public interface IPackageData
{
public string Filename { get; }
public string Base { get; }
public string Name { get; }
public string Version { get; }
public PackageOrigin Origin { get; }
public string Description { get; }
public string Url { get; }
public DateTimeOffset BuildDate { get; }
public DateTimeOffset InstallDate { get; }
public string Packager { get; }
public string MD5Sum { get; }
public string SHA256Sum { get; }
public string Arch { get; }
public long Size { get; }
public long InstalledSize { get; }
public InstallReason InstallReason { get; }
public IReadOnlyCollection<string> Licenses { get; }
public IReadOnlyCollection<string> Groups { get; }
public IReadOnlyCollection<Depend> Depends { get; }
public IReadOnlyCollection<Depend> OptDepends { get; }
public IReadOnlyCollection<Depend> CheckDepends { get; }
public IReadOnlyCollection<Depend> MakeDepends { get; }
public IReadOnlyCollection<Depend> Conflicts { get; }
public IReadOnlyCollection<Depend> Provides { get; }
public IReadOnlyCollection<Depend> Replaces { get; }
public IReadOnlyList<File> FileList { get; }
public IReadOnlyList<Backup> Backup { get; }
public string Base64Signature { get; }
public ValidationType Validation { get; }
public bool HasScriptlet { get; }
public long DownloadSize { get; }
public Database? DB { get; }
}
}

View File

@@ -0,0 +1,11 @@
using System;
namespace Foodsoft.Alpm
{
internal interface IReadOnlyItemsAccessor<out TElement>
{
SafeAlpmHandle SafeAlpmHandle { get; }
public IntPtr GetItems();
public TElement PtrToItem(IntPtr p);
}
}

346
Junk.cs
View File

@@ -1,7 +1,345 @@
namespace Alpm
{
public class Junk
{
using System;
using System.Runtime.InteropServices;
namespace Foodsoft.Alpm
{
/*
* Hooks
*/
enum alpm_hook_when_t
{
HOOK_PRE_TRANSACTION = 1,
HOOK_POST_TRANSACTION
}
/*
* Logging facilities
*/
/** Logging Levels */
enum _alpm_loglevel_t
{
LOG_ERROR = 1,
LOG_WARNING = (1 << 1),
LOG_DEBUG = (1 << 2),
LOG_FUNCTION = (1 << 3)
}
/** Location a package object was loaded from. */
enum alpm_pkgfrom_t
{
PKG_FROM_FILE = 1,
PKG_FROM_LOCALDB,
PKG_FROM_SYNCDB
}
/** Method used to validate a package. */
enum alpm_pkgvalidation_t
{
PKG_VALIDATION_UNKNOWN = 0,
PKG_VALIDATION_NONE = (1 << 0),
PKG_VALIDATION_MD5SUM = (1 << 1),
PKG_VALIDATION_SHA256SUM = (1 << 2),
PKG_VALIDATION_SIGNATURE = (1 << 3)
}
/** Types of version constraints in dependency specs. */
public enum alpm_depmod_t
{
/** No version constraint */
DEP_MOD_ANY = 1,
/** Test version equality (package=x.y.z) */
DEP_MOD_EQ,
/** Test for at least a version (package>=x.y.z) */
DEP_MOD_GE,
/** Test for at most a version (package<=x.y.z) */
DEP_MOD_LE,
/** Test for greater than some version (package>x.y.z) */
DEP_MOD_GT,
/** Test for less than some version (package<x.y.z) */
DEP_MOD_LT
}
/**
* File conflict type.
* Whether the conflict results from a file existing on the filesystem, or with
* another target in the transaction.
*/
enum alpm_fileconflicttype_t
{
FILECONFLICT_TARGET = 1,
FILECONFLICT_FILESYSTEM
}
/** PGP signature verification options */
[Flags]
public enum SigLevel
{
SIG_PACKAGE = (1 << 0),
SIG_PACKAGE_OPTIONAL = (1 << 1),
SIG_PACKAGE_MARGINAL_OK = (1 << 2),
SIG_PACKAGE_UNKNOWN_OK = (1 << 3),
SIG_DATABASE = (1 << 10),
SIG_DATABASE_OPTIONAL = (1 << 11),
SIG_DATABASE_MARGINAL_OK = (1 << 12),
SIG_DATABASE_UNKNOWN_OK = (1 << 13),
SIG_USE_DEFAULT = (1 << 31)
}
/** PGP signature verification status return codes */
enum alpm_sigstatus_t
{
SIGSTATUS_VALID,
SIGSTATUS_KEY_EXPIRED,
SIGSTATUS_SIG_EXPIRED,
SIGSTATUS_KEY_UNKNOWN,
SIGSTATUS_KEY_DISABLED,
SIGSTATUS_INVALID
}
/** PGP signature verification status return codes */
enum alpm_sigvalidity_t
{
SIGVALIDITY_FULL,
SIGVALIDITY_MARGINAL,
SIGVALIDITY_NEVER,
SIGVALIDITY_UNKNOWN
}
/** Dependency */
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct alpm_depend_t
{
string name;
string version;
string desc;
public ulong name_hash;
public alpm_depmod_t mod;
}
[StructLayout(LayoutKind.Sequential)]
public struct AlpmDependPtr
{
private IntPtr ptr;
public alpm_depend_t Unmarshal()
{
return Marshal.PtrToStructure<alpm_depend_t>(ptr);
}
}
/** Missing dependency */
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct alpm_depmissing_t
{
public string target;
public AlpmDependPtr depend;
/* this is used only in the case of a remove dependency error */
public string causingpkg;
}
[StructLayout(LayoutKind.Sequential)]
/** Conflict */
public struct alpm_conflict_t
{
public ulong package1_hash;
public ulong package2_hash;
public string package1;
public string package2;
public AlpmDependPtr reason;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
/** File conflict */
struct alpm_fileconflict_t
{
public string target;
public alpm_fileconflicttype_t type;
public string file;
public string ctarget;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
/** Package group */
public readonly struct alpm_group_t
{
/** group name */
public readonly string name;
/** list of alpm_pkg_t packages */
private readonly unsafe alpm_list_t* packages;
}
/* TODO: alpm_pkg_get_files - need to wrap */
/** File in a package */
public readonly struct alpm_file_t
{
public readonly string name;
public readonly UIntPtr size;
public readonly uint mode;
}
public enum caps
{
ALPM_CAPABILITY_NLS = (1 << 0),
ALPM_CAPABILITY_DOWNLOADER = (1 << 1),
ALPM_CAPABILITY_SIGNATURES = (1 << 2)
}
/** Package filelist container */
public struct _alpm_filelist_t
{
public UIntPtr count;
private IntPtr files;
/* FIXME: This is broken as shit */
public alpm_file_t[] Unmarshal()
{
var iCount = (int) this.count;
var byteCount = Marshal.SizeOf<alpm_file_t>() * iCount;
var byteBuffer = new byte[byteCount];
Marshal.Copy(files, byteBuffer, 0, byteBuffer.Length);
var result = new alpm_file_t[iCount];
Buffer.BlockCopy(byteBuffer, 0, result, 0, byteBuffer.Length);
return result;
}
}
/** Local package or package file backup entry */
public struct _alpm_backup_t
{
string name;
string hash;
}
public class alpm_pgpkey_t
{
public byte[] data;
public string fingerprint;
public string uid;
public string name;
public string email;
public long created;
public long expires;
public uint revoked;
public char pubkey_algo;
}
public class PgpKeyInMarshaler : ICustomMarshaler
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
private class NativePgpKey
{
public IntPtr data;
public string fingerprint;
public string uid;
public string name;
public string email;
public long created;
public long expires;
public uint length;
public uint revoked;
public char pubkey_algo;
}
public void CleanUpManagedData(object ManagedObj) { }
public void CleanUpNativeData(IntPtr pNativeData) { }
public int GetNativeDataSize()
{
throw new NotImplementedException();
}
public IntPtr MarshalManagedToNative(object ManagedObj)
{
throw new NotImplementedException();
}
public object MarshalNativeToManaged(IntPtr pNativeData)
{
var raw = Marshal.PtrToStructure<NativePgpKey>(pNativeData);
var managed = new alpm_pgpkey_t()
{
data = new byte[raw.length],
fingerprint = raw.fingerprint,
uid = raw.uid,
name = raw.name,
email = raw.email,
created = raw.created,
expires = raw.expires,
revoked = raw.revoked,
pubkey_algo = raw.pubkey_algo
};
Marshal.Copy(raw.data, managed.data, 0, (int) raw.length);
return managed;
}
}
/**
* Signature result. Contains the key, status, and validity of a given
* signature.
*/
public readonly struct alpm_sigresult_t
{
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PgpKeyInMarshaler))]
readonly alpm_pgpkey_t key;
readonly alpm_sigstatus_t status;
readonly alpm_sigvalidity_t validity;
}
/**
* Signature list. Contains the number of signatures found and a pointer to an
* array of results. The array is of size count.
*/
public class SigListInMarshaler : ICustomMarshaler
{
public void CleanUpManagedData(object ManagedObj) { }
public void CleanUpNativeData(IntPtr pNativeData) { }
public int GetNativeDataSize()
{
throw new NotImplementedException();
}
public IntPtr MarshalManagedToNative(object ManagedObj)
{
throw new NotImplementedException();
}
public object MarshalNativeToManaged(IntPtr pNativeData)
{
UIntPtr count;
IntPtr data;
unsafe
{
count = *(UIntPtr*) pNativeData;
data = *(IntPtr*) (pNativeData + sizeof(UIntPtr));
}
var iCount = (int) count;
var result = new alpm_sigresult_t[iCount];
// NOTE: I expect this to fail cuz i didn't implement the above GetNativeDataSize
for (var i = 0; i < iCount; ++i, data += Marshal.SizeOf<alpm_sigresult_t>())
{
result[i] = Marshal.PtrToStructure<alpm_sigresult_t>(data);
}
return result;
}
}
}

68
Package.cs Normal file
View File

@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
namespace Foodsoft.Alpm
{
public class Package : IPackageData
{
internal SafePackageHandle Handle { get; }
internal Package(SafePackageHandle handle)
{
Handle = handle;
}
public string Filename => alpm.alpm_pkg_get_filename(Handle);
public string Base => alpm.alpm_pkg_get_base(Handle);
public string Name => alpm.alpm_pkg_get_name(Handle);
public string Version => alpm.alpm_pkg_get_version(Handle);
public PackageOrigin Origin => alpm.alpm_pkg_get_origin(Handle);
public string Description => alpm.alpm_pkg_get_desc(Handle);
public string Url => alpm.alpm_pkg_get_url(Handle);
public DateTimeOffset BuildDate => DateTimeOffset.FromUnixTimeSeconds(alpm.alpm_pkg_get_builddate(Handle));
public DateTimeOffset InstallDate => DateTimeOffset.FromUnixTimeSeconds(alpm.alpm_pkg_get_installdate(Handle));
public string Packager => alpm.alpm_pkg_get_packager(Handle);
public string MD5Sum => alpm.alpm_pkg_get_md5sum(Handle);
public string SHA256Sum => alpm.alpm_pkg_get_sha256sum(Handle);
public string Arch => alpm.alpm_pkg_get_arch(Handle);
public long Size => alpm.alpm_pkg_get_size(Handle);
public long InstalledSize => alpm.alpm_pkg_get_isize(Handle);
public InstallReason InstallReason => alpm.alpm_pkg_get_reason(Handle);
public IReadOnlyCollection<string> Licenses { get; }
public IReadOnlyCollection<string> Groups { get; }
public IReadOnlyCollection<Depend> Depends { get; }
public IReadOnlyCollection<Depend> OptDepends { get; }
public IReadOnlyCollection<Depend> CheckDepends { get; }
public IReadOnlyCollection<Depend> MakeDepends { get; }
public IReadOnlyCollection<Depend> Conflicts { get; }
public IReadOnlyCollection<Depend> Provides { get; }
public IReadOnlyCollection<Depend> Replaces { get; }
public IReadOnlyList<File> FileList { get; }
public IReadOnlyList<Backup> Backup { get; }
public string Base64Signature { get; }
public ValidationType Validation { get; }
public bool HasScriptlet { get; }
public long DownloadSize { get; }
public bool CheckMD5Sum()
{
throw new NotImplementedException();
}
public virtual Database? DB => null;
public IEnumerator<Package> ComputeRequiredBy()
{
throw new NotImplementedException();
}
public IEnumerator<Package> ComputeOptionalFor()
{
throw new NotImplementedException();
}
}
}

View File

@@ -1,24 +1,27 @@
using System;
using System.Collections.Generic;
using System.Data.Common;
using Foodsoft.Alpm;
namespace nalpm
namespace Foodsoft.Alpm
{
class Program
{
static void Main(string[] args)
{
errno_t err = errno_t.ERR_OK;
ErrNo err = ErrNo.ERR_OK;
using var h = new Handle("/", "/home/luebsj/db");
using var db = h.RegisterSyncDB("jkl-repo", SigLevel.SIG_PACKAGE_OPTIONAL | SigLevel.SIG_USE_DEFAULT);
db.Servers = new List<string> {"http://a.b.c", "http://d.e.f", "http://arch.johnluebs.com/x86_64"};
var a = new string[3];
db.Servers.CopyTo(a, 0);
Console.WriteLine("Hello World! {0} {1} {2}", db.Name, Alpm.Version(),
a[0]);
foreach (var a in db.Servers)
{
Console.WriteLine("Hello {0}", a);
}
var b = new string[3];
db.Servers.CopyTo(b, 0);
Console.WriteLine("Hello World! {0} {1} {2}", db.Name, API.Version,
b[0]);
}
}
}

View File

@@ -1,4 +1,47 @@
$HEADER$namespace $NAMESPACE$
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace Foodsoft.Alpm
{
public class $CLASS$ {$END$}
internal class ReadOnlyCollectionWrapper<TImpl, TElement> : IReadOnlyCollection<TElement> where TImpl : struct,
IReadOnlyItemsAccessor<TElement>
{
private TImpl _impl;
private SafeAlpmHandle SafeAlpmHandle => _impl.SafeAlpmHandle;
public ReadOnlyCollectionWrapper(TImpl impl)
{
_impl = impl;
}
private static unsafe IntPtr ListNext(IntPtr list) => ((alpm_list_t*) list)->next;
private static unsafe IntPtr ListData(IntPtr list) => ((alpm_list_t*) list)->data;
public IEnumerator<TElement> GetEnumerator()
{
var safeAlpmHandle = _impl.SafeAlpmHandle;
var release = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
safeAlpmHandle.DangerousAddRef(ref release);
if (!release) throw new ObjectDisposedException(_impl.GetType().FullName);
for (var list = _impl.GetItems(); list != IntPtr.Zero; list = ListNext(list))
{
yield return _impl.PtrToItem(ListData(list));
}
}
finally
{
if (release)
safeAlpmHandle.DangerousRelease();
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public int Count => (int) alpm.alpm_list_count(_impl.GetItems());
}
}

View File

@@ -1,4 +1,21 @@
$HEADER$namespace $NAMESPACE$
using System;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using Foodsoft.Alpm;
namespace Foodsoft.Alpm
{
public class $CLASS$ {$END$}
internal sealed class SafeAlpmHandle : SafeHandle
{
private SafeAlpmHandle() : base(IntPtr.Zero, true) { }
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail), PrePrepareMethod]
protected override bool ReleaseHandle() => alpm.alpm_release(handle) == 0;
public override bool IsInvalid
{
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), PrePrepareMethod]
get => handle == IntPtr.Zero;
}
}
}

52
SafeCachePackageHandle.cs Normal file
View File

@@ -0,0 +1,52 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
namespace Foodsoft.Alpm
{
internal sealed class SafeCachePackageHandle : SafePackageHandle
{
internal SafeDatabaseHandle SafeDatabaseHandle
{
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[PrePrepareMethod]
get;
} = null!;
internal SafeAlpmHandle SafeAlpmHandle => SafeDatabaseHandle.SafeAlpmHandle;
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[PrePrepareMethod]
internal SafeCachePackageHandle(IntPtr pkgPtr, SafeDatabaseHandle dbHandle)
: base()
{
var success = false;
RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally
{
dbHandle.DangerousAddRef(ref success);
if (success)
{
handle = pkgPtr;
SafeDatabaseHandle = dbHandle;
}
}
if (!success) throw new ObjectDisposedException(GetType().FullName);
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), PrePrepareMethod]
protected override bool ReleaseHandle()
{
SafeDatabaseHandle.DangerousRelease();
return true;
}
public override bool IsInvalid
{
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), PrePrepareMethod]
get => handle == IntPtr.Zero;
}
}
}

View File

@@ -1,4 +1,53 @@
$HEADER$namespace $NAMESPACE$
using System;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
namespace Foodsoft.Alpm
{
public class $CLASS$ {$END$}
internal sealed class SafeDatabaseHandle : SafeHandle
{
internal SafeAlpmHandle SafeAlpmHandle
{
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[PrePrepareMethod]
get;
} = null!; // we always throw in the constructor on failure
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[PrePrepareMethod]
internal SafeDatabaseHandle(IntPtr dbPtr, SafeAlpmHandle safeAlpmHandle)
: base(IntPtr.Zero, true)
{
var success = false;
RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally
{
safeAlpmHandle.DangerousAddRef(ref success);
if (success)
{
SafeAlpmHandle = safeAlpmHandle;
handle = dbPtr;
}
}
if (!success) throw new ObjectDisposedException(GetType().FullName);
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail), PrePrepareMethod]
protected override bool ReleaseHandle()
{
var ret = alpm.alpm_db_unregister(handle) == 0;
SafeAlpmHandle.DangerousRelease();
return ret;
}
public override bool IsInvalid
{
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), PrePrepareMethod]
get => handle == IntPtr.Zero;
}
}
}

View File

@@ -1,46 +1,49 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
namespace Foodsoft.Alpm
{
internal struct ListRef : CriticalFinalIDisposable
internal sealed class SafeListHandle : SafeHandle
{
public SafeAlpmHandle SafeAlpmHandle
{
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[PrePrepareMethod]
get;
}
} = null!;
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail), PrePrepareMethod]
public ListRef(SafeAlpmHandle handle)
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[PrePrepareMethod]
internal SafeListHandle(SafeAlpmHandle safeAlpmHandle)
: base(IntPtr.Zero, true)
{
SafeAlpmHandle = null!;
var success = false;
RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally
{
SafeAlpmHandle = handle;
var success = false;
handle.DangerousAddRef(ref success);
safeAlpmHandle.DangerousAddRef(ref success);
if (success)
SafeAlpmHandle = handle;
else
{
SafeAlpmHandle = null!;
throw new ObjectDisposedException(GetType().FullName);
}
SafeAlpmHandle = safeAlpmHandle;
}
if (!success)
throw new ObjectDisposedException(GetType().FullName);
}
~ListRef()
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), PrePrepareMethod]
protected override bool ReleaseHandle()
{
SafeAlpmHandle.DangerousRelease();
return true;
}
public void Dispose()
public override bool IsInvalid
{
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), PrePrepareMethod]
get => SafeAlpmHandle.IsInvalid;
}
}
}

20
SafePackageHandle.cs Normal file
View File

@@ -0,0 +1,20 @@
using System;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
namespace Foodsoft.Alpm
{
internal class SafePackageHandle : SafeHandle
{
protected SafePackageHandle() : base(IntPtr.Zero, true) { }
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail), PrePrepareMethod]
protected override bool ReleaseHandle() => alpm.alpm_pkg_free(handle) == 0;
public override bool IsInvalid
{
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), PrePrepareMethod]
get => handle == IntPtr.Zero;
}
}
}

View File

@@ -4,16 +4,10 @@ using System.Text;
namespace Foodsoft.Alpm
{
internal readonly struct UTF8Marshaler : ICustomMarshaler
internal readonly struct UTF8InMarshaler : ICustomMarshaler
{
private static readonly UTF8Marshaler _instance = default;
private static readonly UTF8InMarshaler _instance = default;
// ReSharper disable once UnusedMember.Local
// ReSharper disable once UnusedParameter.Local
private static ICustomMarshaler GetInstance(string cookie)
{
return _instance;
}
public void CleanUpManagedData(object managedObj) { }
@@ -42,6 +36,7 @@ namespace Foodsoft.Alpm
{
nbWritten = Encoding.UTF8.GetBytes(firstChar, s.Length, pbMem, nb);
}
pbMem[nbWritten] = 0;
return pMem;
}
@@ -50,5 +45,12 @@ namespace Foodsoft.Alpm
{
return Marshal.PtrToStringUTF8(pNativeData)!;
}
// ReSharper disable once UnusedMember.Local
// ReSharper disable once UnusedParameter.Local
private static ICustomMarshaler GetInstance(string cookie)
{
return _instance;
}
}
}

View File

@@ -1,4 +1,35 @@
$HEADER$namespace $NAMESPACE$
namespace Foodsoft.Alpm
{
public class $CLASS$ {$END$}
using System;
using System.Runtime.InteropServices;
using System.Text;
internal readonly struct UTF8OutMarshaler : ICustomMarshaler
{
private static readonly UTF8OutMarshaler _instance = default;
// ReSharper disable once UnusedMember.Local
// ReSharper disable once UnusedParameter.Local
private static ICustomMarshaler GetInstance(string cookie)
{
return _instance;
}
public void CleanUpManagedData(object managedObj) { }
public void CleanUpNativeData(IntPtr pNativeData) { }
public int GetNativeDataSize() => -1;
public object MarshalNativeToManaged(IntPtr pNativeData)
{
return Marshal.PtrToStringUTF8(pNativeData)!;
}
public IntPtr MarshalManagedToNative(object managedObj)
{
throw new NotImplementedException();
}
}
}

View File

@@ -1,7 +1,7 @@
using System;
namespace Foodsoft.Alpm
{
public class Wrapper
{
}
{ }
}

222
alpm.cs
View File

@@ -1,7 +1,225 @@
namespace Alpm
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.WindowsRuntime;
using Foodsoft.Alpm;
namespace Foodsoft.Alpm
{
public class alpm
// ReSharper disable once InconsistentNaming
[StructLayout(LayoutKind.Sequential)]
internal struct alpm_list_t
{
internal IntPtr data;
internal readonly IntPtr prev;
internal readonly IntPtr next;
}
// ReSharper disable once InconsistentNaming
internal static class alpm
{
[DllImport(nameof(alpm))]
public static extern int alpm_pkg_should_ignore(SafeAlpmHandle handle, SafePackageHandle pkg);
[DllImport(nameof(alpm))]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public static extern string alpm_pkg_get_filename(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public static extern string alpm_pkg_get_base(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public static extern string alpm_pkg_get_name(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public static extern string alpm_pkg_get_version(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
public static extern PackageOrigin alpm_pkg_get_origin(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public static extern string alpm_pkg_get_desc(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public static extern string alpm_pkg_get_url(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
public static extern long alpm_pkg_get_builddate(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
public static extern long alpm_pkg_get_installdate(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public static extern string alpm_pkg_get_packager(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public static extern string alpm_pkg_get_md5sum(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public static extern string alpm_pkg_get_sha256sum(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public static extern string alpm_pkg_get_arch(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
public static extern long alpm_pkg_get_size(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
public static extern long alpm_pkg_get_isize(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
public static extern InstallReason alpm_pkg_get_reason(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public static extern string alpm_pkg_get_licenses(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public static extern string alpm_pkg_get_groups(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public static extern string alpm_pkg_get_depends(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public static extern string alpm_pkg_get_optdepends(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public static extern string alpm_pkg_get_checkdepends(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public static extern string alpm_pkg_get_makedepends(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public static extern string alpm_pkg_get_conflicts(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public static extern string alpm_pkg_get_provides(SafePackageHandle pkg);
[DllImport(nameof(alpm))]
public static extern int alpm_pkg_set_reason(SafePackageHandle pkg, InstallReason reason);
[DllImport(nameof(alpm))]
public static extern int alpm_pkg_free(IntPtr ptr);
[DllImport(nameof(alpm))]
public static extern IntPtr alpm_option_get_cachedirs(SafeAlpmHandle handle);
[DllImport(nameof(alpm))]
public static extern int alpm_option_set_cachedirs(SafeAlpmHandle handle, IntPtr cachedirs);
[DllImport(nameof(alpm))]
public static extern int alpm_option_add_cachedir(SafeAlpmHandle handle,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8InMarshaler))] string cachedir);
[DllImport(nameof(alpm))]
public static extern int alpm_option_remove_cachedir(SafeAlpmHandle handle,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8InMarshaler))] string cachedir);
[DllImport(nameof(alpm))]
public static extern ErrNo alpm_errno(SafeAlpmHandle handle);
[DllImport(nameof(alpm))]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public static extern string alpm_strerror(ErrNo err);
[DllImport(nameof(alpm))]
public static extern IntPtr alpm_get_localdb(SafeAlpmHandle handle);
[DllImport(nameof(alpm))]
public static extern unsafe alpm_list_t* alpm_option_get_syncdbs();
[DllImport(nameof(alpm))]
public static extern IntPtr alpm_register_syncdb(SafeAlpmHandle handle, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8InMarshaler))] string treename, SigLevel sigLevel);
[DllImport(nameof(alpm))]
public static extern int alpm_db_unregister_all_syncdbs(SafeAlpmHandle handle);
[DllImport(nameof(alpm))]
public static extern unsafe alpm_list_t* alpm_list_next(alpm_list_t* list);
[DllImport(nameof(alpm))]
public static extern UIntPtr alpm_list_count(IntPtr list);
[DllImport(nameof(alpm))]
public static extern void alpm_list_free(IntPtr list);
[DllImport(nameof(alpm))]
public static extern IntPtr alpm_list_find_str(IntPtr list, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8InMarshaler))] string needle);
[DllImport(nameof(alpm))]
public static extern int alpm_unlock(Handle handle);
[DllImport(nameof(alpm))]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public static extern string alpm_version();
[DllImport(nameof(alpm))]
public static extern caps alpm_capabilities();
[DllImport(nameof(alpm))]
public static extern SafeAlpmHandle alpm_initialize(
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8InMarshaler))]
string root, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8InMarshaler))]
string dbpath, out ErrNo err);
[DllImport(nameof(alpm))]
public static extern int alpm_release(IntPtr handle);
[DllImport(nameof(alpm))]
public static extern int alpm_db_remove_server(SafeDatabaseHandle db,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8InMarshaler))]
string url);
[DllImport(nameof(alpm))]
public static extern int alpm_db_unregister(IntPtr db);
[DllImport(nameof(alpm))]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))]
public static extern string alpm_db_get_name(SafeDatabaseHandle db);
[DllImport(nameof(alpm))]
public static extern SigLevel alpm_db_get_siglevel(SafeDatabaseHandle db);
[DllImport(nameof(alpm))]
public static extern int alpm_db_get_valid(SafeDatabaseHandle db);
[DllImport(nameof(alpm))]
public static extern int alpm_db_update(int force, SafeDatabaseHandle db);
[DllImport(nameof(alpm))]
public static extern IntPtr alpm_db_get_servers(SafeDatabaseHandle db);
[DllImport(nameof(alpm))]
public static extern int alpm_db_set_servers(SafeDatabaseHandle db, IntPtr list);
[DllImport(nameof(alpm))]
public static extern int alpm_db_add_server(SafeDatabaseHandle db,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8InMarshaler))]
string url);
[DllImport(nameof(alpm))]
public static extern IntPtr alpm_pkg_get_pkg(SafeDatabaseHandle db,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8InMarshaler))]
string name);
[DllImport(nameof(alpm))]
public static extern IntPtr alpm_pkg_get_pkgcache(SafeDatabaseHandle db);
}
}