From 9e5970d596d7b1634200d50e96130886f593cede Mon Sep 17 00:00:00 2001
From: rtm <rtm>
Date: Sun, 13 Aug 2006 02:12:44 +0000
Subject: [PATCH] link()

---
 Notes       |  4 +--
 defs.h      |  1 +
 fs.c        | 89 ++++++++++++++++++++++++++++++++++++++---------------
 ide.c       |  2 --
 main.c      |  6 ----
 proc.c      |  3 --
 syscall.c   | 19 +++++++++++-
 syscall.h   |  1 +
 user.h      |  1 +
 usertests.c | 61 ++++++++++++++++++++++++++++++++++++
 usys.S      |  1 +
 11 files changed, 149 insertions(+), 39 deletions(-)

diff --git a/Notes b/Notes
index 7e3edd5..386bc2f 100644
--- a/Notes
+++ b/Notes
@@ -355,8 +355,6 @@ HMM maybe the variables at the end of struct cpu are being overwritten
 OH! recursive interrupts will use up any amount of cpu[].stack!
   underflow and wrecks *previous* cpu's struct
 
-better buffer cache replacement
-read/write of open file that's been unlinked
 disk scheduling
 mkdir
 more than one directory content block
@@ -365,3 +363,5 @@ sh redirection
 indirect blocks
 two bugs in unlink: don't just return if nlink > 0,
   and search for name, not inum
+is there a create/create race for same file name?
+  resulting in two entries w/ same name in directory?
diff --git a/defs.h b/defs.h
index 6a4f1c2..c8e1870 100644
--- a/defs.h
+++ b/defs.h
@@ -123,3 +123,4 @@ int writei(struct inode *ip, char *addr, uint off, uint n);
 struct inode *mknod(char *, short, short, short);
 int unlink(char *cp);
 void iupdate (struct inode *ip);
+int link(char *file1, char *file2);
diff --git a/fs.c b/fs.c
index e01b4fb..7f0d2ea 100644
--- a/fs.c
+++ b/fs.c
@@ -439,14 +439,41 @@ namei(char *path, uint *ret_pinum)
   }
 }
 
+void
+wdir(struct inode *dp, char *name, uint ino)
+{
+  uint off;
+  struct buf *bp = 0;
+  struct dirent *ep = 0;
+  int i;
+
+  for(off = 0; off < dp->size; off += BSIZE) {
+    bp = bread(dp->dev, bmap(dp, off / BSIZE));
+    for(ep = (struct dirent *) bp->data;
+	ep < (struct dirent *) (bp->data + BSIZE);
+	ep++){
+      if(ep->inum == 0)
+	goto found;
+    }
+    brelse(bp);
+  }
+
+  panic("mknod: XXXX no dir entry free\n");
+
+ found:
+  ep->inum = ino;
+  for(i = 0; i < DIRSIZ && name[i]; i++)
+    ep->name[i] = name[i];
+  for( ; i < DIRSIZ; i++)
+    ep->name[i] = '\0';
+  bwrite (bp, bmap(dp, off/BSIZE));   // write directory block
+  brelse(bp);
+}
+
 struct inode *
 mknod(char *cp, short type, short major, short minor)
 {
   struct inode *ip, *dp;
-  struct dirent *ep = 0;
-  int off;
-  int i;
-  struct buf *bp = 0;
   uint pinum = 0;
 
   cprintf("mknod: %s %d %d %d\n", cp, type, major, minor);
@@ -469,27 +496,7 @@ mknod(char *cp, short type, short major, short minor)
 
   iupdate (ip);  // write new inode to disk
 
-  for(off = 0; off < dp->size; off += BSIZE) {
-    bp = bread(dp->dev, bmap(dp, off / BSIZE));
-    for(ep = (struct dirent *) bp->data;
-	ep < (struct dirent *) (bp->data + BSIZE);
-	ep++){
-      if(ep->inum == 0) {
-	goto found;
-      }
-    }
-    brelse(bp);
-  }
-  panic("mknod: XXXX no dir entry free\n");
-
- found:
-  ep->inum = ip->inum;
-  for(i = 0; i < DIRSIZ && cp[i]; i++)
-    ep->name[i] = cp[i];
-  for( ; i < DIRSIZ; i++)
-    ep->name[i] = '\0';
-  bwrite (bp, bmap(dp, off/BSIZE));   // write directory block
-  brelse(bp);
+  wdir(dp, cp, ip->inum);
 
   iput(dp);
 
@@ -541,3 +548,35 @@ unlink(char *cp)
   iput(ip);
   return 0;
 }
