diff --git a/syscall/fs.rs b/syscall/fs.rs
index 91c36e4944ebac2f30836848d98d4c5274b9ebc8..1552f2559cabd34bcc4d60d3e83769a12c31a028 100644
--- a/syscall/fs.rs
+++ b/syscall/fs.rs
@@ -2,9 +2,45 @@
 
 use context;
 use scheme;
-use syscall::data::Stat;
+use syscall::data::{Packet, Stat};
 use syscall::error::*;
 
+pub fn file_op(a: usize, fd: usize, c: usize, d: usize) -> Result<usize> {
+    let file = {
+        let contexts = context::contexts();
+        let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
+        let context = context_lock.read();
+        let file = context.get_file(fd).ok_or(Error::new(EBADF))?;
+        file
+    };
+
+    let scheme = {
+        let schemes = scheme::schemes();
+        let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
+        scheme.clone()
+    };
+
+    let mut packet = Packet {
+        id: 0,
+        a: a,
+        b: file.number,
+        c: c,
+        d: d
+    };
+
+    scheme.handle(&mut packet);
+
+    Error::demux(packet.a)
+}
+
+pub fn file_op_slice(a: usize, fd: usize, slice: &[u8]) -> Result<usize> {
+    file_op(a, fd, slice.as_ptr() as usize, slice.len())
+}
+
+pub fn file_op_mut_slice(a: usize, fd: usize, slice: &mut [u8]) -> Result<usize> {
+    file_op(a, fd, slice.as_mut_ptr() as usize, slice.len())
+}
+
 /// Change the current working directory
 pub fn chdir(path: &[u8]) -> Result<usize> {
     let contexts = context::contexts();
@@ -92,12 +128,22 @@ pub fn dup(fd: usize) -> Result<usize> {
         file
     };
 
-    let scheme = {
-        let schemes = scheme::schemes();
-        let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
-        scheme.clone()
-    };
-    scheme.dup(file.number)
+    let file_id = {
+        let scheme = {
+            let schemes = scheme::schemes();
+            let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
+            scheme.clone()
+        };
+        scheme.dup(file.number)
+    }?;
+
+    let contexts = context::contexts();
+    let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
+    let context = context_lock.read();
+    context.add_file(::context::file::File {
+        scheme: file.scheme,
+        number: file_id
+    }).ok_or(Error::new(EMFILE))
 }
 
 /// Register events for file
@@ -119,129 +165,3 @@ pub fn fevent(fd: usize, flags: usize) -> Result<usize> {
     context::event::register(fd, file.scheme, file.number);
     Ok(0)
 }
-
-/// Get the canonical path of the file
-pub fn fpath(fd: usize, buf: &mut [u8]) -> Result<usize> {
-    let file = {
-        let contexts = context::contexts();
-        let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
-        let context = context_lock.read();
-        let file = context.get_file(fd).ok_or(Error::new(EBADF))?;
-        file
-    };
-
-    let scheme = {
-        let schemes = scheme::schemes();
-        let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
-        scheme.clone()
-    };
-    scheme.fpath(file.number, buf)
-}
-
-/// Get information about the file
-pub fn fstat(fd: usize, stat: &mut Stat) -> Result<usize> {
-    let file = {
-        let contexts = context::contexts();
-        let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
-        let context = context_lock.read();
-        let file = context.get_file(fd).ok_or(Error::new(EBADF))?;
-        file
-    };
-
-    let scheme = {
-        let schemes = scheme::schemes();
-        let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
-        scheme.clone()
-    };
-    scheme.fstat(file.number, stat)
-}
-
-/// Sync the file descriptor
-pub fn fsync(fd: usize) -> Result<usize> {
-    let file = {
-        let contexts = context::contexts();
-        let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
-        let context = context_lock.read();
-        let file = context.get_file(fd).ok_or(Error::new(EBADF))?;
-        file
-    };
-
-    let scheme = {
-        let schemes = scheme::schemes();
-        let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
-        scheme.clone()
-    };
-    scheme.fsync(file.number)
-}
-
-/// Truncate the file descriptor
-pub fn ftruncate(fd: usize, len: usize) -> Result<usize> {
-    let file = {
-        let contexts = context::contexts();
-        let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
-        let context = context_lock.read();
-        let file = context.get_file(fd).ok_or(Error::new(EBADF))?;
-        file
-    };
-
-    let scheme = {
-        let schemes = scheme::schemes();
-        let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
-        scheme.clone()
-    };
-    scheme.ftruncate(file.number, len)
-}
-
-/// Seek to an offset
-pub fn lseek(fd: usize, pos: usize, whence: usize) -> Result<usize> {
-    let file = {
-        let contexts = context::contexts();
-        let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
-        let context = context_lock.read();
-        let file = context.get_file(fd).ok_or(Error::new(EBADF))?;
-        file
-    };
-
-    let scheme = {
-        let schemes = scheme::schemes();
-        let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
-        scheme.clone()
-    };
-    scheme.seek(file.number, pos, whence)
-}
-
-/// Read syscall
-pub fn read(fd: usize, buf: &mut [u8]) -> Result<usize> {
-    let file = {
-        let contexts = context::contexts();
-        let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
-        let context = context_lock.read();
-        let file = context.get_file(fd).ok_or(Error::new(EBADF))?;
-        file
-    };
-
-    let scheme = {
-        let schemes = scheme::schemes();
-        let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
-        scheme.clone()
-    };
-    scheme.read(file.number, buf)
-}
-
-/// Write syscall
-pub fn write(fd: usize, buf: &[u8]) -> Result<usize> {
-    let file = {
-        let contexts = context::contexts();
-        let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
-        let context = context_lock.read();
-        let file = context.get_file(fd).ok_or(Error::new(EBADF))?;
-        file
-    };
-
-    let scheme = {
-        let schemes = scheme::schemes();
-        let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
-        scheme.clone()
-    };
-    scheme.write(file.number, buf)
-}
diff --git a/syscall/mod.rs b/syscall/mod.rs
index 1bb5a56e7ab755ef344488bb5ad23946de813bfc..3edecf97f99d25dba5d9f84ddce277f30b366470 100644
--- a/syscall/mod.rs
+++ b/syscall/mod.rs
@@ -8,7 +8,6 @@ pub use self::fs::*;
 pub use self::process::*;
 pub use self::validate::*;
 
