From a9fcb973f682cdc0495c79950955c39a8e724db9 Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jackpot51@gmail.com>
Date: Sun, 29 Jul 2018 07:18:44 -0600
Subject: [PATCH] Implement utimes and utime Format

---
 Cargo.lock                    |  9 +++++
 Cargo.toml                    |  1 +
 src/arpainet/src/lib.rs       |  2 +-
 src/dirent/src/lib.rs         | 26 +++++++++----
 src/lib.rs                    |  1 +
 src/platform/src/linux/mod.rs | 12 +++++-
 src/platform/src/rawfile.rs   |  6 +--
 src/platform/src/redox/mod.rs | 48 ++++++++++++++---------
 src/platform/src/types.rs     | 18 ++++-----
 src/pwd/src/lib.rs            | 72 +++++++++++++++++++++++------------
 src/signal/src/lib.rs         | 10 +++--
 src/signal/src/linux.rs       | 12 ++++--
 src/signal/src/redox.rs       | 12 ++++--
 src/sys_ioctl/src/lib.rs      |  6 +--
 src/sys_resource/src/lib.rs   |  2 +-
 src/sys_socket/src/lib.rs     | 30 ++++++++++++---
 src/sys_stat/src/lib.rs       |  4 +-
 src/sys_time/src/lib.rs       | 23 ++++++++---
 src/sys_times/src/lib.rs      |  2 +-
 src/sys_un/src/lib.rs         |  2 +-
 src/time/src/lib.rs           |  5 ++-
 src/unistd/src/lib.rs         |  8 ++--
 src/utime/Cargo.toml          | 11 ++++++
 src/utime/build.rs            | 11 ++++++
 src/utime/cbindgen.toml       |  7 ++++
 src/utime/src/lib.rs          | 29 ++++++++++++++
 26 files changed, 268 insertions(+), 101 deletions(-)
 create mode 100644 src/utime/Cargo.toml
 create mode 100644 src/utime/build.rs
 create mode 100644 src/utime/cbindgen.toml
 create mode 100644 src/utime/src/lib.rs

diff --git a/Cargo.lock b/Cargo.lock
index 721878128..18d19d482 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -355,6 +355,7 @@ dependencies = [
  "sys_wait 0.1.0",
  "time 0.1.0",
  "unistd 0.1.0",
+ "utime 0.1.0",
  "wchar 0.1.0",
  "wctype 0.1.0",
 ]
@@ -690,6 +691,14 @@ dependencies = [
  "sys_time 0.1.0",
 ]
 
+[[package]]
+name = "utime"
+version = "0.1.0"
+dependencies = [
+ "cbindgen 0.5.2",
+ "platform 0.1.0",
+]
+
 [[package]]
 name = "va_list"
 version = "0.1.0"
diff --git a/Cargo.toml b/Cargo.toml
index 77643812b..999b40b17 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -47,6 +47,7 @@ sys_utsname = { path = "src/sys_utsname" }
 sys_wait = { path = "src/sys_wait" }
 time = { path = "src/time" }
 unistd = { path = "src/unistd" }
+utime = { path = "src/utime" }
 wchar = { path = "src/wchar" }
 wctype = { path = "src/wctype" }
 
diff --git a/src/arpainet/src/lib.rs b/src/arpainet/src/lib.rs
index 3ef6a8cf9..632cb3966 100644
--- a/src/arpainet/src/lib.rs
+++ b/src/arpainet/src/lib.rs
@@ -15,8 +15,8 @@ use core::str::FromStr;
 use core::{mem, ptr, slice, str};
 use errno::*;
 use netinet::in_h::in_addr;
-use platform::types::*;
 use platform::c_str;
+use platform::types::*;
 
 #[no_mangle]
 pub extern "C" fn htonl(hostlong: u32) -> u32 {
diff --git a/src/dirent/src/lib.rs b/src/dirent/src/lib.rs
index 819b4d4b0..380b400e0 100644
--- a/src/dirent/src/lib.rs
+++ b/src/dirent/src/lib.rs
@@ -31,7 +31,7 @@ pub struct DIR {
 
     // Offset is like the total index, never erased It is used as an
     // alternative to dirent's d_off, but works on redox too.
-    offset: usize
+    offset: usize,
 }
 
 #[repr(C)]
@@ -40,12 +40,16 @@ pub struct dirent {
     pub d_off: off_t,
     pub d_reclen: c_ushort,
     pub d_type: c_uchar,
-    pub d_name: [c_char; 256]
+    pub d_name: [c_char; 256],
 }
 
 #[no_mangle]
 pub extern "C" fn opendir(path: *const c_char) -> *mut DIR {
-    let fd = platform::open(path, fcntl::O_RDONLY | fcntl::O_DIRECTORY | fcntl::O_CLOEXEC, 0o755);
+    let fd = platform::open(
+        path,
+        fcntl::O_RDONLY | fcntl::O_DIRECTORY | fcntl::O_CLOEXEC,
+        0o755,
+    );
 
     if fd < 0 {
         return ptr::null_mut();
@@ -56,7 +60,7 @@ pub extern "C" fn opendir(path: *const c_char) -> *mut DIR {
         buf: [0; _DIR_BUF_SIZE],
         index: 0,
         len: 0,
-        offset: 0
+        offset: 0,
     }))
 }
 
