nuts_container/
lib.rs

1// MIT License
2//
3// Copyright (c) 2022-2024 Robin Doer
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to
7// deal in the Software without restriction, including without limitation the
8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9// sell copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in
13// all copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21// IN THE SOFTWARE.
22
23//! # The basic container
24//!
25//! This module contains types for the basic container handling. A
26//! [`Container`] acts like an encrypted block device, where you can read and
27//! write encrypted blocks of data. See the [`Container`] documentation for
28//! details.
29//!
30//! The [`Container`] has no knowlege about the storage layer. Every type that
31//! implements the [`Backend`] trait can act as the storage layer for the
32//! [`Container`]. The [`Container`] receives (possibly) encrypted data from
33//! the backend and pushes (possibly) encrypted data back to the backend.
34//! See the [`backend` crate](nuts_backend) documentation for details.
35//!
36//! ## Create a container
37//!
38//! The [`Container::create()`] method is used to create a new container. It
39//! expects an instance of a type that implements the [`Create`] trait, which
40//! acts as a builder for the related [`Backend`].
41//!
42//! Example:
43//!
44//! ```rust
45//! use nuts_container::*;
46//! use nuts_memory::MemoryBackend;
47//!
48//! // Create a container with a memory backend.
49//! let backend = MemoryBackend::new();
50//!
51//! // Let's create an encrypted container (with aes128-ctr).
52//! // Because you are encrypting the container, you need to assign a
53//! // password callback.
54//! let kdf = Kdf::pbkdf2(Digest::Sha1, 65536, b"123");
55//! let options = CreateOptionsBuilder::new(Cipher::Aes128Ctr)
56//!     .with_password_callback(|| Ok(b"abc".to_vec()))
57//!     .with_kdf(kdf.clone())
58//!     .build::<MemoryBackend>()
59//!     .unwrap();
60//!
61//! // Create the container and fetch information.
62//! // Here you can directly pass the backend instance to the create() method
63//! // because MemoryBackend implements the Backend::CreateOptions trait.
64//! let container = Container::<MemoryBackend>::create(backend, options).unwrap();
65//! let info = container.info().unwrap();
66//!
67//! assert_eq!(info.cipher, Cipher::Aes128Ctr);
68//! assert_eq!(info.kdf, kdf);
69//! ```
70//!
71//! ## Open a container
72//!
73//! The [`Container::open()`] method is used to open a container. It expects an
74//! instance of a type that implements the [`Open`] trait, which acts as a
75//! builder for the related [`Backend`].
76//!
77//! Example:
78//!
79//! ```rust
80//! use nuts_container::*;
81//! use nuts_memory::MemoryBackend;
82//!
83//! let (backend, kdf) = {
84//!     // In this example you create a container in a separate block.
85//!     // So, the created container is closed again when leaving the scope.
86//!     let backend = MemoryBackend::new();
87//!     let kdf = Kdf::pbkdf2(Digest::Sha1, 65536, b"123");
88//!     let options = CreateOptionsBuilder::new(Cipher::Aes128Ctr)
89//!         .with_password_callback(|| Ok(b"abc".to_vec()))
90//!         .with_kdf(kdf.clone())
91//!         .build::<MemoryBackend>()
92//!         .unwrap();
93//!
94//!     // Create the container.
95//!     let container = Container::<MemoryBackend>::create(backend, options).unwrap();
96//!     let backend = container.into_backend();
97//!
98//!     (backend, kdf)
99//! };
100//!
101//! // Open the container and fetch information.
102//! // Here you can directly pass the backend instance to the open() method
103//! // because MemoryBackend implements the Backend::OpenOptions trait.
104//! let options = OpenOptionsBuilder::new()
105//!     .with_password_callback(|| Ok(b"abc".to_vec()))
106//!     .build::<MemoryBackend>()
107//!     .unwrap();
108//! let container = Container::<MemoryBackend>::open(backend, options).unwrap();
109//! let info = container.info().unwrap();
110//!
111//! assert_eq!(info.cipher, Cipher::Aes128Ctr);
112//! assert_eq!(info.kdf, kdf);
113//! ```
114//!
115//! ## Read from a container
116//!
117//! ```rust
118//! use nuts_container::*;
119//! use nuts_memory::MemoryBackend;
120//!
121//! // Create a container with a memory backend.
122//! let mut backend = MemoryBackend::new();
123//!
124//! // Insert a block into the backend.
125//! // Note that the insert() method is a part of the MemoryBackend and directly
126//! // inserts a block into the backend (bypassing the crypto capabilities of the
127//! // container).
128//! let id = backend.insert().unwrap();
129//!
130//! // Create the container.
131//! let options = CreateOptionsBuilder::new(Cipher::None)
132//!     .build::<MemoryBackend>()
133//!     .unwrap();
134//! let mut container = Container::<MemoryBackend>::create(backend, options).unwrap();
135//!
136//! // Read full block.
137//! let mut buf = [b'x'; 512];
138//! assert_eq!(container.read(&id, &mut buf).unwrap(), 512);
139//! assert_eq!(buf, [0; 512]);
140//!
141//! // Read block into a buffer which is smaller than the block-size.
142//! // The buffer is filled with the first 400 bytes from the block.
143//! let mut buf = [b'x'; 400];
144//! assert_eq!(container.read(&id, &mut buf).unwrap(), 400);
145//! assert_eq!(buf, [0; 400]);
146//!
147//! // Read block into a buffer which is bigger than the block-size.
148//! // The first 512 bytes are filled with the content of the block,
149//! // the remaining 8 bytes are not touched.
150//! let mut buf = [b'x'; 520];
151//! assert_eq!(container.read(&id, &mut buf).unwrap(), 512);
152//! assert_eq!(buf[..512], [0; 512]);
153//! assert_eq!(buf[512..], [b'x'; 8]);
154//! ```
155//!
156//! ## Write into a container
157//!
158//! ```rust
159//! use nuts_container::*;
160//! use nuts_memory::MemoryBackend;
161//!
162//! // In this example you create a container in a separate block.
163//! // So, the created container is closed again when leaving the scope.
164//! let mut backend = MemoryBackend::new();
165//!
166//! // Insert a block into the backend.
167//! // Note that the insert() method is a part of the MemoryBackend and directly
168//! // inserts a block into the backend (bypassing the crypto capabilities of the
169//! // container).
170//! let id = backend.insert().unwrap();
171//!
172//! // Create the container.
173//! let options = CreateOptionsBuilder::new(Cipher::None)
174//!     .build::<MemoryBackend>()
175//!     .unwrap();
176//! let mut container = Container::<MemoryBackend>::create(backend, options).unwrap();
177//!
178//! // Write a full block. The whole block is filled with 'x'.
179//! assert_eq!(container.write(&id, &[b'x'; 512]).unwrap(), 512);
180//!
181//! let mut buf = [0; 512];
182//! assert_eq!(container.read(&id, &mut buf).unwrap(), 512);
183//! assert_eq!(buf, [b'x'; 512]);
184//!
185//! // Write a block from a buffer which is smaller than the block-size.
186//! // The first bytes of the block are filled with the data from the buffer,
187//! // the remaining space is padded with '0'.
188//! assert_eq!(container.write(&id, &[b'x'; 400]).unwrap(), 400);
189//!
190//! let mut buf = [0; 512];
191//! assert_eq!(container.read(&id, &mut buf).unwrap(), 512);
192//! assert_eq!(buf[..400], [b'x'; 400]);
193//! assert_eq!(buf[400..], [0; 112]);
194//!
195//! // Write a block from a buffer which is bigger than the block-size.
196//! // The block is filled with the first data from the buffer.
197//! assert_eq!(container.write(&id, &[b'x'; 520]).unwrap(), 512);
198//!
199//! let mut buf = [0; 512];
200//! assert_eq!(container.read(&id, &mut buf).unwrap(), 512);
201//! assert_eq!(buf, [b'x'; 512]);
202//! ```
203//!
204//! ## The header of a container
205//!
206//! The header of the container stores all data necessary to open the container
207//! again. There are:
208//!
209//! * The [`Cipher`]: The cipher defines the cipher used for encryption and
210//!   decryption of the individual blocks of the container.
211//!
212//!   If the cipher is set to [`Cipher::None`], then encryption is disabled and
213//!   all the data are stored unencrypted in the container.
214//!
215//!   If encryption is enabled (with a cipher which is not [`Cipher::None`]),
216//!   then the blocks of the container are encrypted with a master-key stored
217//!   and secured in the header of the container. This part of the header
218//!   (other sensible data are also stored there) is called _secret_ and is
219//!   encrypted with the wrapping-key derivited by the key derivation function
220//!   ([`Kdf`]). So, with a user supplied passphrase you are derivating the
221//!   wrapping-key, which decrypts the _secret_ part of the header, where the
222//!   master-key (used for en-/decryption of the data blocks) is stored.
223//!
224//! * The key derivation function ([`Kdf`]) defines a way to create a key from
225//!   a user supplied passphrase. In the next step this key is used to encrypt resp.
226//!   decrypt the _secret_ part of the header.
227//!
228//! * The _secret_ is the encrypted part of the header and contains sensible
229//!   data of the container. The secret is encrypted with a wrapping-key, which
230//!   is the output of the [`Kdf`]. The _secret_ contains:
231//!
232//!   * _master-key_: The master-key is used for encryption of the blocks of
233//!     the container.
234//!   * _top-id_: The _top-id_ points to some kind of super-block. During
235//!     [service-creation](Container::create_service) the super-block is
236//!     aquired (if requested by the service) and its id (the _top-id_) is
237//!     stored in the _secret_.
238//!   * _settings of the backend_: The backend of the container stores its
239//!     runtime information in the secret. It gets it back when opening the
240//!     backend again. See [`Backend::Settings`] for more information.
241
242mod buffer;
243mod cipher;
244mod digest;
245mod error;
246mod header;
247mod info;
248mod kdf;
249mod migrate;
250mod options;
251mod ossl;
252mod password;
253mod service;
254mod svec;
255#[cfg(test)]
256mod tests;
257
258use log::debug;
259use nuts_backend::{Backend, Create, Open, ReceiveHeader, HEADER_MAX_SIZE};
260use std::{any, cmp};
261
262use crate::cipher::CipherContext;
263use crate::header::Header;
264use crate::migrate::Migrator;
265use crate::password::PasswordStore;
266
267pub use buffer::BufferError;
268pub use cipher::{Cipher, CipherError};
269pub use digest::Digest;
270pub use error::{ContainerResult, Error};
271pub use header::{HeaderError, LATEST_REVISION};
272pub use info::Info;
273pub use kdf::{Kdf, KdfError};
274pub use migrate::{Migration, MigrationError};
275pub use options::{
276    CreateOptions, CreateOptionsBuilder, ModifyOptions, ModifyOptionsBuilder, OpenOptions,
277    OpenOptionsBuilder,
278};
279pub use password::PasswordError;
280pub use service::{Service, ServiceFactory};
281
282macro_rules! map_err {
283    ($result:expr) => {
284        $result.map_err(|cause| Error::Backend(cause))
285    };
286}
287
288/// The Container type.
289///
290/// A `Container` acts like an encrypted block device, where you can read and
291/// write encrypted blocks of data.
292///
293/// To create a new container use the [`Container::create`] method. You can
294/// open an existing container with the [`Container::open`] method. With the
295/// [`Container::read`] and [`Container::write`] methods you can read data from
296/// the container resp. write data into the container.
297#[derive(Debug)]
298pub struct Container<B: Backend> {
299    backend: B,
300    store: PasswordStore,
301    header: Header<'static, B>,
302    ctx: CipherContext,
303}
304
305impl<B: Backend> Container<B> {
306    /// Creates a new container.
307    ///
308    /// This method expects two arguments:
309    ///
310    /// 1. `backend_options`, which is a type that implements the
311    ///    [`Create`] trait. It acts as a builder for a concrete [`Backend`]
312    ///    instance.
313    /// 2. `options`, which is a builder of this `Container`. A
314    ///    [`CreateOptions`] instance can be created with the
315    ///    [`CreateOptionsBuilder`] utility.
316    ///
317    /// If encryption is turned on, you will be asked for a password over the
318    /// [password callback](CreateOptionsBuilder::with_password_callback). The
319    /// returned password is then used for encryption of the secure part of the
320    /// header.
321    ///
322    /// The header with the (possibly encrypted) secret is created and passed
323    /// to the [`Backend`]. The header contains all information you need to
324    /// open the container again.
325    ///
326    /// # Errors
327    ///
328    /// Errors are listed in the [`Error`] type.
329    pub fn create<C: Create<B>>(
330        backend_options: C,
331        options: CreateOptions,
332    ) -> ContainerResult<Container<B>, B> {
333        let mut header_bytes = [0; HEADER_MAX_SIZE];
334        let settings = backend_options.settings();
335        let header = Header::create(&options, settings)?;
336
337        let callback = options.callback.clone();
338        let mut store = PasswordStore::new(callback);
339
340        header.write(&mut header_bytes, &mut store)?;
341
342        let backend = map_err!(backend_options.build(header_bytes, options.overwrite))?;
343
344        debug!(
345            "Container created, backend: {}, header: {:?}",
346            any::type_name::<B>(),
347            header
348        );
349
350        let ctx = CipherContext::new(header.cipher());
351
352        Ok(Container {
353            backend,
354            store,
355            header,
356            ctx,
357        })
358    }
359
360    /// Creates a [service](Service) running on top of the given `container`.
361    ///
362    /// Basically, this method performs the following tasks:
363    ///
364    /// 1. The super-block is created, if [requested by the service](Service::need_top_id).
365    /// 2. Uses [`ServiceFactory::create`] to create and return the service
366    ///    instance.
367    ///
368    /// This should be the preferred way to create a nuts-service!
369    pub fn create_service<F: ServiceFactory<B>>(
370        mut container: Container<B>,
371    ) -> Result<F::Service, F::Err> {
372        // ensure that you are on the current revision
373        container
374            .header
375            .latest_revision_or_err()
376            .map_err(Error::<B>::Header)?;
377
378        // ensure that the container does not already have a service
379        container
380            .header
381            .accept_sid_for_create()
382            .map_err(Error::<B>::Header)?;
383
384        // aquire top-id (if requested)
385        let top_id = if F::Service::need_top_id() {
386            Some(container.aquire()?)
387        } else {
388            None
389        };
390
391        container.update_header(|header| {
392            header.set_sid(F::Service::sid())?;
393
394            if let Some(id) = top_id {
395                header.set_top_id(id);
396            }
397
398            Ok(true)
399        })?;
400
401        F::create(container)
402    }
403
404    /// Opens an existing container.
405    ///
406    /// This method expects two arguments:
407    ///
408    /// 1. `backend_options`, which is a type that implements the [`Open`]
409    ///    trait. It acts as a builder for a concrete [`Backend`] instance.
410    /// 2. `options`, which is a builder of this `Container`. A
411    ///    [`OpenOptions`] instance can be created with the
412    ///    [`OpenOptionsBuilder`] utility.
413    ///
414    /// If encryption is turned on for the container, you will be asked for a
415    /// password over the
416    /// [password callback](OpenOptionsBuilder::with_password_callback). The
417    /// returned password is then used to decrypt the secure part of the header.
418    ///
419    /// # Errors
420    ///
421    /// Errors are listed in the [`Error`] type.
422    pub fn open<O: Open<B>>(
423        mut backend_options: O,
424        options: OpenOptions,
425    ) -> ContainerResult<Container<B>, B> {
426        let callback = options.callback.clone();
427        let mut store = PasswordStore::new(callback);
428        let migrator = Migrator::default();
429
430        let mut header = Self::read_header(&mut backend_options, migrator, &mut store)?;
431        let settings = header.settings().clone();
432        let backend = map_err!(backend_options.build(settings))?;
433
434        header.migrate()?;
435
436        debug!(
437            "Container opened, backend: {}, header: {:?}",
438            any::type_name::<B>(),
439            header
440        );
441
442        let ctx = CipherContext::new(header.cipher());
443
444        Ok(Container {
445            backend,
446            store,
447            header,
448            ctx,
449        })
450    }
451
452    /// Opens a [service](Service) running on top of an existing container.
453    ///
454    /// Basically, this method uses [`ServiceFactory::open`] to open and return
455    /// the service instance.
456    ///
457    /// This should be the preferred way to open a nuts-service!
458    pub fn open_service<F: ServiceFactory<B>>(
459        mut container: Container<B>,
460        migrate: bool,
461    ) -> Result<F::Service, F::Err> {
462        let migration = F::Service::migration();
463        let migrator = Migrator::default().with_migration(migration);
464
465        container.header.set_migrator(migrator);
466        container.header.migrate().map_err(Error::Header)?;
467        container
468            .header
469            .accept_sid_for_open(F::Service::sid())
470            .map_err(Error::Header)?;
471
472        if migrate {
473            container.update_header(|header| {
474                let changed = header.convert_to_latest(F::Service::sid());
475                Ok(changed)
476            })?;
477        }
478
479        F::open(container)
480    }
481
482    /// Returns the backend of this container.
483    pub fn backend(&self) -> &B {
484        &self.backend
485    }
486
487    /// Consumes this container, returning the inner backend.
488    pub fn into_backend(self) -> B {
489        self.backend
490    }
491
492    /// Returns information from the container.
493    ///
494    /// # Errors
495    ///
496    /// Errors are listed in the [`Error`] type.
497    pub fn info(&self) -> ContainerResult<Info<B>, B> {
498        let backend = map_err!(self.backend.info())?;
499
500        Ok(Info {
501            backend,
502            revision: self.header.revision(),
503            cipher: self.header.cipher(),
504            kdf: self.header.kdf().clone(),
505            bsize_gross: self.backend.block_size(),
506            bsize_net: self.block_size(),
507        })
508    }
509
510    /// Returns the _top-id_ of the container.
511    ///
512    /// A service (running on top of the container) can use the _top-id_ as a
513    /// starting point or some kind of _super-block_. The _top-id_ is stored
514    /// encrypted in the header of the container. Calling this method will
515    /// neither fetch nor create the _top-id_. It returns an entry, where you
516    /// can decide what to do.
517    pub fn top_id(&self) -> Option<&B::Id> {
518        self.header.top_id()
519    }
520
521    /// The (net) block size specifies the number of userdata bytes you can
522    /// store in a block. It can be less than the gross block size specified by
523    /// the [backend](Backend::block_size)!
524    ///
525    /// Depending on the selected cipher, you need to store additional data in
526    /// a block. I.e. an AE-cipher results into a tag, which needs to be stored
527    /// additionally. Such data must be substracted from the gross block size
528    /// and results into the net block size.
529    pub fn block_size(&self) -> u32 {
530        self.backend
531            .block_size()
532            .saturating_sub(self.header.cipher().tag_size())
533    }
534
535    /// Modifies the container with the given options.
536    ///
537    /// Use [`ModifyOptionsBuilder`] to create a [`ModifyOptions`] instance,
538    /// which collects all modification tasks.
539    ///
540    /// # Errors
541    ///
542    /// Errors are listed in the [`Error`] type.
543    pub fn modify(&mut self, options: ModifyOptions) -> ContainerResult<(), B> {
544        let mut changed = false;
545
546        if options.password.is_some() {
547            self.store = PasswordStore::new(options.password.clone());
548            changed = true;
549        }
550
551        self.update_header(|header| {
552            if let Some(kdf) = options.kdf {
553                changed |= header.set_kdf(kdf);
554            }
555
556            Ok(changed)
557        })
558    }
559
560    /// Aquires a new block in the backend.
561    ///
562    /// Once aquired you should be able to [read](Container::read) and
563    /// [write](Container::write) from/to it.
564    ///
565    /// By default an aquired block, which is not written yet, returns an
566    /// all-zero buffer.
567    ///
568    /// Returns the [id](Backend::Id) of the block.
569    ///
570    /// # Errors
571    ///
572    /// Errors are listed in the [`Error`] type.
573    pub fn aquire(&mut self) -> ContainerResult<B::Id, B> {
574        let key = self.header.key();
575        let iv = self.header.iv();
576
577        self.ctx.copy_from_slice(self.block_size() as usize, &[]);
578        let ctext = self.ctx.encrypt(key, iv)?;
579
580        map_err!(self.backend.aquire(ctext))
581    }
582
583    /// Releases a block again.
584    ///
585    /// A released block cannot be [read](Container::read) and
586    /// [written](Container::write), the [id](Backend::Id) cannot be used
587    /// afterwards.
588    ///
589    /// # Errors
590    ///
591    /// Errors are listed in the [`Error`] type.
592    pub fn release(&mut self, id: B::Id) -> ContainerResult<(), B> {
593        map_err!(self.backend.release(id))
594    }
595
596    /// Reads a block from the container.
597    ///
598    /// Reads the block with the given `id` and places the decrypted data in
599    /// `buf`.
600    ///
601    /// You cannot read not more data than [block-size](Backend::block_size)
602    /// bytes. If `buf` is larger, than not the whole buffer is filled. In the
603    /// other direction, if `buf` is not large enough to store the whole block,
604    /// `buf` is filled with the first `buf.len()` bytes.
605    ///
606    /// The methods returns the number of bytes actually read, which cannot be
607    /// greater than the [block-size](Backend::block_size).
608    ///
609    /// # Errors
610    ///
611    /// Errors are listed in the [`Error`] type.
612    pub fn read(&mut self, id: &B::Id, buf: &mut [u8]) -> ContainerResult<usize, B> {
613        let ctext = self.ctx.inp_mut(self.backend.block_size() as usize);
614        map_err!(self.backend.read(id, ctext))?;
615
616        let key = self.header.key();
617        let iv = self.header.iv();
618
619        let ptext = self.ctx.decrypt(key, iv)?;
620
621        let n = cmp::min(ptext.len(), buf.len());
622        buf[..n].copy_from_slice(&ptext[..n]);
623
624        Ok(n)
625    }
626
627    /// Writes a block into the container.
628    ///
629    /// Encrypts the plain data from `buf` and writes the encrypted data into
630    /// the block with the given `id`.
631    ///
632    /// Writes up to `buf.len()` bytes from the unencrypted `buf` buffer into
633    /// the container.
634    ///
635    /// If `buf` is not large enough to fill the whole block, the destination
636    /// block is automatically padded with all zeros.
637    ///
638    /// If `buf` holds more data than the block-size, then the first
639    /// [block-size](Backend::block_size) bytes are copied into the block.
640    ///
641    /// The method returns the number of bytes actually written.
642    ///
643    /// # Errors
644    ///
645    /// Errors are listed in the [`Error`] type.
646    pub fn write(&mut self, id: &B::Id, buf: &[u8]) -> ContainerResult<usize, B> {
647        let len = self.ctx.copy_from_slice(self.block_size() as usize, buf);
648
649        let key = self.header.key();
650        let iv = self.header.iv();
651
652        let ctext = self.ctx.encrypt(key, iv)?;
653
654        map_err!(self.backend.write(id, ctext)).map(|_| len)
655    }
656
657    fn read_header<H: ReceiveHeader<B>>(
658        reader: &mut H,
659        migrator: Migrator<'static>,
660        store: &mut PasswordStore,
661    ) -> ContainerResult<Header<'static, B>, B> {
662        let mut buf = [0; HEADER_MAX_SIZE];
663
664        match reader.get_header_bytes(&mut buf) {
665            Ok(_) => {
666                debug!("got {} header bytes", buf.len());
667                Ok(Header::read(&buf, migrator, store)?)
668            }
669            Err(cause) => Err(Error::Backend(cause)),
670        }
671    }
672
673    fn update_header<F: FnOnce(&mut Header<B>) -> Result<bool, HeaderError>>(
674        &mut self,
675        f: F,
676    ) -> ContainerResult<(), B> {
677        debug!("header before update: {:?}", self.header);
678
679        let changed = f(&mut self.header)?;
680
681        debug!(
682            "header after update: {:?}, changed: {}",
683            self.header, changed
684        );
685
686        if changed {
687            let mut header_bytes = [0; HEADER_MAX_SIZE];
688
689            self.header.write(&mut header_bytes, &mut self.store)?;
690            map_err!(self.backend.write_header(&header_bytes))?;
691        }
692
693        Ok(())
694    }
695
696    /// Deletes the entire container and all traces.
697    ///
698    /// The method must not fail!
699    pub fn delete(self) {
700        self.backend.delete()
701    }
702}