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}