@@ -73,7 +77,7 @@ pub unsafe extern "C" fn readdir(dir: *mut DIR) -> *mut dirent {
         let read = platform::getdents(
             (*dir).fd,
             (*dir).buf.as_mut_ptr() as *mut platform::types::dirent,
-            (*dir).buf.len()
+            (*dir).buf.len(),
         );
         if read <= 0 {
             if read != 0 && read != -errno::ENOENT {
@@ -88,7 +92,8 @@ pub unsafe extern "C" fn readdir(dir: *mut DIR) -> *mut dirent {
 
     let ptr = (*dir).buf.as_mut_ptr().offset((*dir).index as isize) as *mut dirent;
 
-    #[cfg(target_os = "redox")] {
+    #[cfg(target_os = "redox")]
+    {
         if (*dir).index != 0 || (*dir).offset != 0 {
             // This should happen every time but the first, making the offset
             // point to the current element and not the next
@@ -96,7 +101,8 @@ pub unsafe extern "C" fn readdir(dir: *mut DIR) -> *mut dirent {
         }
         (*ptr).d_off = (*dir).offset as off_t;
     }
-    #[cfg(not(target_os = "redox"))] {
+    #[cfg(not(target_os = "redox"))]
+    {
         (*dir).offset = (*ptr).d_off as usize;
     }
 
@@ -104,7 +110,11 @@ pub unsafe extern "C" fn readdir(dir: *mut DIR) -> *mut dirent {
     ptr
 }
 // #[no_mangle]
-pub extern "C" fn readdir_r(_dir: *mut DIR, _entry: *mut dirent, _result: *mut *mut dirent) -> *mut dirent {
+pub extern "C" fn readdir_r(
+    _dir: *mut DIR,
+    _entry: *mut dirent,
+    _result: *mut *mut dirent,
+) -> *mut dirent {
     unimplemented!(); // plus, deprecated
 }
 
diff --git a/src/lib.rs b/src/lib.rs
index 65e556ac6..8f1b88757 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -37,6 +37,7 @@ pub extern crate sys_utsname;
 pub extern crate sys_wait;
 pub extern crate time;
 pub extern crate unistd;
+pub extern crate utime;
 pub extern crate wchar;
 pub extern crate wctype;
 
diff --git a/src/platform/src/linux/mod.rs b/src/platform/src/linux/mod.rs
index 8003b7f27..873720ed2 100644
--- a/src/platform/src/linux/mod.rs
+++ b/src/platform/src/linux/mod.rs
@@ -109,6 +109,10 @@ pub fn futimens(fd: c_int, times: *const timespec) -> c_int {
     e(unsafe { syscall!(UTIMENSAT, fd, ptr::null::<c_char>(), times, 0) }) as c_int
 }
 
+pub fn utimens(path: *const c_char, times: *const timespec) -> c_int {
+    e(unsafe { syscall!(UTIMENSAT, AT_FDCWD, path, times, 0) }) as c_int
+}
+
 pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char {
     if e(unsafe { syscall!(GETCWD, buf, size) }) == !0 {
         ptr::null_mut()
@@ -373,7 +377,13 @@ pub fn shutdown(socket: c_int, how: c_int) -> c_int {
 }
 
 pub unsafe fn sigaction(sig: c_int, act: *const sigaction, oact: *mut sigaction) -> c_int {
-    e(syscall!(RT_SIGACTION, sig, act, oact, mem::size_of::<sigset_t>())) as c_int
+    e(syscall!(
+        RT_SIGACTION,
+        sig,
+        act,
+        oact,
+        mem::size_of::<sigset_t>()
+    )) as c_int
 }
 
 pub fn sigprocmask(how: c_int, set: *const sigset_t, oset: *mut sigset_t) -> c_int {
diff --git a/src/platform/src/rawfile.rs b/src/platform/src/rawfile.rs
index 76aff649c..2efc20d48 100644
--- a/src/platform/src/rawfile.rs
+++ b/src/platform/src/rawfile.rs
@@ -1,5 +1,5 @@
+use super::{close, dup, open, types::*};
 use core::ops::Deref;
-use super::{open, dup, close, types::*};
 
 pub struct RawFile(c_int);
 
@@ -7,14 +7,14 @@ impl RawFile {
     pub fn open(path: *const c_char, oflag: c_int, mode: mode_t) -> Result<RawFile, ()> {
         match open(path, oflag, mode) {
             -1 => Err(()),
-            n => Ok(RawFile(n))
+            n => Ok(RawFile(n)),
         }
     }
 
     pub fn dup(&self) -> Result<RawFile, ()> {
         match dup(self.0) {
             -1 => Err(()),
-            n => Ok(RawFile(n))
+            n => Ok(RawFile(n)),
         }
     }
 
diff --git a/src/platform/src/redox/mod.rs b/src/platform/src/redox/mod.rs
index 099f2fd1c..54a4f1bfc 100644
--- a/src/platform/src/redox/mod.rs
+++ b/src/platform/src/redox/mod.rs
@@ -248,15 +248,15 @@ pub fn fstat(fildes: c_int, buf: *mut stat) -> c_int {
                     (*buf).st_blksize = redox_buf.st_blksize as blksize_t;
                     (*buf).st_atim = timespec {
                         tv_sec: redox_buf.st_atime as time_t,
-                        tv_nsec: 0
+                        tv_nsec: 0,
                     };
                     (*buf).st_mtim = timespec {
                         tv_sec: redox_buf.st_mtime as time_t,
-                        tv_nsec: 0
+                        tv_nsec: 0,
                     };
                     (*buf).st_ctim = timespec {
                         tv_sec: redox_buf.st_ctime as time_t,
-                        tv_nsec: 0
+                        tv_nsec: 0,
                     };
                 }
             }
@@ -275,13 +275,24 @@ pub fn ftruncate(fd: c_int, len: off_t) -> c_int {
 }
 
 pub fn futimens(fd: c_int, times: *const timespec) -> c_int {
-    let times = [
-        unsafe { redox_timespec::from(&*times) },
-        unsafe { redox_timespec::from(&*times.offset(1)) }
-    ];
+    let times = [unsafe { redox_timespec::from(&*times) }, unsafe {
+        redox_timespec::from(&*times.offset(1))
+    }];
     e(syscall::futimens(fd as usize, &times)) as c_int
 }
 
+pub fn utimens(path: *const c_char, times: *const timespec) -> c_int {
+    let path = unsafe { c_str(path) };
+    match syscall::open(path, O_STAT) {
+        Err(err) => e(Err(err)) as c_int,
+        Ok(fd) => {
+            let res = futimens(fd, times);
+            let _ = syscall::close(fd);
+            res
+        }
+    }
+}
+
 pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char {
     let buf_slice = unsafe { slice::from_raw_parts_mut(buf as *mut u8, size as usize) };
     if e(syscall::getcwd(buf_slice)) == !0 {
@@ -307,7 +318,7 @@ pub fn getdents(fd: c_int, mut dirents: *mut dirent, mut bytes: usize) -> c_int
             blen = match syscall::read(fd as usize, &mut buf) {
                 Ok(0) => return amount,
                 Ok(n) => n,
-                Err(err) => return -err.errno
+                Err(err) => return -err.errno,
             };
         }
 
@@ -320,7 +331,7 @@ pub fn getdents(fd: c_int, mut dirents: *mut dirent, mut bytes: usize) -> c_int
                     d_off: 0,
                     d_reclen: mem::size_of::<dirent>() as c_ushort,
                     d_type: 0,
-                    d_name: name
+                    d_name: name,
                 };
                 dirents = dirents.offset(1);
             }
@@ -474,7 +485,10 @@ pub fn getsockopt(
 
 pub fn gettimeofday(tp: *mut timeval, tzp: *mut timezone) -> c_int {
     let mut redox_tp = redox_timespec::default();
-    let err = e(syscall::clock_gettime(syscall::CLOCK_REALTIME, &mut redox_tp)) as c_int;
+    let err = e(syscall::clock_gettime(
+        syscall::CLOCK_REALTIME,
+        &mut redox_tp,
+    )) as c_int;
     if err < 0 {
         return err;
     }
@@ -532,7 +546,7 @@ pub fn lseek(fd: c_int, offset: off_t, whence: c_int) -> off_t {
 
 pub fn lstat(path: *const c_char, buf: *mut stat) -> c_int {
     let path = unsafe { c_str(path) };
-    match syscall::open(path, O_RDONLY | O_NOFOLLOW) {
+    match syscall::open(path, O_STAT | O_NOFOLLOW) {
         Err(err) => e(Err(err)) as c_int,
         Ok(fd) => {
             let res = fstat(fd as i32, buf);
@@ -737,14 +751,14 @@ pub unsafe fn sigaction(sig: c_int, act: *const sigaction, oact: *mut sigaction)
         Some(syscall::SigAction {
             sa_handler: sig_handler,
             sa_mask: [0, m as u64],
-            sa_flags: (*act).sa_flags as usize
+            sa_flags: (*act).sa_flags as usize,
         })
     };
     let mut old = syscall::SigAction::default();
     let ret = e(syscall::sigaction(
         sig as usize,
         act.as_ref(),
-        if oact.is_null() { None } else { Some(&mut old) }
+        if oact.is_null() { None } else { Some(&mut old) },
     )) as c_int;
     if !oact.is_null() {
         let m = old.sa_mask;
@@ -767,7 +781,7 @@ pub fn sigprocmask(how: c_int, set: *const sigset_t, oset: *mut sigset_t) -> c_i
 
 pub fn stat(path: *const c_char, buf: *mut stat) -> c_int {
     let path = unsafe { c_str(path) };
-    match syscall::open(path, O_RDONLY) {
+    match syscall::open(path, O_STAT) {
         Err(err) => e(Err(err)) as c_int,
         Ok(fd) => {
             let res = fstat(fd as i32, buf);
@@ -822,11 +836,7 @@ pub fn socketpair(domain: c_int, kind: c_int, protocol: c_int, socket_vector: *m
 }
 
 pub fn times(out: *mut tms) -> clock_t {
-    let _ = write!(
-        ::FileWriter(2),
-        "unimplemented: times({:p})",
-        out
-    );
+    let _ = write!(::FileWriter(2), "unimplemented: times({:p})", out);
     !0
 }
 
diff --git a/src/platform/src/types.rs b/src/platform/src/types.rs
index eaa7d18cd..4e83ffb90 100644
--- a/src/platform/src/types.rs
+++ b/src/platform/src/types.rs
@@ -1,5 +1,3 @@
-use core::mem;
-
 #[cfg(target_os = "redox")]
 use syscall::data::TimeSpec as redox_timespec;
 // Use repr(u8) as LLVM expects `void*` to be the same as `i8*` to help enable
@@ -127,7 +125,7 @@ pub struct stat {
     // Compared to glibc, our struct is for some reason 24 bytes too small.
     // Accessing atime works, so clearly the struct isn't incorrect...
     // This works.
-    pub _pad: [c_char; 24]
+    pub _pad: [c_char; 24],
 }
 
 pub const AF_INET: c_int = 2;
@@ -154,14 +152,14 @@ pub struct sockaddr {
 #[repr(C)]
 #[derive(Debug, Clone, Copy)]
 pub struct in_addr {
-    pub s_addr: in_addr_t
+    pub s_addr: in_addr_t,
 }
 
 #[repr(C)]
 pub struct sockaddr_in {
     pub sin_family: sa_family_t,
     pub sin_port: in_port_t,
-    pub sin_addr: in_addr
+    pub sin_addr: in_addr,
 }
 
 #[repr(C)]
@@ -169,7 +167,7 @@ pub struct sigaction {
     pub sa_handler: extern "C" fn(c_int),
     pub sa_flags: c_ulong,
     pub sa_restorer: unsafe extern "C" fn(),
-    pub sa_mask: sigset_t
+    pub sa_mask: sigset_t,
 }
 
 pub type sigset_t = c_ulong;
@@ -192,7 +190,7 @@ pub struct dirent {
     pub d_off: off_t,
     pub d_reclen: c_ushort,
     pub d_type: c_uchar,
-    pub d_name: [c_char; 256]
+    pub d_name: [c_char; 256],
 }
 
 #[repr(C)]
@@ -201,7 +199,7 @@ pub struct winsize {
     ws_row: c_ushort,
     ws_col: c_ushort,
     ws_xpixel: c_ushort,
-    ws_ypixel: c_ushort
+    ws_ypixel: c_ushort,
 }
 
 #[repr(C)]
@@ -221,7 +219,7 @@ pub struct rusage {
     pub ru_msgrcv: c_long,
     pub ru_nsignals: c_long,
     pub ru_nvcsw: c_long,
-    pub ru_nivcsw: c_long
+    pub ru_nivcsw: c_long,
 }
 
 #[repr(C)]
@@ -229,5 +227,5 @@ pub struct tms {
     tms_utime: clock_t,
     tms_stime: clock_t,
     tms_cutime: clock_t,
-    tms_cstime: clock_t
+    tms_cstime: clock_t,
 }
diff --git a/src/pwd/src/lib.rs b/src/pwd/src/lib.rs
index 58acf3587..300325c62 100644
--- a/src/pwd/src/lib.rs
+++ b/src/pwd/src/lib.rs
@@ -10,8 +10,8 @@ extern crate platform;
 
 use alloc::vec::Vec;
 use core::ptr;
-use platform::RawFile;
 use platform::types::*;
+use platform::RawFile;
 
 #[repr(C)]
 pub struct passwd {
@@ -21,7 +21,7 @@ pub struct passwd {
     pw_gid: gid_t,
     pw_gecos: *mut c_char,
     pw_dir: *mut c_char,
-    pw_shell: *mut c_char
+    pw_shell: *mut c_char,
 }
 
 static mut PASSWD_BUF: *mut c_char = ptr::null_mut();
@@ -32,23 +32,31 @@ static mut PASSWD: passwd = passwd {
     pw_gid: 0,
     pw_gecos: ptr::null_mut(),
     pw_dir: ptr::null_mut(),
-    pw_shell: ptr::null_mut()
+    pw_shell: ptr::null_mut(),
 };
 
 enum OptionPasswd {
     Error,
     NotFound,
-    Found(*mut c_char)
+    Found(*mut c_char),
 }
 
-fn pwd_lookup<F>(out: *mut passwd, alloc: Option<(*mut c_char, size_t)>, mut callback: F) -> OptionPasswd
-    where
-        // TODO F: FnMut(impl Iterator<Item = &[u8]>) -> bool
-        F: FnMut(&[&[u8]]) -> bool
+fn pwd_lookup<F>(
+    out: *mut passwd,
+    alloc: Option<(*mut c_char, size_t)>,
+    mut callback: F,
+) -> OptionPasswd
+where
+    // TODO F: FnMut(impl Iterator<Item = &[u8]>) -> bool
+    F: FnMut(&[&[u8]]) -> bool,
 {
-    let file = match RawFile::open("/etc/passwd\0".as_ptr() as *const c_char, fcntl::O_RDONLY, 0o644) {
+    let file = match RawFile::open(
+        "/etc/passwd\0".as_ptr() as *const c_char,
+        fcntl::O_RDONLY,
+        0o644,
+    ) {
         Ok(file) => file,
-        Err(_) => return OptionPasswd::Error
+        Err(_) => return OptionPasswd::Error,
     };
 
     let mut buf = Vec::new();
@@ -110,7 +118,8 @@ fn pwd_lookup<F>(out: *mut passwd, alloc: Option<(*mut c_char, size_t)>, mut cal
             continue;
         }
 
-        let len = parts.iter()
+        let len = parts
+            .iter()
             .enumerate()
             .filter(|(i, _)| *i != 2 && *i != 3)
             .map(|(_, part)| part.len() + 1)
@@ -125,7 +134,7 @@ fn pwd_lookup<F>(out: *mut passwd, alloc: Option<(*mut c_char, size_t)>, mut cal
 
         let alloc = match alloc {
             Some((alloc, _)) => alloc,
-            None => unsafe { platform::alloc(len) as *mut c_char }
+            None => unsafe { platform::alloc(len) as *mut c_char },
         };
         // _ prefix so it won't complain about the trailing
         // _off += <thing>
@@ -153,14 +162,15 @@ fn pwd_lookup<F>(out: *mut passwd, alloc: Option<(*mut c_char, size_t)>, mut cal
                 }
                 _off += src.len() as isize + 1;
             };
-            ($entry:expr, parse) => {
+            ($entry:expr,parse) => {
                 unsafe {
-                    $entry = parts.next()
+                    $entry = parts
+                        .next()
                         .and_then(|part| core::str::from_utf8(part).ok())
                         .and_then(|part| part.parse().ok())
                         .unwrap_or(0);
                 }
-            }
+            };
         }
 
         copy_into!((*out).pw_name);
@@ -176,8 +186,13 @@ fn pwd_lookup<F>(out: *mut passwd, alloc: Option<(*mut c_char, size_t)>, mut cal
 }
 
 #[no_mangle]
-pub extern "C" fn getpwnam_r(name: *const c_char, out: *mut passwd, buf: *mut c_char,
-        size: size_t, result: *mut *mut passwd) -> c_int {
+pub extern "C" fn getpwnam_r(
+    name: *const c_char,
+    out: *mut passwd,
+    buf: *mut c_char,
+    size: size_t,
+    result: *mut *mut passwd,
+) -> c_int {
     match pwd_lookup(out, Some((buf, size)), |parts| {
         let part = parts.get(0).unwrap_or(&(&[] as &[u8]));
         for (i, c) in part.iter().enumerate() {
@@ -201,15 +216,21 @@ pub extern "C" fn getpwnam_r(name: *const c_char, out: *mut passwd, buf: *mut c_
         OptionPasswd::Found(_) => unsafe {
             *result = out;
             0
-        }
+        },
     }
 }
 
 #[no_mangle]
-pub extern "C" fn getpwuid_r(uid: uid_t, out: *mut passwd, buf: *mut c_char,
-        size: size_t, result: *mut *mut passwd) -> c_int {
+pub extern "C" fn getpwuid_r(
+    uid: uid_t,
+    out: *mut passwd,
+    buf: *mut c_char,
+    size: size_t,
+    result: *mut *mut passwd,
+) -> c_int {
     match pwd_lookup(out, Some((buf, size)), |parts| {
-        let part = parts.get(2)
+        let part = parts
+            .get(2)
             .and_then(|part| core::str::from_utf8(part).ok())
             .and_then(|part| part.parse().ok());
         part == Some(uid)
@@ -225,7 +246,7 @@ pub extern "C" fn getpwuid_r(uid: uid_t, out: *mut passwd, buf: *mut c_char,
         OptionPasswd::Found(_) => unsafe {
             *result = out;
             0
-        }
+        },
     }
 }
 
@@ -248,14 +269,15 @@ pub extern "C" fn getpwnam(name: *const c_char) -> *mut passwd {
         OptionPasswd::Found(buf) => unsafe {
             PASSWD_BUF = buf;
             &mut PASSWD
-        }
+        },
     }
 }
 
 #[no_mangle]
 pub extern "C" fn getpwuid(uid: uid_t) -> *mut passwd {
     match pwd_lookup(unsafe { &mut PASSWD }, None, |parts| {
-        let part = parts.get(2)
+        let part = parts
+            .get(2)
             .and_then(|part| core::str::from_utf8(part).ok())
             .and_then(|part| part.parse().ok());
         part == Some(uid)
@@ -268,6 +290,6 @@ pub extern "C" fn getpwuid(uid: uid_t) -> *mut passwd {
             }
             PASSWD_BUF = buf;
             &mut PASSWD
-        }
+        },
     }
 }
diff --git a/src/signal/src/lib.rs b/src/signal/src/lib.rs
index 099ce1149..49cf7b884 100644
--- a/src/signal/src/lib.rs
+++ b/src/signal/src/lib.rs
@@ -32,7 +32,7 @@ pub struct sigaction {
     pub sa_handler: extern "C" fn(c_int),
     pub sa_flags: c_ulong,
     pub sa_restorer: unsafe extern "C" fn(),
-    pub sa_mask: sigset_t
+    pub sa_mask: sigset_t,
 }
 
 pub const NSIG: usize = 64;
@@ -54,7 +54,11 @@ pub extern "C" fn raise(sig: c_int) -> c_int {
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn sigaction(sig: c_int, act: *const sigaction, oact: *mut sigaction) -> c_int {
+pub unsafe extern "C" fn sigaction(
+    sig: c_int,
+    act: *const sigaction,
+    oact: *mut sigaction,
+) -> c_int {
     let mut _sigaction = None;
     let ptr = if !act.is_null() {
         _sigaction = Some((*act).clone());
@@ -134,7 +138,7 @@ pub extern "C" fn signal(sig: c_int, func: extern "C" fn(c_int)) -> extern "C" f
         sa_handler: func,
         sa_flags: SA_RESTART as c_ulong,
         sa_restorer: __restore_rt,
-        sa_mask: sigset_t::default()
+        sa_mask: sigset_t::default(),
     };
     let mut old_sa = unsafe { mem::uninitialized() };
     if unsafe { sigaction(sig, &sa, &mut old_sa) } < 0 {
diff --git a/src/signal/src/linux.rs b/src/signal/src/linux.rs
index 8f6b11f20..f2cb86074 100644
--- a/src/signal/src/linux.rs
+++ b/src/signal/src/linux.rs
@@ -1,18 +1,22 @@
 // Needs to be defined in assembly because it can't have a function prologue
 #[cfg(target_arch = "x86_64")]
-global_asm!("
+global_asm!(
+    "
     .global __restore_rt
     __restore_rt:
         mov $15, %rax # <- rax is register, 15 is RT_SIGRETURN
         syscall
-");
+"
+);
 #[cfg(target_arch = "aarch64")]
-global_asm!("
+global_asm!(
+    "
     .global __restore_rt
     __restore_rt:
         mov x8, #139 # <- x8 is register, 139 is RT_SIGRETURN
         svc 0
-");
+"
+);
 
 pub const SIGHUP: usize = 1;
 pub const SIGINT: usize = 2;
diff --git a/src/signal/src/redox.rs b/src/signal/src/redox.rs
index f5ae96b6c..e7c3f9d96 100644
--- a/src/signal/src/redox.rs
+++ b/src/signal/src/redox.rs
@@ -1,18 +1,22 @@
 // Needs to be defined in assembly because it can't have a function prologue
 #[cfg(target_arch = "x86_64")]
-global_asm!("
+global_asm!(
+    "
     .global __restore_rt
     __restore_rt:
         mov $119, %rax # <- rax is register, 119 is SIGRETURN
         int $0x80
-");
+"
+);
 #[cfg(target_arch = "aarch64")]
-global_asm!("
+global_asm!(
+    "
     .global __restore_rt
     __restore_rt:
         mov x8, #119 # <- x8 is register, 119 is SIGRETURN
         svc 0
-");
+"
+);
 
 pub const SIGHUP: usize = 1;
 pub const SIGINT: usize = 2;
diff --git a/src/sys_ioctl/src/lib.rs b/src/sys_ioctl/src/lib.rs
index d62132a14..40b0427bf 100644
--- a/src/sys_ioctl/src/lib.rs
+++ b/src/sys_ioctl/src/lib.rs
@@ -13,19 +13,19 @@ pub struct sgttyb {
     sg_ospeed: c_char,
     sg_erase: c_char,
     sg_kill: c_char,
-    sg_flags: c_ushort
+    sg_flags: c_ushort,
 }
 
 #[cfg(target_os = "linux")]
 pub mod inner {
-    use ::*;
+    use *;
 
     #[repr(C)]
     pub struct winsize {
         ws_row: c_ushort,
         ws_col: c_ushort,
         ws_xpixel: c_ushort,
-        ws_ypixel: c_ushort
+        ws_ypixel: c_ushort,
     }
 
     #[no_mangle]
diff --git a/src/sys_resource/src/lib.rs b/src/sys_resource/src/lib.rs
index 3fde5a1fd..228f26fc7 100644
--- a/src/sys_resource/src/lib.rs
+++ b/src/sys_resource/src/lib.rs
@@ -40,7 +40,7 @@ pub struct rusage {
     pub ru_msgrcv: c_long,
     pub ru_nsignals: c_long,
     pub ru_nvcsw: c_long,
-    pub ru_nivcsw: c_long
+    pub ru_nivcsw: c_long,
 }
 
 // #[no_mangle]
diff --git a/src/sys_socket/src/lib.rs b/src/sys_socket/src/lib.rs
index 505bd5d50..7354e1b6e 100644
--- a/src/sys_socket/src/lib.rs
+++ b/src/sys_socket/src/lib.rs
@@ -28,7 +28,11 @@ pub unsafe extern "C" fn accept(
     address: *mut sockaddr,
     address_len: *mut socklen_t,
 ) -> c_int {
-    platform::accept(socket, address as *mut platform::types::sockaddr, address_len)
+    platform::accept(
+        socket,
+        address as *mut platform::types::sockaddr,
+        address_len,
+    )
 }
 
 #[no_mangle]
@@ -37,7 +41,11 @@ pub unsafe extern "C" fn bind(
     address: *const sockaddr,
     address_len: socklen_t,
 ) -> c_int {
-    platform::bind(socket, address as *const platform::types::sockaddr, address_len)
+    platform::bind(
+        socket,
+        address as *const platform::types::sockaddr,
+        address_len,
+    )
 }
 
 #[no_mangle]
@@ -46,7 +54,11 @@ pub unsafe extern "C" fn connect(
     address: *const sockaddr,
     address_len: socklen_t,
 ) -> c_int {
-    platform::connect(socket, address as *const platform::types::sockaddr, address_len)
+    platform::connect(
+        socket,
+        address as *const platform::types::sockaddr,
+        address_len,
+    )
 }
 
 #[no_mangle]
@@ -55,7 +67,11 @@ pub unsafe extern "C" fn getpeername(
     address: *mut sockaddr,
     address_len: *mut socklen_t,
 ) -> c_int {
-    platform::getpeername(socket, address as *mut platform::types::sockaddr, address_len)
+    platform::getpeername(
+        socket,
+        address as *mut platform::types::sockaddr,
+        address_len,
+    )
 }
 
 #[no_mangle]
@@ -64,7 +80,11 @@ pub unsafe extern "C" fn getsockname(
     address: *mut sockaddr,
     address_len: *mut socklen_t,
 ) -> c_int {
-    platform::getsockname(socket, address as *mut platform::types::sockaddr, address_len)
+    platform::getsockname(
+        socket,
+        address as *mut platform::types::sockaddr,
+        address_len,
+    )
 }
 
 #[no_mangle]
diff --git a/src/sys_stat/src/lib.rs b/src/sys_stat/src/lib.rs
index e894e0c71..ee31788bb 100644
--- a/src/sys_stat/src/lib.rs
+++ b/src/sys_stat/src/lib.rs
@@ -6,7 +6,7 @@ extern crate platform;
 
 use platform::types::*;
 
-pub const S_IFMT:  c_int = 0o0170000;
+pub const S_IFMT: c_int = 0o0170000;
 pub const S_IFBLK: c_int = 0o060000;
 pub const S_IFCHR: c_int = 0o020000;
 pub const S_IFIFO: c_int = 0o010000;
@@ -52,7 +52,7 @@ pub struct stat {
     // Compared to glibc, our struct is for some reason 24 bytes too small.
     // Accessing atime works, so clearly the struct isn't incorrect...
     // This works.
-    pub _pad: [c_char; 24]
+    pub _pad: [c_char; 24],
 }
 
 #[no_mangle]
diff --git a/src/sys_time/src/lib.rs b/src/sys_time/src/lib.rs
index 6ebbf0163..fae8bfddc 100644
--- a/src/sys_time/src/lib.rs
+++ b/src/sys_time/src/lib.rs
@@ -48,13 +48,16 @@ pub extern "C" fn setitimer(
     platform::setitimer(
         which,
         value as *const platform::types::itimerval,
-        ovalue as *mut platform::types::itimerval
+        ovalue as *mut platform::types::itimerval,
     )
 }
 
 #[no_mangle]
 pub extern "C" fn gettimeofday(tp: *mut timeval, tzp: *mut timezone) -> c_int {
-    platform::gettimeofday(tp as *mut platform::types::timeval, tzp as *mut platform::types::timezone)
+    platform::gettimeofday(
+        tp as *mut platform::types::timeval,
+        tzp as *mut platform::types::timezone,
+    )
 }
 
 // #[no_mangle]
@@ -68,9 +71,19 @@ pub extern "C" fn select(
     unimplemented!();
 }
 
-// #[no_mangle]
-pub extern "C" fn utimes(path: *const c_char, times: [timeval; 2]) -> c_int {
-    unimplemented!();
+#[no_mangle]
+pub unsafe extern "C" fn utimes(path: *const c_char, times: *const timeval) -> c_int {
+    let times_spec = [
+        timespec {
+            tv_sec: (*times.offset(0)).tv_sec,
+            tv_nsec: ((*times.offset(0)).tv_usec as i64) * 1000,
+        },
+        timespec {
+            tv_sec: (*times.offset(1)).tv_sec,
+            tv_nsec: ((*times.offset(1)).tv_usec as i64) * 1000,
+        },
+    ];
+    platform::utimens(path, times_spec.as_ptr())
 }
 
 /*
diff --git a/src/sys_times/src/lib.rs b/src/sys_times/src/lib.rs
index 85cc11093..3d8b7f890 100644
--- a/src/sys_times/src/lib.rs
+++ b/src/sys_times/src/lib.rs
@@ -11,7 +11,7 @@ pub struct tms {
     tms_utime: clock_t,
     tms_stime: clock_t,
     tms_cutime: clock_t,
-    tms_cstime: clock_t
+    tms_cstime: clock_t,
 }
 
 #[no_mangle]
diff --git a/src/sys_un/src/lib.rs b/src/sys_un/src/lib.rs
index 577f49a04..19a75443a 100644
--- a/src/sys_un/src/lib.rs
+++ b/src/sys_un/src/lib.rs
@@ -9,5 +9,5 @@ use sys_socket::sa_family_t;
 #[repr(C)]
 pub struct sockaddr_un {
     sun_family: sa_family_t,
-    sun_path: [c_char; 108]
+    sun_path: [c_char; 108],
 }
diff --git a/src/time/src/lib.rs b/src/time/src/lib.rs
index 6ed95d831..3bfc2c8fe 100644
--- a/src/time/src/lib.rs
+++ b/src/time/src/lib.rs
@@ -329,7 +329,10 @@ pub unsafe extern "C" fn mktime(t: *const tm) -> time_t {
 
 #[no_mangle]
 pub extern "C" fn nanosleep(rqtp: *const timespec, rmtp: *mut timespec) -> c_int {
-    platform::nanosleep(rqtp as *const platform::types::timespec, rmtp as *mut platform::types::timespec)
+    platform::nanosleep(
+        rqtp as *const platform::types::timespec,
+        rmtp as *mut platform::types::timespec,
+    )
 }
 
 #[no_mangle]
diff --git a/src/unistd/src/lib.rs b/src/unistd/src/lib.rs
index f3deb9452..76dbb27b1 100644
--- a/src/unistd/src/lib.rs
+++ b/src/unistd/src/lib.rs
@@ -53,7 +53,7 @@ pub extern "C" fn alarm(seconds: c_uint) -> c_uint {
     let mut timer = sys_time::itimerval {
         it_value: sys_time::timeval {
             tv_sec: seconds as time_t,
-            tv_usec: 0
+            tv_usec: 0,
         },
         ..Default::default()
     };
@@ -455,12 +455,12 @@ pub extern "C" fn ualarm(value: useconds_t, interval: useconds_t) -> useconds_t
     let mut timer = sys_time::itimerval {
         it_value: sys_time::timeval {
             tv_sec: 0,
-            tv_usec: value as suseconds_t
+            tv_usec: value as suseconds_t,
         },
         it_interval: sys_time::timeval {
             tv_sec: 0,
-            tv_usec: interval as suseconds_t
-        }
+            tv_usec: interval as suseconds_t,
+        },
     };
     let errno_backup = unsafe { platform::errno };
     let usecs = if sys_time::setitimer(sys_time::ITIMER_REAL, &timer, &mut timer) < 0 {
diff --git a/src/utime/Cargo.toml b/src/utime/Cargo.toml
new file mode 100644
index 000000000..81bcd75cb
--- /dev/null
+++ b/src/utime/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "utime"
+version = "0.1.0"
+authors = ["Jeremy Soller <jackpot51@gmail.com>"]
+build = "build.rs"
+
+[build-dependencies]
+cbindgen = { path = "../../cbindgen" }
+
+[dependencies]
+platform = { path = "../platform" }
diff --git a/src/utime/build.rs b/src/utime/build.rs
new file mode 100644
index 000000000..eb7b3b921
--- /dev/null
+++ b/src/utime/build.rs
@@ -0,0 +1,11 @@
+extern crate cbindgen;
+
+use std::{env, fs};
+
+fn main() {
+    let crate_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
+    fs::create_dir_all("../../target/include").expect("failed to create include directory");
+    cbindgen::generate(crate_dir)
+        .expect("failed to generate bindings")
+        .write_to_file("../../target/include/utime.h");
+}
diff --git a/src/utime/cbindgen.toml b/src/utime/cbindgen.toml
new file mode 100644
index 000000000..37ed9f83d
--- /dev/null
+++ b/src/utime/cbindgen.toml
@@ -0,0 +1,7 @@
+sys_includes = []
+include_guard = "_TEMPLATE_H"
+language = "C"
+style = "Tag"
+
+[enum]
+prefix_with_name = true
diff --git a/src/utime/src/lib.rs b/src/utime/src/lib.rs
new file mode 100644
index 000000000..cea8b06f8
--- /dev/null
+++ b/src/utime/src/lib.rs
@@ -0,0 +1,29 @@
+//! utime implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/utime.h.html
+
+#![no_std]
+
+extern crate platform;
+
+use platform::types::*;
+
+#[repr(C)]
+#[derive(Clone)]
+pub struct utimbuf {
+    pub actime: time_t,
+    pub modtime: time_t,
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn utime(filename: *const c_char, times: *const utimbuf) -> c_int {
+    let times_spec = [
+        timespec {
+            tv_sec: (*times).actime,
+            tv_nsec: 0,
+        },
+        timespec {
+            tv_sec: (*times).modtime,
+            tv_nsec: 0,
+        },
+    ];
+    platform::utimens(filename, times_spec.as_ptr())
+}
-- 
GitLab