pacutils-mtree(3)

πŸ“¦ version 0.15.0, in arch rolling

πŸ’… pacutils-mtree πŸ’…

okay so bestie, welcome to the pacutils-mtree(3) page β€” that's the manual section 3, library-call vibes, and yes it's from pacutils, the whole thing is dated 2025-12-04 and we'll get to that at the very end, promise 🫢


✨ NAME ✨

pacutils-mtree β€” read mtree data for installed packages 🌸

Literally what it says: you want the mtree info for stuff that's already installed on your system, this is the girl for the job.


πŸŽ€ SYNOPSIS πŸŽ€

First, the include, because you gotta:

#include <pacutils/mtree.h>

Then the entry struct, and listen, this is the main character struct, memorize her:

typedef struct pu_mtree_t {
  char *path;
  char *type;
  uid_t uid;
  gid_t gid;
  mode_t mode;
  off_t size;
  char *md5digest;
  char *sha256digest;
} pu_mtree_t;

Then the reader struct (she's the one doing the actual reading):

typedef struct {
  FILE *stream;
  int eof;
  pu_mtree_t defaults;
} pu_mtree_reader_t;

And the functions, all five plus the deprecated one πŸ’€

pu_mtree_reader_t *pu_mtree_reader_open_stream(FILE *stream);
pu_mtree_reader_t *pu_mtree_reader_open_package(alpm_handle_t *h, alpm_pkg_t *p);
pu_mtree_t *pu_mtree_reader_next(pu_mtree_reader_t *reader, pu_mtree_t *dest);
void pu_mtree_reader_free(pu_mtree_reader_t *reader);
void pu_mtree_free(pu_mtree_t *mtree);

/* deprecated */
alpm_list_t *pu_mtree_load_pkg_mtree(alpm_handle_t *handle, alpm_pkg_t *pkg);

πŸ¦‹ DESCRIPTION πŸ¦‹

okay so the whole point of these package mtree reading functions is that they fill gaps in libarchive's mtree reader β€” most notably "md5digest" and "sha256digest", which libarchive is currently not reading at all. not me pointing fingers but πŸ‘€

⚠️ real talk: support here is incomplete β€” this is only meant to supplement libalpm's native mtree reader, not replace it. do not treat this like a full reimplementation, bestie, it is not.

Now the functions one by one:

  • pu_mtree_reader_t *pu_mtree_reader_open_stream(FILE *stream); β€” opens a file stream for parsing. that's it, that's the whole job. πŸŽ€
  • pu_mtree_reader_t *pu_mtree_reader_open_package(alpm_handle_t *h, alpm_pkg_t *p); β€” opens an installed package's mtree file for parsing. heads up though: results are undefined if "p" is not a locally installed package. so like, don't do that. lowkey important. πŸ’€
  • pu_mtree_t *pu_mtree_reader_next(pu_mtree_reader_t *reader, pu_mtree_t *dest); β€” reads and returns the next entry in the mtree file. here's the cute part: if "dest" is "NULL", a brand new "pu_mtree_t" object gets allocated and you (the caller) are responsible for freeing it. otherwise "dest" gets filled with the parsed data. internally allocated memory is automatically freed as needed, so you don't have to stress about that part. 🫢
  • void pu_mtree_free(pu_mtree_t *mtree); β€” frees a "pu_mtree_t" struct. scrub the entry, she's done. ✨
  • void pu_mtree_reader_free(pu_mtree_reader_t *reader); β€” frees a "pu_mtree_reader_t" object. bye reader bestie 🌈
  • alpm_list_t *pu_mtree_load_pkg_mtree(alpm_handle_t *handle, alpm_pkg_t *pkg); β€” returns a list of mtree entries for "pkg". DEPRECATED: use "pu_mtree_reader_open_package" instead. she's iconic but she's retired, periodt πŸ’…

🌟 EXAMPLES 🌟

the classic demo: print file md5sums for a package. here's the whole thing verbatim so you can just copy-paste and slay:

     pu_mtree_t *m;
     pu_mtree_reader_t *r;

     if((r = pu_mtree_reader_open_package(handle, pkg)) == NULL) {
         fprintf(stderr, "error: unable to load mtree data for '%s'\n",
            alpm_pkg_get_name(pkg));
         return;
     }

     while((m = pu_mtree_reader_next(r, NULL))) {
         const char *md5 = m->md5digest;
         printf("%s: %s\n", m->path,
             md5 && md5[0] != '\0' ? md5 : "(no md5sum provided)");
         pu_mtree_free(m);
     }
     if(!reader->eof) {
         fprintf(stderr, "error: unable to read mtree data for '%s'\n",
            alpm_pkg_get_name(pkg));
     }

     pu_mtree_reader_free(r);

a few things worth noticing, since we're here:

  • the NULL passed as dest in pu_mtree_reader_next(r, NULL) β€” that's the allocate-a-new-one path, which is exactly why every loop iteration also calls pu_mtree_free(m). no leaks, we're responsible queens πŸ‘‘
  • the ternary on md5 checks md5 && md5[0] != '\0' before printing, and falls back to "(no md5sum provided)" β€” so an empty digest doesn't get printed as a mystery blank.
  • after the loop, if(!reader->eof) is the vibe check on whether reading actually finished cleanly β€” if not, it yells at stderr and you know something went wrong. πŸ’€

and finally pu_mtree_reader_free(r) to clean up the reader itself.


πŸ’œ SEE ALSO πŸ’œ

go read these next, iykyk:

  • alpm_pkg_mtree_open(3)
  • alpm_pkg_mtree_next(3)
  • alpm_pkg_mtree_close(3)
  • mtree(5) β€” this one is literally the description of "pu_mtree_t" members, so if you were confused about a field, that's your girl πŸŽ€

okay that's the whole page, you ate that πŸ’… one last thing: this was pacutils-mtree(3), section 3 of the manual, from pacutils, version-dated 2025-12-04 β€” go forth and read those mtree files, bestie, you've got this 🌈✨🫢

πŸ“¦ where this page comes from