summaryrefslogtreecommitdiff
path: root/src/libostree/ostree-repo-private.h
blob: daec289c461909b77983651df3f1a860ec5adeab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
/*
 * Copyright (C) 2011,2013 Colin Walters <walters@verbum.org>
 *
 * SPDX-License-Identifier: LGPL-2.0+
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#pragma once

#include <sys/statvfs.h>
#include "config.h"
#include "otutil.h"
#include "ostree-ref.h"
#include "ostree-repo.h"
#include "ostree-remote-private.h"

G_BEGIN_DECLS

#define OSTREE_DELTAPART_VERSION (0)

#define _OSTREE_SUMMARY_CACHE_DIR "summaries"
#define _OSTREE_CACHE_DIR "cache"

#define _OSTREE_MAX_OUTSTANDING_FETCHER_REQUESTS 8
#define _OSTREE_MAX_OUTSTANDING_DELTAPART_REQUESTS 2

/* We want some parallelism with disk writes, but we also
 * want to avoid starting tens or hundreds of threads
 * (via GTask) all writing to disk.  Eventually we may
 * use io_uring which handles backpressure correctly.
 * Also, in "immediate fsync" mode, this helps provide
 * much more backpressure, helping our I/O patterns
 * be nicer for any concurrent processes, such as etcd
 * or other databases.
 * https://github.com/openshift/machine-config-operator/issues/1897
 * */
#define _OSTREE_MAX_OUTSTANDING_WRITE_REQUESTS 3

/* Well-known keys for the additional metadata field in a summary file. */
#define OSTREE_SUMMARY_LAST_MODIFIED "ostree.summary.last-modified"
#define OSTREE_SUMMARY_EXPIRES "ostree.summary.expires"
#define OSTREE_SUMMARY_COLLECTION_ID "ostree.summary.collection-id"
#define OSTREE_SUMMARY_COLLECTION_MAP "ostree.summary.collection-map"
#define OSTREE_SUMMARY_MODE "ostree.summary.mode"
#define OSTREE_SUMMARY_TOMBSTONE_COMMITS "ostree.summary.tombstone-commits"
#define OSTREE_SUMMARY_INDEXED_DELTAS "ostree.summary.indexed-deltas"

#define _OSTREE_PAYLOAD_LINK_PREFIX "../"
#define _OSTREE_PAYLOAD_LINK_PREFIX_LEN (sizeof (_OSTREE_PAYLOAD_LINK_PREFIX) - 1)

/* Well-known keys for the additional metadata field in a commit in a ref entry
 * in a summary file. */
#define OSTREE_COMMIT_TIMESTAMP "ostree.commit.timestamp"

typedef enum {
  OSTREE_REPO_TEST_ERROR_PRE_COMMIT = (1 << 0),
  OSTREE_REPO_TEST_ERROR_INVALID_CACHE = (1 << 1),
} OstreeRepoTestErrorFlags;

struct OstreeRepoCommitModifier {
  gint refcount;  /* atomic */

  OstreeRepoCommitModifierFlags flags;
  OstreeRepoCommitFilter filter;
  gpointer user_data;
  GDestroyNotify destroy_notify;

  OstreeRepoCommitModifierXattrCallback xattr_callback;
  GDestroyNotify xattr_destroy;
  gpointer xattr_user_data;

  GLnxTmpDir sepolicy_tmpdir;
  OstreeSePolicy *sepolicy;
  GHashTable *devino_cache;
};

typedef enum {
  OSTREE_REPO_SYSROOT_KIND_UNKNOWN,
  OSTREE_REPO_SYSROOT_KIND_NO,  /* Not a system repo */
  OSTREE_REPO_SYSROOT_KIND_VIA_SYSROOT, /* Constructed via ostree_sysroot_get_repo() */
  OSTREE_REPO_SYSROOT_KIND_IS_SYSROOT_OSTREE, /* We match /ostree/repo */
} OstreeRepoSysrootKind;

