forked from vieter-v/vieter
Moved archive read code into pkg.v
parent
d538e25da3
commit
1f8f16fe8d
|
@ -1,55 +0,0 @@
|
|||
module archive
|
||||
|
||||
import os
|
||||
|
||||
// Returns the .PKGINFO file's contents & the list of files.
|
||||
pub fn pkg_info(pkg_path string) ?(string, []string) {
|
||||
if !os.is_file(pkg_path) {
|
||||
return error("'$pkg_path' doesn't exist or isn't a file.")
|
||||
}
|
||||
|
||||
a := C.archive_read_new()
|
||||
entry := C.archive_entry_new()
|
||||
mut r := 0
|
||||
|
||||
// Sinds 2020, all newly built Arch packages use zstd
|
||||
C.archive_read_support_filter_zstd(a)
|
||||
// The content should always be a tarball
|
||||
C.archive_read_support_format_tar(a)
|
||||
|
||||
// TODO find out where does this 10240 come from
|
||||
r = C.archive_read_open_filename(a, &char(pkg_path.str), 10240)
|
||||
defer {
|
||||
C.archive_read_free(a)
|
||||
}
|
||||
|
||||
if r != C.ARCHIVE_OK {
|
||||
return error('Failed to open package.')
|
||||
}
|
||||
|
||||
// We iterate over every header in search of the .PKGINFO one
|
||||
mut buf := voidptr(0)
|
||||
mut files := []string{}
|
||||
for C.archive_read_next_header(a, &entry) == C.ARCHIVE_OK {
|
||||
pathname := C.archive_entry_pathname(entry)
|
||||
|
||||
ignored_names := [c'.BUILDINFO', c'.INSTALL', c'.MTREE', c'.PKGINFO', c'.CHANGELOG']
|
||||
if ignored_names.all(C.strcmp(it, pathname) != 0) {
|
||||
unsafe {
|
||||
files << cstring_to_vstring(pathname)
|
||||
}
|
||||
}
|
||||
|
||||
if C.strcmp(pathname, c'.PKGINFO') == 0 {
|
||||
size := C.archive_entry_size(entry)
|
||||
|
||||
// TODO can this unsafe block be avoided?
|
||||
buf = unsafe { malloc(size) }
|
||||
C.archive_read_data(a, voidptr(buf), size)
|
||||
} else {
|
||||
C.archive_read_data_skip(a)
|
||||
}
|
||||
}
|
||||
|
||||
return unsafe { cstring_to_vstring(&char(buf)) }, files
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
module archive
|
||||
|
||||
#flag -larchive
|
||||
|
||||
#include "archive.h"
|
||||
|
||||
struct C.archive {}
|
||||
|
||||
// Create a new archive struct
|
||||
fn C.archive_read_new() &C.archive
|
||||
|
||||
// Configure the archive to work with zstd compression
|
||||
fn C.archive_read_support_filter_zstd(&C.archive)
|
||||
|
||||
// Configure the archive to work with a tarball content
|
||||
fn C.archive_read_support_format_tar(&C.archive)
|
||||
|
||||
// Open an archive for reading
|
||||
fn C.archive_read_open_filename(&C.archive, &char, int) int
|
||||
|
||||
// Go to next entry header in archive
|
||||
fn C.archive_read_next_header(&C.archive, &&C.archive_entry) int
|
||||
|
||||
// Skip reading the current entry
|
||||
fn C.archive_read_data_skip(&C.archive)
|
||||
|
||||
// Free an archive
|
||||
fn C.archive_read_free(&C.archive) int
|
||||
|
||||
// Read an archive entry's contents into a pointer
|
||||
fn C.archive_read_data(&C.archive, voidptr, int)
|
||||
|
||||
#include "archive_entry.h"
|
||||
|
||||
struct C.archive_entry {}
|
||||
|
||||
// Create a new archive_entry struct
|
||||
fn C.archive_entry_new() &C.archive_entry
|
||||
|
||||
// Get the filename of the given entry
|
||||
fn C.archive_entry_pathname(&C.archive_entry) &char
|
||||
|
||||
// Get an entry's file size
|
||||
// Note: this function actually returns an i64, but as this can't be used as an arugment to malloc, we'll just roll with it & assume an entry is never bigger than 4 gigs
|
||||
fn C.archive_entry_size(&C.archive_entry) int
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// Compare two C strings; 0 means they're equal
|
||||
fn C.strcmp(&char, &char) int
|
105
src/pkg.v
105
src/pkg.v
|
@ -1,14 +1,65 @@
|
|||
module pkg
|
||||
|
||||
import archive
|
||||
import time
|
||||
import os
|
||||
|
||||
#flag -larchive
|
||||
|
||||
#include "archive.h"
|
||||
|
||||
struct C.archive {}
|
||||
|
||||
// Create a new archive struct
|
||||
fn C.archive_read_new() &C.archive
|
||||
|
||||
// Configure the archive to work with zstd compression
|
||||
fn C.archive_read_support_filter_zstd(&C.archive)
|
||||
|
||||
// Configure the archive to work with a tarball content
|
||||
fn C.archive_read_support_format_tar(&C.archive)
|
||||
|
||||
// Open an archive for reading
|
||||
fn C.archive_read_open_filename(&C.archive, &char, int) int
|
||||
|
||||
// Go to next entry header in archive
|
||||
fn C.archive_read_next_header(&C.archive, &&C.archive_entry) int
|
||||
|
||||
// Skip reading the current entry
|
||||
fn C.archive_read_data_skip(&C.archive)
|
||||
|
||||
// Free an archive
|
||||
fn C.archive_read_free(&C.archive) int
|
||||
|
||||
// Read an archive entry's contents into a pointer
|
||||
fn C.archive_read_data(&C.archive, voidptr, int)
|
||||
|
||||
#include "archive_entry.h"
|
||||
|
||||
struct C.archive_entry {}
|
||||
|
||||
// Create a new archive_entry struct
|
||||
fn C.archive_entry_new() &C.archive_entry
|
||||
|
||||
// Get the filename of the given entry
|
||||
fn C.archive_entry_pathname(&C.archive_entry) &char
|
||||
|
||||
// Get an entry's file size
|
||||
// Note: this function actually returns an i64, but as this can't be used as an arugment to malloc, we'll just roll with it & assume an entry is never bigger than 4 gigs
|
||||
fn C.archive_entry_size(&C.archive_entry) int
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// Compare two C strings; 0 means they're equal
|
||||
fn C.strcmp(&char, &char) int
|
||||
|
||||
// Represents a read archive
|
||||
struct Pkg {
|
||||
pub:
|
||||
info PkgInfo [required]
|
||||
files []string [required]
|
||||
}
|
||||
|
||||
// Represents the contents of a .PKGINFO file
|
||||
struct PkgInfo {
|
||||
mut:
|
||||
// Single values
|
||||
|
@ -89,9 +140,57 @@ fn parse_pkg_info_string(pkg_info_str &string) ?PkgInfo {
|
|||
return pkg_info
|
||||
}
|
||||
|
||||
// Extracts the file list & .PKGINFO contents from an archive
|
||||
// NOTE: this command currently only supports zstd-compressed tarballs
|
||||
pub fn read_pkg(pkg_path string) ?Pkg {
|
||||
pkg_info_str, files := archive.pkg_info(pkg_path) ?
|
||||
pkg_info := parse_pkg_info_string(pkg_info_str) ?
|
||||
if !os.is_file(pkg_path) {
|
||||
return error("'$pkg_path' doesn't exist or isn't a file.")
|
||||
}
|
||||
|
||||
a := C.archive_read_new()
|
||||
entry := C.archive_entry_new()
|
||||
mut r := 0
|
||||
|
||||
// Sinds 2020, all newly built Arch packages use zstd
|
||||
C.archive_read_support_filter_zstd(a)
|
||||
// The content should always be a tarball
|
||||
C.archive_read_support_format_tar(a)
|
||||
|
||||
// TODO find out where does this 10240 come from
|
||||
r = C.archive_read_open_filename(a, &char(pkg_path.str), 10240)
|
||||
defer {
|
||||
C.archive_read_free(a)
|
||||
}
|
||||
|
||||
if r != C.ARCHIVE_OK {
|
||||
return error('Failed to open package.')
|
||||
}
|
||||
|
||||
// We iterate over every header in search of the .PKGINFO one
|
||||
mut buf := voidptr(0)
|
||||
mut files := []string{}
|
||||
for C.archive_read_next_header(a, &entry) == C.ARCHIVE_OK {
|
||||
pathname := C.archive_entry_pathname(entry)
|
||||
|
||||
ignored_names := [c'.BUILDINFO', c'.INSTALL', c'.MTREE', c'.PKGINFO', c'.CHANGELOG']
|
||||
if ignored_names.all(C.strcmp(it, pathname) != 0) {
|
||||
unsafe {
|
||||
files << cstring_to_vstring(pathname)
|
||||
}
|
||||
}
|
||||
|
||||
if C.strcmp(pathname, c'.PKGINFO') == 0 {
|
||||
size := C.archive_entry_size(entry)
|
||||
|
||||
// TODO can this unsafe block be avoided?
|
||||
buf = unsafe { malloc(size) }
|
||||
C.archive_read_data(a, voidptr(buf), size)
|
||||
} else {
|
||||
C.archive_read_data_skip(a)
|
||||
}
|
||||
}
|
||||
|
||||
pkg_info := parse_pkg_info_string(unsafe { cstring_to_vstring(&char(buf)) }) ?
|
||||
|
||||
return Pkg{
|
||||
info: pkg_info
|
||||
|
|
Loading…
Reference in New Issue