diff -r f8a4e40ab1d6 fs.c
--- a/fs.c	Thu Aug 30 14:32:06 2007 -0400
+++ b/fs.c	Thu Aug 30 14:29:02 2007 -0400
@@ -577,12 +577,18 @@ skipelem(char *path, char *name)
 // If parent != 0, return the inode for the parent and copy the final
 // path element into name, which must have room for DIRSIZ bytes.
 static struct inode*
-_namei(char *path, int parent, char *name)
+_namei(struct inode *root, char *path, int parent, char *name, int depth)
 {
   struct inode *ip, *next;
+  char buf[100], tname[DIRSIZ];
+
+  if(depth > 5)
+    return 0;
 
   if(*path == '/')
     ip = iget(ROOTDEV, 1);
+  else if(root)
+    ip = idup(root);
   else
     ip = idup(cp->cwd);
 
@@ -598,10 +604,24 @@ _namei(char *path, int parent, char *nam
       return ip;
     }
     if((next = dirlookup(ip, name, 0)) == 0){
+      cprintf("did not find %s\n", name);
       iunlockput(ip);
       return 0;
     }
-    iunlockput(ip);
+    iunlock(ip);
+    ilock(next);
+    if(next->type == T_SYMLINK){
+      if(next->size >= sizeof(buf) || readi(next, buf, 0, next->size) != next->size){
+        iunlockput(next);
+        iput(ip);
+        return 0;
+      }
+      buf[next->size] = 0;
+      iunlockput(next);
+      next = _namei(ip, buf, 0, tname, depth+1);
+    }else
+      iunlock(next);
+    iput(ip);
     ip = next;
   }
   if(parent){
@@ -615,11 +635,11 @@ namei(char *path)
 namei(char *path)
 {
   char name[DIRSIZ];
-  return _namei(path, 0, name);
+  return _namei(0, path, 0, name, 0);
 }
 
 struct inode*
 nameiparent(char *path, char *name)
 {
-  return _namei(path, 1, name);
-}
+  return _namei(0, path, 1, name, 0);
+}
diff -r f8a4e40ab1d6 fs.h
--- a/fs.h	Thu Aug 30 14:32:06 2007 -0400
+++ b/fs.h	Thu Aug 30 13:05:43 2007 -0400
@@ -33,6 +33,7 @@ struct dinode {
 #define T_DIR  1   // Directory
 #define T_FILE 2   // File
 #define T_DEV  3   // Special device
+#define T_SYMLINK 4  // Symlink
 
 // Inodes per block.
 #define IPB           (BSIZE / sizeof(struct dinode))
diff -r f8a4e40ab1d6 syscall.c
--- a/syscall.c	Thu Aug 30 14:32:06 2007 -0400
+++ b/syscall.c	Thu Aug 30 13:05:29 2007 -0400
@@ -96,6 +96,7 @@ extern int sys_unlink(void);
 extern int sys_unlink(void);
 extern int sys_wait(void);
 extern int sys_write(void);
+extern int sys_symlink(void);
 
 static int (*syscalls[])(void) = {
 [SYS_chdir]   sys_chdir,
@@ -118,6 +119,7 @@ static int (*syscalls[])(void) = {
 [SYS_unlink]  sys_unlink,
 [SYS_wait]    sys_wait,
 [SYS_write]   sys_write,
+[SYS_symlink]	sys_symlink,
 };
 
 void
diff -r f8a4e40ab1d6 syscall.h
--- a/syscall.h	Thu Aug 30 14:32:06 2007 -0400
+++ b/syscall.h	Thu Aug 30 13:02:48 2007 -0400
@@ -19,3 +19,4 @@
 #define SYS_getpid 18
 #define SYS_sbrk   19
 #define SYS_sleep  20
+#define SYS_symlink 21
diff -r f8a4e40ab1d6 sysfile.c
--- a/sysfile.c	Thu Aug 30 14:32:06 2007 -0400
+++ b/sysfile.c	Thu Aug 30 13:10:31 2007 -0400
@@ -257,6 +257,21 @@ create(char *path, int canexist, short t
 }
 
 int
+sys_symlink(void)
+{
+  char *old, *new;
+  struct inode *ip;
+  
+  if(argstr(0, &old) < 0 || argstr(1, &new) < 0)
+    return -1;
+  if((ip = create(new, 0, T_SYMLINK, 0, 0)) == 0)
+    return -1;
+  writei(ip, old, 0, strlen(old));
+  iunlockput(ip);
+  return 0;
+}
+
+int
 sys_open(void)
 {
   char *path;
@@ -393,3 +408,4 @@ sys_pipe(void)
   fd[1] = fd1;
   return 0;
 }
+
diff -r f8a4e40ab1d6 user.h
--- a/user.h	Thu Aug 30 14:32:06 2007 -0400
+++ b/user.h	Thu Aug 30 13:02:34 2007 -0400
@@ -21,6 +21,7 @@ int getpid();
 int getpid();
 char* sbrk(int);
 int sleep(int);
+int symlink(int);
 
 // ulib.c
 int stat(char*, struct stat*);
diff -r f8a4e40ab1d6 usys.S
--- a/usys.S	Thu Aug 30 14:32:06 2007 -0400
+++ b/usys.S	Thu Aug 30 13:05:54 2007 -0400
@@ -28,3 +28,4 @@ STUB(getpid)
 STUB(getpid)
 STUB(sbrk)
 STUB(sleep)
+STUB(symlink)