Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand documentation substantially #27

Merged
merged 3 commits into from
Mar 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ jobs:
- name: LeakSanitizer
run: docker run --env RUSTFLAGS="-Z sanitizer=leak" posixacl-nightly cargo test --color=always
- name: AddressSanitizer
run: docker run --env RUSTFLAGS="-Z sanitizer=address" posixacl-nightly cargo test --color=always
# --tests to omit doc tests, doesn't play nice with AddressSanitizer
run: docker run --env RUSTFLAGS="-Z sanitizer=address" posixacl-nightly cargo test --tests --color=always

rust-stable:
runs-on: ubuntu-latest
Expand Down
40 changes: 34 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,43 @@ posix-acl
[![Documentation](https://docs.rs/posix-acl/badge.svg)](https://docs.rs/posix-acl/)
[![Tests status](https://github.com/intgr/posix-acl/workflows/Tests/badge.svg?branch=master)](https://github.com/intgr/posix-acl/actions?query=workflow:Tests)

posix-acl is a simple Rust library to interact with POSIX filesystem ACLs. It uses the operating
system's C API internally.

Turns out that the C POSIX ACL library is actually quite annoying to work with and this library
significantly improves on that.
**posix-acl** is a Rust library to interact with POSIX file system Access Control Lists (ACL).
It wraps the operating system's C interface with a safe Rust API. The API is deliberately different
from the POSIX C API to make it easier to use.

NB! Currently only tested on Linux.

Read [Documentation on Docs.rs](https://docs.rs/posix-acl/) for more details.
Resources:
* [Library API documentation on Docs.rs](https://docs.rs/posix-acl/)
* [Background information about ACL behavior](
https://www.usenix.org/legacy/publications/library/proceedings/usenix03/tech/freenix03/full_papers/gruenbacher/gruenbacher_html/main.html)

### Usage example
```rust
use posix_acl::{PosixACL, Qualifier, ACL_READ, ACL_WRITE};

fn main() {
// Read ACL from file (if there is no ACL yet, the OS will synthesize one)
let mut acl = PosixACL::read_acl("/tmp/posix-acl-testfile".as_ref()).unwrap();

// Get permissions of owning user of the file
let perm = acl.get(Qualifier::UserObj).unwrap();
assert_eq!(perm, ACL_READ | ACL_WRITE);

// Get permissions for user UID 1234
let perm = acl.get(Qualifier::User(1234));
assert!(perm.is_none());

// Grant read access to group GID 1234 (adds new entry or overwrites an existing entry)
acl.set(Qualifier::Group(1234), ACL_READ);

// Remove ACL entry of group GID 1234
acl.remove(Qualifier::Group(1234));

// Write ACL back to the file
acl.write_acl("/tmp/posix-acl-testfile".as_ref()).unwrap();
}
```

Release history
---------------
Expand Down
66 changes: 58 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,42 @@
//! posix-acl is a simple Rust library to interact with POSIX filesystem ACLs. It uses the
//! operating system's C API internally.
//! **posix-acl** is a Rust library to interact with POSIX file system Access Control Lists (ACL).
//! It wraps the operating system's C interface with a safe Rust API. The API is deliberately
//! different from the POSIX C API to make it easier to use.
//!
//! See the [`PosixACL`] struct as a starting point.
//! NB! Currently only tested on Linux.
//!
//! While officially called a "list", The main struct [`PosixACL`] implements a "mapping-like"
//! interface where key is the [`Qualifier`] enum and value is `u32` containing permission bits.
//! This is without any loss of functionality, as duplicate entries with the same Qualifier are
//! disallowed by POSIX anyway.
//!
//! For background information about ACL behavior, read [POSIX Access Control Lists on Linux](
//! https://www.usenix.org/legacy/publications/library/proceedings/usenix03/tech/freenix03/full_papers/gruenbacher/gruenbacher_html/main.html).
//!
//! ## Usage example
//! ```
//! use posix_acl::{PosixACL, Qualifier, ACL_READ, ACL_WRITE};
//!
//! # std::fs::File::create("/tmp/posix-acl-testfile");
//! // Read ACL from file (if there is no ACL yet, the OS will synthesize one)
//! let mut acl = PosixACL::read_acl("/tmp/posix-acl-testfile".as_ref()).unwrap();
//!
//! // Get permissions of owning user of the file
//! let perm = acl.get(Qualifier::UserObj).unwrap();
//! assert_eq!(perm, ACL_READ | ACL_WRITE);
//!
//! // Get permissions for user UID 1234
//! let perm = acl.get(Qualifier::User(1234));
//! assert!(perm.is_none());
//!
//! // Grant read access to group GID 1234 (adds new entry or overwrites an existing entry)
//! acl.set(Qualifier::Group(1234), ACL_READ);
//!
//! // Remove ACL entry of group GID 1234
//! acl.remove(Qualifier::Group(1234));
//!
//! // Write ACL back to the file
//! acl.write_acl("/tmp/posix-acl-testfile".as_ref()).unwrap();
//! ```
#[macro_use]
extern crate simple_error;

Expand Down Expand Up @@ -181,6 +215,14 @@ impl PosixACL {
/// contain at least four entries: UserObj, GroupObj, Mask and Other.
///
/// Bits higher than 9 (e.g. SUID flag, etc) are ignored.
///
/// ```
/// use posix_acl::PosixACL;
/// assert_eq!(
/// PosixACL::new(0o751).as_text(),
/// "user::rwx\ngroup::r-x\nmask::r-x\nother::--x\n"
/// );
/// ```
pub fn new(file_mode: u32) -> PosixACL {
let mut acl = PosixACL::empty();
acl.set(UserObj, (file_mode >> 6) & ACL_RWX);
Expand All @@ -202,13 +244,16 @@ impl PosixACL {
PosixACL { acl }
}

/// Read a path's ACL and return as `PosixACL` object.
/// Read a path's access ACL and return as `PosixACL` object.
pub fn read_acl(path: &Path) -> Result<PosixACL, SimpleError> {
Self::read_acl_flags(path, acl_sys::ACL_TYPE_ACCESS)
}

/// Read a directory's default ACL and return as `PosixACL` object.
/// This will fail if `path` is not a directory.
///
/// Default ACL determines permissions for new files and subdirectories created in the
/// directory.
pub fn read_default_acl(path: &Path) -> Result<PosixACL, SimpleError> {
Self::read_acl_flags(path, acl_sys::ACL_TYPE_DEFAULT)
}
Expand All @@ -231,9 +276,9 @@ impl PosixACL {
Ok(PosixACL { acl })
}

/// Write the current ACL to a file. Overwrites any existing ACL on the file.
/// Write this ACL to a path's access ACL. Overwrites any existing access ACL.
///
/// Automatically re-calculates the `Mask` entry and calls validation.
/// Automatically re-calculates the magic `Mask` entry and calls validation.
pub fn write_acl(&mut self, path: &Path) -> Result<(), SimpleError> {
let c_path = path_to_cstring(path);
self.fix_mask();
Expand All @@ -254,7 +299,7 @@ impl PosixACL {
RawACLIterator::new(&self)
}

/// Get all ACLEntry items. The POSIX ACL API does not allow multiple parallel iterators so we
/// Get all ACLEntry items. The POSIX ACL C API does not allow multiple parallel iterators so we
/// return a materialized vector just to be safe.
pub fn entries(&self) -> Vec<ACLEntry> {
unsafe { self.raw_iter() }
Expand Down Expand Up @@ -335,7 +380,10 @@ impl PosixACL {
}
}

/// Re-calculate the `Qualifier::Mask` entry. This is automatically done during `write_acl()`.
/// Re-calculate the `Qualifier::Mask` entry.
///
/// Usually there is no need to call this directly, as this is done during `write_acl()`
/// automatically.
pub fn fix_mask(&mut self) {
unsafe {
check_return(acl_calc_mask(&mut self.acl), "acl_calc_mask");
Expand All @@ -344,6 +392,8 @@ impl PosixACL {

/// Return the textual representation of the ACL. Individual entries are separated by newline
/// (`'\n'`).
///
/// UID/GID are automatically resolved to names by the platform.
pub fn as_text(&self) -> String {
let mut len: ssize_t = 0;
let txt = AutoPtr(unsafe { acl_to_text(self.acl, &mut len) });
Expand Down