typedef struct {
  GHashTable *refs;  /* (element-type utf8 utf8) */
  GHashTable *collection_refs;  /* (element-type OstreeCollectionRef utf8) */
  OstreeRepoTransactionStats stats;
  /* Implementation of min-free-space-percent */
  gulong blocksize;
  fsblkcnt_t max_blocks;
} OstreeRepoTxn;

typedef struct {
  GMutex mutex;  /* All other members should only be accessed with this held */
  int fd;  /* The open file or flock file descriptor */
  guint shared;  /* Number of shared locks curently held */
  guint exclusive;  /* Number of exclusive locks currently held */
} OstreeRepoLock;

typedef enum {
  _OSTREE_FEATURE_NO,
  _OSTREE_FEATURE_MAYBE,
  _OSTREE_FEATURE_YES,
} _OstreeFeatureSupport;

/* Possible values for the sysroot.bootloader configuration variable */
typedef enum {
  CFG_SYSROOT_BOOTLOADER_OPT_AUTO = 0,
  CFG_SYSROOT_BOOTLOADER_OPT_NONE,
  CFG_SYSROOT_BOOTLOADER_OPT_GRUB2,
  CFG_SYSROOT_BOOTLOADER_OPT_SYSLINUX,
  CFG_SYSROOT_BOOTLOADER_OPT_UBOOT,
  CFG_SYSROOT_BOOTLOADER_OPT_ZIPL,
  /* Non-exhaustive */
} OstreeCfgSysrootBootloaderOpt;

static const char* const CFG_SYSROOT_BOOTLOADER_OPTS_STR[] = {
  /* This must be kept in the same order as the enum */
  "auto",
  "none",
  "grub2",
  "syslinux",
  "uboot",
  "zipl",
  NULL,
};

/**
 * OstreeRepo:
 *
 * Private instance structure.
 */
struct OstreeRepo {
  GObject parent;

  char *stagedir_prefix;
  GLnxTmpDir commit_stagedir;
  GLnxLockFile commit_stagedir_lock;

  /* A cached fd-relative version, distinct from the case where we may have a
   * user-provided absolute path.
   */
  GFile *repodir_fdrel;
  GFile *repodir; /* May be %NULL if we were opened via ostree_repo_open_at() */
  int    repo_dir_fd;
  int    tmp_dir_fd;
  int    cache_dir_fd;
  char  *cache_dir;
  int objects_dir_fd;
  int uncompressed_objects_dir_fd;
  GFile *sysroot_dir;
  GWeakRef sysroot; /* Weak to avoid a circular ref; see also `is_system` */
  char *remotes_config_dir;

  OstreeRepoLock lock;

  GMutex txn_lock;
  OstreeRepoTxn txn;
  gboolean txn_locked;
  _OstreeFeatureSupport fs_verity_wanted;
  _OstreeFeatureSupport fs_verity_supported;

  GMutex cache_lock;
  guint dirmeta_cache_refcount;
  /* char * checksum → GVariant * for dirmeta objects, used in the checkout path */
  GHashTable *dirmeta_cache;

  gboolean inited;
  gboolean writable;
  OstreeRepoSysrootKind sysroot_kind;
  GError *writable_error;
  gboolean in_transaction;
  gboolean disable_fsync;
  gboolean per_object_fsync;
  gboolean disable_xattrs;
  guint zlib_compression_level;
  GHashTable *loose_object_devino_hash;
  GHashTable *updated_uncompressed_dirs;

  /* FIXME: The object sizes hash table is really per-commit state, not repo
   * state. Using a single table for the repo means that commits cannot be
   * built simultaneously if they're adding size information. This data should
   * probably be in OstreeMutableTree, but that's gone by the time the actual
   * commit is constructed. At that point the only commit state is in the root
   * OstreeRepoFile.
   */
  GHashTable *object_sizes;

  /* Cache the repo's device/inode to use for comparisons elsewhere */
  dev_t device;
  ino_t inode;
  uid_t owner_uid; /* Cache of repo's owner uid */
  guint min_free_space_percent; /* See the min-free-space-percent config option */
  guint64 min_free_space_mb; /* See the min-free-space-size config option */
  guint64 reserved_blocks;
  gboolean cleanup_stagedir;

