diff --git a/Makefile.build b/Makefile.build
index 2fb7073287800f5c80383e3a10287304011d6a18..a736cc709ae1bf2eba8f4af0079f10c6b39cce67 100644
--- a/Makefile.build
+++ b/Makefile.build
@@ -68,6 +68,7 @@ userprog_SRC += userprog/syscall_halt.c
 userprog_SRC += userprog/syscall_wait.c
 userprog_SRC += userprog/syscall_create.c
 userprog_SRC += userprog/syscall_write.c
+userprog_SRC += userprog/file_descriptors_map.c
 
 # No virtual memory code yet.
 #vm_SRC = vm/file.c			# Some file.
diff --git a/examples/exit b/examples/exit
new file mode 100755
index 0000000000000000000000000000000000000000..a6569c49fe418705632d054e3e5337cf83e9da29
Binary files /dev/null and b/examples/exit differ
diff --git a/examples/touch b/examples/touch
index 0d81b3ea3dccb90bf0a39ad1b64cfed65f0da0ca..f68795f860f0e445ef5ee631e95ee05b7bc9e8c5 100755
Binary files a/examples/touch and b/examples/touch differ
diff --git a/userprog/file_descriptors_map.c b/userprog/file_descriptors_map.c
new file mode 100644
index 0000000000000000000000000000000000000000..7ab7943c883ce468a76190a336fbfc7ef8172028
--- /dev/null
+++ b/userprog/file_descriptors_map.c
@@ -0,0 +1,55 @@
+/*
+ * File Descriptors mapper
+ *
+ * Authored by Joshua Saxby
+ */
+#include <stddef.h>
+#include "filesys/filesys.h"
+#include "system_calls.h"
+
+// this means we can't have more than 255 open file handles at a time
+#define MAX_FILE_POINTERS 255
+
+static struct file* FILE_POINTERS_MAP[MAX_FILE_POINTERS] = {0};
+
+struct file * get_associated_file_pointer(int fd) {
+    switch (fd) {
+    case 0: // keyboard (stdin)
+    case 1: // console (stdout)
+    case 2: // console (stderr)
+        return NULL;
+    default:
+        return FILE_POINTERS_MAP[fd - 3]; // exclude special fds
+    }
+}
+
+int associate_new_file_descriptor(struct file* file_pointer) {
+    // if we have been passed NULL, refuse (it's silly!)
+    if (file_pointer == NULL) return -1;
+    // find the first decriptor which points to NULL
+    for (size_t i = 0; i < MAX_FILE_POINTERS; i++) {
+        if (FILE_POINTERS_MAP[i] == NULL) {
+            FILE_POINTERS_MAP[i] = file_pointer;
+            return i + 3; // exclude special fds
+        }
+    }
+    // if we got here, we've run out of spare slots, return failure
+    return -1;
+}
+
+bool disassociate_file_descriptor(int fd) {
+    // clear the descriptor to NULL
+    switch (fd) {
+    case 0: // keyboard (stdin)
+    case 1: // console (stdout)
+    case 2: // console (stderr)
+        return false;
+    default:
+        if (FILE_POINTERS_MAP[fd - 3] != NULL) { // exclude special fds
+            FILE_POINTERS_MAP[fd - 3] = NULL;
+            return true;
+        } else {
+            return false;
+        }
+    }
+}
diff --git a/userprog/system_calls.h b/userprog/system_calls.h
index be83270c704309e07150583226503aafc2ce1c82..1d56a93e4767fdde504892f2d601684463945baa 100644
--- a/userprog/system_calls.h
+++ b/userprog/system_calls.h
@@ -1,3 +1,4 @@
+#include "filesys/file.h"
 #include "threads/interrupt.h"
 
 /*
@@ -46,3 +47,16 @@ void syscall_write(struct intr_frame *f);
  * NOTE: There are more system calls implemented by Pintos but we are not
  * implementing them because the assignment brief does not ask of it.
  */
+
+/*
+ * special additional stuff for handling file descriptors because they're annoying
+ */
+
+// returns NULL if the given file descriptor does not match a known file
+struct file * get_associated_file_pointer(int fd);
+// remembers the given file, and returns int of file descriptor
+// returns -1 if could not store it (means we've opened too many files)
+int associate_new_file_descriptor(struct file* file_pointer);
+// disassociates the given file descriptor (and its associated pointer)
+// returns false if this failed for some reason
+bool disassociate_file_descriptor(int fd);