+
+int
+link(char *name1, char *name2)
+{
+  struct inode *ip, *dp, *xip;
+  uint pinum = 0;
+
+  cprintf("link(%s, %s)\n", name1, name2);
+
+  if ((xip = namei(name2, &pinum)) != 0) {
+    cprintf("  failed %s exists\n", name2);
+    iput(xip);
+    return -1;
+  }
+
+  if ((ip = namei(name1, &pinum)) == 0){
+    cprintf("  failed %s does not exist\n", name1);
+    return -1;
+  }
+  
+  ip->nlink += 1;
+  iupdate (ip);
+
+  dp = iget(rootdev, pinum);
+  wdir(dp, name2, ip->inum);
+  iput(dp);
+  iput(ip);
+
+  cprintf("  succeeded\n");
+
+  return 0;
+}
diff --git a/ide.c b/ide.c
index 3532121..331553f 100644
--- a/ide.c
+++ b/ide.c
@@ -52,14 +52,12 @@ ide_init(void)
   }
   ioapic_enable (IRQ_IDE, 1);
   ide_wait_ready(0);
-  cprintf ("cpu%d: ide_init:done\n", cpu());
 }
 
 void
 ide_intr(void)
 {
   acquire(&ide_lock);
-  //  cprintf("cpu%d: ide_intr\n", cpu());
   wakeup(&request[tail]);
   release(&ide_lock);
 }
diff --git a/main.c b/main.c
index c164c48..a2ee845 100644
--- a/main.c
+++ b/main.c
@@ -87,8 +87,6 @@ main0(void)
   lapic_enableintr();
 
   // Enable interrupts on this processor.
-  cprintf("cpu%d: nlock %d before -- and sti\n",
-          cpu(), cpus[0].nlock);
   cpus[cpu()].nlock--;
   sti();
 
@@ -98,7 +96,6 @@ main0(void)
   //load_icode(p, _binary_userfs_start, (uint) _binary_userfs_size);
   load_icode(p, _binary_init_start, (uint) _binary_init_size);
   p->state = RUNNABLE;
-  cprintf("loaded init\n");
 
   scheduler();
 }
@@ -123,7 +120,6 @@ mpmain(void)
   cpus[cpu()].booted = 1;
 
   // Enable interrupts on this processor.
-  cprintf("cpu%d: initial nlock %d\n", cpu(), cpus[cpu()].nlock);
   cpus[cpu()].nlock--;
   sti();
 
@@ -139,7 +135,6 @@ load_icode(struct proc *p, uchar *binary, uint size)
 
   // Check magic number on binary
   elf = (struct elfhdr*) binary;
-  cprintf("elf %x magic %x\n", elf, elf->magic);
   if (elf->magic != ELF_MAGIC)
     panic("load_icode: not an ELF binary");
 