  guint test_error_flags; /* OstreeRepoTestErrorFlags */

  GKeyFile *config;
  GHashTable *remotes;
  GMutex remotes_lock;
  OstreeRepoMode mode;
  gboolean enable_uncompressed_cache;
  gboolean generate_sizes;
  guint64 tmp_expiry_seconds;
  gchar *collection_id;
  gboolean add_remotes_config_dir; /* Add new remotes in remotes.d dir */
  gint lock_timeout_seconds;
  guint64 payload_link_threshold;
  gint fs_support_reflink; /* The underlying filesystem has support for ioctl (FICLONE..) */
  gchar **repo_finders;
  OstreeCfgSysrootBootloaderOpt bootloader; /* Configure which bootloader to use. */

  OstreeRepo *parent_repo;
};

typedef struct {
  dev_t dev;
  ino_t ino;
  char checksum[OSTREE_SHA256_STRING_LEN+1];
} OstreeDevIno;

/* A MemoryCacheRef is an in-memory cache of objects (currently just DIRMETA).  This can
 * be used when performing an operation that traverses a repository in someway.  Currently,
 * the primary use case is ostree_repo_checkout_at() avoiding lots of duplicate dirmeta
 * lookups.
 */
typedef struct {
  OstreeRepo *repo;
} OstreeRepoMemoryCacheRef;


void
_ostree_repo_memory_cache_ref_init (OstreeRepoMemoryCacheRef *state,
                                    OstreeRepo               *repo);

void
_ostree_repo_memory_cache_ref_destroy (OstreeRepoMemoryCacheRef *state);
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(OstreeRepoMemoryCacheRef, _ostree_repo_memory_cache_ref_destroy)

#define OSTREE_REPO_TMPDIR_STAGING "staging-"

gboolean
_ostree_repo_allocate_tmpdir (int           tmpdir_dfd,
                              const char   *tmpdir_prefix,
                              GLnxTmpDir   *tmpdir_out,
                              GLnxLockFile *file_lock_out,
                              gboolean *    reusing_dir_out,
                              GCancellable *cancellable,
                              GError      **error);

gboolean
_ostree_repo_has_staging_prefix (const char *filename);

gboolean
_ostree_repo_try_lock_tmpdir (int            tmpdir_dfd,
                              const char    *tmpdir_name,
                              GLnxLockFile  *file_lock_out,
                              gboolean      *out_did_lock,
                              GError       **error);

gboolean
_ostree_repo_ensure_loose_objdir_at (int             dfd,
                                     const char     *loose_path,
                                     GCancellable   *cancellable,
                                     GError        **error);

GFile *
_ostree_repo_get_commit_metadata_loose_path (OstreeRepo        *self,
                                             const char        *checksum);

gboolean
_ostree_repo_has_loose_object (OstreeRepo           *self,
                               const char           *checksum,
                               OstreeObjectType      objtype,
                               gboolean             *out_is_stored,
                               GCancellable         *cancellable,
                               GError             **error);

gboolean
_ostree_write_bareuser_metadata (int fd,
                                 guint32       uid,
                                 guint32       gid,
                                 guint32       mode,
                                 GVariant     *xattrs,
                                 GError       **error);

gboolean
_ostree_repo_write_directory_meta (OstreeRepo   *self,
                                   GFileInfo    *file_info,
                                   GVariant     *xattrs,
                                   guchar      **out_csum,
                                   GCancellable *cancellable,
                                   GError      **error);
gboolean
_ostree_repo_update_refs (OstreeRepo        *self,
                          GHashTable        *refs,
                          GCancellable      *cancellable,
                          GError           **error);

gboolean
_ostree_repo_update_collection_refs (OstreeRepo    *self,
                                     GHashTable    *refs,
                                     GCancellable  *cancellable,
                                     GError       **error);

