Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions doc/manual/rl-next/c-api-path-info.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
synopsis: "C API: Add store path metadata accessors"
prs: [15675]
---

The C API now includes functions for querying store path metadata:

- `nix_store_query_path_info()` - Query metadata for a store path
- `nix_path_info_get_nar_hash()` - Get the NAR hash
- `nix_path_info_get_nar_size()` - Get the NAR size
- `nix_path_info_get_references()` - Iterate over references
- `nix_path_info_get_deriver()` - Get the deriver
- `nix_path_info_get_sigs()` - Iterate over signatures
- `nix_path_info_get_ca()` - Get the content address
- `nix_path_info_free()` - Free store path metadata
1 change: 1 addition & 0 deletions src/libstore-c/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ include_dirs = [ include_directories('.') ]
headers = files(
'nix_api_store.h',
'nix_api_store/derivation.h',
'nix_api_store/path_info.h',
'nix_api_store/store_path.h',
)

Expand Down
109 changes: 109 additions & 0 deletions src/libstore-c/nix_api_store.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "nix/util/base-nix-32.hh"

#include "nix/store/globals.hh"
#include "nix/store/content-address.hh"

extern "C" {

Expand Down Expand Up @@ -381,4 +382,112 @@ nix_err nix_store_copy_path(
NIXC_CATCH_ERRS
}

nix_path_info * nix_store_query_path_info(nix_c_context * context, Store * store, const StorePath * path)
{
if (context)
context->last_err_code = NIX_OK;
try {
auto info = store->ptr->queryPathInfo(path->path);
return new nix_path_info{info};
}
NIXC_CATCH_ERRS_NULL
}

void nix_path_info_free(nix_path_info * path_info)
{
delete path_info;
}

nix_err nix_path_info_get_nar_hash(
nix_c_context * context, const nix_path_info * path_info, nix_get_string_callback callback, void * user_data)
{
if (context)
context->last_err_code = NIX_OK;
try {
auto res = path_info->info->narHash.to_string(nix::HashFormat::Nix32, true);
return call_nix_get_string_callback(res, callback, user_data);
}
NIXC_CATCH_ERRS
}

uint64_t nix_path_info_get_nar_size(nix_c_context * context, const nix_path_info * path_info)
{
if (context)
context->last_err_code = NIX_OK;
try {
return path_info->info->narSize;
}
NIXC_CATCH_ERRS_RES(0);
}

nix_err nix_path_info_get_references(
nix_c_context * context,
const nix_path_info * path_info,
void * user_data,
void (*callback)(nix_c_context * context, void * user_data, const StorePath * store_path))
{
if (context)
context->last_err_code = NIX_OK;
try {
if (callback) {
for (const auto & ref : path_info->info->references) {
const StorePath tmp{ref};
callback(context, user_data, &tmp);
if (context && context->last_err_code != NIX_OK)
return context->last_err_code;
}
}
}
NIXC_CATCH_ERRS
}

StorePath * nix_path_info_get_deriver(nix_c_context * context, const nix_path_info * path_info)
{
if (context)
context->last_err_code = NIX_OK;
try {
if (path_info->info->deriver)
return new StorePath{*path_info->info->deriver};
return nullptr;
}
NIXC_CATCH_ERRS_NULL
}

nix_err nix_path_info_get_sigs(
nix_c_context * context,
const nix_path_info * path_info,
void * user_data,
void (*callback)(nix_c_context * context, void * user_data, const char * sig, unsigned int sig_len))
{
if (context)
context->last_err_code = NIX_OK;
try {
if (callback) {
for (const auto & sig : path_info->info->sigs) {
auto s = sig.to_string();
callback(context, user_data, s.data(), s.size());
if (context && context->last_err_code != NIX_OK)
return context->last_err_code;
}
}
}
NIXC_CATCH_ERRS
}

nix_err nix_path_info_get_ca(
nix_c_context * context, const nix_path_info * path_info, nix_get_string_callback callback, void * user_data)
{
if (context)
context->last_err_code = NIX_OK;
try {
if (!path_info->info->ca)
return nix_set_err_msg(context, NIX_ERR_KEY, "Store path is not content-addressed");
if (callback) {
auto res = renderContentAddress(*path_info->info->ca);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
auto res = renderContentAddress(*path_info->info->ca);
auto res = path_info->info->ca->render();

known to be not false a few lines above.

return call_nix_get_string_callback(res, callback, user_data);
}
}
NIXC_CATCH_ERRS
}

} // extern "C"
14 changes: 14 additions & 0 deletions src/libstore-c/nix_api_store.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "nix_api_util.h"
#include "nix_api_store/store_path.h"
#include "nix_api_store/derivation.h"
#include "nix_api_store/path_info.h"
#include <stdbool.h>

#ifdef __cplusplus
Expand Down Expand Up @@ -283,6 +284,19 @@ StorePath * nix_store_query_path_from_hash_part(nix_c_context * context, Store *
nix_err nix_store_copy_path(
nix_c_context * context, Store * srcStore, Store * dstStore, const StorePath * path, bool repair, bool checkSigs);

/**
* @brief Query metadata about a store path
*
* The path must be valid in the store; otherwise an error is returned.
*
* @note Don't forget to free this with nix_path_info_free()!
* @param[out] context Optional, stores error information
* @param[in] store Nix store reference
* @param[in] path The store path to query
* @return owned nix_path_info, NULL on error
*/
nix_path_info * nix_store_query_path_info(nix_c_context * context, Store * store, const StorePath * path);

// cffi end
#ifdef __cplusplus
}
Expand Down
141 changes: 141 additions & 0 deletions src/libstore-c/nix_api_store/path_info.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#ifndef NIX_API_STORE_PATH_INFO_H
#define NIX_API_STORE_PATH_INFO_H
/**
* @defgroup libstore_pathinfo PathInfo
* @ingroup libstore
* @brief Store path metadata
* @{
*/
/** @file
* @brief Path info operations for querying store object metadata
*/

