From f710fa79db52e86f2c93c1bfa4f6ef0614c15a30 Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jackpot51@gmail.com>
Date: Mon, 21 Nov 2022 14:55:08 -0700
Subject: [PATCH] Recursively set permissions on home directories

---
 src/config/file.rs | 36 +++++++++++++++++++++++-------------
 src/lib.rs         |  9 ++++++---
 2 files changed, 29 insertions(+), 16 deletions(-)

diff --git a/src/config/file.rs b/src/config/file.rs
index cccfbd7..8089513 100644
--- a/src/config/file.rs
+++ b/src/config/file.rs
@@ -1,6 +1,6 @@
 
 use Result;
-use libc::{chown, gid_t, uid_t};
+use libc::{gid_t, uid_t};
 
 use std::io::{Error, Write};
 use std::ffi::{CString, OsStr};
@@ -11,6 +11,24 @@ use std::path::Path;
 
 //type Result<T> = std::result::Result<T, Error>;
 
+fn chown<P: AsRef<Path>>(path: P, uid: uid_t, gid: gid_t, recursive: bool) -> Result<()> {
+    let path = path.as_ref();
+
+    let c_path = CString::new(path.as_os_str().as_bytes()).unwrap();
+    if unsafe { libc::chown(c_path.as_ptr(), uid, gid) } != 0 {
+        return Err(Error::last_os_error().into());
+    }
+
+    if recursive && path.is_dir() {
+        for entry_res in fs::read_dir(path)? {
+            let entry = entry_res?;
+            chown(entry.path(), uid, gid, recursive)?;
+        }
+    }
+
+    Ok(())
+}
+
 #[derive(Clone, Debug, Default, Deserialize)]
 pub struct FileConfig {
     pub path: String,
@@ -21,12 +39,13 @@ pub struct FileConfig {
     pub directory: bool,
     pub mode: Option<u32>,
     pub uid: Option<u32>,
-    pub gid: Option<u32>
+    pub gid: Option<u32>,
+    #[serde(default)]
+    pub recursive_chown: bool,
 }
 
 // TODO: Rewrite impls
 impl FileConfig {
-
     pub(crate) fn create<P: AsRef<Path>>(self, prefix: P) -> Result<()> {
         let path = self.path.trim_start_matches('/');
         let target_file = prefix.as_ref()
@@ -69,15 +88,6 @@ impl FileConfig {
         fs::set_permissions(path, fs::Permissions::from_mode(mode))?;
 
         // chown
-        let c_path = CString::new(path.as_os_str().as_bytes()).unwrap();
-        let ret = unsafe {
-            chown(c_path.as_ptr(), uid as uid_t, gid as gid_t)
-        };
-        // credit to uutils
-        if ret == 0 {
-            Ok(())
-        } else {
-            Err(Error::last_os_error().into())
-        }
+        chown(path, uid, gid, self.recursive_chown)
     }
 }
diff --git a/src/lib.rs b/src/lib.rs
index bbdfcd6..d05f7d8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -219,7 +219,8 @@ pub fn install_dir<P: AsRef<Path>, S: AsRef<str>>(config: Config, output_dir: P,
             directory: true,
             mode: Some(0o0700),
             uid: Some(uid),
-            gid: Some(gid)
+            gid: Some(gid),
+            recursive_chown: true,
         }.create(&output_dir)?;
 
         let password = hash_password(&password)?;
@@ -237,7 +238,8 @@ pub fn install_dir<P: AsRef<Path>, S: AsRef<str>>(config: Config, output_dir: P,
             // Take defaults
             mode: None,
             uid: None,
-            gid: None
+            gid: None,
+            recursive_chown: false,
         }.create(&output_dir)?;
     }
 
@@ -249,7 +251,8 @@ pub fn install_dir<P: AsRef<Path>, S: AsRef<str>>(config: Config, output_dir: P,
             directory: false,
             mode: Some(0o0600),
             uid: Some(0),
-            gid: Some(0)
+            gid: Some(0),
+            recursive_chown: false,
         }.create(&output_dir)?;
     }
 
-- 
GitLab