diff --git a/Cargo.lock b/Cargo.lock
index 8eb6809bf635d20d7cf979f36ccea35e5d029897..811650c2c95bfa65a13b50cecd06313e00c870ce 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -438,6 +438,7 @@ dependencies = [
  "arg_parser 0.1.0 (git+https://github.com/redox-os/arg-parser.git)",
  "argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
  "liner 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "pkgutils 0.1.1 (git+https://github.com/redox-os/pkgutils.git)",
  "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/Cargo.toml b/Cargo.toml
index b873ce4b32dbcb8306088436524eeac70d694684..3b789ff5af75f6c475d5a8d1fe567fc841e8024a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,6 +14,7 @@ path = "src/lib.rs"
 arg_parser = { git = "https://github.com/redox-os/arg-parser.git" }
 argon2rs = { version = "0.2", default-features = false }
 liner = "0.1"
+libc = "0.2"
 failure = "0.1"
 pkgutils = { git = "https://github.com/redox-os/pkgutils.git" }
 rand = "0.3"
diff --git a/src/config/file.rs b/src/config/file.rs
index 86b491e6554ccf9793285d4d0fe727ea4b9b45b0..2104fdfe970d616d165984f56aaec1c9dbd7ee8e 100644
--- a/src/config/file.rs
+++ b/src/config/file.rs
@@ -1,7 +1,74 @@
+
+use Result;
+use libc::chown;
+
+use std::io::{Error, Write};
+use std::ffi::{CString, OsStr};
+use std::fs::{self, File};
+use std::os::unix::ffi::OsStrExt;
+use std::os::unix::fs::{PermissionsExt, symlink};
+use std::path::Path;
+
+//type Result<T> = std::result::Result<T, Error>;
+
 #[derive(Debug, Default, Deserialize)]
 pub struct FileConfig {
     pub path: String,
     pub data: String,
     #[serde(default)]
-    pub symlink: bool
+    pub symlink: bool,
+    pub mode: Option<u32>,
+    pub uid: Option<u32>,
+    pub gid: Option<u32>
+}
+
+// TODO: Rewrite
+impl FileConfig {
+    
+    pub(crate) fn create<P: AsRef<Path>>(self, prefix: P) -> Result<()> {
+        let path = self.path.trim_left_matches('/');
+        let target_file = prefix.as_ref()
+            .join(path);
+        
+        println!("target file: {:?}", target_file);
+        
+        if let Some(parent) = target_file.parent() {
+            println!("Create file parent {}", parent.display());
+            fs::create_dir_all(parent)?;
+        }
+        
+        if self.symlink {
+            println!("Create symlink {}", target_file.display());
+            symlink(&OsStr::new(&self.data), &target_file)?;
+            Ok(())
+        } else {
+            println!("Create file {}", target_file.display());
+            let mut file = File::create(&target_file)?;
+            file.write_all(self.data.as_bytes())?;
+            
+            self.apply_perms(target_file)
+        }
+    }
+    
+    fn apply_perms<P: AsRef<Path>>(&self, target: P) -> Result<()> {
+        let path = target.as_ref();
+        let mode = self.mode.unwrap_or(0o0755);
+        let uid = self.uid.unwrap_or(0);
+        let gid = self.gid.unwrap_or(0);
+        
+        // chmod
+        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, gid)
+        };
+        // credit to uutils
+        if ret == 0 {
+            Ok(())
+        } else {
+            Err(Error::last_os_error().into())
+        }
+    }
 }
diff --git a/src/config/mod.rs b/src/config/mod.rs
index 5465d4f9f896ff4a93d43abba76123c3c9874527..4d302620e1f9c42a7d148c387ef5574718d4afa9 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -1,7 +1,7 @@
 use std::collections::BTreeMap;
 
 mod general;
-mod file;
+pub(crate) mod file;
 mod package;
 mod user;
 
