diff options
author | Justin Wernick <justin@worthe-it.co.za> | 2023-08-11 22:04:19 +0200 |
---|---|---|
committer | Justin Wernick <justin@worthe-it.co.za> | 2023-08-15 21:40:35 +0200 |
commit | 64da82c661b2a28c7a258bd30c0084633d0e1896 (patch) | |
tree | e631e496b70f10d8414a3d1962797aa6354de918 /src | |
parent | 2203a06532979e8c4772dcb134c109e1f308031a (diff) |
Create group directories if they don't already exist
- With the correct ownership
- With the correct permissions
Fix #5
Diffstat (limited to 'src')
-rw-r--r-- | src/git.rs | 53 | ||||
-rw-r--r-- | src/lib.rs | 2 | ||||
-rw-r--r-- | src/user_info.rs | 9 |
3 files changed, 49 insertions, 15 deletions
@@ -1,11 +1,12 @@ use crate::{ parser::{GitReceivePackArgs, GitUploadPackArgs}, - user_info::{get_user_groups, get_username}, + user_info::{get_gid, get_user_groups, get_username}, ShackleError, }; use git2::{ErrorCode, Repository, RepositoryInitMode, RepositoryInitOptions}; use std::{ fs, + os::unix::fs::PermissionsExt, path::{Path, PathBuf}, process::Command, }; @@ -75,24 +76,48 @@ pub fn init( description: &Option<String>, branch: &str, ) -> Result<GitInitResult, ShackleError> { + if let Some(group) = &group { + if !verify_user_is_in_group(group) { + return Err(ShackleError::InvalidGroup); + } + } + + let git_prefix = git_dir_prefix(); + let collection_dir = match group { + Some(group) => group_git_dir(group), + None => personal_git_dir()?, + }; + let path = collection_dir.join(repo_name).with_extension("git"); + + if !git_prefix.is_dir() { + fs::create_dir(&git_prefix)?; + } + + if !collection_dir.is_dir() { + fs::create_dir(&collection_dir)?; + + if let Some(group) = group { + let gid = get_gid(&group).expect("User is in group but no group ID?"); + nix::unistd::chown(&collection_dir, None, Some(gid))?; + } + + let mut perms = collection_dir.metadata()?.permissions(); + perms.set_mode(match group { + Some(_) => 0o2770, + None => 0o700, + }); + fs::set_permissions(&collection_dir, perms)?; + } + let mut init_opts = RepositoryInitOptions::new(); init_opts .bare(true) - .mkdir(true) + .mkdir(false) .no_reinit(true) .initial_head(branch); - - let path = match group { - Some(group) => { - if !verify_user_is_in_group(group) { - return Err(ShackleError::InvalidGroup); - } - - init_opts.mode(RepositoryInitMode::SHARED_GROUP); - group_git_dir(group).join(repo_name).with_extension("git") - } - None => personal_git_dir()?.join(repo_name).with_extension("git"), - }; + if group.is_some() { + init_opts.mode(RepositoryInitMode::SHARED_GROUP); + } Repository::init_opts(&path, &init_opts)?; if let Some(description) = description { @@ -97,6 +97,8 @@ pub enum ShackleError { #[error(transparent)] IoError(#[from] io::Error), #[error(transparent)] + NixError(#[from] nix::errno::Errno), + #[error(transparent)] GitError(#[from] git2::Error), #[error(transparent)] ReadlineError(#[from] ReadlineError), diff --git a/src/user_info.rs b/src/user_info.rs index 7a42db9..a352adb 100644 --- a/src/user_info.rs +++ b/src/user_info.rs @@ -1,4 +1,4 @@ -use nix::unistd::{getgroups, getuid, Group, User}; +use nix::unistd::{getgroups, getuid, Gid, Group, User}; pub fn get_username() -> Option<String> { let uid = getuid(); @@ -13,6 +13,13 @@ pub fn get_user_groups() -> Vec<String> { .collect() } +pub fn get_gid(group_name: &str) -> Option<Gid> { + nix::unistd::Group::from_name(&group_name) + .ok() + .flatten() + .map(|group| group.gid) +} + #[cfg(test)] mod test { use super::*; |