xref: /xv6-public/fs.c (revision ea2909b6)
111a9947fSrtm #include "types.h"
21f544842Skaashoek #include "stat.h"
311a9947fSrtm #include "param.h"
411a9947fSrtm #include "x86.h"
511a9947fSrtm #include "mmu.h"
611a9947fSrtm #include "proc.h"
711a9947fSrtm #include "defs.h"
811a9947fSrtm #include "spinlock.h"
911a9947fSrtm #include "buf.h"
1011a9947fSrtm #include "fs.h"
1111a9947fSrtm #include "fsvar.h"
126fa5ffb5Skaashoek #include "dev.h"
1311a9947fSrtm 
1411a9947fSrtm // these are inodes currently in use
1511a9947fSrtm // an entry is free if count == 0
1611a9947fSrtm struct inode inode[NINODE];
175be0039cSrtm struct spinlock inode_table_lock;
1811a9947fSrtm 
199d3fb671Srtm uint rootdev = 1;
209d3fb671Srtm 
215be0039cSrtm void
225be0039cSrtm iinit(void)
235be0039cSrtm {
245be0039cSrtm   initlock(&inode_table_lock, "inode_table");
255be0039cSrtm }
265be0039cSrtm 
2724111398Skaashoek static uint
2824111398Skaashoek balloc(uint dev)
2924111398Skaashoek {
3024111398Skaashoek   int b;
3124111398Skaashoek   struct buf *bp;
3224111398Skaashoek   struct superblock *sb;
3328d9ef04Skaashoek   int bi = 0;
3424111398Skaashoek   int size;
3524111398Skaashoek   int ninodes;
3624111398Skaashoek   uchar m;
3724111398Skaashoek 
3824111398Skaashoek   bp = bread(dev, 1);
3924111398Skaashoek   sb = (struct superblock *) bp->data;
4024111398Skaashoek   size = sb->size;
4124111398Skaashoek   ninodes = sb->ninodes;
4224111398Skaashoek 
4324111398Skaashoek   for (b = 0; b < size; b++) {
4424111398Skaashoek     if (b % BPB == 0) {
4524111398Skaashoek       brelse(bp);
4624111398Skaashoek       bp = bread(dev, BBLOCK(b, ninodes));
4724111398Skaashoek     }
4824111398Skaashoek     bi = b % BPB;
4924111398Skaashoek     m = 0x1 << (bi % 8);
5024111398Skaashoek     if ((bp->data[bi/8] & m) == 0) {  // is block free?
5124111398Skaashoek       break;
5224111398Skaashoek     }
5324111398Skaashoek   }
5424111398Skaashoek   if (b >= size)
5524111398Skaashoek     panic("balloc: out of blocks\n");
5624111398Skaashoek 
5724111398Skaashoek   bp->data[bi/8] |= 0x1 << (bi % 8);
5805e97551Srtm   bwrite (bp, BBLOCK(b, ninodes));  // mark it allocated on disk
5928d9ef04Skaashoek   brelse(bp);
6024111398Skaashoek   return b;
6124111398Skaashoek }
6224111398Skaashoek 
6328d9ef04Skaashoek static void
6428d9ef04Skaashoek bfree(int dev, uint b)
6528d9ef04Skaashoek {
6628d9ef04Skaashoek   struct buf *bp;
6728d9ef04Skaashoek   struct superblock *sb;
6828d9ef04Skaashoek   int bi;
6928d9ef04Skaashoek   int ninodes;
7028d9ef04Skaashoek   uchar m;
7128d9ef04Skaashoek 
7228d9ef04Skaashoek   bp = bread(dev, 1);
7328d9ef04Skaashoek   sb = (struct superblock *) bp->data;
7428d9ef04Skaashoek   ninodes = sb->ninodes;
7528d9ef04Skaashoek   brelse(bp);
7628d9ef04Skaashoek 
77c372e8dcSkaashoek   bp = bread(dev, b);
78c372e8dcSkaashoek   memset(bp->data, 0, BSIZE);
79c372e8dcSkaashoek   bwrite(bp, b);
80c372e8dcSkaashoek   brelse(bp);
81c372e8dcSkaashoek 
8228d9ef04Skaashoek   bp = bread(dev, BBLOCK(b, ninodes));
8328d9ef04Skaashoek   bi = b % BPB;
8428d9ef04Skaashoek   m = ~(0x1 << (bi %8));
8528d9ef04Skaashoek   bp->data[bi/8] &= m;
8605e97551Srtm   bwrite (bp, BBLOCK(b, ninodes));  // mark it free on disk
8728d9ef04Skaashoek   brelse(bp);
8828d9ef04Skaashoek }
8924111398Skaashoek 
909d3fb671Srtm // returns an inode with busy set and incremented reference count.
9111a9947fSrtm struct inode *
9211a9947fSrtm iget(uint dev, uint inum)
9311a9947fSrtm {
9417e3cf15Srtm   struct inode *ip, *nip;
9511a9947fSrtm   struct dinode *dip;
9611a9947fSrtm   struct buf *bp;
9711a9947fSrtm 
9811a9947fSrtm   acquire(&inode_table_lock);
9911a9947fSrtm 
10011a9947fSrtm  loop:
10117e3cf15Srtm   nip = 0;
10211a9947fSrtm   for(ip = &inode[0]; ip < &inode[NINODE]; ip++){
10311a9947fSrtm     if(ip->count > 0 && ip->dev == dev && ip->inum == inum){
10411a9947fSrtm       if(ip->busy){
10511a9947fSrtm         sleep(ip, &inode_table_lock);
10611a9947fSrtm         goto loop;
10711a9947fSrtm       }
10811a9947fSrtm       ip->count++;
10917a85657Srtm       ip->busy = 1;
11011a9947fSrtm       release(&inode_table_lock);
11111a9947fSrtm       return ip;
11211a9947fSrtm     }
11311a9947fSrtm     if(nip == 0 && ip->count == 0)
11411a9947fSrtm       nip = ip;
11511a9947fSrtm   }
11611a9947fSrtm 
11711a9947fSrtm   if(nip == 0)
11811a9947fSrtm     panic("out of inodes");
11911a9947fSrtm 
12011a9947fSrtm   nip->dev = dev;
12111a9947fSrtm   nip->inum = inum;
12211a9947fSrtm   nip->count = 1;
12311a9947fSrtm   nip->busy = 1;
12411a9947fSrtm 
12511a9947fSrtm   release(&inode_table_lock);
12611a9947fSrtm 
12724111398Skaashoek   bp = bread(dev, IBLOCK(inum));
12811a9947fSrtm   dip = &((struct dinode *)(bp->data))[inum % IPB];
12911a9947fSrtm   nip->type = dip->type;
130e8d11c2eSkaashoek   nip->major = dip->major;
131e8d11c2eSkaashoek   nip->minor = dip->minor;
13211a9947fSrtm   nip->nlink = dip->nlink;
13311a9947fSrtm   nip->size = dip->size;
13411a9947fSrtm   memmove(nip->addrs, dip->addrs, sizeof(nip->addrs));
13511a9947fSrtm   brelse(bp);
13611a9947fSrtm 
13711a9947fSrtm   return nip;
13811a9947fSrtm }
13911a9947fSrtm 
14028d9ef04Skaashoek void
14128d9ef04Skaashoek iupdate (struct inode *ip)
14228d9ef04Skaashoek {
14328d9ef04Skaashoek   struct buf *bp;
14428d9ef04Skaashoek   struct dinode *dip;
14528d9ef04Skaashoek 
14628d9ef04Skaashoek   bp = bread(ip->dev, IBLOCK(ip->inum));
14728d9ef04Skaashoek   dip = &((struct dinode *)(bp->data))[ip->inum % IPB];
14828d9ef04Skaashoek   dip->type = ip->type;
14928d9ef04Skaashoek   dip->major = ip->major;
15028d9ef04Skaashoek   dip->minor = ip->minor;
15128d9ef04Skaashoek   dip->nlink = ip->nlink;
15228d9ef04Skaashoek   dip->size = ip->size;
15328d9ef04Skaashoek   memmove(dip->addrs, ip->addrs, sizeof(ip->addrs));
15405e97551Srtm   bwrite (bp, IBLOCK(ip->inum));   // mark it allocated on the disk
15528d9ef04Skaashoek   brelse(bp);
15628d9ef04Skaashoek }
15728d9ef04Skaashoek 
158e8d11c2eSkaashoek struct inode *
159e8d11c2eSkaashoek ialloc(uint dev, short type)
160e8d11c2eSkaashoek {
161e8d11c2eSkaashoek   struct inode *ip;
162e8d11c2eSkaashoek   struct dinode *dip = 0;
163e8d11c2eSkaashoek   struct superblock *sb;
164e8d11c2eSkaashoek   int ninodes;
165e8d11c2eSkaashoek   int inum;
166e8d11c2eSkaashoek   struct buf *bp;
167e8d11c2eSkaashoek 
168e8d11c2eSkaashoek   bp = bread(dev, 1);
16924111398Skaashoek   sb = (struct superblock *) bp->data;
170e8d11c2eSkaashoek   ninodes = sb->ninodes;
171e8d11c2eSkaashoek   brelse(bp);
172e8d11c2eSkaashoek 
173e8d11c2eSkaashoek   for (inum = 1; inum < ninodes; inum++) {  // loop over inode blocks
17424111398Skaashoek     bp = bread(dev, IBLOCK(inum));
175e8d11c2eSkaashoek     dip = &((struct dinode *)(bp->data))[inum % IPB];
176e8d11c2eSkaashoek     if (dip->type == 0) {  // a free inode
177e8d11c2eSkaashoek       break;
178e8d11c2eSkaashoek     }
179e8d11c2eSkaashoek     brelse(bp);
180e8d11c2eSkaashoek   }
181e8d11c2eSkaashoek 
18217e3cf15Srtm   if (inum >= ninodes)
18324111398Skaashoek     panic ("ialloc: no inodes left\n");
184e8d11c2eSkaashoek 
185e8d11c2eSkaashoek   dip->type = type;
18605e97551Srtm   bwrite (bp, IBLOCK(inum));   // mark it allocated on the disk
187e8d11c2eSkaashoek   brelse(bp);
188e8d11c2eSkaashoek   ip = iget (dev, inum);
189e8d11c2eSkaashoek   return ip;
190e8d11c2eSkaashoek }
191e8d11c2eSkaashoek 
19228d9ef04Skaashoek static void
19324437cd5Skaashoek ifree(struct inode *ip)
194e8d11c2eSkaashoek {
19528d9ef04Skaashoek   ip->type = 0;
19628d9ef04Skaashoek   iupdate(ip);
197e8d11c2eSkaashoek }
198e8d11c2eSkaashoek 
19911a9947fSrtm void
2009d3fb671Srtm ilock(struct inode *ip)
2019d3fb671Srtm {
2029d3fb671Srtm   if(ip->count < 1)
2039d3fb671Srtm     panic("ilock");
2049d3fb671Srtm 
2059d3fb671Srtm   acquire(&inode_table_lock);
2069d3fb671Srtm 
2079d3fb671Srtm   while(ip->busy)
2089d3fb671Srtm     sleep(ip, &inode_table_lock);
2099d3fb671Srtm   ip->busy = 1;
2109d3fb671Srtm 
2119d3fb671Srtm   release(&inode_table_lock);
2129d3fb671Srtm }
2139d3fb671Srtm 
2149d3fb671Srtm // caller is holding onto a reference to this inode, but no
2159d3fb671Srtm // longer needs to examine or change it, so clear ip->busy.
2169d3fb671Srtm void
2179d3fb671Srtm iunlock(struct inode *ip)
2189d3fb671Srtm {
21917e3cf15Srtm   if(ip->busy != 1 || ip->count < 1)
2209d3fb671Srtm     panic("iunlock");
2219d3fb671Srtm 
2229d3fb671Srtm   acquire(&inode_table_lock);
2239d3fb671Srtm 
2249d3fb671Srtm   ip->busy = 0;
2259d3fb671Srtm   wakeup(ip);
2269d3fb671Srtm 
2279d3fb671Srtm   release(&inode_table_lock);
2289d3fb671Srtm }
2299d3fb671Srtm 
23022bac2cbSkaashoek uint
23122bac2cbSkaashoek bmap(struct inode *ip, uint bn)
23222bac2cbSkaashoek {
23322bac2cbSkaashoek   unsigned x;
234*ea2909b6Skaashoek   uint *a;
235*ea2909b6Skaashoek   struct buf *inbp;
23622bac2cbSkaashoek 
237*ea2909b6Skaashoek   if(bn >= MAXFILE)
23822bac2cbSkaashoek     panic("bmap 1");
239*ea2909b6Skaashoek   if (bn < NDIRECT) {
24022bac2cbSkaashoek     x = ip->addrs[bn];
24122bac2cbSkaashoek     if (x == 0)
24222bac2cbSkaashoek       panic("bmap 2");
243*ea2909b6Skaashoek   } else {
244*ea2909b6Skaashoek     cprintf("indirect block read\n");
245*ea2909b6Skaashoek     inbp = bread(ip->dev, INDIRECT);
246*ea2909b6Skaashoek     a = (uint *) inbp->data;
247*ea2909b6Skaashoek     x = a[bn - NDIRECT];
248*ea2909b6Skaashoek     brelse(inbp);
249*ea2909b6Skaashoek     if (x == 0)
250*ea2909b6Skaashoek       panic("bmap 3");
251*ea2909b6Skaashoek   }
25222bac2cbSkaashoek   return x;
25322bac2cbSkaashoek }
25422bac2cbSkaashoek 
25522bac2cbSkaashoek void
25622bac2cbSkaashoek iunlink(struct inode *ip)
25722bac2cbSkaashoek {
258*ea2909b6Skaashoek   int i, j;
25922bac2cbSkaashoek 
26022bac2cbSkaashoek   // free inode, its blocks, and remove dir entry
261*ea2909b6Skaashoek   for (i = 0; i < NADDRS; i++) {
26222bac2cbSkaashoek     if (ip->addrs[i] != 0) {
263*ea2909b6Skaashoek       if (i == INDIRECT) {
264*ea2909b6Skaashoek 	for (j = 0; j < NINDIRECT; j++) {
265*ea2909b6Skaashoek 	  uint *a = (uint *) (ip->addrs[i]);
266*ea2909b6Skaashoek 	  if (a[j] != 0) {
267*ea2909b6Skaashoek 	    bfree(ip->dev, a[j]);
268*ea2909b6Skaashoek 	    a[j] = 0;
269*ea2909b6Skaashoek 	  }
270*ea2909b6Skaashoek 	}
271*ea2909b6Skaashoek       }
272*ea2909b6Skaashoek       else
27322bac2cbSkaashoek 	bfree(ip->dev, ip->addrs[i]);
27422bac2cbSkaashoek       ip->addrs[i] = 0;
27522bac2cbSkaashoek     }
27622bac2cbSkaashoek   }
27722bac2cbSkaashoek   ip->size = 0;
27822bac2cbSkaashoek   ip->major = 0;
27922bac2cbSkaashoek   ip->minor = 0;
28022bac2cbSkaashoek   iupdate(ip);
28122bac2cbSkaashoek   ifree(ip);  // is this the right order?
28222bac2cbSkaashoek }
28322bac2cbSkaashoek 
2849d3fb671Srtm // caller is releasing a reference to this inode.
2859d3fb671Srtm // you must have the inode lock.
2869d3fb671Srtm void
28711a9947fSrtm iput(struct inode *ip)
28811a9947fSrtm {
2899d3fb671Srtm   if(ip->count < 1 || ip->busy != 1)
2909d3fb671Srtm     panic("iput");
2919d3fb671Srtm 
29217e3cf15Srtm   if ((ip->count == 1) && (ip->nlink == 0))
29322bac2cbSkaashoek     iunlink(ip);
29422bac2cbSkaashoek 
29511a9947fSrtm   acquire(&inode_table_lock);
29611a9947fSrtm 
29711a9947fSrtm   ip->count -= 1;
29811a9947fSrtm   ip->busy = 0;
29911a9947fSrtm   wakeup(ip);
30011a9947fSrtm 
30111a9947fSrtm   release(&inode_table_lock);
30211a9947fSrtm }
3039d3fb671Srtm 
3049d3fb671Srtm void
30532630628Srtm idecref(struct inode *ip)
3069d3fb671Srtm {
307211ff0c6Srtm   ilock(ip);
308211ff0c6Srtm   iput(ip);
3099d3fb671Srtm }
3109d3fb671Srtm 
3111f544842Skaashoek void
312e958c538Skaashoek iincref(struct inode *ip)
313e958c538Skaashoek {
314e958c538Skaashoek   ilock(ip);
315e958c538Skaashoek   ip->count++;
316e958c538Skaashoek   iunlock(ip);
317e958c538Skaashoek }
318e958c538Skaashoek 
319e958c538Skaashoek void
3201f544842Skaashoek stati(struct inode *ip, struct stat *st)
3211f544842Skaashoek {
3221f544842Skaashoek   st->st_dev = ip->dev;
3231f544842Skaashoek   st->st_ino = ip->inum;
3241f544842Skaashoek   st->st_type = ip->type;
3251f544842Skaashoek   st->st_nlink = ip->nlink;
3261f544842Skaashoek   st->st_size = ip->size;
3271f544842Skaashoek }
3281f544842Skaashoek 
32922bac2cbSkaashoek #define min(a, b) ((a) < (b) ? (a) : (b))
33022bac2cbSkaashoek 
331c59361f1Srtm int
33217a85657Srtm readi(struct inode *ip, char *dst, uint off, uint n)
333c59361f1Srtm {
334c59361f1Srtm   uint target = n, n1;
335c59361f1Srtm   struct buf *bp;
336c59361f1Srtm 
337939f9edeSkaashoek   if (ip->type == T_DEV) {
338939f9edeSkaashoek     if (ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].d_read)
339939f9edeSkaashoek       return -1;
34017a85657Srtm     return devsw[ip->major].d_read (ip->minor, dst, n);
341939f9edeSkaashoek   }
342939f9edeSkaashoek 
343c59361f1Srtm   while(n > 0 && off < ip->size){
34424111398Skaashoek     bp = bread(ip->dev, bmap(ip, off / BSIZE));
345c59361f1Srtm     n1 = min(n, ip->size - off);
34624111398Skaashoek     n1 = min(n1, BSIZE - (off % BSIZE));
34724111398Skaashoek     memmove(dst, bp->data + (off % BSIZE), n1);
348c59361f1Srtm     n -= n1;
349c59361f1Srtm     off += n1;
350c59361f1Srtm     dst += n1;
351c59361f1Srtm     brelse(bp);
352c59361f1Srtm   }
353c59361f1Srtm 
354c59361f1Srtm   return target - n;
355c59361f1Srtm }
356c59361f1Srtm 
3576fa5ffb5Skaashoek int
358*ea2909b6Skaashoek newblock(struct inode *ip, uint lbn)
359*ea2909b6Skaashoek {
360*ea2909b6Skaashoek   struct buf *inbp;
361*ea2909b6Skaashoek   uint *inaddrs;
362*ea2909b6Skaashoek   uint b;
363*ea2909b6Skaashoek 
364*ea2909b6Skaashoek   if (lbn < NDIRECT) {
365*ea2909b6Skaashoek     if (ip->addrs[lbn] == 0) {
366*ea2909b6Skaashoek       b = balloc(ip->dev);
367*ea2909b6Skaashoek       if (b <= 0) return -1;
368*ea2909b6Skaashoek       ip->addrs[lbn] = b;
369*ea2909b6Skaashoek     }
370*ea2909b6Skaashoek   } else {
371*ea2909b6Skaashoek     cprintf("newblock: use indirect block\n");
372*ea2909b6Skaashoek     if (ip->addrs[INDIRECT] == 0) {
373*ea2909b6Skaashoek       cprintf("newblock: allocate indirect block\n");
374*ea2909b6Skaashoek       b = balloc(ip->dev);
375*ea2909b6Skaashoek       if (b <= 0) return -1;
376*ea2909b6Skaashoek       ip->addrs[INDIRECT] = b;
377*ea2909b6Skaashoek     }
378*ea2909b6Skaashoek     inbp = bread(ip->dev, bmap(ip, INDIRECT));
379*ea2909b6Skaashoek     inaddrs = (uint *) inbp->data;
380*ea2909b6Skaashoek     if (inaddrs[lbn - NDIRECT] == 0) {
381*ea2909b6Skaashoek       b = balloc(ip->dev);
382*ea2909b6Skaashoek       if (b <= 0) return -1;
383*ea2909b6Skaashoek       inaddrs[lbn - NDIRECT] = b;
384*ea2909b6Skaashoek       bwrite(inbp, INDIRECT);
385*ea2909b6Skaashoek     }
386*ea2909b6Skaashoek     brelse(inbp);
387*ea2909b6Skaashoek   }
388*ea2909b6Skaashoek   return 0;
389*ea2909b6Skaashoek }
390*ea2909b6Skaashoek 
391*ea2909b6Skaashoek int
39217a85657Srtm writei(struct inode *ip, char *addr, uint off, uint n)
3936fa5ffb5Skaashoek {
3946fa5ffb5Skaashoek   if (ip->type == T_DEV) {
395939f9edeSkaashoek     if (ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].d_write)
396939f9edeSkaashoek       return -1;
3976fa5ffb5Skaashoek     return devsw[ip->major].d_write (ip->minor, addr, n);
398*ea2909b6Skaashoek   } else if (ip->type == T_FILE || ip->type == T_DIR) {
39928d9ef04Skaashoek     struct buf *bp;
40028d9ef04Skaashoek     int r = 0;
40128d9ef04Skaashoek     int m;
40228d9ef04Skaashoek     int lbn;
40328d9ef04Skaashoek     while (r < n) {
40428d9ef04Skaashoek       lbn = off / BSIZE;
405*ea2909b6Skaashoek       if (lbn >= MAXFILE) return r;
406*ea2909b6Skaashoek       if (newblock(ip, lbn) < 0) {
407*ea2909b6Skaashoek 	cprintf("newblock failed\n");
408*ea2909b6Skaashoek 	return r;
40928d9ef04Skaashoek       }
41022bac2cbSkaashoek       m = min(BSIZE - off % BSIZE, n-r);
411*ea2909b6Skaashoek       bp = bread(ip->dev, bmap(ip, lbn));
41228d9ef04Skaashoek       memmove (bp->data + off % BSIZE, addr, m);
413*ea2909b6Skaashoek       bwrite (bp, bmap(ip, lbn));
41428d9ef04Skaashoek       brelse (bp);
41528d9ef04Skaashoek       r += m;
41628d9ef04Skaashoek       off += m;
41728d9ef04Skaashoek     }
41828d9ef04Skaashoek     if (r > 0) {
41928d9ef04Skaashoek       if (off > ip->size) {
420bdb66433Skaashoek 	if (ip->type == T_DIR) ip->size = ((off / BSIZE) + 1) * BSIZE;
421bdb66433Skaashoek 	else ip->size = off;
42228d9ef04Skaashoek       }
42328d9ef04Skaashoek       iupdate(ip);
42428d9ef04Skaashoek     }
42528d9ef04Skaashoek     return r;
4266fa5ffb5Skaashoek   } else {
4276fa5ffb5Skaashoek     panic ("writei: unknown type\n");
4288a8be1b8Srtm     return 0;
4296fa5ffb5Skaashoek   }
4306fa5ffb5Skaashoek }
4316fa5ffb5Skaashoek 
432211ff0c6Srtm // look up a path name, in one of three modes.
433211ff0c6Srtm // NAMEI_LOOKUP: return locked target inode.
434211ff0c6Srtm // NAMEI_CREATE: return locked parent inode.
435211ff0c6Srtm //   but return 0 if name does exist.
436211ff0c6Srtm // NAMEI_DELETE: return locked parent inode, offset of dirent in *ret_off.
437211ff0c6Srtm //   return 0 if name doesn't exist.
4389d3fb671Srtm struct inode *
439211ff0c6Srtm namei(char *path, int mode, uint *ret_off)
4409d3fb671Srtm {
4419d3fb671Srtm   struct inode *dp;
4428787cd01Skaashoek   struct proc *p = curproc[cpu()];
443211ff0c6Srtm   char *cp = path, *cp1;
4449d3fb671Srtm   uint off, dev;
4459d3fb671Srtm   struct buf *bp;
4469d3fb671Srtm   struct dirent *ep;
447211ff0c6Srtm   int i, atend;
4489d3fb671Srtm   unsigned ninum;
4499d3fb671Srtm 
4508787cd01Skaashoek   if (*cp == '/') dp = iget(rootdev, 1);
4518787cd01Skaashoek   else {
4528787cd01Skaashoek     dp = p->cwd;
4538787cd01Skaashoek     iincref(dp);
4548787cd01Skaashoek     ilock(dp);
4558787cd01Skaashoek   }
4569d3fb671Srtm 
4579d3fb671Srtm   while(*cp == '/')
4589d3fb671Srtm     cp++;
4599d3fb671Srtm 
4609d3fb671Srtm   while(1){
4610633b971Skaashoek     if(*cp == '\0'){
462211ff0c6Srtm       if(mode == NAMEI_LOOKUP)
4639d3fb671Srtm         return dp;
464211ff0c6Srtm       iput(dp);
465211ff0c6Srtm       return 0;
4660633b971Skaashoek     }
4679d3fb671Srtm 
4689d3fb671Srtm     if(dp->type != T_DIR){
4699d3fb671Srtm       iput(dp);
4709d3fb671Srtm       return 0;
4719d3fb671Srtm     }
4729d3fb671Srtm 
47324111398Skaashoek     for(off = 0; off < dp->size; off += BSIZE){
47424111398Skaashoek       bp = bread(dp->dev, bmap(dp, off / BSIZE));
4759d3fb671Srtm       for(ep = (struct dirent *) bp->data;
47624111398Skaashoek           ep < (struct dirent *) (bp->data + BSIZE);
4779d3fb671Srtm           ep++){
4789d3fb671Srtm         if(ep->inum == 0)
4799d3fb671Srtm           continue;
4809d3fb671Srtm         for(i = 0; i < DIRSIZ && cp[i] != '/' && cp[i]; i++)
4819d3fb671Srtm           if(cp[i] != ep->name[i])
4829d3fb671Srtm             break;
4839d3fb671Srtm         if((cp[i] == '\0' || cp[i] == '/') && (i >= DIRSIZ || ep->name[i] == '\0')){
484211ff0c6Srtm           off += (uchar*)ep - bp->data;
4859d3fb671Srtm           ninum = ep->inum;
4869d3fb671Srtm           brelse(bp);
4879d3fb671Srtm           cp += i;
4889d3fb671Srtm           goto found;
4899d3fb671Srtm         }
4909d3fb671Srtm       }
4919d3fb671Srtm       brelse(bp);
4929d3fb671Srtm     }
493211ff0c6Srtm     atend = 1;
494211ff0c6Srtm     for(cp1 = cp; *cp1; cp1++)
495211ff0c6Srtm       if(*cp1 == '/')
496211ff0c6Srtm         atend = 0;
497211ff0c6Srtm     if(mode == NAMEI_CREATE && atend)
498211ff0c6Srtm       return dp;
499211ff0c6Srtm 
5009d3fb671Srtm     iput(dp);
5019d3fb671Srtm     return 0;
5029d3fb671Srtm 
5039d3fb671Srtm   found:
504211ff0c6Srtm     if(mode == NAMEI_DELETE && *cp == '\0'){
505211ff0c6Srtm       *ret_off = off;
506211ff0c6Srtm       return dp;
507211ff0c6Srtm     }
5089d3fb671Srtm     dev = dp->dev;
5099d3fb671Srtm     iput(dp);
5109d3fb671Srtm     dp = iget(dev, ninum);
5117ce01cf9Srtm     if(dp->type == 0 || dp->nlink < 1)
5127ce01cf9Srtm       panic("namei");
5139d3fb671Srtm     while(*cp == '/')
5149d3fb671Srtm       cp++;
5159d3fb671Srtm   }
5169d3fb671Srtm }
517e8d11c2eSkaashoek 
5189e5970d5Srtm void
5199e5970d5Srtm wdir(struct inode *dp, char *name, uint ino)
5209e5970d5Srtm {
5219e5970d5Srtm   uint off;
522e4bcd2a3Srtm   struct dirent de;
5239e5970d5Srtm   int i;
5249e5970d5Srtm 
525e4bcd2a3Srtm   for(off = 0; off < dp->size; off += sizeof(de)){
526e4bcd2a3Srtm     if(readi(dp, (char *) &de, off, sizeof(de)) != sizeof(de))
527e4bcd2a3Srtm       panic("wdir read");
528e4bcd2a3Srtm     if(de.inum == 0)
529e4bcd2a3Srtm       break;
530e4bcd2a3Srtm   }
531211ff0c6Srtm 
532e4bcd2a3Srtm   de.inum = ino;
5339e5970d5Srtm   for(i = 0; i < DIRSIZ && name[i]; i++)
534e4bcd2a3Srtm     de.name[i] = name[i];
5359e5970d5Srtm   for( ; i < DIRSIZ; i++)
536e4bcd2a3Srtm     de.name[i] = '\0';
537e4bcd2a3Srtm 
538e4bcd2a3Srtm   if(writei(dp, (char *) &de, off, sizeof(de)) != sizeof(de))
539e4bcd2a3Srtm     panic("wdir write");
5409e5970d5Srtm }
5419e5970d5Srtm 
542e8d11c2eSkaashoek struct inode *
5430633b971Skaashoek mknod(char *cp, short type, short major, short minor)
544e8d11c2eSkaashoek {
5450633b971Skaashoek   struct inode *ip, *dp;
546e8d11c2eSkaashoek 
547211ff0c6Srtm   if ((dp = namei(cp, NAMEI_CREATE, 0)) == 0)
5480633b971Skaashoek     return 0;
549211ff0c6Srtm 
550e8d11c2eSkaashoek   ip = ialloc(dp->dev, type);
5510633b971Skaashoek   if (ip == 0) {
5520633b971Skaashoek     iput(dp);
5530633b971Skaashoek     return 0;
5540633b971Skaashoek   }
555e8d11c2eSkaashoek   ip->major = major;
556e8d11c2eSkaashoek   ip->minor = minor;
5576c0e444fSkaashoek   ip->size = 0;
5587ce01cf9Srtm   ip->nlink = 1;
5596c0e444fSkaashoek 
5606c0e444fSkaashoek   iupdate (ip);  // write new inode to disk
561e8d11c2eSkaashoek 
5629e5970d5Srtm   wdir(dp, cp, ip->inum);
5630633b971Skaashoek   iput(dp);
564e8d11c2eSkaashoek   return ip;
565e8d11c2eSkaashoek }
56624437cd5Skaashoek 
56724437cd5Skaashoek int
56824437cd5Skaashoek unlink(char *cp)
56924437cd5Skaashoek {
570211ff0c6Srtm   struct inode *ip, *dp;
571211ff0c6Srtm   struct dirent de;
57217e3cf15Srtm   uint off, inum, dev;
57324437cd5Skaashoek 
57417e3cf15Srtm   if ((dp = namei(cp, NAMEI_DELETE, &off)) == 0)
57524437cd5Skaashoek     return -1;
57624437cd5Skaashoek 
57717e3cf15Srtm   dev = dp->dev;
57817e3cf15Srtm 
57917e3cf15Srtm   if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de) || de.inum == 0)
580211ff0c6Srtm     panic("unlink no entry");
58117e3cf15Srtm 
582211ff0c6Srtm   inum = de.inum;
58324437cd5Skaashoek 
584211ff0c6Srtm   memset(&de, 0, sizeof(de));
585211ff0c6Srtm   if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
586211ff0c6Srtm     panic("unlink dir write");
58724437cd5Skaashoek 
58824437cd5Skaashoek   iupdate(dp);
58924437cd5Skaashoek   iput(dp);
590211ff0c6Srtm 
59117e3cf15Srtm   ip = iget(dev, inum);
592211ff0c6Srtm 
593211ff0c6Srtm   ip->nlink--;
594211ff0c6Srtm 
595211ff0c6Srtm   iupdate(ip);
59622bac2cbSkaashoek   iput(ip);
597211ff0c6Srtm 
59824437cd5Skaashoek   return 0;
59924437cd5Skaashoek }
6009e5970d5Srtm 
6019e5970d5Srtm int
6029e5970d5Srtm link(char *name1, char *name2)
6039e5970d5Srtm {
604211ff0c6Srtm   struct inode *ip, *dp;
6059e5970d5Srtm 
60617e3cf15Srtm   if ((ip = namei(name1, NAMEI_LOOKUP, 0)) == 0)
6079e5970d5Srtm     return -1;
608211ff0c6Srtm   if(ip->type == T_DIR){
609211ff0c6Srtm     iput(ip);
610211ff0c6Srtm     return -1;
611211ff0c6Srtm   }
6129e5970d5Srtm 
613211ff0c6Srtm   iunlock(ip);
614211ff0c6Srtm 
615211ff0c6Srtm   if ((dp = namei(name2, NAMEI_CREATE, 0)) == 0) {
616211ff0c6Srtm     idecref(ip);
617211ff0c6Srtm     return -1;
618211ff0c6Srtm   }
619211ff0c6Srtm   if(dp->dev != ip->dev){
620211ff0c6Srtm     idecref(ip);
621211ff0c6Srtm     iput(dp);
622211ff0c6Srtm     return -1;
623211ff0c6Srtm   }
624211ff0c6Srtm 
625211ff0c6Srtm   ilock(ip);
6269e5970d5Srtm   ip->nlink += 1;
6279e5970d5Srtm   iupdate (ip);
6289e5970d5Srtm 
6299e5970d5Srtm   wdir(dp, name2, ip->inum);
6309e5970d5Srtm   iput(dp);
6319e5970d5Srtm   iput(ip);
6329e5970d5Srtm 
6339e5970d5Srtm   return 0;
6349e5970d5Srtm }
635