diff --git a/src/lib.rs b/src/lib.rs
index a34ae1de48c7464da5427057dcbd6d0181fd16a2..ed122a87f0e9f905a16be6f7a530010e43e8edb0 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -3,6 +3,7 @@
 #[macro_use]
 extern crate serde_derive;
 extern crate argon2rs;
+extern crate libc;
 extern crate liner;
 extern crate failure;
 extern crate pkgutils;
@@ -12,6 +13,7 @@ extern crate termion;
 mod config;
 
 pub use config::Config;
+use config::file::FileConfig;
 
 use argon2rs::verifier::Encoded;
 use argon2rs::{Argon2, Variant};
@@ -21,15 +23,12 @@ use termion::input::TermRead;
 use pkgutils::{Repo, Package};
 
 use std::{env, fs};
-use std::ffi::OsStr;
 use std::io::{self, stderr, Write};
-use std::os::unix::ffi::OsStrExt;
-use std::os::unix::fs::symlink;
 use std::path::Path;
 use std::process::{self, Command};
 use std::str::FromStr;
 
-type Result<T> = std::result::Result<T, Error>;
+pub(crate) type Result<T> = std::result::Result<T, Error>;
 
 const REMOTE: &'static str = "https://static.redox-os.org/pkg";
 const TARGET: &'static str = "x86_64-unknown-redox";
@@ -133,28 +132,6 @@ pub fn install<P: AsRef<Path>, S: AsRef<str>>(config: Config, output_dir: P, coo
         Ok(())
     }
     
-    /// Creates a file relative to the output directory
-    fn create_file_relative<P: AsRef<Path>>(path: P, data: &[u8], is_symlink: bool) -> Result<()> {
-        let root = env::var(SYSROOT)?;
-        let target_file = Path::new(&root)
-            .join(path.as_ref());
-        
-        if let Some(parent) = target_file.parent() {
-            println!("Create file parent {}", parent.display());
-            fs::create_dir_all(parent)?;
-        }
-        
-        if is_symlink {
-            println!("Create symlink {}", target_file.display());
-            symlink(&OsStr::from_bytes(data), &target_file)?;
-        } else {
-            println!("Create file {}", target_file.display());
-            let mut file = fs::File::create(&target_file)?;
-            file.write_all(data)?;
-        }
-        Ok(())
-    }
-    
     let mut context = liner::Context::new();
     
     macro_rules! prompt {
@@ -172,22 +149,21 @@ pub fn install<P: AsRef<Path>, S: AsRef<str>>(config: Config, output_dir: P, coo
         })
     }
 
+    let output_dir = output_dir.as_ref();
+
     // Using an env var here to communicate the root dir to the functions
     //   instead of passing it as a param
-    env::set_var(SYSROOT, output_dir.as_ref().as_os_str());
+    env::set_var(SYSROOT, output_dir.as_os_str());
 
-    let output_dir = output_dir.as_ref();
     println!("Install {:#?} to {}", config, output_dir.display());
 
     // TODO: Mount disk if output is a file
     let output_dir = output_dir.to_owned();
 
-    create_dir_relative("")?;
-
     install_packages(&config, output_dir.to_str().unwrap(), cookbook);
 
     for file in config.files {
-        create_file_relative(file.path.trim_matches('/'), file.data.as_bytes(), file.symlink)?;
+        file.create(&output_dir)?;
     }
 
     let mut passwd = String::new();
@@ -233,7 +209,14 @@ pub fn install<P: AsRef<Path>, S: AsRef<str>>(config: Config, output_dir: P, coo
     }
 
     if !passwd.is_empty() {
-        create_file_relative("etc/passwd", passwd.as_bytes(), false)?;
+        FileConfig {
+            path: "/etc/passwd".to_string(),
+            data: passwd,
+            symlink: false,
+            mode: Some(0o755),
+            uid: Some(0),
+            gid: Some(0)
+        }.create(output_dir)?;
     }
 
     Ok(())