From e681715c31142961b2500d78b4ab50e4311ac921 Mon Sep 17 00:00:00 2001 From: "John K. Luebs" Date: Sun, 26 Apr 2020 20:26:29 -0400 Subject: [PATCH] initial --- .gitignore | 2 + .idea/.idea.nalpm.dir/.idea/.gitignore | 13 + .../.idea.nalpm.dir/.idea/.idea.nalpm.dir.iml | 8 + .idea/.idea.nalpm.dir/.idea/encodings.xml | 4 + .idea/.idea.nalpm.dir/.idea/indexLayout.xml | 8 + .idea/.idea.nalpm.dir/.idea/misc.xml | 6 + .idea/.idea.nalpm.dir/.idea/vcs.xml | 6 + .idea/.idea.nalpm.dir/riderModule.iml | 7 + Alpm.cs | 963 ++++++++++++++++++ Folder.DotSettings | 8 + Program.cs | 24 + nalpm.csproj | 10 + 12 files changed, 1059 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.idea.nalpm.dir/.idea/.gitignore create mode 100644 .idea/.idea.nalpm.dir/.idea/.idea.nalpm.dir.iml create mode 100644 .idea/.idea.nalpm.dir/.idea/encodings.xml create mode 100644 .idea/.idea.nalpm.dir/.idea/indexLayout.xml create mode 100644 .idea/.idea.nalpm.dir/.idea/misc.xml create mode 100644 .idea/.idea.nalpm.dir/.idea/vcs.xml create mode 100644 .idea/.idea.nalpm.dir/riderModule.iml create mode 100644 Alpm.cs create mode 100644 Folder.DotSettings create mode 100644 Program.cs create mode 100644 nalpm.csproj diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4ded7c4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/obj/ diff --git a/.idea/.idea.nalpm.dir/.idea/.gitignore b/.idea/.idea.nalpm.dir/.idea/.gitignore new file mode 100644 index 0000000..087e243 --- /dev/null +++ b/.idea/.idea.nalpm.dir/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/modules.xml +/contentModel.xml +/projectSettingsUpdater.xml +/.idea.nalpm.iml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/.idea.nalpm.dir/.idea/.idea.nalpm.dir.iml b/.idea/.idea.nalpm.dir/.idea/.idea.nalpm.dir.iml new file mode 100644 index 0000000..e6bc2ca --- /dev/null +++ b/.idea/.idea.nalpm.dir/.idea/.idea.nalpm.dir.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.nalpm.dir/.idea/encodings.xml b/.idea/.idea.nalpm.dir/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/.idea/.idea.nalpm.dir/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.nalpm.dir/.idea/indexLayout.xml b/.idea/.idea.nalpm.dir/.idea/indexLayout.xml new file mode 100644 index 0000000..27ba142 --- /dev/null +++ b/.idea/.idea.nalpm.dir/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.nalpm.dir/.idea/misc.xml b/.idea/.idea.nalpm.dir/.idea/misc.xml new file mode 100644 index 0000000..28a804d --- /dev/null +++ b/.idea/.idea.nalpm.dir/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/.idea.nalpm.dir/.idea/vcs.xml b/.idea/.idea.nalpm.dir/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/.idea/.idea.nalpm.dir/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/.idea.nalpm.dir/riderModule.iml b/.idea/.idea.nalpm.dir/riderModule.iml new file mode 100644 index 0000000..1a4e0d9 --- /dev/null +++ b/.idea/.idea.nalpm.dir/riderModule.iml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Alpm.cs b/Alpm.cs new file mode 100644 index 0000000..b956b06 --- /dev/null +++ b/Alpm.cs @@ -0,0 +1,963 @@ +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 +// ReSharper disable UnusedMember.Global + +// ReSharper disable InconsistentNaming + +namespace nalpm +{ + public enum errno_t + { + 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 + } + + /** Package install reasons. */ + enum alpm_pkgreason_t + { + /** Explicitly requested by the user. */ + PKG_REASON_EXPLICIT = 0, + + /** Installed as a dependency for another package. */ + PKG_REASON_DEPEND = 1 + } + + + /** 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(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 */ + public 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; + } + + /** 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() * 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(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()) + { + result[i] = Marshal.PtrToStructure(data); + } + + return result; + } + } + + +/* + * 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) + } + + [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 + { + 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_t.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 + { + 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 : ICollection where TImpl : IAlpmItemsAccessor, + ICollection + { + private TImpl _impl; + + public CollectionWrapper(TImpl impl) + { + _impl = impl; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return (IEnumerator) GetEnumerator(); + } + + public IEnumerator GetEnumerator() + { + var result = new List(); + 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 + { + private readonly SafeAlpmHandle _handle; + + public CacheDirCollection(SafeAlpmHandle handle) + { + _handle = handle; + } + + public IEnumerator GetEnumerator() + { + var result = new List(); + 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 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_t errno) : base(Alpm.StrError(errno)) { } + public Exception(errno_t 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 + { + private readonly SafeAlpmHandle _handle; + private readonly DatabaseHandle _db; + + public ServerCollection(SafeAlpmHandle handle, DatabaseHandle db) + { + _handle = handle; + _db = db; + } + + public IEnumerator GetEnumerator() + { + var result = new List(); + 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 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_t Valid => alpm.alpm_db_get_valid(_db) != 0 ? alpm.alpm_errno(_handle) : errno_t.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_t alpm_errno(SafeAlpmHandle handle); + + [DllImport(nameof(alpm))] + public static extern IntPtr alpm_strerror(errno_t 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_t 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_t err) + { + return Marshal.PtrToStringUTF8(alpm.alpm_strerror(err)); + } + + internal static void ErrWrap(SafeAlpmHandle h, Func f) + { + var err = f(); + if (err != 0) + { + throw new Exception(alpm.alpm_errno(h)); + } + } + } +} \ No newline at end of file diff --git a/Folder.DotSettings b/Folder.DotSettings new file mode 100644 index 0000000..1639e72 --- /dev/null +++ b/Folder.DotSettings @@ -0,0 +1,8 @@ + + True + True + True + True + True + True + True \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..e3df67f --- /dev/null +++ b/Program.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Data.Common; + +namespace nalpm +{ + class Program + { + static void Main(string[] args) + { + errno_t err = errno_t.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 {"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]); + + } + } +} diff --git a/nalpm.csproj b/nalpm.csproj new file mode 100644 index 0000000..e76d8c2 --- /dev/null +++ b/nalpm.csproj @@ -0,0 +1,10 @@ + + + + Exe + netcoreapp3.1 + true + enable + + +