~jpastuszek/file-owner

09248a5d191b0e8c09a59eb88f7cc01b25aa8a2a — Jakub Pastuszek 1 year, 5 months ago 0e80181
docs
1 files changed, 32 insertions(+), 1 deletions(-)

M src/lib.rs
M src/lib.rs => src/lib.rs +32 -1
@@ 3,6 3,8 @@ Set and get Unix file owner and group.

UID/GUI numbers or user/group names can be used.

Note: This crate will only compile on Unix systems.

# Usage examples

## Set owner and group by name


@@ 36,8 38,8 @@ let g = "/tmp/baz".group().unwrap();
g.id(); // 99
g.name(); // Some("nogroup")
```

*/

use nix::unistd::chown;
use nix::unistd::{Gid, Uid, Group as NixGroup, User};
use std::path::Path;


@@ 48,6 50,7 @@ use std::fs;
use std::io;
use std::os::unix::fs::MetadataExt;

/// File owner or group error.
#[derive(Debug)]
pub enum FileOwnerError {
    IoError(io::Error),


@@ 96,22 99,27 @@ impl From<Infallible> for FileOwnerError {
    }
}

/// Owner of a file.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Owner(Uid);

impl Owner {
    /// Constructs Owner from UID.
    pub fn from_uid(uid: u32) -> Owner {
        Owner(Uid::from_raw(uid.try_into().unwrap()))
    }

    /// Construct Owner from name.
    pub fn from_name(user: &str) -> Result<Owner, FileOwnerError> {
        Ok(Owner(User::from_name(user)?.ok_or_else(|| FileOwnerError::UserNotFound(user.to_owned()))?.uid))
    }

    /// Gets UID.
    pub fn id(&self) -> u32 {
        self.0.as_raw().try_into().unwrap()
    }

    /// Gets name.
    pub fn name(&self) -> Result<Option<String>, FileOwnerError> {
        Ok(User::from_uid(self.0)?.map(|u| u.name))
    }


@@ 141,22 149,27 @@ impl Display for Owner {
    }
}

/// Group of a file.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Group(Gid);

impl Group {
    /// Constructs Group from GUI.
    pub fn from_gid(gid: u32) -> Group {
        Group(Gid::from_raw(gid.try_into().unwrap()))
    }

    /// Constructs Group from name.
    pub fn from_name(group: &str) -> Result<Group, FileOwnerError> {
        Ok(Group(NixGroup::from_name(group)?.ok_or_else(|| FileOwnerError::GroupNotFound(group.to_owned()))?.gid))
    }

    /// Gets GID.
    pub fn id(&self) -> u32 {
        self.0.as_raw().try_into().unwrap()
    }

    // Gets name.
    pub fn name(&self) -> Result<Option<String>, FileOwnerError> {
        Ok(NixGroup::from_gid(self.0)?.map(|u| u.name))
    }


@@ 186,37 199,55 @@ impl Display for Group {
    }
}

/// Sets owner to file at given path.
pub fn set_owner<E: Into<FileOwnerError>>(path: impl AsRef<Path>, owner: impl TryInto<Owner, Error = E>) -> Result<(), FileOwnerError> {
    Ok(chown(path.as_ref().into(), Some(owner.try_into().map_err(Into::into)?.0), None)?)
}

/// Sets group to file at given path.
pub fn set_group<E: Into<FileOwnerError>>(path: impl AsRef<Path>, group: impl TryInto<Group, Error = E>) -> Result<(), FileOwnerError> {
    Ok(chown(path.as_ref().into(), None, Some(group.try_into().map_err(Into::into)?.0))?)
}

/// Sets owner and group to file at given path.
pub fn set_owner_group<E1: Into<FileOwnerError>, E2: Into<FileOwnerError>>(path: impl AsRef<Path>, owner: impl TryInto<Owner, Error = E1>, group: impl TryInto<Group, Error = E2>) -> Result<(), FileOwnerError> {
    Ok(chown(path.as_ref().into(), Some(owner.try_into().map_err(Into::into)?.0), Some(group.try_into().map_err(Into::into)?.0))?)
}

/// Gets owner of file at given path.
pub fn owner(path: impl AsRef<Path>) -> Result<Owner, FileOwnerError> {
    Ok(Owner::from_uid(fs::metadata(path)?.uid().try_into().unwrap()))
}

/// Gets group of file at given path.
pub fn group(path: impl AsRef<Path>) -> Result<Group, FileOwnerError> {
    Ok(Group::from_gid(fs::metadata(path)?.gid().try_into().unwrap()))
}

/// Gets owner and group of file at given path.
pub fn owner_group(path: impl AsRef<Path>) -> Result<(Owner, Group), FileOwnerError> {
    let meta = fs::metadata(path)?;
    Ok((Owner::from_uid(meta.uid().try_into().unwrap()), Group::from_gid(meta.gid().try_into().unwrap())))
}

/// Extension methods for `T: AsRef<Path>`.
pub trait PathExt {
    /// Sets owner to file at given path.
    fn set_owner<E: Into<FileOwnerError>>(&self, owner: impl TryInto<Owner, Error = E>) -> Result<(), FileOwnerError>;

    /// Sets group to file at given path.
    fn set_group<E: Into<FileOwnerError>>(&self, group: impl TryInto<Group, Error = E>) -> Result<(), FileOwnerError>;

    /// Sets owner and group to file at given path.
    fn set_owner_group<E1: Into<FileOwnerError>, E2: Into<FileOwnerError>>(&self, owner: impl TryInto<Owner, Error = E1>, group: impl TryInto<Group, Error = E2>) -> Result<(), FileOwnerError>;

    /// Gets owner of file at given path.
    fn owner(&self) -> Result<Owner, FileOwnerError>;

    /// Gets group of file at given path.
    fn group(&self) -> Result<Group, FileOwnerError>;

    /// Gets owner and group of file at given path.
    fn owner_group(&self) -> Result<(Owner, Group), FileOwnerError>;
}