diff --git a/.lock b/.lock new file mode 100644 index 0000000..e69de29 diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/crates.js b/crates.js new file mode 100644 index 0000000..0a1a379 --- /dev/null +++ b/crates.js @@ -0,0 +1 @@ +window.ALL_CRATES = ["landlock"]; \ No newline at end of file diff --git a/help.html b/help.html new file mode 100644 index 0000000..d2ce699 --- /dev/null +++ b/help.html @@ -0,0 +1 @@ +Help

Rustdoc help

Back
\ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..c696899 --- /dev/null +++ b/index.html @@ -0,0 +1 @@ + diff --git a/landlock/access/trait.Access.html b/landlock/access/trait.Access.html new file mode 100644 index 0000000..78e51cc --- /dev/null +++ b/landlock/access/trait.Access.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/trait.Access.html...

+ + + \ No newline at end of file diff --git a/landlock/all.html b/landlock/all.html new file mode 100644 index 0000000..409e1d4 --- /dev/null +++ b/landlock/all.html @@ -0,0 +1 @@ +List of all items in this crate

List of all items

Structs

Enums

Traits

Macros

Functions

\ No newline at end of file diff --git a/landlock/compat/enum.ABI.html b/landlock/compat/enum.ABI.html new file mode 100644 index 0000000..f085b4a --- /dev/null +++ b/landlock/compat/enum.ABI.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/enum.ABI.html...

+ + + \ No newline at end of file diff --git a/landlock/compat/enum.CompatLevel.html b/landlock/compat/enum.CompatLevel.html new file mode 100644 index 0000000..1f1c92c --- /dev/null +++ b/landlock/compat/enum.CompatLevel.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/enum.CompatLevel.html...

+ + + \ No newline at end of file diff --git a/landlock/compat/trait.Compatible.html b/landlock/compat/trait.Compatible.html new file mode 100644 index 0000000..8d1820c --- /dev/null +++ b/landlock/compat/trait.Compatible.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/trait.Compatible.html...

+ + + \ No newline at end of file diff --git a/landlock/enum.ABI.html b/landlock/enum.ABI.html new file mode 100644 index 0000000..50fe1e2 --- /dev/null +++ b/landlock/enum.ABI.html @@ -0,0 +1,60 @@ +ABI in landlock - Rust

Enum landlock::ABI

source ·
#[non_exhaustive]
pub enum ABI { + Unsupported = 0, + V1 = 1, + V2 = 2, + V3 = 3, + V4 = 4, + V5 = 5, +}
Expand description

Version of the Landlock ABI.

+

ABI enables getting the features supported by a specific Landlock ABI +(without relying on the kernel version which may not be accessible or patched). +For example, AccessFs::from_all(ABI::V1) +gets all the file system access rights defined by the first version.

+

Without ABI, it would be hazardous to rely on the the full set of access flags +(e.g., BitFlags::<AccessFs>::all() or BitFlags::ALL), +a moving target that would change the semantics of your Landlock rule +when migrating to a newer version of this crate. +Indeed, a simple cargo update or cargo install run by any developer +can result in a new version of this crate (fixing bugs or bringing non-breaking changes). +This crate cannot give any guarantee concerning the new restrictions resulting from +these unknown bits (i.e. access rights) that would not be controlled by your application but by +a future version of this crate instead. +Because we cannot know what the effect on your application of an unknown restriction would be +when handling an untested Landlock access right (i.e. denied-by-default access), +it could trigger bugs in your application.

+

This crate provides a set of tools to sandbox as much as possible +while guaranteeing a consistent behavior thanks to the Compatible methods. +You should also test with different relevant kernel versions, +see landlock-test-tools and +CI integration.

+

This way, we can have the guarantee that the use of a set of tested Landlock ABI works as +expected because features brought by newer Landlock ABI will never be enabled by default +(cf. Linux kernel compatibility contract).

+

In a nutshell, test the access rights you request on a kernel that support them and +on a kernel that doesn’t support them.

+

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

Unsupported = 0

Kernel not supporting Landlock, either because it is not built with Landlock +or Landlock is not enabled at boot.

+
§

V1 = 1

First Landlock ABI, introduced with +Linux 5.13.

+
§

V2 = 2

Second Landlock ABI, introduced with +Linux 5.19.

+
§

V3 = 3

Third Landlock ABI, introduced with +Linux 6.2.

+
§

V4 = 4

Fourth Landlock ABI, introduced with +Linux 6.7.

+
§

V5 = 5

Fifth Landlock ABI, introduced with +Linux 6.10.

+

Trait Implementations§

source§

impl Clone for ABI

source§

fn clone(&self) -> ABI

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Copy for ABI

Auto Trait Implementations§

§

impl Freeze for ABI

§

impl RefUnwindSafe for ABI

§

impl Send for ABI

§

impl Sync for ABI

§

impl Unpin for ABI

§

impl UnwindSafe for ABI

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> CloneToUninit for T
where + T: Copy,

source§

unsafe fn clone_to_uninit(&self, dst: *mut T)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
source§

impl<T> CloneToUninit for T
where + T: Clone,

source§

default unsafe fn clone_to_uninit(&self, dst: *mut T)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T> ToOwned for T
where + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/enum.AccessError.html b/landlock/enum.AccessError.html new file mode 100644 index 0000000..263446c --- /dev/null +++ b/landlock/enum.AccessError.html @@ -0,0 +1,51 @@ +AccessError in landlock - Rust

Enum landlock::AccessError

source ·
pub enum AccessError<T>
where + T: Access,
{ + Empty, + Unknown { + access: BitFlags<T>, + unknown: BitFlags<T>, + }, + Incompatible { + access: BitFlags<T>, + }, + PartiallyCompatible { + access: BitFlags<T>, + incompatible: BitFlags<T>, + }, +}

Variants§

§

Empty

The access-rights set is empty, which doesn’t make sense and would be rejected by the +kernel.

+
§

Unknown

The access-rights set was forged with the unsafe BitFlags::from_bits_unchecked() and it +contains unknown bits.

+

Fields

§access: BitFlags<T>
§unknown: BitFlags<T>
§

Incompatible

The best-effort approach was (deliberately) disabled and the requested access-rights are +fully incompatible with the running kernel.

+

Fields

§access: BitFlags<T>
§

PartiallyCompatible

The best-effort approach was (deliberately) disabled and the requested access-rights are +partially incompatible with the running kernel.

+

Fields

§access: BitFlags<T>
§incompatible: BitFlags<T>

Trait Implementations§

source§

impl<T> Debug for AccessError<T>
where + T: Access + Debug,

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<T> Display for AccessError<T>
where + T: Access, + BitFlags<T>: Debug,

source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<T> Error for AccessError<T>
where + T: Access, + Self: Debug + Display,

1.30.0 · source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
source§

impl<T> From<AccessError<T>> for CompatError<T>
where + T: Access,

source§

fn from(source: AccessError<T>) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl<T> Freeze for AccessError<T>
where + <T as RawBitFlags>::Numeric: Freeze,

§

impl<T> RefUnwindSafe for AccessError<T>
where + <T as RawBitFlags>::Numeric: RefUnwindSafe, + T: RefUnwindSafe,

§

impl<T> Send for AccessError<T>
where + <T as RawBitFlags>::Numeric: Send, + T: Send,

§

impl<T> Sync for AccessError<T>
where + <T as RawBitFlags>::Numeric: Sync, + T: Sync,

§

impl<T> Unpin for AccessError<T>
where + <T as RawBitFlags>::Numeric: Unpin, + T: Unpin,

§

impl<T> UnwindSafe for AccessError<T>
where + <T as RawBitFlags>::Numeric: UnwindSafe, + T: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/enum.AccessFs.html b/landlock/enum.AccessFs.html new file mode 100644 index 0000000..17a0d96 --- /dev/null +++ b/landlock/enum.AccessFs.html @@ -0,0 +1,84 @@ +AccessFs in landlock - Rust

Enum landlock::AccessFs

source ·
#[non_exhaustive]
#[repr(u64)]
pub enum AccessFs { +
Show 16 variants Execute = 1, + WriteFile = 2, + ReadFile = 4, + ReadDir = 8, + RemoveDir = 16, + RemoveFile = 32, + MakeChar = 64, + MakeDir = 128, + MakeReg = 256, + MakeSock = 512, + MakeFifo = 1_024, + MakeBlock = 2_048, + MakeSym = 4_096, + Refer = 8_192, + Truncate = 16_384, + IoctlDev = 32_768, +
}
Expand description

File system access right.

+

Each variant of AccessFs is an access right +for the file system. +A set of access rights can be created with BitFlags<AccessFs>.

+

§Example

+
use landlock::{ABI, Access, AccessFs, BitFlags, make_bitflags};
+
+let exec = AccessFs::Execute;
+
+let exec_set: BitFlags<AccessFs> = exec.into();
+
+let file_content = make_bitflags!(AccessFs::{Execute | WriteFile | ReadFile});
+
+let fs_v1 = AccessFs::from_all(ABI::V1);
+
+let without_exec = fs_v1 & !AccessFs::Execute;
+
+assert_eq!(fs_v1 | AccessFs::Refer, AccessFs::from_all(ABI::V2));
+

§Warning

+

To avoid unknown restrictions don’t use BitFlags::<AccessFs>::all() nor BitFlags::ALL, +but use a version you tested and vetted instead, +for instance AccessFs::from_all(ABI::V1). +Direct use of the BitFlags API is deprecated. +See ABI for the rationale and help to test it.

+

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

Execute = 1

Execute a file.

+
§

WriteFile = 2

Open a file with write access.

+
§

ReadFile = 4

Open a file with read access.

+
§

ReadDir = 8

Open a directory or list its content.

+
§

RemoveDir = 16

Remove an empty directory or rename one.

+
§

RemoveFile = 32

Unlink (or rename) a file.

+
§

MakeChar = 64

Create (or rename or link) a character device.

+
§

MakeDir = 128

Create (or rename) a directory.

+
§

MakeReg = 256

Create (or rename or link) a regular file.

+
§

MakeSock = 512

Create (or rename or link) a UNIX domain socket.

+
§

MakeFifo = 1_024

Create (or rename or link) a named pipe.

+
§

MakeBlock = 2_048

Create (or rename or link) a block device.

+
§

MakeSym = 4_096

Create (or rename or link) a symbolic link.

+
§

Refer = 8_192

Link or rename a file from or to a different directory.

+
§

Truncate = 16_384

Truncate a file with truncate(2), ftruncate(2), creat(2), or open(2) with O_TRUNC.

+
§

IoctlDev = 32_768

Send IOCL commands to a device file.

+

Implementations§

source§

impl AccessFs

source

pub fn from_read(abi: ABI) -> BitFlags<Self>

Gets the access rights identified as read-only according to a specific ABI. +Exclusive with from_write().

+
source

pub fn from_write(abi: ABI) -> BitFlags<Self>

Gets the access rights identified as write-only according to a specific ABI. +Exclusive with from_read().

+
source

pub fn from_file(abi: ABI) -> BitFlags<Self>

Gets the access rights legitimate for non-directory files.

+

Trait Implementations§

source§

impl Access for AccessFs

source§

fn from_all(abi: ABI) -> BitFlags<Self>

Union of from_read() and from_write().

+
source§

impl BitAnd for AccessFs

§

type Output = BitFlags<AccessFs>

The resulting type after applying the & operator.
source§

fn bitand(self, other: Self) -> Self::Output

Performs the & operation. Read more
source§

impl BitFlag for AccessFs

§

fn empty() -> BitFlags<Self>

Create a BitFlags with no flags set (in other words, with a value of 0). Read more
§

fn all() -> BitFlags<Self>

Create a BitFlags with all flags set. Read more
§

fn from_bits(bits: Self::Numeric) -> Result<BitFlags<Self>, FromBitsError<Self>>

Create a BitFlags if the raw value provided does not contain +any illegal flags. Read more
§

fn from_bits_truncate(bits: Self::Numeric) -> BitFlags<Self>

Create a BitFlags from an underlying bitwise value. If any +invalid bits are set, ignore them. Read more
§

unsafe fn from_bits_unchecked(bits: Self::Numeric) -> BitFlags<Self>

Create a BitFlags unsafely, without checking if the bits form +a valid bit pattern for the type. Read more
source§

impl BitOr for AccessFs

§

type Output = BitFlags<AccessFs>

The resulting type after applying the | operator.
source§

fn bitor(self, other: Self) -> Self::Output

Performs the | operation. Read more
source§

impl BitXor for AccessFs

§

type Output = BitFlags<AccessFs>

The resulting type after applying the ^ operator.
source§

fn bitxor(self, other: Self) -> Self::Output

Performs the ^ operation. Read more
source§

impl Clone for AccessFs

source§

fn clone(&self) -> AccessFs

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for AccessFs

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Not for AccessFs

§

type Output = BitFlags<AccessFs>

The resulting type after applying the ! operator.
source§

fn not(self) -> Self::Output

Performs the unary ! operation. Read more
source§

impl PartialEq for AccessFs

source§

fn eq(&self, other: &AccessFs) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl RawBitFlags for AccessFs

§

type Numeric = u64

The underlying integer type.
source§

const EMPTY: Self::Numeric = {transmute(0x0000000000000000): <fs::AccessFs as enumflags2::_internal::RawBitFlags>::Numeric}

A value with no bits set.
source§

const DEFAULT: Self::Numeric = {transmute(0x0000000000000000): <fs::AccessFs as enumflags2::_internal::RawBitFlags>::Numeric}

The value used by the Default implementation. Equivalent to EMPTY, unless +customized.
source§

const ALL_BITS: Self::Numeric = {transmute(0x000000000000ffff): <fs::AccessFs as enumflags2::_internal::RawBitFlags>::Numeric}

A value with all flag bits set.
source§

const BITFLAGS_TYPE_NAME: &'static str = "BitFlags<AccessFs>"

The name of the type for debug formatting purposes. Read more
source§

fn bits(self) -> Self::Numeric

Return the bits as a number type.
source§

impl Copy for AccessFs

source§

impl Eq for AccessFs

source§

impl<F> Rule<AccessFs> for PathBeneath<F>
where + F: AsFd,

source§

impl StructuralPartialEq for AccessFs

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> CloneToUninit for T
where + T: Copy,

source§

unsafe fn clone_to_uninit(&self, dst: *mut T)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
source§

impl<T> CloneToUninit for T
where + T: Clone,

source§

default unsafe fn clone_to_uninit(&self, dst: *mut T)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T> ToOwned for T
where + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/enum.AccessNet.html b/landlock/enum.AccessNet.html new file mode 100644 index 0000000..f7413c8 --- /dev/null +++ b/landlock/enum.AccessNet.html @@ -0,0 +1,50 @@ +AccessNet in landlock - Rust

Enum landlock::AccessNet

source ·
#[non_exhaustive]
#[repr(u64)]
pub enum AccessNet { + BindTcp = 1, + ConnectTcp = 2, +}
Expand description

Network access right.

+

Each variant of AccessNet is an access right +for the network. +A set of access rights can be created with BitFlags<AccessNet>.

+

§Example

+
use landlock::{ABI, Access, AccessNet, BitFlags, make_bitflags};
+
+let bind = AccessNet::BindTcp;
+
+let bind_set: BitFlags<AccessNet> = bind.into();
+
+let bind_connect = make_bitflags!(AccessNet::{BindTcp | ConnectTcp});
+
+let net_v4 = AccessNet::from_all(ABI::V4);
+
+assert_eq!(bind_connect, net_v4);
+

§Warning

+

To avoid unknown restrictions don’t use BitFlags::<AccessNet>::all() nor BitFlags::ALL, +but use a version you tested and vetted instead, +for instance AccessNet::from_all(ABI::V4). +Direct use of the BitFlags API is deprecated. +See ABI for the rationale and help to test it.

+

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

BindTcp = 1

Bind to a TCP port.

+
§

ConnectTcp = 2

Connect to a TCP port.

+

Trait Implementations§

source§

impl Access for AccessNet

§Warning

+

If ABI <= ABI::V3, AccessNet::from_all() returns an empty BitFlags<AccessNet>, which +makes Ruleset::handle_access(AccessNet::from_all(ABI::V3)) return an error.

+
source§

fn from_all(abi: ABI) -> BitFlags<Self>

Gets the access rights defined by a specific ABI.
source§

impl BitAnd for AccessNet

§

type Output = BitFlags<AccessNet>

The resulting type after applying the & operator.
source§

fn bitand(self, other: Self) -> Self::Output

Performs the & operation. Read more
source§

impl BitFlag for AccessNet

§

fn empty() -> BitFlags<Self>

Create a BitFlags with no flags set (in other words, with a value of 0). Read more
§

fn all() -> BitFlags<Self>

Create a BitFlags with all flags set. Read more
§

fn from_bits(bits: Self::Numeric) -> Result<BitFlags<Self>, FromBitsError<Self>>

Create a BitFlags if the raw value provided does not contain +any illegal flags. Read more
§

fn from_bits_truncate(bits: Self::Numeric) -> BitFlags<Self>

Create a BitFlags from an underlying bitwise value. If any +invalid bits are set, ignore them. Read more
§

unsafe fn from_bits_unchecked(bits: Self::Numeric) -> BitFlags<Self>

Create a BitFlags unsafely, without checking if the bits form +a valid bit pattern for the type. Read more
source§

impl BitOr for AccessNet

§

type Output = BitFlags<AccessNet>

The resulting type after applying the | operator.
source§

fn bitor(self, other: Self) -> Self::Output

Performs the | operation. Read more
source§

impl BitXor for AccessNet

§

type Output = BitFlags<AccessNet>

The resulting type after applying the ^ operator.
source§

fn bitxor(self, other: Self) -> Self::Output

Performs the ^ operation. Read more
source§

impl Clone for AccessNet

source§

fn clone(&self) -> AccessNet

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for AccessNet

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Not for AccessNet

§

type Output = BitFlags<AccessNet>

The resulting type after applying the ! operator.
source§

fn not(self) -> Self::Output

Performs the unary ! operation. Read more
source§

impl PartialEq for AccessNet

source§

fn eq(&self, other: &AccessNet) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl RawBitFlags for AccessNet

§

type Numeric = u64

The underlying integer type.
source§

const EMPTY: Self::Numeric = {transmute(0x0000000000000000): <net::AccessNet as enumflags2::_internal::RawBitFlags>::Numeric}

A value with no bits set.
source§

const DEFAULT: Self::Numeric = {transmute(0x0000000000000000): <net::AccessNet as enumflags2::_internal::RawBitFlags>::Numeric}

The value used by the Default implementation. Equivalent to EMPTY, unless +customized.
source§

const ALL_BITS: Self::Numeric = {transmute(0x0000000000000003): <net::AccessNet as enumflags2::_internal::RawBitFlags>::Numeric}

A value with all flag bits set.
source§

const BITFLAGS_TYPE_NAME: &'static str = "BitFlags<AccessNet>"

The name of the type for debug formatting purposes. Read more
source§

fn bits(self) -> Self::Numeric

Return the bits as a number type.
source§

impl Copy for AccessNet

source§

impl Eq for AccessNet

source§

impl Rule<AccessNet> for NetPort

source§

impl StructuralPartialEq for AccessNet

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> CloneToUninit for T
where + T: Copy,

source§

unsafe fn clone_to_uninit(&self, dst: *mut T)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
source§

impl<T> CloneToUninit for T
where + T: Clone,

source§

default unsafe fn clone_to_uninit(&self, dst: *mut T)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T> ToOwned for T
where + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/enum.AddRuleError.html b/landlock/enum.AddRuleError.html new file mode 100644 index 0000000..f9d5eb1 --- /dev/null +++ b/landlock/enum.AddRuleError.html @@ -0,0 +1,41 @@ +AddRuleError in landlock - Rust

Enum landlock::AddRuleError

source ·
#[non_exhaustive]
pub enum AddRuleError<T>
where + T: Access,
{ + AddRuleCall { + source: Error, + }, + UnhandledAccess { + access: BitFlags<T>, + incompatible: BitFlags<T>, + }, + Compat(CompatError<T>), +}
Expand description

Identifies errors when adding a rule to a ruleset.

+

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

AddRuleCall

The landlock_add_rule() system call failed.

+

Fields

This variant is marked as non-exhaustive
Non-exhaustive enum variants could have additional fields added in future. Therefore, non-exhaustive enum variants cannot be constructed in external crates and cannot be matched against.
§source: Error
§

UnhandledAccess

The rule’s access-rights are not all handled by the (requested) ruleset access-rights.

+

Fields

§access: BitFlags<T>
§incompatible: BitFlags<T>
§

Compat(CompatError<T>)

Trait Implementations§

source§

impl<T> Debug for AddRuleError<T>
where + T: Access + Debug,

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<T> Display for AddRuleError<T>
where + T: Access, + BitFlags<T>: Debug, + CompatError<T>: Display,

source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<T> Error for AddRuleError<T>
where + T: Access, + CompatError<T>: Error, + Self: Debug + Display,

source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
source§

impl<A> From<AddRuleError<A>> for AddRulesError
where + A: Access,

source§

fn from(error: AddRuleError<A>) -> Self

Converts to this type from the input type.
source§

impl<T> From<CompatError<T>> for AddRuleError<T>
where + T: Access,

source§

fn from(source: CompatError<T>) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl<T> Freeze for AddRuleError<T>
where + <T as RawBitFlags>::Numeric: Freeze,

§

impl<T> !RefUnwindSafe for AddRuleError<T>

§

impl<T> Send for AddRuleError<T>
where + <T as RawBitFlags>::Numeric: Send, + T: Send,

§

impl<T> Sync for AddRuleError<T>
where + <T as RawBitFlags>::Numeric: Sync, + T: Sync,

§

impl<T> Unpin for AddRuleError<T>
where + <T as RawBitFlags>::Numeric: Unpin, + T: Unpin,

§

impl<T> !UnwindSafe for AddRuleError<T>

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/enum.AddRulesError.html b/landlock/enum.AddRulesError.html new file mode 100644 index 0000000..81c4162 --- /dev/null +++ b/landlock/enum.AddRulesError.html @@ -0,0 +1,18 @@ +AddRulesError in landlock - Rust

Enum landlock::AddRulesError

source ·
#[non_exhaustive]
pub enum AddRulesError { + Fs(AddRuleError<AccessFs>), + Net(AddRuleError<AccessNet>), +}
Expand description

Identifies errors when adding rules to a ruleset thanks to an iterator returning +Result<Rule, E> items.

+

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.

Trait Implementations§

source§

impl Debug for AddRulesError

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Display for AddRulesError

source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Error for AddRulesError

source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
source§

impl<A> From<AddRuleError<A>> for AddRulesError
where + A: Access,

source§

fn from(error: AddRuleError<A>) -> Self

Converts to this type from the input type.
source§

impl From<AddRulesError> for RulesetError

source§

fn from(source: AddRulesError) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/enum.CompatError.html b/landlock/enum.CompatError.html new file mode 100644 index 0000000..3c58e47 --- /dev/null +++ b/landlock/enum.CompatError.html @@ -0,0 +1,33 @@ +CompatError in landlock - Rust

Enum landlock::CompatError

source ·
#[non_exhaustive]
pub enum CompatError<T>
where + T: Access,
{ + PathBeneath(PathBeneathError), + Access(AccessError<T>), +}

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

PathBeneath(PathBeneathError)

§

Access(AccessError<T>)

Trait Implementations§

source§

impl<T> Debug for CompatError<T>
where + T: Access + Debug,

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<T> Display for CompatError<T>
where + T: Access, + AccessError<T>: Display,

source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<T> Error for CompatError<T>
where + T: Access, + AccessError<T>: Error, + Self: Debug + Display,

source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
source§

impl<T> From<AccessError<T>> for CompatError<T>
where + T: Access,

source§

fn from(source: AccessError<T>) -> Self

Converts to this type from the input type.
source§

impl<T> From<CompatError<T>> for AddRuleError<T>
where + T: Access,

source§

fn from(source: CompatError<T>) -> Self

Converts to this type from the input type.
source§

impl<T> From<CompatError<T>> for HandleAccessError<T>
where + T: Access,

source§

fn from(source: CompatError<T>) -> Self

Converts to this type from the input type.
source§

impl<T> From<PathBeneathError> for CompatError<T>
where + T: Access,

source§

fn from(source: PathBeneathError) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl<T> Freeze for CompatError<T>
where + <T as RawBitFlags>::Numeric: Freeze,

§

impl<T> !RefUnwindSafe for CompatError<T>

§

impl<T> Send for CompatError<T>
where + <T as RawBitFlags>::Numeric: Send, + T: Send,

§

impl<T> Sync for CompatError<T>
where + <T as RawBitFlags>::Numeric: Sync, + T: Sync,

§

impl<T> Unpin for CompatError<T>
where + <T as RawBitFlags>::Numeric: Unpin, + T: Unpin,

§

impl<T> !UnwindSafe for CompatError<T>

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/enum.CompatLevel.html b/landlock/enum.CompatLevel.html new file mode 100644 index 0000000..a53d782 --- /dev/null +++ b/landlock/enum.CompatLevel.html @@ -0,0 +1,38 @@ +CompatLevel in landlock - Rust

Enum landlock::CompatLevel

source ·
pub enum CompatLevel {
+    BestEffort,
+    SoftRequirement,
+    HardRequirement,
+}
Expand description

See the Compatible documentation.

+

Variants§

§

BestEffort

Takes into account the build requests if they are supported by the running system, +or silently ignores them otherwise. +Never returns a compatibility error.

+
§

SoftRequirement

Takes into account the build requests if they are supported by the running system, +or silently ignores the whole build object otherwise. +Never returns a compatibility error. +If not supported, +the call to RulesetCreated::restrict_self() +will return a +RestrictionStatus { ruleset: RulesetStatus::NotEnforced, no_new_privs: false, }.

+
§

HardRequirement

Takes into account the build requests if they are supported by the running system, +or returns a compatibility error otherwise (CompatError).

+

Trait Implementations§

source§

impl Clone for CompatLevel

source§

fn clone(&self) -> CompatLevel

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for CompatLevel

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for CompatLevel

source§

fn default() -> CompatLevel

Returns the “default value” for a type. Read more
source§

impl From<Option<CompatLevel>> for CompatLevel

source§

fn from(opt: Option<CompatLevel>) -> Self

Converts to this type from the input type.
source§

impl Ord for CompatLevel

source§

fn cmp(&self, other: &CompatLevel) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
source§

impl PartialEq for CompatLevel

source§

fn eq(&self, other: &CompatLevel) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd for CompatLevel

source§

fn partial_cmp(&self, other: &CompatLevel) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Copy for CompatLevel

source§

impl Eq for CompatLevel

source§

impl StructuralPartialEq for CompatLevel

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> CloneToUninit for T
where + T: Copy,

source§

unsafe fn clone_to_uninit(&self, dst: *mut T)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
source§

impl<T> CloneToUninit for T
where + T: Clone,

source§

default unsafe fn clone_to_uninit(&self, dst: *mut T)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T> ToOwned for T
where + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/enum.CreateRulesetError.html b/landlock/enum.CreateRulesetError.html new file mode 100644 index 0000000..65ef2df --- /dev/null +++ b/landlock/enum.CreateRulesetError.html @@ -0,0 +1,20 @@ +CreateRulesetError in landlock - Rust

Enum landlock::CreateRulesetError

source ·
#[non_exhaustive]
pub enum CreateRulesetError { + CreateRulesetCall { + source: Error, + }, + MissingHandledAccess, +}
Expand description

Identifies errors when creating a ruleset.

+

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

CreateRulesetCall

The landlock_create_ruleset() system call failed.

+

Fields

This variant is marked as non-exhaustive
Non-exhaustive enum variants could have additional fields added in future. Therefore, non-exhaustive enum variants cannot be constructed in external crates and cannot be matched against.
§source: Error
§

MissingHandledAccess

Missing call to RulesetAttr::handle_access().

+

Trait Implementations§

source§

impl Debug for CreateRulesetError

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Display for CreateRulesetError

source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Error for CreateRulesetError

source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
source§

impl From<CreateRulesetError> for RulesetError

source§

fn from(source: CreateRulesetError) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/enum.HandleAccessError.html b/landlock/enum.HandleAccessError.html new file mode 100644 index 0000000..e8d043b --- /dev/null +++ b/landlock/enum.HandleAccessError.html @@ -0,0 +1,31 @@ +HandleAccessError in landlock - Rust

Enum landlock::HandleAccessError

source ·
#[non_exhaustive]
pub enum HandleAccessError<T>
where + T: Access,
{ + Compat(CompatError<T>), +}
Expand description

Identifies errors when updating the ruleset’s handled access-rights.

+

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

Compat(CompatError<T>)

Trait Implementations§

source§

impl<T> Debug for HandleAccessError<T>
where + T: Access + Debug,

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<T> Display for HandleAccessError<T>
where + T: Access, + CompatError<T>: Display,

source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<T> Error for HandleAccessError<T>
where + T: Access, + CompatError<T>: Error, + Self: Debug + Display,

source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
source§

impl<T> From<CompatError<T>> for HandleAccessError<T>
where + T: Access,

source§

fn from(source: CompatError<T>) -> Self

Converts to this type from the input type.
source§

impl<A> From<HandleAccessError<A>> for HandleAccessesError
where + A: Access,

source§

fn from(error: HandleAccessError<A>) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl<T> Freeze for HandleAccessError<T>
where + <T as RawBitFlags>::Numeric: Freeze,

§

impl<T> !RefUnwindSafe for HandleAccessError<T>

§

impl<T> Send for HandleAccessError<T>
where + <T as RawBitFlags>::Numeric: Send, + T: Send,

§

impl<T> Sync for HandleAccessError<T>
where + <T as RawBitFlags>::Numeric: Sync, + T: Sync,

§

impl<T> Unpin for HandleAccessError<T>
where + <T as RawBitFlags>::Numeric: Unpin, + T: Unpin,

§

impl<T> !UnwindSafe for HandleAccessError<T>

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/enum.HandleAccessesError.html b/landlock/enum.HandleAccessesError.html new file mode 100644 index 0000000..9910190 --- /dev/null +++ b/landlock/enum.HandleAccessesError.html @@ -0,0 +1,16 @@ +HandleAccessesError in landlock - Rust

Enum landlock::HandleAccessesError

source ·
#[non_exhaustive]
pub enum HandleAccessesError { + Fs(HandleAccessError<AccessFs>), + Net(HandleAccessError<AccessNet>), +}

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.

Trait Implementations§

source§

impl Debug for HandleAccessesError

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Display for HandleAccessesError

source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Error for HandleAccessesError

source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
source§

impl<A> From<HandleAccessError<A>> for HandleAccessesError
where + A: Access,

source§

fn from(error: HandleAccessError<A>) -> Self

Converts to this type from the input type.
source§

impl From<HandleAccessesError> for RulesetError

source§

fn from(source: HandleAccessesError) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/enum.PathBeneathError.html b/landlock/enum.PathBeneathError.html new file mode 100644 index 0000000..c22bfc3 --- /dev/null +++ b/landlock/enum.PathBeneathError.html @@ -0,0 +1,29 @@ +PathBeneathError in landlock - Rust

Enum landlock::PathBeneathError

source ·
#[non_exhaustive]
pub enum PathBeneathError { + StatCall { + source: Error, + }, + DirectoryAccess { + access: BitFlags<AccessFs>, + incompatible: BitFlags<AccessFs>, + }, +}

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

StatCall

To check that access-rights are consistent with a file descriptor, a call to +RulesetCreatedAttr::add_rule() +looks at the file type with an fstat() system call.

+

Fields

This variant is marked as non-exhaustive
Non-exhaustive enum variants could have additional fields added in future. Therefore, non-exhaustive enum variants cannot be constructed in external crates and cannot be matched against.
§source: Error
§

DirectoryAccess

This error is returned by +RulesetCreatedAttr::add_rule() +if the related PathBeneath object is not set to best-effort, +and if its allowed access-rights contain directory-only ones +whereas the file descriptor doesn’t point to a directory.

+

Fields

§incompatible: BitFlags<AccessFs>

Trait Implementations§

source§

impl Debug for PathBeneathError

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Display for PathBeneathError

source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Error for PathBeneathError

source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
source§

impl<T> From<PathBeneathError> for CompatError<T>
where + T: Access,

source§

fn from(source: PathBeneathError) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/enum.PathFdError.html b/landlock/enum.PathFdError.html new file mode 100644 index 0000000..302c60d --- /dev/null +++ b/landlock/enum.PathFdError.html @@ -0,0 +1,18 @@ +PathFdError in landlock - Rust

Enum landlock::PathFdError

source ·
#[non_exhaustive]
pub enum PathFdError { + OpenCall { + source: Error, + path: PathBuf, + }, +}

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

OpenCall

The open() system call failed.

+

Fields

This variant is marked as non-exhaustive
Non-exhaustive enum variants could have additional fields added in future. Therefore, non-exhaustive enum variants cannot be constructed in external crates and cannot be matched against.
§source: Error
§path: PathBuf

Trait Implementations§

source§

impl Debug for PathFdError

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Display for PathFdError

source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Error for PathFdError

source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/enum.RestrictSelfError.html b/landlock/enum.RestrictSelfError.html new file mode 100644 index 0000000..da0ff29 --- /dev/null +++ b/landlock/enum.RestrictSelfError.html @@ -0,0 +1,21 @@ +RestrictSelfError in landlock - Rust

Enum landlock::RestrictSelfError

source ·
#[non_exhaustive]
pub enum RestrictSelfError { + SetNoNewPrivsCall { + source: Error, + }, + RestrictSelfCall { + source: Error, + }, +}

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

SetNoNewPrivsCall

The prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) system call failed.

+

Fields

This variant is marked as non-exhaustive
Non-exhaustive enum variants could have additional fields added in future. Therefore, non-exhaustive enum variants cannot be constructed in external crates and cannot be matched against.
§source: Error
§

RestrictSelfCall

The landlock_restrict_self() system call failed.

+

Fields

This variant is marked as non-exhaustive
Non-exhaustive enum variants could have additional fields added in future. Therefore, non-exhaustive enum variants cannot be constructed in external crates and cannot be matched against.
§source: Error

Trait Implementations§

source§

impl Debug for RestrictSelfError

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Display for RestrictSelfError

source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Error for RestrictSelfError

source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
source§

impl From<RestrictSelfError> for RulesetError

source§

fn from(source: RestrictSelfError) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/enum.RulesetError.html b/landlock/enum.RulesetError.html new file mode 100644 index 0000000..7fb0901 --- /dev/null +++ b/landlock/enum.RulesetError.html @@ -0,0 +1,18 @@ +RulesetError in landlock - Rust

Enum landlock::RulesetError

source ·
#[non_exhaustive]
pub enum RulesetError { + HandleAccesses(HandleAccessesError), + CreateRuleset(CreateRulesetError), + AddRules(AddRulesError), + RestrictSelf(RestrictSelfError), +}
Expand description

Maps to all errors that can be returned by a ruleset action.

+

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

HandleAccesses(HandleAccessesError)

§

CreateRuleset(CreateRulesetError)

§

AddRules(AddRulesError)

§

RestrictSelf(RestrictSelfError)

Trait Implementations§

source§

impl Debug for RulesetError

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Display for RulesetError

source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Error for RulesetError

source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
source§

impl From<AddRulesError> for RulesetError

source§

fn from(source: AddRulesError) -> Self

Converts to this type from the input type.
source§

impl From<CreateRulesetError> for RulesetError

source§

fn from(source: CreateRulesetError) -> Self

Converts to this type from the input type.
source§

impl From<HandleAccessesError> for RulesetError

source§

fn from(source: HandleAccessesError) -> Self

Converts to this type from the input type.
source§

impl From<RestrictSelfError> for RulesetError

source§

fn from(source: RestrictSelfError) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/enum.RulesetStatus.html b/landlock/enum.RulesetStatus.html new file mode 100644 index 0000000..f998328 --- /dev/null +++ b/landlock/enum.RulesetStatus.html @@ -0,0 +1,23 @@ +RulesetStatus in landlock - Rust

Enum landlock::RulesetStatus

source ·
pub enum RulesetStatus {
+    FullyEnforced,
+    PartiallyEnforced,
+    NotEnforced,
+}
Expand description

Enforcement status of a ruleset.

+

Variants§

§

FullyEnforced

All requested restrictions are enforced.

+
§

PartiallyEnforced

Some requested restrictions are enforced, +following a best-effort approach.

+
§

NotEnforced

The running system doesn’t support Landlock +or a subset of the requested Landlock features.

+

Trait Implementations§

source§

impl Debug for RulesetStatus

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl PartialEq for RulesetStatus

source§

fn eq(&self, other: &RulesetStatus) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Eq for RulesetStatus

source§

impl StructuralPartialEq for RulesetStatus

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/errors/enum.AccessError.html b/landlock/errors/enum.AccessError.html new file mode 100644 index 0000000..4b83eb9 --- /dev/null +++ b/landlock/errors/enum.AccessError.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/enum.AccessError.html...

+ + + \ No newline at end of file diff --git a/landlock/errors/enum.AddRuleError.html b/landlock/errors/enum.AddRuleError.html new file mode 100644 index 0000000..14c0c6f --- /dev/null +++ b/landlock/errors/enum.AddRuleError.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/enum.AddRuleError.html...

+ + + \ No newline at end of file diff --git a/landlock/errors/enum.AddRulesError.html b/landlock/errors/enum.AddRulesError.html new file mode 100644 index 0000000..3b9bd3c --- /dev/null +++ b/landlock/errors/enum.AddRulesError.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/enum.AddRulesError.html...

+ + + \ No newline at end of file diff --git a/landlock/errors/enum.CompatError.html b/landlock/errors/enum.CompatError.html new file mode 100644 index 0000000..ce6d875 --- /dev/null +++ b/landlock/errors/enum.CompatError.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/enum.CompatError.html...

+ + + \ No newline at end of file diff --git a/landlock/errors/enum.CreateRulesetError.html b/landlock/errors/enum.CreateRulesetError.html new file mode 100644 index 0000000..bea5d20 --- /dev/null +++ b/landlock/errors/enum.CreateRulesetError.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/enum.CreateRulesetError.html...

+ + + \ No newline at end of file diff --git a/landlock/errors/enum.HandleAccessError.html b/landlock/errors/enum.HandleAccessError.html new file mode 100644 index 0000000..950acf3 --- /dev/null +++ b/landlock/errors/enum.HandleAccessError.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/enum.HandleAccessError.html...

+ + + \ No newline at end of file diff --git a/landlock/errors/enum.HandleAccessesError.html b/landlock/errors/enum.HandleAccessesError.html new file mode 100644 index 0000000..86b8f0a --- /dev/null +++ b/landlock/errors/enum.HandleAccessesError.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/enum.HandleAccessesError.html...

+ + + \ No newline at end of file diff --git a/landlock/errors/enum.PathBeneathError.html b/landlock/errors/enum.PathBeneathError.html new file mode 100644 index 0000000..d66ac0c --- /dev/null +++ b/landlock/errors/enum.PathBeneathError.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/enum.PathBeneathError.html...

+ + + \ No newline at end of file diff --git a/landlock/errors/enum.PathFdError.html b/landlock/errors/enum.PathFdError.html new file mode 100644 index 0000000..82c43dc --- /dev/null +++ b/landlock/errors/enum.PathFdError.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/enum.PathFdError.html...

+ + + \ No newline at end of file diff --git a/landlock/errors/enum.RestrictSelfError.html b/landlock/errors/enum.RestrictSelfError.html new file mode 100644 index 0000000..9c8f1e0 --- /dev/null +++ b/landlock/errors/enum.RestrictSelfError.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/enum.RestrictSelfError.html...

+ + + \ No newline at end of file diff --git a/landlock/errors/enum.RulesetError.html b/landlock/errors/enum.RulesetError.html new file mode 100644 index 0000000..869ce9e --- /dev/null +++ b/landlock/errors/enum.RulesetError.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/enum.RulesetError.html...

+ + + \ No newline at end of file diff --git a/landlock/fn.path_beneath_rules.html b/landlock/fn.path_beneath_rules.html new file mode 100644 index 0000000..9d941c5 --- /dev/null +++ b/landlock/fn.path_beneath_rules.html @@ -0,0 +1,35 @@ +path_beneath_rules in landlock - Rust

Function landlock::path_beneath_rules

source ·
pub fn path_beneath_rules<I, P, A>(
+    paths: I,
+    access: A,
+) -> impl Iterator<Item = Result<PathBeneath<PathFd>, RulesetError>>
where + I: IntoIterator<Item = P>, + P: AsRef<Path>, + A: Into<BitFlags<AccessFs>>,
Expand description

Helper to quickly create an iterator of PathBeneath rules.

+

Silently ignores paths that cannot be opened, and automatically adjust access rights according +to file types when possible.

+

§Example

+
use landlock::{
+    ABI, Access, AccessFs, Ruleset, RulesetAttr, RulesetCreatedAttr, RulesetStatus, RulesetError,
+    path_beneath_rules,
+};
+
+fn restrict_thread() -> Result<(), RulesetError> {
+    let abi = ABI::V1;
+    let status = Ruleset::default()
+        .handle_access(AccessFs::from_all(abi))?
+        .create()?
+        // Read-only access to /usr, /etc and /dev.
+        .add_rules(path_beneath_rules(&["/usr", "/etc", "/dev"], AccessFs::from_read(abi)))?
+        // Read-write access to /home and /tmp.
+        .add_rules(path_beneath_rules(&["/home", "/tmp"], AccessFs::from_all(abi)))?
+        .restrict_self()?;
+    match status.ruleset {
+        // The FullyEnforced case must be tested by the developer.
+        RulesetStatus::FullyEnforced => println!("Fully sandboxed."),
+        RulesetStatus::PartiallyEnforced => println!("Partially sandboxed."),
+        // Users should be warned that they are not protected.
+        RulesetStatus::NotEnforced => println!("Not sandboxed! Please update your kernel."),
+    }
+    Ok(())
+}
+
\ No newline at end of file diff --git a/landlock/fs/enum.AccessFs.html b/landlock/fs/enum.AccessFs.html new file mode 100644 index 0000000..a47ebbe --- /dev/null +++ b/landlock/fs/enum.AccessFs.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/enum.AccessFs.html...

+ + + \ No newline at end of file diff --git a/landlock/fs/fn.path_beneath_rules.html b/landlock/fs/fn.path_beneath_rules.html new file mode 100644 index 0000000..db8131e --- /dev/null +++ b/landlock/fs/fn.path_beneath_rules.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/fn.path_beneath_rules.html...

+ + + \ No newline at end of file diff --git a/landlock/fs/struct.PathBeneath.html b/landlock/fs/struct.PathBeneath.html new file mode 100644 index 0000000..79705cb --- /dev/null +++ b/landlock/fs/struct.PathBeneath.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/struct.PathBeneath.html...

+ + + \ No newline at end of file diff --git a/landlock/fs/struct.PathFd.html b/landlock/fs/struct.PathFd.html new file mode 100644 index 0000000..31db2d0 --- /dev/null +++ b/landlock/fs/struct.PathFd.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/struct.PathFd.html...

+ + + \ No newline at end of file diff --git a/landlock/index.html b/landlock/index.html new file mode 100644 index 0000000..55144fe --- /dev/null +++ b/landlock/index.html @@ -0,0 +1,70 @@ +landlock - Rust

Crate landlock

source ·
Expand description

Landlock is a security feature available since Linux 5.13. +The goal is to enable to restrict ambient rights +(e.g., global filesystem access) +for a set of processes by creating safe security sandboxes as new security layers +in addition to the existing system-wide access-controls. +This kind of sandbox is expected to help mitigate the security impact of bugs, +unexpected or malicious behaviors in applications. +Landlock empowers any process, including unprivileged ones, to securely restrict themselves. +More information about Landlock can be found in the official website.

+

This crate provides a safe abstraction for the Landlock system calls, along with some helpers.

+

Minimum Supported Rust Version (MSRV): 1.63

+

§Use cases

+

This crate is especially useful to protect users’ data by sandboxing:

+
    +
  • trusted applications dealing with potentially malicious data +(e.g., complex file format, network request) that could exploit security vulnerabilities;
  • +
  • sandbox managers, container runtimes or shells launching untrusted applications.
  • +
+

§Examples

+

A simple example can be found with the path_beneath_rules() helper. +More complex examples can be found with the Ruleset documentation +and the sandboxer example.

+

§Current limitations

+

This crate exposes the Landlock features available as of Linux 5.19 +and then inherits some kernel limitations +that will be addressed with future kernel releases +(e.g., arbitrary mounts are always denied).

+

§Compatibility

+

Types defined in this crate are designed to enable the strictest Landlock configuration +for the given kernel on which the program runs. +In the default best-effort mode, +Ruleset will determine compatibility +with the intersection of the currently running kernel’s features +and those required by the caller. +This way, callers can distinguish between +Landlock compatibility issues inherent to the current system +(e.g., file names that don’t exist) +and misconfiguration that should be fixed in the program +(e.g., empty or inconsistent access rights). +RulesetError identifies such kind of errors.

+

With set_compatibility(CompatLevel::BestEffort), +users of the crate may mark Landlock features that are deemed required +and other features that may be downgraded to use lower security on systems +where they can’t be enforced. +It is discouraged to compare the system’s provided Landlock ABI version directly, +as it is difficult to track detailed ABI differences +which are handled thanks to the Compatible trait.

+

To make it easier to migrate to a new version of this library, +we use the builder pattern +and designed objects to require the minimal set of method arguments. +Most enum are marked as non_exhaustive to enable backward-compatible evolutions.

+

§Test strategy

+

Developers should test their sandboxed applications +with a kernel that supports all requested Landlock features +and check that RulesetCreated::restrict_self() returns a status matching +Ok(RestrictionStatus { ruleset: RulesetStatus::FullyEnforced, no_new_privs: true, }) +to make sure everything works as expected in an enforced sandbox. +Alternatively, using set_compatibility(CompatLevel::HardRequirement) +will immediately inform about unsupported Landlock features. +These configurations should only depend on the test environment +(e.g. by checking an environment variable). +However, applications should only check that no error is returned (i.e. Ok(_)) +and optionally log and inform users that the application is not fully sandboxed +because of missing features from the running kernel.

+

Macros§

  • make_bitflags! provides a succint syntax for creating instances of +BitFlags<T>. Instead of repeating the name of your type for each flag +you want to add, try make_bitflags!(Flags::{Foo | Bar}).

Structs§

Enums§

Traits§

Functions§

\ No newline at end of file diff --git a/landlock/macro.make_bitflags!.html b/landlock/macro.make_bitflags!.html new file mode 100644 index 0000000..1b46a59 --- /dev/null +++ b/landlock/macro.make_bitflags!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.make_bitflags.html...

+ + + \ No newline at end of file diff --git a/landlock/macro.make_bitflags.html b/landlock/macro.make_bitflags.html new file mode 100644 index 0000000..ea525f5 --- /dev/null +++ b/landlock/macro.make_bitflags.html @@ -0,0 +1,18 @@ +make_bitflags in landlock - Rust

Macro landlock::make_bitflags

macro_rules! make_bitflags {
+    ( $enum:ident ::{ $($variant:ident)|* } ) => { ... };
+}
Expand description

make_bitflags! provides a succint syntax for creating instances of +BitFlags<T>. Instead of repeating the name of your type for each flag +you want to add, try make_bitflags!(Flags::{Foo | Bar}).

+ +
use enumflags2::{bitflags, make_bitflags};
+#[bitflags]
+#[repr(u8)]
+#[derive(Clone, Copy, Debug)]
+enum Test {
+    A = 1 << 0,
+    B = 1 << 1,
+    C = 1 << 2,
+}
+let x = make_bitflags!(Test::{A | C});
+assert_eq!(x, Test::A | Test::C);
+
\ No newline at end of file diff --git a/landlock/net/enum.AccessNet.html b/landlock/net/enum.AccessNet.html new file mode 100644 index 0000000..8bcd384 --- /dev/null +++ b/landlock/net/enum.AccessNet.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/enum.AccessNet.html...

+ + + \ No newline at end of file diff --git a/landlock/net/struct.NetPort.html b/landlock/net/struct.NetPort.html new file mode 100644 index 0000000..898e381 --- /dev/null +++ b/landlock/net/struct.NetPort.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/struct.NetPort.html...

+ + + \ No newline at end of file diff --git a/landlock/ruleset/enum.RulesetStatus.html b/landlock/ruleset/enum.RulesetStatus.html new file mode 100644 index 0000000..c92e750 --- /dev/null +++ b/landlock/ruleset/enum.RulesetStatus.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/enum.RulesetStatus.html...

+ + + \ No newline at end of file diff --git a/landlock/ruleset/struct.RestrictionStatus.html b/landlock/ruleset/struct.RestrictionStatus.html new file mode 100644 index 0000000..63e2f53 --- /dev/null +++ b/landlock/ruleset/struct.RestrictionStatus.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/struct.RestrictionStatus.html...

+ + + \ No newline at end of file diff --git a/landlock/ruleset/struct.Ruleset.html b/landlock/ruleset/struct.Ruleset.html new file mode 100644 index 0000000..2906cf1 --- /dev/null +++ b/landlock/ruleset/struct.Ruleset.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/struct.Ruleset.html...

+ + + \ No newline at end of file diff --git a/landlock/ruleset/struct.RulesetCreated.html b/landlock/ruleset/struct.RulesetCreated.html new file mode 100644 index 0000000..79f9ca0 --- /dev/null +++ b/landlock/ruleset/struct.RulesetCreated.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/struct.RulesetCreated.html...

+ + + \ No newline at end of file diff --git a/landlock/ruleset/trait.Rule.html b/landlock/ruleset/trait.Rule.html new file mode 100644 index 0000000..1cb6b90 --- /dev/null +++ b/landlock/ruleset/trait.Rule.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/trait.Rule.html...

+ + + \ No newline at end of file diff --git a/landlock/ruleset/trait.RulesetAttr.html b/landlock/ruleset/trait.RulesetAttr.html new file mode 100644 index 0000000..f3e9c57 --- /dev/null +++ b/landlock/ruleset/trait.RulesetAttr.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/trait.RulesetAttr.html...

+ + + \ No newline at end of file diff --git a/landlock/ruleset/trait.RulesetCreatedAttr.html b/landlock/ruleset/trait.RulesetCreatedAttr.html new file mode 100644 index 0000000..35cff5e --- /dev/null +++ b/landlock/ruleset/trait.RulesetCreatedAttr.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../landlock/trait.RulesetCreatedAttr.html...

+ + + \ No newline at end of file diff --git a/landlock/sidebar-items.js b/landlock/sidebar-items.js new file mode 100644 index 0000000..3121fb2 --- /dev/null +++ b/landlock/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["ABI","AccessError","AccessFs","AccessNet","AddRuleError","AddRulesError","CompatError","CompatLevel","CreateRulesetError","HandleAccessError","HandleAccessesError","PathBeneathError","PathFdError","RestrictSelfError","RulesetError","RulesetStatus"],"fn":["path_beneath_rules"],"macro":["make_bitflags"],"struct":["BitFlags","NetPort","PathBeneath","PathFd","RestrictionStatus","Ruleset","RulesetCreated"],"trait":["Access","Compatible","Rule","RulesetAttr","RulesetCreatedAttr"]}; \ No newline at end of file diff --git a/landlock/struct.BitFlags.html b/landlock/struct.BitFlags.html new file mode 100644 index 0000000..c8edaa3 --- /dev/null +++ b/landlock/struct.BitFlags.html @@ -0,0 +1,399 @@ +BitFlags in landlock - Rust

Struct landlock::BitFlags

pub struct BitFlags<T, N = <T as RawBitFlags>::Numeric> { /* private fields */ }
Expand description

Represents a set of flags of some type T. +T must have the #[bitflags] attribute applied.

+

A BitFlags<T> is as large as the T itself, +and stores one flag per bit.

+

§Comparison operators, PartialOrd and Ord

+

To make it possible to use BitFlags as the key of a +[BTreeMap][std::collections::BTreeMap], BitFlags implements +Ord. There is no meaningful total order for bitflags, +so the implementation simply compares the integer values of the bits.

+

Unfortunately, this means that comparing BitFlags with an operator +like <= will compile, and return values that are probably useless +and not what you expect. In particular, <= does not check whether +one value is a subset of the other. Use BitFlags::contains for that.

+

§Customizing Default

+

By default, creating an instance of BitFlags<T> with Default will result +in an empty set. If that’s undesirable, you may customize this:

+ +
#[bitflags(default = B | C)]
+#[repr(u8)]
+#[derive(Copy, Clone, Debug, PartialEq)]
+enum MyFlag {
+    A = 0b0001,
+    B = 0b0010,
+    C = 0b0100,
+    D = 0b1000,
+}
+
+assert_eq!(BitFlags::default(), MyFlag::B | MyFlag::C);
+

§Memory layout

+

BitFlags<T> is marked with the #[repr(transparent)] trait, meaning +it can be safely transmuted into the corresponding numeric type.

+

Usually, the same can be achieved by using BitFlags::bits in one +direction, and BitFlags::from_bits, BitFlags::from_bits_truncate, +or BitFlags::from_bits_unchecked in the other direction. However, +transmuting might still be useful if, for example, you’re dealing with +an entire array of BitFlags.

+

When transmuting into a BitFlags, make sure that each set bit +corresponds to an existing flag +(cf. from_bits_unchecked).

+

For example:

+ +
#[bitflags]
+#[repr(u8)] // <-- the repr determines the numeric type
+#[derive(Copy, Clone)]
+enum TransmuteMe {
+    One = 1 << 0,
+    Two = 1 << 1,
+}
+
+// NOTE: we use a small, self-contained function to handle the slice
+// conversion to make sure the lifetimes are right.
+fn transmute_slice<'a>(input: &'a [BitFlags<TransmuteMe>]) -> &'a [u8] {
+    unsafe {
+        slice::from_raw_parts(input.as_ptr() as *const u8, input.len())
+    }
+}
+
+let many_flags = &[
+    TransmuteMe::One.into(),
+    TransmuteMe::One | TransmuteMe::Two,
+];
+
+let as_nums = transmute_slice(many_flags);
+assert_eq!(as_nums, &[0b01, 0b11]);
+

§Implementation notes

+

You might expect this struct to be defined as

+ +
struct BitFlags<T: BitFlag> {
+    value: T::Numeric
+}
+

Ideally, that would be the case. However, because const fns cannot +have trait bounds in current Rust, this would prevent us from providing +most const fn APIs. As a workaround, we define BitFlags with two +type parameters, with a default for the second one:

+ +
struct BitFlags<T, N = <T as BitFlag>::Numeric> {
+    value: N,
+    marker: PhantomData<T>,
+}
+

Manually providing a type for the N type parameter shouldn’t ever +be necessary.

+

The types substituted for T and N must always match, creating a +BitFlags value where that isn’t the case is only possible with +incorrect unsafe code.

+

Implementations§

§

impl<T> BitFlags<T>
where + T: BitFlag,

pub fn iter(self) -> Iter<T>

Iterate over the BitFlags.

+ +
let flags = make_bitflags!(MyFlag::{A | C});
+
+flags.iter()
+    .for_each(|flag| println!("{:?}", flag));
+
§

impl<T> BitFlags<T>
where + T: BitFlag,

pub const EMPTY: BitFlags<T> = _

An empty BitFlags. Equivalent to empty(), +but works in a const context.

+

pub const ALL: BitFlags<T> = _

A BitFlags with all flags set. Equivalent to all(), +but works in a const context.

+

pub const CONST_TOKEN: ConstToken<T, <T as RawBitFlags>::Numeric> = _

A [ConstToken] for this type of flag.

+
§

impl<T> BitFlags<T, u8>

pub const unsafe fn from_bits_unchecked_c( + val: u8, + const_token: ConstToken<T, u8>, +) -> BitFlags<T, u8>

Create a new BitFlags unsafely, without checking if the bits form +a valid bit pattern for the type.

+

Const variant of +from_bits_unchecked.

+

Consider using +from_bits_truncate_c instead.

+
§Safety
+

All bits set in val must correspond to a value of the enum.

+

pub const fn from_bits_truncate_c( + bits: u8, + const_token: ConstToken<T, u8>, +) -> BitFlags<T, u8>

Create a BitFlags<T> from an underlying bitwise value. If any +invalid bits are set, ignore them.

+ +
#[bitflags]
+#[repr(u8)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+enum MyFlag {
+    One = 1 << 0,
+    Two = 1 << 1,
+    Three = 1 << 2,
+}
+
+const FLAGS: BitFlags<MyFlag> =
+    BitFlags::<MyFlag>::from_bits_truncate_c(0b10101010, BitFlags::CONST_TOKEN);
+assert_eq!(FLAGS, MyFlag::Two);
+

pub const fn union_c(self, other: BitFlags<T, u8>) -> BitFlags<T, u8>

Bitwise OR — return value contains flag if either argument does.

+

Also available as a | b, but operator overloads are not usable +in const fns at the moment.

+

pub const fn intersection_c(self, other: BitFlags<T, u8>) -> BitFlags<T, u8>

Bitwise AND — return value contains flag if both arguments do.

+

Also available as a & b, but operator overloads are not usable +in const fns at the moment.

+

pub const fn not_c(self, const_token: ConstToken<T, u8>) -> BitFlags<T, u8>

Bitwise NOT — return value contains flag if argument doesn’t.

+

Also available as !a, but operator overloads are not usable +in const fns at the moment.

+

Moreover, due to const fn limitations, not_c needs a +[ConstToken] as an argument.

+ +
#[bitflags]
+#[repr(u8)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+enum MyFlag {
+    One = 1 << 0,
+    Two = 1 << 1,
+    Three = 1 << 2,
+}
+
+const FLAGS: BitFlags<MyFlag> = make_bitflags!(MyFlag::{One | Two});
+const NEGATED: BitFlags<MyFlag> = FLAGS.not_c(BitFlags::CONST_TOKEN);
+assert_eq!(NEGATED, MyFlag::Three);
+

pub const fn bits_c(self) -> u8

Returns the underlying bitwise value.

+

const variant of bits.

+
§

impl<T> BitFlags<T>
where + T: BitFlag,

pub fn from_bits( + bits: <T as RawBitFlags>::Numeric, +) -> Result<BitFlags<T>, FromBitsError<T>>

Create a BitFlags if the raw value provided does not contain +any illegal flags.

+

See also: [a convenience re-export in the BitFlag trait][BitFlag::from_bits], +which can help avoid the need for type hints.

+ +
#[bitflags]
+#[repr(u8)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+enum MyFlag {
+    One = 1 << 0,
+    Two = 1 << 1,
+    Three = 1 << 2,
+}
+
+let flags: BitFlags<MyFlag> = BitFlags::from_bits(0b11).unwrap();
+assert_eq!(flags.contains(MyFlag::One), true);
+assert_eq!(flags.contains(MyFlag::Two), true);
+assert_eq!(flags.contains(MyFlag::Three), false);
+let invalid = BitFlags::<MyFlag>::from_bits(1 << 3);
+assert!(invalid.is_err());
+

pub fn from_bits_truncate(bits: <T as RawBitFlags>::Numeric) -> BitFlags<T>

Create a BitFlags from an underlying bitwise value. If any +invalid bits are set, ignore them.

+

See also: [a convenience re-export in the BitFlag trait][BitFlag::from_bits_truncate], +which can help avoid the need for type hints.

+ +
#[bitflags]
+#[repr(u8)]
+#[derive(Clone, Copy, PartialEq, Eq)]
+enum MyFlag {
+    One = 1 << 0,
+    Two = 1 << 1,
+    Three = 1 << 2,
+}
+
+let flags: BitFlags<MyFlag> = BitFlags::from_bits_truncate(0b1_1011);
+assert_eq!(flags.contains(MyFlag::One), true);
+assert_eq!(flags.contains(MyFlag::Two), true);
+assert_eq!(flags.contains(MyFlag::Three), false);
+

pub unsafe fn from_bits_unchecked( + val: <T as RawBitFlags>::Numeric, +) -> BitFlags<T>

Create a new BitFlags unsafely, without checking if the bits form +a valid bit pattern for the type.

+

Consider using from_bits +or from_bits_truncate instead.

+
§Safety
+

All bits set in val must correspond to a value of the enum.

+
§Example
+
#[bitflags]
+#[repr(u8)]
+#[derive(Clone, Copy, PartialEq, Eq)]
+enum MyFlag {
+    One = 1 << 0,
+    Two = 1 << 1,
+    Three = 1 << 2,
+}
+
+let flags: BitFlags<MyFlag> = unsafe {
+    BitFlags::from_bits_unchecked(0b011)
+};
+
+assert_eq!(flags.contains(MyFlag::One), true);
+assert_eq!(flags.contains(MyFlag::Two), true);
+assert_eq!(flags.contains(MyFlag::Three), false);
+

pub fn from_flag(flag: T) -> BitFlags<T>

Turn a T into a BitFlags<T>. Also available as flag.into().

+

pub fn empty() -> BitFlags<T>

Create a BitFlags with no flags set (in other words, with a value of 0).

+

See also: [BitFlag::empty], a convenience reexport; +BitFlags::EMPTY, the same functionality available +as a constant for const fn code.

+ +
#[bitflags]
+#[repr(u8)]
+#[derive(Clone, Copy, PartialEq, Eq)]
+enum MyFlag {
+    One = 1 << 0,
+    Two = 1 << 1,
+    Three = 1 << 2,
+}
+
+let empty: BitFlags<MyFlag> = BitFlags::empty();
+assert!(empty.is_empty());
+assert_eq!(empty.contains(MyFlag::One), false);
+assert_eq!(empty.contains(MyFlag::Two), false);
+assert_eq!(empty.contains(MyFlag::Three), false);
+

pub fn all() -> BitFlags<T>

Create a BitFlags with all flags set.

+

See also: [BitFlag::all], a convenience reexport; +BitFlags::ALL, the same functionality available +as a constant for const fn code.

+ +
#[bitflags]
+#[repr(u8)]
+#[derive(Clone, Copy, PartialEq, Eq)]
+enum MyFlag {
+    One = 1 << 0,
+    Two = 1 << 1,
+    Three = 1 << 2,
+}
+
+let empty: BitFlags<MyFlag> = BitFlags::all();
+assert!(empty.is_all());
+assert_eq!(empty.contains(MyFlag::One), true);
+assert_eq!(empty.contains(MyFlag::Two), true);
+assert_eq!(empty.contains(MyFlag::Three), true);
+

pub fn is_all(self) -> bool

Returns true if all flags are set

+

pub fn is_empty(self) -> bool

Returns true if no flag is set

+

pub fn len(self) -> usize

Returns the number of flags set.

+

pub fn exactly_one(self) -> Option<T>

If exactly one flag is set, the flag is returned. Otherwise, returns None.

+

See also Itertools::exactly_one.

+

pub fn bits(self) -> <T as RawBitFlags>::Numeric

Returns the underlying bitwise value.

+ +
#[bitflags]
+#[repr(u8)]
+#[derive(Clone, Copy)]
+enum Flags {
+    Foo = 1 << 0,
+    Bar = 1 << 1,
+}
+
+let both_flags = Flags::Foo | Flags::Bar;
+assert_eq!(both_flags.bits(), 0b11);
+

pub fn intersects<B>(self, other: B) -> bool
where + B: Into<BitFlags<T>>,

Returns true if at least one flag is shared.

+

pub fn contains<B>(self, other: B) -> bool
where + B: Into<BitFlags<T>>,

Returns true if all flags are contained.

+

pub fn toggle<B>(&mut self, other: B)
where + B: Into<BitFlags<T>>,

Toggles the matching bits

+

pub fn insert<B>(&mut self, other: B)
where + B: Into<BitFlags<T>>,

Inserts the flags into the BitFlag

+

pub fn remove<B>(&mut self, other: B)
where + B: Into<BitFlags<T>>,

Removes the matching flags

+

pub fn set<B>(&mut self, other: B, cond: bool)
where + B: Into<BitFlags<T>>,

Inserts if cond holds, else removes

+ +
#[bitflags]
+#[derive(Clone, Copy, PartialEq, Debug)]
+#[repr(u8)]
+enum MyFlag {
+    A = 1 << 0,
+    B = 1 << 1,
+    C = 1 << 2,
+}
+
+let mut state = MyFlag::A | MyFlag::C;
+state.set(MyFlag::A | MyFlag::B, false);
+
+// Because the condition was false, both
+// `A` and `B` are removed from the set
+assert_eq!(state, MyFlag::C);
+

Trait Implementations§

§

impl<T> Binary for BitFlags<T>
where + T: BitFlag, + <T as RawBitFlags>::Numeric: Binary,

§

fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
§

impl<T, B> BitAnd<B> for BitFlags<T>
where + T: BitFlag, + B: Into<BitFlags<T>>,

§

type Output = BitFlags<T>

The resulting type after applying the & operator.
§

fn bitand(self, other: B) -> BitFlags<T>

Performs the & operation. Read more
§

impl<T, B> BitAndAssign<B> for BitFlags<T>
where + T: BitFlag, + B: Into<BitFlags<T>>,

§

fn bitand_assign(&mut self, other: B)

Performs the &= operation. Read more
§

impl<T, B> BitOr<B> for BitFlags<T>
where + T: BitFlag, + B: Into<BitFlags<T>>,

§

type Output = BitFlags<T>

The resulting type after applying the | operator.
§

fn bitor(self, other: B) -> BitFlags<T>

Performs the | operation. Read more
§

impl<T, B> BitOrAssign<B> for BitFlags<T>
where + T: BitFlag, + B: Into<BitFlags<T>>,

§

fn bitor_assign(&mut self, other: B)

Performs the |= operation. Read more
§

impl<T, B> BitXor<B> for BitFlags<T>
where + T: BitFlag, + B: Into<BitFlags<T>>,

§

type Output = BitFlags<T>

The resulting type after applying the ^ operator.
§

fn bitxor(self, other: B) -> BitFlags<T>

Performs the ^ operation. Read more
§

impl<T, B> BitXorAssign<B> for BitFlags<T>
where + T: BitFlag, + B: Into<BitFlags<T>>,

§

fn bitxor_assign(&mut self, other: B)

Performs the ^= operation. Read more
§

impl<T, N> Clone for BitFlags<T, N>
where + T: Clone, + N: Clone,

§

fn clone(&self) -> BitFlags<T, N>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
§

impl<T> Debug for BitFlags<T>
where + T: BitFlag + Debug,

§

fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
§

impl<T> Default for BitFlags<T>
where + T: BitFlag,

The default value returned is one with all flags unset, i. e. empty, +unless customized.

+
§

fn default() -> BitFlags<T>

Returns the “default value” for a type. Read more
§

impl<T> Display for BitFlags<T>
where + T: BitFlag + Debug,

§

fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
§

impl<T, B> Extend<B> for BitFlags<T>
where + T: BitFlag, + B: Into<BitFlags<T>>,

§

fn extend<I>(&mut self, it: I)
where + I: IntoIterator<Item = B>,

Extends a collection with the contents of an iterator. Read more
source§

fn extend_one(&mut self, item: A)

🔬This is a nightly-only experimental API. (extend_one)
Extends a collection with exactly one element.
source§

fn extend_reserve(&mut self, additional: usize)

🔬This is a nightly-only experimental API. (extend_one)
Reserves capacity in a collection for the given number of additional elements. Read more
§

impl<T> From<T> for BitFlags<T>
where + T: BitFlag,

§

fn from(t: T) -> BitFlags<T>

Converts to this type from the input type.
§

impl<T, B> FromIterator<B> for BitFlags<T>
where + T: BitFlag, + B: Into<BitFlags<T>>,

§

fn from_iter<I>(it: I) -> BitFlags<T>
where + I: IntoIterator<Item = B>,

Creates a value from an iterator. Read more
§

impl<T, N> Hash for BitFlags<T, N>
where + N: Hash,

§

fn hash<H>(&self, state: &mut H)
where + H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
§

impl<T> IntoIterator for BitFlags<T>
where + T: BitFlag,

§

type IntoIter = Iter<T>

Which kind of iterator are we turning this into?
§

type Item = T

The type of the elements being iterated over.
§

fn into_iter(self) -> <BitFlags<T> as IntoIterator>::IntoIter

Creates an iterator from a value. Read more
§

impl<T> LowerHex for BitFlags<T>
where + T: BitFlag, + <T as RawBitFlags>::Numeric: LowerHex,

§

fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
§

impl<T> Not for BitFlags<T>
where + T: BitFlag,

§

type Output = BitFlags<T>

The resulting type after applying the ! operator.
§

fn not(self) -> BitFlags<T>

Performs the unary ! operation. Read more
§

impl<T> Octal for BitFlags<T>
where + T: BitFlag, + <T as RawBitFlags>::Numeric: Octal,

§

fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
§

impl<T, N> Ord for BitFlags<T, N>
where + N: Ord,

§

fn cmp(&self, other: &BitFlags<T, N>) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Self
where + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Self
where + Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
§

impl<T> PartialEq<T> for BitFlags<T>
where + T: BitFlag,

§

fn eq(&self, other: &T) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl<T, N> PartialEq for BitFlags<T, N>
where + N: PartialEq,

§

fn eq(&self, other: &BitFlags<T, N>) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
§

impl<T, N> PartialOrd for BitFlags<T, N>
where + N: PartialOrd,

§

fn partial_cmp(&self, other: &BitFlags<T, N>) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
§

impl<T> TryFrom<u128> for BitFlags<T>
where + T: BitFlag<Numeric = u128>,

§

type Error = FromBitsError<T>

The type returned in the event of a conversion error.
§

fn try_from( + bits: <T as RawBitFlags>::Numeric, +) -> Result<BitFlags<T>, <BitFlags<T> as TryFrom<u128>>::Error>

Performs the conversion.
§

impl<T> TryFrom<u16> for BitFlags<T>
where + T: BitFlag<Numeric = u16>,

§

type Error = FromBitsError<T>

The type returned in the event of a conversion error.
§

fn try_from( + bits: <T as RawBitFlags>::Numeric, +) -> Result<BitFlags<T>, <BitFlags<T> as TryFrom<u16>>::Error>

Performs the conversion.
§

impl<T> TryFrom<u32> for BitFlags<T>
where + T: BitFlag<Numeric = u32>,

§

type Error = FromBitsError<T>

The type returned in the event of a conversion error.
§

fn try_from( + bits: <T as RawBitFlags>::Numeric, +) -> Result<BitFlags<T>, <BitFlags<T> as TryFrom<u32>>::Error>

Performs the conversion.
§

impl<T> TryFrom<u64> for BitFlags<T>
where + T: BitFlag<Numeric = u64>,

§

type Error = FromBitsError<T>

The type returned in the event of a conversion error.
§

fn try_from( + bits: <T as RawBitFlags>::Numeric, +) -> Result<BitFlags<T>, <BitFlags<T> as TryFrom<u64>>::Error>

Performs the conversion.
§

impl<T> TryFrom<u8> for BitFlags<T>
where + T: BitFlag<Numeric = u8>,

§

type Error = FromBitsError<T>

The type returned in the event of a conversion error.
§

fn try_from( + bits: <T as RawBitFlags>::Numeric, +) -> Result<BitFlags<T>, <BitFlags<T> as TryFrom<u8>>::Error>

Performs the conversion.
§

impl<T> UpperHex for BitFlags<T>
where + T: BitFlag, + <T as RawBitFlags>::Numeric: UpperHex,

§

fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
§

impl<T, N> Copy for BitFlags<T, N>
where + T: Copy, + N: Copy,

§

impl<T, N> Eq for BitFlags<T, N>
where + N: Eq,

Auto Trait Implementations§

§

impl<T, N> Freeze for BitFlags<T, N>
where + N: Freeze,

§

impl<T, N> RefUnwindSafe for BitFlags<T, N>
where + N: RefUnwindSafe, + T: RefUnwindSafe,

§

impl<T, N> Send for BitFlags<T, N>
where + N: Send, + T: Send,

§

impl<T, N> Sync for BitFlags<T, N>
where + N: Sync, + T: Sync,

§

impl<T, N> Unpin for BitFlags<T, N>
where + N: Unpin, + T: Unpin,

§

impl<T, N> UnwindSafe for BitFlags<T, N>
where + N: UnwindSafe, + T: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> CloneToUninit for T
where + T: Copy,

source§

unsafe fn clone_to_uninit(&self, dst: *mut T)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
source§

impl<T> CloneToUninit for T
where + T: Clone,

source§

default unsafe fn clone_to_uninit(&self, dst: *mut T)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T> ToOwned for T
where + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/struct.NetPort.html b/landlock/struct.NetPort.html new file mode 100644 index 0000000..fa687cf --- /dev/null +++ b/landlock/struct.NetPort.html @@ -0,0 +1,40 @@ +NetPort in landlock - Rust

Struct landlock::NetPort

source ·
pub struct NetPort { /* private fields */ }
Expand description

Landlock rule for a network port.

+

§Example

+
use landlock::{AccessNet, NetPort};
+
+fn bind_http() -> NetPort {
+    NetPort::new(80, AccessNet::BindTcp)
+}
+

Implementations§

source§

impl NetPort

source

pub fn new<A>(port: u16, access: A) -> Self
where + A: Into<BitFlags<AccessNet>>,

Creates a new TCP port rule.

+

As defined by the Linux ABI, port with a value of 0 means that TCP bindings will be +allowed for a port range defined by /proc/sys/net/ipv4/ip_local_port_range.

+

Trait Implementations§

source§

impl Compatible for &mut NetPort

source§

fn set_compatibility(self, level: CompatLevel) -> Self

To enable a best-effort security approach, +Landlock features that are not supported by the running system +are silently ignored by default, +which is a sane choice for most use cases. +However, on some rare circumstances, +developers may want to have some guarantees that their applications +will not run if a certain level of sandboxing is not possible. +If we really want to error out when not all our requested requirements are met, +then we can configure it with set_compatibility(). Read more
source§

fn set_best_effort(self, best_effort: bool) -> Self
where + Self: Sized,

👎Deprecated: Use set_compatibility() instead
source§

impl Compatible for NetPort

source§

fn set_compatibility(self, level: CompatLevel) -> Self

To enable a best-effort security approach, +Landlock features that are not supported by the running system +are silently ignored by default, +which is a sane choice for most use cases. +However, on some rare circumstances, +developers may want to have some guarantees that their applications +will not run if a certain level of sandboxing is not possible. +If we really want to error out when not all our requested requirements are met, +then we can configure it with set_compatibility(). Read more
source§

fn set_best_effort(self, best_effort: bool) -> Self
where + Self: Sized,

👎Deprecated: Use set_compatibility() instead
source§

impl Rule<AccessNet> for NetPort

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/struct.PathBeneath.html b/landlock/struct.PathBeneath.html new file mode 100644 index 0000000..af8b89f --- /dev/null +++ b/landlock/struct.PathBeneath.html @@ -0,0 +1,48 @@ +PathBeneath in landlock - Rust

Struct landlock::PathBeneath

source ·
pub struct PathBeneath<F> { /* private fields */ }
Expand description

Landlock rule for a file hierarchy.

+

§Example

+
use landlock::{AccessFs, PathBeneath, PathFd, PathFdError};
+
+fn home_dir() -> Result<PathBeneath<PathFd>, PathFdError> {
+    Ok(PathBeneath::new(PathFd::new("/home")?, AccessFs::ReadDir))
+}
+

Implementations§

source§

impl<F> PathBeneath<F>
where + F: AsFd,

source

pub fn new<A>(parent: F, access: A) -> Self
where + A: Into<BitFlags<AccessFs>>,

Creates a new PathBeneath rule identifying the parent directory of a file hierarchy, +or just a file, and allows access on it. +The parent file descriptor will be automatically closed with the returned PathBeneath.

+

Trait Implementations§

source§

impl<F> Compatible for &mut PathBeneath<F>

source§

fn set_compatibility(self, level: CompatLevel) -> Self

To enable a best-effort security approach, +Landlock features that are not supported by the running system +are silently ignored by default, +which is a sane choice for most use cases. +However, on some rare circumstances, +developers may want to have some guarantees that their applications +will not run if a certain level of sandboxing is not possible. +If we really want to error out when not all our requested requirements are met, +then we can configure it with set_compatibility(). Read more
source§

fn set_best_effort(self, best_effort: bool) -> Self
where + Self: Sized,

👎Deprecated: Use set_compatibility() instead
source§

impl<F> Compatible for PathBeneath<F>

source§

fn set_compatibility(self, level: CompatLevel) -> Self

To enable a best-effort security approach, +Landlock features that are not supported by the running system +are silently ignored by default, +which is a sane choice for most use cases. +However, on some rare circumstances, +developers may want to have some guarantees that their applications +will not run if a certain level of sandboxing is not possible. +If we really want to error out when not all our requested requirements are met, +then we can configure it with set_compatibility(). Read more
source§

fn set_best_effort(self, best_effort: bool) -> Self
where + Self: Sized,

👎Deprecated: Use set_compatibility() instead
source§

impl<F> Rule<AccessFs> for PathBeneath<F>
where + F: AsFd,

Auto Trait Implementations§

§

impl<F> Freeze for PathBeneath<F>
where + F: Freeze,

§

impl<F> RefUnwindSafe for PathBeneath<F>
where + F: RefUnwindSafe,

§

impl<F> Send for PathBeneath<F>
where + F: Send,

§

impl<F> Sync for PathBeneath<F>
where + F: Sync,

§

impl<F> Unpin for PathBeneath<F>
where + F: Unpin,

§

impl<F> UnwindSafe for PathBeneath<F>
where + F: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/struct.PathFd.html b/landlock/struct.PathFd.html new file mode 100644 index 0000000..5d2dcaa --- /dev/null +++ b/landlock/struct.PathFd.html @@ -0,0 +1,24 @@ +PathFd in landlock - Rust

Struct landlock::PathFd

source ·
pub struct PathFd { /* private fields */ }
Expand description

Simple helper to open a file or a directory with the O_PATH flag.

+

This is the recommended way to identify a path +and manage the lifetime of the underlying opened file descriptor. +Indeed, using other AsFd implementations such as File brings more complexity +and may lead to unexpected errors (e.g., denied access).

+

§Example

+
use landlock::{AccessFs, PathBeneath, PathFd, PathFdError};
+
+fn allowed_root_dir(access: AccessFs) -> Result<PathBeneath<PathFd>, PathFdError> {
+    let fd = PathFd::new("/")?;
+    Ok(PathBeneath::new(fd, access))
+}
+

Implementations§

source§

impl PathFd

source

pub fn new<T>(path: T) -> Result<Self, PathFdError>
where + T: AsRef<Path>,

Trait Implementations§

source§

impl AsFd for PathFd

source§

fn as_fd(&self) -> BorrowedFd<'_>

Borrows the file descriptor. Read more

Auto Trait Implementations§

§

impl Freeze for PathFd

§

impl RefUnwindSafe for PathFd

§

impl Send for PathFd

§

impl Sync for PathFd

§

impl Unpin for PathFd

§

impl UnwindSafe for PathFd

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/struct.RestrictionStatus.html b/landlock/struct.RestrictionStatus.html new file mode 100644 index 0000000..02140ac --- /dev/null +++ b/landlock/struct.RestrictionStatus.html @@ -0,0 +1,20 @@ +RestrictionStatus in landlock - Rust

Struct landlock::RestrictionStatus

source ·
#[non_exhaustive]
pub struct RestrictionStatus { + pub ruleset: RulesetStatus, + pub no_new_privs: bool, +}
Expand description

Status of a RulesetCreated +after calling restrict_self().

+

Fields (Non-exhaustive)§

This struct is marked as non-exhaustive
Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.
§ruleset: RulesetStatus

Status of the Landlock ruleset enforcement.

+
§no_new_privs: bool

Status of prctl(2)’s PR_SET_NO_NEW_PRIVS enforcement.

+

Trait Implementations§

source§

impl Debug for RestrictionStatus

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl PartialEq for RestrictionStatus

source§

fn eq(&self, other: &RestrictionStatus) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Eq for RestrictionStatus

source§

impl StructuralPartialEq for RestrictionStatus

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/struct.Ruleset.html b/landlock/struct.Ruleset.html new file mode 100644 index 0000000..a61f368 --- /dev/null +++ b/landlock/struct.Ruleset.html @@ -0,0 +1,119 @@ +Ruleset in landlock - Rust

Struct landlock::Ruleset

source ·
pub struct Ruleset { /* private fields */ }
Expand description

Landlock ruleset builder.

+

Ruleset enables to create a Landlock ruleset in a flexible way +following the builder pattern. +Most build steps return a Result with RulesetError.

+

You should probably not create more than one ruleset per application. +Creating multiple rulesets is only useful when gradually restricting an application +(e.g., a first set of generic restrictions before reading any file, +then a second set of tailored restrictions after reading the configuration).

+

§Simple example

+

Simple helper handling only Landlock-related errors.

+ +
use landlock::{
+    Access, AccessFs, PathBeneath, PathFd, RestrictionStatus, Ruleset, RulesetAttr,
+    RulesetCreatedAttr, RulesetError, ABI,
+};
+use std::os::unix::io::AsFd;
+
+fn restrict_fd<T>(hierarchy: T) -> Result<RestrictionStatus, RulesetError>
+where
+    T: AsFd,
+{
+    // The Landlock ABI should be incremented (and tested) regularly.
+    let abi = ABI::V1;
+    let access_all = AccessFs::from_all(abi);
+    let access_read = AccessFs::from_read(abi);
+    Ok(Ruleset::default()
+        .handle_access(access_all)?
+        .create()?
+        .add_rule(PathBeneath::new(hierarchy, access_read))?
+        .restrict_self()?)
+}
+
+let fd = PathFd::new("/home").expect("failed to open /home");
+let status = restrict_fd(fd).expect("failed to build the ruleset");
+

§Generic example

+

More generic helper handling a set of file hierarchies +and multiple types of error (i.e. RulesetError +and PathFdError.

+ +
use landlock::{
+    Access, AccessFs, PathBeneath, PathFd, PathFdError, RestrictionStatus, Ruleset,
+    RulesetAttr, RulesetCreatedAttr, RulesetError, ABI,
+};
+use thiserror::Error;
+
+#[derive(Debug, Error)]
+enum MyRestrictError {
+    #[error(transparent)]
+    Ruleset(#[from] RulesetError),
+    #[error(transparent)]
+    AddRule(#[from] PathFdError),
+}
+
+fn restrict_paths(hierarchies: &[&str]) -> Result<RestrictionStatus, MyRestrictError> {
+    // The Landlock ABI should be incremented (and tested) regularly.
+    let abi = ABI::V1;
+    let access_all = AccessFs::from_all(abi);
+    let access_read = AccessFs::from_read(abi);
+    Ok(Ruleset::default()
+        .handle_access(access_all)?
+        .create()?
+        .add_rules(
+            hierarchies
+                .iter()
+                .map::<Result<_, MyRestrictError>, _>(|p| {
+                    Ok(PathBeneath::new(PathFd::new(p)?, access_read))
+                }),
+        )?
+        .restrict_self()?)
+}
+
+let status = restrict_paths(&["/usr", "/home"]).expect("failed to build the ruleset");
+

Implementations§

source§

impl Ruleset

source

pub fn new() -> Self

👎Deprecated: Use Ruleset::default() instead
source

pub fn create(self) -> Result<RulesetCreated, RulesetError>

Attempts to create a real Landlock ruleset (if supported by the running kernel). +The returned RulesetCreated is also a builder.

+

On error, returns a wrapped CreateRulesetError.

+

Trait Implementations§

source§

impl AsMut<Ruleset> for Ruleset

source§

fn as_mut(&mut self) -> &mut Ruleset

Converts this type into a mutable reference of the (usually inferred) input type.
source§

impl Compatible for &mut Ruleset

source§

fn set_compatibility(self, level: CompatLevel) -> Self

To enable a best-effort security approach, +Landlock features that are not supported by the running system +are silently ignored by default, +which is a sane choice for most use cases. +However, on some rare circumstances, +developers may want to have some guarantees that their applications +will not run if a certain level of sandboxing is not possible. +If we really want to error out when not all our requested requirements are met, +then we can configure it with set_compatibility(). Read more
source§

fn set_best_effort(self, best_effort: bool) -> Self
where + Self: Sized,

👎Deprecated: Use set_compatibility() instead
source§

impl Compatible for Ruleset

source§

fn set_compatibility(self, level: CompatLevel) -> Self

To enable a best-effort security approach, +Landlock features that are not supported by the running system +are silently ignored by default, +which is a sane choice for most use cases. +However, on some rare circumstances, +developers may want to have some guarantees that their applications +will not run if a certain level of sandboxing is not possible. +If we really want to error out when not all our requested requirements are met, +then we can configure it with set_compatibility(). Read more
source§

fn set_best_effort(self, best_effort: bool) -> Self
where + Self: Sized,

👎Deprecated: Use set_compatibility() instead
source§

impl Default for Ruleset

source§

fn default() -> Self

Returns a new Ruleset. +This call automatically probes the running kernel to know if it supports Landlock.

+

To be able to successfully call create(), +it is required to set the handled accesses with +handle_access().

+
source§

impl RulesetAttr for &mut Ruleset

source§

fn handle_access<T, U>(self, access: T) -> Result<Self, RulesetError>
where + T: Into<BitFlags<U>>, + U: Access,

Attempts to add a set of access rights that will be supported by this ruleset. +By default, all actions requiring these access rights will be denied. +Consecutive calls to handle_access() will be interpreted as logical ORs +with the previous handled accesses. Read more
source§

impl RulesetAttr for Ruleset

source§

fn handle_access<T, U>(self, access: T) -> Result<Self, RulesetError>
where + T: Into<BitFlags<U>>, + U: Access,

Attempts to add a set of access rights that will be supported by this ruleset. +By default, all actions requiring these access rights will be denied. +Consecutive calls to handle_access() will be interpreted as logical ORs +with the previous handled accesses. Read more

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/struct.RulesetCreated.html b/landlock/struct.RulesetCreated.html new file mode 100644 index 0000000..3a098d0 --- /dev/null +++ b/landlock/struct.RulesetCreated.html @@ -0,0 +1,53 @@ +RulesetCreated in landlock - Rust

Struct landlock::RulesetCreated

source ·
pub struct RulesetCreated { /* private fields */ }
Expand description

Ruleset created with Ruleset::create().

+

Implementations§

source§

impl RulesetCreated

source

pub fn restrict_self(self) -> Result<RestrictionStatus, RulesetError>

Attempts to restrict the calling thread with the ruleset +according to the best-effort configuration +(see RulesetCreated::set_compatibility() and CompatLevel::BestEffort). +Call prctl(2) with the PR_SET_NO_NEW_PRIVS +according to the ruleset configuration.

+

On error, returns a wrapped RestrictSelfError.

+
source

pub fn try_clone(&self) -> Result<Self>

Creates a new RulesetCreated instance by duplicating the underlying file descriptor. +Rule modification will affect both RulesetCreated instances simultaneously.

+

On error, returns std::io::Error.

+

Trait Implementations§

source§

impl AsMut<RulesetCreated> for RulesetCreated

source§

fn as_mut(&mut self) -> &mut RulesetCreated

Converts this type into a mutable reference of the (usually inferred) input type.
source§

impl Compatible for &mut RulesetCreated

source§

fn set_compatibility(self, level: CompatLevel) -> Self

To enable a best-effort security approach, +Landlock features that are not supported by the running system +are silently ignored by default, +which is a sane choice for most use cases. +However, on some rare circumstances, +developers may want to have some guarantees that their applications +will not run if a certain level of sandboxing is not possible. +If we really want to error out when not all our requested requirements are met, +then we can configure it with set_compatibility(). Read more
source§

fn set_best_effort(self, best_effort: bool) -> Self
where + Self: Sized,

👎Deprecated: Use set_compatibility() instead
source§

impl Compatible for RulesetCreated

source§

fn set_compatibility(self, level: CompatLevel) -> Self

To enable a best-effort security approach, +Landlock features that are not supported by the running system +are silently ignored by default, +which is a sane choice for most use cases. +However, on some rare circumstances, +developers may want to have some guarantees that their applications +will not run if a certain level of sandboxing is not possible. +If we really want to error out when not all our requested requirements are met, +then we can configure it with set_compatibility(). Read more
source§

fn set_best_effort(self, best_effort: bool) -> Self
where + Self: Sized,

👎Deprecated: Use set_compatibility() instead
source§

impl Drop for RulesetCreated

source§

fn drop(&mut self)

Executes the destructor for this type. Read more
source§

impl RulesetCreatedAttr for &mut RulesetCreated

source§

fn add_rule<T, U>(self, rule: T) -> Result<Self, RulesetError>
where + T: Rule<U>, + U: Access,

Attempts to add a new rule to the ruleset. Read more
source§

fn add_rules<I, T, U, E>(self, rules: I) -> Result<Self, E>
where + I: IntoIterator<Item = Result<T, E>>, + T: Rule<U>, + U: Access, + E: From<RulesetError>,

Attempts to add a set of new rules to the ruleset. Read more
source§

fn set_no_new_privs(self, no_new_privs: bool) -> Self

Configures the ruleset to call prctl(2) with the PR_SET_NO_NEW_PRIVS command +in restrict_self(). Read more
source§

impl RulesetCreatedAttr for RulesetCreated

source§

fn add_rule<T, U>(self, rule: T) -> Result<Self, RulesetError>
where + T: Rule<U>, + U: Access,

Attempts to add a new rule to the ruleset. Read more
source§

fn add_rules<I, T, U, E>(self, rules: I) -> Result<Self, E>
where + I: IntoIterator<Item = Result<T, E>>, + T: Rule<U>, + U: Access, + E: From<RulesetError>,

Attempts to add a set of new rules to the ruleset. Read more
source§

fn set_no_new_privs(self, no_new_privs: bool) -> Self

Configures the ruleset to call prctl(2) with the PR_SET_NO_NEW_PRIVS command +in restrict_self(). Read more

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/landlock/trait.Access.html b/landlock/trait.Access.html new file mode 100644 index 0000000..6f08d59 --- /dev/null +++ b/landlock/trait.Access.html @@ -0,0 +1,8 @@ +Access in landlock - Rust

Trait landlock::Access

source ·
pub trait Access: PrivateAccess {
+    // Required method
+    fn from_all(abi: ABI) -> BitFlags<Self>;
+}

Required Methods§

source

fn from_all(abi: ABI) -> BitFlags<Self>

Gets the access rights defined by a specific ABI.

+

Object Safety§

This trait is not object safe.

Implementors§

source§

impl Access for AccessFs

source§

impl Access for AccessNet

§Warning

+

If ABI <= ABI::V3, AccessNet::from_all() returns an empty BitFlags<AccessNet>, which +makes Ruleset::handle_access(AccessNet::from_all(ABI::V3)) return an error.

+
\ No newline at end of file diff --git a/landlock/trait.Compatible.html b/landlock/trait.Compatible.html new file mode 100644 index 0000000..430c074 --- /dev/null +++ b/landlock/trait.Compatible.html @@ -0,0 +1,121 @@ +Compatible in landlock - Rust

Trait landlock::Compatible

source ·
pub trait Compatible: Sized + OptionCompatLevelMut {
+    // Provided methods
+    fn set_compatibility(self, level: CompatLevel) -> Self { ... }
+    fn set_best_effort(self, best_effort: bool) -> Self
+       where Self: Sized { ... }
+}
Expand description

Properly handles runtime unsupported features.

+

This guarantees consistent behaviors across crate users +and runtime kernels even if this crate get new features. +It eases backward compatibility and enables future-proofness.

+

Landlock is a security feature designed to help improve security of a running system +thanks to application developers. +To protect users as much as possible, +compatibility with the running system should then be handled in a best-effort way, +contrary to common system features. +In some circumstances +(e.g. applications carefully designed to only be run with a specific set of kernel features), +it may be required to error out if some of these features are not available +and will then not be enforced.

+

Provided Methods§

source

fn set_compatibility(self, level: CompatLevel) -> Self

To enable a best-effort security approach, +Landlock features that are not supported by the running system +are silently ignored by default, +which is a sane choice for most use cases. +However, on some rare circumstances, +developers may want to have some guarantees that their applications +will not run if a certain level of sandboxing is not possible. +If we really want to error out when not all our requested requirements are met, +then we can configure it with set_compatibility().

+

The Compatible trait is implemented for all object builders +(e.g. Ruleset). +Such builders have a set of methods to incrementally build an object. +These build methods rely on kernel features that may not be available at runtime. +The set_compatibility() method enables to control the effect of +the following build method calls starting after the set_compatibility() call. +Such effect can be:

+ +

Taking Ruleset as an example, +the handle_access() build method +returns a Result that can be Err(RulesetError) +with a nested CompatError. +Such error can only occur with a running Linux kernel not supporting the requested +Landlock accesses and if the current compatibility level is +CompatLevel::HardRequirement. +However, such error is not possible with CompatLevel::BestEffort +nor CompatLevel::SoftRequirement.

+

The order of this call is important because +it defines the behavior of the following build method calls that return a Result. +If set_compatibility(CompatLevel::HardRequirement) is called on an object, +then a CompatError may be returned for the next method calls, +until the next call to set_compatibility(). +This enables to change the behavior of a set of build method calls, +for instance to be sure that the sandbox will at least restrict some access rights.

+

New objects inherit the compatibility configuration of their parents, if any. +For instance, Ruleset::create() returns +a RulesetCreated object that inherits the +Ruleset’s compatibility configuration.

+
§Example with SoftRequirement
+

Let’s say an application legitimately needs to rename files between directories. +Because of previous Landlock limitations, +this was forbidden with the first version of Landlock, +but it is now handled starting with the second version. +For this use case, we only want the application to be sandboxed +if we have the guarantee that it will not break a legitimate usage (i.e. rename files). +We then create a ruleset which will either support file renaming +(thanks to AccessFs::Refer) or silently do nothing.

+ +
use landlock::*;
+
+fn ruleset_handling_renames() -> Result<RulesetCreated, RulesetError> {
+    Ok(Ruleset::default()
+        // This ruleset must either handle the AccessFs::Refer right,
+        // or it must silently ignore the whole sandboxing.
+        .set_compatibility(CompatLevel::SoftRequirement)
+        .handle_access(AccessFs::Refer)?
+        // However, this ruleset may also handle other (future) access rights
+        // if they are supported by the running kernel.
+        .set_compatibility(CompatLevel::BestEffort)
+        .handle_access(AccessFs::from_all(ABI::V5))?
+        .create()?)
+}
+
§Example with HardRequirement
+

Security-dedicated applications may want to ensure that +an untrusted software component is subject to a minimum of restrictions before launching it. +In this case, we want to create a ruleset which will at least support +all restrictions provided by the first version of Landlock, +and opportunistically handle restrictions supported by newer kernels.

+ +
use landlock::*;
+
+fn ruleset_fragile() -> Result<RulesetCreated, RulesetError> {
+    Ok(Ruleset::default()
+        // This ruleset must either handle at least all accesses defined by
+        // the first Landlock version (e.g. AccessFs::WriteFile),
+        // or the following handle_access() call must return a wrapped
+        // AccessError<AccessFs>::Incompatible error.
+        .set_compatibility(CompatLevel::HardRequirement)
+        .handle_access(AccessFs::from_all(ABI::V1))?
+        // However, this ruleset may also handle new access rights
+        // (e.g. AccessFs::Refer defined by the second version of Landlock)
+        // if they are supported by the running kernel,
+        // but without returning any error otherwise.
+        .set_compatibility(CompatLevel::BestEffort)
+        .handle_access(AccessFs::from_all(ABI::V5))?
+        .create()?)
+}
+
source

fn set_best_effort(self, best_effort: bool) -> Self
where + Self: Sized,

👎Deprecated: Use set_compatibility() instead

Cf. set_compatibility():

+
    +
  • +

    set_best_effort(true) translates to set_compatibility(CompatLevel::BestEffort).

    +
  • +
  • +

    set_best_effort(false) translates to set_compatibility(CompatLevel::HardRequirement).

    +
  • +
+

Object Safety§

This trait is not object safe.

Implementors§

\ No newline at end of file diff --git a/landlock/trait.Rule.html b/landlock/trait.Rule.html new file mode 100644 index 0000000..2bad437 --- /dev/null +++ b/landlock/trait.Rule.html @@ -0,0 +1,3 @@ +Rule in landlock - Rust

Trait landlock::Rule

source ·
pub trait Rule<T>: PrivateRule<T>
where + T: Access,
{ }

Object Safety§

This trait is not object safe.

Implementors§

source§

impl Rule<AccessNet> for NetPort

source§

impl<F> Rule<AccessFs> for PathBeneath<F>
where + F: AsFd,

\ No newline at end of file diff --git a/landlock/trait.RulesetAttr.html b/landlock/trait.RulesetAttr.html new file mode 100644 index 0000000..1ae392b --- /dev/null +++ b/landlock/trait.RulesetAttr.html @@ -0,0 +1,14 @@ +RulesetAttr in landlock - Rust

Trait landlock::RulesetAttr

source ·
pub trait RulesetAttr: Sized + AsMut<Ruleset> + Compatible {
+    // Provided method
+    fn handle_access<T, U>(self, access: T) -> Result<Self, RulesetError>
+       where T: Into<BitFlags<U>>,
+             U: Access { ... }
+}

Provided Methods§

source

fn handle_access<T, U>(self, access: T) -> Result<Self, RulesetError>
where + T: Into<BitFlags<U>>, + U: Access,

Attempts to add a set of access rights that will be supported by this ruleset. +By default, all actions requiring these access rights will be denied. +Consecutive calls to handle_access() will be interpreted as logical ORs +with the previous handled accesses.

+

On error, returns a wrapped HandleAccessesError. +E.g., RulesetError::HandleAccesses(HandleAccessesError::Fs(HandleAccessError<AccessFs>))

+

Object Safety§

This trait is not object safe.

Implementors§

\ No newline at end of file diff --git a/landlock/trait.RulesetCreatedAttr.html b/landlock/trait.RulesetCreatedAttr.html new file mode 100644 index 0000000..9040771 --- /dev/null +++ b/landlock/trait.RulesetCreatedAttr.html @@ -0,0 +1,93 @@ +RulesetCreatedAttr in landlock - Rust

Trait landlock::RulesetCreatedAttr

source ·
pub trait RulesetCreatedAttr: Sized + AsMut<RulesetCreated> + Compatible {
+    // Provided methods
+    fn add_rule<T, U>(self, rule: T) -> Result<Self, RulesetError>
+       where T: Rule<U>,
+             U: Access { ... }
+    fn add_rules<I, T, U, E>(self, rules: I) -> Result<Self, E>
+       where I: IntoIterator<Item = Result<T, E>>,
+             T: Rule<U>,
+             U: Access,
+             E: From<RulesetError> { ... }
+    fn set_no_new_privs(self, no_new_privs: bool) -> Self { ... }
+}

Provided Methods§

source

fn add_rule<T, U>(self, rule: T) -> Result<Self, RulesetError>
where + T: Rule<U>, + U: Access,

Attempts to add a new rule to the ruleset.

+

On error, returns a wrapped AddRulesError.

+
source

fn add_rules<I, T, U, E>(self, rules: I) -> Result<Self, E>
where + I: IntoIterator<Item = Result<T, E>>, + T: Rule<U>, + U: Access, + E: From<RulesetError>,

Attempts to add a set of new rules to the ruleset.

+

On error, returns a (double) wrapped AddRulesError.

+
§Example
+

Create a custom iterator to read paths from environment variable.

+ +
use landlock::{
+    Access, AccessFs, BitFlags, PathBeneath, PathFd, PathFdError, RestrictionStatus, Ruleset,
+    RulesetAttr, RulesetCreatedAttr, RulesetError, ABI,
+};
+use std::env;
+use std::ffi::OsStr;
+use std::os::unix::ffi::{OsStrExt, OsStringExt};
+use thiserror::Error;
+
+#[derive(Debug, Error)]
+enum PathEnvError<'a> {
+    #[error(transparent)]
+    Ruleset(#[from] RulesetError),
+    #[error(transparent)]
+    AddRuleIter(#[from] PathFdError),
+    #[error("missing environment variable {0}")]
+    MissingVar(&'a str),
+}
+
+struct PathEnv {
+    paths: Vec<u8>,
+    access: BitFlags<AccessFs>,
+}
+
+impl PathEnv {
+    // env_var is the name of an environment variable
+    // containing paths requested to be allowed.
+    // Paths are separated with ":", e.g. "/bin:/lib:/usr:/proc".
+    // In case an empty string is provided,
+    // no restrictions are applied.
+    // `access` is the set of access rights allowed for each of the parsed paths.
+    fn new<'a>(
+        env_var: &'a str, access: BitFlags<AccessFs>
+    ) -> Result<Self, PathEnvError<'a>> {
+        Ok(Self {
+            paths: env::var_os(env_var)
+                .ok_or(PathEnvError::MissingVar(env_var))?
+                .into_vec(),
+            access,
+        })
+    }
+
+    fn iter(
+        &self,
+    ) -> impl Iterator<Item = Result<PathBeneath<PathFd>, PathEnvError<'static>>> + '_ {
+        let is_empty = self.paths.is_empty();
+        self.paths
+            .split(|b| *b == b':')
+            // Skips the first empty element from of an empty string.
+            .skip_while(move |_| is_empty)
+            .map(OsStr::from_bytes)
+            .map(move |path|
+                Ok(PathBeneath::new(PathFd::new(path)?, self.access)))
+    }
+}
+
+fn restrict_env() -> Result<RestrictionStatus, PathEnvError<'static>> {
+    Ok(Ruleset::default()
+        .handle_access(AccessFs::from_all(ABI::V1))?
+        .create()?
+        // In the shell: export EXECUTABLE_PATH="/usr:/bin:/sbin"
+        .add_rules(PathEnv::new("EXECUTABLE_PATH", AccessFs::Execute.into())?.iter())?
+        .restrict_self()?)
+}
+
source

fn set_no_new_privs(self, no_new_privs: bool) -> Self

Configures the ruleset to call prctl(2) with the PR_SET_NO_NEW_PRIVS command +in restrict_self().

+

This prctl(2) call is never ignored, even if an error was encountered on a Ruleset or +RulesetCreated method call while CompatLevel::SoftRequirement was set.

+

Object Safety§

This trait is not object safe.

Implementors§

\ No newline at end of file diff --git a/search-index.js b/search-index.js new file mode 100644 index 0000000..a6f29a9 --- /dev/null +++ b/search-index.js @@ -0,0 +1,5 @@ +var searchIndex = new Map(JSON.parse('[\ +["landlock",{"t":"GTKPGGGPGPGPPFTPPGGKPPPGPTPPPPPGPGPPPPPPPPPPPPPFPPPPFPGFGPPPPPPPGFKFKFKGGPPPPPPPPPPPPPNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNQNNNNONNNNNNHNNONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNOOOOOOOOOOOOOOOO","n":["ABI","ALL","Access","Access","AccessError","AccessFs","AccessNet","AddRuleCall","AddRuleError","AddRules","AddRulesError","BestEffort","BindTcp","BitFlags","CONST_TOKEN","Compat","Compat","CompatError","CompatLevel","Compatible","ConnectTcp","CreateRuleset","CreateRulesetCall","CreateRulesetError","DirectoryAccess","EMPTY","Empty","Execute","Fs","Fs","FullyEnforced","HandleAccessError","HandleAccesses","HandleAccessesError","HardRequirement","Incompatible","IoctlDev","MakeBlock","MakeChar","MakeDir","MakeFifo","MakeReg","MakeSock","MakeSym","MissingHandledAccess","Net","Net","NetPort","NotEnforced","OpenCall","PartiallyCompatible","PartiallyEnforced","PathBeneath","PathBeneath","PathBeneathError","PathFd","PathFdError","ReadDir","ReadFile","Refer","RemoveDir","RemoveFile","RestrictSelf","RestrictSelfCall","RestrictSelfError","RestrictionStatus","Rule","Ruleset","RulesetAttr","RulesetCreated","RulesetCreatedAttr","RulesetError","RulesetStatus","SetNoNewPrivsCall","SoftRequirement","StatCall","Truncate","UnhandledAccess","Unknown","Unsupported","V1","V2","V3","V4","V5","WriteFile","add_rule","add_rule","add_rules","add_rules","all","as_fd","as_mut","as_mut","bitand","bitand","bitand","bitand_assign","bitor","bitor","bitor","bitor_assign","bits","bits","bits","bits_c","bitxor","bitxor","bitxor","bitxor_assign","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","clone_into","clone_to_uninit","clone_to_uninit","clone_to_uninit","clone_to_uninit","clone_to_uninit","clone_to_uninit","clone_to_uninit","clone_to_uninit","clone_to_uninit","clone_to_uninit","cmp","cmp","contains","create","default","default","default","drop","empty","eq","eq","eq","eq","eq","eq","eq","exactly_one","extend","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from_all","from_all","from_all","from_bits","from_bits_truncate","from_bits_truncate_c","from_bits_unchecked","from_bits_unchecked_c","from_file","from_flag","from_iter","from_read","from_write","handle_access","handle_access","hash","insert","intersection_c","intersects","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into_iter","is_all","is_empty","iter","len","make_bitflags","new","new","new","new","no_new_privs","not","not","not","not_c","partial_cmp","partial_cmp","path_beneath_rules","remove","restrict_self","ruleset","set","set_best_effort","set_best_effort","set_compatibility","set_compatibility","set_no_new_privs","set_no_new_privs","source","source","source","source","source","source","source","source","source","source","to_owned","to_owned","to_owned","to_owned","to_owned","to_string","to_string","to_string","to_string","to_string","to_string","to_string","to_string","to_string","to_string","to_string","to_string","toggle","try_clone","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","union_c","access","access","access","incompatible","unknown","access","incompatible","source","source","access","incompatible","source","path","source","source","source"],"q":[[0,"landlock"],[436,"landlock::AccessError"],[441,"landlock::AddRuleError"],[444,"landlock::CreateRulesetError"],[445,"landlock::PathBeneathError"],[448,"landlock::PathFdError"],[450,"landlock::RestrictSelfError"],[452,"landlock::ruleset"],[453,"landlock::errors"],[454,"core::result"],[455,"landlock::access"],[456,"core::convert"],[457,"core::iter::traits::collect"],[458,"enumflags2"],[459,"landlock::fs"],[460,"std::os::fd::owned"],[461,"landlock::net"],[462,"core::clone"],[463,"landlock::compat"],[464,"core::cmp"],[465,"core::option"],[466,"core::fmt"],[467,"enumflags2::fallible"],[468,"enumflags2::const_api"],[469,"core::hash"],[470,"enumflags2::iter"],[471,"std::path"],[472,"core::iter::traits::iterator"],[473,"core::error"],[474,"alloc::string"],[475,"std::io::error"],[476,"core::any"]],"i":[0,9,0,41,0,0,0,39,0,2,0,24,19,0,9,36,39,0,0,0,19,2,38,0,42,9,43,18,37,40,29,0,2,0,24,43,18,18,18,18,18,18,18,18,38,37,40,0,29,45,43,29,0,41,0,0,0,18,18,18,18,18,2,44,0,0,0,0,0,0,0,0,0,44,24,42,18,39,43,23,23,23,23,23,23,18,1,1,1,1,9,11,15,16,9,18,19,9,9,18,19,9,9,18,19,9,9,18,19,9,53,11,58,15,16,9,23,24,2,36,37,38,39,40,41,42,43,44,45,18,19,29,30,53,11,58,15,16,9,23,24,2,36,37,38,39,40,41,42,43,44,45,18,19,29,30,9,23,24,18,19,9,23,24,18,19,9,9,23,23,24,24,18,18,19,19,9,24,9,15,15,9,24,16,9,9,9,24,18,19,29,30,9,9,9,9,9,9,9,9,24,2,2,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,18,19,29,30,53,11,58,15,16,9,9,23,24,24,2,2,2,2,2,36,36,37,37,38,39,39,40,40,41,41,41,42,43,44,45,18,19,29,30,4,18,19,9,9,9,9,9,18,9,9,18,18,48,48,9,9,9,9,53,11,58,15,16,9,23,24,2,36,37,38,39,40,41,42,43,44,45,18,19,29,30,9,9,9,9,9,0,53,11,58,15,30,9,18,19,9,9,24,0,9,16,30,9,61,61,61,61,1,1,2,36,37,38,39,40,41,42,44,45,9,23,24,18,19,9,2,36,37,38,39,40,41,42,43,44,45,9,16,53,11,58,15,16,9,9,9,9,9,9,23,24,2,36,37,38,39,40,41,42,43,44,45,18,19,29,30,53,11,58,15,16,9,23,24,2,36,37,38,39,40,41,42,43,44,45,18,19,29,30,53,11,58,15,16,9,23,24,2,36,37,38,39,40,41,42,43,44,45,18,19,29,30,9,70,71,72,72,70,73,73,74,75,76,76,77,78,78,79,80],"f":"``````````````````````````````````````````````````````````````````````````````````````{{be}{{f{bd}}}h{{j{c}}}}0{{bi}{{f{bg}}}h{{j{c}}}{{l{d}}}{{A`{}{{n{{f{eg}}}}}}}}0{{}{{Ab{c}}}Ad}{{{Ah{Af}}}Aj}{{{Ah{AlAn}}}{{Ah{AlAn}}}}{{{Ah{AlB`}}}{{Ah{AlB`}}}}{{{Ab{c}}e}{{Ab{c}}}Ad{{Bb{{Ab{c}}}}}}{{BdBd}c{}}{{BfBf}c{}}{{{Ah{Al{Ab{c}}}}e}BhAd{{Bb{{Ab{c}}}}}}3210{{{Ab{c}}}{}Ad}{Bdc{}}{Bfc{}}{{{Ab{cBj}}}Bj{}}7654{{{Ah{c}}}{{Ah{e}}}{}{}}0000000000000000000000{{{Ah{Alc}}}{{Ah{Ale}}}{}{}}0000000000000000000000{{{Ah{{Ab{ce}}}}}{{Ab{ce}}}BlBl}{{{Ah{Bn}}}Bn}{{{Ah{C`}}}C`}{{{Ah{Bd}}}Bd}{{{Ah{Bf}}}Bf}{{{Ah{c}}{Ah{Ale}}}Bh{}{}}0000{{{Ah{c}}}Bh{}}000000000{{{Ah{{Ab{ce}}}}{Ah{{Ab{ce}}}}}Cb{}Cd}{{{Ah{C`}}{Ah{C`}}}Cb}{{{Ab{c}}e}CfAd{{Bb{{Ab{c}}}}}}{An{{f{B`d}}}}{{}An}{{}{{Ab{c}}}Ad}{{}C`}{{{Ah{AlB`}}}Bh}2{{{Ah{{Ab{ce}}}}{Ah{{Ab{ce}}}}}Cf{}Ch}{{{Ah{{Ab{c}}}}{Ah{c}}}CfAd}{{{Ah{C`}}{Ah{C`}}}Cf}{{{Ah{Bd}}{Ah{Bd}}}Cf}{{{Ah{Bf}}{Ah{Bf}}}Cf}{{{Ah{Cj}}{Ah{Cj}}}Cf}{{{Ah{Cl}}{Ah{Cl}}}Cf}{{{Ab{c}}}{{Cn{c}}}Ad}{{{Ah{Al{Ab{c}}}}g}BhAd{{Bb{{Ab{c}}}}}{{A`{}{{n{e}}}}}}{{{Ah{{Ab{c}}}}{Ah{AlD`}}}{{f{BhDb}}}{AdDd}}{{{Ah{{Ab{c}}}}{Ah{AlD`}}}{{f{BhDb}}}Ad}1000{{{Ah{C`}}{Ah{AlD`}}}Df}{{{Ah{d}}{Ah{AlD`}}}Df}0{{{Ah{{Dh{c}}}}{Ah{AlD`}}}Dfh}{{{Ah{{Dh{c}}}}{Ah{AlD`}}}Df{hDd}}{{{Ah{Dj}}{Ah{AlD`}}}Df}0{{{Ah{Dl}}{Ah{AlD`}}}Df}0{{{Ah{{Dn{c}}}}{Ah{AlD`}}}Dfh}{{{Ah{{Dn{c}}}}{Ah{AlD`}}}Df{hDd}}{{{Ah{E`}}{Ah{AlD`}}}Df}0{{{Ah{{Eb{c}}}}{Ah{AlD`}}}Dfh}{{{Ah{{Eb{c}}}}{Ah{AlD`}}}Df{hDd}}{{{Ah{Ed}}{Ah{AlD`}}}Df}0{{{Ah{{Ef{c}}}}{Ah{AlD`}}}Df{hDd}}{{{Ah{{Ef{c}}}}{Ah{AlD`}}}Dfh}{{{Ah{Eh}}{Ah{AlD`}}}Df}0{{{Ah{Ej}}{Ah{AlD`}}}Df}0{{{Ah{Bd}}{Ah{AlD`}}}Df}{{{Ah{Bf}}{Ah{AlD`}}}Df}{{{Ah{Cj}}{Ah{AlD`}}}Df}{{{Ah{Cl}}{Ah{AlD`}}}Df}{cc{}}0000{c{{Ab{c}}}Ad}11{{{Cn{C`}}}C`}22{Djd}{Ehd}{Dld}{E`d}{{{Eb{c}}}{{Dh{c}}}h}7{{{Dh{c}}}Djh}88{{{Eb{c}}}{{Dn{c}}}h}99{{{Dn{c}}}E`h}{{{Ef{c}}}{{Eb{c}}}h}{Ed{{Eb{c}}}h}<<<<<<<<<{Bn{{Ab{h}}}}{Bn{{Ab{Bd}}}}{Bn{{Ab{Bf}}}}{{}{{f{{Ab{c}}{El{c}}}}}Ad}{{}{{Ab{c}}}Ad}{{Bj{En{cBj}}}{{Ab{cBj}}}{}}104{c{{Ab{c}}}Ad}{g{{Ab{c}}}Ad{{Bb{{Ab{c}}}}}{{A`{}{{n{e}}}}}}66{{F`e}{{f{F`d}}}h{{Bb{{Ab{c}}}}}}0{{{Ah{{Ab{ce}}}}{Ah{Alg}}}Bh{}FbFd}{{{Ah{Al{Ab{c}}}}e}BhAd{{Bb{{Ab{c}}}}}}{{{Ab{cBj}}{Ab{cBj}}}{{Ab{cBj}}}{}}{{{Ab{c}}e}CfAd{{Bb{{Ab{c}}}}}}{ce{}{}}0000000000000000000000{{{Ab{c}}}{}Ad}{{{Ab{c}}}CfAd}0{{{Ab{c}}}{{Ff{c}}}Ad}{{{Ab{c}}}FhAd}`{{ce}{{Fj{c}}}Fl{{Bb{{Ab{Bd}}}}}}{c{{f{AfEj}}}{{G`{Fn}}}}{{Gbc}Gd{{Bb{{Ab{Bf}}}}}}{{}An}`{{{Ab{c}}}{{Ab{c}}}Ad}{Bdc{}}{Bfc{}}{{{Ab{cBj}}{En{cBj}}}{{Ab{cBj}}}{}}{{{Ah{{Ab{ce}}}}{Ah{{Ab{ce}}}}}{{Cn{Cb}}}{}Gf}{{{Ah{C`}}{Ah{C`}}}{{Cn{Cb}}}}{{eg}{{`{{Gh{}{{n{{f{{Fj{Af}}d}}}}}}}}}{{G`{Fn}}}{{A`{}{{n{c}}}}}{{Bb{{Ab{Bd}}}}}}{{{Ah{Al{Ab{c}}}}e}BhAd{{Bb{{Ab{c}}}}}}{B`{{f{Cld}}}}`{{{Ah{Al{Ab{c}}}}eCf}BhAd{{Bb{{Ab{c}}}}}}{{GjCf}Gj}0{{GjC`}Gj}0{{bCf}b}0{{{Ah{d}}}{{Cn{{Ah{Gl}}}}}}{{{Ah{{Dh{c}}}}}{{Cn{{Ah{Gl}}}}}h}{{{Ah{Dj}}}{{Cn{{Ah{Gl}}}}}}{{{Ah{Dl}}}{{Cn{{Ah{Gl}}}}}}{{{Ah{{Dn{c}}}}}{{Cn{{Ah{Gl}}}}}h}{{{Ah{E`}}}{{Cn{{Ah{Gl}}}}}}{{{Ah{{Eb{c}}}}}{{Cn{{Ah{Gl}}}}}h}{{{Ah{Ed}}}{{Cn{{Ah{Gl}}}}}}{{{Ah{Eh}}}{{Cn{{Ah{Gl}}}}}}{{{Ah{Ej}}}{{Cn{{Ah{Gl}}}}}}{{{Ah{c}}}e{}{}}0000{{{Ah{c}}}Gn{}}00000000000{{{Ah{Al{Ab{c}}}}e}BhAd{{Bb{{Ab{c}}}}}}{{{Ah{B`}}}{{H`{B`}}}}{c{{f{e}}}{}{}}00000{{}{{f{{Ab{c}}}}}{{Ad{}{{Hb{Hd}}}}}}{{}{{f{{Ab{c}}}}}{{Ad{}{{Hb{Gb}}}}}}{{}{{f{{Ab{c}}}}}{{Ad{}{{Hb{Bj}}}}}}{{}{{f{{Ab{c}}}}}{{Ad{}{{Hb{Hf}}}}}}{{}{{f{{Ab{c}}}}}{{Ad{}{{Hb{Hh}}}}}}5555555555555555555555555555555555555555{{{Ah{c}}}Hj{}}0000000000000000000000{{{Ab{cBj}}{Ab{cBj}}}{{Ab{cBj}}}{}}````````````````","D":"ADd","p":[[10,"RulesetCreatedAttr",0,452],[6,"RulesetError",0,453],[6,"Result",454],[10,"Access",0,455],[10,"Rule",0,452],[10,"From",456],[17,"Item"],[10,"IntoIterator",457],[5,"BitFlags",0,458],[10,"BitFlag",458],[5,"PathFd",0,459],[1,"reference"],[5,"BorrowedFd",460],[0,"mut"],[5,"Ruleset",0,452],[5,"RulesetCreated",0,452],[10,"Into",456],[6,"AccessFs",0,459],[6,"AccessNet",0,461],[1,"unit"],[1,"u8"],[10,"Clone",462],[6,"ABI",0,463],[6,"CompatLevel",0,463],[6,"Ordering",464],[10,"Ord",464],[1,"bool"],[10,"PartialEq",464],[6,"RulesetStatus",0,452],[5,"RestrictionStatus",0,452],[6,"Option",465],[5,"Formatter",466],[5,"Error",466],[10,"Debug",466],[8,"Result",466],[6,"HandleAccessError",0,453],[6,"HandleAccessesError",0,453],[6,"CreateRulesetError",0,453],[6,"AddRuleError",0,453],[6,"AddRulesError",0,453],[6,"CompatError",0,453],[6,"PathBeneathError",0,453],[6,"AccessError",0,453],[6,"RestrictSelfError",0,453],[6,"PathFdError",0,453],[5,"FromBitsError",467],[5,"ConstToken",468],[10,"RulesetAttr",0,452],[10,"Hash",469],[10,"Hasher",469],[5,"Iter",470],[1,"usize"],[5,"PathBeneath",0,459],[10,"AsFd",460],[5,"Path",471],[10,"AsRef",456],[1,"u16"],[5,"NetPort",0,461],[10,"PartialOrd",464],[10,"Iterator",472],[10,"Compatible",0,463],[10,"Error",473],[5,"String",474],[8,"Result",475],[17,"Numeric"],[1,"u64"],[1,"u32"],[1,"u128"],[5,"TypeId",476],[15,"Unknown",436],[15,"Incompatible",436],[15,"PartiallyCompatible",436],[15,"UnhandledAccess",441],[15,"AddRuleCall",441],[15,"CreateRulesetCall",444],[15,"DirectoryAccess",445],[15,"StatCall",445],[15,"OpenCall",448],[15,"SetNoNewPrivsCall",450],[15,"RestrictSelfCall",450]],"r":[[0,463],[2,455],[4,453],[5,459],[6,461],[8,453],[10,453],[13,458],[17,453],[18,463],[19,463],[23,453],[31,453],[33,453],[47,461],[52,459],[54,453],[55,459],[56,453],[64,453],[65,452],[66,452],[67,452],[68,452],[69,452],[70,452],[71,453],[72,452],[309,458],[321,459]],"b":[[185,"impl-PartialEq-for-BitFlags%3CT,+N%3E"],[186,"impl-PartialEq%3CT%3E-for-BitFlags%3CT%3E"],[194,"impl-Debug-for-BitFlags%3CT%3E"],[195,"impl-UpperHex-for-BitFlags%3CT%3E"],[196,"impl-Display-for-BitFlags%3CT%3E"],[197,"impl-LowerHex-for-BitFlags%3CT%3E"],[198,"impl-Octal-for-BitFlags%3CT%3E"],[199,"impl-Binary-for-BitFlags%3CT%3E"],[201,"impl-Display-for-RulesetError"],[202,"impl-Debug-for-RulesetError"],[203,"impl-Display-for-HandleAccessError%3CT%3E"],[204,"impl-Debug-for-HandleAccessError%3CT%3E"],[205,"impl-Debug-for-HandleAccessesError"],[206,"impl-Display-for-HandleAccessesError"],[207,"impl-Display-for-CreateRulesetError"],[208,"impl-Debug-for-CreateRulesetError"],[209,"impl-Display-for-AddRuleError%3CT%3E"],[210,"impl-Debug-for-AddRuleError%3CT%3E"],[211,"impl-Debug-for-AddRulesError"],[212,"impl-Display-for-AddRulesError"],[213,"impl-Display-for-CompatError%3CT%3E"],[214,"impl-Debug-for-CompatError%3CT%3E"],[215,"impl-Debug-for-PathBeneathError"],[216,"impl-Display-for-PathBeneathError"],[217,"impl-Debug-for-AccessError%3CT%3E"],[218,"impl-Display-for-AccessError%3CT%3E"],[219,"impl-Display-for-RestrictSelfError"],[220,"impl-Debug-for-RestrictSelfError"],[221,"impl-Debug-for-PathFdError"],[222,"impl-Display-for-PathFdError"],[238,"impl-From%3CHandleAccessesError%3E-for-RulesetError"],[239,"impl-From%3CRestrictSelfError%3E-for-RulesetError"],[240,"impl-From%3CCreateRulesetError%3E-for-RulesetError"],[241,"impl-From%3CAddRulesError%3E-for-RulesetError"],[251,"impl-From%3CAccessError%3CT%3E%3E-for-CompatError%3CT%3E"],[252,"impl-From%3CPathBeneathError%3E-for-CompatError%3CT%3E"],[367,"impl-TryFrom%3Cu64%3E-for-BitFlags%3CT%3E"],[368,"impl-TryFrom%3Cu16%3E-for-BitFlags%3CT%3E"],[369,"impl-TryFrom%3Cu8%3E-for-BitFlags%3CT%3E"],[370,"impl-TryFrom%3Cu32%3E-for-BitFlags%3CT%3E"],[371,"impl-TryFrom%3Cu128%3E-for-BitFlags%3CT%3E"]],"c":"OjAAAAEAAAAAAAIAEAAAADoBRwFIAQ==","e":"OzAAAAEAACIBJQADAAIACgAAABAAAgAWAAAAHQABACEAAQAuAAEANgABADkAAAA/AAAAQQAAAEMAAABFAAAARwAAAFwACgBoAAEAawBHALYAAgC6AAYAwgAhAOkAAADsAAAA7wAEAPUAAAD4AAAA+wACAAkBAAARAQAAFgEAADEBAAA4AQAAOgEAADwBAgBAAQEATQEaAGoBSQC1AQ8A"}]\ +]')); +if (typeof exports !== 'undefined') exports.searchIndex = searchIndex; +else if (window.initSearch) window.initSearch(searchIndex); diff --git a/search.desc/landlock/landlock-desc-0-.js b/search.desc/landlock/landlock-desc-0-.js new file mode 100644 index 0000000..d3634d2 --- /dev/null +++ b/search.desc/landlock/landlock-desc-0-.js @@ -0,0 +1 @@ +searchState.loadedDescShard("landlock", 0, "Landlock is a security feature available since Linux 5.13. …\nVersion of the Landlock ABI.\nA BitFlags with all flags set. Equivalent to all(), but …\nFile system access right.\nNetwork access right.\nThe landlock_add_rule() system call failed.\nIdentifies errors when adding a rule to a ruleset.\nIdentifies errors when adding rules to a ruleset thanks to …\nTakes into account the build requests if they are …\nBind to a TCP port.\nRepresents a set of flags of some type T. T must have the …\nA ConstToken for this type of flag.\nSee the Compatible documentation.\nProperly handles runtime unsupported features.\nConnect to a TCP port.\nThe landlock_create_ruleset() system call failed.\nIdentifies errors when creating a ruleset.\nThis error is returned by RulesetCreatedAttr::add_rule() …\nAn empty BitFlags. Equivalent to empty(), but works in a …\nThe access-rights set is empty, which doesn’t make sense …\nExecute a file.\nAll requested restrictions are enforced.\nIdentifies errors when updating the ruleset’s handled …\nTakes into account the build requests if they are …\nThe best-effort approach was (deliberately) disabled and …\nSend IOCL commands to a device file.\nCreate (or rename or link) a block device.\nCreate (or rename or link) a character device.\nCreate (or rename) a directory.\nCreate (or rename or link) a named pipe.\nCreate (or rename or link) a regular file.\nCreate (or rename or link) a UNIX domain socket.\nCreate (or rename or link) a symbolic link.\nMissing call to RulesetAttr::handle_access().\nLandlock rule for a network port.\nThe running system doesn’t support Landlock or a subset …\nThe open() system call failed.\nThe best-effort approach was (deliberately) disabled and …\nSome requested restrictions are enforced, following a …\nLandlock rule for a file hierarchy.\nSimple helper to open a file or a directory with the O_PATH…\nOpen a directory or list its content.\nOpen a file with read access.\nLink or rename a file from or to a different directory.\nRemove an empty directory or rename one.\nUnlink (or rename) a file.\nThe landlock_restrict_self() system call failed.\nStatus of a RulesetCreated after calling restrict_self().\nLandlock ruleset builder.\nRuleset created with Ruleset::create().\nMaps to all errors that can be returned by a ruleset …\nEnforcement status of a ruleset.\nThe prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) system call …\nTakes into account the build requests if they are …\nTo check that access-rights are consistent with a file …\nTruncate a file with truncate(2), ftruncate(2), creat(2), …\nThe rule’s access-rights are not all handled by the …\nThe access-rights set was forged with the unsafe …\nKernel not supporting Landlock, either because it is not …\nFirst Landlock ABI, introduced with Linux 5.13.\nSecond Landlock ABI, introduced with Linux 5.19.\nThird Landlock ABI, introduced with Linux 6.2.\nFourth Landlock ABI, introduced with Linux 6.7.\nFifth Landlock ABI, introduced with Linux 6.10.\nOpen a file with write access.\nAttempts to add a new rule to the ruleset.\nAttempts to add a new rule to the ruleset.\nAttempts to add a set of new rules to the ruleset.\nAttempts to add a set of new rules to the ruleset.\nCreate a BitFlags with all flags set.\nReturns the underlying bitwise value.\nReturns the underlying bitwise value.\nReturns true if all flags are contained.\nAttempts to create a real Landlock ruleset (if supported …\nReturns a new Ruleset. This call automatically probes the …\nCreate a BitFlags with no flags set (in other words, with …\nIf exactly one flag is set, the flag is returned. …\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nGets the access rights defined by a specific ABI.\nUnion of from_read() and from_write().\nCreate a BitFlags if the raw value provided does not …\nCreate a BitFlags from an underlying bitwise value. If any …\nCreate a BitFlags<T> from an underlying bitwise value. If …\nCreate a new BitFlags unsafely, without checking if the …\nCreate a new BitFlags unsafely, without checking if the …\nGets the access rights legitimate for non-directory files.\nTurn a T into a BitFlags<T>. Also available as flag.into().\nGets the access rights identified as read-only according …\nGets the access rights identified as write-only according …\nAttempts to add a set of access rights that will be …\nAttempts to add a set of access rights that will be …\nInserts the flags into the BitFlag\nBitwise AND — return value contains flag if both …\nReturns true if at least one flag is shared.\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nCalls U::from(self).\nReturns true if all flags are set\nReturns true if no flag is set\nIterate over the BitFlags.\nReturns the number of flags set.\nmake_bitflags! provides a succint syntax for creating …\nCreates a new PathBeneath rule identifying the parent …\nCreates a new TCP port rule.\nStatus of prctl(2)’s PR_SET_NO_NEW_PRIVS enforcement.\nBitwise NOT — return value contains flag if argument …\nHelper to quickly create an iterator of PathBeneath rules.\nRemoves the matching flags\nAttempts to restrict the calling thread with the ruleset …\nStatus of the Landlock ruleset enforcement.\nInserts if cond holds, else removes\nCf. set_compatibility():\nCf. set_compatibility():\nTo enable a best-effort security approach, Landlock …\nTo enable a best-effort security approach, Landlock …\nConfigures the ruleset to call prctl(2) with the …\nConfigures the ruleset to call prctl(2) with the …\nToggles the matching bits\nCreates a new RulesetCreated instance by duplicating the …\nBitwise OR — return value contains flag if either …") \ No newline at end of file diff --git a/settings.html b/settings.html new file mode 100644 index 0000000..ff15de5 --- /dev/null +++ b/settings.html @@ -0,0 +1 @@ +Settings

Rustdoc settings

Back
\ No newline at end of file diff --git a/src-files.js b/src-files.js new file mode 100644 index 0000000..6db81b6 --- /dev/null +++ b/src-files.js @@ -0,0 +1,4 @@ +var srcIndex = new Map(JSON.parse('[\ +["landlock",["",[["uapi",[],["landlock.rs","mod.rs"]]],["access.rs","compat.rs","errors.rs","fs.rs","lib.rs","net.rs","ruleset.rs"]]]\ +]')); +createSrcSidebar(); diff --git a/src/landlock/access.rs.html b/src/landlock/access.rs.html new file mode 100644 index 0000000..68472df --- /dev/null +++ b/src/landlock/access.rs.html @@ -0,0 +1,357 @@ +access.rs - source
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
+
use crate::{
+    AccessError, AddRuleError, AddRulesError, BitFlags, CompatError, CompatResult,
+    HandleAccessError, HandleAccessesError, Ruleset, TailoredCompatLevel, TryCompat, ABI,
+};
+use enumflags2::BitFlag;
+
+#[cfg(test)]
+use crate::{make_bitflags, AccessFs, CompatLevel, CompatState, Compatibility};
+
+pub trait Access: PrivateAccess {
+    /// Gets the access rights defined by a specific [`ABI`].
+    fn from_all(abi: ABI) -> BitFlags<Self>;
+}
+
+pub trait PrivateAccess: BitFlag {
+    fn ruleset_handle_access(
+        ruleset: &mut Ruleset,
+        access: BitFlags<Self>,
+    ) -> Result<(), HandleAccessesError>
+    where
+        Self: Access;
+
+    fn into_add_rules_error(error: AddRuleError<Self>) -> AddRulesError
+    where
+        Self: Access;
+
+    fn into_handle_accesses_error(error: HandleAccessError<Self>) -> HandleAccessesError
+    where
+        Self: Access;
+}
+
+// Creates an illegal/overflowed BitFlags<T> with all its bits toggled, including undefined ones.
+fn full_negation<T>(flags: BitFlags<T>) -> BitFlags<T>
+where
+    T: Access,
+{
+    unsafe { BitFlags::<T>::from_bits_unchecked(!flags.bits()) }
+}
+
+#[test]
+fn bit_flags_full_negation() {
+    let scoped_negation = !BitFlags::<AccessFs>::all();
+    assert_eq!(scoped_negation, BitFlags::<AccessFs>::empty());
+    // !BitFlags::<AccessFs>::all() could be equal to full_negation(BitFlags::<AccessFs>::all()))
+    // if all the 64-bits would be used, which is not currently the case.
+    assert_ne!(scoped_negation, full_negation(BitFlags::<AccessFs>::all()));
+}
+
+impl<A> TailoredCompatLevel for BitFlags<A> where A: Access {}
+
+impl<A> TryCompat<A> for BitFlags<A>
+where
+    A: Access,
+{
+    fn try_compat_inner(&mut self, abi: ABI) -> Result<CompatResult<A>, CompatError<A>> {
+        if self.is_empty() {
+            // Empty access-rights would result to a runtime error.
+            Err(AccessError::Empty.into())
+        } else if !Self::all().contains(*self) {
+            // Unknown access-rights (at build time) would result to a runtime error.
+            // This can only be reached by using the unsafe BitFlags::from_bits_unchecked().
+            Err(AccessError::Unknown {
+                access: *self,
+                unknown: *self & full_negation(Self::all()),
+            }
+            .into())
+        } else {
+            let compat = *self & A::from_all(abi);
+            let ret = if compat.is_empty() {
+                Ok(CompatResult::No(
+                    AccessError::Incompatible { access: *self }.into(),
+                ))
+            } else if compat != *self {
+                let error = AccessError::PartiallyCompatible {
+                    access: *self,
+                    incompatible: *self & full_negation(compat),
+                }
+                .into();
+                Ok(CompatResult::Partial(error))
+            } else {
+                Ok(CompatResult::Full)
+            };
+            *self = compat;
+            ret
+        }
+    }
+}
+
+#[test]
+fn compat_bit_flags() {
+    use crate::ABI;
+
+    let mut compat: Compatibility = ABI::V1.into();
+    assert!(compat.state == CompatState::Init);
+
+    let ro_access = make_bitflags!(AccessFs::{Execute | ReadFile | ReadDir});
+    assert_eq!(
+        ro_access,
+        ro_access
+            .try_compat(compat.abi(), compat.level, &mut compat.state)
+            .unwrap()
+            .unwrap()
+    );
+    assert!(compat.state == CompatState::Full);
+
+    let empty_access = BitFlags::<AccessFs>::empty();
+    assert!(matches!(
+        empty_access
+            .try_compat(compat.abi(), compat.level, &mut compat.state)
+            .unwrap_err(),
+        CompatError::Access(AccessError::Empty)
+    ));
+
+    let all_unknown_access = unsafe { BitFlags::<AccessFs>::from_bits_unchecked(1 << 63) };
+    assert!(matches!(
+        all_unknown_access.try_compat(compat.abi(), compat.level, &mut compat.state).unwrap_err(),
+        CompatError::Access(AccessError::Unknown { access, unknown }) if access == all_unknown_access && unknown == all_unknown_access
+    ));
+    // An error makes the state final.
+    assert!(compat.state == CompatState::Dummy);
+
+    let some_unknown_access = unsafe { BitFlags::<AccessFs>::from_bits_unchecked(1 << 63 | 1) };
+    assert!(matches!(
+        some_unknown_access.try_compat(compat.abi(), compat.level, &mut compat.state).unwrap_err(),
+        CompatError::Access(AccessError::Unknown { access, unknown }) if access == some_unknown_access && unknown == all_unknown_access
+    ));
+    assert!(compat.state == CompatState::Dummy);
+
+    compat = ABI::Unsupported.into();
+
+    // Tests that the ruleset is marked as unsupported.
+    assert!(compat.state == CompatState::Init);
+
+    // Access-rights are valid (but ignored) when they are not required for the current ABI.
+    assert_eq!(
+        None,
+        ro_access
+            .try_compat(compat.abi(), compat.level, &mut compat.state)
+            .unwrap()
+    );
+
+    assert!(compat.state == CompatState::No);
+
+    // Access-rights are not valid when they are required for the current ABI.
+    compat.level = Some(CompatLevel::HardRequirement);
+    assert!(matches!(
+        ro_access.try_compat(compat.abi(), compat.level, &mut compat.state).unwrap_err(),
+        CompatError::Access(AccessError::Incompatible { access }) if access == ro_access
+    ));
+
+    compat = ABI::V1.into();
+
+    // Tests that the ruleset is marked as the unknown compatibility state.
+    assert!(compat.state == CompatState::Init);
+
+    // Access-rights are valid (but ignored) when they are not required for the current ABI.
+    assert_eq!(
+        ro_access,
+        ro_access
+            .try_compat(compat.abi(), compat.level, &mut compat.state)
+            .unwrap()
+            .unwrap()
+    );
+
+    // Tests that the ruleset is in an unsupported state, which is important to be able to still
+    // enforce no_new_privs.
+    assert!(compat.state == CompatState::Full);
+
+    let v2_access = ro_access | AccessFs::Refer;
+
+    // Access-rights are not valid when they are required for the current ABI.
+    compat.level = Some(CompatLevel::HardRequirement);
+    assert!(matches!(
+        v2_access.try_compat(compat.abi(), compat.level, &mut compat.state).unwrap_err(),
+        CompatError::Access(AccessError::PartiallyCompatible { access, incompatible })
+            if access == v2_access && incompatible == AccessFs::Refer
+    ));
+}
+
\ No newline at end of file diff --git a/src/landlock/compat.rs.html b/src/landlock/compat.rs.html new file mode 100644 index 0000000..82d7950 --- /dev/null +++ b/src/landlock/compat.rs.html @@ -0,0 +1,1337 @@ +compat.rs - source
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
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+
use crate::{uapi, Access, CompatError};
+
+#[cfg(test)]
+use std::convert::TryInto;
+#[cfg(test)]
+use strum::{EnumCount, IntoEnumIterator};
+#[cfg(test)]
+use strum_macros::{EnumCount as EnumCountMacro, EnumIter};
+
+/// Version of the Landlock [ABI](https://en.wikipedia.org/wiki/Application_binary_interface).
+///
+/// `ABI` enables getting the features supported by a specific Landlock ABI
+/// (without relying on the kernel version which may not be accessible or patched).
+/// For example, [`AccessFs::from_all(ABI::V1)`](Access::from_all)
+/// gets all the file system access rights defined by the first version.
+///
+/// Without `ABI`, it would be hazardous to rely on the the full set of access flags
+/// (e.g., `BitFlags::<AccessFs>::all()` or `BitFlags::ALL`),
+/// a moving target that would change the semantics of your Landlock rule
+/// when migrating to a newer version of this crate.
+/// Indeed, a simple `cargo update` or `cargo install` run by any developer
+/// can result in a new version of this crate (fixing bugs or bringing non-breaking changes).
+/// This crate cannot give any guarantee concerning the new restrictions resulting from
+/// these unknown bits (i.e. access rights) that would not be controlled by your application but by
+/// a future version of this crate instead.
+/// Because we cannot know what the effect on your application of an unknown restriction would be
+/// when handling an untested Landlock access right (i.e. denied-by-default access),
+/// it could trigger bugs in your application.
+///
+/// This crate provides a set of tools to sandbox as much as possible
+/// while guaranteeing a consistent behavior thanks to the [`Compatible`] methods.
+/// You should also test with different relevant kernel versions,
+/// see [landlock-test-tools](https://github.com/landlock-lsm/landlock-test-tools) and
+/// [CI integration](https://github.com/landlock-lsm/rust-landlock/pull/41).
+///
+/// This way, we can have the guarantee that the use of a set of tested Landlock ABI works as
+/// expected because features brought by newer Landlock ABI will never be enabled by default
+/// (cf. [Linux kernel compatibility contract](https://docs.kernel.org/userspace-api/landlock.html#compatibility)).
+///
+/// In a nutshell, test the access rights you request on a kernel that support them and
+/// on a kernel that doesn't support them.
+#[cfg_attr(
+    test,
+    derive(Debug, PartialEq, Eq, PartialOrd, EnumIter, EnumCountMacro)
+)]
+#[derive(Copy, Clone)]
+#[non_exhaustive]
+pub enum ABI {
+    /// Kernel not supporting Landlock, either because it is not built with Landlock
+    /// or Landlock is not enabled at boot.
+    Unsupported = 0,
+    /// First Landlock ABI, introduced with
+    /// [Linux 5.13](https://git.kernel.org/stable/c/17ae69aba89dbfa2139b7f8024b757ab3cc42f59).
+    V1 = 1,
+    /// Second Landlock ABI, introduced with
+    /// [Linux 5.19](https://git.kernel.org/stable/c/cb44e4f061e16be65b8a16505e121490c66d30d0).
+    V2 = 2,
+    /// Third Landlock ABI, introduced with
+    /// [Linux 6.2](https://git.kernel.org/stable/c/299e2b1967578b1442128ba8b3e86ed3427d3651).
+    V3 = 3,
+    /// Fourth Landlock ABI, introduced with
+    /// [Linux 6.7](https://git.kernel.org/stable/c/136cc1e1f5be75f57f1e0404b94ee1c8792cb07d).
+    V4 = 4,
+    /// Fifth Landlock ABI, introduced with
+    /// [Linux 6.10](https://git.kernel.org/stable/c/2fc0e7892c10734c1b7c613ef04836d57d4676d5).
+    V5 = 5,
+}
+
+impl ABI {
+    // Must remain private to avoid inconsistent behavior by passing Ok(self) to a builder method,
+    // e.g. to make it impossible to call ruleset.handle_fs(ABI::new_current()?)
+    fn new_current() -> Self {
+        ABI::from(unsafe {
+            // Landlock ABI version starts at 1 but errno is only set for negative values.
+            uapi::landlock_create_ruleset(
+                std::ptr::null(),
+                0,
+                uapi::LANDLOCK_CREATE_RULESET_VERSION,
+            )
+        })
+    }
+
+    // There is no way to not publicly expose an implementation of an external trait such as
+    // From<i32>.  See RFC https://github.com/rust-lang/rfcs/pull/2529
+    fn from(value: i32) -> ABI {
+        match value {
+            // The only possible error values should be EOPNOTSUPP and ENOSYS, but let's interpret
+            // all kind of errors as unsupported.
+            n if n <= 0 => ABI::Unsupported,
+            1 => ABI::V1,
+            2 => ABI::V2,
+            3 => ABI::V3,
+            4 => ABI::V4,
+            // Returns the greatest known ABI.
+            _ => ABI::V5,
+        }
+    }
+
+    #[cfg(test)]
+    fn is_known(value: i32) -> bool {
+        value > 0 && value < ABI::COUNT as i32
+    }
+}
+
+#[test]
+fn abi_from() {
+    // EOPNOTSUPP (-95), ENOSYS (-38)
+    for n in [-95, -38, -1, 0] {
+        assert_eq!(ABI::from(n), ABI::Unsupported);
+    }
+
+    let mut last_i = 1;
+    let mut last_abi = ABI::Unsupported;
+    for (i, abi) in ABI::iter().enumerate() {
+        last_i = i.try_into().unwrap();
+        last_abi = abi;
+        assert_eq!(ABI::from(last_i), last_abi);
+    }
+
+    assert_eq!(ABI::from(last_i + 1), last_abi);
+    assert_eq!(ABI::from(9), last_abi);
+}
+
+#[test]
+fn known_abi() {
+    assert!(!ABI::is_known(-1));
+    assert!(!ABI::is_known(0));
+    assert!(!ABI::is_known(99));
+
+    let mut last_i = -1;
+    for (i, _) in ABI::iter().enumerate().skip(1) {
+        last_i = i as i32;
+        assert!(ABI::is_known(last_i));
+    }
+    assert!(!ABI::is_known(last_i + 1));
+}
+
+#[cfg(test)]
+lazy_static! {
+    static ref TEST_ABI: ABI = match std::env::var("LANDLOCK_CRATE_TEST_ABI") {
+        Ok(s) => {
+            let n = s.parse::<i32>().unwrap();
+            if ABI::is_known(n) || n == 0 {
+                ABI::from(n)
+            } else {
+                panic!("Unknown ABI: {n}");
+            }
+        }
+        Err(std::env::VarError::NotPresent) => ABI::iter().last().unwrap(),
+        Err(e) => panic!("Failed to read LANDLOCK_CRATE_TEST_ABI: {e}"),
+    };
+}
+
+#[cfg(test)]
+pub(crate) fn can_emulate(mock: ABI, partial_support: ABI, full_support: Option<ABI>) -> bool {
+    mock < partial_support
+        || mock <= *TEST_ABI
+        || if let Some(full) = full_support {
+            full <= *TEST_ABI
+        } else {
+            partial_support <= *TEST_ABI
+        }
+}
+
+#[cfg(test)]
+pub(crate) fn get_errno_from_landlock_status() -> Option<i32> {
+    use std::io::Error;
+
+    if unsafe {
+        uapi::landlock_create_ruleset(std::ptr::null(), 0, uapi::LANDLOCK_CREATE_RULESET_VERSION)
+    } < 0
+    {
+        match Error::last_os_error().raw_os_error() {
+            // Returns ENOSYS when the kernel is not built with Landlock support,
+            // or EOPNOTSUPP when Landlock is supported but disabled at boot time.
+            ret @ Some(libc::ENOSYS | libc::EOPNOTSUPP) => ret,
+            // Other values can only come from bogus seccomp filters or debug tampering.
+            _ => unreachable!(),
+        }
+    } else {
+        None
+    }
+}
+
+#[test]
+fn current_kernel_abi() {
+    // Ensures that the tested Landlock ABI is the latest known version supported by the running
+    // kernel.  If this test failed, you need set the LANDLOCK_CRATE_TEST_ABI environment variable
+    // to the Landlock ABI version supported by your kernel.  With a missing variable, the latest
+    // Landlock ABI version known by this crate is automatically set.
+    // From Linux 5.13 to 5.18, you need to run: LANDLOCK_CRATE_TEST_ABI=1 cargo test
+    assert_eq!(*TEST_ABI, ABI::new_current());
+}
+
+// CompatState is not public outside this crate.
+/// Returned by ruleset builder.
+#[cfg_attr(test, derive(Debug))]
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub enum CompatState {
+    /// Initial undefined state.
+    Init,
+    /// All requested restrictions are enforced.
+    Full,
+    /// Some requested restrictions are enforced, following a best-effort approach.
+    Partial,
+    /// The running system doesn't support Landlock.
+    No,
+    /// Final unsupported state.
+    Dummy,
+}
+
+impl CompatState {
+    fn update(&mut self, other: Self) {
+        *self = match (*self, other) {
+            (CompatState::Init, other) => other,
+            (CompatState::Dummy, _) => CompatState::Dummy,
+            (_, CompatState::Dummy) => CompatState::Dummy,
+            (CompatState::No, CompatState::No) => CompatState::No,
+            (CompatState::Full, CompatState::Full) => CompatState::Full,
+            (_, _) => CompatState::Partial,
+        }
+    }
+}
+
+#[test]
+fn compat_state_update_1() {
+    let mut state = CompatState::Full;
+
+    state.update(CompatState::Full);
+    assert_eq!(state, CompatState::Full);
+
+    state.update(CompatState::No);
+    assert_eq!(state, CompatState::Partial);
+
+    state.update(CompatState::Full);
+    assert_eq!(state, CompatState::Partial);
+
+    state.update(CompatState::Full);
+    assert_eq!(state, CompatState::Partial);
+
+    state.update(CompatState::No);
+    assert_eq!(state, CompatState::Partial);
+
+    state.update(CompatState::Dummy);
+    assert_eq!(state, CompatState::Dummy);
+
+    state.update(CompatState::Full);
+    assert_eq!(state, CompatState::Dummy);
+}
+
+#[test]
+fn compat_state_update_2() {
+    let mut state = CompatState::Full;
+
+    state.update(CompatState::Full);
+    assert_eq!(state, CompatState::Full);
+
+    state.update(CompatState::No);
+    assert_eq!(state, CompatState::Partial);
+
+    state.update(CompatState::Full);
+    assert_eq!(state, CompatState::Partial);
+}
+
+#[cfg_attr(test, derive(Debug, PartialEq))]
+#[derive(Copy, Clone)]
+pub(crate) struct Compatibility {
+    abi: ABI,
+    pub(crate) level: Option<CompatLevel>,
+    pub(crate) state: CompatState,
+}
+
+impl From<ABI> for Compatibility {
+    fn from(abi: ABI) -> Self {
+        Compatibility {
+            abi,
+            level: Default::default(),
+            state: CompatState::Init,
+        }
+    }
+}
+
+impl Compatibility {
+    // Compatibility is a semi-opaque struct.
+    #[allow(clippy::new_without_default)]
+    pub(crate) fn new() -> Self {
+        ABI::new_current().into()
+    }
+
+    pub(crate) fn update(&mut self, state: CompatState) {
+        self.state.update(state);
+    }
+
+    pub(crate) fn abi(&self) -> ABI {
+        self.abi
+    }
+}
+
+pub(crate) mod private {
+    use crate::CompatLevel;
+
+    pub trait OptionCompatLevelMut {
+        fn as_option_compat_level_mut(&mut self) -> &mut Option<CompatLevel>;
+    }
+}
+
+/// Properly handles runtime unsupported features.
+///
+/// This guarantees consistent behaviors across crate users
+/// and runtime kernels even if this crate get new features.
+/// It eases backward compatibility and enables future-proofness.
+///
+/// Landlock is a security feature designed to help improve security of a running system
+/// thanks to application developers.
+/// To protect users as much as possible,
+/// compatibility with the running system should then be handled in a best-effort way,
+/// contrary to common system features.
+/// In some circumstances
+/// (e.g. applications carefully designed to only be run with a specific set of kernel features),
+/// it may be required to error out if some of these features are not available
+/// and will then not be enforced.
+pub trait Compatible: Sized + private::OptionCompatLevelMut {
+    /// To enable a best-effort security approach,
+    /// Landlock features that are not supported by the running system
+    /// are silently ignored by default,
+    /// which is a sane choice for most use cases.
+    /// However, on some rare circumstances,
+    /// developers may want to have some guarantees that their applications
+    /// will not run if a certain level of sandboxing is not possible.
+    /// If we really want to error out when not all our requested requirements are met,
+    /// then we can configure it with `set_compatibility()`.
+    ///
+    /// The `Compatible` trait is implemented for all object builders
+    /// (e.g. [`Ruleset`](crate::Ruleset)).
+    /// Such builders have a set of methods to incrementally build an object.
+    /// These build methods rely on kernel features that may not be available at runtime.
+    /// The `set_compatibility()` method enables to control the effect of
+    /// the following build method calls starting after the `set_compatibility()` call.
+    /// Such effect can be:
+    /// * to silently ignore unsupported features
+    ///   and continue building ([`CompatLevel::BestEffort`]);
+    /// * to silently ignore unsupported features
+    ///   and ignore the whole build ([`CompatLevel::SoftRequirement`]);
+    /// * to return an error for any unsupported feature ([`CompatLevel::HardRequirement`]).
+    ///
+    /// Taking [`Ruleset`](crate::Ruleset) as an example,
+    /// the [`handle_access()`](crate::RulesetAttr::handle_access()) build method
+    /// returns a [`Result`] that can be [`Err(RulesetError)`](crate::RulesetError)
+    /// with a nested [`CompatError`].
+    /// Such error can only occur with a running Linux kernel not supporting the requested
+    /// Landlock accesses *and* if the current compatibility level is
+    /// [`CompatLevel::HardRequirement`].
+    /// However, such error is not possible with [`CompatLevel::BestEffort`]
+    /// nor [`CompatLevel::SoftRequirement`].
+    ///
+    /// The order of this call is important because
+    /// it defines the behavior of the following build method calls that return a [`Result`].
+    /// If `set_compatibility(CompatLevel::HardRequirement)` is called on an object,
+    /// then a [`CompatError`] may be returned for the next method calls,
+    /// until the next call to `set_compatibility()`.
+    /// This enables to change the behavior of a set of build method calls,
+    /// for instance to be sure that the sandbox will at least restrict some access rights.
+    ///
+    /// New objects inherit the compatibility configuration of their parents, if any.
+    /// For instance, [`Ruleset::create()`](crate::Ruleset::create()) returns
+    /// a [`RulesetCreated`](crate::RulesetCreated) object that inherits the
+    /// `Ruleset`'s compatibility configuration.
+    ///
+    /// # Example with `SoftRequirement`
+    ///
+    /// Let's say an application legitimately needs to rename files between directories.
+    /// Because of [previous Landlock limitations](https://docs.kernel.org/userspace-api/landlock.html#file-renaming-and-linking-abi-2),
+    /// this was forbidden with the [first version of Landlock](ABI::V1),
+    /// but it is now handled starting with the [second version](ABI::V2).
+    /// For this use case, we only want the application to be sandboxed
+    /// if we have the guarantee that it will not break a legitimate usage (i.e. rename files).
+    /// We then create a ruleset which will either support file renaming
+    /// (thanks to [`AccessFs::Refer`](crate::AccessFs::Refer)) or silently do nothing.
+    ///
+    /// ```
+    /// use landlock::*;
+    ///
+    /// fn ruleset_handling_renames() -> Result<RulesetCreated, RulesetError> {
+    ///     Ok(Ruleset::default()
+    ///         // This ruleset must either handle the AccessFs::Refer right,
+    ///         // or it must silently ignore the whole sandboxing.
+    ///         .set_compatibility(CompatLevel::SoftRequirement)
+    ///         .handle_access(AccessFs::Refer)?
+    ///         // However, this ruleset may also handle other (future) access rights
+    ///         // if they are supported by the running kernel.
+    ///         .set_compatibility(CompatLevel::BestEffort)
+    ///         .handle_access(AccessFs::from_all(ABI::V5))?
+    ///         .create()?)
+    /// }
+    /// ```
+    ///
+    /// # Example with `HardRequirement`
+    ///
+    /// Security-dedicated applications may want to ensure that
+    /// an untrusted software component is subject to a minimum of restrictions before launching it.
+    /// In this case, we want to create a ruleset which will at least support
+    /// all restrictions provided by the [first version of Landlock](ABI::V1),
+    /// and opportunistically handle restrictions supported by newer kernels.
+    ///
+    /// ```
+    /// use landlock::*;
+    ///
+    /// fn ruleset_fragile() -> Result<RulesetCreated, RulesetError> {
+    ///     Ok(Ruleset::default()
+    ///         // This ruleset must either handle at least all accesses defined by
+    ///         // the first Landlock version (e.g. AccessFs::WriteFile),
+    ///         // or the following handle_access() call must return a wrapped
+    ///         // AccessError<AccessFs>::Incompatible error.
+    ///         .set_compatibility(CompatLevel::HardRequirement)
+    ///         .handle_access(AccessFs::from_all(ABI::V1))?
+    ///         // However, this ruleset may also handle new access rights
+    ///         // (e.g. AccessFs::Refer defined by the second version of Landlock)
+    ///         // if they are supported by the running kernel,
+    ///         // but without returning any error otherwise.
+    ///         .set_compatibility(CompatLevel::BestEffort)
+    ///         .handle_access(AccessFs::from_all(ABI::V5))?
+    ///         .create()?)
+    /// }
+    /// ```
+    fn set_compatibility(mut self, level: CompatLevel) -> Self {
+        *self.as_option_compat_level_mut() = Some(level);
+        self
+    }
+
+    /// Cf. [`set_compatibility()`](Compatible::set_compatibility()):
+    ///
+    /// - `set_best_effort(true)` translates to `set_compatibility(CompatLevel::BestEffort)`.
+    ///
+    /// - `set_best_effort(false)` translates to `set_compatibility(CompatLevel::HardRequirement)`.
+    #[deprecated(note = "Use set_compatibility() instead")]
+    fn set_best_effort(self, best_effort: bool) -> Self
+    where
+        Self: Sized,
+    {
+        self.set_compatibility(match best_effort {
+            true => CompatLevel::BestEffort,
+            false => CompatLevel::HardRequirement,
+        })
+    }
+}
+
+#[test]
+#[allow(deprecated)]
+fn deprecated_set_best_effort() {
+    use crate::{CompatLevel, Compatible, Ruleset};
+
+    assert_eq!(
+        Ruleset::default().set_best_effort(true).compat,
+        Ruleset::default()
+            .set_compatibility(CompatLevel::BestEffort)
+            .compat
+    );
+    assert_eq!(
+        Ruleset::default().set_best_effort(false).compat,
+        Ruleset::default()
+            .set_compatibility(CompatLevel::HardRequirement)
+            .compat
+    );
+}
+
+/// See the [`Compatible`] documentation.
+#[cfg_attr(test, derive(EnumIter))]
+#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub enum CompatLevel {
+    /// Takes into account the build requests if they are supported by the running system,
+    /// or silently ignores them otherwise.
+    /// Never returns a compatibility error.
+    #[default]
+    BestEffort,
+    /// Takes into account the build requests if they are supported by the running system,
+    /// or silently ignores the whole build object otherwise.
+    /// Never returns a compatibility error.
+    /// If not supported,
+    /// the call to [`RulesetCreated::restrict_self()`](crate::RulesetCreated::restrict_self())
+    /// will return a
+    /// [`RestrictionStatus { ruleset: RulesetStatus::NotEnforced, no_new_privs: false, }`](crate::RestrictionStatus).
+    SoftRequirement,
+    /// Takes into account the build requests if they are supported by the running system,
+    /// or returns a compatibility error otherwise ([`CompatError`]).
+    HardRequirement,
+}
+
+impl From<Option<CompatLevel>> for CompatLevel {
+    fn from(opt: Option<CompatLevel>) -> Self {
+        match opt {
+            None => CompatLevel::default(),
+            Some(ref level) => *level,
+        }
+    }
+}
+
+// TailoredCompatLevel could be replaced with AsMut<Option<CompatLevel>>, but only traits defined
+// in the current crate can be implemented for types defined outside of the crate.  Furthermore it
+// provides a default implementation which is handy for types such as BitFlags.
+pub trait TailoredCompatLevel {
+    fn tailored_compat_level<L>(&mut self, parent_level: L) -> CompatLevel
+    where
+        L: Into<CompatLevel>,
+    {
+        parent_level.into()
+    }
+}
+
+impl<T> TailoredCompatLevel for T
+where
+    Self: Compatible,
+{
+    // Every Compatible trait implementation returns its own compatibility level, if set.
+    fn tailored_compat_level<L>(&mut self, parent_level: L) -> CompatLevel
+    where
+        L: Into<CompatLevel>,
+    {
+        // Using a mutable reference is not required but it makes the code simpler (no double AsRef
+        // implementations for each Compatible types), and more importantly it guarantees
+        // consistency with Compatible::set_compatibility().
+        match self.as_option_compat_level_mut() {
+            None => parent_level.into(),
+            // Returns the most constrained compatibility level.
+            Some(ref level) => parent_level.into().max(*level),
+        }
+    }
+}
+
+#[test]
+fn tailored_compat_level() {
+    use crate::{AccessFs, PathBeneath, PathFd};
+
+    fn new_path(level: CompatLevel) -> PathBeneath<PathFd> {
+        PathBeneath::new(PathFd::new("/").unwrap(), AccessFs::Execute).set_compatibility(level)
+    }
+
+    for parent_level in CompatLevel::iter() {
+        assert_eq!(
+            new_path(CompatLevel::BestEffort).tailored_compat_level(parent_level),
+            parent_level
+        );
+        assert_eq!(
+            new_path(CompatLevel::HardRequirement).tailored_compat_level(parent_level),
+            CompatLevel::HardRequirement
+        );
+    }
+
+    assert_eq!(
+        new_path(CompatLevel::SoftRequirement).tailored_compat_level(CompatLevel::SoftRequirement),
+        CompatLevel::SoftRequirement
+    );
+
+    for child_level in CompatLevel::iter() {
+        assert_eq!(
+            new_path(child_level).tailored_compat_level(CompatLevel::BestEffort),
+            child_level
+        );
+        assert_eq!(
+            new_path(child_level).tailored_compat_level(CompatLevel::HardRequirement),
+            CompatLevel::HardRequirement
+        );
+    }
+}
+
+// CompatResult is not public outside this crate.
+pub enum CompatResult<A>
+where
+    A: Access,
+{
+    // Fully matches the request.
+    Full,
+    // Partially matches the request.
+    Partial(CompatError<A>),
+    // Doesn't matches the request.
+    No(CompatError<A>),
+}
+
+// TryCompat is not public outside this crate.
+pub trait TryCompat<A>
+where
+    Self: Sized + TailoredCompatLevel,
+    A: Access,
+{
+    fn try_compat_inner(&mut self, abi: ABI) -> Result<CompatResult<A>, CompatError<A>>;
+
+    // Default implementation for objects without children.
+    //
+    // If returning something other than Ok(Some(self)), the implementation must use its own
+    // compatibility level, if any, with self.tailored_compat_level(default_compat_level), and pass
+    // it with the abi and compat_state to each child.try_compat().  See PathBeneath implementation
+    // and the self.allowed_access.try_compat() call.
+    //
+    // # Warning
+    //
+    // Errors must be prioritized over incompatibility (i.e. return Err(e) over Ok(None)) for all
+    // children.
+    fn try_compat_children<L>(
+        self,
+        _abi: ABI,
+        _parent_level: L,
+        _compat_state: &mut CompatState,
+    ) -> Result<Option<Self>, CompatError<A>>
+    where
+        L: Into<CompatLevel>,
+    {
+        Ok(Some(self))
+    }
+
+    // Update compat_state and return an error according to try_compat_*() error, or to the
+    // compatibility level, i.e. either route compatible object or error.
+    fn try_compat<L>(
+        mut self,
+        abi: ABI,
+        parent_level: L,
+        compat_state: &mut CompatState,
+    ) -> Result<Option<Self>, CompatError<A>>
+    where
+        L: Into<CompatLevel>,
+    {
+        let compat_level = self.tailored_compat_level(parent_level);
+        let some_inner = match self.try_compat_inner(abi) {
+            Ok(CompatResult::Full) => {
+                compat_state.update(CompatState::Full);
+                true
+            }
+            Ok(CompatResult::Partial(error)) => match compat_level {
+                CompatLevel::BestEffort => {
+                    compat_state.update(CompatState::Partial);
+                    true
+                }
+                CompatLevel::SoftRequirement => {
+                    compat_state.update(CompatState::Dummy);
+                    false
+                }
+                CompatLevel::HardRequirement => {
+                    compat_state.update(CompatState::Dummy);
+                    return Err(error);
+                }
+            },
+            Ok(CompatResult::No(error)) => match compat_level {
+                CompatLevel::BestEffort => {
+                    compat_state.update(CompatState::No);
+                    false
+                }
+                CompatLevel::SoftRequirement => {
+                    compat_state.update(CompatState::Dummy);
+                    false
+                }
+                CompatLevel::HardRequirement => {
+                    compat_state.update(CompatState::Dummy);
+                    return Err(error);
+                }
+            },
+            Err(error) => {
+                // Safeguard to help for test consistency.
+                compat_state.update(CompatState::Dummy);
+                return Err(error);
+            }
+        };
+
+        // At this point, any inner error have been returned, so we can proceed with
+        // try_compat_children()?.
+        match self.try_compat_children(abi, compat_level, compat_state)? {
+            Some(n) if some_inner => Ok(Some(n)),
+            _ => Ok(None),
+        }
+    }
+}
+
\ No newline at end of file diff --git a/src/landlock/errors.rs.html b/src/landlock/errors.rs.html new file mode 100644 index 0000000..c5d08f5 --- /dev/null +++ b/src/landlock/errors.rs.html @@ -0,0 +1,423 @@ +errors.rs - source
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
+
use crate::{Access, AccessFs, AccessNet, BitFlags};
+use std::io;
+use std::path::PathBuf;
+use thiserror::Error;
+
+/// Maps to all errors that can be returned by a ruleset action.
+#[derive(Debug, Error)]
+#[non_exhaustive]
+pub enum RulesetError {
+    #[error(transparent)]
+    HandleAccesses(#[from] HandleAccessesError),
+    #[error(transparent)]
+    CreateRuleset(#[from] CreateRulesetError),
+    #[error(transparent)]
+    AddRules(#[from] AddRulesError),
+    #[error(transparent)]
+    RestrictSelf(#[from] RestrictSelfError),
+}
+
+#[test]
+fn ruleset_error_breaking_change() {
+    use crate::*;
+
+    // Generics are part of the API and modifying them can lead to a breaking change.
+    let _: RulesetError = RulesetError::HandleAccesses(HandleAccessesError::Fs(
+        HandleAccessError::Compat(CompatError::Access(AccessError::Empty)),
+    ));
+}
+
+/// Identifies errors when updating the ruleset's handled access-rights.
+#[derive(Debug, Error)]
+#[non_exhaustive]
+pub enum HandleAccessError<T>
+where
+    T: Access,
+{
+    #[error(transparent)]
+    Compat(#[from] CompatError<T>),
+}
+
+#[derive(Debug, Error)]
+#[non_exhaustive]
+pub enum HandleAccessesError {
+    #[error(transparent)]
+    Fs(HandleAccessError<AccessFs>),
+    #[error(transparent)]
+    Net(HandleAccessError<AccessNet>),
+}
+
+// Generically implement for all the access implementations rather than for the cases listed in
+// HandleAccessesError (with #[from]).
+impl<A> From<HandleAccessError<A>> for HandleAccessesError
+where
+    A: Access,
+{
+    fn from(error: HandleAccessError<A>) -> Self {
+        A::into_handle_accesses_error(error)
+    }
+}
+
+/// Identifies errors when creating a ruleset.
+#[derive(Debug, Error)]
+#[non_exhaustive]
+pub enum CreateRulesetError {
+    /// The `landlock_create_ruleset()` system call failed.
+    #[error("failed to create a ruleset: {source}")]
+    #[non_exhaustive]
+    CreateRulesetCall { source: io::Error },
+    /// Missing call to [`RulesetAttr::handle_access()`](crate::RulesetAttr::handle_access).
+    #[error("missing handled access")]
+    MissingHandledAccess,
+}
+
+/// Identifies errors when adding a rule to a ruleset.
+#[derive(Debug, Error)]
+#[non_exhaustive]
+pub enum AddRuleError<T>
+where
+    T: Access,
+{
+    /// The `landlock_add_rule()` system call failed.
+    #[error("failed to add a rule: {source}")]
+    #[non_exhaustive]
+    AddRuleCall { source: io::Error },
+    /// The rule's access-rights are not all handled by the (requested) ruleset access-rights.
+    #[error("access-rights not handled by the ruleset: {incompatible:?}")]
+    UnhandledAccess {
+        access: BitFlags<T>,
+        incompatible: BitFlags<T>,
+    },
+    #[error(transparent)]
+    Compat(#[from] CompatError<T>),
+}
+
+// Generically implement for all the access implementations rather than for the cases listed in
+// AddRulesError (with #[from]).
+impl<A> From<AddRuleError<A>> for AddRulesError
+where
+    A: Access,
+{
+    fn from(error: AddRuleError<A>) -> Self {
+        A::into_add_rules_error(error)
+    }
+}
+
+/// Identifies errors when adding rules to a ruleset thanks to an iterator returning
+/// Result<Rule, E> items.
+#[derive(Debug, Error)]
+#[non_exhaustive]
+pub enum AddRulesError {
+    #[error(transparent)]
+    Fs(AddRuleError<AccessFs>),
+    #[error(transparent)]
+    Net(AddRuleError<AccessNet>),
+}
+
+#[derive(Debug, Error)]
+#[non_exhaustive]
+pub enum CompatError<T>
+where
+    T: Access,
+{
+    #[error(transparent)]
+    PathBeneath(#[from] PathBeneathError),
+    #[error(transparent)]
+    Access(#[from] AccessError<T>),
+}
+
+#[derive(Debug, Error)]
+#[non_exhaustive]
+pub enum PathBeneathError {
+    /// To check that access-rights are consistent with a file descriptor, a call to
+    /// [`RulesetCreatedAttr::add_rule()`](crate::RulesetCreatedAttr::add_rule)
+    /// looks at the file type with an `fstat()` system call.
+    #[error("failed to check file descriptor type: {source}")]
+    #[non_exhaustive]
+    StatCall { source: io::Error },
+    /// This error is returned by
+    /// [`RulesetCreatedAttr::add_rule()`](crate::RulesetCreatedAttr::add_rule)
+    /// if the related PathBeneath object is not set to best-effort,
+    /// and if its allowed access-rights contain directory-only ones
+    /// whereas the file descriptor doesn't point to a directory.
+    #[error("incompatible directory-only access-rights: {incompatible:?}")]
+    DirectoryAccess {
+        access: BitFlags<AccessFs>,
+        incompatible: BitFlags<AccessFs>,
+    },
+}
+
+#[derive(Debug, Error)]
+// Exhaustive enum
+pub enum AccessError<T>
+where
+    T: Access,
+{
+    /// The access-rights set is empty, which doesn't make sense and would be rejected by the
+    /// kernel.
+    #[error("empty access-right")]
+    Empty,
+    /// The access-rights set was forged with the unsafe `BitFlags::from_bits_unchecked()` and it
+    /// contains unknown bits.
+    #[error("unknown access-rights (at build time): {unknown:?}")]
+    Unknown {
+        access: BitFlags<T>,
+        unknown: BitFlags<T>,
+    },
+    /// The best-effort approach was (deliberately) disabled and the requested access-rights are
+    /// fully incompatible with the running kernel.
+    #[error("fully incompatible access-rights: {access:?}")]
+    Incompatible { access: BitFlags<T> },
+    /// The best-effort approach was (deliberately) disabled and the requested access-rights are
+    /// partially incompatible with the running kernel.
+    #[error("partially incompatible access-rights: {incompatible:?}")]
+    PartiallyCompatible {
+        access: BitFlags<T>,
+        incompatible: BitFlags<T>,
+    },
+}
+
+#[derive(Debug, Error)]
+#[non_exhaustive]
+pub enum RestrictSelfError {
+    /// The `prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)` system call failed.
+    #[error("failed to set no_new_privs: {source}")]
+    #[non_exhaustive]
+    SetNoNewPrivsCall { source: io::Error },
+    /// The `landlock_restrict_self() `system call failed.
+    #[error("failed to restrict the calling thread: {source}")]
+    #[non_exhaustive]
+    RestrictSelfCall { source: io::Error },
+}
+
+#[derive(Debug, Error)]
+#[non_exhaustive]
+pub enum PathFdError {
+    /// The `open()` system call failed.
+    #[error("failed to open \"{path}\": {source}")]
+    #[non_exhaustive]
+    OpenCall { source: io::Error, path: PathBuf },
+}
+
+#[cfg(test)]
+#[derive(Debug, Error)]
+pub(crate) enum TestRulesetError {
+    #[error(transparent)]
+    Ruleset(#[from] RulesetError),
+    #[error(transparent)]
+    PathFd(#[from] PathFdError),
+    #[error(transparent)]
+    File(#[from] std::io::Error),
+}
+
\ No newline at end of file diff --git a/src/landlock/fs.rs.html b/src/landlock/fs.rs.html new file mode 100644 index 0000000..bf0f5eb --- /dev/null +++ b/src/landlock/fs.rs.html @@ -0,0 +1,1219 @@ +fs.rs - source
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
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+
use crate::compat::private::OptionCompatLevelMut;
+use crate::{
+    uapi, Access, AddRuleError, AddRulesError, CompatError, CompatLevel, CompatResult, CompatState,
+    Compatible, HandleAccessError, HandleAccessesError, PathBeneathError, PathFdError,
+    PrivateAccess, PrivateRule, Rule, Ruleset, RulesetCreated, RulesetError, TailoredCompatLevel,
+    TryCompat, ABI,
+};
+use enumflags2::{bitflags, make_bitflags, BitFlags};
+use std::fs::OpenOptions;
+use std::io::Error;
+use std::mem::zeroed;
+use std::os::unix::fs::OpenOptionsExt;
+use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, OwnedFd};
+use std::path::Path;
+
+#[cfg(test)]
+use crate::{RulesetAttr, RulesetCreatedAttr};
+#[cfg(test)]
+use strum::IntoEnumIterator;
+
+/// File system access right.
+///
+/// Each variant of `AccessFs` is an [access right](https://www.kernel.org/doc/html/latest/userspace-api/landlock.html#access-rights)
+/// for the file system.
+/// A set of access rights can be created with [`BitFlags<AccessFs>`](BitFlags).
+///
+/// # Example
+///
+/// ```
+/// use landlock::{ABI, Access, AccessFs, BitFlags, make_bitflags};
+///
+/// let exec = AccessFs::Execute;
+///
+/// let exec_set: BitFlags<AccessFs> = exec.into();
+///
+/// let file_content = make_bitflags!(AccessFs::{Execute | WriteFile | ReadFile});
+///
+/// let fs_v1 = AccessFs::from_all(ABI::V1);
+///
+/// let without_exec = fs_v1 & !AccessFs::Execute;
+///
+/// assert_eq!(fs_v1 | AccessFs::Refer, AccessFs::from_all(ABI::V2));
+/// ```
+///
+/// # Warning
+///
+/// To avoid unknown restrictions **don't use `BitFlags::<AccessFs>::all()` nor `BitFlags::ALL`**,
+/// but use a version you tested and vetted instead,
+/// for instance [`AccessFs::from_all(ABI::V1)`](Access::from_all).
+/// Direct use of **the [`BitFlags`] API is deprecated**.
+/// See [`ABI`] for the rationale and help to test it.
+#[bitflags]
+#[repr(u64)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[non_exhaustive]
+pub enum AccessFs {
+    /// Execute a file.
+    Execute = uapi::LANDLOCK_ACCESS_FS_EXECUTE as u64,
+    /// Open a file with write access.
+    WriteFile = uapi::LANDLOCK_ACCESS_FS_WRITE_FILE as u64,
+    /// Open a file with read access.
+    ReadFile = uapi::LANDLOCK_ACCESS_FS_READ_FILE as u64,
+    /// Open a directory or list its content.
+    ReadDir = uapi::LANDLOCK_ACCESS_FS_READ_DIR as u64,
+    /// Remove an empty directory or rename one.
+    RemoveDir = uapi::LANDLOCK_ACCESS_FS_REMOVE_DIR as u64,
+    /// Unlink (or rename) a file.
+    RemoveFile = uapi::LANDLOCK_ACCESS_FS_REMOVE_FILE as u64,
+    /// Create (or rename or link) a character device.
+    MakeChar = uapi::LANDLOCK_ACCESS_FS_MAKE_CHAR as u64,
+    /// Create (or rename) a directory.
+    MakeDir = uapi::LANDLOCK_ACCESS_FS_MAKE_DIR as u64,
+    /// Create (or rename or link) a regular file.
+    MakeReg = uapi::LANDLOCK_ACCESS_FS_MAKE_REG as u64,
+    /// Create (or rename or link) a UNIX domain socket.
+    MakeSock = uapi::LANDLOCK_ACCESS_FS_MAKE_SOCK as u64,
+    /// Create (or rename or link) a named pipe.
+    MakeFifo = uapi::LANDLOCK_ACCESS_FS_MAKE_FIFO as u64,
+    /// Create (or rename or link) a block device.
+    MakeBlock = uapi::LANDLOCK_ACCESS_FS_MAKE_BLOCK as u64,
+    /// Create (or rename or link) a symbolic link.
+    MakeSym = uapi::LANDLOCK_ACCESS_FS_MAKE_SYM as u64,
+    /// Link or rename a file from or to a different directory.
+    Refer = uapi::LANDLOCK_ACCESS_FS_REFER as u64,
+    /// Truncate a file with `truncate(2)`, `ftruncate(2)`, `creat(2)`, or `open(2)` with `O_TRUNC`.
+    Truncate = uapi::LANDLOCK_ACCESS_FS_TRUNCATE as u64,
+    /// Send IOCL commands to a device file.
+    IoctlDev = uapi::LANDLOCK_ACCESS_FS_IOCTL_DEV as u64,
+}
+
+impl Access for AccessFs {
+    /// Union of [`from_read()`](AccessFs::from_read) and [`from_write()`](AccessFs::from_write).
+    fn from_all(abi: ABI) -> BitFlags<Self> {
+        // An empty access-right would be an error if passed to the kernel, but because the kernel
+        // doesn't support Landlock, no Landlock syscall should be called.  try_compat() should
+        // also return RestrictionStatus::Unrestricted when called with unsupported/empty
+        // access-rights.
+        Self::from_read(abi) | Self::from_write(abi)
+    }
+}
+
+impl AccessFs {
+    // Roughly read (i.e. not all FS actions are handled).
+    /// Gets the access rights identified as read-only according to a specific ABI.
+    /// Exclusive with [`from_write()`](AccessFs::from_write).
+    pub fn from_read(abi: ABI) -> BitFlags<Self> {
+        match abi {
+            ABI::Unsupported => BitFlags::EMPTY,
+            ABI::V1 | ABI::V2 | ABI::V3 | ABI::V4 | ABI::V5 => make_bitflags!(AccessFs::{
+                Execute
+                | ReadFile
+                | ReadDir
+            }),
+        }
+    }
+
+    // Roughly write (i.e. not all FS actions are handled).
+    /// Gets the access rights identified as write-only according to a specific ABI.
+    /// Exclusive with [`from_read()`](AccessFs::from_read).
+    pub fn from_write(abi: ABI) -> BitFlags<Self> {
+        match abi {
+            ABI::Unsupported => BitFlags::EMPTY,
+            ABI::V1 => make_bitflags!(AccessFs::{
+                WriteFile
+                | RemoveDir
+                | RemoveFile
+                | MakeChar
+                | MakeDir
+                | MakeReg
+                | MakeSock
+                | MakeFifo
+                | MakeBlock
+                | MakeSym
+            }),
+            ABI::V2 => Self::from_write(ABI::V1) | AccessFs::Refer,
+            ABI::V3 | ABI::V4 => Self::from_write(ABI::V2) | AccessFs::Truncate,
+            ABI::V5 => Self::from_write(ABI::V4) | AccessFs::IoctlDev,
+        }
+    }
+
+    /// Gets the access rights legitimate for non-directory files.
+    pub fn from_file(abi: ABI) -> BitFlags<Self> {
+        Self::from_all(abi) & ACCESS_FILE
+    }
+}
+
+#[test]
+fn consistent_access_fs_rw() {
+    for abi in ABI::iter() {
+        let access_all = AccessFs::from_all(abi);
+        let access_read = AccessFs::from_read(abi);
+        let access_write = AccessFs::from_write(abi);
+        assert_eq!(access_read, !access_write & access_all);
+        assert_eq!(access_read | access_write, access_all);
+    }
+}
+
+impl PrivateAccess for AccessFs {
+    fn ruleset_handle_access(
+        ruleset: &mut Ruleset,
+        access: BitFlags<Self>,
+    ) -> Result<(), HandleAccessesError> {
+        // We need to record the requested accesses for PrivateRule::check_consistency().
+        ruleset.requested_handled_fs |= access;
+        ruleset.actual_handled_fs |= match access
+            .try_compat(
+                ruleset.compat.abi(),
+                ruleset.compat.level,
+                &mut ruleset.compat.state,
+            )
+            .map_err(HandleAccessError::Compat)?
+        {
+            Some(a) => a,
+            None => return Ok(()),
+        };
+        Ok(())
+    }
+
+    fn into_add_rules_error(error: AddRuleError<Self>) -> AddRulesError {
+        AddRulesError::Fs(error)
+    }
+
+    fn into_handle_accesses_error(error: HandleAccessError<Self>) -> HandleAccessesError {
+        HandleAccessesError::Fs(error)
+    }
+}
+
+// TODO: Make ACCESS_FILE a property of AccessFs.
+// TODO: Add tests for ACCESS_FILE.
+const ACCESS_FILE: BitFlags<AccessFs> = make_bitflags!(AccessFs::{
+    ReadFile | WriteFile | Execute | Truncate | IoctlDev
+});
+
+// XXX: What should we do when a stat call failed?
+fn is_file<F>(fd: F) -> Result<bool, Error>
+where
+    F: AsFd,
+{
+    unsafe {
+        let mut stat = zeroed();
+        match libc::fstat(fd.as_fd().as_raw_fd(), &mut stat) {
+            0 => Ok((stat.st_mode & libc::S_IFMT) != libc::S_IFDIR),
+            _ => Err(Error::last_os_error()),
+        }
+    }
+}
+
+/// Landlock rule for a file hierarchy.
+///
+/// # Example
+///
+/// ```
+/// use landlock::{AccessFs, PathBeneath, PathFd, PathFdError};
+///
+/// fn home_dir() -> Result<PathBeneath<PathFd>, PathFdError> {
+///     Ok(PathBeneath::new(PathFd::new("/home")?, AccessFs::ReadDir))
+/// }
+/// ```
+#[cfg_attr(test, derive(Debug))]
+pub struct PathBeneath<F> {
+    attr: uapi::landlock_path_beneath_attr,
+    // Ties the lifetime of a file descriptor to this object.
+    parent_fd: F,
+    allowed_access: BitFlags<AccessFs>,
+    compat_level: Option<CompatLevel>,
+}
+
+impl<F> PathBeneath<F>
+where
+    F: AsFd,
+{
+    /// Creates a new `PathBeneath` rule identifying the `parent` directory of a file hierarchy,
+    /// or just a file, and allows `access` on it.
+    /// The `parent` file descriptor will be automatically closed with the returned `PathBeneath`.
+    pub fn new<A>(parent: F, access: A) -> Self
+    where
+        A: Into<BitFlags<AccessFs>>,
+    {
+        PathBeneath {
+            // Invalid access rights until as_ptr() is called.
+            attr: unsafe { zeroed() },
+            parent_fd: parent,
+            allowed_access: access.into(),
+            compat_level: None,
+        }
+    }
+}
+
+impl<F> TryCompat<AccessFs> for PathBeneath<F>
+where
+    F: AsFd,
+{
+    fn try_compat_children<L>(
+        mut self,
+        abi: ABI,
+        parent_level: L,
+        compat_state: &mut CompatState,
+    ) -> Result<Option<Self>, CompatError<AccessFs>>
+    where
+        L: Into<CompatLevel>,
+    {
+        // Checks with our own compatibility level, if any.
+        self.allowed_access = match self.allowed_access.try_compat(
+            abi,
+            self.tailored_compat_level(parent_level),
+            compat_state,
+        )? {
+            Some(a) => a,
+            None => return Ok(None),
+        };
+        Ok(Some(self))
+    }
+
+    fn try_compat_inner(
+        &mut self,
+        _abi: ABI,
+    ) -> Result<CompatResult<AccessFs>, CompatError<AccessFs>> {
+        // Gets subset of valid accesses according the FD type.
+        let valid_access =
+            if is_file(&self.parent_fd).map_err(|e| PathBeneathError::StatCall { source: e })? {
+                self.allowed_access & ACCESS_FILE
+            } else {
+                self.allowed_access
+            };
+
+        if self.allowed_access != valid_access {
+            let error = PathBeneathError::DirectoryAccess {
+                access: self.allowed_access,
+                incompatible: self.allowed_access ^ valid_access,
+            }
+            .into();
+            self.allowed_access = valid_access;
+            // Linux would return EINVAL.
+            Ok(CompatResult::Partial(error))
+        } else {
+            Ok(CompatResult::Full)
+        }
+    }
+}
+
+#[test]
+fn path_beneath_try_compat_children() {
+    use crate::*;
+
+    // AccessFs::Refer is not handled by ABI::V1 and only for directories.
+    let access_file = AccessFs::ReadFile | AccessFs::Refer;
+
+    // Test error ordering with ABI::V1
+    let mut ruleset = Ruleset::from(ABI::V1).handle_access(access_file).unwrap();
+    // Do not actually perform any syscall.
+    ruleset.compat.state = CompatState::Dummy;
+    assert!(matches!(
+        RulesetCreated::new(ruleset, -1)
+            .set_compatibility(CompatLevel::HardRequirement)
+            .add_rule(PathBeneath::new(PathFd::new("/dev/null").unwrap(), access_file))
+            .unwrap_err(),
+        RulesetError::AddRules(AddRulesError::Fs(AddRuleError::Compat(
+            CompatError::PathBeneath(PathBeneathError::DirectoryAccess { access, incompatible })
+        ))) if access == access_file && incompatible == AccessFs::Refer
+    ));
+
+    // Test error ordering with ABI::V2
+    let mut ruleset = Ruleset::from(ABI::V2).handle_access(access_file).unwrap();
+    // Do not actually perform any syscall.
+    ruleset.compat.state = CompatState::Dummy;
+    assert!(matches!(
+        RulesetCreated::new(ruleset, -1)
+            .set_compatibility(CompatLevel::HardRequirement)
+            .add_rule(PathBeneath::new(PathFd::new("/dev/null").unwrap(), access_file))
+            .unwrap_err(),
+        RulesetError::AddRules(AddRulesError::Fs(AddRuleError::Compat(
+            CompatError::PathBeneath(PathBeneathError::DirectoryAccess { access, incompatible })
+        ))) if access == access_file && incompatible == AccessFs::Refer
+    ));
+}
+
+#[test]
+fn path_beneath_try_compat() {
+    use crate::*;
+
+    let abi = ABI::V1;
+
+    for file in &["/etc/passwd", "/dev/null"] {
+        let mut compat_state = CompatState::Init;
+        let ro_access = AccessFs::ReadDir | AccessFs::ReadFile;
+        assert!(matches!(
+            PathBeneath::new(PathFd::new(file).unwrap(), ro_access)
+                .try_compat(abi, CompatLevel::HardRequirement, &mut compat_state)
+                .unwrap_err(),
+            CompatError::PathBeneath(PathBeneathError::DirectoryAccess { access, incompatible })
+                if access == ro_access && incompatible == AccessFs::ReadDir
+        ));
+
+        let mut compat_state = CompatState::Init;
+        assert!(matches!(
+            PathBeneath::new(PathFd::new(file).unwrap(), BitFlags::EMPTY)
+                .try_compat(abi, CompatLevel::BestEffort, &mut compat_state)
+                .unwrap_err(),
+            CompatError::Access(AccessError::Empty)
+        ));
+    }
+
+    let full_access = AccessFs::from_all(ABI::V1);
+    for compat_level in &[
+        CompatLevel::BestEffort,
+        CompatLevel::SoftRequirement,
+        CompatLevel::HardRequirement,
+    ] {
+        let mut compat_state = CompatState::Init;
+        let mut path_beneath = PathBeneath::new(PathFd::new("/").unwrap(), full_access)
+            .try_compat(abi, *compat_level, &mut compat_state)
+            .unwrap()
+            .unwrap();
+        assert_eq!(compat_state, CompatState::Full);
+
+        // Without synchronization.
+        let raw_access = path_beneath.attr.allowed_access;
+        assert_eq!(raw_access, 0);
+
+        // Synchronize the inner attribute buffer.
+        let _ = path_beneath.as_ptr();
+        let raw_access = path_beneath.attr.allowed_access;
+        assert_eq!(raw_access, full_access.bits());
+    }
+}
+
+impl<F> OptionCompatLevelMut for PathBeneath<F> {
+    fn as_option_compat_level_mut(&mut self) -> &mut Option<CompatLevel> {
+        &mut self.compat_level
+    }
+}
+
+impl<F> OptionCompatLevelMut for &mut PathBeneath<F> {
+    fn as_option_compat_level_mut(&mut self) -> &mut Option<CompatLevel> {
+        &mut self.compat_level
+    }
+}
+
+impl<F> Compatible for PathBeneath<F> {}
+
+impl<F> Compatible for &mut PathBeneath<F> {}
+
+#[test]
+fn path_beneath_compatibility() {
+    let mut path = PathBeneath::new(PathFd::new("/").unwrap(), AccessFs::from_all(ABI::V1));
+    let path_ref = &mut path;
+
+    let level = path_ref.as_option_compat_level_mut();
+    assert_eq!(level, &None);
+    assert_eq!(
+        <Option<CompatLevel> as Into<CompatLevel>>::into(*level),
+        CompatLevel::BestEffort
+    );
+
+    path_ref.set_compatibility(CompatLevel::SoftRequirement);
+    assert_eq!(
+        path_ref.as_option_compat_level_mut(),
+        &Some(CompatLevel::SoftRequirement)
+    );
+
+    path.set_compatibility(CompatLevel::HardRequirement);
+}
+
+// It is useful for documentation generation to explicitely implement Rule for every types, instead
+// of doing it generically.
+impl<F> Rule<AccessFs> for PathBeneath<F> where F: AsFd {}
+
+impl<F> PrivateRule<AccessFs> for PathBeneath<F>
+where
+    F: AsFd,
+{
+    const TYPE_ID: uapi::landlock_rule_type = uapi::landlock_rule_type_LANDLOCK_RULE_PATH_BENEATH;
+
+    fn as_ptr(&mut self) -> *const libc::c_void {
+        self.attr.parent_fd = self.parent_fd.as_fd().as_raw_fd();
+        self.attr.allowed_access = self.allowed_access.bits();
+        &self.attr as *const _ as _
+    }
+
+    fn check_consistency(&self, ruleset: &RulesetCreated) -> Result<(), AddRulesError> {
+        // Checks that this rule doesn't contain a superset of the access-rights handled by the
+        // ruleset.  This check is about requested access-rights but not actual access-rights.
+        // Indeed, we want to get a deterministic behavior, i.e. not based on the running kernel
+        // (which is handled by Ruleset and RulesetCreated).
+        if ruleset.requested_handled_fs.contains(self.allowed_access) {
+            Ok(())
+        } else {
+            Err(AddRuleError::UnhandledAccess {
+                access: self.allowed_access,
+                incompatible: self.allowed_access & !ruleset.requested_handled_fs,
+            }
+            .into())
+        }
+    }
+}
+
+#[test]
+fn path_beneath_check_consistency() {
+    use crate::*;
+
+    let ro_access = AccessFs::ReadDir | AccessFs::ReadFile;
+    let rx_access = AccessFs::Execute | AccessFs::ReadFile;
+    assert!(matches!(
+        Ruleset::from(ABI::Unsupported)
+            .handle_access(ro_access)
+            .unwrap()
+            .create()
+            .unwrap()
+            .add_rule(PathBeneath::new(PathFd::new("/").unwrap(), rx_access))
+            .unwrap_err(),
+        RulesetError::AddRules(AddRulesError::Fs(AddRuleError::UnhandledAccess { access, incompatible }))
+            if access == rx_access && incompatible == AccessFs::Execute
+    ));
+}
+
+/// Simple helper to open a file or a directory with the `O_PATH` flag.
+///
+/// This is the recommended way to identify a path
+/// and manage the lifetime of the underlying opened file descriptor.
+/// Indeed, using other [`AsFd`] implementations such as [`File`] brings more complexity
+/// and may lead to unexpected errors (e.g., denied access).
+///
+/// [`File`]: std::fs::File
+///
+/// # Example
+///
+/// ```
+/// use landlock::{AccessFs, PathBeneath, PathFd, PathFdError};
+///
+/// fn allowed_root_dir(access: AccessFs) -> Result<PathBeneath<PathFd>, PathFdError> {
+///     let fd = PathFd::new("/")?;
+///     Ok(PathBeneath::new(fd, access))
+/// }
+/// ```
+#[cfg_attr(test, derive(Debug))]
+pub struct PathFd {
+    fd: OwnedFd,
+}
+
+impl PathFd {
+    pub fn new<T>(path: T) -> Result<Self, PathFdError>
+    where
+        T: AsRef<Path>,
+    {
+        Ok(PathFd {
+            fd: OpenOptions::new()
+                .read(true)
+                // If the O_PATH is not supported, it is automatically ignored (Linux < 2.6.39).
+                .custom_flags(libc::O_PATH | libc::O_CLOEXEC)
+                .open(path.as_ref())
+                .map_err(|e| PathFdError::OpenCall {
+                    source: e,
+                    path: path.as_ref().into(),
+                })?
+                .into(),
+        })
+    }
+}
+
+impl AsFd for PathFd {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.fd.as_fd()
+    }
+}
+
+#[test]
+fn path_fd() {
+    use std::fs::File;
+    use std::io::Read;
+
+    PathBeneath::new(PathFd::new("/").unwrap(), AccessFs::Execute);
+    PathBeneath::new(File::open("/").unwrap(), AccessFs::Execute);
+
+    let mut buffer = [0; 1];
+    // Checks that PathFd really returns an FD opened with O_PATH (Bad file descriptor error).
+    File::from(PathFd::new("/etc/passwd").unwrap().fd)
+        .read(&mut buffer)
+        .unwrap_err();
+}
+
+/// Helper to quickly create an iterator of PathBeneath rules.
+///
+/// Silently ignores paths that cannot be opened, and automatically adjust access rights according
+/// to file types when possible.
+///
+/// # Example
+///
+/// ```
+/// use landlock::{
+///     ABI, Access, AccessFs, Ruleset, RulesetAttr, RulesetCreatedAttr, RulesetStatus, RulesetError,
+///     path_beneath_rules,
+/// };
+///
+/// fn restrict_thread() -> Result<(), RulesetError> {
+///     let abi = ABI::V1;
+///     let status = Ruleset::default()
+///         .handle_access(AccessFs::from_all(abi))?
+///         .create()?
+///         // Read-only access to /usr, /etc and /dev.
+///         .add_rules(path_beneath_rules(&["/usr", "/etc", "/dev"], AccessFs::from_read(abi)))?
+///         // Read-write access to /home and /tmp.
+///         .add_rules(path_beneath_rules(&["/home", "/tmp"], AccessFs::from_all(abi)))?
+///         .restrict_self()?;
+///     match status.ruleset {
+///         // The FullyEnforced case must be tested by the developer.
+///         RulesetStatus::FullyEnforced => println!("Fully sandboxed."),
+///         RulesetStatus::PartiallyEnforced => println!("Partially sandboxed."),
+///         // Users should be warned that they are not protected.
+///         RulesetStatus::NotEnforced => println!("Not sandboxed! Please update your kernel."),
+///     }
+///     Ok(())
+/// }
+/// ```
+pub fn path_beneath_rules<I, P, A>(
+    paths: I,
+    access: A,
+) -> impl Iterator<Item = Result<PathBeneath<PathFd>, RulesetError>>
+where
+    I: IntoIterator<Item = P>,
+    P: AsRef<Path>,
+    A: Into<BitFlags<AccessFs>>,
+{
+    let access = access.into();
+    paths.into_iter().filter_map(move |p| match PathFd::new(p) {
+        Ok(f) => {
+            let valid_access = match is_file(&f) {
+                Ok(true) => access & ACCESS_FILE,
+                // If the stat call failed, let's blindly rely on the requested access rights.
+                Err(_) | Ok(false) => access,
+            };
+            Some(Ok(PathBeneath::new(f, valid_access)))
+        }
+        Err(_) => None,
+    })
+}
+
+#[test]
+fn path_beneath_rules_iter() {
+    let _ = Ruleset::default()
+        .handle_access(AccessFs::from_all(ABI::V1))
+        .unwrap()
+        .create()
+        .unwrap()
+        .add_rules(path_beneath_rules(
+            &["/usr", "/opt", "/does-not-exist", "/root"],
+            AccessFs::Execute,
+        ))
+        .unwrap();
+}
+
\ No newline at end of file diff --git a/src/landlock/lib.rs.html b/src/landlock/lib.rs.html new file mode 100644 index 0000000..bbabed1 --- /dev/null +++ b/src/landlock/lib.rs.html @@ -0,0 +1,811 @@ +lib.rs - source
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
+
//! Landlock is a security feature available since Linux 5.13.
+//! The goal is to enable to restrict ambient rights
+//! (e.g., global filesystem access)
+//! for a set of processes by creating safe security sandboxes as new security layers
+//! in addition to the existing system-wide access-controls.
+//! This kind of sandbox is expected to help mitigate the security impact of bugs,
+//! unexpected or malicious behaviors in applications.
+//! Landlock empowers any process, including unprivileged ones, to securely restrict themselves.
+//! More information about Landlock can be found in the [official website](https://landlock.io).
+//!
+//! This crate provides a safe abstraction for the Landlock system calls, along with some helpers.
+//!
+//! Minimum Supported Rust Version (MSRV): 1.63
+//!
+//! # Use cases
+//!
+//! This crate is especially useful to protect users' data by sandboxing:
+//! * trusted applications dealing with potentially malicious data
+//!   (e.g., complex file format, network request) that could exploit security vulnerabilities;
+//! * sandbox managers, container runtimes or shells launching untrusted applications.
+//!
+//! # Examples
+//!
+//! A simple example can be found with the [`path_beneath_rules()`] helper.
+//! More complex examples can be found with the [`Ruleset` documentation](Ruleset)
+//! and the [sandboxer example](https://github.com/landlock-lsm/rust-landlock/blob/master/examples/sandboxer.rs).
+//!
+//! # Current limitations
+//!
+//! This crate exposes the Landlock features available as of Linux 5.19
+//! and then inherits some [kernel limitations](https://www.kernel.org/doc/html/latest/userspace-api/landlock.html#current-limitations)
+//! that will be addressed with future kernel releases
+//! (e.g., arbitrary mounts are always denied).
+//!
+//! # Compatibility
+//!
+//! Types defined in this crate are designed to enable the strictest Landlock configuration
+//! for the given kernel on which the program runs.
+//! In the default [best-effort](CompatLevel::BestEffort) mode,
+//! [`Ruleset`] will determine compatibility
+//! with the intersection of the currently running kernel's features
+//! and those required by the caller.
+//! This way, callers can distinguish between
+//! Landlock compatibility issues inherent to the current system
+//! (e.g., file names that don't exist)
+//! and misconfiguration that should be fixed in the program
+//! (e.g., empty or inconsistent access rights).
+//! [`RulesetError`] identifies such kind of errors.
+//!
+//! With [`set_compatibility(CompatLevel::BestEffort)`](Compatible::set_compatibility),
+//! users of the crate may mark Landlock features that are deemed required
+//! and other features that may be downgraded to use lower security on systems
+//! where they can't be enforced.
+//! It is discouraged to compare the system's provided [Landlock ABI](ABI) version directly,
+//! as it is difficult to track detailed ABI differences
+//! which are handled thanks to the [`Compatible`] trait.
+//!
+//! To make it easier to migrate to a new version of this library,
+//! we use the builder pattern
+//! and designed objects to require the minimal set of method arguments.
+//! Most `enum` are marked as `non_exhaustive` to enable backward-compatible evolutions.
+//!
+//! ## Test strategy
+//!
+//! Developers should test their sandboxed applications
+//! with a kernel that supports all requested Landlock features
+//! and check that [`RulesetCreated::restrict_self()`] returns a status matching
+//! [`Ok(RestrictionStatus { ruleset: RulesetStatus::FullyEnforced, no_new_privs: true, })`](RestrictionStatus)
+//! to make sure everything works as expected in an enforced sandbox.
+//! Alternatively, using [`set_compatibility(CompatLevel::HardRequirement)`](Compatible::set_compatibility)
+//! will immediately inform about unsupported Landlock features.
+//! These configurations should only depend on the test environment
+//! (e.g. [by checking an environment variable](https://github.com/landlock-lsm/rust-landlock/search?q=LANDLOCK_CRATE_TEST_ABI)).
+//! However, applications should only check that no error is returned (i.e. `Ok(_)`)
+//! and optionally log and inform users that the application is not fully sandboxed
+//! because of missing features from the running kernel.
+
+#[cfg(test)]
+#[macro_use]
+extern crate lazy_static;
+
+pub use access::Access;
+pub use compat::{CompatLevel, Compatible, ABI};
+pub use enumflags2::{make_bitflags, BitFlags};
+pub use errors::{
+    AccessError, AddRuleError, AddRulesError, CompatError, CreateRulesetError, HandleAccessError,
+    HandleAccessesError, PathBeneathError, PathFdError, RestrictSelfError, RulesetError,
+};
+pub use fs::{path_beneath_rules, AccessFs, PathBeneath, PathFd};
+pub use net::{AccessNet, NetPort};
+pub use ruleset::{
+    RestrictionStatus, Rule, Ruleset, RulesetAttr, RulesetCreated, RulesetCreatedAttr,
+    RulesetStatus,
+};
+
+use access::PrivateAccess;
+use compat::{CompatResult, CompatState, Compatibility, TailoredCompatLevel, TryCompat};
+use ruleset::PrivateRule;
+
+#[cfg(test)]
+use compat::{can_emulate, get_errno_from_landlock_status};
+#[cfg(test)]
+use errors::TestRulesetError;
+#[cfg(test)]
+use strum::IntoEnumIterator;
+
+mod access;
+mod compat;
+mod errors;
+mod fs;
+mod net;
+mod ruleset;
+mod uapi;
+
+#[cfg(test)]
+mod tests {
+    use crate::*;
+
+    // Emulate old kernel supports.
+    fn check_ruleset_support<F>(
+        partial: ABI,
+        full: Option<ABI>,
+        check: F,
+        error_if_abi_lt_partial: bool,
+    ) where
+        F: Fn(Ruleset) -> Result<RestrictionStatus, TestRulesetError> + Send + Copy + 'static,
+    {
+        // If there is no partial support, it means that `full == partial`.
+        assert!(partial <= full.unwrap_or(partial));
+        for abi in ABI::iter() {
+            // Ensures restrict_self() is called on a dedicated thread to avoid inconsistent tests.
+            let ret = std::thread::spawn(move || check(Ruleset::from(abi)))
+                .join()
+                .unwrap();
+
+            // Useful for failed tests and with cargo test -- --show-output
+            println!("Checking ABI {abi:?}: received {ret:#?}");
+            if can_emulate(abi, partial, full) {
+                if abi < partial && error_if_abi_lt_partial {
+                    // TODO: Check exact error type; this may require better error types.
+                    assert!(matches!(ret, Err(TestRulesetError::Ruleset(_))));
+                } else {
+                    let full_support = if let Some(full_inner) = full {
+                        abi >= full_inner
+                    } else {
+                        false
+                    };
+                    let ruleset_status = if full_support {
+                        RulesetStatus::FullyEnforced
+                    } else if abi >= partial {
+                        RulesetStatus::PartiallyEnforced
+                    } else {
+                        RulesetStatus::NotEnforced
+                    };
+                    println!("Expecting ruleset status {ruleset_status:?}");
+                    assert!(matches!(
+                        ret,
+                        Ok(RestrictionStatus {
+                            ruleset,
+                            no_new_privs: true,
+                        }) if ruleset == ruleset_status
+                    ))
+                }
+            } else {
+                // The errno value should be ENOSYS, EOPNOTSUPP, EINVAL (e.g. when an unknown
+                // access right is provided), or E2BIG (e.g. when there is an unknown field in a
+                // Landlock syscall attribute).
+                let errno = get_errno_from_landlock_status();
+                println!("Expecting error {errno:?}");
+                match ret {
+                    Err(TestRulesetError::Ruleset(RulesetError::CreateRuleset(
+                        CreateRulesetError::CreateRulesetCall { source },
+                    ))) => match (source.raw_os_error(), errno) {
+                        (Some(e1), Some(e2)) => assert_eq!(e1, e2),
+                        (Some(e1), None) => assert!(matches!(e1, libc::EINVAL | libc::E2BIG)),
+                        _ => unreachable!(),
+                    },
+                    _ => unreachable!(),
+                }
+            }
+        }
+    }
+
+    #[test]
+    fn allow_root_compat() {
+        let abi = ABI::V1;
+
+        check_ruleset_support(
+            abi,
+            Some(abi),
+            move |ruleset: Ruleset| -> _ {
+                Ok(ruleset
+                    .handle_access(AccessFs::from_all(abi))?
+                    .create()?
+                    .add_rule(PathBeneath::new(PathFd::new("/")?, AccessFs::from_all(abi)))?
+                    .restrict_self()?)
+            },
+            false,
+        );
+    }
+
+    #[test]
+    fn too_much_access_rights_for_a_file() {
+        let abi = ABI::V1;
+
+        check_ruleset_support(
+            abi,
+            Some(abi),
+            move |ruleset: Ruleset| -> _ {
+                Ok(ruleset
+                    .handle_access(AccessFs::from_all(abi))?
+                    .create()?
+                    // Same code as allow_root_compat() but with /etc/passwd instead of /
+                    .add_rule(PathBeneath::new(
+                        PathFd::new("/etc/passwd")?,
+                        // Only allow legitimate access rights on a file.
+                        AccessFs::from_file(abi),
+                    ))?
+                    .restrict_self()?)
+            },
+            false,
+        );
+
+        check_ruleset_support(
+            abi,
+            None,
+            move |ruleset: Ruleset| -> _ {
+                Ok(ruleset
+                    .handle_access(AccessFs::from_all(abi))?
+                    .create()?
+                    // Same code as allow_root_compat() but with /etc/passwd instead of /
+                    .add_rule(PathBeneath::new(
+                        PathFd::new("/etc/passwd")?,
+                        // Tries to allow all access rights on a file.
+                        AccessFs::from_all(abi),
+                    ))?
+                    .restrict_self()?)
+            },
+            false,
+        );
+    }
+
+    #[test]
+    fn path_beneath_rules_with_too_much_access_rights_for_a_file() {
+        let abi = ABI::V1;
+
+        check_ruleset_support(
+            abi,
+            Some(abi),
+            move |ruleset: Ruleset| -> _ {
+                Ok(ruleset
+                    .handle_access(AccessFs::from_all(ABI::V1))?
+                    .create()?
+                    // Same code as too_much_access_rights_for_a_file() but using path_beneath_rules()
+                    .add_rules(path_beneath_rules(["/etc/passwd"], AccessFs::from_all(abi)))?
+                    .restrict_self()?)
+            },
+            false,
+        );
+    }
+
+    #[test]
+    fn allow_root_fragile() {
+        let abi = ABI::V1;
+
+        check_ruleset_support(
+            abi,
+            Some(abi),
+            move |ruleset: Ruleset| -> _ {
+                // Sets default support requirement: abort the whole sandboxing for any Landlock error.
+                Ok(ruleset
+                    // Must have at least the execute check…
+                    .set_compatibility(CompatLevel::HardRequirement)
+                    .handle_access(AccessFs::Execute)?
+                    // …and possibly others.
+                    .set_compatibility(CompatLevel::BestEffort)
+                    .handle_access(AccessFs::from_all(abi))?
+                    .create()?
+                    .set_no_new_privs(true)
+                    .add_rule(PathBeneath::new(PathFd::new("/")?, AccessFs::from_all(abi)))?
+                    .restrict_self()?)
+            },
+            true,
+        );
+    }
+
+    #[test]
+    fn ruleset_enforced() {
+        let abi = ABI::V1;
+
+        check_ruleset_support(
+            abi,
+            Some(abi),
+            move |ruleset: Ruleset| -> _ {
+                Ok(ruleset
+                    // Restricting without rule exceptions is legitimate to forbid a set of actions.
+                    .handle_access(AccessFs::Execute)?
+                    .create()?
+                    .restrict_self()?)
+            },
+            false,
+        );
+    }
+
+    #[test]
+    fn abi_v2_exec_refer() {
+        check_ruleset_support(
+            ABI::V1,
+            Some(ABI::V2),
+            move |ruleset: Ruleset| -> _ {
+                Ok(ruleset
+                    .handle_access(AccessFs::Execute)?
+                    // AccessFs::Refer is not supported by ABI::V1 (best-effort).
+                    .handle_access(AccessFs::Refer)?
+                    .create()?
+                    .restrict_self()?)
+            },
+            false,
+        );
+    }
+
+    #[test]
+    fn abi_v2_refer_only() {
+        // When no access is handled, do not try to create a ruleset without access.
+        check_ruleset_support(
+            ABI::V2,
+            Some(ABI::V2),
+            move |ruleset: Ruleset| -> _ {
+                Ok(ruleset
+                    .handle_access(AccessFs::Refer)?
+                    .create()?
+                    .restrict_self()?)
+            },
+            false,
+        );
+    }
+
+    #[test]
+    fn abi_v3_truncate() {
+        check_ruleset_support(
+            ABI::V2,
+            Some(ABI::V3),
+            move |ruleset: Ruleset| -> _ {
+                Ok(ruleset
+                    .handle_access(AccessFs::Refer)?
+                    .handle_access(AccessFs::Truncate)?
+                    .create()?
+                    .add_rule(PathBeneath::new(PathFd::new("/")?, AccessFs::Refer))?
+                    .restrict_self()?)
+            },
+            false,
+        );
+    }
+
+    #[test]
+    fn ruleset_created_try_clone() {
+        check_ruleset_support(
+            ABI::V1,
+            Some(ABI::V1),
+            move |ruleset: Ruleset| -> _ {
+                Ok(ruleset
+                    .handle_access(AccessFs::Execute)?
+                    .create()?
+                    .add_rule(PathBeneath::new(PathFd::new("/")?, AccessFs::Execute))?
+                    .try_clone()?
+                    .restrict_self()?)
+            },
+            false,
+        );
+    }
+
+    #[test]
+    fn abi_v4_tcp() {
+        check_ruleset_support(
+            ABI::V3,
+            Some(ABI::V4),
+            move |ruleset: Ruleset| -> _ {
+                Ok(ruleset
+                    .handle_access(AccessFs::Truncate)?
+                    .handle_access(AccessNet::BindTcp | AccessNet::ConnectTcp)?
+                    .create()?
+                    .add_rule(NetPort::new(1, AccessNet::ConnectTcp))?
+                    .restrict_self()?)
+            },
+            false,
+        );
+    }
+
+    #[test]
+    fn abi_v5_ioctl_dev() {
+        check_ruleset_support(
+            ABI::V4,
+            Some(ABI::V5),
+            move |ruleset: Ruleset| -> _ {
+                Ok(ruleset
+                    .handle_access(AccessNet::BindTcp)?
+                    .handle_access(AccessFs::IoctlDev)?
+                    .create()?
+                    .add_rule(PathBeneath::new(PathFd::new("/")?, AccessFs::IoctlDev))?
+                    .restrict_self()?)
+            },
+            false,
+        );
+    }
+}
+
\ No newline at end of file diff --git a/src/landlock/net.rs.html b/src/landlock/net.rs.html new file mode 100644 index 0000000..727e4bc --- /dev/null +++ b/src/landlock/net.rs.html @@ -0,0 +1,453 @@ +net.rs - source
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
+
use crate::compat::private::OptionCompatLevelMut;
+use crate::{
+    uapi, Access, AddRuleError, AddRulesError, CompatError, CompatLevel, CompatResult, CompatState,
+    Compatible, HandleAccessError, HandleAccessesError, PrivateAccess, PrivateRule, Rule, Ruleset,
+    RulesetCreated, TailoredCompatLevel, TryCompat, ABI,
+};
+use enumflags2::{bitflags, BitFlags};
+use std::mem::zeroed;
+
+/// Network access right.
+///
+/// Each variant of `AccessNet` is an [access right](https://www.kernel.org/doc/html/latest/userspace-api/landlock.html#access-rights)
+/// for the network.
+/// A set of access rights can be created with [`BitFlags<AccessNet>`](BitFlags).
+///
+/// # Example
+///
+/// ```
+/// use landlock::{ABI, Access, AccessNet, BitFlags, make_bitflags};
+///
+/// let bind = AccessNet::BindTcp;
+///
+/// let bind_set: BitFlags<AccessNet> = bind.into();
+///
+/// let bind_connect = make_bitflags!(AccessNet::{BindTcp | ConnectTcp});
+///
+/// let net_v4 = AccessNet::from_all(ABI::V4);
+///
+/// assert_eq!(bind_connect, net_v4);
+/// ```
+///
+/// # Warning
+///
+/// To avoid unknown restrictions **don't use `BitFlags::<AccessNet>::all()` nor `BitFlags::ALL`**,
+/// but use a version you tested and vetted instead,
+/// for instance [`AccessNet::from_all(ABI::V4)`](Access::from_all).
+/// Direct use of **the [`BitFlags`] API is deprecated**.
+/// See [`ABI`] for the rationale and help to test it.
+#[bitflags]
+#[repr(u64)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[non_exhaustive]
+pub enum AccessNet {
+    /// Bind to a TCP port.
+    BindTcp = uapi::LANDLOCK_ACCESS_NET_BIND_TCP as u64,
+    /// Connect to a TCP port.
+    ConnectTcp = uapi::LANDLOCK_ACCESS_NET_CONNECT_TCP as u64,
+}
+
+/// # Warning
+///
+/// If `ABI <= ABI::V3`, `AccessNet::from_all()` returns an empty `BitFlags<AccessNet>`, which
+/// makes `Ruleset::handle_access(AccessNet::from_all(ABI::V3))` return an error.
+impl Access for AccessNet {
+    fn from_all(abi: ABI) -> BitFlags<Self> {
+        match abi {
+            ABI::Unsupported | ABI::V1 | ABI::V2 | ABI::V3 => BitFlags::EMPTY,
+            ABI::V4 | ABI::V5 => AccessNet::BindTcp | AccessNet::ConnectTcp,
+        }
+    }
+}
+
+impl PrivateAccess for AccessNet {
+    fn ruleset_handle_access(
+        ruleset: &mut Ruleset,
+        access: BitFlags<Self>,
+    ) -> Result<(), HandleAccessesError> {
+        // We need to record the requested accesses for PrivateRule::check_consistency().
+        ruleset.requested_handled_net |= access;
+        ruleset.actual_handled_net |= match access
+            .try_compat(
+                ruleset.compat.abi(),
+                ruleset.compat.level,
+                &mut ruleset.compat.state,
+            )
+            .map_err(HandleAccessError::Compat)?
+        {
+            Some(a) => a,
+            None => return Ok(()),
+        };
+        Ok(())
+    }
+
+    fn into_add_rules_error(error: AddRuleError<Self>) -> AddRulesError {
+        AddRulesError::Net(error)
+    }
+
+    fn into_handle_accesses_error(error: HandleAccessError<Self>) -> HandleAccessesError {
+        HandleAccessesError::Net(error)
+    }
+}
+
+/// Landlock rule for a network port.
+///
+/// # Example
+///
+/// ```
+/// use landlock::{AccessNet, NetPort};
+///
+/// fn bind_http() -> NetPort {
+///     NetPort::new(80, AccessNet::BindTcp)
+/// }
+/// ```
+#[cfg_attr(test, derive(Debug))]
+pub struct NetPort {
+    attr: uapi::landlock_net_port_attr,
+    // Only 16-bit port make sense for now.
+    port: u16,
+    allowed_access: BitFlags<AccessNet>,
+    compat_level: Option<CompatLevel>,
+}
+
+// If we need support for 32 or 64 ports, we'll add a new_32() or a new_64() method returning a
+// Result with a potential overflow error.
+impl NetPort {
+    /// Creates a new TCP port rule.
+    ///
+    /// As defined by the Linux ABI, `port` with a value of `0` means that TCP bindings will be
+    /// allowed for a port range defined by `/proc/sys/net/ipv4/ip_local_port_range`.
+    pub fn new<A>(port: u16, access: A) -> Self
+    where
+        A: Into<BitFlags<AccessNet>>,
+    {
+        NetPort {
+            // Invalid access-rights until as_ptr() is called.
+            attr: unsafe { zeroed() },
+            port,
+            allowed_access: access.into(),
+            compat_level: None,
+        }
+    }
+}
+
+impl Rule<AccessNet> for NetPort {}
+
+impl PrivateRule<AccessNet> for NetPort {
+    const TYPE_ID: uapi::landlock_rule_type = uapi::landlock_rule_type_LANDLOCK_RULE_NET_PORT;
+
+    fn as_ptr(&mut self) -> *const libc::c_void {
+        self.attr.port = self.port as u64;
+        self.attr.allowed_access = self.allowed_access.bits();
+        &self.attr as *const _ as _
+    }
+
+    fn check_consistency(&self, ruleset: &RulesetCreated) -> Result<(), AddRulesError> {
+        // Checks that this rule doesn't contain a superset of the access-rights handled by the
+        // ruleset.  This check is about requested access-rights but not actual access-rights.
+        // Indeed, we want to get a deterministic behavior, i.e. not based on the running kernel
+        // (which is handled by Ruleset and RulesetCreated).
+        if ruleset.requested_handled_net.contains(self.allowed_access) {
+            Ok(())
+        } else {
+            Err(AddRuleError::UnhandledAccess {
+                access: self.allowed_access,
+                incompatible: self.allowed_access & !ruleset.requested_handled_net,
+            }
+            .into())
+        }
+    }
+}
+
+#[test]
+fn net_port_check_consistency() {
+    use crate::*;
+
+    let bind = AccessNet::BindTcp;
+    let bind_connect = bind | AccessNet::ConnectTcp;
+
+    assert!(matches!(
+        Ruleset::from(ABI::Unsupported)
+            .handle_access(bind)
+            .unwrap()
+            .create()
+            .unwrap()
+            .add_rule(NetPort::new(1, bind_connect))
+            .unwrap_err(),
+        RulesetError::AddRules(AddRulesError::Net(AddRuleError::UnhandledAccess { access, incompatible }))
+            if access == bind_connect && incompatible == AccessNet::ConnectTcp
+    ));
+}
+
+impl TryCompat<AccessNet> for NetPort {
+    fn try_compat_children<L>(
+        mut self,
+        abi: ABI,
+        parent_level: L,
+        compat_state: &mut CompatState,
+    ) -> Result<Option<Self>, CompatError<AccessNet>>
+    where
+        L: Into<CompatLevel>,
+    {
+        // Checks with our own compatibility level, if any.
+        self.allowed_access = match self.allowed_access.try_compat(
+            abi,
+            self.tailored_compat_level(parent_level),
+            compat_state,
+        )? {
+            Some(a) => a,
+            None => return Ok(None),
+        };
+        Ok(Some(self))
+    }
+
+    fn try_compat_inner(
+        &mut self,
+        _abi: ABI,
+    ) -> Result<CompatResult<AccessNet>, CompatError<AccessNet>> {
+        Ok(CompatResult::Full)
+    }
+}
+
+impl OptionCompatLevelMut for NetPort {
+    fn as_option_compat_level_mut(&mut self) -> &mut Option<CompatLevel> {
+        &mut self.compat_level
+    }
+}
+
+impl OptionCompatLevelMut for &mut NetPort {
+    fn as_option_compat_level_mut(&mut self) -> &mut Option<CompatLevel> {
+        &mut self.compat_level
+    }
+}
+
+impl Compatible for NetPort {}
+
+impl Compatible for &mut NetPort {}
+
\ No newline at end of file diff --git a/src/landlock/ruleset.rs.html b/src/landlock/ruleset.rs.html new file mode 100644 index 0000000..fa5a377 --- /dev/null +++ b/src/landlock/ruleset.rs.html @@ -0,0 +1,2037 @@ +ruleset.rs - source
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
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+
use crate::compat::private::OptionCompatLevelMut;
+use crate::{
+    uapi, Access, AccessFs, AccessNet, AddRuleError, AddRulesError, BitFlags, CompatLevel,
+    CompatState, Compatibility, Compatible, CreateRulesetError, RestrictSelfError, RulesetError,
+    TryCompat,
+};
+use libc::close;
+use std::io::Error;
+use std::mem::size_of_val;
+use std::os::unix::io::RawFd;
+
+#[cfg(test)]
+use crate::*;
+
+// Public interface without methods and which is impossible to implement outside this crate.
+pub trait Rule<T>: PrivateRule<T>
+where
+    T: Access,
+{
+}
+
+// PrivateRule is not public outside this crate.
+pub trait PrivateRule<T>
+where
+    Self: TryCompat<T> + Compatible,
+    T: Access,
+{
+    const TYPE_ID: uapi::landlock_rule_type;
+
+    /// Returns a raw pointer to the rule's inner attribute.
+    ///
+    /// The caller must ensure that the rule outlives the pointer this function returns, or else it
+    /// will end up pointing to garbage.
+    fn as_ptr(&mut self) -> *const libc::c_void;
+
+    fn check_consistency(&self, ruleset: &RulesetCreated) -> Result<(), AddRulesError>;
+}
+
+/// Enforcement status of a ruleset.
+#[derive(Debug, PartialEq, Eq)]
+pub enum RulesetStatus {
+    /// All requested restrictions are enforced.
+    FullyEnforced,
+    /// Some requested restrictions are enforced,
+    /// following a best-effort approach.
+    PartiallyEnforced,
+    /// The running system doesn't support Landlock
+    /// or a subset of the requested Landlock features.
+    NotEnforced,
+}
+
+impl From<CompatState> for RulesetStatus {
+    fn from(state: CompatState) -> Self {
+        match state {
+            CompatState::Init | CompatState::No | CompatState::Dummy => RulesetStatus::NotEnforced,
+            CompatState::Full => RulesetStatus::FullyEnforced,
+            CompatState::Partial => RulesetStatus::PartiallyEnforced,
+        }
+    }
+}
+
+// The Debug, PartialEq and Eq implementations are useful for crate users to debug and check the
+// result of a Landlock ruleset enforcement.
+/// Status of a [`RulesetCreated`]
+/// after calling [`restrict_self()`](RulesetCreated::restrict_self).
+#[derive(Debug, PartialEq, Eq)]
+#[non_exhaustive]
+pub struct RestrictionStatus {
+    /// Status of the Landlock ruleset enforcement.
+    pub ruleset: RulesetStatus,
+    /// Status of `prctl(2)`'s `PR_SET_NO_NEW_PRIVS` enforcement.
+    pub no_new_privs: bool,
+}
+
+fn prctl_set_no_new_privs() -> Result<(), Error> {
+    match unsafe { libc::prctl(libc::PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) } {
+        0 => Ok(()),
+        _ => Err(Error::last_os_error()),
+    }
+}
+
+fn support_no_new_privs() -> bool {
+    // Only Linux < 3.5 or kernel with seccomp filters should return an error.
+    matches!(
+        unsafe { libc::prctl(libc::PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0) },
+        0 | 1
+    )
+}
+
+/// Landlock ruleset builder.
+///
+/// `Ruleset` enables to create a Landlock ruleset in a flexible way
+/// following the builder pattern.
+/// Most build steps return a [`Result`] with [`RulesetError`].
+///
+/// You should probably not create more than one ruleset per application.
+/// Creating multiple rulesets is only useful when gradually restricting an application
+/// (e.g., a first set of generic restrictions before reading any file,
+/// then a second set of tailored restrictions after reading the configuration).
+///
+/// # Simple example
+///
+/// Simple helper handling only Landlock-related errors.
+///
+/// ```
+/// use landlock::{
+///     Access, AccessFs, PathBeneath, PathFd, RestrictionStatus, Ruleset, RulesetAttr,
+///     RulesetCreatedAttr, RulesetError, ABI,
+/// };
+/// use std::os::unix::io::AsFd;
+///
+/// fn restrict_fd<T>(hierarchy: T) -> Result<RestrictionStatus, RulesetError>
+/// where
+///     T: AsFd,
+/// {
+///     // The Landlock ABI should be incremented (and tested) regularly.
+///     let abi = ABI::V1;
+///     let access_all = AccessFs::from_all(abi);
+///     let access_read = AccessFs::from_read(abi);
+///     Ok(Ruleset::default()
+///         .handle_access(access_all)?
+///         .create()?
+///         .add_rule(PathBeneath::new(hierarchy, access_read))?
+///         .restrict_self()?)
+/// }
+///
+/// let fd = PathFd::new("/home").expect("failed to open /home");
+/// let status = restrict_fd(fd).expect("failed to build the ruleset");
+/// ```
+///
+/// # Generic example
+///
+/// More generic helper handling a set of file hierarchies
+/// and multiple types of error (i.e. [`RulesetError`](crate::RulesetError)
+/// and [`PathFdError`](crate::PathFdError).
+///
+/// ```
+/// use landlock::{
+///     Access, AccessFs, PathBeneath, PathFd, PathFdError, RestrictionStatus, Ruleset,
+///     RulesetAttr, RulesetCreatedAttr, RulesetError, ABI,
+/// };
+/// use thiserror::Error;
+///
+/// #[derive(Debug, Error)]
+/// enum MyRestrictError {
+///     #[error(transparent)]
+///     Ruleset(#[from] RulesetError),
+///     #[error(transparent)]
+///     AddRule(#[from] PathFdError),
+/// }
+///
+/// fn restrict_paths(hierarchies: &[&str]) -> Result<RestrictionStatus, MyRestrictError> {
+///     // The Landlock ABI should be incremented (and tested) regularly.
+///     let abi = ABI::V1;
+///     let access_all = AccessFs::from_all(abi);
+///     let access_read = AccessFs::from_read(abi);
+///     Ok(Ruleset::default()
+///         .handle_access(access_all)?
+///         .create()?
+///         .add_rules(
+///             hierarchies
+///                 .iter()
+///                 .map::<Result<_, MyRestrictError>, _>(|p| {
+///                     Ok(PathBeneath::new(PathFd::new(p)?, access_read))
+///                 }),
+///         )?
+///         .restrict_self()?)
+/// }
+///
+/// let status = restrict_paths(&["/usr", "/home"]).expect("failed to build the ruleset");
+/// ```
+#[cfg_attr(test, derive(Debug))]
+pub struct Ruleset {
+    pub(crate) requested_handled_fs: BitFlags<AccessFs>,
+    pub(crate) requested_handled_net: BitFlags<AccessNet>,
+    pub(crate) actual_handled_fs: BitFlags<AccessFs>,
+    pub(crate) actual_handled_net: BitFlags<AccessNet>,
+    pub(crate) compat: Compatibility,
+}
+
+impl From<Compatibility> for Ruleset {
+    fn from(compat: Compatibility) -> Self {
+        Ruleset {
+            // Non-working default handled FS accesses to force users to set them explicitely.
+            requested_handled_fs: Default::default(),
+            requested_handled_net: Default::default(),
+            actual_handled_fs: Default::default(),
+            actual_handled_net: Default::default(),
+            compat,
+        }
+    }
+}
+
+#[cfg(test)]
+impl From<ABI> for Ruleset {
+    fn from(abi: ABI) -> Self {
+        Ruleset::from(Compatibility::from(abi))
+    }
+}
+
+#[test]
+fn ruleset_add_rule_iter() {
+    assert!(matches!(
+        Ruleset::from(ABI::Unsupported)
+            .handle_access(AccessFs::Execute)
+            .unwrap()
+            .create()
+            .unwrap()
+            .add_rule(PathBeneath::new(
+                PathFd::new("/").unwrap(),
+                AccessFs::ReadFile
+            ))
+            .unwrap_err(),
+        RulesetError::AddRules(AddRulesError::Fs(AddRuleError::UnhandledAccess { .. }))
+    ));
+}
+
+impl Default for Ruleset {
+    /// Returns a new `Ruleset`.
+    /// This call automatically probes the running kernel to know if it supports Landlock.
+    ///
+    /// To be able to successfully call [`create()`](Ruleset::create),
+    /// it is required to set the handled accesses with
+    /// [`handle_access()`](Ruleset::handle_access).
+    fn default() -> Self {
+        // The API should be future-proof: one Rust program or library should have the same
+        // behavior if built with an old or a newer crate (e.g. with an extended ruleset_attr
+        // enum).  It should then not be possible to give an "all-possible-handled-accesses" to the
+        // Ruleset builder because this value would be relative to the running kernel.
+        Compatibility::new().into()
+    }
+}
+
+impl Ruleset {
+    #[allow(clippy::new_without_default)]
+    #[deprecated(note = "Use Ruleset::default() instead")]
+    pub fn new() -> Self {
+        Ruleset::default()
+    }
+
+    /// Attempts to create a real Landlock ruleset (if supported by the running kernel).
+    /// The returned [`RulesetCreated`] is also a builder.
+    ///
+    /// On error, returns a wrapped [`CreateRulesetError`].
+    pub fn create(mut self) -> Result<RulesetCreated, RulesetError> {
+        let body = || -> Result<RulesetCreated, CreateRulesetError> {
+            match self.compat.state {
+                CompatState::Init => {
+                    // Checks that there is at least one requested access (e.g.
+                    // requested_handled_fs): one call to handle_access().
+                    Err(CreateRulesetError::MissingHandledAccess)
+                }
+                CompatState::No | CompatState::Dummy => {
+                    // There is at least one requested access.
+                    #[cfg(test)]
+                    assert!(
+                        !self.requested_handled_fs.is_empty()
+                            || !self.requested_handled_net.is_empty()
+                    );
+
+                    // CompatState::No should be handled as CompatState::Dummy because it is not
+                    // possible to create an actual ruleset.
+                    self.compat.update(CompatState::Dummy);
+                    match self.compat.level.into() {
+                        CompatLevel::HardRequirement => {
+                            Err(CreateRulesetError::MissingHandledAccess)
+                        }
+                        _ => Ok(RulesetCreated::new(self, -1)),
+                    }
+                }
+                CompatState::Full | CompatState::Partial => {
+                    // There is at least one actual handled access.
+                    #[cfg(test)]
+                    assert!(
+                        !self.actual_handled_fs.is_empty() || !self.actual_handled_net.is_empty()
+                    );
+
+                    let attr = uapi::landlock_ruleset_attr {
+                        handled_access_fs: self.actual_handled_fs.bits(),
+                        handled_access_net: self.actual_handled_net.bits(),
+                    };
+                    match unsafe { uapi::landlock_create_ruleset(&attr, size_of_val(&attr), 0) } {
+                        fd if fd >= 0 => Ok(RulesetCreated::new(self, fd)),
+                        _ => Err(CreateRulesetError::CreateRulesetCall {
+                            source: Error::last_os_error(),
+                        }),
+                    }
+                }
+            }
+        };
+        Ok(body()?)
+    }
+}
+
+impl OptionCompatLevelMut for Ruleset {
+    fn as_option_compat_level_mut(&mut self) -> &mut Option<CompatLevel> {
+        &mut self.compat.level
+    }
+}
+
+impl OptionCompatLevelMut for &mut Ruleset {
+    fn as_option_compat_level_mut(&mut self) -> &mut Option<CompatLevel> {
+        &mut self.compat.level
+    }
+}
+
+impl Compatible for Ruleset {}
+
+impl Compatible for &mut Ruleset {}
+
+impl AsMut<Ruleset> for Ruleset {
+    fn as_mut(&mut self) -> &mut Ruleset {
+        self
+    }
+}
+
+// Tests unambiguous type.
+#[test]
+fn ruleset_as_mut() {
+    let mut ruleset = Ruleset::from(ABI::Unsupported);
+    let _ = ruleset.as_mut();
+
+    let mut ruleset_created = Ruleset::from(ABI::Unsupported)
+        .handle_access(AccessFs::Execute)
+        .unwrap()
+        .create()
+        .unwrap();
+    let _ = ruleset_created.as_mut();
+}
+
+pub trait RulesetAttr: Sized + AsMut<Ruleset> + Compatible {
+    /// Attempts to add a set of access rights that will be supported by this ruleset.
+    /// By default, all actions requiring these access rights will be denied.
+    /// Consecutive calls to `handle_access()` will be interpreted as logical ORs
+    /// with the previous handled accesses.
+    ///
+    /// On error, returns a wrapped [`HandleAccessesError`](crate::HandleAccessesError).
+    /// E.g., `RulesetError::HandleAccesses(HandleAccessesError::Fs(HandleAccessError<AccessFs>))`
+    fn handle_access<T, U>(mut self, access: T) -> Result<Self, RulesetError>
+    where
+        T: Into<BitFlags<U>>,
+        U: Access,
+    {
+        U::ruleset_handle_access(self.as_mut(), access.into())?;
+        Ok(self)
+    }
+}
+
+impl RulesetAttr for Ruleset {}
+
+impl RulesetAttr for &mut Ruleset {}
+
+#[test]
+fn ruleset_attr() {
+    let mut ruleset = Ruleset::from(ABI::Unsupported);
+    let ruleset_ref = &mut ruleset;
+
+    // Can pass this reference to prepare the ruleset...
+    ruleset_ref
+        .set_compatibility(CompatLevel::BestEffort)
+        .handle_access(AccessFs::Execute)
+        .unwrap()
+        .handle_access(AccessFs::ReadFile)
+        .unwrap();
+
+    // ...and finally create the ruleset (thanks to non-lexical lifetimes).
+    ruleset
+        .set_compatibility(CompatLevel::BestEffort)
+        .handle_access(AccessFs::Execute)
+        .unwrap()
+        .handle_access(AccessFs::WriteFile)
+        .unwrap()
+        .create()
+        .unwrap();
+}
+
+#[test]
+fn ruleset_created_handle_access_fs() {
+    // Tests AccessFs::ruleset_handle_access()
+    let ruleset = Ruleset::from(ABI::V1)
+        .handle_access(AccessFs::Execute)
+        .unwrap()
+        .handle_access(AccessFs::ReadDir)
+        .unwrap();
+    let access = make_bitflags!(AccessFs::{Execute | ReadDir});
+    assert_eq!(ruleset.requested_handled_fs, access);
+    assert_eq!(ruleset.actual_handled_fs, access);
+
+    // Tests that only the required handled accesses are reported as incompatible:
+    // access should not contains AccessFs::Execute.
+    assert!(matches!(Ruleset::from(ABI::Unsupported)
+        .handle_access(AccessFs::Execute)
+        .unwrap()
+        .set_compatibility(CompatLevel::HardRequirement)
+        .handle_access(AccessFs::ReadDir)
+        .unwrap_err(),
+        RulesetError::HandleAccesses(HandleAccessesError::Fs(HandleAccessError::Compat(
+            CompatError::Access(AccessError::Incompatible { access })
+        ))) if access == AccessFs::ReadDir
+    ));
+}
+
+#[test]
+fn ruleset_created_handle_access_net_tcp() {
+    let access = make_bitflags!(AccessNet::{BindTcp | ConnectTcp});
+
+    // Tests AccessNet::ruleset_handle_access() with ABI that doesn't support TCP rights.
+    let ruleset = Ruleset::from(ABI::V3).handle_access(access).unwrap();
+    assert_eq!(ruleset.requested_handled_net, access);
+    assert_eq!(ruleset.actual_handled_net, BitFlags::<AccessNet>::EMPTY);
+
+    // Tests AccessNet::ruleset_handle_access() with ABI that supports TCP rights.
+    let ruleset = Ruleset::from(ABI::V4).handle_access(access).unwrap();
+    assert_eq!(ruleset.requested_handled_net, access);
+    assert_eq!(ruleset.actual_handled_net, access);
+
+    // Tests that only the required handled accesses are reported as incompatible:
+    // access should not contains AccessNet::BindTcp.
+    assert!(matches!(Ruleset::from(ABI::Unsupported)
+        .handle_access(AccessNet::BindTcp)
+        .unwrap()
+        .set_compatibility(CompatLevel::HardRequirement)
+        .handle_access(AccessNet::ConnectTcp)
+        .unwrap_err(),
+        RulesetError::HandleAccesses(HandleAccessesError::Net(HandleAccessError::Compat(
+            CompatError::Access(AccessError::Incompatible { access })
+        ))) if access == AccessNet::ConnectTcp
+    ));
+}
+
+impl OptionCompatLevelMut for RulesetCreated {
+    fn as_option_compat_level_mut(&mut self) -> &mut Option<CompatLevel> {
+        &mut self.compat.level
+    }
+}
+
+impl OptionCompatLevelMut for &mut RulesetCreated {
+    fn as_option_compat_level_mut(&mut self) -> &mut Option<CompatLevel> {
+        &mut self.compat.level
+    }
+}
+
+impl Compatible for RulesetCreated {}
+
+impl Compatible for &mut RulesetCreated {}
+
+pub trait RulesetCreatedAttr: Sized + AsMut<RulesetCreated> + Compatible {
+    /// Attempts to add a new rule to the ruleset.
+    ///
+    /// On error, returns a wrapped [`AddRulesError`].
+    fn add_rule<T, U>(mut self, rule: T) -> Result<Self, RulesetError>
+    where
+        T: Rule<U>,
+        U: Access,
+    {
+        let body = || -> Result<Self, AddRulesError> {
+            let self_ref = self.as_mut();
+            rule.check_consistency(self_ref)?;
+            let mut compat_rule = match rule
+                .try_compat(
+                    self_ref.compat.abi(),
+                    self_ref.compat.level,
+                    &mut self_ref.compat.state,
+                )
+                .map_err(AddRuleError::Compat)?
+            {
+                Some(r) => r,
+                None => return Ok(self),
+            };
+            match self_ref.compat.state {
+                CompatState::Init | CompatState::No | CompatState::Dummy => Ok(self),
+                CompatState::Full | CompatState::Partial => match unsafe {
+                    uapi::landlock_add_rule(self_ref.fd, T::TYPE_ID, compat_rule.as_ptr(), 0)
+                } {
+                    0 => Ok(self),
+                    _ => Err(AddRuleError::<U>::AddRuleCall {
+                        source: Error::last_os_error(),
+                    }
+                    .into()),
+                },
+            }
+        };
+        Ok(body()?)
+    }
+
+    /// Attempts to add a set of new rules to the ruleset.
+    ///
+    /// On error, returns a (double) wrapped [`AddRulesError`].
+    ///
+    /// # Example
+    ///
+    /// Create a custom iterator to read paths from environment variable.
+    ///
+    /// ```
+    /// use landlock::{
+    ///     Access, AccessFs, BitFlags, PathBeneath, PathFd, PathFdError, RestrictionStatus, Ruleset,
+    ///     RulesetAttr, RulesetCreatedAttr, RulesetError, ABI,
+    /// };
+    /// use std::env;
+    /// use std::ffi::OsStr;
+    /// use std::os::unix::ffi::{OsStrExt, OsStringExt};
+    /// use thiserror::Error;
+    ///
+    /// #[derive(Debug, Error)]
+    /// enum PathEnvError<'a> {
+    ///     #[error(transparent)]
+    ///     Ruleset(#[from] RulesetError),
+    ///     #[error(transparent)]
+    ///     AddRuleIter(#[from] PathFdError),
+    ///     #[error("missing environment variable {0}")]
+    ///     MissingVar(&'a str),
+    /// }
+    ///
+    /// struct PathEnv {
+    ///     paths: Vec<u8>,
+    ///     access: BitFlags<AccessFs>,
+    /// }
+    ///
+    /// impl PathEnv {
+    ///     // env_var is the name of an environment variable
+    ///     // containing paths requested to be allowed.
+    ///     // Paths are separated with ":", e.g. "/bin:/lib:/usr:/proc".
+    ///     // In case an empty string is provided,
+    ///     // no restrictions are applied.
+    ///     // `access` is the set of access rights allowed for each of the parsed paths.
+    ///     fn new<'a>(
+    ///         env_var: &'a str, access: BitFlags<AccessFs>
+    ///     ) -> Result<Self, PathEnvError<'a>> {
+    ///         Ok(Self {
+    ///             paths: env::var_os(env_var)
+    ///                 .ok_or(PathEnvError::MissingVar(env_var))?
+    ///                 .into_vec(),
+    ///             access,
+    ///         })
+    ///     }
+    ///
+    ///     fn iter(
+    ///         &self,
+    ///     ) -> impl Iterator<Item = Result<PathBeneath<PathFd>, PathEnvError<'static>>> + '_ {
+    ///         let is_empty = self.paths.is_empty();
+    ///         self.paths
+    ///             .split(|b| *b == b':')
+    ///             // Skips the first empty element from of an empty string.
+    ///             .skip_while(move |_| is_empty)
+    ///             .map(OsStr::from_bytes)
+    ///             .map(move |path|
+    ///                 Ok(PathBeneath::new(PathFd::new(path)?, self.access)))
+    ///     }
+    /// }
+    ///
+    /// fn restrict_env() -> Result<RestrictionStatus, PathEnvError<'static>> {
+    ///     Ok(Ruleset::default()
+    ///         .handle_access(AccessFs::from_all(ABI::V1))?
+    ///         .create()?
+    ///         // In the shell: export EXECUTABLE_PATH="/usr:/bin:/sbin"
+    ///         .add_rules(PathEnv::new("EXECUTABLE_PATH", AccessFs::Execute.into())?.iter())?
+    ///         .restrict_self()?)
+    /// }
+    /// ```
+    fn add_rules<I, T, U, E>(mut self, rules: I) -> Result<Self, E>
+    where
+        I: IntoIterator<Item = Result<T, E>>,
+        T: Rule<U>,
+        U: Access,
+        E: From<RulesetError>,
+    {
+        for rule in rules {
+            self = self.add_rule(rule?)?;
+        }
+        Ok(self)
+    }
+
+    /// Configures the ruleset to call `prctl(2)` with the `PR_SET_NO_NEW_PRIVS` command
+    /// in [`restrict_self()`](RulesetCreated::restrict_self).
+    ///
+    /// This `prctl(2)` call is never ignored, even if an error was encountered on a [`Ruleset`] or
+    /// [`RulesetCreated`] method call while [`CompatLevel::SoftRequirement`] was set.
+    fn set_no_new_privs(mut self, no_new_privs: bool) -> Self {
+        <Self as AsMut<RulesetCreated>>::as_mut(&mut self).no_new_privs = no_new_privs;
+        self
+    }
+}
+
+/// Ruleset created with [`Ruleset::create()`].
+#[cfg_attr(test, derive(Debug))]
+pub struct RulesetCreated {
+    fd: RawFd,
+    no_new_privs: bool,
+    pub(crate) requested_handled_fs: BitFlags<AccessFs>,
+    pub(crate) requested_handled_net: BitFlags<AccessNet>,
+    compat: Compatibility,
+}
+
+impl RulesetCreated {
+    pub(crate) fn new(ruleset: Ruleset, fd: RawFd) -> Self {
+        // The compatibility state is initialized by Ruleset::create().
+        #[cfg(test)]
+        assert!(!matches!(ruleset.compat.state, CompatState::Init));
+
+        RulesetCreated {
+            fd,
+            no_new_privs: true,
+            requested_handled_fs: ruleset.requested_handled_fs,
+            requested_handled_net: ruleset.requested_handled_net,
+            compat: ruleset.compat,
+        }
+    }
+
+    /// Attempts to restrict the calling thread with the ruleset
+    /// according to the best-effort configuration
+    /// (see [`RulesetCreated::set_compatibility()`] and [`CompatLevel::BestEffort`]).
+    /// Call `prctl(2)` with the `PR_SET_NO_NEW_PRIVS`
+    /// according to the ruleset configuration.
+    ///
+    /// On error, returns a wrapped [`RestrictSelfError`].
+    pub fn restrict_self(mut self) -> Result<RestrictionStatus, RulesetError> {
+        let mut body = || -> Result<RestrictionStatus, RestrictSelfError> {
+            // Enforce no_new_privs even if something failed with SoftRequirement. The rationale is
+            // that no_new_privs should not be an issue on its own if it is not explicitly
+            // deactivated.
+            let enforced_nnp = if self.no_new_privs {
+                if let Err(e) = prctl_set_no_new_privs() {
+                    match self.compat.level.into() {
+                        CompatLevel::BestEffort => {}
+                        CompatLevel::SoftRequirement => {
+                            self.compat.update(CompatState::Dummy);
+                        }
+                        CompatLevel::HardRequirement => {
+                            return Err(RestrictSelfError::SetNoNewPrivsCall { source: e });
+                        }
+                    }
+                    // To get a consistent behavior, calls this prctl whether or not
+                    // Landlock is supported by the running kernel.
+                    let support_nnp = support_no_new_privs();
+                    match self.compat.state {
+                        // It should not be an error for kernel (older than 3.5) not supporting
+                        // no_new_privs.
+                        CompatState::Init | CompatState::No | CompatState::Dummy => {
+                            if support_nnp {
+                                // The kernel seems to be between 3.5 (included) and 5.13 (excluded),
+                                // or Landlock is not enabled; no_new_privs should be supported anyway.
+                                return Err(RestrictSelfError::SetNoNewPrivsCall { source: e });
+                            }
+                        }
+                        // A kernel supporting Landlock should also support no_new_privs (unless
+                        // filtered by seccomp).
+                        CompatState::Full | CompatState::Partial => {
+                            return Err(RestrictSelfError::SetNoNewPrivsCall { source: e })
+                        }
+                    }
+                    false
+                } else {
+                    true
+                }
+            } else {
+                false
+            };
+
+            match self.compat.state {
+                CompatState::Init | CompatState::No | CompatState::Dummy => Ok(RestrictionStatus {
+                    ruleset: self.compat.state.into(),
+                    no_new_privs: enforced_nnp,
+                }),
+                CompatState::Full | CompatState::Partial => {
+                    match unsafe { uapi::landlock_restrict_self(self.fd, 0) } {
+                        0 => {
+                            self.compat.update(CompatState::Full);
+                            Ok(RestrictionStatus {
+                                ruleset: self.compat.state.into(),
+                                no_new_privs: enforced_nnp,
+                            })
+                        }
+                        // TODO: match specific Landlock restrict self errors
+                        _ => Err(RestrictSelfError::RestrictSelfCall {
+                            source: Error::last_os_error(),
+                        }),
+                    }
+                }
+            }
+        };
+        Ok(body()?)
+    }
+
+    /// Creates a new `RulesetCreated` instance by duplicating the underlying file descriptor.
+    /// Rule modification will affect both `RulesetCreated` instances simultaneously.
+    ///
+    /// On error, returns [`std::io::Error`].
+    pub fn try_clone(&self) -> std::io::Result<Self> {
+        Ok(RulesetCreated {
+            fd: match self.fd {
+                -1 => -1,
+                self_fd => match unsafe { libc::fcntl(self_fd, libc::F_DUPFD_CLOEXEC, 0) } {
+                    dup_fd if dup_fd >= 0 => dup_fd,
+                    _ => return Err(Error::last_os_error()),
+                },
+            },
+            no_new_privs: self.no_new_privs,
+            requested_handled_fs: self.requested_handled_fs,
+            requested_handled_net: self.requested_handled_net,
+            compat: self.compat,
+        })
+    }
+}
+
+impl Drop for RulesetCreated {
+    fn drop(&mut self) {
+        if self.fd >= 0 {
+            unsafe { close(self.fd) };
+        }
+    }
+}
+
+impl AsMut<RulesetCreated> for RulesetCreated {
+    fn as_mut(&mut self) -> &mut RulesetCreated {
+        self
+    }
+}
+
+impl RulesetCreatedAttr for RulesetCreated {}
+
+impl RulesetCreatedAttr for &mut RulesetCreated {}
+
+#[test]
+fn ruleset_created_attr() {
+    let mut ruleset_created = Ruleset::from(ABI::Unsupported)
+        .handle_access(AccessFs::Execute)
+        .unwrap()
+        .create()
+        .unwrap();
+    let ruleset_created_ref = &mut ruleset_created;
+
+    // Can pass this reference to populate the ruleset...
+    ruleset_created_ref
+        .set_compatibility(CompatLevel::BestEffort)
+        .add_rule(PathBeneath::new(
+            PathFd::new("/usr").unwrap(),
+            AccessFs::Execute,
+        ))
+        .unwrap()
+        .add_rule(PathBeneath::new(
+            PathFd::new("/etc").unwrap(),
+            AccessFs::Execute,
+        ))
+        .unwrap();
+
+    // ...and finally restrict with the last rules (thanks to non-lexical lifetimes).
+    assert_eq!(
+        ruleset_created
+            .set_compatibility(CompatLevel::BestEffort)
+            .add_rule(PathBeneath::new(
+                PathFd::new("/tmp").unwrap(),
+                AccessFs::Execute,
+            ))
+            .unwrap()
+            .add_rule(PathBeneath::new(
+                PathFd::new("/var").unwrap(),
+                AccessFs::Execute,
+            ))
+            .unwrap()
+            .restrict_self()
+            .unwrap(),
+        RestrictionStatus {
+            ruleset: RulesetStatus::NotEnforced,
+            no_new_privs: true,
+        }
+    );
+}
+
+#[test]
+fn ruleset_compat_dummy() {
+    for level in [CompatLevel::BestEffort, CompatLevel::SoftRequirement] {
+        println!("level: {:?}", level);
+
+        // ABI:Unsupported does not support AccessFs::Execute.
+        let ruleset = Ruleset::from(ABI::Unsupported);
+        assert_eq!(ruleset.compat.state, CompatState::Init);
+
+        let ruleset = ruleset.set_compatibility(level);
+        assert_eq!(ruleset.compat.state, CompatState::Init);
+
+        let ruleset = ruleset.handle_access(AccessFs::Execute).unwrap();
+        assert_eq!(
+            ruleset.compat.state,
+            match level {
+                CompatLevel::BestEffort => CompatState::No,
+                CompatLevel::SoftRequirement => CompatState::Dummy,
+                _ => unreachable!(),
+            }
+        );
+
+        let ruleset_created = ruleset.create().unwrap();
+        // Because the compatibility state was either No or Dummy, calling create() updates it to
+        // Dummy.
+        assert_eq!(ruleset_created.compat.state, CompatState::Dummy);
+
+        let ruleset_created = ruleset_created
+            .add_rule(PathBeneath::new(
+                PathFd::new("/usr").unwrap(),
+                AccessFs::Execute,
+            ))
+            .unwrap();
+        assert_eq!(ruleset_created.compat.state, CompatState::Dummy);
+    }
+}
+
+#[test]
+fn ruleset_compat_partial() {
+    // CompatLevel::BestEffort
+    let ruleset = Ruleset::from(ABI::V1);
+    assert_eq!(ruleset.compat.state, CompatState::Init);
+
+    // ABI::V1 does not support AccessFs::Refer.
+    let ruleset = ruleset.handle_access(AccessFs::Refer).unwrap();
+    assert_eq!(ruleset.compat.state, CompatState::No);
+
+    let ruleset = ruleset.handle_access(AccessFs::Execute).unwrap();
+    assert_eq!(ruleset.compat.state, CompatState::Partial);
+
+    // Requesting to handle another unsupported handled access does not change anything.
+    let ruleset = ruleset.handle_access(AccessFs::Refer).unwrap();
+    assert_eq!(ruleset.compat.state, CompatState::Partial);
+}
+
+#[test]
+fn ruleset_unsupported() {
+    assert_eq!(
+        Ruleset::from(ABI::Unsupported)
+            // BestEffort for Ruleset.
+            .handle_access(AccessFs::Execute)
+            .unwrap()
+            .create()
+            .unwrap()
+            .restrict_self()
+            .unwrap(),
+        RestrictionStatus {
+            ruleset: RulesetStatus::NotEnforced,
+            // With BestEffort, no_new_privs is still enabled.
+            no_new_privs: true,
+        }
+    );
+
+    assert_eq!(
+        Ruleset::from(ABI::Unsupported)
+            // SoftRequirement for Ruleset.
+            .set_compatibility(CompatLevel::SoftRequirement)
+            .handle_access(AccessFs::Execute)
+            .unwrap()
+            .create()
+            .unwrap()
+            .restrict_self()
+            .unwrap(),
+        RestrictionStatus {
+            ruleset: RulesetStatus::NotEnforced,
+            // With SoftRequirement, no_new_privs is still enabled.
+            no_new_privs: true,
+        }
+    );
+
+    matches!(
+        Ruleset::from(ABI::Unsupported)
+            // HardRequirement for Ruleset.
+            .set_compatibility(CompatLevel::HardRequirement)
+            .handle_access(AccessFs::Execute)
+            .unwrap_err(),
+        RulesetError::CreateRuleset(CreateRulesetError::MissingHandledAccess)
+    );
+
+    assert_eq!(
+        Ruleset::from(ABI::Unsupported)
+            .handle_access(AccessFs::Execute)
+            .unwrap()
+            .create()
+            .unwrap()
+            // SoftRequirement for RulesetCreated without any rule.
+            .set_compatibility(CompatLevel::SoftRequirement)
+            .restrict_self()
+            .unwrap(),
+        RestrictionStatus {
+            ruleset: RulesetStatus::NotEnforced,
+            // With SoftRequirement, no_new_privs is untouched if there is no error (e.g. no rule).
+            no_new_privs: true,
+        }
+    );
+
+    // Don't explicitly call create() on a CI that doesn't support Landlock.
+    if compat::can_emulate(ABI::V1, ABI::V1, Some(ABI::V2)) {
+        assert_eq!(
+            Ruleset::from(ABI::V1)
+                .handle_access(make_bitflags!(AccessFs::{Execute | Refer}))
+                .unwrap()
+                .create()
+                .unwrap()
+                // SoftRequirement for RulesetCreated with a rule.
+                .set_compatibility(CompatLevel::SoftRequirement)
+                .add_rule(PathBeneath::new(PathFd::new("/").unwrap(), AccessFs::Refer))
+                .unwrap()
+                .restrict_self()
+                .unwrap(),
+            RestrictionStatus {
+                ruleset: RulesetStatus::NotEnforced,
+                // With SoftRequirement, no_new_privs is still enabled, even if there is an error
+                // (e.g. unsupported access right).
+                no_new_privs: true,
+            }
+        );
+    }
+
+    assert_eq!(
+        Ruleset::from(ABI::Unsupported)
+            .handle_access(AccessFs::Execute)
+            .unwrap()
+            .create()
+            .unwrap()
+            .set_no_new_privs(false)
+            .restrict_self()
+            .unwrap(),
+        RestrictionStatus {
+            ruleset: RulesetStatus::NotEnforced,
+            no_new_privs: false,
+        }
+    );
+
+    assert!(matches!(
+        Ruleset::from(ABI::Unsupported)
+            // Empty access-rights
+            .handle_access(AccessFs::from_all(ABI::Unsupported))
+            .unwrap_err(),
+        RulesetError::HandleAccesses(HandleAccessesError::Fs(HandleAccessError::Compat(
+            CompatError::Access(AccessError::Empty)
+        )))
+    ));
+
+    assert!(matches!(
+        Ruleset::from(ABI::Unsupported)
+            // No handle_access() call.
+            .create()
+            .unwrap_err(),
+        RulesetError::CreateRuleset(CreateRulesetError::MissingHandledAccess)
+    ));
+
+    assert!(matches!(
+        Ruleset::from(ABI::V1)
+            // Empty access-rights
+            .handle_access(AccessFs::from_all(ABI::Unsupported))
+            .unwrap_err(),
+        RulesetError::HandleAccesses(HandleAccessesError::Fs(HandleAccessError::Compat(
+            CompatError::Access(AccessError::Empty)
+        )))
+    ));
+
+    // Tests inconsistency between the ruleset handled access-rights and the rule access-rights.
+    for handled_access in &[
+        make_bitflags!(AccessFs::{Execute | WriteFile}),
+        AccessFs::Execute.into(),
+    ] {
+        let ruleset = Ruleset::from(ABI::V1)
+            .handle_access(*handled_access)
+            .unwrap();
+        // Fakes a call to create() to test without involving the kernel (i.e. no
+        // landlock_ruleset_create() call).
+        let ruleset_created = RulesetCreated::new(ruleset, -1);
+        assert!(matches!(
+            ruleset_created
+                .add_rule(PathBeneath::new(
+                    PathFd::new("/").unwrap(),
+                    AccessFs::ReadFile
+                ))
+                .unwrap_err(),
+            RulesetError::AddRules(AddRulesError::Fs(AddRuleError::UnhandledAccess { .. }))
+        ));
+    }
+}
+
+#[test]
+fn ignore_abi_v2_with_abi_v1() {
+    // We don't need kernel/CI support for Landlock because no related syscalls should actually be
+    // performed.
+    assert_eq!(
+        Ruleset::from(ABI::V1)
+            .set_compatibility(CompatLevel::HardRequirement)
+            .handle_access(AccessFs::from_all(ABI::V1))
+            .unwrap()
+            .set_compatibility(CompatLevel::SoftRequirement)
+            // Because Ruleset only supports V1, Refer will be ignored.
+            .handle_access(AccessFs::Refer)
+            .unwrap()
+            .create()
+            .unwrap()
+            .add_rule(PathBeneath::new(
+                PathFd::new("/tmp").unwrap(),
+                AccessFs::from_all(ABI::V2)
+            ))
+            .unwrap()
+            .add_rule(PathBeneath::new(
+                PathFd::new("/usr").unwrap(),
+                make_bitflags!(AccessFs::{ReadFile | ReadDir})
+            ))
+            .unwrap()
+            .restrict_self()
+            .unwrap(),
+        RestrictionStatus {
+            ruleset: RulesetStatus::NotEnforced,
+            no_new_privs: true,
+        }
+    );
+}
+
+#[test]
+fn unsupported_handled_access() {
+    matches!(
+        Ruleset::from(ABI::V3)
+            .handle_access(AccessNet::from_all(ABI::V3))
+            .unwrap_err(),
+        RulesetError::HandleAccesses(HandleAccessesError::Net(HandleAccessError::Compat(
+            CompatError::Access(AccessError::Empty)
+        )))
+    );
+}
+
\ No newline at end of file diff --git a/src/landlock/uapi/landlock.rs.html b/src/landlock/uapi/landlock.rs.html new file mode 100644 index 0000000..13a29fb --- /dev/null +++ b/src/landlock/uapi/landlock.rs.html @@ -0,0 +1,555 @@ +landlock.rs - source
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
+
/* automatically generated by rust-bindgen 0.69.4 */
+
+pub const __BITS_PER_LONG: u32 = 64;
+pub const __BITS_PER_LONG_LONG: u32 = 64;
+pub const __FD_SETSIZE: u32 = 1024;
+pub const LANDLOCK_CREATE_RULESET_VERSION: u32 = 1;
+pub const LANDLOCK_ACCESS_FS_EXECUTE: u32 = 1;
+pub const LANDLOCK_ACCESS_FS_WRITE_FILE: u32 = 2;
+pub const LANDLOCK_ACCESS_FS_READ_FILE: u32 = 4;
+pub const LANDLOCK_ACCESS_FS_READ_DIR: u32 = 8;
+pub const LANDLOCK_ACCESS_FS_REMOVE_DIR: u32 = 16;
+pub const LANDLOCK_ACCESS_FS_REMOVE_FILE: u32 = 32;
+pub const LANDLOCK_ACCESS_FS_MAKE_CHAR: u32 = 64;
+pub const LANDLOCK_ACCESS_FS_MAKE_DIR: u32 = 128;
+pub const LANDLOCK_ACCESS_FS_MAKE_REG: u32 = 256;
+pub const LANDLOCK_ACCESS_FS_MAKE_SOCK: u32 = 512;
+pub const LANDLOCK_ACCESS_FS_MAKE_FIFO: u32 = 1024;
+pub const LANDLOCK_ACCESS_FS_MAKE_BLOCK: u32 = 2048;
+pub const LANDLOCK_ACCESS_FS_MAKE_SYM: u32 = 4096;
+pub const LANDLOCK_ACCESS_FS_REFER: u32 = 8192;
+pub const LANDLOCK_ACCESS_FS_TRUNCATE: u32 = 16384;
+pub const LANDLOCK_ACCESS_FS_IOCTL_DEV: u32 = 32768;
+pub const LANDLOCK_ACCESS_NET_BIND_TCP: u32 = 1;
+pub const LANDLOCK_ACCESS_NET_CONNECT_TCP: u32 = 2;
+pub type __s8 = ::std::os::raw::c_schar;
+pub type __u8 = ::std::os::raw::c_uchar;
+pub type __s16 = ::std::os::raw::c_short;
+pub type __u16 = ::std::os::raw::c_ushort;
+pub type __s32 = ::std::os::raw::c_int;
+pub type __u32 = ::std::os::raw::c_uint;
+pub type __s64 = ::std::os::raw::c_longlong;
+pub type __u64 = ::std::os::raw::c_ulonglong;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __kernel_fd_set {
+    pub fds_bits: [::std::os::raw::c_ulong; 16usize],
+}
+#[test]
+fn bindgen_test_layout___kernel_fd_set() {
+    const UNINIT: ::std::mem::MaybeUninit<__kernel_fd_set> = ::std::mem::MaybeUninit::uninit();
+    let ptr = UNINIT.as_ptr();
+    assert_eq!(
+        ::std::mem::size_of::<__kernel_fd_set>(),
+        128usize,
+        concat!("Size of: ", stringify!(__kernel_fd_set))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<__kernel_fd_set>(),
+        8usize,
+        concat!("Alignment of ", stringify!(__kernel_fd_set))
+    );
+    assert_eq!(
+        unsafe { ::std::ptr::addr_of!((*ptr).fds_bits) as usize - ptr as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(__kernel_fd_set),
+            "::",
+            stringify!(fds_bits)
+        )
+    );
+}
+pub type __kernel_sighandler_t =
+    ::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
+pub type __kernel_key_t = ::std::os::raw::c_int;
+pub type __kernel_mqd_t = ::std::os::raw::c_int;
+pub type __kernel_old_uid_t = ::std::os::raw::c_ushort;
+pub type __kernel_old_gid_t = ::std::os::raw::c_ushort;
+pub type __kernel_old_dev_t = ::std::os::raw::c_ulong;
+pub type __kernel_long_t = ::std::os::raw::c_long;
+pub type __kernel_ulong_t = ::std::os::raw::c_ulong;
+pub type __kernel_ino_t = __kernel_ulong_t;
+pub type __kernel_mode_t = ::std::os::raw::c_uint;
+pub type __kernel_pid_t = ::std::os::raw::c_int;
+pub type __kernel_ipc_pid_t = ::std::os::raw::c_int;
+pub type __kernel_uid_t = ::std::os::raw::c_uint;
+pub type __kernel_gid_t = ::std::os::raw::c_uint;
+pub type __kernel_suseconds_t = __kernel_long_t;
+pub type __kernel_daddr_t = ::std::os::raw::c_int;
+pub type __kernel_uid32_t = ::std::os::raw::c_uint;
+pub type __kernel_gid32_t = ::std::os::raw::c_uint;
+pub type __kernel_size_t = __kernel_ulong_t;
+pub type __kernel_ssize_t = __kernel_long_t;
+pub type __kernel_ptrdiff_t = __kernel_long_t;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __kernel_fsid_t {
+    pub val: [::std::os::raw::c_int; 2usize],
+}
+#[test]
+fn bindgen_test_layout___kernel_fsid_t() {
+    const UNINIT: ::std::mem::MaybeUninit<__kernel_fsid_t> = ::std::mem::MaybeUninit::uninit();
+    let ptr = UNINIT.as_ptr();
+    assert_eq!(
+        ::std::mem::size_of::<__kernel_fsid_t>(),
+        8usize,
+        concat!("Size of: ", stringify!(__kernel_fsid_t))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<__kernel_fsid_t>(),
+        4usize,
+        concat!("Alignment of ", stringify!(__kernel_fsid_t))
+    );
+    assert_eq!(
+        unsafe { ::std::ptr::addr_of!((*ptr).val) as usize - ptr as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(__kernel_fsid_t),
+            "::",
+            stringify!(val)
+        )
+    );
+}
+pub type __kernel_off_t = __kernel_long_t;
+pub type __kernel_loff_t = ::std::os::raw::c_longlong;
+pub type __kernel_old_time_t = __kernel_long_t;
+pub type __kernel_time_t = __kernel_long_t;
+pub type __kernel_time64_t = ::std::os::raw::c_longlong;
+pub type __kernel_clock_t = __kernel_long_t;
+pub type __kernel_timer_t = ::std::os::raw::c_int;
+pub type __kernel_clockid_t = ::std::os::raw::c_int;
+pub type __kernel_caddr_t = *mut ::std::os::raw::c_char;
+pub type __kernel_uid16_t = ::std::os::raw::c_ushort;
+pub type __kernel_gid16_t = ::std::os::raw::c_ushort;
+pub type __s128 = i128;
+pub type __u128 = u128;
+pub type __le16 = __u16;
+pub type __be16 = __u16;
+pub type __le32 = __u32;
+pub type __be32 = __u32;
+pub type __le64 = __u64;
+pub type __be64 = __u64;
+pub type __sum16 = __u16;
+pub type __wsum = __u32;
+pub type __poll_t = ::std::os::raw::c_uint;
+#[doc = " struct landlock_ruleset_attr - Ruleset definition\n\n Argument of sys_landlock_create_ruleset().  This structure can grow in\n future versions."]
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct landlock_ruleset_attr {
+    #[doc = " @handled_access_fs: Bitmask of actions (cf. `Filesystem flags`_)\n that is handled by this ruleset and should then be forbidden if no\n rule explicitly allow them: it is a deny-by-default list that should\n contain as much Landlock access rights as possible. Indeed, all\n Landlock filesystem access rights that are not part of\n handled_access_fs are allowed.  This is needed for backward\n compatibility reasons.  One exception is the\n %LANDLOCK_ACCESS_FS_REFER access right, which is always implicitly\n handled, but must still be explicitly handled to add new rules with\n this access right."]
+    pub handled_access_fs: __u64,
+    #[doc = " @handled_access_net: Bitmask of actions (cf. `Network flags`_)\n that is handled by this ruleset and should then be forbidden if no\n rule explicitly allow them."]
+    pub handled_access_net: __u64,
+}
+#[test]
+fn bindgen_test_layout_landlock_ruleset_attr() {
+    const UNINIT: ::std::mem::MaybeUninit<landlock_ruleset_attr> =
+        ::std::mem::MaybeUninit::uninit();
+    let ptr = UNINIT.as_ptr();
+    assert_eq!(
+        ::std::mem::size_of::<landlock_ruleset_attr>(),
+        16usize,
+        concat!("Size of: ", stringify!(landlock_ruleset_attr))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<landlock_ruleset_attr>(),
+        8usize,
+        concat!("Alignment of ", stringify!(landlock_ruleset_attr))
+    );
+    assert_eq!(
+        unsafe { ::std::ptr::addr_of!((*ptr).handled_access_fs) as usize - ptr as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(landlock_ruleset_attr),
+            "::",
+            stringify!(handled_access_fs)
+        )
+    );
+    assert_eq!(
+        unsafe { ::std::ptr::addr_of!((*ptr).handled_access_net) as usize - ptr as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(landlock_ruleset_attr),
+            "::",
+            stringify!(handled_access_net)
+        )
+    );
+}
+#[doc = " @LANDLOCK_RULE_PATH_BENEATH: Type of a &struct\n landlock_path_beneath_attr ."]
+pub const landlock_rule_type_LANDLOCK_RULE_PATH_BENEATH: landlock_rule_type = 1;
+#[doc = " @LANDLOCK_RULE_NET_PORT: Type of a &struct\n landlock_net_port_attr ."]
+pub const landlock_rule_type_LANDLOCK_RULE_NET_PORT: landlock_rule_type = 2;
+#[doc = " enum landlock_rule_type - Landlock rule type\n\n Argument of sys_landlock_add_rule()."]
+pub type landlock_rule_type = ::std::os::raw::c_uint;
+#[doc = " struct landlock_path_beneath_attr - Path hierarchy definition\n\n Argument of sys_landlock_add_rule()."]
+#[repr(C, packed)]
+#[derive(Debug, Copy, Clone)]
+pub struct landlock_path_beneath_attr {
+    #[doc = " @allowed_access: Bitmask of allowed actions for this file hierarchy\n (cf. `Filesystem flags`_)."]
+    pub allowed_access: __u64,
+    #[doc = " @parent_fd: File descriptor, preferably opened with ``O_PATH``,\n which identifies the parent directory of a file hierarchy, or just a\n file."]
+    pub parent_fd: __s32,
+}
+#[test]
+fn bindgen_test_layout_landlock_path_beneath_attr() {
+    const UNINIT: ::std::mem::MaybeUninit<landlock_path_beneath_attr> =
+        ::std::mem::MaybeUninit::uninit();
+    let ptr = UNINIT.as_ptr();
+    assert_eq!(
+        ::std::mem::size_of::<landlock_path_beneath_attr>(),
+        12usize,
+        concat!("Size of: ", stringify!(landlock_path_beneath_attr))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<landlock_path_beneath_attr>(),
+        1usize,
+        concat!("Alignment of ", stringify!(landlock_path_beneath_attr))
+    );
+    assert_eq!(
+        unsafe { ::std::ptr::addr_of!((*ptr).allowed_access) as usize - ptr as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(landlock_path_beneath_attr),
+            "::",
+            stringify!(allowed_access)
+        )
+    );
+    assert_eq!(
+        unsafe { ::std::ptr::addr_of!((*ptr).parent_fd) as usize - ptr as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(landlock_path_beneath_attr),
+            "::",
+            stringify!(parent_fd)
+        )
+    );
+}
+#[doc = " struct landlock_net_port_attr - Network port definition\n\n Argument of sys_landlock_add_rule()."]
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct landlock_net_port_attr {
+    #[doc = " @allowed_access: Bitmask of allowed access network for a port\n (cf. `Network flags`_)."]
+    pub allowed_access: __u64,
+    #[doc = " @port: Network port in host endianness.\n\n It should be noted that port 0 passed to :manpage:`bind(2)` will\n bind to an available port from a specific port range. This can be\n configured thanks to the ``/proc/sys/net/ipv4/ip_local_port_range``\n sysctl (also used for IPv6). A Landlock rule with port 0 and the\n ``LANDLOCK_ACCESS_NET_BIND_TCP`` right means that requesting to bind\n on port 0 is allowed and it will automatically translate to binding\n on the related port range."]
+    pub port: __u64,
+}
+#[test]
+fn bindgen_test_layout_landlock_net_port_attr() {
+    const UNINIT: ::std::mem::MaybeUninit<landlock_net_port_attr> =
+        ::std::mem::MaybeUninit::uninit();
+    let ptr = UNINIT.as_ptr();
+    assert_eq!(
+        ::std::mem::size_of::<landlock_net_port_attr>(),
+        16usize,
+        concat!("Size of: ", stringify!(landlock_net_port_attr))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<landlock_net_port_attr>(),
+        8usize,
+        concat!("Alignment of ", stringify!(landlock_net_port_attr))
+    );
+    assert_eq!(
+        unsafe { ::std::ptr::addr_of!((*ptr).allowed_access) as usize - ptr as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(landlock_net_port_attr),
+            "::",
+            stringify!(allowed_access)
+        )
+    );
+    assert_eq!(
+        unsafe { ::std::ptr::addr_of!((*ptr).port) as usize - ptr as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(landlock_net_port_attr),
+            "::",
+            stringify!(port)
+        )
+    );
+}
+
\ No newline at end of file diff --git a/src/landlock/uapi/mod.rs.html b/src/landlock/uapi/mod.rs.html new file mode 100644 index 0000000..520d4b4 --- /dev/null +++ b/src/landlock/uapi/mod.rs.html @@ -0,0 +1,111 @@ +mod.rs - source
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
+
#[allow(dead_code)]
+#[allow(non_camel_case_types)]
+#[allow(non_snake_case)]
+#[allow(non_upper_case_globals)]
+mod landlock;
+
+#[rustfmt::skip]
+pub use self::landlock::{
+    landlock_net_port_attr,
+    landlock_path_beneath_attr,
+    landlock_rule_type,
+    landlock_rule_type_LANDLOCK_RULE_NET_PORT,
+    landlock_rule_type_LANDLOCK_RULE_PATH_BENEATH,
+    landlock_ruleset_attr,
+    LANDLOCK_ACCESS_FS_EXECUTE,
+    LANDLOCK_ACCESS_FS_WRITE_FILE,
+    LANDLOCK_ACCESS_FS_READ_FILE,
+    LANDLOCK_ACCESS_FS_READ_DIR,
+    LANDLOCK_ACCESS_FS_REMOVE_DIR,
+    LANDLOCK_ACCESS_FS_REMOVE_FILE,
+    LANDLOCK_ACCESS_FS_MAKE_CHAR,
+    LANDLOCK_ACCESS_FS_MAKE_DIR,
+    LANDLOCK_ACCESS_FS_MAKE_REG,
+    LANDLOCK_ACCESS_FS_MAKE_SOCK,
+    LANDLOCK_ACCESS_FS_MAKE_FIFO,
+    LANDLOCK_ACCESS_FS_MAKE_BLOCK,
+    LANDLOCK_ACCESS_FS_MAKE_SYM,
+    LANDLOCK_ACCESS_FS_REFER,
+    LANDLOCK_ACCESS_FS_TRUNCATE,
+    LANDLOCK_ACCESS_FS_IOCTL_DEV,
+    LANDLOCK_ACCESS_NET_BIND_TCP,
+    LANDLOCK_ACCESS_NET_CONNECT_TCP,
+    LANDLOCK_CREATE_RULESET_VERSION,
+};
+
+use libc::{
+    __u32, c_int, c_void, size_t, syscall, SYS_landlock_add_rule, SYS_landlock_create_ruleset,
+    SYS_landlock_restrict_self,
+};
+
+#[rustfmt::skip]
+pub unsafe fn landlock_create_ruleset(attr: *const landlock_ruleset_attr, size: size_t,
+                                      flags: __u32) -> c_int {
+    syscall(SYS_landlock_create_ruleset, attr, size, flags) as c_int
+}
+
+#[rustfmt::skip]
+pub unsafe fn landlock_add_rule(ruleset_fd: c_int, rule_type: landlock_rule_type,
+                                rule_attr: *const c_void, flags: __u32) -> c_int {
+    syscall(SYS_landlock_add_rule, ruleset_fd, rule_type, rule_attr, flags) as c_int
+}
+
+pub unsafe fn landlock_restrict_self(ruleset_fd: c_int, flags: __u32) -> c_int {
+    syscall(SYS_landlock_restrict_self, ruleset_fd, flags) as c_int
+}
+
\ No newline at end of file diff --git a/static.files/COPYRIGHT-23e9bde6c69aea69.txt b/static.files/COPYRIGHT-23e9bde6c69aea69.txt new file mode 100644 index 0000000..1447df7 --- /dev/null +++ b/static.files/COPYRIGHT-23e9bde6c69aea69.txt @@ -0,0 +1,50 @@ +# REUSE-IgnoreStart + +These documentation pages include resources by third parties. This copyright +file applies only to those resources. The following third party resources are +included, and carry their own copyright notices and license terms: + +* Fira Sans (FiraSans-Regular.woff2, FiraSans-Medium.woff2): + + Copyright (c) 2014, Mozilla Foundation https://mozilla.org/ + with Reserved Font Name Fira Sans. + + Copyright (c) 2014, Telefonica S.A. + + Licensed under the SIL Open Font License, Version 1.1. + See FiraSans-LICENSE.txt. + +* rustdoc.css, main.js, and playpen.js: + + Copyright 2015 The Rust Developers. + Licensed under the Apache License, Version 2.0 (see LICENSE-APACHE.txt) or + the MIT license (LICENSE-MIT.txt) at your option. + +* normalize.css: + + Copyright (c) Nicolas Gallagher and Jonathan Neal. + Licensed under the MIT license (see LICENSE-MIT.txt). + +* Source Code Pro (SourceCodePro-Regular.ttf.woff2, + SourceCodePro-Semibold.ttf.woff2, SourceCodePro-It.ttf.woff2): + + Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), + with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark + of Adobe Systems Incorporated in the United States and/or other countries. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceCodePro-LICENSE.txt. + +* Source Serif 4 (SourceSerif4-Regular.ttf.woff2, SourceSerif4-Bold.ttf.woff2, + SourceSerif4-It.ttf.woff2): + + Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name + 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United + States and/or other countries. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceSerif4-LICENSE.md. + +This copyright file is intended to be distributed with rustdoc output. + +# REUSE-IgnoreEnd diff --git a/static.files/FiraSans-LICENSE-db4b642586e02d97.txt b/static.files/FiraSans-LICENSE-db4b642586e02d97.txt new file mode 100644 index 0000000..d7e9c14 --- /dev/null +++ b/static.files/FiraSans-LICENSE-db4b642586e02d97.txt @@ -0,0 +1,98 @@ +// REUSE-IgnoreStart + +Digitized data copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A. +with Reserved Font Name < Fira >, + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +// REUSE-IgnoreEnd diff --git a/static.files/FiraSans-Medium-8f9a781e4970d388.woff2 b/static.files/FiraSans-Medium-8f9a781e4970d388.woff2 new file mode 100644 index 0000000..7a1e5fc Binary files /dev/null and b/static.files/FiraSans-Medium-8f9a781e4970d388.woff2 differ diff --git a/static.files/FiraSans-Regular-018c141bf0843ffd.woff2 b/static.files/FiraSans-Regular-018c141bf0843ffd.woff2 new file mode 100644 index 0000000..e766e06 Binary files /dev/null and b/static.files/FiraSans-Regular-018c141bf0843ffd.woff2 differ diff --git a/static.files/LICENSE-APACHE-b91fa81cba47b86a.txt b/static.files/LICENSE-APACHE-b91fa81cba47b86a.txt new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/static.files/LICENSE-APACHE-b91fa81cba47b86a.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/static.files/LICENSE-MIT-65090b722b3f6c56.txt b/static.files/LICENSE-MIT-65090b722b3f6c56.txt new file mode 100644 index 0000000..31aa793 --- /dev/null +++ b/static.files/LICENSE-MIT-65090b722b3f6c56.txt @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/static.files/NanumBarunGothic-0f09457c7a19b7c6.ttf.woff2 b/static.files/NanumBarunGothic-0f09457c7a19b7c6.ttf.woff2 new file mode 100644 index 0000000..1866ad4 Binary files /dev/null and b/static.files/NanumBarunGothic-0f09457c7a19b7c6.ttf.woff2 differ diff --git a/static.files/NanumBarunGothic-LICENSE-18c5adf4b52b4041.txt b/static.files/NanumBarunGothic-LICENSE-18c5adf4b52b4041.txt new file mode 100644 index 0000000..4b3edc2 --- /dev/null +++ b/static.files/NanumBarunGothic-LICENSE-18c5adf4b52b4041.txt @@ -0,0 +1,103 @@ +// REUSE-IgnoreStart + +Copyright (c) 2010, NAVER Corporation (https://www.navercorp.com/), + +with Reserved Font Name Nanum, Naver Nanum, NanumGothic, Naver NanumGothic, +NanumMyeongjo, Naver NanumMyeongjo, NanumBrush, Naver NanumBrush, NanumPen, +Naver NanumPen, Naver NanumGothicEco, NanumGothicEco, Naver NanumMyeongjoEco, +NanumMyeongjoEco, Naver NanumGothicLight, NanumGothicLight, NanumBarunGothic, +Naver NanumBarunGothic, NanumSquareRound, NanumBarunPen, MaruBuri + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +// REUSE-IgnoreEnd diff --git a/static.files/SourceCodePro-It-1cc31594bf4f1f79.ttf.woff2 b/static.files/SourceCodePro-It-1cc31594bf4f1f79.ttf.woff2 new file mode 100644 index 0000000..462c34e Binary files /dev/null and b/static.files/SourceCodePro-It-1cc31594bf4f1f79.ttf.woff2 differ diff --git a/static.files/SourceCodePro-LICENSE-d180d465a756484a.txt b/static.files/SourceCodePro-LICENSE-d180d465a756484a.txt new file mode 100644 index 0000000..0d2941e --- /dev/null +++ b/static.files/SourceCodePro-LICENSE-d180d465a756484a.txt @@ -0,0 +1,97 @@ +// REUSE-IgnoreStart + +Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +// REUSE-IgnoreEnd diff --git a/static.files/SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2 b/static.files/SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2 new file mode 100644 index 0000000..10b558e Binary files /dev/null and b/static.files/SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2 differ diff --git a/static.files/SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2 b/static.files/SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2 new file mode 100644 index 0000000..5ec64ee Binary files /dev/null and b/static.files/SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2 differ diff --git a/static.files/SourceSerif4-Bold-a2c9cd1067f8b328.ttf.woff2 b/static.files/SourceSerif4-Bold-a2c9cd1067f8b328.ttf.woff2 new file mode 100644 index 0000000..181a07f Binary files /dev/null and b/static.files/SourceSerif4-Bold-a2c9cd1067f8b328.ttf.woff2 differ diff --git a/static.files/SourceSerif4-It-acdfaf1a8af734b1.ttf.woff2 b/static.files/SourceSerif4-It-acdfaf1a8af734b1.ttf.woff2 new file mode 100644 index 0000000..2ae08a7 Binary files /dev/null and b/static.files/SourceSerif4-It-acdfaf1a8af734b1.ttf.woff2 differ diff --git a/static.files/SourceSerif4-LICENSE-3bb119e13b1258b7.md b/static.files/SourceSerif4-LICENSE-3bb119e13b1258b7.md new file mode 100644 index 0000000..175fa4f --- /dev/null +++ b/static.files/SourceSerif4-LICENSE-3bb119e13b1258b7.md @@ -0,0 +1,98 @@ + + +Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries. +Copyright 2014 - 2023 Adobe (http://www.adobe.com/), with Reserved Font Name ‘Source’. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + + diff --git a/static.files/SourceSerif4-Regular-46f98efaafac5295.ttf.woff2 b/static.files/SourceSerif4-Regular-46f98efaafac5295.ttf.woff2 new file mode 100644 index 0000000..0263fc3 Binary files /dev/null and b/static.files/SourceSerif4-Regular-46f98efaafac5295.ttf.woff2 differ diff --git a/static.files/favicon-2c020d218678b618.svg b/static.files/favicon-2c020d218678b618.svg new file mode 100644 index 0000000..8b34b51 --- /dev/null +++ b/static.files/favicon-2c020d218678b618.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/static.files/favicon-32x32-422f7d1d52889060.png b/static.files/favicon-32x32-422f7d1d52889060.png new file mode 100644 index 0000000..69b8613 Binary files /dev/null and b/static.files/favicon-32x32-422f7d1d52889060.png differ diff --git a/static.files/main-d2fab2bf619172d3.js b/static.files/main-d2fab2bf619172d3.js new file mode 100644 index 0000000..8fc48ed --- /dev/null +++ b/static.files/main-d2fab2bf619172d3.js @@ -0,0 +1,11 @@ +"use strict";window.RUSTDOC_TOOLTIP_HOVER_MS=300;window.RUSTDOC_TOOLTIP_HOVER_EXIT_MS=450;function resourcePath(basename,extension){return getVar("root-path")+basename+getVar("resource-suffix")+extension}function hideMain(){addClass(document.getElementById(MAIN_ID),"hidden")}function showMain(){removeClass(document.getElementById(MAIN_ID),"hidden")}function blurHandler(event,parentElem,hideCallback){if(!parentElem.contains(document.activeElement)&&!parentElem.contains(event.relatedTarget)){hideCallback()}}window.rootPath=getVar("root-path");window.currentCrate=getVar("current-crate");function setMobileTopbar(){const mobileTopbar=document.querySelector(".mobile-topbar");const locationTitle=document.querySelector(".sidebar h2.location");if(mobileTopbar){const mobileTitle=document.createElement("h2");mobileTitle.className="location";if(hasClass(document.querySelector(".rustdoc"),"crate")){mobileTitle.innerHTML=`Crate ${window.currentCrate}`}else if(locationTitle){mobileTitle.innerHTML=locationTitle.innerHTML}mobileTopbar.appendChild(mobileTitle)}}function getVirtualKey(ev){if("key"in ev&&typeof ev.key!=="undefined"){return ev.key}const c=ev.charCode||ev.keyCode;if(c===27){return"Escape"}return String.fromCharCode(c)}const MAIN_ID="main-content";const SETTINGS_BUTTON_ID="settings-menu";const ALTERNATIVE_DISPLAY_ID="alternative-display";const NOT_DISPLAYED_ID="not-displayed";const HELP_BUTTON_ID="help-button";function getSettingsButton(){return document.getElementById(SETTINGS_BUTTON_ID)}function getHelpButton(){return document.getElementById(HELP_BUTTON_ID)}function getNakedUrl(){return window.location.href.split("?")[0].split("#")[0]}function insertAfter(newNode,referenceNode){referenceNode.parentNode.insertBefore(newNode,referenceNode.nextSibling)}function getOrCreateSection(id,classes){let el=document.getElementById(id);if(!el){el=document.createElement("section");el.id=id;el.className=classes;insertAfter(el,document.getElementById(MAIN_ID))}return el}function getAlternativeDisplayElem(){return getOrCreateSection(ALTERNATIVE_DISPLAY_ID,"content hidden")}function getNotDisplayedElem(){return getOrCreateSection(NOT_DISPLAYED_ID,"hidden")}function switchDisplayedElement(elemToDisplay){const el=getAlternativeDisplayElem();if(el.children.length>0){getNotDisplayedElem().appendChild(el.firstElementChild)}if(elemToDisplay===null){addClass(el,"hidden");showMain();return}el.appendChild(elemToDisplay);hideMain();removeClass(el,"hidden")}function browserSupportsHistoryApi(){return window.history&&typeof window.history.pushState==="function"}function preLoadCss(cssUrl){const link=document.createElement("link");link.href=cssUrl;link.rel="preload";link.as="style";document.getElementsByTagName("head")[0].appendChild(link)}(function(){const isHelpPage=window.location.pathname.endsWith("/help.html");function loadScript(url,errorCallback){const script=document.createElement("script");script.src=url;if(errorCallback!==undefined){script.onerror=errorCallback}document.head.append(script)}getSettingsButton().onclick=event=>{if(event.ctrlKey||event.altKey||event.metaKey){return}window.hideAllModals(false);addClass(getSettingsButton(),"rotate");event.preventDefault();loadScript(getVar("static-root-path")+getVar("settings-js"));setTimeout(()=>{const themes=getVar("themes").split(",");for(const theme of themes){if(theme!==""){preLoadCss(getVar("root-path")+theme+".css")}}},0)};window.searchState={loadingText:"Loading search results...",input:document.getElementsByClassName("search-input")[0],outputElement:()=>{let el=document.getElementById("search");if(!el){el=document.createElement("section");el.id="search";getNotDisplayedElem().appendChild(el)}return el},title:document.title,titleBeforeSearch:document.title,timeout:null,currentTab:0,focusedByTab:[null,null,null],clearInputTimeout:()=>{if(searchState.timeout!==null){clearTimeout(searchState.timeout);searchState.timeout=null}},isDisplayed:()=>searchState.outputElement().parentElement.id===ALTERNATIVE_DISPLAY_ID,focus:()=>{searchState.input.focus()},defocus:()=>{searchState.input.blur()},showResults:search=>{if(search===null||typeof search==="undefined"){search=searchState.outputElement()}switchDisplayedElement(search);searchState.mouseMovedAfterSearch=false;document.title=searchState.title},removeQueryParameters:()=>{document.title=searchState.titleBeforeSearch;if(browserSupportsHistoryApi()){history.replaceState(null,"",getNakedUrl()+window.location.hash)}},hideResults:()=>{switchDisplayedElement(null);searchState.removeQueryParameters()},getQueryStringParams:()=>{const params={};window.location.search.substring(1).split("&").map(s=>{const pair=s.split("=").map(x=>x.replace(/\+/g," "));params[decodeURIComponent(pair[0])]=typeof pair[1]==="undefined"?null:decodeURIComponent(pair[1])});return params},setup:()=>{const search_input=searchState.input;if(!searchState.input){return}let searchLoaded=false;function sendSearchForm(){document.getElementsByClassName("search-form")[0].submit()}function loadSearch(){if(!searchLoaded){searchLoaded=true;loadScript(getVar("static-root-path")+getVar("search-js"),sendSearchForm);loadScript(resourcePath("search-index",".js"),sendSearchForm)}}search_input.addEventListener("focus",()=>{search_input.origPlaceholder=search_input.placeholder;search_input.placeholder="Type your search here.";loadSearch()});if(search_input.value!==""){loadSearch()}const params=searchState.getQueryStringParams();if(params.search!==undefined){searchState.setLoadingSearch();loadSearch()}},setLoadingSearch:()=>{const search=searchState.outputElement();search.innerHTML="

"+searchState.loadingText+"

";searchState.showResults(search)},descShards:new Map(),loadDesc:async function({descShard,descIndex}){if(descShard.promise===null){descShard.promise=new Promise((resolve,reject)=>{descShard.resolve=resolve;const ds=descShard;const fname=`${ds.crate}-desc-${ds.shard}-`;const url=resourcePath(`search.desc/${descShard.crate}/${fname}`,".js",);loadScript(url,reject)})}const list=await descShard.promise;return list[descIndex]},loadedDescShard:function(crate,shard,data){this.descShards.get(crate)[shard].resolve(data.split("\n"))},};const toggleAllDocsId="toggle-all-docs";let savedHash="";function handleHashes(ev){if(ev!==null&&searchState.isDisplayed()&&ev.newURL){switchDisplayedElement(null);const hash=ev.newURL.slice(ev.newURL.indexOf("#")+1);if(browserSupportsHistoryApi()){history.replaceState(null,"",getNakedUrl()+window.location.search+"#"+hash)}const elem=document.getElementById(hash);if(elem){elem.scrollIntoView()}}const pageId=window.location.hash.replace(/^#/,"");if(savedHash!==pageId){savedHash=pageId;if(pageId!==""){expandSection(pageId)}}if(savedHash.startsWith("impl-")){const splitAt=savedHash.indexOf("/");if(splitAt!==-1){const implId=savedHash.slice(0,splitAt);const assocId=savedHash.slice(splitAt+1);const implElem=document.getElementById(implId);if(implElem&&implElem.parentElement.tagName==="SUMMARY"&&implElem.parentElement.parentElement.tagName==="DETAILS"){onEachLazy(implElem.parentElement.parentElement.querySelectorAll(`[id^="${assocId}"]`),item=>{const numbered=/([^-]+)-([0-9]+)/.exec(item.id);if(item.id===assocId||(numbered&&numbered[1]===assocId)){openParentDetails(item);item.scrollIntoView();setTimeout(()=>{window.location.replace("#"+item.id)},0)}},)}}}}function onHashChange(ev){hideSidebar();handleHashes(ev)}function openParentDetails(elem){while(elem){if(elem.tagName==="DETAILS"){elem.open=true}elem=elem.parentNode}}function expandSection(id){openParentDetails(document.getElementById(id))}function handleEscape(ev){searchState.clearInputTimeout();searchState.hideResults();ev.preventDefault();searchState.defocus();window.hideAllModals(true)}function handleShortcut(ev){const disableShortcuts=getSettingValue("disable-shortcuts")==="true";if(ev.ctrlKey||ev.altKey||ev.metaKey||disableShortcuts){return}if(document.activeElement.tagName==="INPUT"&&document.activeElement.type!=="checkbox"&&document.activeElement.type!=="radio"){switch(getVirtualKey(ev)){case"Escape":handleEscape(ev);break}}else{switch(getVirtualKey(ev)){case"Escape":handleEscape(ev);break;case"s":case"S":case"/":ev.preventDefault();searchState.focus();break;case"+":ev.preventDefault();expandAllDocs();break;case"-":ev.preventDefault();collapseAllDocs();break;case"?":showHelp();break;default:break}}}document.addEventListener("keypress",handleShortcut);document.addEventListener("keydown",handleShortcut);function addSidebarItems(){if(!window.SIDEBAR_ITEMS){return}const sidebar=document.getElementsByClassName("sidebar-elems")[0];function block(shortty,id,longty){const filtered=window.SIDEBAR_ITEMS[shortty];if(!filtered){return}const modpath=hasClass(document.querySelector(".rustdoc"),"mod")?"../":"";const h3=document.createElement("h3");h3.innerHTML=`${longty}`;const ul=document.createElement("ul");ul.className="block "+shortty;for(const name of filtered){let path;if(shortty==="mod"){path=`${modpath}${name}/index.html`}else{path=`${modpath}${shortty}.${name}.html`}let current_page=document.location.href.toString();if(current_page.endsWith("/")){current_page+="index.html"}const link=document.createElement("a");link.href=path;link.textContent=name;const li=document.createElement("li");if(link.href===current_page){li.classList.add("current")}li.appendChild(link);ul.appendChild(li)}sidebar.appendChild(h3);sidebar.appendChild(ul)}if(sidebar){block("primitive","primitives","Primitive Types");block("mod","modules","Modules");block("macro","macros","Macros");block("struct","structs","Structs");block("enum","enums","Enums");block("constant","constants","Constants");block("static","static","Statics");block("trait","traits","Traits");block("fn","functions","Functions");block("type","types","Type Aliases");block("union","unions","Unions");block("foreigntype","foreign-types","Foreign Types");block("keyword","keywords","Keywords");block("opaque","opaque-types","Opaque Types");block("attr","attributes","Attribute Macros");block("derive","derives","Derive Macros");block("traitalias","trait-aliases","Trait Aliases")}}window.register_implementors=imp=>{const implementors=document.getElementById("implementors-list");const synthetic_implementors=document.getElementById("synthetic-implementors-list");const inlined_types=new Set();const TEXT_IDX=0;const SYNTHETIC_IDX=1;const TYPES_IDX=2;if(synthetic_implementors){onEachLazy(synthetic_implementors.getElementsByClassName("impl"),el=>{const aliases=el.getAttribute("data-aliases");if(!aliases){return}aliases.split(",").forEach(alias=>{inlined_types.add(alias)})})}let currentNbImpls=implementors.getElementsByClassName("impl").length;const traitName=document.querySelector(".main-heading h1 > .trait").textContent;const baseIdName="impl-"+traitName+"-";const libs=Object.getOwnPropertyNames(imp);const script=document.querySelector("script[data-ignore-extern-crates]");const ignoreExternCrates=new Set((script?script.getAttribute("data-ignore-extern-crates"):"").split(","),);for(const lib of libs){if(lib===window.currentCrate||ignoreExternCrates.has(lib)){continue}const structs=imp[lib];struct_loop:for(const struct of structs){const list=struct[SYNTHETIC_IDX]?synthetic_implementors:implementors;if(struct[SYNTHETIC_IDX]){for(const struct_type of struct[TYPES_IDX]){if(inlined_types.has(struct_type)){continue struct_loop}inlined_types.add(struct_type)}}const code=document.createElement("h3");code.innerHTML=struct[TEXT_IDX];addClass(code,"code-header");onEachLazy(code.getElementsByTagName("a"),elem=>{const href=elem.getAttribute("href");if(href&&!href.startsWith("#")&&!/^(?:[a-z+]+:)?\/\//.test(href)){elem.setAttribute("href",window.rootPath+href)}});const currentId=baseIdName+currentNbImpls;const anchor=document.createElement("a");anchor.href="#"+currentId;addClass(anchor,"anchor");const display=document.createElement("div");display.id=currentId;addClass(display,"impl");display.appendChild(anchor);display.appendChild(code);list.appendChild(display);currentNbImpls+=1}}};if(window.pending_implementors){window.register_implementors(window.pending_implementors)}window.register_type_impls=imp=>{if(!imp||!imp[window.currentCrate]){return}window.pending_type_impls=null;const idMap=new Map();let implementations=document.getElementById("implementations-list");let trait_implementations=document.getElementById("trait-implementations-list");let trait_implementations_header=document.getElementById("trait-implementations");const script=document.querySelector("script[data-self-path]");const selfPath=script?script.getAttribute("data-self-path"):null;const mainContent=document.querySelector("#main-content");const sidebarSection=document.querySelector(".sidebar section");let methods=document.querySelector(".sidebar .block.method");let associatedTypes=document.querySelector(".sidebar .block.associatedtype");let associatedConstants=document.querySelector(".sidebar .block.associatedconstant");let sidebarTraitList=document.querySelector(".sidebar .block.trait-implementation");for(const impList of imp[window.currentCrate]){const types=impList.slice(2);const text=impList[0];const isTrait=impList[1]!==0;const traitName=impList[1];if(types.indexOf(selfPath)===-1){continue}let outputList=isTrait?trait_implementations:implementations;if(outputList===null){const outputListName=isTrait?"Trait Implementations":"Implementations";const outputListId=isTrait?"trait-implementations-list":"implementations-list";const outputListHeaderId=isTrait?"trait-implementations":"implementations";const outputListHeader=document.createElement("h2");outputListHeader.id=outputListHeaderId;outputListHeader.innerText=outputListName;outputList=document.createElement("div");outputList.id=outputListId;if(isTrait){const link=document.createElement("a");link.href=`#${outputListHeaderId}`;link.innerText="Trait Implementations";const h=document.createElement("h3");h.appendChild(link);trait_implementations=outputList;trait_implementations_header=outputListHeader;sidebarSection.appendChild(h);sidebarTraitList=document.createElement("ul");sidebarTraitList.className="block trait-implementation";sidebarSection.appendChild(sidebarTraitList);mainContent.appendChild(outputListHeader);mainContent.appendChild(outputList)}else{implementations=outputList;if(trait_implementations){mainContent.insertBefore(outputListHeader,trait_implementations_header);mainContent.insertBefore(outputList,trait_implementations_header)}else{const mainContent=document.querySelector("#main-content");mainContent.appendChild(outputListHeader);mainContent.appendChild(outputList)}}}const template=document.createElement("template");template.innerHTML=text;onEachLazy(template.content.querySelectorAll("a"),elem=>{const href=elem.getAttribute("href");if(href&&!href.startsWith("#")&&!/^(?:[a-z+]+:)?\/\//.test(href)){elem.setAttribute("href",window.rootPath+href)}});onEachLazy(template.content.querySelectorAll("[id]"),el=>{let i=0;if(idMap.has(el.id)){i=idMap.get(el.id)}else if(document.getElementById(el.id)){i=1;while(document.getElementById(`${el.id}-${2 * i}`)){i=2*i}while(document.getElementById(`${el.id}-${i}`)){i+=1}}if(i!==0){const oldHref=`#${el.id}`;const newHref=`#${el.id}-${i}`;el.id=`${el.id}-${i}`;onEachLazy(template.content.querySelectorAll("a[href]"),link=>{if(link.getAttribute("href")===oldHref){link.href=newHref}})}idMap.set(el.id,i+1)});const templateAssocItems=template.content.querySelectorAll("section.tymethod, "+"section.method, section.associatedtype, section.associatedconstant");if(isTrait){const li=document.createElement("li");const a=document.createElement("a");a.href=`#${template.content.querySelector(".impl").id}`;a.textContent=traitName;li.appendChild(a);sidebarTraitList.append(li)}else{onEachLazy(templateAssocItems,item=>{let block=hasClass(item,"associatedtype")?associatedTypes:(hasClass(item,"associatedconstant")?associatedConstants:(methods));if(!block){const blockTitle=hasClass(item,"associatedtype")?"Associated Types":(hasClass(item,"associatedconstant")?"Associated Constants":("Methods"));const blockClass=hasClass(item,"associatedtype")?"associatedtype":(hasClass(item,"associatedconstant")?"associatedconstant":("method"));const blockHeader=document.createElement("h3");const blockLink=document.createElement("a");blockLink.href="#implementations";blockLink.innerText=blockTitle;blockHeader.appendChild(blockLink);block=document.createElement("ul");block.className=`block ${blockClass}`;const insertionReference=methods||sidebarTraitList;if(insertionReference){const insertionReferenceH=insertionReference.previousElementSibling;sidebarSection.insertBefore(blockHeader,insertionReferenceH);sidebarSection.insertBefore(block,insertionReferenceH)}else{sidebarSection.appendChild(blockHeader);sidebarSection.appendChild(block)}if(hasClass(item,"associatedtype")){associatedTypes=block}else if(hasClass(item,"associatedconstant")){associatedConstants=block}else{methods=block}}const li=document.createElement("li");const a=document.createElement("a");a.innerText=item.id.split("-")[0].split(".")[1];a.href=`#${item.id}`;li.appendChild(a);block.appendChild(li)})}outputList.appendChild(template.content)}for(const list of[methods,associatedTypes,associatedConstants,sidebarTraitList]){if(!list){continue}const newChildren=Array.prototype.slice.call(list.children);newChildren.sort((a,b)=>{const aI=a.innerText;const bI=b.innerText;return aIbI?1:0});list.replaceChildren(...newChildren)}};if(window.pending_type_impls){window.register_type_impls(window.pending_type_impls)}function addSidebarCrates(){if(!window.ALL_CRATES){return}const sidebarElems=document.getElementsByClassName("sidebar-elems")[0];if(!sidebarElems){return}const h3=document.createElement("h3");h3.innerHTML="Crates";const ul=document.createElement("ul");ul.className="block crate";for(const crate of window.ALL_CRATES){const link=document.createElement("a");link.href=window.rootPath+crate+"/index.html";link.textContent=crate;const li=document.createElement("li");if(window.rootPath!=="./"&&crate===window.currentCrate){li.className="current"}li.appendChild(link);ul.appendChild(li)}sidebarElems.appendChild(h3);sidebarElems.appendChild(ul)}function expandAllDocs(){const innerToggle=document.getElementById(toggleAllDocsId);removeClass(innerToggle,"will-expand");onEachLazy(document.getElementsByClassName("toggle"),e=>{if(!hasClass(e,"type-contents-toggle")&&!hasClass(e,"more-examples-toggle")){e.open=true}});innerToggle.title="collapse all docs";innerToggle.children[0].innerText="\u2212"}function collapseAllDocs(){const innerToggle=document.getElementById(toggleAllDocsId);addClass(innerToggle,"will-expand");onEachLazy(document.getElementsByClassName("toggle"),e=>{if(e.parentNode.id!=="implementations-list"||(!hasClass(e,"implementors-toggle")&&!hasClass(e,"type-contents-toggle"))){e.open=false}});innerToggle.title="expand all docs";innerToggle.children[0].innerText="+"}function toggleAllDocs(){const innerToggle=document.getElementById(toggleAllDocsId);if(!innerToggle){return}if(hasClass(innerToggle,"will-expand")){expandAllDocs()}else{collapseAllDocs()}}(function(){const toggles=document.getElementById(toggleAllDocsId);if(toggles){toggles.onclick=toggleAllDocs}const hideMethodDocs=getSettingValue("auto-hide-method-docs")==="true";const hideImplementations=getSettingValue("auto-hide-trait-implementations")==="true";const hideLargeItemContents=getSettingValue("auto-hide-large-items")!=="false";function setImplementorsTogglesOpen(id,open){const list=document.getElementById(id);if(list!==null){onEachLazy(list.getElementsByClassName("implementors-toggle"),e=>{e.open=open})}}if(hideImplementations){setImplementorsTogglesOpen("trait-implementations-list",false);setImplementorsTogglesOpen("blanket-implementations-list",false)}onEachLazy(document.getElementsByClassName("toggle"),e=>{if(!hideLargeItemContents&&hasClass(e,"type-contents-toggle")){e.open=true}if(hideMethodDocs&&hasClass(e,"method-toggle")){e.open=false}})}());window.rustdoc_add_line_numbers_to_examples=()=>{onEachLazy(document.getElementsByClassName("rust-example-rendered"),x=>{const parent=x.parentNode;const line_numbers=parent.querySelectorAll(".example-line-numbers");if(line_numbers.length>0){return}const count=x.textContent.split("\n").length;const elems=[];for(let i=0;i{onEachLazy(document.getElementsByClassName("rust-example-rendered"),x=>{const parent=x.parentNode;const line_numbers=parent.querySelectorAll(".example-line-numbers");for(const node of line_numbers){parent.removeChild(node)}})};if(getSettingValue("line-numbers")==="true"){window.rustdoc_add_line_numbers_to_examples()}function showSidebar(){window.hideAllModals(false);const sidebar=document.getElementsByClassName("sidebar")[0];addClass(sidebar,"shown")}function hideSidebar(){const sidebar=document.getElementsByClassName("sidebar")[0];removeClass(sidebar,"shown")}window.addEventListener("resize",()=>{if(window.CURRENT_TOOLTIP_ELEMENT){const base=window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE;const force_visible=base.TOOLTIP_FORCE_VISIBLE;hideTooltip(false);if(force_visible){showTooltip(base);base.TOOLTIP_FORCE_VISIBLE=true}}});const mainElem=document.getElementById(MAIN_ID);if(mainElem){mainElem.addEventListener("click",hideSidebar)}onEachLazy(document.querySelectorAll("a[href^='#']"),el=>{el.addEventListener("click",()=>{expandSection(el.hash.slice(1));hideSidebar()})});onEachLazy(document.querySelectorAll(".toggle > summary:not(.hideme)"),el=>{el.addEventListener("click",e=>{if(e.target.tagName!=="SUMMARY"&&e.target.tagName!=="A"){e.preventDefault()}})});function showTooltip(e){const notable_ty=e.getAttribute("data-notable-ty");if(!window.NOTABLE_TRAITS&¬able_ty){const data=document.getElementById("notable-traits-data");if(data){window.NOTABLE_TRAITS=JSON.parse(data.innerText)}else{throw new Error("showTooltip() called with notable without any notable traits!")}}if(window.CURRENT_TOOLTIP_ELEMENT&&window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE===e){clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);return}window.hideAllModals(false);const wrapper=document.createElement("div");if(notable_ty){wrapper.innerHTML="
"+window.NOTABLE_TRAITS[notable_ty]+"
"}else{if(e.getAttribute("title")!==null){e.setAttribute("data-title",e.getAttribute("title"));e.removeAttribute("title")}if(e.getAttribute("data-title")!==null){const titleContent=document.createElement("div");titleContent.className="content";titleContent.appendChild(document.createTextNode(e.getAttribute("data-title")));wrapper.appendChild(titleContent)}}wrapper.className="tooltip popover";const focusCatcher=document.createElement("div");focusCatcher.setAttribute("tabindex","0");focusCatcher.onfocus=hideTooltip;wrapper.appendChild(focusCatcher);const pos=e.getBoundingClientRect();wrapper.style.top=(pos.top+window.scrollY+pos.height)+"px";wrapper.style.left=0;wrapper.style.right="auto";wrapper.style.visibility="hidden";const body=document.getElementsByTagName("body")[0];body.appendChild(wrapper);const wrapperPos=wrapper.getBoundingClientRect();const finalPos=pos.left+window.scrollX-wrapperPos.width+24;if(finalPos>0){wrapper.style.left=finalPos+"px"}else{wrapper.style.setProperty("--popover-arrow-offset",(wrapperPos.right-pos.right+4)+"px",)}wrapper.style.visibility="";window.CURRENT_TOOLTIP_ELEMENT=wrapper;window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE=e;clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);wrapper.onpointerenter=ev=>{if(ev.pointerType!=="mouse"){return}clearTooltipHoverTimeout(e)};wrapper.onpointerleave=ev=>{if(ev.pointerType!=="mouse"){return}if(!e.TOOLTIP_FORCE_VISIBLE&&!e.contains(ev.relatedTarget)){setTooltipHoverTimeout(e,false);addClass(wrapper,"fade-out")}}}function setTooltipHoverTimeout(element,show){clearTooltipHoverTimeout(element);if(!show&&!window.CURRENT_TOOLTIP_ELEMENT){return}if(show&&window.CURRENT_TOOLTIP_ELEMENT){return}if(window.CURRENT_TOOLTIP_ELEMENT&&window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE!==element){return}element.TOOLTIP_HOVER_TIMEOUT=setTimeout(()=>{if(show){showTooltip(element)}else if(!element.TOOLTIP_FORCE_VISIBLE){hideTooltip(false)}},show?window.RUSTDOC_TOOLTIP_HOVER_MS:window.RUSTDOC_TOOLTIP_HOVER_EXIT_MS)}function clearTooltipHoverTimeout(element){if(element.TOOLTIP_HOVER_TIMEOUT!==undefined){removeClass(window.CURRENT_TOOLTIP_ELEMENT,"fade-out");clearTimeout(element.TOOLTIP_HOVER_TIMEOUT);delete element.TOOLTIP_HOVER_TIMEOUT}}function tooltipBlurHandler(event){if(window.CURRENT_TOOLTIP_ELEMENT&&!window.CURRENT_TOOLTIP_ELEMENT.contains(document.activeElement)&&!window.CURRENT_TOOLTIP_ELEMENT.contains(event.relatedTarget)&&!window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.contains(document.activeElement)&&!window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.contains(event.relatedTarget)){setTimeout(()=>hideTooltip(false),0)}}function hideTooltip(focus){if(window.CURRENT_TOOLTIP_ELEMENT){if(window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE){if(focus){window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.focus()}window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE=false}const body=document.getElementsByTagName("body")[0];body.removeChild(window.CURRENT_TOOLTIP_ELEMENT);clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);window.CURRENT_TOOLTIP_ELEMENT=null}}onEachLazy(document.getElementsByClassName("tooltip"),e=>{e.onclick=()=>{e.TOOLTIP_FORCE_VISIBLE=e.TOOLTIP_FORCE_VISIBLE?false:true;if(window.CURRENT_TOOLTIP_ELEMENT&&!e.TOOLTIP_FORCE_VISIBLE){hideTooltip(true)}else{showTooltip(e);window.CURRENT_TOOLTIP_ELEMENT.setAttribute("tabindex","0");window.CURRENT_TOOLTIP_ELEMENT.focus();window.CURRENT_TOOLTIP_ELEMENT.onblur=tooltipBlurHandler}return false};e.onpointerenter=ev=>{if(ev.pointerType!=="mouse"){return}setTooltipHoverTimeout(e,true)};e.onpointermove=ev=>{if(ev.pointerType!=="mouse"){return}setTooltipHoverTimeout(e,true)};e.onpointerleave=ev=>{if(ev.pointerType!=="mouse"){return}if(!e.TOOLTIP_FORCE_VISIBLE&&window.CURRENT_TOOLTIP_ELEMENT&&!window.CURRENT_TOOLTIP_ELEMENT.contains(ev.relatedTarget)){setTooltipHoverTimeout(e,false);addClass(window.CURRENT_TOOLTIP_ELEMENT,"fade-out")}}});const sidebar_menu_toggle=document.getElementsByClassName("sidebar-menu-toggle")[0];if(sidebar_menu_toggle){sidebar_menu_toggle.addEventListener("click",()=>{const sidebar=document.getElementsByClassName("sidebar")[0];if(!hasClass(sidebar,"shown")){showSidebar()}else{hideSidebar()}})}function helpBlurHandler(event){blurHandler(event,getHelpButton(),window.hidePopoverMenus)}function buildHelpMenu(){const book_info=document.createElement("span");const channel=getVar("channel");book_info.className="top";book_info.innerHTML=`You can find more information in \ +the rustdoc book.`;const shortcuts=[["?","Show this help dialog"],["S / /","Focus the search field"],["↑","Move up in search results"],["↓","Move down in search results"],["← / →","Switch result tab (when results focused)"],["⏎","Go to active search result"],["+","Expand all sections"],["-","Collapse all sections"],].map(x=>"
"+x[0].split(" ").map((y,index)=>((index&1)===0?""+y+"":" "+y+" ")).join("")+"
"+x[1]+"
").join("");const div_shortcuts=document.createElement("div");addClass(div_shortcuts,"shortcuts");div_shortcuts.innerHTML="

Keyboard Shortcuts

"+shortcuts+"
";const infos=[`For a full list of all search features, take a look here.`,"Prefix searches with a type followed by a colon (e.g., fn:) to \ + restrict the search to a given item kind.","Accepted kinds are: fn, mod, struct, \ + enum, trait, type, macro, \ + and const.","Search functions by type signature (e.g., vec -> usize or \ + -> vec or String, enum:Cow -> bool)","You can look for items with an exact name by putting double quotes around \ + your request: \"string\"","Look for functions that accept or return \ + slices and \ + arrays by writing \ + square brackets (e.g., -> [u8] or [] -> Option)","Look for items inside another one by searching for a path: vec::Vec",].map(x=>"

"+x+"

").join("");const div_infos=document.createElement("div");addClass(div_infos,"infos");div_infos.innerHTML="

Search Tricks

"+infos;const rustdoc_version=document.createElement("span");rustdoc_version.className="bottom";const rustdoc_version_code=document.createElement("code");rustdoc_version_code.innerText="rustdoc "+getVar("rustdoc-version");rustdoc_version.appendChild(rustdoc_version_code);const container=document.createElement("div");if(!isHelpPage){container.className="popover"}container.id="help";container.style.display="none";const side_by_side=document.createElement("div");side_by_side.className="side-by-side";side_by_side.appendChild(div_shortcuts);side_by_side.appendChild(div_infos);container.appendChild(book_info);container.appendChild(side_by_side);container.appendChild(rustdoc_version);if(isHelpPage){const help_section=document.createElement("section");help_section.appendChild(container);document.getElementById("main-content").appendChild(help_section);container.style.display="block"}else{const help_button=getHelpButton();help_button.appendChild(container);container.onblur=helpBlurHandler;help_button.onblur=helpBlurHandler;help_button.children[0].onblur=helpBlurHandler}return container}window.hideAllModals=switchFocus=>{hideSidebar();window.hidePopoverMenus();hideTooltip(switchFocus)};window.hidePopoverMenus=()=>{onEachLazy(document.querySelectorAll(".search-form .popover"),elem=>{elem.style.display="none"})};function getHelpMenu(buildNeeded){let menu=getHelpButton().querySelector(".popover");if(!menu&&buildNeeded){menu=buildHelpMenu()}return menu}function showHelp(){getHelpButton().querySelector("a").focus();const menu=getHelpMenu(true);if(menu.style.display==="none"){window.hideAllModals();menu.style.display=""}}if(isHelpPage){showHelp();document.querySelector(`#${HELP_BUTTON_ID} > a`).addEventListener("click",event=>{const target=event.target;if(target.tagName!=="A"||target.parentElement.id!==HELP_BUTTON_ID||event.ctrlKey||event.altKey||event.metaKey){return}event.preventDefault()})}else{document.querySelector(`#${HELP_BUTTON_ID} > a`).addEventListener("click",event=>{const target=event.target;if(target.tagName!=="A"||target.parentElement.id!==HELP_BUTTON_ID||event.ctrlKey||event.altKey||event.metaKey){return}event.preventDefault();const menu=getHelpMenu(true);const shouldShowHelp=menu.style.display==="none";if(shouldShowHelp){showHelp()}else{window.hidePopoverMenus()}})}setMobileTopbar();addSidebarItems();addSidebarCrates();onHashChange(null);window.addEventListener("hashchange",onHashChange);searchState.setup()}());(function(){const SIDEBAR_MIN=100;const SIDEBAR_MAX=500;const RUSTDOC_MOBILE_BREAKPOINT=700;const BODY_MIN=400;const SIDEBAR_VANISH_THRESHOLD=SIDEBAR_MIN/2;const sidebarButton=document.getElementById("sidebar-button");if(sidebarButton){sidebarButton.addEventListener("click",e=>{removeClass(document.documentElement,"hide-sidebar");updateLocalStorage("hide-sidebar","false");if(document.querySelector(".rustdoc.src")){window.rustdocToggleSrcSidebar()}e.preventDefault()})}let currentPointerId=null;let desiredSidebarSize=null;let pendingSidebarResizingFrame=false;const resizer=document.querySelector(".sidebar-resizer");const sidebar=document.querySelector(".sidebar");if(!resizer||!sidebar){return}const isSrcPage=hasClass(document.body,"src");function hideSidebar(){if(isSrcPage){window.rustdocCloseSourceSidebar();updateLocalStorage("src-sidebar-width",null);document.documentElement.style.removeProperty("--src-sidebar-width");sidebar.style.removeProperty("--src-sidebar-width");resizer.style.removeProperty("--src-sidebar-width")}else{addClass(document.documentElement,"hide-sidebar");updateLocalStorage("hide-sidebar","true");updateLocalStorage("desktop-sidebar-width",null);document.documentElement.style.removeProperty("--desktop-sidebar-width");sidebar.style.removeProperty("--desktop-sidebar-width");resizer.style.removeProperty("--desktop-sidebar-width")}}function showSidebar(){if(isSrcPage){window.rustdocShowSourceSidebar()}else{removeClass(document.documentElement,"hide-sidebar");updateLocalStorage("hide-sidebar","false")}}function changeSidebarSize(size){if(isSrcPage){updateLocalStorage("src-sidebar-width",size);sidebar.style.setProperty("--src-sidebar-width",size+"px");resizer.style.setProperty("--src-sidebar-width",size+"px")}else{updateLocalStorage("desktop-sidebar-width",size);sidebar.style.setProperty("--desktop-sidebar-width",size+"px");resizer.style.setProperty("--desktop-sidebar-width",size+"px")}}function isSidebarHidden(){return isSrcPage?!hasClass(document.documentElement,"src-sidebar-expanded"):hasClass(document.documentElement,"hide-sidebar")}function resize(e){if(currentPointerId===null||currentPointerId!==e.pointerId){return}e.preventDefault();const pos=e.clientX-3;if(pos=SIDEBAR_MIN){if(isSidebarHidden()){showSidebar()}const constrainedPos=Math.min(pos,window.innerWidth-BODY_MIN,SIDEBAR_MAX);changeSidebarSize(constrainedPos);desiredSidebarSize=constrainedPos;if(pendingSidebarResizingFrame!==false){clearTimeout(pendingSidebarResizingFrame)}pendingSidebarResizingFrame=setTimeout(()=>{if(currentPointerId===null||pendingSidebarResizingFrame===false){return}pendingSidebarResizingFrame=false;document.documentElement.style.setProperty("--resizing-sidebar-width",desiredSidebarSize+"px",)},100)}}window.addEventListener("resize",()=>{if(window.innerWidth=(window.innerWidth-BODY_MIN)){changeSidebarSize(window.innerWidth-BODY_MIN)}else if(desiredSidebarSize!==null&&desiredSidebarSize>SIDEBAR_MIN){changeSidebarSize(desiredSidebarSize)}});function stopResize(e){if(currentPointerId===null){return}if(e){e.preventDefault()}desiredSidebarSize=sidebar.getBoundingClientRect().width;removeClass(resizer,"active");window.removeEventListener("pointermove",resize,false);window.removeEventListener("pointerup",stopResize,false);removeClass(document.documentElement,"sidebar-resizing");document.documentElement.style.removeProperty("--resizing-sidebar-width");if(resizer.releasePointerCapture){resizer.releasePointerCapture(currentPointerId);currentPointerId=null}}function initResize(e){if(currentPointerId!==null||e.altKey||e.ctrlKey||e.metaKey||e.button!==0){return}if(resizer.setPointerCapture){resizer.setPointerCapture(e.pointerId);if(!resizer.hasPointerCapture(e.pointerId)){resizer.releasePointerCapture(e.pointerId);return}currentPointerId=e.pointerId}window.hideAllModals(false);e.preventDefault();window.addEventListener("pointermove",resize,false);window.addEventListener("pointercancel",stopResize,false);window.addEventListener("pointerup",stopResize,false);addClass(resizer,"active");addClass(document.documentElement,"sidebar-resizing");const pos=e.clientX-sidebar.offsetLeft-3;document.documentElement.style.setProperty("--resizing-sidebar-width",pos+"px");desiredSidebarSize=null}resizer.addEventListener("pointerdown",initResize,false)}());(function(){let reset_button_timeout=null;const but=document.getElementById("copy-path");if(!but){return}but.onclick=()=>{const parent=but.parentElement;const path=[];onEach(parent.childNodes,child=>{if(child.tagName==="A"){path.push(child.textContent)}});const el=document.createElement("textarea");el.value=path.join("::");el.setAttribute("readonly","");el.style.position="absolute";el.style.left="-9999px";document.body.appendChild(el);el.select();document.execCommand("copy");document.body.removeChild(el);but.classList.add("clicked");if(reset_button_timeout!==null){window.clearTimeout(reset_button_timeout)}function reset_button(){reset_button_timeout=null;but.classList.remove("clicked")}reset_button_timeout=window.setTimeout(reset_button,1000)}}()) \ No newline at end of file diff --git a/static.files/normalize-76eba96aa4d2e634.css b/static.files/normalize-76eba96aa4d2e634.css new file mode 100644 index 0000000..469959f --- /dev/null +++ b/static.files/normalize-76eba96aa4d2e634.css @@ -0,0 +1,2 @@ + /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ +html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:0.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type="button"],[type="reset"],[type="submit"],button{-webkit-appearance:button}[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:0.35em 0.75em 0.625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type="checkbox"],[type="radio"]{box-sizing:border-box;padding:0}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto}[type="search"]{-webkit-appearance:textfield;outline-offset:-2px}[type="search"]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none} \ No newline at end of file diff --git a/static.files/noscript-df360f571f6edeae.css b/static.files/noscript-df360f571f6edeae.css new file mode 100644 index 0000000..4c310ae --- /dev/null +++ b/static.files/noscript-df360f571f6edeae.css @@ -0,0 +1 @@ + #main-content .attributes{margin-left:0 !important;}#copy-path,#sidebar-button,.sidebar-resizer{display:none !important;}nav.sub{display:none;}.src .sidebar{display:none;}.notable-traits{display:none;}:root,:root:not([data-theme]){--main-background-color:white;--main-color:black;--settings-input-color:#2196f3;--settings-input-border-color:#717171;--settings-button-color:#000;--settings-button-border-focus:#717171;--sidebar-background-color:#f5f5f5;--sidebar-background-color-hover:#e0e0e0;--code-block-background-color:#f5f5f5;--scrollbar-track-background-color:#dcdcdc;--scrollbar-thumb-background-color:rgba(36,37,39,0.6);--scrollbar-color:rgba(36,37,39,0.6) #d9d9d9;--headings-border-bottom-color:#ddd;--border-color:#e0e0e0;--button-background-color:#fff;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:none;--mobile-sidebar-menu-filter:none;--search-input-focused-border-color:#66afe9;--copy-path-button-color:#999;--copy-path-img-filter:invert(50%);--copy-path-img-hover-filter:invert(35%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#ad378a;--trait-link-color:#6e4fc9;--assoc-item-link-color:#3873ad;--function-link-color:#ad7c37;--macro-link-color:#068000;--keyword-link-color:#3873ad;--mod-link-color:#3873ad;--link-color:#3873ad;--sidebar-link-color:#356da4;--sidebar-current-link-background-color:#fff;--search-result-link-focus-background-color:#ccc;--search-result-border-color:#aaa3;--search-color:#000;--search-error-code-background-color:#d0cccc;--search-results-alias-color:#000;--search-results-grey-color:#999;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:#e6e6e6;--search-tab-button-not-selected-background:#e6e6e6;--search-tab-button-selected-border-top-color:#0089ff;--search-tab-button-selected-background:#fff;--settings-menu-filter:none;--stab-background-color:#fff5d6;--stab-code-color:#000;--code-highlight-kw-color:#8959a8;--code-highlight-kw-2-color:#4271ae;--code-highlight-lifetime-color:#b76514;--code-highlight-prelude-color:#4271ae;--code-highlight-prelude-val-color:#c82829;--code-highlight-number-color:#718c00;--code-highlight-string-color:#718c00;--code-highlight-literal-color:#c82829;--code-highlight-attribute-color:#c82829;--code-highlight-self-color:#c82829;--code-highlight-macro-color:#3e999f;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#8e908c;--code-highlight-doc-comment-color:#4d4d4c;--src-line-numbers-span-color:#c67e2d;--src-line-number-highlighted-background-color:#fdffd3;--test-arrow-color:#f5f5f5;--test-arrow-background-color:rgba(78,139,202,0.2);--test-arrow-hover-color:#f5f5f5;--test-arrow-hover-background-color:rgb(78,139,202);--target-background-color:#fdffd3;--target-border-color:#ad7c37;--kbd-color:#000;--kbd-background:#fafbfc;--kbd-box-shadow-color:#c6cbd1;--rust-logo-filter:initial;--crate-search-div-filter:invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) brightness(114%) contrast(76%);--crate-search-div-hover-filter:invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%);--crate-search-hover-border:#717171;--src-sidebar-background-selected:#fff;--src-sidebar-background-hover:#e0e0e0;--table-alt-row-background-color:#f5f5f5;--codeblock-link-background:#eee;--scrape-example-toggle-line-background:#ccc;--scrape-example-toggle-line-hover-background:#999;--scrape-example-code-line-highlight:#fcffd6;--scrape-example-code-line-highlight-focus:#f6fdb0;--scrape-example-help-border-color:#555;--scrape-example-help-color:#333;--scrape-example-help-hover-border-color:#000;--scrape-example-help-hover-color:#000;--scrape-example-code-wrapper-background-start:rgba(255,255,255,1);--scrape-example-code-wrapper-background-end:rgba(255,255,255,0);--sidebar-resizer-hover:hsl(207,90%,66%);--sidebar-resizer-active:hsl(207,90%,54%);}@media (prefers-color-scheme:dark){:root,:root:not([data-theme]){--main-background-color:#353535;--main-color:#ddd;--settings-input-color:#2196f3;--settings-input-border-color:#999;--settings-button-color:#000;--settings-button-border-focus:#ffb900;--sidebar-background-color:#505050;--sidebar-background-color-hover:#676767;--code-block-background-color:#2A2A2A;--scrollbar-track-background-color:#717171;--scrollbar-thumb-background-color:rgba(32,34,37,.6);--scrollbar-color:rgba(32,34,37,.6) #5a5a5a;--headings-border-bottom-color:#d2d2d2;--border-color:#e0e0e0;--button-background-color:#f0f0f0;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:invert(100%);--mobile-sidebar-menu-filter:invert(100%);--search-input-focused-border-color:#008dfd;--copy-path-button-color:#999;--copy-path-img-filter:invert(50%);--copy-path-img-hover-filter:invert(65%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#2dbfb8;--trait-link-color:#b78cf2;--assoc-item-link-color:#d2991d;--function-link-color:#2bab63;--macro-link-color:#09bd00;--keyword-link-color:#d2991d;--mod-link-color:#d2991d;--link-color:#d2991d;--sidebar-link-color:#fdbf35;--sidebar-current-link-background-color:#444;--search-result-link-focus-background-color:#616161;--search-result-border-color:#aaa3;--search-color:#111;--search-error-code-background-color:#484848;--search-results-alias-color:#fff;--search-results-grey-color:#ccc;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:#252525;--search-tab-button-not-selected-background:#252525;--search-tab-button-selected-border-top-color:#0089ff;--search-tab-button-selected-background:#353535;--stab-background-color:#314559;--stab-code-color:#e6e1cf;--code-highlight-kw-color:#ab8ac1;--code-highlight-kw-2-color:#769acb;--code-highlight-lifetime-color:#d97f26;--code-highlight-prelude-color:#769acb;--code-highlight-prelude-val-color:#ee6868;--code-highlight-number-color:#83a300;--code-highlight-string-color:#83a300;--code-highlight-literal-color:#ee6868;--code-highlight-attribute-color:#ee6868;--code-highlight-self-color:#ee6868;--code-highlight-macro-color:#3e999f;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#8d8d8b;--code-highlight-doc-comment-color:#8ca375;--src-line-numbers-span-color:#3b91e2;--src-line-number-highlighted-background-color:#0a042f;--test-arrow-color:#dedede;--test-arrow-background-color:rgba(78,139,202,0.2);--test-arrow-hover-color:#dedede;--test-arrow-hover-background-color:#4e8bca;--target-background-color:#494a3d;--target-border-color:#bb7410;--kbd-color:#000;--kbd-background:#fafbfc;--kbd-box-shadow-color:#c6cbd1;--rust-logo-filter:drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 -1px 0 #fff);--crate-search-div-filter:invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg) brightness(90%) contrast(90%);--crate-search-div-hover-filter:invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%);--crate-search-hover-border:#2196f3;--src-sidebar-background-selected:#333;--src-sidebar-background-hover:#444;--table-alt-row-background-color:#2a2a2a;--codeblock-link-background:#333;--scrape-example-toggle-line-background:#999;--scrape-example-toggle-line-hover-background:#c5c5c5;--scrape-example-code-line-highlight:#5b3b01;--scrape-example-code-line-highlight-focus:#7c4b0f;--scrape-example-help-border-color:#aaa;--scrape-example-help-color:#eee;--scrape-example-help-hover-border-color:#fff;--scrape-example-help-hover-color:#fff;--scrape-example-code-wrapper-background-start:rgba(53,53,53,1);--scrape-example-code-wrapper-background-end:rgba(53,53,53,0);--sidebar-resizer-hover:hsl(207,30%,54%);--sidebar-resizer-active:hsl(207,90%,54%);}} \ No newline at end of file diff --git a/static.files/rust-logo-151179464ae7ed46.svg b/static.files/rust-logo-151179464ae7ed46.svg new file mode 100644 index 0000000..62424d8 --- /dev/null +++ b/static.files/rust-logo-151179464ae7ed46.svg @@ -0,0 +1,61 @@ + + + diff --git a/static.files/rustdoc-c5d6553a23f1e5a6.css b/static.files/rustdoc-c5d6553a23f1e5a6.css new file mode 100644 index 0000000..9f64990 --- /dev/null +++ b/static.files/rustdoc-c5d6553a23f1e5a6.css @@ -0,0 +1,46 @@ + :root{--nav-sub-mobile-padding:8px;--search-typename-width:6.75rem;--desktop-sidebar-width:200px;--src-sidebar-width:300px;--desktop-sidebar-z-index:100;--sidebar-elems-left-padding:24px;}@font-face {font-family:'Fira Sans';font-style:normal;font-weight:400;src:local('Fira Sans'),url("FiraSans-Regular-018c141bf0843ffd.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Fira Sans';font-style:normal;font-weight:500;src:local('Fira Sans Medium'),url("FiraSans-Medium-8f9a781e4970d388.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:normal;font-weight:400;src:local('Source Serif 4'),url("SourceSerif4-Regular-46f98efaafac5295.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:italic;font-weight:400;src:local('Source Serif 4 Italic'),url("SourceSerif4-It-acdfaf1a8af734b1.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:normal;font-weight:700;src:local('Source Serif 4 Bold'),url("SourceSerif4-Bold-a2c9cd1067f8b328.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:normal;font-weight:400;src:url("SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:italic;font-weight:400;src:url("SourceCodePro-It-1cc31594bf4f1f79.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:normal;font-weight:600;src:url("SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'NanumBarunGothic';src:url("NanumBarunGothic-0f09457c7a19b7c6.ttf.woff2") format("woff2");font-display:swap;unicode-range:U+AC00-D7AF,U+1100-11FF,U+3130-318F,U+A960-A97F,U+D7B0-D7FF;}*{box-sizing:border-box;}body{font:1rem/1.5 "Source Serif 4",NanumBarunGothic,serif;margin:0;position:relative;overflow-wrap:break-word;overflow-wrap:anywhere;font-feature-settings:"kern","liga";background-color:var(--main-background-color);color:var(--main-color);}h1{font-size:1.5rem;}h2{font-size:1.375rem;}h3{font-size:1.25rem;}h1,h2,h3,h4,h5,h6{font-weight:500;}h1,h2,h3,h4{margin:25px 0 15px 0;padding-bottom:6px;}.docblock h3,.docblock h4,h5,h6{margin:15px 0 5px 0;}.docblock>h2:first-child,.docblock>h3:first-child,.docblock>h4:first-child,.docblock>h5:first-child,.docblock>h6:first-child{margin-top:0;}.main-heading h1{margin:0;padding:0;flex-grow:1;overflow-wrap:break-word;overflow-wrap:anywhere;}.main-heading{display:flex;flex-wrap:wrap;padding-bottom:6px;margin-bottom:15px;}.content h2,.top-doc .docblock>h3,.top-doc .docblock>h4{border-bottom:1px solid var(--headings-border-bottom-color);}h1,h2{line-height:1.25;padding-top:3px;padding-bottom:9px;}h3.code-header{font-size:1.125rem;}h4.code-header{font-size:1rem;}.code-header{font-weight:600;margin:0;padding:0;white-space:pre-wrap;}#crate-search,h1,h2,h3,h4,h5,h6,.sidebar,.mobile-topbar,.search-input,.search-results .result-name,.item-name>a,.out-of-band,span.since,a.src,#help-button>a,summary.hideme,.scraped-example-list,ul.all-items{font-family:"Fira Sans",Arial,NanumBarunGothic,sans-serif;}#toggle-all-docs,a.anchor,.section-header a,#src-sidebar a,.rust a,.sidebar h2 a,.sidebar h3 a,.mobile-topbar h2 a,h1 a,.search-results a,.stab,.result-name i{color:var(--main-color);}span.enum,a.enum,span.struct,a.struct,span.union,a.union,span.primitive,a.primitive,span.type,a.type,span.foreigntype,a.foreigntype{color:var(--type-link-color);}span.trait,a.trait,span.traitalias,a.traitalias{color:var(--trait-link-color);}span.associatedtype,a.associatedtype,span.constant,a.constant,span.static,a.static{color:var(--assoc-item-link-color);}span.fn,a.fn,span.method,a.method,span.tymethod,a.tymethod{color:var(--function-link-color);}span.attr,a.attr,span.derive,a.derive,span.macro,a.macro{color:var(--macro-link-color);}span.mod,a.mod{color:var(--mod-link-color);}span.keyword,a.keyword{color:var(--keyword-link-color);}a{color:var(--link-color);text-decoration:none;}ol,ul{padding-left:24px;}ul ul,ol ul,ul ol,ol ol{margin-bottom:.625em;}p,.docblock>.warning{margin:0 0 .75em 0;}p:last-child,.docblock>.warning:last-child{margin:0;}button{padding:1px 6px;cursor:pointer;}button#toggle-all-docs{padding:0;background:none;border:none;-webkit-appearance:none;opacity:1;}.rustdoc{display:flex;flex-direction:row;flex-wrap:nowrap;}main{position:relative;flex-grow:1;padding:10px 15px 40px 45px;min-width:0;}.src main{padding:15px;}.width-limiter{max-width:960px;margin-right:auto;}details:not(.toggle) summary{margin-bottom:.6em;}code,pre,a.test-arrow,.code-header{font-family:"Source Code Pro",monospace;}.docblock code,.docblock-short code{border-radius:3px;padding:0 0.125em;}.docblock pre code,.docblock-short pre code{padding:0;}pre{padding:14px;line-height:1.5;}pre.item-decl{overflow-x:auto;}.item-decl .type-contents-toggle{contain:initial;}.src .content pre{padding:20px;}.rustdoc.src .example-wrap pre.src-line-numbers{padding:20px 0 20px 4px;}img{max-width:100%;}.logo-container{line-height:0;display:block;}.rust-logo{filter:var(--rust-logo-filter);}.sidebar{font-size:0.875rem;flex:0 0 var(--desktop-sidebar-width);width:var(--desktop-sidebar-width);overflow-y:scroll;overscroll-behavior:contain;position:sticky;height:100vh;top:0;left:0;z-index:var(--desktop-sidebar-z-index);}.rustdoc.src .sidebar{flex-basis:50px;width:50px;border-right:1px solid;overflow-x:hidden;overflow-y:hidden;}.hide-sidebar .sidebar,.hide-sidebar .sidebar-resizer{display:none;}.sidebar-resizer{touch-action:none;width:9px;cursor:col-resize;z-index:calc(var(--desktop-sidebar-z-index) + 1);position:fixed;height:100%;left:calc(var(--desktop-sidebar-width) + 1px);}.rustdoc.src .sidebar-resizer{left:49px;}.src-sidebar-expanded .src .sidebar-resizer{left:var(--src-sidebar-width);}.sidebar-resizing{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;}.sidebar-resizing*{cursor:col-resize !important;}.sidebar-resizing .sidebar{position:fixed;}.sidebar-resizing>body{padding-left:var(--resizing-sidebar-width);}.sidebar-resizer:hover,.sidebar-resizer:active,.sidebar-resizer:focus,.sidebar-resizer.active{width:10px;margin:0;left:var(--desktop-sidebar-width);border-left:solid 1px var(--sidebar-resizer-hover);}.src-sidebar-expanded .rustdoc.src .sidebar-resizer:hover,.src-sidebar-expanded .rustdoc.src .sidebar-resizer:active,.src-sidebar-expanded .rustdoc.src .sidebar-resizer:focus,.src-sidebar-expanded .rustdoc.src .sidebar-resizer.active{left:calc(var(--src-sidebar-width) - 1px);}@media (pointer:coarse){.sidebar-resizer{display:none !important;}}.sidebar-resizer.active{padding:0 140px;width:2px;margin-left:-140px;border-left:none;}.sidebar-resizer.active:before{border-left:solid 2px var(--sidebar-resizer-active);display:block;height:100%;content:"";}.sidebar,.mobile-topbar,.sidebar-menu-toggle,#src-sidebar{background-color:var(--sidebar-background-color);}.src .sidebar>*{visibility:hidden;}.src-sidebar-expanded .src .sidebar{overflow-y:auto;flex-basis:var(--src-sidebar-width);width:var(--src-sidebar-width);}.src-sidebar-expanded .src .sidebar>*{visibility:visible;}#all-types{margin-top:1em;}*{scrollbar-width:initial;scrollbar-color:var(--scrollbar-color);}.sidebar{scrollbar-width:thin;scrollbar-color:var(--scrollbar-color);}::-webkit-scrollbar{width:12px;}.sidebar::-webkit-scrollbar{width:8px;}::-webkit-scrollbar-track{-webkit-box-shadow:inset 0;background-color:var(--scrollbar-track-background-color);}.sidebar::-webkit-scrollbar-track{background-color:var(--scrollbar-track-background-color);}::-webkit-scrollbar-thumb,.sidebar::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb-background-color);}.hidden{display:none !important;}.logo-container>img{height:48px;width:48px;}ul.block,.block li{padding:0;margin:0;list-style:none;}.sidebar-elems a,.sidebar>h2 a{display:block;padding:0.25rem;margin-right:0.25rem;border-left:solid var(--sidebar-elems-left-padding) transparent;margin-left:calc(-0.25rem - var(--sidebar-elems-left-padding));background-clip:border-box;}.sidebar h2{overflow-wrap:anywhere;padding:0;margin:0.7rem 0;}.sidebar h3{font-size:1.125rem;padding:0;margin:0;}.sidebar-elems,.sidebar>.version,.sidebar>h2{padding-left:var(--sidebar-elems-left-padding);}.sidebar a{color:var(--sidebar-link-color);}.sidebar .current,.sidebar .current a,.sidebar-crate a.logo-container:hover+h2 a,.sidebar a:hover:not(.logo-container){background-color:var(--sidebar-current-link-background-color);}.sidebar-elems .block{margin-bottom:2em;}.sidebar-elems .block li a{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;}.sidebar-crate{display:flex;align-items:center;justify-content:center;margin:14px 32px 1rem;row-gap:10px;column-gap:32px;flex-wrap:wrap;}.sidebar-crate h2{flex-grow:1;margin:0 -8px;align-self:start;}.sidebar-crate .logo-container{margin:0 calc(-16px - var(--sidebar-elems-left-padding));padding:0 var(--sidebar-elems-left-padding);text-align:center;}.sidebar-crate .logo-container img{margin-top:-16px;border-top:solid 16px transparent;box-sizing:content-box;position:relative;background-clip:border-box;z-index:1;}.sidebar-crate h2 a{display:block;border-left:solid var(--sidebar-elems-left-padding) transparent;background-clip:border-box;margin:0 calc(-24px + 0.25rem) 0 calc(-0.2rem - var(--sidebar-elems-left-padding));padding:calc((16px - 0.57rem ) / 2 ) 0.25rem;padding-left:0.2rem;}.sidebar-crate h2 .version{display:block;font-weight:normal;font-size:1rem;overflow-wrap:break-word;}.sidebar-crate+.version{margin-top:-1rem;margin-bottom:1rem;}.mobile-topbar{display:none;}.rustdoc .example-wrap{display:flex;position:relative;margin-bottom:10px;}.rustdoc .example-wrap:last-child{margin-bottom:0px;}.rustdoc .example-wrap pre{margin:0;flex-grow:1;}.rustdoc:not(.src) .example-wrap pre{overflow:auto hidden;}.rustdoc .example-wrap pre.example-line-numbers,.rustdoc .example-wrap pre.src-line-numbers{flex-grow:0;min-width:fit-content;overflow:initial;text-align:right;-webkit-user-select:none;user-select:none;padding:14px 8px;color:var(--src-line-numbers-span-color);}.rustdoc .example-wrap pre.src-line-numbers{padding:14px 0;}.src-line-numbers a,.src-line-numbers span{color:var(--src-line-numbers-span-color);padding:0 8px;}.src-line-numbers :target{background-color:transparent;border-right:none;padding:0 8px;}.src-line-numbers .line-highlighted{background-color:var(--src-line-number-highlighted-background-color);}.search-loading{text-align:center;}.docblock-short{overflow-wrap:break-word;overflow-wrap:anywhere;}.docblock :not(pre)>code,.docblock-short code{white-space:pre-wrap;}.top-doc .docblock h2{font-size:1.375rem;}.top-doc .docblock h3{font-size:1.25rem;}.top-doc .docblock h4,.top-doc .docblock h5{font-size:1.125rem;}.top-doc .docblock h6{font-size:1rem;}.docblock h5{font-size:1rem;}.docblock h6{font-size:0.875rem;}.docblock{margin-left:24px;position:relative;}.docblock>:not(.more-examples-toggle):not(.example-wrap){max-width:100%;overflow-x:auto;}.out-of-band{flex-grow:0;font-size:1.125rem;}.docblock code,.docblock-short code,pre,.rustdoc.src .example-wrap{background-color:var(--code-block-background-color);}#main-content{position:relative;}.docblock table{margin:.5em 0;border-collapse:collapse;}.docblock table td,.docblock table th{padding:.5em;border:1px solid var(--border-color);}.docblock table tbody tr:nth-child(2n){background:var(--table-alt-row-background-color);}div.where{white-space:pre-wrap;font-size:0.875rem;}.item-info{display:block;margin-left:24px;}.item-info code{font-size:0.875rem;}#main-content>.item-info{margin-left:0;}nav.sub{flex-grow:1;flex-flow:row nowrap;margin:4px 0 25px 0;display:flex;align-items:center;}.search-form{position:relative;display:flex;height:34px;flex-grow:1;}.src nav.sub{margin:0 0 15px 0;}.section-header{display:block;position:relative;}.section-header:hover>.anchor,.impl:hover>.anchor,.trait-impl:hover>.anchor,.variant:hover>.anchor{display:initial;}.anchor{display:none;position:absolute;left:-0.5em;background:none !important;}.anchor.field{left:-5px;}.section-header>.anchor{left:-15px;padding-right:8px;}h2.section-header>.anchor{padding-right:6px;}a.doc-anchor{color:var(--main-color);display:none;position:absolute;left:-17px;padding-right:5px;padding-left:3px;}*:hover>.doc-anchor{display:block;}.top-doc>.docblock>*:first-child>.doc-anchor{display:none !important;}.main-heading a:hover,.example-wrap .rust a:hover,.all-items a:hover,.docblock a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover:not(.doc-anchor),.docblock-short a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover,.item-info a{text-decoration:underline;}.crate.block li.current a{font-weight:500;}table,.item-table{overflow-wrap:break-word;}.item-table{display:table;padding:0;margin:0;}.item-table>li{display:table-row;}.item-table>li>div{display:table-cell;}.item-table>li>.item-name{padding-right:1.25rem;}.search-results-title{margin-top:0;white-space:nowrap;display:flex;align-items:baseline;}#crate-search-div{position:relative;min-width:5em;}#crate-search{min-width:115px;padding:0 23px 0 4px;max-width:100%;text-overflow:ellipsis;border:1px solid var(--border-color);border-radius:4px;outline:none;cursor:pointer;-moz-appearance:none;-webkit-appearance:none;text-indent:0.01px;background-color:var(--main-background-color);color:inherit;line-height:1.5;font-weight:500;}#crate-search:hover,#crate-search:focus{border-color:var(--crate-search-hover-border);}#crate-search-div::after{pointer-events:none;width:100%;height:100%;position:absolute;top:0;left:0;content:"";background-repeat:no-repeat;background-size:20px;background-position:calc(100% - 2px) 56%;background-image:url('data:image/svg+xml, \ + ');filter:var(--crate-search-div-filter);}#crate-search-div:hover::after,#crate-search-div:focus-within::after{filter:var(--crate-search-div-hover-filter);}#crate-search>option{font-size:1rem;}.search-input{-webkit-appearance:none;outline:none;border:1px solid var(--border-color);border-radius:2px;padding:8px;font-size:1rem;flex-grow:1;background-color:var(--button-background-color);color:var(--search-color);}.search-input:focus{border-color:var(--search-input-focused-border-color);}.search-results{display:none;}.search-results.active{display:block;}.search-results>a{display:flex;margin-left:2px;margin-right:2px;border-bottom:1px solid var(--search-result-border-color);gap:1em;}.search-results>a>div.desc{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;flex:2;}.search-results a:hover,.search-results a:focus{background-color:var(--search-result-link-focus-background-color);}.search-results .result-name{display:flex;align-items:center;justify-content:start;flex:3;}.search-results .result-name .alias{color:var(--search-results-alias-color);}.search-results .result-name .grey{color:var(--search-results-grey-color);}.search-results .result-name .typename{color:var(--search-results-grey-color);font-size:0.875rem;width:var(--search-typename-width);}.search-results .result-name .path{word-break:break-all;max-width:calc(100% - var(--search-typename-width));display:inline-block;}.search-results .result-name .path>*{display:inline;}.popover{position:absolute;top:100%;right:0;z-index:calc(var(--desktop-sidebar-z-index) + 1);margin-top:7px;border-radius:3px;border:1px solid var(--border-color);background-color:var(--main-background-color);color:var(--main-color);--popover-arrow-offset:11px;}.popover::before{content:'';position:absolute;right:var(--popover-arrow-offset);border:solid var(--border-color);border-width:1px 1px 0 0;background-color:var(--main-background-color);padding:4px;transform:rotate(-45deg);top:-5px;}.setting-line{margin:1.2em 0.6em;}.setting-radio input,.setting-check input{margin-right:0.3em;height:1.2rem;width:1.2rem;border:2px solid var(--settings-input-border-color);outline:none;-webkit-appearance:none;cursor:pointer;}.setting-radio input{border-radius:50%;}.setting-radio span,.setting-check span{padding-bottom:1px;}.setting-radio{margin-top:0.1em;margin-bottom:0.1em;min-width:3.8em;padding:0.3em;display:inline-flex;align-items:center;cursor:pointer;}.setting-radio+.setting-radio{margin-left:0.5em;}.setting-check{margin-right:20px;display:flex;align-items:center;cursor:pointer;}.setting-radio input:checked{box-shadow:inset 0 0 0 3px var(--main-background-color);background-color:var(--settings-input-color);}.setting-check input:checked{background-color:var(--settings-input-color);border-width:1px;content:url('data:image/svg+xml,\ + \ + ');}.setting-radio input:focus,.setting-check input:focus{box-shadow:0 0 1px 1px var(--settings-input-color);}.setting-radio input:checked:focus{box-shadow:inset 0 0 0 3px var(--main-background-color),0 0 2px 2px var(--settings-input-color);}.setting-radio input:hover,.setting-check input:hover{border-color:var(--settings-input-color) !important;}#help.popover{max-width:600px;--popover-arrow-offset:48px;}#help dt{float:left;clear:left;margin-right:0.5rem;}#help span.top,#help span.bottom{text-align:center;display:block;font-size:1.125rem;}#help span.top{margin:10px 0;border-bottom:1px solid var(--border-color);padding-bottom:4px;margin-bottom:6px;}#help span.bottom{clear:both;border-top:1px solid var(--border-color);}.side-by-side>div{width:50%;float:left;padding:0 20px 20px 17px;}.item-info .stab{display:block;padding:3px;margin-bottom:5px;}.item-name .stab{margin-left:0.3125em;}.stab{padding:0 2px;font-size:0.875rem;font-weight:normal;color:var(--main-color);background-color:var(--stab-background-color);width:fit-content;white-space:pre-wrap;border-radius:3px;display:inline;vertical-align:baseline;}.stab.portability>code{background:none;color:var(--stab-code-color);}.stab .emoji,.item-info .stab::before{font-size:1.25rem;}.stab .emoji{margin-right:0.3rem;}.item-info .stab::before{content:"\0";width:0;display:inline-block;color:transparent;}.emoji{text-shadow:1px 0 0 black,-1px 0 0 black,0 1px 0 black,0 -1px 0 black;}.since{font-weight:normal;font-size:initial;}.rightside{padding-left:12px;float:right;}.rightside:not(a),.out-of-band{color:var(--right-side-color);}pre.rust{tab-size:4;-moz-tab-size:4;}pre.rust .kw{color:var(--code-highlight-kw-color);}pre.rust .kw-2{color:var(--code-highlight-kw-2-color);}pre.rust .lifetime{color:var(--code-highlight-lifetime-color);}pre.rust .prelude-ty{color:var(--code-highlight-prelude-color);}pre.rust .prelude-val{color:var(--code-highlight-prelude-val-color);}pre.rust .string{color:var(--code-highlight-string-color);}pre.rust .number{color:var(--code-highlight-number-color);}pre.rust .bool-val{color:var(--code-highlight-literal-color);}pre.rust .self{color:var(--code-highlight-self-color);}pre.rust .attr{color:var(--code-highlight-attribute-color);}pre.rust .macro,pre.rust .macro-nonterminal{color:var(--code-highlight-macro-color);}pre.rust .question-mark{font-weight:bold;color:var(--code-highlight-question-mark-color);}pre.rust .comment{color:var(--code-highlight-comment-color);}pre.rust .doccomment{color:var(--code-highlight-doc-comment-color);}.rustdoc.src .example-wrap pre.rust a{background:var(--codeblock-link-background);}.example-wrap.compile_fail,.example-wrap.should_panic{border-left:2px solid var(--codeblock-error-color);}.ignore.example-wrap{border-left:2px solid var(--codeblock-ignore-color);}.example-wrap.compile_fail:hover,.example-wrap.should_panic:hover{border-left:2px solid var(--codeblock-error-hover-color);}.example-wrap.ignore:hover{border-left:2px solid var(--codeblock-ignore-hover-color);}.example-wrap.compile_fail .tooltip,.example-wrap.should_panic .tooltip{color:var(--codeblock-error-color);}.example-wrap.ignore .tooltip{color:var(--codeblock-ignore-color);}.example-wrap.compile_fail:hover .tooltip,.example-wrap.should_panic:hover .tooltip{color:var(--codeblock-error-hover-color);}.example-wrap.ignore:hover .tooltip{color:var(--codeblock-ignore-hover-color);}.example-wrap .tooltip{position:absolute;display:block;left:-25px;top:5px;margin:0;line-height:1;}.example-wrap.compile_fail .tooltip,.example-wrap.should_panic .tooltip,.example-wrap.ignore .tooltip{font-weight:bold;font-size:1.25rem;}.content .docblock .warning{border-left:2px solid var(--warning-border-color);padding:14px;position:relative;overflow-x:visible !important;}.content .docblock .warning::before{color:var(--warning-border-color);content:"ⓘ";position:absolute;left:-25px;top:5px;font-weight:bold;font-size:1.25rem;}.top-doc>.docblock>.warning:first-child::before{top:20px;}a.test-arrow{visibility:hidden;position:absolute;padding:5px 10px 5px 10px;border-radius:5px;font-size:1.375rem;top:5px;right:5px;z-index:1;color:var(--test-arrow-color);background-color:var(--test-arrow-background-color);}a.test-arrow:hover{color:var(--test-arrow-hover-color);background-color:var(--test-arrow-hover-background-color);}.example-wrap:hover .test-arrow{visibility:visible;}.code-attribute{font-weight:300;color:var(--code-attribute-color);}.item-spacer{width:100%;height:12px;display:block;}.out-of-band>span.since{font-size:1.25rem;}.sub-variant h4{font-size:1rem;font-weight:400;margin-top:0;margin-bottom:0;}.sub-variant{margin-left:24px;margin-bottom:40px;}.sub-variant>.sub-variant-field{margin-left:24px;}:target{padding-right:3px;background-color:var(--target-background-color);border-right:3px solid var(--target-border-color);}.code-header a.tooltip{color:inherit;margin-right:15px;position:relative;}.code-header a.tooltip:hover{color:var(--link-color);}a.tooltip:hover::after{position:absolute;top:calc(100% - 10px);left:-15px;right:-15px;height:20px;content:"\00a0";}.fade-out{opacity:0;transition:opacity 0.45s cubic-bezier(0,0,0.1,1.0);}.popover.tooltip .content{margin:0.25em 0.5em;}.popover.tooltip .content pre,.popover.tooltip .content code{background:transparent;margin:0;padding:0;font-size:1.25rem;white-space:pre-wrap;}.popover.tooltip .content>h3:first-child{margin:0 0 5px 0;}.search-failed{text-align:center;margin-top:20px;display:none;}.search-failed.active{display:block;}.search-failed>ul{text-align:left;max-width:570px;margin-left:auto;margin-right:auto;}#search-tabs{display:flex;flex-direction:row;gap:1px;margin-bottom:4px;}#search-tabs button{text-align:center;font-size:1.125rem;border:0;border-top:2px solid;flex:1;line-height:1.5;color:inherit;}#search-tabs button:not(.selected){background-color:var(--search-tab-button-not-selected-background);border-top-color:var(--search-tab-button-not-selected-border-top-color);}#search-tabs button:hover,#search-tabs button.selected{background-color:var(--search-tab-button-selected-background);border-top-color:var(--search-tab-button-selected-border-top-color);}#search-tabs .count{font-size:1rem;font-variant-numeric:tabular-nums;color:var(--search-tab-title-count-color);}#search .error code{border-radius:3px;background-color:var(--search-error-code-background-color);}.search-corrections{font-weight:normal;}#src-sidebar{width:100%;overflow:auto;}#src-sidebar div.files>a:hover,details.dir-entry summary:hover,#src-sidebar div.files>a:focus,details.dir-entry summary:focus{background-color:var(--src-sidebar-background-hover);}#src-sidebar div.files>a.selected{background-color:var(--src-sidebar-background-selected);}.src-sidebar-title{position:sticky;top:0;display:flex;padding:8px 8px 0 48px;margin-bottom:7px;background:var(--sidebar-background-color);border-bottom:1px solid var(--border-color);}#settings-menu,#help-button{margin-left:4px;display:flex;}#sidebar-button{display:none;line-height:0;}.hide-sidebar #sidebar-button,.src #sidebar-button{display:flex;margin-right:4px;position:fixed;left:6px;height:34px;width:34px;background-color:var(--main-background-color);z-index:1;}.src #sidebar-button{left:8px;z-index:calc(var(--desktop-sidebar-z-index) + 1);}.hide-sidebar .src #sidebar-button{position:static;}#settings-menu>a,#help-button>a,#sidebar-button>a{display:flex;align-items:center;justify-content:center;background-color:var(--button-background-color);border:1px solid var(--border-color);border-radius:2px;color:var(--settings-button-color);font-size:20px;width:33px;}#settings-menu>a:hover,#settings-menu>a:focus,#help-button>a:hover,#help-button>a:focus,#sidebar-button>a:hover,#sidebar-button>a:focus{border-color:var(--settings-button-border-focus);}#settings-menu>a{line-height:0;font-size:0;}#settings-menu>a:before{content:url('data:image/svg+xml,\ + ');width:22px;height:22px;filter:var(--settings-menu-filter);}#sidebar-button>a:before{content:url('data:image/svg+xml,\ + \ + \ + ');width:22px;height:22px;}#copy-path{color:var(--copy-path-button-color);background:var(--main-background-color);height:34px;width:33px;margin-left:10px;padding:0;padding-left:2px;border:0;font-size:0;}#copy-path::before{filter:var(--copy-path-img-filter);content:url('data:image/svg+xml,\ +\ +\ +');width:19px;height:18px;}#copy-path:hover::before{filter:var(--copy-path-img-hover-filter);}#copy-path.clicked::before{content:url('data:image/svg+xml,\ + \ + ');}@keyframes rotating{from{transform:rotate(0deg);}to{transform:rotate(360deg);}}#settings-menu.rotate>a img{animation:rotating 2s linear infinite;}kbd{display:inline-block;padding:3px 5px;font:15px monospace;line-height:10px;vertical-align:middle;border:solid 1px var(--border-color);border-radius:3px;color:var(--kbd-color);background-color:var(--kbd-background);box-shadow:inset 0 -1px 0 var(--kbd-box-shadow-color);}ul.all-items>li{list-style:none;}details.dir-entry{padding-left:4px;}details.dir-entry>summary{margin:0 0 0 -4px;padding:0 0 0 4px;cursor:pointer;}details.dir-entry div.folders,details.dir-entry div.files{padding-left:23px;}details.dir-entry a{display:block;}details.toggle{contain:layout;position:relative;}details.toggle>summary.hideme{cursor:pointer;font-size:1rem;}details.toggle>summary{list-style:none;outline:none;}details.toggle>summary::-webkit-details-marker,details.toggle>summary::marker{display:none;}details.toggle>summary.hideme>span{margin-left:9px;}details.toggle>summary::before{background:url('data:image/svg+xml,') no-repeat top left;content:"";cursor:pointer;width:16px;height:16px;display:inline-block;vertical-align:middle;opacity:.5;filter:var(--toggle-filter);}details.toggle>summary.hideme>span,.more-examples-toggle summary,.more-examples-toggle .hide-more{color:var(--toggles-color);}details.toggle>summary::after{content:"Expand";overflow:hidden;width:0;height:0;position:absolute;}details.toggle>summary.hideme::after{content:"";}details.toggle>summary:focus::before,details.toggle>summary:hover::before{opacity:1;}details.toggle>summary:focus-visible::before{outline:1px dotted #000;outline-offset:1px;}details.non-exhaustive{margin-bottom:8px;}details.toggle>summary.hideme::before{position:relative;}details.toggle>summary:not(.hideme)::before{position:absolute;left:-24px;top:4px;}.impl-items>details.toggle>summary:not(.hideme)::before{position:absolute;left:-24px;}details.toggle[open] >summary.hideme{position:absolute;}details.toggle[open] >summary.hideme>span{display:none;}details.toggle[open] >summary::before{background:url('data:image/svg+xml,') no-repeat top left;}details.toggle[open] >summary::after{content:"Collapse";}.docblock summary>*{display:inline-block;}.docblock>.example-wrap:first-child .tooltip{margin-top:16px;}.src #sidebar-button>a:before,.sidebar-menu-toggle:before{content:url('data:image/svg+xml,\ + ');opacity:0.75;}.sidebar-menu-toggle:hover:before,.sidebar-menu-toggle:active:before,.sidebar-menu-toggle:focus:before{opacity:1;}.src #sidebar-button>a:before{content:url('data:image/svg+xml,\ + \ + \ + ');opacity:0.75;}@media (max-width:850px){#search-tabs .count{display:block;}}@media (max-width:700px){*[id]{scroll-margin-top:45px;}.rustdoc{display:block;}main{padding-left:15px;padding-top:0px;}.main-heading{flex-direction:column;}.out-of-band{text-align:left;margin-left:initial;padding:initial;}.out-of-band .since::before{content:"Since ";}.sidebar .logo-container,.sidebar .location,.sidebar-resizer{display:none;}.sidebar{position:fixed;top:45px;left:-1000px;z-index:11;height:calc(100vh - 45px);width:200px;}.src main,.rustdoc.src .sidebar{top:0;padding:0;height:100vh;border:0;}.src .search-form{margin-left:40px;}.hide-sidebar .search-form{margin-left:32px;}.hide-sidebar .src .search-form{margin-left:0;}.sidebar.shown,.src-sidebar-expanded .src .sidebar,.rustdoc:not(.src) .sidebar:focus-within{left:0;}.mobile-topbar h2{padding-bottom:0;margin:auto 0.5em auto auto;overflow:hidden;font-size:24px;white-space:nowrap;text-overflow:ellipsis;}.mobile-topbar .logo-container>img{max-width:35px;max-height:35px;margin:5px 0 5px 20px;}.mobile-topbar{display:flex;flex-direction:row;position:sticky;z-index:10;font-size:2rem;height:45px;width:100%;left:0;top:0;}.hide-sidebar .mobile-topbar{display:none;}.sidebar-menu-toggle{width:45px;border:none;line-height:0;}.hide-sidebar .sidebar-menu-toggle{display:none;}.sidebar-elems{margin-top:1em;}.anchor{display:none !important;}#main-content>details.toggle>summary::before,#main-content>div>details.toggle>summary::before{left:-11px;}#copy-path,#help-button{display:none;}#sidebar-button>a:before{content:url('data:image/svg+xml,\ + \ + \ + ');width:22px;height:22px;}.sidebar-menu-toggle:before{filter:var(--mobile-sidebar-menu-filter);}.sidebar-menu-toggle:hover{background:var(--main-background-color);}.item-table,.item-row,.item-table>li,.item-table>li>div,.search-results>a,.search-results>a>div{display:block;}.search-results>a{padding:5px 0px;}.search-results>a>div.desc,.item-table>li>div.desc{padding-left:2em;}.search-results .result-name{display:block;}.search-results .result-name .typename{width:initial;margin-right:0;}.search-results .result-name .typename,.search-results .result-name .path{display:inline;}.src-sidebar-expanded .src .sidebar{position:fixed;max-width:100vw;width:100vw;}.src .src-sidebar-title{padding-top:0;}details.toggle:not(.top-doc)>summary{margin-left:10px;}.impl-items>details.toggle>summary:not(.hideme)::before,#main-content>details.toggle:not(.top-doc)>summary::before,#main-content>div>details.toggle>summary::before{left:-11px;}.impl-items>.item-info{margin-left:34px;}.src nav.sub{margin:0;padding:var(--nav-sub-mobile-padding);}}@media (min-width:701px){.scraped-example-title{position:absolute;z-index:10;background:var(--main-background-color);bottom:8px;right:5px;padding:2px 4px;box-shadow:0 0 4px var(--main-background-color);}.item-table>li>.item-name{width:33%;}.item-table>li>div{padding-bottom:5px;word-break:break-all;}}@media print{nav.sidebar,nav.sub,.out-of-band,a.src,#copy-path,details.toggle[open] >summary::before,details.toggle>summary::before,details.toggle.top-doc>summary{display:none;}.docblock{margin-left:0;}main{padding:10px;}}@media (max-width:464px){.docblock{margin-left:12px;}.docblock code{overflow-wrap:break-word;overflow-wrap:anywhere;}nav.sub{flex-direction:column;}.search-form{align-self:stretch;}}.variant,.implementors-toggle>summary,.impl,#implementors-list>.docblock,.impl-items>section,.impl-items>.toggle>summary,.methods>section,.methods>.toggle>summary{margin-bottom:0.75em;}.variants>.docblock,.implementors-toggle>.docblock,.impl-items>.toggle[open]:not(:last-child),.methods>.toggle[open]:not(:last-child),.implementors-toggle[open]:not(:last-child){margin-bottom:2em;}#trait-implementations-list .impl-items>.toggle:not(:last-child),#synthetic-implementations-list .impl-items>.toggle:not(:last-child),#blanket-implementations-list .impl-items>.toggle:not(:last-child){margin-bottom:1em;}.scraped-example-list .scrape-help{margin-left:10px;padding:0 4px;font-weight:normal;font-size:12px;position:relative;bottom:1px;border:1px solid var(--scrape-example-help-border-color);border-radius:50px;color:var(--scrape-example-help-color);}.scraped-example-list .scrape-help:hover{border-color:var(--scrape-example-help-hover-border-color);color:var(--scrape-example-help-hover-color);}.scraped-example{position:relative;}.scraped-example .code-wrapper{position:relative;display:flex;flex-direction:row;flex-wrap:wrap;width:100%;}.scraped-example:not(.expanded) .code-wrapper{max-height:calc(1.5em * 5 + 10px);}.scraped-example:not(.expanded) .code-wrapper pre{overflow-y:hidden;padding-bottom:0;max-height:calc(1.5em * 5 + 10px);}.more-scraped-examples .scraped-example:not(.expanded) .code-wrapper,.more-scraped-examples .scraped-example:not(.expanded) .code-wrapper pre{max-height:calc(1.5em * 10 + 10px);}.scraped-example .code-wrapper .next,.scraped-example .code-wrapper .prev,.scraped-example .code-wrapper .expand{color:var(--main-color);position:absolute;top:0.25em;z-index:1;padding:0;background:none;border:none;-webkit-appearance:none;opacity:1;}.scraped-example .code-wrapper .prev{right:2.25em;}.scraped-example .code-wrapper .next{right:1.25em;}.scraped-example .code-wrapper .expand{right:0.25em;}.scraped-example:not(.expanded) .code-wrapper::before,.scraped-example:not(.expanded) .code-wrapper::after{content:" ";width:100%;height:5px;position:absolute;z-index:1;}.scraped-example:not(.expanded) .code-wrapper::before{top:0;background:linear-gradient(to bottom,var(--scrape-example-code-wrapper-background-start),var(--scrape-example-code-wrapper-background-end));}.scraped-example:not(.expanded) .code-wrapper::after{bottom:0;background:linear-gradient(to top,var(--scrape-example-code-wrapper-background-start),var(--scrape-example-code-wrapper-background-end));}.scraped-example .code-wrapper .example-wrap{width:100%;overflow-y:hidden;margin-bottom:0;}.scraped-example:not(.expanded) .code-wrapper .example-wrap{overflow-x:hidden;}.scraped-example .example-wrap .rust span.highlight{background:var(--scrape-example-code-line-highlight);}.scraped-example .example-wrap .rust span.highlight.focus{background:var(--scrape-example-code-line-highlight-focus);}.more-examples-toggle{max-width:calc(100% + 25px);margin-top:10px;margin-left:-25px;}.more-examples-toggle .hide-more{margin-left:25px;cursor:pointer;}.more-scraped-examples{margin-left:25px;position:relative;}.toggle-line{position:absolute;top:5px;bottom:0;right:calc(100% + 10px);padding:0 4px;cursor:pointer;}.toggle-line-inner{min-width:2px;height:100%;background:var(--scrape-example-toggle-line-background);}.toggle-line:hover .toggle-line-inner{background:var(--scrape-example-toggle-line-hover-background);}.more-scraped-examples .scraped-example,.example-links{margin-top:20px;}.more-scraped-examples .scraped-example:first-child{margin-top:5px;}.example-links ul{margin-bottom:0;}:root[data-theme="light"],:root:not([data-theme]){--main-background-color:white;--main-color:black;--settings-input-color:#2196f3;--settings-input-border-color:#717171;--settings-button-color:#000;--settings-button-border-focus:#717171;--sidebar-background-color:#f5f5f5;--sidebar-background-color-hover:#e0e0e0;--code-block-background-color:#f5f5f5;--scrollbar-track-background-color:#dcdcdc;--scrollbar-thumb-background-color:rgba(36,37,39,0.6);--scrollbar-color:rgba(36,37,39,0.6) #d9d9d9;--headings-border-bottom-color:#ddd;--border-color:#e0e0e0;--button-background-color:#fff;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:none;--mobile-sidebar-menu-filter:none;--search-input-focused-border-color:#66afe9;--copy-path-button-color:#999;--copy-path-img-filter:invert(50%);--copy-path-img-hover-filter:invert(35%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#ad378a;--trait-link-color:#6e4fc9;--assoc-item-link-color:#3873ad;--function-link-color:#ad7c37;--macro-link-color:#068000;--keyword-link-color:#3873ad;--mod-link-color:#3873ad;--link-color:#3873ad;--sidebar-link-color:#356da4;--sidebar-current-link-background-color:#fff;--search-result-link-focus-background-color:#ccc;--search-result-border-color:#aaa3;--search-color:#000;--search-error-code-background-color:#d0cccc;--search-results-alias-color:#000;--search-results-grey-color:#999;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:#e6e6e6;--search-tab-button-not-selected-background:#e6e6e6;--search-tab-button-selected-border-top-color:#0089ff;--search-tab-button-selected-background:#fff;--settings-menu-filter:none;--stab-background-color:#fff5d6;--stab-code-color:#000;--code-highlight-kw-color:#8959a8;--code-highlight-kw-2-color:#4271ae;--code-highlight-lifetime-color:#b76514;--code-highlight-prelude-color:#4271ae;--code-highlight-prelude-val-color:#c82829;--code-highlight-number-color:#718c00;--code-highlight-string-color:#718c00;--code-highlight-literal-color:#c82829;--code-highlight-attribute-color:#c82829;--code-highlight-self-color:#c82829;--code-highlight-macro-color:#3e999f;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#8e908c;--code-highlight-doc-comment-color:#4d4d4c;--src-line-numbers-span-color:#c67e2d;--src-line-number-highlighted-background-color:#fdffd3;--test-arrow-color:#f5f5f5;--test-arrow-background-color:rgba(78,139,202,0.2);--test-arrow-hover-color:#f5f5f5;--test-arrow-hover-background-color:rgb(78,139,202);--target-background-color:#fdffd3;--target-border-color:#ad7c37;--kbd-color:#000;--kbd-background:#fafbfc;--kbd-box-shadow-color:#c6cbd1;--rust-logo-filter:initial;--crate-search-div-filter:invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) brightness(114%) contrast(76%);--crate-search-div-hover-filter:invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%);--crate-search-hover-border:#717171;--src-sidebar-background-selected:#fff;--src-sidebar-background-hover:#e0e0e0;--table-alt-row-background-color:#f5f5f5;--codeblock-link-background:#eee;--scrape-example-toggle-line-background:#ccc;--scrape-example-toggle-line-hover-background:#999;--scrape-example-code-line-highlight:#fcffd6;--scrape-example-code-line-highlight-focus:#f6fdb0;--scrape-example-help-border-color:#555;--scrape-example-help-color:#333;--scrape-example-help-hover-border-color:#000;--scrape-example-help-hover-color:#000;--scrape-example-code-wrapper-background-start:rgba(255,255,255,1);--scrape-example-code-wrapper-background-end:rgba(255,255,255,0);--sidebar-resizer-hover:hsl(207,90%,66%);--sidebar-resizer-active:hsl(207,90%,54%);}:root[data-theme="dark"]{--main-background-color:#353535;--main-color:#ddd;--settings-input-color:#2196f3;--settings-input-border-color:#999;--settings-button-color:#000;--settings-button-border-focus:#ffb900;--sidebar-background-color:#505050;--sidebar-background-color-hover:#676767;--code-block-background-color:#2A2A2A;--scrollbar-track-background-color:#717171;--scrollbar-thumb-background-color:rgba(32,34,37,.6);--scrollbar-color:rgba(32,34,37,.6) #5a5a5a;--headings-border-bottom-color:#d2d2d2;--border-color:#e0e0e0;--button-background-color:#f0f0f0;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:invert(100%);--mobile-sidebar-menu-filter:invert(100%);--search-input-focused-border-color:#008dfd;--copy-path-button-color:#999;--copy-path-img-filter:invert(50%);--copy-path-img-hover-filter:invert(65%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#2dbfb8;--trait-link-color:#b78cf2;--assoc-item-link-color:#d2991d;--function-link-color:#2bab63;--macro-link-color:#09bd00;--keyword-link-color:#d2991d;--mod-link-color:#d2991d;--link-color:#d2991d;--sidebar-link-color:#fdbf35;--sidebar-current-link-background-color:#444;--search-result-link-focus-background-color:#616161;--search-result-border-color:#aaa3;--search-color:#111;--search-error-code-background-color:#484848;--search-results-alias-color:#fff;--search-results-grey-color:#ccc;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:#252525;--search-tab-button-not-selected-background:#252525;--search-tab-button-selected-border-top-color:#0089ff;--search-tab-button-selected-background:#353535;--settings-menu-filter:none;--stab-background-color:#314559;--stab-code-color:#e6e1cf;--code-highlight-kw-color:#ab8ac1;--code-highlight-kw-2-color:#769acb;--code-highlight-lifetime-color:#d97f26;--code-highlight-prelude-color:#769acb;--code-highlight-prelude-val-color:#ee6868;--code-highlight-number-color:#83a300;--code-highlight-string-color:#83a300;--code-highlight-literal-color:#ee6868;--code-highlight-attribute-color:#ee6868;--code-highlight-self-color:#ee6868;--code-highlight-macro-color:#3e999f;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#8d8d8b;--code-highlight-doc-comment-color:#8ca375;--src-line-numbers-span-color:#3b91e2;--src-line-number-highlighted-background-color:#0a042f;--test-arrow-color:#dedede;--test-arrow-background-color:rgba(78,139,202,0.2);--test-arrow-hover-color:#dedede;--test-arrow-hover-background-color:#4e8bca;--target-background-color:#494a3d;--target-border-color:#bb7410;--kbd-color:#000;--kbd-background:#fafbfc;--kbd-box-shadow-color:#c6cbd1;--rust-logo-filter:drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 -1px 0 #fff);--crate-search-div-filter:invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg) brightness(90%) contrast(90%);--crate-search-div-hover-filter:invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%);--crate-search-hover-border:#2196f3;--src-sidebar-background-selected:#333;--src-sidebar-background-hover:#444;--table-alt-row-background-color:#2a2a2a;--codeblock-link-background:#333;--scrape-example-toggle-line-background:#999;--scrape-example-toggle-line-hover-background:#c5c5c5;--scrape-example-code-line-highlight:#5b3b01;--scrape-example-code-line-highlight-focus:#7c4b0f;--scrape-example-help-border-color:#aaa;--scrape-example-help-color:#eee;--scrape-example-help-hover-border-color:#fff;--scrape-example-help-hover-color:#fff;--scrape-example-code-wrapper-background-start:rgba(53,53,53,1);--scrape-example-code-wrapper-background-end:rgba(53,53,53,0);--sidebar-resizer-hover:hsl(207,30%,54%);--sidebar-resizer-active:hsl(207,90%,54%);}:root[data-theme="ayu"]{--main-background-color:#0f1419;--main-color:#c5c5c5;--settings-input-color:#ffb454;--settings-input-border-color:#999;--settings-button-color:#fff;--settings-button-border-focus:#e0e0e0;--sidebar-background-color:#14191f;--sidebar-background-color-hover:rgba(70,70,70,0.33);--code-block-background-color:#191f26;--scrollbar-track-background-color:transparent;--scrollbar-thumb-background-color:#5c6773;--scrollbar-color:#5c6773 #24292f;--headings-border-bottom-color:#5c6773;--border-color:#5c6773;--button-background-color:#141920;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:invert(100%);--mobile-sidebar-menu-filter:invert(100%);--search-input-focused-border-color:#5c6773;--copy-path-button-color:#fff;--copy-path-img-filter:invert(70%);--copy-path-img-hover-filter:invert(100%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#ffa0a5;--trait-link-color:#39afd7;--assoc-item-link-color:#39afd7;--function-link-color:#fdd687;--macro-link-color:#a37acc;--keyword-link-color:#39afd7;--mod-link-color:#39afd7;--link-color:#39afd7;--sidebar-link-color:#53b1db;--sidebar-current-link-background-color:transparent;--search-result-link-focus-background-color:#3c3c3c;--search-result-border-color:#aaa3;--search-color:#fff;--search-error-code-background-color:#4f4c4c;--search-results-alias-color:#c5c5c5;--search-results-grey-color:#999;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:none;--search-tab-button-not-selected-background:transparent !important;--search-tab-button-selected-border-top-color:none;--search-tab-button-selected-background:#141920 !important;--settings-menu-filter:invert(100%);--stab-background-color:#314559;--stab-code-color:#e6e1cf;--code-highlight-kw-color:#ff7733;--code-highlight-kw-2-color:#ff7733;--code-highlight-lifetime-color:#ff7733;--code-highlight-prelude-color:#69f2df;--code-highlight-prelude-val-color:#ff7733;--code-highlight-number-color:#b8cc52;--code-highlight-string-color:#b8cc52;--code-highlight-literal-color:#ff7733;--code-highlight-attribute-color:#e6e1cf;--code-highlight-self-color:#36a3d9;--code-highlight-macro-color:#a37acc;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#788797;--code-highlight-doc-comment-color:#a1ac88;--src-line-numbers-span-color:#5c6773;--src-line-number-highlighted-background-color:rgba(255,236,164,0.06);--test-arrow-color:#788797;--test-arrow-background-color:rgba(57,175,215,0.09);--test-arrow-hover-color:#c5c5c5;--test-arrow-hover-background-color:rgba(57,175,215,0.368);--target-background-color:rgba(255,236,164,0.06);--target-border-color:rgba(255,180,76,0.85);--kbd-color:#c5c5c5;--kbd-background:#314559;--kbd-box-shadow-color:#5c6773;--rust-logo-filter:drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 -1px 0 #fff);--crate-search-div-filter:invert(41%) sepia(12%) saturate(487%) hue-rotate(171deg) brightness(94%) contrast(94%);--crate-search-div-hover-filter:invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg) brightness(113%) contrast(76%);--crate-search-hover-border:#e0e0e0;--src-sidebar-background-selected:#14191f;--src-sidebar-background-hover:#14191f;--table-alt-row-background-color:#191f26;--codeblock-link-background:#333;--scrape-example-toggle-line-background:#999;--scrape-example-toggle-line-hover-background:#c5c5c5;--scrape-example-code-line-highlight:#5b3b01;--scrape-example-code-line-highlight-focus:#7c4b0f;--scrape-example-help-border-color:#aaa;--scrape-example-help-color:#eee;--scrape-example-help-hover-border-color:#fff;--scrape-example-help-hover-color:#fff;--scrape-example-code-wrapper-background-start:rgba(15,20,25,1);--scrape-example-code-wrapper-background-end:rgba(15,20,25,0);--sidebar-resizer-hover:hsl(34,50%,33%);--sidebar-resizer-active:hsl(34,100%,66%);}:root[data-theme="ayu"] h1,:root[data-theme="ayu"] h2,:root[data-theme="ayu"] h3,:root[data-theme="ayu"] h4,:where(:root[data-theme="ayu"]) h1 a,:root[data-theme="ayu"] .sidebar h2 a,:root[data-theme="ayu"] .sidebar h3 a{color:#fff;}:root[data-theme="ayu"] .docblock code{color:#ffb454;}:root[data-theme="ayu"] .docblock a>code{color:#39AFD7 !important;}:root[data-theme="ayu"] .code-header,:root[data-theme="ayu"] .docblock pre>code,:root[data-theme="ayu"] pre,:root[data-theme="ayu"] pre>code,:root[data-theme="ayu"] .item-info code,:root[data-theme="ayu"] .rustdoc.source .example-wrap{color:#e6e1cf;}:root[data-theme="ayu"] .sidebar .current,:root[data-theme="ayu"] .sidebar .current a,:root[data-theme="ayu"] .sidebar a:hover,:root[data-theme="ayu"] #src-sidebar div.files>a:hover,:root[data-theme="ayu"] details.dir-entry summary:hover,:root[data-theme="ayu"] #src-sidebar div.files>a:focus,:root[data-theme="ayu"] details.dir-entry summary:focus,:root[data-theme="ayu"] #src-sidebar div.files>a.selected{color:#ffb44c;}:root[data-theme="ayu"] .sidebar-elems .location{color:#ff7733;}:root[data-theme="ayu"] .src-line-numbers .line-highlighted{color:#708090;padding-right:7px;border-right:1px solid #ffb44c;}:root[data-theme="ayu"] .search-results a:hover,:root[data-theme="ayu"] .search-results a:focus{color:#fff !important;background-color:#3c3c3c;}:root[data-theme="ayu"] .search-results a{color:#0096cf;}:root[data-theme="ayu"] .search-results a div.desc{color:#c5c5c5;}:root[data-theme="ayu"] .result-name .primitive>i,:root[data-theme="ayu"] .result-name .keyword>i{color:#788797;}:root[data-theme="ayu"] #search-tabs>button.selected{border-bottom:1px solid #ffb44c !important;border-top:none;}:root[data-theme="ayu"] #search-tabs>button:not(.selected){border:none;background-color:transparent !important;}:root[data-theme="ayu"] #search-tabs>button:hover{border-bottom:1px solid rgba(242,151,24,0.3);}:root[data-theme="ayu"] #settings-menu>a img,:root[data-theme="ayu"] #sidebar-button>a:before{filter:invert(100);} \ No newline at end of file diff --git a/static.files/scrape-examples-ef1e698c1d417c0c.js b/static.files/scrape-examples-ef1e698c1d417c0c.js new file mode 100644 index 0000000..ba830e3 --- /dev/null +++ b/static.files/scrape-examples-ef1e698c1d417c0c.js @@ -0,0 +1 @@ +"use strict";(function(){const DEFAULT_MAX_LINES=5;const HIDDEN_MAX_LINES=10;function scrollToLoc(elt,loc,isHidden){const lines=elt.querySelector(".src-line-numbers");let scrollOffset;const maxLines=isHidden?HIDDEN_MAX_LINES:DEFAULT_MAX_LINES;if(loc[1]-loc[0]>maxLines){const line=Math.max(0,loc[0]-1);scrollOffset=lines.children[line].offsetTop}else{const wrapper=elt.querySelector(".code-wrapper");const halfHeight=wrapper.offsetHeight/2;const offsetTop=lines.children[loc[0]].offsetTop;const lastLine=lines.children[loc[1]];const offsetBot=lastLine.offsetTop+lastLine.offsetHeight;const offsetMid=(offsetTop+offsetBot)/2;scrollOffset=offsetMid-halfHeight}lines.scrollTo(0,scrollOffset);elt.querySelector(".rust").scrollTo(0,scrollOffset)}function updateScrapedExample(example,isHidden){const locs=JSON.parse(example.attributes.getNamedItem("data-locs").textContent);let locIndex=0;const highlights=Array.prototype.slice.call(example.querySelectorAll(".highlight"));const link=example.querySelector(".scraped-example-title a");if(locs.length>1){const onChangeLoc=changeIndex=>{removeClass(highlights[locIndex],"focus");changeIndex();scrollToLoc(example,locs[locIndex][0],isHidden);addClass(highlights[locIndex],"focus");const url=locs[locIndex][1];const title=locs[locIndex][2];link.href=url;link.innerHTML=title};example.querySelector(".prev").addEventListener("click",()=>{onChangeLoc(()=>{locIndex=(locIndex-1+locs.length)%locs.length})});example.querySelector(".next").addEventListener("click",()=>{onChangeLoc(()=>{locIndex=(locIndex+1)%locs.length})})}const expandButton=example.querySelector(".expand");if(expandButton){expandButton.addEventListener("click",()=>{if(hasClass(example,"expanded")){removeClass(example,"expanded");scrollToLoc(example,locs[0][0],isHidden)}else{addClass(example,"expanded")}})}scrollToLoc(example,locs[0][0],isHidden)}const firstExamples=document.querySelectorAll(".scraped-example-list > .scraped-example");onEachLazy(firstExamples,el=>updateScrapedExample(el,false));onEachLazy(document.querySelectorAll(".more-examples-toggle"),toggle=>{onEachLazy(toggle.querySelectorAll(".toggle-line, .hide-more"),button=>{button.addEventListener("click",()=>{toggle.open=false})});const moreExamples=toggle.querySelectorAll(".scraped-example");toggle.querySelector("summary").addEventListener("click",()=>{setTimeout(()=>{onEachLazy(moreExamples,el=>updateScrapedExample(el,true))})},{once:true})})})() \ No newline at end of file diff --git a/static.files/search-d234aafac6c221dd.js b/static.files/search-d234aafac6c221dd.js new file mode 100644 index 0000000..3f587f6 --- /dev/null +++ b/static.files/search-d234aafac6c221dd.js @@ -0,0 +1,5 @@ +"use strict";if(!Array.prototype.toSpliced){Array.prototype.toSpliced=function(){const me=this.slice();Array.prototype.splice.apply(me,arguments);return me}}(function(){const itemTypes=["keyword","primitive","mod","externcrate","import","struct","enum","fn","type","static","trait","impl","tymethod","method","structfield","variant","macro","associatedtype","constant","associatedconstant","union","foreigntype","existential","attr","derive","traitalias","generic",];const longItemTypes=["keyword","primitive type","module","extern crate","re-export","struct","enum","function","type alias","static","trait","","trait method","method","struct field","enum variant","macro","assoc type","constant","assoc const","union","foreign type","existential type","attribute macro","derive macro","trait alias",];const TY_GENERIC=itemTypes.indexOf("generic");const TY_IMPORT=itemTypes.indexOf("import");const ROOT_PATH=typeof window!=="undefined"?window.rootPath:"../";const UNBOXING_LIMIT=5;const REGEX_IDENT=/\p{ID_Start}\p{ID_Continue}*|_\p{ID_Continue}+/uy;const REGEX_INVALID_TYPE_FILTER=/[^a-z]/ui;function printTab(nb){let iter=0;let foundCurrentTab=false;let foundCurrentResultSet=false;onEachLazy(document.getElementById("search-tabs").childNodes,elem=>{if(nb===iter){addClass(elem,"selected");foundCurrentTab=true}else{removeClass(elem,"selected")}iter+=1});const isTypeSearch=(nb>0||iter===1);iter=0;onEachLazy(document.getElementById("results").childNodes,elem=>{if(nb===iter){addClass(elem,"active");foundCurrentResultSet=true}else{removeClass(elem,"active")}iter+=1});if(foundCurrentTab&&foundCurrentResultSet){searchState.currentTab=nb;const correctionsElem=document.getElementsByClassName("search-corrections");if(isTypeSearch){removeClass(correctionsElem[0],"hidden")}else{addClass(correctionsElem[0],"hidden")}}else if(nb!==0){printTab(0)}}const editDistanceState={current:[],prev:[],prevPrev:[],calculate:function calculate(a,b,limit){if(a.lengthlimit){return limit+1}while(b.length>0&&b[0]===a[0]){a=a.substring(1);b=b.substring(1)}while(b.length>0&&b[b.length-1]===a[a.length-1]){a=a.substring(0,a.length-1);b=b.substring(0,b.length-1)}if(b.length===0){return minDist}const aLength=a.length;const bLength=b.length;for(let i=0;i<=bLength;++i){this.current[i]=0;this.prev[i]=i;this.prevPrev[i]=Number.MAX_VALUE}for(let i=1;i<=aLength;++i){this.current[0]=i;const aIdx=i-1;for(let j=1;j<=bLength;++j){const bIdx=j-1;const substitutionCost=a[aIdx]===b[bIdx]?0:1;this.current[j]=Math.min(this.prev[j]+1,this.current[j-1]+1,this.prev[j-1]+substitutionCost,);if((i>1)&&(j>1)&&(a[aIdx]===b[bIdx-1])&&(a[aIdx-1]===b[bIdx])){this.current[j]=Math.min(this.current[j],this.prevPrev[j-2]+1,)}}const prevPrevTmp=this.prevPrev;this.prevPrev=this.prev;this.prev=this.current;this.current=prevPrevTmp}const distance=this.prev[bLength];return distance<=limit?distance:(limit+1)},};function editDistance(a,b,limit){return editDistanceState.calculate(a,b,limit)}function initSearch(rawSearchIndex){const MAX_RESULTS=200;const NO_TYPE_FILTER=-1;let searchIndex;let searchIndexDeprecated;let searchIndexEmptyDesc;let functionTypeFingerprint;let currentResults;const typeNameIdMap=new Map();const ALIASES=new Map();const typeNameIdOfArray=buildTypeMapIndex("array");const typeNameIdOfSlice=buildTypeMapIndex("slice");const typeNameIdOfArrayOrSlice=buildTypeMapIndex("[]");const typeNameIdOfTuple=buildTypeMapIndex("tuple");const typeNameIdOfUnit=buildTypeMapIndex("unit");const typeNameIdOfTupleOrUnit=buildTypeMapIndex("()");const typeNameIdOfFn=buildTypeMapIndex("fn");const typeNameIdOfFnMut=buildTypeMapIndex("fnmut");const typeNameIdOfFnOnce=buildTypeMapIndex("fnonce");const typeNameIdOfHof=buildTypeMapIndex("->");function buildTypeMapIndex(name,isAssocType){if(name===""||name===null){return null}if(typeNameIdMap.has(name)){const obj=typeNameIdMap.get(name);obj.assocOnly=isAssocType&&obj.assocOnly;return obj.id}else{const id=typeNameIdMap.size;typeNameIdMap.set(name,{id,assocOnly:isAssocType});return id}}function isSpecialStartCharacter(c){return"<\"".indexOf(c)!==-1}function isEndCharacter(c){return"=,>-])".indexOf(c)!==-1}function itemTypeFromName(typename){const index=itemTypes.findIndex(i=>i===typename);if(index<0){throw["Unknown type filter ",typename]}return index}function getStringElem(query,parserState,isInGenerics){if(isInGenerics){throw["Unexpected ","\""," in generics"]}else if(query.literalSearch){throw["Cannot have more than one literal search element"]}else if(parserState.totalElems-parserState.genericsElems>0){throw["Cannot use literal search when there is more than one element"]}parserState.pos+=1;const start=parserState.pos;const end=getIdentEndPosition(parserState);if(parserState.pos>=parserState.length){throw["Unclosed ","\""]}else if(parserState.userQuery[end]!=="\""){throw["Unexpected ",parserState.userQuery[end]," in a string element"]}else if(start===end){throw["Cannot have empty string element"]}parserState.pos+=1;query.literalSearch=true}function isPathStart(parserState){return parserState.userQuery.slice(parserState.pos,parserState.pos+2)==="::"}function isReturnArrow(parserState){return parserState.userQuery.slice(parserState.pos,parserState.pos+2)==="->"}function consumeIdent(parserState){REGEX_IDENT.lastIndex=parserState.pos;const match=parserState.userQuery.match(REGEX_IDENT);if(match){parserState.pos+=match[0].length;return true}return false}function isSeparatorCharacter(c){return c===","||c==="="}function isPathSeparator(c){return c===":"||c===" "}function prevIs(parserState,lookingFor){let pos=parserState.pos;while(pos>0){const c=parserState.userQuery[pos-1];if(c===lookingFor){return true}else if(c!==" "){break}pos-=1}return false}function isLastElemGeneric(elems,parserState){return(elems.length>0&&elems[elems.length-1].generics.length>0)||prevIs(parserState,">")}function skipWhitespace(parserState){while(parserState.pos0){throw["Cannot have more than one element if you use quotes"]}const typeFilter=parserState.typeFilter;parserState.typeFilter=null;if(name==="!"){if(typeFilter!==null&&typeFilter!=="primitive"){throw["Invalid search type: primitive never type ","!"," and ",typeFilter," both specified",]}if(generics.length!==0){throw["Never type ","!"," does not accept generic parameters",]}const bindingName=parserState.isInBinding;parserState.isInBinding=null;return makePrimitiveElement("never",{bindingName})}const quadcolon=/::\s*::/.exec(path);if(path.startsWith("::")){throw["Paths cannot start with ","::"]}else if(path.endsWith("::")){throw["Paths cannot end with ","::"]}else if(quadcolon!==null){throw["Unexpected ",quadcolon[0]]}const pathSegments=path.split(/(?:::\s*)|(?:\s+(?:::\s*)?)/);if(pathSegments.length===0||(pathSegments.length===1&&pathSegments[0]==="")){if(generics.length>0||prevIs(parserState,">")){throw["Found generics without a path"]}else{throw["Unexpected ",parserState.userQuery[parserState.pos]]}}for(const[i,pathSegment]of pathSegments.entries()){if(pathSegment==="!"){if(i!==0){throw["Never type ","!"," is not associated item"]}pathSegments[i]="never"}}parserState.totalElems+=1;if(isInGenerics){parserState.genericsElems+=1}const bindingName=parserState.isInBinding;parserState.isInBinding=null;const bindings=new Map();const pathLast=pathSegments[pathSegments.length-1];return{name:name.trim(),id:null,fullPath:pathSegments,pathWithoutLast:pathSegments.slice(0,pathSegments.length-1),pathLast,normalizedPathLast:pathLast.replace(/_/g,""),generics:generics.filter(gen=>{if(gen.bindingName!==null){if(gen.name!==null){gen.bindingName.generics.unshift(gen)}bindings.set(gen.bindingName.name,gen.bindingName.generics);return false}return true}),bindings,typeFilter,bindingName,}}function getIdentEndPosition(parserState){let afterIdent=consumeIdent(parserState);let end=parserState.pos;let macroExclamation=-1;while(parserState.pos0){throw["Unexpected ",c," after ",parserState.userQuery[parserState.pos-1]," (not a valid identifier)"]}else{throw["Unexpected ",c," (not a valid identifier)"]}parserState.pos+=1;afterIdent=consumeIdent(parserState);end=parserState.pos}if(macroExclamation!==-1){if(parserState.typeFilter===null){parserState.typeFilter="macro"}else if(parserState.typeFilter!=="macro"){throw["Invalid search type: macro ","!"," and ",parserState.typeFilter," both specified",]}end=macroExclamation}return end}function getFilteredNextElem(query,parserState,elems,isInGenerics){const start=parserState.pos;if(parserState.userQuery[parserState.pos]===":"&&!isPathStart(parserState)){throw["Expected type filter before ",":"]}getNextElem(query,parserState,elems,isInGenerics);if(parserState.userQuery[parserState.pos]===":"&&!isPathStart(parserState)){if(parserState.typeFilter!==null){throw["Unexpected ",":"," (expected path after type filter ",parserState.typeFilter+":",")",]}if(elems.length===0){throw["Expected type filter before ",":"]}else if(query.literalSearch){throw["Cannot use quotes on type filter"]}const typeFilterElem=elems.pop();checkExtraTypeFilterCharacters(start,parserState);parserState.typeFilter=typeFilterElem.name;parserState.pos+=1;parserState.totalElems-=1;query.literalSearch=false;getNextElem(query,parserState,elems,isInGenerics)}}function getNextElem(query,parserState,elems,isInGenerics){const generics=[];skipWhitespace(parserState);let start=parserState.pos;let end;if("[(".indexOf(parserState.userQuery[parserState.pos])!==-1){let endChar=")";let name="()";let friendlyName="tuple";if(parserState.userQuery[parserState.pos]==="["){endChar="]";name="[]";friendlyName="slice"}parserState.pos+=1;const{foundSeparator}=getItemsBefore(query,parserState,generics,endChar);const typeFilter=parserState.typeFilter;const bindingName=parserState.isInBinding;parserState.typeFilter=null;parserState.isInBinding=null;for(const gen of generics){if(gen.bindingName!==null){throw["Type parameter ","=",` cannot be within ${friendlyName} `,name]}}if(name==="()"&&!foundSeparator&&generics.length===1&&typeFilter===null){elems.push(generics[0])}else if(name==="()"&&generics.length===1&&generics[0].name==="->"){generics[0].typeFilter=typeFilter;elems.push(generics[0])}else{if(typeFilter!==null&&typeFilter!=="primitive"){throw["Invalid search type: primitive ",name," and ",typeFilter," both specified",]}parserState.totalElems+=1;if(isInGenerics){parserState.genericsElems+=1}elems.push(makePrimitiveElement(name,{bindingName,generics}))}}else if(parserState.userQuery[parserState.pos]==="&"){if(parserState.typeFilter!==null&&parserState.typeFilter!=="primitive"){throw["Invalid search type: primitive ","&"," and ",parserState.typeFilter," both specified",]}parserState.typeFilter=null;parserState.pos+=1;let c=parserState.userQuery[parserState.pos];while(c===" "&&parserState.pos=end){throw["Found generics without a path"]}parserState.pos+=1;getItemsBefore(query,parserState,generics,">")}else if(parserState.pos=end){throw["Found generics without a path"]}if(parserState.isInBinding){throw["Unexpected ","("," after ","="]}parserState.pos+=1;const typeFilter=parserState.typeFilter;parserState.typeFilter=null;getItemsBefore(query,parserState,generics,")");skipWhitespace(parserState);if(isReturnArrow(parserState)){parserState.pos+=2;skipWhitespace(parserState);getFilteredNextElem(query,parserState,generics,isInGenerics);generics[generics.length-1].bindingName=makePrimitiveElement("output")}else{generics.push(makePrimitiveElement(null,{bindingName:makePrimitiveElement("output"),typeFilter:null,}))}parserState.typeFilter=typeFilter}if(isStringElem){skipWhitespace(parserState)}if(start>=end&&generics.length===0){return}if(parserState.userQuery[parserState.pos]==="="){if(parserState.isInBinding){throw["Cannot write ","="," twice in a binding"]}if(!isInGenerics){throw["Type parameter ","="," must be within generics list"]}const name=parserState.userQuery.slice(start,end).trim();if(name==="!"){throw["Type parameter ","="," key cannot be ","!"," never type"]}if(name.includes("!")){throw["Type parameter ","="," key cannot be ","!"," macro"]}if(name.includes("::")){throw["Type parameter ","="," key cannot contain ","::"," path"]}if(name.includes(":")){throw["Type parameter ","="," key cannot contain ",":"," type"]}parserState.isInBinding={name,generics}}else{elems.push(createQueryElement(query,parserState,parserState.userQuery.slice(start,end),generics,isInGenerics,),)}}}function getItemsBefore(query,parserState,elems,endChar){let foundStopChar=true;let foundSeparator=false;const oldTypeFilter=parserState.typeFilter;parserState.typeFilter=null;const oldIsInBinding=parserState.isInBinding;parserState.isInBinding=null;let hofParameters=null;let extra="";if(endChar===">"){extra="<"}else if(endChar==="]"){extra="["}else if(endChar===")"){extra="("}else if(endChar===""){extra="->"}else{extra=endChar}while(parserState.pos"," after ","="]}hofParameters=[...elems];elems.length=0;parserState.pos+=2;foundStopChar=true;foundSeparator=false;continue}else if(c===" "){parserState.pos+=1;continue}else if(isSeparatorCharacter(c)){parserState.pos+=1;foundStopChar=true;foundSeparator=true;continue}else if(c===":"&&isPathStart(parserState)){throw["Unexpected ","::",": paths cannot start with ","::"]}else if(isEndCharacter(c)){throw["Unexpected ",c," after ",extra]}if(!foundStopChar){let extra=[];if(isLastElemGeneric(query.elems,parserState)){extra=[" after ",">"]}else if(prevIs(parserState,"\"")){throw["Cannot have more than one element if you use quotes"]}if(endChar!==""){throw["Expected ",",",", ","=",", or ",endChar,...extra,", found ",c,]}throw["Expected ",","," or ","=",...extra,", found ",c,]}const posBefore=parserState.pos;getFilteredNextElem(query,parserState,elems,endChar!=="");if(endChar!==""&&parserState.pos>=parserState.length){throw["Unclosed ",extra]}if(posBefore===parserState.pos){parserState.pos+=1}foundStopChar=false}if(parserState.pos>=parserState.length&&endChar!==""){throw["Unclosed ",extra]}parserState.pos+=1;if(hofParameters){foundSeparator=false;if([...elems,...hofParameters].some(x=>x.bindingName)||parserState.isInBinding){throw["Unexpected ","="," within ","->"]}const hofElem=makePrimitiveElement("->",{generics:hofParameters,bindings:new Map([["output",[...elems]]]),typeFilter:null,});elems.length=0;elems[0]=hofElem}parserState.typeFilter=oldTypeFilter;parserState.isInBinding=oldIsInBinding;return{foundSeparator}}function checkExtraTypeFilterCharacters(start,parserState){const query=parserState.userQuery.slice(start,parserState.pos).trim();const match=query.match(REGEX_INVALID_TYPE_FILTER);if(match){throw["Unexpected ",match[0]," in type filter (before ",":",")",]}}function parseInput(query,parserState){let foundStopChar=true;while(parserState.pos"){if(isReturnArrow(parserState)){break}throw["Unexpected ",c," (did you mean ","->","?)"]}else if(parserState.pos>0){throw["Unexpected ",c," after ",parserState.userQuery[parserState.pos-1]]}throw["Unexpected ",c]}else if(c===" "){skipWhitespace(parserState);continue}if(!foundStopChar){let extra="";if(isLastElemGeneric(query.elems,parserState)){extra=[" after ",">"]}else if(prevIs(parserState,"\"")){throw["Cannot have more than one element if you use quotes"]}if(parserState.typeFilter!==null){throw["Expected ",","," or ","->",...extra,", found ",c,]}throw["Expected ",",",", ",":"," or ","->",...extra,", found ",c,]}const before=query.elems.length;getFilteredNextElem(query,parserState,query.elems,false);if(query.elems.length===before){parserState.pos+=1}foundStopChar=false}if(parserState.typeFilter!==null){throw["Unexpected ",":"," (expected path after type filter ",parserState.typeFilter+":",")",]}while(parserState.pos"]}break}else{parserState.pos+=1}}}function newParsedQuery(userQuery){return{original:userQuery,userQuery:userQuery.toLowerCase(),elems:[],returned:[],foundElems:0,totalElems:0,literalSearch:false,error:null,correction:null,proposeCorrectionFrom:null,proposeCorrectionTo:null,typeFingerprint:new Uint32Array(4),}}function buildUrl(search,filterCrates){let extra="?search="+encodeURIComponent(search);if(filterCrates!==null){extra+="&filter-crate="+encodeURIComponent(filterCrates)}return getNakedUrl()+extra+window.location.hash}function getFilterCrates(){const elem=document.getElementById("crate-search");if(elem&&elem.value!=="all crates"&&rawSearchIndex.has(elem.value)){return elem.value}return null}function parseQuery(userQuery){function convertTypeFilterOnElem(elem){if(elem.typeFilter!==null){let typeFilter=elem.typeFilter;if(typeFilter==="const"){typeFilter="constant"}elem.typeFilter=itemTypeFromName(typeFilter)}else{elem.typeFilter=NO_TYPE_FILTER}for(const elem2 of elem.generics){convertTypeFilterOnElem(elem2)}for(const constraints of elem.bindings.values()){for(const constraint of constraints){convertTypeFilterOnElem(constraint)}}}userQuery=userQuery.trim().replace(/\r|\n|\t/g," ");const parserState={length:userQuery.length,pos:0,totalElems:0,genericsElems:0,typeFilter:null,isInBinding:null,userQuery:userQuery.toLowerCase(),};let query=newParsedQuery(userQuery);try{parseInput(query,parserState);for(const elem of query.elems){convertTypeFilterOnElem(elem)}for(const elem of query.returned){convertTypeFilterOnElem(elem)}}catch(err){query=newParsedQuery(userQuery);query.error=err;return query}if(!query.literalSearch){query.literalSearch=parserState.totalElems>1}query.foundElems=query.elems.length+query.returned.length;query.totalElems=parserState.totalElems;return query}function createQueryResults(results_in_args,results_returned,results_others,parsedQuery){return{"in_args":results_in_args,"returned":results_returned,"others":results_others,"query":parsedQuery,}}async function execQuery(parsedQuery,filterCrates,currentCrate){const results_others=new Map(),results_in_args=new Map(),results_returned=new Map();function transformResults(results){const duplicates=new Set();const out=[];for(const result of results){if(result.id!==-1){const obj=searchIndex[result.id];obj.dist=result.dist;const res=buildHrefAndPath(obj);obj.displayPath=pathSplitter(res[0]);obj.fullPath=res[2]+"|"+obj.ty;if(duplicates.has(obj.fullPath)){continue}if(obj.ty===TY_IMPORT&&duplicates.has(res[2])){continue}if(duplicates.has(res[2]+"|"+TY_IMPORT)){continue}duplicates.add(obj.fullPath);duplicates.add(res[2]);obj.href=res[1];out.push(obj);if(out.length>=MAX_RESULTS){break}}}return out}async function sortResults(results,isType,preferredCrate){const userQuery=parsedQuery.userQuery;const result_list=[];for(const result of results.values()){result.item=searchIndex[result.id];result.word=searchIndex[result.id].word;result_list.push(result)}result_list.sort((aaa,bbb)=>{let a,b;a=(aaa.word!==userQuery);b=(bbb.word!==userQuery);if(a!==b){return a-b}a=(aaa.index<0);b=(bbb.index<0);if(a!==b){return a-b}a=aaa.path_dist;b=bbb.path_dist;if(a!==b){return a-b}a=aaa.index;b=bbb.index;if(a!==b){return a-b}a=(aaa.dist);b=(bbb.dist);if(a!==b){return a-b}a=searchIndexDeprecated.get(aaa.item.crate).contains(aaa.item.bitIndex);b=searchIndexDeprecated.get(bbb.item.crate).contains(bbb.item.bitIndex);if(a!==b){return a-b}a=(aaa.item.crate!==preferredCrate);b=(bbb.item.crate!==preferredCrate);if(a!==b){return a-b}a=aaa.word.length;b=bbb.word.length;if(a!==b){return a-b}a=aaa.word;b=bbb.word;if(a!==b){return(a>b?+1:-1)}a=searchIndexEmptyDesc.get(aaa.item.crate).contains(aaa.item.bitIndex);b=searchIndexEmptyDesc.get(bbb.item.crate).contains(bbb.item.bitIndex);if(a!==b){return a-b}a=aaa.item.ty;b=bbb.item.ty;if(a!==b){return a-b}a=aaa.item.path;b=bbb.item.path;if(a!==b){return(a>b?+1:-1)}return 0});return transformResults(result_list)}function unifyFunctionTypes(fnTypesIn,queryElems,whereClause,mgensIn,solutionCb,unboxingDepth,){if(unboxingDepth>=UNBOXING_LIMIT){return false}const mgens=mgensIn===null?null:new Map(mgensIn);if(queryElems.length===0){return!solutionCb||solutionCb(mgens)}if(!fnTypesIn||fnTypesIn.length===0){return false}const ql=queryElems.length;const fl=fnTypesIn.length;if(ql===1&&queryElems[0].generics.length===0&&queryElems[0].bindings.size===0){const queryElem=queryElems[0];for(const fnType of fnTypesIn){if(!unifyFunctionTypeIsMatchCandidate(fnType,queryElem,mgens)){continue}if(fnType.id<0&&queryElem.id<0){if(mgens&&mgens.has(fnType.id)&&mgens.get(fnType.id)!==queryElem.id){continue}const mgensScratch=new Map(mgens);mgensScratch.set(fnType.id,queryElem.id);if(!solutionCb||solutionCb(mgensScratch)){return true}}else if(!solutionCb||solutionCb(mgens?new Map(mgens):null)){return true}}for(const fnType of fnTypesIn){if(!unifyFunctionTypeIsUnboxCandidate(fnType,queryElem,whereClause,mgens,unboxingDepth+1,)){continue}if(fnType.id<0){if(mgens&&mgens.has(fnType.id)&&mgens.get(fnType.id)!==0){continue}const mgensScratch=new Map(mgens);mgensScratch.set(fnType.id,0);if(unifyFunctionTypes(whereClause[(-fnType.id)-1],queryElems,whereClause,mgensScratch,solutionCb,unboxingDepth+1,)){return true}}else if(unifyFunctionTypes([...fnType.generics,...Array.from(fnType.bindings.values()).flat()],queryElems,whereClause,mgens?new Map(mgens):null,solutionCb,unboxingDepth+1,)){return true}}return false}const fnTypes=fnTypesIn.slice();const flast=fl-1;const qlast=ql-1;const queryElem=queryElems[qlast];let queryElemsTmp=null;for(let i=flast;i>=0;i-=1){const fnType=fnTypes[i];if(!unifyFunctionTypeIsMatchCandidate(fnType,queryElem,mgens)){continue}let mgensScratch;if(fnType.id<0){mgensScratch=new Map(mgens);if(mgensScratch.has(fnType.id)&&mgensScratch.get(fnType.id)!==queryElem.id){continue}mgensScratch.set(fnType.id,queryElem.id)}else{mgensScratch=mgens}fnTypes[i]=fnTypes[flast];fnTypes.length=flast;if(!queryElemsTmp){queryElemsTmp=queryElems.slice(0,qlast)}const passesUnification=unifyFunctionTypes(fnTypes,queryElemsTmp,whereClause,mgensScratch,mgensScratch=>{if(fnType.generics.length===0&&queryElem.generics.length===0&&fnType.bindings.size===0&&queryElem.bindings.size===0){return!solutionCb||solutionCb(mgensScratch)}const solution=unifyFunctionTypeCheckBindings(fnType,queryElem,whereClause,mgensScratch,unboxingDepth,);if(!solution){return false}const simplifiedGenerics=solution.simplifiedGenerics;for(const simplifiedMgens of solution.mgens){const passesUnification=unifyFunctionTypes(simplifiedGenerics,queryElem.generics,whereClause,simplifiedMgens,solutionCb,unboxingDepth,);if(passesUnification){return true}}return false},unboxingDepth,);if(passesUnification){return true}fnTypes[flast]=fnTypes[i];fnTypes[i]=fnType;fnTypes.length=fl}for(let i=flast;i>=0;i-=1){const fnType=fnTypes[i];if(!unifyFunctionTypeIsUnboxCandidate(fnType,queryElem,whereClause,mgens,unboxingDepth+1,)){continue}let mgensScratch;if(fnType.id<0){mgensScratch=new Map(mgens);if(mgensScratch.has(fnType.id)&&mgensScratch.get(fnType.id)!==0){continue}mgensScratch.set(fnType.id,0)}else{mgensScratch=mgens}const generics=fnType.id<0?whereClause[(-fnType.id)-1]:fnType.generics;const bindings=fnType.bindings?Array.from(fnType.bindings.values()).flat():[];const passesUnification=unifyFunctionTypes(fnTypes.toSpliced(i,1,...generics,...bindings),queryElems,whereClause,mgensScratch,solutionCb,unboxingDepth+1,);if(passesUnification){return true}}return false}function unifyFunctionTypeIsMatchCandidate(fnType,queryElem,mgensIn){if(!typePassesFilter(queryElem.typeFilter,fnType.ty)){return false}if(fnType.id<0&&queryElem.id<0){if(mgensIn){if(mgensIn.has(fnType.id)&&mgensIn.get(fnType.id)!==queryElem.id){return false}for(const[fid,qid]of mgensIn.entries()){if(fnType.id!==fid&&queryElem.id===qid){return false}if(fnType.id===fid&&queryElem.id!==qid){return false}}}return true}else{if(queryElem.id===typeNameIdOfArrayOrSlice&&(fnType.id===typeNameIdOfSlice||fnType.id===typeNameIdOfArray)){}else if(queryElem.id===typeNameIdOfTupleOrUnit&&(fnType.id===typeNameIdOfTuple||fnType.id===typeNameIdOfUnit)){}else if(queryElem.id===typeNameIdOfHof&&(fnType.id===typeNameIdOfFn||fnType.id===typeNameIdOfFnMut||fnType.id===typeNameIdOfFnOnce)){}else if(fnType.id!==queryElem.id||queryElem.id===null){return false}if((fnType.generics.length+fnType.bindings.size)===0&&queryElem.generics.length!==0){return false}if(fnType.bindings.size0){const fnTypePath=fnType.path!==undefined&&fnType.path!==null?fnType.path.split("::"):[];if(queryElemPathLength>fnTypePath.length){return false}let i=0;for(const path of fnTypePath){if(path===queryElem.pathWithoutLast[i]){i+=1;if(i>=queryElemPathLength){break}}}if(i0){let mgensSolutionSet=[mgensIn];for(const[name,constraints]of queryElem.bindings.entries()){if(mgensSolutionSet.length===0){return false}if(!fnType.bindings.has(name)){return false}const fnTypeBindings=fnType.bindings.get(name);mgensSolutionSet=mgensSolutionSet.flatMap(mgens=>{const newSolutions=[];unifyFunctionTypes(fnTypeBindings,constraints,whereClause,mgens,newMgens=>{newSolutions.push(newMgens);return false},unboxingDepth,);return newSolutions})}if(mgensSolutionSet.length===0){return false}const binds=Array.from(fnType.bindings.entries()).flatMap(entry=>{const[name,constraints]=entry;if(queryElem.bindings.has(name)){return[]}else{return constraints}});if(simplifiedGenerics.length>0){simplifiedGenerics=[...simplifiedGenerics,...binds]}else{simplifiedGenerics=binds}return{simplifiedGenerics,mgens:mgensSolutionSet}}return{simplifiedGenerics,mgens:[mgensIn]}}function unifyFunctionTypeIsUnboxCandidate(fnType,queryElem,whereClause,mgens,unboxingDepth,){if(unboxingDepth>=UNBOXING_LIMIT){return false}if(fnType.id<0&&queryElem.id>=0){if(!whereClause){return false}if(mgens&&mgens.has(fnType.id)&&mgens.get(fnType.id)!==0){return false}const mgensTmp=new Map(mgens);mgensTmp.set(fnType.id,null);return checkIfInList(whereClause[(-fnType.id)-1],queryElem,whereClause,mgensTmp,unboxingDepth,)}else if(fnType.generics.length>0||fnType.bindings.size>0){const simplifiedGenerics=[...fnType.generics,...Array.from(fnType.bindings.values()).flat(),];return checkIfInList(simplifiedGenerics,queryElem,whereClause,mgens,unboxingDepth,)}return false}function checkIfInList(list,elem,whereClause,mgens,unboxingDepth){for(const entry of list){if(checkType(entry,elem,whereClause,mgens,unboxingDepth)){return true}}return false}function checkType(row,elem,whereClause,mgens,unboxingDepth){if(unboxingDepth>=UNBOXING_LIMIT){return false}if(row.bindings.size===0&&elem.bindings.size===0){if(elem.id<0&&mgens===null){return row.id<0||checkIfInList(row.generics,elem,whereClause,mgens,unboxingDepth+1,)}if(row.id>0&&elem.id>0&&elem.pathWithoutLast.length===0&&typePassesFilter(elem.typeFilter,row.ty)&&elem.generics.length===0&&elem.id!==typeNameIdOfArrayOrSlice&&elem.id!==typeNameIdOfTupleOrUnit&&elem.id!==typeNameIdOfHof){return row.id===elem.id||checkIfInList(row.generics,elem,whereClause,mgens,unboxingDepth,)}}return unifyFunctionTypes([row],[elem],whereClause,mgens,null,unboxingDepth)}function checkPath(contains,ty){if(contains.length===0){return 0}const maxPathEditDistance=Math.floor(contains.reduce((acc,next)=>acc+next.length,0)/3,);let ret_dist=maxPathEditDistance+1;const path=ty.path.split("::");if(ty.parent&&ty.parent.name){path.push(ty.parent.name.toLowerCase())}const length=path.length;const clength=contains.length;pathiter:for(let i=length-clength;i>=0;i-=1){let dist_total=0;for(let x=0;xmaxPathEditDistance){continue pathiter}dist_total+=dist}}ret_dist=Math.min(ret_dist,Math.round(dist_total/clength))}return ret_dist>maxPathEditDistance?null:ret_dist}function typePassesFilter(filter,type){if(filter<=NO_TYPE_FILTER||filter===type)return true;const name=itemTypes[type];switch(itemTypes[filter]){case"constant":return name==="associatedconstant";case"fn":return name==="method"||name==="tymethod";case"type":return name==="primitive"||name==="associatedtype";case"trait":return name==="traitalias"}return false}function createAliasFromItem(item){return{crate:item.crate,name:item.name,path:item.path,descShard:item.descShard,descIndex:item.descIndex,exactPath:item.exactPath,ty:item.ty,parent:item.parent,type:item.type,is_alias:true,bitIndex:item.bitIndex,implDisambiguator:item.implDisambiguator,}}async function handleAliases(ret,query,filterCrates,currentCrate){const lowerQuery=query.toLowerCase();const aliases=[];const crateAliases=[];if(filterCrates!==null){if(ALIASES.has(filterCrates)&&ALIASES.get(filterCrates).has(lowerQuery)){const query_aliases=ALIASES.get(filterCrates).get(lowerQuery);for(const alias of query_aliases){aliases.push(createAliasFromItem(searchIndex[alias]))}}}else{for(const[crate,crateAliasesIndex]of ALIASES){if(crateAliasesIndex.has(lowerQuery)){const pushTo=crate===currentCrate?crateAliases:aliases;const query_aliases=crateAliasesIndex.get(lowerQuery);for(const alias of query_aliases){pushTo.push(createAliasFromItem(searchIndex[alias]))}}}}const sortFunc=(aaa,bbb)=>{if(aaa.path{return searchIndexEmptyDesc.get(alias.crate).contains(alias.bitIndex)?"":searchState.loadDesc(alias)};const[crateDescs,descs]=await Promise.all([Promise.all(crateAliases.map(fetchDesc)),Promise.all(aliases.map(fetchDesc)),]);const pushFunc=alias=>{alias.alias=query;const res=buildHrefAndPath(alias);alias.displayPath=pathSplitter(res[0]);alias.fullPath=alias.displayPath+alias.name;alias.href=res[1];ret.others.unshift(alias);if(ret.others.length>MAX_RESULTS){ret.others.pop()}};aliases.forEach((alias,i)=>{alias.desc=descs[i]});aliases.forEach(pushFunc);crateAliases.forEach((alias,i)=>{alias.desc=crateDescs[i]});crateAliases.forEach(pushFunc)}function addIntoResults(results,fullId,id,index,dist,path_dist,maxEditDistance){if(dist<=maxEditDistance||index!==-1){if(results.has(fullId)){const result=results.get(fullId);if(result.dontValidate||result.dist<=dist){return}}results.set(fullId,{id:id,index:index,dontValidate:parsedQuery.literalSearch,dist:dist,path_dist:path_dist,})}}function handleSingleArg(row,pos,elem,results_others,results_in_args,results_returned,maxEditDistance,){if(!row||(filterCrates!==null&&row.crate!==filterCrates)){return}let path_dist=0;const fullId=row.id;const tfpDist=compareTypeFingerprints(fullId,parsedQuery.typeFingerprint,);if(tfpDist!==null){const in_args=row.type&&row.type.inputs&&checkIfInList(row.type.inputs,elem,row.type.where_clause,null,0);const returned=row.type&&row.type.output&&checkIfInList(row.type.output,elem,row.type.where_clause,null,0);if(in_args){results_in_args.max_dist=Math.max(results_in_args.max_dist||0,tfpDist);const maxDist=results_in_args.sizenormalizedIndex&&normalizedIndex!==-1)){index=normalizedIndex}if(elem.fullPath.length>1){path_dist=checkPath(elem.pathWithoutLast,row);if(path_dist===null){return}}if(parsedQuery.literalSearch){if(row.word===elem.pathLast){addIntoResults(results_others,fullId,pos,index,0,path_dist)}return}const dist=editDistance(row.normalizedName,elem.normalizedPathLast,maxEditDistance);if(index===-1&&dist>maxEditDistance){return}addIntoResults(results_others,fullId,pos,index,dist,path_dist,maxEditDistance)}function handleArgs(row,pos,results){if(!row||(filterCrates!==null&&row.crate!==filterCrates)||!row.type){return}const tfpDist=compareTypeFingerprints(row.id,parsedQuery.typeFingerprint,);if(tfpDist===null){return}if(results.size>=MAX_RESULTS&&tfpDist>results.max_dist){return}if(!unifyFunctionTypes(row.type.inputs,parsedQuery.elems,row.type.where_clause,null,mgens=>{return unifyFunctionTypes(row.type.output,parsedQuery.returned,row.type.where_clause,mgens,null,0,)},0,)){return}results.max_dist=Math.max(results.max_dist||0,tfpDist);addIntoResults(results,row.id,pos,0,tfpDist,0,Number.MAX_VALUE)}function innerRunQuery(){const queryLen=parsedQuery.elems.reduce((acc,next)=>acc+next.pathLast.length,0)+parsedQuery.returned.reduce((acc,next)=>acc+next.pathLast.length,0);const maxEditDistance=Math.floor(queryLen/3);const genericSymbols=new Map();function convertNameToId(elem,isAssocType){const loweredName=elem.pathLast.toLowerCase();if(typeNameIdMap.has(loweredName)&&(isAssocType||!typeNameIdMap.get(loweredName).assocOnly)){elem.id=typeNameIdMap.get(loweredName).id}else if(!parsedQuery.literalSearch){let match=null;let matchDist=maxEditDistance+1;let matchName="";for(const[name,{id,assocOnly}]of typeNameIdMap){const dist=Math.min(editDistance(name,loweredName,maxEditDistance),editDistance(name,elem.normalizedPathLast,maxEditDistance),);if(dist<=matchDist&&dist<=maxEditDistance&&(isAssocType||!assocOnly)){if(dist===matchDist&&matchName>name){continue}match=id;matchDist=dist;matchName=name}}if(match!==null){parsedQuery.correction=matchName}elem.id=match}if((elem.id===null&&parsedQuery.totalElems>1&&elem.typeFilter===-1&&elem.generics.length===0&&elem.bindings.size===0)||elem.typeFilter===TY_GENERIC){if(genericSymbols.has(elem.name)){elem.id=genericSymbols.get(elem.name)}else{elem.id=-(genericSymbols.size+1);genericSymbols.set(elem.name,elem.id)}if(elem.typeFilter===-1&&elem.name.length>=3){const maxPartDistance=Math.floor(elem.name.length/3);let matchDist=maxPartDistance+1;let matchName="";for(const name of typeNameIdMap.keys()){const dist=editDistance(name,elem.name,maxPartDistance);if(dist<=matchDist&&dist<=maxPartDistance){if(dist===matchDist&&matchName>name){continue}matchDist=dist;matchName=name}}if(matchName!==""){parsedQuery.proposeCorrectionFrom=elem.name;parsedQuery.proposeCorrectionTo=matchName}}elem.typeFilter=TY_GENERIC}if(elem.generics.length>0&&elem.typeFilter===TY_GENERIC){parsedQuery.error=["Generic type parameter ",elem.name," does not accept generic parameters",]}for(const elem2 of elem.generics){convertNameToId(elem2)}elem.bindings=new Map(Array.from(elem.bindings.entries()).map(entry=>{const[name,constraints]=entry;if(!typeNameIdMap.has(name)){parsedQuery.error=["Type parameter ",name," does not exist",];return[null,[]]}for(const elem2 of constraints){convertNameToId(elem2)}return[typeNameIdMap.get(name).id,constraints]}),)}const fps=new Set();for(const elem of parsedQuery.elems){convertNameToId(elem);buildFunctionTypeFingerprint(elem,parsedQuery.typeFingerprint,fps)}for(const elem of parsedQuery.returned){convertNameToId(elem);buildFunctionTypeFingerprint(elem,parsedQuery.typeFingerprint,fps)}if(parsedQuery.foundElems===1&&parsedQuery.returned.length===0){if(parsedQuery.elems.length===1){const elem=parsedQuery.elems[0];for(let i=0,nSearchIndex=searchIndex.length;i0){const sortQ=(a,b)=>{const ag=a.generics.length===0&&a.bindings.size===0;const bg=b.generics.length===0&&b.bindings.size===0;if(ag!==bg){return ag-bg}const ai=a.id>0;const bi=b.id>0;return ai-bi};parsedQuery.elems.sort(sortQ);parsedQuery.returned.sort(sortQ);for(let i=0,nSearchIndex=searchIndex.length;i{const descs=await Promise.all(list.map(result=>{return searchIndexEmptyDesc.get(result.crate).contains(result.bitIndex)?"":searchState.loadDesc(result)}));for(const[i,result]of list.entries()){result.desc=descs[i]}}));if(parsedQuery.error!==null&&ret.others.length!==0){ret.query.error=null}return ret}function nextTab(direction){const next=(searchState.currentTab+direction+3)%searchState.focusedByTab.length;searchState.focusedByTab[searchState.currentTab]=document.activeElement;printTab(next);focusSearchResult()}function focusSearchResult(){const target=searchState.focusedByTab[searchState.currentTab]||document.querySelectorAll(".search-results.active a").item(0)||document.querySelectorAll("#search-tabs button").item(searchState.currentTab);searchState.focusedByTab[searchState.currentTab]=null;if(target){target.focus()}}function buildHrefAndPath(item){let displayPath;let href;const type=itemTypes[item.ty];const name=item.name;let path=item.path;let exactPath=item.exactPath;if(type==="mod"){displayPath=path+"::";href=ROOT_PATH+path.replace(/::/g,"/")+"/"+name+"/index.html"}else if(type==="import"){displayPath=item.path+"::";href=ROOT_PATH+item.path.replace(/::/g,"/")+"/index.html#reexport."+name}else if(type==="primitive"||type==="keyword"){displayPath="";href=ROOT_PATH+path.replace(/::/g,"/")+"/"+type+"."+name+".html"}else if(type==="externcrate"){displayPath="";href=ROOT_PATH+name+"/index.html"}else if(item.parent!==undefined){const myparent=item.parent;let anchor=type+"."+name;const parentType=itemTypes[myparent.ty];let pageType=parentType;let pageName=myparent.name;exactPath=`${myparent.exactPath}::${myparent.name}`;if(parentType==="primitive"){displayPath=myparent.name+"::"}else if(type==="structfield"&&parentType==="variant"){const enumNameIdx=item.path.lastIndexOf("::");const enumName=item.path.substr(enumNameIdx+2);path=item.path.substr(0,enumNameIdx);displayPath=path+"::"+enumName+"::"+myparent.name+"::";anchor="variant."+myparent.name+".field."+name;pageType="enum";pageName=enumName}else{displayPath=path+"::"+myparent.name+"::"}if(item.implDisambiguator!==null){anchor=item.implDisambiguator+"/"+anchor}href=ROOT_PATH+path.replace(/::/g,"/")+"/"+pageType+"."+pageName+".html#"+anchor}else{displayPath=item.path+"::";href=ROOT_PATH+item.path.replace(/::/g,"/")+"/"+type+"."+name+".html"}return[displayPath,href,`${exactPath}::${name}`]}function pathSplitter(path){const tmp=""+path.replace(/::/g,"::");if(tmp.endsWith("")){return tmp.slice(0,tmp.length-6)}return tmp}async function addTab(array,query,display){const extraClass=display?" active":"";const output=document.createElement("div");if(array.length>0){output.className="search-results "+extraClass;for(const item of array){const name=item.name;const type=itemTypes[item.ty];const longType=longItemTypes[item.ty];const typeName=longType.length!==0?`${longType}`:"?";const link=document.createElement("a");link.className="result-"+type;link.href=item.href;const resultName=document.createElement("div");resultName.className="result-name";resultName.insertAdjacentHTML("beforeend",`${typeName}`);link.appendChild(resultName);let alias=" ";if(item.is_alias){alias=`
\ +${item.alias} - see \ +
`}resultName.insertAdjacentHTML("beforeend",`
${alias}\ +${item.displayPath}${name}\ +
`);const description=document.createElement("div");description.className="desc";description.insertAdjacentHTML("beforeend",item.desc);link.appendChild(description);output.appendChild(link)}}else if(query.error===null){output.className="search-failed"+extraClass;output.innerHTML="No results :(
"+"Try on DuckDuckGo?

"+"Or try looking in one of these:"}return[output,array.length]}function makeTabHeader(tabNb,text,nbElems){const fmtNbElems=nbElems<10?`\u{2007}(${nbElems})\u{2007}\u{2007}`:nbElems<100?`\u{2007}(${nbElems})\u{2007}`:`\u{2007}(${nbElems})`;if(searchState.currentTab===tabNb){return""}return""}async function showResults(results,go_to_first,filterCrates){const search=searchState.outputElement();if(go_to_first||(results.others.length===1&&getSettingValue("go-to-only-result")==="true")){window.onunload=()=>{};searchState.removeQueryParameters();const elem=document.createElement("a");elem.href=results.others[0].href;removeClass(elem,"active");document.body.appendChild(elem);elem.click();return}if(results.query===undefined){results.query=parseQuery(searchState.input.value)}currentResults=results.query.userQuery;const[ret_others,ret_in_args,ret_returned]=await Promise.all([addTab(results.others,results.query,true),addTab(results.in_args,results.query,false),addTab(results.returned,results.query,false),]);let currentTab=searchState.currentTab;if((currentTab===0&&ret_others[1]===0)||(currentTab===1&&ret_in_args[1]===0)||(currentTab===2&&ret_returned[1]===0)){if(ret_others[1]!==0){currentTab=0}else if(ret_in_args[1]!==0){currentTab=1}else if(ret_returned[1]!==0){currentTab=2}}let crates="";if(rawSearchIndex.size>1){crates=" in 
"}let output=`

Results${crates}

`;if(results.query.error!==null){const error=results.query.error;error.forEach((value,index)=>{value=value.split("<").join("<").split(">").join(">");if(index%2!==0){error[index]=`${value.replaceAll(" ", " ")}`}else{error[index]=value}});output+=`

Query parser error: "${error.join("")}".

`;output+="
"+makeTabHeader(0,"In Names",ret_others[1])+"
";currentTab=0}else if(results.query.foundElems<=1&&results.query.returned.length===0){output+="
"+makeTabHeader(0,"In Names",ret_others[1])+makeTabHeader(1,"In Parameters",ret_in_args[1])+makeTabHeader(2,"In Return Types",ret_returned[1])+"
"}else{const signatureTabTitle=results.query.elems.length===0?"In Function Return Types":results.query.returned.length===0?"In Function Parameters":"In Function Signatures";output+="
"+makeTabHeader(0,signatureTabTitle,ret_others[1])+"
";currentTab=0}if(results.query.correction!==null){const orig=results.query.returned.length>0?results.query.returned[0].name:results.query.elems[0].name;output+="

"+`Type "${orig}" not found. `+"Showing results for closest type name "+`"${results.query.correction}" instead.

`}if(results.query.proposeCorrectionFrom!==null){const orig=results.query.proposeCorrectionFrom;const targ=results.query.proposeCorrectionTo;output+="

"+`Type "${orig}" not found and used as generic parameter. `+`Consider searching for "${targ}" instead.

`}const resultsElem=document.createElement("div");resultsElem.id="results";resultsElem.appendChild(ret_others[0]);resultsElem.appendChild(ret_in_args[0]);resultsElem.appendChild(ret_returned[0]);search.innerHTML=output;const crateSearch=document.getElementById("crate-search");if(crateSearch){crateSearch.addEventListener("input",updateCrate)}search.appendChild(resultsElem);searchState.showResults(search);const elems=document.getElementById("search-tabs").childNodes;searchState.focusedByTab=[];let i=0;for(const elem of elems){const j=i;elem.onclick=()=>printTab(j);searchState.focusedByTab.push(null);i+=1}printTab(currentTab)}function updateSearchHistory(url){if(!browserSupportsHistoryApi()){return}const params=searchState.getQueryStringParams();if(!history.state&&!params.search){history.pushState(null,"",url)}else{history.replaceState(null,"",url)}}async function search(forced){const query=parseQuery(searchState.input.value.trim());let filterCrates=getFilterCrates();if(!forced&&query.userQuery===currentResults){if(query.userQuery.length>0){putBackSearch()}return}searchState.setLoadingSearch();const params=searchState.getQueryStringParams();if(filterCrates===null&¶ms["filter-crate"]!==undefined){filterCrates=params["filter-crate"]}searchState.title="Results for "+query.original+" - Rust";updateSearchHistory(buildUrl(query.original,filterCrates));await showResults(await execQuery(query,filterCrates,window.currentCrate),params.go_to_first,filterCrates)}function buildItemSearchTypeAll(types,lowercasePaths){return types.length>0?types.map(type=>buildItemSearchType(type,lowercasePaths)):EMPTY_GENERICS_ARRAY}const EMPTY_BINDINGS_MAP=new Map();const EMPTY_GENERICS_ARRAY=[];let TYPES_POOL=new Map();function buildItemSearchType(type,lowercasePaths,isAssocType){const PATH_INDEX_DATA=0;const GENERICS_DATA=1;const BINDINGS_DATA=2;let pathIndex,generics,bindings;if(typeof type==="number"){pathIndex=type;generics=EMPTY_GENERICS_ARRAY;bindings=EMPTY_BINDINGS_MAP}else{pathIndex=type[PATH_INDEX_DATA];generics=buildItemSearchTypeAll(type[GENERICS_DATA],lowercasePaths,);if(type.length>BINDINGS_DATA&&type[BINDINGS_DATA].length>0){bindings=new Map(type[BINDINGS_DATA].map(binding=>{const[assocType,constraints]=binding;return[buildItemSearchType(assocType,lowercasePaths,true).id,buildItemSearchTypeAll(constraints,lowercasePaths),]}))}else{bindings=EMPTY_BINDINGS_MAP}}let result;if(pathIndex<0){result={id:pathIndex,ty:TY_GENERIC,path:null,exactPath:null,generics,bindings,}}else if(pathIndex===0){result={id:null,ty:null,path:null,exactPath:null,generics,bindings,}}else{const item=lowercasePaths[pathIndex-1];result={id:buildTypeMapIndex(item.name,isAssocType),ty:item.ty,path:item.path,exactPath:item.exactPath,generics,bindings,}}const cr=TYPES_POOL.get(result.id);if(cr){if(cr.generics.length===result.generics.length&&cr.generics!==result.generics&&cr.generics.every((x,i)=>result.generics[i]===x)){result.generics=cr.generics}if(cr.bindings.size===result.bindings.size&&cr.bindings!==result.bindings){let ok=true;for(const[k,v]of cr.bindings.entries()){const v2=result.bindings.get(v);if(!v2){ok=false;break}if(v!==v2&&v.length===v2.length&&v.every((x,i)=>v2[i]===x)){result.bindings.set(k,v)}else if(v!==v2){ok=false;break}}if(ok){result.bindings=cr.bindings}}if(cr.ty===result.ty&&cr.path===result.path&&cr.bindings===result.bindings&&cr.generics===result.generics&&cr.ty===result.ty){return cr}}TYPES_POOL.set(result.id,result);return result}function buildFunctionSearchTypeCallback(lowercasePaths){return functionSearchType=>{if(functionSearchType===0){return null}const INPUTS_DATA=0;const OUTPUT_DATA=1;let inputs,output;if(typeof functionSearchType[INPUTS_DATA]==="number"){inputs=[buildItemSearchType(functionSearchType[INPUTS_DATA],lowercasePaths)]}else{inputs=buildItemSearchTypeAll(functionSearchType[INPUTS_DATA],lowercasePaths,)}if(functionSearchType.length>1){if(typeof functionSearchType[OUTPUT_DATA]==="number"){output=[buildItemSearchType(functionSearchType[OUTPUT_DATA],lowercasePaths)]}else{output=buildItemSearchTypeAll(functionSearchType[OUTPUT_DATA],lowercasePaths,)}}else{output=[]}const where_clause=[];const l=functionSearchType.length;for(let i=2;i{k=(~~k+0x7ed55d16)+(k<<12);k=(k ^ 0xc761c23c)^(k>>>19);k=(~~k+0x165667b1)+(k<<5);k=(~~k+0xd3a2646c)^(k<<9);k=(~~k+0xfd7046c5)+(k<<3);return(k ^ 0xb55a4f09)^(k>>>16)};const hashint2=k=>{k=~k+(k<<15);k ^=k>>>12;k+=k<<2;k ^=k>>>4;k=Math.imul(k,2057);return k ^(k>>16)};if(input!==null){const h0a=hashint1(input);const h0b=hashint2(input);const h1a=~~(h0a+Math.imul(h0b,2));const h1b=~~(h0a+Math.imul(h0b,3));const h2a=~~(h0a+Math.imul(h0b,4));const h2b=~~(h0a+Math.imul(h0b,5));output[0]|=(1<<(h0a%32))|(1<<(h1b%32));output[1]|=(1<<(h1a%32))|(1<<(h2b%32));output[2]|=(1<<(h2a%32))|(1<<(h0b%32));fps.add(input)}for(const g of type.generics){buildFunctionTypeFingerprint(g,output,fps)}const fb={id:null,ty:0,generics:EMPTY_GENERICS_ARRAY,bindings:EMPTY_BINDINGS_MAP,};for(const[k,v]of type.bindings.entries()){fb.id=k;fb.generics=v;buildFunctionTypeFingerprint(fb,output,fps)}output[3]=fps.size}function compareTypeFingerprints(fullId,queryFingerprint){const fh0=functionTypeFingerprint[fullId*4];const fh1=functionTypeFingerprint[(fullId*4)+1];const fh2=functionTypeFingerprint[(fullId*4)+2];const[qh0,qh1,qh2]=queryFingerprint;const[in0,in1,in2]=[fh0&qh0,fh1&qh1,fh2&qh2];if((in0 ^ qh0)||(in1 ^ qh1)||(in2 ^ qh2)){return null}return functionTypeFingerprint[(fullId*4)+3]}class VlqHexDecoder{constructor(string,cons){this.string=string;this.cons=cons;this.offset=0;this.backrefQueue=[]}decodeList(){let c=this.string.charCodeAt(this.offset);const ret=[];while(c!==125){ret.push(this.decode());c=this.string.charCodeAt(this.offset)}this.offset+=1;return ret}decode(){let n=0;let c=this.string.charCodeAt(this.offset);if(c===123){this.offset+=1;return this.decodeList()}while(c<96){n=(n<<4)|(c&0xF);this.offset+=1;c=this.string.charCodeAt(this.offset)}n=(n<<4)|(c&0xF);const[sign,value]=[n&1,n>>1];this.offset+=1;return sign?-value:value}next(){const c=this.string.charCodeAt(this.offset);if(c>=48&&c<64){this.offset+=1;return this.backrefQueue[c-48]}if(c===96){this.offset+=1;return this.cons(0)}const result=this.cons(this.decode());this.backrefQueue.unshift(result);if(this.backrefQueue.length>16){this.backrefQueue.pop()}return result}}class RoaringBitmap{constructor(str){const strdecoded=atob(str);const u8array=new Uint8Array(strdecoded.length);for(let j=0;j=4){offsets=[];for(let j=0;j>3]&(1<<(j&0x7))){const runcount=(u8array[i]|(u8array[i+1]<<8));i+=2;this.containers.push(new RoaringBitmapRun(runcount,u8array.slice(i,i+(runcount*4)),));i+=runcount*4}else if(this.cardinalities[j]>=4096){this.containers.push(new RoaringBitmapBits(u8array.slice(i,i+8192)));i+=8192}else{const end=this.cardinalities[j]*2;this.containers.push(new RoaringBitmapArray(this.cardinalities[j],u8array.slice(i,i+end),));i+=end}}}contains(keyvalue){const key=keyvalue>>16;const value=keyvalue&0xFFFF;for(let i=0;i=start&&value<=(start+lenm1)){return true}}return false}}class RoaringBitmapArray{constructor(cardinality,array){this.cardinality=cardinality;this.array=array}contains(value){const l=this.cardinality*2;for(let i=0;i>3]&(1<<(value&7)))}}function buildIndex(rawSearchIndex){searchIndex=[];searchIndexDeprecated=new Map();searchIndexEmptyDesc=new Map();let currentIndex=0;let id=0;for(const crate of rawSearchIndex.values()){id+=crate.t.length+1}functionTypeFingerprint=new Uint32Array((id+1)*4);id=0;for(const[crate,crateCorpus]of rawSearchIndex){const itemDescShardDecoder=new VlqHexDecoder(crateCorpus.D,noop=>noop);let descShard={crate,shard:0,start:0,len:itemDescShardDecoder.next(),promise:null,resolve:null,};const descShardList=[descShard];searchIndexDeprecated.set(crate,new RoaringBitmap(crateCorpus.c));searchIndexEmptyDesc.set(crate,new RoaringBitmap(crateCorpus.e));let descIndex=0;const crateRow={crate,ty:3,name:crate,path:"",descShard,descIndex,exactPath:"",desc:crateCorpus.doc,parent:undefined,type:null,id,word:crate,normalizedName:crate.indexOf("_")===-1?crate:crate.replace(/_/g,""),bitIndex:0,implDisambiguator:null,};id+=1;searchIndex.push(crateRow);currentIndex+=1;if(!searchIndexEmptyDesc.get(crate).contains(0)){descIndex+=1}const itemTypes=crateCorpus.t;const itemNames=crateCorpus.n;const itemPaths=new Map(crateCorpus.q);const itemReexports=new Map(crateCorpus.r);const itemParentIdxs=crateCorpus.i;const implDisambiguator=new Map(crateCorpus.b);const paths=crateCorpus.p;const aliases=crateCorpus.a;const lowercasePaths=[];const itemFunctionDecoder=new VlqHexDecoder(crateCorpus.f,buildFunctionSearchTypeCallback(lowercasePaths),);let len=paths.length;let lastPath=itemPaths.get(0);for(let i=0;i2){path=itemPaths.has(elem[2])?itemPaths.get(elem[2]):lastPath;lastPath=path}const exactPath=elem.length>3?itemPaths.get(elem[3]):path;lowercasePaths.push({ty,name:name.toLowerCase(),path,exactPath});paths[i]={ty,name,path,exactPath}}lastPath="";len=itemTypes.length;for(let i=0;i=descShard.len&&!searchIndexEmptyDesc.get(crate).contains(bitIndex)){descShard={crate,shard:descShard.shard+1,start:descShard.start+descShard.len,len:itemDescShardDecoder.next(),promise:null,resolve:null,};descIndex=0;descShardList.push(descShard)}let word="";if(typeof itemNames[i]==="string"){word=itemNames[i].toLowerCase()}const path=itemPaths.has(i)?itemPaths.get(i):lastPath;const type=itemFunctionDecoder.next();if(type!==null){if(type){const fp=functionTypeFingerprint.subarray(id*4,(id+1)*4);const fps=new Set();for(const t of type.inputs){buildFunctionTypeFingerprint(t,fp,fps)}for(const t of type.output){buildFunctionTypeFingerprint(t,fp,fps)}for(const w of type.where_clause){for(const t of w){buildFunctionTypeFingerprint(t,fp,fps)}}}}const row={crate,ty:itemTypes.charCodeAt(i)-65,name:itemNames[i],path,descShard,descIndex,exactPath:itemReexports.has(i)?itemPaths.get(itemReexports.get(i)):path,parent:itemParentIdxs[i]>0?paths[itemParentIdxs[i]-1]:undefined,type,id,word,normalizedName:word.indexOf("_")===-1?word:word.replace(/_/g,""),bitIndex,implDisambiguator:implDisambiguator.has(i)?implDisambiguator.get(i):null,};id+=1;searchIndex.push(row);lastPath=row.path;if(!searchIndexEmptyDesc.get(crate).contains(bitIndex)){descIndex+=1}}if(aliases){const currentCrateAliases=new Map();ALIASES.set(crate,currentCrateAliases);for(const alias_name in aliases){if(!Object.prototype.hasOwnProperty.call(aliases,alias_name)){continue}let currentNameAliases;if(currentCrateAliases.has(alias_name)){currentNameAliases=currentCrateAliases.get(alias_name)}else{currentNameAliases=[];currentCrateAliases.set(alias_name,currentNameAliases)}for(const local_alias of aliases[alias_name]){currentNameAliases.push(local_alias+currentIndex)}}}currentIndex+=itemTypes.length;searchState.descShards.set(crate,descShardList)}TYPES_POOL=new Map()}function onSearchSubmit(e){e.preventDefault();searchState.clearInputTimeout();search()}function putBackSearch(){const search_input=searchState.input;if(!searchState.input){return}if(search_input.value!==""&&!searchState.isDisplayed()){searchState.showResults();if(browserSupportsHistoryApi()){history.replaceState(null,"",buildUrl(search_input.value,getFilterCrates()))}document.title=searchState.title}}function registerSearchEvents(){const params=searchState.getQueryStringParams();if(searchState.input.value===""){searchState.input.value=params.search||""}const searchAfter500ms=()=>{searchState.clearInputTimeout();if(searchState.input.value.length===0){searchState.hideResults()}else{searchState.timeout=setTimeout(search,500)}};searchState.input.onkeyup=searchAfter500ms;searchState.input.oninput=searchAfter500ms;document.getElementsByClassName("search-form")[0].onsubmit=onSearchSubmit;searchState.input.onchange=e=>{if(e.target!==document.activeElement){return}searchState.clearInputTimeout();setTimeout(search,0)};searchState.input.onpaste=searchState.input.onchange;searchState.outputElement().addEventListener("keydown",e=>{if(e.altKey||e.ctrlKey||e.shiftKey||e.metaKey){return}if(e.which===38){const previous=document.activeElement.previousElementSibling;if(previous){previous.focus()}else{searchState.focus()}e.preventDefault()}else if(e.which===40){const next=document.activeElement.nextElementSibling;if(next){next.focus()}const rect=document.activeElement.getBoundingClientRect();if(window.innerHeight-rect.bottom{if(e.which===40){focusSearchResult();e.preventDefault()}});searchState.input.addEventListener("focus",()=>{putBackSearch()});searchState.input.addEventListener("blur",()=>{searchState.input.placeholder=searchState.input.origPlaceholder});if(browserSupportsHistoryApi()){const previousTitle=document.title;window.addEventListener("popstate",e=>{const params=searchState.getQueryStringParams();document.title=previousTitle;currentResults=null;if(params.search&¶ms.search.length>0){searchState.input.value=params.search;e.preventDefault();search()}else{searchState.input.value="";searchState.hideResults()}})}window.onpageshow=()=>{const qSearch=searchState.getQueryStringParams().search;if(searchState.input.value===""&&qSearch){searchState.input.value=qSearch}search()}}function updateCrate(ev){if(ev.target.value==="all crates"){const query=searchState.input.value.trim();updateSearchHistory(buildUrl(query,null))}currentResults=null;search(true)}buildIndex(rawSearchIndex);if(typeof window!=="undefined"){registerSearchEvents();if(window.searchState.getQueryStringParams().search){search()}}if(typeof exports!=="undefined"){exports.initSearch=initSearch;exports.execQuery=execQuery;exports.parseQuery=parseQuery}}if(typeof window!=="undefined"){window.initSearch=initSearch;if(window.searchIndex!==undefined){initSearch(window.searchIndex)}}else{initSearch(new Map())}})() \ No newline at end of file diff --git a/static.files/settings-4313503d2e1961c2.js b/static.files/settings-4313503d2e1961c2.js new file mode 100644 index 0000000..ab425fe --- /dev/null +++ b/static.files/settings-4313503d2e1961c2.js @@ -0,0 +1,17 @@ +"use strict";(function(){const isSettingsPage=window.location.pathname.endsWith("/settings.html");function changeSetting(settingName,value){if(settingName==="theme"){const useSystem=value==="system preference"?"true":"false";updateLocalStorage("use-system-theme",useSystem)}updateLocalStorage(settingName,value);switch(settingName){case"theme":case"preferred-dark-theme":case"preferred-light-theme":updateTheme();updateLightAndDark();break;case"line-numbers":if(value===true){window.rustdoc_add_line_numbers_to_examples()}else{window.rustdoc_remove_line_numbers_from_examples()}break;case"hide-sidebar":if(value===true){addClass(document.documentElement,"hide-sidebar")}else{removeClass(document.documentElement,"hide-sidebar")}break}}function showLightAndDark(){removeClass(document.getElementById("preferred-light-theme"),"hidden");removeClass(document.getElementById("preferred-dark-theme"),"hidden")}function hideLightAndDark(){addClass(document.getElementById("preferred-light-theme"),"hidden");addClass(document.getElementById("preferred-dark-theme"),"hidden")}function updateLightAndDark(){const useSystem=getSettingValue("use-system-theme");if(useSystem==="true"||(useSystem===null&&getSettingValue("theme")===null)){showLightAndDark()}else{hideLightAndDark()}}function setEvents(settingsElement){updateLightAndDark();onEachLazy(settingsElement.querySelectorAll("input[type=\"checkbox\"]"),toggle=>{const settingId=toggle.id;const settingValue=getSettingValue(settingId);if(settingValue!==null){toggle.checked=settingValue==="true"}toggle.onchange=()=>{changeSetting(toggle.id,toggle.checked)}});onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"),elem=>{const settingId=elem.name;let settingValue=getSettingValue(settingId);if(settingId==="theme"){const useSystem=getSettingValue("use-system-theme");if(useSystem==="true"||settingValue===null){settingValue=useSystem==="false"?"light":"system preference"}}if(settingValue!==null&&settingValue!=="null"){elem.checked=settingValue===elem.value}elem.addEventListener("change",ev=>{changeSetting(ev.target.name,ev.target.value)})})}function buildSettingsPageSections(settings){let output="";for(const setting of settings){const js_data_name=setting["js_name"];const setting_name=setting["name"];if(setting["options"]!==undefined){output+=`\ +
+
${setting_name}
+
`;onEach(setting["options"],option=>{const checked=option===setting["default"]?" checked":"";const full=`${js_data_name}-${option.replace(/ /g,"-")}`;output+=`\ + `});output+=`\ +
+
`}else{const checked=setting["default"]===true?" checked":"";output+=`\ +
\ + \ +
`}}return output}function buildSettingsPage(){const theme_names=getVar("themes").split(",").filter(t=>t);theme_names.push("light","dark","ayu");const settings=[{"name":"Theme","js_name":"theme","default":"system preference","options":theme_names.concat("system preference"),},{"name":"Preferred light theme","js_name":"preferred-light-theme","default":"light","options":theme_names,},{"name":"Preferred dark theme","js_name":"preferred-dark-theme","default":"dark","options":theme_names,},{"name":"Auto-hide item contents for large items","js_name":"auto-hide-large-items","default":true,},{"name":"Auto-hide item methods' documentation","js_name":"auto-hide-method-docs","default":false,},{"name":"Auto-hide trait implementation documentation","js_name":"auto-hide-trait-implementations","default":false,},{"name":"Directly go to item in search if there is only one result","js_name":"go-to-only-result","default":false,},{"name":"Show line numbers on code examples","js_name":"line-numbers","default":false,},{"name":"Hide persistent navigation bar","js_name":"hide-sidebar","default":false,},{"name":"Disable keyboard shortcuts","js_name":"disable-shortcuts","default":false,},];const elementKind=isSettingsPage?"section":"div";const innerHTML=`
${buildSettingsPageSections(settings)}
`;const el=document.createElement(elementKind);el.id="settings";if(!isSettingsPage){el.className="popover"}el.innerHTML=innerHTML;if(isSettingsPage){document.getElementById(MAIN_ID).appendChild(el)}else{el.setAttribute("tabindex","-1");getSettingsButton().appendChild(el)}return el}const settingsMenu=buildSettingsPage();function displaySettings(){settingsMenu.style.display="";onEachLazy(settingsMenu.querySelectorAll("input[type='checkbox']"),el=>{const val=getSettingValue(el.id);const checked=val==="true";if(checked!==el.checked&&val!==null){el.checked=checked}})}function settingsBlurHandler(event){blurHandler(event,getSettingsButton(),window.hidePopoverMenus)}if(isSettingsPage){getSettingsButton().onclick=event=>{event.preventDefault()}}else{const settingsButton=getSettingsButton();const settingsMenu=document.getElementById("settings");settingsButton.onclick=event=>{if(settingsMenu.contains(event.target)){return}event.preventDefault();const shouldDisplaySettings=settingsMenu.style.display==="none";window.hideAllModals();if(shouldDisplaySettings){displaySettings()}};settingsButton.onblur=settingsBlurHandler;settingsButton.querySelector("a").onblur=settingsBlurHandler;onEachLazy(settingsMenu.querySelectorAll("input"),el=>{el.onblur=settingsBlurHandler});settingsMenu.onblur=settingsBlurHandler}setTimeout(()=>{setEvents(settingsMenu);if(!isSettingsPage){displaySettings()}removeClass(getSettingsButton(),"rotate")},0)})() \ No newline at end of file diff --git a/static.files/src-script-e66d777a5a92e9b2.js b/static.files/src-script-e66d777a5a92e9b2.js new file mode 100644 index 0000000..d0aebb8 --- /dev/null +++ b/static.files/src-script-e66d777a5a92e9b2.js @@ -0,0 +1 @@ +"use strict";(function(){const rootPath=getVar("root-path");const NAME_OFFSET=0;const DIRS_OFFSET=1;const FILES_OFFSET=2;const RUSTDOC_MOBILE_BREAKPOINT=700;function closeSidebarIfMobile(){if(window.innerWidth{removeClass(document.documentElement,"src-sidebar-expanded");updateLocalStorage("source-sidebar-show","false")};window.rustdocShowSourceSidebar=()=>{addClass(document.documentElement,"src-sidebar-expanded");updateLocalStorage("source-sidebar-show","true")};window.rustdocToggleSrcSidebar=()=>{if(document.documentElement.classList.contains("src-sidebar-expanded")){window.rustdocCloseSourceSidebar()}else{window.rustdocShowSourceSidebar()}};function createSrcSidebar(){const container=document.querySelector("nav.sidebar");const sidebar=document.createElement("div");sidebar.id="src-sidebar";let hasFoundFile=false;for(const[key,source]of srcIndex){source[NAME_OFFSET]=key;hasFoundFile=createDirEntry(source,sidebar,"",hasFoundFile)}container.appendChild(sidebar);const selected_elem=sidebar.getElementsByClassName("selected")[0];if(typeof selected_elem!=="undefined"){selected_elem.focus()}}function highlightSrcLines(){const match=window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/);if(!match){return}let from=parseInt(match[1],10);let to=from;if(typeof match[2]!=="undefined"){to=parseInt(match[2],10)}if(to{onEachLazy(e.getElementsByTagName("a"),i_e=>{removeClass(i_e,"line-highlighted")})});for(let i=from;i<=to;++i){elem=document.getElementById(i);if(!elem){break}addClass(elem,"line-highlighted")}}const handleSrcHighlight=(function(){let prev_line_id=0;const set_fragment=name=>{const x=window.scrollX,y=window.scrollY;if(browserSupportsHistoryApi()){history.replaceState(null,null,"#"+name);highlightSrcLines()}else{location.replace("#"+name)}window.scrollTo(x,y)};return ev=>{let cur_line_id=parseInt(ev.target.id,10);if(isNaN(cur_line_id)||ev.ctrlKey||ev.altKey||ev.metaKey){return}ev.preventDefault();if(ev.shiftKey&&prev_line_id){if(prev_line_id>cur_line_id){const tmp=prev_line_id;prev_line_id=cur_line_id;cur_line_id=tmp}set_fragment(prev_line_id+"-"+cur_line_id)}else{prev_line_id=cur_line_id;set_fragment(cur_line_id)}}}());window.addEventListener("hashchange",highlightSrcLines);onEachLazy(document.getElementsByClassName("src-line-numbers"),el=>{el.addEventListener("click",handleSrcHighlight)});highlightSrcLines();window.createSrcSidebar=createSrcSidebar})() \ No newline at end of file diff --git a/static.files/storage-118b08c4c78b968e.js b/static.files/storage-118b08c4c78b968e.js new file mode 100644 index 0000000..9818946 --- /dev/null +++ b/static.files/storage-118b08c4c78b968e.js @@ -0,0 +1,24 @@ +"use strict";const builtinThemes=["light","dark","ayu"];const darkThemes=["dark","ayu"];window.currentTheme=document.getElementById("themeStyle");const settingsDataset=(function(){const settingsElement=document.getElementById("default-settings");return settingsElement&&settingsElement.dataset?settingsElement.dataset:null})();function getSettingValue(settingName){const current=getCurrentValue(settingName);if(current===null&&settingsDataset!==null){const def=settingsDataset[settingName.replace(/-/g,"_")];if(def!==undefined){return def}}return current}const localStoredTheme=getSettingValue("theme");function hasClass(elem,className){return elem&&elem.classList&&elem.classList.contains(className)}function addClass(elem,className){if(elem&&elem.classList){elem.classList.add(className)}}function removeClass(elem,className){if(elem&&elem.classList){elem.classList.remove(className)}}function onEach(arr,func){for(const elem of arr){if(func(elem)){return true}}return false}function onEachLazy(lazyArray,func){return onEach(Array.prototype.slice.call(lazyArray),func)}function updateLocalStorage(name,value){try{window.localStorage.setItem("rustdoc-"+name,value)}catch(e){}}function getCurrentValue(name){try{return window.localStorage.getItem("rustdoc-"+name)}catch(e){return null}}const getVar=(function getVar(name){const el=document.querySelector("head > meta[name='rustdoc-vars']");return el?el.attributes["data-"+name].value:null});function switchTheme(newThemeName,saveTheme){const themeNames=getVar("themes").split(",").filter(t=>t);themeNames.push(...builtinThemes);if(themeNames.indexOf(newThemeName)===-1){return}if(saveTheme){updateLocalStorage("theme",newThemeName)}document.documentElement.setAttribute("data-theme",newThemeName);if(builtinThemes.indexOf(newThemeName)!==-1){if(window.currentTheme){window.currentTheme.parentNode.removeChild(window.currentTheme);window.currentTheme=null}}else{const newHref=getVar("root-path")+encodeURIComponent(newThemeName)+getVar("resource-suffix")+".css";if(!window.currentTheme){if(document.readyState==="loading"){document.write(``);window.currentTheme=document.getElementById("themeStyle")}else{window.currentTheme=document.createElement("link");window.currentTheme.rel="stylesheet";window.currentTheme.id="themeStyle";window.currentTheme.href=newHref;document.documentElement.appendChild(window.currentTheme)}}else if(newHref!==window.currentTheme.href){window.currentTheme.href=newHref}}}const updateTheme=(function(){const mql=window.matchMedia("(prefers-color-scheme: dark)");function updateTheme(){if(getSettingValue("use-system-theme")!=="false"){const lightTheme=getSettingValue("preferred-light-theme")||"light";const darkTheme=getSettingValue("preferred-dark-theme")||"dark";updateLocalStorage("use-system-theme","true");switchTheme(mql.matches?darkTheme:lightTheme,true)}else{switchTheme(getSettingValue("theme"),false)}}mql.addEventListener("change",updateTheme);return updateTheme})();if(getSettingValue("use-system-theme")!=="false"&&window.matchMedia){if(getSettingValue("use-system-theme")===null&&getSettingValue("preferred-dark-theme")===null&&darkThemes.indexOf(localStoredTheme)>=0){updateLocalStorage("preferred-dark-theme",localStoredTheme)}}updateTheme();if(getSettingValue("source-sidebar-show")==="true"){addClass(document.documentElement,"src-sidebar-expanded")}if(getSettingValue("hide-sidebar")==="true"){addClass(document.documentElement,"hide-sidebar")}function updateSidebarWidth(){const desktopSidebarWidth=getSettingValue("desktop-sidebar-width");if(desktopSidebarWidth&&desktopSidebarWidth!=="null"){document.documentElement.style.setProperty("--desktop-sidebar-width",desktopSidebarWidth+"px",)}const srcSidebarWidth=getSettingValue("src-sidebar-width");if(srcSidebarWidth&&srcSidebarWidth!=="null"){document.documentElement.style.setProperty("--src-sidebar-width",srcSidebarWidth+"px",)}}updateSidebarWidth();window.addEventListener("pageshow",ev=>{if(ev.persisted){setTimeout(updateTheme,0);setTimeout(updateSidebarWidth,0)}});class RustdocSearchElement extends HTMLElement{constructor(){super()}connectedCallback(){const rootPath=getVar("root-path");const currentCrate=getVar("current-crate");this.innerHTML=``}}window.customElements.define("rustdoc-search",RustdocSearchElement) \ No newline at end of file diff --git a/trait.impl/core/clone/trait.Clone.js b/trait.impl/core/clone/trait.Clone.js new file mode 100644 index 0000000..6148c75 --- /dev/null +++ b/trait.impl/core/clone/trait.Clone.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl Clone for ABI"],["impl Clone for AccessFs"],["impl Clone for AccessNet"],["impl Clone for CompatLevel"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/cmp/trait.Eq.js b/trait.impl/core/cmp/trait.Eq.js new file mode 100644 index 0000000..e4b91f2 --- /dev/null +++ b/trait.impl/core/cmp/trait.Eq.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl Eq for AccessFs"],["impl Eq for AccessNet"],["impl Eq for CompatLevel"],["impl Eq for RulesetStatus"],["impl Eq for RestrictionStatus"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/cmp/trait.Ord.js b/trait.impl/core/cmp/trait.Ord.js new file mode 100644 index 0000000..12a1fac --- /dev/null +++ b/trait.impl/core/cmp/trait.Ord.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl Ord for CompatLevel"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/cmp/trait.PartialEq.js b/trait.impl/core/cmp/trait.PartialEq.js new file mode 100644 index 0000000..fc5aeab --- /dev/null +++ b/trait.impl/core/cmp/trait.PartialEq.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl PartialEq for AccessFs"],["impl PartialEq for AccessNet"],["impl PartialEq for CompatLevel"],["impl PartialEq for RulesetStatus"],["impl PartialEq for RestrictionStatus"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/cmp/trait.PartialOrd.js b/trait.impl/core/cmp/trait.PartialOrd.js new file mode 100644 index 0000000..ce8b917 --- /dev/null +++ b/trait.impl/core/cmp/trait.PartialOrd.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl PartialOrd for CompatLevel"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/convert/trait.AsMut.js b/trait.impl/core/convert/trait.AsMut.js new file mode 100644 index 0000000..4d058bf --- /dev/null +++ b/trait.impl/core/convert/trait.AsMut.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl AsMut<Ruleset> for Ruleset"],["impl AsMut<RulesetCreated> for RulesetCreated"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/convert/trait.From.js b/trait.impl/core/convert/trait.From.js new file mode 100644 index 0000000..b677d2c --- /dev/null +++ b/trait.impl/core/convert/trait.From.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl From<Option<CompatLevel>> for CompatLevel"],["impl From<AddRulesError> for RulesetError"],["impl From<CreateRulesetError> for RulesetError"],["impl From<HandleAccessesError> for RulesetError"],["impl From<RestrictSelfError> for RulesetError"],["impl<A> From<AddRuleError<A>> for AddRulesError
where\n A: Access,
"],["impl<A> From<HandleAccessError<A>> for HandleAccessesError
where\n A: Access,
"],["impl<T> From<AccessError<T>> for CompatError<T>
where\n T: Access,
"],["impl<T> From<CompatError<T>> for AddRuleError<T>
where\n T: Access,
"],["impl<T> From<CompatError<T>> for HandleAccessError<T>
where\n T: Access,
"],["impl<T> From<PathBeneathError> for CompatError<T>
where\n T: Access,
"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/default/trait.Default.js b/trait.impl/core/default/trait.Default.js new file mode 100644 index 0000000..ca8c6c4 --- /dev/null +++ b/trait.impl/core/default/trait.Default.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl Default for CompatLevel"],["impl Default for Ruleset"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/error/trait.Error.js b/trait.impl/core/error/trait.Error.js new file mode 100644 index 0000000..8dc333f --- /dev/null +++ b/trait.impl/core/error/trait.Error.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl Error for AddRulesError"],["impl Error for CreateRulesetError"],["impl Error for HandleAccessesError"],["impl Error for PathBeneathError"],["impl Error for PathFdError"],["impl Error for RestrictSelfError"],["impl Error for RulesetError"],["impl<T> Error for AccessError<T>
where\n T: Access,\n Self: Debug + Display,
"],["impl<T> Error for AddRuleError<T>
where\n T: Access,\n CompatError<T>: Error,\n Self: Debug + Display,
"],["impl<T> Error for CompatError<T>
where\n T: Access,\n AccessError<T>: Error,\n Self: Debug + Display,
"],["impl<T> Error for HandleAccessError<T>
where\n T: Access,\n CompatError<T>: Error,\n Self: Debug + Display,
"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/fmt/trait.Debug.js b/trait.impl/core/fmt/trait.Debug.js new file mode 100644 index 0000000..53264fc --- /dev/null +++ b/trait.impl/core/fmt/trait.Debug.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl Debug for AccessFs"],["impl Debug for AccessNet"],["impl Debug for AddRulesError"],["impl Debug for CompatLevel"],["impl Debug for CreateRulesetError"],["impl Debug for HandleAccessesError"],["impl Debug for PathBeneathError"],["impl Debug for PathFdError"],["impl Debug for RestrictSelfError"],["impl Debug for RulesetError"],["impl Debug for RulesetStatus"],["impl Debug for RestrictionStatus"],["impl<T> Debug for AccessError<T>
where\n T: Access + Debug,
"],["impl<T> Debug for AddRuleError<T>
where\n T: Access + Debug,
"],["impl<T> Debug for CompatError<T>
where\n T: Access + Debug,
"],["impl<T> Debug for HandleAccessError<T>
where\n T: Access + Debug,
"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/fmt/trait.Display.js b/trait.impl/core/fmt/trait.Display.js new file mode 100644 index 0000000..0de3611 --- /dev/null +++ b/trait.impl/core/fmt/trait.Display.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl Display for AddRulesError"],["impl Display for CreateRulesetError"],["impl Display for HandleAccessesError"],["impl Display for PathBeneathError"],["impl Display for PathFdError"],["impl Display for RestrictSelfError"],["impl Display for RulesetError"],["impl<T> Display for AccessError<T>
where\n T: Access,\n BitFlags<T>: Debug,
"],["impl<T> Display for AddRuleError<T>
where\n T: Access,\n BitFlags<T>: Debug,\n CompatError<T>: Display,
"],["impl<T> Display for CompatError<T>
where\n T: Access,\n AccessError<T>: Display,
"],["impl<T> Display for HandleAccessError<T>
where\n T: Access,\n CompatError<T>: Display,
"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/marker/trait.Copy.js b/trait.impl/core/marker/trait.Copy.js new file mode 100644 index 0000000..f7f1c9a --- /dev/null +++ b/trait.impl/core/marker/trait.Copy.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl Copy for ABI"],["impl Copy for AccessFs"],["impl Copy for AccessNet"],["impl Copy for CompatLevel"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/marker/trait.Freeze.js b/trait.impl/core/marker/trait.Freeze.js new file mode 100644 index 0000000..8a09ca8 --- /dev/null +++ b/trait.impl/core/marker/trait.Freeze.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl Freeze for ABI",1,["landlock::compat::ABI"]],["impl Freeze for AccessFs",1,["landlock::fs::AccessFs"]],["impl Freeze for AccessNet",1,["landlock::net::AccessNet"]],["impl Freeze for AddRulesError",1,["landlock::errors::AddRulesError"]],["impl Freeze for CompatLevel",1,["landlock::compat::CompatLevel"]],["impl Freeze for CreateRulesetError",1,["landlock::errors::CreateRulesetError"]],["impl Freeze for HandleAccessesError",1,["landlock::errors::HandleAccessesError"]],["impl Freeze for PathBeneathError",1,["landlock::errors::PathBeneathError"]],["impl Freeze for PathFdError",1,["landlock::errors::PathFdError"]],["impl Freeze for RestrictSelfError",1,["landlock::errors::RestrictSelfError"]],["impl Freeze for RulesetError",1,["landlock::errors::RulesetError"]],["impl Freeze for RulesetStatus",1,["landlock::ruleset::RulesetStatus"]],["impl Freeze for NetPort",1,["landlock::net::NetPort"]],["impl Freeze for PathFd",1,["landlock::fs::PathFd"]],["impl Freeze for RestrictionStatus",1,["landlock::ruleset::RestrictionStatus"]],["impl Freeze for Ruleset",1,["landlock::ruleset::Ruleset"]],["impl Freeze for RulesetCreated",1,["landlock::ruleset::RulesetCreated"]],["impl<F> Freeze for PathBeneath<F>
where\n F: Freeze,
",1,["landlock::fs::PathBeneath"]],["impl<T> Freeze for AccessError<T>
where\n <T as RawBitFlags>::Numeric: Freeze,
",1,["landlock::errors::AccessError"]],["impl<T> Freeze for AddRuleError<T>
where\n <T as RawBitFlags>::Numeric: Freeze,
",1,["landlock::errors::AddRuleError"]],["impl<T> Freeze for CompatError<T>
where\n <T as RawBitFlags>::Numeric: Freeze,
",1,["landlock::errors::CompatError"]],["impl<T> Freeze for HandleAccessError<T>
where\n <T as RawBitFlags>::Numeric: Freeze,
",1,["landlock::errors::HandleAccessError"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/marker/trait.Send.js b/trait.impl/core/marker/trait.Send.js new file mode 100644 index 0000000..5e21ddf --- /dev/null +++ b/trait.impl/core/marker/trait.Send.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl Send for ABI",1,["landlock::compat::ABI"]],["impl Send for AccessFs",1,["landlock::fs::AccessFs"]],["impl Send for AccessNet",1,["landlock::net::AccessNet"]],["impl Send for AddRulesError",1,["landlock::errors::AddRulesError"]],["impl Send for CompatLevel",1,["landlock::compat::CompatLevel"]],["impl Send for CreateRulesetError",1,["landlock::errors::CreateRulesetError"]],["impl Send for HandleAccessesError",1,["landlock::errors::HandleAccessesError"]],["impl Send for PathBeneathError",1,["landlock::errors::PathBeneathError"]],["impl Send for PathFdError",1,["landlock::errors::PathFdError"]],["impl Send for RestrictSelfError",1,["landlock::errors::RestrictSelfError"]],["impl Send for RulesetError",1,["landlock::errors::RulesetError"]],["impl Send for RulesetStatus",1,["landlock::ruleset::RulesetStatus"]],["impl Send for NetPort",1,["landlock::net::NetPort"]],["impl Send for PathFd",1,["landlock::fs::PathFd"]],["impl Send for RestrictionStatus",1,["landlock::ruleset::RestrictionStatus"]],["impl Send for Ruleset",1,["landlock::ruleset::Ruleset"]],["impl Send for RulesetCreated",1,["landlock::ruleset::RulesetCreated"]],["impl<F> Send for PathBeneath<F>
where\n F: Send,
",1,["landlock::fs::PathBeneath"]],["impl<T> Send for AccessError<T>
where\n <T as RawBitFlags>::Numeric: Send,\n T: Send,
",1,["landlock::errors::AccessError"]],["impl<T> Send for AddRuleError<T>
where\n <T as RawBitFlags>::Numeric: Send,\n T: Send,
",1,["landlock::errors::AddRuleError"]],["impl<T> Send for CompatError<T>
where\n <T as RawBitFlags>::Numeric: Send,\n T: Send,
",1,["landlock::errors::CompatError"]],["impl<T> Send for HandleAccessError<T>
where\n <T as RawBitFlags>::Numeric: Send,\n T: Send,
",1,["landlock::errors::HandleAccessError"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/marker/trait.StructuralPartialEq.js b/trait.impl/core/marker/trait.StructuralPartialEq.js new file mode 100644 index 0000000..8cd033e --- /dev/null +++ b/trait.impl/core/marker/trait.StructuralPartialEq.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl StructuralPartialEq for AccessFs"],["impl StructuralPartialEq for AccessNet"],["impl StructuralPartialEq for CompatLevel"],["impl StructuralPartialEq for RulesetStatus"],["impl StructuralPartialEq for RestrictionStatus"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/marker/trait.Sync.js b/trait.impl/core/marker/trait.Sync.js new file mode 100644 index 0000000..b6e536a --- /dev/null +++ b/trait.impl/core/marker/trait.Sync.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl Sync for ABI",1,["landlock::compat::ABI"]],["impl Sync for AccessFs",1,["landlock::fs::AccessFs"]],["impl Sync for AccessNet",1,["landlock::net::AccessNet"]],["impl Sync for AddRulesError",1,["landlock::errors::AddRulesError"]],["impl Sync for CompatLevel",1,["landlock::compat::CompatLevel"]],["impl Sync for CreateRulesetError",1,["landlock::errors::CreateRulesetError"]],["impl Sync for HandleAccessesError",1,["landlock::errors::HandleAccessesError"]],["impl Sync for PathBeneathError",1,["landlock::errors::PathBeneathError"]],["impl Sync for PathFdError",1,["landlock::errors::PathFdError"]],["impl Sync for RestrictSelfError",1,["landlock::errors::RestrictSelfError"]],["impl Sync for RulesetError",1,["landlock::errors::RulesetError"]],["impl Sync for RulesetStatus",1,["landlock::ruleset::RulesetStatus"]],["impl Sync for NetPort",1,["landlock::net::NetPort"]],["impl Sync for PathFd",1,["landlock::fs::PathFd"]],["impl Sync for RestrictionStatus",1,["landlock::ruleset::RestrictionStatus"]],["impl Sync for Ruleset",1,["landlock::ruleset::Ruleset"]],["impl Sync for RulesetCreated",1,["landlock::ruleset::RulesetCreated"]],["impl<F> Sync for PathBeneath<F>
where\n F: Sync,
",1,["landlock::fs::PathBeneath"]],["impl<T> Sync for AccessError<T>
where\n <T as RawBitFlags>::Numeric: Sync,\n T: Sync,
",1,["landlock::errors::AccessError"]],["impl<T> Sync for AddRuleError<T>
where\n <T as RawBitFlags>::Numeric: Sync,\n T: Sync,
",1,["landlock::errors::AddRuleError"]],["impl<T> Sync for CompatError<T>
where\n <T as RawBitFlags>::Numeric: Sync,\n T: Sync,
",1,["landlock::errors::CompatError"]],["impl<T> Sync for HandleAccessError<T>
where\n <T as RawBitFlags>::Numeric: Sync,\n T: Sync,
",1,["landlock::errors::HandleAccessError"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/marker/trait.Unpin.js b/trait.impl/core/marker/trait.Unpin.js new file mode 100644 index 0000000..b2bb9ee --- /dev/null +++ b/trait.impl/core/marker/trait.Unpin.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl Unpin for ABI",1,["landlock::compat::ABI"]],["impl Unpin for AccessFs",1,["landlock::fs::AccessFs"]],["impl Unpin for AccessNet",1,["landlock::net::AccessNet"]],["impl Unpin for AddRulesError",1,["landlock::errors::AddRulesError"]],["impl Unpin for CompatLevel",1,["landlock::compat::CompatLevel"]],["impl Unpin for CreateRulesetError",1,["landlock::errors::CreateRulesetError"]],["impl Unpin for HandleAccessesError",1,["landlock::errors::HandleAccessesError"]],["impl Unpin for PathBeneathError",1,["landlock::errors::PathBeneathError"]],["impl Unpin for PathFdError",1,["landlock::errors::PathFdError"]],["impl Unpin for RestrictSelfError",1,["landlock::errors::RestrictSelfError"]],["impl Unpin for RulesetError",1,["landlock::errors::RulesetError"]],["impl Unpin for RulesetStatus",1,["landlock::ruleset::RulesetStatus"]],["impl Unpin for NetPort",1,["landlock::net::NetPort"]],["impl Unpin for PathFd",1,["landlock::fs::PathFd"]],["impl Unpin for RestrictionStatus",1,["landlock::ruleset::RestrictionStatus"]],["impl Unpin for Ruleset",1,["landlock::ruleset::Ruleset"]],["impl Unpin for RulesetCreated",1,["landlock::ruleset::RulesetCreated"]],["impl<F> Unpin for PathBeneath<F>
where\n F: Unpin,
",1,["landlock::fs::PathBeneath"]],["impl<T> Unpin for AccessError<T>
where\n <T as RawBitFlags>::Numeric: Unpin,\n T: Unpin,
",1,["landlock::errors::AccessError"]],["impl<T> Unpin for AddRuleError<T>
where\n <T as RawBitFlags>::Numeric: Unpin,\n T: Unpin,
",1,["landlock::errors::AddRuleError"]],["impl<T> Unpin for CompatError<T>
where\n <T as RawBitFlags>::Numeric: Unpin,\n T: Unpin,
",1,["landlock::errors::CompatError"]],["impl<T> Unpin for HandleAccessError<T>
where\n <T as RawBitFlags>::Numeric: Unpin,\n T: Unpin,
",1,["landlock::errors::HandleAccessError"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/ops/bit/trait.BitAnd.js b/trait.impl/core/ops/bit/trait.BitAnd.js new file mode 100644 index 0000000..57fd20b --- /dev/null +++ b/trait.impl/core/ops/bit/trait.BitAnd.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl BitAnd for AccessFs"],["impl BitAnd for AccessNet"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/ops/bit/trait.BitOr.js b/trait.impl/core/ops/bit/trait.BitOr.js new file mode 100644 index 0000000..d92ffc3 --- /dev/null +++ b/trait.impl/core/ops/bit/trait.BitOr.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl BitOr for AccessFs"],["impl BitOr for AccessNet"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/ops/bit/trait.BitXor.js b/trait.impl/core/ops/bit/trait.BitXor.js new file mode 100644 index 0000000..996ee88 --- /dev/null +++ b/trait.impl/core/ops/bit/trait.BitXor.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl BitXor for AccessFs"],["impl BitXor for AccessNet"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/ops/bit/trait.Not.js b/trait.impl/core/ops/bit/trait.Not.js new file mode 100644 index 0000000..1ba0d41 --- /dev/null +++ b/trait.impl/core/ops/bit/trait.Not.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl Not for AccessFs"],["impl Not for AccessNet"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/ops/drop/trait.Drop.js b/trait.impl/core/ops/drop/trait.Drop.js new file mode 100644 index 0000000..2b32376 --- /dev/null +++ b/trait.impl/core/ops/drop/trait.Drop.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl Drop for RulesetCreated"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/panic/unwind_safe/trait.RefUnwindSafe.js b/trait.impl/core/panic/unwind_safe/trait.RefUnwindSafe.js new file mode 100644 index 0000000..a4d7b6d --- /dev/null +++ b/trait.impl/core/panic/unwind_safe/trait.RefUnwindSafe.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl !RefUnwindSafe for AddRulesError",1,["landlock::errors::AddRulesError"]],["impl !RefUnwindSafe for CreateRulesetError",1,["landlock::errors::CreateRulesetError"]],["impl !RefUnwindSafe for HandleAccessesError",1,["landlock::errors::HandleAccessesError"]],["impl !RefUnwindSafe for PathBeneathError",1,["landlock::errors::PathBeneathError"]],["impl !RefUnwindSafe for PathFdError",1,["landlock::errors::PathFdError"]],["impl !RefUnwindSafe for RestrictSelfError",1,["landlock::errors::RestrictSelfError"]],["impl !RefUnwindSafe for RulesetError",1,["landlock::errors::RulesetError"]],["impl RefUnwindSafe for ABI",1,["landlock::compat::ABI"]],["impl RefUnwindSafe for AccessFs",1,["landlock::fs::AccessFs"]],["impl RefUnwindSafe for AccessNet",1,["landlock::net::AccessNet"]],["impl RefUnwindSafe for CompatLevel",1,["landlock::compat::CompatLevel"]],["impl RefUnwindSafe for RulesetStatus",1,["landlock::ruleset::RulesetStatus"]],["impl RefUnwindSafe for NetPort",1,["landlock::net::NetPort"]],["impl RefUnwindSafe for PathFd",1,["landlock::fs::PathFd"]],["impl RefUnwindSafe for RestrictionStatus",1,["landlock::ruleset::RestrictionStatus"]],["impl RefUnwindSafe for Ruleset",1,["landlock::ruleset::Ruleset"]],["impl RefUnwindSafe for RulesetCreated",1,["landlock::ruleset::RulesetCreated"]],["impl<F> RefUnwindSafe for PathBeneath<F>
where\n F: RefUnwindSafe,
",1,["landlock::fs::PathBeneath"]],["impl<T> !RefUnwindSafe for AddRuleError<T>",1,["landlock::errors::AddRuleError"]],["impl<T> !RefUnwindSafe for CompatError<T>",1,["landlock::errors::CompatError"]],["impl<T> !RefUnwindSafe for HandleAccessError<T>",1,["landlock::errors::HandleAccessError"]],["impl<T> RefUnwindSafe for AccessError<T>
where\n <T as RawBitFlags>::Numeric: RefUnwindSafe,\n T: RefUnwindSafe,
",1,["landlock::errors::AccessError"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/panic/unwind_safe/trait.UnwindSafe.js b/trait.impl/core/panic/unwind_safe/trait.UnwindSafe.js new file mode 100644 index 0000000..08ad991 --- /dev/null +++ b/trait.impl/core/panic/unwind_safe/trait.UnwindSafe.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl !UnwindSafe for AddRulesError",1,["landlock::errors::AddRulesError"]],["impl !UnwindSafe for CreateRulesetError",1,["landlock::errors::CreateRulesetError"]],["impl !UnwindSafe for HandleAccessesError",1,["landlock::errors::HandleAccessesError"]],["impl !UnwindSafe for PathBeneathError",1,["landlock::errors::PathBeneathError"]],["impl !UnwindSafe for PathFdError",1,["landlock::errors::PathFdError"]],["impl !UnwindSafe for RestrictSelfError",1,["landlock::errors::RestrictSelfError"]],["impl !UnwindSafe for RulesetError",1,["landlock::errors::RulesetError"]],["impl UnwindSafe for ABI",1,["landlock::compat::ABI"]],["impl UnwindSafe for AccessFs",1,["landlock::fs::AccessFs"]],["impl UnwindSafe for AccessNet",1,["landlock::net::AccessNet"]],["impl UnwindSafe for CompatLevel",1,["landlock::compat::CompatLevel"]],["impl UnwindSafe for RulesetStatus",1,["landlock::ruleset::RulesetStatus"]],["impl UnwindSafe for NetPort",1,["landlock::net::NetPort"]],["impl UnwindSafe for PathFd",1,["landlock::fs::PathFd"]],["impl UnwindSafe for RestrictionStatus",1,["landlock::ruleset::RestrictionStatus"]],["impl UnwindSafe for Ruleset",1,["landlock::ruleset::Ruleset"]],["impl UnwindSafe for RulesetCreated",1,["landlock::ruleset::RulesetCreated"]],["impl<F> UnwindSafe for PathBeneath<F>
where\n F: UnwindSafe,
",1,["landlock::fs::PathBeneath"]],["impl<T> !UnwindSafe for AddRuleError<T>",1,["landlock::errors::AddRuleError"]],["impl<T> !UnwindSafe for CompatError<T>",1,["landlock::errors::CompatError"]],["impl<T> !UnwindSafe for HandleAccessError<T>",1,["landlock::errors::HandleAccessError"]],["impl<T> UnwindSafe for AccessError<T>
where\n <T as RawBitFlags>::Numeric: UnwindSafe,\n T: UnwindSafe,
",1,["landlock::errors::AccessError"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/enumflags2/_internal/trait.RawBitFlags.js b/trait.impl/enumflags2/_internal/trait.RawBitFlags.js new file mode 100644 index 0000000..575dfb9 --- /dev/null +++ b/trait.impl/enumflags2/_internal/trait.RawBitFlags.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl RawBitFlags for AccessFs"],["impl RawBitFlags for AccessNet"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/enumflags2/trait.BitFlag.js b/trait.impl/enumflags2/trait.BitFlag.js new file mode 100644 index 0000000..866102a --- /dev/null +++ b/trait.impl/enumflags2/trait.BitFlag.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl BitFlag for AccessFs"],["impl BitFlag for AccessNet"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/landlock/access/trait.Access.js b/trait.impl/landlock/access/trait.Access.js new file mode 100644 index 0000000..cd53510 --- /dev/null +++ b/trait.impl/landlock/access/trait.Access.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/landlock/compat/trait.Compatible.js b/trait.impl/landlock/compat/trait.Compatible.js new file mode 100644 index 0000000..cd53510 --- /dev/null +++ b/trait.impl/landlock/compat/trait.Compatible.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/landlock/ruleset/trait.Rule.js b/trait.impl/landlock/ruleset/trait.Rule.js new file mode 100644 index 0000000..cd53510 --- /dev/null +++ b/trait.impl/landlock/ruleset/trait.Rule.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/landlock/ruleset/trait.RulesetAttr.js b/trait.impl/landlock/ruleset/trait.RulesetAttr.js new file mode 100644 index 0000000..cd53510 --- /dev/null +++ b/trait.impl/landlock/ruleset/trait.RulesetAttr.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/landlock/ruleset/trait.RulesetCreatedAttr.js b/trait.impl/landlock/ruleset/trait.RulesetCreatedAttr.js new file mode 100644 index 0000000..cd53510 --- /dev/null +++ b/trait.impl/landlock/ruleset/trait.RulesetCreatedAttr.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/std/os/fd/owned/trait.AsFd.js b/trait.impl/std/os/fd/owned/trait.AsFd.js new file mode 100644 index 0000000..824ef1b --- /dev/null +++ b/trait.impl/std/os/fd/owned/trait.AsFd.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"landlock":[["impl AsFd for PathFd"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file