#include <stdint.h>

#include "nix_api_util.h"
#include "nix_api_store/store_path.h"

#ifdef __cplusplus
extern "C" {
#endif
// cffi start

/** @brief Opaque handle to store path metadata */
typedef struct nix_path_info nix_path_info;

/**
* @brief Deallocate a nix_path_info
*
* Does not fail.
* @param[in] path_info the nix_path_info to free
*/
void nix_path_info_free(nix_path_info * path_info);

/**
* @brief Get the NAR hash of a store path
*
* Returns the hash as a string with algorithm prefix in Nix base-32 encoding,
* e.g. "sha256:1b8m03r63zqhnjf7l5nh...". This is the format used in narinfo files.
*
* @param[out] context Optional, stores error information
* @param[in] path_info the nix_path_info to read from
* @param[in] callback called with the hash string
* @param[in] user_data arbitrary data, passed to the callback when it's called
* @return NIX_OK on success, error code on failure
*/
nix_err nix_path_info_get_nar_hash(
nix_c_context * context, const nix_path_info * path_info, nix_get_string_callback callback, void * user_data);

/**
* @brief Get the NAR size of a store path
*
* @param[out] context Optional, stores error information
* @param[in] path_info the nix_path_info to read from
* @return NAR size in bytes, 0 on error. Note that a NAR always has a root object,
* so an actual NAR stream is never empty.
*/
uint64_t nix_path_info_get_nar_size(nix_c_context * context, const nix_path_info * path_info);

/**
* @brief Iterate over the references of a store path
*
* Calls the callback once for each reference. The StorePath passed to the
* callback is borrowed and only valid for the duration of the callback.
* Iteration stops if the callback returns with `context` in an error state.
*
* @param[out] context Optional, stores error information
* @param[in] path_info the nix_path_info to read from
* @param[in] user_data arbitrary data, passed to the callback
* @param[in] callback called for each referenced store path
* @return NIX_OK on success, error code on failure
*/
nix_err nix_path_info_get_references(
nix_c_context * context,
const nix_path_info * path_info,
void * user_data,
void (*callback)(nix_c_context * context, void * user_data, const StorePath * store_path));

/**
* @brief Get the deriver of a store path
*
* @note Don't forget to free the result with nix_store_path_free()!
* @param[out] context Optional, stores error information
* @param[in] path_info the nix_path_info to read from
* @return owned StorePath of the deriver, or NULL if no deriver is known
*/
StorePath * nix_path_info_get_deriver(nix_c_context * context, const nix_path_info * path_info);

/**
* @brief Iterate over the signatures of a store path
*
* Calls the callback once for each signature string (format: "keyName:base64sig").
* The `sig` data is borrowed and the callback must not assume that the buffer
* persists after it returns.
*
* Iteration stops if the callback returns with `context` in an error state.
*
* @param[out] context Optional, stores error information
* @param[in] path_info the nix_path_info to read from
* @param[in] user_data arbitrary data, passed to the callback
* @param[in] callback called for each signature string
* @return NIX_OK on success, error code on failure
*/
nix_err nix_path_info_get_sigs(
nix_c_context * context,
const nix_path_info * path_info,
void * user_data,
void (*callback)(nix_c_context * context, void * user_data, const char * sig, unsigned int sig_len));

/**
* @brief Get the content address of a store path, if it has one
*
* If so, "returns" the hash as a string with method and algorithm prefix in Nix base-32 encoding,
* e.g. `"fixed:r:sha256:1i89icvvs2f3cym00414i3bbl1qidhg0b5yrmdlx9cjkj5is6ljg"`.
*
* If the store object referenced by `path_info` is not content-addressed,
* the return code is `NIX_ERR_KEY`, and the callback is not called.
*
* `NIX_ERR_KEY` is only returned when `path_info` is not content-addressed.
*
* Input-addressed store paths have a content hash (see `nix_path_info_get_nar_hash`,
* but no content *address*, so that results in NIX_ERR_KEY, distinguishable from
* other, perhaps more unexpected errors.
*
* @param[out] context Optional, stores error information
* @param[in] path_info the nix_path_info to read from
* @param[in] callback called with the content address string (only called when present)
* @param[in] user_data arbitrary data, passed to the callback when it's called
* @return NIX_OK on success, NIX_ERR_KEY if the path is not content-addressed,
* another error code on failure
*/
nix_err nix_path_info_get_ca(
nix_c_context * context, const nix_path_info * path_info, nix_get_string_callback callback, void * user_data);

// cffi end
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif // NIX_API_STORE_PATH_INFO_H
6 changes: 6 additions & 0 deletions src/libstore-c/nix_api_store_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define NIX_API_STORE_INTERNAL_H
#include "nix/store/store-api.hh"
#include "nix/store/derivations.hh"
#include "nix/store/path-info.hh"

extern "C" {

Expand All @@ -20,6 +21,11 @@ struct nix_derivation
nix::Derivation drv;
};

struct nix_path_info
{
nix::ref<const nix::ValidPathInfo> info;
};

} // extern "C"

#endif
Loading
Loading