gboolean
_ostree_repo_file_replace_contents (OstreeRepo    *self,
                                    int            dfd,
                                    const char    *path,
                                    const guint8  *buf,
                                    gsize          len,
                                    GCancellable  *cancellable,
                                    GError       **error);

gboolean
_ostree_repo_write_ref (OstreeRepo                 *self,
                        const char                 *remote,
                        const OstreeCollectionRef  *ref,
                        const char                 *rev,
                        const char                 *alias,
                        GCancellable               *cancellable,
                        GError                    **error);

OstreeRepoFile *
_ostree_repo_file_new_for_commit (OstreeRepo  *repo,
                                  const char  *commit,
                                  GError     **error);

OstreeRepoFile *
_ostree_repo_file_new_root (OstreeRepo  *repo,
                            const char  *contents_checksum,
                            const char  *metadata_checksum);

gboolean
_ostree_repo_traverse_dirtree_internal (OstreeRepo      *repo,
                                        const char      *dirtree_checksum,
                                        int              recursion_depth,
                                        GHashTable      *inout_reachable,
                                        GHashTable      *inout_content_names,
                                        GCancellable    *cancellable,
                                        GError         **error);

OstreeRepoCommitFilterResult
_ostree_repo_commit_modifier_apply (OstreeRepo               *self,
                                    OstreeRepoCommitModifier *modifier,
                                    const char               *path,
                                    GFileInfo                *file_info,
                                    GFileInfo               **out_modified_info);

void
_ostree_repo_setup_generate_sizes (OstreeRepo               *self,
                                   OstreeRepoCommitModifier *modifier);

gboolean
_ostree_repo_remote_name_is_file (const char *remote_name);

#ifndef OSTREE_DISABLE_GPGME
OstreeGpgVerifyResult *
_ostree_repo_gpg_verify_with_metadata (OstreeRepo          *self,
                                       GBytes              *signed_data,
                                       GVariant            *metadata,
                                       const char          *remote_name,
                                       GFile               *keyringdir,
                                       GFile               *extra_keyring,
                                       GCancellable        *cancellable,
                                       GError             **error);

OstreeGpgVerifyResult *
_ostree_repo_verify_commit_internal (OstreeRepo    *self,
                                     const char    *commit_checksum,
                                     const char    *remote_name,
                                     GFile         *keyringdir,
                                     GFile         *extra_keyring,
                                     GCancellable  *cancellable,
                                     GError       **error);
#endif /* OSTREE_DISABLE_GPGME */

typedef enum {
  _OSTREE_REPO_IMPORT_FLAGS_NONE = 0,
  _OSTREE_REPO_IMPORT_FLAGS_TRUSTED = (1 << 0),
  _OSTREE_REPO_IMPORT_FLAGS_VERIFY_BAREUSERONLY = (1 << 1),
} OstreeRepoImportFlags;

gboolean
_ostree_repo_import_object (OstreeRepo           *self,
                            OstreeRepo           *source,
                            OstreeObjectType      objtype,
                            const char           *checksum,
                            OstreeRepoImportFlags flags,
                            GCancellable         *cancellable,
                            GError              **error);

gboolean
_ostree_repo_commit_tmpf_final (OstreeRepo        *self,
                                const char        *checksum,
                                OstreeObjectType   objtype,
                                GLnxTmpfile       *tmpf,
                                GCancellable      *cancellable,
                                GError           **error);

typedef struct {
  gboolean initialized;
  gpointer opaque0[10];
  guint opaque1[10];
} OstreeRepoBareContent;
void _ostree_repo_bare_content_cleanup (OstreeRepoBareContent *regwrite);
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(OstreeRepoBareContent, _ostree_repo_bare_content_cleanup)

gboolean
_ostree_repo_bare_content_open (OstreeRepo            *self,
                                const char            *checksum,
                                guint64                content_len,
                                guint                  uid,
                                guint                  gid,
                                guint                  mode,
                                GVariant              *xattrs,
                                OstreeRepoBareContent *out_regwrite,
                                GCancellable        *cancellable,
                                GError             **error);