-use self::data::Stat;
 use self::error::{Error, Result, ENOSYS};
 use self::number::*;
 
@@ -25,33 +24,35 @@ pub mod validate;
 pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack: usize) -> usize {
     #[inline(always)]
     fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize, stack: usize) -> Result<usize> {
-        match a {
-            SYS_EXIT => exit(b),
-            SYS_READ => read(b, validate_slice_mut(c as *mut u8, d)?),
-            SYS_WRITE => write(b, validate_slice(c as *const u8, d)?),
-            SYS_OPEN => open(validate_slice(b as *const u8, c)?, d),
-            SYS_CLOSE => close(b),
-            SYS_WAITPID => waitpid(b, c, d),
-            SYS_EXECVE => exec(validate_slice(b as *const u8, c)?, validate_slice(d as *const [usize; 2], e)?),
-            SYS_CHDIR => chdir(validate_slice(b as *const u8, c)?),
-            SYS_LSEEK => lseek(b, c, d),
-            SYS_GETPID => getpid(),
-            SYS_FSTAT => fstat(b, &mut validate_slice_mut(c as *mut Stat, 1)?[0]),
-            SYS_DUP => dup(b),
-            SYS_BRK => brk(b),
-            SYS_FTRUNCATE => ftruncate(b, c),
-            SYS_IOPL => iopl(b),
-            SYS_FSYNC => fsync(b),
-            SYS_CLONE => clone(b, stack),
-            SYS_YIELD => sched_yield(),
-            SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?),
-            SYS_FEVENT => fevent(b, c),
-            SYS_FPATH => fpath(b, validate_slice_mut(c as *mut u8, d)?),
-            SYS_PHYSMAP => physmap(b, c, d),
-            SYS_PHYSUNMAP => physunmap(b),
-            _ => {
-                println!("Unknown syscall {}", a);
-                Err(Error::new(ENOSYS))
+        match a & SYS_CLASS {
+            SYS_CLASS_FILE => match a & SYS_ARG {
+                SYS_ARG_SLICE => file_op_slice(a, b, validate_slice(c as *const u8, d)?),
+                SYS_ARG_MSLICE => file_op_mut_slice(a, b, validate_slice_mut(c as *mut u8, d)?),
+                _ => match a {
+                    SYS_CLOSE => close(b),
+                    SYS_DUP => dup(b),
+                    SYS_FEVENT => fevent(b, c),
+                    _ => file_op(a, b, c, d)
+                }
+            },
+            SYS_CLASS_PATH => match a {
+                SYS_OPEN => open(validate_slice(b as *const u8, c)?, d),
+                _ => unreachable!()
+            },
+            _ => match a {
+                SYS_EXIT => exit(b),
+                SYS_WAITPID => waitpid(b, c, d),
+                SYS_EXECVE => exec(validate_slice(b as *const u8, c)?, validate_slice(d as *const [usize; 2], e)?),
+                SYS_CHDIR => chdir(validate_slice(b as *const u8, c)?),
+                SYS_GETPID => getpid(),
+                SYS_BRK => brk(b),
+                SYS_IOPL => iopl(b),
+                SYS_CLONE => clone(b, stack),
+                SYS_YIELD => sched_yield(),
+                SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?),
+                SYS_PHYSMAP => physmap(b, c, d),
+                SYS_PHYSUNMAP => physunmap(b),
+                _ => Err(Error::new(ENOSYS))
             }
         }
     }
diff --git a/syscall/process.rs b/syscall/process.rs
index 5150b95d88f911e8c431d1caedeaf8a784979466..487750334e365b5a5df23e62372bb6c5b50652de 100644
--- a/syscall/process.rs
+++ b/syscall/process.rs
@@ -395,7 +395,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
         let mut data = vec![];
         loop {
             let mut buf = [0; 16384];
-            let count = syscall::read(file, &mut buf)?;
+            let count = syscall::file_op_mut_slice(syscall::number::SYS_READ, file, &mut buf)?;
             if count > 0 {
                 data.extend_from_slice(&buf[..count]);
             } else {