diff --git a/src/header/libgen/cbindgen.toml b/src/header/libgen/cbindgen.toml
new file mode 100644
index 0000000000000000000000000000000000000000..b3c8f6bd3cae22acc59545626b33a73ab4f49c0b
--- /dev/null
+++ b/src/header/libgen/cbindgen.toml
@@ -0,0 +1,7 @@
+sys_includes = []
+include_guard = "_LIBGEN_H"
+language = "C"
+style = "Tag"
+
+[enum]
+prefix_with_name = true
diff --git a/src/header/libgen/mod.rs b/src/header/libgen/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..8128df98cd41181dd36c5eba9f3cd9c08d7c5226
--- /dev/null
+++ b/src/header/libgen/mod.rs
@@ -0,0 +1,49 @@
+//! libgen implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/libgen.h.html
+
+use core::ptr;
+
+use platform::types::c_char;
+
+use header::string::strlen;
+
+#[no_mangle]
+pub unsafe extern "C" fn basename(str: *mut c_char) -> *mut c_char {
+    if str == ptr::null_mut() || strlen(str) == 0 {
+        return ".\0".as_ptr() as *mut c_char;
+    }
+    let mut end = strlen(str) as isize - 1;
+    while end >= 0 && *str.offset(end) == b'/' as c_char {
+        end -= 1;
+    }
+    if end == -1 {
+        return "/\0".as_ptr() as *mut c_char;
+    }
+    let mut begin = end;
+    while begin >= 0 && *str.offset(begin) != b'/' as c_char {
+        begin -= 1;
+    }
+    *str.offset(end + 1) = 0;
+    return str.offset(begin + 1) as *mut c_char;
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn dirname(str: *mut c_char) -> *mut c_char {
+    if str == ptr::null_mut() || strlen(str) == 0 {
+        return ".\0".as_ptr() as *mut c_char;
+    }
+    let mut end = strlen(str) as isize - 1;
+    while end > 0 && *str.offset(end) == b'/' as c_char {
+        end -= 1;
+    }
+    while end >= 0 && *str.offset(end) != b'/' as c_char {
+        end -= 1;
+    }
+    while end > 0 && *str.offset(end) == b'/' as c_char {
+        end -= 1;
+    }
+    if end == -1 {
+        return ".\0".as_ptr() as *mut c_char;
+    }
+    *str.offset(end + 1) = 0;
+    return str;
+}
diff --git a/src/header/mod.rs b/src/header/mod.rs
index 08cf34c826c427bd42e78374aa5d2d592dde6986..fc6201556bc248fbb56fc56d200889be8d31db5c 100644
--- a/src/header/mod.rs
+++ b/src/header/mod.rs
@@ -12,6 +12,7 @@ pub mod getopt;
 pub mod grp;
 pub mod inttypes;
 pub mod limits;
+pub mod libgen;
 pub mod locale;
 pub mod netdb;
 pub mod netinet_in;
diff --git a/tests/Makefile b/tests/Makefile
index bdc7168fe45d3a5d87d1d4ff8a7b393011406b1d..2a8cb5aefce53abd421bb08c786a9750218fd420 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -11,6 +11,7 @@ EXPECT_BINS=\
 	fcntl/create \
 	fcntl/fcntl \
 	fnmatch \
+	libgen \
 	locale \
 	math \
 	netdb \
diff --git a/tests/expected/libgen.stderr b/tests/expected/libgen.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/libgen.stdout b/tests/expected/libgen.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..c19d73cc8b270fd10cb1da2115bf1549c9747498
--- /dev/null
+++ b/tests/expected/libgen.stdout
@@ -0,0 +1,18 @@
+Testing libgen.h
+OK on basename(/usr/lib), expected: 'lib', got: 'lib'
+OK on basename(//usr//lib//), expected: 'lib', got: 'lib'
+OK on basename(/usr/), expected: 'usr', got: 'usr'
+OK on basename(), expected: '.', got: '.'
+OK on basename(/), expected: '/', got: '/'
+OK on basename(///), expected: '/', got: '/'
+OK on basename(NULL), expected: '.', got: '.'
+OK on dirname(/usr/lib), expected: '/usr', got: '/usr'
+OK on dirname(//usr//lib//), expected: '//usr', got: '//usr'
+OK on dirname(/usr), expected: '/', got: '/'
+OK on dirname(usr), expected: '.', got: '.'
+OK on dirname(/), expected: '/', got: '/'
+OK on dirname(///), expected: '/', got: '/'
+OK on dirname(.), expected: '.', got: '.'
+OK on dirname(..), expected: '.', got: '.'
+OK on dirname(), expected: '.', got: '.'
+OK on dirname(NULL), expected: '.', got: '.'
diff --git a/tests/libgen.c b/tests/libgen.c
new file mode 100644
index 0000000000000000000000000000000000000000..f38f70f0f01cdd36025482ca61169e1e5d1989c3
--- /dev/null
+++ b/tests/libgen.c
@@ -0,0 +1,81 @@
+#include <libgen.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+typedef struct {
+  char * in;
+  char * expected_out;
+} test_case;
+
+// API for basename and dirname allow the passed in string to
+// be modified. This means we have to pass a modifiable copy.
+char * get_mutable_string(char *str) {
+  if (str == NULL)
+    return NULL;
+  char * copy = malloc(sizeof(char) * (strlen(str) + 1));
+  copy = strcpy(copy, str);
+  return copy;
+}
+
+void test_basename() {
+  test_case test_cases[] =
+  { {"/usr/lib", "lib"},
+    {"//usr//lib//", "lib"},
+    {"/usr/", "usr"},
+    {"", "."},
+    {"/", "/"},
+    {"///","/"},
+    {NULL, "."}
+  };
+  for (int i = 0;i < sizeof(test_cases)/sizeof(test_case);i++) {
+    char * in = get_mutable_string(test_cases[i].in);
+    char * out = basename(in);
+    if (!out) {
+      printf("Error on basename(%s), expected: '%s', got NULL\n", test_cases[i].in != 0 ? test_cases[i].in : "NULL", test_cases[i].expected_out);
+    } else if (strcmp(out, test_cases[i].expected_out) != 0) {
+      printf("Error on basename(%s), expected: '%s', got: '%s'\n", test_cases[i].in != 0 ? test_cases[i].in : "NULL", test_cases[i].expected_out, out); 
+    } else {
+      printf("OK on basename(%s), expected: '%s', got: '%s'\n", test_cases[i].in != 0 ? test_cases[i].in : "NULL", test_cases[i].expected_out, out);
+    }
+    if (!in)
+      free(in);
+  }
+  return;
+}
+
+void test_dirname() {
+  test_case test_cases[] =
+  { {"/usr/lib", "/usr"},
+    {"//usr//lib//", "//usr"},
+    {"/usr", "/"},
+    {"usr", "."},
+    {"/", "/"},
+    {"///","/"},
+    {".", "."},
+    {"..", "."},
+    {"", "."},
+    {NULL, "."}
+  };
+  for (int i = 0;i < sizeof(test_cases)/sizeof(test_case);i++) {
+    char * in = get_mutable_string(test_cases[i].in);
+    char * out = dirname(in);
+    if (!out) {
+      printf("Error on dirname(%s), expected: '%s', got NULL\n", test_cases[i].in != 0 ? test_cases[i].in : "NULL", test_cases[i].expected_out);
+    } else if (strcmp(out, test_cases[i].expected_out) != 0) {
+      printf("Error on dirname(%s), expected: '%s', got: '%s'\n", test_cases[i].in != 0 ? test_cases[i].in : "NULL", test_cases[i].expected_out, out); 
+    } else {
+      printf("OK on dirname(%s), expected: '%s', got: '%s'\n", test_cases[i].in != 0 ? test_cases[i].in : "NULL", test_cases[i].expected_out, out);
+    }
+    if (!in)
+      free(in);
+  }
+  return;
+}
+
+int main() {
+  printf("Testing libgen.h\n");
+  test_basename();
+  test_dirname();
+  return 0;
+}