gboolean
_ostree_repo_bare_content_write (OstreeRepo                 *repo,
                                 OstreeRepoBareContent      *barewrite,
                                 const guint8               *buf,
                                 size_t                      len,
                                 GCancellable               *cancellable,
                                 GError                    **error);

gboolean
_ostree_repo_bare_content_commit (OstreeRepo                 *self,
                                  OstreeRepoBareContent      *barewrite,
                                  char                       *checksum_buf,
                                  size_t                      buflen,
                                  GCancellable               *cancellable,
                                  GError                    **error);

OstreeContentWriter *
_ostree_content_writer_new (OstreeRepo            *repo,
                           const char            *checksum,
                           guint                  uid,
                           guint                  gid,
                           guint                  mode,
                           guint64                content_len,
                           GVariant              *xattrs,
                           GError               **error);

gboolean
_ostree_repo_load_file_bare (OstreeRepo         *self,
                             const char         *checksum,
                             int                *out_fd,
                             struct stat        *out_stbuf,
                             char              **out_symlink,
                             GVariant          **out_xattrs,
                             GCancellable       *cancellable,
                             GError            **error);

gboolean
_ostree_repo_update_mtime (OstreeRepo        *self,
                           GError           **error);

gboolean
_ostree_repo_add_remote (OstreeRepo   *self,
                         OstreeRemote *remote);
gboolean
_ostree_repo_remove_remote (OstreeRepo   *self,
                            OstreeRemote *remote);
OstreeRemote *
_ostree_repo_get_remote (OstreeRepo  *self,
                         const char  *name,
                         GError     **error);
OstreeRemote *
_ostree_repo_get_remote_inherited (OstreeRepo  *self,
                                   const char  *name,
                                   GError     **error);

gboolean
_ostree_repo_maybe_regenerate_summary (OstreeRepo    *self,
                                       GCancellable  *cancellable,
                                       GError       **error);


gboolean _ostree_repo_parse_fsverity_config (OstreeRepo *self, GError **error);

gboolean
_ostree_tmpf_fsverity_core (GLnxTmpfile *tmpf,
                            _OstreeFeatureSupport fsverity_requested,
                            gboolean    *supported,
                            GError     **error);

gboolean
_ostree_tmpf_fsverity (OstreeRepo *self,
                       GLnxTmpfile *tmpf,
                       GError    **error);

gboolean
_ostree_repo_verify_bindings (const char  *collection_id,
                              const char  *ref_name,
                              GVariant    *commit,
                              GError     **error);

/**
 * OstreeRepoAutoTransaction:
 *
 * A transaction guard for a specific #OstreeRepo. It can be explicitly
 * completed through abort/commit. If the guard has not been completed
 * beforehand, on cleanup it is automatically aborted.
 *
 * Taken from flatpak; may be made into public API later
 */
typedef struct
{
  gint atomic_refcount;
  OstreeRepo *repo;
} OstreeRepoAutoTransaction;

OstreeRepoAutoTransaction *
_ostree_repo_auto_transaction_start (OstreeRepo     *repo,
                                     GCancellable   *cancellable,
                                     GError        **error);

gboolean
_ostree_repo_auto_transaction_abort (OstreeRepoAutoTransaction  *txn,
                                     GCancellable               *cancellable,
                                     GError                    **error);

gboolean
_ostree_repo_auto_transaction_commit (OstreeRepoAutoTransaction  *txn,
                                      OstreeRepoTransactionStats *out_stats,
                                      GCancellable               *cancellable,
                                      GError                    **error);

OstreeRepoAutoTransaction *
_ostree_repo_auto_transaction_ref (OstreeRepoAutoTransaction *txn);

void
_ostree_repo_auto_transaction_unref (OstreeRepoAutoTransaction *txn);

GType _ostree_repo_auto_transaction_get_type (void);

G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoAutoTransaction, _ostree_repo_auto_transaction_unref);

G_END_DECLS