@@ -151,7 +146,6 @@ load_icode(struct proc *p, uchar *binary, uint size)
   for (i = 0; i < elf->phnum; i++, ph++) {
     if (ph->type != ELF_PROG_LOAD)
       continue;
-    cprintf("va %x memsz %d\n", ph->va, ph->memsz);
     if (ph->va + ph->memsz < ph->va)
       panic("load_icode: overflow in elf header segment");
     if (ph->va + ph->memsz >= p->sz)
diff --git a/proc.c b/proc.c
index 5f8769b..7290693 100644
--- a/proc.c
+++ b/proc.c
@@ -140,9 +140,6 @@ scheduler(void)
   struct proc *p;
   int i;
 
-  cprintf("cpu%d: start scheduler jmpbuf %p\n",
-          cpu(), &cpus[cpu()].jmpbuf);
-
   if(cpus[cpu()].nlock != 0){
     cprintf("la %x lr %x\n", cpus[cpu()].lastacquire, cpus[cpu()].lastrelease   );
     panic("holding locks at first entry to scheduler");
diff --git a/syscall.c b/syscall.c
index 48da287..4505c89 100644
--- a/syscall.c
+++ b/syscall.c
@@ -303,7 +303,6 @@ sys_unlink(void)
   return r;
 }
 
-
 int
 sys_fstat(void)
 {
@@ -325,6 +324,21 @@ sys_fstat(void)
   return r;
 }
 
+int
+sys_link(void)
+{
+  struct proc *cp = curproc[cpu()];
+  uint name1, name2;
+  int r;
+  
+  if(fetcharg(0, &name1) < 0 || checkstring(name1) < 0)
+    return -1;
+  if(fetcharg(1, &name2) < 0 || checkstring(name2) < 0)
+    return -1;
+  r = link(cp->mem + name1, cp->mem + name2);
+  return r;
+}
+
 int
 sys_exec(void)
 {
@@ -543,6 +557,9 @@ syscall(void)
   case SYS_fstat:
     ret = sys_fstat();
     break;
+  case SYS_link:
+    ret = sys_link();
+    break;
   default:
     cprintf("unknown sys call %d\n", num);
     // XXX fault
diff --git a/syscall.h b/syscall.h
index ca2855c..01d09ff 100644
--- a/syscall.h
+++ b/syscall.h
@@ -12,4 +12,5 @@
 #define SYS_mknod 15
 #define SYS_unlink 16
 #define SYS_fstat 17
+#define SYS_link 18
 
diff --git a/user.h b/user.h
index 9dd1684..52b804b 100644
--- a/user.h
+++ b/user.h
@@ -16,6 +16,7 @@ int mknod (char*,short,short,short);
 int unlink (char*);
 struct stat;
 int fstat (int fd, struct stat *stat);
+int link(char *, char *);
 
 int puts(char*);
 char* strcpy(char*, char*);
diff --git a/usertests.c b/usertests.c
index 3cb4a37..2d6b065 100644
--- a/usertests.c
+++ b/usertests.c
@@ -344,11 +344,72 @@ unlinkread()
   puts("unlinkread ok\n");
 }
 
+void
+linktest()
+{
+  int fd;
+
+  unlink("lf1");
+  unlink("lf2");
+
+  fd = open("lf1", O_CREATE|O_RDWR);
+  if(fd < 0){
+    puts("create lf1 failed\n");
+    exit();
+  }
+  if(write(fd, "hello", 5) != 5){
+    puts("write lf1 failed\n");
+    exit();
+  }
+  close(fd);
+
+  if(link("lf1", "lf2") < 0){
+    puts("link lf1 lf2 failed\n");
+    exit();
+  }
+  unlink("lf1");
+
+  if(open("lf1", 0) >= 0){
+    puts("unlinked lf1 but it is still there!\n");
+    exit();
+  }
+
+  fd = open("lf2", 0);
+  if(fd < 0){
+    puts("open lf2 failed\n");
+    exit();
+  }
+  if(read(fd, buf, sizeof(buf)) != 5){
+    puts("read lf2 failed\n");
+    exit();
+  }
+  close(fd);
+    
+  if(link("lf2", "lf2") >= 0){
+    puts("link lf2 lf2 succeeded! oops\n");
+    exit();
+  }
+
+  unlink("lf2");
+  if(link("lf2", "lf1") >= 0){
+    puts("link non-existant succeeded! oops\n");
+    exit();
+  }
+
+  if(link(".", "lf1") >= 0){
+    puts("link . lf1 succeeded! oops\n");
+    exit();
+  }
+
+  puts("linktest ok\n");
+}
+
 int
 main(int argc, char *argv[])
 {
   puts("usertests starting\n");
 
+  linktest();
   unlinkread();
   createdelete();
   twofiles();
diff --git a/usys.S b/usys.S
index f9565e5..73170c3 100644
--- a/usys.S
+++ b/usys.S
@@ -22,3 +22,4 @@ STUB(open)
 STUB(mknod)
 STUB(unlink)
 STUB(fstat)
+STUB(link)
-- 
GitLab